
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@deckflow/decktools-sdk
Advanced tools
Languages: English | 简体中文 | 繁體中文 | Français | Español | Русский | 日本語
TypeScript SDK for DeckTools/Deckflow task APIs in Node.js and browsers.
pnpm add @deckflow/decktools-sdk
In this monorepo:
pnpm --filter @deckflow/decktools-sdk build
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.
localStorage under df_uuid.~/.deckflow/auth-uuid (override the directory with DECKFLOW_CONFIG_DIR).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);
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.
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:
'./a.pptx'Uint8Array or ArrayBufferBlob/FileFor 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.
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);
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.Every helper accepts { spaceId?, files?, fileIds?, name?, params?, upload? }, sets the backend task type, uploads files when needed, and returns a typed DeckTask.
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 } });
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'] },
});
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.
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' },
});
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.
Blob/File; the SDK reads the file name and calculates MD5.deck.tasks.wait(taskId, { useEventStream: false }).FAQs
DeckTools TypeScript SDK for Node.js and browsers
The npm package @deckflow/decktools-sdk receives a total of 0 weekly downloads. As such, @deckflow/decktools-sdk popularity was classified as not popular.
We found that @deckflow/decktools-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.