New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@deckflow/decktools-sdk

Package Overview
Dependencies
Maintainers
3
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@deckflow/decktools-sdk

DeckTools TypeScript SDK for Node.js and browsers

latest
Source
npmnpm
Version
1.0.0
Version published
Weekly downloads
0
Maintainers
3
Weekly downloads
 
Created
Source

Languages: English | 简体中文 | 繁體中文 | Français | Español | Русский | 日本語

@deckflow/decktools-sdk

TypeScript SDK for DeckTools/Deckflow task APIs in Node.js and browsers.

Install

pnpm add @deckflow/decktools-sdk

In this monorepo:

pnpm --filter @deckflow/decktools-sdk build

Create a Client

Use the root entry point in Node.js. Browser applications should use the dedicated @deckflow/decktools-sdk/browser entry point documented below.

import { createDeck } from '@deckflow/decktools-sdk';

const deck = createDeck({
  root: 'https://app.deckflow.com/v1',
  token: 'user-token',
  apiKey: 'api-key',
  spaceId: 'space-id',
});

Options:

  • root?: string - API root address. Defaults to https://app.deckflow.com/v1.
  • token?: string - sent as X-Auth-Token.
  • apiKey?: string - sent as Authorization: Bearer {apiKey}.
  • spaceId?: string - default space id for task and file calls.
  • authUuid?: string - explicit client UUID (UUID v4) sent as X-Auth-UUID. Skips automatic persistence.
  • authUuidStorage?: { get(), set(value) } - custom storage for client UUID (SSR, tests, embedded apps).
  • onUnauthorized?: () => Promise<{ token: string; spaceId?: string } | string> - called once after a 401, then the request is retried.
  • onPaymentRequired?: () => Promise<void> - called once after a 402, then the request is retried.
  • allowGuestFallback?: boolean - allow expired credentials to be cleared and retried as guest; defaults to true in Node and false in /browser.
  • retryMutations?: boolean - retry POSTs after transient network/server failures; defaults to true in Node and false in /browser.

token, apiKey, and spaceId are all optional. When spaceId is omitted the SDK resolves it from GET /user, an endpoint that only requires X-Auth-UUID. This means token and apiKey can both be empty: the SDK runs in guest mode, the server identifies the guest by X-Auth-UUID and enforces usage limits and rate quotas. This is useful for try-before-login experiences.

const deck = createDeck({ authUuid: 'f47ac10b-58cc-4372-a567-0e02b2c3d479' });
await deck.generation({ params: { inputText: 'Write a launch plan', pageCount: 8 } });

Every DeckTools API request automatically includes X-Auth-UUID, a stable UUID v4 used to track the client across sessions.

  • Browser: persisted in localStorage under df_uuid.
  • Node.js: persisted in ~/.deckflow/auth-uuid (override the directory with DECKFLOW_CONFIG_DIR).
  • Explicit override: pass authUuid or set DECKTOOLS_AUTH_UUID (Node only) for fixed IDs in CI, containers, or multi-tenant servers.
const uuid = await deck.getAuthUuid();
console.log('Client UUID:', uuid);

Browser entry point

The browser entry point shares the task/upload/parse implementation but excludes Node file and UUID storage code. It is safe to import during SSR. Local paths are rejected; use File, named Blob, or named binary data instead.

import { createDeck } from '@deckflow/decktools-sdk/browser';

const deck = createDeck({ root: 'https://api.example.com/v1', token: userAccessToken });
const controller = new AbortController();
const parsed = await deck.parse({ file, name: file.name }, {
  signal: controller.signal,
  onTask: (task) => console.log('Created:', task.id),
  upload: { onProgress: (fraction) => console.log('Uploaded:', fraction) },
  wait: { onProgress: (task) => console.log(task.status) },
});
const view = await deck.convert({ irKey: parsed.irKey }, { signal: controller.signal });
console.log(view.markdown);

Both facades accept signal and onTask. Upload APIs, task creation, task reads, downloads, waits and subscriptions also accept signal. Aborting stops HTTP, uploads, SSE and polling/retry delays; it does not cancel or delete a cloud task that has already been created. Keep the onTask id to resume inspection later. An interrupted submission may already exist remotely, so do not blindly submit it again.

Browser authentication fails closed: a 401 may refresh credentials once with onUnauthorized, but a missing/empty/failed refresh or another 401 raises an error without switching to guest. Starting without credentials remains an explicit guest-mode option. Browser POSTs are not automatically retried after ambiguous transport failures. Do not put long-lived server API keys in browser code; use a user-scoped token or a backend proxy. API, SSE and storage endpoints must allow your origin through CORS, including exposing ETag for multipart uploads.

Upload progress is coarse-grained: single/inline uploads report 1 after the request succeeds; multipart uploads report completed parts up to 0.95 and 1 after completion. No artificial byte-level progress is emitted.

Create Tasks With Files

Pass user-selected files directly to task methods. The SDK uploads them internally and sends the resulting file ids to the task API:

const task = await deck.convertPptToPdf({
  files: ['./slides.pptx'],
  upload: {
    onProgress: (p) => console.log(`${Math.round(p * 100)}%`),
  },
});

files supports:

  • Node.js file path: './a.pptx'
  • Node.js/browser binary data: Uint8Array or ArrayBuffer
  • Browser Blob/File

For browser file pickers, pass the selected File object:

await deck.convertPptToPdf({
  files: [file],
});

For binary data without a file name, include per-file upload options:

await deck.imageOcr({
  files: [{ input: bytes, name: 'image.png' }],
  params: { language: 'en' },
});

For compatibility with existing integrations, fileIds is still accepted and can be combined with files.

Generic Task API

const task = await deck.tasks.create({
  type: 'convertor.ppt2pdf',
  files: ['./slides.pptx'],
  name: 'slides',
  params: {},
});

await deck.tasks.list({ type: 'convertor.ppt2pdf', startIndex: 0, maxResults: 50 });
await deck.tasks.get(task.id);
await deck.tasks.wait(task.id, { timeout: 300, useEventStream: true });
await deck.tasks.down<'convertor.ppt2pdf'>(task.id);
await deck.tasks.delete(task.id);

const cancel = await deck.tasks.subscribe(task.id, {
  onUpdate: (next) => console.log(next.status),
  onError: console.error,
});
cancel();

Task detail responses are for status/progress metadata. Task results should be read through deck.tasks.down(...) or the backend-name alias deck.ttask.down(...).

const result = await deck.ttask.down<'convertor.ppt2pdf'>(task.id);
const generationDownload = await deck.ttask.down<'generation'>(task.id, { type: 'pptx' });
console.log(generationDownload.downloadUrl);

Result Types

The SDK exports concrete result types for every task type through DeckTaskTypeResult.

Most file-producing tasks return tuple-shaped file results because that is the backend contract:

type FileResult = [
  path: string,
  bytes: number,
  hash: string,
];

type ConvertFileResult = [
  path: string,
  bytes: number,
  hash: string,
  bounds?: { w?: number; h?: number; total?: number } | null,
];

path is the storage key or relative path in raw backend data. When the task detail API expands downloadable results, it may already be a signed/access URL.

Examples:

  • deck.convertPptToPdf(...) returns ConvertFileResult[].
  • deck.convertHtmlToPptx(...) returns { target: FileResult; usedFonts: string[] }.
  • deck.pptxSplit(...) returns { ppt, sections, slides } with typed slide file metadata.
  • deck.pptxGetFontInfo(...) returns { fonts, embeddedFont, subsetFont }.
  • deck.pptxGetTextShapes(...) returns typed page/shape/text/image metadata.

Typed Task Helpers

Every helper accepts { spaceId?, files?, fileIds?, name?, params?, upload? }, sets the backend task type, uploads files when needed, and returns a typed DeckTask.

File and Image

await deck.fileCompress({ files: ['./document.pdf'] });
await deck.imageOcr({ files: [file], params: { language: 'en' } });
await deck.imageConvertWebp({ files: [file] });
await deck.imageResize({ files: [file], params: { maxWidth: 1024 } });

PPTX

await deck.pptxSplit({ files: ['./slides.pptx'], params: { indexes: [0, 1] } });
await deck.pptxJoin({ files: ['./part1.pptx', './part2.pptx'], name: 'merged' });
await deck.pptxGetFontInfo({ files: ['./slides.pptx'] });
await deck.pptxGetTextShapes({
  files: ['./slides.pptx'],
  params: { includeNotes: true, ignoreEmptyText: true },
});
await deck.pptxEmbedFonts({
  files: ['./slides.pptx'],
  params: { usedFonts: ['Arial'] },
});

Converters

await deck.convertPptToImage({
  files: ['./slides.pptx'],
  params: { resolution: 1920, format: 'jpg' },
});
await deck.convertPptToPptx({ files: ['./slides.ppt'] });
await deck.convertPptToPdf({ files: ['./slides.pptx'] });
await deck.convertDocToPdf({ files: ['./handbook.docx'] });
await deck.convertPptToVideo({ files: ['./slides.pptx'] });
await deck.convertPdfToImage({ files: ['./document.pdf'] });
await deck.convertKeynoteToImage({ files: ['./deck.key'] });
await deck.convertKeynoteToHtml({ files: ['./deck.key'] });
await deck.convertKeynoteToPdf({ files: ['./deck.key'] });
await deck.convertHtmlToPng({
  files: [{ input: htmlBytes, name: 'page.html' }],
  params: { width: 1280, height: 720, fullPage: true },
});
await deck.convertMarkdownToPng({
  files: [{ input: markdownBytes, name: 'page.md' }],
  params: { theme: 'dark', pageWidth: 960 },
});
await deck.convertHtmlToPptx({
  files: [{ input: htmlBytes, name: 'deck.html' }],
  params: { width: 1280, height: 720, needEmbedFonts: false },
});
await deck.convertHtmlToPptx({
  files: ['./page1.html', './page2.html'],
  params: { width: 1280, height: 720 },
});

Ordered multi-source files are meaningful for task types that map the whole file array into backend parameters, including pptx.join, convertor.html2pptx, html.buildPlayer, and generation. Most other task types read one source file; pass one file per task for those.

HTML Player, Generation, Translation, Revamp

await deck.htmlBuildPlayer({
  params: {
    contents: [{ key: 'pages/1.html' }],
    pageWidth: 1280,
    pageHeight: 720,
    title: 'Deck',
    description: 'Deck player',
    brandMarkPosition: 'none',
  },
});

await deck.generation({
  files: [referenceFile],
  params: {
    inputText: 'Write a product launch plan',
    enableSearch: true,
    pageCount: 8,
  },
});

await deck.translation({
  files: [file],
  params: {
    from: 'zh',
    to: 'en',
    model: 'Standard',
    useGlossary: false,
    imageTranslate: false,
  },
});

await deck.revamp({
  files: [file],
  params: { lang: 'zh' },
});

Parse Documents

Parsing and view generation are two separate primitives:

  • deck.parse() turns a document into an IR — a structured representation you can hold on to. It never returns Markdown.
  • deck.convert() turns a stored IR into a view, by reference. It never re-parses the source.

That split is the point: parse once, convert as many times as you like. The IR stays available for 7 days, and converting costs no upload and no re-parse.

const parsed = await deck.parse('./slides.pptx');
parsed.ir;      // structured result, passed through verbatim
parsed.irKey;   // the reference — this is what convert() consumes

const { markdown } = await deck.convert({ irKey: parsed.irKey });

convert() also accepts the parse task id, which is handy when you stored the task rather than the key:

await deck.convert({ taskId: parsed.taskId }, { to: 'markdown' });

ir is the response body passed through verbatim, so type it with the task type's result:

import type { PdfParseResult, PptxParseResult } from '@deckflow/decktools-sdk';

const report = await deck.parse<PdfParseResult>('./report.pdf');
report.ir.document.elements;

Parse params ride on the parse options and are only sent to the task types that accept them — password, parseProfile, includeImages for .pdf, stayImageAreaRate for .key:

await deck.parse('./report.pdf', { parseProfile: 'quality', password: 'pw' });

View params belong to convert(), not to parsing — markdownPages for .pptx / .key, markdownMeta (per-element provenance comments) for .pdf:

await deck.convert({ irKey }, { markdownPages: true });
await deck.convert({ irKey }, { markdownMeta: true });

Already-uploaded files take { fileId, name }; links take { url, mode }:

await deck.parse({ fileId: 'uploaded-file-id', name: 'slides.pptx' });
await deck.parse({ url: 'https://example.com/article', mode: 'runtime' });

Supported extensions are .pdf, .pptx, .docx, and .key. The low-level helpers (deck.pdfParse → pdf.pdfParse, deck.pptxParse, deck.docxParse, deck.keynoteParse, deck.htmlGetByURL, deck.convertIr → parse.convert) take the backend params directly.

Images in a converted view are signed URLs that expire. convert() returns an images[] manifest — the same shape for every format — mapping each URL to its persistent key and a suggested on-disk path, so a client that wants to keep the Markdown can download them and rewrite the links.

Conversion degrades rather than fails by default: when rendering breaks, markdownError explains why and markdown is empty. Pass markdownStrict: true to make the task fail instead.

This needs a backend running @deckflow/platform-slave 0.22.0 or newer. Against older servers parse() throws instead of returning a result with no irKey, which would be a result nothing could convert.

Browser and Node.js Notes

  • Task helpers accept files directly and upload them before task creation.
  • Node.js uploads can read a path and calculate MD5.
  • Browser uploads can use Blob/File; the SDK reads the file name and calculates MD5.
  • Server-Sent Event subscription works in Node.js and modern browsers; polling remains available with deck.tasks.wait(taskId, { useEventStream: false }).

FAQs

Package last updated on 07 Sep 2026

Related posts