@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.
Files changed (100) hide show
  1. package/README.md +2 -1
  2. package/dist/adapters/bun.d.ts +13 -1
  3. package/dist/adapters/bun.js +8 -1
  4. package/dist/adapters/cloudflare.d.ts +7 -1
  5. package/dist/adapters/cloudflare.js +6 -1
  6. package/dist/adapters/deno.d.ts +11 -1
  7. package/dist/adapters/deno.js +8 -1
  8. package/dist/adapters/fastly.d.ts +12 -2
  9. package/dist/adapters/fastly.js +12 -2
  10. package/dist/adapters/lambda.d.ts +37 -1
  11. package/dist/adapters/lambda.js +6 -1
  12. package/dist/adapters/node.d.ts +12 -1
  13. package/dist/adapters/node.js +7 -1
  14. package/dist/adapters/vercel.d.ts +13 -1
  15. package/dist/adapters/vercel.js +12 -1
  16. package/dist/app.d.ts +67 -17
  17. package/dist/app.js +97 -31
  18. package/dist/banner.d.ts +6 -0
  19. package/dist/banner.js +6 -0
  20. package/dist/cli.d.ts +35 -0
  21. package/dist/cli.js +23 -1
  22. package/dist/combine.d.ts +8 -0
  23. package/dist/combine.js +8 -0
  24. package/dist/compression.d.ts +3 -0
  25. package/dist/compression.js +3 -0
  26. package/dist/config.d.ts +4 -0
  27. package/dist/config.js +4 -0
  28. package/dist/conn-info.d.ts +35 -2
  29. package/dist/conn-info.js +35 -2
  30. package/dist/contract.d.ts +2 -0
  31. package/dist/contract.js +2 -0
  32. package/dist/cookie.d.ts +12 -0
  33. package/dist/cookie.js +12 -0
  34. package/dist/dependency.d.ts +4 -0
  35. package/dist/dependency.js +3 -0
  36. package/dist/discriminator.d.ts +13 -0
  37. package/dist/discriminator.js +23 -1
  38. package/dist/docs.d.ts +78 -0
  39. package/dist/docs.js +21 -0
  40. package/dist/errors.d.ts +16 -0
  41. package/dist/errors.js +14 -0
  42. package/dist/etag.d.ts +2 -0
  43. package/dist/etag.js +2 -0
  44. package/dist/fetch-guard.d.ts +7 -0
  45. package/dist/fetch-guard.js +7 -0
  46. package/dist/fetch-resilience.d.ts +4 -0
  47. package/dist/fetch-resilience.js +4 -0
  48. package/dist/http-signatures.d.ts +32 -0
  49. package/dist/http-signatures.js +30 -0
  50. package/dist/index.d.ts +2 -0
  51. package/dist/index.js +1 -0
  52. package/dist/ip-restriction.d.ts +40 -3
  53. package/dist/ip-restriction.js +35 -3
  54. package/dist/jwk.d.ts +12 -1
  55. package/dist/jwk.js +6 -0
  56. package/dist/jwt.d.ts +14 -0
  57. package/dist/jwt.js +10 -0
  58. package/dist/load-shedding.d.ts +3 -0
  59. package/dist/load-shedding.js +3 -0
  60. package/dist/logger.d.ts +13 -0
  61. package/dist/logger.js +3 -0
  62. package/dist/mcp.d.ts +574 -0
  63. package/dist/mcp.js +623 -0
  64. package/dist/middleware.d.ts +68 -0
  65. package/dist/middleware.js +17 -0
  66. package/dist/mtls.d.ts +19 -2
  67. package/dist/mtls.js +12 -2
  68. package/dist/multipart.d.ts +42 -5
  69. package/dist/multipart.js +41 -5
  70. package/dist/openapi.d.ts +15 -9
  71. package/dist/openapi.js +6 -9
  72. package/dist/rate-limit-redis.d.ts +21 -2
  73. package/dist/rate-limit-redis.js +17 -2
  74. package/dist/safe-redirect.d.ts +6 -0
  75. package/dist/safe-redirect.js +6 -0
  76. package/dist/sbom.cdx.json +9 -9
  77. package/dist/sbom.spdx.json +5 -5
  78. package/dist/scheduler.d.ts +4 -0
  79. package/dist/schema.d.ts +25 -0
  80. package/dist/security-schemes.d.ts +50 -0
  81. package/dist/security-schemes.js +6 -0
  82. package/dist/security.d.ts +33 -0
  83. package/dist/security.js +28 -10
  84. package/dist/session.d.ts +34 -5
  85. package/dist/session.js +31 -5
  86. package/dist/streaming.d.ts +19 -0
  87. package/dist/streaming.js +16 -0
  88. package/dist/subdomains.d.ts +4 -0
  89. package/dist/subdomains.js +4 -0
  90. package/dist/time-claims.d.ts +22 -2
  91. package/dist/time-claims.js +6 -0
  92. package/dist/tracing.d.ts +12 -0
  93. package/dist/tracing.js +6 -0
  94. package/dist/types.d.ts +70 -1
  95. package/dist/waf.js +21 -1
  96. package/dist/webhook-delivery.d.ts +6 -0
  97. package/dist/webhook-delivery.js +5 -0
  98. package/dist/websocket.d.ts +137 -4
  99. package/dist/websocket.js +105 -4
  100. package/package.json +6 -1
@@ -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;
@@ -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
- * Returns `undefined` for an empty or unparseable header.
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
- * Returns `undefined` for an empty or unparseable header.
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) {
@@ -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
- /** Validator for a required single uploaded `File`/`Blob` field. */
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
- /** Type-only check used by the OpenAPI generator. */
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
- /** Type-only check used by the OpenAPI generator and request-body parser. */
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
- /** Internal: pull the multipart shape so the OpenAPI generator can walk it. */
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
- /** Internal: read the file-field options used for OpenAPI documentation. */
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
- /** Shared implementation for the `fileField` overloads above. */
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
- /** Type-only check used by the OpenAPI generator. */
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
- /** Type-only check used by the OpenAPI generator and request-body parser. */
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
- /** Internal: pull the multipart shape so the OpenAPI generator can walk it. */
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
- /** Internal: read the file-field options used for OpenAPI documentation. */
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 (or any JSON-safe object) as YAML 1.2.
116
- *
117
- * Pure function with no runtime dependency. Output is the canonical form
118
- * consumed by Swagger UI's `/swagger.yaml` style endpoints.
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 (or any JSON-safe object) as YAML 1.2.
489
- *
490
- * Pure function with no runtime dependency. Output is the canonical form
491
- * consumed by Swagger UI's `/swagger.yaml` style endpoints.
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
- /** Wrap an [`ioredis`](https://github.com/redis/ioredis) client. */
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
- /** Wrap a [`node-redis`](https://github.com/redis/node-redis) v4+ client. */
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;
@@ -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
- /** Wrap an [`ioredis`](https://github.com/redis/ioredis) client. */
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
- /** Wrap a [`node-redis`](https://github.com/redis/node-redis) v4+ client. */
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) {
@@ -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
  */
@@ -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
  */