
Security News
arXiv Is Rate Limiting Authors Following a Flood of AI Slop Submissions
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.
@deckops/sdk
Advanced tools
Languages: English | 简体中文 | 繁體中文 | Français | Español | Русский | 日本語
TypeScript SDK for Deckops/Deckflow task APIs in Node.js and browsers.
pnpm add @deckops/sdk
In this monorepo:
pnpm --filter @deckops/sdk build
import { createDeck } from '@deckops/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.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 Deckops 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 DECKOPS_AUTH_UUID (Node only) for fixed IDs in CI, containers, or multi-tenant servers.const uuid = await deck.getAuthUuid();
console.log('Client UUID:', uuid);
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 '@deckops/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
Deckops TypeScript SDK for Node.js and browsers
The npm package @deckops/sdk receives a total of 46 weekly downloads. As such, @deckops/sdk popularity was classified as not popular.
We found that @deckops/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
arXiv now limits authors to two submissions a month as AI slop overwhelms moderators, delays good papers, and sparks debate over applying the limit to everyone.

Research
/Security News
A new GhostAction wave hits hundreds of GitHub repos, expanding CI/CD secret theft to cloud and AI credentials in source code and git history.

Research
/Security News
Tensorlake npm SDK version 0.5.144 was compromised in a ChainDrop / Shai-Hulud attack, delivering credential-stealing malware.