# @deckflow/deckparse

> Parse any document into an agent-operable representation. Parse once, convert repeatedly: PDF, PPTX, DOCX, Keynote and URLs into durable IR artifacts and Markdown.

Latest version **0.2.0** (published 2026-09-01) · MIT license · 0 weekly downloads

> **Deprecated.** This package is deprecated.

## Install

```sh
npm install @deckflow/deckparse
pnpm add @deckflow/deckparse
yarn add @deckflow/deckparse
bun add @deckflow/deckparse
```

Provides the command `deckparse`.

## Health

**Score 10/100 (F)** — status: deprecated.

Negative: deprecated.

## Facts

| | |
|---|---|
| Version | 0.2.0 |
| Published | 2026-09-01 |
| First published | 2026-09-01 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=18.0.0 |
| Dependencies | 6 |
| Unpacked size | 842.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Maintainers | stonephp, guangfei, jaywang1992 |
| Keywords | cli, parse, deckflow, pdf, pptx, docx, keynote, markdown, ir, document-parsing |

## Links

- npm: https://www.npmjs.com/package/@deckflow/deckparse
- Repository: https://github.com/deckflow/deckparse
- Homepage: https://github.com/deckflow/deckparse#readme
- Issues: https://github.com/deckflow/deckparse/issues
- npm.io page: https://npm.io/package/@deckflow/deckparse

## Dependencies (6)

- [zod](https://npm.io/package/zod.md) ^3.22.0
- [open](https://npm.io/package/open.md) ^10.1.0
- [chalk](https://npm.io/package/chalk.md) ^5.3.0
- [p-limit](https://npm.io/package/p-limit.md) ^5.0.0
- [commander](https://npm.io/package/commander.md) ^11.1.0
- [@deckops/sdk](https://npm.io/package/@deckops/sdk.md) 0.8.0-next.0

## Alternatives

- [@cantoo/pdf-lib](https://npm.io/package/@cantoo/pdf-lib.md) — 297.9K weekly downloads
- [datatables.net-buttons](https://npm.io/package/datatables.net-buttons.md) — 200.1K weekly downloads
- [@ckeditor/ckeditor5-export-pdf](https://npm.io/package/@ckeditor/ckeditor5-export-pdf.md) — 167.0K weekly downloads
- [scanbot-web-sdk](https://npm.io/package/scanbot-web-sdk.md) — 15.0K weekly downloads
- [@syncfusion/ej2-angular-pdfviewer](https://npm.io/package/@syncfusion/ej2-angular-pdfviewer.md) — 8.8K weekly downloads

## Recent versions

- 0.2.0 (latest) — 2026-09-01

## README

# 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.

```bash
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](https://github.com/deckflow) family: [DeckRender](https://github.com/deckflow/deckrender) turns documents into pixels, DeckParse turns them into state an agent can hold on to.

## Install

```bash
npx -y @deckflow/deckparse@latest doc.pdf
```

```bash
npm install -g @deckflow/deckparse
```

The CLI and Node.js entry require Node.js 18 or newer. Frontend applications use the separate [browser entry](#use-it-in-the-browser).

## 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

```bash
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

```bash
$ 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:

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

Environment variables win over stored files: `DECKPARSE_API_KEY` → `DECKFLOW_API_KEY` → `DECKHTML_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

```ts
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

```bash
npm install @deckflow/deckparse
```

```ts
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`:

```ts
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

```bash
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](patches/README.md).

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

---
_Source: https://npm.io/package/@deckflow/deckparse · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
