diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 64557a1..4fe3891 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -61,6 +61,18 @@ jobs: include: - os: ubuntu-latest target: x86_64-unknown-linux-gnu + # napi-cross builds gnu targets against an old glibc sysroot for + # broad distro compatibility; musl targets cross-compile with + # zig via cargo-zigbuild (napi's -x flag). + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + build-flags: --use-napi-cross + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + build-flags: -x + - os: ubuntu-latest + target: aarch64-unknown-linux-musl + build-flags: -x - os: macos-14 target: aarch64-apple-darwin - os: windows-latest @@ -70,11 +82,27 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} - uses: oven-sh/setup-bun@v2 with: bun-version: latest + - name: Install zig + if: contains(matrix.target, 'musl') + uses: mlugg/setup-zig@v2 + with: + version: 0.14.1 + + - name: Install cargo-zigbuild + if: contains(matrix.target, 'musl') + uses: taiki-e/install-action@v2 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + tool: cargo-zigbuild + - name: Cache cargo uses: actions/cache@v4 with: @@ -82,10 +110,11 @@ jobs: ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ + ~/.napi-rs napi/target/ - key: ${{ runner.os }}-cargo-napi-${{ hashFiles('**/Cargo.lock') }} + key: ${{ matrix.target }}-cargo-napi-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-cargo-napi- + ${{ matrix.target }}-cargo-napi- - name: Install dependencies working-directory: napi @@ -93,7 +122,7 @@ jobs: - name: Build native addon working-directory: napi - run: bunx napi build --platform --release + run: bunx napi build --platform --release --target ${{ matrix.target }} ${{ matrix.build-flags }} - name: Upload native binary uses: actions/upload-artifact@v4 @@ -112,9 +141,54 @@ jobs: napi/index.d.ts if-no-files-found: error + smoke-test: + name: Smoke test ${{ matrix.target }} + needs: [check-version, build] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + - os: ubuntu-latest + target: x86_64-unknown-linux-musl + - os: ubuntu-24.04-arm + target: aarch64-unknown-linux-gnu + - os: ubuntu-24.04-arm + target: aarch64-unknown-linux-musl + - os: macos-14 + target: aarch64-apple-darwin + - os: windows-latest + target: x86_64-pc-windows-msvc + steps: + - uses: actions/checkout@v4 + + - name: Download native binary + uses: actions/download-artifact@v4 + with: + name: bindings-${{ matrix.target }} + path: napi + + - name: Download generated JS bindings + uses: actions/download-artifact@v4 + with: + name: js-bindings + path: napi + + # musl binaries must load under a real musl libc, so run inside Alpine. + - name: Run smoke test (Alpine) + if: contains(matrix.target, 'musl') + run: docker run --rm -v "$PWD:/repo" -w /repo/napi node:24-alpine node test.mjs + + - name: Run smoke test + if: ${{ !contains(matrix.target, 'musl') }} + working-directory: napi + run: node test.mjs + publish: name: Publish to npm - needs: [check-version, build] + needs: [check-version, build, smoke-test] runs-on: ubuntu-latest permissions: contents: read @@ -154,9 +228,12 @@ jobs: node -e ' const [suffix, version] = process.argv.slice(1) const meta = { - "linux-x64-gnu": { os: ["linux"], cpu: ["x64"], libc: ["glibc"] }, - "darwin-arm64": { os: ["darwin"], cpu: ["arm64"] }, - "win32-x64-msvc": { os: ["win32"], cpu: ["x64"] }, + "linux-x64-gnu": { os: ["linux"], cpu: ["x64"], libc: ["glibc"] }, + "linux-x64-musl": { os: ["linux"], cpu: ["x64"], libc: ["musl"] }, + "linux-arm64-gnu": { os: ["linux"], cpu: ["arm64"], libc: ["glibc"] }, + "linux-arm64-musl": { os: ["linux"], cpu: ["arm64"], libc: ["musl"] }, + "darwin-arm64": { os: ["darwin"], cpu: ["arm64"] }, + "win32-x64-msvc": { os: ["win32"], cpu: ["x64"] }, }[suffix] if (!meta) { console.error(`unknown platform suffix: ${suffix} — add it to the meta map`) diff --git a/napi/Cargo.lock b/napi/Cargo.lock index d5a3cca..a90be1c 100644 --- a/napi/Cargo.lock +++ b/napi/Cargo.lock @@ -499,11 +499,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "rand_core", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -557,6 +559,25 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "2.13.0" @@ -833,6 +854,7 @@ name = "pdf-inspector" version = "0.1.7" dependencies = [ "env_logger", + "include_dir", "log", "lopdf", "once_cell", diff --git a/napi/README.md b/napi/README.md index efdb4d2..ba6d3f4 100644 --- a/napi/README.md +++ b/napi/README.md @@ -34,7 +34,7 @@ npm install @firecrawl/pdf-inspector bun add @firecrawl/pdf-inspector ``` -Prebuilt binaries for **Linux x64**, **macOS ARM64**, and **Windows x64** — npm installs only the one matching your platform. No Rust toolchain needed. +Prebuilt binaries for **Linux x64/ARM64** (glibc and musl/Alpine), **macOS ARM64**, and **Windows x64** — npm installs only the one matching your platform. No Rust toolchain needed. ## API @@ -116,9 +116,12 @@ Prebuilt binaries ship as platform-specific packages installed automatically via | Platform | Architecture | Package | |----------|-------------|---------| -| Linux | x64 (glibc) | `@firecrawl/pdf-inspector-linux-x64-gnu` | -| macOS | ARM64 | `@firecrawl/pdf-inspector-darwin-arm64` | -| Windows | x64 | `@firecrawl/pdf-inspector-win32-x64-msvc` | +| Linux | x64 (glibc) | `@firecrawl/pdf-inspector-linux-x64-gnu` | +| Linux | x64 (musl/Alpine) | `@firecrawl/pdf-inspector-linux-x64-musl` | +| Linux | ARM64 (glibc) | `@firecrawl/pdf-inspector-linux-arm64-gnu` | +| Linux | ARM64 (musl/Alpine) | `@firecrawl/pdf-inspector-linux-arm64-musl` | +| macOS | ARM64 | `@firecrawl/pdf-inspector-darwin-arm64` | +| Windows | x64 | `@firecrawl/pdf-inspector-win32-x64-msvc` | ## License diff --git a/napi/bun.lock b/napi/bun.lock index 21d8a39..67d2372 100644 --- a/napi/bun.lock +++ b/napi/bun.lock @@ -8,9 +8,12 @@ "@napi-rs/cli": "^3.4.1", }, "optionalDependencies": { - "@firecrawl/pdf-inspector-darwin-arm64": "1.11.0", - "@firecrawl/pdf-inspector-linux-x64-gnu": "1.11.0", - "@firecrawl/pdf-inspector-win32-x64-msvc": "1.11.0", + "@firecrawl/pdf-inspector-darwin-arm64": "1.12.0", + "@firecrawl/pdf-inspector-linux-arm64-gnu": "1.12.0", + "@firecrawl/pdf-inspector-linux-arm64-musl": "1.12.0", + "@firecrawl/pdf-inspector-linux-x64-gnu": "1.12.0", + "@firecrawl/pdf-inspector-linux-x64-musl": "1.12.0", + "@firecrawl/pdf-inspector-win32-x64-msvc": "1.12.0", }, }, }, diff --git a/napi/package.json b/napi/package.json index 89af641..1139fbc 100644 --- a/napi/package.json +++ b/napi/package.json @@ -1,6 +1,6 @@ { "name": "@firecrawl/pdf-inspector", - "version": "1.11.2", + "version": "1.12.0", "description": "Fast PDF classification and text extraction. Detect text-based vs scanned PDFs, extract text by region with quality checks. Native Rust performance via napi-rs.", "main": "index.js", "types": "index.d.ts", @@ -37,6 +37,9 @@ "binaryName": "pdf-inspector", "targets": [ "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", "aarch64-apple-darwin", "x86_64-pc-windows-msvc" ] @@ -49,8 +52,11 @@ "@napi-rs/cli": "^3.4.1" }, "optionalDependencies": { - "@firecrawl/pdf-inspector-linux-x64-gnu": "1.11.2", - "@firecrawl/pdf-inspector-darwin-arm64": "1.11.2", - "@firecrawl/pdf-inspector-win32-x64-msvc": "1.11.2" + "@firecrawl/pdf-inspector-linux-x64-gnu": "1.12.0", + "@firecrawl/pdf-inspector-linux-x64-musl": "1.12.0", + "@firecrawl/pdf-inspector-linux-arm64-gnu": "1.12.0", + "@firecrawl/pdf-inspector-linux-arm64-musl": "1.12.0", + "@firecrawl/pdf-inspector-darwin-arm64": "1.12.0", + "@firecrawl/pdf-inspector-win32-x64-msvc": "1.12.0" } }