npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lumir-company/dms-client

v0.0.3

Published

DMS 브라우저 클라이언트 SDK (업로드/다운로드/재개/미리보기).

Downloads

50

Readme

@lumir-company/dms-client

브라우저 환경에서 DMS 서버와 연동하기 위한 TypeScript SDK입니다.

  • 파일 업로드/다운로드
  • 브라우저 saveAs 다운로드
  • 파일 미리보기 (인라인 표시용 Blob)
  • 폴더 조회/생성/이동/이름 변경/삭제
  • 파일 이동/이름 변경/삭제
  • 업로드/다운로드/미리보기 진행률 콜백
  • SDK 이벤트 관찰
  • 전체 요청 취소

설치

npm install @lumir-company/dms-client

빠른 시작

import { DmsClient } from '@lumir-company/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 '@lumir-company/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"',
  },
});

미리보기

서버 GET /v1/files/:fileId/preview 를 호출해 파일 바이트를 그대로 받습니다. 서버는 Content-Disposition: inline 으로 응답하므로, 브라우저가 렌더링 가능한 타입(이미지/PDF/비디오/오디오/텍스트 등)은 그대로 화면에 띄울 수 있고, 그렇지 않은 타입은 폴백 처리할 수 있습니다.

Bearer 인증을 쓰는 SDK 특성상 <img src="..."> 에 URL 을 직접 박을 수 없습니다. 대신 받아온 Blob 을 URL.createObjectURL 로 변환해서 사용합니다.

기본 사용

const blob = await client.preview('file-123');

const objectUrl = URL.createObjectURL(blob);
imgEl.src = objectUrl;

// 사용이 끝나면 메모리 해제
URL.revokeObjectURL(objectUrl);

진행률 표시

const blob = await client.preview('file-123', {
  onProgress: ({ bytesDownloaded, bytesTotal, percent }) => {
    console.log(bytesDownloaded, bytesTotal, percent);
  },
});

타입별 렌더링 예시

const blob = await client.preview('file-123');
const url = URL.createObjectURL(blob);

if (blob.type.startsWith('image/')) {
  const img = document.createElement('img');
  img.src = url;
  document.body.appendChild(img);
} else if (blob.type === 'application/pdf') {
  const frame = document.createElement('iframe');
  frame.src = url;
  document.body.appendChild(frame);
} else if (blob.type.startsWith('video/')) {
  const video = document.createElement('video');
  video.src = url;
  video.controls = true;
  document.body.appendChild(video);
}

preview() 는 내부적으로 다운로드와 동일한 스트리밍 파이프라인을 사용하므로 signal, tags, resume 옵션도 동일하게 받습니다.

폴더 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:start
  • session:complete
  • session:aborted
  • request:start
  • request:complete
  • request:error
  • request:retry
  • upload:progress
  • download:progress (다운로드와 미리보기 모두에서 발생, event.operation 으로 구분)
  • queue:wait
  • resume:persisted
  • resume:matched
  • resume:mismatch

resumePending

resumePending()은 현재 IndexedDB에 저장된 보류 업로드 세션 목록만 반환합니다. 실제 업로드 재개 실행까지 자동으로 처리하지는 않습니다.

const pendingSessions = await client.resumePending();
console.log(pendingSessions);

에러 처리

SDK는 다음 에러 클래스를 export 합니다.

  • DmsSdkError
  • DmsNetworkError
  • DmsHttpError
  • DmsAuthError
  • DmsNotFoundError
  • DmsValidationError
  • DmsAbortError
  • DmsQueueError
  • DmsResumeError
  • DmsConfigError
import { DmsAuthError, DmsHttpError } from '@lumir-company/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 '@lumir-company/dms-client';

개발

npm install
npm run build
npm test
npm run test:int
npm run demo

참고

  • 브라우저 데모: examples/browser-demo
  • 상세 스펙 문서: docs/specs/