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
@@ -163,6 +163,11 @@ export interface EncodingPrefResult {
163
163
  export interface AcceptNegotiatorInstance {
164
164
  /** Best supported encoding for `header`, or null for identity. */
165
165
  negotiate(header: Uint8Array): string | null
166
+ /** Best supported encoding for `header` with SERVER-preference tie-breaking
167
+ * (RFC 7231 server semantics — the supported list's order breaks q-value
168
+ * ties), or null for identity. On the napi fallback this is the projected
169
+ * `negotiate_server_preference` method. */
170
+ negotiateServerPreference(header: Uint8Array): string | null
166
171
  /** Opaque handle (bun:ffi fast path) — `castrum_accept_negotiator_negotiate`. */
167
172
  innerPtr?(): bigint
168
173
  }
@@ -10,15 +10,25 @@ import { asNumber } from './options'
10
10
  /** Raw packed-wire FFI namespace. */
11
11
  export interface RustPacked {
12
12
  // ── Sync batch (packed in → packed out) ──
13
+ /** Packed CRC32 batch: packed `[u8[]]` items → packed u32 results. */
13
14
  crc32BatchPacked(input: Uint8Array): Uint8Array
15
+ /** Packed JSON-validity batch: packed `[u8[]]` items → packed 0/1 bitset. */
14
16
  jsonValidBatchPacked(input: Uint8Array): Uint8Array
17
+ /** Packed email-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
15
18
  validateEmailBatchPacked(input: Uint8Array): Uint8Array
19
+ /** Packed UUID-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
16
20
  validateUuidBatchPacked(input: Uint8Array): Uint8Array
21
+ /** Packed IPv4-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
17
22
  validateIpv4BatchPacked(input: Uint8Array): Uint8Array
23
+ /** Packed IPv6-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
18
24
  validateIpv6BatchPacked(input: Uint8Array): Uint8Array
25
+ /** Packed JSON-sum batch: packed `[{id}]` docs → packed `[ok u8][sum i64 LE]`. */
19
26
  jsonSumBatchPacked(input: Uint8Array): Uint8Array
27
+ /** Packed query-string parser batch: packed `[u8[]]` queries → packed pair lists. */
20
28
  queryParseBatchPacked(input: Uint8Array): Uint8Array
29
+ /** Packed cookie-header parser batch: packed `[u8[]]` headers → packed pair lists. */
21
30
  cookieParseBatchPacked(input: Uint8Array): Uint8Array
31
+ /** Packed HTTP-request parser batch: packed `[u8[]]` requests → packed request sections. */
22
32
  httpParseRequestBatchPacked(input: Uint8Array): Uint8Array
23
33
  /** Batch RFC 6902 JSON Patch (two packed lists, zipped) → packed results. */
24
34
  jsonPatchBatchPacked(docs: Uint8Array, patches: Uint8Array): Uint8Array
@@ -26,24 +36,39 @@ export interface RustPacked {
26
36
  fnv1A64BatchPacked(input: Uint8Array): Uint8Array
27
37
  /** Packed ETag batch (10 strong / 12 weak bytes per item). */
28
38
  etagBatchPacked(input: Uint8Array, weak?: boolean | null): Uint8Array
39
+ /** Packed percent-encoding batch: packed `[u8[]]` items → packed hex-percent bytes. */
29
40
  urlEncodeBatchPacked(input: Uint8Array): Uint8Array
41
+ /** Packed percent-decoding batch: packed `[u8[]]` items → packed decoded bytes (string-safe). */
30
42
  urlDecodeBatchPacked(input: Uint8Array): Uint8Array
43
+ /** Packed percent-decoding batch returning raw bytes (`%FF` preserved). */
31
44
  urlDecodeBytesBatchPacked(input: Uint8Array): Uint8Array
45
+ /** Packed MIME-lookup batch: packed `[u8[]]` extensions → packed media-type strings. */
32
46
  mimeFromExtensionBatchPacked(input: Uint8Array): Uint8Array
47
+ /** Packed WebSocket accept-key batch: packed `[u8[]]` keys → packed base64 SHA-1 results. */
33
48
  wsAcceptKeyBatchPacked(input: Uint8Array): Uint8Array
34
49
 
35
50
  // ── Batch metadata / counts ──
51
+ /** Valid JSON count in a packed JSON batch (0..n; invalid items not counted). */
36
52
  jsonValidBatchCountPacked(input: Uint8Array): number
53
+ /** Valid-email count in a packed email batch. */
37
54
  validateEmailBatchCountPacked(input: Uint8Array): number
55
+ /** Valid-UUID count in a packed UUID batch. */
38
56
  validateUuidBatchCountPacked(input: Uint8Array): number
57
+ /** Valid-IPv4 count in a packed IPv4 batch. */
39
58
  validateIpv4BatchCountPacked(input: Uint8Array): number
59
+ /** Valid-IPv6 count in a packed IPv6 batch. */
40
60
  validateIpv6BatchCountPacked(input: Uint8Array): number
61
+ /** Total `id` sum across a packed JSON batch (valid items only). */
41
62
  jsonSumBatchTotalPacked(input: Uint8Array): number
63
+ /** Total packed-output length (bytes) a query batch will produce. */
42
64
  queryParseBatchTotalLenPacked(input: Uint8Array): number
65
+ /** Total packed-output length (bytes) a cookie batch will produce. */
43
66
  cookieParseBatchTotalLenPacked(input: Uint8Array): number
67
+ /** Total packed-output length (bytes) an HTTP-request batch will produce. */
44
68
  httpParseRequestBatchTotalLenPacked(input: Uint8Array): number
45
69
 
46
70
  // ── Backend-framework features ──
71
+ /** Packed Argon2id-hash batch: packed `[u8[]]` passwords + shared salt → packed PHC strings. */
47
72
  passwordHashBatchPacked(
48
73
  input: Uint8Array,
49
74
  salt: Uint8Array,
@@ -53,47 +78,60 @@ export interface RustPacked {
53
78
  passwordVerifyBatchPacked(passwords: Uint8Array, phcs: Uint8Array): Uint8Array
54
79
  /** Packed URL-resolve batch (two packed lists, zipped) → packed results. */
55
80
  urlResolveBatchPacked(bases: Uint8Array, references: Uint8Array): Uint8Array
81
+ /** Packed AEAD-encrypt batch (packed inputs + shared key/nonce) → packed ciphertexts. */
56
82
  aeadEncryptBatchPacked(
57
83
  input: Uint8Array,
58
84
  key: Uint8Array,
59
85
  nonce: Uint8Array,
60
86
  algorithm?: string | null,
61
87
  ): Uint8Array
88
+ /** Packed AEAD-decrypt batch (packed inputs + shared key/nonce) → packed plaintexts. */
62
89
  aeadDecryptBatchPacked(
63
90
  input: Uint8Array,
64
91
  key: Uint8Array,
65
92
  nonce: Uint8Array,
66
93
  algorithm?: string | null,
67
94
  ): Uint8Array
95
+ /** Packed gzip-compress batch: packed `[u8[]]` items → packed gzip streams. */
68
96
  gzipCompressBatchPacked(input: Uint8Array, level?: number | null): Uint8Array
97
+ /** Packed gzip-decompress batch (64 MiB cap per item) → packed plaintexts. */
69
98
  gzipDecompressBatchPacked(input: Uint8Array): Uint8Array
99
+ /** Packed brotli-compress batch: packed `[u8[]]` items → packed brotli streams. */
70
100
  brotliCompressBatchPacked(input: Uint8Array, quality?: number | null): Uint8Array
101
+ /** Packed brotli-decompress batch (64 MiB cap per item) → packed plaintexts. */
71
102
  brotliDecompressBatchPacked(input: Uint8Array): Uint8Array
103
+ /** Packed HS256 JWT-sign batch (packed claims + shared secret) → packed tokens. */
72
104
  jwtSignBatchPacked(
73
105
  input: Uint8Array,
74
106
  secret: Uint8Array,
75
107
  ttlSeconds: number | null,
76
108
  nowSeconds: number,
77
109
  ): Uint8Array
110
+ /** Packed HS256 JWT-verify batch (packed tokens + shared secret) → packed claims/validity. */
78
111
  jwtVerifyBatchPacked(input: Uint8Array, secret: Uint8Array, nowSeconds: number): Uint8Array
79
112
  /** Batch HMAC-SHA256 sign (packed in → hex-signature byte results). */
80
113
  hmacSha256BatchPacked(input: Uint8Array, key: Uint8Array): Uint8Array
81
114
  /** Batch HMAC-SHA256 verify (two packed lists: data + hex sigs, zipped) → bitset. */
82
115
  hmacSha256VerifyBatchPacked(input: Uint8Array, sigs: Uint8Array, key: Uint8Array): Uint8Array
116
+ /** Packed multipart/form-data parser batch (packed bodies + shared boundary) → packed parts. */
83
117
  multipartParseBatchPacked(input: Uint8Array, boundary: Uint8Array): Uint8Array
118
+ /** Packed minijinja template batch: packed contexts + shared source → packed renders. */
84
119
  templateRenderBatchPacked(input: Uint8Array, source: string): Uint8Array
120
+ /** Packed SSE-frame batch: packed data + shared event/id/retry → packed frames. */
85
121
  sseEncodeBatchPacked(
86
122
  input: Uint8Array,
87
123
  event: string | null,
88
124
  id: string | null,
89
125
  retry: number | null,
90
126
  ): Uint8Array
127
+ /** Packed WebSocket-frame encode batch: packed payloads + shared opcode/mask/fin → packed frames. */
91
128
  wsFrameEncodeBatchPacked(
92
129
  input: Uint8Array,
93
130
  opcode: number,
94
131
  mask: boolean,
95
132
  fin: boolean,
96
133
  ): Uint8Array
134
+ /** Packed WebSocket-frame decode batch: packed frames → packed (fin, opcode, payload) results. */
97
135
  wsFrameDecodeBatchPacked(input: Uint8Array): Uint8Array
98
136
  }
99
137
 
@@ -162,6 +162,10 @@ function ffiAcceptNegotiator(
162
162
  void keepAlive
163
163
  return ffi.acceptNegotiatorNegotiate(inner, header)
164
164
  },
165
+ negotiateServerPreference(header) {
166
+ void keepAlive
167
+ return ffi.acceptNegotiatorNegotiateServer(inner, header)
168
+ },
165
169
  }
166
170
  }
167
171