castrum 0.9.1 → 0.9.3
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/README.md +1 -1
- package/castrum.linux-x64-gnu.node +0 -0
- package/dist/index.d.ts +239 -5
- package/dist/index.js +3852 -3375
- package/docs/ARCHITECTURE.md +11 -9
- package/docs/BENCHMARKS.md +70 -38
- package/docs/CASE_STUDY.md +10 -7
- package/docs/ENVIRONMENT.md +16 -1
- package/docs/FFI_BUN_GUIDE.md +18 -10
- package/docs/GETTING_STARTED.md +5 -4
- package/docs/HOW_TO_ADD_AN_OP.md +180 -0
- package/docs/INGRESS-ROUTER.md +3 -2
- package/docs/INGRESS.md +6 -3
- package/docs/NATIVE-ROUTE.md +28 -4
- package/docs/REPO_MAP.md +60 -30
- package/docs/adr/0001-two-wire-formats.md +1 -1
- package/docs/ai/LOCAL_DEV.md +81 -0
- package/docs/ai/TREE.md +1070 -0
- package/package.json +24 -23
- package/src/ingress/decode/result-base.ts +10 -2
- package/src/ingress/handlers.ts +45 -290
- package/src/ingress/headers/security.ts +41 -0
- package/src/ingress/index.ts +12 -148
- package/src/ingress/native-route.ts +182 -0
- package/src/ingress/packing/gather-raw-headers.ts +26 -2
- package/src/ingress/packing/route-wire.ts +197 -0
- package/src/ingress/packing/select-headers.ts +8 -1
- package/src/ingress/path-matcher.ts +115 -0
- package/src/ingress/response/baked-response.ts +302 -0
- package/src/ingress/router.ts +42 -2
- package/src/ingress/routes/common.ts +9 -1
- package/src/ingress/routes/json-write.ts +21 -18
- package/src/ingress/routes/native.ts +130 -0
- package/src/ingress/server-node.ts +1 -1
- package/src/ingress/server.ts +38 -99
- package/src/ingress/sync.ts +151 -0
- package/src/ingress/types.ts +9 -0
- package/src/native/ffi/build/codecs.ts +736 -0
- package/src/native/ffi/build/compress.ts +248 -0
- package/src/native/ffi/build/instances.ts +598 -0
- package/src/native/ffi/build/parse.ts +539 -0
- package/src/native/ffi/build/util.ts +140 -0
- package/src/native/ffi/build.ts +94 -0
- package/src/native/ffi/selftest.ts +11 -718
- package/src/native/ffi/types.ts +25 -0
- package/src/native/ffi.ts +36 -1320
- package/src/native/types/instances.ts +5 -0
- package/src/rust-ffi/packed.ts +38 -0
- package/src/rust-ffi/scalar/factories.ts +4 -0
package/README.md
CHANGED
|
@@ -168,7 +168,7 @@ isEmail([a, b, c]); // one packed batch call
|
|
|
168
168
|
## Testing
|
|
169
169
|
|
|
170
170
|
```bash
|
|
171
|
-
bun test # TypeScript unit tests (~
|
|
171
|
+
bun test # TypeScript unit tests (~760)
|
|
172
172
|
bun run test:rust # Rust unit tests (cargo test)
|
|
173
173
|
bun run typecheck # TypeScript typecheck
|
|
174
174
|
bun run test:node # Node.js integration tests (run `bun run build:js` first)
|
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -96,6 +96,11 @@ export interface EncodingPrefResult {
|
|
|
96
96
|
export interface AcceptNegotiatorInstance {
|
|
97
97
|
/** Best supported encoding for `header`, or null for identity. */
|
|
98
98
|
negotiate(header: Uint8Array): string | null;
|
|
99
|
+
/** Best supported encoding for `header` with SERVER-preference tie-breaking
|
|
100
|
+
* (RFC 7231 server semantics — the supported list's order breaks q-value
|
|
101
|
+
* ties), or null for identity. On the napi fallback this is the projected
|
|
102
|
+
* `negotiate_server_preference` method. */
|
|
103
|
+
negotiateServerPreference(header: Uint8Array): string | null;
|
|
99
104
|
/** Opaque handle (bun:ffi fast path) — `castrum_accept_negotiator_negotiate`. */
|
|
100
105
|
innerPtr?(): bigint;
|
|
101
106
|
}
|
|
@@ -573,6 +578,14 @@ export interface OptimizedIngressHandler {
|
|
|
573
578
|
string,
|
|
574
579
|
string
|
|
575
580
|
][];
|
|
581
|
+
/**
|
|
582
|
+
* Zero-DOM JSON-validity check bound to this handler's native transport
|
|
583
|
+
* (bun:ffi primary, napi fallback). Provided so the pure route factories
|
|
584
|
+
* (`routes/*`) can validate request bodies via dependency injection without
|
|
585
|
+
* importing the native layer. Always present on handlers from
|
|
586
|
+
* `createIngressHandler`; optional so hand-rolled mocks need not provide it.
|
|
587
|
+
*/
|
|
588
|
+
jsonValid?: (bytes: Uint8Array) => boolean;
|
|
576
589
|
/**
|
|
577
590
|
* Build a zero-copy `Response` whose body is the request's pooled output
|
|
578
591
|
* slice. The pooled buffer is returned to its pool once the body has been
|
|
@@ -626,6 +639,14 @@ export interface BakedHandlerOptions {
|
|
|
626
639
|
bodyTimeoutMs?: number;
|
|
627
640
|
/** Fallback handler used for write error paths. Defaults to the write ingress. */
|
|
628
641
|
fallback?: OptimizedIngressHandler;
|
|
642
|
+
/**
|
|
643
|
+
* Zero-DOM JSON-validity check for the write-route fallback validation
|
|
644
|
+
* (`jsonWriteHandler` when neither `requireJsonBody` nor a `schema` is
|
|
645
|
+
* configured). Injected so the pure route factories never import the native
|
|
646
|
+
* layer (dependency injection across the purity boundary). Defaults to the
|
|
647
|
+
* `ingress.jsonValid` capability that `createIngressHandler` provides.
|
|
648
|
+
*/
|
|
649
|
+
jsonValid?: (bytes: Uint8Array) => boolean;
|
|
629
650
|
/**
|
|
630
651
|
* When true, route the JSON-validity fallback check through the higher-order
|
|
631
652
|
* loader (`loader("jsonValid")`) instead of the direct native call —
|
|
@@ -635,6 +656,142 @@ export interface BakedHandlerOptions {
|
|
|
635
656
|
*/
|
|
636
657
|
enableLoader?: boolean;
|
|
637
658
|
}
|
|
659
|
+
/** Route descriptor magic (`"ROUT"` LE). Must match `ROUTE_DESC_MAGIC` in Rust. */
|
|
660
|
+
export declare const ROUTE_DESC_MAGIC = 1380930900;
|
|
661
|
+
/** Wire version — bump on ANY descriptor/frame/result layout change. */
|
|
662
|
+
export declare const ROUTE_DESC_VERSION = 3;
|
|
663
|
+
/** Descriptor stage tags (the ordered pipeline a route instance runs). */
|
|
664
|
+
export declare const ROUTE_STAGE: {
|
|
665
|
+
readonly parseQuery: 0;
|
|
666
|
+
readonly parseCookies: 1;
|
|
667
|
+
readonly validateQuery: 2;
|
|
668
|
+
readonly validateCookies: 3;
|
|
669
|
+
readonly validateBody: 4;
|
|
670
|
+
readonly requireJsonBody: 5;
|
|
671
|
+
};
|
|
672
|
+
/** A descriptor stage tag (`ROUTE_STAGE` values, must match Rust). */
|
|
673
|
+
export type RouteStageTag = (typeof ROUTE_STAGE)[keyof typeof ROUTE_STAGE];
|
|
674
|
+
/** Descriptor part tags (`RoutePartKind`): the schema-bearing request parts. */
|
|
675
|
+
export declare const ROUTE_PART: {
|
|
676
|
+
readonly body: 3;
|
|
677
|
+
};
|
|
678
|
+
/** Result flag bits (`ROUTE_RESULT_FLAG_*` in Rust). */
|
|
679
|
+
export declare const ROUTE_FLAG: {
|
|
680
|
+
readonly OK: number;
|
|
681
|
+
readonly BODY_VALID_JSON: number;
|
|
682
|
+
readonly QUERY_VALID: number;
|
|
683
|
+
readonly COOKIE_VALID: number;
|
|
684
|
+
readonly BODY_VALID: number;
|
|
685
|
+
};
|
|
686
|
+
/** Frame flag: the body section is present (bit 0 of the frame flags word). */
|
|
687
|
+
export declare const ROUTE_FRAME_FLAG_HAS_BODY: number;
|
|
688
|
+
/** Size limits a route descriptor carries. */
|
|
689
|
+
export interface RouteWireLimits {
|
|
690
|
+
maxBodyBytes: number;
|
|
691
|
+
maxQueryBytes: number;
|
|
692
|
+
maxCookieBytes: number;
|
|
693
|
+
maxPairs: number;
|
|
694
|
+
}
|
|
695
|
+
/** A schema part carried by the descriptor (part tag + draft-07 JSON bytes). */
|
|
696
|
+
export interface RouteWireSchema {
|
|
697
|
+
part: number;
|
|
698
|
+
bytes: Uint8Array;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Encode a route plan into the descriptor wire.
|
|
702
|
+
*
|
|
703
|
+
* Layout: `[magic u32][version u32][maxBody u32][maxQuery u32][maxCookie u32]
|
|
704
|
+
* [maxPairs u32][stageCount u32][stages u8…][schemaCount u32]
|
|
705
|
+
* { [part u8][len u32][schema] }…`
|
|
706
|
+
*/
|
|
707
|
+
export declare function encodeRouteDescriptor(pipeline: readonly RouteStageTag[], schemas: readonly RouteWireSchema[], limits: RouteWireLimits): Uint8Array;
|
|
708
|
+
/**
|
|
709
|
+
* Encode a request frame: `[flags u32][qLen][query][cLen][cookie]([bLen][body])`.
|
|
710
|
+
* The `flags` word currently only carries `ROUTE_FRAME_FLAG_HAS_BODY`.
|
|
711
|
+
*/
|
|
712
|
+
export declare function packRouteFrame(query: string, cookie: string, body: Uint8Array | null): Uint8Array;
|
|
713
|
+
/** A decoded `[name, value]` pair from a result section. */
|
|
714
|
+
export type RouteWirePair = [
|
|
715
|
+
string,
|
|
716
|
+
string
|
|
717
|
+
];
|
|
718
|
+
/** The decoded route result: the verdict header + optional pair sections. */
|
|
719
|
+
export interface RouteWireResult {
|
|
720
|
+
/** `ROUTE_FLAG_*` bits from the result header. */
|
|
721
|
+
flags: number;
|
|
722
|
+
/** `0` = ok; `400` = not-JSON under requireJsonBody; `422` = schema fail. */
|
|
723
|
+
errorCode: number;
|
|
724
|
+
/** Decoded query pairs (present iff the plan compiled `parseQuery`). */
|
|
725
|
+
query: RouteWirePair[];
|
|
726
|
+
/** Decoded cookie pairs (present iff the plan compiled `parseCookies`). */
|
|
727
|
+
cookie: RouteWirePair[];
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Decode the result wire: `[flags u32][errorCode u32]` + a query pair section
|
|
731
|
+
* iff `query` and a cookie pair section iff `cookie` (the caller knows its own
|
|
732
|
+
* plan). Sections are `[count u32] { [nameLen u32][name][valueLen u32][value] }`.
|
|
733
|
+
*/
|
|
734
|
+
export declare function decodeRouteResult(buf: Uint8Array, opts: {
|
|
735
|
+
query: boolean;
|
|
736
|
+
cookie: boolean;
|
|
737
|
+
}): RouteWireResult;
|
|
738
|
+
/** Plan for a compiled native route (the stage/limit/schema surface). */
|
|
739
|
+
export interface NativeRoutePlan {
|
|
740
|
+
/** Parse + lenient-decode the query string into pairs (stage 0). */
|
|
741
|
+
parseQuery?: boolean;
|
|
742
|
+
/** Parse + lenient-decode the Cookie header into pairs (stage 1). */
|
|
743
|
+
parseCookies?: boolean;
|
|
744
|
+
/** Reject a missing / non-JSON body with 400 (stage 5, first-failure-wins). */
|
|
745
|
+
requireJsonBody?: boolean;
|
|
746
|
+
/** Validate the body against `schema` with 422 on failure (stage 4). */
|
|
747
|
+
validateBody?: boolean;
|
|
748
|
+
/** Draft-07 JSON schema bytes for the body (`validateBody`). */
|
|
749
|
+
schema?: Uint8Array;
|
|
750
|
+
/** Max body bytes before `requireJsonBody`/`validateBody` fail (default 2 MiB). */
|
|
751
|
+
maxBodyBytes?: number;
|
|
752
|
+
/** Max query bytes before the parse VALID bit clears (default 8192). */
|
|
753
|
+
maxQueryBytes?: number;
|
|
754
|
+
/** Max cookie bytes before the parse VALID bit clears (default 8192). */
|
|
755
|
+
maxCookieBytes?: number;
|
|
756
|
+
/** Max pairs per section (0 = unlimited; default 0). */
|
|
757
|
+
maxPairs?: number;
|
|
758
|
+
}
|
|
759
|
+
/** A compiled per-route native stack (route-wire v3). */
|
|
760
|
+
export interface NativeRoute {
|
|
761
|
+
/** Whether the plan compiled `parseQuery` (the result carries a query section). */
|
|
762
|
+
readonly parseQuery: boolean;
|
|
763
|
+
/** Whether the plan compiled `parseCookies` (the result carries a cookie section). */
|
|
764
|
+
readonly parseCookies: boolean;
|
|
765
|
+
/**
|
|
766
|
+
* Run one request frame through the compiled stack and return the decoded
|
|
767
|
+
* verdict. The frame is `[flags u32][qLen][query][cLen][cookie]([bLen][body])`
|
|
768
|
+
* — build it with {@link packRouteFrame}. Reuses one growable output buffer
|
|
769
|
+
* (the needed-size convention: `0` = real error → throws; `> out.length` =
|
|
770
|
+
* exact required size → retry once).
|
|
771
|
+
*/
|
|
772
|
+
runFrame(frame: Uint8Array): RouteWireResult;
|
|
773
|
+
/** Convenience: pack a `(query, cookie, body)` frame then {@link runFrame}. */
|
|
774
|
+
run(query: string, cookie: string, body: Uint8Array | null): RouteWireResult;
|
|
775
|
+
/** Free the native handle (idempotent; safe to call once at shutdown). */
|
|
776
|
+
destroy(): void;
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Compile a per-route native stack from a plan. Returns a compiled route whose
|
|
780
|
+
* `run`/`runFrame` perform the parse + verdict in ONE native call.
|
|
781
|
+
*
|
|
782
|
+
* @example
|
|
783
|
+
* ```ts
|
|
784
|
+
* const route = createNativeRoute({ parseQuery: true, parseCookies: true })
|
|
785
|
+
* const result = route.run('page=1&limit=20', 'session=abc', null)
|
|
786
|
+
* // result.flags & ROUTE_FLAG.OK → parse succeeded; result.query = [['page','1'],…]
|
|
787
|
+
* ```
|
|
788
|
+
*/
|
|
789
|
+
export declare function createNativeRoute(plan?: NativeRoutePlan): NativeRoute;
|
|
790
|
+
/** A matched dynamic route: the handler map + the extracted path params. */
|
|
791
|
+
export interface PathMatch {
|
|
792
|
+
methods: Record<string, unknown>;
|
|
793
|
+
params: Record<string, string>;
|
|
794
|
+
}
|
|
638
795
|
/** A raw web-standard route handler (`Request` → `Response`), e.g. the
|
|
639
796
|
* health/metrics probes (`livenessHandler`, `readinessHandler`,
|
|
640
797
|
* `healthHandler`, `metricsHandler`). Accepted as `BakedRoute.read` and
|
|
@@ -677,6 +834,22 @@ export interface BakedRoute {
|
|
|
677
834
|
/** Read the body for native validation (default false — framework owns it). */
|
|
678
835
|
readBody?: boolean;
|
|
679
836
|
};
|
|
837
|
+
/**
|
|
838
|
+
* A LEAN native-stack responder route: the route-wire v3 per-route stack
|
|
839
|
+
* (`createNativeRoute`) runs ONLY the plan's stages in ONE native call —
|
|
840
|
+
* no CORS/rate-limit/security/IP/metadata envelope. Wired for `methods`
|
|
841
|
+
* (default GET) by `nativeRouteHandler` (src/ingress/routes/native.ts).
|
|
842
|
+
*/
|
|
843
|
+
native?: {
|
|
844
|
+
/** The route-wire v3 plan (parse/validate stages + limits). */
|
|
845
|
+
plan: NativeRoutePlan;
|
|
846
|
+
/** The JS 2xx builder. */
|
|
847
|
+
handler: NativeResponder;
|
|
848
|
+
/** HTTP methods to wire (default `['GET']`). */
|
|
849
|
+
methods?: ReadonlyArray<string>;
|
|
850
|
+
/** Read the body for `requireJsonBody`/`validateBody` (default false). */
|
|
851
|
+
readBody?: boolean;
|
|
852
|
+
};
|
|
680
853
|
/** Overrides `maxBodyBytes` for this route's write/echo handlers. */
|
|
681
854
|
maxBodyBytes?: number;
|
|
682
855
|
/**
|
|
@@ -770,11 +943,6 @@ export interface GracefulShutdownOptions {
|
|
|
770
943
|
* `process.exit`) to tear down without hanging.
|
|
771
944
|
*/
|
|
772
945
|
export declare function gracefulShutdown(handles: ReadonlyArray<ServerHandle>, options?: GracefulShutdownOptions): () => void;
|
|
773
|
-
/** A matched dynamic route: the handler map + the extracted path params. */
|
|
774
|
-
export interface PathMatch {
|
|
775
|
-
methods: Record<string, unknown>;
|
|
776
|
-
params: Record<string, string>;
|
|
777
|
-
}
|
|
778
946
|
/** Options for `createWebSocketUpgrade` (supported subprotocols). */ export interface WebSocketUpgradeOptions {
|
|
779
947
|
/** Subprotocols this server supports; the first client-requested match wins. */
|
|
780
948
|
protocols?: ReadonlyArray<string>;
|
|
@@ -894,15 +1062,25 @@ export interface RustBatch {
|
|
|
894
1062
|
}
|
|
895
1063
|
/** Raw packed-wire FFI namespace. */
|
|
896
1064
|
export interface RustPacked {
|
|
1065
|
+
/** Packed CRC32 batch: packed `[u8[]]` items → packed u32 results. */
|
|
897
1066
|
crc32BatchPacked(input: Uint8Array): Uint8Array;
|
|
1067
|
+
/** Packed JSON-validity batch: packed `[u8[]]` items → packed 0/1 bitset. */
|
|
898
1068
|
jsonValidBatchPacked(input: Uint8Array): Uint8Array;
|
|
1069
|
+
/** Packed email-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
|
|
899
1070
|
validateEmailBatchPacked(input: Uint8Array): Uint8Array;
|
|
1071
|
+
/** Packed UUID-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
|
|
900
1072
|
validateUuidBatchPacked(input: Uint8Array): Uint8Array;
|
|
1073
|
+
/** Packed IPv4-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
|
|
901
1074
|
validateIpv4BatchPacked(input: Uint8Array): Uint8Array;
|
|
1075
|
+
/** Packed IPv6-validator batch: packed `[u8[]]` items → packed 0/1 bitset. */
|
|
902
1076
|
validateIpv6BatchPacked(input: Uint8Array): Uint8Array;
|
|
1077
|
+
/** Packed JSON-sum batch: packed `[{id}]` docs → packed `[ok u8][sum i64 LE]`. */
|
|
903
1078
|
jsonSumBatchPacked(input: Uint8Array): Uint8Array;
|
|
1079
|
+
/** Packed query-string parser batch: packed `[u8[]]` queries → packed pair lists. */
|
|
904
1080
|
queryParseBatchPacked(input: Uint8Array): Uint8Array;
|
|
1081
|
+
/** Packed cookie-header parser batch: packed `[u8[]]` headers → packed pair lists. */
|
|
905
1082
|
cookieParseBatchPacked(input: Uint8Array): Uint8Array;
|
|
1083
|
+
/** Packed HTTP-request parser batch: packed `[u8[]]` requests → packed request sections. */
|
|
906
1084
|
httpParseRequestBatchPacked(input: Uint8Array): Uint8Array;
|
|
907
1085
|
/** Batch RFC 6902 JSON Patch (two packed lists, zipped) → packed results. */
|
|
908
1086
|
jsonPatchBatchPacked(docs: Uint8Array, patches: Uint8Array): Uint8Array;
|
|
@@ -910,41 +1088,69 @@ export interface RustPacked {
|
|
|
910
1088
|
fnv1A64BatchPacked(input: Uint8Array): Uint8Array;
|
|
911
1089
|
/** Packed ETag batch (10 strong / 12 weak bytes per item). */
|
|
912
1090
|
etagBatchPacked(input: Uint8Array, weak?: boolean | null): Uint8Array;
|
|
1091
|
+
/** Packed percent-encoding batch: packed `[u8[]]` items → packed hex-percent bytes. */
|
|
913
1092
|
urlEncodeBatchPacked(input: Uint8Array): Uint8Array;
|
|
1093
|
+
/** Packed percent-decoding batch: packed `[u8[]]` items → packed decoded bytes (string-safe). */
|
|
914
1094
|
urlDecodeBatchPacked(input: Uint8Array): Uint8Array;
|
|
1095
|
+
/** Packed percent-decoding batch returning raw bytes (`%FF` preserved). */
|
|
915
1096
|
urlDecodeBytesBatchPacked(input: Uint8Array): Uint8Array;
|
|
1097
|
+
/** Packed MIME-lookup batch: packed `[u8[]]` extensions → packed media-type strings. */
|
|
916
1098
|
mimeFromExtensionBatchPacked(input: Uint8Array): Uint8Array;
|
|
1099
|
+
/** Packed WebSocket accept-key batch: packed `[u8[]]` keys → packed base64 SHA-1 results. */
|
|
917
1100
|
wsAcceptKeyBatchPacked(input: Uint8Array): Uint8Array;
|
|
1101
|
+
/** Valid JSON count in a packed JSON batch (0..n; invalid items not counted). */
|
|
918
1102
|
jsonValidBatchCountPacked(input: Uint8Array): number;
|
|
1103
|
+
/** Valid-email count in a packed email batch. */
|
|
919
1104
|
validateEmailBatchCountPacked(input: Uint8Array): number;
|
|
1105
|
+
/** Valid-UUID count in a packed UUID batch. */
|
|
920
1106
|
validateUuidBatchCountPacked(input: Uint8Array): number;
|
|
1107
|
+
/** Valid-IPv4 count in a packed IPv4 batch. */
|
|
921
1108
|
validateIpv4BatchCountPacked(input: Uint8Array): number;
|
|
1109
|
+
/** Valid-IPv6 count in a packed IPv6 batch. */
|
|
922
1110
|
validateIpv6BatchCountPacked(input: Uint8Array): number;
|
|
1111
|
+
/** Total `id` sum across a packed JSON batch (valid items only). */
|
|
923
1112
|
jsonSumBatchTotalPacked(input: Uint8Array): number;
|
|
1113
|
+
/** Total packed-output length (bytes) a query batch will produce. */
|
|
924
1114
|
queryParseBatchTotalLenPacked(input: Uint8Array): number;
|
|
1115
|
+
/** Total packed-output length (bytes) a cookie batch will produce. */
|
|
925
1116
|
cookieParseBatchTotalLenPacked(input: Uint8Array): number;
|
|
1117
|
+
/** Total packed-output length (bytes) an HTTP-request batch will produce. */
|
|
926
1118
|
httpParseRequestBatchTotalLenPacked(input: Uint8Array): number;
|
|
1119
|
+
/** Packed Argon2id-hash batch: packed `[u8[]]` passwords + shared salt → packed PHC strings. */
|
|
927
1120
|
passwordHashBatchPacked(input: Uint8Array, salt: Uint8Array, options?: PasswordHashOptions | null): Uint8Array;
|
|
928
1121
|
/** Packed password-verify batch (two packed lists, zipped) → bitset. */
|
|
929
1122
|
passwordVerifyBatchPacked(passwords: Uint8Array, phcs: Uint8Array): Uint8Array;
|
|
930
1123
|
/** Packed URL-resolve batch (two packed lists, zipped) → packed results. */
|
|
931
1124
|
urlResolveBatchPacked(bases: Uint8Array, references: Uint8Array): Uint8Array;
|
|
1125
|
+
/** Packed AEAD-encrypt batch (packed inputs + shared key/nonce) → packed ciphertexts. */
|
|
932
1126
|
aeadEncryptBatchPacked(input: Uint8Array, key: Uint8Array, nonce: Uint8Array, algorithm?: string | null): Uint8Array;
|
|
1127
|
+
/** Packed AEAD-decrypt batch (packed inputs + shared key/nonce) → packed plaintexts. */
|
|
933
1128
|
aeadDecryptBatchPacked(input: Uint8Array, key: Uint8Array, nonce: Uint8Array, algorithm?: string | null): Uint8Array;
|
|
1129
|
+
/** Packed gzip-compress batch: packed `[u8[]]` items → packed gzip streams. */
|
|
934
1130
|
gzipCompressBatchPacked(input: Uint8Array, level?: number | null): Uint8Array;
|
|
1131
|
+
/** Packed gzip-decompress batch (64 MiB cap per item) → packed plaintexts. */
|
|
935
1132
|
gzipDecompressBatchPacked(input: Uint8Array): Uint8Array;
|
|
1133
|
+
/** Packed brotli-compress batch: packed `[u8[]]` items → packed brotli streams. */
|
|
936
1134
|
brotliCompressBatchPacked(input: Uint8Array, quality?: number | null): Uint8Array;
|
|
1135
|
+
/** Packed brotli-decompress batch (64 MiB cap per item) → packed plaintexts. */
|
|
937
1136
|
brotliDecompressBatchPacked(input: Uint8Array): Uint8Array;
|
|
1137
|
+
/** Packed HS256 JWT-sign batch (packed claims + shared secret) → packed tokens. */
|
|
938
1138
|
jwtSignBatchPacked(input: Uint8Array, secret: Uint8Array, ttlSeconds: number | null, nowSeconds: number): Uint8Array;
|
|
1139
|
+
/** Packed HS256 JWT-verify batch (packed tokens + shared secret) → packed claims/validity. */
|
|
939
1140
|
jwtVerifyBatchPacked(input: Uint8Array, secret: Uint8Array, nowSeconds: number): Uint8Array;
|
|
940
1141
|
/** Batch HMAC-SHA256 sign (packed in → hex-signature byte results). */
|
|
941
1142
|
hmacSha256BatchPacked(input: Uint8Array, key: Uint8Array): Uint8Array;
|
|
942
1143
|
/** Batch HMAC-SHA256 verify (two packed lists: data + hex sigs, zipped) → bitset. */
|
|
943
1144
|
hmacSha256VerifyBatchPacked(input: Uint8Array, sigs: Uint8Array, key: Uint8Array): Uint8Array;
|
|
1145
|
+
/** Packed multipart/form-data parser batch (packed bodies + shared boundary) → packed parts. */
|
|
944
1146
|
multipartParseBatchPacked(input: Uint8Array, boundary: Uint8Array): Uint8Array;
|
|
1147
|
+
/** Packed minijinja template batch: packed contexts + shared source → packed renders. */
|
|
945
1148
|
templateRenderBatchPacked(input: Uint8Array, source: string): Uint8Array;
|
|
1149
|
+
/** Packed SSE-frame batch: packed data + shared event/id/retry → packed frames. */
|
|
946
1150
|
sseEncodeBatchPacked(input: Uint8Array, event: string | null, id: string | null, retry: number | null): Uint8Array;
|
|
1151
|
+
/** Packed WebSocket-frame encode batch: packed payloads + shared opcode/mask/fin → packed frames. */
|
|
947
1152
|
wsFrameEncodeBatchPacked(input: Uint8Array, opcode: number, mask: boolean, fin: boolean): Uint8Array;
|
|
1153
|
+
/** Packed WebSocket-frame decode batch: packed frames → packed (fin, opcode, payload) results. */
|
|
948
1154
|
wsFrameDecodeBatchPacked(input: Uint8Array): Uint8Array;
|
|
949
1155
|
}
|
|
950
1156
|
/**
|
|
@@ -1902,6 +2108,28 @@ export interface RouterRouteSpec {
|
|
|
1902
2108
|
/** Read the body for native validation (default false — framework owns it). */
|
|
1903
2109
|
readBody?: boolean;
|
|
1904
2110
|
};
|
|
2111
|
+
/**
|
|
2112
|
+
* A LEAN native-stack responder route: the route-wire v3 per-route stack
|
|
2113
|
+
* (`createNativeRoute` over `castrum_route_*`) runs ONLY the stages in
|
|
2114
|
+
* `plan` (parseQuery/parseCookies/requireJsonBody/validateBody) in ONE
|
|
2115
|
+
* native call — no CORS/rate-limit/security/IP/metadata envelope. On a
|
|
2116
|
+
* verdict failure the route rejects (400 non-JSON / 422 schema); on success
|
|
2117
|
+
* the responder builds the 2xx from the decoded snapshot. Measured ~580ns
|
|
2118
|
+
* cheaper per request than the full-pipeline responder on a
|
|
2119
|
+
* parseQuery+parseCookies route (bench/cost/native-route-vs-router.ts).
|
|
2120
|
+
* Wired for `methods` (default `['GET']`). When set, `read`/`write`/etc.
|
|
2121
|
+
* for this route are ignored.
|
|
2122
|
+
*/
|
|
2123
|
+
native?: {
|
|
2124
|
+
/** The route-wire v3 plan (parse/validate stages + limits). */
|
|
2125
|
+
plan: NativeRoutePlan;
|
|
2126
|
+
/** The JS 2xx builder (receives the decoded query/cookies/body snapshot). */
|
|
2127
|
+
handler: NativeResponder;
|
|
2128
|
+
/** HTTP methods to wire (default `['GET']`). */
|
|
2129
|
+
methods?: ReadonlyArray<string>;
|
|
2130
|
+
/** Read the body for `requireJsonBody`/`validateBody` (default false). */
|
|
2131
|
+
readBody?: boolean;
|
|
2132
|
+
};
|
|
1905
2133
|
/** Terminal envelope style for this route's responder (default: router-level
|
|
1906
2134
|
* `terminalStyle` or `'castrum'`). */
|
|
1907
2135
|
terminalStyle?: TerminalStyle;
|
|
@@ -1981,6 +2209,9 @@ export declare function createIngressRouter(options: CreateIngressRouterOptions)
|
|
|
1981
2209
|
*
|
|
1982
2210
|
* The callback runs on the fast-path result and MUST be synchronous. Use
|
|
1983
2211
|
* {@link createIngress} when you want automatic body reading + error contexts.
|
|
2212
|
+
*
|
|
2213
|
+
* @param options fast-path ingress options
|
|
2214
|
+
* @returns a sync handler (callback must be synchronous)
|
|
1984
2215
|
*/
|
|
1985
2216
|
export declare function createIngressSync(options?: IngressOptions): SyncIngressHandler;
|
|
1986
2217
|
/**
|
|
@@ -1989,6 +2220,9 @@ export declare function createIngressSync(options?: IngressOptions): SyncIngress
|
|
|
1989
2220
|
*
|
|
1990
2221
|
* Recommended default for serverless/edge-style `fetch` handlers. For maximum
|
|
1991
2222
|
* throughput use `createIngressFast` / `createIngressSync` directly.
|
|
2223
|
+
*
|
|
2224
|
+
* @param options fast-path ingress options (security applied here, not forwarded)
|
|
2225
|
+
* @returns an async handler returning a snapshot context
|
|
1992
2226
|
*/
|
|
1993
2227
|
export declare function createIngress(options?: IngressOptions): IngressHandler;
|
|
1994
2228
|
/** Readonly snapshot of the ingress decision, safe after `run()` returns. */
|