castrum 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +153 -630
  2. package/castrum.linux-x64-gnu.node +0 -0
  3. package/dist/index.d.ts +1374 -1772
  4. package/dist/index.js +5570 -4169
  5. package/docs/API.md +337 -0
  6. package/docs/ARCHITECTURE.md +106 -14
  7. package/docs/BENCHMARKS.md +83 -47
  8. package/docs/CASE_STUDY.md +240 -0
  9. package/docs/ENVIRONMENT.md +8 -6
  10. package/docs/FFI_BUN_GUIDE.md +327 -0
  11. package/docs/GETTING_STARTED.md +15 -32
  12. package/docs/INGRESS-ROUTER.md +81 -0
  13. package/docs/INGRESS.md +5 -4
  14. package/docs/NATIVE-ROUTE.md +53 -0
  15. package/docs/REPO_MAP.md +46 -26
  16. package/docs/adr/0003-bun-builtins-delegation.md +6 -5
  17. package/docs/bun-builtins-decision-matrix.md +25 -18
  18. package/index.ts +9 -16
  19. package/package.json +36 -24
  20. package/src/ingress/body.ts +167 -27
  21. package/src/ingress/handlers.ts +91 -15
  22. package/src/ingress/health.ts +1 -0
  23. package/src/ingress/index.ts +39 -27
  24. package/src/ingress/packing/gather-raw-headers.ts +85 -21
  25. package/src/ingress/packing/header-packing.ts +5 -5
  26. package/src/ingress/packing/input-packer.ts +17 -3
  27. package/src/ingress/packing/select-headers.ts +12 -6
  28. package/src/ingress/router.ts +237 -0
  29. package/src/ingress/routes/common.ts +42 -1
  30. package/src/ingress/routes/fallback.ts +2 -2
  31. package/src/ingress/routes/head.ts +3 -13
  32. package/src/ingress/routes/index.ts +5 -4
  33. package/src/ingress/routes/json-write.ts +7 -31
  34. package/src/ingress/routes/options.ts +2 -12
  35. package/src/ingress/routes/read.ts +3 -13
  36. package/src/ingress/routes/responder.ts +159 -0
  37. package/src/ingress/server-node.ts +6 -6
  38. package/src/ingress/server.ts +45 -13
  39. package/src/ingress/types.ts +35 -1
  40. package/src/integration/pipeline.ts +3 -0
  41. package/src/integration/streaming.ts +2 -3
  42. package/src/integration/websocket.ts +4 -3
  43. package/src/loader/batch.ts +4 -0
  44. package/src/loader/cost.ts +1 -0
  45. package/src/loader/index.ts +43 -228
  46. package/src/loader/state.ts +84 -0
  47. package/src/loader/types.ts +145 -0
  48. package/src/native/ffi/constants.ts +58 -0
  49. package/src/native/ffi/selftest.ts +729 -0
  50. package/src/native/ffi/types.ts +474 -0
  51. package/src/native/ffi.ts +1063 -829
  52. package/src/native/loader.ts +52 -6
  53. package/src/native/types/instances.ts +274 -0
  54. package/src/native/types.ts +41 -238
  55. package/src/runtime/builtins.ts +131 -0
  56. package/src/runtime/codec.ts +147 -0
  57. package/src/runtime/detect.ts +36 -0
  58. package/src/runtime/index.ts +28 -0
  59. package/src/runtime/native.ts +35 -0
  60. package/src/runtime/server.ts +31 -0
  61. package/src/runtime/transport.ts +64 -0
  62. package/src/runtime/types.ts +173 -0
  63. package/src/runtime/uuid.ts +45 -0
  64. package/src/runtime/websocket.ts +30 -0
  65. package/src/rust-ffi/addon.ts +1 -1
  66. package/src/rust-ffi/batch/build.ts +155 -0
  67. package/src/rust-ffi/batch/index.ts +8 -0
  68. package/src/rust-ffi/batch/types.ts +92 -0
  69. package/src/rust-ffi/client.ts +5 -6
  70. package/src/rust-ffi/context.ts +39 -10
  71. package/src/rust-ffi/index.ts +28 -17
  72. package/src/rust-ffi/into.ts +21 -0
  73. package/src/rust-ffi/options.ts +1 -1
  74. package/src/rust-ffi/packed.ts +2 -2
  75. package/src/rust-ffi/proven.ts +16 -30
  76. package/src/rust-ffi/scalar/crypto.ts +188 -107
  77. package/src/rust-ffi/scalar/factories.ts +253 -27
  78. package/src/rust-ffi/scalar/hashing.ts +43 -41
  79. package/src/rust-ffi/scalar/http.ts +208 -77
  80. package/src/rust-ffi/scalar/index.ts +3 -3
  81. package/src/rust-ffi/scalar/interface.ts +88 -213
  82. package/src/rust-ffi/scalar/json-packed.ts +175 -0
  83. package/src/rust-ffi/scalar/json.ts +28 -12
  84. package/src/rust-ffi/scalar/payload.ts +159 -42
  85. package/src/rust-ffi/text.ts +31 -5
  86. package/src/selection.ts +27 -31
  87. package/src/shared/adaptive.ts +1 -2
  88. package/src/shared/buffer-pool.ts +72 -17
  89. package/src/shared/bytes.ts +75 -6
  90. package/src/shared/codec.ts +78 -0
  91. package/src/shared/env.ts +4 -4
  92. package/src/shared/log.ts +1 -0
  93. package/src/shared/packed/index.ts +10 -0
  94. package/src/shared/packed/parsers.ts +31 -0
  95. package/src/shared/packed/schema.ts +23 -0
  96. package/src/shared/{packed.ts → packed/wire.ts} +31 -39
  97. package/src/shared/proven.ts +189 -496
  98. package/src/shared/runtime.ts +20 -25
  99. package/src/shared/uuid.ts +12 -28
  100. package/src/data/json-rows.ts +0 -33
  101. package/src/rust-ffi/batch.ts +0 -431
  102. package/src/shared/bench-classify.ts +0 -209
@@ -1,230 +1,139 @@
1
1
  // src/rust-ffi/scalar/interface.ts — The `RustScalar` method surface.
2
2
  //
3
- // One file per public method (with its perf JSDoc, written by
4
- // `scripts/annotate-performance.ts`). The implementation is split into domain
3
+ // One file per public method. The implementation is split into domain
5
4
  // builders (hashing, json, http, crypto, payload, factories) composed by
6
5
  // `buildScalar` in index.ts.
7
6
 
8
7
  import type {
9
- HmacSignerInstance,
10
- SchemaValidatorInstance,
11
- TemplateRendererInstance,
12
- FormParserInstance,
13
- MediaTypeParserInstance,
14
- MediaTypeResult,
15
- MediaTypeMatcherInstance,
16
- ConditionalRequestInstance,
17
- EncodingPrefResult,
18
8
  AcceptNegotiatorInstance,
9
+ AeadCipherInstance,
10
+ Argon2HasherInstance,
19
11
  Base64CodecInstance,
12
+ ConditionalRequestInstance,
20
13
  CookieSignerInstance,
21
14
  CsrfProtectorInstance,
22
- UrlBuilderInstance,
15
+ EncodingPrefResult,
16
+ FormParserInstance,
17
+ HmacSignerInstance,
23
18
  JwtSignerInstance,
24
- AeadCipherInstance,
25
- Argon2HasherInstance,
26
- RateLimiterInstance,
19
+ MediaTypeMatcherInstance,
20
+ MediaTypeParserInstance,
21
+ MediaTypeResult,
27
22
  MultipartPart,
28
- WsFrame,
29
23
  PasswordHashOptions,
24
+ RateLimiterInstance,
25
+ SchemaValidatorInstance,
26
+ TemplateRendererInstance,
27
+ UrlBuilderInstance,
28
+ WsFrame,
30
29
  } from '../../native'
31
30
 
32
- /** Scalar + factory + runtime methods of the Rust client. */
31
+ /**
32
+ * The flat `rust.*` scalar method surface: bytes in → normalized out. Built by
33
+ * the scalar builders from the native addon + Bun built-in delegations.
34
+ */
33
35
  export interface RustScalar {
34
36
  // ── Scalar utilities (bytes in → normalized out) ──
35
- /**
36
- * @performance CRC32: ~3.7x slower than the JS baseline (2/3 tasks failed) [check:annotate]
37
- * @deprecated Slower than the native JS baseline (~3.7x) — prefer the JS/Bun baseline. [check:annotate]
38
- * @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]
39
- */
40
37
  crc32(input: Uint8Array): number
41
- /**
42
- * @performance FNV-1a 64: ~6.6x faster than the JS baseline [check:annotate]
43
- */
44
38
  fnv1a64(input: Uint8Array): bigint
45
39
  /**
46
40
  * XXH3-64 over raw bytes (high-throughput non-cryptographic hash).
47
41
  * Compare against `Bun.hash.xxHash3` — see docs/bun-builtins-decision-matrix.md.
48
42
  */
49
43
  xxh3(input: Uint8Array): bigint
50
- /**
51
- * @performance HMAC sign: ~1.1x faster than the JS baseline (2/3 tasks won) [check:annotate]
52
- */
53
- hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array
54
- /**
55
- * @performance HMAC verify: ~2.5x faster than the JS baseline [check:annotate]
56
- */
57
- hmacSha256Verify(key: Uint8Array, data: Uint8Array, sig: Uint8Array): boolean
58
- /**
59
- * @performance JSON valid: ~3.2x faster than the JS baseline (8/8 tasks won) [check:annotate]
60
- */
44
+ hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array | string
45
+ hmacSha256Verify(key: Uint8Array, data: Uint8Array, sig: Uint8Array | string): boolean
61
46
  jsonValid(input: Uint8Array): boolean
62
47
  /**
63
- * Parse JSON to a JS value (native sonic-rs DOM → napi). Throws on invalid JSON.
64
- * @performance JSON parse: ~5.0x slower than the JS baseline [check:annotate]
65
- * @deprecated Slower than the native JS baseline (~5.0x) — prefer the JS/Bun baseline. [check:annotate]
66
- * @remarks Bun's JSON.parse beats the native DOM + napi marshaling path (~5x). [check:annotate]
48
+ * Parse JSON to a JS value (FFI packed structural parse on Bun — sonic-rs
49
+ * parses ONCE, JS assembles from a token stream with no re-parse; napi
50
+ * sonic-rs DOM fallback). Throws on invalid JSON.
67
51
  */
68
52
  jsonParse(input: Uint8Array): unknown
69
- /**
70
- * @performance JSON sum: ~2.9x faster than the JS baseline (4/4 tasks won) [check:annotate]
71
- */
72
53
  jsonSumIds(input: Uint8Array): bigint
54
+ jsonPatch(doc: Uint8Array, patch: Uint8Array): Uint8Array | string
55
+ mimeFromExtension(ext: Uint8Array): Uint8Array | string
56
+ randomToken(byteLen: number): Uint8Array | string
57
+ randomTokenInto(byteLen: number, output: Uint8Array): number
58
+ urlEncode(input: Uint8Array): Uint8Array | string
59
+ urlDecode(input: Uint8Array): Uint8Array
73
60
  /**
74
- * @performance JSON Patch: ~1.2x faster than the JS baseline [check:annotate]
75
- * @remarks Modest but real win; swings ~0.9-1.5x run-to-run (DOM marshal dominated). [check:annotate]
76
- */
77
- jsonPatch(doc: Uint8Array, patch: Uint8Array): Uint8Array
78
- /**
79
- * @performance MIME lookup: ≈ parity with the JS baseline [check:annotate]
80
- * @remarks Noisy sub-µs op: wins ~1.6x on good runs, loses on bad runs; phf table lookup. [check:annotate]
81
- */
82
- mimeFromExtension(ext: Uint8Array): Uint8Array
83
- /**
84
- * @performance Random token: ≈ parity with the JS baseline [check:annotate]
85
- */
86
- randomToken(byteLen: number): Uint8Array
87
- /**
88
- * @performance URL encode: ~2.2x slower than the JS baseline (2/3 tasks failed) [check:annotate]
89
- * @deprecated Slower than the native JS baseline (~2.2x) — prefer the JS/Bun baseline. [check:annotate]
90
- * @remarks Loses ~2.8x on the shipped baseline release build (only wins in the LOCAL SIMD perf build). [check:annotate]
91
- */
92
- urlEncode(input: Uint8Array): Uint8Array
93
- /**
94
- * @performance URL decode: ~2.2x slower than the JS baseline (2/3 tasks failed) [check:annotate]
95
- * @deprecated Slower than the native JS baseline (~2.2x) — prefer the JS/Bun baseline. [check:annotate]
96
- * @remarks Loses ~2.8x on the shipped baseline release build (only wins in the LOCAL SIMD perf build). [check:annotate]
61
+ * Strict percent-decode without UTF-8 validation.
97
62
  */
98
- urlDecode(input: Uint8Array): Uint8Array
99
- /** Strict percent-decode without UTF-8 validation. */
100
63
  urlDecodeBytes(input: Uint8Array): Uint8Array
101
- /** Reusable-output percent-encode; returns bytes written. */
102
64
  urlEncodeInto(input: Uint8Array, output: Uint8Array): number
103
- /** Reusable-output percent-decode; returns bytes written. */
104
65
  urlDecodeInto(input: Uint8Array, output: Uint8Array): number
105
- /**
106
- * @performance Email validation: ~3.1x faster than the JS baseline (4/4 tasks won) [check:annotate]
107
- */
108
66
  validateEmail(input: Uint8Array): boolean
109
- /**
110
- * @performance UUID validation: ≈ parity with the JS baseline (2/4 tasks won) [check:annotate]
111
- */
112
67
  validateUuid(input: Uint8Array): boolean
113
- /**
114
- * @performance IPv4 validation: ≈ parity with the JS baseline (2/2 tasks won) [check:annotate]
115
- */
116
68
  validateIpv4(input: Uint8Array): boolean
117
- /**
118
- * @performance IPv6 validation: ~1.9x faster than the JS baseline [check:annotate]
119
- */
120
69
  validateIpv6(input: Uint8Array): boolean
121
- /**
122
- * @performance WebSocket accept: ~1.9x faster than the JS baseline (1/2 tasks won) [check:annotate]
123
- */
124
- wsAcceptKey(key: Uint8Array): Uint8Array
70
+ wsAcceptKey(key: Uint8Array): Uint8Array | string
71
+ wsAcceptKeyInto(key: Uint8Array, output: Uint8Array): number
125
72
 
126
73
  // ── Low-level / packed scalar ──
127
- /**
128
- * @performance HTTP parse: ~5.3x faster than the JS baseline (6/6 tasks won) [check:annotate]
129
- */
130
74
  httpParseRequestPacked(input: Uint8Array): Uint8Array
131
- /**
132
- * @performance Query parse: ~3.8x faster than the JS baseline (6/6 tasks won) [check:annotate]
133
- */
134
75
  queryParsePacked(input: Uint8Array): Uint8Array
135
- /**
136
- * @performance Cookie parse: ~2.6x faster than the JS baseline (5/5 tasks won) [check:annotate]
137
- */
138
76
  cookieParsePacked(input: Uint8Array): Uint8Array
139
- /** Reusable-output packed HTTP parse; returns bytes written. */
140
77
  httpParseRequestPackedInto(input: Uint8Array, output: Uint8Array): number
141
- /** Reusable-output packed query parse; returns bytes written. */
142
78
  queryParsePackedInto(input: Uint8Array, output: Uint8Array): number
143
- /** Reusable-output packed cookie parse; returns bytes written. */
144
79
  cookieParsePackedInto(input: Uint8Array, output: Uint8Array): number
145
80
  /**
146
81
  * Parse an application/x-www-form-urlencoded body into packed pairs.
147
- * @performance Form parse: ~4.7x faster than the JS baseline (2/2 tasks won) [check:annotate]
148
- * @remarks Benchmarked via the FormParser instance (same parser core). [check:annotate]
149
82
  */
150
83
  formParsePacked(input: Uint8Array): Uint8Array
84
+ formParsePackedInto(input: Uint8Array, output: Uint8Array): number
151
85
  /**
152
86
  * Parse a Content-Type header into a structured media type.
153
- * @performance Media type parse: ~1.3x slower than the JS baseline [check:annotate]
154
- * @deprecated Slower than the native JS baseline (~1.3x) — prefer the JS/Bun baseline. [check:annotate]
155
- * @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]
156
87
  */
157
88
  parseMediaType(input: Uint8Array): MediaTypeResult
158
89
  /**
159
90
  * Generate a strong/weak ETag (crc32-based).
160
- * @performance ETag: ≈ parity with the JS baseline [check:annotate]
161
91
  */
162
- etag(data: Uint8Array, weak?: boolean): Uint8Array
163
- /** Reusable-output etag; returns bytes written (10 strong / 12 weak). */
92
+ etag(data: Uint8Array, weak?: boolean): Uint8Array | string
164
93
  etagInto(data: Uint8Array, output: Uint8Array, weak?: boolean): number
165
94
  /**
166
95
  * Format a unix timestamp as an IMF-fixdate HTTP-date.
167
- * @performance HTTP date: ~1.5x slower than the JS baseline (2/2 tasks failed) [check:annotate]
168
- * @deprecated Slower than the native JS baseline (~1.5x) — prefer the JS/Bun baseline. [check:annotate]
169
- * @remarks Date.toUTCString() is native (~1.5-1.7x loss); pooled httpDateInto cuts it to ~1.3x. [check:annotate]
170
96
  */
171
- httpDate(secs?: number): Uint8Array
172
- /** Reusable-output http-date; returns bytes written (29). Throws if `output` is too small or the year is out of the fixed-width range. */
97
+ httpDate(secs?: number): Uint8Array | string
173
98
  httpDateInto(secs: number | undefined, output: Uint8Array): number
174
- /** Parse an IMF-fixdate HTTP-date back to unix seconds. */
175
99
  parseHttpDate(input: Uint8Array): bigint | null
176
- /** Parse an Accept-Encoding header into ordered preferences. */
177
100
  parseAcceptEncoding(input: Uint8Array): EncodingPrefResult[]
178
101
  /**
179
102
  * Base64 encode (standard by default; url-safe/padding configurable).
180
- * @performance Base64 encode: ~1.6x slower than the JS baseline [check:annotate]
181
- * @deprecated Slower than the native JS baseline (~1.6x) — prefer the JS/Bun baseline. [check:annotate]
182
- * @remarks Bun Buffer base64 is SIMD; loses ~1.5x. [check:annotate]
183
103
  */
184
- base64Encode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array
104
+ base64Encode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array | string
185
105
  /**
186
106
  * Base64 decode (standard); throws on invalid input.
187
- * @performance Base64 decode: ≈ parity with the JS baseline [check:annotate]
188
107
  */
189
108
  base64Decode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array
190
- /** Reusable-output base64 encode; returns bytes written. */
191
109
  base64EncodeInto(
192
110
  input: Uint8Array,
193
111
  output: Uint8Array,
194
112
  urlSafe?: boolean,
195
113
  padding?: boolean,
196
114
  ): number
197
- /** Reusable-output base64 decode; returns bytes written. Throws on invalid input. */
198
115
  base64DecodeInto(
199
116
  input: Uint8Array,
200
117
  output: Uint8Array,
201
118
  urlSafe?: boolean,
202
119
  padding?: boolean,
203
120
  ): number
204
- base64UrlEncode(input: Uint8Array): Uint8Array
121
+ base64UrlEncode(input: Uint8Array): Uint8Array | string
205
122
  base64UrlDecode(input: Uint8Array): Uint8Array
206
123
  /**
207
124
  * Lowercase hex encode.
208
- * @performance Hex encode: ~1.4x slower than the JS baseline (1/2 tasks failed) [check:annotate]
209
- * @deprecated Slower than the native JS baseline (~1.4x) — prefer the JS/Bun baseline. [check:annotate]
210
- * @remarks Buffer.toString('hex') is native SIMD; pooled hexEncodeInto cuts the loss from ~2.2x to ~1.35x. [check:annotate]
211
125
  */
212
- hexEncode(input: Uint8Array): Uint8Array
126
+ hexEncode(input: Uint8Array): Uint8Array | string
213
127
  /**
214
128
  * Hex decode; throws on odd length or invalid digits.
215
- * @performance Hex decode: ≈ parity with the JS baseline [check:annotate]
216
- * @remarks Slightly slower than Buffer hex decode (~1.3x). [check:annotate]
217
129
  */
218
130
  hexDecode(input: Uint8Array): Uint8Array
219
- /** Reusable-output lowercase-hex encode; returns bytes written. */
220
131
  hexEncodeInto(input: Uint8Array, output: Uint8Array): number
221
- /** Reusable-output hex decode; returns bytes written. Throws on bad input. */
222
132
  hexDecodeInto(input: Uint8Array, output: Uint8Array): number
223
- /** Reusable-output HMAC-SHA256 hex (64 bytes); returns bytes written. Throws on too-small buffer. */
224
133
  hmacSha256Into(key: Uint8Array, data: Uint8Array, output: Uint8Array): number
225
- /** Reusable-output cookie sign (`value.<64-hex>`); returns bytes written. Throws on too-small buffer. */
226
134
  signCookieInto(value: Uint8Array, secret: Uint8Array, output: Uint8Array): number
227
- /** Reusable-output AEAD encrypt (ct + 16-byte tag); returns bytes written. Throws on too-small buffer. */
135
+ verifyCookieInto(signed: Uint8Array, secret: Uint8Array, output: Uint8Array): number | null
136
+ csrfTokenInto(secret: Uint8Array, output: Uint8Array): number
228
137
  aeadEncryptInto(
229
138
  key: Uint8Array,
230
139
  nonce: Uint8Array,
@@ -232,7 +141,6 @@ export interface RustScalar {
232
141
  output: Uint8Array,
233
142
  algorithm?: string | null,
234
143
  ): number
235
- /** Reusable-output WS frame encode; returns bytes written. Throws on too-small buffer. */
236
144
  wsFrameEncodeInto(
237
145
  opcode: number,
238
146
  payload: Uint8Array,
@@ -240,61 +148,41 @@ export interface RustScalar {
240
148
  fin: boolean,
241
149
  output: Uint8Array,
242
150
  ): number
243
- /** Reusable-output gzip compress; returns bytes written. Throws on too-small buffer. */
244
151
  gzipCompressInto(data: Uint8Array, output: Uint8Array, level?: number | null): number
245
- /** Reusable-output brotli compress; returns bytes written. Throws on too-small buffer. */
246
152
  brotliCompressInto(data: Uint8Array, output: Uint8Array, quality?: number | null): number
247
153
  /**
248
154
  * Sign a cookie value as `value.signature` (HMAC-SHA256 hex).
249
- * @performance Cookie sign: ~1.0x faster than the JS baseline [check:annotate]
250
155
  */
251
- signCookie(value: Uint8Array, secret: Uint8Array): Uint8Array
156
+ signCookie(value: Uint8Array, secret: Uint8Array): Uint8Array | string
252
157
  /**
253
158
  * Verify a signed cookie; returns the value or null.
254
- * @performance Cookie verify: ~9.5x faster than the JS baseline [check:annotate]
255
159
  */
256
- verifyCookie(signed: Uint8Array, secret: Uint8Array): Uint8Array | null
160
+ verifyCookie(signed: Uint8Array, secret: Uint8Array): Uint8Array | string | null
257
161
  /**
258
162
  * Create a CSRF token (32-byte random hex + HMAC signature).
259
- * @performance CSRF create: ~13.7x faster than the JS baseline [check:annotate]
260
163
  */
261
- csrfToken(secret: Uint8Array): Uint8Array
164
+ csrfToken(secret: Uint8Array): Uint8Array | string
262
165
  /**
263
166
  * Constant-time verify a CSRF token.
264
- * @performance CSRF verify: ~3.3x faster than the JS baseline [check:annotate]
265
167
  */
266
168
  csrfVerify(token: Uint8Array, secret: Uint8Array): boolean
267
169
  /**
268
170
  * Resolve a URL reference against a base (RFC 3986).
269
- * @performance URL resolve: ~1.8x slower than the JS baseline [check:annotate]
270
- * @deprecated Slower than the native JS baseline (~1.8x) — prefer the JS/Bun baseline. [check:annotate]
271
- * @remarks Auto-deprecated: 1/1 benchmarks failed in the latest run (static classification was parity). [check:annotate]
272
- * @remarks Noisy ~1.5µs op; swings 0.74-1.03x run-to-run. UrlBuilder reuses the parsed base. [check:annotate]
273
171
  */
274
- urlResolve(base: Uint8Array, reference: Uint8Array): Uint8Array
172
+ urlResolve(base: Uint8Array, reference: Uint8Array): Uint8Array | string
275
173
  /**
276
174
  * Build a percent-encoded query string from params (sorted keys).
277
- * @performance URL query build: ~1.4x slower than the JS baseline [check:annotate]
278
- * @deprecated Slower than the native JS baseline (~1.4x) — prefer the JS/Bun baseline. [check:annotate]
279
- * @remarks encodeURIComponent baseline wins (~1.2-1.35x). [check:annotate]
280
175
  */
281
- urlEncodeQuery(params: Record<string, string>): Uint8Array
176
+ urlEncodeQuery(params: Record<string, string>): Uint8Array | string
282
177
 
283
178
  // ── Factories / runtime ──
284
- /**
285
- * @performance JSON schema validate: ~1.7x faster than the JS baseline (2/2 tasks won) [check:annotate]
286
- * @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]
287
- */
288
179
  createSchemaValidator(schema: Uint8Array): SchemaValidatorInstance
289
180
  createHmacSigner(key: Uint8Array): HmacSignerInstance
290
181
  createTemplateRenderer(source: string): TemplateRendererInstance
291
- /** Higher-order form parser: owns a reusable output buffer (setup once). */
292
182
  createFormParser(capacity?: number): FormParserInstance
293
- /** Higher-order media-type parser: reusable wildcard matcher. */
294
183
  createMediaTypeParser(): MediaTypeParserInstance
295
184
  /**
296
185
  * Higher-order conditional-request check: per-resource 304 decision (setup once).
297
- * @performance Conditional request: ~1.7x faster than the JS baseline [check:annotate]
298
186
  */
299
187
  createConditionalRequest(
300
188
  etagValue: Uint8Array,
@@ -302,24 +190,15 @@ export interface RustScalar {
302
190
  ): ConditionalRequestInstance
303
191
  /**
304
192
  * Higher-order negotiator: precompiles supported encodings once.
305
- * @performance Accept-Encoding negotiate: ~4.2x faster than the JS baseline [check:annotate]
306
193
  */
307
194
  createAcceptNegotiator(supported: string[]): AcceptNegotiatorInstance
308
- /** Higher-order codec: base64 config compiled once. */
309
195
  createBase64Codec(urlSafe?: boolean, padding?: boolean): Base64CodecInstance
310
- /** Higher-order cookie signer: HMAC key compiled once. */
311
196
  createCookieSigner(secret: Uint8Array): CookieSignerInstance
312
- /** Higher-order CSRF protector: HMAC key compiled once. */
313
197
  createCsrfProtector(secret: Uint8Array): CsrfProtectorInstance
314
- /** Higher-order URL builder: base parsed once, reused. */
315
198
  createUrlBuilder(base: Uint8Array): UrlBuilderInstance
316
- /** Higher-order JWT signer: HS256 key + ttl compiled once. */
317
199
  createJwtSigner(secret: Uint8Array, ttlSeconds?: number): JwtSignerInstance
318
- /** Higher-order AEAD cipher: algorithm + key compiled once. */
319
200
  createAeadCipher(key: Uint8Array, algorithm?: string): AeadCipherInstance
320
- /** Higher-order argon2id hasher: params compiled once. */
321
201
  createArgon2Hasher(options?: PasswordHashOptions | null): Argon2HasherInstance
322
- /** Higher-order media-type matcher: expected precompiled once. */
323
202
  createMediaTypeMatcher(expected: Uint8Array): MediaTypeMatcherInstance
324
203
  /**
325
204
  * Sharded fixed-window per-key rate limiter. `maxEntries` clamps internally
@@ -337,11 +216,6 @@ export interface RustScalar {
337
216
  rayonNumThreads(): number
338
217
 
339
218
  // ── Backend-framework scalar features ──
340
- /**
341
- * @performance JWT sign: ~1.1x slower than the JS baseline [check:annotate]
342
- * @deprecated Slower than the native JS baseline (~1.1x) — prefer the JS/Bun baseline. [check:annotate]
343
- * @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]
344
- */
345
219
  jwtSign(
346
220
  claims: Record<string, unknown>,
347
221
  secret: Uint8Array,
@@ -352,99 +226,100 @@ export interface RustScalar {
352
226
  * Sign a JWT from pre-serialized claim JSON bytes — skips the napi
353
227
  * `serde_json::Value` marshal of `jwtSign` for callers that already hold the
354
228
  * bytes (same injection semantics).
355
- * @performance JWT sign (bytes): ≈ parity with the JS baseline [check:annotate]
356
- * @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]
357
229
  */
358
230
  jwtSignBytes(
359
231
  claimsJson: Uint8Array,
360
232
  secret: Uint8Array,
361
233
  ttlSeconds?: number | null,
362
234
  nowSeconds?: number,
363
- ): Uint8Array
364
- /**
365
- * @performance JWT verify: ~1.7x faster than the JS baseline (2/2 tasks won) [check:annotate]
366
- */
235
+ ): Uint8Array | string
236
+ jwtSignBytesInto(
237
+ claimsJson: Uint8Array,
238
+ secret: Uint8Array,
239
+ output: Uint8Array,
240
+ ttlSeconds?: number | null,
241
+ nowSeconds?: number,
242
+ ): number
367
243
  jwtVerify(token: Uint8Array, secret: Uint8Array, nowSeconds?: number): unknown
368
- /**
369
- * @performance Password hash: ~18.2x faster than the JS baseline (2/2 tasks won) [check:annotate]
370
- * @remarks argon2id vs node:crypto scrypt. [check:annotate]
371
- */
372
244
  passwordHash(
373
245
  password: Uint8Array,
374
246
  salt: Uint8Array,
375
247
  options?: PasswordHashOptions | null,
376
- ): Uint8Array
248
+ ): Uint8Array | string
377
249
  passwordVerify(password: Uint8Array, phc: Uint8Array): boolean
378
- /** bcrypt password hash → `$2b$` PHC string (cost clamped 4..=31). */
250
+ /**
251
+ * bcrypt password hash → `$2b$` PHC string (cost clamped 4..=31).
252
+ */
379
253
  passwordHashBcrypt(password: Uint8Array, cost: number): string
380
- /** Verify a password against a bcrypt `$2b$` PHC string. */
254
+ /**
255
+ * Verify a password against a bcrypt `$2b$` PHC string.
256
+ */
381
257
  passwordVerifyBcrypt(password: Uint8Array, hash: string): boolean
382
- /** PBKDF2-HMAC-SHA256 key derivation (dkLen clamped to 1 MiB). */
383
- pbkdf2Sha256(password: Uint8Array, salt: Uint8Array, rounds: number, dkLen: number): Uint8Array
384
258
  /**
385
- * @performance AEAD encrypt: ~1.3x faster than the JS baseline [check:annotate]
259
+ * PBKDF2-HMAC-SHA256 key derivation (dkLen clamped to 1 MiB).
386
260
  */
261
+ pbkdf2Sha256(password: Uint8Array, salt: Uint8Array, rounds: number, dkLen: number): Uint8Array
387
262
  aeadEncrypt(
388
263
  key: Uint8Array,
389
264
  nonce: Uint8Array,
390
265
  plaintext: Uint8Array,
391
266
  algorithm?: string | null,
392
267
  ): Uint8Array
393
- /**
394
- * @performance AEAD decrypt: ~1.4x faster than the JS baseline [check:annotate]
395
- */
396
268
  aeadDecrypt(
397
269
  key: Uint8Array,
398
270
  nonce: Uint8Array,
399
271
  ciphertext: Uint8Array,
400
272
  algorithm?: string | null,
401
273
  ): Uint8Array | null
402
- /**
403
- * @performance Gzip compress: ≈ parity with the JS baseline (1/2 tasks won) [check:annotate]
404
- */
405
274
  gzipCompress(data: Uint8Array, level?: number | null): Uint8Array
406
275
  /**
407
- * @performance Gzip decompress: ~1.0x faster than the JS baseline [check:annotate]
408
- * @remarks zlib-rs vs node zlib; swings 1.0-1.4x run-to-run. [check:annotate]
409
276
  * @param maxDecompressed Caps decompressed output (default 64 MiB) as a
410
277
  * decompression-bomb guard; a larger value errors.
411
278
  */
412
279
  gzipDecompress(data: Uint8Array, maxDecompressed?: number | null): Uint8Array
413
280
  /**
414
- * @performance Brotli compress: ~1.7x slower than the JS baseline [check:annotate]
415
- * @deprecated Slower than the native JS baseline (~1.7x) — prefer the JS/Bun baseline. [check:annotate]
416
- * @remarks The native brotli baseline wins for small inputs. [check:annotate]
281
+ * gzip-decompress into `output` (pooled — caller-owned buffer); returns bytes
282
+ * written. Throws when `output` is too small (the exact required size is
283
+ * reported) or the input is invalid / exceeds `maxDecompressed`.
284
+ * @param maxDecompressed Caps decompressed output (default 64 MiB) as a
285
+ * decompression-bomb guard; a larger value errors.
417
286
  */
287
+ gzipDecompressInto(data: Uint8Array, output: Uint8Array, maxDecompressed?: number | null): number
418
288
  brotliCompress(data: Uint8Array, quality?: number | null): Uint8Array
419
289
  /**
420
- * @performance Brotli decompress: ~1.4x slower than the JS baseline [check:annotate]
421
- * @deprecated Slower than the native JS baseline (~1.4x) — prefer the JS/Bun baseline. [check:annotate]
422
- * @remarks Auto-deprecated: 1/1 benchmarks failed in the latest run (static classification was proven). [check:annotate]
423
290
  * @param maxDecompressed Caps decompressed output (default 64 MiB) as a
424
291
  * decompression-bomb guard; a larger value errors.
425
292
  */
426
293
  brotliDecompress(data: Uint8Array, maxDecompressed?: number | null): Uint8Array
427
294
  /**
428
- * @performance Multipart parse: ~1.9x faster than the JS baseline [check:annotate]
295
+ * brotli-decompress into `output` (pooled — caller-owned buffer); returns
296
+ * bytes written. Throws when `output` is too small (the exact required size
297
+ * is reported) or the input is invalid / exceeds `maxDecompressed`.
298
+ * @param maxDecompressed Caps decompressed output (default 64 MiB) as a
299
+ * decompression-bomb guard; a larger value errors.
429
300
  */
301
+ brotliDecompressInto(
302
+ data: Uint8Array,
303
+ output: Uint8Array,
304
+ maxDecompressed?: number | null,
305
+ ): number
430
306
  multipartParse(body: Uint8Array, boundary: Uint8Array): MultipartPart[]
431
- /** Zero-copy packed sibling of `multipartParse` (packed parts layout). */
432
307
  multipartParsePacked(body: Uint8Array, boundary: Uint8Array): Uint8Array
433
- /**
434
- * @performance WS frame encode: ~2.0x faster than the JS baseline [check:annotate]
435
- */
308
+ multipartParsePackedInto(body: Uint8Array, boundary: Uint8Array, output: Uint8Array): number
436
309
  wsFrameEncode(opcode: number, payload: Uint8Array, mask: boolean, fin: boolean): Uint8Array
437
- /**
438
- * @performance WS frame decode: ~2.3x faster than the JS baseline [check:annotate]
439
- */
440
310
  wsFrameDecode(data: Uint8Array): WsFrame | null
441
- /**
442
- * @performance SSE encode: ≈ parity with the JS baseline [check:annotate]
443
- */
311
+ wsFrameDecodePackedInto(data: Uint8Array, output: Uint8Array): number | null
444
312
  sseEncodeEvent(
445
313
  event: string | null,
446
314
  data: Uint8Array,
447
315
  id: string | null,
448
316
  retry: number | null,
449
317
  ): Uint8Array
318
+ sseEncodeEventInto(
319
+ event: string | null,
320
+ data: Uint8Array,
321
+ id: string | null,
322
+ retry: number | null,
323
+ output: Uint8Array,
324
+ ): number
450
325
  }