castrum 0.7.0

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 (86) hide show
  1. package/Cargo.toml +73 -0
  2. package/README.md +432 -0
  3. package/bench.ts +3 -0
  4. package/castrum.linux-x64-gnu.node +0 -0
  5. package/index.ts +24 -0
  6. package/package.json +94 -0
  7. package/rust/batch.rs +195 -0
  8. package/rust/cookie_parser.rs +70 -0
  9. package/rust/cors.rs +263 -0
  10. package/rust/hashing.rs +164 -0
  11. package/rust/headers.rs +234 -0
  12. package/rust/hmac_sha256.rs +113 -0
  13. package/rust/http_parser.rs +132 -0
  14. package/rust/ingress.rs +616 -0
  15. package/rust/ingress_constants.rs +89 -0
  16. package/rust/ip_trust.rs +185 -0
  17. package/rust/json_ops.rs +66 -0
  18. package/rust/json_patch_ops.rs +25 -0
  19. package/rust/json_schema.rs +151 -0
  20. package/rust/json_ser.rs +429 -0
  21. package/rust/lib.rs +48 -0
  22. package/rust/method.rs +141 -0
  23. package/rust/mime_lookup.rs +76 -0
  24. package/rust/output.rs +238 -0
  25. package/rust/proxy.rs +90 -0
  26. package/rust/query_parser.rs +141 -0
  27. package/rust/random_token.rs +52 -0
  28. package/rust/rate_limit.rs +203 -0
  29. package/rust/terminal.rs +95 -0
  30. package/rust/unit_tests.rs +843 -0
  31. package/rust/url_codec.rs +133 -0
  32. package/rust/util.rs +537 -0
  33. package/rust/validation.rs +107 -0
  34. package/rust/websocket.rs +23 -0
  35. package/src/baseline/index.ts +12 -0
  36. package/src/baseline/tasks/cookie.ts +22 -0
  37. package/src/baseline/tasks/hashing.ts +18 -0
  38. package/src/baseline/tasks/hmac.ts +38 -0
  39. package/src/baseline/tasks/http.ts +62 -0
  40. package/src/baseline/tasks/json-patch.ts +12 -0
  41. package/src/baseline/tasks/json.ts +50 -0
  42. package/src/baseline/tasks/mime.ts +5 -0
  43. package/src/baseline/tasks/query.ts +14 -0
  44. package/src/baseline/tasks/token.ts +15 -0
  45. package/src/baseline/tasks/url.ts +11 -0
  46. package/src/baseline/tasks/validation.ts +19 -0
  47. package/src/baseline/tasks/websocket.ts +14 -0
  48. package/src/bench/assert.ts +70 -0
  49. package/src/bench/checks.ts +227 -0
  50. package/src/bench/checksum.ts +27 -0
  51. package/src/bench/comparisons.ts +70 -0
  52. package/src/bench/concurrent-worker.ts +135 -0
  53. package/src/bench/fixtures.ts +233 -0
  54. package/src/bench/index.ts +2 -0
  55. package/src/bench/measure.ts +177 -0
  56. package/src/bench/now.ts +3 -0
  57. package/src/bench/report.ts +79 -0
  58. package/src/bench/run.ts +57 -0
  59. package/src/bench/tasks/complex.ts +232 -0
  60. package/src/bench/tasks/concurrent.ts +213 -0
  61. package/src/bench/tasks/cookie.ts +44 -0
  62. package/src/bench/tasks/hashing.ts +33 -0
  63. package/src/bench/tasks/hmac.ts +36 -0
  64. package/src/bench/tasks/http.ts +50 -0
  65. package/src/bench/tasks/index.ts +52 -0
  66. package/src/bench/tasks/json-patch.ts +21 -0
  67. package/src/bench/tasks/json.ts +33 -0
  68. package/src/bench/tasks/mime.ts +21 -0
  69. package/src/bench/tasks/query.ts +44 -0
  70. package/src/bench/tasks/stress.ts +142 -0
  71. package/src/bench/tasks/token.ts +20 -0
  72. package/src/bench/tasks/url.ts +34 -0
  73. package/src/bench/tasks/validation.ts +57 -0
  74. package/src/bench/tasks/websocket.ts +21 -0
  75. package/src/bench/types.ts +60 -0
  76. package/src/data/json-rows.ts +33 -0
  77. package/src/ingress/constants.ts +56 -0
  78. package/src/ingress/fast.ts +1082 -0
  79. package/src/ingress/handlers.ts +1202 -0
  80. package/src/ingress/index.ts +457 -0
  81. package/src/ingress/packed-input.ts +59 -0
  82. package/src/native/index.ts +207 -0
  83. package/src/rust-ffi/index.ts +555 -0
  84. package/src/shared/bytes.ts +36 -0
  85. package/src/shared/json.ts +18 -0
  86. package/src/shared/packed.ts +316 -0
package/Cargo.toml ADDED
@@ -0,0 +1,73 @@
1
+ [package]
2
+ name = "castrum"
3
+ # Keep in sync with package.json "version" (single source of truth: the npm package).
4
+ version = "0.7.0"
5
+ edition = "2021"
6
+
7
+ [lib]
8
+ name = "castrum"
9
+ crate-type = ["cdylib"]
10
+ path = "rust/lib.rs"
11
+
12
+ [dependencies]
13
+ napi = { version = "3", features = ["napi10"] }
14
+ napi-derive = "3"
15
+
16
+ serde = { version = "1", features = ["derive"] }
17
+ serde_json = "1"
18
+ sonic-rs = "0.5"
19
+
20
+ # default-features=false: drop resolve-http + tls-aws-lc-rs which pull in
21
+ # reqwest -> hyper/h2/tokio/rustls (large binary, attack surface). Format
22
+ # validators (email etc.) are built-in and NOT feature-gated in 0.48.
23
+ jsonschema = { version = "0.48", default-features = false, features = ["resolve-file"] }
24
+ json-patch = "4"
25
+ aws-lc-rs = "1"
26
+ base64 = "0.23"
27
+ crc32fast = "1"
28
+ httparse = "1"
29
+ mime_guess = "2"
30
+ phf = { version = "0.14", features = ["macros"] }
31
+ getrandom = "0.4"
32
+ memchr = "2"
33
+ simdutf8 = "0.1"
34
+ email_address = "0.2"
35
+ fast_chemail = { version = "0.9", optional = true }
36
+ rayon = "1"
37
+ # mimalloc is set as the Rust #[global_allocator] (see rust/lib.rs). We DELIBERATELY
38
+ # do NOT enable the "override" feature: it interposes libc malloc/free at the
39
+ # process level, which is an embedding hazard when this cdylib is dlopen'd into
40
+ # Bun (which itself embeds mimalloc -> symbol clashes). The Rust-level global
41
+ # allocator keeps most of the allocation win without replacing the host malloc.
42
+ mimalloc = { version = "0.1", features = ["local_dynamic_tls"] }
43
+ core_affinity = "0.8"
44
+
45
+ parking_lot = "0.12"
46
+ xxhash-rust = { version = "0.8", features = ["xxh3"] }
47
+ ipnet = "2"
48
+ lru = "0.12"
49
+
50
+ [build-dependencies]
51
+ napi-build = "2"
52
+
53
+ [features]
54
+ default = ["fast-email"]
55
+ fast-email = ["dep:fast_chemail"]
56
+
57
+ [profile.release]
58
+ opt-level = 3
59
+ lto = "fat"
60
+ codegen-units = 1
61
+ strip = "symbols"
62
+ debug = 0
63
+ incremental = false
64
+ # Safety: this is an embedded cdylib loaded into the Bun process. panic = "unwind"
65
+ # (the default) lets napi's catch_unwind convert Rust panics into JS exceptions
66
+ # instead of aborting the host process. overflow-checks = true catches integer
67
+ # overflow in release; the cost is negligible relative to the safety gain.
68
+ overflow-checks = true
69
+ debug-assertions = false
70
+
71
+ [profile.release.package."*"]
72
+ opt-level = 3
73
+ codegen-units = 1
package/README.md ADDED
@@ -0,0 +1,432 @@
1
+ # castrum
2
+
3
+ **Enterprise-Grade Bun + Rust FFI Runtime Benchmark Package**
4
+
5
+ A high-performance Bun backend framework with Rust-accelerated FFI functions, providing production-grade HTTP ingress pipeline, validation, hashing, JSON processing, and more — all with benchmark-grade performance.
6
+
7
+ ---
8
+
9
+ ## Architecture Overview
10
+
11
+ ```
12
+ ┌─────────────────────────────────────────────────────────────────┐
13
+ │ TypeScript (Bun) Layer │
14
+ │ │
15
+ │ index.ts (entry point) │
16
+ │ ├── src/rust-ffi/ Raw Rust FFI bindings │
17
+ │ ├── src/native/ NAPI native addon loader │
18
+ │ ├── src/ingress/ High-performance HTTP ingress pipeline │
19
+ │ ├── src/baseline/ JS baseline (benchmark reference) │
20
+ │ ├── src/data/ Data serialization utilities │
21
+ │ └── src/shared/ Shared constants and helpers │
22
+ │ │
23
+ ├─────────────────── NAPI Bridge (napi-rs) ──────────────────────┤
24
+ │ │
25
+ │ Rust (cdylib) Layer │
26
+ │ │
27
+ │ rust/lib.rs │
28
+ │ ├── Core Pipeline: ingress, cors, rate_limit, ip_trust │
29
+ │ ├── Parsers: http_parser, query_parser, cookie_parser │
30
+ │ ├── Validation: validation (email/uuid/IP) │
31
+ │ ├── JSON: json_ops, json_patch_ops, json_schema, │
32
+ │ │ json_ser │
33
+ │ ├── Crypto: hashing, hmac_sha256, random_token │
34
+ │ ├── Data: url_codec, mime_lookup, websocket │
35
+ │ ├── Batch: batch │
36
+ │ ├── Utilities: util, method, headers, output, terminal │
37
+ └─────────────────────────────────────────────────────────────────┘
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```bash
43
+ # Install dependencies
44
+ bun install
45
+
46
+ # Build Rust native addon (release)
47
+ bun run build
48
+
49
+ # Run benchmarks
50
+ bun bench.ts
51
+
52
+ # Run tests
53
+ bun test
54
+ ```
55
+
56
+ ## Build
57
+
58
+ ```bash
59
+ # Production build
60
+ bun run build
61
+
62
+ # Debug build
63
+ bun run build:debug
64
+ ```
65
+
66
+ ## Benchmarks
67
+
68
+ ```bash
69
+ # Full benchmark suite
70
+ bun bench.ts
71
+
72
+ # HTTP server benchmarks
73
+ bun run bench:http
74
+
75
+ # Compare with specific frameworks
76
+ bun run bench:http:elysia # vs Elysia
77
+ bun run bench:http:ingress # vs Ingress (native)
78
+ bun run bench:http:bun-only # vs raw Bun
79
+
80
+ # Load patterns
81
+ bun run bench:http:smoke # smoke test
82
+ bun run bench:http:stress # stress test
83
+ bun run bench:http:heavy # heavy JSON
84
+ bun run bench:http:crud # CRUD operations
85
+ bun run bench:http:soak # soak (endurance) test
86
+ bun run bench:http:storm # storm (burst) test
87
+ bun run bench:http:boundary # boundary conditions
88
+ ```
89
+
90
+ ## API Reference
91
+
92
+ ### Core Exports
93
+
94
+ ```ts
95
+ import { rust, native, rustBatch } from "castrum";
96
+
97
+ // `rust` — All Rust FFI native implementations (flat, complete API)
98
+ // `native` — JavaScript/Bun baseline implementations for benchmarking
99
+ // `rustBatch` — Back-compat alias === rust.batch
100
+ ```
101
+
102
+ ### Rust Utility API
103
+
104
+ `rust` is a single flat object exposing **every** native Rust utility with
105
+ optimized defaults baked in. Text-oriented operations also have ergonomic
106
+ string variants under `rust.text`.
107
+
108
+ | Namespace | Description |
109
+ |-----------|-------------|
110
+ | `rust.crc32(...)`, `rust.jsonValid(...)`, … | Scalar utilities (bytes in → typed out) |
111
+ | `rust.text.mimeFromExtension(".js")`, … | String ergonomics (string in → string/bool out) |
112
+ | `rust.batch.jsonValid(docs)`, … | High-throughput batch (arrays → unpacked results) |
113
+ | `rust.packed.jsonValidBatchPacked(p)`, … | Raw packed low-level variants + metadata |
114
+ | `rust.configure({ ... })` | Override defaults on the shared instance |
115
+
116
+ #### Scalar utilities
117
+
118
+ | Function | Returns |
119
+ |----------|---------|
120
+ | `crc32(input)` | `number` — CRC32 checksum |
121
+ | `fnv1a64(input)` | `bigint` — FNV-1a 64-bit hash |
122
+ | `hmacSha256(key, data)` | `Uint8Array` — HMAC-SHA256 signature |
123
+ | `hmacSha256Verify(key, data, sig)` | `boolean` |
124
+ | `jsonValid(input)` | `boolean` — JSON validity check |
125
+ | `jsonSumIds(input)` | `bigint` — sum of numeric `id` fields |
126
+ | `jsonPatch(doc, patch)` | `Uint8Array` — RFC 6902 result |
127
+ | `mimeFromExtension(ext)` | `Uint8Array` — MIME type |
128
+ | `randomToken(byteLen)` | `Uint8Array` — CSPRNG token |
129
+ | `urlEncode(input)` / `urlDecode(input)` | `Uint8Array` — percent encode/decode |
130
+ | `urlDecodeBytes(input)` | `Uint8Array` — strict %-decode (no UTF-8 check) |
131
+ | `validateEmail/Uuid/Ipv4/Ipv6(input)` | `boolean` |
132
+ | `wsAcceptKey(key)` | `Uint8Array` — WebSocket accept key |
133
+
134
+ Low-level / packed variants: `rust.httpParseRequestPacked`, `rust.queryParsePacked`,
135
+ `rust.cookieParsePacked`.
136
+
137
+ #### String ergonomics (`rust.text`)
138
+
139
+ ```ts
140
+ rust.text.mimeFromExtension(".js"); // "text/javascript"
141
+ rust.text.mimeFromExtension("html"); // "text/html"
142
+ rust.text.urlEncode("a b"); // "a%20b"
143
+ rust.text.urlDecode("a%20b"); // "a b"
144
+ rust.text.wsAcceptKey(keyBase64); // base64 accept key
145
+ rust.text.validateEmail("a@b.co"); // true
146
+ ```
147
+
148
+ #### Batch operations (`rust.batch`)
149
+
150
+ All batch helpers accept `Uint8Array[]` and return unpacked, ready-to-use results:
151
+
152
+ ```ts
153
+ const docs = [encoder.encode('{"id":1}'), encoder.encode('{"id":2}')];
154
+
155
+ rust.batch.jsonValid(docs); // Uint8Array bitset (1 per doc)
156
+ rust.batch.crc32(docs); // Uint32Array
157
+ rust.batch.jsonSumIds(docs); // BigInt64Array
158
+ rust.batch.queryParse(docs); // Uint8Array[]
159
+ rust.batch.schemaValidate(validator, docs); // bitset
160
+ ```
161
+
162
+ Raw packed + metadata variants (advanced): `rust.packed.*` mirrors the native
163
+ functions 1:1 (`jsonValidBatchPacked`, `jsonValidBatchCountPacked`,
164
+ `queryParseBatchTotalLenPacked`, …).
165
+
166
+ #### Configuring defaults
167
+
168
+ Defaults are selected automatically, and can be overridden:
169
+
170
+ ```ts
171
+ // Defaults:
172
+ // rayonThreads = max(1, hardwareConcurrency - 1)
173
+ // (env override: CASTRUM_RAYON_THREADS / RUST_RAYON_THREADS)
174
+ // mimeCache = true
175
+ // hmacCache = true
176
+
177
+ // Override per-instance options on the shared instance:
178
+ rust.configure({ mimeCache: false, hmacCache: false });
179
+
180
+ // Or create an isolated instance with custom defaults:
181
+ import { createRust } from "castrum";
182
+ const myRust = createRust({ mimeCache: false });
183
+ ```
184
+
185
+ > **Thread pool note**: the rayon pool is process-wide and initialized **once**
186
+ > (native `OnceLock`) — the first initialization wins. Because importing the
187
+ > module initializes it with the default, set
188
+ > `CASTRUM_RAYON_THREADS` / `RUST_RAYON_THREADS` (or call
189
+ > `rust.configure({ rayonThreads })` / `createRust({ rayonThreads })` before any
190
+ > other pool use) to tune it. `mimeCache` / `hmacCache` are per-instance and can
191
+ > be toggled any time.
192
+
193
+ ### Sub-modules
194
+
195
+ | Import | Description |
196
+ |--------|-------------|
197
+ | `import { encoder, decoder } from "castrum"` | Text encode/decode utilities |
198
+ | `import { packBatch, packPairs, unpackBitset, unpackByteResults, unpackI64ArrayAsBigInt, unpackU32Array } from "castrum"` | Batch/pair packing + unpacking utilities |
199
+ | `import { readPairsPacked, pairsToObject, readHttpPacked } from "castrum"` | Decode packed pairs / parsed HTTP buffers |
200
+ | `import { parseQueryString, parseCookieHeader } from "castrum"` | High-level string parsers (no hand-packing) |
201
+ | `import { jsonRowsBytes, createJsonRows } from "castrum"` | JSON row serialization |
202
+ | `import { createIngress, createIngressSync, createIngressFast } from "castrum"` | HTTP ingress pipeline (low-level) |
203
+ | `import { createIngressHandler, createIngressServer, readHandler, jsonWriteHandler, echoHandler, fallbackHandler } from "castrum"` | **Pre-baked** ingress handlers — route factories + Bun.serve builder |
204
+
205
+ ```ts
206
+ import { parseQueryString, parseCookieHeader } from "castrum";
207
+
208
+ parseQueryString("a=1&b=2&tag=a&tag=b"); // { a: "1", b: "2", tag: ["a", "b"] }
209
+ parseCookieHeader("session=abc; theme=dark"); // { session: "abc", theme: "dark" }
210
+ ```
211
+
212
+ > **Environment variables**: See [docs/ENVIRONMENT.md](./docs/ENVIRONMENT.md) for the
213
+ > full reference of `INGRESS_*`, `CASTRUM_*` and `RUST_*` runtime variables.
214
+
215
+ ### Ingress Pipeline
216
+
217
+ The ingress system is a high-performance request processing pipeline that handles:
218
+
219
+ - **Method routing** — GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS
220
+ - **CORS evaluation** — Origin validation, preflight handling
221
+ - **Rate limiting** — Token-bucket per IP with configurable window
222
+ - **IP trust & proxy** — X-Forwarded-For, X-Real-IP resolution
223
+ - **HTTPS detection** — X-Forwarded-Proto based
224
+ - **Cookie parsing** — Structured JSON output
225
+ - **Query parsing** — Key-value pair extraction
226
+ - **JSON body validation** — Syntax + optional schema validation
227
+ - **Body size guarding** — Configurable max body size
228
+ - **Security headers** — HSTS, CSP, X-Frame-Options, etc.
229
+
230
+ ```ts
231
+ // Fast synchronous handler (zero allocations per call)
232
+ import { createIngressFast } from "castrum";
233
+
234
+ const handler = createIngressFast({
235
+ cors: { allowOrigin: ["https://example.com"] },
236
+ rateLimit: { limit: 100, windowMs: 60_000 },
237
+ parseCookies: true,
238
+ parseQuery: true,
239
+ });
240
+
241
+ // Inside a Bun server:
242
+ Bun.serve({
243
+ port: 3000,
244
+ async fetch(req) {
245
+ return handler.run(req, req.headers.get("x-forwarded-for"), null, "", (result) => {
246
+ if (result.ok) {
247
+ return new Response("OK", { status: 200 });
248
+ }
249
+ return new Response("Error", { status: result.status });
250
+ });
251
+ },
252
+ });
253
+ ```
254
+
255
+ #### Pre-baked handlers (recommended for servers)
256
+
257
+ `src/ingress/handlers.ts` provides ready-to-use route handlers and a `Bun.serve`
258
+ builder so **any system can consume the optimized ingress pipeline in a few
259
+ lines** — no need to hand-build responses or manage header templates:
260
+
261
+ ```ts
262
+ import { createIngressHandler, createIngressServer } from "castrum";
263
+
264
+ const ingress = createIngressHandler({
265
+ parseCookies: true,
266
+ parseQuery: true,
267
+ cors: { allowOrigin: ["https://app.example.com"] },
268
+ rateLimit: { limit: 1000, windowMs: 60_000 },
269
+ });
270
+
271
+ createIngressServer({
272
+ port: 3000,
273
+ routes: {
274
+ "/health": { read: ingress }, // GET + HEAD
275
+ "/api/users": { read: ingress, write: ingress }, // + POST/PUT/PATCH
276
+ "/api/echo": { echo: ingress }, // POST echo
277
+ },
278
+ });
279
+ ```
280
+
281
+ The route factories (`readHandler`, `headHandler`, `jsonWriteHandler`,
282
+ `echoHandler`, `fallbackHandler`) are runtime-agnostic — use them with any
283
+ fetch-style server. The benchmark server (`bench/servers/ingress-server.ts`)
284
+ is built entirely from these and re-exports them. See
285
+ [docs/INGRESS.md](./docs/INGRESS.md) for the full pre-baked API reference.
286
+
287
+
288
+ ---
289
+
290
+ ## Project Structure
291
+
292
+ ```
293
+ castrum/
294
+ ├── index.ts # Entry point / public API
295
+ ├── AGENTS.md # AI agent instructions (commands, constraints, gotchas)
296
+ ├── bench.ts # Benchmark runner
297
+ ├── build.rs # NAPI build script
298
+ ├── Cargo.toml # Rust dependencies & build config
299
+ ├── package.json # Node/Bun package config
300
+ ├── tsconfig.json # TypeScript config
301
+ │
302
+ ├── rust/ # Rust source (cdylib)
303
+ │ ├── lib.rs # Crate root, module declarations
304
+ │ ├── ingress.rs # NAPI ingress class
305
+ │ ├── cors.rs # CORS engine
306
+ │ ├── rate_limit.rs # Keyed rate limiter
307
+ │ ├── ip_trust.rs # IP trust & proxy resolution
308
+ │ ├── http_parser.rs # HTTP request parser
309
+ │ ├── query_parser.rs # Query string parser
310
+ │ ├── cookie_parser.rs # Cookie header parser
311
+ │ ├── validation.rs # Email/UUID/IP validation
312
+ │ ├── hashing.rs # FNV-1a & fast hashing
313
+ │ ├── hmac_sha256.rs # HMAC-SHA256
314
+ │ ├── json_ops.rs # JSON operations
315
+ │ ├── json_patch_ops.rs # JSON Patch operations
316
+ │ ├── json_schema.rs # JSON Schema validation
317
+ │ ├── json_ser.rs # JSON serialization utilities
318
+ │ ├── url_codec.rs # URL encode/decode
319
+ │ ├── mime_lookup.rs # MIME type lookup
320
+ │ ├── websocket.rs # WebSocket utilities
321
+ │ ├── random_token.rs # Secure random token generation
322
+ │ ├── batch.rs # Batch processing
323
+ │ ├── method.rs # HTTP method enum
324
+ │ ├── headers.rs # Header packing
325
+ │ ├── output.rs # Output buffer layout
326
+ │ ├── terminal.rs # Terminal response writers
327
+ │ ├── proxy.rs # Proxy detection utilities
328
+ │ ├── util.rs # Core utilities
329
+ │ └── ingress_constants.rs # NAPI-exported constants
330
+ │
331
+ ├── src/ # TypeScript source
332
+ │ ├── ingress/ # Ingress pipeline (TS layer)
333
+ │ │ ├── index.ts # Public API + async factory
334
+ │ │ ├── fast.ts # Fast synchronous handler (packed input)
335
+ │ │ ├── handlers.ts # PRE-BAKED handlers + createIngressServer
336
+ │ │ ├── constants.ts # Layout constants (from Rust)
337
+ │ │ └── packed-input.ts # Input buffer packing
338
+ │ ├── native/ # Native addon loader
339
+ │ │ └── index.ts # Module loading + type definitions
340
+ │ ├── rust-ffi/ # Rust FFI bindings
341
+ │ │ └── index.ts # Flat, complete FFI API
342
+ │ ├── baseline/ # JS baseline implementations
343
+ │ │ ├── index.ts # Aggregator
344
+ │ │ └── tasks/ # Individual baseline implementations
345
+ │ ├── bench/ # Benchmark framework
346
+ │ ├── data/ # Data serialization
347
+ │ └── shared/ # Shared utilities
348
+ │
349
+ ├── bench/ # HTTP benchmark servers
350
+ │ ├── servers/ # bun-server.ts, elysia-server.ts, ingress-server.ts (+ shared.ts)
351
+ │ ├── load.ts # HTTP load generator & scenarios
352
+ │ └── run-bench.ts # Benchmark runner
353
+ │
354
+ ├── test/ # Tests (see CONTRIBUTING.md → Testing Requirements)
355
+ ├── docs/ # Documentation
356
+ └── scripts/ # Build/utility scripts
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Performance Characteristics
362
+
363
+ All Rust FFI functions are designed for **zero-allocation** paths where possible:
364
+
365
+ - **Ingress pipeline**: Single output buffer written by Rust, read by JS — minimal copies
366
+ - **Validation functions**: Pure CPU-bound, 10-100x faster than JS equivalents
367
+ - **Hashing**: SIMD-optimized crates under the hood
368
+ - **Batch operations**: Packed binary format minimizes NAPI boundary crossings
369
+ - **JSON parsing**: Uses `sonic-rs` (Rust) — one of the fastest JSON parsers available
370
+
371
+ ---
372
+
373
+ ## Testing
374
+
375
+ ```bash
376
+ # Run all tests
377
+ bun test
378
+
379
+ # Run specific test file
380
+ bun test test/unit/ingress/fast.test.ts
381
+
382
+ # Run tests with coverage
383
+ bun test --coverage
384
+ ```
385
+
386
+ ---
387
+
388
+ ## Publishing
389
+
390
+ The package ships **all platform native addons in a single tarball**, so a release
391
+ needs every `napi.targets` platform artifact present (see `scripts/prepublish.mjs`).
392
+
393
+ ### Automatic (recommended)
394
+
395
+ CI builds every platform addon and publishes to npm when you push a `v*` tag.
396
+ Bump `version` in `package.json` (and `Cargo.toml`), add a `CHANGELOG.md` entry,
397
+ then:
398
+
399
+ ```bash
400
+ git tag v0.6.0 && git push origin v0.6.0
401
+ ```
402
+
403
+ ### Manual
404
+
405
+ To build and publish a release by hand (no CI needed; npm logged in or `NPM_TOKEN`
406
+ exported):
407
+
408
+ ```bash
409
+ bun run publish:manual # build + publish current version
410
+ bun run publish:manual -- --increment minor # bump version + tag + push + publish
411
+ bun run publish:manual:dry # print the plan, change nothing
412
+ ```
413
+
414
+ `publish:manual` bumps the version (`--increment`), creates + pushes the `v<version>`
415
+ git tag via `bun pm version` (keeping `Cargo.toml`, `Cargo.lock`, and `CHANGELOG.md`
416
+ in sync), builds the host addon locally, and runs `npm publish --access public`.
417
+
418
+ > **Platform note:** because only the current platform can be built locally, the
419
+ > manual publish ships a **single-platform tarball** (it sets
420
+ > `CASTRUM_PUBLISH_ALLOW_PARTIAL=1` so `prepublishOnly` doesn't fail on the missing
421
+ > platforms). For a full multi-platform tarball, push a `v*` tag and let the CI
422
+ > workflow build + publish.
423
+
424
+ ---
425
+
426
+ ## License
427
+
428
+ MIT
429
+
430
+ ## Contributing
431
+
432
+ Please see [CONTRIBUTING.md](./CONTRIBUTING.md).
package/bench.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { runBenchmark } from "./src/bench";
2
+
3
+ runBenchmark();
Binary file
package/index.ts ADDED
@@ -0,0 +1,24 @@
1
+ export * from "./src/rust-ffi";
2
+
3
+ export * as native from "./src/baseline";
4
+
5
+ export { encoder, decoder } from "./src/shared/bytes";
6
+
7
+ export {
8
+ packBatch,
9
+ packPairs,
10
+ readPairsPacked,
11
+ readHttpPacked,
12
+ pairsToObject,
13
+ parseQueryString,
14
+ parseCookieHeader,
15
+ unpackBitset,
16
+ unpackByteResults,
17
+ unpackI64ArrayAsBigInt,
18
+ unpackU32Array,
19
+ } from "./src/shared/packed";
20
+ export type { Pair, ParsedHttpRequestPacked } from "./src/shared/packed";
21
+
22
+ export { jsonRowsBytes, createJsonRows } from "./src/data/json-rows";
23
+ export type { JsonRow } from "./src/data/json-rows";
24
+ export * from "./src/ingress";
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "castrum",
3
+ "version": "0.7.0",
4
+ "private": false,
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
+ "type": "module",
7
+ "main": "index.ts",
8
+ "module": "index.ts",
9
+ "types": "index.ts",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "bun",
13
+ "rust",
14
+ "napi",
15
+ "ffi",
16
+ "ingress",
17
+ "http",
18
+ "validation",
19
+ "hashing",
20
+ "json",
21
+ "performance",
22
+ "benchmark"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/Axylabs/flux-rs.git"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "exports": {
32
+ ".": "./index.ts"
33
+ },
34
+ "files": [
35
+ "index.ts",
36
+ "bench.ts",
37
+ "src",
38
+ "rust",
39
+ "Cargo.toml",
40
+ "README.md",
41
+ "*.node"
42
+ ],
43
+ "scripts": {
44
+ "build": "napi build --release --platform",
45
+ "bench": "bun run build && bun bench.ts",
46
+ "check": "bun bench.ts",
47
+ "test": "bun test",
48
+ "build:debug": "napi build --platform",
49
+ "artifacts": "napi artifacts",
50
+ "publish:manual": "node scripts/publish-manual.mjs",
51
+ "publish:manual:dry": "node scripts/publish-manual.mjs --dry-run",
52
+ "prepublishOnly": "node scripts/prepublish.mjs",
53
+ "bench:http": "bun run bench/run-bench.ts",
54
+ "bench:http:smoke": "bun run bench/run-bench.ts smoke",
55
+ "bench:http:stress": "bun run bench/run-bench.ts stress",
56
+ "bench:http:heavy": "bun run bench/run-bench.ts heavy-json",
57
+ "bench:http:crud": "bun run bench/run-bench.ts crud",
58
+ "bench:http:spike": "bun run bench/run-bench.ts spike",
59
+ "bench:http:soak": "bun run bench/run-bench.ts soak",
60
+ "bench:http:storm": "bun run bench/run-bench.ts storm",
61
+ "bench:http:boundary": "bun run bench/run-bench.ts boundary",
62
+ "bench:http:elysia": "bun run bench/run-bench.ts '' elysia",
63
+ "bench:http:ingress": "bun run bench/run-bench.ts '' ingress",
64
+ "bench:http:bun-only": "bun run bench/run-bench.ts '' bun",
65
+ "bench:http:all-heavy": "bun run bench/run-bench.ts 1"
66
+ },
67
+ "dependencies": {
68
+ "crc-32": "^1.2.2",
69
+ "fast-json-patch": "^3.1.1",
70
+ "mime-types": "^3.0.2",
71
+ "validator": "^13.15.35"
72
+ },
73
+ "devDependencies": {
74
+ "@elysia/cors": "^1.4.2",
75
+ "@napi-rs/cli": "^3.7.4",
76
+ "@types/bun": "^1.3.14",
77
+ "@types/mime-types": "^3.0.1",
78
+ "@types/validator": "^13.15.10",
79
+ "elysia": "^1.4.0"
80
+ },
81
+ "engines": {
82
+ "bun": ">=1.1.0"
83
+ },
84
+ "napi": {
85
+ "binaryName": "castrum",
86
+ "targets": [
87
+ "aarch64-apple-darwin",
88
+ "aarch64-unknown-linux-gnu",
89
+ "x86_64-apple-darwin",
90
+ "x86_64-pc-windows-msvc",
91
+ "x86_64-unknown-linux-gnu"
92
+ ]
93
+ }
94
+ }