castrum 0.9.0 → 0.9.1

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 (102) hide show
  1. package/README.md +153 -630
  2. package/castrum.linux-x64-gnu.node +0 -0
  3. package/dist/index.d.ts +1374 -1772
  4. package/dist/index.js +5570 -4169
  5. package/docs/API.md +337 -0
  6. package/docs/ARCHITECTURE.md +106 -14
  7. package/docs/BENCHMARKS.md +83 -47
  8. package/docs/CASE_STUDY.md +240 -0
  9. package/docs/ENVIRONMENT.md +8 -6
  10. package/docs/FFI_BUN_GUIDE.md +327 -0
  11. package/docs/GETTING_STARTED.md +15 -32
  12. package/docs/INGRESS-ROUTER.md +81 -0
  13. package/docs/INGRESS.md +5 -4
  14. package/docs/NATIVE-ROUTE.md +53 -0
  15. package/docs/REPO_MAP.md +46 -26
  16. package/docs/adr/0003-bun-builtins-delegation.md +6 -5
  17. package/docs/bun-builtins-decision-matrix.md +25 -18
  18. package/index.ts +9 -16
  19. package/package.json +36 -24
  20. package/src/ingress/body.ts +167 -27
  21. package/src/ingress/handlers.ts +91 -15
  22. package/src/ingress/health.ts +1 -0
  23. package/src/ingress/index.ts +39 -27
  24. package/src/ingress/packing/gather-raw-headers.ts +85 -21
  25. package/src/ingress/packing/header-packing.ts +5 -5
  26. package/src/ingress/packing/input-packer.ts +17 -3
  27. package/src/ingress/packing/select-headers.ts +12 -6
  28. package/src/ingress/router.ts +237 -0
  29. package/src/ingress/routes/common.ts +42 -1
  30. package/src/ingress/routes/fallback.ts +2 -2
  31. package/src/ingress/routes/head.ts +3 -13
  32. package/src/ingress/routes/index.ts +5 -4
  33. package/src/ingress/routes/json-write.ts +7 -31
  34. package/src/ingress/routes/options.ts +2 -12
  35. package/src/ingress/routes/read.ts +3 -13
  36. package/src/ingress/routes/responder.ts +159 -0
  37. package/src/ingress/server-node.ts +6 -6
  38. package/src/ingress/server.ts +45 -13
  39. package/src/ingress/types.ts +35 -1
  40. package/src/integration/pipeline.ts +3 -0
  41. package/src/integration/streaming.ts +2 -3
  42. package/src/integration/websocket.ts +4 -3
  43. package/src/loader/batch.ts +4 -0
  44. package/src/loader/cost.ts +1 -0
  45. package/src/loader/index.ts +43 -228
  46. package/src/loader/state.ts +84 -0
  47. package/src/loader/types.ts +145 -0
  48. package/src/native/ffi/constants.ts +58 -0
  49. package/src/native/ffi/selftest.ts +729 -0
  50. package/src/native/ffi/types.ts +474 -0
  51. package/src/native/ffi.ts +1063 -829
  52. package/src/native/loader.ts +52 -6
  53. package/src/native/types/instances.ts +274 -0
  54. package/src/native/types.ts +41 -238
  55. package/src/runtime/builtins.ts +131 -0
  56. package/src/runtime/codec.ts +147 -0
  57. package/src/runtime/detect.ts +36 -0
  58. package/src/runtime/index.ts +28 -0
  59. package/src/runtime/native.ts +35 -0
  60. package/src/runtime/server.ts +31 -0
  61. package/src/runtime/transport.ts +64 -0
  62. package/src/runtime/types.ts +173 -0
  63. package/src/runtime/uuid.ts +45 -0
  64. package/src/runtime/websocket.ts +30 -0
  65. package/src/rust-ffi/addon.ts +1 -1
  66. package/src/rust-ffi/batch/build.ts +155 -0
  67. package/src/rust-ffi/batch/index.ts +8 -0
  68. package/src/rust-ffi/batch/types.ts +92 -0
  69. package/src/rust-ffi/client.ts +5 -6
  70. package/src/rust-ffi/context.ts +39 -10
  71. package/src/rust-ffi/index.ts +28 -17
  72. package/src/rust-ffi/into.ts +21 -0
  73. package/src/rust-ffi/options.ts +1 -1
  74. package/src/rust-ffi/packed.ts +2 -2
  75. package/src/rust-ffi/proven.ts +16 -30
  76. package/src/rust-ffi/scalar/crypto.ts +188 -107
  77. package/src/rust-ffi/scalar/factories.ts +253 -27
  78. package/src/rust-ffi/scalar/hashing.ts +43 -41
  79. package/src/rust-ffi/scalar/http.ts +208 -77
  80. package/src/rust-ffi/scalar/index.ts +3 -3
  81. package/src/rust-ffi/scalar/interface.ts +88 -213
  82. package/src/rust-ffi/scalar/json-packed.ts +175 -0
  83. package/src/rust-ffi/scalar/json.ts +28 -12
  84. package/src/rust-ffi/scalar/payload.ts +159 -42
  85. package/src/rust-ffi/text.ts +31 -5
  86. package/src/selection.ts +27 -31
  87. package/src/shared/adaptive.ts +1 -2
  88. package/src/shared/buffer-pool.ts +72 -17
  89. package/src/shared/bytes.ts +75 -6
  90. package/src/shared/codec.ts +78 -0
  91. package/src/shared/env.ts +4 -4
  92. package/src/shared/log.ts +1 -0
  93. package/src/shared/packed/index.ts +10 -0
  94. package/src/shared/packed/parsers.ts +31 -0
  95. package/src/shared/packed/schema.ts +23 -0
  96. package/src/shared/{packed.ts → packed/wire.ts} +31 -39
  97. package/src/shared/proven.ts +189 -496
  98. package/src/shared/runtime.ts +20 -25
  99. package/src/shared/uuid.ts +12 -28
  100. package/src/data/json-rows.ts +0 -33
  101. package/src/rust-ffi/batch.ts +0 -431
  102. package/src/shared/bench-classify.ts +0 -209
package/docs/REPO_MAP.md CHANGED
@@ -19,7 +19,7 @@ agent editing this repo, [`AGENTS.md`](../AGENTS.md) is the agent-facing map.
19
19
  Under Bun, `bun:ffi` is the PRIMARY transport; NAPI is the fallback
20
20
  (Node, `CASTRUM_FFI_MODE=napi`, or a failed ffi self-test).
21
21
  - **TypeScript** (`src/`) provides the ergonomic public API: the flat `rust.*`
22
- FFI client, the `proven` performance surface, and the ingress layer.
22
+ FFI client and the ingress layer.
23
23
  - It ships benchmarks: a **CPU benchmark** (`bench.ts` → `src/bench`) and an
24
24
  **HTTP benchmark** (`bench/run-bench.ts` + `bench/servers/*`).
25
25
 
@@ -43,8 +43,6 @@ Bun is the primary runtime; Node.js ≥20.3 is supported via a compiled ESM entr
43
43
  | Installed-tarball e2e | `bun run verify:install` | pack → install → import from `node_modules` |
44
44
  | Typecheck | `bun run typecheck` | `bunx tsc --noEmit` (only `index.ts`, `bench.ts`, `src/`) |
45
45
  | CPU benchmark + correctness | `bun run check` | == `bun bench.ts`; writes `bench/results/cpu/` |
46
- | Proven-surface audit | `bun run check:proven[:fail]` | `:fail` gates CI on regressions |
47
- | Performance JSDoc | `bun run check:annotate` | rewrites perf JSDoc from CPU report; `--dry-run` previews |
48
46
  | HTTP bench (all servers) | `bun run bench:http` | |
49
47
  | HTTP smoke (fast sanity) | `bun run bench:http:smoke` | **the wire-format guard** (CI-gated) |
50
48
  | Startup bench | `bun run bench:startup` | import + first-call timing |
@@ -62,7 +60,7 @@ Bun is the primary runtime; Node.js ≥20.3 is supported via a compiled ESM entr
62
60
  ### Source (what you edit)
63
61
 
64
62
  ```
65
- index.ts Package entry (Bun). Re-exports src/rust-ffi, proven, shared helpers, src/ingress.
63
+ index.ts Package entry (Bun). Re-exports src/rust-ffi, shared helpers, src/ingress.
66
64
  bench.ts CPU benchmark entry point → src/bench/run.ts.
67
65
 
68
66
  examples/ Runnable sample app (basic-server.ts + README) — see also README Quick Start.
@@ -70,28 +68,46 @@ examples/ Runnable sample app (basic-server.ts + README) — see
70
68
 
71
69
  src/
72
70
  native/ The native transport layer: bun:ffi (primary on Bun) + NAPI fallback.
73
- types.ts NativeAddon interface + every instance type (mirrors index.d.ts).
71
+ types.ts NativeAddon module-surface interface (mirrors index.d.ts).
72
+ types/instances.ts Per-class INSTANCE types (Ingress, SchemaValidator, JwtSigner, ...) + result types.
74
73
  loader.ts Addon path resolution (multi-root) + getAddon()/lazyAddon().
75
74
  ffi.ts bun:ffi C-ABI bindings (Bun-only): lazy bind + bind-time self-test,
76
75
  CASTRUM_FFI_MODE gating, castrum_ingress_layout blob for constants.ts.
76
+ ffi/ ffi/types.ts (BunFFI interface) + constants.ts + selftest.ts (bind-time self-test).
77
77
  index.ts Barrel.
78
+ runtime/ THE RUNTIME ADAPTER seam (Bun/Node) — selected once at load.
79
+ detect.ts Cached runtime detection — the ONLY place `typeof Bun` is checked.
80
+ types.ts RuntimeAdapter contract (codec/uuid/env/builtins/transport/server/websocket).
81
+ codec.ts Runtime-native UTF-8 codec (Bun transfer vs TextEncoder/Decoder).
82
+ uuid.ts uuidv7 (Bun.randomUUIDv7 vs crypto.randomUUID).
83
+ builtins.ts BUN_WINS delegation registry (single source; `has(op)`).
84
+ transport.ts bun:ffi-first `resolve(op)` + ffi/napi surfaces (lazy bind).
85
+ native.ts FFI-facing seam (codec/uuid/env/builtins/transport) — imported by rust-ffi.
86
+ server.ts createIngressServer: Bun.serve on Bun, node:http on Node.
87
+ websocket.ts 101 upgrade on Bun; clear Bun-only error on Node.
88
+ index.ts FULL adapter `runtime` (native + server + websocket) — for the public API.
78
89
  rust-ffi/ The flat `rust.*` FFI client (TS wrappers over the addon).
79
90
  client.ts createRust() factory + the default `rust` instance + configure().
80
- scalar/ / text.ts / batch.ts / packed.ts namespaces (buildScalar, buildText, ...).
81
- context.ts Per-instance state (caches, rayon-pool bookkeeping).
91
+ scalar/ / text.ts / packed.ts namespaces (buildScalar, buildText, ...).
92
+ batch/ Array-of-bytes batch namespace: types.ts (RustBatch interface) + build.ts (impl) + index.ts.
93
+ context.ts Per-instance state (caches, rayon-pool bookkeeping, runtime seam).
82
94
  options.ts RustOptions + rayon-thread resolution + coercion helpers.
83
95
  addon.ts The single shared lazy addon proxy.
84
- proven.ts `proven` client — the FULL rust.* surface, annotated (same object as `rust`).
85
96
  index.ts Barrel (exports rust, createRust, types).
86
97
  shared/ Cross-cutting helpers.
87
- runtime.ts THE ONLY place `typeof Bun` is checked (isBun/isNode).
88
- bytes.ts Shared TextEncoder/Decoder singletons + toPlainBuffer.
89
- packed.ts Packed-wire unpackers (unpackU32Array, packBatch, readPairsPacked, ...).
98
+ runtime.ts Facade over src/runtime/detect.ts (isBun/isNode — cached).
99
+ codec.ts Facade over src/runtime/codec.ts.
100
+ uuid.ts Facade over src/runtime/uuid.ts.
101
+ bytes.ts encoder/decoder (Uint8Array|string union normalization) + toPlainBuffer.
102
+ packed/ Packed wire-format helpers (split from the old packed.ts monolith).
103
+ wire.ts PURE byte encode/decode (u32/bitset/i64/byte-results/multipart, pairs, pack-scratch) — no addon.
104
+ schema.ts SchemaValidator alias + schemaValidateBatch/Count.
105
+ parsers.ts lazy-addon string parsers (parseQueryString/parseCookieHeader/parseFormBody).
106
+ index.ts Barrel (existing `../shared/packed` imports unchanged).
90
107
  request-id.ts Zero-alloc request-id generator (both ingress paths).
91
108
  buffer-pool.ts Generic reusable byte-buffer pool (pooled ingress output).
92
109
  response.ts pooledBodyResponse (releases the pool on body consume).
93
110
  log.ts createStructuredLogger (CASTRUM_LOG_LEVEL-gated JSON lines).
94
- proven.ts PROVEN_SURFACE registry (PURE DATA — no addon imports).
95
111
  ingress/ The HTTP ingress pipeline (two paths — see §4.2).
96
112
  fast.ts PATH 1: createIngressFast (packed-input via handleRequestPacked).
97
113
  handlers.ts PATH 2: createIngressHandler (JS-packs the frame via IngressInputPacker
@@ -130,7 +146,9 @@ rust/ ONE cdylib crate (Cargo [lib] → lib.rs).
130
146
  ingress/ THE ingress pipeline: mod.rs (napi boundary), pipeline.rs (core 8-stage),
131
147
  options/time/packed, cors, proxy, ip_trust, rate_limit, terminal,
132
148
  output.rs (single numeric layout source), ingress_constants.rs (napi projection).
133
- ffi.rs #[no_mangle] extern "C" exports (45 castrum_* symbols) for Bun's bun:ffi
149
+ ffi.rs #[no_mangle] extern "C" exports (79 castrum_* symbols — 71 direct + 4
150
+ validator_c_abi! + 4 compress_to_out!; parity guarded by
151
+ test/unit/features/ffi-symbol-parity.test.ts) for Bun's bun:ffi
134
152
  primary transport, incl. castrum_ingress_layout (the layout blob).
135
153
  unit_tests.rs / test_support.rs Cross-module Rust test suites.
136
154
  ```
@@ -185,22 +203,22 @@ this reason. **Shared between both paths**: `generateRequestId`
185
203
  - `src/native/loader.ts` resolves the `.node` from multiple roots so it works
186
204
  from both the source layout (`src/…`) and the bundled layout (`dist/…`).
187
205
  Honors `CASTRUM_NATIVE_LIBRARY_PATH` / `NAPI_RS_NATIVE_LIBRARY_PATH`.
188
- - Runtime detection lives **only** in `src/shared/runtime.ts`
189
- (`isBun`/`isNode`). `createIngressServer` is Bun-only; Node users use
190
- `createIngressServerNode` (same route handlers via `buildRouteHandlers`).
206
+ - Runtime detection lives **only** in `src/runtime/detect.ts` (resolved once at
207
+ load; `src/shared/runtime.ts` is a thin facade). The public
208
+ `createIngressServer` (via the adapter's `server`) picks `Bun.serve` on Bun
209
+ and the `node:http` backend on Node; `createIngressServerNode` stays for
210
+ pinned Node users (same route handlers via `buildRouteHandlers`).
191
211
  - ⚠️ `src/ingress/constants.ts` is the **one module that dlopens the addon at
192
212
  import time** (its constants are needed as soon as ingress is imported).
193
213
  Everything else is lazy.
194
214
 
195
- ### 4.4 The `proven` performance surface
196
- `src/shared/proven.ts` (`PROVEN_SURFACE`) is the single source of truth for the
197
- per-function performance classifications. It is **pure data** (no addon
198
- imports) so `scripts/check-proven.ts` can audit it without dlopening.
199
- `src/rust-ffi/proven.ts` exposes the FULL `rust.*` surface (nothing is
200
- filtered); each function's JSDoc carries its measured performance vs the JS
201
- baseline, written by `scripts/annotate-performance.ts` (`bun run check:annotate`)
202
- and marked `@deprecated` when slower. `bun run check:proven:fail` (CI) audits
203
- the registry against the CPU benchmark report on a **release** build.
215
+ ### 4.4 The runtime adapter
216
+ `src/runtime/` is the single seam for every Bun-vs-Node and transport decision
217
+ (detection, codec, uuid, env, the BUN_WINS built-in delegation, the bun:ffi-vs-
218
+ napi transport, the ingress server backend, websocket) — selected ONCE at
219
+ module load. The FFI layer imports the seam (`src/runtime/native.ts`); the
220
+ public API imports the full `runtime` (`src/runtime/index.ts`). No
221
+ `isBun()` / `getBunFFI()` branches in builders.
204
222
 
205
223
  ### 4.5 Pooled output buffers (path 2)
206
224
  `createIngressHandler` owns a `BufferPool` (`src/shared/buffer-pool.ts`) sized
@@ -251,9 +269,11 @@ consumed.
251
269
  | Doc | Purpose |
252
270
  |-----|---------|
253
271
  | [`GETTING_STARTED.md`](./GETTING_STARTED.md) | Beginner tutorial (intern-friendly) |
272
+ | [`API.md`](./API.md) | The complete public API reference |
273
+ | [`CASE_STUDY.md`](./CASE_STUDY.md) | Data-driven case study: how castrum was built and measured |
254
274
  | [`ARCHITECTURE.md`](./ARCHITECTURE.md) | Deep-dive: modules, data flow, output layout, memory, concurrency |
255
275
  | [`INGRESS.md`](./INGRESS.md) | The pre-baked ingress API + route factories + servers |
256
276
  | [`BENCHMARKS.md`](./BENCHMARKS.md) | Benchmark scenarios, report format, how to run |
257
277
  | [`ENVIRONMENT.md`](./ENVIRONMENT.md) | All `CASTRUM_*` env vars (+ legacy aliases) |
258
278
  | [`AGENTS.md`](../AGENTS.md) | AI-agent editing guidance (commands, constraints, gotchas) |
259
- | `README.md` | Public-facing quick start + API reference |
279
+ | `README.md` | Public-facing overview + quick start |
@@ -17,7 +17,7 @@ Every overlapping op is **benchmarked against its Bun built-in** before it is
17
17
  built, kept, or delegated. Results live in
18
18
  `docs/bun-builtins-decision-matrix.md`. Rules:
19
19
 
20
- 1. **Delegate to Bun** at the `@flux/native` wrapper layer where Bun wins
20
+ 1. **Delegate to Bun** at the selection/delegation layer where Bun wins
21
21
  clearly: non-crypto hashing (`Bun.hash.crc32` ~3x, `xxHash3` ~4x),
22
22
  gzip (`Bun.gzipSync`/`gunzipSync`), `Bun.randomUUIDv7` (~2x), HMAC
23
23
  (`Bun.CryptoHasher` ~1.2x).
@@ -31,10 +31,11 @@ built, kept, or delegated. Results live in
31
31
 
32
32
  - New `rust.*` primitives ship with a Bun-built-in baseline + decision-matrix
33
33
  entry (`xxh3`, `passwordHashBcrypt`/`verifyBcrypt`, `pbkdf2Sha256`).
34
- - `PROVEN_SURFACE` classifications reflect the Bun/JS baseline honestly
35
- (e.g. `xxh3` is `not-competitive` vs `Bun.hash.xxHash3`).
36
- - Diagnostic benchmark tasks use `diag:` names so they never perturb the
37
- `check:proven` audit.
34
+ - The Bun/JS baselines are recorded honestly in the decision matrix
35
+ (e.g. `xxh3` is measured `Bun.hash.xxHash3` ~4x faster — the public
36
+ `rust.xxh3` delegates to it under Bun via the runtime adapter's `builtins`).
37
+ - Diagnostic benchmark tasks use `diag:` names so they are never mistaken for
38
+ shipped-op `native:`/`rust:` comparisons.
38
39
 
39
40
  ## See also
40
41
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Question this answers**: for the same workload, does a Bun native built-in
4
4
  > beat the castrum Rust op? Where it does, castrum should stop reinventing the
5
- > wheel and `@flux/native` should delegate to Bun; where castrum wins (or Bun
5
+ > wheel and delegate to Bun; where castrum wins (or Bun
6
6
  > has no sync equivalent), the Rust op stands.
7
7
 
8
8
  ## Methodology
@@ -12,9 +12,8 @@
12
12
  shipped profile).
13
13
  - **Driver**: `bun run check` (CPU benchmark → `bench/results/cpu/latest.json`).
14
14
  Each pair runs on the SAME input (fixture payloads, see table).
15
- - **Naming**: diagnostic comparisons use `diag:` task names so
16
- `scripts/check-proven.ts` never aggregates them into a `PROVEN_SURFACE`
17
- entry (see `src/bench/comparisons.ts`).
15
+ - **Naming**: diagnostic comparisons use `diag:` task names so they are kept out
16
+ of the shipped-op `native:`/`rust:` comparisons (see `src/bench/comparisons.ts`).
18
17
  - **Honesty guard**: every Bun API is verified to actually execute real work at
19
18
  runtime before a result is trusted. This is important — the first run
20
19
  produced false "wins" (brotli 156×, validators 3–5×) because this Bun
@@ -56,22 +55,30 @@
56
55
 
57
56
  ## Decisions
58
57
 
59
- ### → Delegate to Bun at the `@flux/native` wrapper layer (Bun wins)
58
+ ### → Delegate to Bun at the selection layer (Bun wins)
60
59
  These rust ops lose to Bun's native implementation on the SAME workload — the
61
60
  FFI crossing cannot beat Bun's in-process C++:
62
61
 
62
+ This table mirrors `BUILTIN_OPS` in `src/runtime/builtins.ts` (the 11 ops that
63
+ delegate to Bun built-ins under Bun; `src/selection.ts` derives from it). `fnv1a64` is parity/either but is NOT delegated
64
+ (`Bun.hash` is wyhash — a different algorithm — and rust `fnv1a64` stays the
65
+ benchmarked impl).
66
+
63
67
  | Op | Recommendation |
64
68
  |---|---|
65
69
  | `crc32` | Prefer `Bun.hash.crc32`; keep rust as fallback (pure-TS path already exists). |
66
- | `xxh3` | Prefer `Bun.hash.xxHash3` (~4×); keep the rust export as the Node/non-Bun fast path. Classified `not-competitive` in `PROVEN_SURFACE`. |
67
- | `gzipCompress` / `gzipDecompress` | Prefer `Bun.gzipSync` / `Bun.gunzipSync`. |
70
+ | `xxh3` | Prefer `Bun.hash.xxHash3` (~4×); keep the rust export as the Node/non-Bun fast path. The runtime adapter delegates the public `rust.xxh3` to Bun under Bun. |
71
+ | `gzipCompress` | Prefer `Bun.gzipSync` (~2×). **`gzipDecompress` is deliberately NOT delegated** — `Bun.gunzipSync` has no decompression-bomb cap; the rust surface keeps its native 64 MiB-capped path under Bun. |
68
72
  | `randomToken` | Prefer `Bun.randomUUIDv7()` (or `crypto.getRandomValues`) for token-sized output; keep rust for byte-precise control. |
69
73
  | `hmacSha256` | Prefer `Bun.CryptoHasher("sha256", key)` (1.17× — mild; keep rust batch path, which wins on larger inputs). |
70
- | `fnv1a64` | Parity — either is fine; `Bun.hash` (wyhash) is a stronger algorithm, prefer it for NEW non-crypto hashing needs. |
74
+ | `urlEncode` / `urlDecode` | Prefer `encodeURIComponent` / `decodeURIComponent` (JSC string builtins — ~11.5×, zero alloc). |
75
+ | `base64Encode` / `base64UrlEncode` | Prefer `Buffer.toString('base64'|'base64url')`. |
76
+ | `hexEncode` | Prefer `Buffer.toString('hex')`. |
77
+ | `httpDate` | Prefer `Date.toUTCString()`. |
71
78
 
72
- **Delegation rule of thumb**: rust stays the default only where it is
73
- `proven` against its **Bun** baseline (not just its JS baseline). These are the
74
- ops where rust genuinely wins or Bun has no equivalent.
79
+ **Delegation rule of thumb**: rust stays the default only where it beats its
80
+ **Bun** baseline (not just its JS baseline). These are the ops where rust
81
+ genuinely wins or Bun has no equivalent.
75
82
 
76
83
  ### → Keep rust (rust wins or Bun has no equivalent)
77
84
  | Op | Rationale |
@@ -83,19 +90,19 @@ ops where rust genuinely wins or Bun has no equivalent.
83
90
  | `validateEmail` / `validateUuid` / `validateIpv4` / `validateIpv6` | `Bun.validators` absent in 1.4; keep rust. Re-check when Bun adds it. |
84
91
  | `jsonValid` / `jsonSumIds` / packed parsers / ingress | No Bun sync equivalent for the zero-DOM / zero-copy semantics; keep rust. |
85
92
 
86
- ### → Add primitives that close gaps (Phase 2)
87
- | Gap | Plan |
93
+ ### → Implemented primitives (gaps closed)
94
+ | Primitive | Outcome |
88
95
  |---|---|
89
- | Public XXH3-64 (`rust.xxh3`) | **Done** — exposed; measured Bun.hash.xxHash3 4.15× faster → classify `not-competitive`, prefer Bun under Bun. |
90
- | bcrypt | **Done** — `rust.passwordHashBcrypt`/`passwordVerifyBcrypt`; hash parity, verify rust 1.49×. |
91
- | PBKDF2 | **Done** — `rust.pbkdf2Sha256`; parity with node:crypto, only sync option in Bun. |
92
- | UUIDv7 | `Bun.randomUUIDv7` already wins — **do not** build a rust UUIDv7; use Bun. |
96
+ | `rust.xxh3` (XXH3-64) | Exposed; measured `Bun.hash.xxHash3` 4.15× faster → the runtime adapter delegates the public `rust.xxh3` to Bun under Bun (Node keeps the addon). |
97
+ | `rust.passwordHashBcrypt` / `rust.passwordVerifyBcrypt` | bcrypt `$2b$` PHC; hash parity, verify rust 1.49×. |
98
+ | `rust.pbkdf2Sha256` | PBKDF2-HMAC-SHA256; parity with `node:crypto`, the only sync option in Bun. |
99
+ | UUIDv7 (`uuidv7()`) | `Bun.randomUUIDv7` already wins — delegated to Bun (`crypto.randomUUID` on Node), not built in Rust. |
93
100
 
94
101
  ## Summary
95
102
 
96
103
  **The "don't reinvent the wheel" takeaway:** for non-cryptographic hashing,
97
104
  random tokens, and gzip, Bun 1.4's built-ins are already faster than any
98
- FFI-crossing Rust op — `@flux/native` should prefer them. Rust retains a clear,
105
+ FFI-crossing Rust op — the selection layer should prefer them. Rust retains a clear,
99
106
  defensible moat exactly where it matters: **argon2id password hashing
100
107
  (≈1.9× vs Bun)**, the **zero-DOM / zero-copy parsers and JSON paths** (no Bun
101
108
  sync equivalent), and **brotli** (no Bun sync API).
package/index.ts CHANGED
@@ -1,9 +1,15 @@
1
1
  // index.ts — castrum package entry (barrel).
2
2
  //
3
3
  // Re-exports the full public API: the flat `rust.*` FFI surface
4
- // (src/rust-ffi), the runtime selection hints (src/selection), the
5
- // performance-proven registry (src/shared/proven), and the higher-order
6
- // loader (src/loader). See AGENTS.md for the layout map.
4
+ // (src/rust-ffi), the runtime selection hints (src/selection), and the
5
+ // higher-order loader (src/loader). See AGENTS.md for the layout map.
6
+ //
7
+ // EAGER-DLOPEN CONTRACT: this barrel unconditionally re-exports `src/ingress`
8
+ // → `src/ingress/constants.ts`, which is the ONE module that touches native at
9
+ // import time (it reads the Rust binary layout and runs the bind-time
10
+ // self-test). This is intentional — even `import { rust }` pays the eager
11
+ // load. Do NOT add more eager-native modules; keep everything else lazy (see
12
+ // test/unit/features/import-contract.test.ts).
7
13
 
8
14
  export * from './src/rust-ffi'
9
15
 
@@ -15,19 +21,6 @@ export * from './src/rust-ffi'
15
21
  export { opImpl, isNativeOp, opDecision } from './src/selection'
16
22
  export type { OpImpl, OpDecision } from './src/selection'
17
23
 
18
- // Performance-proven surface: only `rust.*` functions that beat their JS
19
- // baseline in benchmarks. See src/shared/proven.ts for the registry.
20
- export {
21
- proven,
22
- PROVEN_SURFACE,
23
- provenStatus,
24
- isProven,
25
- provenSurface,
26
- provenSummary,
27
- } from './src/rust-ffi/proven'
28
- export type { ProvenClient, ProvenKey } from './src/rust-ffi/proven'
29
- export type { PerformanceStatus, ProvenEntry } from './src/shared/proven'
30
-
31
24
  export { encoder, decoder } from './src/shared/bytes'
32
25
  // Bounded EWMA adaptive-estimate utility (drives BufferPool adaptive sizing
33
26
  // and reusable runtime self-optimization decisions).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "castrum",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "private": false,
5
5
  "description": "Enterprise-grade Bun + Rust runtime: Rust-accelerated FFI primitives, a production-grade HTTP ingress pipeline, validation, hashing, and JSON processing with benchmark-grade performance.",
6
6
  "type": "module",
@@ -25,6 +25,10 @@
25
25
  "type": "git",
26
26
  "url": "git+https://github.com/Axylabs/flux-rs.git"
27
27
  },
28
+ "homepage": "https://github.com/Axylabs/flux-rs#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/Axylabs/flux-rs/issues"
31
+ },
28
32
  "publishConfig": {
29
33
  "access": "public"
30
34
  },
@@ -45,18 +49,21 @@
45
49
  "README.md",
46
50
  "*.node",
47
51
  "!src/bench",
48
- "!src/baseline"
52
+ "!src/baseline",
53
+ "!src/data"
49
54
  ],
50
55
  "scripts": {
51
56
  "build": "napi build --release --platform",
52
57
  "build:perf": "bash scripts/build-perf.sh",
58
+ "build:v3": "bash scripts/build-v3.sh",
59
+ "build:all": "bun run build && bun run build:v3",
53
60
  "build:js": "bun run build:js:bundle && bun run build:js:types",
54
61
  "build:js:bundle": "bun build ./index.ts --target=node --format=esm --outdir=dist",
55
62
  "build:js:types": "dts-bundle-generator -o dist/index.d.ts index.ts",
56
63
  "bench": "bun run build && bun bench.ts",
57
64
  "check": "bun bench.ts",
58
65
  "test": "bun test",
59
- "test:all": "bun test && bun run typecheck && bun run typecheck:test && bun run lint:ci && cargo test --lib",
66
+ "test:all": "bun test && bun run typecheck && bun run typecheck:test && bun run lint:ci && bun run check:clean && cargo test --lib",
60
67
  "test:coverage": "node scripts/check-coverage.mjs",
61
68
  "setup": "bun install && bun run build",
62
69
  "test:node": "node --test test/integration/node-smoke.test.mjs test/integration/node-enterprise.test.mjs",
@@ -72,38 +79,42 @@
72
79
  "deny": "cargo deny check",
73
80
  "check:version": "bun scripts/check-version.mjs",
74
81
  "check:jsdoc": "bun scripts/check-jsdoc.ts",
82
+ "check:selection": "bun scripts/select-native.ts --check",
83
+ "check:clean": "bun scripts/check-clean.ts",
75
84
  "audit": "bun audit",
76
85
  "publish:manual": "node scripts/publish-manual.mjs",
77
86
  "publish:manual:dry": "node scripts/publish-manual.mjs --dry-run",
78
87
  "prepublishOnly": "bun run build:js && node scripts/prepublish.mjs",
79
- "check:proven": "bun scripts/check-proven.ts",
80
- "check:proven:fail": "bun scripts/check-proven.ts --fail",
81
- "check:annotate": "bun scripts/annotate-performance.ts",
82
- "check:annotate:dry": "bun scripts/annotate-performance.ts --dry-run",
83
- "check:docs": "bun run check && bun run check:annotate && bun run check:proven",
84
- "bench:http": "bun run bench/run-bench.ts",
85
- "bench:http:smoke": "bun run bench/run-bench.ts smoke",
86
- "bench:http:stress": "bun run bench/run-bench.ts stress",
87
- "bench:http:heavy": "bun run bench/run-bench.ts heavy-json",
88
- "bench:http:crud": "bun run bench/run-bench.ts crud",
89
- "bench:http:spike": "bun run bench/run-bench.ts spike",
90
- "bench:http:soak": "bun run bench/run-bench.ts soak",
91
- "bench:http:storm": "bun run bench/run-bench.ts storm",
92
- "bench:http:boundary": "bun run bench/run-bench.ts boundary",
93
- "bench:http:elysia": "bun run bench/run-bench.ts '' elysia",
94
- "bench:http:ingress": "bun run bench/run-bench.ts '' ingress",
95
- "bench:http:bun-only": "bun run bench/run-bench.ts '' bun",
96
- "bench:http:all-heavy": "bun run bench/run-bench.ts 1",
88
+ "bench:http": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts",
89
+ "bench:http:smoke": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts smoke",
90
+ "bench:http:stress": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts stress",
91
+ "bench:http:heavy": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts heavy-json",
92
+ "bench:http:crud": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts crud",
93
+ "bench:http:spike": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts spike",
94
+ "bench:http:soak": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts soak",
95
+ "bench:http:storm": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts storm",
96
+ "bench:http:boundary": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts boundary",
97
+ "bench:http:elysia": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts '' elysia",
98
+ "bench:http:ingress": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts '' ingress",
99
+ "bench:http:bun-only": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts '' bun",
100
+ "bench:http:all-heavy": "BUN_CONFIG_MAX_HTTP_REQUESTS=65536 bun run bench/run-bench.ts 1",
101
+ "bench:http:ac": "bun bench/autocannon-stress.mjs",
102
+ "bench:http:stress:ac": "SCENARIO=03-stress bun bench/autocannon-stress.mjs",
97
103
  "bench:startup": "bun run bench/startup.ts",
104
+ "bench:load": "bun run bench/load-phase.ts",
98
105
  "bench:ffi": "bun run bench/ffi-all.ts",
99
106
  "bench:ffi:load": "bun run bench/ffi-load.ts",
100
107
  "bench:ffi:public": "bun run bench/ffi-public.ts",
101
108
  "bench:ffi:workers": "bun run bench/ffi-workers.ts",
109
+ "bench:margin": "bun run bench/ffi-margin.ts",
110
+ "bench:router": "bun run bench/router-cost.ts",
111
+ "bench:ingress-cost": "bun run bench/ingress-cost.ts",
112
+ "bench:ingress-cost:post": "bun run bench/ingress-cost-post.ts",
102
113
  "verify:native:batch": "bun run scripts/verify-native-batch.ts"
103
114
  },
104
115
  "dependencies": {},
105
116
  "peerDependencies": {
106
- "@types/node": ">=20"
117
+ "@types/node": "^26.1.2"
107
118
  },
108
119
  "peerDependenciesMeta": {
109
120
  "@types/node": {
@@ -112,14 +123,15 @@
112
123
  },
113
124
  "devDependencies": {
114
125
  "@elysia/cors": "^1.4.2",
115
- "@napi-rs/cli": "^3.7.4",
126
+ "@napi-rs/cli": "^3.8.6",
116
127
  "@types/bun": "^1.3.14",
117
128
  "@types/mime-types": "^3.0.1",
129
+ "autocannon": "^8.0.0",
118
130
  "@types/validator": "^13.15.10",
119
131
  "ajv": "^8.20.0",
120
132
  "crc-32": "^1.2.2",
121
133
  "dts-bundle-generator": "^9.5.1",
122
- "elysia": "^1.4.0",
134
+ "elysia": "^1.4.29",
123
135
  "fast-json-patch": "^3.1.1",
124
136
  "mime-types": "^3.0.2",
125
137
  "typescript": "5.9.3",