@daloyjs/core 1.0.0-beta.5 → 1.0.0-beta.7
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 +2 -1
- package/dist/adapters/bun.d.ts +13 -1
- package/dist/adapters/bun.js +8 -1
- package/dist/adapters/cloudflare.d.ts +7 -1
- package/dist/adapters/cloudflare.js +6 -1
- package/dist/adapters/deno.d.ts +11 -1
- package/dist/adapters/deno.js +8 -1
- package/dist/adapters/fastly.d.ts +12 -2
- package/dist/adapters/fastly.js +12 -2
- package/dist/adapters/lambda.d.ts +37 -1
- package/dist/adapters/lambda.js +6 -1
- package/dist/adapters/node.d.ts +12 -1
- package/dist/adapters/node.js +7 -1
- package/dist/adapters/vercel.d.ts +13 -1
- package/dist/adapters/vercel.js +12 -1
- package/dist/app.d.ts +67 -17
- package/dist/app.js +97 -31
- package/dist/banner.d.ts +6 -0
- package/dist/banner.js +6 -0
- package/dist/cli.d.ts +35 -0
- package/dist/cli.js +23 -1
- package/dist/combine.d.ts +8 -0
- package/dist/combine.js +8 -0
- package/dist/compression.d.ts +3 -0
- package/dist/compression.js +3 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +4 -0
- package/dist/conn-info.d.ts +35 -2
- package/dist/conn-info.js +35 -2
- package/dist/contract.d.ts +2 -0
- package/dist/contract.js +2 -0
- package/dist/cookie.d.ts +12 -0
- package/dist/cookie.js +12 -0
- package/dist/dependency.d.ts +4 -0
- package/dist/dependency.js +3 -0
- package/dist/discriminator.d.ts +13 -0
- package/dist/discriminator.js +23 -1
- package/dist/docs.d.ts +78 -0
- package/dist/docs.js +21 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +14 -0
- package/dist/etag.d.ts +2 -0
- package/dist/etag.js +2 -0
- package/dist/fetch-guard.d.ts +7 -0
- package/dist/fetch-guard.js +7 -0
- package/dist/fetch-resilience.d.ts +4 -0
- package/dist/fetch-resilience.js +4 -0
- package/dist/http-signatures.d.ts +32 -0
- package/dist/http-signatures.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/ip-restriction.d.ts +40 -3
- package/dist/ip-restriction.js +35 -3
- package/dist/jwk.d.ts +12 -1
- package/dist/jwk.js +6 -0
- package/dist/jwt.d.ts +14 -0
- package/dist/jwt.js +10 -0
- package/dist/load-shedding.d.ts +3 -0
- package/dist/load-shedding.js +3 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.js +3 -0
- package/dist/mcp.d.ts +574 -0
- package/dist/mcp.js +623 -0
- package/dist/middleware.d.ts +68 -0
- package/dist/middleware.js +17 -0
- package/dist/mtls.d.ts +19 -2
- package/dist/mtls.js +12 -2
- package/dist/multipart.d.ts +42 -5
- package/dist/multipart.js +41 -5
- package/dist/openapi.d.ts +15 -9
- package/dist/openapi.js +6 -9
- package/dist/rate-limit-redis.d.ts +21 -2
- package/dist/rate-limit-redis.js +17 -2
- package/dist/safe-redirect.d.ts +6 -0
- package/dist/safe-redirect.js +6 -0
- package/dist/sbom.cdx.json +9 -9
- package/dist/sbom.spdx.json +5 -5
- package/dist/scheduler.d.ts +4 -0
- package/dist/schema.d.ts +25 -0
- package/dist/security-schemes.d.ts +50 -0
- package/dist/security-schemes.js +6 -0
- package/dist/security.d.ts +33 -0
- package/dist/security.js +28 -10
- package/dist/session.d.ts +34 -5
- package/dist/session.js +31 -5
- package/dist/streaming.d.ts +19 -0
- package/dist/streaming.js +16 -0
- package/dist/subdomains.d.ts +4 -0
- package/dist/subdomains.js +4 -0
- package/dist/time-claims.d.ts +22 -2
- package/dist/time-claims.js +6 -0
- package/dist/tracing.d.ts +12 -0
- package/dist/tracing.js +6 -0
- package/dist/types.d.ts +70 -1
- package/dist/waf.js +21 -1
- package/dist/webhook-delivery.d.ts +6 -0
- package/dist/webhook-delivery.js +5 -0
- package/dist/websocket.d.ts +137 -4
- package/dist/websocket.js +105 -4
- package/package.json +6 -1
package/dist/middleware.d.ts
CHANGED
|
@@ -78,16 +78,38 @@ export interface CspDirectivesOptions {
|
|
|
78
78
|
}
|
|
79
79
|
/** Options for {@link secureHeaders}. Every field can be disabled with `false`. */
|
|
80
80
|
export interface SecureHeadersOptions {
|
|
81
|
+
/**
|
|
82
|
+
* `Content-Security-Policy` value: a raw header string, a
|
|
83
|
+
* {@link CspDirectivesOptions} object (enables nonces / Trusted Types),
|
|
84
|
+
* or `false` to omit. Defaults to
|
|
85
|
+
* `"default-src 'self'; frame-ancestors 'none'"`.
|
|
86
|
+
*/
|
|
81
87
|
contentSecurityPolicy?: string | false | CspDirectivesOptions;
|
|
88
|
+
/**
|
|
89
|
+
* `Strict-Transport-Security` settings (`maxAgeSeconds` in seconds).
|
|
90
|
+
* Defaults to `{ maxAgeSeconds: 31536000, includeSubDomains: true }`.
|
|
91
|
+
*/
|
|
82
92
|
hsts?: {
|
|
83
93
|
maxAgeSeconds: number;
|
|
84
94
|
includeSubDomains?: boolean;
|
|
85
95
|
preload?: boolean;
|
|
86
96
|
} | false;
|
|
97
|
+
/**
|
|
98
|
+
* `X-Frame-Options` value. Defaults to `"DENY"`. Disabling it with
|
|
99
|
+
* `false` while the CSP also lacks `frame-ancestors` throws at
|
|
100
|
+
* construction time (clickjacking guard).
|
|
101
|
+
*/
|
|
87
102
|
frameOptions?: "DENY" | "SAMEORIGIN" | false;
|
|
103
|
+
/** `Referrer-Policy` value. Defaults to `"no-referrer"`. */
|
|
88
104
|
referrerPolicy?: string | false;
|
|
105
|
+
/**
|
|
106
|
+
* `Permissions-Policy` value. Defaults to
|
|
107
|
+
* `"camera=(), microphone=(), geolocation=(), clipboard-write=()"`.
|
|
108
|
+
*/
|
|
89
109
|
permissionsPolicy?: string | false;
|
|
110
|
+
/** `Cross-Origin-Opener-Policy` value. Defaults to `"same-origin"`. */
|
|
90
111
|
crossOriginOpenerPolicy?: string | false;
|
|
112
|
+
/** `Cross-Origin-Resource-Policy` value. Defaults to `"same-origin"`. */
|
|
91
113
|
crossOriginResourcePolicy?: string | false;
|
|
92
114
|
/**
|
|
93
115
|
* `Cross-Origin-Embedder-Policy` (COEP). Off by default because
|
|
@@ -101,7 +123,12 @@ export interface SecureHeadersOptions {
|
|
|
101
123
|
* @since 0.37.0
|
|
102
124
|
*/
|
|
103
125
|
crossOriginEmbedderPolicy?: "require-corp" | "credentialless" | "unsafe-none" | false;
|
|
126
|
+
/** Emit `X-Content-Type-Options: nosniff`. Defaults to `true`. */
|
|
104
127
|
noSniff?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Emit `X-XSS-Protection: 0` (disables the legacy XSS auditor, per
|
|
130
|
+
* modern guidance). Defaults to `false` (header omitted).
|
|
131
|
+
*/
|
|
105
132
|
xssProtection?: boolean;
|
|
106
133
|
/**
|
|
107
134
|
* Reporting API endpoint declarations rendered as the
|
|
@@ -165,6 +192,11 @@ export declare const SECURE_HEADERS_MARKER: unique symbol;
|
|
|
165
192
|
* {@link SecureHeadersOptions} for the full list). Pass `false` for any
|
|
166
193
|
* field to disable that header; handler-set headers always win.
|
|
167
194
|
*
|
|
195
|
+
* @param opts - Per-header overrides. Pass `false` to disable a header.
|
|
196
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)`, stamped with
|
|
197
|
+
* {@link SECURE_HEADERS_MARKER}.
|
|
198
|
+
* @throws {Error} When `frameOptions: false` is combined with a CSP that has
|
|
199
|
+
* no `frame-ancestors` directive (would disable every clickjacking defense).
|
|
168
200
|
* @since 0.1.0
|
|
169
201
|
*/
|
|
170
202
|
export declare function secureHeaders(opts?: SecureHeadersOptions): Hooks;
|
|
@@ -286,11 +318,30 @@ export declare const CSRF_HOOK_MARKER: unique symbol;
|
|
|
286
318
|
export type CorsOriginAllow = (origin: string) => boolean;
|
|
287
319
|
/** Options for {@link cors}. */
|
|
288
320
|
export interface CorsOptions {
|
|
321
|
+
/**
|
|
322
|
+
* Allowed cross-origin caller(s): a single origin string, an array of
|
|
323
|
+
* origins, or a predicate. `"*"` is rejected with `credentials: true`
|
|
324
|
+
* and refused at boot on production `secureDefaults` apps.
|
|
325
|
+
*/
|
|
289
326
|
origin: string | string[] | ((origin: string) => boolean);
|
|
327
|
+
/**
|
|
328
|
+
* Verbs advertised on preflight (`Access-Control-Allow-Methods`).
|
|
329
|
+
* Defaults to `["GET", "HEAD", "POST"]`. `"*"` is rejected.
|
|
330
|
+
*/
|
|
290
331
|
methods?: string[];
|
|
332
|
+
/**
|
|
333
|
+
* Request headers advertised on preflight (`Access-Control-Allow-Headers`).
|
|
334
|
+
* Defaults to `["content-type", "authorization"]`.
|
|
335
|
+
*/
|
|
291
336
|
allowedHeaders?: string[];
|
|
337
|
+
/** Response headers exposed to browser JS (`Access-Control-Expose-Headers`). None by default. */
|
|
292
338
|
exposedHeaders?: string[];
|
|
339
|
+
/**
|
|
340
|
+
* Emit `Access-Control-Allow-Credentials: true`. Defaults to `false`.
|
|
341
|
+
* Cannot be combined with a wildcard `origin`.
|
|
342
|
+
*/
|
|
293
343
|
credentials?: boolean;
|
|
344
|
+
/** Preflight cache lifetime in seconds (`Access-Control-Max-Age`). Defaults to `600`. */
|
|
294
345
|
maxAgeSeconds?: number;
|
|
295
346
|
}
|
|
296
347
|
/**
|
|
@@ -327,6 +378,11 @@ export declare function cors(opts: CorsOptions): Hooks;
|
|
|
327
378
|
* (`@daloyjs/core/rate-limit-redis`).
|
|
328
379
|
*/
|
|
329
380
|
export interface RateLimitStore {
|
|
381
|
+
/**
|
|
382
|
+
* Record one request for `key` in the window of `windowMs` milliseconds
|
|
383
|
+
* and return the updated `count` plus the window's absolute reset time
|
|
384
|
+
* (`resetMs`, epoch milliseconds).
|
|
385
|
+
*/
|
|
330
386
|
hit(key: string, windowMs: number): Promise<{
|
|
331
387
|
count: number;
|
|
332
388
|
resetMs: number;
|
|
@@ -437,6 +493,9 @@ export interface LoginThrottleOptions {
|
|
|
437
493
|
* same `groupId`) across related routes so an attacker cannot bypass the limit
|
|
438
494
|
* by rotating between password, OTP, and reset endpoints.
|
|
439
495
|
*
|
|
496
|
+
* @param opts - Throttle tuning (see {@link LoginThrottleOptions}); every field has a safe default.
|
|
497
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)` or per-route `hooks`.
|
|
498
|
+
* @throws {Error} When `windowMs`/`max` are not positive integers or the delay options are negative.
|
|
440
499
|
* @since 0.23.0
|
|
441
500
|
*/
|
|
442
501
|
export declare function loginThrottle(opts?: LoginThrottleOptions): Hooks;
|
|
@@ -627,6 +686,11 @@ export interface CsrfOptions {
|
|
|
627
686
|
* allowedOrigins: ["https://app.example.com"],
|
|
628
687
|
* }));
|
|
629
688
|
* ```
|
|
689
|
+
*
|
|
690
|
+
* @param opts - Strategy, cookie/header names, and cookie attributes (see {@link CsrfOptions}).
|
|
691
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)`, stamped with {@link CSRF_HOOK_MARKER}.
|
|
692
|
+
* @throws {Error} When `strategy` is unknown or the cookie name/attributes are invalid
|
|
693
|
+
* (e.g. `__Host-` prefix without `secure: true`, `path: "/"`, and no `domain`).
|
|
630
694
|
*/
|
|
631
695
|
export declare function csrf(opts?: CsrfOptions): Hooks;
|
|
632
696
|
/** Options for {@link basicAuth}. */
|
|
@@ -723,6 +787,10 @@ export declare const REQUIRE_SCOPES_HOOK_MARKER: unique symbol;
|
|
|
723
787
|
* });
|
|
724
788
|
* ```
|
|
725
789
|
*
|
|
790
|
+
* @param scopes - Required scope strings; must be non-empty and free of RFC 6749 illegal characters.
|
|
791
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)` or per-route `hooks`,
|
|
792
|
+
* stamped with {@link REQUIRE_SCOPES_HOOK_MARKER}.
|
|
793
|
+
* @throws {Error} When `scopes` is empty or contains a non-string, empty, or illegal-character scope.
|
|
726
794
|
* @since 0.21.0
|
|
727
795
|
*/
|
|
728
796
|
export declare function requireScopes(scopes: readonly string[]): Hooks;
|
package/dist/middleware.js
CHANGED
|
@@ -148,6 +148,11 @@ export const SECURE_HEADERS_MARKER = Symbol.for("daloyjs.middleware.secureHeader
|
|
|
148
148
|
* {@link SecureHeadersOptions} for the full list). Pass `false` for any
|
|
149
149
|
* field to disable that header; handler-set headers always win.
|
|
150
150
|
*
|
|
151
|
+
* @param opts - Per-header overrides. Pass `false` to disable a header.
|
|
152
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)`, stamped with
|
|
153
|
+
* {@link SECURE_HEADERS_MARKER}.
|
|
154
|
+
* @throws {Error} When `frameOptions: false` is combined with a CSP that has
|
|
155
|
+
* no `frame-ancestors` directive (would disable every clickjacking defense).
|
|
151
156
|
* @since 0.1.0
|
|
152
157
|
*/
|
|
153
158
|
export function secureHeaders(opts = {}) {
|
|
@@ -706,6 +711,9 @@ function wait(ms) {
|
|
|
706
711
|
* same `groupId`) across related routes so an attacker cannot bypass the limit
|
|
707
712
|
* by rotating between password, OTP, and reset endpoints.
|
|
708
713
|
*
|
|
714
|
+
* @param opts - Throttle tuning (see {@link LoginThrottleOptions}); every field has a safe default.
|
|
715
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)` or per-route `hooks`.
|
|
716
|
+
* @throws {Error} When `windowMs`/`max` are not positive integers or the delay options are negative.
|
|
709
717
|
* @since 0.23.0
|
|
710
718
|
*/
|
|
711
719
|
export function loginThrottle(opts = {}) {
|
|
@@ -912,6 +920,11 @@ function csrfCookieAttributes(opts) {
|
|
|
912
920
|
* allowedOrigins: ["https://app.example.com"],
|
|
913
921
|
* }));
|
|
914
922
|
* ```
|
|
923
|
+
*
|
|
924
|
+
* @param opts - Strategy, cookie/header names, and cookie attributes (see {@link CsrfOptions}).
|
|
925
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)`, stamped with {@link CSRF_HOOK_MARKER}.
|
|
926
|
+
* @throws {Error} When `strategy` is unknown or the cookie name/attributes are invalid
|
|
927
|
+
* (e.g. `__Host-` prefix without `secure: true`, `path: "/"`, and no `domain`).
|
|
915
928
|
*/
|
|
916
929
|
export function csrf(opts = {}) {
|
|
917
930
|
const strategy = opts.strategy ?? "double-submit";
|
|
@@ -1191,6 +1204,10 @@ function readUserScopes(user) {
|
|
|
1191
1204
|
* });
|
|
1192
1205
|
* ```
|
|
1193
1206
|
*
|
|
1207
|
+
* @param scopes - Required scope strings; must be non-empty and free of RFC 6749 illegal characters.
|
|
1208
|
+
* @returns A {@link Hooks} bundle ready for `app.use(...)` or per-route `hooks`,
|
|
1209
|
+
* stamped with {@link REQUIRE_SCOPES_HOOK_MARKER}.
|
|
1210
|
+
* @throws {Error} When `scopes` is empty or contains a non-string, empty, or illegal-character scope.
|
|
1194
1211
|
* @since 0.21.0
|
|
1195
1212
|
*/
|
|
1196
1213
|
export function requireScopes(scopes) {
|
package/dist/mtls.d.ts
CHANGED
|
@@ -84,6 +84,9 @@ export type ClientCertificateSource = ClientCertificate | undefined | (() => Cli
|
|
|
84
84
|
* Pass a thunk to defer the read until {@link getClientCertificate} is first
|
|
85
85
|
* called; the resolved value is cached back onto the request.
|
|
86
86
|
*
|
|
87
|
+
* @param request The incoming request to stash the certificate on.
|
|
88
|
+
* @param source The certificate, a lazy thunk producing one, or `undefined`
|
|
89
|
+
* when the connection presented no client certificate.
|
|
87
90
|
* @since 0.37.0
|
|
88
91
|
*/
|
|
89
92
|
export declare function setClientCertificate(request: Request, source: ClientCertificateSource): void;
|
|
@@ -93,6 +96,8 @@ export declare function setClientCertificate(request: Request, source: ClientCer
|
|
|
93
96
|
* adapter does not expose TLS peer info). If a lazy thunk was stashed, it is
|
|
94
97
|
* resolved once and the result cached.
|
|
95
98
|
*
|
|
99
|
+
* @param request The request previously seen by {@link setClientCertificate}.
|
|
100
|
+
* @returns The attached certificate, or `undefined` when none was presented.
|
|
96
101
|
* @since 0.37.0
|
|
97
102
|
*/
|
|
98
103
|
export declare function getClientCertificate(request: Request): ClientCertificate | undefined;
|
|
@@ -104,12 +109,19 @@ export declare function getClientCertificate(request: Request): ClientCertificat
|
|
|
104
109
|
* @since 0.37.0
|
|
105
110
|
*/
|
|
106
111
|
export interface PeerCertificateLike {
|
|
112
|
+
/** Subject RDN attributes keyed by short name (e.g. `CN`, `O`). */
|
|
107
113
|
subject?: Record<string, string | string[]> | null;
|
|
114
|
+
/** Issuer RDN attributes keyed by short name. */
|
|
108
115
|
issuer?: Record<string, string | string[]> | null;
|
|
116
|
+
/** Validity start as a Node-formatted date string. */
|
|
109
117
|
valid_from?: string;
|
|
118
|
+
/** Validity end as a Node-formatted date string. */
|
|
110
119
|
valid_to?: string;
|
|
120
|
+
/** SHA-256 fingerprint, colon-delimited hex as Node emits it. */
|
|
111
121
|
fingerprint256?: string;
|
|
122
|
+
/** Certificate serial number as a hex string. */
|
|
112
123
|
serialNumber?: string;
|
|
124
|
+
/** Subject Alternative Names rendered as `DNS:a, IP Address:1.2.3.4, ...`. */
|
|
113
125
|
subjectaltname?: string;
|
|
114
126
|
}
|
|
115
127
|
/**
|
|
@@ -120,6 +132,9 @@ export interface PeerCertificateLike {
|
|
|
120
132
|
* @param raw - The structured peer-certificate object from the TLS socket.
|
|
121
133
|
* @param verified - Whether the socket reported `authorized === true` (the
|
|
122
134
|
* chain was verified against the configured CA).
|
|
135
|
+
* @returns The normalized certificate, or `undefined` when `raw` is missing
|
|
136
|
+
* or carries no identifying fields (no subject, issuer, fingerprint, or
|
|
137
|
+
* serial).
|
|
123
138
|
* @since 0.37.0
|
|
124
139
|
*/
|
|
125
140
|
export declare function normalizePeerCertificate(raw: PeerCertificateLike | null | undefined, verified: boolean): ClientCertificate | undefined;
|
|
@@ -131,8 +146,10 @@ export declare function normalizePeerCertificate(raw: PeerCertificateLike | null
|
|
|
131
146
|
* and is the one returned. Because Envoy only emits XFCC for connections it
|
|
132
147
|
* mutually authenticated, the result is marked `verified: true`.
|
|
133
148
|
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
149
|
+
* @param headerValue Raw XFCC header value; `null`/`undefined` are tolerated.
|
|
150
|
+
* @returns The certificate parsed from the first XFCC element, or `undefined`
|
|
151
|
+
* for an empty or unparseable header. Only trust this header behind a proxy
|
|
152
|
+
* you control that strips client-supplied XFCC.
|
|
136
153
|
* @since 0.37.0
|
|
137
154
|
*/
|
|
138
155
|
export declare function parseForwardedClientCert(headerValue: string | null | undefined): ClientCertificate | undefined;
|
package/dist/mtls.js
CHANGED
|
@@ -36,6 +36,9 @@ const CLIENT_CERT_SYMBOL = Symbol.for("daloyjs.clientCertificate");
|
|
|
36
36
|
* Pass a thunk to defer the read until {@link getClientCertificate} is first
|
|
37
37
|
* called; the resolved value is cached back onto the request.
|
|
38
38
|
*
|
|
39
|
+
* @param request The incoming request to stash the certificate on.
|
|
40
|
+
* @param source The certificate, a lazy thunk producing one, or `undefined`
|
|
41
|
+
* when the connection presented no client certificate.
|
|
39
42
|
* @since 0.37.0
|
|
40
43
|
*/
|
|
41
44
|
export function setClientCertificate(request, source) {
|
|
@@ -47,6 +50,8 @@ export function setClientCertificate(request, source) {
|
|
|
47
50
|
* adapter does not expose TLS peer info). If a lazy thunk was stashed, it is
|
|
48
51
|
* resolved once and the result cached.
|
|
49
52
|
*
|
|
53
|
+
* @param request The request previously seen by {@link setClientCertificate}.
|
|
54
|
+
* @returns The attached certificate, or `undefined` when none was presented.
|
|
50
55
|
* @since 0.37.0
|
|
51
56
|
*/
|
|
52
57
|
export function getClientCertificate(request) {
|
|
@@ -67,6 +72,9 @@ export function getClientCertificate(request) {
|
|
|
67
72
|
* @param raw - The structured peer-certificate object from the TLS socket.
|
|
68
73
|
* @param verified - Whether the socket reported `authorized === true` (the
|
|
69
74
|
* chain was verified against the configured CA).
|
|
75
|
+
* @returns The normalized certificate, or `undefined` when `raw` is missing
|
|
76
|
+
* or carries no identifying fields (no subject, issuer, fingerprint, or
|
|
77
|
+
* serial).
|
|
70
78
|
* @since 0.37.0
|
|
71
79
|
*/
|
|
72
80
|
export function normalizePeerCertificate(raw, verified) {
|
|
@@ -205,8 +213,10 @@ function cnFromDN(dn) {
|
|
|
205
213
|
* and is the one returned. Because Envoy only emits XFCC for connections it
|
|
206
214
|
* mutually authenticated, the result is marked `verified: true`.
|
|
207
215
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
216
|
+
* @param headerValue Raw XFCC header value; `null`/`undefined` are tolerated.
|
|
217
|
+
* @returns The certificate parsed from the first XFCC element, or `undefined`
|
|
218
|
+
* for an empty or unparseable header. Only trust this header behind a proxy
|
|
219
|
+
* you control that strips client-supplied XFCC.
|
|
210
220
|
* @since 0.37.0
|
|
211
221
|
*/
|
|
212
222
|
export function parseForwardedClientCert(headerValue) {
|
package/dist/multipart.d.ts
CHANGED
|
@@ -114,6 +114,7 @@ export type UploadedFile = Blob & {
|
|
|
114
114
|
* emit `format: binary`/`byte` accordingly.
|
|
115
115
|
*/
|
|
116
116
|
export interface FileFieldSchema<Output = UploadedFile> extends StandardSchemaV1<unknown, Output> {
|
|
117
|
+
/** Resolved {@link FileFieldOptions} (with `format` defaulted) stamped on the schema for OpenAPI generation. */
|
|
117
118
|
readonly [FILE_FIELD_MARKER]: Required<Pick<FileFieldOptions, "format">> & FileFieldOptions;
|
|
118
119
|
}
|
|
119
120
|
/**
|
|
@@ -122,13 +123,26 @@ export interface FileFieldSchema<Output = UploadedFile> extends StandardSchemaV1
|
|
|
122
123
|
* Use inside a `multipartObject({...})` body schema, or directly inside any
|
|
123
124
|
* Standard-Schema-compatible object schema (Zod, Valibot, ...). DaloyJS
|
|
124
125
|
* keeps the underlying `File` reference so handlers can stream the body.
|
|
126
|
+
*
|
|
127
|
+
* @param options - Field constraints with `optional: true`; `null`/`undefined` values pass through.
|
|
128
|
+
* @returns A {@link FileFieldSchema} whose output may be `null`/`undefined`.
|
|
125
129
|
*/
|
|
126
130
|
export declare function fileField(options: FileFieldOptions & {
|
|
127
131
|
optional: true;
|
|
128
132
|
}): FileFieldSchema<UploadedFile | null | undefined>;
|
|
129
|
-
/**
|
|
133
|
+
/**
|
|
134
|
+
* Validator for a required single uploaded `File`/`Blob` field.
|
|
135
|
+
*
|
|
136
|
+
* @param options - Field constraints (`maxBytes`, `accept`, `filename`, `magicBytes`, ...).
|
|
137
|
+
* @returns A {@link FileFieldSchema} that rejects missing or non-file values.
|
|
138
|
+
*/
|
|
130
139
|
export declare function fileField(options?: FileFieldOptions): FileFieldSchema<UploadedFile>;
|
|
131
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Type-only check used by the OpenAPI generator.
|
|
142
|
+
*
|
|
143
|
+
* @param s - Candidate value to test for the `FILE_FIELD_MARKER` key.
|
|
144
|
+
* @returns `true` when `s` is a {@link fileField}-produced schema.
|
|
145
|
+
*/
|
|
132
146
|
export declare function isFileFieldSchema(s: unknown): s is FileFieldSchema;
|
|
133
147
|
/** Options for {@link multipartObject}. */
|
|
134
148
|
export interface MultipartObjectOptions {
|
|
@@ -154,15 +168,38 @@ interface MultipartSchema<S extends MultipartShape> extends StandardSchemaV1<Rec
|
|
|
154
168
|
* body. Each entry in `shape` validates one form field by name. File fields
|
|
155
169
|
* should use {@link fileField}; non-file fields can use any Standard-Schema
|
|
156
170
|
* validator (`z.string()`, `v.number()`, ...).
|
|
171
|
+
*
|
|
172
|
+
* @param shape - Record mapping form-field names to per-field validators.
|
|
173
|
+
* @param options - `strict: true` rejects undeclared extra fields. Defaults
|
|
174
|
+
* to `{ strict: false }` (extras pass through unvalidated).
|
|
175
|
+
* @returns A marker-carrying schema the OpenAPI generator renders as
|
|
176
|
+
* `multipart/form-data`; validation issues are prefixed with the field name.
|
|
157
177
|
*/
|
|
158
178
|
export declare function multipartObject<S extends MultipartShape>(shape: S, options?: MultipartObjectOptions): MultipartSchema<S>;
|
|
159
|
-
/**
|
|
179
|
+
/**
|
|
180
|
+
* Type-only check used by the OpenAPI generator and request-body parser.
|
|
181
|
+
*
|
|
182
|
+
* @param s - Candidate value to test for the `MULTIPART_SCHEMA_MARKER` key.
|
|
183
|
+
* @returns `true` when `s` is a {@link multipartObject}-produced schema.
|
|
184
|
+
*/
|
|
160
185
|
export declare function isMultipartObjectSchema(s: unknown): s is MultipartSchema<MultipartShape>;
|
|
161
|
-
/**
|
|
186
|
+
/**
|
|
187
|
+
* Internal: pull the multipart shape so the OpenAPI generator can walk it.
|
|
188
|
+
*
|
|
189
|
+
* @param s - Candidate schema value.
|
|
190
|
+
* @returns The `{ shape, strict }` config stored under the multipart marker,
|
|
191
|
+
* or `undefined` when `s` is not a {@link multipartObject} schema.
|
|
192
|
+
*/
|
|
162
193
|
export declare function getMultipartShape(s: unknown): {
|
|
163
194
|
shape: MultipartShape;
|
|
164
195
|
strict: boolean;
|
|
165
196
|
} | undefined;
|
|
166
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* Internal: read the file-field options used for OpenAPI documentation.
|
|
199
|
+
*
|
|
200
|
+
* @param s - Candidate schema value.
|
|
201
|
+
* @returns The resolved {@link FileFieldOptions} stored under the file-field
|
|
202
|
+
* marker, or `undefined` when `s` is not a {@link fileField} schema.
|
|
203
|
+
*/
|
|
167
204
|
export declare function getFileFieldOptions(s: unknown): (Required<Pick<FileFieldOptions, "format">> & FileFieldOptions) | undefined;
|
|
168
205
|
export {};
|
package/dist/multipart.js
CHANGED
|
@@ -233,7 +233,15 @@ async function verifyMagicBytes(file, signatures) {
|
|
|
233
233
|
}
|
|
234
234
|
return undefined;
|
|
235
235
|
}
|
|
236
|
-
/**
|
|
236
|
+
/**
|
|
237
|
+
* Shared implementation for the `fileField` overloads above.
|
|
238
|
+
*
|
|
239
|
+
* @param options - Field constraints; `format` defaults to `"binary"`, and
|
|
240
|
+
* the scriptable-image guard defaults to on whenever `magicBytes` is set.
|
|
241
|
+
* @returns The marker-carrying {@link FileFieldSchema} validator.
|
|
242
|
+
* @throws Error at construction when `magicBytes` config is malformed (bad
|
|
243
|
+
* offset, empty/out-of-range bytes, or `true` without a sniffable `accept`).
|
|
244
|
+
*/
|
|
237
245
|
export function fileField(options = {}) {
|
|
238
246
|
const opts = {
|
|
239
247
|
...options,
|
|
@@ -312,7 +320,12 @@ export function fileField(options = {}) {
|
|
|
312
320
|
};
|
|
313
321
|
return schema;
|
|
314
322
|
}
|
|
315
|
-
/**
|
|
323
|
+
/**
|
|
324
|
+
* Type-only check used by the OpenAPI generator.
|
|
325
|
+
*
|
|
326
|
+
* @param s - Candidate value to test for the `FILE_FIELD_MARKER` key.
|
|
327
|
+
* @returns `true` when `s` is a {@link fileField}-produced schema.
|
|
328
|
+
*/
|
|
316
329
|
export function isFileFieldSchema(s) {
|
|
317
330
|
return !!s && typeof s === "object" && FILE_FIELD_MARKER in s;
|
|
318
331
|
}
|
|
@@ -321,6 +334,12 @@ export function isFileFieldSchema(s) {
|
|
|
321
334
|
* body. Each entry in `shape` validates one form field by name. File fields
|
|
322
335
|
* should use {@link fileField}; non-file fields can use any Standard-Schema
|
|
323
336
|
* validator (`z.string()`, `v.number()`, ...).
|
|
337
|
+
*
|
|
338
|
+
* @param shape - Record mapping form-field names to per-field validators.
|
|
339
|
+
* @param options - `strict: true` rejects undeclared extra fields. Defaults
|
|
340
|
+
* to `{ strict: false }` (extras pass through unvalidated).
|
|
341
|
+
* @returns A marker-carrying schema the OpenAPI generator renders as
|
|
342
|
+
* `multipart/form-data`; validation issues are prefixed with the field name.
|
|
324
343
|
*/
|
|
325
344
|
export function multipartObject(shape, options = {}) {
|
|
326
345
|
const strict = options.strict ?? false;
|
|
@@ -368,17 +387,34 @@ export function multipartObject(shape, options = {}) {
|
|
|
368
387
|
};
|
|
369
388
|
return schema;
|
|
370
389
|
}
|
|
371
|
-
/**
|
|
390
|
+
/**
|
|
391
|
+
* Type-only check used by the OpenAPI generator and request-body parser.
|
|
392
|
+
*
|
|
393
|
+
* @param s - Candidate value to test for the `MULTIPART_SCHEMA_MARKER` key.
|
|
394
|
+
* @returns `true` when `s` is a {@link multipartObject}-produced schema.
|
|
395
|
+
*/
|
|
372
396
|
export function isMultipartObjectSchema(s) {
|
|
373
397
|
return !!s && typeof s === "object" && MULTIPART_SCHEMA_MARKER in s;
|
|
374
398
|
}
|
|
375
|
-
/**
|
|
399
|
+
/**
|
|
400
|
+
* Internal: pull the multipart shape so the OpenAPI generator can walk it.
|
|
401
|
+
*
|
|
402
|
+
* @param s - Candidate schema value.
|
|
403
|
+
* @returns The `{ shape, strict }` config stored under the multipart marker,
|
|
404
|
+
* or `undefined` when `s` is not a {@link multipartObject} schema.
|
|
405
|
+
*/
|
|
376
406
|
export function getMultipartShape(s) {
|
|
377
407
|
if (!isMultipartObjectSchema(s))
|
|
378
408
|
return undefined;
|
|
379
409
|
return s[MULTIPART_SCHEMA_MARKER];
|
|
380
410
|
}
|
|
381
|
-
/**
|
|
411
|
+
/**
|
|
412
|
+
* Internal: read the file-field options used for OpenAPI documentation.
|
|
413
|
+
*
|
|
414
|
+
* @param s - Candidate schema value.
|
|
415
|
+
* @returns The resolved {@link FileFieldOptions} stored under the file-field
|
|
416
|
+
* marker, or `undefined` when `s` is not a {@link fileField} schema.
|
|
417
|
+
*/
|
|
382
418
|
export function getFileFieldOptions(s) {
|
|
383
419
|
if (!isFileFieldSchema(s))
|
|
384
420
|
return undefined;
|
package/dist/openapi.d.ts
CHANGED
|
@@ -38,14 +38,23 @@ export interface SecuritySchemeMap {
|
|
|
38
38
|
* (no execution path on the producer side).
|
|
39
39
|
*/
|
|
40
40
|
export interface WebhookDefinition {
|
|
41
|
+
/** HTTP method the producer uses when delivering the webhook. */
|
|
41
42
|
method: HttpMethod;
|
|
43
|
+
/** Stable operation id for codegen. Omitted from the document when unset. */
|
|
42
44
|
operationId?: string;
|
|
45
|
+
/** Short one-line summary shown in docs UIs. */
|
|
43
46
|
summary?: string;
|
|
47
|
+
/** Longer CommonMark description of the webhook operation. */
|
|
44
48
|
description?: string;
|
|
49
|
+
/** Tags used to group the operation in docs UIs. */
|
|
45
50
|
tags?: string[];
|
|
51
|
+
/** Mark the webhook operation as deprecated in the document. */
|
|
46
52
|
deprecated?: boolean;
|
|
53
|
+
/** Request schemas (body, headers, ...) the producer sends. Same shape as route `request`. */
|
|
47
54
|
request?: RequestSchemas;
|
|
55
|
+
/** Map of status code to response schema the consumer is expected to return. */
|
|
48
56
|
responses: ResponsesMap;
|
|
57
|
+
/** Security requirement(s) documented on the webhook operation (e.g. a signature scheme). */
|
|
49
58
|
auth?: AuthSpec;
|
|
50
59
|
/**
|
|
51
60
|
* Optional OpenAPI 3.1 callbacks attached to this webhook operation.
|
|
@@ -112,16 +121,13 @@ export interface OpenAPIOptions {
|
|
|
112
121
|
*/
|
|
113
122
|
export declare function generateOpenAPI(app: App, options: OpenAPIOptions): Record<string, unknown>;
|
|
114
123
|
/**
|
|
115
|
-
* Serialize an OpenAPI document (
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
124
|
+
* Serialize an OpenAPI document (from {@link generateOpenAPI}) — or any
|
|
125
|
+
* JSON-safe object — to YAML 1.2 using a minimal built-in emitter. Pure
|
|
126
|
+
* transform with no runtime dependency; output is the form consumed by
|
|
127
|
+
* `/swagger.yaml`-style endpoints and build-time artifacts.
|
|
119
128
|
*
|
|
129
|
+
* @param doc - JSON-safe object to serialize (typically the generated document).
|
|
130
|
+
* @returns The YAML text, without a leading newline.
|
|
120
131
|
* @since 0.13.1
|
|
121
132
|
*/
|
|
122
|
-
/**
|
|
123
|
-
* Serialize an OpenAPI document (from {@link generateOpenAPI}) to YAML using a
|
|
124
|
-
* minimal built-in emitter. No external dependencies; suitable for build-time
|
|
125
|
-
* artifacts. Reads/writes nothing; pure transform.
|
|
126
|
-
*/
|
|
127
133
|
export declare function openapiToYAML(doc: Record<string, unknown>): string;
|
package/dist/openapi.js
CHANGED
|
@@ -485,18 +485,15 @@ function yamlEmit(value, indent) {
|
|
|
485
485
|
return ` ${yamlScalar(value)}\n`;
|
|
486
486
|
}
|
|
487
487
|
/**
|
|
488
|
-
* Serialize an OpenAPI document (
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
488
|
+
* Serialize an OpenAPI document (from {@link generateOpenAPI}) — or any
|
|
489
|
+
* JSON-safe object — to YAML 1.2 using a minimal built-in emitter. Pure
|
|
490
|
+
* transform with no runtime dependency; output is the form consumed by
|
|
491
|
+
* `/swagger.yaml`-style endpoints and build-time artifacts.
|
|
492
492
|
*
|
|
493
|
+
* @param doc - JSON-safe object to serialize (typically the generated document).
|
|
494
|
+
* @returns The YAML text, without a leading newline.
|
|
493
495
|
* @since 0.13.1
|
|
494
496
|
*/
|
|
495
|
-
/**
|
|
496
|
-
* Serialize an OpenAPI document (from {@link generateOpenAPI}) to YAML using a
|
|
497
|
-
* minimal built-in emitter. No external dependencies; suitable for build-time
|
|
498
|
-
* artifacts. Reads/writes nothing; pure transform.
|
|
499
|
-
*/
|
|
500
497
|
export function openapiToYAML(doc) {
|
|
501
498
|
const result = yamlEmit(doc, "");
|
|
502
499
|
return result.startsWith("\n") ? result.slice(1) : result;
|
|
@@ -50,10 +50,12 @@ import type { RateLimitStore } from "./middleware.js";
|
|
|
50
50
|
* required by the bundled script.
|
|
51
51
|
*/
|
|
52
52
|
export interface RedisCommands {
|
|
53
|
+
/** Run a Lua script atomically with the given `KEYS` / `ARGV` and return the raw Redis reply. */
|
|
53
54
|
eval(script: string, keys: string[], args: string[]): Promise<unknown>;
|
|
54
55
|
}
|
|
55
56
|
/** Options accepted by {@link redisRateLimitStore}. */
|
|
56
57
|
export interface RedisRateLimitStoreOptions {
|
|
58
|
+
/** Redis transport (see {@link ioredisAdapter} / {@link nodeRedisAdapter} for common clients). */
|
|
57
59
|
client: RedisCommands;
|
|
58
60
|
/**
|
|
59
61
|
* Optional namespace prefix for every Redis key. Defaults to `"daloy:rl:"`.
|
|
@@ -83,6 +85,11 @@ export interface RedisRateLimitStoreOptions {
|
|
|
83
85
|
* abuse-sensitive limiters in front of auth, password-reset, or other
|
|
84
86
|
* credential endpoints, pass `onError: () => "fail-closed"` so a Redis
|
|
85
87
|
* outage rejects rather than silently disables the limit.
|
|
88
|
+
*
|
|
89
|
+
* @param opts - Redis client, key prefix, and error policy; see
|
|
90
|
+
* {@link RedisRateLimitStoreOptions}.
|
|
91
|
+
* @returns A {@link RateLimitStore} whose `hit()` atomically increments the
|
|
92
|
+
* windowed counter in Redis and reports `{ count, resetMs }`.
|
|
86
93
|
*/
|
|
87
94
|
export declare function redisRateLimitStore(opts: RedisRateLimitStoreOptions): RateLimitStore;
|
|
88
95
|
/**
|
|
@@ -90,19 +97,31 @@ export declare function redisRateLimitStore(opts: RedisRateLimitStoreOptions): R
|
|
|
90
97
|
* takes `(script, numKeys, ...keysAndArgs)` is used.
|
|
91
98
|
*/
|
|
92
99
|
export interface IoredisLike {
|
|
100
|
+
/** ioredis-style `EVAL`: script, number of keys, then keys and args flattened. */
|
|
93
101
|
eval(script: string, numKeys: number, ...keysAndArgs: string[]): Promise<unknown>;
|
|
94
102
|
}
|
|
95
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Wrap an [`ioredis`](https://github.com/redis/ioredis) client.
|
|
105
|
+
*
|
|
106
|
+
* @param client - Connected ioredis instance (only its `eval` is used).
|
|
107
|
+
* @returns A {@link RedisCommands} transport for {@link redisRateLimitStore}.
|
|
108
|
+
*/
|
|
96
109
|
export declare function ioredisAdapter(client: IoredisLike): RedisCommands;
|
|
97
110
|
/**
|
|
98
111
|
* Shape of a `node-redis` v4+ client we care about. The v4 `eval` takes an
|
|
99
112
|
* options object instead of variadic arguments.
|
|
100
113
|
*/
|
|
101
114
|
export interface NodeRedisLike {
|
|
115
|
+
/** node-redis v4+ `EVAL`: script plus a `{ keys, arguments }` options object. */
|
|
102
116
|
eval(script: string, options: {
|
|
103
117
|
keys: string[];
|
|
104
118
|
arguments: string[];
|
|
105
119
|
}): Promise<unknown>;
|
|
106
120
|
}
|
|
107
|
-
/**
|
|
121
|
+
/**
|
|
122
|
+
* Wrap a [`node-redis`](https://github.com/redis/node-redis) v4+ client.
|
|
123
|
+
*
|
|
124
|
+
* @param client - Connected node-redis v4+ instance (only its `eval` is used).
|
|
125
|
+
* @returns A {@link RedisCommands} transport for {@link redisRateLimitStore}.
|
|
126
|
+
*/
|
|
108
127
|
export declare function nodeRedisAdapter(client: NodeRedisLike): RedisCommands;
|
package/dist/rate-limit-redis.js
CHANGED
|
@@ -84,6 +84,11 @@ function toNumber(value) {
|
|
|
84
84
|
* abuse-sensitive limiters in front of auth, password-reset, or other
|
|
85
85
|
* credential endpoints, pass `onError: () => "fail-closed"` so a Redis
|
|
86
86
|
* outage rejects rather than silently disables the limit.
|
|
87
|
+
*
|
|
88
|
+
* @param opts - Redis client, key prefix, and error policy; see
|
|
89
|
+
* {@link RedisRateLimitStoreOptions}.
|
|
90
|
+
* @returns A {@link RateLimitStore} whose `hit()` atomically increments the
|
|
91
|
+
* windowed counter in Redis and reports `{ count, resetMs }`.
|
|
87
92
|
*/
|
|
88
93
|
export function redisRateLimitStore(opts) {
|
|
89
94
|
const prefix = opts.prefix ?? "daloy:rl:";
|
|
@@ -106,7 +111,12 @@ export function redisRateLimitStore(opts) {
|
|
|
106
111
|
},
|
|
107
112
|
};
|
|
108
113
|
}
|
|
109
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Wrap an [`ioredis`](https://github.com/redis/ioredis) client.
|
|
116
|
+
*
|
|
117
|
+
* @param client - Connected ioredis instance (only its `eval` is used).
|
|
118
|
+
* @returns A {@link RedisCommands} transport for {@link redisRateLimitStore}.
|
|
119
|
+
*/
|
|
110
120
|
export function ioredisAdapter(client) {
|
|
111
121
|
return {
|
|
112
122
|
eval(script, keys, args) {
|
|
@@ -114,7 +124,12 @@ export function ioredisAdapter(client) {
|
|
|
114
124
|
},
|
|
115
125
|
};
|
|
116
126
|
}
|
|
117
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* Wrap a [`node-redis`](https://github.com/redis/node-redis) v4+ client.
|
|
129
|
+
*
|
|
130
|
+
* @param client - Connected node-redis v4+ instance (only its `eval` is used).
|
|
131
|
+
* @returns A {@link RedisCommands} transport for {@link redisRateLimitStore}.
|
|
132
|
+
*/
|
|
118
133
|
export function nodeRedisAdapter(client) {
|
|
119
134
|
return {
|
|
120
135
|
eval(script, keys, args) {
|
package/dist/safe-redirect.d.ts
CHANGED
|
@@ -47,7 +47,9 @@
|
|
|
47
47
|
export type SafeRedirectBlockReason = "empty-target" | "invalid-control-characters" | "protocol-relative" | "backslash-path" | "path-not-allowed" | "origin-not-allowed" | "scheme-not-allowed" | "parse-failed";
|
|
48
48
|
/** Thrown when {@link safeRedirect} refuses a candidate URL and no `fallback` is configured. */
|
|
49
49
|
export declare class OpenRedirectBlockedError extends Error {
|
|
50
|
+
/** Machine-readable {@link SafeRedirectBlockReason} explaining the refusal. */
|
|
50
51
|
readonly reason: SafeRedirectBlockReason;
|
|
52
|
+
/** The candidate URL that was refused, verbatim. */
|
|
51
53
|
readonly target: string;
|
|
52
54
|
constructor(reason: SafeRedirectBlockReason, target: string);
|
|
53
55
|
}
|
|
@@ -88,6 +90,10 @@ export interface SafeRedirectOptions {
|
|
|
88
90
|
*
|
|
89
91
|
* @param target - User-supplied URL candidate (path or absolute URL).
|
|
90
92
|
* @param options - Allowlist + response configuration.
|
|
93
|
+
* @returns A redirect `Response` (default `303`) with `Location` set to the
|
|
94
|
+
* validated target (or the `fallback`) and `Cache-Control: no-store`.
|
|
95
|
+
* @throws {TypeError} for a non-redirect `status` or malformed
|
|
96
|
+
* `allowedPaths` / `allowedOrigins` / `fallback` entries.
|
|
91
97
|
*
|
|
92
98
|
* @since 0.35.0
|
|
93
99
|
*/
|
package/dist/safe-redirect.js
CHANGED
|
@@ -45,7 +45,9 @@
|
|
|
45
45
|
*/
|
|
46
46
|
/** Thrown when {@link safeRedirect} refuses a candidate URL and no `fallback` is configured. */
|
|
47
47
|
export class OpenRedirectBlockedError extends Error {
|
|
48
|
+
/** Machine-readable {@link SafeRedirectBlockReason} explaining the refusal. */
|
|
48
49
|
reason;
|
|
50
|
+
/** The candidate URL that was refused, verbatim. */
|
|
49
51
|
target;
|
|
50
52
|
constructor(reason, target) {
|
|
51
53
|
super(`safeRedirect: refused redirect (${reason})`);
|
|
@@ -148,6 +150,10 @@ function hasEncodedProtocolRelativePrefix(value) {
|
|
|
148
150
|
*
|
|
149
151
|
* @param target - User-supplied URL candidate (path or absolute URL).
|
|
150
152
|
* @param options - Allowlist + response configuration.
|
|
153
|
+
* @returns A redirect `Response` (default `303`) with `Location` set to the
|
|
154
|
+
* validated target (or the `fallback`) and `Cache-Control: no-store`.
|
|
155
|
+
* @throws {TypeError} for a non-redirect `status` or malformed
|
|
156
|
+
* `allowedPaths` / `allowedOrigins` / `fallback` entries.
|
|
151
157
|
*
|
|
152
158
|
* @since 0.35.0
|
|
153
159
|
*/
|