✦Spectra SDK Docs

Storage JS SDK

Storage JS SDK는 사용자 계정 root / 기준으로 파일을 업로드, 조회, 다운로드, 삭제한다.

현재 배포 버전은 0.1.3이다.

설치

npm install @spectra-platform/storage-sdk

API tree

Storage JS SDK
├─ Client setup
│  ├─ new SpectraStorageClient(config)
│  └─ createSpectraStorageClient(config)
└─ Files
   ├─ listFiles(options?)
   ├─ uploadFile(input)
   ├─ uploadImage(input)
   ├─ uploadFile(fileOrBlob, options)   # legacy compatible
   ├─ uploadImage(file, options?)       # legacy compatible
   ├─ getDownloadUrl(path)
   ├─ downloadBlob(path)
   └─ deleteFile(path)

Auth 객체와 함께 사용

Storage SDK는 Auth SDK의 access token provider를 사용한다. SDK 내부에서 auth.getAccessToken({ service: "storage" })를 호출하므로 기본 Storage SDK 설정은 Storage secret이나 Secret Key를 요구하지 않는다.

import { SpectraAuthClient } from "@spectra-platform/auth-sdk";
import { SpectraStorageClient } from "@spectra-platform/storage-sdk";

const auth = new SpectraAuthClient({
  projectId: "proj_...",
  // Current Auth SDK compatibility field. It is not a primary product key.
  publicClientId: "app_...",
  environment: "test",
  redirectUri: "https://myapp.example.com/auth/callback",
});

const storage = new SpectraStorageClient({
  projectId: "proj_...",
  auth,
});

업로드 직전에 문제가 생기면 Auth session과 Storage service token을 한 번만 분리해서 확인한다.

일반 앱 코드에서 매 업로드마다 forceRefresh: true를 선행 호출하지 않는다. Storage SDK가 필요한

service token 발급과 401/403 재시도를 내부에서 처리한다.

const session = await auth.getSession();
const storageToken = await auth.getAccessToken({
  service: "storage",
});

console.log(Boolean(session), Boolean(storageToken));

session이 없으면 소비 앱의 Auth callback/sessionStore 문제다. session은 있는데 APP_SESSION_UNAUTHORIZED가

나오면 SDK error의 requestId를 Platform CS에 전달한다. Platform은 Auth API audit denial_reason으로

service-token 발급 거절 원인을 좁힌다.

forceRefresh: true는 Platform CS가 명시적으로 요청한 단발성 진단에서만 사용하고, 업로드 루프나 파일 선택 이벤트에서 반복 호출하지 않는다.

API detail

new SpectraStorageClient(config)

Storage client를 만든다.

createSpectraStorageClient(config)

new SpectraStorageClient(config)와 같은 결과를 반환하는 factory helper다.

listFiles(options?)

user-root prefix 기준으로 파일과 하위 prefix를 조회한다.

const listed = await storage.listFiles({
  prefix: "/community/reviews/",
  limit: 50,
});

console.log(listed.files, listed.prefixes, listed.nextCursor);

주요 입력:

uploadFile(input)

일반 파일, 이미지, 영상 Blob을 업로드한다. 권장 public API는 객체형 입력이다. SDK는 먼저 upload intent를 만들고 signed URL로 bytes를 올린 뒤 complete 요청을 보낸다.

const object = await storage.uploadFile({
  file,
  path: "/community/reviews/photo.jpg",
  visibility: "private",
  context: "community",
  fileInfo: {
    originalName: file.name,
    fingerprint: `${file.name}|${file.size}|${file.type}|${file.lastModified}`,
    lastModified: file.lastModified,
  },
  onProgress: ({ loaded, total }) => {
    console.log(loaded, total);
  },
});

주요 객체형 입력:

객체형 입력의 context/fileInfo는 SDK가 safe metadata key로 바꿔 서버에 보낸다.

{
  "context": "community",
  "original_file_name": "한글파일명.png",
  "file_fingerprint": "한글파일명.png|12345|image/png|1786...",
  "last_modified": "1786..."
}

Storage API는 이 logical metadata를 원문으로 저장한다. 단, signed PUT에 필요한

x-amz-meta-user-* header value는 Storage API가 브라우저-safe ASCII 값으로 인코딩해서 내려준다.

소비 앱이 직접 S3/MinIO metadata header를 만들면 안 된다.

uploadImage(input)

이미지 전용 helper다. image/* Blob만 허용한다.

const image = await storage.uploadImage({
  file,
  directory: "/reviews/",
  visibility: "private",
  context: "review",
  fileInfo: {
    originalName: file.name,
    lastModified: file.lastModified,
  },
});

path와 directory는 동시에 넣을 수 없다.

visibility: "public_read"는 읽기 URL을 가진 사람이 object를 읽을 수 있다는 뜻이다. 쓰기, 덮어쓰기, 삭제, quota, audit, moderation은 여전히 Storage 정책을 따른다. Bucket ACL, CDN, signed PUT header 같은 내부 설정은 기본 앱 코드에서 직접 다루지 않는다.

getDownloadUrl(path)

임시 download URL을 발급받는다.

const url = await storage.getDownloadUrl(object.objectKey);
window.open(url, "_blank", "noopener,noreferrer");

downloadBlob(path)

download URL을 발급받아 Blob으로 내려받는다.

const blob = await storage.downloadBlob(object.objectKey);

deleteFile(path)

user-root 파일을 삭제한다.

await storage.deleteFile(object.objectKey);

Chat, 커뮤니티, 리뷰 첨부

Storage SDK는 파일의 binary 저장을 맡고, Chat 또는 앱 Backend는 object reference만 저장한다.

const image = await storage.uploadImage({
  file,
  directory: "/community/reviews/",
  visibility: "private",
  context: "community",
  fileInfo: {
    originalName: file.name,
    lastModified: file.lastModified,
  },
});

await chat.sendMessage(room.id, {
  text: "사진 첨부",
  attachments: [
    {
      objectKey: image.objectKey,
      contentType: image.contentType,
      byteSize: image.byteSize,
      checksumSha256: image.checksumSha256,
    },
  ],
});

주의

Storage SDK는 app-user token으로 내 파일 작업을 수행한다. 서버 관리자 권한이 필요한 bucket 운영, quota 정책 변경, audit export는 browser SDK 범위가 아니다. 그런 작업은 서버에 보관한 환경(test/live)에 묶인 Project ID + Secret Key로 Project를 확인하고 Storage service toggle이 켜져 있을 때 수행한다.