castrum 0.7.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +154 -368
- package/castrum.linux-x64-gnu.node +0 -0
- package/dist/index.d.ts +2763 -0
- package/dist/index.js +8707 -0
- package/docs/API.md +337 -0
- package/docs/ARCHITECTURE.md +507 -0
- package/docs/BENCHMARKS.md +343 -0
- package/docs/CASE_STUDY.md +240 -0
- package/docs/ENVIRONMENT.md +81 -0
- package/docs/FFI_BUN_GUIDE.md +327 -0
- package/docs/GETTING_STARTED.md +192 -0
- package/docs/INGRESS-ROUTER.md +81 -0
- package/docs/INGRESS.md +746 -0
- package/docs/NATIVE-ROUTE.md +53 -0
- package/docs/REPO_MAP.md +279 -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 +43 -0
- package/docs/bun-builtins-decision-matrix.md +115 -0
- package/index.ts +44 -8
- package/package.json +98 -33
- package/src/ingress/body.ts +289 -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 +639 -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 +68 -0
- package/src/ingress/index.ts +142 -405
- package/src/ingress/metrics.ts +132 -0
- package/src/ingress/options.ts +197 -0
- package/src/ingress/packing/gather-raw-headers.ts +139 -0
- package/src/ingress/packing/header-packing.ts +75 -0
- package/src/ingress/packing/input-packer.ts +164 -0
- package/src/ingress/packing/scratch.ts +50 -0
- package/src/ingress/packing/select-headers.ts +102 -0
- package/src/ingress/response/error-bodies.ts +75 -0
- package/src/ingress/response/terminal.ts +59 -0
- package/src/ingress/router.ts +237 -0
- package/src/ingress/routes/common.ts +79 -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 +27 -0
- package/src/ingress/routes/index.ts +11 -0
- package/src/ingress/routes/json-write.ts +129 -0
- package/src/ingress/routes/options.ts +26 -0
- package/src/ingress/routes/read.ts +35 -0
- package/src/ingress/routes/responder.ts +159 -0
- package/src/ingress/server-node.ts +376 -0
- package/src/ingress/server.ts +475 -0
- package/src/ingress/shared.ts +132 -0
- package/src/ingress/status.ts +97 -0
- package/src/ingress/types.ts +191 -0
- package/src/integration/batch.ts +58 -0
- package/src/integration/index.ts +29 -0
- package/src/integration/pipeline.ts +220 -0
- package/src/integration/streaming.ts +78 -0
- package/src/integration/websocket.ts +93 -0
- package/src/loader/batch.ts +137 -0
- package/src/loader/cost.ts +105 -0
- package/src/loader/index.ts +745 -0
- package/src/loader/ops.ts +657 -0
- package/src/loader/state.ts +84 -0
- package/src/loader/types.ts +145 -0
- package/src/native/ffi/constants.ts +58 -0
- package/src/native/ffi/selftest.ts +729 -0
- package/src/native/ffi/types.ts +474 -0
- package/src/native/ffi.ts +1775 -0
- package/src/native/index.ts +8 -207
- package/src/native/loader.ts +240 -0
- package/src/native/types/instances.ts +274 -0
- package/src/native/types.ts +401 -0
- package/src/runtime/builtins.ts +131 -0
- package/src/runtime/codec.ts +147 -0
- package/src/runtime/detect.ts +36 -0
- package/src/runtime/index.ts +28 -0
- package/src/runtime/native.ts +35 -0
- package/src/runtime/server.ts +31 -0
- package/src/runtime/transport.ts +64 -0
- package/src/runtime/types.ts +173 -0
- package/src/runtime/uuid.ts +45 -0
- package/src/runtime/websocket.ts +30 -0
- package/src/rust-ffi/addon.ts +10 -0
- package/src/rust-ffi/batch/build.ts +155 -0
- package/src/rust-ffi/batch/index.ts +8 -0
- package/src/rust-ffi/batch/types.ts +92 -0
- package/src/rust-ffi/client.ts +87 -0
- package/src/rust-ffi/context.ts +193 -0
- package/src/rust-ffi/index.ts +51 -541
- package/src/rust-ffi/into.ts +21 -0
- package/src/rust-ffi/options.ts +113 -0
- package/src/rust-ffi/packed.ts +253 -0
- package/src/rust-ffi/proven.ts +28 -0
- package/src/rust-ffi/scalar/crypto.ts +346 -0
- package/src/rust-ffi/scalar/factories.ts +459 -0
- package/src/rust-ffi/scalar/hashing.ts +74 -0
- package/src/rust-ffi/scalar/http.ts +337 -0
- package/src/rust-ffi/scalar/index.ts +31 -0
- package/src/rust-ffi/scalar/interface.ts +325 -0
- package/src/rust-ffi/scalar/json-packed.ts +175 -0
- package/src/rust-ffi/scalar/json.ts +61 -0
- package/src/rust-ffi/scalar/payload.ts +241 -0
- package/src/rust-ffi/text.ts +121 -0
- package/src/selection.json +194 -0
- package/src/selection.ts +73 -0
- package/src/shared/adaptive.ts +67 -0
- package/src/shared/buffer-pool.ts +264 -0
- package/src/shared/bytes.ts +108 -9
- package/src/shared/codec.ts +78 -0
- package/src/shared/env.ts +20 -0
- package/src/shared/log.ts +75 -0
- package/src/shared/metrics.ts +247 -0
- package/src/shared/packed/index.ts +10 -0
- package/src/shared/packed/parsers.ts +31 -0
- package/src/shared/packed/schema.ts +23 -0
- package/src/shared/packed/wire.ts +504 -0
- package/src/shared/proven.ts +289 -0
- package/src/shared/request-id.ts +67 -0
- package/src/shared/response.ts +104 -0
- package/src/shared/runtime.ts +29 -0
- package/src/shared/trace.ts +81 -0
- package/src/shared/uuid.ts +15 -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/data/json-rows.ts +0 -33
- package/src/ingress/packed-input.ts +0 -59
- package/src/shared/json.ts +0 -18
- package/src/shared/packed.ts +0 -316
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
// src/native/ffi/types.ts — bun:ffi C-ABI type surface (pure types).
|
|
2
|
+
//
|
|
3
|
+
// The bound-function contract (`BunFFI`), the transport selection
|
|
4
|
+
// (`FfiMode`), and the raw `(ptr,len)` symbol signatures (`Raw2..Raw10`)
|
|
5
|
+
// used by the transport core. No runtime code — erased at compile time.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The bound bun:ffi C-ABI surface. Each member is a dlopen'd `castrum_*`
|
|
9
|
+
* symbol wrapped so inputs are `(ptr,len)` byte slices and text outputs are
|
|
10
|
+
* returned as JS strings via JSC's native transfer (cstring clone) — zero
|
|
11
|
+
* `TextEncoder`/`TextDecoder` on the Bun path. `*Into` variants write into a
|
|
12
|
+
* caller buffer and return the byte count; variable-size ops return the exact
|
|
13
|
+
* required size on a too-small buffer so the transport grows once and retries
|
|
14
|
+
* exactly once.
|
|
15
|
+
*/
|
|
16
|
+
export interface BunFFI {
|
|
17
|
+
crc32(input: Uint8Array): number
|
|
18
|
+
fnv1a64(input: Uint8Array): bigint
|
|
19
|
+
xxh3(input: Uint8Array): bigint
|
|
20
|
+
jsonValid(input: Uint8Array): boolean
|
|
21
|
+
/** UTF-8 validity probe (native replacement for a fatal `TextDecoder`). */
|
|
22
|
+
utf8Valid(input: Uint8Array): boolean
|
|
23
|
+
/** Lowercase-hex encode → string (native transfer, zero encode). */
|
|
24
|
+
hexEncode(input: Uint8Array): string
|
|
25
|
+
/** Lowercase-hex encode into `output`; returns bytes written. */
|
|
26
|
+
hexEncodeInto(input: Uint8Array, output: Uint8Array): number
|
|
27
|
+
/** RFC 3986 percent-encode → string. */
|
|
28
|
+
urlEncode(input: Uint8Array): string
|
|
29
|
+
/** RFC 3986 percent-encode into `output`; returns bytes written. */
|
|
30
|
+
urlEncodeInto(input: Uint8Array, output: Uint8Array): number
|
|
31
|
+
|
|
32
|
+
// ── Validators (u8 → boolean) — `cstring` ARG ────────────────────
|
|
33
|
+
// The input crosses as a `cstring` ARG: the engine transcodes the JS string
|
|
34
|
+
// to a call-scoped NUL-terminated UTF-8 buffer in-engine, so the JS side does
|
|
35
|
+
// ZERO `encoder.encode` work and Rust borrows via `CStr::from_ptr`.
|
|
36
|
+
validateEmail(input: string): boolean
|
|
37
|
+
validateUuid(input: string): boolean
|
|
38
|
+
validateIpv4(input: string): boolean
|
|
39
|
+
validateIpv6(input: string): boolean
|
|
40
|
+
/** Sum of `id` fields across a JSON array → bigint (throws on non-array input). */
|
|
41
|
+
jsonSumIds(input: Uint8Array): bigint
|
|
42
|
+
|
|
43
|
+
// ── Constant-time verify (u8 → boolean) ───────────────────────────
|
|
44
|
+
hmacSha256Verify(key: Uint8Array, data: Uint8Array, signature: Uint8Array): boolean
|
|
45
|
+
csrfVerify(token: Uint8Array, secret: Uint8Array): boolean
|
|
46
|
+
passwordVerify(password: Uint8Array, phc: Uint8Array): boolean
|
|
47
|
+
/** `phc` is a `cstring` ARG (the engine transcodes the JS PHC string in-engine). */
|
|
48
|
+
passwordVerifyBcrypt(password: Uint8Array, phc: string): boolean
|
|
49
|
+
|
|
50
|
+
// ── Decoders (throw on malformed input — napi `Result` parity) ──
|
|
51
|
+
/** Hex-decode into a fresh buffer (size `input.length / 2`). */
|
|
52
|
+
hexDecode(input: Uint8Array): Uint8Array
|
|
53
|
+
/** Hex-decode into `output`; returns bytes written (throws if too small). */
|
|
54
|
+
hexDecodeInto(input: Uint8Array, output: Uint8Array): number
|
|
55
|
+
/** Percent-decode into a fresh buffer (size `input.length`). */
|
|
56
|
+
urlDecode(input: Uint8Array): Uint8Array
|
|
57
|
+
/** Percent-decode into `output`; returns bytes written (throws if too small). */
|
|
58
|
+
urlDecodeInto(input: Uint8Array, output: Uint8Array): number
|
|
59
|
+
/** base64-decode into a fresh buffer (size `ceil(len/4)*3`). */
|
|
60
|
+
base64Decode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): Uint8Array
|
|
61
|
+
/** base64-decode into `output`; returns bytes written (throws if too small). */
|
|
62
|
+
base64DecodeInto(
|
|
63
|
+
input: Uint8Array,
|
|
64
|
+
output: Uint8Array,
|
|
65
|
+
urlSafe?: boolean,
|
|
66
|
+
padding?: boolean,
|
|
67
|
+
): number
|
|
68
|
+
|
|
69
|
+
// ── Fixed-size output writers ─────────────────────────────────────
|
|
70
|
+
/** RFC 6455 Sec-WebSocket-Accept → string (cstring return; `key` is a `cstring` ARG). */
|
|
71
|
+
wsAcceptKey(key: string): string
|
|
72
|
+
/** RFC 6455 Sec-WebSocket-Accept into `output`; returns bytes written. */
|
|
73
|
+
wsAcceptKeyInto(key: Uint8Array, output: Uint8Array): number
|
|
74
|
+
/** crc32 ETag → string (10 strong / 12 weak chars, cstring return). */
|
|
75
|
+
etag(data: Uint8Array, weak?: boolean): string
|
|
76
|
+
/** crc32 ETag into `output`; returns bytes written. */
|
|
77
|
+
etagInto(data: Uint8Array, output: Uint8Array, weak?: boolean): number
|
|
78
|
+
/** Evaluate a precompiled `ConditionalRequest` (opaque `inner` handle from its
|
|
79
|
+
* napi `inner_ptr()`) — true → 304. `null` header args = absent (flags encode
|
|
80
|
+
* presence so a present-but-empty header is distinct). A null (0) handle → false. */
|
|
81
|
+
conditionalIsNotModified(
|
|
82
|
+
inner: number,
|
|
83
|
+
ifNoneMatch: Uint8Array | null,
|
|
84
|
+
ifModifiedSince: Uint8Array | null,
|
|
85
|
+
): boolean
|
|
86
|
+
/** Precompiled `MediaTypeMatcher` wildcard match (opaque `inner` handle). */
|
|
87
|
+
mediaTypeMatcherMatches(inner: number, actual: Uint8Array): boolean
|
|
88
|
+
/** Precompiled `AcceptNegotiator` → best supported encoding (opaque `inner`
|
|
89
|
+
* handle); `null` = identity. */
|
|
90
|
+
acceptNegotiatorNegotiate(inner: number, header: Uint8Array): string | null
|
|
91
|
+
/** Precompiled `JwtSigner` → compact token from pre-serialized claim JSON
|
|
92
|
+
* (opaque `inner` handle); throws on invalid claims / null handle. */
|
|
93
|
+
jwtSignerSign(inner: number, claimsJson: Uint8Array, nowSeconds: number): Uint8Array
|
|
94
|
+
/** Precompiled `JwtSigner` → claims JSON bytes (opaque `inner` handle);
|
|
95
|
+
* `null` = invalid signature / expired / malformed. */
|
|
96
|
+
jwtSignerVerify(inner: number, token: Uint8Array, nowSeconds: number): Uint8Array | null
|
|
97
|
+
/** Compiled `TemplateRenderer` → UTF-8 bytes from a pre-serialized JSON
|
|
98
|
+
* context (opaque `inner` handle); throws on invalid context / render error. */
|
|
99
|
+
templateRender(inner: number, contextJson: Uint8Array): Uint8Array
|
|
100
|
+
/** Compiled `SchemaValidator` → whether a document is valid (opaque `inner` handle). */
|
|
101
|
+
schemaValidatorValidate(inner: number, doc: Uint8Array): boolean
|
|
102
|
+
/** `RateLimiter` string-key check → { allowed, remaining, resetMs } (opaque
|
|
103
|
+
* `inner` handle; `key` is a `cstring` ARG); throws on a null handle. */
|
|
104
|
+
rateLimiterCheck(inner: number, key: string, nowMs: number): RateLimiterVerdict
|
|
105
|
+
/** `RateLimiter` pre-hashed key check → { allowed, remaining, resetMs }. */
|
|
106
|
+
rateLimiterCheckKey(inner: number, key: number, nowMs: number): RateLimiterVerdict
|
|
107
|
+
/** `byteLen` random bytes → `byteLen * 2` hex-char string (cstring return). */
|
|
108
|
+
randomToken(byteLen: number): string
|
|
109
|
+
/** base64-encode → string. */
|
|
110
|
+
base64Encode(input: Uint8Array, urlSafe?: boolean, padding?: boolean): string
|
|
111
|
+
/** base64-encode into `output`; returns bytes written. */
|
|
112
|
+
base64EncodeInto(
|
|
113
|
+
input: Uint8Array,
|
|
114
|
+
output: Uint8Array,
|
|
115
|
+
urlSafe?: boolean,
|
|
116
|
+
padding?: boolean,
|
|
117
|
+
): number
|
|
118
|
+
/** HMAC-SHA256 → 64-char lowercase-hex string. */
|
|
119
|
+
hmacSha256(key: Uint8Array, data: Uint8Array): string
|
|
120
|
+
/** HMAC-SHA256 hex into `output`; returns bytes written (throws if too small). */
|
|
121
|
+
hmacSha256Into(key: Uint8Array, data: Uint8Array, output: Uint8Array): number
|
|
122
|
+
/** Sign cookie `value` as `value.<64-hex>` → string (cstring return). */
|
|
123
|
+
signCookie(value: Uint8Array, secret: Uint8Array): string
|
|
124
|
+
/** Sign cookie into `output`; returns bytes written (throws if too small). */
|
|
125
|
+
signCookieInto(value: Uint8Array, secret: Uint8Array, output: Uint8Array): number
|
|
126
|
+
/** Verify a signed cookie → value string, or `null` on bad signature. */
|
|
127
|
+
verifyCookie(signed: Uint8Array, secret: Uint8Array): string | null
|
|
128
|
+
/** Verify a signed cookie into `output`; returns value length or `null` on bad signature. */
|
|
129
|
+
verifyCookieInto(signed: Uint8Array, secret: Uint8Array, output: Uint8Array): number | null
|
|
130
|
+
/** CSRF token (129 chars: 64 rnd-hex + '.' + 64 sig-hex) → string. */
|
|
131
|
+
csrfToken(secret: Uint8Array): string
|
|
132
|
+
/** CSRF token into `output`; returns bytes written (throws if too small). */
|
|
133
|
+
csrfTokenInto(secret: Uint8Array, output: Uint8Array): number
|
|
134
|
+
/** Argon2id PHC hash → string (m/t/p/out_len params). */
|
|
135
|
+
passwordHash(
|
|
136
|
+
password: Uint8Array,
|
|
137
|
+
salt: Uint8Array,
|
|
138
|
+
mCost: number,
|
|
139
|
+
tCost: number,
|
|
140
|
+
pCost: number,
|
|
141
|
+
outLen: number,
|
|
142
|
+
): string
|
|
143
|
+
/** bcrypt `$2b$` PHC → string (cost clamped 4..=31). */
|
|
144
|
+
passwordHashBcrypt(password: Uint8Array, cost: number): string
|
|
145
|
+
/** PBKDF2-HMAC-SHA256 → `dkLen` bytes (rounds, dkLen clamped). */
|
|
146
|
+
pbkdf2Sha256(password: Uint8Array, salt: Uint8Array, rounds: number, dkLen: number): Uint8Array
|
|
147
|
+
/** AEAD encrypt (0 = AES-256-GCM, 1 = ChaCha20-Poly1305) → ct+tag. */
|
|
148
|
+
aeadEncrypt(
|
|
149
|
+
key: Uint8Array,
|
|
150
|
+
nonce: Uint8Array,
|
|
151
|
+
plaintext: Uint8Array,
|
|
152
|
+
algorithm?: number,
|
|
153
|
+
): Uint8Array
|
|
154
|
+
/** AEAD encrypt into `output` (ct + 16-byte tag); returns bytes written. */
|
|
155
|
+
aeadEncryptInto(
|
|
156
|
+
key: Uint8Array,
|
|
157
|
+
nonce: Uint8Array,
|
|
158
|
+
plaintext: Uint8Array,
|
|
159
|
+
output: Uint8Array,
|
|
160
|
+
algorithm?: number,
|
|
161
|
+
): number
|
|
162
|
+
/** AEAD decrypt → plaintext, or `null` on auth failure. */
|
|
163
|
+
aeadDecrypt(
|
|
164
|
+
key: Uint8Array,
|
|
165
|
+
nonce: Uint8Array,
|
|
166
|
+
ciphertext: Uint8Array,
|
|
167
|
+
algorithm?: number,
|
|
168
|
+
): Uint8Array | null
|
|
169
|
+
|
|
170
|
+
// ── Frame / patch / compression (variable-size → grow-retry) ─────
|
|
171
|
+
/** RFC 6455 frame encode into a fresh buffer. */
|
|
172
|
+
wsFrameEncode(opcode: number, payload: Uint8Array, mask: boolean, fin: boolean): Uint8Array
|
|
173
|
+
/** RFC 6455 frame encode into `output`; returns bytes written (throws if too small). */
|
|
174
|
+
wsFrameEncodeInto(
|
|
175
|
+
opcode: number,
|
|
176
|
+
payload: Uint8Array,
|
|
177
|
+
mask: boolean,
|
|
178
|
+
fin: boolean,
|
|
179
|
+
output: Uint8Array,
|
|
180
|
+
): number
|
|
181
|
+
/** RFC 6902 JSON patch → JSON text string. */
|
|
182
|
+
jsonPatch(doc: Uint8Array, patch: Uint8Array): string
|
|
183
|
+
/** gzip-compress into a fresh buffer (level clamped 0..=9, default 6). */
|
|
184
|
+
gzipCompress(data: Uint8Array, level?: number): Uint8Array
|
|
185
|
+
/** gzip-compress into `output`; returns bytes written (throws if too small). */
|
|
186
|
+
gzipCompressInto(data: Uint8Array, output: Uint8Array, level?: number): number
|
|
187
|
+
/** gzip-decompress into a fresh buffer (capped by `maxDecompressed`). */
|
|
188
|
+
gzipDecompress(data: Uint8Array, maxDecompressed?: number): Uint8Array
|
|
189
|
+
/** gzip-decompress into `output`; returns bytes written (throws if too small). */
|
|
190
|
+
gzipDecompressInto(data: Uint8Array, output: Uint8Array, maxDecompressed?: number): number
|
|
191
|
+
/** brotli-compress into a fresh buffer (quality clamped 0..=11, default 5). */
|
|
192
|
+
brotliCompress(data: Uint8Array, quality?: number): Uint8Array
|
|
193
|
+
/** brotli-compress into `output`; returns bytes written (throws if too small). */
|
|
194
|
+
brotliCompressInto(data: Uint8Array, output: Uint8Array, quality?: number): number
|
|
195
|
+
/** brotli-decompress into a fresh buffer (capped by `maxDecompressed`). */
|
|
196
|
+
brotliDecompress(data: Uint8Array, maxDecompressed?: number): Uint8Array
|
|
197
|
+
/** brotli-decompress into `output`; returns bytes written (throws if too small). */
|
|
198
|
+
brotliDecompressInto(data: Uint8Array, output: Uint8Array, maxDecompressed?: number): number
|
|
199
|
+
|
|
200
|
+
// ── Packed parsers (into caller buffers) ─────────────────────────
|
|
201
|
+
/** HTTP request parse → packed output into `output`; returns bytes written. */
|
|
202
|
+
httpParseRequestPackedInto(input: Uint8Array, output: Uint8Array): number
|
|
203
|
+
/** Query string parse → packed output into `output`; returns bytes written. */
|
|
204
|
+
queryParsePackedInto(input: Uint8Array, output: Uint8Array): number
|
|
205
|
+
/** Cookie header parse → packed output into `output`; returns bytes written. */
|
|
206
|
+
cookieParsePackedInto(input: Uint8Array, output: Uint8Array): number
|
|
207
|
+
|
|
208
|
+
// ── Excluded-surface additions (packed / opaque-handle) ─────────
|
|
209
|
+
/** Sign JWT (HS256) from pre-serialized claim JSON (ttl<=0 → no iat/exp) → string. */
|
|
210
|
+
jwtSignBytes(claimsJson: Uint8Array, secret: Uint8Array, ttl: number, now: number): string
|
|
211
|
+
/** Sign JWT into `output`; returns bytes written (throws if too small). */
|
|
212
|
+
jwtSignBytesInto(
|
|
213
|
+
claimsJson: Uint8Array,
|
|
214
|
+
secret: Uint8Array,
|
|
215
|
+
ttl: number,
|
|
216
|
+
now: number,
|
|
217
|
+
output: Uint8Array,
|
|
218
|
+
): number
|
|
219
|
+
/** Decode a WS frame into packed `[flags][opcode][u32 len][payload]`; null on malformed. */
|
|
220
|
+
wsFrameDecodePacked(data: Uint8Array): Uint8Array | null
|
|
221
|
+
/**
|
|
222
|
+
* Decode a WS frame into `output` (sized ≥ `data.length + 6`); returns bytes
|
|
223
|
+
* written, null on malformed. Pooled sibling of `wsFrameDecodePacked`.
|
|
224
|
+
*/
|
|
225
|
+
wsFrameDecodePackedInto(data: Uint8Array, output: Uint8Array): number | null
|
|
226
|
+
/** Parse multipart/form-data into the packed parts layout. */
|
|
227
|
+
multipartParsePacked(body: Uint8Array, boundary: Uint8Array): Uint8Array
|
|
228
|
+
/** Parse multipart/form-data into `output`; returns bytes written (throws if too small). */
|
|
229
|
+
multipartParsePackedInto(body: Uint8Array, boundary: Uint8Array, output: Uint8Array): number
|
|
230
|
+
/** Parse x-www-form-urlencoded into packed pairs into `output`. */
|
|
231
|
+
formParsePackedInto(input: Uint8Array, output: Uint8Array): number
|
|
232
|
+
/**
|
|
233
|
+
* Verify an HS256 JWT → claims JSON text (cstring return; `null` on invalid
|
|
234
|
+
* signature / expired / malformed). `nowSeconds` is an i64 C arg.
|
|
235
|
+
*/
|
|
236
|
+
jwtVerify(token: Uint8Array, secret: Uint8Array, nowSeconds: number): string | null
|
|
237
|
+
/**
|
|
238
|
+
* Parse JSON → packed token stream bytes (structural, no re-parse). Layout:
|
|
239
|
+
* `[u32 strCount]{[u32 len][utf8]}... [u32 treeLen][tree]` — a deduplicated
|
|
240
|
+
* string table followed by a start/end-marker value tree:
|
|
241
|
+
* `0=null 1=false 2=true 3=number(f64 LE) 4=string(u32 table idx)
|
|
242
|
+
* 5=array start 6=object start 7=array end 8=object end
|
|
243
|
+
* 9=object key(u32 table idx)` (object body `6,(9,keyIdx,value)*,8`).
|
|
244
|
+
* Throws on invalid JSON / too-small output. The scalar wrapper decodes the
|
|
245
|
+
* table once and assembles the value — no second parse.
|
|
246
|
+
*/
|
|
247
|
+
jsonParsePacked(input: Uint8Array): Uint8Array
|
|
248
|
+
/**
|
|
249
|
+
* Parse a Content-Type header → packed verdict bytes:
|
|
250
|
+
* `[u32 mediaTypeLen][mediaType][u32 charsetLen (0xFFFFFFFF = none)][charset]
|
|
251
|
+
* [u32 boundaryLen][boundary][u32 paramCount]{[u32 keyLen][key][u32 valLen][val]}`.
|
|
252
|
+
* Throws on invalid media type / too-small output.
|
|
253
|
+
*/
|
|
254
|
+
parseMediaType(input: Uint8Array): Uint8Array
|
|
255
|
+
/** Parse an IMF-fixdate → unix seconds, or `null` on malformed (packed
|
|
256
|
+
* `[u8 ok][i64 secs LE]` output, decoded here). */
|
|
257
|
+
parseHttpDate(input: Uint8Array): bigint | null
|
|
258
|
+
/**
|
|
259
|
+
* Parse an Accept-Encoding header → packed verdict bytes:
|
|
260
|
+
* `[u32 count]{[u32 encLen][enc][f32 q][u32 order]}` (empty header → count 0).
|
|
261
|
+
* Throws on too-small output.
|
|
262
|
+
*/
|
|
263
|
+
parseAcceptEncoding(input: Uint8Array): Uint8Array
|
|
264
|
+
/** Percent-encode a query from packed pairs (the `packPairs` layout) → string,
|
|
265
|
+
* keys SORTED (matches napi `BTreeMap` ordering); `null` on malformed input. */
|
|
266
|
+
urlEncodeQuery(input: Uint8Array): string | null
|
|
267
|
+
/** RFC 3986 URL resolution (base + reference) → string; `null` on non-UTF-8. */
|
|
268
|
+
urlResolve(base: Uint8Array, reference: Uint8Array): string | null
|
|
269
|
+
/** Resolve a reference against a `UrlBuilder`'s PRECOMPILED base (opaque
|
|
270
|
+
* `inner` handle from its napi `inner_ptr()`) → bytes; throws on a null
|
|
271
|
+
* handle / non-UTF-8 reference / too-small output. */
|
|
272
|
+
urlBuilderResolve(inner: number, reference: Uint8Array): Uint8Array
|
|
273
|
+
/** Extension → MIME type → string (unknown → `application/octet-stream`; `ext` is a `cstring` ARG). */
|
|
274
|
+
mimeFromExtension(ext: string): string | null
|
|
275
|
+
/**
|
|
276
|
+
* 29-byte HTTP-date (`Sun, 06 Nov 1994 08:49:37 GMT`) into `output`; returns
|
|
277
|
+
* bytes written (throws on too-small / out-of-range year). FFI sibling of the
|
|
278
|
+
* napi `httpDateInto` — kills the napi crossing on the hot path.
|
|
279
|
+
*/
|
|
280
|
+
httpDateInto(secs: number, output: Uint8Array): number
|
|
281
|
+
/** 29-byte HTTP-date → string (allocating sibling of httpDateInto). */
|
|
282
|
+
httpDate(secs?: number): string
|
|
283
|
+
/**
|
|
284
|
+
* Encode one SSE event → bytes (fresh buffer). event/id null = line omitted
|
|
285
|
+
* (a present-but-empty string emits the line, matching napi `Option`).
|
|
286
|
+
* FFI sibling of the napi `sse_encode_event` — kills the napi crossing.
|
|
287
|
+
*/
|
|
288
|
+
sseEncodeEvent(
|
|
289
|
+
event: string | null,
|
|
290
|
+
data: Uint8Array,
|
|
291
|
+
id: string | null,
|
|
292
|
+
retry: number | null,
|
|
293
|
+
): Uint8Array
|
|
294
|
+
/**
|
|
295
|
+
* Encode one SSE event into `output` (sized ≥ `data.length + 64`); returns
|
|
296
|
+
* bytes written (throws if too small / invalid UTF-8). Pooled sibling of
|
|
297
|
+
* `sseEncodeEvent` — removes the per-call output-buffer alloc.
|
|
298
|
+
*/
|
|
299
|
+
sseEncodeEventInto(
|
|
300
|
+
event: string | null,
|
|
301
|
+
data: Uint8Array,
|
|
302
|
+
id: string | null,
|
|
303
|
+
retry: number | null,
|
|
304
|
+
output: Uint8Array,
|
|
305
|
+
): number
|
|
306
|
+
/** Random hex token into `output`; returns bytes written (throws if too small). */
|
|
307
|
+
randomTokenInto(byteLen: number, output: Uint8Array): number
|
|
308
|
+
/**
|
|
309
|
+
* Run the ingress pipeline on a packed frame via the opaque inner handle from
|
|
310
|
+
* `Ingress.ingressInnerPtr()` (valid only while the instance is alive — the
|
|
311
|
+
* caller must hold it). Returns bytes written; throws on error / too-small.
|
|
312
|
+
*/
|
|
313
|
+
ingressHandlePacked(
|
|
314
|
+
inner: number,
|
|
315
|
+
input: Uint8Array,
|
|
316
|
+
body: Uint8Array | null,
|
|
317
|
+
output: Uint8Array,
|
|
318
|
+
): number
|
|
319
|
+
/**
|
|
320
|
+
* Run the ingress pipeline from raw request components via the opaque inner
|
|
321
|
+
* handle (valid only while the instance is alive). `url`/`ip` are JS strings
|
|
322
|
+
* passed as `bun:ffi` `cstring` ARGs — the engine transcodes them to
|
|
323
|
+
* call-scoped NUL-terminated UTF-8 buffers in-engine, so the JS side skips
|
|
324
|
+
* the frame assembly + `Buffer.write` encode for the URL/IP. `rid`/`headers`
|
|
325
|
+
* are the packed byte slices; `body` is the request body (or null); `output`
|
|
326
|
+
* receives the packed decision. Same wire format as {@link ingressHandlePacked}.
|
|
327
|
+
* Returns bytes written; throws on error / too-small.
|
|
328
|
+
*/
|
|
329
|
+
ingressHandleComponents(
|
|
330
|
+
inner: number,
|
|
331
|
+
methodKind: number,
|
|
332
|
+
url: string,
|
|
333
|
+
ip: string,
|
|
334
|
+
rid: Uint8Array,
|
|
335
|
+
headers: Uint8Array,
|
|
336
|
+
body: Uint8Array | null,
|
|
337
|
+
output: Uint8Array,
|
|
338
|
+
): number
|
|
339
|
+
/**
|
|
340
|
+
* Write the ingress binary-layout constants (38 × u32 LE — `rust/ffi.rs`
|
|
341
|
+
* `IngressLayout`, numeric source `rust/ingress/output.rs`) into `output`;
|
|
342
|
+
* returns bytes written. Lets `src/ingress/constants.ts` read the layout via
|
|
343
|
+
* bun:ffi on Bun so importing the package does NOT dlopen the napi addon.
|
|
344
|
+
*/
|
|
345
|
+
ingressLayout(out: Uint8Array): number
|
|
346
|
+
|
|
347
|
+
// ── Per-route native stack (`castrum_route_*`) ──────────────────
|
|
348
|
+
/**
|
|
349
|
+
* Compile a route descriptor (the `@ignex/native` route-wire v3 format:
|
|
350
|
+
* magic `ROUT`, version 3, limits, stage tags, draft-07 body schema) into an
|
|
351
|
+
* opaque handle. Returns the handle (`0` = invalid descriptor / compile
|
|
352
|
+
* failure / panic — throws). The handle is owned by the caller and must be
|
|
353
|
+
* released with {@link routeDestroy}.
|
|
354
|
+
*/
|
|
355
|
+
routeCompile(descriptor: Uint8Array): number
|
|
356
|
+
/**
|
|
357
|
+
* Run a compiled route on one request frame, writing the packed verdict
|
|
358
|
+
* (`[flags u32][errorCode u32]` + optional query/cookie pair sections) into
|
|
359
|
+
* `output`. Returns bytes written (`0` = real error — throws; `> output.length`
|
|
360
|
+
* = the EXACT required size — the caller allocates once and retries, per the
|
|
361
|
+
* growExact convention).
|
|
362
|
+
*/
|
|
363
|
+
routeRun(handle: number, frame: Uint8Array, output: Uint8Array): number
|
|
364
|
+
/** Destroy a compiled route handle (frees the native `Box<NativeRoute>`). */
|
|
365
|
+
routeDestroy(handle: number): void
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* bun:ffi transport selection (from `CASTRUM_FFI_MODE`; legacy `RUST_FFI_MODE`
|
|
370
|
+
* accepted):
|
|
371
|
+
*
|
|
372
|
+
* - `auto` (default): use bun:ffi on Bun, silently fall back to napi when the
|
|
373
|
+
* bind or self-test fails (and always on Node).
|
|
374
|
+
* - `ffi`: force bun:ffi on Bun — throw a clear error if it can't bind or the
|
|
375
|
+
* self-test fails (use in benches/CI that MUST run ffi).
|
|
376
|
+
* - `napi`: never bind — every call goes through the napi addon (the fallback;
|
|
377
|
+
* useful for exercising the fallback path on Bun).
|
|
378
|
+
*/
|
|
379
|
+
export type FfiMode = 'auto' | 'ffi' | 'napi'
|
|
380
|
+
|
|
381
|
+
/** Unpacked rate-limit verdict (from the packed
|
|
382
|
+
* `[u8 allowed][u32 remaining LE][i64 reset_ms LE]` C-ABI output). */
|
|
383
|
+
export interface RateLimiterVerdict {
|
|
384
|
+
allowed: boolean
|
|
385
|
+
remaining: number
|
|
386
|
+
resetMs: number
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Raw 2-arg C-ABI symbol signature (`(ptr,len)` pairs → scalar result). */
|
|
390
|
+
export type Raw2 = (a: unknown, b: unknown) => number | bigint
|
|
391
|
+
/** Raw 3-arg C-ABI symbol signature. */
|
|
392
|
+
export type Raw3 = (a: unknown, b: unknown, c: unknown) => number | bigint
|
|
393
|
+
/** Raw 4-arg C-ABI symbol signature. */
|
|
394
|
+
export type Raw4 = (a: unknown, b: unknown, c: unknown, d: unknown) => number | bigint
|
|
395
|
+
/** Raw 5-arg C-ABI symbol signature. */
|
|
396
|
+
export type Raw5 = (a: unknown, b: unknown, c: unknown, d: unknown, e: unknown) => number | bigint
|
|
397
|
+
/** Raw 6-arg C-ABI symbol signature. */
|
|
398
|
+
export type Raw6 = (
|
|
399
|
+
a: unknown,
|
|
400
|
+
b: unknown,
|
|
401
|
+
c: unknown,
|
|
402
|
+
d: unknown,
|
|
403
|
+
e: unknown,
|
|
404
|
+
f: unknown,
|
|
405
|
+
) => number | bigint
|
|
406
|
+
/** Raw 7-arg C-ABI symbol signature. */
|
|
407
|
+
export type Raw7 = (
|
|
408
|
+
a: unknown,
|
|
409
|
+
b: unknown,
|
|
410
|
+
c: unknown,
|
|
411
|
+
d: unknown,
|
|
412
|
+
e: unknown,
|
|
413
|
+
f: unknown,
|
|
414
|
+
g: unknown,
|
|
415
|
+
) => number | bigint
|
|
416
|
+
/** Raw 8-arg C-ABI symbol signature. */
|
|
417
|
+
export type Raw8 = (
|
|
418
|
+
a: unknown,
|
|
419
|
+
b: unknown,
|
|
420
|
+
c: unknown,
|
|
421
|
+
d: unknown,
|
|
422
|
+
e: unknown,
|
|
423
|
+
f: unknown,
|
|
424
|
+
g: unknown,
|
|
425
|
+
h: unknown,
|
|
426
|
+
) => number | bigint
|
|
427
|
+
/** Raw 9-arg C-ABI symbol signature. */
|
|
428
|
+
export type Raw9 = (
|
|
429
|
+
a: unknown,
|
|
430
|
+
b: unknown,
|
|
431
|
+
c: unknown,
|
|
432
|
+
d: unknown,
|
|
433
|
+
e: unknown,
|
|
434
|
+
f: unknown,
|
|
435
|
+
g: unknown,
|
|
436
|
+
h: unknown,
|
|
437
|
+
i: unknown,
|
|
438
|
+
) => number | bigint
|
|
439
|
+
/** Raw 10-arg C-ABI symbol signature. */
|
|
440
|
+
export type Raw10 = (
|
|
441
|
+
a: unknown,
|
|
442
|
+
b: unknown,
|
|
443
|
+
c: unknown,
|
|
444
|
+
d: unknown,
|
|
445
|
+
e: unknown,
|
|
446
|
+
f: unknown,
|
|
447
|
+
g: unknown,
|
|
448
|
+
h: unknown,
|
|
449
|
+
i: unknown,
|
|
450
|
+
j: unknown,
|
|
451
|
+
) => number | bigint
|
|
452
|
+
|
|
453
|
+
/** Raw 12-arg C-ABI symbol signature (`castrum_ingress_handle_components`). */
|
|
454
|
+
export type Raw12 = (
|
|
455
|
+
a: unknown,
|
|
456
|
+
b: unknown,
|
|
457
|
+
c: unknown,
|
|
458
|
+
d: unknown,
|
|
459
|
+
e: unknown,
|
|
460
|
+
f: unknown,
|
|
461
|
+
g: unknown,
|
|
462
|
+
h: unknown,
|
|
463
|
+
i: unknown,
|
|
464
|
+
j: unknown,
|
|
465
|
+
k: unknown,
|
|
466
|
+
l: unknown,
|
|
467
|
+
) => number | bigint
|
|
468
|
+
|
|
469
|
+
/** A raw C-ABI symbol whose return type is `cstring` — the engine clones the
|
|
470
|
+
* null-terminated string at return (`null` = C NULL, i.e. a failure sentinel).
|
|
471
|
+
* Used by the fixed-size ASCII writers (ws_accept_key, etag, random_token,
|
|
472
|
+
* sign/verify_cookie, csrf_token, jwt_sign_bytes).
|
|
473
|
+
*/
|
|
474
|
+
export type RawCStr = (...a: unknown[]) => string | null
|