@daloyjs/core 1.0.0-beta.6 → 1.0.0-rc.0

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 (99) hide show
  1. package/README.md +2 -2
  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 +223 -12
  14. package/dist/adapters/vercel.d.ts +13 -1
  15. package/dist/adapters/vercel.js +12 -1
  16. package/dist/app.d.ts +78 -17
  17. package/dist/app.js +444 -86
  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 +1 -1
  51. package/dist/ip-restriction.d.ts +40 -3
  52. package/dist/ip-restriction.js +35 -3
  53. package/dist/jwk.d.ts +12 -1
  54. package/dist/jwk.js +6 -0
  55. package/dist/jwt.d.ts +14 -0
  56. package/dist/jwt.js +10 -0
  57. package/dist/load-shedding.d.ts +3 -0
  58. package/dist/load-shedding.js +3 -0
  59. package/dist/logger.d.ts +13 -0
  60. package/dist/logger.js +3 -0
  61. package/dist/mcp.d.ts +152 -10
  62. package/dist/mcp.js +223 -19
  63. package/dist/middleware.d.ts +68 -0
  64. package/dist/middleware.js +17 -0
  65. package/dist/mtls.d.ts +19 -2
  66. package/dist/mtls.js +12 -2
  67. package/dist/multipart.d.ts +42 -5
  68. package/dist/multipart.js +41 -5
  69. package/dist/openapi.d.ts +15 -9
  70. package/dist/openapi.js +6 -9
  71. package/dist/rate-limit-redis.d.ts +21 -2
  72. package/dist/rate-limit-redis.js +17 -2
  73. package/dist/safe-redirect.d.ts +6 -0
  74. package/dist/safe-redirect.js +6 -0
  75. package/dist/sbom.cdx.json +9 -9
  76. package/dist/sbom.spdx.json +5 -5
  77. package/dist/scheduler.d.ts +4 -0
  78. package/dist/schema.d.ts +25 -0
  79. package/dist/security-schemes.d.ts +50 -0
  80. package/dist/security-schemes.js +6 -0
  81. package/dist/security.d.ts +33 -0
  82. package/dist/security.js +28 -10
  83. package/dist/session.d.ts +34 -5
  84. package/dist/session.js +31 -5
  85. package/dist/streaming.d.ts +19 -0
  86. package/dist/streaming.js +16 -0
  87. package/dist/subdomains.d.ts +4 -0
  88. package/dist/subdomains.js +4 -0
  89. package/dist/time-claims.d.ts +22 -2
  90. package/dist/time-claims.js +6 -0
  91. package/dist/tracing.d.ts +12 -0
  92. package/dist/tracing.js +6 -0
  93. package/dist/types.d.ts +70 -1
  94. package/dist/waf.js +21 -1
  95. package/dist/webhook-delivery.d.ts +6 -0
  96. package/dist/webhook-delivery.js +5 -0
  97. package/dist/websocket.d.ts +137 -4
  98. package/dist/websocket.js +105 -4
  99. package/package.json +1 -1
@@ -14,66 +14,92 @@ export type ApiKeyLocation = "header" | "query" | "cookie";
14
14
  export interface HttpBearerSchemeOptions {
15
15
  /** Hint about the bearer token format (e.g. "JWT"). */
16
16
  bearerFormat?: string;
17
+ /** Human-readable description shown in the generated docs (CommonMark). */
17
18
  description?: string;
18
19
  /** Require payload/body authentication for routes using this scheme. */
19
20
  requirePayloadAuth?: boolean;
20
21
  }
21
22
  /** Options for {@link httpBasicScheme}. */
22
23
  export interface HttpBasicSchemeOptions {
24
+ /** Human-readable description shown in the generated docs (CommonMark). */
23
25
  description?: string;
24
26
  /** Require payload/body authentication for routes using this scheme. */
25
27
  requirePayloadAuth?: boolean;
26
28
  }
27
29
  /** Options for {@link apiKeyScheme}. */
28
30
  export interface ApiKeySchemeOptions {
31
+ /** Where the key is presented: `"header"`, `"query"`, or `"cookie"`. */
29
32
  in: ApiKeyLocation;
33
+ /** Name of the header, query parameter, or cookie that carries the key. */
30
34
  name: string;
35
+ /** Human-readable description shown in the generated docs (CommonMark). */
31
36
  description?: string;
32
37
  /** Require payload/body authentication for routes using this scheme. */
33
38
  requirePayloadAuth?: boolean;
34
39
  }
35
40
  /** OAuth2 Implicit flow object (deprecated in OAuth 2.1 but still part of OpenAPI). */
36
41
  export interface OAuth2ImplicitFlow {
42
+ /** Authorization endpoint URL (OpenAPI `authorizationUrl`; must be TLS). */
37
43
  authorizationUrl: string;
44
+ /** Optional URL for obtaining refresh tokens. */
38
45
  refreshUrl?: string;
46
+ /** Map of scope name to short description. May be empty. */
39
47
  scopes: Record<string, string>;
40
48
  }
41
49
  /** OAuth2 Resource Owner Password Credentials flow object. */
42
50
  export interface OAuth2PasswordFlow {
51
+ /** Token endpoint URL (OpenAPI `tokenUrl`; must be TLS). */
43
52
  tokenUrl: string;
53
+ /** Optional URL for obtaining refresh tokens. */
44
54
  refreshUrl?: string;
55
+ /** Map of scope name to short description. May be empty. */
45
56
  scopes: Record<string, string>;
46
57
  }
47
58
  /** OAuth2 Client Credentials flow object. */
48
59
  export interface OAuth2ClientCredentialsFlow {
60
+ /** Token endpoint URL (OpenAPI `tokenUrl`; must be TLS). */
49
61
  tokenUrl: string;
62
+ /** Optional URL for obtaining refresh tokens. */
50
63
  refreshUrl?: string;
64
+ /** Map of scope name to short description. May be empty. */
51
65
  scopes: Record<string, string>;
52
66
  }
53
67
  /** OAuth2 Authorization Code flow object (the recommended interactive flow). */
54
68
  export interface OAuth2AuthorizationCodeFlow {
69
+ /** Authorization endpoint URL (OpenAPI `authorizationUrl`; must be TLS). */
55
70
  authorizationUrl: string;
71
+ /** Token endpoint URL (OpenAPI `tokenUrl`; must be TLS). */
56
72
  tokenUrl: string;
73
+ /** Optional URL for obtaining refresh tokens. */
57
74
  refreshUrl?: string;
75
+ /** Map of scope name to short description. May be empty. */
58
76
  scopes: Record<string, string>;
59
77
  }
60
78
  /** Container for all OAuth2 flows supported by a single scheme. At least one entry is required. */
61
79
  export interface OAuth2Flows {
80
+ /** Implicit flow (deprecated in OAuth 2.1; avoid for new APIs). */
62
81
  implicit?: OAuth2ImplicitFlow;
82
+ /** Resource Owner Password Credentials flow. */
63
83
  password?: OAuth2PasswordFlow;
84
+ /** Client Credentials flow (machine-to-machine). */
64
85
  clientCredentials?: OAuth2ClientCredentialsFlow;
86
+ /** Authorization Code flow (the recommended interactive flow). */
65
87
  authorizationCode?: OAuth2AuthorizationCodeFlow;
66
88
  }
67
89
  /** Options for {@link oauth2Scheme}. */
68
90
  export interface OAuth2SchemeOptions {
91
+ /** Supported OAuth2 flows. At least one entry is required. */
69
92
  flows: OAuth2Flows;
93
+ /** Human-readable description shown in the generated docs (CommonMark). */
70
94
  description?: string;
71
95
  /** Require payload/body authentication for routes using this scheme. */
72
96
  requirePayloadAuth?: boolean;
73
97
  }
74
98
  /** Options for {@link openIdConnectScheme}. */
75
99
  export interface OpenIdConnectSchemeOptions {
100
+ /** OpenID Connect Discovery URL (typically ends in `/.well-known/openid-configuration`). */
76
101
  openIdConnectUrl: string;
102
+ /** Human-readable description shown in the generated docs (CommonMark). */
77
103
  description?: string;
78
104
  /** Require payload/body authentication for routes using this scheme. */
79
105
  requirePayloadAuth?: boolean;
@@ -82,38 +108,56 @@ export interface OpenIdConnectSchemeOptions {
82
108
  export declare const REQUIRE_PAYLOAD_AUTH_EXTENSION: "x-daloy-require-payload-auth";
83
109
  /** Mixin shape for schemes that opt into payload authentication via {@link REQUIRE_PAYLOAD_AUTH_EXTENSION}. */
84
110
  export interface RequirePayloadAuthExtension {
111
+ /** Set to `true` when routes using this scheme must also pass payload (signed body) authentication. */
85
112
  readonly [REQUIRE_PAYLOAD_AUTH_EXTENSION]?: true;
86
113
  }
87
114
  /** OpenAPI HTTP Bearer security scheme returned by {@link httpBearerScheme}. */
88
115
  export interface HttpBearerScheme extends RequirePayloadAuthExtension {
116
+ /** OpenAPI security scheme `type` discriminant. Always `"http"`. */
89
117
  type: "http";
118
+ /** HTTP auth scheme name per RFC 9110. Always `"bearer"`. */
90
119
  scheme: "bearer";
120
+ /** Hint about the bearer token format (e.g. "JWT"). */
91
121
  bearerFormat?: string;
122
+ /** Human-readable description shown in the generated docs (CommonMark). */
92
123
  description?: string;
93
124
  }
94
125
  /** OpenAPI HTTP Basic security scheme returned by {@link httpBasicScheme}. */
95
126
  export interface HttpBasicScheme extends RequirePayloadAuthExtension {
127
+ /** OpenAPI security scheme `type` discriminant. Always `"http"`. */
96
128
  type: "http";
129
+ /** HTTP auth scheme name per RFC 9110. Always `"basic"`. */
97
130
  scheme: "basic";
131
+ /** Human-readable description shown in the generated docs (CommonMark). */
98
132
  description?: string;
99
133
  }
100
134
  /** OpenAPI API-key security scheme returned by {@link apiKeyScheme}. */
101
135
  export interface ApiKeyScheme extends RequirePayloadAuthExtension {
136
+ /** OpenAPI security scheme `type` discriminant. Always `"apiKey"`. */
102
137
  type: "apiKey";
138
+ /** Where the key is presented: `"header"`, `"query"`, or `"cookie"`. */
103
139
  in: ApiKeyLocation;
140
+ /** Name of the header, query parameter, or cookie that carries the key. */
104
141
  name: string;
142
+ /** Human-readable description shown in the generated docs (CommonMark). */
105
143
  description?: string;
106
144
  }
107
145
  /** OpenAPI OAuth2 security scheme returned by {@link oauth2Scheme}. */
108
146
  export interface OAuth2Scheme extends RequirePayloadAuthExtension {
147
+ /** OpenAPI security scheme `type` discriminant. Always `"oauth2"`. */
109
148
  type: "oauth2";
149
+ /** Supported OAuth2 flows (at least one entry). */
110
150
  flows: OAuth2Flows;
151
+ /** Human-readable description shown in the generated docs (CommonMark). */
111
152
  description?: string;
112
153
  }
113
154
  /** OpenAPI OpenID Connect security scheme returned by {@link openIdConnectScheme}. */
114
155
  export interface OpenIdConnectScheme extends RequirePayloadAuthExtension {
156
+ /** OpenAPI security scheme `type` discriminant. Always `"openIdConnect"`. */
115
157
  type: "openIdConnect";
158
+ /** OpenID Connect Discovery URL (typically ends in `/.well-known/openid-configuration`). */
116
159
  openIdConnectUrl: string;
160
+ /** Human-readable description shown in the generated docs (CommonMark). */
117
161
  description?: string;
118
162
  }
119
163
  /** Union of every concrete security scheme this module can build. */
@@ -122,12 +166,18 @@ export type SecurityScheme = HttpBearerScheme | HttpBasicScheme | ApiKeyScheme |
122
166
  * Returns `true` when `scheme` opts into payload (signed body) authentication
123
167
  * via either the legacy `requirePayloadAuth` flag or the canonical
124
168
  * {@link REQUIRE_PAYLOAD_AUTH_EXTENSION} OpenAPI extension.
169
+ *
170
+ * @param scheme - Candidate security scheme object (non-objects are tolerated).
171
+ * @returns `true` when payload auth is required; `false` otherwise.
125
172
  */
126
173
  export declare function securitySchemeRequiresPayloadAuth(scheme: unknown): boolean;
127
174
  /**
128
175
  * Normalize a builder output into a spec-compliant OpenAPI security scheme by
129
176
  * stripping the convenience `requirePayloadAuth` flag and emitting the
130
177
  * canonical {@link REQUIRE_PAYLOAD_AUTH_EXTENSION} extension instead.
178
+ *
179
+ * @param scheme - Candidate security scheme object (non-objects pass through untouched).
180
+ * @returns A copy without `requirePayloadAuth` (extension set when it was `true`), or the input itself when no normalization is needed.
131
181
  */
132
182
  export declare function toOpenAPISecurityScheme(scheme: unknown): unknown;
133
183
  /**
@@ -20,6 +20,9 @@ function markRequirePayloadAuth(scheme, options) {
20
20
  * Returns `true` when `scheme` opts into payload (signed body) authentication
21
21
  * via either the legacy `requirePayloadAuth` flag or the canonical
22
22
  * {@link REQUIRE_PAYLOAD_AUTH_EXTENSION} OpenAPI extension.
23
+ *
24
+ * @param scheme - Candidate security scheme object (non-objects are tolerated).
25
+ * @returns `true` when payload auth is required; `false` otherwise.
23
26
  */
24
27
  export function securitySchemeRequiresPayloadAuth(scheme) {
25
28
  if (!scheme || typeof scheme !== "object")
@@ -32,6 +35,9 @@ export function securitySchemeRequiresPayloadAuth(scheme) {
32
35
  * Normalize a builder output into a spec-compliant OpenAPI security scheme by
33
36
  * stripping the convenience `requirePayloadAuth` flag and emitting the
34
37
  * canonical {@link REQUIRE_PAYLOAD_AUTH_EXTENSION} extension instead.
38
+ *
39
+ * @param scheme - Candidate security scheme object (non-objects pass through untouched).
40
+ * @returns A copy without `requirePayloadAuth` (extension set when it was `true`), or the input itself when no normalization is needed.
35
41
  */
36
42
  export function toOpenAPISecurityScheme(scheme) {
37
43
  if (!scheme || typeof scheme !== "object")
@@ -105,6 +105,21 @@ export declare function sanitizeHeaderValue(value: string): string;
105
105
  * @since 0.1.0
106
106
  */
107
107
  export declare function timingSafeEqual(a: string, b: string): boolean;
108
+ /**
109
+ * Generate a cryptographically strong, URL-safe identifier (~22 chars).
110
+ *
111
+ * Uses Web Crypto's `crypto.randomUUID()` when available, falling back to
112
+ * 16 random bytes via `crypto.getRandomValues()`. The last-resort fallback
113
+ * (timestamp + `Math.random()`) only triggers in environments without
114
+ * WebCrypto, which is none of Node 20+/Bun/Deno/Cloudflare Workers/Vercel
115
+ * Edge.
116
+ *
117
+ * Suitable for request ids, session ids, and short-lived correlation tokens.
118
+ * Do not use for long-lived secrets unless you also sign or wrap them.
119
+ *
120
+ * @returns A random URL-safe id string.
121
+ * @since 0.1.0
122
+ */
108
123
  export declare function randomId(): string;
109
124
  /**
110
125
  * Header names that MUST appear at most once on a request per RFC 7230.
@@ -126,6 +141,7 @@ export declare const SMUGGLING_SINGLETON_HEADERS: readonly string[];
126
141
  * Throws {@link BadRequestError} so the framework returns a structured
127
142
  * `400 problem+json` instead of forwarding a smuggling-class request.
128
143
  *
144
+ * @param headers - Normalized request headers to inspect.
129
145
  * @since 0.15.0
130
146
  */
131
147
  export declare function assertNoDuplicateSingletonHeaders(headers: Headers): void;
@@ -163,6 +179,7 @@ export declare const RESERVED_INBOUND_HEADER_PREFIXES: readonly string[];
163
179
  * `400 problem+json` instead of routing a request that may be probing
164
180
  * for an internal-dispatch bypass.
165
181
  *
182
+ * @param headers - Normalized request headers to inspect (names arrive lowercased).
166
183
  * @since 0.36.0
167
184
  */
168
185
  export declare function assertNoReservedInternalHeaders(headers: Headers): void;
@@ -229,6 +246,8 @@ export declare const WEAK_SECRET_STRINGS: readonly string[];
229
246
  * The thrown `Error` includes the `scope` argument (e.g. `"session"`) so
230
247
  * the developer sees which subsystem rejected the secret.
231
248
  *
249
+ * @param secret - Candidate secret value to vet.
250
+ * @param scope - Subsystem name used to prefix the thrown error message.
232
251
  * @since 0.17.0
233
252
  */
234
253
  export declare function assertStrongSecret(secret: unknown, scope: string): void;
@@ -283,6 +302,11 @@ export declare const WEBHOOK_DEFAULT_TOLERANCE_SECONDS = 300;
283
302
  * });
284
303
  * ```
285
304
  *
305
+ * @param opts - Payload, expected signature, shared secret, and optional
306
+ * `algorithm` (defaults to `"sha256"`), `timestamp`, `toleranceSeconds`,
307
+ * and `now` clock for replay-window checks.
308
+ * @returns `true` only when the signature matches the HMAC of the (optionally
309
+ * timestamp-prefixed) payload and the timestamp is within tolerance.
286
310
  * @since 0.15.0
287
311
  */
288
312
  export declare function verifyWebhookSignature(opts: {
@@ -325,6 +349,11 @@ export declare function verifyWebhookSignature(opts: {
325
349
  * companion of {@link verifyWebhookSignature}; useful for tests, for
326
350
  * outbound webhook senders, and for diffing implementations.
327
351
  *
352
+ * @param opts - Payload, shared secret, optional `algorithm` (defaults to
353
+ * `"sha256"`), and optional `timestamp` to bind the signature to.
354
+ * @returns The hex-encoded HMAC digest.
355
+ * @throws TypeError on an unsupported algorithm or malformed timestamp;
356
+ * Error when WebCrypto is unavailable.
328
357
  * @since 0.15.0
329
358
  */
330
359
  export declare function signWebhookPayload(opts: {
@@ -415,6 +444,8 @@ export declare function assertSafeRelativePath(input: string): string;
415
444
  * Returns `true` on the first hit. Use before passing untrusted data
416
445
  * into a query object that may be interpreted as an operator expression.
417
446
  *
447
+ * @param value - Parsed, untrusted JSON value to scan recursively.
448
+ * @returns `true` when any nested key starts with `$`; `false` otherwise.
418
449
  * @since 0.35.0
419
450
  */
420
451
  export declare function hasMongoOperatorKeys(value: unknown): boolean;
@@ -424,6 +455,8 @@ export declare function hasMongoOperatorKeys(value: unknown): boolean;
424
455
  * threading it into a NoSQL driver — closes the
425
456
  * `{"password": {"$ne": null}}` authentication-bypass class of bug.
426
457
  *
458
+ * @param value - Parsed, untrusted JSON value to scan recursively.
459
+ * @throws BadRequestError when any nested key starts with `$`.
427
460
  * @since 0.35.0
428
461
  */
429
462
  export declare function assertNoMongoOperators(value: unknown): void;
package/dist/security.js CHANGED
@@ -197,6 +197,16 @@ export function timingSafeEqual(a, b) {
197
197
  }
198
198
  return mismatch === 0;
199
199
  }
200
+ // Cache the Web Crypto entry points at module load so randomId() doesn't pay
201
+ // for a `globalThis.crypto` + optional-chain property lookup per request.
202
+ // Falls back to the runtime lookup path if Web Crypto is patched/replaced
203
+ // after module load (test harnesses, custom runtimes) — the cache is only
204
+ // trusted when `globalThis.crypto` is still the same reference, otherwise
205
+ // the stubbed object would be silently bypassed.
206
+ const _webCrypto = globalThis.crypto;
207
+ const _randomUUID = _webCrypto && typeof _webCrypto.randomUUID === "function"
208
+ ? _webCrypto.randomUUID.bind(_webCrypto)
209
+ : undefined;
200
210
  /**
201
211
  * Generate a cryptographically strong, URL-safe identifier (~22 chars).
202
212
  *
@@ -212,16 +222,6 @@ export function timingSafeEqual(a, b) {
212
222
  * @returns A random URL-safe id string.
213
223
  * @since 0.1.0
214
224
  */
215
- // Cache the Web Crypto entry points at module load so randomId() doesn't pay
216
- // for a `globalThis.crypto` + optional-chain property lookup per request.
217
- // Falls back to the runtime lookup path if Web Crypto is patched/replaced
218
- // after module load (test harnesses, custom runtimes) — the cache is only
219
- // trusted when `globalThis.crypto` is still the same reference, otherwise
220
- // the stubbed object would be silently bypassed.
221
- const _webCrypto = globalThis.crypto;
222
- const _randomUUID = _webCrypto && typeof _webCrypto.randomUUID === "function"
223
- ? _webCrypto.randomUUID.bind(_webCrypto)
224
- : undefined;
225
225
  export function randomId() {
226
226
  const c = globalThis.crypto;
227
227
  if (c === _webCrypto && _randomUUID !== undefined)
@@ -260,6 +260,7 @@ export const SMUGGLING_SINGLETON_HEADERS = Object.freeze([
260
260
  * Throws {@link BadRequestError} so the framework returns a structured
261
261
  * `400 problem+json` instead of forwarding a smuggling-class request.
262
262
  *
263
+ * @param headers - Normalized request headers to inspect.
263
264
  * @since 0.15.0
264
265
  */
265
266
  export function assertNoDuplicateSingletonHeaders(headers) {
@@ -307,6 +308,7 @@ export const RESERVED_INBOUND_HEADER_PREFIXES = Object.freeze([
307
308
  * `400 problem+json` instead of routing a request that may be probing
308
309
  * for an internal-dispatch bypass.
309
310
  *
311
+ * @param headers - Normalized request headers to inspect (names arrive lowercased).
310
312
  * @since 0.36.0
311
313
  */
312
314
  export function assertNoReservedInternalHeaders(headers) {
@@ -426,6 +428,8 @@ const WEAK_SECRET_SET = new Set(WEAK_SECRET_STRINGS.map((s) => s.toLowerCase()))
426
428
  * The thrown `Error` includes the `scope` argument (e.g. `"session"`) so
427
429
  * the developer sees which subsystem rejected the secret.
428
430
  *
431
+ * @param secret - Candidate secret value to vet.
432
+ * @param scope - Subsystem name used to prefix the thrown error message.
429
433
  * @since 0.17.0
430
434
  */
431
435
  export function assertStrongSecret(secret, scope) {
@@ -603,6 +607,11 @@ function buildSignedPayloadBytes(payload, timestamp) {
603
607
  * });
604
608
  * ```
605
609
  *
610
+ * @param opts - Payload, expected signature, shared secret, and optional
611
+ * `algorithm` (defaults to `"sha256"`), `timestamp`, `toleranceSeconds`,
612
+ * and `now` clock for replay-window checks.
613
+ * @returns `true` only when the signature matches the HMAC of the (optionally
614
+ * timestamp-prefixed) payload and the timestamp is within tolerance.
606
615
  * @since 0.15.0
607
616
  */
608
617
  export async function verifyWebhookSignature(opts) {
@@ -648,6 +657,11 @@ export async function verifyWebhookSignature(opts) {
648
657
  * companion of {@link verifyWebhookSignature}; useful for tests, for
649
658
  * outbound webhook senders, and for diffing implementations.
650
659
  *
660
+ * @param opts - Payload, shared secret, optional `algorithm` (defaults to
661
+ * `"sha256"`), and optional `timestamp` to bind the signature to.
662
+ * @returns The hex-encoded HMAC digest.
663
+ * @throws TypeError on an unsupported algorithm or malformed timestamp;
664
+ * Error when WebCrypto is unavailable.
651
665
  * @since 0.15.0
652
666
  */
653
667
  export async function signWebhookPayload(opts) {
@@ -840,6 +854,8 @@ function walkForMongoOperators(value) {
840
854
  * Returns `true` on the first hit. Use before passing untrusted data
841
855
  * into a query object that may be interpreted as an operator expression.
842
856
  *
857
+ * @param value - Parsed, untrusted JSON value to scan recursively.
858
+ * @returns `true` when any nested key starts with `$`; `false` otherwise.
843
859
  * @since 0.35.0
844
860
  */
845
861
  export function hasMongoOperatorKeys(value) {
@@ -851,6 +867,8 @@ export function hasMongoOperatorKeys(value) {
851
867
  * threading it into a NoSQL driver — closes the
852
868
  * `{"password": {"$ne": null}}` authentication-bypass class of bug.
853
869
  *
870
+ * @param value - Parsed, untrusted JSON value to scan recursively.
871
+ * @throws BadRequestError when any nested key starts with `$`.
854
872
  * @since 0.35.0
855
873
  */
856
874
  export function assertNoMongoOperators(value) {
package/dist/session.d.ts CHANGED
@@ -49,8 +49,11 @@ export interface SessionRecord {
49
49
  * lazily delete expired records.
50
50
  */
51
51
  export interface SessionStore {
52
+ /** Load the record for a session id, or `null` when missing/expired. */
52
53
  get(sid: string): SessionRecord | null | Promise<SessionRecord | null>;
54
+ /** Persist (create or overwrite) the record for a session id. */
53
55
  set(sid: string, record: SessionRecord): void | Promise<void>;
56
+ /** Delete the record for a session id; a no-op when it does not exist. */
54
57
  destroy(sid: string): void | Promise<void>;
55
58
  /** Optional fast-path for rolling sessions; falls back to `set()` if omitted. */
56
59
  touch?(sid: string, expiresAt: number): void | Promise<void>;
@@ -128,9 +131,13 @@ export type SessionContext = {
128
131
  */
129
132
  export declare class MemorySessionStore implements SessionStore {
130
133
  private readonly map;
134
+ /** Load a record; expired records are deleted and reported as `null`. */
131
135
  get(sid: string): SessionRecord | null;
136
+ /** Store (or overwrite) a record for a session id. */
132
137
  set(sid: string, record: SessionRecord): void;
138
+ /** Remove the record for a session id, if present. */
133
139
  destroy(sid: string): void;
140
+ /** Extend an existing record's expiry (ms since epoch) without rewriting data. */
134
141
  touch(sid: string, expiresAt: number): void;
135
142
  /** Test helper. Remove every record. */
136
143
  clear(): void;
@@ -155,6 +162,14 @@ export declare class MemorySessionStore implements SessionStore {
155
162
  * const app = new App();
156
163
  * app.use(session({ secret: process.env.SESSION_SECRET! }));
157
164
  * ```
165
+ *
166
+ * @param opts Secrets, cookie attributes, store, TTL, and rolling behavior;
167
+ * see {@link SessionOptions}. Cookies default to `__Host-` prefixed,
168
+ * `HttpOnly`, `Secure`, `SameSite=Lax`.
169
+ * @returns A {@link Hooks} object that loads/verifies the session before the
170
+ * handler and persists mutations plus the `Set-Cookie` header afterwards.
171
+ * @throws Error at setup time on missing/short secrets, invalid cookie
172
+ * attribute combinations, or a non-positive `ttlSeconds`.
158
173
  */
159
174
  export declare function session(opts: SessionOptions): Hooks;
160
175
  /** Options for {@link rotateSession}. */
@@ -177,18 +192,32 @@ export interface RotateSessionOptions {
177
192
  * session key-rotation arrays: old cookies verify with any configured secret
178
193
  * and rotated cookies are re-signed with the first/current secret.
179
194
  *
195
+ * @param opts Which session keys (or computed value) to watch, and whether
196
+ * payload data survives rotation (`keepData`, default `true`); see
197
+ * {@link RotateSessionOptions}.
198
+ * @returns A {@link Hooks} object that snapshots the watched value before the
199
+ * handler and regenerates the session id when it changed afterwards
200
+ * (session-fixation defense).
180
201
  * @since 0.23.0
181
202
  */
182
203
  export declare function rotateSession(opts?: RotateSessionOptions): Hooks;
183
204
  /**
184
- * Sign an arbitrary string with HMAC-SHA256. Returns `${value}.${sig}` where
185
- * `sig` is URL-safe base64. Useful for building custom signed cookies or
186
- * tokens that do not need a session store.
205
+ * Sign an arbitrary string with HMAC-SHA256. Useful for building custom
206
+ * signed cookies or tokens that do not need a session store.
207
+ *
208
+ * @param value String to sign; must not contain `.` (the separator).
209
+ * @param secret HMAC key, at least 16 characters.
210
+ * @returns `${value}.${sig}` where `sig` is URL-safe base64.
211
+ * @throws Error when `value` contains `.` or the secret is too short.
187
212
  */
188
213
  export declare function signValue(value: string, secret: string): Promise<string>;
189
214
  /**
190
- * Verify a `signValue()`-produced string. Returns the original value when the
191
- * signature checks out, otherwise `null`. Constant-time on the signature.
215
+ * Verify a `signValue()`-produced string. Constant-time on the signature
216
+ * comparison.
217
+ *
218
+ * @param signed The `${value}.${sig}` string to verify.
219
+ * @param secret HMAC key(s); an array lets rotated old secrets still verify.
220
+ * @returns The original value when any secret's signature matches, else `null`.
192
221
  */
193
222
  export declare function verifySignedValue(signed: string, secret: string | string[]): Promise<string | null>;
194
223
  /** Type-augmentation helper: `interface AppState extends SessionState {}`. */
package/dist/session.js CHANGED
@@ -161,6 +161,7 @@ function makeSessionContext(id, data, internal, regenerate) {
161
161
  */
162
162
  export class MemorySessionStore {
163
163
  map = new Map();
164
+ /** Load a record; expired records are deleted and reported as `null`. */
164
165
  get(sid) {
165
166
  const rec = this.map.get(sid);
166
167
  if (!rec)
@@ -171,12 +172,15 @@ export class MemorySessionStore {
171
172
  }
172
173
  return rec;
173
174
  }
175
+ /** Store (or overwrite) a record for a session id. */
174
176
  set(sid, record) {
175
177
  this.map.set(sid, record);
176
178
  }
179
+ /** Remove the record for a session id, if present. */
177
180
  destroy(sid) {
178
181
  this.map.delete(sid);
179
182
  }
183
+ /** Extend an existing record's expiry (ms since epoch) without rewriting data. */
180
184
  touch(sid, expiresAt) {
181
185
  const rec = this.map.get(sid);
182
186
  if (rec)
@@ -210,6 +214,14 @@ export class MemorySessionStore {
210
214
  * const app = new App();
211
215
  * app.use(session({ secret: process.env.SESSION_SECRET! }));
212
216
  * ```
217
+ *
218
+ * @param opts Secrets, cookie attributes, store, TTL, and rolling behavior;
219
+ * see {@link SessionOptions}. Cookies default to `__Host-` prefixed,
220
+ * `HttpOnly`, `Secure`, `SameSite=Lax`.
221
+ * @returns A {@link Hooks} object that loads/verifies the session before the
222
+ * handler and persists mutations plus the `Set-Cookie` header afterwards.
223
+ * @throws Error at setup time on missing/short secrets, invalid cookie
224
+ * attribute combinations, or a non-positive `ttlSeconds`.
213
225
  */
214
226
  export function session(opts) {
215
227
  const cookieName = opts.cookieName ?? DEFAULT_COOKIE_NAME;
@@ -432,6 +444,12 @@ function stableSnapshot(value) {
432
444
  * session key-rotation arrays: old cookies verify with any configured secret
433
445
  * and rotated cookies are re-signed with the first/current secret.
434
446
  *
447
+ * @param opts Which session keys (or computed value) to watch, and whether
448
+ * payload data survives rotation (`keepData`, default `true`); see
449
+ * {@link RotateSessionOptions}.
450
+ * @returns A {@link Hooks} object that snapshots the watched value before the
451
+ * handler and regenerates the session id when it changed afterwards
452
+ * (session-fixation defense).
435
453
  * @since 0.23.0
436
454
  */
437
455
  export function rotateSession(opts = {}) {
@@ -462,9 +480,13 @@ export function rotateSession(opts = {}) {
462
480
  }
463
481
  // ---------- Low-level signing helpers (re-exported for advanced use) ----------
464
482
  /**
465
- * Sign an arbitrary string with HMAC-SHA256. Returns `${value}.${sig}` where
466
- * `sig` is URL-safe base64. Useful for building custom signed cookies or
467
- * tokens that do not need a session store.
483
+ * Sign an arbitrary string with HMAC-SHA256. Useful for building custom
484
+ * signed cookies or tokens that do not need a session store.
485
+ *
486
+ * @param value String to sign; must not contain `.` (the separator).
487
+ * @param secret HMAC key, at least 16 characters.
488
+ * @returns `${value}.${sig}` where `sig` is URL-safe base64.
489
+ * @throws Error when `value` contains `.` or the secret is too short.
468
490
  */
469
491
  export async function signValue(value, secret) {
470
492
  if (value.includes(".")) {
@@ -475,8 +497,12 @@ export async function signValue(value, secret) {
475
497
  return `${value}.${sig}`;
476
498
  }
477
499
  /**
478
- * Verify a `signValue()`-produced string. Returns the original value when the
479
- * signature checks out, otherwise `null`. Constant-time on the signature.
500
+ * Verify a `signValue()`-produced string. Constant-time on the signature
501
+ * comparison.
502
+ *
503
+ * @param signed The `${value}.${sig}` string to verify.
504
+ * @param secret HMAC key(s); an array lets rotated old secrets still verify.
505
+ * @returns The original value when any secret's signature matches, else `null`.
480
506
  */
481
507
  export async function verifySignedValue(signed, secret) {
482
508
  const dot = signed.lastIndexOf(".");
@@ -36,8 +36,11 @@
36
36
  * and reconnection control without sending an event payload.
37
37
  */
38
38
  export interface SSEMessage {
39
+ /** Event payload. Strings are sent verbatim; other values are `JSON.stringify`-ed. */
39
40
  data?: unknown;
41
+ /** Event name (`event:` field). Newlines are replaced with spaces to prevent frame injection. */
40
42
  event?: string;
43
+ /** Last-event ID (`id:` field). Newlines are replaced with spaces to prevent frame injection. */
41
44
  id?: string;
42
45
  /** Reconnection delay in milliseconds. */
43
46
  retry?: number;
@@ -76,11 +79,19 @@ type IterableSource<T> = AsyncIterable<T> | Iterable<T> | (() => AsyncIterable<T
76
79
  * Build a backpressure-safe `ReadableStream` from an async iterable of SSE
77
80
  * messages. The iterator is only advanced when the consumer pulls the next
78
81
  * chunk, so a slow client cannot cause unbounded buffering.
82
+ *
83
+ * @param source Async/sync iterable (or factory) yielding {@link SSEMessage}s or plain strings.
84
+ * @param opts Abort signal and optional keep-alive interval; see {@link SSEStreamOptions}.
85
+ * @returns A `ReadableStream<Uint8Array>` of encoded `text/event-stream` frames.
79
86
  */
80
87
  export declare function sseStream(source: IterableSource<SSEMessage | string>, opts?: SSEStreamOptions): ReadableStream<Uint8Array>;
81
88
  /**
82
89
  * Wrap `sseStream` in a `Response` with the proper SSE headers
83
90
  * (`text/event-stream`, no caching, keep-alive). Caller-supplied headers win.
91
+ *
92
+ * @param source Async/sync iterable (or factory) yielding {@link SSEMessage}s or plain strings.
93
+ * @param opts Status, headers, abort signal, and keep-alive; see {@link SSEResponseOptions}.
94
+ * @returns A streaming `Response` (default status `200`) with SSE headers applied.
84
95
  */
85
96
  export declare function sseResponse(source: IterableSource<SSEMessage | string>, opts?: SSEResponseOptions): Response;
86
97
  /**
@@ -88,11 +99,19 @@ export declare function sseResponse(source: IterableSource<SSEMessage | string>,
88
99
  * JSON) records from an async iterable. Each yielded value is encoded with
89
100
  * `JSON.stringify` and terminated with `\n`. Values that stringify to
90
101
  * `undefined` throw because they cannot be represented as valid NDJSON.
102
+ *
103
+ * @param source Async/sync iterable (or factory) yielding JSON-serializable values.
104
+ * @param opts Optional abort signal; see {@link StreamOptions}.
105
+ * @returns A `ReadableStream<Uint8Array>` of newline-terminated JSON records.
91
106
  */
92
107
  export declare function ndjsonStream<T>(source: IterableSource<T>, opts?: StreamOptions): ReadableStream<Uint8Array>;
93
108
  /**
94
109
  * Wrap `ndjsonStream` in a `Response` with `application/x-ndjson` and
95
110
  * cache-busting headers. Caller-supplied headers win.
111
+ *
112
+ * @param source Async/sync iterable (or factory) yielding JSON-serializable values.
113
+ * @param opts Status, headers, and abort signal; see {@link NDJSONResponseOptions}.
114
+ * @returns A streaming `Response` (default status `200`) with NDJSON headers applied.
96
115
  */
97
116
  export declare function ndjsonResponse<T>(source: IterableSource<T>, opts?: NDJSONResponseOptions): Response;
98
117
  export {};
package/dist/streaming.js CHANGED
@@ -87,6 +87,10 @@ function encodeNDJSON(value) {
87
87
  * Build a backpressure-safe `ReadableStream` from an async iterable of SSE
88
88
  * messages. The iterator is only advanced when the consumer pulls the next
89
89
  * chunk, so a slow client cannot cause unbounded buffering.
90
+ *
91
+ * @param source Async/sync iterable (or factory) yielding {@link SSEMessage}s or plain strings.
92
+ * @param opts Abort signal and optional keep-alive interval; see {@link SSEStreamOptions}.
93
+ * @returns A `ReadableStream<Uint8Array>` of encoded `text/event-stream` frames.
90
94
  */
91
95
  export function sseStream(source, opts = {}) {
92
96
  const iterator = getAsyncIterator(source);
@@ -165,6 +169,10 @@ export function sseStream(source, opts = {}) {
165
169
  /**
166
170
  * Wrap `sseStream` in a `Response` with the proper SSE headers
167
171
  * (`text/event-stream`, no caching, keep-alive). Caller-supplied headers win.
172
+ *
173
+ * @param source Async/sync iterable (or factory) yielding {@link SSEMessage}s or plain strings.
174
+ * @param opts Status, headers, abort signal, and keep-alive; see {@link SSEResponseOptions}.
175
+ * @returns A streaming `Response` (default status `200`) with SSE headers applied.
168
176
  */
169
177
  export function sseResponse(source, opts = {}) {
170
178
  const stream = sseStream(source, opts);
@@ -185,6 +193,10 @@ export function sseResponse(source, opts = {}) {
185
193
  * JSON) records from an async iterable. Each yielded value is encoded with
186
194
  * `JSON.stringify` and terminated with `\n`. Values that stringify to
187
195
  * `undefined` throw because they cannot be represented as valid NDJSON.
196
+ *
197
+ * @param source Async/sync iterable (or factory) yielding JSON-serializable values.
198
+ * @param opts Optional abort signal; see {@link StreamOptions}.
199
+ * @returns A `ReadableStream<Uint8Array>` of newline-terminated JSON records.
188
200
  */
189
201
  export function ndjsonStream(source, opts = {}) {
190
202
  const iterator = getAsyncIterator(source);
@@ -246,6 +258,10 @@ export function ndjsonStream(source, opts = {}) {
246
258
  /**
247
259
  * Wrap `ndjsonStream` in a `Response` with `application/x-ndjson` and
248
260
  * cache-busting headers. Caller-supplied headers win.
261
+ *
262
+ * @param source Async/sync iterable (or factory) yielding JSON-serializable values.
263
+ * @param opts Status, headers, and abort signal; see {@link NDJSONResponseOptions}.
264
+ * @returns A streaming `Response` (default status `200`) with NDJSON headers applied.
249
265
  */
250
266
  export function ndjsonResponse(source, opts = {}) {
251
267
  const stream = ndjsonStream(source, opts);
@@ -92,6 +92,10 @@ export interface SubdomainsResult {
92
92
  * // => { baseDomain: "bar.s3.amazonaws.com", subdomain: "foo", labels: ["foo"] }
93
93
  * ```
94
94
  *
95
+ * @param hostname - Hostname to split (lowercased; a trailing FQDN dot is stripped).
96
+ * @param opts - Optional pinned `baseDomain`, `extraSuffixes`, and the `production` staleness gate.
97
+ * @returns The registrable {@link SubdomainsResult} (`baseDomain`, `subdomain`, `labels`).
98
+ * @throws {Error} On an empty hostname, a host outside a declared `baseDomain`, or a stale PSL snapshot in production.
95
99
  * @since 0.24.0
96
100
  */
97
101
  export declare function subdomains(hostname: string, opts?: SubdomainsOptions): SubdomainsResult;
@@ -93,6 +93,10 @@ export const MAX_SNAPSHOT_AGE_DAYS = 90;
93
93
  * // => { baseDomain: "bar.s3.amazonaws.com", subdomain: "foo", labels: ["foo"] }
94
94
  * ```
95
95
  *
96
+ * @param hostname - Hostname to split (lowercased; a trailing FQDN dot is stripped).
97
+ * @param opts - Optional pinned `baseDomain`, `extraSuffixes`, and the `production` staleness gate.
98
+ * @returns The registrable {@link SubdomainsResult} (`baseDomain`, `subdomain`, `labels`).
99
+ * @throws {Error} On an empty hostname, a host outside a declared `baseDomain`, or a stale PSL snapshot in production.
96
100
  * @since 0.24.0
97
101
  */
98
102
  export function subdomains(hostname, opts = {}) {