crossbind 0.0.1 → 2.0.0-beta.50

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 +145 -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 +305 -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 +40 -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,145 @@
1
+ # crossbind
2
+
3
+ ## 2.0.0-beta.50
4
+
5
+ ### Major Changes
6
+
7
+ - **Generated framework identifiers moved to `dev.crossbind`.** Every iOS and macOS framework
8
+ crossbind builds now identifies itself as `dev.crossbind.<name>` rather than
9
+ `org.js.cpp.<name>`. Anything that pins, inspects or signs against the old identifier has to be
10
+ updated.
11
+
12
+ ### Minor Changes
13
+
14
+ - **`RUNNER=LOCAL` no longer needs nightly Rust for shared-memory wasm.** The st and mt sysroots
15
+ shipped inside the toolchain image are now readable by a host build too: the CLI resolves a
16
+ pinned index digest and streams the layer straight out of the registry over HTTPS — no docker, no
17
+ second artifact hosted anywhere, the same object the image embeds. mt links a std that was
18
+ already built with the shared-memory features, so `-Zbuild-std` and the nightly toolchain are
19
+ gone from that path. Where the host compiler does not match the one that produced the rlibs, the
20
+ build says so and falls back to the nightly rebuild instead of failing.
21
+
22
+ - **Cargo dependencies build themselves.** A cargo package carries every target in one package, so
23
+ a missing prebuilt never meant "not for this platform" — it meant nobody had built it, and
24
+ nothing did. On android that surfaced as an error; on wasm the dependency dropped out of the link
25
+ and the module built clean and died at init. The dependency step now builds it, and a guard
26
+ refuses to link one that is still missing afterwards.
27
+
28
+ - **`RUNNER=DOCKER_EXEC` works with the cargo mount.** `docker exec` does not create the working
29
+ directory `--workdir` names, and a container made before the cargo mount existed kept its
30
+ registry inside itself — which made bridge generation read a host path that was never written.
31
+ Both are handled, and a container that is missing, stopped or wrongly mounted now fails with the
32
+ exact `docker run` command that fixes it.
33
+
34
+ ### Patch Changes
35
+
36
+ - Pinned to the 1.0.2 toolchain images. They are published to GHCR, mirrored to Docker Hub with
37
+ byte-identical digests, and signed with keyless Sigstore certificates that verify on both
38
+ registries — including the android `linux/amd64` leaf the CLI pins directly.
39
+
40
+ ## 2.0.0-beta.35
41
+
42
+ ### Patch Changes
43
+
44
+ - **wasi runner: a platform's env no longer replaces the shared one** — a recipe declares its
45
+ environment once for every platform and adds per-platform knobs on top, but the runner merged
46
+ the blocks with a shallow `Object.assign`, so the wasi block's `env` dropped the shared one.
47
+ Every `gdal*-wasi` command therefore ran without `GDAL_DATA` (and said so) even though the
48
+ data directory was mounted. `data` and `env` now merge key by key.
49
+
50
+ ## 2.0.0-beta.34
51
+
52
+ ### Patch Changes
53
+
54
+ - **`decompress` and `follow-redirects` are gone** — upstream archives are extracted with the
55
+ system `tar` and downloaded with `fetch`, which follows redirects itself. That drops an
56
+ unfixable critical advisory (CVE-2026-53486, zip-slip; upstream unmaintained since 2020) and
57
+ a package with five advisories in its history from every consumer's tree.
58
+ - **Source downloads require https** — the scheme is asserted before the request and again on
59
+ the final URL, so a redirect cannot downgrade the transport. Loopback stays exempt for tests.
60
+
61
+ ## 2.0.0-beta.33
62
+
63
+ ### Minor Changes
64
+
65
+ - **`platform: 'wasi'`** — compile a project into a single WASI command component
66
+ (`wasm32-wasip3`, runs under wasmtime 47+). Dual-mode toolchain: host wasi-sdk via
67
+ `WASI_SDK_PATH` / `CROSSBIND_WASI_SDK_PATH`, or zero-config inside the digest-pinned
68
+ docker image. New `targetSpecs.specs.wasiFlags`; data lands in a real `dist/data/`
69
+ folder. See `docs/api/wasi.md`.
70
+ - **Rust bindings, first-class** — import plain Rust like a C++ header: direct crate
71
+ imports via the `cargo:` scheme (`import { Uuid } from 'cargo:uuid'`, declared in
72
+ the top-level `cargoDependencies` map), app-local `.rs` sources, and whole-crate
73
+ packages via `export.type: 'cargo'`. The engine does not depend on the binding
74
+ layer — consumers (or the bundler plugins) declare `@crossbind/core-embind-rust`.
75
+ TypeScript declarations are generated under `.crossbind/` (never in your source
76
+ tree) and wired by the shared `@crossbind/typescript-config` package - add one
77
+ `"extends": "@crossbind/typescript-config"` line (TS 5.5+) and never manage
78
+ the wiring by hand. See `docs/api/rust.md`.
79
+ - **`-bin` tool engine** — a recipe-declared `bin` map drives everything a
80
+ `-bin-wasi` package ships: generated `<tool>-wasi` npm command shims over the
81
+ in-engine runner (`src/runtime/wasiRun.mjs` — mounts and guest env resolved from
82
+ the config graph at call time), a derived `.npmignore`, a pure-data
83
+ `crossbind-bin.json` and an optional multicall multitool binary.
84
+ - **TypeScript declarations for C++ `.h` imports** — the bridge step now emits a
85
+ best-effort `.d.ts` per imported header (classes, constructors, method
86
+ signatures; unparsed members fall back to `any`) into the `.crossbind/types/`
87
+ mirror, alongside the Rust declarations - both wired by
88
+ `@crossbind/typescript-config`. A top-level `dts: 'sync' | 'promise'` config
89
+ field picks the flavor: `'promise'` wraps every generated return for
90
+ `useWorker`-style async runtimes (constructors stay sync-typed; write
91
+ `await new X(...)`). Packages can publish their types: `types: true` emits
92
+ one combined declaration over every public header into
93
+ `dist/types/index.d.ts` and wires package.json `types`/`typesVersions`
94
+ automatically. std::vector crosses as a typed `CppVector<T>`; shared_ptr
95
+ returns resolve to `X | null`.
96
+ - **`crossbind licenses`** — list bundled native dependencies with SPDX expressions,
97
+ write derived `THIRD-PARTY-LICENSES.md` notices and CycloneDX SBOMs
98
+ (`--notices` / `--sbom` / `--check`); `--platform` additionally rows up vendored
99
+ copies (recipe `bundled` map) and the statically linked wasi toolchain runtime.
100
+ - **Provenance + derived license for `-bin` packages** — every wasi build stamps a
101
+ machine-readable `crossbind.provenance` block (recipe, source sha256, build
102
+ environment, SBOM pointer) and derives the npm `license` field as the AND of all
103
+ effective component licenses, plus a derived root `LICENSE` (the same
104
+ expression followed by every component's full license text - built from the
105
+ same rows as the NOTICE and SBOM).
106
+
107
+ ## 2.0.0-beta.26
108
+
109
+ **Potentially breaking — `VectorUChar`.** The shared runtime (`commonBridges.cpp`) now
110
+ registers `std::vector<unsigned char>` as `VectorUChar` for every target (wasm and the
111
+ native JSI runtimes). If your own code — or a wrapped library such as gdal3.js —
112
+ already registers `VectorUChar` locally, remove that registration before upgrading:
113
+ embind aborts initialisation when the same vector name is registered twice.
114
+
115
+ ## 2.0.0-beta
116
+
117
+ The 2.0.0 line is a ground-up rework — native iOS/Android via JSI, multi-bundler
118
+ plugins (Vite, Rollup, Webpack, Metro), an MCP server, and per-library
119
+ `@crossbind/port-*` families — published on the `beta` dist-tag. Per-release
120
+ notes for the beta line are tracked in the git history and on npm until 2.0
121
+ stabilises; the entries below cover the 1.x line.
122
+
123
+ ## 1.0.4
124
+
125
+ ### Patch Changes
126
+
127
+ - fix: workaround for race condition with turbomodule in android.
128
+
129
+ ## 1.0.1
130
+
131
+ ### Patch Changes
132
+
133
+ - fix: include prebuilt/_/_config.general.name_/_.h in dependency header search paths
134
+
135
+ ## 1.0.0
136
+
137
+ ### Major Changes
138
+
139
+ - 🚀 first stable release
140
+
141
+ ## 1.0.0-beta.33
142
+
143
+ ### Patch Changes
144
+
145
+ - 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.50",
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
+ }