castrum 0.7.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/LICENSE +21 -0
- package/README.md +154 -368
- package/castrum.linux-x64-gnu.node +0 -0
- package/dist/index.d.ts +2763 -0
- package/dist/index.js +8707 -0
- package/docs/API.md +337 -0
- package/docs/ARCHITECTURE.md +507 -0
- package/docs/BENCHMARKS.md +343 -0
- package/docs/CASE_STUDY.md +240 -0
- package/docs/ENVIRONMENT.md +81 -0
- package/docs/FFI_BUN_GUIDE.md +327 -0
- package/docs/GETTING_STARTED.md +192 -0
- package/docs/INGRESS-ROUTER.md +81 -0
- package/docs/INGRESS.md +746 -0
- package/docs/NATIVE-ROUTE.md +53 -0
- package/docs/REPO_MAP.md +279 -0
- package/docs/adr/0001-two-wire-formats.md +39 -0
- package/docs/adr/0002-zero-dom-fast-schema.md +38 -0
- package/docs/adr/0003-bun-builtins-delegation.md +43 -0
- package/docs/bun-builtins-decision-matrix.md +115 -0
- package/index.ts +44 -8
- package/package.json +98 -33
- package/src/ingress/body.ts +289 -0
- package/src/ingress/constants.ts +220 -48
- package/src/ingress/context.ts +136 -0
- package/src/ingress/decode/baked-result.ts +121 -0
- package/src/ingress/decode/fast-result.ts +160 -0
- package/src/ingress/decode/packed-sections.ts +56 -0
- package/src/ingress/decode/result-base.ts +172 -0
- package/src/ingress/errors.ts +72 -0
- package/src/ingress/fast.ts +152 -1021
- package/src/ingress/handlers.ts +639 -1001
- package/src/ingress/headers/baked-templates.ts +102 -0
- package/src/ingress/headers/cors.ts +44 -0
- package/src/ingress/headers/fast-templates.ts +238 -0
- package/src/ingress/headers/hsts.ts +83 -0
- package/src/ingress/health.ts +68 -0
- package/src/ingress/index.ts +142 -405
- package/src/ingress/metrics.ts +132 -0
- package/src/ingress/options.ts +197 -0
- package/src/ingress/packing/gather-raw-headers.ts +139 -0
- package/src/ingress/packing/header-packing.ts +75 -0
- package/src/ingress/packing/input-packer.ts +164 -0
- package/src/ingress/packing/scratch.ts +50 -0
- package/src/ingress/packing/select-headers.ts +102 -0
- package/src/ingress/response/error-bodies.ts +75 -0
- package/src/ingress/response/terminal.ts +59 -0
- package/src/ingress/router.ts +237 -0
- package/src/ingress/routes/common.ts +79 -0
- package/src/ingress/routes/delete.ts +14 -0
- package/src/ingress/routes/echo.ts +107 -0
- package/src/ingress/routes/fallback.ts +23 -0
- package/src/ingress/routes/head.ts +27 -0
- package/src/ingress/routes/index.ts +11 -0
- package/src/ingress/routes/json-write.ts +129 -0
- package/src/ingress/routes/options.ts +26 -0
- package/src/ingress/routes/read.ts +35 -0
- package/src/ingress/routes/responder.ts +159 -0
- package/src/ingress/server-node.ts +376 -0
- package/src/ingress/server.ts +475 -0
- package/src/ingress/shared.ts +132 -0
- package/src/ingress/status.ts +97 -0
- package/src/ingress/types.ts +191 -0
- package/src/integration/batch.ts +58 -0
- package/src/integration/index.ts +29 -0
- package/src/integration/pipeline.ts +220 -0
- package/src/integration/streaming.ts +78 -0
- package/src/integration/websocket.ts +93 -0
- package/src/loader/batch.ts +137 -0
- package/src/loader/cost.ts +105 -0
- package/src/loader/index.ts +745 -0
- package/src/loader/ops.ts +657 -0
- 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 +1775 -0
- package/src/native/index.ts +8 -207
- package/src/native/loader.ts +240 -0
- package/src/native/types/instances.ts +274 -0
- package/src/native/types.ts +401 -0
- 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 +10 -0
- 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 +87 -0
- package/src/rust-ffi/context.ts +193 -0
- package/src/rust-ffi/index.ts +51 -541
- package/src/rust-ffi/into.ts +21 -0
- package/src/rust-ffi/options.ts +113 -0
- package/src/rust-ffi/packed.ts +253 -0
- package/src/rust-ffi/proven.ts +28 -0
- package/src/rust-ffi/scalar/crypto.ts +346 -0
- package/src/rust-ffi/scalar/factories.ts +459 -0
- package/src/rust-ffi/scalar/hashing.ts +74 -0
- package/src/rust-ffi/scalar/http.ts +337 -0
- package/src/rust-ffi/scalar/index.ts +31 -0
- package/src/rust-ffi/scalar/interface.ts +325 -0
- package/src/rust-ffi/scalar/json-packed.ts +175 -0
- package/src/rust-ffi/scalar/json.ts +61 -0
- package/src/rust-ffi/scalar/payload.ts +241 -0
- package/src/rust-ffi/text.ts +121 -0
- package/src/selection.json +194 -0
- package/src/selection.ts +73 -0
- package/src/shared/adaptive.ts +67 -0
- package/src/shared/buffer-pool.ts +264 -0
- package/src/shared/bytes.ts +108 -9
- package/src/shared/codec.ts +78 -0
- package/src/shared/env.ts +20 -0
- package/src/shared/log.ts +75 -0
- package/src/shared/metrics.ts +247 -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/wire.ts +504 -0
- package/src/shared/proven.ts +289 -0
- package/src/shared/request-id.ts +67 -0
- package/src/shared/response.ts +104 -0
- package/src/shared/runtime.ts +29 -0
- package/src/shared/trace.ts +81 -0
- package/src/shared/uuid.ts +15 -0
- package/Cargo.toml +0 -73
- package/bench.ts +0 -3
- package/rust/batch.rs +0 -195
- package/rust/cookie_parser.rs +0 -70
- package/rust/cors.rs +0 -263
- package/rust/hashing.rs +0 -164
- package/rust/headers.rs +0 -234
- package/rust/hmac_sha256.rs +0 -113
- package/rust/http_parser.rs +0 -132
- package/rust/ingress.rs +0 -616
- package/rust/ingress_constants.rs +0 -89
- package/rust/ip_trust.rs +0 -185
- package/rust/json_ops.rs +0 -66
- package/rust/json_patch_ops.rs +0 -25
- package/rust/json_schema.rs +0 -151
- package/rust/json_ser.rs +0 -429
- package/rust/lib.rs +0 -48
- package/rust/method.rs +0 -141
- package/rust/mime_lookup.rs +0 -76
- package/rust/output.rs +0 -238
- package/rust/proxy.rs +0 -90
- package/rust/query_parser.rs +0 -141
- package/rust/random_token.rs +0 -52
- package/rust/rate_limit.rs +0 -203
- package/rust/terminal.rs +0 -95
- package/rust/unit_tests.rs +0 -843
- package/rust/url_codec.rs +0 -133
- package/rust/util.rs +0 -537
- package/rust/validation.rs +0 -107
- package/rust/websocket.rs +0 -23
- package/src/baseline/index.ts +0 -12
- package/src/baseline/tasks/cookie.ts +0 -22
- package/src/baseline/tasks/hashing.ts +0 -18
- package/src/baseline/tasks/hmac.ts +0 -38
- package/src/baseline/tasks/http.ts +0 -62
- package/src/baseline/tasks/json-patch.ts +0 -12
- package/src/baseline/tasks/json.ts +0 -50
- package/src/baseline/tasks/mime.ts +0 -5
- package/src/baseline/tasks/query.ts +0 -14
- package/src/baseline/tasks/token.ts +0 -15
- package/src/baseline/tasks/url.ts +0 -11
- package/src/baseline/tasks/validation.ts +0 -19
- package/src/baseline/tasks/websocket.ts +0 -14
- package/src/bench/assert.ts +0 -70
- package/src/bench/checks.ts +0 -227
- package/src/bench/checksum.ts +0 -27
- package/src/bench/comparisons.ts +0 -70
- package/src/bench/concurrent-worker.ts +0 -135
- package/src/bench/fixtures.ts +0 -233
- package/src/bench/index.ts +0 -2
- package/src/bench/measure.ts +0 -177
- package/src/bench/now.ts +0 -3
- package/src/bench/report.ts +0 -79
- package/src/bench/run.ts +0 -57
- package/src/bench/tasks/complex.ts +0 -232
- package/src/bench/tasks/concurrent.ts +0 -213
- package/src/bench/tasks/cookie.ts +0 -44
- package/src/bench/tasks/hashing.ts +0 -33
- package/src/bench/tasks/hmac.ts +0 -36
- package/src/bench/tasks/http.ts +0 -50
- package/src/bench/tasks/index.ts +0 -52
- package/src/bench/tasks/json-patch.ts +0 -21
- package/src/bench/tasks/json.ts +0 -33
- package/src/bench/tasks/mime.ts +0 -21
- package/src/bench/tasks/query.ts +0 -44
- package/src/bench/tasks/stress.ts +0 -142
- package/src/bench/tasks/token.ts +0 -20
- package/src/bench/tasks/url.ts +0 -34
- package/src/bench/tasks/validation.ts +0 -57
- package/src/bench/tasks/websocket.ts +0 -21
- package/src/bench/types.ts +0 -60
- package/src/data/json-rows.ts +0 -33
- package/src/ingress/packed-input.ts +0 -59
- package/src/shared/json.ts +0 -18
- package/src/shared/packed.ts +0 -316
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
# Architecture Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
castrum is a **hybrid Bun + Rust** runtime benchmark package that provides high-performance backend primitives through a native bridge with **two transports**: `bun:ffi` (the C-ABI fast path, PRIMARY under Bun) and NAPI via napi-rs (the fallback — Node, forced `CASTRUM_FFI_MODE=napi`, or a failed ffi self-test). The architecture is designed for zero-copy data transfer between TypeScript and Rust, with batching support for high-throughput scenarios.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Two-Layer Architecture
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
13
|
+
│ TypeScript Layer │
|
|
14
|
+
│ │
|
|
15
|
+
│ Purpose: API ergonomics, runtime safety, async handling │
|
|
16
|
+
│ Runtime: Bun (JavaScriptCore) │
|
|
17
|
+
│ Pattern: Factory functions, lazy evaluation, batching │
|
|
18
|
+
└──────────↕ Native Bridge: bun:ffi (Bun, primary) + NAPI (fallback) ↕──────────┘
|
|
19
|
+
│ │
|
|
20
|
+
│ Rust Layer (cdylib) │
|
|
21
|
+
│ │
|
|
22
|
+
│ Purpose: Performance-critical computation, I/O handling │
|
|
23
|
+
│ Allocator: mimalloc (global) │
|
|
24
|
+
│ Pattern: Stateless functions, pre-allocated buffers │
|
|
25
|
+
└─────────────────────────────────────────────────────────────┘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Native Bridge (two transports)
|
|
29
|
+
|
|
30
|
+
The bridge between TypeScript and Rust has **two transports**, both loading the SAME
|
|
31
|
+
cdylib (built with napi-rs):
|
|
32
|
+
|
|
33
|
+
- **`bun:ffi` (PRIMARY on Bun)** — `src/native/ffi.ts` `dlopen`s the addon's
|
|
34
|
+
`extern "C"` exports (`rust/ffi.rs`, 79 `castrum_*` symbols — 71 direct + 4
|
|
35
|
+
`validator_c_abi!` + 4 `compress_to_out!`, parity guarded by
|
|
36
|
+
`test/unit/features/ffi-symbol-parity.test.ts`) and Bun JIT-calls them
|
|
37
|
+
directly (~10-20ns crossing vs ~100-350ns N-API). A bind-time self-test guards
|
|
38
|
+
correctness: on ANY failure the layer is disabled and calls fall back to napi.
|
|
39
|
+
`CASTRUM_FFI_MODE=auto|ffi|napi` selects the transport (default `auto`).
|
|
40
|
+
- **NAPI (napi-rs v3) — the fallback** — used under Node.js, when `bun:ffi` is
|
|
41
|
+
unavailable (self-test failure, `CASTRUM_FFI_MODE=napi`), and for surfaces with no
|
|
42
|
+
C-ABI export. Since Phase 6 the compiled-once instances are NOT napi-only — their
|
|
43
|
+
hot per-call ops route through the C-ABI via an opaque-`usize` handle
|
|
44
|
+
(`conditional_is_not_modified`, `media_type_matcher_matches`,
|
|
45
|
+
`accept_negotiator_negotiate`, `jwt_signer_sign`/`_verify`, `template_render`,
|
|
46
|
+
`schema_validator_validate`, `rate_limiter_check*`, `url_builder_resolve`), and
|
|
47
|
+
`jwtVerify` has `castrum_jwt_verify`. Still napi-only: `rust.batch.*` /
|
|
48
|
+
`rust.packed.*`, `text.*`, and the DOM `jsonParse` (only `castrum_json_parse_packed`
|
|
49
|
+
exists).
|
|
50
|
+
|
|
51
|
+
Shared characteristics:
|
|
52
|
+
|
|
53
|
+
- **Zero-copy buffer sharing**: `Uint8Array` objects are passed by reference to Rust, avoiding serialization
|
|
54
|
+
- **Synchronous calls**: All functions are synchronous, running on the main JS thread
|
|
55
|
+
- **Thread pool**: Rayon is available for parallel CPU-bound work
|
|
56
|
+
|
|
57
|
+
### Dual-binary CPU-detect (x86-64-v3 SIMD variant)
|
|
58
|
+
|
|
59
|
+
On `linux-x64` the package ships a second artifact, `castrum.linux-x64-v3-gnu.node`,
|
|
60
|
+
built with `-C target-cpu=x86-64-v3 -C target-feature=+avx2,+bmi2,+fma,+sse4.2`
|
|
61
|
+
(`scripts/build-v3.sh`, package script `build:v3`; `build:all` builds both). The
|
|
62
|
+
loader (`src/native/loader.ts`) picks the v3 variant at runtime when the host
|
|
63
|
+
CPU exposes AVX2+BMI2+FMA+SSE4.2 (read from `/proc/cpuinfo`), falling back to the
|
|
64
|
+
baseline artifact otherwise — a v3 binary dlopened on an unsupported CPU would
|
|
65
|
+
SIGILL (not catchable from JS), so detection is conservative and requires ALL
|
|
66
|
+
four flags. The v3 variant is OPTIONAL (an absent v3 file resolves to baseline),
|
|
67
|
+
so `build:v3` is never a hard publish requirement.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Module Architecture
|
|
72
|
+
|
|
73
|
+
> **Canonical tree**: [`REPO_MAP.md`](./REPO_MAP.md) is the single-source module map
|
|
74
|
+
> (src/ + rust/ trees, kept in sync). The trees below are the deep-dive annotations.
|
|
75
|
+
|
|
76
|
+
### Rust Modules
|
|
77
|
+
|
|
78
|
+
One cdylib crate (`Cargo [lib] → rust/lib.rs`) decomposed into domain folders.
|
|
79
|
+
`lib.rs` is a declaration hub with a module map; `util/mod.rs` re-exports the
|
|
80
|
+
shared-infra names so legacy `crate::util::*` call sites keep working.
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
rust/
|
|
84
|
+
├── lib.rs ── Crate root: folder declarations + module map, global allocator
|
|
85
|
+
├── test_support.rs ── shared #[cfg(test)] helpers (pack_headers, decode_packed_pairs, Rng)
|
|
86
|
+
├── unit_tests.rs ── cross-module test suite
|
|
87
|
+
│
|
|
88
|
+
├── util/ ── Shared infrastructure (mod.rs re-exports crate::util::*)
|
|
89
|
+
│ ├── bytes.rs ── byte primitives (word-compare, hex, %XX decode, cookie_pairs)
|
|
90
|
+
│ ├── packed.rs ── zero-alloc packed iterators + byte writers (VecWriter, PackedIter)
|
|
91
|
+
│ ├── batch.rs ── aggregate packed batch napi APIs (bitset/count/sum/direct)
|
|
92
|
+
│ ├── batch_core.rs ── generic rayon-parallel batch helpers
|
|
93
|
+
│ ├── threadpool.rs ── rayon pool init + parallelism heuristic
|
|
94
|
+
│ └── validation.rs ── email / UUID / IPv4 / IPv6 validators
|
|
95
|
+
│
|
|
96
|
+
├── http/ ── HTTP wire formats & parsing
|
|
97
|
+
│ ├── headers.rs ── zero-alloc packed-header parser (HeaderRefs)
|
|
98
|
+
│ ├── method.rs ── HTTP method classification
|
|
99
|
+
│ ├── http_parser.rs ── HTTP request line + headers → packed request (httparse)
|
|
100
|
+
│ ├── query_parser.rs ── query/form string → packed pairs
|
|
101
|
+
│ ├── cookie_parser.rs ── cookie header → packed pairs
|
|
102
|
+
│ ├── form.rs ── x-www-form-urlencoded parser + FormParser instance
|
|
103
|
+
│ ├── media_type.rs ── Content-Type parser + MediaTypeParser / MediaTypeMatcher
|
|
104
|
+
│ ├── url_codec.rs ── percent-encoding encode/decode
|
|
105
|
+
│ ├── url_join.rs ── RFC 3986 url_resolve + query builder (UrlBuilder)
|
|
106
|
+
│ ├── etag.rs ── etag / http_date + ConditionalRequest (304)
|
|
107
|
+
│ ├── accept.rs ── Accept-Encoding negotiation (AcceptNegotiator)
|
|
108
|
+
│ ├── mime_lookup.rs ── extension → MIME (phf table)
|
|
109
|
+
│ └── multipart.rs ── multipart/form-data parser (+ limits)
|
|
110
|
+
│
|
|
111
|
+
├── crypto/ ── Auth & hashing (compiled-once instances)
|
|
112
|
+
│ ├── hmac_sha256.rs ── HMAC-SHA256 (+ HmacSigner)
|
|
113
|
+
│ ├── cookie_sign.rs ── signed cookies (CookieSigner)
|
|
114
|
+
│ ├── csrf.rs ── CSRF tokens (CsrfProtector)
|
|
115
|
+
│ ├── jwt.rs ── HS256 JWT sign/verify (+ JwtSigner, precomputed header)
|
|
116
|
+
│ ├── aead.rs ── AES-256-GCM / chacha20-poly1305 (+ AeadCipher)
|
|
117
|
+
│ ├── argon2.rs ── argon2id password hashing (+ Argon2Hasher)
|
|
118
|
+
│ ├── base64.rs ── base64/base64url/hex codecs (+ Base64Codec)
|
|
119
|
+
│ ├── hashing.rs ── FNV-1a / XXH3 / crc32
|
|
120
|
+
│ └── random_token.rs ── random hex tokens
|
|
121
|
+
│
|
|
122
|
+
├── json/ ── JSON & schema
|
|
123
|
+
│ ├── json_ops.rs ── zero-DOM validate/sum + DOM parse (sonic Value → JS)
|
|
124
|
+
│ ├── napi_marshal.rs ── sonic_rs::Value → napi walker (sonic_value_to_js, napi
|
|
125
|
+
│ │ serde-json Number parity) + sonic_values_equal
|
|
126
|
+
│ │ (jsonschema cmp::equal; shared by jwt_verify, json_parse,
|
|
127
|
+
│ │ fast_schema enum/const/uniqueItems)
|
|
128
|
+
│ ├── json_ser.rs ── zero-alloc JSON escaping + cookie/query → JSON writers
|
|
129
|
+
│ ├── json_patch_ops.rs ── CUSTOM sonic RFC 6902 engine (Pointer ~0/~1 unescape +
|
|
130
|
+
│ │ add/remove/replace/move/copy/test incl. array `-`/bounds +
|
|
131
|
+
│ │ 1==1.0; json-patch/jsonptr deps REMOVED)
|
|
132
|
+
│ ├── json_schema.rs ── SchemaValidator napi class (fast + jsonschema fallback)
|
|
133
|
+
│ └── fast_schema/ ── zero-DOM draft-07 JSON Schema fast path
|
|
134
|
+
│ └── mod.rs + types.rs / cursor.rs / compile.rs / validate.rs / errors.rs / email.rs (format:"email" replica) / tests.rs
|
|
135
|
+
│
|
|
136
|
+
├── payload/ ── Output & streaming
|
|
137
|
+
│ ├── compress.rs ── gzip (zlib-rs) + brotli + batch
|
|
138
|
+
│ ├── sse.rs ── SSE event framing + batch
|
|
139
|
+
│ ├── ws_frames.rs ── RFC 6455 frame codec + batch
|
|
140
|
+
│ ├── websocket.rs ── WebSocket accept-key
|
|
141
|
+
│ └── template.rs ── minijinja rendering (TemplateRenderer) + batch
|
|
142
|
+
│
|
|
143
|
+
└── ingress/ ── The ingress pipeline
|
|
144
|
+
├── mod.rs ── thin napi boundary: Ingress class + entry points
|
|
145
|
+
├── pipeline.rs ── core 8-stage pipeline (IngressInner::handle_packed,
|
|
146
|
+
│ write_body_sections, BodySections, IngressSchema)
|
|
147
|
+
├── tests.rs ── ingress unit tests
|
|
148
|
+
├── options.rs ── napi option structs + Limits
|
|
149
|
+
├── time.rs ── monotonic/wall-clock helpers
|
|
150
|
+
├── packed.rs ── packed-input readers + builder
|
|
151
|
+
├── cors.rs ── CORS engine (origin matching, preflight evaluation)
|
|
152
|
+
├── proxy.rs ── HTTPS detection, URL extraction
|
|
153
|
+
├── ip_trust.rs ── IP resolution (X-Forwarded-For, X-Real-IP)
|
|
154
|
+
├── rate_limit.rs ── token-bucket rate limiter (per-IP keyed)
|
|
155
|
+
├── terminal.rs ── terminal response builders (errors)
|
|
156
|
+
├── output.rs ── SINGLE NUMERIC SOURCE for the output-buffer layout
|
|
157
|
+
└── ingress_constants.rs ── NAPI projection of output.rs (no drift)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### TypeScript Modules
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
src/
|
|
164
|
+
├── ingress/ ── HTTP ingress pipeline (TS layer), decomposed by task
|
|
165
|
+
│ ├── index.ts ── Public API barrel + async factory
|
|
166
|
+
│ ├── fast.ts ── Thin: createIngressFast (packed input) + re-exports
|
|
167
|
+
│ ├── handlers.ts ── Thin: createIngressHandler (packs frame in JS → handleRequestPacked) + response builders
|
|
168
|
+
│ ├── server.ts ── createIngressServer (Bun.serve builder) + buildRouteHandlers + gracefulShutdown
|
|
169
|
+
│ ├── server-node.ts ── createIngressServerNode (node:http adapter, same route handlers; the runtime adapter picks the backend)
|
|
170
|
+
│ ├── constants.ts ── Layout constants (from Rust NAPI)
|
|
171
|
+
│ ├── shared.ts ── JS constants shared by both paths
|
|
172
|
+
│ ├── status.ts ── Status normalization helpers (both paths)
|
|
173
|
+
│ ├── errors.ts ── Fast-path error-code name/message mapping
|
|
174
|
+
│ ├── options.ts ── IngressFast option types + validation + trustProxy warning
|
|
175
|
+
│ ├── types.ts ── Public API types
|
|
176
|
+
│ ├── body.ts ── Streaming request-body reader (size guard + bodyTimeoutMs)
|
|
177
|
+
│ ├── context.ts ── Result snapshot + synthetic/error context builders
|
|
178
|
+
│ ├── packing/ ── header-packing, input-packer, gather-raw-headers
|
|
179
|
+
│ ├── headers/ ── cors, hsts, fast-templates, baked-templates
|
|
180
|
+
│ ├── decode/ ── fast-result, baked-result (two decoders, NOT unified)
|
|
181
|
+
│ ├── response/ ── terminal (fast), error-bodies (pre-baked)
|
|
182
|
+
│ └── routes/ ── read/head/json-write/echo/fallback factories
|
|
183
|
+
│
|
|
184
|
+
├── shared/
|
|
185
|
+
│ ├── runtime.ts ── facade over src/runtime/detect.ts (isBun/isNode — cached)
|
|
186
|
+
│ ├── codec.ts ── facade over src/runtime/codec.ts (Bun-native UTF-8 codec)
|
|
187
|
+
│ ├── uuid.ts ── facade over src/runtime/uuid.ts
|
|
188
|
+
│ ├── log.ts ── createStructuredLogger (CASTRUM_LOG_LEVEL-gated JSON lines)
|
|
189
|
+
│ ├── request-id.ts ── zero-alloc request ID generator
|
|
190
|
+
│ ├── buffer-pool.ts ── reusable output-buffer pool
|
|
191
|
+
│ ├── response.ts ── pooledBodyResponse (zero-copy response)
|
|
192
|
+
│ ├── bytes.ts ── codec-backed encoder/decoder + toBytes/toText normalizers
|
|
193
|
+
│ └── packed.ts ── packed-wire unpackers + packers
|
|
194
|
+
│
|
|
195
|
+
├── native/ ── Native transport: bun:ffi (primary on Bun) + NAPI fallback
|
|
196
|
+
│ ├── types.ts ── NativeAddon interface + instance types
|
|
197
|
+
│ ├── loader.ts ── Path resolution (multi-root + env override) + getAddon/lazyAddon
|
|
198
|
+
│ ├── ffi.ts ── bun:ffi C-ABI bindings (Bun-only; bind-time self-test +
|
|
199
|
+
│ │ CASTRUM_FFI_MODE gating; castrum_ingress_layout blob)
|
|
200
|
+
│ └── index.ts ── Barrel
|
|
201
|
+
│
|
|
202
|
+
├── runtime/ ── RUNTIME ADAPTER seam (Bun/Node), selected once at load
|
|
203
|
+
│ ├── detect.ts ── cached runtime detection (the ONLY place `typeof Bun` is checked)
|
|
204
|
+
│ ├── types.ts ── RuntimeAdapter contract (codec/uuid/env/builtins/transport/server/websocket)
|
|
205
|
+
│ ├── codec.ts ── runtime-native UTF-8 codec (Bun transfer vs TextEncoder/Decoder)
|
|
206
|
+
│ ├── uuid.ts ── uuidv7 (Bun.randomUUIDv7 vs crypto.randomUUID)
|
|
207
|
+
│ ├── builtins.ts ── BUN_WINS delegation registry (single source, `has(op)`)
|
|
208
|
+
│ ├── transport.ts ── bun:ffi-first `resolve(op)` + ffi/napi surfaces (lazy bind)
|
|
209
|
+
│ ├── native.ts ── FFI-facing seam (codec/uuid/env/builtins/transport) — imported by rust-ffi
|
|
210
|
+
│ ├── server.ts ── createIngressServer: Bun.serve on Bun, node:http on Node
|
|
211
|
+
│ ├── websocket.ts ── 101 upgrade on Bun; clear Bun-only error on Node
|
|
212
|
+
│ └── index.ts ── FULL adapter `runtime` (native + server + websocket) — for the public API
|
|
213
|
+
│
|
|
214
|
+
├── rust-ffi/ ── Rust FFI bindings
|
|
215
|
+
│ ├── options.ts ── RustOptions + input-normalization helpers
|
|
216
|
+
│ ├── addon.ts ── shared lazy addon proxy
|
|
217
|
+
│ ├── context.ts ── per-instance state + namespace helpers
|
|
218
|
+
│ ├── text.ts ── string namespace
|
|
219
|
+
│ ├── batch.ts ── array-of-bytes namespace
|
|
220
|
+
│ ├── packed.ts ── raw packed-wire namespace
|
|
221
|
+
│ ├── scalar/ ── scalar/feature methods (interface + per-domain builders)
|
|
222
|
+
│ ├── client.ts ── createRust factory + default `rust`
|
|
223
|
+
│ └── index.ts ── Barrel
|
|
224
|
+
│
|
|
225
|
+
├── baseline/ ── JS baseline implementations
|
|
226
|
+
│ ├── index.ts ── Aggregator
|
|
227
|
+
│ └── tasks/ ── 21 baseline tasks (cookie, hashing, hmac, http, json,
|
|
228
|
+
│ json-patch, mime, query, token, url, validation,
|
|
229
|
+
│ websocket, aead, compress, jwt, multipart, password,
|
|
230
|
+
│ streaming, template, pbkdf2, bun-builtins) — full list in docs/REPO_MAP.md
|
|
231
|
+
│
|
|
232
|
+
├── bench/ ── Benchmark framework
|
|
233
|
+
│ ├── index.ts ── Benchmark orchestrator
|
|
234
|
+
│ ├── assert.ts ── Result assertions
|
|
235
|
+
│ ├── checks.ts ── Correctness checks
|
|
236
|
+
│ ├── checksum.ts ── Checksum verification
|
|
237
|
+
│ ├── comparisons.ts ── Comparison reports
|
|
238
|
+
│ ├── concurrent-worker.ts ── Concurrent worker pool
|
|
239
|
+
│ ├── fixtures.ts ── Test fixtures
|
|
240
|
+
│ ├── measure.ts ── Measurement utilities
|
|
241
|
+
│ ├── now.ts ── High-resolution timer
|
|
242
|
+
│ ├── report.ts ── Report generation
|
|
243
|
+
│ ├── run.ts ── Benchmark runner
|
|
244
|
+
│ ├── types.ts ── Type definitions
|
|
245
|
+
│ └── tasks/ ── 33 benchmark tasks (complex, concurrent, cookie,
|
|
246
|
+
│ hashing, hmac, http, json, json-patch, mime, query,
|
|
247
|
+
│ stress, token, url, validation, websocket, aead,
|
|
248
|
+
│ compress, jwt, password, streaming, template,
|
|
249
|
+
│ json-schema, media-type, form, etag, accept,
|
|
250
|
+
│ encoding, cookie-sign, csrf, url-join, multipart,
|
|
251
|
+
│ loader, bun-builtins) — see docs/REPO_MAP.md
|
|
252
|
+
│
|
|
253
|
+
├── data/ ── Benchmark-fixture data (internal)
|
|
254
|
+
│ └── json-rows.ts ── JSON row serialization
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
> **Two ingress consumption paths** (see `docs/INGRESS.md`):
|
|
258
|
+
> 1. `src/ingress/fast.ts` (`createIngressFast`) — JS packs headers
|
|
259
|
+
> (`IngressInputPacker`) → Rust `handle_request_packed`. Wire format from
|
|
260
|
+
> `buildTerminalResponse`: `{"error":{code,status,message,requestId}}`,
|
|
261
|
+
> `x-ratelimit-*`.
|
|
262
|
+
> 2. `src/ingress/handlers.ts` (`createIngressHandler` + route factories +
|
|
263
|
+
> `createIngressServer`) — JS packs the request frame (`IngressInputPacker`
|
|
264
|
+
> + `gatherRawHeadersPacked`) and drives the SAME native core as path 1
|
|
265
|
+
> (`handle_request_packed`). Different wire format: success
|
|
266
|
+
> `{"ok":true,...,"requestId":...}`, errors
|
|
267
|
+
> `{"ok":false,"error":{code,message}}`, `ratelimit-*` headers. The
|
|
268
|
+
> benchmark server (`bench/servers/ingress-server.ts`) uses this path and
|
|
269
|
+
> re-exports the pre-baked functions.
|
|
270
|
+
|
|
271
|
+
## Node.js Compatibility
|
|
272
|
+
|
|
273
|
+
**Bun is the primary target.** Bun resolves the `bun` exports condition → raw
|
|
274
|
+
`index.ts` (native TS execution, zero startup cost). For Node.js consumers, the
|
|
275
|
+
package ships a compiled ESM bundle built by `bun run build:js`:
|
|
276
|
+
|
|
277
|
+
- `package.json` `exports` → `{ types: ./dist/index.d.ts, bun: ./index.ts,
|
|
278
|
+
node: ./dist/index.js, default: ./dist/index.js }`.
|
|
279
|
+
- `dist/index.js` is a single-file ESM bundle (all runtime deps inlined); Node
|
|
280
|
+
requires `>= 20.3` (N-API floor).
|
|
281
|
+
- The addon loader (`src/native/loader.ts`) resolves `castrum.<platform>-<arch>.node`
|
|
282
|
+
from multiple candidate roots so the same loader works from `src/native/…`
|
|
283
|
+
(Bun, source layout) and `dist/…` (Node, bundled layout), plus the
|
|
284
|
+
`CASTRUM_NATIVE_LIBRARY_PATH` / `NAPI_RS_NATIVE_LIBRARY_PATH` override.
|
|
285
|
+
- `src/runtime/detect.ts` is the single runtime-detection seam (the ONLY place
|
|
286
|
+
`typeof Bun` is checked); `src/shared/runtime.ts` is a thin facade over it.
|
|
287
|
+
- The public `createIngressServer` is runtime-adaptive: it delegates to the
|
|
288
|
+
Bun.serve builder (`src/ingress/server.ts`) on Bun and to `createIngressServerNode`
|
|
289
|
+
(`src/ingress/server-node.ts`, same route handlers over `node:http`) on Node,
|
|
290
|
+
via `src/runtime/server.ts`. The `BakedServer.server` type is a
|
|
291
|
+
runtime-agnostic `ServerHandle` so Node TS consumers don't need `@types/bun`.
|
|
292
|
+
- The benchmark tooling (`bench/`, `bun:test` suites) remains Bun-only by design.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Data Flow
|
|
297
|
+
|
|
298
|
+
### Ingress Pipeline (Request Processing)
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
Request
|
|
302
|
+
│
|
|
303
|
+
▼
|
|
304
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
305
|
+
│ TypeScript: packHeaders() │
|
|
306
|
+
│ - Pre-encoded header names (cookie, origin, xff, etc.) │
|
|
307
|
+
│ - Binary packing with length-prefixed (u16 + u32) format │
|
|
308
|
+
│ - TLS header buffer (8KB, recycled across calls) │
|
|
309
|
+
└──────────────────┬───────────────────────────────────────────┘
|
|
310
|
+
│ packed headers + URL bytes + method kind
|
|
311
|
+
▼
|
|
312
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
313
|
+
│ Rust: Ingress::handle_request_packed() │
|
|
314
|
+
│ │
|
|
315
|
+
│ 1. Parse packed input (method, url, ip, rid, headers) │
|
|
316
|
+
│ 2. IP trust resolution │
|
|
317
|
+
│ 3. HTTPS detection │
|
|
318
|
+
│ 4. CORS evaluation │
|
|
319
|
+
│ 5. Rate limiting check │
|
|
320
|
+
│ 6. Body size guard │
|
|
321
|
+
│ 7. JSON validation & schema check │
|
|
322
|
+
│ 8. Cookie parsing → output buffer │
|
|
323
|
+
│ 9. Query parsing → output buffer │
|
|
324
|
+
│ 10. Optional metadata JSON │
|
|
325
|
+
│ 11. Write output header (verdict, status, flags, ...) │
|
|
326
|
+
└──────────────────┬───────────────────────────────────────────┘
|
|
327
|
+
│ output buffer
|
|
328
|
+
▼
|
|
329
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
330
|
+
│ TypeScript: FastIngressResult.refresh() │
|
|
331
|
+
│ - Read output header fields from binary buffer │
|
|
332
|
+
│ - Store slices for lazy decode (cookies, query, body) │
|
|
333
|
+
│ - Caller inspects result and builds Response │
|
|
334
|
+
└──────────────────────────────────────────────────────────────┘
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Batch Processing
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
Multiple Inputs
|
|
341
|
+
│
|
|
342
|
+
▼
|
|
343
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
344
|
+
│ TypeScript: packBatch() │
|
|
345
|
+
│ - Pack each input into binary format with length prefix │
|
|
346
|
+
│ - Single Uint8Array sent to Rust │
|
|
347
|
+
└──────────────────┬───────────────────────────────────────────┘
|
|
348
|
+
│ packed batch
|
|
349
|
+
▼
|
|
350
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
351
|
+
│ Rust: SchemaValidator.validateBatchPacked() │
|
|
352
|
+
│ - Iterate over packed inputs in a tight loop │
|
|
353
|
+
│ - Process each through validation pipeline │
|
|
354
|
+
│ - Write results as packed output (bitset or length-prefixed)│
|
|
355
|
+
└──────────────────┬───────────────────────────────────────────┘
|
|
356
|
+
│ packed results
|
|
357
|
+
▼
|
|
358
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
359
|
+
│ TypeScript: unpackBitset() / unpackByteResults() │
|
|
360
|
+
│ - Extract individual results from packed output │
|
|
361
|
+
│ - Map back to original inputs │
|
|
362
|
+
└──────────────────────────────────────────────────────────────┘
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Output Buffer Layout
|
|
368
|
+
|
|
369
|
+
The output buffer is a binary format shared between Rust and TypeScript. All offsets are defined in `rust/ingress/output.rs` and exported via `rust/ingress/ingress_constants.rs` to `src/ingress/constants.ts`.
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
Offset (bytes)
|
|
373
|
+
├─ 0: OUT_VERDICT (u8) 0=pass, 1=terminal
|
|
374
|
+
├─ 1: OUT_ERROR_CODE (u8) Error code enum
|
|
375
|
+
├─ 2: OUT_STATUS (u16) HTTP status code (LE)
|
|
376
|
+
├─ 4: OUT_FLAGS (u32) Bitfield of FLAG_* values (LE)
|
|
377
|
+
├─ 8: OUT_RATE_LIMIT (u32) Rate limit ceiling (LE)
|
|
378
|
+
├─ 12: OUT_RATE_REMAINING (u32) Remaining requests (LE)
|
|
379
|
+
├─ 16: OUT_RATE_RESET (u64) Rate limit reset timestamp ms (LE)
|
|
380
|
+
├─ 24: OUT_RETRY_AFTER (u64) Retry-After duration ms (LE)
|
|
381
|
+
├─ 32: OUT_COOKIES_JSON_LEN (u32) Cookie JSON length (LE)
|
|
382
|
+
├─ 36: OUT_QUERY_JSON_LEN (u32) Query JSON length (LE)
|
|
383
|
+
├─ 40: OUT_HEADER_VARIANT (u8) Header variant index
|
|
384
|
+
├─ 44: OUT_BODY_JSON_LEN (u32) Body metadata JSON length (LE)
|
|
385
|
+
├─ 48: OUT_DATA_START ─── Variable-length data starts here
|
|
386
|
+
│ ├── Cookie JSON string (if present)
|
|
387
|
+
│ ├── Query JSON string (if present)
|
|
388
|
+
│ └── Body metadata JSON (if emitMetadataJson enabled)
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Flags (bitfield)
|
|
392
|
+
|
|
393
|
+
| Flag | Bit | Description |
|
|
394
|
+
|------|-----|-------------|
|
|
395
|
+
| `FLAG_HAS_COOKIES` | 0 | Cookie data present in output |
|
|
396
|
+
| `FLAG_HAS_QUERY` | 1 | Query data present in output |
|
|
397
|
+
| `FLAG_BODY_VALID_JSON` | 2 | Body is valid JSON |
|
|
398
|
+
| `FLAG_SCHEMA_VALID` | 3 | Body passes JSON Schema validation |
|
|
399
|
+
| `FLAG_CORS_ALLOWED` | 4 | CORS origin allowed |
|
|
400
|
+
| `FLAG_IS_PREFLIGHT` | 5 | Request is a CORS preflight |
|
|
401
|
+
| `FLAG_RATE_LIMITED` | 6 | Rate limit exceeded |
|
|
402
|
+
| `FLAG_HTTPS` | 7 | Request is HTTPS (detected or configured) |
|
|
403
|
+
| `FLAG_TRUSTED_PROXY` | 8 | Request from trusted proxy |
|
|
404
|
+
| `FLAG_BODY_TRUNCATED` | 9 | Output data truncated due to buffer size |
|
|
405
|
+
|
|
406
|
+
### Error Codes
|
|
407
|
+
|
|
408
|
+
| Code | Value | Description |
|
|
409
|
+
|------|-------|-------------|
|
|
410
|
+
| `ERR_CODE_NONE` | 0 | No error |
|
|
411
|
+
| `ERR_CODE_CORS_PREFLIGHT` | 1 | CORS preflight rejected |
|
|
412
|
+
| `ERR_CODE_RATE_LIMITED` | 2 | Rate limit exceeded |
|
|
413
|
+
| `ERR_CODE_BODY_TOO_LARGE` | 3 | Request body exceeds maxBodyBytes |
|
|
414
|
+
| `ERR_CODE_INVALID_JSON` | 4 | Invalid JSON in body |
|
|
415
|
+
| `ERR_CODE_SCHEMA_VALIDATION` | 5 | Schema validation failed |
|
|
416
|
+
| `ERR_CODE_BAD_REQUEST` | 6 | Malformed request |
|
|
417
|
+
| `ERR_CODE_REQUEST_TOO_LARGE` | 7 | Request headers/URL too large |
|
|
418
|
+
| `ERR_CODE_INTERNAL` | 8 | Internal server error |
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Memory Management
|
|
423
|
+
|
|
424
|
+
1. **Global allocator**: mimalloc (`MiMalloc`) for fast, scalable allocation
|
|
425
|
+
2. **Buffer reuse**: Output buffers are recycled across requests where possible
|
|
426
|
+
3. **Zero-copy**: `Uint8Array` passed to Rust functions are used in-place, not copied
|
|
427
|
+
4. **Slice overlap detection**: Rust checks for input/output buffer overlap and copies if needed
|
|
428
|
+
5. **Thread-local caches**: Header buffers use thread-local recycling to reduce allocation pressure
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## JSON & zero-DOM architecture
|
|
433
|
+
|
|
434
|
+
- **`sonic_rs::Value` is the primary DOM** on every crate boundary that allows
|
|
435
|
+
it (compact 16-byte tagged nodes, borrowed/inline strings, zero per-key heap
|
|
436
|
+
`String`). `serde_json::Value` REMAINS only where a crate is hardwired to it
|
|
437
|
+
and cannot be swapped: the jsonschema 0.48 DOM fallback
|
|
438
|
+
(`json_schema.rs` + `pipeline.rs::IngressSchema`), `selection.rs`, and the
|
|
439
|
+
napi JS-object input of `jwt_sign` / `JwtSigner::sign`.
|
|
440
|
+
- **`rust/json/napi_marshal.rs`** is the single sonic→JS bridge:
|
|
441
|
+
`sonic_value_to_js` walks a `sonic_rs::Value` into a napi value with
|
|
442
|
+
**byte-parity** to napi's `serde-json` `ToNapiValue for serde_json::Number`
|
|
443
|
+
(PosInt u64 ≤ u32::MAX → Number, larger → BigInt; NegInt within ±2^53-1 →
|
|
444
|
+
Number, outside → BigInt; Float → Number). `sonic_values_equal` replicates
|
|
445
|
+
jsonschema `cmp::equal` (exact cross-type numeric equality + insertion-order
|
|
446
|
+
object keys) for fast_schema enum/const/uniqueItems and is unit-pinned against
|
|
447
|
+
a serde_json reference over a value corpus.
|
|
448
|
+
- **Zero-DOM hot paths** (no `serde_json::Value` on the per-request path):
|
|
449
|
+
- `castrum_json_parse_packed` (FFI) parses ONCE with sonic-rs and emits a
|
|
450
|
+
typed token stream (deduped string table) that the JS decoder assembles
|
|
451
|
+
with NO second JSON text parse.
|
|
452
|
+
- JWT verify (`verify_token_with_key`) decodes the payload ONCE, checks
|
|
453
|
+
`exp`/`nbf`/`iat` over `sonic_rs::Value`, and returns the payload BYTES
|
|
454
|
+
(no re-serialize); `jwt_verify` / `JwtSigner::verify` marshal via the
|
|
455
|
+
walker. JWT sign (`jwtSignBytes`, `JwtSigner::signBytes`,
|
|
456
|
+
`castrum_jwt_sign_bytes*`) injects `iat`/`exp` into a sonic object
|
|
457
|
+
(`inject_and_payload_b64_sonic`) and serializes with `sonic_rs::to_vec`.
|
|
458
|
+
- fast_schema enum/const/uniqueItems re-parse the doc into `sonic_rs::Value`
|
|
459
|
+
and compare with `sonic_values_equal` (no `Vec<serde_json::Value>`).
|
|
460
|
+
- minijinja contexts are `sonic_rs::Value` (implements `Serialize`).
|
|
461
|
+
- **Custom RFC 6902 patch engine** (`json_patch_ops.rs`): no longer round-trips
|
|
462
|
+
through the serde_json-DOM `json-patch` crate. A `Pointer` type (`~0`/`~1`
|
|
463
|
+
unescape, RFC 6901) + `PatchOp` parser + applicator (add incl. array `-` and
|
|
464
|
+
bounds, remove, replace, move, copy, test incl. `1 == 1.0`) runs directly on
|
|
465
|
+
`sonic_rs::Value`, keeping `JsonPatchError` semantics, the input/output size
|
|
466
|
+
guards, and the packed batch entry points. `json-patch` and `jsonptr` deps
|
|
467
|
+
are removed.
|
|
468
|
+
- **Serialization determinism (`sonic sort_keys`)**: sonic's owned `Value`
|
|
469
|
+
backs MUTABLE objects with `AHashMap` (non-deterministic iteration order), so
|
|
470
|
+
the crate enables `sort_keys` (`Cargo.toml`), swapping the owned map to
|
|
471
|
+
`BTreeMap` → deterministic sorted serialization. This is a hard wire-format
|
|
472
|
+
requirement: JWT sign and the patch engine must emit byte-identical output
|
|
473
|
+
across the FFI/napi/scalar/bulk transports. Parsed (unmutated) values keep
|
|
474
|
+
the shared Vec (insertion order) — only `as_object_mut()` + `insert` switches
|
|
475
|
+
to the map — so `sonic_values_equal` / `sonic_value_to_js` (which iterate the
|
|
476
|
+
shared representation) keep insertion-order semantics.
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Concurrency Model
|
|
481
|
+
|
|
482
|
+
- **Synchronous calls**: Run on the main JS thread (Bun's event loop)
|
|
483
|
+
- **Rayon**: Available for parallel CPU-bound work (e.g., batch validation)
|
|
484
|
+
- **Rate limiter**: Uses `parking_lot::Mutex` for low-contention access
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## Dependency Graph
|
|
489
|
+
|
|
490
|
+
```
|
|
491
|
+
[ingress] ────┬─── [cors] ──── [headers] ──── [method]
|
|
492
|
+
├─── [rate_limit] ─── [ip_trust]
|
|
493
|
+
├─── [proxy]
|
|
494
|
+
├─── [output] ──── [terminal]
|
|
495
|
+
├─── [json_ser] ──── [util]
|
|
496
|
+
├─── [query_parser]
|
|
497
|
+
└─── [cookie_parser]
|
|
498
|
+
[hashing] ──── [hmac_sha256]
|
|
499
|
+
[validation]
|
|
500
|
+
[json_ops] ──── [json_patch_ops]
|
|
501
|
+
[json_schema]
|
|
502
|
+
[url_codec]
|
|
503
|
+
[mime_lookup]
|
|
504
|
+
[websocket]
|
|
505
|
+
[random_token]
|
|
506
|
+
[batch]
|
|
507
|
+
[http_parser]
|