* feat(napi): add processPdfAsync, classifyPdfAsync, extractPagesMarkdownAsync
The Node bindings are synchronous, so every call parses on the event
loop thread — up to hundreds of milliseconds of dead loop per document
in a server. Add additive AsyncTask-based variants that run the same
shared implementations on the libuv thread pool and return promises.
The existing synchronous exports keep their names, signatures, and
behaviour; each sync/async pair shares one implementation. Panics in
compute() are caught and surfaced as rejections, matching the sync
error contract.
Closes#336
Co-authored-by: Abimael Martell <abimaelmartell@users.noreply.github.com>
* fix(napi): read async task buffers in place instead of copying
Review feedback on #337: buffer.to_vec() copied the whole PDF on the
event loop before the task was queued, so large inputs still stalled
the loop and doubled peak memory. The tasks now hold the napi Buffer
itself — its ref pins the JS allocation for the task's lifetime and
the backing store is stable, so compute() reads it directly from the
worker thread. Callers must not mutate the buffer until the promise
settles (same contract as Node's async fs APIs); documented on each
export and in the README.
The suggested removal of ts_return_type was checked and rejected:
without it napi-rs generates Promise<unknown> for AsyncTask returns.
A comment now records that finding.
Co-authored-by: Abimael Martell <abimaelmartell@users.noreply.github.com>
* fix(napi): copy async task input on the JS thread for soundness
Review feedback on #337: holding the napi Buffer and reading it from
the libuv worker was unsound. Buffer derefs straight to the JS-side
allocation, so a caller mutating it before the promise settled would
race the worker's reads — undefined behavior, not a recoverable error,
and the documented don't-mutate contract was unenforceable. Deferring
the copy to compute() would not help: any off-thread read races the
same way. The JS thread is the only race-free place to take the copy,
because JS is single-threaded and nothing can mutate the buffer during
the synchronous part of the call.
Revert to an owned Vec<u8> copied at call time. The cost is one memcpy,
negligible next to the parse the async variants exist to unblock. Docs
now state the buffer may be reused or mutated immediately, and a test
locks in the copy semantics by mutating the input while a parse is in
flight.
Co-authored-by: Abimael Martell <abimaelmartell@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Abimael Martell <abimaelmartell@users.noreply.github.com>
Adds x86_64-unknown-linux-musl, aarch64-unknown-linux-gnu, and
aarch64-unknown-linux-musl to the napi build targets so
@firecrawl/pdf-inspector works on Alpine and ARM64 Linux deployments.
- gnu arm64 cross-compiles with --use-napi-cross (old-glibc sysroot),
musl targets with -x (zig + cargo-zigbuild), per the napi-rs template
- new platform packages carry npm libc metadata (glibc/musl)
- smoke-test job runs napi/test.mjs on all six targets before publish
(Alpine containers for musl, ubuntu-24.04-arm runners for ARM64)
- bump to 1.12.0 to trigger publishing of all platform packages
Closes#216
Concise Features list and the opendataloader-bench comparison table on
each registry readme, adapted per ecosystem. Bump all three versions
(crate 0.1.6, python 0.2.5, npm 1.11.1) to republish the pages.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(npm): split platform binaries into optionalDependencies (1.11.0)
The single package bundled all three .node binaries (17.6 MB unpacked)
so every install downloaded every platform. Publish one package per
platform (@firecrawl/pdf-inspector-{linux-x64-gnu,darwin-arm64,
win32-x64-msvc}) holding just its binary; the napi-generated loader
already falls back to exactly these names. Main package drops *.node
from files (8.5 kB tarball) and pins the platform packages as
optionalDependencies, re-stamped to the exact version at publish time.
Publish workflow gains a workflow_dispatch fallback and per-package
already-published checks so partial releases can be retried.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(npm): document Windows support and platform packages; drop stale napi.package.name
Review follow-ups: the README claimed only linux-x64 and macOS ARM64
despite the win32-x64-msvc binary shipping, and napi.package.name
(@firecrawl/pdf-inspector-js) contradicts the real platform package
prefix — the loader and workflow derive it from the root package name.
Verified the generated loader is unchanged without the config.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>