castrum 0.9.1 → 0.9.2

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 (49) hide show
  1. package/README.md +1 -1
  2. package/castrum.linux-x64-gnu.node +0 -0
  3. package/dist/index.d.ts +239 -5
  4. package/dist/index.js +3852 -3375
  5. package/docs/ARCHITECTURE.md +11 -9
  6. package/docs/BENCHMARKS.md +70 -38
  7. package/docs/CASE_STUDY.md +10 -7
  8. package/docs/ENVIRONMENT.md +16 -1
  9. package/docs/FFI_BUN_GUIDE.md +18 -10
  10. package/docs/GETTING_STARTED.md +5 -4
  11. package/docs/HOW_TO_ADD_AN_OP.md +180 -0
  12. package/docs/INGRESS-ROUTER.md +3 -2
  13. package/docs/INGRESS.md +6 -3
  14. package/docs/NATIVE-ROUTE.md +28 -4
  15. package/docs/REPO_MAP.md +60 -30
  16. package/docs/adr/0001-two-wire-formats.md +1 -1
  17. package/docs/ai/LOCAL_DEV.md +81 -0
  18. package/docs/ai/TREE.md +1070 -0
  19. package/package.json +24 -23
  20. package/src/ingress/decode/result-base.ts +10 -2
  21. package/src/ingress/handlers.ts +45 -290
  22. package/src/ingress/headers/security.ts +41 -0
  23. package/src/ingress/index.ts +12 -148
  24. package/src/ingress/native-route.ts +182 -0
  25. package/src/ingress/packing/gather-raw-headers.ts +26 -2
  26. package/src/ingress/packing/route-wire.ts +197 -0
  27. package/src/ingress/packing/select-headers.ts +8 -1
  28. package/src/ingress/path-matcher.ts +115 -0
  29. package/src/ingress/response/baked-response.ts +302 -0
  30. package/src/ingress/router.ts +42 -2
  31. package/src/ingress/routes/common.ts +9 -1
  32. package/src/ingress/routes/json-write.ts +21 -18
  33. package/src/ingress/routes/native.ts +130 -0
  34. package/src/ingress/server-node.ts +1 -1
  35. package/src/ingress/server.ts +38 -99
  36. package/src/ingress/sync.ts +151 -0
  37. package/src/ingress/types.ts +9 -0
  38. package/src/native/ffi/build/codecs.ts +736 -0
  39. package/src/native/ffi/build/compress.ts +248 -0
  40. package/src/native/ffi/build/instances.ts +598 -0
  41. package/src/native/ffi/build/parse.ts +539 -0
  42. package/src/native/ffi/build/util.ts +140 -0
  43. package/src/native/ffi/build.ts +94 -0
  44. package/src/native/ffi/selftest.ts +11 -718
  45. package/src/native/ffi/types.ts +25 -0
  46. package/src/native/ffi.ts +36 -1320
  47. package/src/native/types/instances.ts +5 -0
  48. package/src/rust-ffi/packed.ts +38 -0
  49. package/src/rust-ffi/scalar/factories.ts +4 -0
@@ -0,0 +1,94 @@
1
+ // src/native/ffi/build.ts — the `build()` orchestrator for the BunFFI surface.
2
+ //
3
+ // `build(sym, useBufferLength)` sets up the shared per-bind state — the
4
+ // probe-gated `lenOrView`/`oneArg` argument adapters and the pooled scratch
5
+ // buffers — then delegates to the four domain builders (each receives the raw
6
+ // dlopen'd symbols + this context) and merges their method objects into the
7
+ // final `BunFFI`. Extracted from the former monolithic `ffi.ts` so the
8
+ // per-call wrapper surface is navigable by domain:
9
+ // - `build/codecs.ts` hashing / codec / crypto / auth / ws-key / etag
10
+ // - `build/compress.ts` gzip / brotli / json patch
11
+ // - `build/parse.ts` packed parsers / media-type / http-date / sse
12
+ // - `build/instances.ts` opaque-handle evals + ingress + route stack
13
+
14
+ import { buildCodecs } from './build/codecs'
15
+ import { buildCompress } from './build/compress'
16
+ import { buildInstances } from './build/instances'
17
+ import { buildParse } from './build/parse'
18
+ import type { BuildCtx } from './build/util'
19
+ import type { BunFFI } from './types'
20
+
21
+ /**
22
+ * Assemble the `BunFFI` surface from the raw dlopen'd symbols.
23
+ *
24
+ * @param sym The `symbols` object from `dlopen(path, {...})`.
25
+ * @param useBufferLength `true` when the engine's `buffer`/`buffer_length`
26
+ * ABI pair is live (see the probe in `ffi.ts`).
27
+ */
28
+ export function build(
29
+ sym: Record<string, (...a: unknown[]) => unknown>,
30
+ useBufferLength: boolean,
31
+ ): BunFFI {
32
+ // Single-buffer input fns: with the probe-gated `buffer/buffer_length` ABI the
33
+ // engine reads ptr + byteLength off the SAME TypedArray at call time (an
34
+ // atomic snapshot — pass the view twice, per Bun's docs); with `(ptr,len)` we
35
+ // pass the length explicitly. The branch is on a bind-time constant, so the
36
+ // JIT folds it away at the call site.
37
+ const oneArg = (raw: (...a: unknown[]) => number | bigint, v: Uint8Array): number | bigint =>
38
+ useBufferLength ? raw(v, v) : raw(v, v.length)
39
+ // Phase 1.1: under `buffer`/`buffer_length` the engine reads ptr + byteLength
40
+ // off the SAME view, so every `(ptr,len)` pair passes the view itself for the
41
+ // length slot (atomic snapshot, one JS arg fewer); under `(ptr,usize)` it's
42
+ // the explicit length. The branch is a bind-time constant → JIT folds it.
43
+ const lenOrView = (v: Uint8Array): Uint8Array | number => (useBufferLength ? v : v.length)
44
+
45
+ // ── Reusable scratch for the STRING-returning encode wrappers ────────
46
+ // Each wrapper writes its result and decodes it into an immutable JS string
47
+ // (or primitive) SYNCHRONOUSLY before the next call reuses the buffer — the
48
+ // same safety rationale as `jsonSumOut` / `generateRequestId`. Per-Worker
49
+ // module state (single-threaded event loop); never shared across Workers.
50
+ // NOT used for byte-returning ops (hexDecode/urlDecode/base64Decode/aead/
51
+ // wsFrame/packed parsers): their returned `Uint8Array` aliases the buffer
52
+ // and escapes to the caller — those stay on `*Into` (caller-owned).
53
+ let encodeScratch = new Uint8Array(0)
54
+ const scratchFor = (size: number): Uint8Array => {
55
+ if (encodeScratch.byteLength < size) encodeScratch = new Uint8Array(size)
56
+ return encodeScratch
57
+ }
58
+ // Pooled 9-byte scratch for jsonSumIds (the packed `[u8 ok][i64 sum LE]`
59
+ // output). The wrapper returns the BigInt VALUE (no byte aliasing escapes),
60
+ // so a single reused buffer + cached DataView is safe — removes the per-call
61
+ // Uint8Array + DataView allocs (measured ~400ns of the FFI wrapper cost).
62
+ const jsonSumOut = new Uint8Array(9)
63
+ const jsonSumView = new DataView(jsonSumOut.buffer)
64
+ // Fixed-size packed-verdict scratch + cached DataViews (parseHttpDate 9 B,
65
+ // rate-limit check 13 B) — same pooled pattern as `jsonSumView`. Kept
66
+ // separate from the growable `encodeScratch` so the cached DataViews are
67
+ // never invalidated by a buffer replacement.
68
+ const dateScratch = new Uint8Array(9)
69
+ const dateScratchView = new DataView(dateScratch.buffer)
70
+ const rateScratch = new Uint8Array(13)
71
+ const rateScratchView = new DataView(rateScratch.buffer)
72
+
73
+ const ctx: BuildCtx = {
74
+ useBufferLength,
75
+ lenOrView,
76
+ oneArg,
77
+ scratchFor,
78
+ jsonSumOut,
79
+ jsonSumView,
80
+ dateScratch,
81
+ dateScratchView,
82
+ rateScratch,
83
+ rateScratchView,
84
+ }
85
+
86
+ // Merge the domain surfaces. Each builder's method bodies are verbatim from
87
+ // the original single return object; the cast asserts the merged shape.
88
+ return {
89
+ ...buildCodecs(sym, ctx),
90
+ ...buildCompress(sym, ctx),
91
+ ...buildParse(sym, ctx),
92
+ ...buildInstances(sym, ctx),
93
+ } as BunFFI
94
+ }