npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@deckflow/deckprobe

v2.4.0

Published

CLI and browser SDK for probing PDF, Microsoft Office, and Apple iWork documents with DeckProbe

Readme

@deckflow/deckprobe

DeckProbe 2.2 for JavaScript: the deckprobe command line tool for Node, and a browser SDK that runs the same Rust engine in WebAssembly. In the browser, documents stay in the browser — the package does not upload files.

npm install @deckflow/deckprobe

Command line

Installing the package puts deckprobe on PATH, or run it without installing:

npx @deckflow/deckprobe --help
npx @deckflow/deckprobe -t slide_count deck.pptx

This is the same native binary the standalone installers ship, so every flag, help page, JSON report, and exit code matches the CLI reference exactly. The binary arrives through a per-platform optional dependency for the targets DeckProbe releases: macOS arm64/x64, Linux arm64/x64 (glibc and musl), and Windows x64.

If installation skipped optional dependencies, deckprobe reports which platform package is missing. Install it directly, or build from source with cargo install --git https://github.com/deckflow/deckprobe --locked deckprobe.

Node API

The node export condition loads the WebAssembly binary from disk, so the package works under Node with no configuration:

import { probeFile } from "@deckflow/deckprobe";

const report = await probeFile("deck.pptx", {
  targets: ["@summary", "@security"],
  level: "metadata",
});

probeFile() reports source_kind: "local_file" and produces a report byte for byte identical to the native CLI on the same input. probe() accepts Buffer, Uint8Array, and ArrayBuffer alongside the browser input types, and reports node_bytes. deckProbeWasmPath exposes the absolute path of the binary being loaded.

probeFile() reads the whole file into memory, because the WebAssembly engine takes bytes rather than a file handle. The deckprobe command reads lazily instead — for a 300 KB PPTX it touches under 18 KB — so prefer the CLI, or --jsonl for batches, when inputs are large.

Public imports

| Need | Import | |---|---| | Probe on the calling thread | import { initDeckProbe, probe } from "@deckflow/deckprobe" | | Discover supported formats, targets, schema, or runtime version | import { formats, targets, schema, version } from "@deckflow/deckprobe" | | Probe in a module Worker (browser only) | import { createDeckProbeWorker } from "@deckflow/deckprobe/worker" | | Probe a file on disk (Node only) | import { probeFile } from "@deckflow/deckprobe" | | Use TypeScript response and option types | import type { ProbeResult, ProbeCallOptions } from "@deckflow/deckprobe" |

probe() lazily initializes the WASM runtime. Use initDeckProbe() during application startup or an idle period when the first interaction should avoid that initialization cost.

Choose an execution path

| Path | Choose it when | |---|---| | probe() on the main thread | The probe is small and its result directly drives an interaction. | | createDeckProbeWorker() | Files are user-provided or potentially large, or deep inspection must not block rendering. |

Both paths run the same engine; the Worker adds byte-copy and messaging cost in exchange for keeping the UI thread responsive. The first probe on either path also pays one-time WASM initialization; see the execution modes overview. Measure on your own corpus before optimizing.

Initialize on application startup or during idle time when you want the first user interaction to use the warm path:

import { initDeckProbe, probe } from "@deckflow/deckprobe";

await initDeckProbe();

const report = await probe(file, {
  targets: ["@summary", "@security"],
  level: "metadata",
});

For larger documents, run the probe away from the UI thread. Keep the worker alive across a batch, then terminate it with its owning component or job:

import { createDeckProbeWorker } from "@deckflow/deckprobe/worker";

const worker = createDeckProbeWorker();
try {
  const report = await worker.probe(file, { targets: ["@summary"] });
} finally {
  worker.terminate();
}

terminate() cancels all outstanding work and permanently closes that Worker wrapper. Later probe() calls reject immediately; create a new wrapper for a new batch. File and Blob reads happen inside the Worker, while direct probe() intentionally runs input conversion and parsing on the calling thread.

Bundlers

The package ships a WebAssembly binary next to its JavaScript wrapper and resolves it relative to that wrapper. Any tool that moves the wrapper without moving the binary breaks initialization.

Vite

Vite's dependency pre-bundling rewrites @deckflow/deckprobe into node_modules/.vite/deps/ and does not copy the adjacent .wasm file, so the dev server requests a binary that is not there. Every Vite version is affected in dev; vite build is not affected — a production build resolves and emits the binary correctly. That asymmetry is the clearest way to recognize the problem.

The reported error depends on how the dev server answers the missing path:

| Vite | Error | |---|---| | 4.x | TypeError: Failed to execute 'compile' on 'WebAssembly': HTTP status code is not ok | | 5.x, 6.x, 7.x | CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 3c 21 64 6f |

On Vite 5 and newer the SPA fallback answers with index.html, so the request succeeds and WebAssembly rejects the HTML body instead — 3c 21 64 6f is <!do. The Worker entry point fails the same way and surfaces it as DeckProbe worker failed to load.

Exclude the package from dependency pre-bundling. This is the recommended fix, and the only one that covers the Worker entry point:

// vite.config.ts
import { defineConfig } from "vite";

export default defineConfig({
  optimizeDeps: {
    exclude: ["@deckflow/deckprobe"],
  },
});

Excluding the package name also covers the /worker subpath; it does not need its own entry.

If you only use the main-thread entry point, passing the binary URL works without touching the Vite configuration:

import { initDeckProbe, probe } from "@deckflow/deckprobe";
import wasmUrl from "@deckflow/deckprobe/wasm?url";

await initDeckProbe(wasmUrl);

?url is Vite's asset syntax; add /// <reference types="vite/client" /> so TypeScript types the import. Call initDeckProbe(wasmUrl) before the first probe() or discovery call, because the first initialization wins.

This form does not help createDeckProbeWorker(). The Worker runs its own module instance, so a URL passed on the main thread never reaches it, and pre-bundling relocates worker-runtime.js itself. Use optimizeDeps.exclude whenever the Worker entry point is in play.

Other bundlers

@deckflow/deckprobe/wasm is the stable path to the binary and accepts the same treatment elsewhere: bundlers that understand new URL(..., import.meta.url) (webpack 5, Rollup, esbuild) need no configuration, and anything else can load the binary itself and hand it to initDeckProbe():

await initDeckProbe(await fetch("/assets/deckprobe_wasm_bg.wasm"));

initDeckProbe() accepts a URL or path, a Request or Response, raw bytes, or a compiled WebAssembly.Module (InitInput). Use the Response or bytes form when a CDN origin, a sub-path deployment, or a strict CSP makes the default relative URL wrong.

Uint8Array, ArrayBuffer, and Blob inputs require options.name with a filename extension. File inputs use File.name automatically. Successful and partial probes return the same schema-v2 report as the native CLI; recognized probe failures return the schema-v2 error envelope.

Apple iWork files use the same selectors and target IDs as the native engine. For example:

const report = await probe(file, {
  level: "deep",
  targets: [
    "iwork.producer_build",
    "iwork.asset_type_counts",
    "iwork.preview_dimensions",
    "iwork.archive_object_count",
    "iwork.message_type_counts",
    "keynote.slide_size",
    "keynote.hidden_slide_count",
    "iwork.all_iwa_valid",
  ],
});

targets("key"), targets("numbers"), and targets("pages") return typed TargetSpecReport entries. Their applicable and supported_levels fields distinguish the shared catalog from targets the chosen iWork driver can execute.

Build

npm ci
npm run build
npx playwright install chromium
npm test

npm run build regenerates the Rust WASM package and then compiles the TypeScript wrapper, so it requires cargo, the wasm32-unknown-unknown target, and the local wasm-pack dependency. The generated files under wasm/ are build artifacts and are intentionally ignored by Git. Rebuild them after a version bump: the smoke tests assert that the compiled runtime reports the same version as package.json.

npm test runs the type check, the version and artifact checks, and three browser suites. npm run test:vite is the bundler guard: it packs the real tarball, installs it into a throwaway Vite consumer, and asserts that both documented Vite fixes and a production build still reach the WASM binary. It drives Vite through this package's own dependency, so it needs Node ^20.19.0 || >=22.12.0 — the range Vite 7 requires.

The package is published independently as @deckflow/deckprobe while its Rust binding remains part of the main DeckProbe Cargo workspace.