npm.io
0.2.0 • Published 3 weeks agoCLI

@deckflow/deckparse

Licence
MIT
Version
0.2.0
Deps
6
Size
843 kB
Vulns
0
Weekly
0
Stars
1
DeprecatedThis package is deprecated

DeckParse

Parse any document into an agent-operable representation.

DeckParse turns documents into durable IR artifacts and derives views from them. Parse once — then convert, again and again, without ever re-reading the source.

deckparse doc.pdf                  # document → IR artifact (doc/)
deckparse convert doc/             # artifact → markdown view, no re-parse
deckparse convert doc.pdf -o doc.md  # one-shot: portable markdown, images localized

It is the Parse pillar of the DeckFlow family: DeckRender turns documents into pixels, DeckParse turns them into state an agent can hold on to.

Install

npx -y @deckflow/deckparse@latest doc.pdf
npm install -g @deckflow/deckparse

The CLI and Node.js entry require Node.js 18 or newer. Frontend applications use the separate browser entry.

Two verbs, deliberately

parse    document → IR artifact     the only parsing action; produces IR, never markdown
convert  IR artifact → view        --to markdown (v1); never re-parses the source

deckparse doc.pdf is parse. The artifact it leaves behind is the point:

doc/
├── ir.json          the parsed document model, server response verbatim
├── assets/          images by persistent identity
├── manifest.json    source hash, cloud references, what exists where
└── views/markdown/  written by convert, never by parse
  • Parse twice, pay once. Same bytes + same options = instant local reuse, zero cloud calls. --json reports "engine": "local-cache" so scripts can verify instead of assume.
  • Convert never re-parses. The view is derived from the stored IR by reference (reusedParse: true is asserted, not hoped). The IR stays convertible for 7 days; after that, a clear ir_expired error says exactly what to re-run.
  • Markdown that survives the week. Image links in cloud responses are signed URLs that expire in hours. DeckParse downloads every image and rewrites the links — a convert that can't secure its images fails rather than shipping links that will rot (--keep-remote-images opts out).

Supported formats

deckparse formats
Input parse → IR convert → markdown flags
.pdf versioned IR (stable node ids, bbox, schemaVersion) --profile fast|balanced|quality, --password, --no-images, --anchors
.pptx --split-pages
.docx
.key --stay-image-area-rate, --split-pages
http(s) URL --mode source|runtime
.doc .ppt .xls(x) .pages .numbers clear error + a way out

Unsupported pairs fail with a hint, never an approximation.

Machine-readable output

$ deckparse convert doc/ --json
{
  "ok": true,
  "op": "convert",
  "engine": "cloud",
  "format": "pdf",
  "taskId": "t_abc123",
  "reusedParse": true,
  "outputs": [{ "file": "doc/views/markdown/index.md", "bytes": 48213 }],
  "warnings": [],
  "durationMs": 728
}

Errors carry a stable error.code and a distinct exit code:

exit error.code meaning
2 usage_error bad flags, or a flag that cannot apply to this input
3 unsupported unsupported extension or --to target
4 auth_error credential rejected or expired
5 input_error, ir_not_found, ir_expired, ir_schema_unsupported, ir_invalid, asset_error fixable by the caller — each carries a hint saying how
6 backend_error task failed; includes the taskId for follow-up
7 not_implemented reserved verbs (extract, modify, export)
8 quota_error guest quota exhausted — deckparse auth login

Authentication is shared

Credentials live in ~/.deckflow/credentials and are shared with every DeckFlow CLI — log in once through DeckParse, DeckRender or DeckHTML and the others pick it up:

deckparse auth login
deckparse config list     # every value, and exactly where it came from

Environment variables win over stored files: DECKPARSE_API_KEYDECKFLOW_API_KEYDECKHTML_API_KEY (and DECKPARSE_TOKEN / DECKPARSE_API_BASE / DECKPARSE_SPACE_ID likewise). Each field resolves independently — when something authenticates oddly, deckparse config list shows which file or variable is responsible.

Where parsing happens: all parsing runs in the DeckFlow cloud — the document is uploaded over HTTPS, parsed there, results downloaded back. Nothing in v1 keeps a document on your machine. If your documents cannot leave your machine, DeckParse is not for you yet.

Use it as a Node.js library

import { parse, openArtifact } from '@deckflow/deckparse';

const doc = await parse('doc.pdf', { profile: 'quality' });
doc.irKey;                          // the cloud reference convert consumes
await doc.convert();                // view materialized into the artifact
await doc.convert({ anchors: true }); // pdf: provenance comments carrying node ids

// Days later, in another process — no cloud call to reopen:
const same = await openArtifact('doc/');
await same.convert({ splitPages: true });

extract, modify and export are reserved verbs on the same handle — the roadmap runs Parse → Extract → Modify → Export → render-verified round trips.

Use it in the browser

npm install @deckflow/deckparse
import { createClient } from '@deckflow/deckparse/browser';

const client = createClient({
  apiBase: 'https://app.deckflow.com/v1',
  token: userAccessToken, // user-scoped credential approved for browser use
  // onUnauthorized: async () => refreshUserAccessToken(),
});

// file is the File selected by an <input type="file">.
const controller = new AbortController();
const doc = await client.parse(file, {
  signal: controller.signal,
  timeout: 300, // seconds; only bounds task waiting, not upload time
  onProgress(event) {
    if (event.phase === 'upload') console.log(event.progress); // 0..1
    else console.log(event.taskId, event.status); // available after submission
  },
});

const ir = await doc.ir(); // in-memory server response; no filesystem access
const view = await doc.convert();
console.log(view.markdown, view.images);

// The source is not uploaded or parsed again.
await client.convert({ irKey: doc.irKey }, { strict: true });

Inputs are File, { file: Blob | Uint8Array | ArrayBuffer, name: string }, or { url: 'https://…' }. Bare paths, stdin, unnamed Blobs and Node-only options such as out/force are rejected before any request. PDF parse options (profile, password, includeImages), Keynote's stayImageAreaRate, URL mode, and Markdown options (anchors, splitPages, strict) keep their Node names. Format-specific flags are checked when the input/document format is known.

parse() returns a BrowserParsedDocument with taskId, type, irKey, irSchemaVersion, ir() and convert(). Conversion returns BrowserConvertResult: markdown, optional markdownPages, images, format, schemaVersion, taskId and reusedParse: true. It does not return local paths, create artifact directories, cache documents between calls, or download all images. A markdownError is an error, never successful placeholder content.

Authentication and deployment
  • Do not put a server API key in browser code or a frontend environment variable. The browser client deliberately has no apiKey option. Direct cloud access requires credentials and permissions intended for browser users; issuing short-lived/scoped credentials is a backend responsibility, not a feature this SDK creates.
  • If your application uses a secret API key or an existing login cookie, use an authenticated backend proxy and pass apiBase: '/api/deckparse'. The proxy must preserve the upstream API paths, authorize each operation/space, protect cookie-authenticated mutations against CSRF, and keep secrets server-side. Omitting token is appropriate only for such a proxy or intentionally permitted guest access. The SDK does not add a backend service.
  • A 401 may refresh through onUnauthorized once. Return a nonempty token string for the same user; account/default-space changes require an explicit new client. Failed refreshes reject with auth_error; they never switch to a guest identity/space. Task-creation POSTs are not automatically replayed on ambiguous network failures or gateway errors. Files of at least 4 MiB are uploaded first and referenced by fileId; that reduces large request failures but is not a server-side idempotency guarantee.
  • For direct access, configure CORS for the API, event stream, signed upload endpoints, result downloads and image assets. Allow the methods/headers actually used, including X-Auth-Token, X-Auth-UUID, Content-Type and response-event-stream; multipart uploads need Access-Control-Expose-Headers: ETag. API credentials must not be forwarded to signed storage URLs. Production permissions/CORS must be verified for your deployment; localhost tests cannot certify them.
Cancellation, recovery and result lifetime

Every browser parse/convert accepts signal, onProgress, timeout (seconds), useEventStream and pollInterval (milliseconds). Upload progress reports completed upload work, not a guaranteed continuous byte-level progress stream; small inline uploads report completion after the request succeeds. Aborting stops the client's HTTP requests, uploads and waiting; it does not cancel or refund a cloud task that was already submitted. An aborted call preserves the signal's abort reason (normally AbortError). Do not automatically call parse() again after an uncertain submission failure.

Keep the task id from onProgress. Other operation errors use DeckParseError with stable code, hint and, once known, taskId:

const task = await client.getTask(savedParseTaskId);
if (task.status === 'completed') {
  // Retrieve a view of the completed parse without another upload/parse.
  const view = await client.convert({ taskId: task.id });
}

Operations may specify spaceId without changing the client's default; document handles keep their parse space for later conversions. When recovering an operation in a different space, pass that same spaceId to getTask() and to a subsequent by-reference convert().

Cloud IR references currently have a 7-day retention period; doc.ir() retaining a local snapshot does not extend it. Image ref values are signed, expiring URLs for temporary preview, not permanent links. Persisting/offline-exporting assets is an explicit application concern. Treat document content as untrusted and sanitize rendered Markdown/HTML in your display layer.

The browser entry is framework-independent ESM and safe to import during SSR. It targets modern browsers with Fetch, Web Crypto, Blob/File and AbortController; use HTTPS (localhost is suitable for development). It still uploads documents for cloud parsing — browser support does not mean offline/on-device parsing.

Development

pnpm install
pnpm check          # typecheck + unit + integration + build
pnpm check:browser  # DOM-only types + HTTP integration + browser export checks
pnpm browser:smoke  # open the printed localhost URL for real-browser checks

# conformance drives the built CLI against a real backend:
DECKPARSE_API_BASE=… DECKPARSE_TOKEN=… \
CONFORMANCE_PDF=sample.pdf CONFORMANCE_PPTX=sample.pptx pnpm conformance

The browser bundle and declarations are self-contained: consumers need no Node polyfills, bundler aliases or dependency patches. Until the upstream browser fix is published, source builds apply a version-pinned pnpm patch that adds the browser entry to @deckops/sdk; the existing upstream Node entry is unchanged. Commit patches/ and the lockfile together and use pnpm install --frozen-lockfile for reproducible builds. See patch maintenance.

Browser tests use a local fake API and synthetic bytes; they verify transport contracts, not real document parsing quality or production CORS. pnpm browser:smoke serves its page and API on separate localhost origins to exercise preflights, signed uploads and response-header visibility in a real browser.

The --json envelope, error codes, exit codes, artifact layout and the shared credential file format are public contracts. Changing any of them is a breaking change; note it in CHANGELOG.md.

License

MIT DeckFlow

Keywords