@seowoohyeok/dms-client
v0.0.2
Published
DMS 브라우저 클라이언트 SDK (업로드/다운로드/재개).
Readme
@seowoohyeok/dms-client
브라우저 환경에서 DMS 서버와 연동하기 위한 TypeScript SDK입니다.
- 파일 업로드/다운로드
- 브라우저
saveAs다운로드 - 폴더 조회/생성/이동/이름 변경/삭제
- 파일 이동/이름 변경/삭제
- 업로드/다운로드 진행률 콜백
- SDK 이벤트 관찰
- 전체 요청 취소
설치
npm install @seowoohyeok/dms-client빠른 시작
import { DmsClient } from '@seowoohyeok/dms-client';
const client = new DmsClient({
baseUrl: 'https://dms.example.com',
getToken: async () => '...jwt...',
});
const uploaded = await client.upload(file, {
folderId: 'folder-123',
onProgress: (progress) => {
console.log('upload', progress.percent);
},
});
const blob = await client.download(uploaded.id, {
onProgress: (progress) => {
console.log('download', progress.percent);
},
});클라이언트 생성
import { DmsClient } from '@seowoohyeok/dms-client';
const client = new DmsClient({
baseUrl: 'https://dms.example.com',
getToken: async ({ forceRefresh } = {}) => {
return forceRefresh ? 'new-token' : 'cached-token';
},
apiKey: 'dmsp_xxx',
tags: {
app: 'browser-admin',
screen: 'file-manager',
},
observer: {
onEvent(event) {
console.log(event.type, event.operation, event.traceId);
},
},
multipartThreshold: 100 * 1024 * 1024,
chunkSize: 5 * 1024 * 1024,
concurrency: 3,
retry: {
maxAttempts: 3,
initialDelayMs: 500,
maxDelayMs: 10000,
},
});주요 옵션
baseUrl: DMS 서버 절대 URL.http또는https만 허용됩니다.getToken: 요청마다 Bearer 토큰을 반환하는 비동기 함수입니다.apiKey: 서비스 프로젝트 API 키입니다. 설정하면 업로드/폴더 생성/파일 및 폴더 쓰기 요청에 자동 포함됩니다.tags: 모든 요청에 공통으로 붙는 추적 태그입니다.observer.onEvent: SDK 이벤트 수신기입니다.multipartThreshold: 이 크기 이상 파일은 multipart 업로드를 사용합니다.chunkSize: multipart 업로드 청크 크기입니다.concurrency: multipart 업로드 동시 전송 수입니다.retry: 네트워크/서버 오류 재시도 정책입니다.
업로드
기본 업로드
const result = await client.upload(file, {
folderId: 'folder-123',
});진행률 표시
const result = await client.upload(file, {
folderId: 'folder-123',
onProgress: ({ bytesUploaded, bytesTotal, percent, partsCompleted, partsTotal }) => {
console.log(bytesUploaded, bytesTotal, percent, partsCompleted, partsTotal);
},
});업로드 모드 강제
await client.upload(file, {
folderId: 'folder-123',
force: 'simple',
});
await client.upload(file, {
folderId: 'folder-123',
force: 'multipart',
});큐 대기 처리
서버가 multipart 업로드를 바로 시작하지 못하면 onQueued가 호출될 수 있습니다.
await client.upload(file, {
folderId: 'folder-123',
onQueued: async ({ ticket, proceed, cancel }) => {
console.log('queued', ticket);
const userAccepted = true;
if (userAccepted) {
await proceed();
return;
}
await cancel();
},
});lockPassword 사용
apiKey를 사용하지 않는 환경이면 쓰기 요청에서 lockPassword를 넘길 수 있습니다.
await client.upload(file, {
folderId: 'folder-123',
lockPassword: 'my-secret',
});업로드 반환값
upload()는 서버 응답을 그대로 포함한 UploadResult를 반환합니다.
const uploaded = await client.upload(file, { folderId: 'folder-123' });
console.log(uploaded.id);
console.log(uploaded.name);
console.log(uploaded.size);
console.log(uploaded.state);
console.log(uploaded.syncEventId);다운로드
Blob 다운로드
const blob = await client.download('file-123');진행률 표시
const blob = await client.download('file-123', {
onProgress: ({ bytesDownloaded, bytesTotal, percent }) => {
console.log(bytesDownloaded, bytesTotal, percent);
},
});브라우저 저장
await client.saveAs('file-123');
await client.saveAs('file-123', 'report.pdf');이어받기
const partialBlob = new Blob([partialBytes], { type: 'application/pdf' });
const completed = await client.download('file-123', {
resume: {
fromBlob: partialBlob,
etag: '"etag-value"',
},
});폴더 API
조회
const info = await client.folders.getInfo('folder-123');
const root = await client.folders.getRoot();
const qms = await client.folders.getQms();
const contents = await client.folders.listContents('folder-123', {
page: 1,
pageSize: 50,
sort: 'name,asc',
});
const tree = await client.folders.getTree('folder-123');
const treeByPath = await client.folders.getTreeByPath('/projects/2026');
const searched = await client.folders.search('folder-123', {
keyword: 'report',
page: 1,
pageSize: 20,
});생성
const created = await client.folders.create({
name: '2026 계획',
parentId: 'parent-folder-id',
});
const createdWithPassword = await client.folders.create({
name: '보안 폴더',
parentId: 'parent-folder-id',
lockPassword: 'my-secret',
});이동, 이름 변경, 삭제
await client.folders.move('folder-123', {
targetParentId: 'target-parent-id',
});
await client.folders.rename('folder-123', {
name: '변경된 폴더명',
});
await client.folders.delete('folder-123');파일 API
await client.files.move('file-123', {
targetFolderId: 'target-folder-id',
});
await client.files.rename('file-123', {
name: 'renamed-report.pdf',
});
await client.files.delete('file-123');공통 옵션
업로드/다운로드/폴더/파일 API 일부는 아래 옵션을 공통으로 받습니다.
signal:AbortController로 요청 취소tags: 요청별 추적 태그 추가lockPassword: 쓰기 요청 시 문서 잠금 비밀번호 전달
예시:
const controller = new AbortController();
await client.files.rename(
'file-123',
{ name: 'report-final.pdf' },
{
signal: controller.signal,
tags: { feature: 'bulk-rename' },
lockPassword: 'my-secret',
},
);취소
단일 요청 취소
const controller = new AbortController();
const promise = client.download('file-123', {
signal: controller.signal,
});
controller.abort();
await promise;전체 요청 취소
client.cancelAll();이벤트 관찰
observer.onEvent로 SDK 내부 이벤트를 구독할 수 있습니다.
const client = new DmsClient({
baseUrl: 'https://dms.example.com',
getToken: async () => 'token',
observer: {
onEvent(event) {
switch (event.type) {
case 'session:start':
case 'session:complete':
case 'session:aborted':
case 'upload:progress':
case 'download:progress':
case 'request:start':
case 'request:complete':
case 'request:error':
case 'request:retry':
case 'queue:wait':
console.log(event);
break;
}
},
},
});대표 event.type:
session:startsession:completesession:abortedrequest:startrequest:completerequest:errorrequest:retryupload:progressdownload:progressqueue:waitresume:persistedresume:matchedresume:mismatch
resumePending
resumePending()은 현재 IndexedDB에 저장된 보류 업로드 세션 목록만 반환합니다.
실제 업로드 재개 실행까지 자동으로 처리하지는 않습니다.
const pendingSessions = await client.resumePending();
console.log(pendingSessions);에러 처리
SDK는 다음 에러 클래스를 export 합니다.
DmsSdkErrorDmsNetworkErrorDmsHttpErrorDmsAuthErrorDmsNotFoundErrorDmsValidationErrorDmsAbortErrorDmsQueueErrorDmsResumeErrorDmsConfigError
import { DmsAuthError, DmsHttpError } from '@seowoohyeok/dms-client';
try {
await client.download('file-123');
} catch (error) {
if (error instanceof DmsAuthError) {
console.error('auth failed', error.status, error.traceId);
} else if (error instanceof DmsHttpError) {
console.error('http error', error.status, error.body);
} else {
console.error(error);
}
}TypeScript export
패키지는 아래 주요 타입을 함께 export 합니다.
import type {
DmsClientConfig,
UploadOptions,
DownloadOptions,
UploadProgress,
DownloadProgress,
UploadResult,
WriteOpts,
FolderReadOpts,
FolderInfo,
RootFolderInfo,
FolderTreeNode,
FolderFlatNode,
FolderContents,
FolderItem,
GetFolderContentsQuery,
SearchFolderContentsQuery,
CreateFolderRequest,
CreateFolderResponse,
MoveFolderRequest,
RenameFolderRequest,
MoveFileRequest,
RenameFileRequest,
SdkEvent,
SdkEventBase,
SdkOperation,
} from '@seowoohyeok/dms-client';개발
npm install
npm run build
npm test
npm run test:int
npm run demo참고
- 브라우저 데모:
examples/browser-demo - 상세 스펙 문서:
docs/specs/
