crossbind 0.0.1 → 2.0.0-beta.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/AGENTS.md +92 -0
  2. package/CHANGELOG.md +156 -0
  3. package/LICENSE +21 -0
  4. package/README.md +133 -0
  5. package/package.json +52 -4
  6. package/src/actions/buildBinTools.js +0 -0
  7. package/src/actions/buildCargo.js +88 -0
  8. package/src/actions/buildDependencies.js +157 -0
  9. package/src/actions/buildExternal.js +57 -0
  10. package/src/actions/buildJs.js +93 -0
  11. package/src/actions/buildLib.js +115 -0
  12. package/src/actions/buildTypes.js +33 -0
  13. package/src/actions/buildWasiCommand.js +101 -0
  14. package/src/actions/buildWasm.js +322 -0
  15. package/src/actions/createInterface.js +172 -0
  16. package/src/actions/createLib.js +249 -0
  17. package/src/actions/createXCFramework.js +82 -0
  18. package/src/actions/extensions.js +7 -0
  19. package/src/actions/getAllBridges.js +20 -0
  20. package/src/actions/getCmakeParameters.js +66 -0
  21. package/src/actions/getData.js +46 -0
  22. package/src/actions/getDependLibs.js +25 -0
  23. package/src/actions/isSourceNewer.js +35 -0
  24. package/src/actions/licenses.js +156 -0
  25. package/src/actions/run.js +307 -0
  26. package/src/actions/target.js +54 -0
  27. package/src/assets/cmake/CMakeLists.txt +61 -0
  28. package/src/assets/cmake/dist.cmake +57 -0
  29. package/src/assets/cmake/ios.toolchain.cmake +1176 -0
  30. package/src/assets/cpp-runtime/browser.cpp +12 -0
  31. package/src/assets/cpp-runtime/commonBridges.cpp +17 -0
  32. package/src/assets/cpp-runtime/crossbindEmptySource.cpp +9 -0
  33. package/src/assets/cpp-runtime/node.cpp +19 -0
  34. package/src/assets/js-runtime/adapters/exception-decode.js +79 -0
  35. package/src/assets/js-runtime/adapters/fs-browser.js +173 -0
  36. package/src/assets/js-runtime/adapters/fs-node.js +28 -0
  37. package/src/assets/js-runtime/adapters/path-fs.js +6 -0
  38. package/src/assets/js-runtime/adapters/path-url.js +8 -0
  39. package/src/assets/js-runtime/adapters/vector-coercion.js +209 -0
  40. package/src/assets/js-runtime/adapters/worker-comlink.js +309 -0
  41. package/src/assets/js-runtime/browser.js +16 -0
  42. package/src/assets/js-runtime/core.js +193 -0
  43. package/src/assets/js-runtime/edge.js +18 -0
  44. package/src/assets/js-runtime/node.js +20 -0
  45. package/src/assets/packaging/crossbind-package.podspec +17 -0
  46. package/src/assets/wasi-runtime/stubs.c +84 -0
  47. package/src/bin.js +416 -0
  48. package/src/index.js +19 -0
  49. package/src/integration/getCrossbindScript.js +180 -0
  50. package/src/integration/getDependFilePath.js +132 -0
  51. package/src/runtime/wasiRun.mjs +118 -0
  52. package/src/state/calculateDependencyParameters.js +97 -0
  53. package/src/state/index.js +128 -0
  54. package/src/state/loadConfig.js +215 -0
  55. package/src/utils/appRustCrates.js +106 -0
  56. package/src/utils/binTools.js +76 -0
  57. package/src/utils/bridgeAsyncGuard.js +37 -0
  58. package/src/utils/cargoTarget.js +15 -0
  59. package/src/utils/cppDts.js +201 -0
  60. package/src/utils/cppFieldBindings.js +23 -0
  61. package/src/utils/dependencyRebuild.js +99 -0
  62. package/src/utils/dirLock.js +71 -0
  63. package/src/utils/downloadAndExtractFile.js +102 -0
  64. package/src/utils/familyManifest.js +17 -0
  65. package/src/utils/findFiles.js +5 -0
  66. package/src/utils/fixPackageName.js +7 -0
  67. package/src/utils/flattenConfigForTable.js +75 -0
  68. package/src/utils/getAbsolutePath.js +14 -0
  69. package/src/utils/getCMakeListsFilePath.js +17 -0
  70. package/src/utils/getOsUserAndGroupId.js +11 -0
  71. package/src/utils/getParentPath.js +12 -0
  72. package/src/utils/hash.js +33 -0
  73. package/src/utils/inputStamp.js +28 -0
  74. package/src/utils/licenseReport.js +94 -0
  75. package/src/utils/linkLayout.js +34 -0
  76. package/src/utils/loadJs.js +31 -0
  77. package/src/utils/loadJson.js +16 -0
  78. package/src/utils/logger.js +110 -0
  79. package/src/utils/ociArtifact.js +124 -0
  80. package/src/utils/overrideDependency.js +99 -0
  81. package/src/utils/provenance.js +54 -0
  82. package/src/utils/pullDockerImage.js +105 -0
  83. package/src/utils/replaceBasePathForDocker.js +18 -0
  84. package/src/utils/resolveEmbindRust.js +66 -0
  85. package/src/utils/runCargo.js +228 -0
  86. package/src/utils/rustBridgeGen.js +1013 -0
  87. package/src/utils/rustMt.js +76 -0
  88. package/src/utils/rustSysroot.js +171 -0
  89. package/src/utils/rustSysrootPin.js +11 -0
  90. package/src/utils/systemKeys.js +29 -0
  91. package/src/utils/targets.js +109 -0
  92. package/src/utils/wasiToolchain.js +47 -0
  93. package/src/utils/writeIfChanged.js +8 -0
  94. package/src/utils/writeJson.js +9 -0
  95. package/vitest.config.js +46 -0
package/AGENTS.md ADDED
@@ -0,0 +1,92 @@
1
+ # AGENTS.md — core/crossbind
2
+
3
+ > The CLI + build orchestrator that everything else in the monorepo plugs into. **The most-touched package**, also the most blast-radius-sensitive.
4
+
5
+ ## What lives here
6
+
7
+ - `bin.js` — `crossbind` / `crossbind` CLI entry; commander commands, target filtering, top-level orchestration.
8
+ - `src/index.js` — public API barrel re-exported as the `crossbind` npm package (`createLib`, `buildWasm`, `state`, `getData`, `isSourceNewer`, …).
9
+ - `src/actions/` — the actual build steps. **Most edits land here.**
10
+ - `src/state/` — config loading + target matrix.
11
+ - `src/utils/` — small helpers (logger, hashing, fs, JSON I/O, Docker pull, …).
12
+ - `src/integration/` — `getCrossbindScript`, `getDependFilePath` (consumer-side helpers used by plugins).
13
+ - `src/assets/` — runtime artifacts shipped with the published package: `js-runtime/` (browser/node/edge JS shims), `cpp-runtime/` (C++ entrypoints), `cmake/` (CMake templates), `packaging/` (podspec template).
14
+
15
+ Use `docs/CODEMAP.md` (repo root) for "concept → file" lookups before guessing.
16
+
17
+ ## Build pipeline orchestration (the hot path)
18
+
19
+ Order of operations when a user runs `pnpm crossbind build`:
20
+
21
+ 1. **`bin.js`** parses CLI flags, calls `getBuildTargets` to expand the target matrix.
22
+ 2. For each target:
23
+ - **`actions/createLib.js`** compiles user C++ to a static lib per platform (cmake/make for wasm/android via Docker; xcodebuild on darwin for iOS). Cache short-circuit when `<output>/prebuilt/<target>/lib` exists, unless `options.force`.
24
+ - **`actions/createXCFramework.js`** combines iOS slices into an `.xcframework` (darwin only).
25
+ - **`actions/buildWasm.js`** runs `emcc` for wasm targets, then **`actions/buildJs.js`** rolls up the JS loader.
26
+ 3. **`actions/run.js`** is the shell-out boundary: every cmake / make / emcc / xcodebuild call goes through it.
27
+
28
+ Side-quests:
29
+ - **`actions/createInterface.js`** generates SWIG bridge files from `.h`.
30
+ - **`actions/getDependLibs.js`** resolves transitive C++ libs to link.
31
+ - **`actions/getCmakeParameters.js`** builds the `-D...` arg list for cmake.
32
+ - **`actions/isSourceNewer.js`** mtime check used by plugins to decide when to force-rebuild.
33
+
34
+ ## Public API contract
35
+
36
+ Anything exported from `src/index.js` is consumed by `plugins/*` and a few CLI scripts (`scripts/check-*.js`). Treat its surface as semver-public — additive changes free, breaking changes need a beta bump and a CHANGELOG note.
37
+
38
+ Currently exported (snapshot):
39
+
40
+ ```
41
+ state, createLib, createBridgeFile, buildWasm, isSourceNewer, getData,
42
+ getCmakeParameters, createXCFramework, getAllBridges, run, getTargetParams,
43
+ getBuildTargets, getFilteredBuildTargets, getFilteredTargetSpec,
44
+ getCrossbindScript, getDependFilePath, getParentPath
45
+ ```
46
+
47
+ If you add a new action, decide explicitly: is this internal (don't export) or part of the contract (export from `index.js` and document)?
48
+
49
+ ## Logger conventions
50
+
51
+ `src/utils/logger.js` is the only canonical writer to stdout / stderr.
52
+
53
+ - `logger.startStep(target, fileType)` — opens an in-place TTY line ("compiling…").
54
+ - `logger.doneStep(target, fileType, detail?)` — replaces it with timing + detail.
55
+ - `logger.cachedStep(target, fileType)` — for cache-hit short-circuits.
56
+ - `logger.startTask(label)` / `doneTask(label, detail?)` / `cachedTask(label)` — for non-target work (xcframework, etc.).
57
+ - `logger.info(text)` / `logger.error(text)` — for one-off messages.
58
+
59
+ **Don't add `console.log` in this package.** Route everything through the logger; CI / non-TTY automatically gets newline output.
60
+
61
+ ## Validation
62
+
63
+ Anything you change here triggers the **strict** validation gate from the root playbook:
64
+
65
+ ```bash
66
+ pnpm run ci:linux:build && pnpm run e2e:dev && pnpm run e2e:prod
67
+ ```
68
+
69
+ Plus, depending on the area:
70
+
71
+ - Touched a new public export → search consumers: `grep -rn "from 'crossbind'" plugins examples scripts`.
72
+ - Touched `actions/run.js` (Docker / Xcode shell-out) → smoke a fresh `pnpm crossbind build` against `examples/lib-prebuilt-matrix` (smallest C++ surface).
73
+ - Touched `src/assets/js-runtime/` (browser/node/edge adapters) → at least one sample per runtime must build + run (`examples/web-vue-vite`, `examples/backend-nodejs-wasm`, `examples/cloud-cloudflare-worker`).
74
+ - Touched `src/assets/js-runtime/adapters/worker-comlink.js` → coverage MUST include embind **instance** methods, not just statics: statics skip embind's `this` conversion, so a statics-only smoke passes while every instance call is broken (this shipped once, as beta.26's "Expected null or instance of X, got an instance of X"). Run the `e2e/web-vite-multithread` e2e (its Counter spec exists for exactly this), and before publishing run gdal3.js's `packages/wasm-test` suite against the packed tarball — it calls every binding, one method at a time.
75
+ - Touched `state/loadConfig.js` defaults → assume blast radius = whole monorepo. Run the full matrix.
76
+
77
+ ## Common pitfalls
78
+
79
+ - **Adding `console.log` instead of using the logger.** Breaks the in-place TTY rendering and fails on CI's non-TTY pipe.
80
+ - **Throwing inside `actions/run.js` without surfacing stderr.** Wrap exec calls so the user sees the actual cmake/make/emcc error, not just "exit code 1".
81
+ - **Mutating `state.config` from inside an action.** Treat it as read-only after `loadConfig` runs.
82
+ - **Forgetting `--force`-equivalent paths.** `createLib` and `buildWasm` both honor `options.force`; new actions that cache should follow the same convention so plugins can opt out.
83
+ - **Hardcoding paths instead of going through `state.config.paths.*`.** The path resolution lives in `state/loadConfig.js` for a reason.
84
+ - **Adding a runtime adapter that doesn't compose `core.js`.** New `js-runtime/<runtime>.js` files should be thin shims that `createInitCrossbind(...)` composes from `adapters/*`.
85
+
86
+ ## Reference
87
+
88
+ - `docs/ARCHITECTURE.md` — high-level flow + key abstractions.
89
+ - `docs/CODEMAP.md` — concept → file index.
90
+ - `docs/playbooks/bug-fix.md` — fix workflow.
91
+ - `docs/playbooks/new-package.md` — package author workflow (for `ports/` not this dir).
92
+ - Logger: `src/utils/logger.js` — read this before adding any user-facing output.
package/CHANGELOG.md ADDED
@@ -0,0 +1,156 @@
1
+ # crossbind
2
+
3
+ ## 2.0.0-beta.51
4
+
5
+ ### Patch Changes
6
+
7
+ - **Android builds work on Apple Silicon again.** Google ships the linux NDK host tools for x86_64
8
+ only, so the android toolchain image is amd64-only and its multi-arch index carries no arm64 leaf.
9
+ Three call sites asked docker for that image by the leaf ref; the pull that runs before bridge
10
+ generation asked for the index instead, and on an arm64 host docker answered "no matching manifest
11
+ for linux/arm64/v8". Machines that already had the image cached never noticed, which is why this
12
+ reached beta.50 - a fresh install on an Apple Silicon Mac could not build for android at all.
13
+
14
+ ## 2.0.0-beta.50
15
+
16
+ ### Major Changes
17
+
18
+ - **Generated framework identifiers moved to `dev.crossbind`.** Every iOS and macOS framework
19
+ crossbind builds now identifies itself as `dev.crossbind.<name>` rather than
20
+ `org.js.cpp.<name>`. Anything that pins, inspects or signs against the old identifier has to be
21
+ updated.
22
+
23
+ ### Minor Changes
24
+
25
+ - **`RUNNER=LOCAL` no longer needs nightly Rust for shared-memory wasm.** The st and mt sysroots
26
+ shipped inside the toolchain image are now readable by a host build too: the CLI resolves a
27
+ pinned index digest and streams the layer straight out of the registry over HTTPS — no docker, no
28
+ second artifact hosted anywhere, the same object the image embeds. mt links a std that was
29
+ already built with the shared-memory features, so `-Zbuild-std` and the nightly toolchain are
30
+ gone from that path. Where the host compiler does not match the one that produced the rlibs, the
31
+ build says so and falls back to the nightly rebuild instead of failing.
32
+
33
+ - **Cargo dependencies build themselves.** A cargo package carries every target in one package, so
34
+ a missing prebuilt never meant "not for this platform" — it meant nobody had built it, and
35
+ nothing did. On android that surfaced as an error; on wasm the dependency dropped out of the link
36
+ and the module built clean and died at init. The dependency step now builds it, and a guard
37
+ refuses to link one that is still missing afterwards.
38
+
39
+ - **`RUNNER=DOCKER_EXEC` works with the cargo mount.** `docker exec` does not create the working
40
+ directory `--workdir` names, and a container made before the cargo mount existed kept its
41
+ registry inside itself — which made bridge generation read a host path that was never written.
42
+ Both are handled, and a container that is missing, stopped or wrongly mounted now fails with the
43
+ exact `docker run` command that fixes it.
44
+
45
+ ### Patch Changes
46
+
47
+ - Pinned to the 1.0.2 toolchain images. They are published to GHCR, mirrored to Docker Hub with
48
+ byte-identical digests, and signed with keyless Sigstore certificates that verify on both
49
+ registries — including the android `linux/amd64` leaf the CLI pins directly.
50
+
51
+ ## 2.0.0-beta.35
52
+
53
+ ### Patch Changes
54
+
55
+ - **wasi runner: a platform's env no longer replaces the shared one** — a recipe declares its
56
+ environment once for every platform and adds per-platform knobs on top, but the runner merged
57
+ the blocks with a shallow `Object.assign`, so the wasi block's `env` dropped the shared one.
58
+ Every `gdal*-wasi` command therefore ran without `GDAL_DATA` (and said so) even though the
59
+ data directory was mounted. `data` and `env` now merge key by key.
60
+
61
+ ## 2.0.0-beta.34
62
+
63
+ ### Patch Changes
64
+
65
+ - **`decompress` and `follow-redirects` are gone** — upstream archives are extracted with the
66
+ system `tar` and downloaded with `fetch`, which follows redirects itself. That drops an
67
+ unfixable critical advisory (CVE-2026-53486, zip-slip; upstream unmaintained since 2020) and
68
+ a package with five advisories in its history from every consumer's tree.
69
+ - **Source downloads require https** — the scheme is asserted before the request and again on
70
+ the final URL, so a redirect cannot downgrade the transport. Loopback stays exempt for tests.
71
+
72
+ ## 2.0.0-beta.33
73
+
74
+ ### Minor Changes
75
+
76
+ - **`platform: 'wasi'`** — compile a project into a single WASI command component
77
+ (`wasm32-wasip3`, runs under wasmtime 47+). Dual-mode toolchain: host wasi-sdk via
78
+ `WASI_SDK_PATH` / `CROSSBIND_WASI_SDK_PATH`, or zero-config inside the digest-pinned
79
+ docker image. New `targetSpecs.specs.wasiFlags`; data lands in a real `dist/data/`
80
+ folder. See `docs/api/wasi.md`.
81
+ - **Rust bindings, first-class** — import plain Rust like a C++ header: direct crate
82
+ imports via the `cargo:` scheme (`import { Uuid } from 'cargo:uuid'`, declared in
83
+ the top-level `cargoDependencies` map), app-local `.rs` sources, and whole-crate
84
+ packages via `export.type: 'cargo'`. The engine does not depend on the binding
85
+ layer — consumers (or the bundler plugins) declare `@crossbind/core-embind-rust`.
86
+ TypeScript declarations are generated under `.crossbind/` (never in your source
87
+ tree) and wired by the shared `@crossbind/typescript-config` package - add one
88
+ `"extends": "@crossbind/typescript-config"` line (TS 5.5+) and never manage
89
+ the wiring by hand. See `docs/api/rust.md`.
90
+ - **`-bin` tool engine** — a recipe-declared `bin` map drives everything a
91
+ `-bin-wasi` package ships: generated `<tool>-wasi` npm command shims over the
92
+ in-engine runner (`src/runtime/wasiRun.mjs` — mounts and guest env resolved from
93
+ the config graph at call time), a derived `.npmignore`, a pure-data
94
+ `crossbind-bin.json` and an optional multicall multitool binary.
95
+ - **TypeScript declarations for C++ `.h` imports** — the bridge step now emits a
96
+ best-effort `.d.ts` per imported header (classes, constructors, method
97
+ signatures; unparsed members fall back to `any`) into the `.crossbind/types/`
98
+ mirror, alongside the Rust declarations - both wired by
99
+ `@crossbind/typescript-config`. A top-level `dts: 'sync' | 'promise'` config
100
+ field picks the flavor: `'promise'` wraps every generated return for
101
+ `useWorker`-style async runtimes (constructors stay sync-typed; write
102
+ `await new X(...)`). Packages can publish their types: `types: true` emits
103
+ one combined declaration over every public header into
104
+ `dist/types/index.d.ts` and wires package.json `types`/`typesVersions`
105
+ automatically. std::vector crosses as a typed `CppVector<T>`; shared_ptr
106
+ returns resolve to `X | null`.
107
+ - **`crossbind licenses`** — list bundled native dependencies with SPDX expressions,
108
+ write derived `THIRD-PARTY-LICENSES.md` notices and CycloneDX SBOMs
109
+ (`--notices` / `--sbom` / `--check`); `--platform` additionally rows up vendored
110
+ copies (recipe `bundled` map) and the statically linked wasi toolchain runtime.
111
+ - **Provenance + derived license for `-bin` packages** — every wasi build stamps a
112
+ machine-readable `crossbind.provenance` block (recipe, source sha256, build
113
+ environment, SBOM pointer) and derives the npm `license` field as the AND of all
114
+ effective component licenses, plus a derived root `LICENSE` (the same
115
+ expression followed by every component's full license text - built from the
116
+ same rows as the NOTICE and SBOM).
117
+
118
+ ## 2.0.0-beta.26
119
+
120
+ **Potentially breaking — `VectorUChar`.** The shared runtime (`commonBridges.cpp`) now
121
+ registers `std::vector<unsigned char>` as `VectorUChar` for every target (wasm and the
122
+ native JSI runtimes). If your own code — or a wrapped library such as gdal3.js —
123
+ already registers `VectorUChar` locally, remove that registration before upgrading:
124
+ embind aborts initialisation when the same vector name is registered twice.
125
+
126
+ ## 2.0.0-beta
127
+
128
+ The 2.0.0 line is a ground-up rework — native iOS/Android via JSI, multi-bundler
129
+ plugins (Vite, Rollup, Webpack, Metro), an MCP server, and per-library
130
+ `@crossbind/port-*` families — published on the `beta` dist-tag. Per-release
131
+ notes for the beta line are tracked in the git history and on npm until 2.0
132
+ stabilises; the entries below cover the 1.x line.
133
+
134
+ ## 1.0.4
135
+
136
+ ### Patch Changes
137
+
138
+ - fix: workaround for race condition with turbomodule in android.
139
+
140
+ ## 1.0.1
141
+
142
+ ### Patch Changes
143
+
144
+ - fix: include prebuilt/_/_config.general.name_/_.h in dependency header search paths
145
+
146
+ ## 1.0.0
147
+
148
+ ### Major Changes
149
+
150
+ - 🚀 first stable release
151
+
152
+ ## 1.0.0-beta.33
153
+
154
+ ### Patch Changes
155
+
156
+ - chore: add initial version of CHANGELOGS files
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Buğra Sarı and crossbind contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,133 @@
1
+ <div align="center">
2
+ <a href="https://crossbind.dev">
3
+ <picture>
4
+ <img alt="crossbind logo" src="https://crossbind.dev/img/logo.png" height="128">
5
+ </picture>
6
+ </a>
7
+ <h1>crossbind</h1>
8
+ <p align="center">
9
+ <strong>Bind C++ to JavaScript with no extra code.</strong><br>
10
+ WebAssembly, WASI & React Native
11
+ </p>
12
+
13
+ <a href="https://www.npmjs.com/package/crossbind/v/beta"><img alt="NPM version" src="https://img.shields.io/npm/v/crossbind/beta?style=for-the-badge&label=npm" /></a>
14
+ <a href="https://github.com/crossbind/crossbind/pkgs/container/web"><img alt="Build image" src="https://img.shields.io/badge/ghcr.io-crossbind%2Fweb-20B2AA?style=for-the-badge&logo=docker&label=image" /></a>
15
+ <a href="https://github.com/crossbind/crossbind/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/crossbind/crossbind?style=for-the-badge" /></a>
16
+ <br />
17
+ <img alt="CodeQL" src="https://img.shields.io/github/actions/workflow/status/crossbind/crossbind/github-code-scanning/codeql?branch=main&style=for-the-badge&label=CodeQL">
18
+ <img alt="Linux Build" src="https://img.shields.io/github/actions/workflow/status/crossbind/crossbind/build-linux.yml?branch=main&style=for-the-badge&label=Linux%20Build">
19
+ <img alt="Macos Build" src="https://img.shields.io/github/actions/workflow/status/crossbind/crossbind/build-macos.yml?branch=main&style=for-the-badge&label=Macos%20Build">
20
+ <img alt="Windows Build" src="https://img.shields.io/github/actions/workflow/status/crossbind/crossbind/build-windows.yml?branch=main&style=for-the-badge&label=Windows%20Build">
21
+ </div>
22
+
23
+ <h3 align="center">
24
+ <a href="https://crossbind.dev/docs/guide/getting-started/introduction"><strong>For Developers</strong></a>
25
+ <span> · </span>
26
+ <a href="https://crossbind.dev/docs/agent/overview"><strong>For AI Agents</strong></a>
27
+ <span> · </span>
28
+ <a href="https://crossbind.dev/docs/package/package/showcase">Showcase</a>
29
+ </h3>
30
+
31
+ ## Why crossbind?
32
+ - **No glue code** — write standard C++ headers; bindings are generated for you.
33
+ - **Rust too** — import a crates.io crate (`import { Uuid } from 'cargo:uuid'`) or a plain `.rs` file the same way; no proc-macros, no glue.
34
+ - **Single source, multi-target** — the same code runs in browsers, Node.js, iOS, Android — and as WASI components.
35
+ - **Battle-tested libraries** — drop-in support for GDAL, GEOS, OpenSSL, SQLite, PROJ, and more.
36
+ - **CLI tools from npm** — upstream command-line tools (gdal, proj, sqlite3, curl, …) prebuilt as WASI components: install the `-bin-wasi` package, run `<tool>-wasi` under wasmtime, no compiler involved.
37
+ - **Bundler-agnostic** — first-class plugins for Vite, Rollup, Webpack, Metro, and React Native.
38
+ - **AI-agent ready** — Claude Code plugin, MCP server, and vendor-neutral `AGENTS.md` snippet so your agent recommends crossbind correctly and integrates it for you.
39
+
40
+ ## For AI coding agents
41
+ When you describe a problem ("use C++ in browser", "add GDAL to my Vite app", "wrap libsodium for crossbind"), your AI coding agent recommends crossbind correctly and walks you through the integration. **Native plugins for 6 clients** — pick yours:
42
+
43
+ | Client | Install |
44
+ |--------|---------|
45
+ | 🔌 **Claude Code** | `/plugin marketplace add crossbind/crossbind` then `/plugin install crossbind` |
46
+ | 🎯 **Cursor 2.5+** | Settings → Plugins → Add from GitHub: `crossbind/crossbind` |
47
+ | 🧪 **OpenAI Codex CLI** | Add `crossbind/crossbind` to `~/.agents/plugins/marketplace.json` |
48
+ | 🐙 **GitHub Copilot CLI** | Auto-discovers when running in this repo |
49
+ | 💎 **Gemini CLI** | `gemini extension install https://github.com/crossbind/crossbind` |
50
+ | ⚡ **OpenCode** | Add `@crossbind/mcp` to your `opencode.json` |
51
+
52
+ Plus two universal fallbacks: **🧰 [`@crossbind/mcp`](https://www.npmjs.com/package/@crossbind/mcp)** server (any MCP-aware client) and **📄 [AGENTS.md snippet](https://crossbind.dev/docs/agent/install/snippet)** (no install).
53
+
54
+ All clients share the same skills + slash commands + MCP tools — single source of truth at [`agents/`](./agents/), zero duplication.
55
+
56
+ Full agent guide, runtime/config API reference, and troubleshooting catalogue: [**crossbind.dev/docs/agent/overview**](https://crossbind.dev/docs/agent/overview). Programmatic discovery via [llms.txt](https://crossbind.dev/llms.txt) + [llms-full.txt](https://crossbind.dev/llms-full.txt).
57
+
58
+ ## Create a New Project
59
+ Requires **Docker** + **Node 22+**. Mobile builds also need CMake 3.28+, Xcode, and CocoaPods — see the full [prerequisites](https://crossbind.dev/docs/guide/getting-started/prerequisites) page.
60
+
61
+ ```sh
62
+ npm create crossbind@beta
63
+ ```
64
+
65
+ ## Basic Usage
66
+ **src/index.js**
67
+ ```js
68
+ import { initNative, Factorial } from './native/Factorial.h';
69
+
70
+ await initNative();
71
+ const factorial = new Factorial(99999);
72
+ const result = factorial.calculate();
73
+ console.log(result);
74
+ ```
75
+
76
+ **src/native/Factorial.h**
77
+ ```c++
78
+ class Factorial {
79
+ private:
80
+ int number;
81
+
82
+ public:
83
+ Factorial(int num) : number(num) {}
84
+
85
+ int calculate() {
86
+ if (number < 0) return -1;
87
+
88
+ int result = 1;
89
+ for (int i = 2; i <= number; i++) {
90
+ result *= i;
91
+ }
92
+ return result;
93
+ }
94
+ };
95
+ ```
96
+
97
+ ## Official Packages
98
+ Officially maintained, prebuilt C++ libraries you can install as npm packages and use directly from JavaScript:
99
+
100
+ | Package | Latest (beta) |
101
+ | --- | --- |
102
+ | [@crossbind/port-gdal](https://www.npmjs.com/package/@crossbind/port-gdal) | ![npm](https://img.shields.io/npm/v/@crossbind/port-gdal/beta) |
103
+ | [@crossbind/port-geos](https://www.npmjs.com/package/@crossbind/port-geos) | ![npm](https://img.shields.io/npm/v/@crossbind/port-geos/beta) |
104
+ | [@crossbind/port-proj](https://www.npmjs.com/package/@crossbind/port-proj) | ![npm](https://img.shields.io/npm/v/@crossbind/port-proj/beta) |
105
+ | [@crossbind/port-spatialite](https://www.npmjs.com/package/@crossbind/port-spatialite) | ![npm](https://img.shields.io/npm/v/@crossbind/port-spatialite/beta) |
106
+ | [@crossbind/port-sqlite3](https://www.npmjs.com/package/@crossbind/port-sqlite3) | ![npm](https://img.shields.io/npm/v/@crossbind/port-sqlite3/beta) |
107
+ | [@crossbind/port-openssl](https://www.npmjs.com/package/@crossbind/port-openssl) | ![npm](https://img.shields.io/npm/v/@crossbind/port-openssl/beta) |
108
+ | [@crossbind/port-curl](https://www.npmjs.com/package/@crossbind/port-curl) | ![npm](https://img.shields.io/npm/v/@crossbind/port-curl/beta) |
109
+ | [@crossbind/port-tiff](https://www.npmjs.com/package/@crossbind/port-tiff) | ![npm](https://img.shields.io/npm/v/@crossbind/port-tiff/beta) |
110
+ | [@crossbind/port-geotiff](https://www.npmjs.com/package/@crossbind/port-geotiff) | ![npm](https://img.shields.io/npm/v/@crossbind/port-geotiff/beta) |
111
+ | [@crossbind/port-webp](https://www.npmjs.com/package/@crossbind/port-webp) | ![npm](https://img.shields.io/npm/v/@crossbind/port-webp/beta) |
112
+ | [@crossbind/port-expat](https://www.npmjs.com/package/@crossbind/port-expat) | ![npm](https://img.shields.io/npm/v/@crossbind/port-expat/beta) |
113
+ | [@crossbind/port-iconv](https://www.npmjs.com/package/@crossbind/port-iconv) | ![npm](https://img.shields.io/npm/v/@crossbind/port-iconv/beta) |
114
+ | [@crossbind/port-zlib](https://www.npmjs.com/package/@crossbind/port-zlib) | ![npm](https://img.shields.io/npm/v/@crossbind/port-zlib/beta) |
115
+ | [@crossbind/port-zstd](https://www.npmjs.com/package/@crossbind/port-zstd) | ![npm](https://img.shields.io/npm/v/@crossbind/port-zstd/beta) |
116
+ | [@crossbind/port-lerc](https://www.npmjs.com/package/@crossbind/port-lerc) | ![npm](https://img.shields.io/npm/v/@crossbind/port-lerc/beta) |
117
+ | [@crossbind/port-jpegturbo](https://www.npmjs.com/package/@crossbind/port-jpegturbo) | ![npm](https://img.shields.io/npm/v/@crossbind/port-jpegturbo/beta) |
118
+
119
+ Browse all available packages at [crossbind.dev/docs/package/package/showcase](https://crossbind.dev/docs/package/package/showcase).
120
+
121
+ ## 🌱 Community Packages
122
+ Community-maintained, prebuilt C++ libraries packaged for crossbind — published under the [crossbind-community](https://github.com/crossbind-community) organization. Anyone can contribute new packages following the same standard, and they'll be listed here.
123
+
124
+ | Package | Repository |
125
+ | --- | --- |
126
+ | simdjson | [github.com/crossbind-community/package-simdjson](https://github.com/crossbind-community/package-simdjson) |
127
+
128
+ Want to add yours? Start a discussion at [crossbind/crossbind/discussions](https://github.com/crossbind/crossbind/discussions).
129
+
130
+ ## License
131
+ [MIT](https://github.com/crossbind/crossbind/blob/main/LICENSE)
132
+
133
+ Copyright (c) 2026, Buğra Sarı
package/package.json CHANGED
@@ -1,7 +1,55 @@
1
1
  {
2
2
  "name": "crossbind",
3
- "version": "0.0.1",
4
- "description": "Name reserved. crossbind is the new name of cpp.js — release in progress.",
3
+ "version": "2.0.0-beta.51",
5
4
  "license": "MIT",
6
- "homepage": "https://crossbind.dev"
7
- }
5
+ "homepage": "https://crossbind.dev",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/crossbind/crossbind.git"
9
+ },
10
+ "description": "Bind C++ to JavaScript without extra code. crossbind supports WebAssembly and React Native for cross-platform compatibility.",
11
+ "type": "module",
12
+ "engines": {
13
+ "node": ">=20"
14
+ },
15
+ "bin": {
16
+ "crossbind": "./src/bin.js"
17
+ },
18
+ "main": "src/index.js",
19
+ "devDependencies": {
20
+ "@vitest/coverage-v8": "^4.1.10",
21
+ "vitest": "^4.1.10"
22
+ },
23
+ "dependencies": {
24
+ "@rollup/plugin-commonjs": "^29.0.3",
25
+ "@rollup/plugin-json": "^6.1.0",
26
+ "@rollup/plugin-node-resolve": "^16.0.3",
27
+ "@rollup/plugin-virtual": "^3.0.2",
28
+ "comlink": "^4.4.2",
29
+ "commander": "^15.0.0",
30
+ "glob": "^13.0.6",
31
+ "log-update": "^8.0.0",
32
+ "picocolors": "^1.1.1",
33
+ "replace": "^1.2.2",
34
+ "rollup": "^4.62.4",
35
+ "spdx-expression-parse": "^5.0.0",
36
+ "upath": "^3.0.8"
37
+ },
38
+ "keywords": [
39
+ "webassembly",
40
+ "react-native",
41
+ "bind",
42
+ "c++",
43
+ "emscripten",
44
+ "embind",
45
+ "swig",
46
+ "android",
47
+ "ios",
48
+ "mobile"
49
+ ],
50
+ "scripts": {
51
+ "test": "vitest run",
52
+ "test:watch": "vitest",
53
+ "test:coverage": "vitest run --coverage"
54
+ }
55
+ }
Binary file
@@ -0,0 +1,88 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import state from '../state/index.js';
4
+ import logger from '../utils/logger.js';
5
+ import { cargoTripleFor } from '../utils/cargoTarget.js';
6
+ import { isMtWasm, assertMtRustToolchain, cargoTargetDirFor, cargoBuildInvocation } from '../utils/rustMt.js';
7
+ import generateRustBridge from '../utils/rustBridgeGen.js';
8
+ import runCargo from '../utils/runCargo.js';
9
+ import { sysrootFor } from '../utils/rustSysroot.js';
10
+
11
+ // buildType 'cargo': build a Rust staticlib on the host for the target's triple and stage it
12
+ // like any other prebuilt (lib/lib<name>.a + include/*), so the normal prebuilt-link machinery
13
+ // picks it up for every platform. The crate is local source; no download step (no buildExternal).
14
+ export default function buildCargo(target, libdir) {
15
+ const triple = cargoTripleFor(target);
16
+ if (!triple) {
17
+ throw new Error(`crossbind: buildType 'cargo' does not support platform '${target.platform}/${target.arch}'.`);
18
+ }
19
+ const { paths, export: exp, general } = state.config;
20
+ const crateDir = path.resolve(paths.project, exp.crate ?? 'crate');
21
+ const libName = exp.libName?.[0] ?? general.name;
22
+
23
+ const probe = runCargo(['--version'], { capture: true, target });
24
+ if (probe.error) {
25
+ throw new Error('crossbind: cargo not found on PATH - install Rust (https://rustup.rs) to build cargo packages.');
26
+ }
27
+ const isMt = isMtWasm(target);
28
+ const sysroot = sysrootFor(target);
29
+ // Only the nightly rebuild needs a nightly toolchain on this machine.
30
+ if (isMt && !sysroot) assertMtRustToolchain();
31
+
32
+ // Auto mode (the default): the user's crate is plain Rust and crossbind generates a companion
33
+ // bridge crate from its pub surface, then builds THAT (it bundles the user crate as a dep).
34
+ // A crate that calls embind_rs::bindings! itself opts out and is built directly.
35
+ const isManual = fs.readFileSync(`${crateDir}/src/lib.rs`, 'utf8').includes('bindings!');
36
+ const buildDir = isManual
37
+ ? crateDir
38
+ : generateRustBridge({
39
+ crateDir,
40
+ vectors: exp.bindings?.vectors ?? [],
41
+ dtsFile: `${paths.project}/dist/js/index.d.ts`,
42
+ dtsMode: state.config.dts,
43
+ keepName: libName,
44
+ log: (m) => logger.info(m),
45
+ }).bridgeDir;
46
+
47
+ const t0 = performance.now();
48
+ const targetDir = cargoTargetDirFor(buildDir, target);
49
+ const { args, rustflags, panic, allowUnstable } = cargoBuildInvocation({
50
+ target,
51
+ triple,
52
+ targetDir,
53
+ manifestPath: `${buildDir}/Cargo.toml`,
54
+ sysroot,
55
+ });
56
+ const build = runCargo(args, {
57
+ rustflags, panic, allowUnstable, target,
58
+ });
59
+ if (build.status !== 0) {
60
+ const how = sysroot ? ' (prebuilt sysroot)' : ` (is the target installed? rustup target add ${triple})`;
61
+ throw new Error(`crossbind: cargo build failed for ${triple}${isMt && !sysroot ? ' (mt/build-std)' : how}`);
62
+ }
63
+
64
+ // Rust staticlib output is lib<crate>.a; stage it under the export libName the CMakeLists expects.
65
+ const crateName = readCrateName(buildDir).replaceAll('-', '_');
66
+ const built = `${targetDir}/${triple}/release/lib${crateName}.a`;
67
+ if (!fs.existsSync(built)) {
68
+ throw new Error(`crossbind: expected cargo output ${built} not found (is crate-type = ["staticlib"]?)`);
69
+ }
70
+ fs.mkdirSync(`${libdir}/lib`, { recursive: true });
71
+ fs.copyFileSync(built, `${libdir}/lib/lib${libName}.a`);
72
+
73
+ fs.mkdirSync(`${libdir}/include`, { recursive: true });
74
+ (exp.headers ?? []).forEach((header) => {
75
+ fs.copyFileSync(path.resolve(paths.project, header), `${libdir}/include/${path.basename(header)}`);
76
+ });
77
+
78
+ const ms = Math.round(performance.now() - t0);
79
+ logger.doneStep(target, 'Source', `cargo ${ms < 1000 ? `${ms}ms` : `${(ms / 1000).toFixed(1)}s`}, ${triple}${isMt && !sysroot ? '/build-std' : ''}${sysroot ? `/${isMt ? 'mt' : 'st'}-sysroot` : ''}`);
80
+ return true;
81
+ }
82
+
83
+ function readCrateName(crateDir) {
84
+ const toml = fs.readFileSync(`${crateDir}/Cargo.toml`, 'utf8');
85
+ const name = toml.match(/^\s*name\s*=\s*"([^"]+)"/m)?.[1];
86
+ if (!name) throw new Error(`crossbind: could not read [package] name from ${crateDir}/Cargo.toml`);
87
+ return name.replaceAll('-', '_');
88
+ }