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.
- package/README.md +153 -630
- package/castrum.linux-x64-gnu.node +0 -0
- package/dist/index.d.ts +1374 -1772
- package/dist/index.js +5570 -4169
- package/docs/API.md +337 -0
- package/docs/ARCHITECTURE.md +106 -14
- package/docs/BENCHMARKS.md +83 -47
- package/docs/CASE_STUDY.md +240 -0
- package/docs/ENVIRONMENT.md +8 -6
- package/docs/FFI_BUN_GUIDE.md +327 -0
- package/docs/GETTING_STARTED.md +15 -32
- package/docs/INGRESS-ROUTER.md +81 -0
- package/docs/INGRESS.md +5 -4
- package/docs/NATIVE-ROUTE.md +53 -0
- package/docs/REPO_MAP.md +46 -26
- package/docs/adr/0003-bun-builtins-delegation.md +6 -5
- package/docs/bun-builtins-decision-matrix.md +25 -18
- package/index.ts +9 -16
- package/package.json +36 -24
- package/src/ingress/body.ts +167 -27
- package/src/ingress/handlers.ts +91 -15
- package/src/ingress/health.ts +1 -0
- package/src/ingress/index.ts +39 -27
- package/src/ingress/packing/gather-raw-headers.ts +85 -21
- package/src/ingress/packing/header-packing.ts +5 -5
- package/src/ingress/packing/input-packer.ts +17 -3
- package/src/ingress/packing/select-headers.ts +12 -6
- package/src/ingress/router.ts +237 -0
- package/src/ingress/routes/common.ts +42 -1
- package/src/ingress/routes/fallback.ts +2 -2
- package/src/ingress/routes/head.ts +3 -13
- package/src/ingress/routes/index.ts +5 -4
- package/src/ingress/routes/json-write.ts +7 -31
- package/src/ingress/routes/options.ts +2 -12
- package/src/ingress/routes/read.ts +3 -13
- package/src/ingress/routes/responder.ts +159 -0
- package/src/ingress/server-node.ts +6 -6
- package/src/ingress/server.ts +45 -13
- package/src/ingress/types.ts +35 -1
- package/src/integration/pipeline.ts +3 -0
- package/src/integration/streaming.ts +2 -3
- package/src/integration/websocket.ts +4 -3
- package/src/loader/batch.ts +4 -0
- package/src/loader/cost.ts +1 -0
- package/src/loader/index.ts +43 -228
- package/src/loader/state.ts +84 -0
- package/src/loader/types.ts +145 -0
- package/src/native/ffi/constants.ts +58 -0
- package/src/native/ffi/selftest.ts +729 -0
- package/src/native/ffi/types.ts +474 -0
- package/src/native/ffi.ts +1063 -829
- package/src/native/loader.ts +52 -6
- package/src/native/types/instances.ts +274 -0
- package/src/native/types.ts +41 -238
- package/src/runtime/builtins.ts +131 -0
- package/src/runtime/codec.ts +147 -0
- package/src/runtime/detect.ts +36 -0
- package/src/runtime/index.ts +28 -0
- package/src/runtime/native.ts +35 -0
- package/src/runtime/server.ts +31 -0
- package/src/runtime/transport.ts +64 -0
- package/src/runtime/types.ts +173 -0
- package/src/runtime/uuid.ts +45 -0
- package/src/runtime/websocket.ts +30 -0
- package/src/rust-ffi/addon.ts +1 -1
- package/src/rust-ffi/batch/build.ts +155 -0
- package/src/rust-ffi/batch/index.ts +8 -0
- package/src/rust-ffi/batch/types.ts +92 -0
- package/src/rust-ffi/client.ts +5 -6
- package/src/rust-ffi/context.ts +39 -10
- package/src/rust-ffi/index.ts +28 -17
- package/src/rust-ffi/into.ts +21 -0
- package/src/rust-ffi/options.ts +1 -1
- package/src/rust-ffi/packed.ts +2 -2
- package/src/rust-ffi/proven.ts +16 -30
- package/src/rust-ffi/scalar/crypto.ts +188 -107
- package/src/rust-ffi/scalar/factories.ts +253 -27
- package/src/rust-ffi/scalar/hashing.ts +43 -41
- package/src/rust-ffi/scalar/http.ts +208 -77
- package/src/rust-ffi/scalar/index.ts +3 -3
- package/src/rust-ffi/scalar/interface.ts +88 -213
- package/src/rust-ffi/scalar/json-packed.ts +175 -0
- package/src/rust-ffi/scalar/json.ts +28 -12
- package/src/rust-ffi/scalar/payload.ts +159 -42
- package/src/rust-ffi/text.ts +31 -5
- package/src/selection.ts +27 -31
- package/src/shared/adaptive.ts +1 -2
- package/src/shared/buffer-pool.ts +72 -17
- package/src/shared/bytes.ts +75 -6
- package/src/shared/codec.ts +78 -0
- package/src/shared/env.ts +4 -4
- package/src/shared/log.ts +1 -0
- package/src/shared/packed/index.ts +10 -0
- package/src/shared/packed/parsers.ts +31 -0
- package/src/shared/packed/schema.ts +23 -0
- package/src/shared/{packed.ts → packed/wire.ts} +31 -39
- package/src/shared/proven.ts +189 -496
- package/src/shared/runtime.ts +20 -25
- package/src/shared/uuid.ts +12 -28
- package/src/data/json-rows.ts +0 -33
- package/src/rust-ffi/batch.ts +0 -431
- 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
|
|
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,
|
|
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
|
|
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 /
|
|
81
|
-
|
|
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
|
|
88
|
-
|
|
89
|
-
|
|
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 (
|
|
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/
|
|
189
|
-
|
|
190
|
-
`
|
|
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
|
|
196
|
-
`src/
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
`src/
|
|
200
|
-
|
|
201
|
-
|
|
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
|
|
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
|
|
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
|
-
-
|
|
35
|
-
(e.g. `xxh3` is
|
|
36
|
-
|
|
37
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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.
|
|
67
|
-
| `gzipCompress`
|
|
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
|
-
| `
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
### →
|
|
87
|
-
|
|
|
93
|
+
### → Implemented primitives (gaps closed)
|
|
94
|
+
| Primitive | Outcome |
|
|
88
95
|
|---|---|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
| UUIDv7 | `Bun.randomUUIDv7` already wins —
|
|
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 —
|
|
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
|
-
//
|
|
6
|
-
//
|
|
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.
|
|
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
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"bench:http": "bun run bench/run-bench.ts",
|
|
85
|
-
"bench:http:
|
|
86
|
-
"bench:http:
|
|
87
|
-
"bench:http:
|
|
88
|
-
"bench:http:
|
|
89
|
-
"bench:http:
|
|
90
|
-
"bench:http:
|
|
91
|
-
"bench:http:
|
|
92
|
-
"bench:http:
|
|
93
|
-
"bench:http:
|
|
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": "
|
|
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.
|
|
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.
|
|
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",
|