@daloyjs/core 0.7.4 → 0.8.2

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 (67) hide show
  1. package/README.md +33 -63
  2. package/dist/adapters/bun.d.ts +26 -4
  3. package/dist/adapters/bun.d.ts.map +1 -1
  4. package/dist/adapters/bun.js +16 -4
  5. package/dist/adapters/bun.js.map +1 -1
  6. package/dist/adapters/cloudflare.d.ts +21 -4
  7. package/dist/adapters/cloudflare.d.ts.map +1 -1
  8. package/dist/adapters/cloudflare.js.map +1 -1
  9. package/dist/adapters/deno.d.ts +25 -2
  10. package/dist/adapters/deno.d.ts.map +1 -1
  11. package/dist/adapters/deno.js +39 -7
  12. package/dist/adapters/deno.js.map +1 -1
  13. package/dist/adapters/fastly.d.ts +23 -0
  14. package/dist/adapters/fastly.d.ts.map +1 -0
  15. package/dist/adapters/fastly.js +11 -0
  16. package/dist/adapters/fastly.js.map +1 -0
  17. package/dist/adapters/lambda.d.ts +67 -0
  18. package/dist/adapters/lambda.d.ts.map +1 -0
  19. package/dist/adapters/lambda.js +117 -0
  20. package/dist/adapters/lambda.js.map +1 -0
  21. package/dist/adapters/node.d.ts +7 -0
  22. package/dist/adapters/node.d.ts.map +1 -1
  23. package/dist/adapters/node.js +17 -4
  24. package/dist/adapters/node.js.map +1 -1
  25. package/dist/adapters/vercel.d.ts +35 -7
  26. package/dist/adapters/vercel.d.ts.map +1 -1
  27. package/dist/adapters/vercel.js +22 -1
  28. package/dist/adapters/vercel.js.map +1 -1
  29. package/dist/app.d.ts +235 -8
  30. package/dist/app.d.ts.map +1 -1
  31. package/dist/app.js +222 -8
  32. package/dist/app.js.map +1 -1
  33. package/dist/client.d.ts +27 -0
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +27 -0
  36. package/dist/client.js.map +1 -1
  37. package/dist/errors.d.ts +169 -3
  38. package/dist/errors.d.ts.map +1 -1
  39. package/dist/errors.js +143 -0
  40. package/dist/errors.js.map +1 -1
  41. package/dist/logger.d.ts +26 -0
  42. package/dist/logger.d.ts.map +1 -1
  43. package/dist/logger.js +26 -0
  44. package/dist/logger.js.map +1 -1
  45. package/dist/middleware.d.ts +143 -0
  46. package/dist/middleware.d.ts.map +1 -1
  47. package/dist/middleware.js +147 -4
  48. package/dist/middleware.js.map +1 -1
  49. package/dist/openapi.d.ts +32 -0
  50. package/dist/openapi.d.ts.map +1 -1
  51. package/dist/openapi.js +33 -2
  52. package/dist/openapi.js.map +1 -1
  53. package/dist/schema.d.ts +33 -2
  54. package/dist/schema.d.ts.map +1 -1
  55. package/dist/schema.js +33 -2
  56. package/dist/schema.js.map +1 -1
  57. package/dist/security-schemes.d.ts +75 -5
  58. package/dist/security-schemes.d.ts.map +1 -1
  59. package/dist/security-schemes.js +75 -5
  60. package/dist/security-schemes.js.map +1 -1
  61. package/dist/security.d.ts +73 -4
  62. package/dist/security.d.ts.map +1 -1
  63. package/dist/security.js +73 -4
  64. package/dist/security.js.map +1 -1
  65. package/dist/types.d.ts +195 -5
  66. package/dist/types.d.ts.map +1 -1
  67. package/package.json +9 -1
package/dist/schema.js CHANGED
@@ -1,9 +1,40 @@
1
- /** Validate any Standard-Schema-compatible schema. */
1
+ /**
2
+ * Run a Standard-Schema validator over an arbitrary input. Awaits async
3
+ * validators automatically and returns the spec-defined
4
+ * `{ value }` / `{ issues }` result.
5
+ *
6
+ * DaloyJS calls this internally for every declared request schema; you can
7
+ * also use it directly inside hooks or business logic.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { z } from "zod";
12
+ * import { validate } from "@daloyjs/core";
13
+ *
14
+ * const schema = z.object({ name: z.string() });
15
+ * const result = await validate(schema, { name: "Ada" });
16
+ * if (result.issues) throw new Error(result.issues[0].message);
17
+ * console.log(result.value.name);
18
+ * ```
19
+ *
20
+ * @param schema - Any Standard-Schema-compatible validator.
21
+ * @param value - The value to validate.
22
+ * @returns Fulfills with the validation result.
23
+ * @since 0.1.0
24
+ */
2
25
  export async function validate(schema, value) {
3
26
  const r = schema["~standard"].validate(value);
4
27
  return r instanceof Promise ? r : r;
5
28
  }
6
- /** Light-weight check for "looks like a Standard Schema". */
29
+ /**
30
+ * Duck-typed runtime check that an unknown value looks like a Standard
31
+ * Schema validator (has a `~standard.validate` function). Useful in helpers
32
+ * that accept either a schema or a raw value.
33
+ *
34
+ * @param x - Value to test.
35
+ * @returns `true` when `x` exposes the Standard Schema contract.
36
+ * @since 0.1.0
37
+ */
7
38
  export function isStandardSchema(x) {
8
39
  return (!!x &&
9
40
  typeof x === "object" &&
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAqDA,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAS,EACT,KAAc;IAEd,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAC,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAS,CAAC;AAC/C,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,gBAAgB,CAAC,CAAU;IACzC,OAAO,CACL,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,KAAK,QAAQ;QACrB,WAAW,IAAK,CAAY;QAC5B,OAAQ,CAAS,CAAC,WAAW,CAAC,EAAE,QAAQ,KAAK,UAAU,CACxD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAqDA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAS,EACT,KAAc;IAEd,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAC,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAS,CAAC;AAC/C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAU;IACzC,OAAO,CACL,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,KAAK,QAAQ;QACrB,WAAW,IAAK,CAAY;QAC5B,OAAQ,CAAS,CAAC,WAAW,CAAC,EAAE,QAAQ,KAAK,UAAU,CACxD,CAAC;AACJ,CAAC"}
@@ -85,14 +85,84 @@ export interface OpenIdConnectScheme {
85
85
  description?: string;
86
86
  }
87
87
  export type SecurityScheme = HttpBearerScheme | HttpBasicScheme | ApiKeyScheme | OAuth2Scheme | OpenIdConnectScheme;
88
- /** HTTP Bearer token scheme (e.g. `Authorization: Bearer <token>`). */
88
+ /**
89
+ * Build an OpenAPI Security Scheme Object for HTTP Bearer authentication
90
+ * (e.g. `Authorization: Bearer <token>`).
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import { App, httpBearerScheme } from "@daloyjs/core";
95
+ * import { generateOpenAPI } from "@daloyjs/core/openapi";
96
+ *
97
+ * const app = new App();
98
+ * const doc = generateOpenAPI(app, {
99
+ * info: { title: "Books API", version: "1.0.0" },
100
+ * securitySchemes: { bearerAuth: httpBearerScheme({ bearerFormat: "JWT" }) },
101
+ * });
102
+ * ```
103
+ *
104
+ * @param options - Optional `bearerFormat` hint and `description`.
105
+ * @returns A spec-shaped `{ type, scheme, ... }` object.
106
+ * @since 0.1.0
107
+ */
89
108
  export declare function httpBearerScheme(options?: HttpBearerSchemeOptions): HttpBearerScheme;
90
- /** HTTP Basic auth scheme (`Authorization: Basic <base64>`). */
109
+ /**
110
+ * Build an OpenAPI Security Scheme Object for HTTP Basic authentication
111
+ * (`Authorization: Basic <base64>`).
112
+ *
113
+ * @param options - Optional human-readable `description`.
114
+ * @returns A spec-shaped `{ type: "http", scheme: "basic", ... }` object.
115
+ * @since 0.1.0
116
+ */
91
117
  export declare function httpBasicScheme(options?: HttpBasicSchemeOptions): HttpBasicScheme;
92
- /** API key scheme delivered in a header, query parameter, or cookie. */
118
+ /**
119
+ * Build an OpenAPI Security Scheme Object for an API key delivered in a
120
+ * request header, query parameter, or cookie.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * apiKeyScheme({ in: "header", name: "x-api-key" })
125
+ * ```
126
+ *
127
+ * @param options - Required `in` location and `name`, plus optional `description`.
128
+ * @returns A spec-shaped `{ type: "apiKey", in, name, ... }` object.
129
+ * @throws {TypeError} When `in` is not `"header" | "query" | "cookie"` or `name` is empty.
130
+ * @since 0.1.0
131
+ */
93
132
  export declare function apiKeyScheme(options: ApiKeySchemeOptions): ApiKeyScheme;
94
- /** OAuth 2.0 scheme. At least one flow is required. */
133
+ /**
134
+ * Build an OpenAPI Security Scheme Object for OAuth 2.0. At least one flow
135
+ * (implicit, password, client credentials, or authorization code) must be
136
+ * declared.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * oauth2Scheme({
141
+ * flows: {
142
+ * authorizationCode: {
143
+ * authorizationUrl: "https://example.com/oauth/authorize",
144
+ * tokenUrl: "https://example.com/oauth/token",
145
+ * scopes: { "orders:read": "Read your orders" },
146
+ * },
147
+ * },
148
+ * })
149
+ * ```
150
+ *
151
+ * @param options - Object with at least one `flows.*` entry.
152
+ * @returns A spec-shaped `{ type: "oauth2", flows, ... }` object.
153
+ * @throws {TypeError} When no OAuth2 flow is declared.
154
+ * @since 0.1.0
155
+ */
95
156
  export declare function oauth2Scheme(options: OAuth2SchemeOptions): OAuth2Scheme;
96
- /** OpenID Connect Discovery scheme. */
157
+ /**
158
+ * Build an OpenAPI Security Scheme Object for OpenID Connect Discovery.
159
+ * The `openIdConnectUrl` must be a non-empty string (typically ending in
160
+ * `/.well-known/openid-configuration`).
161
+ *
162
+ * @param options - Object with the required `openIdConnectUrl`.
163
+ * @returns A spec-shaped `{ type: "openIdConnect", openIdConnectUrl, ... }` object.
164
+ * @throws {TypeError} When `openIdConnectUrl` is missing or empty.
165
+ * @since 0.1.0
166
+ */
97
167
  export declare function openIdConnectScheme(options: OpenIdConnectSchemeOptions): OpenIdConnectScheme;
98
168
  //# sourceMappingURL=security-schemes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"security-schemes.d.ts","sourceRoot":"","sources":["../src/security-schemes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"security-schemes.d.ts","sourceRoot":"","sources":["../src/security-schemes.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,26 @@
8
8
  * Spec reference:
9
9
  * https://spec.openapis.org/oas/v3.1.0#security-scheme-object
10
10
  */
11
- /** HTTP Bearer token scheme (e.g. `Authorization: Bearer <token>`). */
11
+ /**
12
+ * Build an OpenAPI Security Scheme Object for HTTP Bearer authentication
13
+ * (e.g. `Authorization: Bearer <token>`).
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { App, httpBearerScheme } from "@daloyjs/core";
18
+ * import { generateOpenAPI } from "@daloyjs/core/openapi";
19
+ *
20
+ * const app = new App();
21
+ * const doc = generateOpenAPI(app, {
22
+ * info: { title: "Books API", version: "1.0.0" },
23
+ * securitySchemes: { bearerAuth: httpBearerScheme({ bearerFormat: "JWT" }) },
24
+ * });
25
+ * ```
26
+ *
27
+ * @param options - Optional `bearerFormat` hint and `description`.
28
+ * @returns A spec-shaped `{ type, scheme, ... }` object.
29
+ * @since 0.1.0
30
+ */
12
31
  export function httpBearerScheme(options = {}) {
13
32
  const scheme = { type: "http", scheme: "bearer" };
14
33
  if (options.bearerFormat !== undefined)
@@ -17,14 +36,34 @@ export function httpBearerScheme(options = {}) {
17
36
  scheme.description = options.description;
18
37
  return scheme;
19
38
  }
20
- /** HTTP Basic auth scheme (`Authorization: Basic <base64>`). */
39
+ /**
40
+ * Build an OpenAPI Security Scheme Object for HTTP Basic authentication
41
+ * (`Authorization: Basic <base64>`).
42
+ *
43
+ * @param options - Optional human-readable `description`.
44
+ * @returns A spec-shaped `{ type: "http", scheme: "basic", ... }` object.
45
+ * @since 0.1.0
46
+ */
21
47
  export function httpBasicScheme(options = {}) {
22
48
  const scheme = { type: "http", scheme: "basic" };
23
49
  if (options.description !== undefined)
24
50
  scheme.description = options.description;
25
51
  return scheme;
26
52
  }
27
- /** API key scheme delivered in a header, query parameter, or cookie. */
53
+ /**
54
+ * Build an OpenAPI Security Scheme Object for an API key delivered in a
55
+ * request header, query parameter, or cookie.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * apiKeyScheme({ in: "header", name: "x-api-key" })
60
+ * ```
61
+ *
62
+ * @param options - Required `in` location and `name`, plus optional `description`.
63
+ * @returns A spec-shaped `{ type: "apiKey", in, name, ... }` object.
64
+ * @throws {TypeError} When `in` is not `"header" | "query" | "cookie"` or `name` is empty.
65
+ * @since 0.1.0
66
+ */
28
67
  export function apiKeyScheme(options) {
29
68
  if (options.in !== "header" && options.in !== "query" && options.in !== "cookie") {
30
69
  throw new TypeError(`apiKeyScheme: "in" must be one of "header" | "query" | "cookie", got "${String(options.in)}"`);
@@ -41,7 +80,29 @@ export function apiKeyScheme(options) {
41
80
  scheme.description = options.description;
42
81
  return scheme;
43
82
  }
44
- /** OAuth 2.0 scheme. At least one flow is required. */
83
+ /**
84
+ * Build an OpenAPI Security Scheme Object for OAuth 2.0. At least one flow
85
+ * (implicit, password, client credentials, or authorization code) must be
86
+ * declared.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * oauth2Scheme({
91
+ * flows: {
92
+ * authorizationCode: {
93
+ * authorizationUrl: "https://example.com/oauth/authorize",
94
+ * tokenUrl: "https://example.com/oauth/token",
95
+ * scopes: { "orders:read": "Read your orders" },
96
+ * },
97
+ * },
98
+ * })
99
+ * ```
100
+ *
101
+ * @param options - Object with at least one `flows.*` entry.
102
+ * @returns A spec-shaped `{ type: "oauth2", flows, ... }` object.
103
+ * @throws {TypeError} When no OAuth2 flow is declared.
104
+ * @since 0.1.0
105
+ */
45
106
  export function oauth2Scheme(options) {
46
107
  const flows = options.flows ?? {};
47
108
  const hasFlow = flows.implicit !== undefined ||
@@ -56,7 +117,16 @@ export function oauth2Scheme(options) {
56
117
  scheme.description = options.description;
57
118
  return scheme;
58
119
  }
59
- /** OpenID Connect Discovery scheme. */
120
+ /**
121
+ * Build an OpenAPI Security Scheme Object for OpenID Connect Discovery.
122
+ * The `openIdConnectUrl` must be a non-empty string (typically ending in
123
+ * `/.well-known/openid-configuration`).
124
+ *
125
+ * @param options - Object with the required `openIdConnectUrl`.
126
+ * @returns A spec-shaped `{ type: "openIdConnect", openIdConnectUrl, ... }` object.
127
+ * @throws {TypeError} When `openIdConnectUrl` is missing or empty.
128
+ * @since 0.1.0
129
+ */
60
130
  export function openIdConnectScheme(options) {
61
131
  if (typeof options.openIdConnectUrl !== "string" || options.openIdConnectUrl.length === 0) {
62
132
  throw new TypeError(`openIdConnectScheme: "openIdConnectUrl" must be a non-empty string`);
@@ -1 +1 @@
1
- {"version":3,"file":"security-schemes.js","sourceRoot":"","sources":["../src/security-schemes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"security-schemes.js","sourceRoot":"","sources":["../src/security-schemes.ts"],"names":[],"mappings":"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"}
@@ -8,14 +8,83 @@
8
8
  * - timingSafeEqual: constant-time string comparison for token checks.
9
9
  * - randomId: cryptographically strong request id.
10
10
  */
11
- /** Read a request body to bytes with a hard size cap. */
11
+ /**
12
+ * Read a `Request` body to a `Uint8Array` while enforcing a hard byte cap.
13
+ *
14
+ * The cap is checked first against the declared `Content-Length` (so the
15
+ * fast-path rejects oversize bodies without reading any bytes), then against
16
+ * the actual streamed total. Either trigger throws
17
+ * {@link PayloadTooLargeError} (mapped to `413`). DaloyJS calls this for
18
+ * every request automatically; use it directly only from custom plugins
19
+ * that need raw bytes.
20
+ *
21
+ * @param req - Standard `Request` to drain.
22
+ * @param limit - Maximum number of bytes to accept.
23
+ * @returns Fulfills with the body as a `Uint8Array`.
24
+ * @throws {PayloadTooLargeError} When the declared or actual size exceeds `limit`.
25
+ * @throws {BadRequestError} When `Content-Length` is present but invalid.
26
+ * @since 0.1.0
27
+ */
12
28
  export declare function readBodyLimited(req: Request, limit: number): Promise<Uint8Array>;
13
- /** JSON.parse that drops dangerous keys (prototype pollution defence). */
29
+ /**
30
+ * Parse a JSON string while stripping the dangerous keys `__proto__`,
31
+ * `constructor`, and `prototype` from every nested object. Throws
32
+ * {@link BadRequestError} on invalid JSON — the message is intentionally
33
+ * generic to avoid revealing parser internals to attackers.
34
+ *
35
+ * @param text - The JSON text to parse. Empty string returns `undefined`.
36
+ * @returns The parsed value with prototype-pollution keys removed.
37
+ * @throws {BadRequestError} When the input is not valid JSON.
38
+ * @since 0.1.0
39
+ */
14
40
  export declare function safeJsonParse(text: string): unknown;
41
+ /**
42
+ * Validate a candidate HTTP header name against RFC 7230 token grammar and
43
+ * return its lowercased form (Headers normalize to lowercase). Useful when
44
+ * accepting header names from user/config input.
45
+ *
46
+ * @param name - The header name to validate.
47
+ * @returns The lowercased header name.
48
+ * @throws {BadRequestError} When `name` contains illegal characters.
49
+ * @since 0.1.0
50
+ */
15
51
  export declare function sanitizeHeaderName(name: string): string;
52
+ /**
53
+ * Reject HTTP header values containing CR, LF, or NUL bytes — the classic
54
+ * header / response-splitting vector. Returns the value untouched on
55
+ * success.
56
+ *
57
+ * @param value - The header value to validate.
58
+ * @returns The same `value` if it is safe to write to a header.
59
+ * @throws {BadRequestError} When `value` contains `\r`, `\n`, or `\0`.
60
+ * @since 0.1.0
61
+ */
16
62
  export declare function sanitizeHeaderValue(value: string): string;
17
- /** Constant-time string comparison. Use for tokens, signatures, etc. */
63
+ /**
64
+ * Constant-time string comparison resistant to timing attacks. Use whenever
65
+ * comparing secrets such as CSRF tokens, HMAC signatures, or API keys; never
66
+ * use `===` for those comparisons.
67
+ *
68
+ * @param a - First string.
69
+ * @param b - Second string.
70
+ * @returns `true` when the strings have the same length and contents.
71
+ * @since 0.1.0
72
+ */
18
73
  export declare function timingSafeEqual(a: string, b: string): boolean;
19
- /** Cryptographically strong request id (URL-safe, ~22 chars). */
74
+ /**
75
+ * Generate a cryptographically strong, URL-safe identifier (~22 chars).
76
+ *
77
+ * Uses Web Crypto's `crypto.randomUUID()` when available, falling back to
78
+ * 16 random bytes via `crypto.getRandomValues()`. The last-resort fallback
79
+ * (timestamp + `Math.random()`) only triggers in environments without
80
+ * WebCrypto, which is none of Node 20+/Bun/Deno/Cloudflare Workers/Vercel
81
+ * Edge.
82
+ *
83
+ * Suitable for request ids, session ids, and short-lived correlation tokens.
84
+ * Do not use for long-lived secrets unless you also sign or wrap them.
85
+ *
86
+ * @returns A random URL-safe id string.
87
+ * @since 0.1.0
88
+ */
20
89
  export declare function randomId(): string;
21
90
  //# sourceMappingURL=security.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,yDAAyD;AACzD,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC,CAsCrB;AAID,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUnD;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED,iEAAiE;AACjE,wBAAgB,QAAQ,IAAI,MAAM,CAUjC"}
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC,CAsCrB;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUnD;AAID;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAUjC"}
package/dist/security.js CHANGED
@@ -9,7 +9,23 @@
9
9
  * - randomId: cryptographically strong request id.
10
10
  */
11
11
  import { PayloadTooLargeError, BadRequestError, } from "./errors.js";
12
- /** Read a request body to bytes with a hard size cap. */
12
+ /**
13
+ * Read a `Request` body to a `Uint8Array` while enforcing a hard byte cap.
14
+ *
15
+ * The cap is checked first against the declared `Content-Length` (so the
16
+ * fast-path rejects oversize bodies without reading any bytes), then against
17
+ * the actual streamed total. Either trigger throws
18
+ * {@link PayloadTooLargeError} (mapped to `413`). DaloyJS calls this for
19
+ * every request automatically; use it directly only from custom plugins
20
+ * that need raw bytes.
21
+ *
22
+ * @param req - Standard `Request` to drain.
23
+ * @param limit - Maximum number of bytes to accept.
24
+ * @returns Fulfills with the body as a `Uint8Array`.
25
+ * @throws {PayloadTooLargeError} When the declared or actual size exceeds `limit`.
26
+ * @throws {BadRequestError} When `Content-Length` is present but invalid.
27
+ * @since 0.1.0
28
+ */
13
29
  export async function readBodyLimited(req, limit) {
14
30
  // Trust Content-Length when present — fail fast.
15
31
  const cl = req.headers.get("content-length");
@@ -53,7 +69,17 @@ export async function readBodyLimited(req, limit) {
53
69
  return out;
54
70
  }
55
71
  const FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
56
- /** JSON.parse that drops dangerous keys (prototype pollution defence). */
72
+ /**
73
+ * Parse a JSON string while stripping the dangerous keys `__proto__`,
74
+ * `constructor`, and `prototype` from every nested object. Throws
75
+ * {@link BadRequestError} on invalid JSON — the message is intentionally
76
+ * generic to avoid revealing parser internals to attackers.
77
+ *
78
+ * @param text - The JSON text to parse. Empty string returns `undefined`.
79
+ * @returns The parsed value with prototype-pollution keys removed.
80
+ * @throws {BadRequestError} When the input is not valid JSON.
81
+ * @since 0.1.0
82
+ */
57
83
  export function safeJsonParse(text) {
58
84
  if (text.length === 0)
59
85
  return undefined;
@@ -69,12 +95,32 @@ export function safeJsonParse(text) {
69
95
  }
70
96
  }
71
97
  const HEADER_NAME_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
98
+ /**
99
+ * Validate a candidate HTTP header name against RFC 7230 token grammar and
100
+ * return its lowercased form (Headers normalize to lowercase). Useful when
101
+ * accepting header names from user/config input.
102
+ *
103
+ * @param name - The header name to validate.
104
+ * @returns The lowercased header name.
105
+ * @throws {BadRequestError} When `name` contains illegal characters.
106
+ * @since 0.1.0
107
+ */
72
108
  export function sanitizeHeaderName(name) {
73
109
  if (!HEADER_NAME_RE.test(name)) {
74
110
  throw new BadRequestError(`Invalid header name: ${name}`);
75
111
  }
76
112
  return name.toLowerCase();
77
113
  }
114
+ /**
115
+ * Reject HTTP header values containing CR, LF, or NUL bytes — the classic
116
+ * header / response-splitting vector. Returns the value untouched on
117
+ * success.
118
+ *
119
+ * @param value - The header value to validate.
120
+ * @returns The same `value` if it is safe to write to a header.
121
+ * @throws {BadRequestError} When `value` contains `\r`, `\n`, or `\0`.
122
+ * @since 0.1.0
123
+ */
78
124
  export function sanitizeHeaderValue(value) {
79
125
  // Block CRLF + NUL — the classic header / response splitting vector.
80
126
  if (/[\r\n\0]/.test(value)) {
@@ -82,7 +128,16 @@ export function sanitizeHeaderValue(value) {
82
128
  }
83
129
  return value;
84
130
  }
85
- /** Constant-time string comparison. Use for tokens, signatures, etc. */
131
+ /**
132
+ * Constant-time string comparison resistant to timing attacks. Use whenever
133
+ * comparing secrets such as CSRF tokens, HMAC signatures, or API keys; never
134
+ * use `===` for those comparisons.
135
+ *
136
+ * @param a - First string.
137
+ * @param b - Second string.
138
+ * @returns `true` when the strings have the same length and contents.
139
+ * @since 0.1.0
140
+ */
86
141
  export function timingSafeEqual(a, b) {
87
142
  const len = Math.max(a.length, b.length);
88
143
  let mismatch = a.length ^ b.length;
@@ -91,7 +146,21 @@ export function timingSafeEqual(a, b) {
91
146
  }
92
147
  return mismatch === 0;
93
148
  }
94
- /** Cryptographically strong request id (URL-safe, ~22 chars). */
149
+ /**
150
+ * Generate a cryptographically strong, URL-safe identifier (~22 chars).
151
+ *
152
+ * Uses Web Crypto's `crypto.randomUUID()` when available, falling back to
153
+ * 16 random bytes via `crypto.getRandomValues()`. The last-resort fallback
154
+ * (timestamp + `Math.random()`) only triggers in environments without
155
+ * WebCrypto, which is none of Node 20+/Bun/Deno/Cloudflare Workers/Vercel
156
+ * Edge.
157
+ *
158
+ * Suitable for request ids, session ids, and short-lived correlation tokens.
159
+ * Do not use for long-lived secrets unless you also sign or wrap them.
160
+ *
161
+ * @returns A random URL-safe id string.
162
+ * @since 0.1.0
163
+ */
95
164
  export function randomId() {
96
165
  const c = globalThis.crypto;
97
166
  if (c?.randomUUID)
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,oBAAoB,EACpB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAY,EACZ,KAAa;IAEb,iDAAiD;IACjD,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7C,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,eAAe,CAAC,wBAAwB,CAAC,CAAC;QACtF,IAAI,CAAC,GAAG,KAAK;YAAE,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAExC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IACpC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,iDAAiD;IACjD,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI;YAAE,MAAM;QAChB,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;QAC1B,IAAI,KAAK,GAAG,KAAK,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;YACD,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACnB,MAAM,IAAI,CAAC,CAAC,UAAU,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACrC,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAC;YAC9C,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,eAAe,CAAC,cAAc,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,MAAM,cAAc,GAAG,gCAAgC,CAAC;AAExD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,eAAe,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,qEAAqE;IACrE,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,eAAe,CAAC,sBAAsB,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,CAAS;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,QAAQ,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,QAAQ,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,QAAQ,KAAK,CAAC,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,CAAC,GAAwB,UAAkB,CAAC,MAAM,CAAC;IACzD,IAAI,CAAC,EAAE,UAAU;QAAE,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IACzC,IAAI,CAAC,EAAE,eAAe,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,4EAA4E;IAC5E,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7E,CAAC"}