Repository navigation
archiver-web: lazy-load libarchive.js; split api2ai into its own package - #72
Conversation
…d rar ZIP and GZIP still go through JSZip/fflate with no WASM. Every other container/compression format is handled by a WebAssembly libarchive.js backend that's only fetched (local install or CDN) the first time one of those formats is actually used, via extract()/compress() dispatching on detectArchiveKind() (filename extension, or magic-byte sniffing when no filename is given). Also hardens extraction against zip-slip/path-traversal across all backends (safeRelativePath), and works around two real libarchive.js 2.0.2 bugs: it can't write an uncompressed archive, and it can't reliably round-trip standalone bzip2/xz or write a valid .7z container (surfaced as clear errors instead of silent data loss). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014rhu5fjwSki5rfJMg1DnHi
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
The `api2ai` CLI generator lived at
apps/api2ai-mcp-generator/lib/api2ai/generate-mcp-use-server.js, but its
own package.json (name "api2ai") belonged to the whole api2ai.com Next.js
dashboard app — publishing that app's ~150 dependencies just to ship a
zero-dependency CLI script was never going to work as documented.
Move the generator to packages/api2ai as a small, dedicated package
(name "api2ai", bin "api2ai") so `npx api2ai <spec> [output]` works the
way both READMEs and the docs site already described. Renamed the app's
own package to api2ai-mcp-generator to free up the name and avoid an
npm-workspaces name collision, and fixed the generator's `isMainModule`
CLI-entrypoint check to resolve the npm/npx bin symlink correctly
instead of a fragile path.includes('api2ai') heuristic.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rhu5fjwSki5rfJMg1DnHi
Finishes the previous commit's package split: removes the now-moved apps/api2ai-mcp-generator/lib/api2ai/generate-mcp-use-server.js, and updates the app's README/docs and package.json (which still referenced the old in-app file path and its own now-freed "api2ai" package name). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014rhu5fjwSki5rfJMg1DnHi
CI's "packages"/"test" jobs failed: grab-api.js's and grab-url's "full"
builds trace into content-processors.ts's lazy import("archiver-web"),
and from there into archiver-web's own dynamic import of
libarchive.js/dist/libarchive-node.mjs. Neither config externalized
that specifier, so Rollup bundled it and choked on its bare
`worker_threads`/`url` imports getting browser-stubbed — the same
failure archiver-web's own build hit before its vite.config.ts learned
to externalize libarchive.js.
Apply the same fix here: treat libarchive.js like jszip already is
(resolved at runtime by archiver-web, never bundled into these
packages either). Verified by rebuilding grab-url, grab-api.js,
grab-url-cli, archiver-web and api2client, and running the full
test:coverage suite (368 tests, including packaging.test.ts) locally.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rhu5fjwSki5rfJMg1DnHi
…guard Adds tests for detectArchiveKind(), round-trips for tar/tar.gz/tar.bz2/ tar.xz/standalone-gzip, and the error paths for unsupported creation (.rar, .7z) and unsupported standalone-.bz2/.xz extraction — addresses Codecov's patch-coverage flag on PR #72. The zip-slip test needed a second look: a zip built with an entry named "../../evil.txt" doesn't actually carry that path through JSZip's own loadAsync() — JSZip collapses it to "evil.txt" while parsing the zip, before archiver-web's own safeRelativePath() ever sees it, so asserting the entry gets dropped was asserting something that isn't true (and isn't what protects anyone here). Added a second test that hand-builds a raw USTAR tar buffer with the same traversal name, bypassing any writer-side sanitization, to exercise safeRelativePath() on the one path where it's actually load-bearing: libarchive.js's tar reader does not sanitize entry paths on its own. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014rhu5fjwSki5rfJMg1DnHi
|
The Generated by Claude Code |
Summary
archiver-web
archiver-webnow supports TAR, TAR.GZ, TAR.BZ2, TAR.XZ, 7z and RAR, in addition to ZIP and GZIP.libarchive.js(WebAssembly) backend — only fetched (local install, or CDN as a fallback) the first time one of those formats is actually used.extract()/compress()pick the right backend via a newdetectArchiveKind()(filename extension), with magic-byte sniffing as a fallback when no filename is given. Both gained optionalfilename/formatoptions; the CLI (bin-extract) now passes the input filename through automatically.safeRelativePath()and applied it across every extraction backend (ZIP, ZIP streaming, and the new libarchive.js path) to reject zip-slip / path-traversal entries (../.., absolute paths) — this package's own.claude/CLAUDE.mdcalls that out as its main safety invariant, and it wasn't previously enforced anywhere.libarchive.js@2.0.2(reproduced directly against the library, not this wrapper) rather than silently mishandling them:.taris written internally as.tar.gzand gunzipped withfflateto recover raw tar bytes..7zcontainer.compress()now throws a clear error for.7zoutput, andextract()throws a clear error for standalone.bz2/.xz, instead of returning an unusable/empty result.README.md/readme.md,packages/README.md, and the package's.claude/CLAUDE.mdto document the new format matrix and these limitations.api2ai
api2aiOpenAPI→MCP-server generator lived atapps/api2ai-mcp-generator/lib/api2ai/generate-mcp-use-server.js, but itsbin/files/package name ("api2ai") belonged to the whole api2ai.com Next.js dashboard app'spackage.json— publishing that app's ~150 dependencies just to ship a zero-dependency CLI script was never actually going to work as documented.packages/api2aias its own small package (nameapi2ai, binapi2ai), sonpx api2ai <spec> [output]now works the way both READMEs and the docs site already described.api2ai-mcp-generatorto free up the name and avoid an npm-workspaces name collision.isMainModuleCLI-entrypoint check, which used a fragilepath.includes('api2ai')heuristic, to correctly resolve the npm/npx bin symlink instead.Test plan
archiver-web
tsc --noEmitpassesvite buildsucceeds, withjszip/fflate/libarchive.js(incl. its Node subpath) confirmed externalized rather than bundled.zip,.tar,.tar.gz,.tar.bz2,.tar.xz, standalone.gz../../evil.txtentry.rar/.7zcreation and standalone.bz2/.xzextraction throw clear errors instead of failing silentlybin-compress→.tar.gz,bin-extract→ recovers original filesbun testrunstsx test.ts, but notest.tsfile is present) — all verification above was manualapi2ai
npm installat the repo root succeeds with no workspace name collisionnode_modules/.bin/api2ai --helpresolves through the real bin symlink and prints usageisMainModulefix works through the actual npm/npx bin symlink, not just directnode path/to/file.jsexecutionimport { generateMcpServer, extractTools, loadOpenApiSpec } from "api2ai"resolves and exports the expected functions🤖 Generated with Claude Code
https://claude.ai/code/session_014rhu5fjwSki5rfJMg1DnHi