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.
Files changed (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -368
  3. package/castrum.linux-x64-gnu.node +0 -0
  4. package/dist/index.d.ts +2763 -0
  5. package/dist/index.js +8707 -0
  6. package/docs/API.md +337 -0
  7. package/docs/ARCHITECTURE.md +507 -0
  8. package/docs/BENCHMARKS.md +343 -0
  9. package/docs/CASE_STUDY.md +240 -0
  10. package/docs/ENVIRONMENT.md +81 -0
  11. package/docs/FFI_BUN_GUIDE.md +327 -0
  12. package/docs/GETTING_STARTED.md +192 -0
  13. package/docs/INGRESS-ROUTER.md +81 -0
  14. package/docs/INGRESS.md +746 -0
  15. package/docs/NATIVE-ROUTE.md +53 -0
  16. package/docs/REPO_MAP.md +279 -0
  17. package/docs/adr/0001-two-wire-formats.md +39 -0
  18. package/docs/adr/0002-zero-dom-fast-schema.md +38 -0
  19. package/docs/adr/0003-bun-builtins-delegation.md +43 -0
  20. package/docs/bun-builtins-decision-matrix.md +115 -0
  21. package/index.ts +44 -8
  22. package/package.json +98 -33
  23. package/src/ingress/body.ts +289 -0
  24. package/src/ingress/constants.ts +220 -48
  25. package/src/ingress/context.ts +136 -0
  26. package/src/ingress/decode/baked-result.ts +121 -0
  27. package/src/ingress/decode/fast-result.ts +160 -0
  28. package/src/ingress/decode/packed-sections.ts +56 -0
  29. package/src/ingress/decode/result-base.ts +172 -0
  30. package/src/ingress/errors.ts +72 -0
  31. package/src/ingress/fast.ts +152 -1021
  32. package/src/ingress/handlers.ts +639 -1001
  33. package/src/ingress/headers/baked-templates.ts +102 -0
  34. package/src/ingress/headers/cors.ts +44 -0
  35. package/src/ingress/headers/fast-templates.ts +238 -0
  36. package/src/ingress/headers/hsts.ts +83 -0
  37. package/src/ingress/health.ts +68 -0
  38. package/src/ingress/index.ts +142 -405
  39. package/src/ingress/metrics.ts +132 -0
  40. package/src/ingress/options.ts +197 -0
  41. package/src/ingress/packing/gather-raw-headers.ts +139 -0
  42. package/src/ingress/packing/header-packing.ts +75 -0
  43. package/src/ingress/packing/input-packer.ts +164 -0
  44. package/src/ingress/packing/scratch.ts +50 -0
  45. package/src/ingress/packing/select-headers.ts +102 -0
  46. package/src/ingress/response/error-bodies.ts +75 -0
  47. package/src/ingress/response/terminal.ts +59 -0
  48. package/src/ingress/router.ts +237 -0
  49. package/src/ingress/routes/common.ts +79 -0
  50. package/src/ingress/routes/delete.ts +14 -0
  51. package/src/ingress/routes/echo.ts +107 -0
  52. package/src/ingress/routes/fallback.ts +23 -0
  53. package/src/ingress/routes/head.ts +27 -0
  54. package/src/ingress/routes/index.ts +11 -0
  55. package/src/ingress/routes/json-write.ts +129 -0
  56. package/src/ingress/routes/options.ts +26 -0
  57. package/src/ingress/routes/read.ts +35 -0
  58. package/src/ingress/routes/responder.ts +159 -0
  59. package/src/ingress/server-node.ts +376 -0
  60. package/src/ingress/server.ts +475 -0
  61. package/src/ingress/shared.ts +132 -0
  62. package/src/ingress/status.ts +97 -0
  63. package/src/ingress/types.ts +191 -0
  64. package/src/integration/batch.ts +58 -0
  65. package/src/integration/index.ts +29 -0
  66. package/src/integration/pipeline.ts +220 -0
  67. package/src/integration/streaming.ts +78 -0
  68. package/src/integration/websocket.ts +93 -0
  69. package/src/loader/batch.ts +137 -0
  70. package/src/loader/cost.ts +105 -0
  71. package/src/loader/index.ts +745 -0
  72. package/src/loader/ops.ts +657 -0
  73. package/src/loader/state.ts +84 -0
  74. package/src/loader/types.ts +145 -0
  75. package/src/native/ffi/constants.ts +58 -0
  76. package/src/native/ffi/selftest.ts +729 -0
  77. package/src/native/ffi/types.ts +474 -0
  78. package/src/native/ffi.ts +1775 -0
  79. package/src/native/index.ts +8 -207
  80. package/src/native/loader.ts +240 -0
  81. package/src/native/types/instances.ts +274 -0
  82. package/src/native/types.ts +401 -0
  83. package/src/runtime/builtins.ts +131 -0
  84. package/src/runtime/codec.ts +147 -0
  85. package/src/runtime/detect.ts +36 -0
  86. package/src/runtime/index.ts +28 -0
  87. package/src/runtime/native.ts +35 -0
  88. package/src/runtime/server.ts +31 -0
  89. package/src/runtime/transport.ts +64 -0
  90. package/src/runtime/types.ts +173 -0
  91. package/src/runtime/uuid.ts +45 -0
  92. package/src/runtime/websocket.ts +30 -0
  93. package/src/rust-ffi/addon.ts +10 -0
  94. package/src/rust-ffi/batch/build.ts +155 -0
  95. package/src/rust-ffi/batch/index.ts +8 -0
  96. package/src/rust-ffi/batch/types.ts +92 -0
  97. package/src/rust-ffi/client.ts +87 -0
  98. package/src/rust-ffi/context.ts +193 -0
  99. package/src/rust-ffi/index.ts +51 -541
  100. package/src/rust-ffi/into.ts +21 -0
  101. package/src/rust-ffi/options.ts +113 -0
  102. package/src/rust-ffi/packed.ts +253 -0
  103. package/src/rust-ffi/proven.ts +28 -0
  104. package/src/rust-ffi/scalar/crypto.ts +346 -0
  105. package/src/rust-ffi/scalar/factories.ts +459 -0
  106. package/src/rust-ffi/scalar/hashing.ts +74 -0
  107. package/src/rust-ffi/scalar/http.ts +337 -0
  108. package/src/rust-ffi/scalar/index.ts +31 -0
  109. package/src/rust-ffi/scalar/interface.ts +325 -0
  110. package/src/rust-ffi/scalar/json-packed.ts +175 -0
  111. package/src/rust-ffi/scalar/json.ts +61 -0
  112. package/src/rust-ffi/scalar/payload.ts +241 -0
  113. package/src/rust-ffi/text.ts +121 -0
  114. package/src/selection.json +194 -0
  115. package/src/selection.ts +73 -0
  116. package/src/shared/adaptive.ts +67 -0
  117. package/src/shared/buffer-pool.ts +264 -0
  118. package/src/shared/bytes.ts +108 -9
  119. package/src/shared/codec.ts +78 -0
  120. package/src/shared/env.ts +20 -0
  121. package/src/shared/log.ts +75 -0
  122. package/src/shared/metrics.ts +247 -0
  123. package/src/shared/packed/index.ts +10 -0
  124. package/src/shared/packed/parsers.ts +31 -0
  125. package/src/shared/packed/schema.ts +23 -0
  126. package/src/shared/packed/wire.ts +504 -0
  127. package/src/shared/proven.ts +289 -0
  128. package/src/shared/request-id.ts +67 -0
  129. package/src/shared/response.ts +104 -0
  130. package/src/shared/runtime.ts +29 -0
  131. package/src/shared/trace.ts +81 -0
  132. package/src/shared/uuid.ts +15 -0
  133. package/Cargo.toml +0 -73
  134. package/bench.ts +0 -3
  135. package/rust/batch.rs +0 -195
  136. package/rust/cookie_parser.rs +0 -70
  137. package/rust/cors.rs +0 -263
  138. package/rust/hashing.rs +0 -164
  139. package/rust/headers.rs +0 -234
  140. package/rust/hmac_sha256.rs +0 -113
  141. package/rust/http_parser.rs +0 -132
  142. package/rust/ingress.rs +0 -616
  143. package/rust/ingress_constants.rs +0 -89
  144. package/rust/ip_trust.rs +0 -185
  145. package/rust/json_ops.rs +0 -66
  146. package/rust/json_patch_ops.rs +0 -25
  147. package/rust/json_schema.rs +0 -151
  148. package/rust/json_ser.rs +0 -429
  149. package/rust/lib.rs +0 -48
  150. package/rust/method.rs +0 -141
  151. package/rust/mime_lookup.rs +0 -76
  152. package/rust/output.rs +0 -238
  153. package/rust/proxy.rs +0 -90
  154. package/rust/query_parser.rs +0 -141
  155. package/rust/random_token.rs +0 -52
  156. package/rust/rate_limit.rs +0 -203
  157. package/rust/terminal.rs +0 -95
  158. package/rust/unit_tests.rs +0 -843
  159. package/rust/url_codec.rs +0 -133
  160. package/rust/util.rs +0 -537
  161. package/rust/validation.rs +0 -107
  162. package/rust/websocket.rs +0 -23
  163. package/src/baseline/index.ts +0 -12
  164. package/src/baseline/tasks/cookie.ts +0 -22
  165. package/src/baseline/tasks/hashing.ts +0 -18
  166. package/src/baseline/tasks/hmac.ts +0 -38
  167. package/src/baseline/tasks/http.ts +0 -62
  168. package/src/baseline/tasks/json-patch.ts +0 -12
  169. package/src/baseline/tasks/json.ts +0 -50
  170. package/src/baseline/tasks/mime.ts +0 -5
  171. package/src/baseline/tasks/query.ts +0 -14
  172. package/src/baseline/tasks/token.ts +0 -15
  173. package/src/baseline/tasks/url.ts +0 -11
  174. package/src/baseline/tasks/validation.ts +0 -19
  175. package/src/baseline/tasks/websocket.ts +0 -14
  176. package/src/bench/assert.ts +0 -70
  177. package/src/bench/checks.ts +0 -227
  178. package/src/bench/checksum.ts +0 -27
  179. package/src/bench/comparisons.ts +0 -70
  180. package/src/bench/concurrent-worker.ts +0 -135
  181. package/src/bench/fixtures.ts +0 -233
  182. package/src/bench/index.ts +0 -2
  183. package/src/bench/measure.ts +0 -177
  184. package/src/bench/now.ts +0 -3
  185. package/src/bench/report.ts +0 -79
  186. package/src/bench/run.ts +0 -57
  187. package/src/bench/tasks/complex.ts +0 -232
  188. package/src/bench/tasks/concurrent.ts +0 -213
  189. package/src/bench/tasks/cookie.ts +0 -44
  190. package/src/bench/tasks/hashing.ts +0 -33
  191. package/src/bench/tasks/hmac.ts +0 -36
  192. package/src/bench/tasks/http.ts +0 -50
  193. package/src/bench/tasks/index.ts +0 -52
  194. package/src/bench/tasks/json-patch.ts +0 -21
  195. package/src/bench/tasks/json.ts +0 -33
  196. package/src/bench/tasks/mime.ts +0 -21
  197. package/src/bench/tasks/query.ts +0 -44
  198. package/src/bench/tasks/stress.ts +0 -142
  199. package/src/bench/tasks/token.ts +0 -20
  200. package/src/bench/tasks/url.ts +0 -34
  201. package/src/bench/tasks/validation.ts +0 -57
  202. package/src/bench/tasks/websocket.ts +0 -21
  203. package/src/bench/types.ts +0 -60
  204. package/src/data/json-rows.ts +0 -33
  205. package/src/ingress/packed-input.ts +0 -59
  206. package/src/shared/json.ts +0 -18
  207. package/src/shared/packed.ts +0 -316
@@ -0,0 +1,274 @@
1
+ // src/native/types/instances.ts — Native addon class-instance types.
2
+ //
3
+ // The per-class instance interfaces + their result/option payload types,
4
+ // separated from `NativeAddon` (the module surface in ../types.ts) so the
5
+ // class-shaped types live in one place. `../types.ts` re-exports everything
6
+ // here, so `import { IngressInstance } from '../native/types'` keeps working.
7
+
8
+ /** The native Ingress class instance (hot-path pipeline). */
9
+ export interface IngressInstance {
10
+ handleRequestPacked(input: Uint8Array, body: Uint8Array | null, output: Uint8Array): number
11
+
12
+ handleRequestFullSync(
13
+ methodKind: number,
14
+ url: string,
15
+ ip: string,
16
+ requestId: string,
17
+ headers: Array<[string, string]>,
18
+ body: Uint8Array | null,
19
+ outputBufferSize?: number,
20
+ ): Uint8Array
21
+
22
+ /**
23
+ * Reusable-output variant of `handleRequestFullSync`: packs the request in
24
+ * Rust and writes the packed decision into `output`, returning the number of
25
+ * bytes written. Pool the output buffer across requests to avoid per-request
26
+ * allocation (see `src/shared/buffer-pool.ts`).
27
+ */
28
+ handleRequestFullSyncInto(
29
+ methodKind: number,
30
+ url: string,
31
+ ip: string,
32
+ requestId: string,
33
+ headers: Array<[string, string]>,
34
+ body: Uint8Array | null,
35
+ output: Uint8Array,
36
+ ): number
37
+
38
+ /**
39
+ * Opaque handle to the inner pipeline state for the `bun:ffi` fast path.
40
+ * Internal only — the returned pointer is valid only while THIS instance is
41
+ * alive and must never be dereferenced from JS. Present only on addons built
42
+ * with the `castrum_ingress_handle_packed` C-ABI export; guard with
43
+ * `typeof handler.ingressInnerPtr === 'function'`.
44
+ */
45
+ ingressInnerPtr?(): bigint
46
+ }
47
+
48
+ /**
49
+ * The native `Route` class instance (per-route native stack — the
50
+ * `@ignex/native` route-wire v3 contract). Constructed from a compiled route
51
+ * descriptor; `run` processes one packed request frame and returns the packed
52
+ * verdict result bytes written (`0` = error / too-small, `> output.length` =
53
+ * the exact required size — the growExact convention).
54
+ */
55
+ export interface RouteInstance {
56
+ run(frame: Uint8Array, output: Uint8Array): number
57
+ destroy?(): void
58
+ }
59
+
60
+ /** A single JSON Schema validation error (fast path + DOM fallback). */
61
+ export interface SchemaError {
62
+ /** RFC 6901 JSON pointer to the failing instance value ("" = root). */
63
+ instancePath: string
64
+ /** JSON pointer into the schema at the failing keyword. */
65
+ schemaPath: string
66
+ /** The failing keyword (e.g. "type", "pattern", "required"). */
67
+ keyword: string
68
+ /** Human-readable failure message. */
69
+ message: string
70
+ }
71
+
72
+ /** The native `SchemaValidator` class instance. */
73
+ export interface SchemaValidatorInstance {
74
+ /** Validate a single JSON document. */
75
+ validate(input: Uint8Array): boolean
76
+ /** Opaque handle (bun:ffi fast path) — `castrum_schema_validator_validate`. */
77
+ innerPtr?(): bigint
78
+ /** Validate a single JSON document, returning detailed errors (empty = valid). */
79
+ validateDetailed(input: Uint8Array): SchemaError[]
80
+ /** Validate a single JSON document, returning only the first error (null = valid). */
81
+ validateFirstError(input: Uint8Array): SchemaError | null
82
+ validateBatchPackedCount(packed: Uint8Array): number
83
+ validateBatchPackedBitset(packed: Uint8Array): Uint8Array
84
+ /**
85
+ * One-pass validate + extract: validate `input` against the schema and
86
+ * capture scalar values / array lengths at `paths` during the same native
87
+ * walk (no `JSON.parse`, no DOM). For "derive" routes (response built from a
88
+ * handful of body fields) this replaces `JSON.parse` + Ajv on the happy path
89
+ * and rejects invalid bodies with zero DOM/GC.
90
+ *
91
+ * `paths` are RFC 6901 JSON pointers of OBJECT KEYS; a trailing `/-`
92
+ * captures the ARRAY LENGTH at that path (e.g. `"/totalCents"`,
93
+ * `"/lineItems/-"`). Array-index steps are not supported.
94
+ */
95
+ derive(input: Uint8Array, paths: string[]): JsonDeriveResult
96
+ }
97
+
98
+ /** A single derived value captured during one-pass validation. */
99
+ export interface JsonDeriveValue {
100
+ /** `"int" | "number" | "string" | "bool" | "null"`. */
101
+ kind: string
102
+ int: number | null
103
+ number: number | null
104
+ text: string | null
105
+ boolean: boolean | null
106
+ }
107
+
108
+ /** Result of a one-pass `validate + derive`. */
109
+ export interface JsonDeriveResult {
110
+ /** `true` when the document is schema-valid; `false` → caller rejects. */
111
+ ok: boolean
112
+ /** One entry per requested path (`null` = path absent from the document). */
113
+ values: Array<JsonDeriveValue | null>
114
+ }
115
+
116
+ /** The native `HmacSigner` class instance. */
117
+ export interface HmacSignerInstance {
118
+ sign(data: Uint8Array): Uint8Array
119
+ verify(data: Uint8Array, sig: Uint8Array): boolean
120
+ }
121
+
122
+ /** The native `FormParser` class instance (reusable output buffer). */
123
+ export interface FormParserInstance {
124
+ /** Parse an x-www-form-urlencoded body into packed pairs (reuses the buffer). */
125
+ parse(input: Uint8Array): Uint8Array
126
+ /** Zero-alloc parse into a caller-provided output buffer. */
127
+ parseInto(input: Uint8Array, output: Uint8Array): number
128
+ }
129
+
130
+ /** A parsed Content-Type / media type. */
131
+ export interface MediaTypeResult {
132
+ /** Lowercased `type/subtype`. */
133
+ mediaType: string
134
+ charset: string | null
135
+ boundary: string | null
136
+ params: Record<string, string>
137
+ }
138
+
139
+ /** The native `MediaTypeParser` class instance. */
140
+ export interface MediaTypeParserInstance {
141
+ parse(input: Uint8Array): MediaTypeResult
142
+ }
143
+
144
+ /** The native `ConditionalRequest` class instance (per-resource 304 checks). */
145
+ export interface ConditionalRequestInstance {
146
+ isNotModified(ifNoneMatch: Uint8Array | null, ifModifiedSince: Uint8Array | null): boolean
147
+ /** Opaque handle to the precompiled state (present when the bun:ffi fast path
148
+ * is active) — `castrum_conditional_is_not_modified` in rust/ffi.rs. */
149
+ innerPtr?(): bigint
150
+ }
151
+
152
+ /** One parsed Accept-Encoding preference. */
153
+ export interface EncodingPrefResult {
154
+ encoding: string
155
+ q: number
156
+ order: number
157
+ }
158
+
159
+ /**
160
+ * The native `AcceptNegotiator` class instance (supported encodings compiled
161
+ * once). Best supported encoding for a header, or `null` for identity.
162
+ */
163
+ export interface AcceptNegotiatorInstance {
164
+ /** Best supported encoding for `header`, or null for identity. */
165
+ negotiate(header: Uint8Array): string | null
166
+ /** Opaque handle (bun:ffi fast path) — `castrum_accept_negotiator_negotiate`. */
167
+ innerPtr?(): bigint
168
+ }
169
+
170
+ /** The native `Base64Codec` class instance (config compiled once). */
171
+ export interface Base64CodecInstance {
172
+ encode(input: Uint8Array): Uint8Array
173
+ decode(input: Uint8Array): Uint8Array
174
+ }
175
+
176
+ /** Result of a native rate-limit check for one key at a point in time. */
177
+ export interface RateCheckResult {
178
+ allowed: boolean
179
+ remaining: number
180
+ resetMs: number
181
+ }
182
+
183
+ /** The native `RateLimiter` class instance (sharded fixed-window state). */
184
+ export interface RateLimiterInstance {
185
+ check(key: string, nowMs: number): RateCheckResult
186
+ checkKey(key: number, nowMs: number): RateCheckResult
187
+ /** Opaque handle (bun:ffi fast path) — `castrum_rate_limiter_check*`. */
188
+ innerPtr?(): bigint
189
+ }
190
+
191
+ /** The native `CookieSigner` class instance (HMAC key compiled once). */
192
+ export interface CookieSignerInstance {
193
+ sign(value: Uint8Array): Uint8Array
194
+ /** Returns the signed value without its signature, or null on invalid. */
195
+ verify(signed: Uint8Array): Uint8Array | null
196
+ }
197
+
198
+ /** The native `CsrfProtector` class instance (HMAC key compiled once). */
199
+ export interface CsrfProtectorInstance {
200
+ create(): Uint8Array
201
+ verify(token: Uint8Array): boolean
202
+ }
203
+
204
+ /** The native `UrlBuilder` class instance (base parsed once). */
205
+ export interface UrlBuilderInstance {
206
+ resolve(reference: Uint8Array): Uint8Array
207
+ /** Opaque handle to the precompiled base (present when the bun:ffi fast path
208
+ * is active) — `castrum_url_builder_resolve` in rust/ffi.rs. */
209
+ innerPtr?(): bigint
210
+ }
211
+
212
+ /** Options for `passwordHash` (argon2id). */
213
+ export interface PasswordHashOptions {
214
+ mCost?: number
215
+ tCost?: number
216
+ pCost?: number
217
+ outLen?: number
218
+ }
219
+
220
+ /** A parsed multipart/form-data part. */
221
+ export interface MultipartPart {
222
+ name: string
223
+ filename: string | null
224
+ contentType: string | null
225
+ data: Uint8Array
226
+ }
227
+
228
+ /** A decoded RFC 6455 websocket frame. */
229
+ export interface WsFrame {
230
+ fin: boolean
231
+ opcode: number
232
+ payload: Uint8Array
233
+ }
234
+
235
+ /** The native `TemplateRenderer` class instance. */
236
+ export interface TemplateRendererInstance {
237
+ render(context: unknown): Uint8Array
238
+ /** Render from pre-serialized JSON context bytes (no napi Value marshal). */
239
+ renderBytes(contextJson: Uint8Array): Uint8Array
240
+ /** Parallel batch render: packed contexts in → packed rendered out. */
241
+ renderBatchPacked(data: Uint8Array): Uint8Array
242
+ /** Opaque handle (bun:ffi fast path) — `castrum_template_render`. */
243
+ innerPtr?(): bigint
244
+ }
245
+
246
+ /** The native `MediaTypeMatcher` class instance (expected precompiled once). */
247
+ export interface MediaTypeMatcherInstance {
248
+ /** Wildcard match against the precompiled expected type. */
249
+ matches(actual: Uint8Array): boolean
250
+ /** Opaque handle (bun:ffi fast path) — `castrum_media_type_matcher_matches`. */
251
+ innerPtr?(): bigint
252
+ }
253
+
254
+ /** The native `JwtSigner` class instance (HS256 key + ttl compiled once). */
255
+ export interface JwtSignerInstance {
256
+ sign(claims: unknown, nowSeconds: number): Uint8Array
257
+ /** Sign from pre-serialized claim JSON bytes (no napi Value marshal). */
258
+ signBytes(claimsJson: Uint8Array, nowSeconds: number): Uint8Array
259
+ verify(token: Uint8Array, nowSeconds: number): unknown
260
+ /** Opaque handle (bun:ffi fast path) — `castrum_jwt_signer_*`. */
261
+ innerPtr?(): bigint
262
+ }
263
+
264
+ /** The native `AeadCipher` class instance (algorithm + key compiled once). */
265
+ export interface AeadCipherInstance {
266
+ encrypt(nonce: Uint8Array, plaintext: Uint8Array): Uint8Array
267
+ decrypt(nonce: Uint8Array, ciphertext: Uint8Array): Uint8Array | null
268
+ }
269
+
270
+ /** The native `Argon2Hasher` class instance (params compiled once). */
271
+ export interface Argon2HasherInstance {
272
+ hash(password: Uint8Array, salt: Uint8Array): Uint8Array
273
+ verify(password: Uint8Array, phc: Uint8Array): boolean
274
+ }
@@ -0,0 +1,401 @@
1
+ // src/native/types.ts — Type declarations for the native addon surface.
2
+ //
3
+ // The `NativeAddon` interface mirrors the napi-rs generated declaration
4
+ // (index.d.ts) and types every class + function + layout constant exported by
5
+ // the Rust cdylib. Keeping it separate from the loader (./loader.ts) means
6
+ // type-only consumers never pull in the file-system loading logic.
7
+ //
8
+ // The per-class INSTANCE types live in ./types/instances.ts. They are imported
9
+ // here (so `NativeAddon` can reference them) and re-exported so existing
10
+ // `import { X } from '../native/types'` call sites keep working.
11
+
12
+ import type {
13
+ AcceptNegotiatorInstance,
14
+ AeadCipherInstance,
15
+ Argon2HasherInstance,
16
+ Base64CodecInstance,
17
+ ConditionalRequestInstance,
18
+ CookieSignerInstance,
19
+ CsrfProtectorInstance,
20
+ EncodingPrefResult,
21
+ FormParserInstance,
22
+ HmacSignerInstance,
23
+ IngressInstance,
24
+ JwtSignerInstance,
25
+ MediaTypeMatcherInstance,
26
+ MediaTypeParserInstance,
27
+ MediaTypeResult,
28
+ MultipartPart,
29
+ PasswordHashOptions,
30
+ RateLimiterInstance,
31
+ RouteInstance,
32
+ SchemaValidatorInstance,
33
+ TemplateRendererInstance,
34
+ UrlBuilderInstance,
35
+ WsFrame,
36
+ } from './types/instances'
37
+
38
+ export * from './types/instances'
39
+
40
+ /**
41
+ * Full shape of the native addon module: classes, scalar/batch functions and
42
+ * the ingress binary-layout constants (single source of truth:
43
+ * rust/ingress_constants.rs).
44
+ */
45
+ export interface NativeAddon {
46
+ HmacSigner: new (key: Uint8Array) => HmacSignerInstance
47
+ Ingress: new (options: Record<string, unknown>) => IngressInstance
48
+ /**
49
+ * Per-route native stack (the `@ignex/native` route-wire v3 contract).
50
+ * Compile a route descriptor once at construction; `run` processes one
51
+ * packed request frame (parseQuery/parseCookies/requireJsonBody/
52
+ * validateBody) into the packed verdict result.
53
+ */
54
+ Route: new (
55
+ descriptor: Uint8Array,
56
+ ) => RouteInstance
57
+
58
+ /**
59
+ * Benchmark-driven native-vs-JS decision (single source of truth:
60
+ * `rust/selection.rs`, audited by `scripts/select-native.ts --check`).
61
+ * Returns `"native"` when the Rust addon is the recommended impl for `op`,
62
+ * `"js"` when a pure-JS implementation wins, or `null` for unknown ops.
63
+ * Consumers read this ONCE at load time and bind each op to a fixed impl.
64
+ */
65
+ opImpl(op: string): 'native' | 'js' | null
66
+
67
+ // ── Ingress binary-layout constants (single source of truth: rust/ingress_constants.rs) ──
68
+ INGRESS_OUT_VERDICT: number
69
+ INGRESS_OUT_ERROR_CODE: number
70
+ INGRESS_OUT_STATUS: number
71
+ INGRESS_OUT_FLAGS: number
72
+ INGRESS_OUT_RATE_LIMIT: number
73
+ INGRESS_OUT_RATE_REMAINING: number
74
+ INGRESS_OUT_RATE_RESET: number
75
+ INGRESS_OUT_RETRY_AFTER: number
76
+ INGRESS_OUT_COOKIES_JSON_LEN: number
77
+ INGRESS_OUT_QUERY_JSON_LEN: number
78
+ INGRESS_OUT_HEADER_VARIANT: number
79
+ INGRESS_OUT_BODY_JSON_LEN: number
80
+ INGRESS_OUT_DATA_START: number
81
+ INGRESS_FLAG_HAS_COOKIES: number
82
+ INGRESS_FLAG_HAS_QUERY: number
83
+ INGRESS_FLAG_BODY_VALID_JSON: number
84
+ INGRESS_FLAG_SCHEMA_VALID: number
85
+ INGRESS_FLAG_CORS_ALLOWED: number
86
+ INGRESS_FLAG_IS_PREFLIGHT: number
87
+ INGRESS_FLAG_RATE_LIMITED: number
88
+ INGRESS_FLAG_HTTPS: number
89
+ INGRESS_FLAG_TRUSTED_PROXY: number
90
+ INGRESS_FLAG_BODY_TRUNCATED: number
91
+ INGRESS_HV_JSON: number
92
+ INGRESS_HV_CORS_SIMPLE: number
93
+ INGRESS_HV_CORS_PREFLIGHT: number
94
+ INGRESS_HV_RATE_ACTIVE: number
95
+ INGRESS_HV_RATE_LIMITED: number
96
+ INGRESS_HV_COUNT: number
97
+ INGRESS_ERR_NONE: number
98
+ INGRESS_ERR_CORS_PREFLIGHT: number
99
+ INGRESS_ERR_RATE_LIMITED: number
100
+ INGRESS_ERR_BODY_TOO_LARGE: number
101
+ INGRESS_ERR_INVALID_JSON: number
102
+ INGRESS_ERR_SCHEMA_VALIDATION: number
103
+ INGRESS_ERR_BAD_REQUEST: number
104
+ INGRESS_ERR_REQUEST_TOO_LARGE: number
105
+ INGRESS_ERR_INTERNAL: number
106
+
107
+ crc32(input: Uint8Array): number
108
+ fnv1a64(input: Uint8Array): bigint
109
+ /** XXH3-64 (high-throughput non-cryptographic hash). */
110
+ xxh3(input: Uint8Array): bigint
111
+ /** Packed FNV-1a 64 batch (i64 per item). */
112
+ fnv1A64BatchPacked(input: Uint8Array): Uint8Array
113
+
114
+ hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array
115
+ hmacSha256Verify(key: Uint8Array, data: Uint8Array, sig: Uint8Array): boolean
116
+
117
+ jsonValid(input: Uint8Array): boolean
118
+ jsonParse(input: Uint8Array): unknown
119
+ jsonSumIds(input: Uint8Array): bigint
120
+
121
+ jsonPatch(doc: Uint8Array, patch: Uint8Array): Uint8Array
122
+ /** Batch RFC 6902 JSON Patch (two packed lists, zipped) → packed results. */
123
+ jsonPatchBatchPacked(docs: Uint8Array, patches: Uint8Array): Uint8Array
124
+
125
+ mimeFromExtension(ext: Uint8Array): Uint8Array
126
+ mimeFromExtensionBatchPacked(input: Uint8Array): Uint8Array
127
+ randomToken(byteLen: number): Uint8Array
128
+
129
+ urlEncode(input: Uint8Array): Uint8Array
130
+ /** String-input percent-encode (no Uint8Array round-trip). */
131
+ urlEncodeStr(input: string): string
132
+ /** String-input percent-decode; throws on invalid UTF-8 output. */
133
+ urlDecodeStr(input: string): string
134
+ urlDecode(input: Uint8Array): Uint8Array
135
+ urlDecodeBytes(input: Uint8Array): Uint8Array
136
+ urlEncodeBatchPacked(input: Uint8Array): Uint8Array
137
+ urlDecodeBatchPacked(input: Uint8Array): Uint8Array
138
+ urlDecodeBytesBatchPacked(input: Uint8Array): Uint8Array
139
+ /** Reusable-output percent-encode; returns bytes written. Throws if `output` is too small. */
140
+ urlEncodeInto(input: Uint8Array, output: Uint8Array): number
141
+ /** Reusable-output percent-decode; returns bytes written. Throws if `output` is too small. */
142
+ urlDecodeInto(input: Uint8Array, output: Uint8Array): number
143
+
144
+ validateEmail(input: Uint8Array): boolean
145
+ validateUuid(input: Uint8Array): boolean
146
+ validateIpv4(input: Uint8Array): boolean
147
+ validateIpv6(input: Uint8Array): boolean
148
+
149
+ wsAcceptKey(key: Uint8Array): Uint8Array
150
+ wsAcceptKeyBatchPacked(input: Uint8Array): Uint8Array
151
+
152
+ // ── Backend-framework features ──
153
+ jwtSign(
154
+ claims: unknown,
155
+ secret: Uint8Array,
156
+ ttlSeconds: number | null,
157
+ nowSeconds: number,
158
+ ): Uint8Array
159
+ /** Sign from pre-serialized claim JSON bytes (no napi Value marshal). */
160
+ jwtSignBytes(
161
+ claimsJson: Uint8Array,
162
+ secret: Uint8Array,
163
+ ttlSeconds: number | null,
164
+ nowSeconds: number,
165
+ ): Uint8Array
166
+ jwtVerify(token: Uint8Array, secret: Uint8Array, nowSeconds: number): unknown
167
+
168
+ passwordHash(
169
+ password: Uint8Array,
170
+ salt: Uint8Array,
171
+ options?: PasswordHashOptions | null,
172
+ ): Uint8Array
173
+ passwordVerify(password: Uint8Array, phc: Uint8Array): boolean
174
+ /** bcrypt password hash → `$2b$` PHC string (cost clamped 4..=31). */
175
+ passwordHashBcrypt(password: Uint8Array, cost: number): string
176
+ /** Verify a password against a bcrypt `$2b$` PHC string. */
177
+ passwordVerifyBcrypt(password: Uint8Array, hash: string): boolean
178
+ /** PBKDF2-HMAC-SHA256 key derivation (dkLen clamped to 1 MiB). */
179
+ pbkdf2Sha256(password: Uint8Array, salt: Uint8Array, rounds: number, dkLen: number): Uint8Array
180
+ /** Packed password-verify batch (two packed lists, zipped) → bitset. */
181
+ passwordVerifyBatchPacked(passwords: Uint8Array, phcs: Uint8Array): Uint8Array
182
+ passwordHashBatchPacked(
183
+ data: Uint8Array,
184
+ salt: Uint8Array,
185
+ options?: PasswordHashOptions | null,
186
+ ): Uint8Array
187
+
188
+ aeadEncrypt(
189
+ key: Uint8Array,
190
+ nonce: Uint8Array,
191
+ plaintext: Uint8Array,
192
+ algorithm?: string | null,
193
+ ): Uint8Array
194
+ aeadDecrypt(
195
+ key: Uint8Array,
196
+ nonce: Uint8Array,
197
+ ciphertext: Uint8Array,
198
+ algorithm?: string | null,
199
+ ): Uint8Array | null
200
+ aeadEncryptBatchPacked(
201
+ data: Uint8Array,
202
+ key: Uint8Array,
203
+ nonce: Uint8Array,
204
+ algorithm?: string | null,
205
+ ): Uint8Array
206
+ aeadDecryptBatchPacked(
207
+ data: Uint8Array,
208
+ key: Uint8Array,
209
+ nonce: Uint8Array,
210
+ algorithm?: string | null,
211
+ ): Uint8Array
212
+
213
+ gzipCompress(data: Uint8Array, level?: number | null): Uint8Array
214
+ gzipDecompress(data: Uint8Array, maxDecompressed?: number | null): Uint8Array
215
+ brotliCompress(data: Uint8Array, quality?: number | null): Uint8Array
216
+ brotliDecompress(data: Uint8Array, maxDecompressed?: number | null): Uint8Array
217
+ gzipCompressBatchPacked(data: Uint8Array, level?: number | null): Uint8Array
218
+ gzipDecompressBatchPacked(data: Uint8Array, maxDecompressed?: number | null): Uint8Array
219
+ brotliCompressBatchPacked(data: Uint8Array, quality?: number | null): Uint8Array
220
+ brotliDecompressBatchPacked(data: Uint8Array, maxDecompressed?: number | null): Uint8Array
221
+
222
+ multipartParse(body: Uint8Array, boundary: Uint8Array): MultipartPart[]
223
+ multipartParseBatchPacked(data: Uint8Array, boundary: Uint8Array): Uint8Array
224
+ /** Zero-copy scalar sibling of `multipartParse` — returns the packed parts
225
+ * layout (`[u32 count]{[u32 len][name][has_filename][filename][ct][data]}`)
226
+ * instead of JS objects, skipping the per-part String alloc + data copy. */
227
+ multipartParsePacked(body: Uint8Array, boundary: Uint8Array): Uint8Array
228
+ jwtSignBatchPacked(
229
+ data: Uint8Array,
230
+ secret: Uint8Array,
231
+ ttlSeconds: number | null,
232
+ nowSeconds: number,
233
+ ): Uint8Array
234
+ jwtVerifyBatchPacked(data: Uint8Array, secret: Uint8Array, nowSeconds: number): Uint8Array
235
+
236
+ TemplateRenderer: new (source: string) => TemplateRendererInstance
237
+ templateRenderBatchPacked(data: Uint8Array, source: string): Uint8Array
238
+ JwtSigner: new (secret: Uint8Array, ttlSeconds?: number | null) => JwtSignerInstance
239
+ AeadCipher: new (key: Uint8Array, algorithm?: string | null) => AeadCipherInstance
240
+ Argon2Hasher: new (options?: PasswordHashOptions | null) => Argon2HasherInstance
241
+ MediaTypeMatcher: new (expected: Uint8Array) => MediaTypeMatcherInstance
242
+ RateLimiter: new (
243
+ limit: number,
244
+ windowMs: number,
245
+ maxEntries?: number | null,
246
+ ) => RateLimiterInstance
247
+
248
+ wsFrameEncode(opcode: number, payload: Uint8Array, mask: boolean, fin: boolean): Uint8Array
249
+ wsFrameDecode(data: Uint8Array): WsFrame | null
250
+ wsFrameEncodeBatchPacked(
251
+ data: Uint8Array,
252
+ opcode: number,
253
+ mask: boolean,
254
+ fin: boolean,
255
+ ): Uint8Array
256
+ wsFrameDecodeBatchPacked(data: Uint8Array): Uint8Array
257
+
258
+ sseEncodeEvent(
259
+ event: string | null,
260
+ data: Uint8Array,
261
+ id: string | null,
262
+ retry: number | null,
263
+ ): Uint8Array
264
+ sseEncodeBatchPacked(
265
+ data: Uint8Array,
266
+ event: string | null,
267
+ id: string | null,
268
+ retry: number | null,
269
+ ): Uint8Array
270
+
271
+ SchemaValidator: new (schema: Uint8Array) => SchemaValidatorInstance
272
+ FormParser: new (capacity?: number) => FormParserInstance
273
+ MediaTypeParser: new () => MediaTypeParserInstance
274
+ ConditionalRequest: new (
275
+ etagValue: Uint8Array,
276
+ lastModifiedSecs?: number,
277
+ ) => ConditionalRequestInstance
278
+ AcceptNegotiator: new (supported: string[]) => AcceptNegotiatorInstance
279
+ Base64Codec: new (urlSafe?: boolean, padding?: boolean) => Base64CodecInstance
280
+ CookieSigner: new (secret: Uint8Array) => CookieSignerInstance
281
+ CsrfProtector: new (secret: Uint8Array) => CsrfProtectorInstance
282
+ UrlBuilder: new (base: Uint8Array) => UrlBuilderInstance
283
+ parseAcceptEncoding(input: Uint8Array): EncodingPrefResult[]
284
+ urlResolve(base: Uint8Array, reference: Uint8Array): Uint8Array
285
+ /** Packed URL-resolve batch (two packed lists, zipped) → packed results. */
286
+ urlResolveBatchPacked(bases: Uint8Array, references: Uint8Array): Uint8Array
287
+ urlEncodeQuery(params: Record<string, string>): Uint8Array
288
+ csrfToken(secret: Uint8Array): Uint8Array
289
+ csrfVerify(token: Uint8Array, secret: Uint8Array): boolean
290
+ csrfVerifyBatchPacked(data: Uint8Array, secret: Uint8Array): Uint8Array
291
+ signCookie(value: Uint8Array, secret: Uint8Array): Uint8Array
292
+ verifyCookie(signed: Uint8Array, secret: Uint8Array): Uint8Array | null
293
+ signCookieBatchPacked(data: Uint8Array, secret: Uint8Array): Uint8Array
294
+ verifyCookieBatchPacked(data: Uint8Array, secret: Uint8Array): Uint8Array
295
+ /** Batch HMAC-SHA256 sign (packed in → hex-signature byte results). */
296
+ hmacSha256BatchPacked(input: Uint8Array, key: Uint8Array): Uint8Array
297
+ /** Batch HMAC-SHA256 verify (two packed lists: data + hex sigs, zipped) → bitset. */
298
+ hmacSha256VerifyBatchPacked(input: Uint8Array, sigs: Uint8Array, key: Uint8Array): Uint8Array
299
+ base64Encode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array
300
+ base64Decode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array
301
+ /** Reusable-output base64 encode; returns bytes written. Throws if `output` is too small. */
302
+ base64EncodeInto(
303
+ input: Uint8Array,
304
+ output: Uint8Array,
305
+ urlSafe?: boolean,
306
+ padding?: boolean,
307
+ ): number
308
+ /** Reusable-output base64 decode; returns bytes written. Throws on invalid input or if `output` is too small. */
309
+ base64DecodeInto(
310
+ input: Uint8Array,
311
+ output: Uint8Array,
312
+ urlSafe?: boolean,
313
+ padding?: boolean,
314
+ ): number
315
+ base64UrlEncode(input: Uint8Array): Uint8Array
316
+ base64UrlDecode(input: Uint8Array): Uint8Array
317
+ hexEncode(input: Uint8Array): Uint8Array
318
+ hexDecode(input: Uint8Array): Uint8Array
319
+ /** Reusable-output lowercase-hex encode; returns bytes written. Throws if `output` is too small. */
320
+ hexEncodeInto(input: Uint8Array, output: Uint8Array): number
321
+ /** Reusable-output hex decode; returns bytes written. Throws on bad input or if `output` is too small. */
322
+ hexDecodeInto(input: Uint8Array, output: Uint8Array): number
323
+ parseMediaType(input: Uint8Array): MediaTypeResult
324
+ etag(input: Uint8Array, weak?: boolean): Uint8Array
325
+ /** Reusable-output etag; returns bytes written (10 strong / 12 weak). Throws if `output` is too small. */
326
+ etagInto(input: Uint8Array, output: Uint8Array, weak?: boolean): number
327
+ /** Packed ETag batch (10 strong / 12 weak bytes per item). */
328
+ etagBatchPacked(input: Uint8Array, weak?: boolean | null): Uint8Array
329
+ httpDate(secs?: number): Uint8Array
330
+ /** Reusable-output http-date; returns bytes written (29). Throws if `output` is too small or the year is out of the fixed-width range. */
331
+ httpDateInto(secs: number | undefined, output: Uint8Array): number
332
+ parseHttpDate(input: Uint8Array): bigint | null
333
+
334
+ initThreadPool(rayonThreads?: number): void
335
+ rayonNumThreads(): number
336
+
337
+ jsonValidBatchPacked(input: Uint8Array): Uint8Array
338
+ validateEmailBatchPacked(input: Uint8Array): Uint8Array
339
+ validateUuidBatchPacked(input: Uint8Array): Uint8Array
340
+ validateIpv4BatchPacked(input: Uint8Array): Uint8Array
341
+ validateIpv6BatchPacked(input: Uint8Array): Uint8Array
342
+
343
+ jsonSumBatchPacked(input: Uint8Array): Uint8Array
344
+ queryParseBatchPacked(input: Uint8Array): Uint8Array
345
+ cookieParseBatchPacked(input: Uint8Array): Uint8Array
346
+ formParseBatchPacked(input: Uint8Array): Uint8Array
347
+ httpParseRequestBatchPacked(input: Uint8Array): Uint8Array
348
+ hexEncodeBatchPacked(input: Uint8Array): Uint8Array
349
+ hexDecodeBatchPacked(input: Uint8Array): Uint8Array
350
+ base64EncodeBatchPacked(
351
+ input: Uint8Array,
352
+ urlSafe?: boolean | null,
353
+ padding?: boolean | null,
354
+ ): Uint8Array
355
+ base64DecodeBatchPacked(
356
+ input: Uint8Array,
357
+ urlSafe?: boolean | null,
358
+ padding?: boolean | null,
359
+ ): Uint8Array
360
+
361
+ httpParseRequestPacked(input: Uint8Array): Uint8Array
362
+ /** Reusable-output packed HTTP parse; returns bytes written. Throws if `output` is too small. */
363
+ httpParseRequestPackedInto(input: Uint8Array, output: Uint8Array): number
364
+
365
+ queryParsePacked(input: Uint8Array): Uint8Array
366
+ /** Reusable-output packed query parse; returns bytes written. Throws if `output` is too small. */
367
+ queryParsePackedInto(input: Uint8Array, output: Uint8Array): number
368
+
369
+ cookieParsePacked(input: Uint8Array): Uint8Array
370
+ /** Reusable-output packed cookie parse; returns bytes written. Throws if `output` is too small. */
371
+ cookieParsePackedInto(input: Uint8Array, output: Uint8Array): number
372
+
373
+ formParsePacked(input: Uint8Array): Uint8Array
374
+
375
+ crc32BatchPacked(input: Uint8Array): Uint8Array
376
+
377
+ // ── Reusable-output (`_into`) packed batch variants ──
378
+ // Write the packed batch result into a caller-provided `output` buffer and
379
+ // return the number of bytes written (0 on empty). Wire format is identical
380
+ // to the allocating `*BatchPacked` variants. Throws when `output` is too
381
+ // small (the JS loader sizes these from a pool before calling).
382
+ jsonValidBatchPackedInto(input: Uint8Array, output: Uint8Array): number
383
+ validateEmailBatchPackedInto(input: Uint8Array, output: Uint8Array): number
384
+ validateUuidBatchPackedInto(input: Uint8Array, output: Uint8Array): number
385
+ validateIpv4BatchPackedInto(input: Uint8Array, output: Uint8Array): number
386
+ validateIpv6BatchPackedInto(input: Uint8Array, output: Uint8Array): number
387
+ jsonSumBatchPackedInto(input: Uint8Array, output: Uint8Array): number
388
+ fnv1A64BatchPackedInto(input: Uint8Array, output: Uint8Array): number
389
+ crc32BatchPackedInto(input: Uint8Array, output: Uint8Array): number
390
+
391
+ // ── Batch metadata / counts ──
392
+ jsonValidBatchCountPacked(input: Uint8Array): number
393
+ validateEmailBatchCountPacked(input: Uint8Array): number
394
+ validateUuidBatchCountPacked(input: Uint8Array): number
395
+ validateIpv4BatchCountPacked(input: Uint8Array): number
396
+ validateIpv6BatchCountPacked(input: Uint8Array): number
397
+ jsonSumBatchTotalPacked(input: Uint8Array): number
398
+ queryParseBatchTotalLenPacked(input: Uint8Array): number
399
+ cookieParseBatchTotalLenPacked(input: Uint8Array): number
400
+ httpParseRequestBatchTotalLenPacked(input: Uint8Array): number
401
+ }