castrum 0.7.0 → 0.9.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.
- package/LICENSE +21 -0
- package/README.md +322 -59
- package/castrum.linux-x64-gnu.node +0 -0
- package/dist/index.d.ts +3161 -0
- package/dist/index.js +7306 -0
- package/docs/ARCHITECTURE.md +415 -0
- package/docs/BENCHMARKS.md +307 -0
- package/docs/ENVIRONMENT.md +79 -0
- package/docs/GETTING_STARTED.md +209 -0
- package/docs/INGRESS.md +745 -0
- package/docs/REPO_MAP.md +259 -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 +42 -0
- package/docs/bun-builtins-decision-matrix.md +108 -0
- package/index.ts +51 -8
- package/package.json +73 -20
- package/src/data/json-rows.ts +13 -13
- package/src/ingress/body.ts +149 -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 +563 -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 +67 -0
- package/src/ingress/index.ts +130 -405
- package/src/ingress/metrics.ts +132 -0
- package/src/ingress/options.ts +197 -0
- package/src/ingress/packing/gather-raw-headers.ts +75 -0
- package/src/ingress/packing/header-packing.ts +75 -0
- package/src/ingress/packing/input-packer.ts +150 -0
- package/src/ingress/packing/scratch.ts +50 -0
- package/src/ingress/packing/select-headers.ts +96 -0
- package/src/ingress/response/error-bodies.ts +75 -0
- package/src/ingress/response/terminal.ts +59 -0
- package/src/ingress/routes/common.ts +38 -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 +37 -0
- package/src/ingress/routes/index.ts +10 -0
- package/src/ingress/routes/json-write.ts +153 -0
- package/src/ingress/routes/options.ts +36 -0
- package/src/ingress/routes/read.ts +45 -0
- package/src/ingress/server-node.ts +376 -0
- package/src/ingress/server.ts +443 -0
- package/src/ingress/shared.ts +132 -0
- package/src/ingress/status.ts +97 -0
- package/src/ingress/types.ts +157 -0
- package/src/integration/batch.ts +58 -0
- package/src/integration/index.ts +29 -0
- package/src/integration/pipeline.ts +217 -0
- package/src/integration/streaming.ts +79 -0
- package/src/integration/websocket.ts +92 -0
- package/src/loader/batch.ts +133 -0
- package/src/loader/cost.ts +104 -0
- package/src/loader/index.ts +930 -0
- package/src/loader/ops.ts +657 -0
- package/src/native/ffi.ts +1541 -0
- package/src/native/index.ts +8 -207
- package/src/native/loader.ts +194 -0
- package/src/native/types.ts +598 -0
- package/src/rust-ffi/addon.ts +10 -0
- package/src/rust-ffi/batch.ts +431 -0
- package/src/rust-ffi/client.ts +88 -0
- package/src/rust-ffi/context.ts +164 -0
- package/src/rust-ffi/index.ts +40 -541
- package/src/rust-ffi/options.ts +113 -0
- package/src/rust-ffi/packed.ts +253 -0
- package/src/rust-ffi/proven.ts +42 -0
- package/src/rust-ffi/scalar/crypto.ts +265 -0
- package/src/rust-ffi/scalar/factories.ts +233 -0
- package/src/rust-ffi/scalar/hashing.ts +72 -0
- package/src/rust-ffi/scalar/http.ts +206 -0
- package/src/rust-ffi/scalar/index.ts +31 -0
- package/src/rust-ffi/scalar/interface.ts +450 -0
- package/src/rust-ffi/scalar/json.ts +45 -0
- package/src/rust-ffi/scalar/payload.ts +124 -0
- package/src/rust-ffi/text.ts +95 -0
- package/src/selection.json +194 -0
- package/src/selection.ts +77 -0
- package/src/shared/adaptive.ts +68 -0
- package/src/shared/bench-classify.ts +209 -0
- package/src/shared/buffer-pool.ts +209 -0
- package/src/shared/bytes.ts +35 -5
- package/src/shared/env.ts +20 -0
- package/src/shared/log.ts +74 -0
- package/src/shared/metrics.ts +247 -0
- package/src/shared/packed.ts +350 -154
- package/src/shared/proven.ts +596 -0
- package/src/shared/request-id.ts +67 -0
- package/src/shared/response.ts +104 -0
- package/src/shared/runtime.ts +34 -0
- package/src/shared/trace.ts +81 -0
- package/src/shared/uuid.ts +31 -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/ingress/packed-input.ts +0 -59
- package/src/shared/json.ts +0 -18
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3161 @@
|
|
|
1
|
+
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
+
|
|
3
|
+
/** A single JSON Schema validation error (fast path + DOM fallback). */
|
|
4
|
+
export interface SchemaError {
|
|
5
|
+
/** RFC 6901 JSON pointer to the failing instance value ("" = root). */
|
|
6
|
+
instancePath: string;
|
|
7
|
+
/** JSON pointer into the schema at the failing keyword. */
|
|
8
|
+
schemaPath: string;
|
|
9
|
+
/** The failing keyword (e.g. "type", "pattern", "required"). */
|
|
10
|
+
keyword: string;
|
|
11
|
+
/** Human-readable failure message. */
|
|
12
|
+
message: string;
|
|
13
|
+
}
|
|
14
|
+
/** The native `SchemaValidator` class instance. */
|
|
15
|
+
export interface SchemaValidatorInstance {
|
|
16
|
+
/** Validate a single JSON document. */
|
|
17
|
+
validate(input: Uint8Array): boolean;
|
|
18
|
+
/** Validate a single JSON document, returning detailed errors (empty = valid). */
|
|
19
|
+
validateDetailed(input: Uint8Array): SchemaError[];
|
|
20
|
+
/** Validate a single JSON document, returning only the first error (null = valid). */
|
|
21
|
+
validateFirstError(input: Uint8Array): SchemaError | null;
|
|
22
|
+
validateBatchPackedCount(packed: Uint8Array): number;
|
|
23
|
+
validateBatchPackedBitset(packed: Uint8Array): Uint8Array;
|
|
24
|
+
validateBatchStreaming(batchBytes: Uint8Array): number;
|
|
25
|
+
/**
|
|
26
|
+
* One-pass validate + extract: validate `input` against the schema and
|
|
27
|
+
* capture scalar values / array lengths at `paths` during the same native
|
|
28
|
+
* walk (no `JSON.parse`, no DOM). For "derive" routes (response built from a
|
|
29
|
+
* handful of body fields) this replaces `JSON.parse` + Ajv on the happy path
|
|
30
|
+
* and rejects invalid bodies with zero DOM/GC.
|
|
31
|
+
*
|
|
32
|
+
* `paths` are RFC 6901 JSON pointers of OBJECT KEYS; a trailing `/-`
|
|
33
|
+
* captures the ARRAY LENGTH at that path (e.g. `"/totalCents"`,
|
|
34
|
+
* `"/lineItems/-"`). Array-index steps are not supported.
|
|
35
|
+
*/
|
|
36
|
+
derive(input: Uint8Array, paths: string[]): JsonDeriveResult;
|
|
37
|
+
}
|
|
38
|
+
/** A single derived value captured during one-pass validation. */
|
|
39
|
+
export interface JsonDeriveValue {
|
|
40
|
+
/** `"int" | "number" | "string" | "bool" | "null"`. */
|
|
41
|
+
kind: string;
|
|
42
|
+
int: number | null;
|
|
43
|
+
number: number | null;
|
|
44
|
+
text: string | null;
|
|
45
|
+
boolean: boolean | null;
|
|
46
|
+
}
|
|
47
|
+
/** Result of a one-pass `validate + derive`. */
|
|
48
|
+
export interface JsonDeriveResult {
|
|
49
|
+
/** `true` when the document is schema-valid; `false` → caller rejects. */
|
|
50
|
+
ok: boolean;
|
|
51
|
+
/** One entry per requested path (`null` = path absent from the document). */
|
|
52
|
+
values: Array<JsonDeriveValue | null>;
|
|
53
|
+
}
|
|
54
|
+
/** The native `HmacSigner` class instance. */
|
|
55
|
+
export interface HmacSignerInstance {
|
|
56
|
+
sign(data: Uint8Array): Uint8Array;
|
|
57
|
+
verify(data: Uint8Array, sig: Uint8Array): boolean;
|
|
58
|
+
}
|
|
59
|
+
/** The native `FormParser` class instance (reusable output buffer). */
|
|
60
|
+
export interface FormParserInstance {
|
|
61
|
+
/** Parse an x-www-form-urlencoded body into packed pairs (reuses the buffer). */
|
|
62
|
+
parse(input: Uint8Array): Uint8Array;
|
|
63
|
+
/** Zero-alloc parse into a caller-provided output buffer. */
|
|
64
|
+
parseInto(input: Uint8Array, output: Uint8Array): number;
|
|
65
|
+
}
|
|
66
|
+
/** A parsed Content-Type / media type. */
|
|
67
|
+
export interface MediaTypeResult {
|
|
68
|
+
/** Lowercased `type/subtype`. */
|
|
69
|
+
mediaType: string;
|
|
70
|
+
charset: string | null;
|
|
71
|
+
boundary: string | null;
|
|
72
|
+
params: Record<string, string>;
|
|
73
|
+
}
|
|
74
|
+
/** The native `MediaTypeParser` class instance. */
|
|
75
|
+
export interface MediaTypeParserInstance {
|
|
76
|
+
parse(input: Uint8Array): MediaTypeResult;
|
|
77
|
+
/** Wildcard match: any/any, type/any, or exact type/subtype. */
|
|
78
|
+
matches(actual: Uint8Array, expected: Uint8Array): boolean;
|
|
79
|
+
}
|
|
80
|
+
/** The native `ConditionalRequest` class instance (per-resource 304 checks). */
|
|
81
|
+
export interface ConditionalRequestInstance {
|
|
82
|
+
isNotModified(ifNoneMatch: Uint8Array | null, ifModifiedSince: Uint8Array | null): boolean;
|
|
83
|
+
}
|
|
84
|
+
/** One parsed Accept-Encoding preference. */
|
|
85
|
+
export interface EncodingPrefResult {
|
|
86
|
+
encoding: string;
|
|
87
|
+
q: number;
|
|
88
|
+
order: number;
|
|
89
|
+
}
|
|
90
|
+
/** The native `AcceptNegotiator` class instance. */
|
|
91
|
+
export interface AcceptNegotiatorInstance {
|
|
92
|
+
/** Best supported encoding for `header`, or null for identity. */
|
|
93
|
+
negotiate(header: Uint8Array): string | null;
|
|
94
|
+
}
|
|
95
|
+
/** The native `Base64Codec` class instance (config compiled once). */
|
|
96
|
+
export interface Base64CodecInstance {
|
|
97
|
+
encode(input: Uint8Array): Uint8Array;
|
|
98
|
+
decode(input: Uint8Array): Uint8Array;
|
|
99
|
+
}
|
|
100
|
+
/** Result of a native rate-limit check for one key at a point in time. */
|
|
101
|
+
export interface RateCheckResult {
|
|
102
|
+
allowed: boolean;
|
|
103
|
+
remaining: number;
|
|
104
|
+
resetMs: number;
|
|
105
|
+
}
|
|
106
|
+
/** The native `RateLimiter` class instance (sharded fixed-window state). */
|
|
107
|
+
export interface RateLimiterInstance {
|
|
108
|
+
check(key: string, nowMs: number): RateCheckResult;
|
|
109
|
+
checkKey(key: number, nowMs: number): RateCheckResult;
|
|
110
|
+
}
|
|
111
|
+
/** The native `CookieSigner` class instance (HMAC key compiled once). */
|
|
112
|
+
export interface CookieSignerInstance {
|
|
113
|
+
sign(value: Uint8Array): Uint8Array;
|
|
114
|
+
/** Returns the signed value without its signature, or null on invalid. */
|
|
115
|
+
verify(signed: Uint8Array): Uint8Array | null;
|
|
116
|
+
}
|
|
117
|
+
/** The native `CsrfProtector` class instance (HMAC key compiled once). */
|
|
118
|
+
export interface CsrfProtectorInstance {
|
|
119
|
+
create(): Uint8Array;
|
|
120
|
+
verify(token: Uint8Array): boolean;
|
|
121
|
+
}
|
|
122
|
+
/** The native `UrlBuilder` class instance (base parsed once). */
|
|
123
|
+
export interface UrlBuilderInstance {
|
|
124
|
+
resolve(reference: Uint8Array): Uint8Array;
|
|
125
|
+
}
|
|
126
|
+
/** Options for `passwordHash` (argon2id). */
|
|
127
|
+
export interface PasswordHashOptions {
|
|
128
|
+
mCost?: number;
|
|
129
|
+
tCost?: number;
|
|
130
|
+
pCost?: number;
|
|
131
|
+
outLen?: number;
|
|
132
|
+
}
|
|
133
|
+
/** A parsed multipart/form-data part. */
|
|
134
|
+
export interface MultipartPart {
|
|
135
|
+
name: string;
|
|
136
|
+
filename: string | null;
|
|
137
|
+
contentType: string | null;
|
|
138
|
+
data: Uint8Array;
|
|
139
|
+
}
|
|
140
|
+
/** A decoded RFC 6455 websocket frame. */
|
|
141
|
+
export interface WsFrame {
|
|
142
|
+
fin: boolean;
|
|
143
|
+
opcode: number;
|
|
144
|
+
payload: Uint8Array;
|
|
145
|
+
}
|
|
146
|
+
/** The native `TemplateRenderer` class instance. */
|
|
147
|
+
export interface TemplateRendererInstance {
|
|
148
|
+
render(context: unknown): Uint8Array;
|
|
149
|
+
/** Render from pre-serialized JSON context bytes (no napi Value marshal). */
|
|
150
|
+
renderBytes(contextJson: Uint8Array): Uint8Array;
|
|
151
|
+
/** Parallel batch render: packed contexts in → packed rendered out. */
|
|
152
|
+
renderBatchPacked(data: Uint8Array): Uint8Array;
|
|
153
|
+
}
|
|
154
|
+
/** The native `MediaTypeMatcher` class instance (expected precompiled once). */
|
|
155
|
+
export interface MediaTypeMatcherInstance {
|
|
156
|
+
/** Wildcard match against the precompiled expected type. */
|
|
157
|
+
matches(actual: Uint8Array): boolean;
|
|
158
|
+
}
|
|
159
|
+
/** The native `JwtSigner` class instance (HS256 key + ttl compiled once). */
|
|
160
|
+
export interface JwtSignerInstance {
|
|
161
|
+
sign(claims: unknown, nowSeconds: number): Uint8Array;
|
|
162
|
+
/** Sign from pre-serialized claim JSON bytes (no napi Value marshal). */
|
|
163
|
+
signBytes(claimsJson: Uint8Array, nowSeconds: number): Uint8Array;
|
|
164
|
+
verify(token: Uint8Array, nowSeconds: number): unknown;
|
|
165
|
+
}
|
|
166
|
+
/** The native `AeadCipher` class instance (algorithm + key compiled once). */
|
|
167
|
+
export interface AeadCipherInstance {
|
|
168
|
+
encrypt(nonce: Uint8Array, plaintext: Uint8Array): Uint8Array;
|
|
169
|
+
decrypt(nonce: Uint8Array, ciphertext: Uint8Array): Uint8Array | null;
|
|
170
|
+
}
|
|
171
|
+
/** The native `Argon2Hasher` class instance (params compiled once). */
|
|
172
|
+
export interface Argon2HasherInstance {
|
|
173
|
+
hash(password: Uint8Array, salt: Uint8Array): Uint8Array;
|
|
174
|
+
verify(password: Uint8Array, phc: Uint8Array): boolean;
|
|
175
|
+
}
|
|
176
|
+
/** Options accepted by `createRust` / `rust.configure`. */
|
|
177
|
+
export interface RustOptions {
|
|
178
|
+
/**
|
|
179
|
+
* Rayon thread pool size.
|
|
180
|
+
*
|
|
181
|
+
* The rayon pool is process-wide and initialized **once** (native
|
|
182
|
+
* `OnceLock`) — the first initialization wins. Importing this module
|
|
183
|
+
* initializes the pool with defaults, so this option only takes effect when
|
|
184
|
+
* the pool has not yet been created. For reliable control set
|
|
185
|
+
* `CASTRUM_RAYON_THREADS` / `RUST_RAYON_THREADS` before import.
|
|
186
|
+
* Default: max(1, hardwareConcurrency - 1).
|
|
187
|
+
*/
|
|
188
|
+
rayonThreads?: number;
|
|
189
|
+
/** Cache MIME lookups keyed by normalized extension. Default: true. */
|
|
190
|
+
mimeCache?: boolean;
|
|
191
|
+
/** Reuse HMAC signers keyed by key-buffer identity. Default: true. */
|
|
192
|
+
hmacCache?: boolean;
|
|
193
|
+
}
|
|
194
|
+
/** String-oriented FFI namespace. */
|
|
195
|
+
export interface RustText {
|
|
196
|
+
/**
|
|
197
|
+
* Resolve a lowercase file extension to a MIME type string (e.g. `"html"` →
|
|
198
|
+
* `"text/html"`). Unknown extensions return `"application/octet-stream"`.
|
|
199
|
+
* @param ext the file extension WITHOUT a leading dot, case-insensitive.
|
|
200
|
+
* @returns the MIME type for `ext`.
|
|
201
|
+
*/
|
|
202
|
+
mimeFromExtension(ext: string): string;
|
|
203
|
+
/**
|
|
204
|
+
* RFC 3986 percent-encode a string (the `encodeURIComponent` unreserved
|
|
205
|
+
* set). Under Bun this delegates to the native `encodeURIComponent` for
|
|
206
|
+
* ~4x speed with byte-for-byte parity.
|
|
207
|
+
* @param input the string to encode.
|
|
208
|
+
* @returns the percent-encoded string.
|
|
209
|
+
*/
|
|
210
|
+
urlEncode(input: string): string;
|
|
211
|
+
/**
|
|
212
|
+
* Percent-decode a string. Throws on malformed `%XX` or invalid UTF-8
|
|
213
|
+
* output (parity with `decodeURIComponent`, which is used under Bun).
|
|
214
|
+
* @param input the percent-encoded string to decode.
|
|
215
|
+
* @returns the decoded string.
|
|
216
|
+
*/
|
|
217
|
+
urlDecode(input: string): string;
|
|
218
|
+
/**
|
|
219
|
+
* Compute the RFC 6455 `Sec-WebSocket-Accept` value for a client key.
|
|
220
|
+
* @param key the base64 `Sec-WebSocket-Key` header value.
|
|
221
|
+
* @returns the 28-byte base64 accept value.
|
|
222
|
+
*/
|
|
223
|
+
wsAcceptKey(key: string): string;
|
|
224
|
+
/** @param input an email address. @returns whether it is RFC-valid. */
|
|
225
|
+
validateEmail(input: string): boolean;
|
|
226
|
+
/** @param input a UUID string. @returns whether it is a valid (v1-v8) UUID. */
|
|
227
|
+
validateUuid(input: string): boolean;
|
|
228
|
+
/** @param input an IPv4 address. @returns whether it is valid. */
|
|
229
|
+
validateIpv4(input: string): boolean;
|
|
230
|
+
/** @param input an IPv6 address. @returns whether it is valid. */
|
|
231
|
+
validateIpv6(input: string): boolean;
|
|
232
|
+
}
|
|
233
|
+
export type SchemaValidator = SchemaValidatorInstance;
|
|
234
|
+
/**
|
|
235
|
+
* Unpack a packed u32 array: `[u32 count]{[u32 value]}` → `Uint32Array`.
|
|
236
|
+
* @throws {RangeError} when the buffer is shorter than `count` × 4 bytes.
|
|
237
|
+
*/
|
|
238
|
+
export declare function unpackU32Array(bytes: Uint8Array): Uint32Array;
|
|
239
|
+
/**
|
|
240
|
+
* Unpack a packed bitset: `[u32 count]{bit per item}` → one 0/1 byte per item.
|
|
241
|
+
* @throws {RangeError} when the buffer is shorter than `count` bits.
|
|
242
|
+
*/
|
|
243
|
+
export declare function unpackBitset(bytes: Uint8Array): Uint8Array;
|
|
244
|
+
/**
|
|
245
|
+
* Unpack a packed i64 array as SIGNED `BigInt64Array`.
|
|
246
|
+
* @throws {RangeError} when the buffer is shorter than `count` × 8 bytes.
|
|
247
|
+
*/
|
|
248
|
+
export declare function unpackI64ArrayAsBigInt(bytes: Uint8Array): BigInt64Array;
|
|
249
|
+
/**
|
|
250
|
+
* Unpack a packed byte-results buffer: `[u32 count]{[u32 len][bytes]}` → one
|
|
251
|
+
* `Uint8Array` slice per item. The slices reference `bytes`'s backing store
|
|
252
|
+
* (zero-copy) — copy them if held beyond the buffer's lifetime.
|
|
253
|
+
*/
|
|
254
|
+
export declare function unpackByteResults(bytes: Uint8Array): Uint8Array[];
|
|
255
|
+
export type Pair = [
|
|
256
|
+
string,
|
|
257
|
+
string
|
|
258
|
+
];
|
|
259
|
+
export declare function readPairsPacked(bytes: Uint8Array): Pair[];
|
|
260
|
+
export declare function pairsToObject(pairs: Pair[]): Record<string, string | string[]>;
|
|
261
|
+
export interface ParsedHttpRequestPacked {
|
|
262
|
+
method: string;
|
|
263
|
+
path: string;
|
|
264
|
+
version: string;
|
|
265
|
+
headers: Record<string, string>;
|
|
266
|
+
}
|
|
267
|
+
export declare function readHttpPacked(bytes: Uint8Array): ParsedHttpRequestPacked;
|
|
268
|
+
/**
|
|
269
|
+
* Build a packed batch buffer. Returns an OWNED buffer (safe to hold across
|
|
270
|
+
* later calls) — this is the public entry point. Hot internal paths that can
|
|
271
|
+
* guarantee synchronous consumption should use `withPackScratch` instead.
|
|
272
|
+
*/
|
|
273
|
+
export declare function packBatch(items: Uint8Array[]): Uint8Array;
|
|
274
|
+
export declare function packPairs(pairs: Array<[
|
|
275
|
+
string,
|
|
276
|
+
string
|
|
277
|
+
]>): Uint8Array;
|
|
278
|
+
export declare function parseQueryString(query: string): Record<string, string | string[]>;
|
|
279
|
+
export declare function parseCookieHeader(header: string): Record<string, string | string[]>;
|
|
280
|
+
/** Parse an application/x-www-form-urlencoded body into a key/value object. */
|
|
281
|
+
export declare function parseFormBody(body: Uint8Array): Record<string, string | string[]>;
|
|
282
|
+
/** Array-of-bytes FFI namespace. */
|
|
283
|
+
export interface RustBatch {
|
|
284
|
+
jsonValid(items: Uint8Array[]): Uint8Array;
|
|
285
|
+
crc32(items: Uint8Array[]): Uint32Array;
|
|
286
|
+
validateEmail(items: Uint8Array[]): Uint8Array;
|
|
287
|
+
validateUuid(items: Uint8Array[]): Uint8Array;
|
|
288
|
+
validateIpv4(items: Uint8Array[]): Uint8Array;
|
|
289
|
+
validateIpv6(items: Uint8Array[]): Uint8Array;
|
|
290
|
+
jsonSumIds(items: Uint8Array[]): BigInt64Array;
|
|
291
|
+
queryParse(items: Uint8Array[]): Uint8Array[];
|
|
292
|
+
cookieParse(items: Uint8Array[]): Uint8Array[];
|
|
293
|
+
httpParseRequest(items: Uint8Array[]): Uint8Array[];
|
|
294
|
+
/** Apply N RFC 6902 patches (docs and patches zipped). Fail-fast on error. */
|
|
295
|
+
jsonPatch(docs: Uint8Array[], patches: Uint8Array[]): Uint8Array[];
|
|
296
|
+
/** Encode N items to lowercase hex (packed in → byte results). */
|
|
297
|
+
hexEncode(items: Uint8Array[]): Uint8Array[];
|
|
298
|
+
/** Decode N lowercase/uppercase hex strings to bytes. */
|
|
299
|
+
hexDecode(items: Uint8Array[]): Uint8Array[];
|
|
300
|
+
/** Base64-encode N items (standard by default; url-safe/padding configurable). */
|
|
301
|
+
base64Encode(items: Uint8Array[], urlSafe?: boolean, padding?: boolean): Uint8Array[];
|
|
302
|
+
/** Base64-decode N items (standard by default; url-safe/padding configurable). */
|
|
303
|
+
base64Decode(items: Uint8Array[], urlSafe?: boolean, padding?: boolean): Uint8Array[];
|
|
304
|
+
formParse(items: Uint8Array[]): Uint8Array[];
|
|
305
|
+
/** Sign N cookie values (packed → byte results). */
|
|
306
|
+
signCookie(items: Uint8Array[], secret: Uint8Array): Uint8Array[];
|
|
307
|
+
/** Verify N signed cookies (bitset of valid). */
|
|
308
|
+
verifyCookie(items: Uint8Array[], secret: Uint8Array): Uint8Array;
|
|
309
|
+
/** Verify N CSRF tokens (bitset of valid). */
|
|
310
|
+
csrfVerify(items: Uint8Array[], secret: Uint8Array): Uint8Array;
|
|
311
|
+
schemaValidate(validator: SchemaValidator, items: Uint8Array[]): Uint8Array;
|
|
312
|
+
schemaValidateCount(validator: SchemaValidator, items: Uint8Array[]): number;
|
|
313
|
+
/** Hash N items with FNV-1a 64 (packed → unsigned u64 array). */
|
|
314
|
+
fnv1a64(items: Uint8Array[]): BigUint64Array;
|
|
315
|
+
/** Generate N ETags (strong by default; weak flag applies to all items). */
|
|
316
|
+
etag(items: Uint8Array[], weak?: boolean | null): Uint8Array[];
|
|
317
|
+
urlEncode(items: Uint8Array[]): Uint8Array[];
|
|
318
|
+
/** Percent-decode N strings (UTF-8 validated; malformed items → empty). */
|
|
319
|
+
urlDecode(items: Uint8Array[]): Uint8Array[];
|
|
320
|
+
/** Strict percent-decode N strings (no UTF-8 validation). */
|
|
321
|
+
urlDecodeBytes(items: Uint8Array[]): Uint8Array[];
|
|
322
|
+
mimeFromExtension(items: Uint8Array[]): Uint8Array[];
|
|
323
|
+
wsAcceptKey(items: Uint8Array[]): Uint8Array[];
|
|
324
|
+
/** Base64url-encode N items (URL-safe, no padding). */
|
|
325
|
+
base64UrlEncode(items: Uint8Array[]): Uint8Array[];
|
|
326
|
+
/** Base64url-decode N items (URL-safe, no padding). */
|
|
327
|
+
base64UrlDecode(items: Uint8Array[]): Uint8Array[];
|
|
328
|
+
passwordHash(passwords: Uint8Array[], salt: Uint8Array, options?: PasswordHashOptions | null): Uint8Array[];
|
|
329
|
+
aeadEncrypt(key: Uint8Array, nonce: Uint8Array, items: Uint8Array[], algorithm?: string | null): Uint8Array[];
|
|
330
|
+
aeadDecrypt(key: Uint8Array, nonce: Uint8Array, items: Uint8Array[], algorithm?: string | null): Uint8Array[];
|
|
331
|
+
gzipCompress(items: Uint8Array[], level?: number | null): Uint8Array[];
|
|
332
|
+
gzipDecompress(items: Uint8Array[], maxDecompressed?: number | null): Uint8Array[];
|
|
333
|
+
brotliCompress(items: Uint8Array[], quality?: number | null): Uint8Array[];
|
|
334
|
+
brotliDecompress(items: Uint8Array[], maxDecompressed?: number | null): Uint8Array[];
|
|
335
|
+
jwtVerify(tokens: Uint8Array[], secret: Uint8Array, nowSeconds: number): Uint8Array;
|
|
336
|
+
/** Sign N messages to lowercase-hex HMAC-SHA256 signatures (packed → byte results). */
|
|
337
|
+
hmacSha256(items: Uint8Array[], key: Uint8Array): Uint8Array[];
|
|
338
|
+
/** Verify N message + hex-signature pairs (two packed lists, zipped) → bitset of valid. */
|
|
339
|
+
hmacSha256Verify(items: Uint8Array[], sigs: Uint8Array[], key: Uint8Array): Uint8Array;
|
|
340
|
+
/** Verify N password+PHC pairs (two packed lists, zipped) → bitset of valid. */
|
|
341
|
+
passwordVerify(items: Uint8Array[], phcs: Uint8Array[]): Uint8Array;
|
|
342
|
+
/** Resolve N references against N bases (two packed lists, zipped). */
|
|
343
|
+
urlResolve(bases: Uint8Array[], references: Uint8Array[]): Uint8Array[];
|
|
344
|
+
/** Sign N JSON claim documents (packed → signed tokens). */
|
|
345
|
+
jwtSign(items: Uint8Array[], secret: Uint8Array, ttlSeconds?: number | null, nowSeconds?: number): Uint8Array[];
|
|
346
|
+
/** Encode N SSE events with shared event/id/retry. */
|
|
347
|
+
sseEncode(items: Uint8Array[], event?: string | null, id?: string | null, retry?: number | null): Uint8Array[];
|
|
348
|
+
/** Encode N frames (same opcode/mask/fin) from payloads. */
|
|
349
|
+
wsFrameEncode(items: Uint8Array[], opcode: number, mask: boolean, fin: boolean): Uint8Array[];
|
|
350
|
+
/** Decode N frames → payloads (opcodes/flags dropped; failed items → empty). */
|
|
351
|
+
wsFrameDecode(items: Uint8Array[]): Uint8Array[];
|
|
352
|
+
/** Parse N multipart bodies → array of parts per item (same boundary). */
|
|
353
|
+
multipartParse(items: Uint8Array[], boundary: Uint8Array): MultipartPart[][];
|
|
354
|
+
/**
|
|
355
|
+
* @performance Template render: ~1.7x slower than the JS baseline (1/3 tasks failed) [check:annotate]
|
|
356
|
+
* @deprecated Slower than the native JS baseline (~1.7x) — prefer the JS/Bun baseline. [check:annotate]
|
|
357
|
+
* @remarks Promotion candidate: 2/3 benchmarks won in the latest run (static: not-competitive). [check:annotate]
|
|
358
|
+
* @remarks The allocating render marshals the context via napi DOM (~1.5x loss). Use TemplateRenderer.renderBytes (JSON-bytes context) which avoids it and wins ~1.37x. [check:annotate]
|
|
359
|
+
*/
|
|
360
|
+
templateRender(source: string, contexts: Uint8Array[]): Uint8Array[];
|
|
361
|
+
}
|
|
362
|
+
/** Raw packed-wire FFI namespace. */
|
|
363
|
+
export interface RustPacked {
|
|
364
|
+
crc32BatchPacked(input: Uint8Array): Uint8Array;
|
|
365
|
+
jsonValidBatchPacked(input: Uint8Array): Uint8Array;
|
|
366
|
+
validateEmailBatchPacked(input: Uint8Array): Uint8Array;
|
|
367
|
+
validateUuidBatchPacked(input: Uint8Array): Uint8Array;
|
|
368
|
+
validateIpv4BatchPacked(input: Uint8Array): Uint8Array;
|
|
369
|
+
validateIpv6BatchPacked(input: Uint8Array): Uint8Array;
|
|
370
|
+
jsonSumBatchPacked(input: Uint8Array): Uint8Array;
|
|
371
|
+
queryParseBatchPacked(input: Uint8Array): Uint8Array;
|
|
372
|
+
cookieParseBatchPacked(input: Uint8Array): Uint8Array;
|
|
373
|
+
httpParseRequestBatchPacked(input: Uint8Array): Uint8Array;
|
|
374
|
+
/** Batch RFC 6902 JSON Patch (two packed lists, zipped) → packed results. */
|
|
375
|
+
jsonPatchBatchPacked(docs: Uint8Array, patches: Uint8Array): Uint8Array;
|
|
376
|
+
/** Packed FNV-1a 64 batch (i64 per item). */
|
|
377
|
+
fnv1A64BatchPacked(input: Uint8Array): Uint8Array;
|
|
378
|
+
/** Packed ETag batch (10 strong / 12 weak bytes per item). */
|
|
379
|
+
etagBatchPacked(input: Uint8Array, weak?: boolean | null): Uint8Array;
|
|
380
|
+
urlEncodeBatchPacked(input: Uint8Array): Uint8Array;
|
|
381
|
+
urlDecodeBatchPacked(input: Uint8Array): Uint8Array;
|
|
382
|
+
urlDecodeBytesBatchPacked(input: Uint8Array): Uint8Array;
|
|
383
|
+
mimeFromExtensionBatchPacked(input: Uint8Array): Uint8Array;
|
|
384
|
+
wsAcceptKeyBatchPacked(input: Uint8Array): Uint8Array;
|
|
385
|
+
jsonValidBatchCountPacked(input: Uint8Array): number;
|
|
386
|
+
validateEmailBatchCountPacked(input: Uint8Array): number;
|
|
387
|
+
validateUuidBatchCountPacked(input: Uint8Array): number;
|
|
388
|
+
validateIpv4BatchCountPacked(input: Uint8Array): number;
|
|
389
|
+
validateIpv6BatchCountPacked(input: Uint8Array): number;
|
|
390
|
+
jsonSumBatchTotalPacked(input: Uint8Array): number;
|
|
391
|
+
queryParseBatchTotalLenPacked(input: Uint8Array): number;
|
|
392
|
+
cookieParseBatchTotalLenPacked(input: Uint8Array): number;
|
|
393
|
+
httpParseRequestBatchTotalLenPacked(input: Uint8Array): number;
|
|
394
|
+
passwordHashBatchPacked(input: Uint8Array, salt: Uint8Array, options?: PasswordHashOptions | null): Uint8Array;
|
|
395
|
+
/** Packed password-verify batch (two packed lists, zipped) → bitset. */
|
|
396
|
+
passwordVerifyBatchPacked(passwords: Uint8Array, phcs: Uint8Array): Uint8Array;
|
|
397
|
+
/** Packed URL-resolve batch (two packed lists, zipped) → packed results. */
|
|
398
|
+
urlResolveBatchPacked(bases: Uint8Array, references: Uint8Array): Uint8Array;
|
|
399
|
+
aeadEncryptBatchPacked(input: Uint8Array, key: Uint8Array, nonce: Uint8Array, algorithm?: string | null): Uint8Array;
|
|
400
|
+
aeadDecryptBatchPacked(input: Uint8Array, key: Uint8Array, nonce: Uint8Array, algorithm?: string | null): Uint8Array;
|
|
401
|
+
gzipCompressBatchPacked(input: Uint8Array, level?: number | null): Uint8Array;
|
|
402
|
+
gzipDecompressBatchPacked(input: Uint8Array): Uint8Array;
|
|
403
|
+
brotliCompressBatchPacked(input: Uint8Array, quality?: number | null): Uint8Array;
|
|
404
|
+
brotliDecompressBatchPacked(input: Uint8Array): Uint8Array;
|
|
405
|
+
jwtSignBatchPacked(input: Uint8Array, secret: Uint8Array, ttlSeconds: number | null, nowSeconds: number): Uint8Array;
|
|
406
|
+
jwtVerifyBatchPacked(input: Uint8Array, secret: Uint8Array, nowSeconds: number): Uint8Array;
|
|
407
|
+
/** Batch HMAC-SHA256 sign (packed in → hex-signature byte results). */
|
|
408
|
+
hmacSha256BatchPacked(input: Uint8Array, key: Uint8Array): Uint8Array;
|
|
409
|
+
/** Batch HMAC-SHA256 verify (two packed lists: data + hex sigs, zipped) → bitset. */
|
|
410
|
+
hmacSha256VerifyBatchPacked(input: Uint8Array, sigs: Uint8Array, key: Uint8Array): Uint8Array;
|
|
411
|
+
multipartParseBatchPacked(input: Uint8Array, boundary: Uint8Array): Uint8Array;
|
|
412
|
+
templateRenderBatchPacked(input: Uint8Array, source: string): Uint8Array;
|
|
413
|
+
sseEncodeBatchPacked(input: Uint8Array, event: string | null, id: string | null, retry: number | null): Uint8Array;
|
|
414
|
+
wsFrameEncodeBatchPacked(input: Uint8Array, opcode: number, mask: boolean, fin: boolean): Uint8Array;
|
|
415
|
+
wsFrameDecodeBatchPacked(input: Uint8Array): Uint8Array;
|
|
416
|
+
}
|
|
417
|
+
/** Scalar + factory + runtime methods of the Rust client. */
|
|
418
|
+
export interface RustScalar {
|
|
419
|
+
/**
|
|
420
|
+
* @performance CRC32: ~3.7x slower than the JS baseline (2/3 tasks failed) [check:annotate]
|
|
421
|
+
* @deprecated Slower than the native JS baseline (~3.7x) — prefer the JS/Bun baseline. [check:annotate]
|
|
422
|
+
* @remarks Sub-µs FFI-crossing bound vs the same-engine JS crc-32 loop (~0.23-0.44x across runs); use the packed crc32BatchPacked path which wins on larger inputs. [check:annotate]
|
|
423
|
+
*/
|
|
424
|
+
crc32(input: Uint8Array): number;
|
|
425
|
+
/**
|
|
426
|
+
* @performance FNV-1a 64: ~6.6x faster than the JS baseline [check:annotate]
|
|
427
|
+
*/
|
|
428
|
+
fnv1a64(input: Uint8Array): bigint;
|
|
429
|
+
/**
|
|
430
|
+
* XXH3-64 over raw bytes (high-throughput non-cryptographic hash).
|
|
431
|
+
* Compare against `Bun.hash.xxHash3` — see docs/bun-builtins-decision-matrix.md.
|
|
432
|
+
*/
|
|
433
|
+
xxh3(input: Uint8Array): bigint;
|
|
434
|
+
/**
|
|
435
|
+
* @performance HMAC sign: ~1.1x faster than the JS baseline (2/3 tasks won) [check:annotate]
|
|
436
|
+
*/
|
|
437
|
+
hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;
|
|
438
|
+
/**
|
|
439
|
+
* @performance HMAC verify: ~2.5x faster than the JS baseline [check:annotate]
|
|
440
|
+
*/
|
|
441
|
+
hmacSha256Verify(key: Uint8Array, data: Uint8Array, sig: Uint8Array): boolean;
|
|
442
|
+
/**
|
|
443
|
+
* @performance JSON valid: ~3.2x faster than the JS baseline (8/8 tasks won) [check:annotate]
|
|
444
|
+
*/
|
|
445
|
+
jsonValid(input: Uint8Array): boolean;
|
|
446
|
+
/**
|
|
447
|
+
* Parse JSON to a JS value (native sonic-rs DOM → napi). Throws on invalid JSON.
|
|
448
|
+
* @performance JSON parse: ~5.0x slower than the JS baseline [check:annotate]
|
|
449
|
+
* @deprecated Slower than the native JS baseline (~5.0x) — prefer the JS/Bun baseline. [check:annotate]
|
|
450
|
+
* @remarks Bun's JSON.parse beats the native DOM + napi marshaling path (~5x). [check:annotate]
|
|
451
|
+
*/
|
|
452
|
+
jsonParse(input: Uint8Array): unknown;
|
|
453
|
+
/**
|
|
454
|
+
* @performance JSON sum: ~2.9x faster than the JS baseline (4/4 tasks won) [check:annotate]
|
|
455
|
+
*/
|
|
456
|
+
jsonSumIds(input: Uint8Array): bigint;
|
|
457
|
+
/**
|
|
458
|
+
* @performance JSON Patch: ~1.2x faster than the JS baseline [check:annotate]
|
|
459
|
+
* @remarks Modest but real win; swings ~0.9-1.5x run-to-run (DOM marshal dominated). [check:annotate]
|
|
460
|
+
*/
|
|
461
|
+
jsonPatch(doc: Uint8Array, patch: Uint8Array): Uint8Array;
|
|
462
|
+
/**
|
|
463
|
+
* @performance MIME lookup: ≈ parity with the JS baseline [check:annotate]
|
|
464
|
+
* @remarks Noisy sub-µs op: wins ~1.6x on good runs, loses on bad runs; phf table lookup. [check:annotate]
|
|
465
|
+
*/
|
|
466
|
+
mimeFromExtension(ext: Uint8Array): Uint8Array;
|
|
467
|
+
/**
|
|
468
|
+
* @performance Random token: ≈ parity with the JS baseline [check:annotate]
|
|
469
|
+
*/
|
|
470
|
+
randomToken(byteLen: number): Uint8Array;
|
|
471
|
+
/**
|
|
472
|
+
* @performance URL encode: ~2.2x slower than the JS baseline (2/3 tasks failed) [check:annotate]
|
|
473
|
+
* @deprecated Slower than the native JS baseline (~2.2x) — prefer the JS/Bun baseline. [check:annotate]
|
|
474
|
+
* @remarks Loses ~2.8x on the shipped baseline release build (only wins in the LOCAL SIMD perf build). [check:annotate]
|
|
475
|
+
*/
|
|
476
|
+
urlEncode(input: Uint8Array): Uint8Array;
|
|
477
|
+
/**
|
|
478
|
+
* @performance URL decode: ~2.2x slower than the JS baseline (2/3 tasks failed) [check:annotate]
|
|
479
|
+
* @deprecated Slower than the native JS baseline (~2.2x) — prefer the JS/Bun baseline. [check:annotate]
|
|
480
|
+
* @remarks Loses ~2.8x on the shipped baseline release build (only wins in the LOCAL SIMD perf build). [check:annotate]
|
|
481
|
+
*/
|
|
482
|
+
urlDecode(input: Uint8Array): Uint8Array;
|
|
483
|
+
/** Strict percent-decode without UTF-8 validation. */
|
|
484
|
+
urlDecodeBytes(input: Uint8Array): Uint8Array;
|
|
485
|
+
/** Reusable-output percent-encode; returns bytes written. */
|
|
486
|
+
urlEncodeInto(input: Uint8Array, output: Uint8Array): number;
|
|
487
|
+
/** Reusable-output percent-decode; returns bytes written. */
|
|
488
|
+
urlDecodeInto(input: Uint8Array, output: Uint8Array): number;
|
|
489
|
+
/**
|
|
490
|
+
* @performance Email validation: ~3.1x faster than the JS baseline (4/4 tasks won) [check:annotate]
|
|
491
|
+
*/
|
|
492
|
+
validateEmail(input: Uint8Array): boolean;
|
|
493
|
+
/**
|
|
494
|
+
* @performance UUID validation: ≈ parity with the JS baseline (2/4 tasks won) [check:annotate]
|
|
495
|
+
*/
|
|
496
|
+
validateUuid(input: Uint8Array): boolean;
|
|
497
|
+
/**
|
|
498
|
+
* @performance IPv4 validation: ≈ parity with the JS baseline (2/2 tasks won) [check:annotate]
|
|
499
|
+
*/
|
|
500
|
+
validateIpv4(input: Uint8Array): boolean;
|
|
501
|
+
/**
|
|
502
|
+
* @performance IPv6 validation: ~1.9x faster than the JS baseline [check:annotate]
|
|
503
|
+
*/
|
|
504
|
+
validateIpv6(input: Uint8Array): boolean;
|
|
505
|
+
/**
|
|
506
|
+
* @performance WebSocket accept: ~1.9x faster than the JS baseline (1/2 tasks won) [check:annotate]
|
|
507
|
+
*/
|
|
508
|
+
wsAcceptKey(key: Uint8Array): Uint8Array;
|
|
509
|
+
/**
|
|
510
|
+
* @performance HTTP parse: ~5.3x faster than the JS baseline (6/6 tasks won) [check:annotate]
|
|
511
|
+
*/
|
|
512
|
+
httpParseRequestPacked(input: Uint8Array): Uint8Array;
|
|
513
|
+
/**
|
|
514
|
+
* @performance Query parse: ~3.8x faster than the JS baseline (6/6 tasks won) [check:annotate]
|
|
515
|
+
*/
|
|
516
|
+
queryParsePacked(input: Uint8Array): Uint8Array;
|
|
517
|
+
/**
|
|
518
|
+
* @performance Cookie parse: ~2.6x faster than the JS baseline (5/5 tasks won) [check:annotate]
|
|
519
|
+
*/
|
|
520
|
+
cookieParsePacked(input: Uint8Array): Uint8Array;
|
|
521
|
+
/** Reusable-output packed HTTP parse; returns bytes written. */
|
|
522
|
+
httpParseRequestPackedInto(input: Uint8Array, output: Uint8Array): number;
|
|
523
|
+
/** Reusable-output packed query parse; returns bytes written. */
|
|
524
|
+
queryParsePackedInto(input: Uint8Array, output: Uint8Array): number;
|
|
525
|
+
/** Reusable-output packed cookie parse; returns bytes written. */
|
|
526
|
+
cookieParsePackedInto(input: Uint8Array, output: Uint8Array): number;
|
|
527
|
+
/**
|
|
528
|
+
* Parse an application/x-www-form-urlencoded body into packed pairs.
|
|
529
|
+
* @performance Form parse: ~4.7x faster than the JS baseline (2/2 tasks won) [check:annotate]
|
|
530
|
+
* @remarks Benchmarked via the FormParser instance (same parser core). [check:annotate]
|
|
531
|
+
*/
|
|
532
|
+
formParsePacked(input: Uint8Array): Uint8Array;
|
|
533
|
+
/**
|
|
534
|
+
* Parse a Content-Type header into a structured media type.
|
|
535
|
+
* @performance Media type parse: ~1.3x slower than the JS baseline [check:annotate]
|
|
536
|
+
* @deprecated Slower than the native JS baseline (~1.3x) — prefer the JS/Bun baseline. [check:annotate]
|
|
537
|
+
* @remarks Consistent ~0.71-0.81x (sub-µs FFI crossing vs the JS baseline); use MediaTypeMatcher (precompiled expected) for the zero-alloc match path. [check:annotate]
|
|
538
|
+
*/
|
|
539
|
+
parseMediaType(input: Uint8Array): MediaTypeResult;
|
|
540
|
+
/**
|
|
541
|
+
* Generate a strong/weak ETag (crc32-based).
|
|
542
|
+
* @performance ETag: ≈ parity with the JS baseline [check:annotate]
|
|
543
|
+
*/
|
|
544
|
+
etag(data: Uint8Array, weak?: boolean): Uint8Array;
|
|
545
|
+
/** Reusable-output etag; returns bytes written (10 strong / 12 weak). */
|
|
546
|
+
etagInto(data: Uint8Array, output: Uint8Array, weak?: boolean): number;
|
|
547
|
+
/**
|
|
548
|
+
* Format a unix timestamp as an IMF-fixdate HTTP-date.
|
|
549
|
+
* @performance HTTP date: ~1.5x slower than the JS baseline (2/2 tasks failed) [check:annotate]
|
|
550
|
+
* @deprecated Slower than the native JS baseline (~1.5x) — prefer the JS/Bun baseline. [check:annotate]
|
|
551
|
+
* @remarks Date.toUTCString() is native (~1.5-1.7x loss); pooled httpDateInto cuts it to ~1.3x. [check:annotate]
|
|
552
|
+
*/
|
|
553
|
+
httpDate(secs?: number): Uint8Array;
|
|
554
|
+
/** Reusable-output http-date; returns bytes written (29). Throws if `output` is too small or the year is out of the fixed-width range. */
|
|
555
|
+
httpDateInto(secs: number | undefined, output: Uint8Array): number;
|
|
556
|
+
/** Parse an IMF-fixdate HTTP-date back to unix seconds. */
|
|
557
|
+
parseHttpDate(input: Uint8Array): bigint | null;
|
|
558
|
+
/** Parse an Accept-Encoding header into ordered preferences. */
|
|
559
|
+
parseAcceptEncoding(input: Uint8Array): EncodingPrefResult[];
|
|
560
|
+
/**
|
|
561
|
+
* Base64 encode (standard by default; url-safe/padding configurable).
|
|
562
|
+
* @performance Base64 encode: ~1.6x slower than the JS baseline [check:annotate]
|
|
563
|
+
* @deprecated Slower than the native JS baseline (~1.6x) — prefer the JS/Bun baseline. [check:annotate]
|
|
564
|
+
* @remarks Bun Buffer base64 is SIMD; loses ~1.5x. [check:annotate]
|
|
565
|
+
*/
|
|
566
|
+
base64Encode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array;
|
|
567
|
+
/**
|
|
568
|
+
* Base64 decode (standard); throws on invalid input.
|
|
569
|
+
* @performance Base64 decode: ≈ parity with the JS baseline [check:annotate]
|
|
570
|
+
*/
|
|
571
|
+
base64Decode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array;
|
|
572
|
+
/** Reusable-output base64 encode; returns bytes written. */
|
|
573
|
+
base64EncodeInto(input: Uint8Array, output: Uint8Array, urlSafe?: boolean, padding?: boolean): number;
|
|
574
|
+
/** Reusable-output base64 decode; returns bytes written. Throws on invalid input. */
|
|
575
|
+
base64DecodeInto(input: Uint8Array, output: Uint8Array, urlSafe?: boolean, padding?: boolean): number;
|
|
576
|
+
base64UrlEncode(input: Uint8Array): Uint8Array;
|
|
577
|
+
base64UrlDecode(input: Uint8Array): Uint8Array;
|
|
578
|
+
/**
|
|
579
|
+
* Lowercase hex encode.
|
|
580
|
+
* @performance Hex encode: ~1.4x slower than the JS baseline (1/2 tasks failed) [check:annotate]
|
|
581
|
+
* @deprecated Slower than the native JS baseline (~1.4x) — prefer the JS/Bun baseline. [check:annotate]
|
|
582
|
+
* @remarks Buffer.toString('hex') is native SIMD; pooled hexEncodeInto cuts the loss from ~2.2x to ~1.35x. [check:annotate]
|
|
583
|
+
*/
|
|
584
|
+
hexEncode(input: Uint8Array): Uint8Array;
|
|
585
|
+
/**
|
|
586
|
+
* Hex decode; throws on odd length or invalid digits.
|
|
587
|
+
* @performance Hex decode: ≈ parity with the JS baseline [check:annotate]
|
|
588
|
+
* @remarks Slightly slower than Buffer hex decode (~1.3x). [check:annotate]
|
|
589
|
+
*/
|
|
590
|
+
hexDecode(input: Uint8Array): Uint8Array;
|
|
591
|
+
/** Reusable-output lowercase-hex encode; returns bytes written. */
|
|
592
|
+
hexEncodeInto(input: Uint8Array, output: Uint8Array): number;
|
|
593
|
+
/** Reusable-output hex decode; returns bytes written. Throws on bad input. */
|
|
594
|
+
hexDecodeInto(input: Uint8Array, output: Uint8Array): number;
|
|
595
|
+
/** Reusable-output HMAC-SHA256 hex (64 bytes); returns bytes written. Throws on too-small buffer. */
|
|
596
|
+
hmacSha256Into(key: Uint8Array, data: Uint8Array, output: Uint8Array): number;
|
|
597
|
+
/** Reusable-output cookie sign (`value.<64-hex>`); returns bytes written. Throws on too-small buffer. */
|
|
598
|
+
signCookieInto(value: Uint8Array, secret: Uint8Array, output: Uint8Array): number;
|
|
599
|
+
/** Reusable-output AEAD encrypt (ct + 16-byte tag); returns bytes written. Throws on too-small buffer. */
|
|
600
|
+
aeadEncryptInto(key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, output: Uint8Array, algorithm?: string | null): number;
|
|
601
|
+
/** Reusable-output WS frame encode; returns bytes written. Throws on too-small buffer. */
|
|
602
|
+
wsFrameEncodeInto(opcode: number, payload: Uint8Array, mask: boolean, fin: boolean, output: Uint8Array): number;
|
|
603
|
+
/** Reusable-output gzip compress; returns bytes written. Throws on too-small buffer. */
|
|
604
|
+
gzipCompressInto(data: Uint8Array, output: Uint8Array, level?: number | null): number;
|
|
605
|
+
/** Reusable-output brotli compress; returns bytes written. Throws on too-small buffer. */
|
|
606
|
+
brotliCompressInto(data: Uint8Array, output: Uint8Array, quality?: number | null): number;
|
|
607
|
+
/**
|
|
608
|
+
* Sign a cookie value as `value.signature` (HMAC-SHA256 hex).
|
|
609
|
+
* @performance Cookie sign: ~1.0x faster than the JS baseline [check:annotate]
|
|
610
|
+
*/
|
|
611
|
+
signCookie(value: Uint8Array, secret: Uint8Array): Uint8Array;
|
|
612
|
+
/**
|
|
613
|
+
* Verify a signed cookie; returns the value or null.
|
|
614
|
+
* @performance Cookie verify: ~9.5x faster than the JS baseline [check:annotate]
|
|
615
|
+
*/
|
|
616
|
+
verifyCookie(signed: Uint8Array, secret: Uint8Array): Uint8Array | null;
|
|
617
|
+
/**
|
|
618
|
+
* Create a CSRF token (32-byte random hex + HMAC signature).
|
|
619
|
+
* @performance CSRF create: ~13.7x faster than the JS baseline [check:annotate]
|
|
620
|
+
*/
|
|
621
|
+
csrfToken(secret: Uint8Array): Uint8Array;
|
|
622
|
+
/**
|
|
623
|
+
* Constant-time verify a CSRF token.
|
|
624
|
+
* @performance CSRF verify: ~3.3x faster than the JS baseline [check:annotate]
|
|
625
|
+
*/
|
|
626
|
+
csrfVerify(token: Uint8Array, secret: Uint8Array): boolean;
|
|
627
|
+
/**
|
|
628
|
+
* Resolve a URL reference against a base (RFC 3986).
|
|
629
|
+
* @performance URL resolve: ~1.8x slower than the JS baseline [check:annotate]
|
|
630
|
+
* @deprecated Slower than the native JS baseline (~1.8x) — prefer the JS/Bun baseline. [check:annotate]
|
|
631
|
+
* @remarks Auto-deprecated: 1/1 benchmarks failed in the latest run (static classification was parity). [check:annotate]
|
|
632
|
+
* @remarks Noisy ~1.5µs op; swings 0.74-1.03x run-to-run. UrlBuilder reuses the parsed base. [check:annotate]
|
|
633
|
+
*/
|
|
634
|
+
urlResolve(base: Uint8Array, reference: Uint8Array): Uint8Array;
|
|
635
|
+
/**
|
|
636
|
+
* Build a percent-encoded query string from params (sorted keys).
|
|
637
|
+
* @performance URL query build: ~1.4x slower than the JS baseline [check:annotate]
|
|
638
|
+
* @deprecated Slower than the native JS baseline (~1.4x) — prefer the JS/Bun baseline. [check:annotate]
|
|
639
|
+
* @remarks encodeURIComponent baseline wins (~1.2-1.35x). [check:annotate]
|
|
640
|
+
*/
|
|
641
|
+
urlEncodeQuery(params: Record<string, string>): Uint8Array;
|
|
642
|
+
/**
|
|
643
|
+
* @performance JSON schema validate: ~1.7x faster than the JS baseline (2/2 tasks won) [check:annotate]
|
|
644
|
+
* @remarks Zero-DOM fast path validates raw bytes for the common keyword subset (scalar ~1.2-2.4x, batch ~1.0-1.56x vs ajv); unsupported keywords fall back to the jsonschema crate. [check:annotate]
|
|
645
|
+
*/
|
|
646
|
+
createSchemaValidator(schema: Uint8Array): SchemaValidatorInstance;
|
|
647
|
+
createHmacSigner(key: Uint8Array): HmacSignerInstance;
|
|
648
|
+
createTemplateRenderer(source: string): TemplateRendererInstance;
|
|
649
|
+
/** Higher-order form parser: owns a reusable output buffer (setup once). */
|
|
650
|
+
createFormParser(capacity?: number): FormParserInstance;
|
|
651
|
+
/** Higher-order media-type parser: reusable wildcard matcher. */
|
|
652
|
+
createMediaTypeParser(): MediaTypeParserInstance;
|
|
653
|
+
/**
|
|
654
|
+
* Higher-order conditional-request check: per-resource 304 decision (setup once).
|
|
655
|
+
* @performance Conditional request: ~1.7x faster than the JS baseline [check:annotate]
|
|
656
|
+
*/
|
|
657
|
+
createConditionalRequest(etagValue: Uint8Array, lastModifiedSecs?: number): ConditionalRequestInstance;
|
|
658
|
+
/**
|
|
659
|
+
* Higher-order negotiator: precompiles supported encodings once.
|
|
660
|
+
* @performance Accept-Encoding negotiate: ~4.2x faster than the JS baseline [check:annotate]
|
|
661
|
+
*/
|
|
662
|
+
createAcceptNegotiator(supported: string[]): AcceptNegotiatorInstance;
|
|
663
|
+
/** Higher-order codec: base64 config compiled once. */
|
|
664
|
+
createBase64Codec(urlSafe?: boolean, padding?: boolean): Base64CodecInstance;
|
|
665
|
+
/** Higher-order cookie signer: HMAC key compiled once. */
|
|
666
|
+
createCookieSigner(secret: Uint8Array): CookieSignerInstance;
|
|
667
|
+
/** Higher-order CSRF protector: HMAC key compiled once. */
|
|
668
|
+
createCsrfProtector(secret: Uint8Array): CsrfProtectorInstance;
|
|
669
|
+
/** Higher-order URL builder: base parsed once, reused. */
|
|
670
|
+
createUrlBuilder(base: Uint8Array): UrlBuilderInstance;
|
|
671
|
+
/** Higher-order JWT signer: HS256 key + ttl compiled once. */
|
|
672
|
+
createJwtSigner(secret: Uint8Array, ttlSeconds?: number): JwtSignerInstance;
|
|
673
|
+
/** Higher-order AEAD cipher: algorithm + key compiled once. */
|
|
674
|
+
createAeadCipher(key: Uint8Array, algorithm?: string): AeadCipherInstance;
|
|
675
|
+
/** Higher-order argon2id hasher: params compiled once. */
|
|
676
|
+
createArgon2Hasher(options?: PasswordHashOptions | null): Argon2HasherInstance;
|
|
677
|
+
/** Higher-order media-type matcher: expected precompiled once. */
|
|
678
|
+
createMediaTypeMatcher(expected: Uint8Array): MediaTypeMatcherInstance;
|
|
679
|
+
/**
|
|
680
|
+
* Sharded fixed-window per-key rate limiter. `maxEntries` clamps internally
|
|
681
|
+
* (default 1,048,576). Each instance owns an independent budget.
|
|
682
|
+
* @remarks Scalar per-check cost: ~3-14x SLOWER than the JS Map baseline —
|
|
683
|
+
* prefer the ingress pipeline (one FFI for all stages) for native rate
|
|
684
|
+
* limiting in a request path. [measured 2026-08]
|
|
685
|
+
*/
|
|
686
|
+
createRateLimiter(limit: number, windowMs: number, maxEntries?: number | null): RateLimiterInstance;
|
|
687
|
+
initThreadPool(rayonThreads?: number): void;
|
|
688
|
+
rayonNumThreads(): number;
|
|
689
|
+
/**
|
|
690
|
+
* @performance JWT sign: ~1.1x slower than the JS baseline [check:annotate]
|
|
691
|
+
* @deprecated Slower than the native JS baseline (~1.1x) — prefer the JS/Bun baseline. [check:annotate]
|
|
692
|
+
* @remarks Base64 + claims DOM marshal overhead. Use jwtSignBytes (claims as JSON bytes) which skips the napi Value marshal and flips to a ~1.07x win. [check:annotate]
|
|
693
|
+
*/
|
|
694
|
+
jwtSign(claims: Record<string, unknown>, secret: Uint8Array, ttlSeconds?: number | null, nowSeconds?: number): Uint8Array;
|
|
695
|
+
/**
|
|
696
|
+
* Sign a JWT from pre-serialized claim JSON bytes — skips the napi
|
|
697
|
+
* `serde_json::Value` marshal of `jwtSign` for callers that already hold the
|
|
698
|
+
* bytes (same injection semantics).
|
|
699
|
+
* @performance JWT sign (bytes): ≈ parity with the JS baseline [check:annotate]
|
|
700
|
+
* @remarks Byte-JSON claims overload avoids the napi serde_json::Value DOM marshal; flips jwtSign from a ~1.3x loss to ~1.07x (parity). [check:annotate]
|
|
701
|
+
*/
|
|
702
|
+
jwtSignBytes(claimsJson: Uint8Array, secret: Uint8Array, ttlSeconds?: number | null, nowSeconds?: number): Uint8Array;
|
|
703
|
+
/**
|
|
704
|
+
* @performance JWT verify: ~1.7x faster than the JS baseline (2/2 tasks won) [check:annotate]
|
|
705
|
+
*/
|
|
706
|
+
jwtVerify(token: Uint8Array, secret: Uint8Array, nowSeconds?: number): unknown;
|
|
707
|
+
/**
|
|
708
|
+
* @performance Password hash: ~18.2x faster than the JS baseline (2/2 tasks won) [check:annotate]
|
|
709
|
+
* @remarks argon2id vs node:crypto scrypt. [check:annotate]
|
|
710
|
+
*/
|
|
711
|
+
passwordHash(password: Uint8Array, salt: Uint8Array, options?: PasswordHashOptions | null): Uint8Array;
|
|
712
|
+
passwordVerify(password: Uint8Array, phc: Uint8Array): boolean;
|
|
713
|
+
/** bcrypt password hash → `$2b$` PHC string (cost clamped 4..=31). */
|
|
714
|
+
passwordHashBcrypt(password: Uint8Array, cost: number): string;
|
|
715
|
+
/** Verify a password against a bcrypt `$2b$` PHC string. */
|
|
716
|
+
passwordVerifyBcrypt(password: Uint8Array, hash: string): boolean;
|
|
717
|
+
/** PBKDF2-HMAC-SHA256 key derivation (dkLen clamped to 1 MiB). */
|
|
718
|
+
pbkdf2Sha256(password: Uint8Array, salt: Uint8Array, rounds: number, dkLen: number): Uint8Array;
|
|
719
|
+
/**
|
|
720
|
+
* @performance AEAD encrypt: ~1.3x faster than the JS baseline [check:annotate]
|
|
721
|
+
*/
|
|
722
|
+
aeadEncrypt(key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, algorithm?: string | null): Uint8Array;
|
|
723
|
+
/**
|
|
724
|
+
* @performance AEAD decrypt: ~1.4x faster than the JS baseline [check:annotate]
|
|
725
|
+
*/
|
|
726
|
+
aeadDecrypt(key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, algorithm?: string | null): Uint8Array | null;
|
|
727
|
+
/**
|
|
728
|
+
* @performance Gzip compress: ≈ parity with the JS baseline (1/2 tasks won) [check:annotate]
|
|
729
|
+
*/
|
|
730
|
+
gzipCompress(data: Uint8Array, level?: number | null): Uint8Array;
|
|
731
|
+
/**
|
|
732
|
+
* @performance Gzip decompress: ~1.0x faster than the JS baseline [check:annotate]
|
|
733
|
+
* @remarks zlib-rs vs node zlib; swings 1.0-1.4x run-to-run. [check:annotate]
|
|
734
|
+
* @param maxDecompressed Caps decompressed output (default 64 MiB) as a
|
|
735
|
+
* decompression-bomb guard; a larger value errors.
|
|
736
|
+
*/
|
|
737
|
+
gzipDecompress(data: Uint8Array, maxDecompressed?: number | null): Uint8Array;
|
|
738
|
+
/**
|
|
739
|
+
* @performance Brotli compress: ~1.7x slower than the JS baseline [check:annotate]
|
|
740
|
+
* @deprecated Slower than the native JS baseline (~1.7x) — prefer the JS/Bun baseline. [check:annotate]
|
|
741
|
+
* @remarks The native brotli baseline wins for small inputs. [check:annotate]
|
|
742
|
+
*/
|
|
743
|
+
brotliCompress(data: Uint8Array, quality?: number | null): Uint8Array;
|
|
744
|
+
/**
|
|
745
|
+
* @performance Brotli decompress: ~1.4x slower than the JS baseline [check:annotate]
|
|
746
|
+
* @deprecated Slower than the native JS baseline (~1.4x) — prefer the JS/Bun baseline. [check:annotate]
|
|
747
|
+
* @remarks Auto-deprecated: 1/1 benchmarks failed in the latest run (static classification was proven). [check:annotate]
|
|
748
|
+
* @param maxDecompressed Caps decompressed output (default 64 MiB) as a
|
|
749
|
+
* decompression-bomb guard; a larger value errors.
|
|
750
|
+
*/
|
|
751
|
+
brotliDecompress(data: Uint8Array, maxDecompressed?: number | null): Uint8Array;
|
|
752
|
+
/**
|
|
753
|
+
* @performance Multipart parse: ~1.9x faster than the JS baseline [check:annotate]
|
|
754
|
+
*/
|
|
755
|
+
multipartParse(body: Uint8Array, boundary: Uint8Array): MultipartPart[];
|
|
756
|
+
/** Zero-copy packed sibling of `multipartParse` (packed parts layout). */
|
|
757
|
+
multipartParsePacked(body: Uint8Array, boundary: Uint8Array): Uint8Array;
|
|
758
|
+
/**
|
|
759
|
+
* @performance WS frame encode: ~2.0x faster than the JS baseline [check:annotate]
|
|
760
|
+
*/
|
|
761
|
+
wsFrameEncode(opcode: number, payload: Uint8Array, mask: boolean, fin: boolean): Uint8Array;
|
|
762
|
+
/**
|
|
763
|
+
* @performance WS frame decode: ~2.3x faster than the JS baseline [check:annotate]
|
|
764
|
+
*/
|
|
765
|
+
wsFrameDecode(data: Uint8Array): WsFrame | null;
|
|
766
|
+
/**
|
|
767
|
+
* @performance SSE encode: ≈ parity with the JS baseline [check:annotate]
|
|
768
|
+
*/
|
|
769
|
+
sseEncodeEvent(event: string | null, data: Uint8Array, id: string | null, retry: number | null): Uint8Array;
|
|
770
|
+
}
|
|
771
|
+
/** The full Rust FFI client (scalar methods + namespaces + configuration). */
|
|
772
|
+
export interface RustClient extends RustScalar {
|
|
773
|
+
text: RustText;
|
|
774
|
+
batch: RustBatch;
|
|
775
|
+
packed: RustPacked;
|
|
776
|
+
/**
|
|
777
|
+
* Resolve the native transport in use on this runtime: `"ffi"` (bun:ffi —
|
|
778
|
+
* the PRIMARY transport under Bun) or `"napi"` (Node, forced
|
|
779
|
+
* `CASTRUM_FFI_MODE=napi`, or a failed ffi bind-time self-test).
|
|
780
|
+
*/
|
|
781
|
+
transport(): "ffi" | "napi";
|
|
782
|
+
/** Whether the bun:ffi transport is live (equivalent to `transport() === "ffi"`). */
|
|
783
|
+
ffiActive(): boolean;
|
|
784
|
+
/**
|
|
785
|
+
* Update defaults on this instance. `mimeCache` / `hmacCache` apply
|
|
786
|
+
* immediately (per-instance). `rayonThreads` is applied only if the
|
|
787
|
+
* process-wide pool is not yet initialized (see {@link RustOptions}).
|
|
788
|
+
*/
|
|
789
|
+
configure(options: RustOptions): void;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Create an isolated Rust client with the given defaults.
|
|
793
|
+
*
|
|
794
|
+
* `mimeCache` / `hmacCache` are per-instance. `rayonThreads` only applies
|
|
795
|
+
* before the process-wide rayon pool is initialized (once per process — see
|
|
796
|
+
* {@link RustOptions.rayonThreads}); the pool defaults to the env var or
|
|
797
|
+
* `max(1, hardwareConcurrency - 1)` otherwise.
|
|
798
|
+
*/
|
|
799
|
+
export declare function createRust(options?: RustOptions): RustClient;
|
|
800
|
+
/**
|
|
801
|
+
* The default, ready-to-use `RustClient` created with no options (resolves
|
|
802
|
+
* rayon threads from the host automatically). Most consumers just do
|
|
803
|
+
* `import { rust } from "castrum"` and call `rust.<fn>(...)` directly.
|
|
804
|
+
*/
|
|
805
|
+
export declare const rust: RustClient;
|
|
806
|
+
/** Recommended implementation for an operation. */
|
|
807
|
+
export type OpImpl = "native" | "js";
|
|
808
|
+
export interface OpDecision {
|
|
809
|
+
/** The recommended implementation when the addon is available. */
|
|
810
|
+
readonly impl: OpImpl;
|
|
811
|
+
/** Why this decision (measured ratio / rationale). */
|
|
812
|
+
readonly note?: string;
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* The benchmark-driven native-vs-JS decision for `op` — runtime-aware.
|
|
816
|
+
*
|
|
817
|
+
* Returns `"native"` when the Rust addon is the recommended implementation,
|
|
818
|
+
* `"js"` when a pure-JS (or Bun built-in) implementation wins, or `null` for
|
|
819
|
+
* unknown ops (or when the addon is unavailable — with no addon there is no
|
|
820
|
+
* "native" choice). Under Bun, ops in {@link BUN_WINS} resolve to `"js"` so the
|
|
821
|
+
* consumer's JS path delegates to the faster Bun built-in.
|
|
822
|
+
*/
|
|
823
|
+
export declare const opImpl: (op: string) => OpImpl | null;
|
|
824
|
+
/** `true` when the Rust addon is the recommended impl for `op`. */
|
|
825
|
+
export declare const isNativeOp: (op: string) => boolean;
|
|
826
|
+
/** The decision record for `op`, or `null` when unknown. */
|
|
827
|
+
export declare const opDecision: (op: string) => OpDecision | null;
|
|
828
|
+
export type PerformanceStatus = "proven" | "parity" | "not-competitive" | "unmeasured";
|
|
829
|
+
export interface ProvenEntry {
|
|
830
|
+
/** Public `rust.<name>` method key. */
|
|
831
|
+
name: string;
|
|
832
|
+
/** Benchmark comparison label (see src/bench/comparisons.ts). */
|
|
833
|
+
label: string;
|
|
834
|
+
/** Baseline task name in the CPU report. */
|
|
835
|
+
nativeTask: string;
|
|
836
|
+
/** Rust task name in the CPU report. */
|
|
837
|
+
rustTask: string;
|
|
838
|
+
status: PerformanceStatus;
|
|
839
|
+
/** Typical rust-vs-baseline ratio from release/perf builds (rust faster = >1). */
|
|
840
|
+
typicalRatio?: number;
|
|
841
|
+
/** Why this classification. */
|
|
842
|
+
note?: string;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Curated registry. Classifications are based on release/perf-build results
|
|
846
|
+
* (docs + prior runs); the audit script re-checks them against the latest
|
|
847
|
+
* report. Borderline wins are kept as "parity" so the `proven` surface stays
|
|
848
|
+
* honest.
|
|
849
|
+
*
|
|
850
|
+
* `as const satisfies` keeps the literal `name`/`status` types so the
|
|
851
|
+
* `ProvenKey` type (below) can be derived at the type level.
|
|
852
|
+
*/
|
|
853
|
+
export declare const PROVEN_SURFACE: readonly [
|
|
854
|
+
{
|
|
855
|
+
readonly name: "fnv1a64";
|
|
856
|
+
readonly label: "FNV-1a 64";
|
|
857
|
+
readonly nativeTask: "native:fnv1a64";
|
|
858
|
+
readonly rustTask: "rust:fnv1a64";
|
|
859
|
+
readonly status: "proven";
|
|
860
|
+
readonly typicalRatio: 11;
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
readonly name: "jsonValid";
|
|
864
|
+
readonly label: "JSON valid";
|
|
865
|
+
readonly nativeTask: "native:json_valid";
|
|
866
|
+
readonly rustTask: "rust:json_valid";
|
|
867
|
+
readonly status: "proven";
|
|
868
|
+
readonly typicalRatio: 3;
|
|
869
|
+
},
|
|
870
|
+
{
|
|
871
|
+
readonly name: "jsonSumIds";
|
|
872
|
+
readonly label: "JSON sum";
|
|
873
|
+
readonly nativeTask: "native:json_sum";
|
|
874
|
+
readonly rustTask: "rust:json_sum";
|
|
875
|
+
readonly status: "proven";
|
|
876
|
+
readonly typicalRatio: 3;
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
readonly name: "httpParseRequestPacked";
|
|
880
|
+
readonly label: "HTTP parse";
|
|
881
|
+
readonly nativeTask: "native:http_parse";
|
|
882
|
+
readonly rustTask: "rust:http_parse";
|
|
883
|
+
readonly status: "proven";
|
|
884
|
+
readonly typicalRatio: 4;
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
readonly name: "queryParsePacked";
|
|
888
|
+
readonly label: "Query parse";
|
|
889
|
+
readonly nativeTask: "native:query_parse";
|
|
890
|
+
readonly rustTask: "rust:query_parse";
|
|
891
|
+
readonly status: "proven";
|
|
892
|
+
readonly typicalRatio: 4;
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
readonly name: "cookieParsePacked";
|
|
896
|
+
readonly label: "Cookie parse";
|
|
897
|
+
readonly nativeTask: "native:cookie_parse";
|
|
898
|
+
readonly rustTask: "rust:cookie_parse";
|
|
899
|
+
readonly status: "proven";
|
|
900
|
+
readonly typicalRatio: 2.5;
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
readonly name: "wsAcceptKey";
|
|
904
|
+
readonly label: "WebSocket accept";
|
|
905
|
+
readonly nativeTask: "native:ws_accept_key";
|
|
906
|
+
readonly rustTask: "rust:ws_accept_key";
|
|
907
|
+
readonly status: "proven";
|
|
908
|
+
readonly typicalRatio: 1.6;
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
readonly name: "jsonPatch";
|
|
912
|
+
readonly label: "JSON Patch";
|
|
913
|
+
readonly nativeTask: "native:json_patch";
|
|
914
|
+
readonly rustTask: "rust:json_patch";
|
|
915
|
+
readonly status: "proven";
|
|
916
|
+
readonly typicalRatio: 1.2;
|
|
917
|
+
readonly note: "Modest but real win; swings ~0.9-1.5x run-to-run (DOM marshal dominated).";
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
readonly name: "hmacSha256";
|
|
921
|
+
readonly label: "HMAC sign";
|
|
922
|
+
readonly nativeTask: "native:hmac_sha256";
|
|
923
|
+
readonly rustTask: "rust:hmac_sha256";
|
|
924
|
+
readonly status: "proven";
|
|
925
|
+
readonly typicalRatio: 1.5;
|
|
926
|
+
readonly note: "Classification vs the node:crypto baseline. Under Bun the public rust.hmacSha256 delegates to Bun.CryptoHasher (BUN_WINS \u2014 hex re-encoded to the same contract); this row measures the raw addon (see src/bench/raw-native.ts).";
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
readonly name: "hmacSha256Verify";
|
|
930
|
+
readonly label: "HMAC verify";
|
|
931
|
+
readonly nativeTask: "native:hmac_verify";
|
|
932
|
+
readonly rustTask: "rust:hmac_verify";
|
|
933
|
+
readonly status: "proven";
|
|
934
|
+
readonly typicalRatio: 2.4;
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
readonly name: "validateEmail";
|
|
938
|
+
readonly label: "Email validation";
|
|
939
|
+
readonly nativeTask: "native:validate_email";
|
|
940
|
+
readonly rustTask: "rust:validate_email";
|
|
941
|
+
readonly status: "proven";
|
|
942
|
+
readonly typicalRatio: 3;
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
readonly name: "validateIpv6";
|
|
946
|
+
readonly label: "IPv6 validation";
|
|
947
|
+
readonly nativeTask: "native:validate_ipv6";
|
|
948
|
+
readonly rustTask: "rust:validate_ipv6";
|
|
949
|
+
readonly status: "proven";
|
|
950
|
+
readonly typicalRatio: 1.3;
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
readonly name: "urlEncode";
|
|
954
|
+
readonly label: "URL encode";
|
|
955
|
+
readonly nativeTask: "native:url_encode";
|
|
956
|
+
readonly rustTask: "rust:url_encode";
|
|
957
|
+
readonly status: "not-competitive";
|
|
958
|
+
readonly note: "Public rust.urlEncode delegates to encodeURIComponent under Bun (BUN_WINS \u2014 ~3-4x faster than the FFI crossing; skips the C-ABI call). The rust: column measures the RAW addon (src/bench/raw-native.ts): the small-input FFI crossing loses (~0.58x), but LARGE inputs win (rust:url_encode_large ~1.45x) \u2014 the honest report no longer self-compares the built-in. Rust addon remains the Node path. Byte parity pinned by test/unit/features/url.test.ts + test/unit/features/wiring.test.ts.";
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
readonly name: "urlDecode";
|
|
962
|
+
readonly label: "URL decode";
|
|
963
|
+
readonly nativeTask: "native:url_decode";
|
|
964
|
+
readonly rustTask: "rust:url_decode";
|
|
965
|
+
readonly status: "not-competitive";
|
|
966
|
+
readonly note: "Public rust.urlDecode delegates to decodeURIComponent under Bun (BUN_WINS \u2014 ~4-8x faster than the FFI crossing; strict UTF-8 semantics match: both throw on malformed/invalid). The rust: column measures the RAW addon (src/bench/raw-native.ts): the small-input FFI crossing loses (~0.55x), but LARGE inputs win (rust:url_decode_large ~3.45x) \u2014 the honest report no longer self-compares the built-in. Rust addon remains the Node path and the raw-bytes urlDecodeBytes stays native. Parity pinned by test/unit/features/url.test.ts + test/unit/features/wiring.test.ts.";
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
readonly name: "jwtVerify";
|
|
970
|
+
readonly label: "JWT verify";
|
|
971
|
+
readonly nativeTask: "native:jwt_verify";
|
|
972
|
+
readonly rustTask: "rust:jwt_verify";
|
|
973
|
+
readonly status: "proven";
|
|
974
|
+
readonly typicalRatio: 1.4;
|
|
975
|
+
},
|
|
976
|
+
{
|
|
977
|
+
readonly name: "passwordHash";
|
|
978
|
+
readonly label: "Password hash";
|
|
979
|
+
readonly nativeTask: "native:password_hash";
|
|
980
|
+
readonly rustTask: "rust:password_hash";
|
|
981
|
+
readonly status: "proven";
|
|
982
|
+
readonly typicalRatio: 19;
|
|
983
|
+
readonly note: "argon2id vs node:crypto scrypt.";
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
readonly name: "aeadEncrypt";
|
|
987
|
+
readonly label: "AEAD encrypt";
|
|
988
|
+
readonly nativeTask: "native:aead_encrypt";
|
|
989
|
+
readonly rustTask: "rust:aead_encrypt";
|
|
990
|
+
readonly status: "proven";
|
|
991
|
+
readonly typicalRatio: 1.6;
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
readonly name: "aeadDecrypt";
|
|
995
|
+
readonly label: "AEAD decrypt";
|
|
996
|
+
readonly nativeTask: "native:aead_decrypt";
|
|
997
|
+
readonly rustTask: "rust:aead_decrypt";
|
|
998
|
+
readonly status: "proven";
|
|
999
|
+
readonly typicalRatio: 2;
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
readonly name: "gzipDecompress";
|
|
1003
|
+
readonly label: "Gzip decompress";
|
|
1004
|
+
readonly nativeTask: "native:gzip_decompress";
|
|
1005
|
+
readonly rustTask: "rust:gzip_decompress";
|
|
1006
|
+
readonly status: "proven";
|
|
1007
|
+
readonly typicalRatio: 1.4;
|
|
1008
|
+
readonly note: "zlib-rs vs node zlib; swings 1.0-1.4x run-to-run. Deliberately NOT delegated to Bun.gunzipSync under Bun (NOT in BUN_WINS): Bun's decompressor has no output-size bound, and the native path keeps the 64 MiB decompression-bomb cap.";
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
readonly name: "brotliDecompress";
|
|
1012
|
+
readonly label: "Brotli decompress";
|
|
1013
|
+
readonly nativeTask: "native:brotli_decompress";
|
|
1014
|
+
readonly rustTask: "rust:brotli_decompress";
|
|
1015
|
+
readonly status: "proven";
|
|
1016
|
+
readonly typicalRatio: 1.9;
|
|
1017
|
+
},
|
|
1018
|
+
{
|
|
1019
|
+
readonly name: "multipartParse";
|
|
1020
|
+
readonly label: "Multipart parse";
|
|
1021
|
+
readonly nativeTask: "native:multipart_parse";
|
|
1022
|
+
readonly rustTask: "rust:multipart_parse";
|
|
1023
|
+
readonly status: "proven";
|
|
1024
|
+
readonly typicalRatio: 2.3;
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
readonly name: "wsFrameEncode";
|
|
1028
|
+
readonly label: "WS frame encode";
|
|
1029
|
+
readonly nativeTask: "native:ws_frame_encode";
|
|
1030
|
+
readonly rustTask: "rust:ws_frame_encode";
|
|
1031
|
+
readonly status: "proven";
|
|
1032
|
+
readonly typicalRatio: 1.8;
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
readonly name: "wsFrameDecode";
|
|
1036
|
+
readonly label: "WS frame decode";
|
|
1037
|
+
readonly nativeTask: "native:ws_frame_decode";
|
|
1038
|
+
readonly rustTask: "rust:ws_frame_decode";
|
|
1039
|
+
readonly status: "proven";
|
|
1040
|
+
readonly typicalRatio: 2;
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
readonly name: "createSchemaValidator";
|
|
1044
|
+
readonly label: "JSON schema validate";
|
|
1045
|
+
readonly nativeTask: "native:json_schema_validate";
|
|
1046
|
+
readonly rustTask: "rust:json_schema_validate";
|
|
1047
|
+
readonly status: "proven";
|
|
1048
|
+
readonly note: "Zero-DOM fast path validates raw bytes for the common keyword subset (scalar ~1.2-2.4x, batch ~1.0-1.56x vs ajv); unsupported keywords fall back to the jsonschema crate.";
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
readonly name: "crc32";
|
|
1052
|
+
readonly label: "CRC32";
|
|
1053
|
+
readonly nativeTask: "native:crc32";
|
|
1054
|
+
readonly rustTask: "rust:crc32";
|
|
1055
|
+
readonly status: "not-competitive";
|
|
1056
|
+
readonly note: "Raw addon vs the same-engine JS crc-32 loop (~0.23-0.44x across runs). Under Bun the public rust.crc32 delegates to Bun.hash.crc32 (BUN_WINS, ~2.8-8.4x) \u2014 this row measures the raw addon (src/bench/raw-native.ts).";
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
readonly name: "xxh3";
|
|
1060
|
+
readonly label: "XXH3-64";
|
|
1061
|
+
readonly nativeTask: "diag:bun_hash_xxh3";
|
|
1062
|
+
readonly rustTask: "diag:xxh3";
|
|
1063
|
+
readonly status: "not-competitive";
|
|
1064
|
+
readonly note: "Bun.hash.xxHash3 wins ~4x (in-process C++ beats the FFI crossing). The public rust.xxh3 now DELEGATES to Bun.hash.xxHash3 under Bun (BUN_WINS); the addon remains the Node/non-Bun fast path. See docs/bun-builtins-decision-matrix.md.";
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
readonly name: "randomToken";
|
|
1068
|
+
readonly label: "Random token";
|
|
1069
|
+
readonly nativeTask: "native:random_token";
|
|
1070
|
+
readonly rustTask: "rust:random_token";
|
|
1071
|
+
readonly status: "parity";
|
|
1072
|
+
readonly typicalRatio: 1.1;
|
|
1073
|
+
readonly note: "Raw addon vs crypto.getRandomValues baseline. Under Bun the public rust.randomToken delegates to crypto.getRandomValues + native hex (BUN_WINS, same 2n-hex format + 16 MiB guard) \u2014 this row measures the raw addon (src/bench/raw-native.ts).";
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
readonly name: "validateUuid";
|
|
1077
|
+
readonly label: "UUID validation";
|
|
1078
|
+
readonly nativeTask: "native:validate_uuid";
|
|
1079
|
+
readonly rustTask: "rust:validate_uuid";
|
|
1080
|
+
readonly status: "parity";
|
|
1081
|
+
readonly typicalRatio: 1;
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
readonly name: "validateIpv4";
|
|
1085
|
+
readonly label: "IPv4 validation";
|
|
1086
|
+
readonly nativeTask: "native:validate_ipv4";
|
|
1087
|
+
readonly rustTask: "rust:validate_ipv4";
|
|
1088
|
+
readonly status: "parity";
|
|
1089
|
+
readonly typicalRatio: 1.05;
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
readonly name: "mimeFromExtension";
|
|
1093
|
+
readonly label: "MIME lookup";
|
|
1094
|
+
readonly nativeTask: "native:mime";
|
|
1095
|
+
readonly rustTask: "rust:mime";
|
|
1096
|
+
readonly status: "parity";
|
|
1097
|
+
readonly typicalRatio: 1.4;
|
|
1098
|
+
readonly note: "Consistently ~1.38-1.44x rust after the 2026-08-12 marshal reduction (cachedMime no longer per-call slices; text.mimeFromExtension memoizes the decoded string). phf table lookup.";
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
readonly name: "gzipCompress";
|
|
1102
|
+
readonly label: "Gzip compress";
|
|
1103
|
+
readonly nativeTask: "native:gzip_compress";
|
|
1104
|
+
readonly rustTask: "rust:gzip_compress";
|
|
1105
|
+
readonly status: "parity";
|
|
1106
|
+
readonly typicalRatio: 1;
|
|
1107
|
+
readonly note: "Raw addon vs node zlib baseline. Under Bun the public rust.gzipCompress delegates to Bun.gzipSync (BUN_WINS, ~2x; decompression-parity with the addon \u2014 only the header OS byte differs) \u2014 this row measures the raw addon (src/bench/raw-native.ts).";
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
readonly name: "sseEncodeEvent";
|
|
1111
|
+
readonly label: "SSE encode";
|
|
1112
|
+
readonly nativeTask: "native:sse_encode";
|
|
1113
|
+
readonly rustTask: "rust:sse_encode";
|
|
1114
|
+
readonly status: "parity";
|
|
1115
|
+
readonly typicalRatio: 1.1;
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
readonly name: "passwordHashBcrypt";
|
|
1119
|
+
readonly label: "Password hash (bcrypt)";
|
|
1120
|
+
readonly nativeTask: "diag:bun_password_bcrypt_hash";
|
|
1121
|
+
readonly rustTask: "diag:bcrypt_hash";
|
|
1122
|
+
readonly status: "parity";
|
|
1123
|
+
readonly note: "Bun.password.bcrypt ~1.24x faster at cost 10 (noisy KDF); rust is self-contained and non-Bun. See docs/bun-builtins-decision-matrix.md.";
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
readonly name: "passwordVerifyBcrypt";
|
|
1127
|
+
readonly label: "Password verify (bcrypt)";
|
|
1128
|
+
readonly nativeTask: "diag:bun_password_bcrypt_verify";
|
|
1129
|
+
readonly rustTask: "diag:bcrypt_verify";
|
|
1130
|
+
readonly status: "parity";
|
|
1131
|
+
readonly note: "Rust ~1.49x vs Bun.password.verify at cost 10; KDF timings noisy \u2014 parity for gate stability.";
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
readonly name: "pbkdf2Sha256";
|
|
1135
|
+
readonly label: "PBKDF2-HMAC-SHA256";
|
|
1136
|
+
readonly nativeTask: "diag:pbkdf2_sha256";
|
|
1137
|
+
readonly rustTask: "diag:pbkdf2_sha256_rust";
|
|
1138
|
+
readonly status: "parity";
|
|
1139
|
+
readonly note: "~1.08x vs node:crypto pbkdf2Sync at 100k rounds (parity); Bun has no synchronous PBKDF2.";
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
readonly name: "jsonParse";
|
|
1143
|
+
readonly label: "JSON parse";
|
|
1144
|
+
readonly nativeTask: "native:json_parse";
|
|
1145
|
+
readonly rustTask: "rust:json_parse";
|
|
1146
|
+
readonly status: "not-competitive";
|
|
1147
|
+
readonly note: "Bun's JSON.parse beats the native DOM + napi marshaling path (~5x).";
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
readonly name: "jwtSign";
|
|
1151
|
+
readonly label: "JWT sign";
|
|
1152
|
+
readonly nativeTask: "native:jwt_sign";
|
|
1153
|
+
readonly rustTask: "rust:jwt_sign";
|
|
1154
|
+
readonly status: "not-competitive";
|
|
1155
|
+
readonly note: "Base64 + claims DOM marshal overhead. Use jwtSignBytes (claims as JSON bytes) which skips the napi Value marshal and flips to a ~1.07x win.";
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
readonly name: "jwtSignBytes";
|
|
1159
|
+
readonly label: "JWT sign (bytes)";
|
|
1160
|
+
readonly nativeTask: "native:jwt_sign";
|
|
1161
|
+
readonly rustTask: "rust:jwt_sign_bytes";
|
|
1162
|
+
readonly status: "parity";
|
|
1163
|
+
readonly note: "Byte-JSON claims overload avoids the napi serde_json::Value DOM marshal; flips jwtSign from a ~1.3x loss to ~1.07x (parity).";
|
|
1164
|
+
},
|
|
1165
|
+
{
|
|
1166
|
+
readonly name: "brotliCompress";
|
|
1167
|
+
readonly label: "Brotli compress";
|
|
1168
|
+
readonly nativeTask: "native:brotli_compress";
|
|
1169
|
+
readonly rustTask: "rust:brotli_compress";
|
|
1170
|
+
readonly status: "not-competitive";
|
|
1171
|
+
readonly note: "The native brotli baseline wins for small inputs.";
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
readonly name: "templateRender";
|
|
1175
|
+
readonly label: "Template render";
|
|
1176
|
+
readonly nativeTask: "native:template_render";
|
|
1177
|
+
readonly rustTask: "rust:template_render";
|
|
1178
|
+
readonly status: "not-competitive";
|
|
1179
|
+
readonly note: "The allocating render marshals the context via napi DOM (~1.5x loss). Use TemplateRenderer.renderBytes (JSON-bytes context) which avoids it and wins ~1.37x.";
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
readonly name: "formParsePacked";
|
|
1183
|
+
readonly label: "Form parse";
|
|
1184
|
+
readonly nativeTask: "native:form_parse";
|
|
1185
|
+
readonly rustTask: "rust:form_parse";
|
|
1186
|
+
readonly status: "proven";
|
|
1187
|
+
readonly typicalRatio: 5.8;
|
|
1188
|
+
readonly note: "Benchmarked via the FormParser instance (same parser core).";
|
|
1189
|
+
},
|
|
1190
|
+
{
|
|
1191
|
+
readonly name: "parseMediaType";
|
|
1192
|
+
readonly label: "Media type parse";
|
|
1193
|
+
readonly nativeTask: "native:media_type_parse";
|
|
1194
|
+
readonly rustTask: "rust:media_type_parse";
|
|
1195
|
+
readonly status: "not-competitive";
|
|
1196
|
+
readonly note: "Consistent ~0.71-0.81x (sub-\u00B5s FFI crossing vs the JS baseline); use MediaTypeMatcher (precompiled expected) for the zero-alloc match path.";
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
readonly name: "etag";
|
|
1200
|
+
readonly label: "ETag";
|
|
1201
|
+
readonly nativeTask: "native:etag";
|
|
1202
|
+
readonly rustTask: "rust:etag";
|
|
1203
|
+
readonly status: "parity";
|
|
1204
|
+
readonly typicalRatio: 1.06;
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
readonly name: "httpDate";
|
|
1208
|
+
readonly label: "HTTP date";
|
|
1209
|
+
readonly nativeTask: "native:http_date";
|
|
1210
|
+
readonly rustTask: "rust:http_date";
|
|
1211
|
+
readonly status: "not-competitive";
|
|
1212
|
+
readonly note: "Delegates to Date.toUTCString() under Bun (BUN_WINS \u2014 ~3.7x faster than the FFI crossing; byte-identical RFC 1123 for HTTP timestamps, incl. leap years/epoch). Rust addon remains the Node path; pooled httpDateInto stays native.";
|
|
1213
|
+
},
|
|
1214
|
+
{
|
|
1215
|
+
readonly name: "createConditionalRequest";
|
|
1216
|
+
readonly label: "Conditional request";
|
|
1217
|
+
readonly nativeTask: "native:conditional";
|
|
1218
|
+
readonly rustTask: "rust:conditional";
|
|
1219
|
+
readonly status: "proven";
|
|
1220
|
+
readonly typicalRatio: 1.4;
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
readonly name: "createAcceptNegotiator";
|
|
1224
|
+
readonly label: "Accept-Encoding negotiate";
|
|
1225
|
+
readonly nativeTask: "native:accept_negotiate";
|
|
1226
|
+
readonly rustTask: "rust:accept_negotiate";
|
|
1227
|
+
readonly status: "proven";
|
|
1228
|
+
readonly typicalRatio: 4;
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
readonly name: "base64Encode";
|
|
1232
|
+
readonly label: "Base64 encode";
|
|
1233
|
+
readonly nativeTask: "native:base64_encode";
|
|
1234
|
+
readonly rustTask: "rust:base64_encode";
|
|
1235
|
+
readonly status: "not-competitive";
|
|
1236
|
+
readonly note: "Delegates to Buffer base64 under Bun for the standard padded, non-url-safe case (BUN_WINS \u2014 ~2x faster than the FFI crossing); url-safe/unpadded falls through to native. Rust addon remains the Node path. Parity pinned by test/unit/features/encoding.test.ts.";
|
|
1237
|
+
},
|
|
1238
|
+
{
|
|
1239
|
+
readonly name: "base64Decode";
|
|
1240
|
+
readonly label: "Base64 decode";
|
|
1241
|
+
readonly nativeTask: "native:base64_decode";
|
|
1242
|
+
readonly rustTask: "rust:base64_decode";
|
|
1243
|
+
readonly status: "parity";
|
|
1244
|
+
readonly typicalRatio: 1.17;
|
|
1245
|
+
},
|
|
1246
|
+
{
|
|
1247
|
+
readonly name: "hexEncode";
|
|
1248
|
+
readonly label: "Hex encode";
|
|
1249
|
+
readonly nativeTask: "native:hex_encode";
|
|
1250
|
+
readonly rustTask: "rust:hex_encode";
|
|
1251
|
+
readonly status: "not-competitive";
|
|
1252
|
+
readonly note: "Buffer.toString('hex') is native SIMD; pooled hexEncodeInto cuts the loss from ~2.2x to ~1.35x.";
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
readonly name: "hexDecode";
|
|
1256
|
+
readonly label: "Hex decode";
|
|
1257
|
+
readonly nativeTask: "native:hex_decode";
|
|
1258
|
+
readonly rustTask: "rust:hex_decode";
|
|
1259
|
+
readonly status: "parity";
|
|
1260
|
+
readonly typicalRatio: 0.78;
|
|
1261
|
+
readonly note: "Slightly slower than Buffer hex decode (~1.3x).";
|
|
1262
|
+
},
|
|
1263
|
+
{
|
|
1264
|
+
readonly name: "signCookie";
|
|
1265
|
+
readonly label: "Cookie sign";
|
|
1266
|
+
readonly nativeTask: "native:cookie_sign";
|
|
1267
|
+
readonly rustTask: "rust:cookie_sign";
|
|
1268
|
+
readonly status: "proven";
|
|
1269
|
+
readonly typicalRatio: 9;
|
|
1270
|
+
},
|
|
1271
|
+
{
|
|
1272
|
+
readonly name: "verifyCookie";
|
|
1273
|
+
readonly label: "Cookie verify";
|
|
1274
|
+
readonly nativeTask: "native:cookie_verify";
|
|
1275
|
+
readonly rustTask: "rust:cookie_verify";
|
|
1276
|
+
readonly status: "proven";
|
|
1277
|
+
readonly typicalRatio: 2.1;
|
|
1278
|
+
},
|
|
1279
|
+
{
|
|
1280
|
+
readonly name: "csrfToken";
|
|
1281
|
+
readonly label: "CSRF create";
|
|
1282
|
+
readonly nativeTask: "native:csrf_create";
|
|
1283
|
+
readonly rustTask: "rust:csrf_create";
|
|
1284
|
+
readonly status: "proven";
|
|
1285
|
+
readonly typicalRatio: 13.8;
|
|
1286
|
+
},
|
|
1287
|
+
{
|
|
1288
|
+
readonly name: "csrfVerify";
|
|
1289
|
+
readonly label: "CSRF verify";
|
|
1290
|
+
readonly nativeTask: "native:csrf_verify";
|
|
1291
|
+
readonly rustTask: "rust:csrf_verify";
|
|
1292
|
+
readonly status: "proven";
|
|
1293
|
+
readonly typicalRatio: 2.7;
|
|
1294
|
+
},
|
|
1295
|
+
{
|
|
1296
|
+
readonly name: "urlResolve";
|
|
1297
|
+
readonly label: "URL resolve";
|
|
1298
|
+
readonly nativeTask: "native:url_resolve";
|
|
1299
|
+
readonly rustTask: "rust:url_resolve";
|
|
1300
|
+
readonly status: "parity";
|
|
1301
|
+
readonly typicalRatio: 1.11;
|
|
1302
|
+
readonly note: "Noisy ~1.5\u00B5s op; swings 0.74-1.03x run-to-run. UrlBuilder reuses the parsed base.";
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
readonly name: "urlEncodeQuery";
|
|
1306
|
+
readonly label: "URL query build";
|
|
1307
|
+
readonly nativeTask: "native:url_encode_query";
|
|
1308
|
+
readonly rustTask: "rust:url_encode_query";
|
|
1309
|
+
readonly status: "not-competitive";
|
|
1310
|
+
readonly note: "encodeURIComponent baseline wins (~1.2-1.35x).";
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
readonly name: "passwordVerify";
|
|
1314
|
+
readonly label: "Password verify";
|
|
1315
|
+
readonly nativeTask: "";
|
|
1316
|
+
readonly rustTask: "";
|
|
1317
|
+
readonly status: "unmeasured";
|
|
1318
|
+
readonly note: "Depends on the hash cost; no standalone comparison.";
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
readonly name: "urlDecodeBytes";
|
|
1322
|
+
readonly label: "URL decode (bytes)";
|
|
1323
|
+
readonly nativeTask: "";
|
|
1324
|
+
readonly rustTask: "";
|
|
1325
|
+
readonly status: "unmeasured";
|
|
1326
|
+
},
|
|
1327
|
+
{
|
|
1328
|
+
readonly name: "configure";
|
|
1329
|
+
readonly label: "configure";
|
|
1330
|
+
readonly nativeTask: "";
|
|
1331
|
+
readonly rustTask: "";
|
|
1332
|
+
readonly status: "unmeasured";
|
|
1333
|
+
readonly note: "Config only.";
|
|
1334
|
+
},
|
|
1335
|
+
{
|
|
1336
|
+
readonly name: "initThreadPool";
|
|
1337
|
+
readonly label: "initThreadPool";
|
|
1338
|
+
readonly nativeTask: "";
|
|
1339
|
+
readonly rustTask: "";
|
|
1340
|
+
readonly status: "unmeasured";
|
|
1341
|
+
readonly note: "Runtime setup only.";
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
readonly name: "rayonNumThreads";
|
|
1345
|
+
readonly label: "rayonNumThreads";
|
|
1346
|
+
readonly nativeTask: "";
|
|
1347
|
+
readonly rustTask: "";
|
|
1348
|
+
readonly status: "unmeasured";
|
|
1349
|
+
readonly note: "Introspection only.";
|
|
1350
|
+
}
|
|
1351
|
+
];
|
|
1352
|
+
/** An entry of the registry with a specific status (type-level). */
|
|
1353
|
+
export type ProvenEntryOf<S extends PerformanceStatus> = Extract<(typeof PROVEN_SURFACE)[number], {
|
|
1354
|
+
status: S;
|
|
1355
|
+
}>;
|
|
1356
|
+
/**
|
|
1357
|
+
* The `rust.<name>` keys whose status is "proven" — the only keys exposed on
|
|
1358
|
+
* the `proven` surface. Derived from the registry so the type can never drift
|
|
1359
|
+
* from the data.
|
|
1360
|
+
*/
|
|
1361
|
+
export type ProvenKey = ProvenEntryOf<"proven">["name"];
|
|
1362
|
+
/** Look up the status of a public function by its `rust.<name>` key. */
|
|
1363
|
+
export declare function provenStatus(name: string): PerformanceStatus | undefined;
|
|
1364
|
+
/** Whether a function is part of the performance-proven surface. */
|
|
1365
|
+
export declare function isProven(name: string): boolean;
|
|
1366
|
+
/** The entries that are performance-proven (Rust clearly wins). */
|
|
1367
|
+
export declare function provenSurface(): ProvenEntry[];
|
|
1368
|
+
/** Aggregate summary of the registry (status → count). */
|
|
1369
|
+
export declare function provenSummary(): Record<PerformanceStatus, number>;
|
|
1370
|
+
/**
|
|
1371
|
+
* The performance-annotated client: the full {@link RustClient} surface.
|
|
1372
|
+
* Each exported function's JSDoc notes its measured performance vs the JS
|
|
1373
|
+
* baseline; functions slower than the baseline carry `@deprecated`.
|
|
1374
|
+
*/
|
|
1375
|
+
export type ProvenClient = RustClient;
|
|
1376
|
+
/**
|
|
1377
|
+
* The full `rust.*` surface with benchmark-annotated JSDoc. Identical to
|
|
1378
|
+
* `rust` — the annotations and `@deprecated` markers are what communicate
|
|
1379
|
+
* performance now, not a curated subset.
|
|
1380
|
+
*/
|
|
1381
|
+
export declare const proven: ProvenClient;
|
|
1382
|
+
/**
|
|
1383
|
+
* Shared TextEncoder instance for encoding strings to UTF-8 bytes.
|
|
1384
|
+
*
|
|
1385
|
+
* Reusing a single encoder avoids allocation overhead in hot paths.
|
|
1386
|
+
*/
|
|
1387
|
+
export declare const encoder: TextEncoder;
|
|
1388
|
+
/**
|
|
1389
|
+
* Shared TextDecoder instance for decoding UTF-8 bytes to strings.
|
|
1390
|
+
*
|
|
1391
|
+
* Reusing a single decoder avoids allocation overhead in hot paths.
|
|
1392
|
+
*/
|
|
1393
|
+
export declare const decoder: TextDecoder;
|
|
1394
|
+
export interface AdaptiveEstimateOptions {
|
|
1395
|
+
/**
|
|
1396
|
+
* EWMA smoothing factor in (0, 1]. Higher reacts faster to new samples;
|
|
1397
|
+
* lower smooths more. Default: 0.25.
|
|
1398
|
+
*/
|
|
1399
|
+
alpha?: number;
|
|
1400
|
+
/** Starting estimate. Default 0 (the first sample wins). */
|
|
1401
|
+
initial?: number;
|
|
1402
|
+
/** Clamp the estimate to at least this. Default 0. */
|
|
1403
|
+
min?: number;
|
|
1404
|
+
/** Clamp the estimate to at most this (bounds memory / resources). Default Infinity. */
|
|
1405
|
+
max?: number;
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* A bounded exponential-moving-average estimate of an observed quantity.
|
|
1409
|
+
*
|
|
1410
|
+
* `sample(x)` folds a new observation into the running estimate; `estimate`
|
|
1411
|
+
* reads the current value. The estimate is clamped to `[min, max]`, so it is
|
|
1412
|
+
* safe to drive resource sizing (buffer pools, batch thresholds) with it —
|
|
1413
|
+
* a single outlier cannot blow up the estimate, and it decays toward recent
|
|
1414
|
+
* observations.
|
|
1415
|
+
*/
|
|
1416
|
+
export declare class AdaptiveEstimate {
|
|
1417
|
+
private readonly alpha;
|
|
1418
|
+
private readonly min;
|
|
1419
|
+
private readonly max;
|
|
1420
|
+
private readonly initial;
|
|
1421
|
+
private value;
|
|
1422
|
+
constructor(options?: AdaptiveEstimateOptions);
|
|
1423
|
+
/** Fold a new observation into the running estimate. */
|
|
1424
|
+
sample(x: number): void;
|
|
1425
|
+
/** Current estimate (clamped to `[min, max]`). */
|
|
1426
|
+
get estimate(): number;
|
|
1427
|
+
/** Reset the estimate (back to `initial`). */
|
|
1428
|
+
reset(): void;
|
|
1429
|
+
}
|
|
1430
|
+
/** Generate a UUIDv7 (time-ordered) string, preferring Bun's native built-in. */
|
|
1431
|
+
export declare function uuidv7(): string;
|
|
1432
|
+
/** Default histogram buckets (Prometheus-style, seconds). */
|
|
1433
|
+
export declare const DEFAULT_BUCKETS: readonly number[];
|
|
1434
|
+
export type Labels = Readonly<Record<string, string>>;
|
|
1435
|
+
/** A single labelled counter value. */
|
|
1436
|
+
export interface Counter {
|
|
1437
|
+
/** Increment by 1 (or `by`). `labels` must match the label names exactly. */
|
|
1438
|
+
inc(labels?: Labels, by?: number): void;
|
|
1439
|
+
}
|
|
1440
|
+
/** A single labelled gauge value (can go up and down). */
|
|
1441
|
+
export interface Gauge {
|
|
1442
|
+
inc(labels?: Labels, by?: number): void;
|
|
1443
|
+
dec(labels?: Labels, by?: number): void;
|
|
1444
|
+
set(labels: Labels | undefined, value: number): void;
|
|
1445
|
+
}
|
|
1446
|
+
/** A single labelled histogram. */
|
|
1447
|
+
export interface Histogram {
|
|
1448
|
+
/** Record one observation. `labels` must match the label names exactly. */
|
|
1449
|
+
observe(value: number, labels?: Labels): void;
|
|
1450
|
+
}
|
|
1451
|
+
/** The metrics registry factory. */
|
|
1452
|
+
export interface MetricsRegistry {
|
|
1453
|
+
/** Create (or fetch) a counter. `help` is only used on first creation. */
|
|
1454
|
+
counter(name: string, help: string, labelNames?: readonly string[]): Counter;
|
|
1455
|
+
/** Create (or fetch) a gauge. */
|
|
1456
|
+
gauge(name: string, help: string, labelNames?: readonly string[]): Gauge;
|
|
1457
|
+
/**
|
|
1458
|
+
* Create (or fetch) a histogram. `buckets`/`help` only apply on first
|
|
1459
|
+
* creation; later calls with the same name return the existing histogram.
|
|
1460
|
+
*/
|
|
1461
|
+
histogram(name: string, help: string, buckets?: readonly number[], labelNames?: readonly string[]): Histogram;
|
|
1462
|
+
/** Render the Prometheus text exposition format. */
|
|
1463
|
+
render(): string;
|
|
1464
|
+
/** Reset all metrics (for tests / interval rotation). */
|
|
1465
|
+
reset(): void;
|
|
1466
|
+
}
|
|
1467
|
+
/** Create a fresh metrics registry. */
|
|
1468
|
+
export declare function createMetrics(): MetricsRegistry;
|
|
1469
|
+
/** User-facing CORS configuration. */
|
|
1470
|
+
export interface CorsOptions {
|
|
1471
|
+
allowOrigin?: string[];
|
|
1472
|
+
allowMethods?: string[];
|
|
1473
|
+
allowHeaders?: string[];
|
|
1474
|
+
exposeHeaders?: string[];
|
|
1475
|
+
allowCredentials?: boolean;
|
|
1476
|
+
maxAge?: number;
|
|
1477
|
+
}
|
|
1478
|
+
/** Precomputed, immutable CORS policy strings. */
|
|
1479
|
+
export interface CorsStaticStrings {
|
|
1480
|
+
readonly allowMethodsJoined: string;
|
|
1481
|
+
readonly allowHeadersJoined: string;
|
|
1482
|
+
readonly exposeHeadersJoined: string;
|
|
1483
|
+
readonly maxAgeString: string | null;
|
|
1484
|
+
readonly isWildcard: boolean;
|
|
1485
|
+
readonly credentials: boolean;
|
|
1486
|
+
}
|
|
1487
|
+
/** User-facing security-headers configuration. */
|
|
1488
|
+
export interface SecurityHeadersOptions {
|
|
1489
|
+
contentSecurityPolicy?: string;
|
|
1490
|
+
hsts?: boolean;
|
|
1491
|
+
hstsMaxAge?: number;
|
|
1492
|
+
hstsIncludeSubdomains?: boolean;
|
|
1493
|
+
hstsPreload?: boolean;
|
|
1494
|
+
frameOptions?: string;
|
|
1495
|
+
nosniff?: boolean;
|
|
1496
|
+
referrerPolicy?: string;
|
|
1497
|
+
coep?: string;
|
|
1498
|
+
coop?: string;
|
|
1499
|
+
corp?: string;
|
|
1500
|
+
xssProtection?: string;
|
|
1501
|
+
}
|
|
1502
|
+
/** Bounds-checked section offsets for one ingress output buffer. */
|
|
1503
|
+
export interface PackedSectionLayout {
|
|
1504
|
+
/** Cookie-JSON length clamped to the buffer (0 if none / out of range). */
|
|
1505
|
+
safeCookiesLen: number;
|
|
1506
|
+
/** Byte offset where the query-JSON section begins. */
|
|
1507
|
+
queryStart: number;
|
|
1508
|
+
/** Query-JSON length clamped to the buffer (0 if none / out of range). */
|
|
1509
|
+
safeQueryLen: number;
|
|
1510
|
+
/** Byte offset where the body-JSON section begins. */
|
|
1511
|
+
bodyJsonStart: number;
|
|
1512
|
+
/** Body-JSON length clamped to the buffer (0 if none / out of range). */
|
|
1513
|
+
safeBodyJsonLen: number;
|
|
1514
|
+
/** Whether any declared section length overran the buffer. */
|
|
1515
|
+
truncated: boolean;
|
|
1516
|
+
}
|
|
1517
|
+
declare abstract class IngressResultBase {
|
|
1518
|
+
/** Raw native verdict byte (0 = accepted). */
|
|
1519
|
+
verdict: number;
|
|
1520
|
+
/** Raw native error-code byte. */
|
|
1521
|
+
errorCode: number;
|
|
1522
|
+
/** Normalized HTTP status. */
|
|
1523
|
+
status: number;
|
|
1524
|
+
/** Header template variant byte emitted by the native core. */
|
|
1525
|
+
headerVariant: number;
|
|
1526
|
+
/** Remaining rate-limit budget (count). */
|
|
1527
|
+
rateRemaining: number;
|
|
1528
|
+
/** Rate-limit window reset (ms epoch). */
|
|
1529
|
+
rateResetMs: number;
|
|
1530
|
+
/** Retry-After value (ms). */
|
|
1531
|
+
retryAfterMs: number;
|
|
1532
|
+
/** True when the pipeline returned a terminal (error) verdict. */
|
|
1533
|
+
terminal: boolean;
|
|
1534
|
+
/** True when the pipeline accepted the request (verdict 0 + 2xx/3xx). */
|
|
1535
|
+
ok: boolean;
|
|
1536
|
+
/** True when the request was a CORS preflight. */
|
|
1537
|
+
isPreflight: boolean;
|
|
1538
|
+
/** True when the CORS engine allowed the request origin. */
|
|
1539
|
+
corsAllowed: boolean;
|
|
1540
|
+
/** True when the request was rate-limited. */
|
|
1541
|
+
rateLimited: boolean;
|
|
1542
|
+
/** True when the request came from a trusted proxy. */
|
|
1543
|
+
trustedProxy: boolean;
|
|
1544
|
+
/** True when the request body parsed as valid JSON. */
|
|
1545
|
+
bodyValidJson: boolean;
|
|
1546
|
+
/** True when the request body validated against the ingress schema. */
|
|
1547
|
+
schemaValid: boolean;
|
|
1548
|
+
/** True when a declared output section overran the buffer. */
|
|
1549
|
+
bodyTruncated: boolean;
|
|
1550
|
+
/** Request body bytes (may be an empty view). */
|
|
1551
|
+
body: Uint8Array;
|
|
1552
|
+
protected _buf: Uint8Array;
|
|
1553
|
+
protected _bodyJsonStart: number;
|
|
1554
|
+
protected _bodyJsonLen: number;
|
|
1555
|
+
private _cookiesBuf;
|
|
1556
|
+
private _queryBuf;
|
|
1557
|
+
private _cookiesDecoded;
|
|
1558
|
+
private _queryDecoded;
|
|
1559
|
+
/** Reset the shared fields to their empty state (call from subclass `invalidate`). */
|
|
1560
|
+
protected resetShared(): void;
|
|
1561
|
+
/** Recompute `terminal`/`ok` from the (subclass-set) verdict + status. */
|
|
1562
|
+
protected updateOkTerminal(): void;
|
|
1563
|
+
/**
|
|
1564
|
+
* Store the rate-limit window fields. Both decoders read the same OUT_*
|
|
1565
|
+
* slots and gate them on the same conditions (a positive budget OR the
|
|
1566
|
+
* rate-limited flag), so the read cannot drift between paths.
|
|
1567
|
+
*/
|
|
1568
|
+
protected setRateWindow(rateLimit: number, rateLimited: boolean, view: DataView): void;
|
|
1569
|
+
/**
|
|
1570
|
+
* Store the bounds-checked cookie/query/body JSON sections from `layout`.
|
|
1571
|
+
*
|
|
1572
|
+
* `bodyJsonLen` is the body-JSON length to trust for `bodyJson()`: the fast
|
|
1573
|
+
* path passes the RAW declared length (it re-checks bounds on read), the
|
|
1574
|
+
* baked path passes the already-clamped `layout.safeBodyJsonLen`. Sections
|
|
1575
|
+
* are stored as slices and decoded lazily by `cookiesJson()`/`queryJson()`.
|
|
1576
|
+
*/
|
|
1577
|
+
protected setSections(buf: Uint8Array, layout: PackedSectionLayout, bodyJsonLen: number): void;
|
|
1578
|
+
/** Decoded cookies-JSON section, or `"{}"` when absent. */
|
|
1579
|
+
cookiesJson(): string;
|
|
1580
|
+
/** Decoded query-JSON section, or `"{}"` when absent. */
|
|
1581
|
+
queryJson(): string;
|
|
1582
|
+
/** Bounds-checked body-JSON slice (empty when absent / out of range). */
|
|
1583
|
+
protected bodyJsonSlice(): Uint8Array;
|
|
1584
|
+
}
|
|
1585
|
+
/** Zero-alloc, lazy-decoding view over a native Ingress output buffer. */
|
|
1586
|
+
export declare class FastIngressResult extends IngressResultBase {
|
|
1587
|
+
status: number;
|
|
1588
|
+
verdict: number;
|
|
1589
|
+
errorCode: number;
|
|
1590
|
+
flags: number;
|
|
1591
|
+
https: boolean;
|
|
1592
|
+
hasCookies: boolean;
|
|
1593
|
+
hasQuery: boolean;
|
|
1594
|
+
rateLimit: number;
|
|
1595
|
+
requestId: string;
|
|
1596
|
+
refresh(buf: Uint8Array, body: Uint8Array, requestId: string): void;
|
|
1597
|
+
invalidate(): void;
|
|
1598
|
+
setInternalError(requestId: string): void;
|
|
1599
|
+
/** Bounds-checked body-JSON section, or an empty view when absent. */
|
|
1600
|
+
bodyJson(): Uint8Array;
|
|
1601
|
+
}
|
|
1602
|
+
/** Options accepted by `createIngressFast` / `createIngress`. */
|
|
1603
|
+
export interface IngressFastOptions {
|
|
1604
|
+
trustProxy?: boolean;
|
|
1605
|
+
trustedProxies?: {
|
|
1606
|
+
enabled?: boolean;
|
|
1607
|
+
networks?: string[];
|
|
1608
|
+
};
|
|
1609
|
+
parseCookies?: boolean;
|
|
1610
|
+
parseQuery?: boolean;
|
|
1611
|
+
requireJsonBody?: boolean;
|
|
1612
|
+
schema?: Uint8Array;
|
|
1613
|
+
cors?: CorsOptions;
|
|
1614
|
+
rateLimit?: {
|
|
1615
|
+
limit?: number;
|
|
1616
|
+
windowMs?: number;
|
|
1617
|
+
maxEntries?: number;
|
|
1618
|
+
};
|
|
1619
|
+
/**
|
|
1620
|
+
* Structured security-header options (CSP/HSTS) — honored by the fast/async
|
|
1621
|
+
* paths (`createIngressFast` throws on it; `createIngress` applies it via
|
|
1622
|
+
* `buildResponseContext`). The PRE-BAKED path (`createIngressHandler`)
|
|
1623
|
+
* instead takes raw `securityHeaders: [name, value][]` pairs. The two paths
|
|
1624
|
+
* intentionally use different option shapes (see docs/INGRESS.md).
|
|
1625
|
+
*/
|
|
1626
|
+
security?: SecurityHeadersOptions;
|
|
1627
|
+
https?: boolean;
|
|
1628
|
+
maxBodyBytes?: number;
|
|
1629
|
+
enableSecurityHeaders?: boolean;
|
|
1630
|
+
enableRequestIds?: boolean;
|
|
1631
|
+
enableBodySizeGuard?: boolean;
|
|
1632
|
+
emitMetadataJson?: boolean;
|
|
1633
|
+
readBody?: boolean;
|
|
1634
|
+
outputBufferSize?: number;
|
|
1635
|
+
/**
|
|
1636
|
+
* Overall deadline (ms) for reading a request body in the async
|
|
1637
|
+
* `createIngress` path. 0 disables. Default: `DEFAULT_BODY_TIMEOUT_MS` (30s).
|
|
1638
|
+
* Ignored by the sync `createIngressFast` (it does not read bodies).
|
|
1639
|
+
*/
|
|
1640
|
+
bodyTimeoutMs?: number;
|
|
1641
|
+
/**
|
|
1642
|
+
* Invoked when the native pipeline throws (the request becomes a 500).
|
|
1643
|
+
* Native failures are otherwise silent in the fast path. Never throws.
|
|
1644
|
+
*/
|
|
1645
|
+
onError?: (error: Error) => void;
|
|
1646
|
+
/**
|
|
1647
|
+
* When true, run one probe GET at construction so the `run()` closure,
|
|
1648
|
+
* packed pipeline and FFI ingress call are JIT-warmed before the first real
|
|
1649
|
+
* request (cuts cold-invocation tail latency in serverless-style
|
|
1650
|
+
* deployments). Opt-in; default false. Not forwarded to the native addon.
|
|
1651
|
+
*/
|
|
1652
|
+
warmOnCreate?: boolean;
|
|
1653
|
+
limits?: {
|
|
1654
|
+
maxUrlBytes?: number;
|
|
1655
|
+
maxQueryBytes?: number;
|
|
1656
|
+
maxCookieBytes?: number;
|
|
1657
|
+
maxHeadersBytes?: number;
|
|
1658
|
+
maxHeaders?: number;
|
|
1659
|
+
maxPairs?: number;
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
/** The zero-alloc sync handler returned by `createIngressFast`. */
|
|
1663
|
+
export interface IngressFastHandler {
|
|
1664
|
+
run<T>(req: Request, ip: string | undefined, body: Uint8Array | null, requestId: string, fn: (result: FastIngressResult) => T): T;
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Options accepted by `createIngressHandler` (path 2).
|
|
1668
|
+
*
|
|
1669
|
+
* Same native option surface as the fast path, minus `onError` — path 2
|
|
1670
|
+
* reports native failures through `BakedIngressRuntime.onError` instead of the
|
|
1671
|
+
* options bag.
|
|
1672
|
+
*/
|
|
1673
|
+
export type IngressHandlerOptions = Omit<IngressFastOptions, "onError">;
|
|
1674
|
+
/** Zero-alloc, reusable result decoder for the pre-baked handler path. */
|
|
1675
|
+
export declare class BakedIngressResult extends IngressResultBase {
|
|
1676
|
+
refresh(buf: Uint8Array, body: Uint8Array, view: DataView): void;
|
|
1677
|
+
invalidate(): void;
|
|
1678
|
+
setInternalError(): void;
|
|
1679
|
+
bodyJson(copy: boolean): Uint8Array;
|
|
1680
|
+
}
|
|
1681
|
+
/** Public ingress options (extends the fast-path options). */
|
|
1682
|
+
export interface IngressOptions extends IngressFastOptions {
|
|
1683
|
+
enableRequestIds?: boolean;
|
|
1684
|
+
/**
|
|
1685
|
+
* Invoked before a request is processed (for tracing/context hooks).
|
|
1686
|
+
* Only used by the async `createIngress` path.
|
|
1687
|
+
*/
|
|
1688
|
+
onRequest?: (req: Request, requestId: string, ip: string | undefined) => void;
|
|
1689
|
+
/**
|
|
1690
|
+
* Invoked after a terminal context (and its `Response`) is produced, for
|
|
1691
|
+
* metrics/logging hooks. Only used by the async `createIngress` path.
|
|
1692
|
+
*/
|
|
1693
|
+
onResponse?: (req: Request, result: IngressContext, status: number, requestId: string) => void;
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Readonly structural view of a decoded ingress result.
|
|
1697
|
+
*
|
|
1698
|
+
* Note: the exported `FastIngressResult` class is the zero-alloc implementation;
|
|
1699
|
+
* this interface is the readonly view used by the public sync/async handlers.
|
|
1700
|
+
*/
|
|
1701
|
+
export interface IngressResult {
|
|
1702
|
+
readonly status: number;
|
|
1703
|
+
readonly verdict: number;
|
|
1704
|
+
readonly flags: number;
|
|
1705
|
+
readonly errorCode: number;
|
|
1706
|
+
readonly terminal: boolean;
|
|
1707
|
+
readonly ok: boolean;
|
|
1708
|
+
readonly https: boolean;
|
|
1709
|
+
readonly trustedProxy: boolean;
|
|
1710
|
+
readonly hasCookies: boolean;
|
|
1711
|
+
readonly hasQuery: boolean;
|
|
1712
|
+
readonly bodyValidJson: boolean;
|
|
1713
|
+
readonly schemaValid: boolean;
|
|
1714
|
+
readonly corsAllowed: boolean;
|
|
1715
|
+
readonly isPreflight: boolean;
|
|
1716
|
+
readonly rateLimited: boolean;
|
|
1717
|
+
readonly rateLimit: number;
|
|
1718
|
+
readonly rateRemaining: number;
|
|
1719
|
+
readonly rateResetMs: number;
|
|
1720
|
+
readonly retryAfterMs: number;
|
|
1721
|
+
readonly body: Uint8Array;
|
|
1722
|
+
readonly headerVariant: number;
|
|
1723
|
+
readonly requestId: string;
|
|
1724
|
+
readonly bodyTruncated: boolean;
|
|
1725
|
+
cookiesJson(): string;
|
|
1726
|
+
queryJson(): string;
|
|
1727
|
+
bodyJson(): Uint8Array;
|
|
1728
|
+
}
|
|
1729
|
+
/** A result plus the terminal Response computed for it. */
|
|
1730
|
+
export interface IngressContext extends IngressResult {
|
|
1731
|
+
response: Response | null;
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Synchronous ingress handler.
|
|
1735
|
+
*
|
|
1736
|
+
* The callback runs on the zero-alloc result object and MUST be synchronous:
|
|
1737
|
+
* returning a Promise (or any thenable) throws. The result is invalidated after
|
|
1738
|
+
* `run()` returns, so capture the fields you need inside the callback (or use
|
|
1739
|
+
* the async {@link IngressHandler} which snapshots for you).
|
|
1740
|
+
*/
|
|
1741
|
+
export interface SyncIngressHandler {
|
|
1742
|
+
run<T>(req: Request, ip: string | undefined, body: Uint8Array | null, requestId: string, fn: (result: IngressResult) => T): T;
|
|
1743
|
+
}
|
|
1744
|
+
/** Async ingress handler (wraps {@link SyncIngressHandler} with body reading). */
|
|
1745
|
+
export type IngressHandler = (req: Request, ip?: string) => Promise<IngressContext>;
|
|
1746
|
+
/** Mutable per-request context threaded through the pre-baked handler run. */
|
|
1747
|
+
export interface BakedContext {
|
|
1748
|
+
/** The request-id string (null when `emitRequestIdHeader` is off). */
|
|
1749
|
+
requestIdHeader: string | null;
|
|
1750
|
+
/** The `Origin` request header when CORS extraction is enabled. */
|
|
1751
|
+
origin: string | null;
|
|
1752
|
+
}
|
|
1753
|
+
/**
|
|
1754
|
+
* An optimized ingress handler. `run()` is the zero-alloc pipeline entry
|
|
1755
|
+
* point; the response-builder methods are pre-baked and bound to this
|
|
1756
|
+
* handler's configuration, so consumers can build custom routes without
|
|
1757
|
+
* touching header templates or error bodies.
|
|
1758
|
+
*/
|
|
1759
|
+
export interface OptimizedIngressHandler {
|
|
1760
|
+
run<T>(req: Request, ip: string | undefined, body: Uint8Array | null, fn: (result: BakedIngressResult, ctx: BakedContext) => T): T;
|
|
1761
|
+
responseHeaders(variant: number, requestIdHeader: string | null, origin: string | null, rateRemaining?: number, rateResetSecs?: number, retryAfterSecs?: number): [
|
|
1762
|
+
string,
|
|
1763
|
+
string
|
|
1764
|
+
][];
|
|
1765
|
+
terminalHeaders(variant: number, ctx: BakedContext, result: BakedIngressResult | null): [
|
|
1766
|
+
string,
|
|
1767
|
+
string
|
|
1768
|
+
][];
|
|
1769
|
+
/** `req` is accepted for back-compat but unused by the baked terminal path. */
|
|
1770
|
+
terminalResponse(req: Request | undefined, result: BakedIngressResult, ctx: BakedContext): Response | null;
|
|
1771
|
+
/** `req` is accepted for back-compat but unused by the baked error path. */
|
|
1772
|
+
errorResponse(req: Request | undefined, result: BakedIngressResult | null, status: number, code: string, message: string, ctx: BakedContext): Response;
|
|
1773
|
+
internalErrorResponse(ctx: BakedContext, result?: BakedIngressResult): Response;
|
|
1774
|
+
withContentType(headers: ReadonlyArray<[
|
|
1775
|
+
string,
|
|
1776
|
+
string
|
|
1777
|
+
]>, contentType: string): [
|
|
1778
|
+
string,
|
|
1779
|
+
string
|
|
1780
|
+
][];
|
|
1781
|
+
/**
|
|
1782
|
+
* Build a zero-copy `Response` whose body is the request's pooled output
|
|
1783
|
+
* slice. The pooled buffer is returned to its pool once the body has been
|
|
1784
|
+
* consumed (stream closed) or the request aborted. Use when `copyBody` is
|
|
1785
|
+
* `false`; otherwise a copied body is released eagerly at the end of `run()`.
|
|
1786
|
+
*/
|
|
1787
|
+
zeroCopyResponse(result: BakedIngressResult, ctx: BakedContext, init: ResponseInit): Response;
|
|
1788
|
+
}
|
|
1789
|
+
/** Offset of the verdict byte (0 = accepted, nonzero = terminal error). */
|
|
1790
|
+
export declare const OUT_VERDICT: number;
|
|
1791
|
+
/** Offset of the error-code byte (see ERR_CODE_* below). */
|
|
1792
|
+
export declare const OUT_ERROR_CODE: number;
|
|
1793
|
+
/** Offset of the raw u16 status. */
|
|
1794
|
+
export declare const OUT_STATUS: number;
|
|
1795
|
+
/** Offset of the u32 flags word (see FLAG_* below). */
|
|
1796
|
+
export declare const OUT_FLAGS: number;
|
|
1797
|
+
/** Offset of the u32 rate-limit budget (U32_MAX = disabled). */
|
|
1798
|
+
export declare const OUT_RATE_LIMIT: number;
|
|
1799
|
+
/** Offset of the u32 rate-limit remaining count. */
|
|
1800
|
+
export declare const OUT_RATE_REMAINING: number;
|
|
1801
|
+
/** Offset of the u64 rate-limit window reset (ms epoch). */
|
|
1802
|
+
export declare const OUT_RATE_RESET: number;
|
|
1803
|
+
/** Offset of the u64 Retry-After value (ms). */
|
|
1804
|
+
export declare const OUT_RETRY_AFTER: number;
|
|
1805
|
+
/** Offset of the u32 cookies-JSON section length. */
|
|
1806
|
+
export declare const OUT_COOKIES_JSON_LEN: number;
|
|
1807
|
+
/** Offset of the u32 query-JSON section length. */
|
|
1808
|
+
export declare const OUT_QUERY_JSON_LEN: number;
|
|
1809
|
+
/** Offset of the header-template variant byte (see HV_* below). */
|
|
1810
|
+
export declare const OUT_HEADER_VARIANT: number;
|
|
1811
|
+
/** Offset of the u32 body-JSON section length. */
|
|
1812
|
+
export declare const OUT_BODY_JSON_LEN: number;
|
|
1813
|
+
/** Byte offset where the variable-length JSON sections begin. */
|
|
1814
|
+
export declare const OUT_DATA_START: number;
|
|
1815
|
+
/** Request carried a cookie header (cookie-JSON section present). */
|
|
1816
|
+
export declare const FLAG_HAS_COOKIES: number;
|
|
1817
|
+
/** Request carried a query string (query-JSON section present). */
|
|
1818
|
+
export declare const FLAG_HAS_QUERY: number;
|
|
1819
|
+
/** The request body parsed as valid JSON. */
|
|
1820
|
+
export declare const FLAG_BODY_VALID_JSON: number;
|
|
1821
|
+
/** The request body validated against the ingress schema. */
|
|
1822
|
+
export declare const FLAG_SCHEMA_VALID: number;
|
|
1823
|
+
/** The CORS engine allowed the request origin. */
|
|
1824
|
+
export declare const FLAG_CORS_ALLOWED: number;
|
|
1825
|
+
/** The request was a CORS preflight (OPTIONS + request-method). */
|
|
1826
|
+
export declare const FLAG_IS_PREFLIGHT: number;
|
|
1827
|
+
/** The request was rate-limited. */
|
|
1828
|
+
export declare const FLAG_RATE_LIMITED: number;
|
|
1829
|
+
/** The request arrived over HTTPS (trusted-proxy scheme). */
|
|
1830
|
+
export declare const FLAG_HTTPS: number;
|
|
1831
|
+
/** The request came from a trusted proxy (per the proxy config). */
|
|
1832
|
+
export declare const FLAG_TRUSTED_PROXY: number;
|
|
1833
|
+
/** A declared output section overran the buffer (truncated). */
|
|
1834
|
+
export declare const FLAG_BODY_TRUNCATED: number;
|
|
1835
|
+
/** Response body is JSON (`content-type: application/json`). */
|
|
1836
|
+
export declare const HV_JSON: number;
|
|
1837
|
+
/** CORS simple-request variant (Origin echoed + vary headers). */
|
|
1838
|
+
export declare const HV_CORS_SIMPLE: number;
|
|
1839
|
+
/** CORS preflight variant (allow-methods/headers/max-age). */
|
|
1840
|
+
export declare const HV_CORS_PREFLIGHT: number;
|
|
1841
|
+
/** Rate-limit active variant (`ratelimit-limit` header). */
|
|
1842
|
+
export declare const HV_RATE_ACTIVE: number;
|
|
1843
|
+
/** Rate-limited variant (Retry-After emitted). */
|
|
1844
|
+
export declare const HV_RATE_LIMITED: number;
|
|
1845
|
+
/** Total number of header-variant combinations (32). */
|
|
1846
|
+
export declare const HV_COUNT: number;
|
|
1847
|
+
/** No error (accepted). */
|
|
1848
|
+
export declare const ERR_CODE_NONE: number;
|
|
1849
|
+
/** CORS preflight rejected. */
|
|
1850
|
+
export declare const ERR_CODE_CORS_PREFLIGHT: number;
|
|
1851
|
+
/** Rate limit exceeded. */
|
|
1852
|
+
export declare const ERR_CODE_RATE_LIMITED: number;
|
|
1853
|
+
/** Request body exceeded the size guard. */
|
|
1854
|
+
export declare const ERR_CODE_BODY_TOO_LARGE: number;
|
|
1855
|
+
/** Request body is not valid JSON. */
|
|
1856
|
+
export declare const ERR_CODE_INVALID_JSON: number;
|
|
1857
|
+
/** Request body failed schema validation. */
|
|
1858
|
+
export declare const ERR_CODE_SCHEMA_VALIDATION: number;
|
|
1859
|
+
/** Malformed request (bad request line / headers). */
|
|
1860
|
+
export declare const ERR_CODE_BAD_REQUEST: number;
|
|
1861
|
+
/** Request headers/URL exceeded the configured limits. */
|
|
1862
|
+
export declare const ERR_CODE_REQUEST_TOO_LARGE: number;
|
|
1863
|
+
/** Internal pipeline failure (maps to 500). */
|
|
1864
|
+
export declare const ERR_CODE_INTERNAL: number;
|
|
1865
|
+
/**
|
|
1866
|
+
* JS-only error-code sentinel for a request-body read timeout in the async
|
|
1867
|
+
* `createIngress` path.
|
|
1868
|
+
*
|
|
1869
|
+
* The native pipeline never emits this value — it is a JS body-reader error
|
|
1870
|
+
* (`REQUEST_TIMEOUT` from `readBodyWithLimit`) mapped onto the numeric
|
|
1871
|
+
* error-code contract so the shared status/name/message helpers stay
|
|
1872
|
+
* consistent. Deliberately not sourced from Rust (see the header comment:
|
|
1873
|
+
* numeric layout values come from the addon; this one is a JS-level error).
|
|
1874
|
+
*/
|
|
1875
|
+
export declare const ERR_CODE_REQUEST_TIMEOUT: number;
|
|
1876
|
+
/**
|
|
1877
|
+
* Whether a raw status is a legal HTTP response status for the ingress
|
|
1878
|
+
* pipeline (101 switch-protocol or any 2xx–5xx).
|
|
1879
|
+
*/
|
|
1880
|
+
export declare function isValidResponseStatus(status: number): boolean;
|
|
1881
|
+
/**
|
|
1882
|
+
* Map a native ingress error code to the HTTP status that should be returned.
|
|
1883
|
+
* A permitted CORS preflight always yields 204.
|
|
1884
|
+
*/
|
|
1885
|
+
export declare function statusForErrorCode(errorCode: number, isPreflightAllowed: boolean): number;
|
|
1886
|
+
/**
|
|
1887
|
+
* Normalize a raw status to a legal response status, falling back to the
|
|
1888
|
+
* error-code mapping when the raw status is not legal.
|
|
1889
|
+
*/
|
|
1890
|
+
export declare function normalizeResponseStatus(status: number, errorCode: number, isPreflightAllowed: boolean): number;
|
|
1891
|
+
/**
|
|
1892
|
+
* Compute a safe terminal status for a result: a permitted CORS preflight
|
|
1893
|
+
* yields 204, otherwise the normalized status (or the error-code mapping).
|
|
1894
|
+
*/
|
|
1895
|
+
export declare function safeTerminalStatus(r: {
|
|
1896
|
+
readonly status: number;
|
|
1897
|
+
readonly errorCode: number;
|
|
1898
|
+
readonly isPreflight: boolean;
|
|
1899
|
+
readonly corsAllowed: boolean;
|
|
1900
|
+
}): number;
|
|
1901
|
+
/** Map a native error code to its stable string name. */
|
|
1902
|
+
export declare function errorCodeName(code: number): string;
|
|
1903
|
+
/** Map a native error code (plus status context) to a human message. */
|
|
1904
|
+
export declare function errorMessage(status: number, code: number): string;
|
|
1905
|
+
declare function createStructuredLogger(stream?: Pick<NodeJS.WritableStream, "write">, env?: NodeJS.ProcessEnv): {
|
|
1906
|
+
/** Record one completed request. */
|
|
1907
|
+
request(info: {
|
|
1908
|
+
requestId: string;
|
|
1909
|
+
method: string;
|
|
1910
|
+
path: string;
|
|
1911
|
+
status: number;
|
|
1912
|
+
durationMs: number;
|
|
1913
|
+
ip?: string;
|
|
1914
|
+
}): void;
|
|
1915
|
+
error(info: {
|
|
1916
|
+
requestId?: string;
|
|
1917
|
+
method?: string;
|
|
1918
|
+
path?: string;
|
|
1919
|
+
code?: string;
|
|
1920
|
+
message: string;
|
|
1921
|
+
}): void;
|
|
1922
|
+
};
|
|
1923
|
+
/** Pre-encoded static error bodies, keyed by error-code string name. */
|
|
1924
|
+
export declare const ERROR_BODIES: Record<string, Uint8Array>;
|
|
1925
|
+
/** Options accepted by the pre-baked route factories. */
|
|
1926
|
+
export interface BakedHandlerOptions {
|
|
1927
|
+
/** Resolve the client IP from the server object (e.g. `srv.requestIP`). */
|
|
1928
|
+
getIp?: (req: Request, srv: unknown) => string | undefined;
|
|
1929
|
+
/** Copy body slices instead of sharing the native buffer. Default: true (safe). */
|
|
1930
|
+
copyBody?: boolean;
|
|
1931
|
+
/** Maximum request body bytes for write/echo handlers. Default: 1 MiB. */
|
|
1932
|
+
maxBodyBytes?: number;
|
|
1933
|
+
/**
|
|
1934
|
+
* Overall deadline (ms) for reading the request body. Default: 30s
|
|
1935
|
+
* (`DEFAULT_BODY_TIMEOUT_MS`). Set `0` to disable. Protects against
|
|
1936
|
+
* slowloris / trickling bodies.
|
|
1937
|
+
*/
|
|
1938
|
+
bodyTimeoutMs?: number;
|
|
1939
|
+
/** Fallback handler used for write error paths. Defaults to the write ingress. */
|
|
1940
|
+
fallback?: OptimizedIngressHandler;
|
|
1941
|
+
/**
|
|
1942
|
+
* When true, route the JSON-validity fallback check through the higher-order
|
|
1943
|
+
* loader (`loader("jsonValid")`) instead of the direct native call —
|
|
1944
|
+
* exercising the loader's dispatch + counters on the real request path.
|
|
1945
|
+
* Default: false (the direct call is marginally faster for a single request;
|
|
1946
|
+
* the loader pays off for same-tick bursts / bulk work, see src/integration/batch.ts).
|
|
1947
|
+
*/
|
|
1948
|
+
enableLoader?: boolean;
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Pre-baked GET read handler: returns the ingress body JSON on success.
|
|
1952
|
+
*/
|
|
1953
|
+
export declare function readHandler(ingress: OptimizedIngressHandler, opts?: BakedHandlerOptions): (req: Request, srv?: unknown) => Response;
|
|
1954
|
+
/**
|
|
1955
|
+
* Pre-baked HEAD read handler: headers only, no body.
|
|
1956
|
+
*/
|
|
1957
|
+
export declare function headHandler(ingress: OptimizedIngressHandler, opts?: BakedHandlerOptions): (req: Request, srv?: unknown) => Response;
|
|
1958
|
+
/**
|
|
1959
|
+
* Pre-baked JSON-write handler (POST/PUT/PATCH): enforces Content-Type,
|
|
1960
|
+
* content-length/body-size limits, JSON validity and (optionally) schema
|
|
1961
|
+
* validation, then returns the ingress body JSON on success.
|
|
1962
|
+
*/
|
|
1963
|
+
export declare function jsonWriteHandler(ingress: OptimizedIngressHandler, opts?: BakedHandlerOptions): (req: Request, srv?: unknown) => Promise<Response>;
|
|
1964
|
+
/**
|
|
1965
|
+
* Pre-baked echo handler: streams the request body back with the client's
|
|
1966
|
+
* Content-Type, bounded by `maxBodyBytes`.
|
|
1967
|
+
*/
|
|
1968
|
+
export declare function echoHandler(ingress: OptimizedIngressHandler, opts?: BakedHandlerOptions): (req: Request, srv?: unknown) => Promise<Response>;
|
|
1969
|
+
/**
|
|
1970
|
+
* Pre-baked fallback handler: 404 for unmatched routes / OPTIONS.
|
|
1971
|
+
*/
|
|
1972
|
+
export declare function fallbackHandler(ingress: OptimizedIngressHandler, opts?: BakedHandlerOptions): (req: Request, srv?: unknown) => Response;
|
|
1973
|
+
/** A raw web-standard route handler (`Request` → `Response`), e.g. the
|
|
1974
|
+
* health/metrics probes (`livenessHandler`, `readinessHandler`,
|
|
1975
|
+
* `healthHandler`, `metricsHandler`). Accepted as `BakedRoute.read` and
|
|
1976
|
+
* served for GET directly, outside the ingress pipeline. The optional third
|
|
1977
|
+
* arg carries the matched dynamic path params (`:param`/`*`) on the Node
|
|
1978
|
+
* adapter (Bun's native router handles matching; the ingress pipeline does
|
|
1979
|
+
* not echo params in its response). */
|
|
1980
|
+
type RouteHandler = (req: Request, srv?: unknown, params?: Record<string, string>) => Response | Promise<Response>;
|
|
1981
|
+
/** Route spec for the Bun.serve builder. */
|
|
1982
|
+
export interface BakedRoute {
|
|
1983
|
+
/**
|
|
1984
|
+
* Wires GET + HEAD read handlers. Accepts an optimized ingress handler OR a
|
|
1985
|
+
* raw `RouteHandler` function (health/metrics probes are raw — see
|
|
1986
|
+
* src/ingress/health.ts). A raw handler is served for GET only.
|
|
1987
|
+
*/
|
|
1988
|
+
read?: OptimizedIngressHandler | RouteHandler;
|
|
1989
|
+
/** Wires POST/PUT/PATCH JSON-write handlers (and OPTIONS fallback). */
|
|
1990
|
+
write?: OptimizedIngressHandler;
|
|
1991
|
+
/** Wires a POST echo handler. */
|
|
1992
|
+
echo?: OptimizedIngressHandler;
|
|
1993
|
+
/** Wires a GET read handler (cookies-style route). */
|
|
1994
|
+
cookies?: OptimizedIngressHandler;
|
|
1995
|
+
/** Wires a DELETE read-style handler. */
|
|
1996
|
+
delete?: OptimizedIngressHandler;
|
|
1997
|
+
/** Overrides `maxBodyBytes` for this route's write/echo handlers. */
|
|
1998
|
+
maxBodyBytes?: number;
|
|
1999
|
+
/**
|
|
2000
|
+
* Overall deadline (ms) for reading the request body on this route's
|
|
2001
|
+
* write/echo handlers. Default: 30_000 (`DEFAULT_BODY_TIMEOUT_MS`).
|
|
2002
|
+
* Set 0 to disable.
|
|
2003
|
+
*/
|
|
2004
|
+
bodyTimeoutMs?: number;
|
|
2005
|
+
}
|
|
2006
|
+
/** RFC 6455 handshake values returned by `CreateIngressServerOptions.upgrade`. */
|
|
2007
|
+
export interface NodeUpgradeHandshake {
|
|
2008
|
+
/** `Sec-WebSocket-Accept` value (compute via `rust.text.wsAcceptKey`). */
|
|
2009
|
+
accept: string;
|
|
2010
|
+
/** Optional negotiated subprotocol (`Sec-WebSocket-Protocol`). */
|
|
2011
|
+
protocol?: string;
|
|
2012
|
+
}
|
|
2013
|
+
/** Options for {@link createIngressServer}. */
|
|
2014
|
+
export interface CreateIngressServerOptions {
|
|
2015
|
+
port: number;
|
|
2016
|
+
hostname?: string;
|
|
2017
|
+
idleTimeout?: number;
|
|
2018
|
+
maxRequestBodySize?: number;
|
|
2019
|
+
reusePort?: boolean;
|
|
2020
|
+
copyBody?: boolean;
|
|
2021
|
+
getIp?: (req: Request, srv: unknown) => string | undefined;
|
|
2022
|
+
routes: Record<string, BakedRoute>;
|
|
2023
|
+
fallback?: OptimizedIngressHandler;
|
|
2024
|
+
/**
|
|
2025
|
+
* Invoked when an unhandled error escapes a request handler (currently wired
|
|
2026
|
+
* on the Node adapter; the Bun path uses runtime.onResponse). Never throws —
|
|
2027
|
+
* hook failures are swallowed.
|
|
2028
|
+
*/
|
|
2029
|
+
onError?: (info: {
|
|
2030
|
+
error: Error;
|
|
2031
|
+
request?: Request;
|
|
2032
|
+
}) => void;
|
|
2033
|
+
/** Node adapter only: ms to receive the complete request (headers + body).
|
|
2034
|
+
* Guards slowloris/trickling requests. Default: 30_000. */
|
|
2035
|
+
requestTimeoutMs?: number;
|
|
2036
|
+
/** Node adapter only: ms to receive the request headers. Default: 30_000. */
|
|
2037
|
+
headersTimeoutMs?: number;
|
|
2038
|
+
/** Node adapter only: max requests per keep-alive socket before Node forces
|
|
2039
|
+
* a fresh connection (bounds long-lived socket reuse). Default: 1000. */
|
|
2040
|
+
maxRequestsPerSocket?: number;
|
|
2041
|
+
/** Node adapter only: optional WebSocket upgrade handler. Return the RFC 6455
|
|
2042
|
+
* handshake values (see {@link NodeUpgradeHandshake}) to complete the
|
|
2043
|
+
* handshake on the hijacked socket; return null/undefined to decline the
|
|
2044
|
+
* upgrade. Ignored by the Bun server. (`createWebSocketUpgrade` is Bun-only
|
|
2045
|
+
* — Node's Response cannot carry a 101.) */
|
|
2046
|
+
upgrade?: (req: Request) => NodeUpgradeHandshake | null | undefined;
|
|
2047
|
+
/** Node adapter only: called after a WebSocket upgrade handshake completes
|
|
2048
|
+
* (the 101 response was accepted), with the hijacked socket so the caller
|
|
2049
|
+
* can attach a frame codec/message loop (e.g. the `ws` library). Ignored by
|
|
2050
|
+
* the Bun server. */
|
|
2051
|
+
onUpgrade?: (socket: import("node:stream").Duplex, req: unknown, head: Buffer) => void;
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Minimal surface of the running server that castrum relies on.
|
|
2055
|
+
*
|
|
2056
|
+
* This is intentionally NOT `ReturnType<typeof Bun.serve>` so that the public
|
|
2057
|
+
* types stay runtime-agnostic — Node.js TypeScript consumers don't need
|
|
2058
|
+
* `@types/bun` just to import castrum's types. Bun's server exposes far more
|
|
2059
|
+
* fields; treat the handle as opaque.
|
|
2060
|
+
*/
|
|
2061
|
+
export interface ServerHandle {
|
|
2062
|
+
/** The port the server is bound to, when known (Bun exposes it; Node's
|
|
2063
|
+
* http.Server does not — use `BakedServer.port` instead). */
|
|
2064
|
+
port?: number;
|
|
2065
|
+
/** Force-stop the server. Bun semantics: `true` drops active connections. */
|
|
2066
|
+
stop(force?: boolean): void;
|
|
2067
|
+
}
|
|
2068
|
+
/** A running server instance plus a stop helper. */
|
|
2069
|
+
export interface BakedServer {
|
|
2070
|
+
server: ServerHandle;
|
|
2071
|
+
stop(): void;
|
|
2072
|
+
port: number;
|
|
2073
|
+
}
|
|
2074
|
+
export interface GracefulShutdownOptions {
|
|
2075
|
+
/** Grace period (ms) to drain in-flight requests before force-closing. */
|
|
2076
|
+
timeoutMs?: number;
|
|
2077
|
+
/** Signals to listen for. Default: SIGTERM + SIGINT. */
|
|
2078
|
+
signals?: NodeJS.Signals[];
|
|
2079
|
+
}
|
|
2080
|
+
/**
|
|
2081
|
+
* Wire SIGTERM/SIGINT to a graceful shutdown: soft-stop (drain in-flight
|
|
2082
|
+
* requests) then force-close after `timeoutMs`. Works with both the Bun and
|
|
2083
|
+
* Node server handles (both expose `stop(force?)`).
|
|
2084
|
+
*
|
|
2085
|
+
* Returns a cleanup function that removes the signal listeners. Call it (or
|
|
2086
|
+
* `process.exit`) to tear down without hanging.
|
|
2087
|
+
*/
|
|
2088
|
+
export declare function gracefulShutdown(handles: ReadonlyArray<ServerHandle>, options?: GracefulShutdownOptions): () => void;
|
|
2089
|
+
/** Build a Bun.serve config from pre-baked route handlers. */
|
|
2090
|
+
export declare function createIngressServer(options: CreateIngressServerOptions): BakedServer;
|
|
2091
|
+
/** A Node.js ingress server: {@link BakedServer} plus an async ready signal. */
|
|
2092
|
+
export interface NodeIngressServer extends BakedServer {
|
|
2093
|
+
/**
|
|
2094
|
+
* Resolves to the actually-bound port once the server is listening
|
|
2095
|
+
* (`node:http` binds asynchronously; useful when `port: 0`).
|
|
2096
|
+
*/
|
|
2097
|
+
ready: Promise<number>;
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Start a Node.js `node:http` server serving the same pre-baked ingress route
|
|
2101
|
+
* handlers as {@link createIngressServer}. Returns a {@link NodeIngressServer};
|
|
2102
|
+
* `stop()` drains in-flight connections (graceful) before closing, and
|
|
2103
|
+
* `ready` resolves to the bound port once listening.
|
|
2104
|
+
*
|
|
2105
|
+
* Requires Node.js >= 20.3 (N-API floor). Bun users should prefer
|
|
2106
|
+
* {@link createIngressServer} (Bun.serve).
|
|
2107
|
+
*/
|
|
2108
|
+
export declare function createIngressServerNode(options: CreateIngressServerOptions): NodeIngressServer;
|
|
2109
|
+
/** Sentinel value used by Rust to mean "rate limiting disabled". */
|
|
2110
|
+
export declare const RATE_LIMIT_U32_MAX = 4294967295;
|
|
2111
|
+
export interface BakedIngressRuntime {
|
|
2112
|
+
/** Emit an `x-request-id` header on responses. Default: false. */
|
|
2113
|
+
emitRequestIdHeader?: boolean;
|
|
2114
|
+
/** Enable security headers on responses. Default: true. */
|
|
2115
|
+
enableSecurityHeaders?: boolean;
|
|
2116
|
+
/**
|
|
2117
|
+
* Ordered `[name, value]` security headers (names are lowercased).
|
|
2118
|
+
* NOTE: this PRE-BAKED path takes RAW `[name, value]` pairs here; the
|
|
2119
|
+
* fast/async paths (`createIngressFast`/`createIngress`) instead take a
|
|
2120
|
+
* structured `security: SecurityHeadersOptions` object (CSP/HSTS builders).
|
|
2121
|
+
* The two paths intentionally use different option shapes (see
|
|
2122
|
+
* docs/INGRESS.md).
|
|
2123
|
+
*/
|
|
2124
|
+
securityHeaders?: ReadonlyArray<[
|
|
2125
|
+
string,
|
|
2126
|
+
string
|
|
2127
|
+
]>;
|
|
2128
|
+
/** Native output buffer size in bytes. Default: 131072. */
|
|
2129
|
+
outputBufferSize?: number;
|
|
2130
|
+
/** Invoked before a request is processed (for tracing/context hooks). */
|
|
2131
|
+
onRequest?: (req: Request, requestId: string, ip: string | undefined) => void;
|
|
2132
|
+
/** Invoked after a Response is produced (for metrics/logging hooks). */
|
|
2133
|
+
onResponse?: (req: Request, result: BakedIngressResult, status: number, requestId: string) => void;
|
|
2134
|
+
/**
|
|
2135
|
+
* Invoked when the native pipeline fails (the request becomes a 500).
|
|
2136
|
+
* Native failures are otherwise silent — wire this to your error tracker.
|
|
2137
|
+
*/
|
|
2138
|
+
onError?: (req: Request, requestId: string, error: Error) => void;
|
|
2139
|
+
/**
|
|
2140
|
+
* Emit one structured JSON line per request/error via the built-in logger
|
|
2141
|
+
* (gated by `CASTRUM_LOG_LEVEL`). Default: false.
|
|
2142
|
+
*/
|
|
2143
|
+
structuredLog?: boolean;
|
|
2144
|
+
/**
|
|
2145
|
+
* Custom structured logger (e.g. with a custom stream or extra fields).
|
|
2146
|
+
* When provided, request/error lines go here instead of the built-in stderr
|
|
2147
|
+
* logger and `structuredLog` is implicitly enabled.
|
|
2148
|
+
*/
|
|
2149
|
+
logger?: ReturnType<typeof createStructuredLogger>;
|
|
2150
|
+
/**
|
|
2151
|
+
* Hard cap on concurrently borrowed output buffers (zero-copy responses not
|
|
2152
|
+
* yet consumed). Bounds memory when zero-copy responses are consumed
|
|
2153
|
+
* slowly; when exceeded, requests fail with a 500 (pool exhaustion) instead
|
|
2154
|
+
* of allocating unbounded temporaries. 0 (default) is unlimited — see
|
|
2155
|
+
* `BufferPool.maxInFlight`.
|
|
2156
|
+
*/
|
|
2157
|
+
maxInFlight?: number;
|
|
2158
|
+
/**
|
|
2159
|
+
* Abandonment guard (ms) for zero-copy responses: if a response body is
|
|
2160
|
+
* neither pulled nor cancelled within this window, its pooled buffer is
|
|
2161
|
+
* released and the stream closed. Bounds memory under abandoned (unread)
|
|
2162
|
+
* zero-copy responses. 0 (default) disables it — see `pooledBodyResponse`.
|
|
2163
|
+
*/
|
|
2164
|
+
zeroCopyTimeoutMs?: number;
|
|
2165
|
+
}
|
|
2166
|
+
/**
|
|
2167
|
+
* Create a pre-baked ingress handler (path 2).
|
|
2168
|
+
*
|
|
2169
|
+
* The request frame (url/ip/rid/headers) is packed in JS via `IngressInputPacker`
|
|
2170
|
+
* + `gatherRawHeadersPacked` and driven through the same native core as the
|
|
2171
|
+
* fast path (`Ingress.handleRequestPacked`), writing into a pooled output
|
|
2172
|
+
* buffer (no per-request allocation). Responses use the benchmark wire format
|
|
2173
|
+
* (`{"ok":false,"error":{...}}` + `ratelimit-*` headers) — see AGENTS.md for
|
|
2174
|
+
* why this differs from `createIngressFast`.
|
|
2175
|
+
*
|
|
2176
|
+
* Returns an `OptimizedIngressHandler` whose response-builder methods are
|
|
2177
|
+
* bound to this handler's configuration. Pair it with the route factories
|
|
2178
|
+
* (`readHandler`, `jsonWriteHandler`, ...) or `createIngressServer`.
|
|
2179
|
+
*/
|
|
2180
|
+
export declare function createIngressHandler(options?: IngressHandlerOptions, runtime?: BakedIngressRuntime): OptimizedIngressHandler;
|
|
2181
|
+
/**
|
|
2182
|
+
* Generate the next request ID as 16 lowercase hex bytes (zero-alloc).
|
|
2183
|
+
*
|
|
2184
|
+
* @returns A shared buffer aliased across calls — decode/copy before the next
|
|
2185
|
+
* `generateRequestId()` invocation.
|
|
2186
|
+
*/
|
|
2187
|
+
export declare function generateRequestId(): Uint8Array;
|
|
2188
|
+
/** A single precomputed header-variant template. */
|
|
2189
|
+
export interface HeaderTemplate {
|
|
2190
|
+
readonly entries: ReadonlyArray<readonly [
|
|
2191
|
+
string,
|
|
2192
|
+
string
|
|
2193
|
+
]>;
|
|
2194
|
+
readonly needsOriginEcho: boolean;
|
|
2195
|
+
readonly needsRateDynamic: boolean;
|
|
2196
|
+
readonly needsRetryAfter: boolean;
|
|
2197
|
+
readonly needsDynamicHsts: boolean;
|
|
2198
|
+
}
|
|
2199
|
+
/** Precomputed per-handler response context. */
|
|
2200
|
+
export interface ResponseBuildContext {
|
|
2201
|
+
readonly templates: HeaderTemplate[];
|
|
2202
|
+
readonly corsStatic: CorsStaticStrings | null;
|
|
2203
|
+
readonly hstsValue: string | null;
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Build the full response context (header templates + static CORS strings +
|
|
2207
|
+
* HSTS value) for a handler configuration.
|
|
2208
|
+
*/
|
|
2209
|
+
export declare function buildResponseContext(options: {
|
|
2210
|
+
cors?: CorsOptions;
|
|
2211
|
+
security?: SecurityHeadersOptions;
|
|
2212
|
+
https?: boolean;
|
|
2213
|
+
enableSecurityHeaders?: boolean;
|
|
2214
|
+
rateLimit?: {
|
|
2215
|
+
limit?: number;
|
|
2216
|
+
};
|
|
2217
|
+
}): ResponseBuildContext;
|
|
2218
|
+
/**
|
|
2219
|
+
* Build the response headers for a decoded result, applying the dynamic parts
|
|
2220
|
+
* (request-id, origin echo, rate-limit counters, retry-after, dynamic HSTS).
|
|
2221
|
+
*/
|
|
2222
|
+
export declare function headersForResult(ctx: ResponseBuildContext, r: {
|
|
2223
|
+
readonly headerVariant: number;
|
|
2224
|
+
readonly corsAllowed: boolean;
|
|
2225
|
+
readonly rateRemaining: number;
|
|
2226
|
+
readonly rateResetMs: number;
|
|
2227
|
+
readonly retryAfterMs: number;
|
|
2228
|
+
readonly https: boolean;
|
|
2229
|
+
}, req: Request, requestId: string): Headers;
|
|
2230
|
+
/**
|
|
2231
|
+
* Build a terminal response for a result, or `null` when the result is not
|
|
2232
|
+
* terminal (the caller should serve the body instead).
|
|
2233
|
+
*/
|
|
2234
|
+
export declare function buildTerminalResponse(ctx: ResponseBuildContext, r: {
|
|
2235
|
+
readonly terminal: boolean;
|
|
2236
|
+
readonly isPreflight: boolean;
|
|
2237
|
+
readonly corsAllowed: boolean;
|
|
2238
|
+
readonly errorCode: number;
|
|
2239
|
+
readonly status: number;
|
|
2240
|
+
readonly headerVariant: number;
|
|
2241
|
+
readonly https: boolean;
|
|
2242
|
+
readonly rateLimit: number;
|
|
2243
|
+
readonly rateRemaining: number;
|
|
2244
|
+
readonly rateResetMs: number;
|
|
2245
|
+
readonly retryAfterMs: number;
|
|
2246
|
+
}, req: Request, requestId: string): Response | null;
|
|
2247
|
+
/** Default maximum request body size in bytes. */
|
|
2248
|
+
export declare const DEFAULT_MAX_BODY_BYTES = 1048576;
|
|
2249
|
+
/**
|
|
2250
|
+
* Default overall deadline (ms) for reading a request body. Non-zero so the
|
|
2251
|
+
* async `createIngress` / route handlers are protected against slowloris and
|
|
2252
|
+
* trickling bodies by default. Set `bodyTimeoutMs: 0` to disable.
|
|
2253
|
+
*/
|
|
2254
|
+
export declare const DEFAULT_BODY_TIMEOUT_MS = 30000;
|
|
2255
|
+
/** Maps HTTP methods to the native Ingress method-kind enum. */
|
|
2256
|
+
export declare const METHOD_KIND: Record<string, number>;
|
|
2257
|
+
/** Which request headers to extract into the packed input. */
|
|
2258
|
+
export interface HeaderPlan {
|
|
2259
|
+
cookie: boolean;
|
|
2260
|
+
cors: boolean;
|
|
2261
|
+
proxy: boolean;
|
|
2262
|
+
proto: boolean;
|
|
2263
|
+
}
|
|
2264
|
+
/**
|
|
2265
|
+
* Create a fast packed-input ingress handler (path 1).
|
|
2266
|
+
*
|
|
2267
|
+
* JS packs the request headers into a binary buffer (`IngressInputPacker`) and
|
|
2268
|
+
* the native `Ingress.handleRequestPacked` decodes them. Responses use the
|
|
2269
|
+
* `{"error":{...}}` wire format with `x-ratelimit-*` headers.
|
|
2270
|
+
*
|
|
2271
|
+
* Prefer this when you want the lowest-overhead pipeline and will call `run()`
|
|
2272
|
+
* yourself with a **synchronous** callback. For ready-made route handlers and a
|
|
2273
|
+
* server builder, use `createIngressHandler` (path 2).
|
|
2274
|
+
*/
|
|
2275
|
+
export declare function createIngressFast(options?: IngressFastOptions): IngressFastHandler;
|
|
2276
|
+
/** The runtime hooks + registry for ingress metrics. */
|
|
2277
|
+
export interface IngressMetrics {
|
|
2278
|
+
registry: MetricsRegistry;
|
|
2279
|
+
/** Pass as the runtime to `createIngressHandler`. */
|
|
2280
|
+
runtime: Pick<BakedIngressRuntime, "onRequest" | "onResponse" | "onError">;
|
|
2281
|
+
/** Render the Prometheus exposition. */
|
|
2282
|
+
render(): string;
|
|
2283
|
+
}
|
|
2284
|
+
/**
|
|
2285
|
+
* Build ingress request/error/latency metrics wired to the pre-baked handler
|
|
2286
|
+
* runtime hooks. Metric names follow the Prometheus `castrum_http_*` scheme.
|
|
2287
|
+
*/
|
|
2288
|
+
export declare function createIngressMetrics(): IngressMetrics;
|
|
2289
|
+
/**
|
|
2290
|
+
* Route handler exposing the registry in Prometheus text format
|
|
2291
|
+
* (`content-type: text/plain; version=0.0.4`). Serve it as a `read` route:
|
|
2292
|
+
*
|
|
2293
|
+
* createIngressServer({ routes: { "/metrics": { read: metricsHandler(m) } } })
|
|
2294
|
+
*/
|
|
2295
|
+
export declare function metricsHandler(metrics: IngressMetrics): (_req: Request) => Response;
|
|
2296
|
+
/**
|
|
2297
|
+
* Liveness probe: `200 {"status":"ok"}` as long as the process is alive.
|
|
2298
|
+
* Never touches dependencies.
|
|
2299
|
+
*/
|
|
2300
|
+
export declare function livenessHandler(): (_req: Request) => Response;
|
|
2301
|
+
/**
|
|
2302
|
+
* Readiness probe: runs the optional async `check` (dependency readiness).
|
|
2303
|
+
* Returns `200 {"status":"ready"}` when the check passes (or no check is
|
|
2304
|
+
* given), `503 {"status":"not_ready"}` when it throws or returns false.
|
|
2305
|
+
*/
|
|
2306
|
+
export declare function readinessHandler(check?: () => boolean | Promise<boolean>): (_req: Request) => Promise<Response>;
|
|
2307
|
+
/**
|
|
2308
|
+
* Combined health probe: liveness by default, plus an optional readiness
|
|
2309
|
+
* `check`. When a `check` is provided the response is 503 on failure
|
|
2310
|
+
* (readiness semantics), otherwise always 200.
|
|
2311
|
+
*/
|
|
2312
|
+
export declare function healthHandler(check?: () => boolean | Promise<boolean>): ((_req: Request) => Response) | ((_req: Request) => Promise<Response>);
|
|
2313
|
+
/** A parsed W3C trace context (valid per the spec's length/hex rules). */
|
|
2314
|
+
export interface TraceContext {
|
|
2315
|
+
/** Version, always `"00"` for accepted headers. */
|
|
2316
|
+
version: string;
|
|
2317
|
+
/** 32 hex chars — the trace id (shared across the whole trace). */
|
|
2318
|
+
traceId: string;
|
|
2319
|
+
/** 16 hex chars — the current span id. */
|
|
2320
|
+
spanId: string;
|
|
2321
|
+
/** The flags byte (bit 0 = sampled). */
|
|
2322
|
+
flags: number;
|
|
2323
|
+
/** True when the `sampled` (bit 0) flag is set. */
|
|
2324
|
+
sampled: boolean;
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* Parse a `traceparent` header value into a {@link TraceContext}, or `null`
|
|
2328
|
+
* when malformed (wrong version / length / non-hex). Invalid contexts are
|
|
2329
|
+
* ignored per the spec — callers should generate a fresh trace then.
|
|
2330
|
+
*/
|
|
2331
|
+
export declare function parseTraceParent(header: string | null | undefined): TraceContext | null;
|
|
2332
|
+
/** Random 32-hex trace id (crypto-backed where available). */
|
|
2333
|
+
export declare function createTraceId(): string;
|
|
2334
|
+
/** Random 16-hex span id. */
|
|
2335
|
+
export declare function createSpanId(): string;
|
|
2336
|
+
/** Serialize a trace context back to a `traceparent` header value. */
|
|
2337
|
+
export declare function serializeTraceParent(ctx: TraceContext): string;
|
|
2338
|
+
/**
|
|
2339
|
+
* Synchronous convenience wrapper over `createIngressFast` (path 1).
|
|
2340
|
+
*
|
|
2341
|
+
* The callback runs on the fast-path result and MUST be synchronous. Use
|
|
2342
|
+
* {@link createIngress} when you want automatic body reading + error contexts.
|
|
2343
|
+
*/
|
|
2344
|
+
export declare function createIngressSync(options?: IngressOptions): SyncIngressHandler;
|
|
2345
|
+
/**
|
|
2346
|
+
* Async ingress factory: reads the request body (size guard + deadline) and
|
|
2347
|
+
* returns a snapshot `IngressContext` with a terminal `Response`.
|
|
2348
|
+
*
|
|
2349
|
+
* Recommended default for serverless/edge-style `fetch` handlers. For maximum
|
|
2350
|
+
* throughput use `createIngressFast` / `createIngressSync` directly.
|
|
2351
|
+
*/
|
|
2352
|
+
export declare function createIngress(options?: IngressOptions): IngressHandler;
|
|
2353
|
+
/** Readonly snapshot of the ingress decision, safe after `run()` returns. */
|
|
2354
|
+
export interface PipelineResult {
|
|
2355
|
+
readonly ok: boolean;
|
|
2356
|
+
readonly status: number;
|
|
2357
|
+
readonly errorCode: number;
|
|
2358
|
+
readonly terminal: boolean;
|
|
2359
|
+
readonly rateLimited: boolean;
|
|
2360
|
+
readonly bodyValidJson: boolean;
|
|
2361
|
+
readonly schemaValid: boolean;
|
|
2362
|
+
readonly bodyTruncated: boolean;
|
|
2363
|
+
readonly requestId: string;
|
|
2364
|
+
/** The raw request body the pipeline saw (read-only; aliases the request body). */
|
|
2365
|
+
readonly body: Uint8Array;
|
|
2366
|
+
/** The ingress metadata JSON body (when `emitMetadataJson` is on), else empty. */
|
|
2367
|
+
readonly metadataJson: Uint8Array;
|
|
2368
|
+
}
|
|
2369
|
+
/** Per-request context threaded into the app's handler. */
|
|
2370
|
+
export interface PipelineContext {
|
|
2371
|
+
readonly requestId: string;
|
|
2372
|
+
readonly ip: string | undefined;
|
|
2373
|
+
/** Mutable per-request storage for middleware/user state. */
|
|
2374
|
+
readonly locals: Map<string, unknown>;
|
|
2375
|
+
}
|
|
2376
|
+
export interface PreprocessOutcome {
|
|
2377
|
+
/** True when the pipeline short-circuited (error/denied) — serve `response`. */
|
|
2378
|
+
readonly terminal: boolean;
|
|
2379
|
+
readonly response: Response | null;
|
|
2380
|
+
readonly result: PipelineResult | null;
|
|
2381
|
+
readonly ctx: PipelineContext;
|
|
2382
|
+
}
|
|
2383
|
+
export interface CreatePipelineOptions {
|
|
2384
|
+
/** Ingress options (same surface as `createIngressHandler`). */
|
|
2385
|
+
options?: IngressHandlerOptions;
|
|
2386
|
+
/** Runtime hooks: onRequest/onResponse/onError, logging, pool sizing. */
|
|
2387
|
+
runtime?: BakedIngressRuntime;
|
|
2388
|
+
/** Body limit for `readBody`/`preprocess`. Default: 1 MiB. */
|
|
2389
|
+
maxBodyBytes?: number;
|
|
2390
|
+
/** Body-read deadline (ms) for `readBody`/`preprocess`. Default: 30s. */
|
|
2391
|
+
bodyTimeoutMs?: number;
|
|
2392
|
+
/**
|
|
2393
|
+
* When true (default), `preprocess` reads a request body (guarded) so the
|
|
2394
|
+
* result carries it. Set false when the app handler owns the body.
|
|
2395
|
+
*/
|
|
2396
|
+
readBody?: boolean;
|
|
2397
|
+
/**
|
|
2398
|
+
* Optional renderer for the OK (non-terminal) case of `handleRequest`.
|
|
2399
|
+
* Defaults to a minimal `{"ok":true,"requestId":...}` JSON body.
|
|
2400
|
+
*/
|
|
2401
|
+
render?: (result: PipelineResult, ctx: PipelineContext) => Response | Promise<Response>;
|
|
2402
|
+
}
|
|
2403
|
+
export interface IngressPipeline {
|
|
2404
|
+
/** The underlying pre-baked handler (custom route factories / responses). */
|
|
2405
|
+
readonly ingress: OptimizedIngressHandler;
|
|
2406
|
+
/** Run the pipeline for a middleware/framework. */
|
|
2407
|
+
preprocess(req: Request, ip?: string): Promise<PreprocessOutcome>;
|
|
2408
|
+
/** Fetch-compatible handler: terminal response or the renderer's response. */
|
|
2409
|
+
handleRequest(req: Request, ip?: string): Promise<Response>;
|
|
2410
|
+
/** Stream-read a request body with the configured limits. */
|
|
2411
|
+
readBody(req: Request, maxBytes?: number, timeoutMs?: number): Promise<Uint8Array>;
|
|
2412
|
+
}
|
|
2413
|
+
/**
|
|
2414
|
+
* Create a framework-agnostic ingress pipeline.
|
|
2415
|
+
*
|
|
2416
|
+
* @example
|
|
2417
|
+
* ```ts
|
|
2418
|
+
* // Plain Bun.serve fetch handler
|
|
2419
|
+
* const pipeline = createPipeline({ options: { parseCookies: true } });
|
|
2420
|
+
* Bun.serve({ port: 3000, fetch: (req) => pipeline.handleRequest(req) });
|
|
2421
|
+
*
|
|
2422
|
+
* // Hono-style middleware: short-circuit on terminal, else handle the app route
|
|
2423
|
+
* app.use("*", async (c, next) => {
|
|
2424
|
+
* const { terminal, response, ctx } = await pipeline.preprocess(c.req.raw);
|
|
2425
|
+
* if (terminal && response) return response;
|
|
2426
|
+
* c.set("ingress", ctx); // pass requestId / locals into the app handler
|
|
2427
|
+
* await next();
|
|
2428
|
+
* });
|
|
2429
|
+
* ```
|
|
2430
|
+
*/
|
|
2431
|
+
export declare function createPipeline(opts?: CreatePipelineOptions): IngressPipeline;
|
|
2432
|
+
export interface WebSocketUpgradeOptions {
|
|
2433
|
+
/** Subprotocols this server supports; the first client-requested match wins. */
|
|
2434
|
+
protocols?: ReadonlyArray<string>;
|
|
2435
|
+
}
|
|
2436
|
+
export interface WebSocketUpgradeResult {
|
|
2437
|
+
/** The 101 Switching Protocols response — return it from your fetch handler. */
|
|
2438
|
+
readonly response: Response;
|
|
2439
|
+
/** The client's `Sec-WebSocket-Key` (handy for connection logging). */
|
|
2440
|
+
readonly key: string;
|
|
2441
|
+
/** The negotiated subprotocol, if any. */
|
|
2442
|
+
readonly protocol: string | null;
|
|
2443
|
+
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Build a WebSocket 101 upgrade handshake response for a request.
|
|
2446
|
+
*
|
|
2447
|
+
* Validates `Sec-WebSocket-Key` presence and computes the RFC 6455 accept key
|
|
2448
|
+
* via the native `rust.wsAcceptKey`, optionally negotiates a subprotocol, and
|
|
2449
|
+
* returns a ready-to-serve `Response`. Returns `null` when the request is not a
|
|
2450
|
+
* valid upgrade (missing/empty key).
|
|
2451
|
+
*
|
|
2452
|
+
* This only produces the handshake — pair it with your framework's own
|
|
2453
|
+
* WebSocket server (Bun.serve's `websocket` handler, or a WS library), which
|
|
2454
|
+
* owns the subsequent frames:
|
|
2455
|
+
*
|
|
2456
|
+
* @example
|
|
2457
|
+
* ```ts
|
|
2458
|
+
* const srv = Bun.serve({
|
|
2459
|
+
* port: 3000,
|
|
2460
|
+
* fetch(req, server) {
|
|
2461
|
+
* const up = createWebSocketUpgrade(req, { protocols: ["chat"] });
|
|
2462
|
+
* if (up && server.upgrade(req, { data: { protocol: up.protocol } })) {
|
|
2463
|
+
* return up.response;
|
|
2464
|
+
* }
|
|
2465
|
+
* return new Response("Not a websocket", { status: 400 });
|
|
2466
|
+
* },
|
|
2467
|
+
* websocket: {
|
|
2468
|
+
* message(ws, msg) { ws.send(msg); },
|
|
2469
|
+
* },
|
|
2470
|
+
* });
|
|
2471
|
+
* ```
|
|
2472
|
+
*/
|
|
2473
|
+
export declare function createWebSocketUpgrade(req: Request, opts?: WebSocketUpgradeOptions): WebSocketUpgradeResult | null;
|
|
2474
|
+
export interface SseEvent {
|
|
2475
|
+
/** Optional `event:` field. */
|
|
2476
|
+
event?: string | null;
|
|
2477
|
+
/** Optional `id:` field. */
|
|
2478
|
+
id?: string | null;
|
|
2479
|
+
/** Optional `retry:` field (ms). */
|
|
2480
|
+
retry?: number | null;
|
|
2481
|
+
/** Event data. */
|
|
2482
|
+
data: string | Uint8Array;
|
|
2483
|
+
}
|
|
2484
|
+
/**
|
|
2485
|
+
* Build a `text/event-stream` Response from an (async) iterable of events.
|
|
2486
|
+
*
|
|
2487
|
+
* Each event is framed with the native `rust.sseEncodeEvent` (zero-DOM, byte
|
|
2488
|
+
* parity with the FFI primitive), so SSE stays on the fast path:
|
|
2489
|
+
*
|
|
2490
|
+
* @example
|
|
2491
|
+
* ```ts
|
|
2492
|
+
* async function* tick() {
|
|
2493
|
+
* for (let i = 0; i < 5; i++) {
|
|
2494
|
+
* await Bun.sleep(250);
|
|
2495
|
+
* yield { event: "tick", data: String(i) };
|
|
2496
|
+
* }
|
|
2497
|
+
* }
|
|
2498
|
+
* return sseResponse(tick(), { headers: { "x-request-id": rid } });
|
|
2499
|
+
* ```
|
|
2500
|
+
*/
|
|
2501
|
+
export declare function sseResponse(events: AsyncIterable<SseEvent> | Iterable<SseEvent>, init?: ResponseInit): Response;
|
|
2502
|
+
/** Result kinds supported by the loader (mirrors the packed batch wire shapes). */
|
|
2503
|
+
export type LoaderResultKind = "boolean" | "number" | "bigint" | "bytes";
|
|
2504
|
+
/** Single-item (scalar) result type for a kind. */
|
|
2505
|
+
export type ScalarResult<K extends LoaderResultKind> = K extends "boolean" ? boolean : K extends "number" ? number : K extends "bigint" ? bigint : Uint8Array;
|
|
2506
|
+
/** Bulk (array-input) result type for a kind — same shape as `rust.batch.*`. */
|
|
2507
|
+
export type BulkResult<K extends LoaderResultKind> = K extends "boolean" ? Uint8Array : K extends "number" ? Uint32Array : K extends "bigint" ? BigInt64Array : Uint8Array[];
|
|
2508
|
+
/**
|
|
2509
|
+
* Bulk-result type overrides per op. Bigint ops whose hashes can set the high
|
|
2510
|
+
* bit (e.g. `fnv1a64`) return an UNSIGNED `BigUint64Array` to match the scalar
|
|
2511
|
+
* `rust.<op>`; the default signed `BigInt64Array` stays for sum-style ops.
|
|
2512
|
+
*/
|
|
2513
|
+
export interface LoaderOpBulkOverride {
|
|
2514
|
+
fnv1a64: BigUint64Array;
|
|
2515
|
+
}
|
|
2516
|
+
/** Bulk result type of a specific op (per-op override wins). */
|
|
2517
|
+
export type LoaderBulk<K extends LoaderOpName> = K extends keyof LoaderOpBulkOverride ? LoaderOpBulkOverride[K] : BulkResult<LoaderOpKind<K>>;
|
|
2518
|
+
/** Every op the loader can dispatch. */
|
|
2519
|
+
export type LoaderOpName = "crc32" | "fnv1a64" | "jsonValid" | "jsonSumIds" | "validateEmail" | "validateUuid" | "validateIpv4" | "validateIpv6" | "queryParse" | "cookieParse" | "formParse" | "httpParseRequest" | "hexEncode" | "hexDecode" | "base64Encode" | "base64Decode" | "base64UrlEncode" | "base64UrlDecode" | "gzipCompress" | "gzipDecompress" | "brotliCompress" | "brotliDecompress" | "etag" | "urlEncode" | "urlDecode" | "urlDecodeBytes" | "wsAcceptKey" | "mimeFromExtension" | "signCookie" | "verifyCookie" | "csrfVerify" | "passwordHash" | "passwordVerify" | "hmacSha256" | "hmacSha256Verify" | "aeadEncrypt" | "aeadDecrypt" | "jwtSign" | "jwtVerify" | "jsonPatch" | "urlResolve" | "wsFrameEncode" | "sseEncode" | "schemaValidate";
|
|
2520
|
+
/** Extra arguments (after the item/items) for each op — the SINGLE call shape. */
|
|
2521
|
+
export interface LoaderOpArgs {
|
|
2522
|
+
crc32: [
|
|
2523
|
+
];
|
|
2524
|
+
fnv1a64: [
|
|
2525
|
+
];
|
|
2526
|
+
jsonValid: [
|
|
2527
|
+
];
|
|
2528
|
+
jsonSumIds: [
|
|
2529
|
+
];
|
|
2530
|
+
validateEmail: [
|
|
2531
|
+
];
|
|
2532
|
+
validateUuid: [
|
|
2533
|
+
];
|
|
2534
|
+
validateIpv4: [
|
|
2535
|
+
];
|
|
2536
|
+
validateIpv6: [
|
|
2537
|
+
];
|
|
2538
|
+
queryParse: [
|
|
2539
|
+
];
|
|
2540
|
+
cookieParse: [
|
|
2541
|
+
];
|
|
2542
|
+
formParse: [
|
|
2543
|
+
];
|
|
2544
|
+
httpParseRequest: [
|
|
2545
|
+
];
|
|
2546
|
+
hexEncode: [
|
|
2547
|
+
];
|
|
2548
|
+
hexDecode: [
|
|
2549
|
+
];
|
|
2550
|
+
base64Encode: [
|
|
2551
|
+
urlSafe?: boolean,
|
|
2552
|
+
padding?: boolean
|
|
2553
|
+
];
|
|
2554
|
+
base64Decode: [
|
|
2555
|
+
urlSafe?: boolean,
|
|
2556
|
+
padding?: boolean
|
|
2557
|
+
];
|
|
2558
|
+
base64UrlEncode: [
|
|
2559
|
+
];
|
|
2560
|
+
base64UrlDecode: [
|
|
2561
|
+
];
|
|
2562
|
+
gzipCompress: [
|
|
2563
|
+
level?: number | null
|
|
2564
|
+
];
|
|
2565
|
+
gzipDecompress: [
|
|
2566
|
+
];
|
|
2567
|
+
brotliCompress: [
|
|
2568
|
+
quality?: number | null
|
|
2569
|
+
];
|
|
2570
|
+
brotliDecompress: [
|
|
2571
|
+
];
|
|
2572
|
+
etag: [
|
|
2573
|
+
weak?: boolean | null
|
|
2574
|
+
];
|
|
2575
|
+
urlEncode: [
|
|
2576
|
+
];
|
|
2577
|
+
urlDecode: [
|
|
2578
|
+
];
|
|
2579
|
+
urlDecodeBytes: [
|
|
2580
|
+
];
|
|
2581
|
+
wsAcceptKey: [
|
|
2582
|
+
];
|
|
2583
|
+
mimeFromExtension: [
|
|
2584
|
+
];
|
|
2585
|
+
signCookie: [
|
|
2586
|
+
secret: Uint8Array
|
|
2587
|
+
];
|
|
2588
|
+
/** Boolean-validity op: returns valid/invalid (use `rust.verifyCookie` for the value). */
|
|
2589
|
+
verifyCookie: [
|
|
2590
|
+
secret: Uint8Array
|
|
2591
|
+
];
|
|
2592
|
+
csrfVerify: [
|
|
2593
|
+
secret: Uint8Array
|
|
2594
|
+
];
|
|
2595
|
+
passwordHash: [
|
|
2596
|
+
salt: Uint8Array,
|
|
2597
|
+
options?: PasswordHashOptions | null
|
|
2598
|
+
];
|
|
2599
|
+
passwordVerify: [
|
|
2600
|
+
phc: Uint8Array
|
|
2601
|
+
];
|
|
2602
|
+
hmacSha256: [
|
|
2603
|
+
key: Uint8Array
|
|
2604
|
+
];
|
|
2605
|
+
hmacSha256Verify: [
|
|
2606
|
+
key: Uint8Array,
|
|
2607
|
+
sig: Uint8Array
|
|
2608
|
+
];
|
|
2609
|
+
aeadEncrypt: [
|
|
2610
|
+
key: Uint8Array,
|
|
2611
|
+
nonce: Uint8Array,
|
|
2612
|
+
algorithm?: string | null
|
|
2613
|
+
];
|
|
2614
|
+
aeadDecrypt: [
|
|
2615
|
+
key: Uint8Array,
|
|
2616
|
+
nonce: Uint8Array,
|
|
2617
|
+
algorithm?: string | null
|
|
2618
|
+
];
|
|
2619
|
+
jwtSign: [
|
|
2620
|
+
secret: Uint8Array,
|
|
2621
|
+
ttlSeconds?: number | null,
|
|
2622
|
+
nowSeconds?: number
|
|
2623
|
+
];
|
|
2624
|
+
/** Boolean-validity op: returns valid/invalid (use `rust.jwtVerify` for the payload). */
|
|
2625
|
+
jwtVerify: [
|
|
2626
|
+
secret: Uint8Array,
|
|
2627
|
+
nowSeconds?: number
|
|
2628
|
+
];
|
|
2629
|
+
jsonPatch: [
|
|
2630
|
+
patch: Uint8Array
|
|
2631
|
+
];
|
|
2632
|
+
urlResolve: [
|
|
2633
|
+
base: Uint8Array
|
|
2634
|
+
];
|
|
2635
|
+
wsFrameEncode: [
|
|
2636
|
+
opcode: number,
|
|
2637
|
+
mask: boolean,
|
|
2638
|
+
fin: boolean
|
|
2639
|
+
];
|
|
2640
|
+
sseEncode: [
|
|
2641
|
+
event?: string | null,
|
|
2642
|
+
id?: string | null,
|
|
2643
|
+
retry?: number | null
|
|
2644
|
+
];
|
|
2645
|
+
schemaValidate: [
|
|
2646
|
+
validator: SchemaValidator
|
|
2647
|
+
];
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Extra arguments for the BULK call shape. Paired ops take a per-item
|
|
2651
|
+
* companion ARRAY here; every other op inherits the scalar `LoaderOpArgs`
|
|
2652
|
+
* shape (companions are shared across the batch).
|
|
2653
|
+
*/
|
|
2654
|
+
export interface LoaderOpBulkArgs {
|
|
2655
|
+
jsonPatch: [
|
|
2656
|
+
patches: Uint8Array[]
|
|
2657
|
+
];
|
|
2658
|
+
hmacSha256Verify: [
|
|
2659
|
+
key: Uint8Array,
|
|
2660
|
+
sigs: Uint8Array[]
|
|
2661
|
+
];
|
|
2662
|
+
passwordVerify: [
|
|
2663
|
+
phcs: Uint8Array[]
|
|
2664
|
+
];
|
|
2665
|
+
urlResolve: [
|
|
2666
|
+
bases: Uint8Array[]
|
|
2667
|
+
];
|
|
2668
|
+
}
|
|
2669
|
+
/** Bulk call shape for any op (defaults to the scalar shape). */
|
|
2670
|
+
export type LoaderBulkArgs<K extends LoaderOpName> = K extends keyof LoaderOpBulkArgs ? LoaderOpBulkArgs[K] : LoaderOpArgs[K];
|
|
2671
|
+
declare function boolElem(bulk: unknown, index: number): boolean;
|
|
2672
|
+
declare function numElem(bulk: unknown, index: number): number;
|
|
2673
|
+
declare function bigElem(bulk: unknown, index: number): bigint;
|
|
2674
|
+
declare function byteElem(bulk: unknown, index: number): Uint8Array;
|
|
2675
|
+
declare function boolFast(_view: DataView, output: Uint8Array, index: number): boolean;
|
|
2676
|
+
declare function bitsetOutSize(count: number): number;
|
|
2677
|
+
declare function u32Fast(view: DataView, _output: Uint8Array, index: number): number;
|
|
2678
|
+
declare function u32OutSize(count: number): number;
|
|
2679
|
+
declare function i64Fast(view: DataView, _output: Uint8Array, index: number): bigint;
|
|
2680
|
+
declare function u64Fast(view: DataView, _output: Uint8Array, index: number): bigint;
|
|
2681
|
+
declare function i64OutSize(count: number): number;
|
|
2682
|
+
/**
|
|
2683
|
+
* Registry — single source of truth for loader-op wiring. Every op must have
|
|
2684
|
+
* a scalar variant and a packed batch variant; ops whose scalar returns
|
|
2685
|
+
* something other than the bulk element (e.g. `jwtVerify` returning the
|
|
2686
|
+
* decoded payload, `verifyCookie` returning the value) are deliberately
|
|
2687
|
+
* EXCLUDED so single and bulk semantics stay identical.
|
|
2688
|
+
*/
|
|
2689
|
+
export declare const LOADER_OPS: {
|
|
2690
|
+
readonly crc32: {
|
|
2691
|
+
readonly kind: "number";
|
|
2692
|
+
readonly scalar: (i: Uint8Array) => number;
|
|
2693
|
+
readonly batch: (items: Uint8Array[]) => Uint32Array<ArrayBufferLike>;
|
|
2694
|
+
readonly element: typeof numElem;
|
|
2695
|
+
readonly fast: {
|
|
2696
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2697
|
+
readonly element: typeof u32Fast;
|
|
2698
|
+
readonly outSize: typeof u32OutSize;
|
|
2699
|
+
};
|
|
2700
|
+
};
|
|
2701
|
+
readonly fnv1a64: {
|
|
2702
|
+
readonly kind: "bigint";
|
|
2703
|
+
readonly unsigned: true;
|
|
2704
|
+
readonly scalar: (i: Uint8Array) => bigint;
|
|
2705
|
+
readonly batch: (items: Uint8Array[]) => BigUint64Array<ArrayBufferLike>;
|
|
2706
|
+
readonly element: typeof bigElem;
|
|
2707
|
+
readonly fast: {
|
|
2708
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2709
|
+
readonly element: typeof u64Fast;
|
|
2710
|
+
readonly outSize: typeof i64OutSize;
|
|
2711
|
+
};
|
|
2712
|
+
};
|
|
2713
|
+
readonly jsonValid: {
|
|
2714
|
+
readonly kind: "boolean";
|
|
2715
|
+
readonly scalar: (i: Uint8Array) => boolean;
|
|
2716
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>;
|
|
2717
|
+
readonly element: typeof boolElem;
|
|
2718
|
+
readonly fast: {
|
|
2719
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2720
|
+
readonly element: typeof boolFast;
|
|
2721
|
+
readonly outSize: typeof bitsetOutSize;
|
|
2722
|
+
};
|
|
2723
|
+
};
|
|
2724
|
+
readonly jsonSumIds: {
|
|
2725
|
+
readonly kind: "bigint";
|
|
2726
|
+
readonly scalar: (i: Uint8Array) => bigint;
|
|
2727
|
+
readonly batch: (items: Uint8Array[]) => BigInt64Array<ArrayBufferLike>;
|
|
2728
|
+
readonly element: typeof bigElem;
|
|
2729
|
+
readonly fast: {
|
|
2730
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2731
|
+
readonly element: typeof i64Fast;
|
|
2732
|
+
readonly outSize: typeof i64OutSize;
|
|
2733
|
+
};
|
|
2734
|
+
};
|
|
2735
|
+
readonly validateEmail: {
|
|
2736
|
+
readonly kind: "boolean";
|
|
2737
|
+
readonly scalar: (i: Uint8Array) => boolean;
|
|
2738
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>;
|
|
2739
|
+
readonly element: typeof boolElem;
|
|
2740
|
+
readonly fast: {
|
|
2741
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2742
|
+
readonly element: typeof boolFast;
|
|
2743
|
+
readonly outSize: typeof bitsetOutSize;
|
|
2744
|
+
};
|
|
2745
|
+
};
|
|
2746
|
+
readonly validateUuid: {
|
|
2747
|
+
readonly kind: "boolean";
|
|
2748
|
+
readonly scalar: (i: Uint8Array) => boolean;
|
|
2749
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>;
|
|
2750
|
+
readonly element: typeof boolElem;
|
|
2751
|
+
readonly fast: {
|
|
2752
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2753
|
+
readonly element: typeof boolFast;
|
|
2754
|
+
readonly outSize: typeof bitsetOutSize;
|
|
2755
|
+
};
|
|
2756
|
+
};
|
|
2757
|
+
readonly validateIpv4: {
|
|
2758
|
+
readonly kind: "boolean";
|
|
2759
|
+
readonly scalar: (i: Uint8Array) => boolean;
|
|
2760
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>;
|
|
2761
|
+
readonly element: typeof boolElem;
|
|
2762
|
+
readonly fast: {
|
|
2763
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2764
|
+
readonly element: typeof boolFast;
|
|
2765
|
+
readonly outSize: typeof bitsetOutSize;
|
|
2766
|
+
};
|
|
2767
|
+
};
|
|
2768
|
+
readonly validateIpv6: {
|
|
2769
|
+
readonly kind: "boolean";
|
|
2770
|
+
readonly scalar: (i: Uint8Array) => boolean;
|
|
2771
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>;
|
|
2772
|
+
readonly element: typeof boolElem;
|
|
2773
|
+
readonly fast: {
|
|
2774
|
+
readonly batch: (packed: Uint8Array<ArrayBufferLike>, output: Uint8Array<ArrayBufferLike>) => number;
|
|
2775
|
+
readonly element: typeof boolFast;
|
|
2776
|
+
readonly outSize: typeof bitsetOutSize;
|
|
2777
|
+
};
|
|
2778
|
+
};
|
|
2779
|
+
readonly queryParse: {
|
|
2780
|
+
readonly kind: "bytes";
|
|
2781
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2782
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2783
|
+
readonly element: typeof byteElem;
|
|
2784
|
+
};
|
|
2785
|
+
readonly cookieParse: {
|
|
2786
|
+
readonly kind: "bytes";
|
|
2787
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2788
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2789
|
+
readonly element: typeof byteElem;
|
|
2790
|
+
};
|
|
2791
|
+
readonly formParse: {
|
|
2792
|
+
readonly kind: "bytes";
|
|
2793
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2794
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2795
|
+
readonly element: typeof byteElem;
|
|
2796
|
+
};
|
|
2797
|
+
readonly httpParseRequest: {
|
|
2798
|
+
readonly kind: "bytes";
|
|
2799
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2800
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2801
|
+
readonly element: typeof byteElem;
|
|
2802
|
+
};
|
|
2803
|
+
readonly hexEncode: {
|
|
2804
|
+
readonly kind: "bytes";
|
|
2805
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2806
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2807
|
+
readonly element: typeof byteElem;
|
|
2808
|
+
};
|
|
2809
|
+
readonly hexDecode: {
|
|
2810
|
+
readonly kind: "bytes";
|
|
2811
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2812
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2813
|
+
readonly element: typeof byteElem;
|
|
2814
|
+
};
|
|
2815
|
+
readonly base64Encode: {
|
|
2816
|
+
readonly kind: "bytes";
|
|
2817
|
+
readonly scalar: (i: Uint8Array, urlSafe?: boolean, padding?: boolean) => Uint8Array<ArrayBufferLike>;
|
|
2818
|
+
readonly batch: (items: Uint8Array[], urlSafe?: boolean, padding?: boolean) => Uint8Array<ArrayBufferLike>[];
|
|
2819
|
+
readonly element: typeof byteElem;
|
|
2820
|
+
};
|
|
2821
|
+
readonly base64Decode: {
|
|
2822
|
+
readonly kind: "bytes";
|
|
2823
|
+
readonly scalar: (i: Uint8Array, urlSafe?: boolean, padding?: boolean) => Uint8Array<ArrayBufferLike>;
|
|
2824
|
+
readonly batch: (items: Uint8Array[], urlSafe?: boolean, padding?: boolean) => Uint8Array<ArrayBufferLike>[];
|
|
2825
|
+
readonly element: typeof byteElem;
|
|
2826
|
+
};
|
|
2827
|
+
readonly base64UrlEncode: {
|
|
2828
|
+
readonly kind: "bytes";
|
|
2829
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2830
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2831
|
+
readonly element: typeof byteElem;
|
|
2832
|
+
};
|
|
2833
|
+
readonly base64UrlDecode: {
|
|
2834
|
+
readonly kind: "bytes";
|
|
2835
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2836
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2837
|
+
readonly element: typeof byteElem;
|
|
2838
|
+
};
|
|
2839
|
+
readonly gzipCompress: {
|
|
2840
|
+
readonly kind: "bytes";
|
|
2841
|
+
readonly scalar: (i: Uint8Array, level?: number | null) => Uint8Array<ArrayBufferLike>;
|
|
2842
|
+
readonly batch: (items: Uint8Array[], level?: number | null) => Uint8Array<ArrayBufferLike>[];
|
|
2843
|
+
readonly element: typeof byteElem;
|
|
2844
|
+
};
|
|
2845
|
+
readonly gzipDecompress: {
|
|
2846
|
+
readonly kind: "bytes";
|
|
2847
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2848
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2849
|
+
readonly element: typeof byteElem;
|
|
2850
|
+
};
|
|
2851
|
+
readonly brotliCompress: {
|
|
2852
|
+
readonly kind: "bytes";
|
|
2853
|
+
readonly scalar: (i: Uint8Array, quality?: number | null) => Uint8Array<ArrayBufferLike>;
|
|
2854
|
+
readonly batch: (items: Uint8Array[], quality?: number | null) => Uint8Array<ArrayBufferLike>[];
|
|
2855
|
+
readonly element: typeof byteElem;
|
|
2856
|
+
};
|
|
2857
|
+
readonly brotliDecompress: {
|
|
2858
|
+
readonly kind: "bytes";
|
|
2859
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2860
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2861
|
+
readonly element: typeof byteElem;
|
|
2862
|
+
};
|
|
2863
|
+
readonly etag: {
|
|
2864
|
+
readonly kind: "bytes";
|
|
2865
|
+
readonly scalar: (i: Uint8Array, weak?: boolean | null) => Uint8Array<ArrayBufferLike>;
|
|
2866
|
+
readonly batch: (items: Uint8Array[], weak?: boolean | null) => Uint8Array<ArrayBufferLike>[];
|
|
2867
|
+
readonly element: typeof byteElem;
|
|
2868
|
+
};
|
|
2869
|
+
readonly urlEncode: {
|
|
2870
|
+
readonly kind: "bytes";
|
|
2871
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2872
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2873
|
+
readonly element: typeof byteElem;
|
|
2874
|
+
};
|
|
2875
|
+
readonly urlDecode: {
|
|
2876
|
+
readonly kind: "bytes";
|
|
2877
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2878
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2879
|
+
readonly element: typeof byteElem;
|
|
2880
|
+
};
|
|
2881
|
+
readonly urlDecodeBytes: {
|
|
2882
|
+
readonly kind: "bytes";
|
|
2883
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2884
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2885
|
+
readonly element: typeof byteElem;
|
|
2886
|
+
};
|
|
2887
|
+
readonly wsAcceptKey: {
|
|
2888
|
+
readonly kind: "bytes";
|
|
2889
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2890
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2891
|
+
readonly element: typeof byteElem;
|
|
2892
|
+
};
|
|
2893
|
+
readonly mimeFromExtension: {
|
|
2894
|
+
readonly kind: "bytes";
|
|
2895
|
+
readonly scalar: (i: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2896
|
+
readonly batch: (items: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2897
|
+
readonly element: typeof byteElem;
|
|
2898
|
+
};
|
|
2899
|
+
readonly signCookie: {
|
|
2900
|
+
readonly kind: "bytes";
|
|
2901
|
+
readonly scalar: (i: Uint8Array, secret: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2902
|
+
readonly batch: (items: Uint8Array[], secret: Uint8Array) => Uint8Array<ArrayBufferLike>[];
|
|
2903
|
+
readonly element: typeof byteElem;
|
|
2904
|
+
};
|
|
2905
|
+
readonly verifyCookie: {
|
|
2906
|
+
readonly kind: "boolean";
|
|
2907
|
+
readonly scalar: (i: Uint8Array, secret: Uint8Array) => boolean;
|
|
2908
|
+
readonly batch: (items: Uint8Array[], secret: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2909
|
+
readonly element: typeof boolElem;
|
|
2910
|
+
};
|
|
2911
|
+
readonly csrfVerify: {
|
|
2912
|
+
readonly kind: "boolean";
|
|
2913
|
+
readonly scalar: (i: Uint8Array, secret: Uint8Array) => boolean;
|
|
2914
|
+
readonly batch: (items: Uint8Array[], secret: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2915
|
+
readonly element: typeof boolElem;
|
|
2916
|
+
};
|
|
2917
|
+
readonly passwordHash: {
|
|
2918
|
+
readonly kind: "bytes";
|
|
2919
|
+
readonly scalar: (i: Uint8Array, salt: Uint8Array, options?: PasswordHashOptions | null) => Uint8Array<ArrayBufferLike>;
|
|
2920
|
+
readonly batch: (items: Uint8Array[], salt: Uint8Array, options?: PasswordHashOptions | null) => Uint8Array<ArrayBufferLike>[];
|
|
2921
|
+
readonly element: typeof byteElem;
|
|
2922
|
+
};
|
|
2923
|
+
readonly passwordVerify: {
|
|
2924
|
+
readonly kind: "boolean";
|
|
2925
|
+
readonly pairedRest: [
|
|
2926
|
+
0
|
|
2927
|
+
];
|
|
2928
|
+
readonly scalar: (i: Uint8Array, phc: Uint8Array) => boolean;
|
|
2929
|
+
readonly batch: (items: Uint8Array[], phcs: Uint8Array[]) => Uint8Array<ArrayBufferLike>;
|
|
2930
|
+
readonly element: typeof boolElem;
|
|
2931
|
+
};
|
|
2932
|
+
readonly aeadEncrypt: {
|
|
2933
|
+
readonly kind: "bytes";
|
|
2934
|
+
readonly scalar: (i: Uint8Array, key: Uint8Array, nonce: Uint8Array, algorithm?: string | null) => Uint8Array<ArrayBufferLike>;
|
|
2935
|
+
readonly batch: (items: Uint8Array[], key: Uint8Array, nonce: Uint8Array, algorithm?: string | null) => Uint8Array<ArrayBufferLike>[];
|
|
2936
|
+
readonly element: typeof byteElem;
|
|
2937
|
+
};
|
|
2938
|
+
readonly aeadDecrypt: {
|
|
2939
|
+
readonly kind: "bytes";
|
|
2940
|
+
readonly scalar: (i: Uint8Array, key: Uint8Array, nonce: Uint8Array, algorithm?: string | null) => Uint8Array<ArrayBufferLike>;
|
|
2941
|
+
readonly batch: (items: Uint8Array[], key: Uint8Array, nonce: Uint8Array, algorithm?: string | null) => Uint8Array<ArrayBufferLike>[];
|
|
2942
|
+
readonly element: typeof byteElem;
|
|
2943
|
+
};
|
|
2944
|
+
readonly jwtSign: {
|
|
2945
|
+
readonly kind: "bytes";
|
|
2946
|
+
readonly scalar: (i: Uint8Array, secret: Uint8Array, ttlSeconds?: number | null, nowSeconds?: number) => Uint8Array<ArrayBufferLike>;
|
|
2947
|
+
readonly batch: (items: Uint8Array[], secret: Uint8Array, ttlSeconds?: number | null, nowSeconds?: number) => Uint8Array<ArrayBufferLike>[];
|
|
2948
|
+
readonly element: typeof byteElem;
|
|
2949
|
+
};
|
|
2950
|
+
readonly jwtVerify: {
|
|
2951
|
+
readonly kind: "boolean";
|
|
2952
|
+
readonly scalar: (i: Uint8Array, secret: Uint8Array, nowSeconds?: number) => boolean;
|
|
2953
|
+
readonly batch: (items: Uint8Array[], secret: Uint8Array, nowSeconds?: number) => Uint8Array<ArrayBufferLike>;
|
|
2954
|
+
readonly element: typeof boolElem;
|
|
2955
|
+
};
|
|
2956
|
+
readonly jsonPatch: {
|
|
2957
|
+
readonly kind: "bytes";
|
|
2958
|
+
readonly pairedRest: [
|
|
2959
|
+
0
|
|
2960
|
+
];
|
|
2961
|
+
readonly scalar: (i: Uint8Array, patch: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2962
|
+
readonly batch: (items: Uint8Array[], patches: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2963
|
+
readonly element: typeof byteElem;
|
|
2964
|
+
};
|
|
2965
|
+
readonly urlResolve: {
|
|
2966
|
+
readonly kind: "bytes";
|
|
2967
|
+
readonly pairedRest: [
|
|
2968
|
+
0
|
|
2969
|
+
];
|
|
2970
|
+
readonly scalar: (i: Uint8Array, base: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2971
|
+
readonly batch: (items: Uint8Array[], bases: Uint8Array[]) => Uint8Array<ArrayBufferLike>[];
|
|
2972
|
+
readonly element: typeof byteElem;
|
|
2973
|
+
};
|
|
2974
|
+
readonly wsFrameEncode: {
|
|
2975
|
+
readonly kind: "bytes";
|
|
2976
|
+
readonly scalar: (i: Uint8Array, opcode: number, mask: boolean, fin: boolean) => Uint8Array<ArrayBufferLike>;
|
|
2977
|
+
readonly batch: (items: Uint8Array[], opcode: number, mask: boolean, fin: boolean) => Uint8Array<ArrayBufferLike>[];
|
|
2978
|
+
readonly element: typeof byteElem;
|
|
2979
|
+
};
|
|
2980
|
+
readonly sseEncode: {
|
|
2981
|
+
readonly kind: "bytes";
|
|
2982
|
+
readonly scalar: (i: Uint8Array, event?: string | null, id?: string | null, retry?: number | null) => Uint8Array<ArrayBufferLike>;
|
|
2983
|
+
readonly batch: (items: Uint8Array[], event?: string | null, id?: string | null, retry?: number | null) => Uint8Array<ArrayBufferLike>[];
|
|
2984
|
+
readonly element: typeof byteElem;
|
|
2985
|
+
};
|
|
2986
|
+
readonly schemaValidate: {
|
|
2987
|
+
readonly kind: "boolean";
|
|
2988
|
+
readonly scalar: (i: Uint8Array, validator: SchemaValidator) => boolean;
|
|
2989
|
+
readonly batch: (items: Uint8Array[], validator: SchemaValidator) => Uint8Array<ArrayBufferLike>;
|
|
2990
|
+
readonly element: typeof boolElem;
|
|
2991
|
+
};
|
|
2992
|
+
readonly hmacSha256: {
|
|
2993
|
+
readonly kind: "bytes";
|
|
2994
|
+
readonly scalar: (i: Uint8Array, key: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
2995
|
+
readonly batch: (items: Uint8Array[], key: Uint8Array) => Uint8Array<ArrayBufferLike>[];
|
|
2996
|
+
readonly element: typeof byteElem;
|
|
2997
|
+
};
|
|
2998
|
+
readonly hmacSha256Verify: {
|
|
2999
|
+
readonly kind: "boolean";
|
|
3000
|
+
readonly pairedRest: [
|
|
3001
|
+
1
|
|
3002
|
+
];
|
|
3003
|
+
readonly scalar: (i: Uint8Array, key: Uint8Array, sig: Uint8Array) => boolean;
|
|
3004
|
+
readonly batch: (items: Uint8Array[], key: Uint8Array, sigs: Uint8Array[]) => Uint8Array<ArrayBufferLike>;
|
|
3005
|
+
readonly element: typeof boolElem;
|
|
3006
|
+
};
|
|
3007
|
+
};
|
|
3008
|
+
/** Kind of a specific op. */
|
|
3009
|
+
export type LoaderOpKind<K extends LoaderOpName> = (typeof LOADER_OPS)[K]["kind"];
|
|
3010
|
+
/** Single-item result type of a specific op. */
|
|
3011
|
+
export type LoaderScalar<K extends LoaderOpName> = ScalarResult<LoaderOpKind<K>>;
|
|
3012
|
+
/** All op names, as a readonly array (for iteration). */
|
|
3013
|
+
export declare const LOADER_OP_NAMES: LoaderOpName[];
|
|
3014
|
+
/** Options for `createLoader()` / `loader.configure()`. */
|
|
3015
|
+
export interface LoaderOptions {
|
|
3016
|
+
/** Let each op adapt `batchMin` from measured dispatch cost. Default true. */
|
|
3017
|
+
adaptive?: boolean;
|
|
3018
|
+
/** Initial batch threshold in [2, 8]. Default 2 (batch wins for n >= 2). */
|
|
3019
|
+
batchMin?: number;
|
|
3020
|
+
/** Max cached keys (bounded LRU). 0 disables caching. Default 256. */
|
|
3021
|
+
maxCacheKeys?: number;
|
|
3022
|
+
/** Default `cache` behavior for `load()`. Default true. */
|
|
3023
|
+
caching?: boolean;
|
|
3024
|
+
/** Sample timing every N dispatches (hot-path cost control). Default 32. */
|
|
3025
|
+
sampleEvery?: number;
|
|
3026
|
+
/**
|
|
3027
|
+
* `load()` dispatch strategy. `"auto"` (default) switches each op between
|
|
3028
|
+
* `"single"` (low load → direct scalar call, no coalescer) and
|
|
3029
|
+
* `"coalesce"` (rising load → one packed batch call) from observed load.
|
|
3030
|
+
*/
|
|
3031
|
+
loadStrategy?: LoadStrategy;
|
|
3032
|
+
}
|
|
3033
|
+
/** Options for `load()` / `opFn.load()`. */
|
|
3034
|
+
export interface LoadOptions {
|
|
3035
|
+
/**
|
|
3036
|
+
* Explicit cache key. When omitted (and caching is on) the default key is
|
|
3037
|
+
* `fnv1a64(input)` — which costs one extra native call per load.
|
|
3038
|
+
*/
|
|
3039
|
+
key?: string;
|
|
3040
|
+
/** Override the loader-wide caching toggle for this call. Default true. */
|
|
3041
|
+
cache?: boolean;
|
|
3042
|
+
}
|
|
3043
|
+
/** Per-op counters exposed on `opFn.stats`. */
|
|
3044
|
+
export interface LoaderOpStats {
|
|
3045
|
+
scalarCalls: number;
|
|
3046
|
+
batchCalls: number;
|
|
3047
|
+
itemsDispatched: number;
|
|
3048
|
+
cachedHits: number;
|
|
3049
|
+
/** Current learned batch threshold for this op. */
|
|
3050
|
+
batchMin: number;
|
|
3051
|
+
/** Current `load()` strategy: "single" (low load) or "coalesce" (bulk). */
|
|
3052
|
+
mode: "single" | "coalesce";
|
|
3053
|
+
}
|
|
3054
|
+
/** Aggregate loader statistics. */
|
|
3055
|
+
export interface LoaderStats {
|
|
3056
|
+
scalarCalls: number;
|
|
3057
|
+
batchCalls: number;
|
|
3058
|
+
itemsDispatched: number;
|
|
3059
|
+
flushes: number;
|
|
3060
|
+
cachedHits: number;
|
|
3061
|
+
cacheSize: number;
|
|
3062
|
+
cacheEvictions: number;
|
|
3063
|
+
}
|
|
3064
|
+
/** A specialized, pre-bound op function returned by `loader(op)`. */
|
|
3065
|
+
export interface LoaderOpFn<K extends LoaderOpName> {
|
|
3066
|
+
/** Single item → scalar result. */
|
|
3067
|
+
(input: Uint8Array, ...rest: LoaderOpArgs[K]): LoaderScalar<K>;
|
|
3068
|
+
/** Bulk items → ONE packed batch call; same shape as `rust.batch.<op>`. */
|
|
3069
|
+
(inputs: Uint8Array[], ...rest: LoaderBulkArgs<K>): LoaderBulk<K>;
|
|
3070
|
+
readonly name: K;
|
|
3071
|
+
readonly stats: LoaderOpStats;
|
|
3072
|
+
clear(): void;
|
|
3073
|
+
/** Sync cache peek (default key `fnv1a64(input)` unless `key` given). */
|
|
3074
|
+
cache(input: Uint8Array, key?: string): LoaderScalar<K> | undefined;
|
|
3075
|
+
/**
|
|
3076
|
+
* Coalesced, cache-aware load. Unavailable (`undefined`) on ops that require
|
|
3077
|
+
* extra arguments (e.g. `hmacSha256`, `signCookie`) — use `run` for those.
|
|
3078
|
+
*/
|
|
3079
|
+
load: K extends LoadableName ? LoaderLoadFn<K> : undefined;
|
|
3080
|
+
}
|
|
3081
|
+
export type LoaderLoadFn<K extends LoaderOpName> = (input: Uint8Array, opts?: LoadOptions) => Promise<LoaderScalar<K>>;
|
|
3082
|
+
/** Ops whose extra args are all optional/empty → they support `load()`. */
|
|
3083
|
+
export type LoadableName = {
|
|
3084
|
+
[K in LoaderOpName]: LoaderOpArgs[K] extends [
|
|
3085
|
+
] | [
|
|
3086
|
+
unknown?
|
|
3087
|
+
] | [
|
|
3088
|
+
unknown?,
|
|
3089
|
+
unknown?
|
|
3090
|
+
] | [
|
|
3091
|
+
unknown?,
|
|
3092
|
+
unknown?,
|
|
3093
|
+
unknown?
|
|
3094
|
+
] ? K : never;
|
|
3095
|
+
}[LoaderOpName];
|
|
3096
|
+
/** A validator-bound helper returned by `loader.schema(validator)`. */
|
|
3097
|
+
export interface LoaderSchemaFn {
|
|
3098
|
+
/** Single JSON document → valid? */
|
|
3099
|
+
(input: Uint8Array): boolean;
|
|
3100
|
+
/** Bulk JSON documents → bitset (1 per doc). */
|
|
3101
|
+
(inputs: Uint8Array[]): Uint8Array;
|
|
3102
|
+
/** Count how many bulk documents are valid. */
|
|
3103
|
+
count(inputs: Uint8Array[]): number;
|
|
3104
|
+
}
|
|
3105
|
+
/** The global callable loader. */
|
|
3106
|
+
interface Loader$1 {
|
|
3107
|
+
/** Higher-order function: `loader(op)` → specialized hot op function. */
|
|
3108
|
+
<K extends LoaderOpName>(op: K): LoaderOpFn<K>;
|
|
3109
|
+
/** Single-item dispatch. */
|
|
3110
|
+
run<K extends LoaderOpName>(op: K, input: Uint8Array, ...rest: LoaderOpArgs[K]): LoaderScalar<K>;
|
|
3111
|
+
/** Bulk dispatch (one packed batch call, or adaptive scalar loop). */
|
|
3112
|
+
run<K extends LoaderOpName>(op: K, inputs: Uint8Array[], ...rest: LoaderBulkArgs<K>): LoaderBulk<K>;
|
|
3113
|
+
/** Coalesced, cache-aware load (ops with required extra args throw). */
|
|
3114
|
+
load<K extends LoadableName>(op: K, input: Uint8Array, opts?: LoadOptions): Promise<LoaderScalar<K>>;
|
|
3115
|
+
/** Sync cache peek. */
|
|
3116
|
+
cache<K extends LoaderOpName>(op: K, input: Uint8Array, key?: string): LoaderScalar<K> | undefined;
|
|
3117
|
+
/**
|
|
3118
|
+
* Bind a `SchemaValidator` for repeated single/bulk JSON-schema validation
|
|
3119
|
+
* plus a whole-batch `count`. The returned callable uses the loader's normal
|
|
3120
|
+
* dispatch machinery (cost model + counters).
|
|
3121
|
+
*/
|
|
3122
|
+
schema(validator: SchemaValidator): LoaderSchemaFn;
|
|
3123
|
+
/** Clear the shared cache (pending coalesced loads still flush). */
|
|
3124
|
+
clear(): void;
|
|
3125
|
+
/** Update options at runtime. */
|
|
3126
|
+
configure(options: LoaderOptions): void;
|
|
3127
|
+
readonly stats: LoaderStats;
|
|
3128
|
+
readonly opNames: LoaderOpName[];
|
|
3129
|
+
}
|
|
3130
|
+
/** Load-dispatch strategy selector for `load()`. */
|
|
3131
|
+
export type LoadStrategy = "auto" | "single" | "coalesce";
|
|
3132
|
+
/** Create an isolated loader with the given defaults. */
|
|
3133
|
+
export declare function createLoader(options?: LoaderOptions): Loader$1;
|
|
3134
|
+
/**
|
|
3135
|
+
* The global, ready-to-use loader. Most consumers just do
|
|
3136
|
+
* `import { loader } from "castrum"` and either `loader("validateEmail")(…)`
|
|
3137
|
+
* (higher-order function) or `loader.run("validateEmail", …)`.
|
|
3138
|
+
*/
|
|
3139
|
+
export declare const loader: Loader$1;
|
|
3140
|
+
/**
|
|
3141
|
+
* Batch-validate JSON documents against a schema through the loader's bulk
|
|
3142
|
+
* `schemaValidate` path. Returns a bitset — byte `i` is 1 when document `i`
|
|
3143
|
+
* is valid (same shape as `rust.batch.schemaValidate`).
|
|
3144
|
+
*/
|
|
3145
|
+
export declare function validateMany(validator: SchemaValidator, docs: Uint8Array[]): Uint8Array;
|
|
3146
|
+
/** Count how many of `docs` validate against `validator` (one packed call). */
|
|
3147
|
+
export declare function validateCount(validator: SchemaValidator, docs: Uint8Array[]): number;
|
|
3148
|
+
/**
|
|
3149
|
+
* Generic loader bulk dispatch: `loader.run(op, items, ...rest)` → one packed
|
|
3150
|
+
* batch native call (or the adaptive scalar loop for tiny batches).
|
|
3151
|
+
*/
|
|
3152
|
+
export declare function runMany<K extends LoaderOpName>(op: K, items: Uint8Array[], ...rest: LoaderBulkArgs<K>): LoaderBulk<K>;
|
|
3153
|
+
/** Single-item loader dispatch — pairs with `runMany` for mixed workloads. */
|
|
3154
|
+
export declare function runOne<K extends LoaderOpName>(op: K, item: Uint8Array, ...rest: LoaderOpArgs[K]): LoaderScalar<K>;
|
|
3155
|
+
|
|
3156
|
+
export {
|
|
3157
|
+
Loader$1 as Loader,
|
|
3158
|
+
RouteHandler as IngressNodeRouteHandler,
|
|
3159
|
+
};
|
|
3160
|
+
|
|
3161
|
+
export {};
|