hono-ban 1.1.0 → 1.3.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 (39) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +65 -4
  3. package/dist/{schema-helpers-bwCFve8i.js → constants-rUzQOaX_.js} +2 -8
  4. package/dist/constants-rUzQOaX_.js.map +1 -0
  5. package/dist/formats/google-api.js +3 -2
  6. package/dist/formats/google-api.js.map +1 -1
  7. package/dist/formats/json-api.js +3 -2
  8. package/dist/formats/json-api.js.map +1 -1
  9. package/dist/formats/plain.js +2 -1
  10. package/dist/formats/plain.js.map +1 -1
  11. package/dist/formats/problem-details.js +1 -1
  12. package/dist/formats/stripe.js +2 -1
  13. package/dist/formats/stripe.js.map +1 -1
  14. package/dist/headers-Bnn4uoV4.js +76 -0
  15. package/dist/headers-Bnn4uoV4.js.map +1 -0
  16. package/dist/{hook-TWCLnCmZ.d.ts → hook-RdzR-1NX.d.ts} +2 -2
  17. package/dist/hook-RdzR-1NX.d.ts.map +1 -0
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +5 -75
  20. package/dist/index.js.map +1 -1
  21. package/dist/{member-name-k4VABr91.js → member-name-Bn3zp8gx.js} +2 -2
  22. package/dist/{member-name-k4VABr91.js.map → member-name-Bn3zp8gx.js.map} +1 -1
  23. package/dist/postgresql.d.ts +160 -0
  24. package/dist/postgresql.d.ts.map +1 -0
  25. package/dist/postgresql.js +285 -0
  26. package/dist/postgresql.js.map +1 -0
  27. package/dist/{problem-details-DeUg_NjG.js → problem-details-G3eerc0Q.js} +4 -3
  28. package/dist/{problem-details-DeUg_NjG.js.map → problem-details-G3eerc0Q.js.map} +1 -1
  29. package/dist/schema-helpers-B4HL9TmU.js +9 -0
  30. package/dist/schema-helpers-B4HL9TmU.js.map +1 -0
  31. package/dist/standard-schema.d.ts +2 -2
  32. package/dist/testing.d.ts +1 -1
  33. package/dist/{types-DYr4CtCC.d.ts → types-DH_JfdBQ.d.ts} +3 -1
  34. package/dist/{types-DYr4CtCC.d.ts.map → types-DH_JfdBQ.d.ts.map} +1 -1
  35. package/dist/valibot.d.ts +2 -2
  36. package/dist/zod.d.ts +2 -2
  37. package/package.json +6 -1
  38. package/dist/hook-TWCLnCmZ.d.ts.map +0 -1
  39. package/dist/schema-helpers-bwCFve8i.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # hono-ban
2
2
 
3
+ ## 1.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`dd1a1b1`](https://github.com/ali-issa/hono-ban/commit/dd1a1b1188aa722d263ab8592c26e1f097b63a51) Thanks [@ali-issa](https://github.com/ali-issa)! - `ban.validation()` accepts `cause`, and `hono-ban/postgresql` keeps its reporting contract for every
8
+ mapping kind.
9
+
10
+ - `ValidationOptions` gains an optional `cause`, stored on the error like every other `cause` and
11
+ never rendered, so a converted validator or driver failure reaches `ErrorReport.error.cause`.
12
+ - `postgresMapper()` passes the driver error as `cause` for `{ issue }` mappings too. Previously an
13
+ ordinary mapping put it on `report.error.cause` and an issue mapping left that member undefined.
14
+ - `postgresMapper()` reads `codes` entries as own properties, like `constraints` and `columns`, and
15
+ rejects a `retryAfter` above `Number.MAX_SAFE_INTEGER`, whose `String()` form is exponential and
16
+ not RFC 9110 `delay-seconds`.
17
+
18
+ ## 1.2.0
19
+
20
+ ### Minor Changes
21
+
22
+ - [`4a17ce0`](https://github.com/ali-issa/hono-ban/commit/4a17ce0676177c9ceff6f877731ab8f7ce513e2b) Thanks [@ali-issa](https://github.com/ali-issa)! - Add `hono-ban/postgresql`: `postgresMapper(options?)` turns a Postgres driver error into a catalog
23
+ entry by SQLSTATE with constant client-facing text, for `createBan({ map })` or
24
+ `ban.onError({ map })`.
25
+
26
+ - Recognizes the errors of node-postgres, PGlite, postgres.js, Neon, and Bun, directly or through
27
+ the `cause` of an ORM wrapper such as Drizzle's `DrizzleQueryError` (also Sequelize 6 `original`
28
+ and Objection `nativeError`). Nothing from the driver's `message`, `detail`, or `hint` reaches
29
+ `detail`, `meta`, or `headers`; the driver error stays on the report.
30
+ - Built-in table: unique, exclusion, foreign key, and restrict violations are 409; not-null, check,
31
+ and data exceptions are 422; serialization failures, deadlocks, `NOWAIT` locks, read-only
32
+ replicas, and the connection, resource, and operator classes are 503, with `Retry-After` when
33
+ `retryAfter` is set. Codes with no row (syntax, privilege, `RAISE`, statement timeout, commit
34
+ outcome unknown) fall through to the handler's constant 500 with `handled: false`.
35
+ - `constraints`, `columns`, and `codes` override the entry, detail, meta, and headers per constraint
36
+ name, `table.column`, SQLSTATE, or class; a constraint or column can instead map to a validation
37
+ error with one issue at a path.
38
+ - `findPostgresError(value)` and `readPostgresFields(error)` are exported for `onReport` sinks.
39
+
3
40
  ## 1.1.0
4
41
 
5
42
  ### Minor Changes
package/README.md CHANGED
@@ -90,6 +90,67 @@ throw ban.ORDER_CONFLICT({
90
90
  });
91
91
  ```
92
92
 
93
+ ### Database errors
94
+
95
+ `hono-ban/postgresql` maps a Postgres driver error to a catalog entry by SQLSTATE with constant
96
+ client-facing text. It recognizes the errors of node-postgres, postgres.js, PGlite, Neon, and Bun,
97
+ thrown directly or wrapped by Drizzle, Kysely, TypeORM, MikroORM, Slonik, or Sequelize:
98
+
99
+ ```ts
100
+ import { postgresMapper } from 'hono-ban/postgresql';
101
+
102
+ const ban = createBan({
103
+ map: postgresMapper({
104
+ constraints: {
105
+ users_email_key: { issue: { path: ['email'], message: 'That email is already registered' } },
106
+ orders_customer_id_fkey: 'The customer does not exist',
107
+ },
108
+ columns: { 'users.email': { issue: { path: ['email'], message: 'Email is required' } } },
109
+ codes: { '42501': { key: 'FORBIDDEN' } },
110
+ retryAfter: 1,
111
+ }),
112
+ });
113
+ ```
114
+
115
+ A unique violation is a 409, a not-null or check violation a 422, a serialization failure or a
116
+ deadlock a 503 with `Retry-After`. `constraints` and `columns` refine the wording per constraint
117
+ name or `table.column`, or turn the violation into a validation error with one issue at a path, the
118
+ shape a form already handles; `codes` overrides the entry per SQLSTATE or class. Nothing from the
119
+ driver's message, detail, or hint reaches a body: the driver error stays on the report as
120
+ `report.error.cause`, and `findPostgresError(report.cause)` reads it out of any wrapper. Codes with
121
+ no row, such as a syntax error, a missing table, or a `RAISE EXCEPTION`, fall through to the
122
+ constant 500 with `handled: false`. The full table and the precedence rules are in SPEC section
123
+ 6.10.
124
+
125
+ How each driver's support is verified (versions are the pins in `e2e/package.json`; the dated matrix
126
+ is in ADR 0015):
127
+
128
+ | Driver or ORM | Verified by |
129
+ | -------------------------------------------- | ------------------------------------------------------------------------------------------ |
130
+ | node-postgres (`pg`) | Real server errors over the wire protocol (PGlite behind `pglite-socket`) in the e2e suite |
131
+ | postgres.js (`postgres`) | The same, plus a type-level check of its error type against the mapper's input type |
132
+ | PGlite | Real server errors in-process in the e2e suite |
133
+ | Drizzle | Real server errors through its wrapper in the e2e suite |
134
+ | Neon, Bun SQL, Sequelize 6 | Error shapes built from the driver source, driven over HTTP |
135
+ | Kysely, TypeORM, MikroORM, Slonik, Objection | Source inspection of how each rethrows or wraps the driver error (ADR 0015) |
136
+
137
+ To put an application-authored `RAISE` message on the wire, compose your own `map`:
138
+
139
+ ```ts
140
+ import { findPostgresError, postgresMapper } from 'hono-ban/postgresql';
141
+
142
+ const postgres = postgresMapper();
143
+ const ban = createBan({
144
+ map: (thrown, ban) => {
145
+ const error = findPostgresError(thrown);
146
+ if (error?.code === 'P0001' && error instanceof Error) {
147
+ return ban.badRequest(error.message, { cause: thrown });
148
+ }
149
+ return postgres(thrown, ban);
150
+ },
151
+ });
152
+ ```
153
+
93
154
  ### Headers some statuses require
94
155
 
95
156
  HTTP makes the application, not the library, responsible for a few headers: a 401 MUST carry
@@ -348,12 +409,12 @@ app.onError(
348
409
  | `hono-ban/zod`, `hono-ban/valibot`, `hono-ban/standard-schema` | validator hooks and issue converters |
349
410
  | `hono-ban/openapi` | `errorResponses`, `errorResponse`, `errorSchema`, `validationResponse`, `validationSchema` |
350
411
  | `hono-ban/otel` | `traceIdFromOtel` |
412
+ | `hono-ban/postgresql` | `postgresMapper`, `findPostgresError`, `readPostgresFields` |
351
413
  | `hono-ban/testing` | `expectBanError`, `renderError`, `assertFormatConformance` |
352
414
 
353
- Database and driver error translation is not part of the core. Map driver errors to catalog entries
354
- in `createBan({ map })` with constant client-facing messages, never the driver's own text (a
355
- PostgreSQL `DETAIL` line can contain the failing row). A companion package for Postgres SQLSTATE
356
- mapping is planned and will be linked here when it ships.
415
+ Other databases go through `createBan({ map })` the same way `hono-ban/postgresql` does: catalog
416
+ entries with constant client-facing messages, never the driver's own text (a driver's detail line
417
+ can contain the failing row).
357
418
 
358
419
  ## Documentation
359
420
 
@@ -61,12 +61,6 @@ const PROTO_KEYS = /* @__PURE__ */ new Set([
61
61
  "prototype"
62
62
  ]);
63
63
  //#endregion
64
- //#region src/formats/schema-helpers.ts
65
- /** A single allowed value, spelled for the target dialect. */
66
- function constant(value, dialect) {
67
- return dialect === "openapi-3.0" ? { enum: [value] } : { const: value };
68
- }
69
- //#endregion
70
- export { DEFAULT_MAX_BODY_BYTES as a, MALFORMED_JSON_MESSAGE as c, TRACEPARENT_PATTERN as d, TRUNCATED_DETAIL_LENGTH as f, DEFAULT_ERROR_ID_HEADER as i, PROTO_KEYS as l, VALIDATION_DETAIL as m, BODY_HEADERS as n, DEFAULT_REQUEST_ID_HEADER as o, UNEXPECTED_DETAIL as p, DEFAULT_CACHE_CONTROL as r, EXTENSION_NAME_PATTERN as s, constant as t, REQUEST_ID_PATTERN as u };
64
+ export { DEFAULT_REQUEST_ID_HEADER as a, PROTO_KEYS as c, TRUNCATED_DETAIL_LENGTH as d, UNEXPECTED_DETAIL as f, DEFAULT_MAX_BODY_BYTES as i, REQUEST_ID_PATTERN as l, DEFAULT_CACHE_CONTROL as n, EXTENSION_NAME_PATTERN as o, VALIDATION_DETAIL as p, DEFAULT_ERROR_ID_HEADER as r, MALFORMED_JSON_MESSAGE as s, BODY_HEADERS as t, TRACEPARENT_PATTERN as u };
71
65
 
72
- //# sourceMappingURL=schema-helpers-bwCFve8i.js.map
66
+ //# sourceMappingURL=constants-rUzQOaX_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants-rUzQOaX_.js","names":[],"sources":["../src/internal/constants.ts"],"sourcesContent":["/**\n * Shared constants. Every value here is named in `docs/SPEC.md` section 13.\n * @packageDocumentation\n */\n\nexport const UNEXPECTED_DETAIL = 'An unexpected error occurred';\nexport const VALIDATION_DETAIL = 'Request validation failed';\n/**\n * The exact message Hono's built-in validator uses when JSON parsing fails.\n * @ref https://github.com/honojs/hono/blob/main/src/validator/validator.ts\n */\nexport const MALFORMED_JSON_MESSAGE = 'Malformed JSON in request body';\nexport const DEFAULT_REQUEST_ID_HEADER = 'X-Request-Id';\nexport const DEFAULT_ERROR_ID_HEADER = 'X-Error-Id';\n/**\n * `Cache-Control` the handler adds when neither the options nor the error\n * supply one (SPEC 6.9, ADR 0012). 404, 405, 410, 414, and 501 are\n * heuristically cacheable, and every body carries an occurrence id, so a\n * shared cache could replay one client's error to another; a 429 MUST NOT be\n * stored at all.\n * @ref https://www.rfc-editor.org/rfc/rfc9110#section-15.1\n * @ref https://www.rfc-editor.org/rfc/rfc9111#section-5.2.2.5\n * @ref https://www.rfc-editor.org/rfc/rfc6585#section-4\n */\nexport const DEFAULT_CACHE_CONTROL = 'no-store';\nexport const DEFAULT_MAX_BODY_BYTES = 65_536;\nexport const TRUNCATED_DETAIL_LENGTH = 1024;\nexport const REQUEST_ID_PATTERN: RegExp = /^[A-Za-z0-9._-]{1,128}$/u;\n/**\n * `version \"-\" trace-id \"-\" parent-id \"-\" trace-flags`, lowercase hex only.\n * @ref https://www.w3.org/TR/trace-context/#traceparent-header-field-values\n */\nexport const TRACEPARENT_PATTERN: RegExp =\n /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})/u;\nexport const TRACEPARENT_LENGTH = 55;\n/**\n * RFC 9457 section 4 (the paragraph after the definition requirements):\n * extension member names SHOULD start with a letter, use only\n * ALPHA / DIGIT / \"_\", and be at least three characters long.\n * @ref https://www.rfc-editor.org/rfc/rfc9457#section-4\n */\nexport const EXTENSION_NAME_PATTERN: RegExp = /^[A-Za-z][A-Za-z0-9_]{2,}$/u;\n/**\n * Headers that describe a response body. `ban.from()` drops them when it\n * adopts the headers of an `HTTPException` response whose body it discards:\n * a stale `Content-Length` truncates the rendered JSON on the wire and a stale\n * `Content-Encoding` makes clients decompress plain text.\n * @ref https://www.rfc-editor.org/rfc/rfc9110#section-8.3 (Content-Type, then 8.4, 8.6, 8.7)\n * @ref https://www.rfc-editor.org/rfc/rfc9110#section-14.4 (Content-Range)\n * @ref https://www.rfc-editor.org/rfc/rfc9112#section-6.1 (Transfer-Encoding)\n */\nexport const BODY_HEADERS: ReadonlySet<string> = new Set([\n 'content-type',\n 'content-length',\n 'content-encoding',\n 'content-location',\n 'content-range',\n 'transfer-encoding',\n]);\nexport const PROTO_KEYS: ReadonlySet<string> = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n]);\n"],"mappings":";;;;;AAKA,MAAa,oBAAoB;AACjC,MAAa,oBAAoB;;;;;AAKjC,MAAa,yBAAyB;AACtC,MAAa,4BAA4B;AACzC,MAAa,0BAA0B;;;;;;;;;;;AAWvC,MAAa,wBAAwB;AACrC,MAAa,yBAAyB;AACtC,MAAa,0BAA0B;AACvC,MAAa,qBAA6B;;;;;AAK1C,MAAa,sBACX;;;;;;;AAQF,MAAa,yBAAiC;;;;;;;;;;AAU9C,MAAa,+BAAoC,IAAI,IAAI;CACvD;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AACD,MAAa,6BAAkC,IAAI,IAAI;CACrD;CACA;CACA;AACF,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { n as safeStringify } from "../json-Bjfm-jxl.js";
2
- import { t as constant } from "../schema-helpers-bwCFve8i.js";
3
- import { t as assertMemberName } from "../member-name-k4VABr91.js";
2
+ import "../constants-rUzQOaX_.js";
3
+ import { t as assertMemberName } from "../member-name-Bn3zp8gx.js";
4
+ import { t as constant } from "../schema-helpers-B4HL9TmU.js";
4
5
  //#region src/formats/google-api/details.ts
5
6
  /** `google.protobuf.Any` type URLs: the `type.googleapis.com/` prefix plus the full message name. */
6
7
  const ERROR_INFO_TYPE = "type.googleapis.com/google.rpc.ErrorInfo";
@@ -1 +1 @@
1
- {"version":3,"file":"google-api.js","names":["retryInfo","errorInfo","retryInfo"],"sources":["../../src/formats/google-api/details.ts","../../src/formats/google-api/rpc-code.ts","../../src/formats/google-api/schema.ts","../../src/formats/google-api/index.ts"],"sourcesContent":["/**\n * The standard `google.rpc` detail payloads this format renders (SPEC 7.6.2)\n * in their proto3 JSON form: each message packed as a `google.protobuf.Any`\n * carries an `@type` member holding its type URL, field names are\n * lowerCamelCase, and fields at their default value (empty string, empty\n * repeated, empty map) are omitted.\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n * @ref https://protobuf.dev/programming-guides/json/\n * @packageDocumentation\n */\nimport type { ValidationIssue } from '../../validation/issue';\n\nimport { safeStringify } from '../../internal/json';\n\n/** `google.protobuf.Any` type URLs: the `type.googleapis.com/` prefix plus the full message name. */\nexport const ERROR_INFO_TYPE =\n 'type.googleapis.com/google.rpc.ErrorInfo' as const;\nexport const BAD_REQUEST_TYPE =\n 'type.googleapis.com/google.rpc.BadRequest' as const;\nexport const RETRY_INFO_TYPE =\n 'type.googleapis.com/google.rpc.RetryInfo' as const;\nexport const REQUEST_INFO_TYPE =\n 'type.googleapis.com/google.rpc.RequestInfo' as const;\nexport const DEBUG_INFO_TYPE =\n 'type.googleapis.com/google.rpc.DebugInfo' as const;\nexport const HELP_TYPE = 'type.googleapis.com/google.rpc.Help' as const;\n\n/**\n * `google.rpc.ErrorInfo`: the machine-readable identifier AIP-193 requires\n * in every error. `reason` is the catalog code, `domain` the format option.\n * @ref https://google.aip.dev/193#errorinfo\n */\nexport interface GoogleApiErrorInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.ErrorInfo';\n readonly reason: string;\n readonly domain: string;\n readonly metadata?: Readonly<Record<string, string>>;\n}\n\n/** `google.rpc.BadRequest.FieldViolation`, one per validation issue. */\nexport interface GoogleApiFieldViolation {\n /** Dot path with `[index]` for array positions, for example `items[0].sku`. */\n readonly field?: string;\n readonly description: string;\n /** The issue code in UPPER_SNAKE_CASE, when the validator gave one. */\n readonly reason?: string;\n}\n\nexport interface GoogleApiBadRequest {\n readonly '@type': 'type.googleapis.com/google.rpc.BadRequest';\n readonly fieldViolations: ReadonlyArray<GoogleApiFieldViolation>;\n}\n\n/** `google.rpc.RetryInfo`, from a delay-seconds `Retry-After` header. */\nexport interface GoogleApiRetryInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.RetryInfo';\n /** A `google.protobuf.Duration` in JSON form, for example `30s`. */\n readonly retryDelay: string;\n}\n\n/** `google.rpc.RequestInfo` carrying the error id (SPEC 10.2). */\nexport interface GoogleApiRequestInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.RequestInfo';\n readonly requestId: string;\n}\n\n/** `google.rpc.DebugInfo`, present only when the handler includes the stack. */\nexport interface GoogleApiDebugInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.DebugInfo';\n readonly stackEntries: ReadonlyArray<string>;\n}\n\nexport interface GoogleApiHelpLink {\n readonly description: string;\n readonly url: string;\n}\n\n/** `google.rpc.Help` with one link to the error's documentation. */\nexport interface GoogleApiHelp {\n readonly '@type': 'type.googleapis.com/google.rpc.Help';\n readonly links: ReadonlyArray<GoogleApiHelpLink>;\n}\n\nexport type GoogleApiDetail =\n | GoogleApiErrorInfo\n | GoogleApiBadRequest\n | GoogleApiRetryInfo\n | GoogleApiRequestInfo\n | GoogleApiDebugInfo\n | GoogleApiHelp;\n\n/**\n * `ErrorInfo.metadata` keys \"must match a regular expression of\n * `[a-z][a-zA-Z0-9-_]+`\" and \"must be limited to 64 characters in length\"\n * (the comment on the field in `error_details.proto`).\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n */\nexport const METADATA_KEY_PATTERN: RegExp = /^[a-z][a-zA-Z0-9_-]{1,63}$/u;\n\n/**\n * `ErrorInfo.metadata` is `map<string, string>`, so every value becomes a\n * string: strings as they are, everything else as JSON. Values JSON cannot\n * represent (`undefined`, functions, symbols) are dropped, and so is every\n * key outside `METADATA_KEY_PATTERN` (`order.id`, `UserId`): a key the\n * grammar rejects would make the body fail the schema, and throwing here\n * would turn the error being rendered into a 500 (SPEC 7.6.2).\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n */\nexport function toMetadata(\n meta: Readonly<Record<string, unknown>>,\n): Record<string, string> {\n const metadata: Record<string, string> = {};\n for (const key of Object.keys(meta)) {\n if (!METADATA_KEY_PATTERN.test(key)) {\n continue;\n }\n const value = meta[key];\n if (typeof value === 'string') {\n metadata[key] = value;\n } else if (typeof value === 'bigint') {\n metadata[key] = value.toString();\n } else if (\n value !== undefined &&\n typeof value !== 'function' &&\n typeof value !== 'symbol'\n ) {\n metadata[key] = safeStringify(value);\n }\n }\n return metadata;\n}\n\n/**\n * `BadRequest.FieldViolation.field`: \"a sequence of dot-separated identifiers\"\n * with repeated-field positions in square brackets, so `['items', 0, 'sku']`\n * is `items[0].sku`. An empty path names the whole request and yields no\n * `field` (proto3 JSON omits empty strings).\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n */\nexport function fieldPath(path: ReadonlyArray<string | number>): string {\n let out = '';\n for (const segment of path) {\n if (typeof segment === 'number') {\n out += `[${String(segment)}]`;\n } else {\n out += out === '' ? segment : `.${segment}`;\n }\n }\n return out;\n}\n\n/**\n * `FieldViolation.reason` \"should be at most 63 characters and match\n * `[A-Z][A-Z0-9_]+[A-Z0-9]`\"; validator codes are lower snake case\n * (`invalid_type`), so they are upper-cased. Not validated further.\n */\nexport function fieldViolation(\n issue: ValidationIssue,\n): GoogleApiFieldViolation {\n const field = fieldPath(issue.path);\n return {\n ...(field === '' ? {} : { field }),\n description: issue.message,\n ...(issue.code === undefined ? {} : { reason: issue.code.toUpperCase() }),\n };\n}\n\nconst DELAY_SECONDS_PATTERN = /^[0-9]+$/u;\n\n/**\n * `RetryInfo.retry_delay` from a `Retry-After` header in its delay-seconds\n * form. The HTTP-date form needs the current time to become a duration, and\n * formats are pure, so it is left out.\n * @ref https://www.rfc-editor.org/rfc/rfc9110#section-10.2.3\n * @ref https://protobuf.dev/programming-guides/json/ (Duration)\n */\nexport function retryInfo(headers: Headers): GoogleApiRetryInfo | undefined {\n const value = headers.get('retry-after');\n if (value === null || !DELAY_SECONDS_PATTERN.test(value)) {\n return undefined;\n }\n return { '@type': RETRY_INFO_TYPE, retryDelay: `${value}s` };\n}\n\n/** RFC 3986 section 3.1 scheme followed by a colon: an absolute URI. */\nconst ABSOLUTE_URI_PATTERN = /^[A-Za-z][A-Za-z0-9+.-]*:/u;\n\n/**\n * `Help.Link.url` \"must be an absolute URL, including scheme\", so a relative\n * `type` yields no `Help` payload.\n * @ref https://google.aip.dev/193#help\n * @ref https://www.rfc-editor.org/rfc/rfc3986#section-3.1\n */\nexport function help(code: string, url?: string): GoogleApiHelp | undefined {\n if (url === undefined || !ABSOLUTE_URI_PATTERN.test(url)) {\n return undefined;\n }\n return {\n '@type': HELP_TYPE,\n links: [{ description: `Documentation for ${code} errors`, url }],\n };\n}\n","/**\n * `google.rpc.Code` names and the HTTP status each one is derived from\n * (SPEC 7.6.1). The forward mapping (code to HTTP status) is the \"HTTP\n * Mapping\" line on every enum value in `code.proto`; it is many-to-one, so the\n * reverse table below is the one Google's own client library uses when it\n * turns an HTTP error into a status code.\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto\n * @ref https://github.com/googleapis/gax-nodejs/blob/main/gax/src/status.ts\n * @packageDocumentation\n */\n\n/** Every value of the `google.rpc.Code` enum, by name. */\nexport type GoogleRpcCode =\n | 'OK'\n | 'CANCELLED'\n | 'UNKNOWN'\n | 'INVALID_ARGUMENT'\n | 'DEADLINE_EXCEEDED'\n | 'NOT_FOUND'\n | 'ALREADY_EXISTS'\n | 'PERMISSION_DENIED'\n | 'RESOURCE_EXHAUSTED'\n | 'FAILED_PRECONDITION'\n | 'ABORTED'\n | 'OUT_OF_RANGE'\n | 'UNIMPLEMENTED'\n | 'INTERNAL'\n | 'UNAVAILABLE'\n | 'DATA_LOSS'\n | 'UNAUTHENTICATED';\n\nconst RPC_CODES: ReadonlySet<string> = new Set<GoogleRpcCode>([\n 'OK',\n 'CANCELLED',\n 'UNKNOWN',\n 'INVALID_ARGUMENT',\n 'DEADLINE_EXCEEDED',\n 'NOT_FOUND',\n 'ALREADY_EXISTS',\n 'PERMISSION_DENIED',\n 'RESOURCE_EXHAUSTED',\n 'FAILED_PRECONDITION',\n 'ABORTED',\n 'OUT_OF_RANGE',\n 'UNIMPLEMENTED',\n 'INTERNAL',\n 'UNAVAILABLE',\n 'DATA_LOSS',\n 'UNAUTHENTICATED',\n]);\n\n/**\n * `HttpCodeToRpcCodeMap` from gax-nodejs, verbatim. Where several codes share\n * an HTTP status the table keeps the one gax picked: `INVALID_ARGUMENT` for\n * 400 (not `FAILED_PRECONDITION` or `OUT_OF_RANGE`), `ABORTED` for 409 (not\n * `ALREADY_EXISTS`), `INTERNAL` for 500 (not `UNKNOWN` or `DATA_LOSS`).\n * @ref https://github.com/googleapis/gax-nodejs/blob/main/gax/src/status.ts\n */\nconst BY_HTTP_STATUS: ReadonlyMap<number, GoogleRpcCode> = new Map<\n number,\n GoogleRpcCode\n>([\n [400, 'INVALID_ARGUMENT'],\n [401, 'UNAUTHENTICATED'],\n [403, 'PERMISSION_DENIED'],\n [404, 'NOT_FOUND'],\n [409, 'ABORTED'],\n [416, 'OUT_OF_RANGE'],\n [429, 'RESOURCE_EXHAUSTED'],\n [499, 'CANCELLED'],\n [501, 'UNIMPLEMENTED'],\n [503, 'UNAVAILABLE'],\n [504, 'DEADLINE_EXCEEDED'],\n]);\n\nconst SUCCESS = 200;\nconst REDIRECT = 300;\nconst CLIENT_ERROR = 400;\nconst SERVER_ERROR = 500;\nconst END = 600;\n\nexport function isGoogleRpcCode(value: string): value is GoogleRpcCode {\n return RPC_CODES.has(value);\n}\n\n/**\n * The `google.rpc.Code` name for an HTTP status, following\n * `rpcCodeFromHttpStatusCode` in gax-nodejs: the table first, then `OK` for\n * any 2xx, `FAILED_PRECONDITION` for any other 4xx, `INTERNAL` for any other\n * 5xx, and `UNKNOWN` for everything else.\n * @ref https://github.com/googleapis/gax-nodejs/blob/main/gax/src/status.ts\n */\nexport function rpcCodeFromStatus(status: number): GoogleRpcCode {\n const mapped = BY_HTTP_STATUS.get(status);\n if (mapped !== undefined) {\n return mapped;\n }\n if (status >= SUCCESS && status < REDIRECT) {\n return 'OK';\n }\n if (status >= CLIENT_ERROR && status < SERVER_ERROR) {\n return 'FAILED_PRECONDITION';\n }\n if (status >= SERVER_ERROR && status < END) {\n return 'INTERNAL';\n }\n return 'UNKNOWN';\n}\n\n/**\n * The `status` member for an entry (SPEC 7.6.1): an explicit per-code option,\n * else the catalog code itself when it already names a `google.rpc.Code`\n * (`NOT_FOUND`, `ALREADY_EXISTS`), else the HTTP-derived default.\n */\nexport function resolveRpcCode(\n code: string,\n status: number,\n overrides?: Readonly<Record<string, GoogleRpcCode>>,\n): GoogleRpcCode {\n const explicit = overrides?.[code];\n if (explicit !== undefined) {\n return explicit;\n }\n if (isGoogleRpcCode(code)) {\n return code;\n }\n return rpcCodeFromStatus(status);\n}\n","/**\n * JSON Schema for the AIP-193 body (SPEC 7.6.3). Every detail payload is a\n * closed object pinned to its `@type`; `details` is an array of the payloads\n * this format can render for the entry, at least one long because\n * `ErrorInfo` is always present. `contains` and `prefixItems` would state that\n * more precisely, but OpenAPI 3.0 has neither, so both dialects use `items`.\n * @ref https://google.aip.dev/193#http11json-representation\n * @ref https://spec.openapis.org/oas/v3.0.3#schema-object\n * @packageDocumentation\n */\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { JsonSchema, SchemaContext, SchemaDialect } from '../context';\nimport type { GoogleRpcCode } from './rpc-code';\n\nimport { constant } from '../schema-helpers';\nimport {\n BAD_REQUEST_TYPE,\n DEBUG_INFO_TYPE,\n ERROR_INFO_TYPE,\n HELP_TYPE,\n METADATA_KEY_PATTERN,\n REQUEST_INFO_TYPE,\n RETRY_INFO_TYPE,\n} from './details';\nimport { resolveRpcCode } from './rpc-code';\n\nexport interface GoogleApiSchemaOptions {\n readonly domain: string;\n readonly rpcCodes: Readonly<Record<string, GoogleRpcCode>> | undefined;\n readonly includeRequestInfo: boolean;\n}\n\nconst STRING: JsonSchema = { type: 'string' };\n\nfunction detail(\n typeUrl: string,\n dialect: SchemaDialect,\n properties: Record<string, JsonSchema>,\n required: ReadonlyArray<string>,\n): JsonSchema {\n return {\n type: 'object',\n required: ['@type', ...required],\n properties: { '@type': constant(typeUrl, dialect), ...properties },\n additionalProperties: false,\n };\n}\n\n/**\n * `metadata` keys follow the `error_details.proto` grammar the renderer\n * enforces. `propertyNames` states it in JSON Schema 2020-12; the OpenAPI\n * 3.0 schema object has neither it nor `patternProperties`, so that dialect\n * types the values only.\n * @ref https://json-schema.org/draft/2020-12/json-schema-core#name-propertynames\n * @ref https://spec.openapis.org/oas/v3.0.3#properties\n */\nfunction metadata(dialect: SchemaDialect): JsonSchema {\n return {\n type: 'object',\n ...(dialect === 'openapi-3.0'\n ? {}\n : { propertyNames: { pattern: METADATA_KEY_PATTERN.source } }),\n additionalProperties: STRING,\n };\n}\n\nfunction errorInfo(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: GoogleApiSchemaOptions,\n): JsonSchema {\n return detail(\n ERROR_INFO_TYPE,\n ctx.dialect,\n {\n reason: constant(definition.code, ctx.dialect),\n domain: constant(options.domain, ctx.dialect),\n metadata: metadata(ctx.dialect),\n },\n ['reason', 'domain'],\n );\n}\n\nfunction badRequest(dialect: SchemaDialect): JsonSchema {\n return detail(\n BAD_REQUEST_TYPE,\n dialect,\n {\n fieldViolations: {\n type: 'array',\n items: {\n type: 'object',\n required: ['description'],\n properties: { field: STRING, description: STRING, reason: STRING },\n additionalProperties: false,\n },\n },\n },\n ['fieldViolations'],\n );\n}\n\nfunction retryInfo(dialect: SchemaDialect): JsonSchema {\n return detail(\n RETRY_INFO_TYPE,\n dialect,\n { retryDelay: { type: 'string', pattern: '^[0-9]+s$' } },\n ['retryDelay'],\n );\n}\n\nfunction requestInfo(dialect: SchemaDialect): JsonSchema {\n return detail(REQUEST_INFO_TYPE, dialect, { requestId: STRING }, [\n 'requestId',\n ]);\n}\n\nfunction debugInfo(dialect: SchemaDialect): JsonSchema {\n return detail(\n DEBUG_INFO_TYPE,\n dialect,\n { stackEntries: { type: 'array', items: STRING } },\n ['stackEntries'],\n );\n}\n\nfunction helpDetail(dialect: SchemaDialect): JsonSchema {\n return detail(\n HELP_TYPE,\n dialect,\n {\n links: {\n type: 'array',\n minItems: 1,\n items: {\n type: 'object',\n required: ['description', 'url'],\n properties: {\n description: STRING,\n url: { type: 'string', format: 'uri' },\n },\n additionalProperties: false,\n },\n },\n },\n ['links'],\n );\n}\n\nexport function bodySchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: GoogleApiSchemaOptions,\n validation: boolean,\n): JsonSchema {\n const payloads: Array<JsonSchema> = [errorInfo(definition, ctx, options)];\n if (validation) {\n payloads.push(badRequest(ctx.dialect));\n }\n payloads.push(retryInfo(ctx.dialect));\n if (options.includeRequestInfo) {\n payloads.push(requestInfo(ctx.dialect));\n }\n payloads.push(debugInfo(ctx.dialect), helpDetail(ctx.dialect));\n return {\n type: 'object',\n required: ['error'],\n properties: {\n error: {\n type: 'object',\n required: ['code', 'message', 'status', 'details'],\n properties: {\n code: constant(definition.status, ctx.dialect),\n message: STRING,\n status: constant(\n resolveRpcCode(\n definition.code,\n definition.status,\n options.rpcCodes,\n ),\n ctx.dialect,\n ),\n details: { type: 'array', minItems: 1, items: { anyOf: payloads } },\n },\n additionalProperties: false,\n },\n },\n additionalProperties: false,\n };\n}\n","/**\n * Google API error format (SPEC 7.6): the AIP-193 HTTP/1.1+JSON\n * representation of `google.rpc.Status`, `{ error: { code, message, status,\n * details } }`, with `code` the HTTP status, `status` the `google.rpc.Code`\n * name, and `details` the standard payloads from `error_details.proto`\n * packed as `google.protobuf.Any`. `ErrorInfo` is always present, as AIP-193\n * requires.\n * @ref https://google.aip.dev/193#http11json-representation\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\nimport type { GoogleApiDetail, GoogleApiErrorInfo } from './details';\nimport type { GoogleRpcCode } from './rpc-code';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { assertMemberName } from '../../internal/member-name';\nimport {\n BAD_REQUEST_TYPE,\n DEBUG_INFO_TYPE,\n ERROR_INFO_TYPE,\n fieldViolation,\n help,\n METADATA_KEY_PATTERN,\n REQUEST_INFO_TYPE,\n retryInfo,\n toMetadata,\n} from './details';\nimport { resolveRpcCode } from './rpc-code';\nimport { bodySchema } from './schema';\n\nexport type {\n GoogleApiBadRequest,\n GoogleApiDebugInfo,\n GoogleApiDetail,\n GoogleApiErrorInfo,\n GoogleApiFieldViolation,\n GoogleApiHelp,\n GoogleApiHelpLink,\n GoogleApiRequestInfo,\n GoogleApiRetryInfo,\n} from './details';\nexport type { GoogleRpcCode } from './rpc-code';\n\nexport interface GoogleApiOptions {\n /**\n * `ErrorInfo.domain`: \"the logical grouping to which the reason belongs\",\n * globally unique, typically the service name (`pubsub.googleapis.com`).\n * Required because AIP-193 requires `ErrorInfo` and a domain has no\n * derivable default.\n * @ref https://google.aip.dev/193#errorinfo\n */\n readonly domain: string;\n /**\n * `status` per catalog code, for entries whose HTTP status maps to the\n * wrong `google.rpc.Code` by default (a 409 that is `ALREADY_EXISTS`, not\n * `ABORTED`). A catalog code that is itself a `google.rpc.Code` name needs\n * no entry here.\n */\n readonly rpcCodes?: Readonly<Record<string, GoogleRpcCode>> | undefined;\n /** Base for the `Help` link; overrides the instance `docsBaseUrl`. */\n readonly helpLinkBaseUrl?: string | undefined;\n /** Key for the trace id inside `ErrorInfo.metadata`. Default `traceId`; `false` disables. */\n readonly traceIdMetadataKey?: string | false | undefined;\n /** Emit `RequestInfo.requestId` with the error id. Default true. */\n readonly includeRequestInfo?: boolean | undefined;\n}\n\n/** The `error` member: AIP-193's `Error.Status`, not `google.rpc.Status`. */\nexport interface GoogleApiStatus {\n /** The HTTP status code. */\n readonly code: number;\n readonly message: string;\n /** The `google.rpc.Code` name. */\n readonly status: GoogleRpcCode;\n readonly details: ReadonlyArray<GoogleApiDetail>;\n}\n\nexport interface GoogleApiBody {\n readonly error: GoogleApiStatus;\n}\n\n/**\n * Google APIs answer errors as plain JSON; there is no dedicated media type.\n * @ref https://google.aip.dev/193#http11json-representation\n */\nexport const GOOGLE_API_CONTENT_TYPE = 'application/json';\n\n/**\n * `metadata` keys written from `ctx.meta` that a `traceIdMetadataKey` of the\n * same name would silently replace: `location` carries the validation target\n * (SPEC 8.2).\n */\nconst RESERVED_METADATA_KEYS: ReadonlySet<string> = new Set(['location']);\n\ninterface Resolved {\n readonly domain: string;\n readonly rpcCodes: Readonly<Record<string, GoogleRpcCode>> | undefined;\n readonly helpLinkBaseUrl: string | undefined;\n readonly traceIdMetadataKey: string | false;\n readonly includeRequestInfo: boolean;\n}\n\nfunction errorInfo(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n): GoogleApiErrorInfo {\n const metadata = toMetadata(ctx.meta);\n if (options.traceIdMetadataKey !== false && ctx.traceId !== undefined) {\n metadata[options.traceIdMetadataKey] = ctx.traceId;\n }\n return {\n '@type': ERROR_INFO_TYPE,\n reason: error.code,\n domain: options.domain,\n ...(Object.keys(metadata).length === 0 ? {} : { metadata }),\n };\n}\n\nfunction helpUrl(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n): string | undefined {\n if (error.type !== undefined) {\n return error.type;\n }\n const base = options.helpLinkBaseUrl ?? ctx.docsBaseUrl;\n return base === undefined ? undefined : `${base}/${error.code}`;\n}\n\n/**\n * Detail order (SPEC 7.6.2): `ErrorInfo`, `BadRequest` (validation only),\n * `RetryInfo`, `RequestInfo`, `DebugInfo`, `Help`. Each type appears at most\n * once, as AIP-193 requires.\n */\nfunction renderBody(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n issues?: ReadonlyArray<ValidationIssue>,\n): GoogleApiBody {\n const details: Array<GoogleApiDetail> = [errorInfo(error, ctx, options)];\n // proto3 JSON omits an empty repeated field and the schema requires\n // `fieldViolations`, so a validation error without issues has no\n // `BadRequest`; `message` still says validation failed.\n if (issues !== undefined && issues.length > 0) {\n details.push({\n '@type': BAD_REQUEST_TYPE,\n fieldViolations: issues.map((issue) => fieldViolation(issue)),\n });\n }\n const retry = retryInfo(error.headers);\n if (retry !== undefined) {\n details.push(retry);\n }\n if (options.includeRequestInfo) {\n details.push({ '@type': REQUEST_INFO_TYPE, requestId: error.id });\n }\n if (ctx.stack !== undefined) {\n details.push({\n '@type': DEBUG_INFO_TYPE,\n stackEntries: ctx.stack.split('\\n'),\n });\n }\n const link = help(error.code, helpUrl(error, ctx, options));\n if (link !== undefined) {\n details.push(link);\n }\n return {\n error: {\n code: error.status,\n message:\n error.detail ??\n (issues === undefined ? error.title : VALIDATION_DETAIL),\n status: resolveRpcCode(error.code, error.status, options.rpcCodes),\n details,\n },\n };\n}\n\n/**\n * AIP-193 Google API errors (SPEC 7.6). Throws `TypeError` when\n * `traceIdMetadataKey` falls outside the `ErrorInfo.metadata` key grammar\n * or names a key the format writes from `ctx.meta`.\n * @ref https://google.aip.dev/193\n */\nexport function googleApi(\n options: GoogleApiOptions,\n): ErrorFormat<GoogleApiBody> {\n const resolved: Resolved = {\n domain: options.domain,\n rpcCodes: options.rpcCodes,\n helpLinkBaseUrl: options.helpLinkBaseUrl,\n traceIdMetadataKey: options.traceIdMetadataKey ?? 'traceId',\n includeRequestInfo: options.includeRequestInfo ?? true,\n };\n if (resolved.traceIdMetadataKey !== false) {\n assertMemberName(\n 'traceIdMetadataKey',\n resolved.traceIdMetadataKey,\n RESERVED_METADATA_KEYS,\n METADATA_KEY_PATTERN,\n );\n }\n const schemaOptions = {\n domain: resolved.domain,\n rpcCodes: resolved.rpcCodes,\n includeRequestInfo: resolved.includeRequestInfo,\n };\n return {\n name: 'google-api',\n contentType: GOOGLE_API_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): GoogleApiBody {\n return renderBody(error, ctx, resolved);\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): GoogleApiBody {\n return renderBody(error, ctx, resolved, issues);\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return bodySchema(definition, ctx, schemaOptions, false);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return bodySchema(definition, ctx, schemaOptions, true);\n },\n };\n}\n"],"mappings":";;;;;AAeA,MAAa,kBACX;AACF,MAAa,mBACX;AACF,MAAa,kBACX;AACF,MAAa,oBACX;AACF,MAAa,kBACX;AACF,MAAa,YAAY;;;;;;;AAwEzB,MAAa,uBAA+B;;;;;;;;;;AAW5C,SAAgB,WACd,MACwB;CACxB,MAAM,WAAmC,CAAC;CAC1C,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG;EACnC,IAAI,CAAC,qBAAqB,KAAK,GAAG,GAChC;EAEF,MAAM,QAAQ,KAAK;EACnB,IAAI,OAAO,UAAU,UACnB,SAAS,OAAO;OACX,IAAI,OAAO,UAAU,UAC1B,SAAS,OAAO,MAAM,SAAS;OAC1B,IACL,UAAU,KAAA,KACV,OAAO,UAAU,cACjB,OAAO,UAAU,UAEjB,SAAS,OAAO,cAAc,KAAK;CAEvC;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,UAAU,MAA8C;CACtE,IAAI,MAAM;CACV,KAAK,MAAM,WAAW,MACpB,IAAI,OAAO,YAAY,UACrB,OAAO,IAAI,OAAO,OAAO,EAAE;MAE3B,OAAO,QAAQ,KAAK,UAAU,IAAI;CAGtC,OAAO;AACT;;;;;;AAOA,SAAgB,eACd,OACyB;CACzB,MAAM,QAAQ,UAAU,MAAM,IAAI;CAClC,OAAO;EACL,GAAI,UAAU,KAAK,CAAC,IAAI,EAAE,MAAM;EAChC,aAAa,MAAM;EACnB,GAAI,MAAM,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,KAAK,YAAY,EAAE;CACzE;AACF;AAEA,MAAM,wBAAwB;;;;;;;;AAS9B,SAAgBA,YAAU,SAAkD;CAC1E,MAAM,QAAQ,QAAQ,IAAI,aAAa;CACvC,IAAI,UAAU,QAAQ,CAAC,sBAAsB,KAAK,KAAK,GACrD;CAEF,OAAO;EAAE,SAAS;EAAiB,YAAY,GAAG,MAAM;CAAG;AAC7D;;AAGA,MAAM,uBAAuB;;;;;;;AAQ7B,SAAgB,KAAK,MAAc,KAAyC;CAC1E,IAAI,QAAQ,KAAA,KAAa,CAAC,qBAAqB,KAAK,GAAG,GACrD;CAEF,OAAO;EACL,SAAS;EACT,OAAO,CAAC;GAAE,aAAa,qBAAqB,KAAK;GAAU;EAAI,CAAC;CAClE;AACF;;;AC1KA,MAAM,4BAAiC,IAAI,IAAmB;CAC5D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;;;;AASD,MAAM,iCAAqD,IAAI,IAG7D;CACA,CAAC,KAAK,kBAAkB;CACxB,CAAC,KAAK,iBAAiB;CACvB,CAAC,KAAK,mBAAmB;CACzB,CAAC,KAAK,WAAW;CACjB,CAAC,KAAK,SAAS;CACf,CAAC,KAAK,cAAc;CACpB,CAAC,KAAK,oBAAoB;CAC1B,CAAC,KAAK,WAAW;CACjB,CAAC,KAAK,eAAe;CACrB,CAAC,KAAK,aAAa;CACnB,CAAC,KAAK,mBAAmB;AAC3B,CAAC;AAED,MAAM,UAAU;AAChB,MAAM,WAAW;AACjB,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,MAAM;AAEZ,SAAgB,gBAAgB,OAAuC;CACrE,OAAO,UAAU,IAAI,KAAK;AAC5B;;;;;;;;AASA,SAAgB,kBAAkB,QAA+B;CAC/D,MAAM,SAAS,eAAe,IAAI,MAAM;CACxC,IAAI,WAAW,KAAA,GACb,OAAO;CAET,IAAI,UAAU,WAAW,SAAS,UAChC,OAAO;CAET,IAAI,UAAU,gBAAgB,SAAS,cACrC,OAAO;CAET,IAAI,UAAU,gBAAgB,SAAS,KACrC,OAAO;CAET,OAAO;AACT;;;;;;AAOA,SAAgB,eACd,MACA,QACA,WACe;CACf,MAAM,WAAW,YAAY;CAC7B,IAAI,aAAa,KAAA,GACf,OAAO;CAET,IAAI,gBAAgB,IAAI,GACtB,OAAO;CAET,OAAO,kBAAkB,MAAM;AACjC;;;AC/FA,MAAM,SAAqB,EAAE,MAAM,SAAS;AAE5C,SAAS,OACP,SACA,SACA,YACA,UACY;CACZ,OAAO;EACL,MAAM;EACN,UAAU,CAAC,SAAS,GAAG,QAAQ;EAC/B,YAAY;GAAE,SAAS,SAAS,SAAS,OAAO;GAAG,GAAG;EAAW;EACjE,sBAAsB;CACxB;AACF;;;;;;;;;AAUA,SAAS,SAAS,SAAoC;CACpD,OAAO;EACL,MAAM;EACN,GAAI,YAAY,gBACZ,CAAC,IACD,EAAE,eAAe,EAAE,SAAS,qBAAqB,OAAO,EAAE;EAC9D,sBAAsB;CACxB;AACF;AAEA,SAASC,YACP,YACA,KACA,SACY;CACZ,OAAO,OACL,iBACA,IAAI,SACJ;EACE,QAAQ,SAAS,WAAW,MAAM,IAAI,OAAO;EAC7C,QAAQ,SAAS,QAAQ,QAAQ,IAAI,OAAO;EAC5C,UAAU,SAAS,IAAI,OAAO;CAChC,GACA,CAAC,UAAU,QAAQ,CACrB;AACF;AAEA,SAAS,WAAW,SAAoC;CACtD,OAAO,OACL,kBACA,SACA,EACE,iBAAiB;EACf,MAAM;EACN,OAAO;GACL,MAAM;GACN,UAAU,CAAC,aAAa;GACxB,YAAY;IAAE,OAAO;IAAQ,aAAa;IAAQ,QAAQ;GAAO;GACjE,sBAAsB;EACxB;CACF,EACF,GACA,CAAC,iBAAiB,CACpB;AACF;AAEA,SAAS,UAAU,SAAoC;CACrD,OAAO,OACL,iBACA,SACA,EAAE,YAAY;EAAE,MAAM;EAAU,SAAS;CAAY,EAAE,GACvD,CAAC,YAAY,CACf;AACF;AAEA,SAAS,YAAY,SAAoC;CACvD,OAAO,OAAO,mBAAmB,SAAS,EAAE,WAAW,OAAO,GAAG,CAC/D,WACF,CAAC;AACH;AAEA,SAAS,UAAU,SAAoC;CACrD,OAAO,OACL,iBACA,SACA,EAAE,cAAc;EAAE,MAAM;EAAS,OAAO;CAAO,EAAE,GACjD,CAAC,cAAc,CACjB;AACF;AAEA,SAAS,WAAW,SAAoC;CACtD,OAAO,OACL,WACA,SACA,EACE,OAAO;EACL,MAAM;EACN,UAAU;EACV,OAAO;GACL,MAAM;GACN,UAAU,CAAC,eAAe,KAAK;GAC/B,YAAY;IACV,aAAa;IACb,KAAK;KAAE,MAAM;KAAU,QAAQ;IAAM;GACvC;GACA,sBAAsB;EACxB;CACF,EACF,GACA,CAAC,OAAO,CACV;AACF;AAEA,SAAgB,WACd,YACA,KACA,SACA,YACY;CACZ,MAAM,WAA8B,CAACA,YAAU,YAAY,KAAK,OAAO,CAAC;CACxE,IAAI,YACF,SAAS,KAAK,WAAW,IAAI,OAAO,CAAC;CAEvC,SAAS,KAAK,UAAU,IAAI,OAAO,CAAC;CACpC,IAAI,QAAQ,oBACV,SAAS,KAAK,YAAY,IAAI,OAAO,CAAC;CAExC,SAAS,KAAK,UAAU,IAAI,OAAO,GAAG,WAAW,IAAI,OAAO,CAAC;CAC7D,OAAO;EACL,MAAM;EACN,UAAU,CAAC,OAAO;EAClB,YAAY,EACV,OAAO;GACL,MAAM;GACN,UAAU;IAAC;IAAQ;IAAW;IAAU;GAAS;GACjD,YAAY;IACV,MAAM,SAAS,WAAW,QAAQ,IAAI,OAAO;IAC7C,SAAS;IACT,QAAQ,SACN,eACE,WAAW,MACX,WAAW,QACX,QAAQ,QACV,GACA,IAAI,OACN;IACA,SAAS;KAAE,MAAM;KAAS,UAAU;KAAG,OAAO,EAAE,OAAO,SAAS;IAAE;GACpE;GACA,sBAAsB;EACxB,EACF;EACA,sBAAsB;CACxB;AACF;;;;;;;AClGA,MAAa,0BAA0B;;;;;;AAOvC,MAAM,yCAA8C,IAAI,IAAI,CAAC,UAAU,CAAC;AAUxE,SAAS,UACP,OACA,KACA,SACoB;CACpB,MAAM,WAAW,WAAW,IAAI,IAAI;CACpC,IAAI,QAAQ,uBAAuB,SAAS,IAAI,YAAY,KAAA,GAC1D,SAAS,QAAQ,sBAAsB,IAAI;CAE7C,OAAO;EACL,SAAS;EACT,QAAQ,MAAM;EACd,QAAQ,QAAQ;EAChB,GAAI,OAAO,KAAK,QAAQ,CAAC,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,SAAS;CAC3D;AACF;AAEA,SAAS,QACP,OACA,KACA,SACoB;CACpB,IAAI,MAAM,SAAS,KAAA,GACjB,OAAO,MAAM;CAEf,MAAM,OAAO,QAAQ,mBAAmB,IAAI;CAC5C,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,GAAG,KAAK,GAAG,MAAM;AAC3D;;;;;;AAOA,SAAS,WACP,OACA,KACA,SACA,QACe;CACf,MAAM,UAAkC,CAAC,UAAU,OAAO,KAAK,OAAO,CAAC;CAIvE,IAAI,WAAW,KAAA,KAAa,OAAO,SAAS,GAC1C,QAAQ,KAAK;EACX,SAAS;EACT,iBAAiB,OAAO,KAAK,UAAU,eAAe,KAAK,CAAC;CAC9D,CAAC;CAEH,MAAM,QAAQC,YAAU,MAAM,OAAO;CACrC,IAAI,UAAU,KAAA,GACZ,QAAQ,KAAK,KAAK;CAEpB,IAAI,QAAQ,oBACV,QAAQ,KAAK;EAAE,SAAS;EAAmB,WAAW,MAAM;CAAG,CAAC;CAElE,IAAI,IAAI,UAAU,KAAA,GAChB,QAAQ,KAAK;EACX,SAAS;EACT,cAAc,IAAI,MAAM,MAAM,IAAI;CACpC,CAAC;CAEH,MAAM,OAAO,KAAK,MAAM,MAAM,QAAQ,OAAO,KAAK,OAAO,CAAC;CAC1D,IAAI,SAAS,KAAA,GACX,QAAQ,KAAK,IAAI;CAEnB,OAAO,EACL,OAAO;EACL,MAAM,MAAM;EACZ,SACE,MAAM,WACL,WAAW,KAAA,IAAY,MAAM,QAAA;EAChC,QAAQ,eAAe,MAAM,MAAM,MAAM,QAAQ,QAAQ,QAAQ;EACjE;CACF,EACF;AACF;;;;;;;AAQA,SAAgB,UACd,SAC4B;CAC5B,MAAM,WAAqB;EACzB,QAAQ,QAAQ;EAChB,UAAU,QAAQ;EAClB,iBAAiB,QAAQ;EACzB,oBAAoB,QAAQ,sBAAsB;EAClD,oBAAoB,QAAQ,sBAAsB;CACpD;CACA,IAAI,SAAS,uBAAuB,OAClC,iBACE,sBACA,SAAS,oBACT,wBACA,oBACF;CAEF,MAAM,gBAAgB;EACpB,QAAQ,SAAS;EACjB,UAAU,SAAS;EACnB,oBAAoB,SAAS;CAC/B;CACA,OAAO;EACL,MAAM;EACN,aAAa;EACb,OAAO,OAAiB,KAAmC;GACzD,OAAO,WAAW,OAAO,KAAK,QAAQ;EACxC;EACA,iBACE,OACA,QACA,KACe;GACf,OAAO,WAAW,OAAO,KAAK,UAAU,MAAM;EAChD;EACA,OAAO,YAAgC,KAAgC;GACrE,OAAO,WAAW,YAAY,KAAK,eAAe,KAAK;EACzD;EACA,iBACE,YACA,KACY;GACZ,OAAO,WAAW,YAAY,KAAK,eAAe,IAAI;EACxD;CACF;AACF"}
1
+ {"version":3,"file":"google-api.js","names":["retryInfo","errorInfo","retryInfo"],"sources":["../../src/formats/google-api/details.ts","../../src/formats/google-api/rpc-code.ts","../../src/formats/google-api/schema.ts","../../src/formats/google-api/index.ts"],"sourcesContent":["/**\n * The standard `google.rpc` detail payloads this format renders (SPEC 7.6.2)\n * in their proto3 JSON form: each message packed as a `google.protobuf.Any`\n * carries an `@type` member holding its type URL, field names are\n * lowerCamelCase, and fields at their default value (empty string, empty\n * repeated, empty map) are omitted.\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n * @ref https://protobuf.dev/programming-guides/json/\n * @packageDocumentation\n */\nimport type { ValidationIssue } from '../../validation/issue';\n\nimport { safeStringify } from '../../internal/json';\n\n/** `google.protobuf.Any` type URLs: the `type.googleapis.com/` prefix plus the full message name. */\nexport const ERROR_INFO_TYPE =\n 'type.googleapis.com/google.rpc.ErrorInfo' as const;\nexport const BAD_REQUEST_TYPE =\n 'type.googleapis.com/google.rpc.BadRequest' as const;\nexport const RETRY_INFO_TYPE =\n 'type.googleapis.com/google.rpc.RetryInfo' as const;\nexport const REQUEST_INFO_TYPE =\n 'type.googleapis.com/google.rpc.RequestInfo' as const;\nexport const DEBUG_INFO_TYPE =\n 'type.googleapis.com/google.rpc.DebugInfo' as const;\nexport const HELP_TYPE = 'type.googleapis.com/google.rpc.Help' as const;\n\n/**\n * `google.rpc.ErrorInfo`: the machine-readable identifier AIP-193 requires\n * in every error. `reason` is the catalog code, `domain` the format option.\n * @ref https://google.aip.dev/193#errorinfo\n */\nexport interface GoogleApiErrorInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.ErrorInfo';\n readonly reason: string;\n readonly domain: string;\n readonly metadata?: Readonly<Record<string, string>>;\n}\n\n/** `google.rpc.BadRequest.FieldViolation`, one per validation issue. */\nexport interface GoogleApiFieldViolation {\n /** Dot path with `[index]` for array positions, for example `items[0].sku`. */\n readonly field?: string;\n readonly description: string;\n /** The issue code in UPPER_SNAKE_CASE, when the validator gave one. */\n readonly reason?: string;\n}\n\nexport interface GoogleApiBadRequest {\n readonly '@type': 'type.googleapis.com/google.rpc.BadRequest';\n readonly fieldViolations: ReadonlyArray<GoogleApiFieldViolation>;\n}\n\n/** `google.rpc.RetryInfo`, from a delay-seconds `Retry-After` header. */\nexport interface GoogleApiRetryInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.RetryInfo';\n /** A `google.protobuf.Duration` in JSON form, for example `30s`. */\n readonly retryDelay: string;\n}\n\n/** `google.rpc.RequestInfo` carrying the error id (SPEC 10.2). */\nexport interface GoogleApiRequestInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.RequestInfo';\n readonly requestId: string;\n}\n\n/** `google.rpc.DebugInfo`, present only when the handler includes the stack. */\nexport interface GoogleApiDebugInfo {\n readonly '@type': 'type.googleapis.com/google.rpc.DebugInfo';\n readonly stackEntries: ReadonlyArray<string>;\n}\n\nexport interface GoogleApiHelpLink {\n readonly description: string;\n readonly url: string;\n}\n\n/** `google.rpc.Help` with one link to the error's documentation. */\nexport interface GoogleApiHelp {\n readonly '@type': 'type.googleapis.com/google.rpc.Help';\n readonly links: ReadonlyArray<GoogleApiHelpLink>;\n}\n\nexport type GoogleApiDetail =\n | GoogleApiErrorInfo\n | GoogleApiBadRequest\n | GoogleApiRetryInfo\n | GoogleApiRequestInfo\n | GoogleApiDebugInfo\n | GoogleApiHelp;\n\n/**\n * `ErrorInfo.metadata` keys \"must match a regular expression of\n * `[a-z][a-zA-Z0-9-_]+`\" and \"must be limited to 64 characters in length\"\n * (the comment on the field in `error_details.proto`).\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n */\nexport const METADATA_KEY_PATTERN: RegExp = /^[a-z][a-zA-Z0-9_-]{1,63}$/u;\n\n/**\n * `ErrorInfo.metadata` is `map<string, string>`, so every value becomes a\n * string: strings as they are, everything else as JSON. Values JSON cannot\n * represent (`undefined`, functions, symbols) are dropped, and so is every\n * key outside `METADATA_KEY_PATTERN` (`order.id`, `UserId`): a key the\n * grammar rejects would make the body fail the schema, and throwing here\n * would turn the error being rendered into a 500 (SPEC 7.6.2).\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n */\nexport function toMetadata(\n meta: Readonly<Record<string, unknown>>,\n): Record<string, string> {\n const metadata: Record<string, string> = {};\n for (const key of Object.keys(meta)) {\n if (!METADATA_KEY_PATTERN.test(key)) {\n continue;\n }\n const value = meta[key];\n if (typeof value === 'string') {\n metadata[key] = value;\n } else if (typeof value === 'bigint') {\n metadata[key] = value.toString();\n } else if (\n value !== undefined &&\n typeof value !== 'function' &&\n typeof value !== 'symbol'\n ) {\n metadata[key] = safeStringify(value);\n }\n }\n return metadata;\n}\n\n/**\n * `BadRequest.FieldViolation.field`: \"a sequence of dot-separated identifiers\"\n * with repeated-field positions in square brackets, so `['items', 0, 'sku']`\n * is `items[0].sku`. An empty path names the whole request and yields no\n * `field` (proto3 JSON omits empty strings).\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n */\nexport function fieldPath(path: ReadonlyArray<string | number>): string {\n let out = '';\n for (const segment of path) {\n if (typeof segment === 'number') {\n out += `[${String(segment)}]`;\n } else {\n out += out === '' ? segment : `.${segment}`;\n }\n }\n return out;\n}\n\n/**\n * `FieldViolation.reason` \"should be at most 63 characters and match\n * `[A-Z][A-Z0-9_]+[A-Z0-9]`\"; validator codes are lower snake case\n * (`invalid_type`), so they are upper-cased. Not validated further.\n */\nexport function fieldViolation(\n issue: ValidationIssue,\n): GoogleApiFieldViolation {\n const field = fieldPath(issue.path);\n return {\n ...(field === '' ? {} : { field }),\n description: issue.message,\n ...(issue.code === undefined ? {} : { reason: issue.code.toUpperCase() }),\n };\n}\n\nconst DELAY_SECONDS_PATTERN = /^[0-9]+$/u;\n\n/**\n * `RetryInfo.retry_delay` from a `Retry-After` header in its delay-seconds\n * form. The HTTP-date form needs the current time to become a duration, and\n * formats are pure, so it is left out.\n * @ref https://www.rfc-editor.org/rfc/rfc9110#section-10.2.3\n * @ref https://protobuf.dev/programming-guides/json/ (Duration)\n */\nexport function retryInfo(headers: Headers): GoogleApiRetryInfo | undefined {\n const value = headers.get('retry-after');\n if (value === null || !DELAY_SECONDS_PATTERN.test(value)) {\n return undefined;\n }\n return { '@type': RETRY_INFO_TYPE, retryDelay: `${value}s` };\n}\n\n/** RFC 3986 section 3.1 scheme followed by a colon: an absolute URI. */\nconst ABSOLUTE_URI_PATTERN = /^[A-Za-z][A-Za-z0-9+.-]*:/u;\n\n/**\n * `Help.Link.url` \"must be an absolute URL, including scheme\", so a relative\n * `type` yields no `Help` payload.\n * @ref https://google.aip.dev/193#help\n * @ref https://www.rfc-editor.org/rfc/rfc3986#section-3.1\n */\nexport function help(code: string, url?: string): GoogleApiHelp | undefined {\n if (url === undefined || !ABSOLUTE_URI_PATTERN.test(url)) {\n return undefined;\n }\n return {\n '@type': HELP_TYPE,\n links: [{ description: `Documentation for ${code} errors`, url }],\n };\n}\n","/**\n * `google.rpc.Code` names and the HTTP status each one is derived from\n * (SPEC 7.6.1). The forward mapping (code to HTTP status) is the \"HTTP\n * Mapping\" line on every enum value in `code.proto`; it is many-to-one, so the\n * reverse table below is the one Google's own client library uses when it\n * turns an HTTP error into a status code.\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto\n * @ref https://github.com/googleapis/gax-nodejs/blob/main/gax/src/status.ts\n * @packageDocumentation\n */\n\n/** Every value of the `google.rpc.Code` enum, by name. */\nexport type GoogleRpcCode =\n | 'OK'\n | 'CANCELLED'\n | 'UNKNOWN'\n | 'INVALID_ARGUMENT'\n | 'DEADLINE_EXCEEDED'\n | 'NOT_FOUND'\n | 'ALREADY_EXISTS'\n | 'PERMISSION_DENIED'\n | 'RESOURCE_EXHAUSTED'\n | 'FAILED_PRECONDITION'\n | 'ABORTED'\n | 'OUT_OF_RANGE'\n | 'UNIMPLEMENTED'\n | 'INTERNAL'\n | 'UNAVAILABLE'\n | 'DATA_LOSS'\n | 'UNAUTHENTICATED';\n\nconst RPC_CODES: ReadonlySet<string> = new Set<GoogleRpcCode>([\n 'OK',\n 'CANCELLED',\n 'UNKNOWN',\n 'INVALID_ARGUMENT',\n 'DEADLINE_EXCEEDED',\n 'NOT_FOUND',\n 'ALREADY_EXISTS',\n 'PERMISSION_DENIED',\n 'RESOURCE_EXHAUSTED',\n 'FAILED_PRECONDITION',\n 'ABORTED',\n 'OUT_OF_RANGE',\n 'UNIMPLEMENTED',\n 'INTERNAL',\n 'UNAVAILABLE',\n 'DATA_LOSS',\n 'UNAUTHENTICATED',\n]);\n\n/**\n * `HttpCodeToRpcCodeMap` from gax-nodejs, verbatim. Where several codes share\n * an HTTP status the table keeps the one gax picked: `INVALID_ARGUMENT` for\n * 400 (not `FAILED_PRECONDITION` or `OUT_OF_RANGE`), `ABORTED` for 409 (not\n * `ALREADY_EXISTS`), `INTERNAL` for 500 (not `UNKNOWN` or `DATA_LOSS`).\n * @ref https://github.com/googleapis/gax-nodejs/blob/main/gax/src/status.ts\n */\nconst BY_HTTP_STATUS: ReadonlyMap<number, GoogleRpcCode> = new Map<\n number,\n GoogleRpcCode\n>([\n [400, 'INVALID_ARGUMENT'],\n [401, 'UNAUTHENTICATED'],\n [403, 'PERMISSION_DENIED'],\n [404, 'NOT_FOUND'],\n [409, 'ABORTED'],\n [416, 'OUT_OF_RANGE'],\n [429, 'RESOURCE_EXHAUSTED'],\n [499, 'CANCELLED'],\n [501, 'UNIMPLEMENTED'],\n [503, 'UNAVAILABLE'],\n [504, 'DEADLINE_EXCEEDED'],\n]);\n\nconst SUCCESS = 200;\nconst REDIRECT = 300;\nconst CLIENT_ERROR = 400;\nconst SERVER_ERROR = 500;\nconst END = 600;\n\nexport function isGoogleRpcCode(value: string): value is GoogleRpcCode {\n return RPC_CODES.has(value);\n}\n\n/**\n * The `google.rpc.Code` name for an HTTP status, following\n * `rpcCodeFromHttpStatusCode` in gax-nodejs: the table first, then `OK` for\n * any 2xx, `FAILED_PRECONDITION` for any other 4xx, `INTERNAL` for any other\n * 5xx, and `UNKNOWN` for everything else.\n * @ref https://github.com/googleapis/gax-nodejs/blob/main/gax/src/status.ts\n */\nexport function rpcCodeFromStatus(status: number): GoogleRpcCode {\n const mapped = BY_HTTP_STATUS.get(status);\n if (mapped !== undefined) {\n return mapped;\n }\n if (status >= SUCCESS && status < REDIRECT) {\n return 'OK';\n }\n if (status >= CLIENT_ERROR && status < SERVER_ERROR) {\n return 'FAILED_PRECONDITION';\n }\n if (status >= SERVER_ERROR && status < END) {\n return 'INTERNAL';\n }\n return 'UNKNOWN';\n}\n\n/**\n * The `status` member for an entry (SPEC 7.6.1): an explicit per-code option,\n * else the catalog code itself when it already names a `google.rpc.Code`\n * (`NOT_FOUND`, `ALREADY_EXISTS`), else the HTTP-derived default.\n */\nexport function resolveRpcCode(\n code: string,\n status: number,\n overrides?: Readonly<Record<string, GoogleRpcCode>>,\n): GoogleRpcCode {\n const explicit = overrides?.[code];\n if (explicit !== undefined) {\n return explicit;\n }\n if (isGoogleRpcCode(code)) {\n return code;\n }\n return rpcCodeFromStatus(status);\n}\n","/**\n * JSON Schema for the AIP-193 body (SPEC 7.6.3). Every detail payload is a\n * closed object pinned to its `@type`; `details` is an array of the payloads\n * this format can render for the entry, at least one long because\n * `ErrorInfo` is always present. `contains` and `prefixItems` would state that\n * more precisely, but OpenAPI 3.0 has neither, so both dialects use `items`.\n * @ref https://google.aip.dev/193#http11json-representation\n * @ref https://spec.openapis.org/oas/v3.0.3#schema-object\n * @packageDocumentation\n */\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { JsonSchema, SchemaContext, SchemaDialect } from '../context';\nimport type { GoogleRpcCode } from './rpc-code';\n\nimport { constant } from '../schema-helpers';\nimport {\n BAD_REQUEST_TYPE,\n DEBUG_INFO_TYPE,\n ERROR_INFO_TYPE,\n HELP_TYPE,\n METADATA_KEY_PATTERN,\n REQUEST_INFO_TYPE,\n RETRY_INFO_TYPE,\n} from './details';\nimport { resolveRpcCode } from './rpc-code';\n\nexport interface GoogleApiSchemaOptions {\n readonly domain: string;\n readonly rpcCodes: Readonly<Record<string, GoogleRpcCode>> | undefined;\n readonly includeRequestInfo: boolean;\n}\n\nconst STRING: JsonSchema = { type: 'string' };\n\nfunction detail(\n typeUrl: string,\n dialect: SchemaDialect,\n properties: Record<string, JsonSchema>,\n required: ReadonlyArray<string>,\n): JsonSchema {\n return {\n type: 'object',\n required: ['@type', ...required],\n properties: { '@type': constant(typeUrl, dialect), ...properties },\n additionalProperties: false,\n };\n}\n\n/**\n * `metadata` keys follow the `error_details.proto` grammar the renderer\n * enforces. `propertyNames` states it in JSON Schema 2020-12; the OpenAPI\n * 3.0 schema object has neither it nor `patternProperties`, so that dialect\n * types the values only.\n * @ref https://json-schema.org/draft/2020-12/json-schema-core#name-propertynames\n * @ref https://spec.openapis.org/oas/v3.0.3#properties\n */\nfunction metadata(dialect: SchemaDialect): JsonSchema {\n return {\n type: 'object',\n ...(dialect === 'openapi-3.0'\n ? {}\n : { propertyNames: { pattern: METADATA_KEY_PATTERN.source } }),\n additionalProperties: STRING,\n };\n}\n\nfunction errorInfo(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: GoogleApiSchemaOptions,\n): JsonSchema {\n return detail(\n ERROR_INFO_TYPE,\n ctx.dialect,\n {\n reason: constant(definition.code, ctx.dialect),\n domain: constant(options.domain, ctx.dialect),\n metadata: metadata(ctx.dialect),\n },\n ['reason', 'domain'],\n );\n}\n\nfunction badRequest(dialect: SchemaDialect): JsonSchema {\n return detail(\n BAD_REQUEST_TYPE,\n dialect,\n {\n fieldViolations: {\n type: 'array',\n items: {\n type: 'object',\n required: ['description'],\n properties: { field: STRING, description: STRING, reason: STRING },\n additionalProperties: false,\n },\n },\n },\n ['fieldViolations'],\n );\n}\n\nfunction retryInfo(dialect: SchemaDialect): JsonSchema {\n return detail(\n RETRY_INFO_TYPE,\n dialect,\n { retryDelay: { type: 'string', pattern: '^[0-9]+s$' } },\n ['retryDelay'],\n );\n}\n\nfunction requestInfo(dialect: SchemaDialect): JsonSchema {\n return detail(REQUEST_INFO_TYPE, dialect, { requestId: STRING }, [\n 'requestId',\n ]);\n}\n\nfunction debugInfo(dialect: SchemaDialect): JsonSchema {\n return detail(\n DEBUG_INFO_TYPE,\n dialect,\n { stackEntries: { type: 'array', items: STRING } },\n ['stackEntries'],\n );\n}\n\nfunction helpDetail(dialect: SchemaDialect): JsonSchema {\n return detail(\n HELP_TYPE,\n dialect,\n {\n links: {\n type: 'array',\n minItems: 1,\n items: {\n type: 'object',\n required: ['description', 'url'],\n properties: {\n description: STRING,\n url: { type: 'string', format: 'uri' },\n },\n additionalProperties: false,\n },\n },\n },\n ['links'],\n );\n}\n\nexport function bodySchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: GoogleApiSchemaOptions,\n validation: boolean,\n): JsonSchema {\n const payloads: Array<JsonSchema> = [errorInfo(definition, ctx, options)];\n if (validation) {\n payloads.push(badRequest(ctx.dialect));\n }\n payloads.push(retryInfo(ctx.dialect));\n if (options.includeRequestInfo) {\n payloads.push(requestInfo(ctx.dialect));\n }\n payloads.push(debugInfo(ctx.dialect), helpDetail(ctx.dialect));\n return {\n type: 'object',\n required: ['error'],\n properties: {\n error: {\n type: 'object',\n required: ['code', 'message', 'status', 'details'],\n properties: {\n code: constant(definition.status, ctx.dialect),\n message: STRING,\n status: constant(\n resolveRpcCode(\n definition.code,\n definition.status,\n options.rpcCodes,\n ),\n ctx.dialect,\n ),\n details: { type: 'array', minItems: 1, items: { anyOf: payloads } },\n },\n additionalProperties: false,\n },\n },\n additionalProperties: false,\n };\n}\n","/**\n * Google API error format (SPEC 7.6): the AIP-193 HTTP/1.1+JSON\n * representation of `google.rpc.Status`, `{ error: { code, message, status,\n * details } }`, with `code` the HTTP status, `status` the `google.rpc.Code`\n * name, and `details` the standard payloads from `error_details.proto`\n * packed as `google.protobuf.Any`. `ErrorInfo` is always present, as AIP-193\n * requires.\n * @ref https://google.aip.dev/193#http11json-representation\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto\n * @ref https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\nimport type { GoogleApiDetail, GoogleApiErrorInfo } from './details';\nimport type { GoogleRpcCode } from './rpc-code';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { assertMemberName } from '../../internal/member-name';\nimport {\n BAD_REQUEST_TYPE,\n DEBUG_INFO_TYPE,\n ERROR_INFO_TYPE,\n fieldViolation,\n help,\n METADATA_KEY_PATTERN,\n REQUEST_INFO_TYPE,\n retryInfo,\n toMetadata,\n} from './details';\nimport { resolveRpcCode } from './rpc-code';\nimport { bodySchema } from './schema';\n\nexport type {\n GoogleApiBadRequest,\n GoogleApiDebugInfo,\n GoogleApiDetail,\n GoogleApiErrorInfo,\n GoogleApiFieldViolation,\n GoogleApiHelp,\n GoogleApiHelpLink,\n GoogleApiRequestInfo,\n GoogleApiRetryInfo,\n} from './details';\nexport type { GoogleRpcCode } from './rpc-code';\n\nexport interface GoogleApiOptions {\n /**\n * `ErrorInfo.domain`: \"the logical grouping to which the reason belongs\",\n * globally unique, typically the service name (`pubsub.googleapis.com`).\n * Required because AIP-193 requires `ErrorInfo` and a domain has no\n * derivable default.\n * @ref https://google.aip.dev/193#errorinfo\n */\n readonly domain: string;\n /**\n * `status` per catalog code, for entries whose HTTP status maps to the\n * wrong `google.rpc.Code` by default (a 409 that is `ALREADY_EXISTS`, not\n * `ABORTED`). A catalog code that is itself a `google.rpc.Code` name needs\n * no entry here.\n */\n readonly rpcCodes?: Readonly<Record<string, GoogleRpcCode>> | undefined;\n /** Base for the `Help` link; overrides the instance `docsBaseUrl`. */\n readonly helpLinkBaseUrl?: string | undefined;\n /** Key for the trace id inside `ErrorInfo.metadata`. Default `traceId`; `false` disables. */\n readonly traceIdMetadataKey?: string | false | undefined;\n /** Emit `RequestInfo.requestId` with the error id. Default true. */\n readonly includeRequestInfo?: boolean | undefined;\n}\n\n/** The `error` member: AIP-193's `Error.Status`, not `google.rpc.Status`. */\nexport interface GoogleApiStatus {\n /** The HTTP status code. */\n readonly code: number;\n readonly message: string;\n /** The `google.rpc.Code` name. */\n readonly status: GoogleRpcCode;\n readonly details: ReadonlyArray<GoogleApiDetail>;\n}\n\nexport interface GoogleApiBody {\n readonly error: GoogleApiStatus;\n}\n\n/**\n * Google APIs answer errors as plain JSON; there is no dedicated media type.\n * @ref https://google.aip.dev/193#http11json-representation\n */\nexport const GOOGLE_API_CONTENT_TYPE = 'application/json';\n\n/**\n * `metadata` keys written from `ctx.meta` that a `traceIdMetadataKey` of the\n * same name would silently replace: `location` carries the validation target\n * (SPEC 8.2).\n */\nconst RESERVED_METADATA_KEYS: ReadonlySet<string> = new Set(['location']);\n\ninterface Resolved {\n readonly domain: string;\n readonly rpcCodes: Readonly<Record<string, GoogleRpcCode>> | undefined;\n readonly helpLinkBaseUrl: string | undefined;\n readonly traceIdMetadataKey: string | false;\n readonly includeRequestInfo: boolean;\n}\n\nfunction errorInfo(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n): GoogleApiErrorInfo {\n const metadata = toMetadata(ctx.meta);\n if (options.traceIdMetadataKey !== false && ctx.traceId !== undefined) {\n metadata[options.traceIdMetadataKey] = ctx.traceId;\n }\n return {\n '@type': ERROR_INFO_TYPE,\n reason: error.code,\n domain: options.domain,\n ...(Object.keys(metadata).length === 0 ? {} : { metadata }),\n };\n}\n\nfunction helpUrl(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n): string | undefined {\n if (error.type !== undefined) {\n return error.type;\n }\n const base = options.helpLinkBaseUrl ?? ctx.docsBaseUrl;\n return base === undefined ? undefined : `${base}/${error.code}`;\n}\n\n/**\n * Detail order (SPEC 7.6.2): `ErrorInfo`, `BadRequest` (validation only),\n * `RetryInfo`, `RequestInfo`, `DebugInfo`, `Help`. Each type appears at most\n * once, as AIP-193 requires.\n */\nfunction renderBody(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n issues?: ReadonlyArray<ValidationIssue>,\n): GoogleApiBody {\n const details: Array<GoogleApiDetail> = [errorInfo(error, ctx, options)];\n // proto3 JSON omits an empty repeated field and the schema requires\n // `fieldViolations`, so a validation error without issues has no\n // `BadRequest`; `message` still says validation failed.\n if (issues !== undefined && issues.length > 0) {\n details.push({\n '@type': BAD_REQUEST_TYPE,\n fieldViolations: issues.map((issue) => fieldViolation(issue)),\n });\n }\n const retry = retryInfo(error.headers);\n if (retry !== undefined) {\n details.push(retry);\n }\n if (options.includeRequestInfo) {\n details.push({ '@type': REQUEST_INFO_TYPE, requestId: error.id });\n }\n if (ctx.stack !== undefined) {\n details.push({\n '@type': DEBUG_INFO_TYPE,\n stackEntries: ctx.stack.split('\\n'),\n });\n }\n const link = help(error.code, helpUrl(error, ctx, options));\n if (link !== undefined) {\n details.push(link);\n }\n return {\n error: {\n code: error.status,\n message:\n error.detail ??\n (issues === undefined ? error.title : VALIDATION_DETAIL),\n status: resolveRpcCode(error.code, error.status, options.rpcCodes),\n details,\n },\n };\n}\n\n/**\n * AIP-193 Google API errors (SPEC 7.6). Throws `TypeError` when\n * `traceIdMetadataKey` falls outside the `ErrorInfo.metadata` key grammar\n * or names a key the format writes from `ctx.meta`.\n * @ref https://google.aip.dev/193\n */\nexport function googleApi(\n options: GoogleApiOptions,\n): ErrorFormat<GoogleApiBody> {\n const resolved: Resolved = {\n domain: options.domain,\n rpcCodes: options.rpcCodes,\n helpLinkBaseUrl: options.helpLinkBaseUrl,\n traceIdMetadataKey: options.traceIdMetadataKey ?? 'traceId',\n includeRequestInfo: options.includeRequestInfo ?? true,\n };\n if (resolved.traceIdMetadataKey !== false) {\n assertMemberName(\n 'traceIdMetadataKey',\n resolved.traceIdMetadataKey,\n RESERVED_METADATA_KEYS,\n METADATA_KEY_PATTERN,\n );\n }\n const schemaOptions = {\n domain: resolved.domain,\n rpcCodes: resolved.rpcCodes,\n includeRequestInfo: resolved.includeRequestInfo,\n };\n return {\n name: 'google-api',\n contentType: GOOGLE_API_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): GoogleApiBody {\n return renderBody(error, ctx, resolved);\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): GoogleApiBody {\n return renderBody(error, ctx, resolved, issues);\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return bodySchema(definition, ctx, schemaOptions, false);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return bodySchema(definition, ctx, schemaOptions, true);\n },\n };\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { t as constant } from "../schema-helpers-bwCFve8i.js";
2
- import { t as assertMemberName } from "../member-name-k4VABr91.js";
1
+ import "../constants-rUzQOaX_.js";
2
+ import { t as assertMemberName } from "../member-name-Bn3zp8gx.js";
3
+ import { t as constant } from "../schema-helpers-B4HL9TmU.js";
3
4
  import { a as pointerFromPath, r as nameFromPath, t as isPointerLocation } from "../issue-B-7iyCBE.js";
4
5
  import { n as readLocation } from "../validation-entries-9R5RK-AZ.js";
5
6
  //#region src/formats/json-api/schema.ts
@@ -1 +1 @@
1
- {"version":3,"file":"json-api.js","names":[],"sources":["../../src/formats/json-api/schema.ts","../../src/formats/json-api/index.ts"],"sourcesContent":["/**\n * JSON Schema for the JSON:API error document (SPEC 7.2.3): a closed\n * `{ errors: [ErrorObject, ...] }` whose error objects pin `status`, `code`,\n * and `title` to the definition and are closed too.\n * @ref https://jsonapi.org/format/#error-objects\n * @packageDocumentation\n */\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { JsonSchema, SchemaContext } from '../context';\n\nimport { constant } from '../schema-helpers';\n\nexport interface JsonApiSchemaOptions {\n readonly includeId: boolean;\n}\n\nfunction errorObjectSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: JsonApiSchemaOptions,\n): JsonSchema {\n const properties: Record<string, JsonSchema> = {\n ...(options.includeId ? { id: { type: 'string' } } : {}),\n // Links are URI references (RFC 3986 section 4.1), the same class RFC\n // 9457 uses for `type`, so a relative `about` link conforms too.\n // @ref https://jsonapi.org/format/#document-links\n // @ref https://www.rfc-editor.org/rfc/rfc3986#section-4.1\n links: {\n type: 'object',\n properties: {\n type: { type: 'string', format: 'uri-reference' },\n about: { type: 'string', format: 'uri-reference' },\n },\n additionalProperties: false,\n },\n status: constant(String(definition.status), ctx.dialect),\n code: constant(definition.code, ctx.dialect),\n title: constant(definition.title, ctx.dialect),\n detail: { type: 'string' },\n source: {\n type: 'object',\n properties: {\n pointer: { type: 'string' },\n parameter: { type: 'string' },\n header: { type: 'string' },\n },\n additionalProperties: false,\n },\n meta: { type: 'object' },\n };\n return {\n type: 'object',\n required: ['status', 'code', 'title'],\n properties,\n additionalProperties: false,\n };\n}\n\nexport function bodySchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: JsonApiSchemaOptions,\n): JsonSchema {\n return {\n type: 'object',\n required: ['errors'],\n properties: {\n errors: {\n type: 'array',\n minItems: 1,\n items: errorObjectSchema(definition, ctx, options),\n },\n },\n additionalProperties: false,\n };\n}\n","/**\n * JSON:API 1.1 error document format (SPEC 7.2): `{ errors: [ErrorObject] }`\n * with one error object per validation issue.\n * @ref https://jsonapi.org/format/#errors\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { IssueLocation, ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { assertMemberName } from '../../internal/member-name';\nimport {\n isPointerLocation,\n nameFromPath,\n pointerFromPath,\n} from '../../validation/issue';\nimport { readLocation } from '../validation-entries';\nimport { bodySchema } from './schema';\n\nexport interface JsonApiOptions {\n /** Base for `links.type`; overrides the instance `docsBaseUrl`. */\n readonly typeLinkBaseUrl?: string | undefined;\n /** Produces `links.about`, a URL for this occurrence. */\n readonly aboutLink?:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n /** Emit `id`. Default true. */\n readonly includeId?: boolean | undefined;\n /** Key for the trace id inside `meta`. Default `traceId`; `false` disables. */\n readonly traceIdMetaKey?: string | false | undefined;\n}\n\nexport interface JsonApiLinks {\n readonly type?: string;\n readonly about?: string;\n}\n\nexport interface JsonApiSource {\n readonly pointer?: string;\n readonly parameter?: string;\n readonly header?: string;\n}\n\n/**\n * A JSON:API 1.1 error object.\n * @ref https://jsonapi.org/format/#error-objects\n */\nexport interface JsonApiErrorObject {\n readonly id?: string;\n readonly links?: JsonApiLinks;\n /** The HTTP status as a string, as the specification requires. */\n readonly status: string;\n readonly code: string;\n readonly title: string;\n readonly detail?: string;\n readonly source?: JsonApiSource;\n readonly meta?: Readonly<Record<string, unknown>>;\n}\n\nexport interface JsonApiBody {\n readonly errors: ReadonlyArray<JsonApiErrorObject>;\n}\n\n/**\n * No parameters: the specification allows only `ext` and `profile`.\n * @ref https://jsonapi.org/format/#content-negotiation-servers\n */\nexport const JSON_API_CONTENT_TYPE = 'application/vnd.api+json';\n\n/**\n * Member names: at least one character, starting and ending with a letter,\n * digit, or a code point at U+0080 or above, with `-`, `_`, and space allowed\n * in between.\n * @ref https://jsonapi.org/format/#document-member-names\n */\nconst MEMBER_NAME_PATTERN =\n /^[A-Za-z0-9\\u0080-\\u{10FFFF}](?:[A-Za-z0-9\\u0080-\\u{10FFFF} _-]*[A-Za-z0-9\\u0080-\\u{10FFFF}])?$/u;\n/**\n * `meta` keys this format writes itself (7.2.1, 7.2.2); a `traceIdMetaKey`\n * with one of these names would be overwritten or overwrite it.\n */\nconst RESERVED_META_KEYS: ReadonlySet<string> = new Set([\n 'stack',\n 'location',\n 'name',\n 'code',\n 'expected',\n 'received',\n]);\n\ninterface Resolved {\n readonly typeLinkBaseUrl: string | undefined;\n readonly aboutLink:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n readonly includeId: boolean;\n readonly traceIdMetaKey: string | false;\n}\n\nfunction links(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n): JsonApiLinks | undefined {\n const base = options.typeLinkBaseUrl ?? ctx.docsBaseUrl;\n const type =\n error.type ?? (base === undefined ? undefined : `${base}/${error.code}`);\n const about = options.aboutLink?.(error, ctx);\n if (type === undefined && about === undefined) {\n return undefined;\n }\n return {\n ...(type === undefined ? {} : { type }),\n ...(about === undefined ? {} : { about }),\n };\n}\n\nfunction sharedMeta(\n ctx: RenderContext,\n options: Resolved,\n): Record<string, unknown> {\n const meta: Record<string, unknown> = { ...ctx.meta };\n if (options.traceIdMetaKey !== false && ctx.traceId !== undefined) {\n meta[options.traceIdMetaKey] = ctx.traceId;\n }\n if (ctx.stack !== undefined) {\n meta['stack'] = ctx.stack;\n }\n return meta;\n}\n\nfunction errorObject(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n detail: string | undefined,\n source: JsonApiSource | undefined,\n meta: Record<string, unknown>,\n): JsonApiErrorObject {\n const linkMembers = links(error, ctx, options);\n return {\n ...(options.includeId ? { id: error.id } : {}),\n ...(linkMembers === undefined ? {} : { links: linkMembers }),\n status: String(error.status),\n code: error.code,\n title: error.title,\n ...(detail === undefined ? {} : { detail }),\n ...(source === undefined ? {} : { source }),\n ...(Object.keys(meta).length === 0 ? {} : { meta }),\n };\n}\n\n/**\n * `source.pointer` for bodies, `source.parameter` for query parameters,\n * `source.header` for headers. JSON:API has no member for path or cookie\n * parameters, so those are described in `meta` instead.\n * @ref https://jsonapi.org/format/#error-objects\n */\nfunction issueSource(\n issue: ValidationIssue,\n location: IssueLocation,\n): JsonApiSource | undefined {\n if (isPointerLocation(location)) {\n return { pointer: pointerFromPath(issue.path) };\n }\n if (location === 'query') {\n return { parameter: nameFromPath(issue.path) };\n }\n if (location === 'header') {\n return { header: nameFromPath(issue.path) };\n }\n return undefined;\n}\n\nfunction issueMeta(\n issue: ValidationIssue,\n location: IssueLocation,\n shared: Record<string, unknown>,\n): Record<string, unknown> {\n const meta: Record<string, unknown> = { ...shared, location };\n if (location === 'param' || location === 'cookie') {\n meta['name'] = nameFromPath(issue.path);\n }\n if (issue.code !== undefined) {\n meta['code'] = issue.code;\n }\n if (issue.expected !== undefined) {\n meta['expected'] = issue.expected;\n }\n if (issue.received !== undefined) {\n meta['received'] = issue.received;\n }\n return meta;\n}\n\n/**\n * JSON:API 1.1 error documents (SPEC 7.2). Throws `TypeError` when\n * `traceIdMetaKey` names a `meta` key the format writes itself or is not a\n * valid member name.\n * @ref https://jsonapi.org/format/#errors\n */\nexport function jsonApi(\n options: JsonApiOptions = {},\n): ErrorFormat<JsonApiBody> {\n const resolved: Resolved = {\n typeLinkBaseUrl: options.typeLinkBaseUrl,\n aboutLink: options.aboutLink,\n includeId: options.includeId ?? true,\n traceIdMetaKey: options.traceIdMetaKey ?? 'traceId',\n };\n if (resolved.traceIdMetaKey !== false) {\n assertMemberName(\n 'traceIdMetaKey',\n resolved.traceIdMetaKey,\n RESERVED_META_KEYS,\n MEMBER_NAME_PATTERN,\n );\n }\n return {\n name: 'json-api',\n contentType: JSON_API_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): JsonApiBody {\n return {\n errors: [\n errorObject(\n error,\n ctx,\n resolved,\n error.detail,\n undefined,\n sharedMeta(ctx, resolved),\n ),\n ],\n };\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): JsonApiBody {\n const location = readLocation(ctx.meta);\n const shared = sharedMeta(ctx, resolved);\n if (issues.length === 0) {\n // `errors` must hold at least one object (7.2.3), so a validation\n // error without issues renders the summary the detail would carry.\n return {\n errors: [\n errorObject(\n error,\n ctx,\n resolved,\n error.detail ?? VALIDATION_DETAIL,\n undefined,\n { ...shared, location },\n ),\n ],\n };\n }\n return {\n errors: issues.map((issue) =>\n errorObject(\n error,\n ctx,\n resolved,\n issue.message,\n issueSource(issue, location),\n issueMeta(issue, location, shared),\n ),\n ),\n };\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return bodySchema(definition, ctx, resolved);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return bodySchema(definition, ctx, resolved);\n },\n };\n}\n"],"mappings":";;;;;AAgBA,SAAS,kBACP,YACA,KACA,SACY;CA8BZ,OAAO;EACL,MAAM;EACN,UAAU;GAAC;GAAU;GAAQ;EAAO;EACpC,YAAA;GA/BA,GAAI,QAAQ,YAAY,EAAE,IAAI,EAAE,MAAM,SAAS,EAAE,IAAI,CAAC;GAKtD,OAAO;IACL,MAAM;IACN,YAAY;KACV,MAAM;MAAE,MAAM;MAAU,QAAQ;KAAgB;KAChD,OAAO;MAAE,MAAM;MAAU,QAAQ;KAAgB;IACnD;IACA,sBAAsB;GACxB;GACA,QAAQ,SAAS,OAAO,WAAW,MAAM,GAAG,IAAI,OAAO;GACvD,MAAM,SAAS,WAAW,MAAM,IAAI,OAAO;GAC3C,OAAO,SAAS,WAAW,OAAO,IAAI,OAAO;GAC7C,QAAQ,EAAE,MAAM,SAAS;GACzB,QAAQ;IACN,MAAM;IACN,YAAY;KACV,SAAS,EAAE,MAAM,SAAS;KAC1B,WAAW,EAAE,MAAM,SAAS;KAC5B,QAAQ,EAAE,MAAM,SAAS;IAC3B;IACA,sBAAsB;GACxB;GACA,MAAM,EAAE,MAAM,SAAS;EAKd;EACT,sBAAsB;CACxB;AACF;AAEA,SAAgB,WACd,YACA,KACA,SACY;CACZ,OAAO;EACL,MAAM;EACN,UAAU,CAAC,QAAQ;EACnB,YAAY,EACV,QAAQ;GACN,MAAM;GACN,UAAU;GACV,OAAO,kBAAkB,YAAY,KAAK,OAAO;EACnD,EACF;EACA,sBAAsB;CACxB;AACF;;;;;;;ACLA,MAAa,wBAAwB;;;;;;;AAQrC,MAAM,sBACJ;;;;;AAKF,MAAM,qCAA0C,IAAI,IAAI;CACtD;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAWD,SAAS,MACP,OACA,KACA,SAC0B;CAC1B,MAAM,OAAO,QAAQ,mBAAmB,IAAI;CAC5C,MAAM,OACJ,MAAM,SAAS,SAAS,KAAA,IAAY,KAAA,IAAY,GAAG,KAAK,GAAG,MAAM;CACnE,MAAM,QAAQ,QAAQ,YAAY,OAAO,GAAG;CAC5C,IAAI,SAAS,KAAA,KAAa,UAAU,KAAA,GAClC;CAEF,OAAO;EACL,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;EACrC,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;CACzC;AACF;AAEA,SAAS,WACP,KACA,SACyB;CACzB,MAAM,OAAgC,EAAE,GAAG,IAAI,KAAK;CACpD,IAAI,QAAQ,mBAAmB,SAAS,IAAI,YAAY,KAAA,GACtD,KAAK,QAAQ,kBAAkB,IAAI;CAErC,IAAI,IAAI,UAAU,KAAA,GAChB,KAAK,WAAW,IAAI;CAEtB,OAAO;AACT;AAEA,SAAS,YACP,OACA,KACA,SACA,QACA,QACA,MACoB;CACpB,MAAM,cAAc,MAAM,OAAO,KAAK,OAAO;CAC7C,OAAO;EACL,GAAI,QAAQ,YAAY,EAAE,IAAI,MAAM,GAAG,IAAI,CAAC;EAC5C,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,YAAY;EAC1D,QAAQ,OAAO,MAAM,MAAM;EAC3B,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;EACzC,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;EACzC,GAAI,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,KAAK;CACnD;AACF;;;;;;;AAQA,SAAS,YACP,OACA,UAC2B;CAC3B,IAAI,kBAAkB,QAAQ,GAC5B,OAAO,EAAE,SAAS,gBAAgB,MAAM,IAAI,EAAE;CAEhD,IAAI,aAAa,SACf,OAAO,EAAE,WAAW,aAAa,MAAM,IAAI,EAAE;CAE/C,IAAI,aAAa,UACf,OAAO,EAAE,QAAQ,aAAa,MAAM,IAAI,EAAE;AAG9C;AAEA,SAAS,UACP,OACA,UACA,QACyB;CACzB,MAAM,OAAgC;EAAE,GAAG;EAAQ;CAAS;CAC5D,IAAI,aAAa,WAAW,aAAa,UACvC,KAAK,UAAU,aAAa,MAAM,IAAI;CAExC,IAAI,MAAM,SAAS,KAAA,GACjB,KAAK,UAAU,MAAM;CAEvB,IAAI,MAAM,aAAa,KAAA,GACrB,KAAK,cAAc,MAAM;CAE3B,IAAI,MAAM,aAAa,KAAA,GACrB,KAAK,cAAc,MAAM;CAE3B,OAAO;AACT;;;;;;;AAQA,SAAgB,QACd,UAA0B,CAAC,GACD;CAC1B,MAAM,WAAqB;EACzB,iBAAiB,QAAQ;EACzB,WAAW,QAAQ;EACnB,WAAW,QAAQ,aAAa;EAChC,gBAAgB,QAAQ,kBAAkB;CAC5C;CACA,IAAI,SAAS,mBAAmB,OAC9B,iBACE,kBACA,SAAS,gBACT,oBACA,mBACF;CAEF,OAAO;EACL,MAAM;EACN,aAAa;EACb,OAAO,OAAiB,KAAiC;GACvD,OAAO,EACL,QAAQ,CACN,YACE,OACA,KACA,UACA,MAAM,QACN,KAAA,GACA,WAAW,KAAK,QAAQ,CAC1B,CACF,EACF;EACF;EACA,iBACE,OACA,QACA,KACa;GACb,MAAM,WAAW,aAAa,IAAI,IAAI;GACtC,MAAM,SAAS,WAAW,KAAK,QAAQ;GACvC,IAAI,OAAO,WAAW,GAGpB,OAAO,EACL,QAAQ,CACN,YACE,OACA,KACA,UACA,MAAM,UAAA,6BACN,KAAA,GACA;IAAE,GAAG;IAAQ;GAAS,CACxB,CACF,EACF;GAEF,OAAO,EACL,QAAQ,OAAO,KAAK,UAClB,YACE,OACA,KACA,UACA,MAAM,SACN,YAAY,OAAO,QAAQ,GAC3B,UAAU,OAAO,UAAU,MAAM,CACnC,CACF,EACF;EACF;EACA,OAAO,YAAgC,KAAgC;GACrE,OAAO,WAAW,YAAY,KAAK,QAAQ;EAC7C;EACA,iBACE,YACA,KACY;GACZ,OAAO,WAAW,YAAY,KAAK,QAAQ;EAC7C;CACF;AACF"}
1
+ {"version":3,"file":"json-api.js","names":[],"sources":["../../src/formats/json-api/schema.ts","../../src/formats/json-api/index.ts"],"sourcesContent":["/**\n * JSON Schema for the JSON:API error document (SPEC 7.2.3): a closed\n * `{ errors: [ErrorObject, ...] }` whose error objects pin `status`, `code`,\n * and `title` to the definition and are closed too.\n * @ref https://jsonapi.org/format/#error-objects\n * @packageDocumentation\n */\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { JsonSchema, SchemaContext } from '../context';\n\nimport { constant } from '../schema-helpers';\n\nexport interface JsonApiSchemaOptions {\n readonly includeId: boolean;\n}\n\nfunction errorObjectSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: JsonApiSchemaOptions,\n): JsonSchema {\n const properties: Record<string, JsonSchema> = {\n ...(options.includeId ? { id: { type: 'string' } } : {}),\n // Links are URI references (RFC 3986 section 4.1), the same class RFC\n // 9457 uses for `type`, so a relative `about` link conforms too.\n // @ref https://jsonapi.org/format/#document-links\n // @ref https://www.rfc-editor.org/rfc/rfc3986#section-4.1\n links: {\n type: 'object',\n properties: {\n type: { type: 'string', format: 'uri-reference' },\n about: { type: 'string', format: 'uri-reference' },\n },\n additionalProperties: false,\n },\n status: constant(String(definition.status), ctx.dialect),\n code: constant(definition.code, ctx.dialect),\n title: constant(definition.title, ctx.dialect),\n detail: { type: 'string' },\n source: {\n type: 'object',\n properties: {\n pointer: { type: 'string' },\n parameter: { type: 'string' },\n header: { type: 'string' },\n },\n additionalProperties: false,\n },\n meta: { type: 'object' },\n };\n return {\n type: 'object',\n required: ['status', 'code', 'title'],\n properties,\n additionalProperties: false,\n };\n}\n\nexport function bodySchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: JsonApiSchemaOptions,\n): JsonSchema {\n return {\n type: 'object',\n required: ['errors'],\n properties: {\n errors: {\n type: 'array',\n minItems: 1,\n items: errorObjectSchema(definition, ctx, options),\n },\n },\n additionalProperties: false,\n };\n}\n","/**\n * JSON:API 1.1 error document format (SPEC 7.2): `{ errors: [ErrorObject] }`\n * with one error object per validation issue.\n * @ref https://jsonapi.org/format/#errors\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { IssueLocation, ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { assertMemberName } from '../../internal/member-name';\nimport {\n isPointerLocation,\n nameFromPath,\n pointerFromPath,\n} from '../../validation/issue';\nimport { readLocation } from '../validation-entries';\nimport { bodySchema } from './schema';\n\nexport interface JsonApiOptions {\n /** Base for `links.type`; overrides the instance `docsBaseUrl`. */\n readonly typeLinkBaseUrl?: string | undefined;\n /** Produces `links.about`, a URL for this occurrence. */\n readonly aboutLink?:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n /** Emit `id`. Default true. */\n readonly includeId?: boolean | undefined;\n /** Key for the trace id inside `meta`. Default `traceId`; `false` disables. */\n readonly traceIdMetaKey?: string | false | undefined;\n}\n\nexport interface JsonApiLinks {\n readonly type?: string;\n readonly about?: string;\n}\n\nexport interface JsonApiSource {\n readonly pointer?: string;\n readonly parameter?: string;\n readonly header?: string;\n}\n\n/**\n * A JSON:API 1.1 error object.\n * @ref https://jsonapi.org/format/#error-objects\n */\nexport interface JsonApiErrorObject {\n readonly id?: string;\n readonly links?: JsonApiLinks;\n /** The HTTP status as a string, as the specification requires. */\n readonly status: string;\n readonly code: string;\n readonly title: string;\n readonly detail?: string;\n readonly source?: JsonApiSource;\n readonly meta?: Readonly<Record<string, unknown>>;\n}\n\nexport interface JsonApiBody {\n readonly errors: ReadonlyArray<JsonApiErrorObject>;\n}\n\n/**\n * No parameters: the specification allows only `ext` and `profile`.\n * @ref https://jsonapi.org/format/#content-negotiation-servers\n */\nexport const JSON_API_CONTENT_TYPE = 'application/vnd.api+json';\n\n/**\n * Member names: at least one character, starting and ending with a letter,\n * digit, or a code point at U+0080 or above, with `-`, `_`, and space allowed\n * in between.\n * @ref https://jsonapi.org/format/#document-member-names\n */\nconst MEMBER_NAME_PATTERN =\n /^[A-Za-z0-9\\u0080-\\u{10FFFF}](?:[A-Za-z0-9\\u0080-\\u{10FFFF} _-]*[A-Za-z0-9\\u0080-\\u{10FFFF}])?$/u;\n/**\n * `meta` keys this format writes itself (7.2.1, 7.2.2); a `traceIdMetaKey`\n * with one of these names would be overwritten or overwrite it.\n */\nconst RESERVED_META_KEYS: ReadonlySet<string> = new Set([\n 'stack',\n 'location',\n 'name',\n 'code',\n 'expected',\n 'received',\n]);\n\ninterface Resolved {\n readonly typeLinkBaseUrl: string | undefined;\n readonly aboutLink:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n readonly includeId: boolean;\n readonly traceIdMetaKey: string | false;\n}\n\nfunction links(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n): JsonApiLinks | undefined {\n const base = options.typeLinkBaseUrl ?? ctx.docsBaseUrl;\n const type =\n error.type ?? (base === undefined ? undefined : `${base}/${error.code}`);\n const about = options.aboutLink?.(error, ctx);\n if (type === undefined && about === undefined) {\n return undefined;\n }\n return {\n ...(type === undefined ? {} : { type }),\n ...(about === undefined ? {} : { about }),\n };\n}\n\nfunction sharedMeta(\n ctx: RenderContext,\n options: Resolved,\n): Record<string, unknown> {\n const meta: Record<string, unknown> = { ...ctx.meta };\n if (options.traceIdMetaKey !== false && ctx.traceId !== undefined) {\n meta[options.traceIdMetaKey] = ctx.traceId;\n }\n if (ctx.stack !== undefined) {\n meta['stack'] = ctx.stack;\n }\n return meta;\n}\n\nfunction errorObject(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n detail: string | undefined,\n source: JsonApiSource | undefined,\n meta: Record<string, unknown>,\n): JsonApiErrorObject {\n const linkMembers = links(error, ctx, options);\n return {\n ...(options.includeId ? { id: error.id } : {}),\n ...(linkMembers === undefined ? {} : { links: linkMembers }),\n status: String(error.status),\n code: error.code,\n title: error.title,\n ...(detail === undefined ? {} : { detail }),\n ...(source === undefined ? {} : { source }),\n ...(Object.keys(meta).length === 0 ? {} : { meta }),\n };\n}\n\n/**\n * `source.pointer` for bodies, `source.parameter` for query parameters,\n * `source.header` for headers. JSON:API has no member for path or cookie\n * parameters, so those are described in `meta` instead.\n * @ref https://jsonapi.org/format/#error-objects\n */\nfunction issueSource(\n issue: ValidationIssue,\n location: IssueLocation,\n): JsonApiSource | undefined {\n if (isPointerLocation(location)) {\n return { pointer: pointerFromPath(issue.path) };\n }\n if (location === 'query') {\n return { parameter: nameFromPath(issue.path) };\n }\n if (location === 'header') {\n return { header: nameFromPath(issue.path) };\n }\n return undefined;\n}\n\nfunction issueMeta(\n issue: ValidationIssue,\n location: IssueLocation,\n shared: Record<string, unknown>,\n): Record<string, unknown> {\n const meta: Record<string, unknown> = { ...shared, location };\n if (location === 'param' || location === 'cookie') {\n meta['name'] = nameFromPath(issue.path);\n }\n if (issue.code !== undefined) {\n meta['code'] = issue.code;\n }\n if (issue.expected !== undefined) {\n meta['expected'] = issue.expected;\n }\n if (issue.received !== undefined) {\n meta['received'] = issue.received;\n }\n return meta;\n}\n\n/**\n * JSON:API 1.1 error documents (SPEC 7.2). Throws `TypeError` when\n * `traceIdMetaKey` names a `meta` key the format writes itself or is not a\n * valid member name.\n * @ref https://jsonapi.org/format/#errors\n */\nexport function jsonApi(\n options: JsonApiOptions = {},\n): ErrorFormat<JsonApiBody> {\n const resolved: Resolved = {\n typeLinkBaseUrl: options.typeLinkBaseUrl,\n aboutLink: options.aboutLink,\n includeId: options.includeId ?? true,\n traceIdMetaKey: options.traceIdMetaKey ?? 'traceId',\n };\n if (resolved.traceIdMetaKey !== false) {\n assertMemberName(\n 'traceIdMetaKey',\n resolved.traceIdMetaKey,\n RESERVED_META_KEYS,\n MEMBER_NAME_PATTERN,\n );\n }\n return {\n name: 'json-api',\n contentType: JSON_API_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): JsonApiBody {\n return {\n errors: [\n errorObject(\n error,\n ctx,\n resolved,\n error.detail,\n undefined,\n sharedMeta(ctx, resolved),\n ),\n ],\n };\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): JsonApiBody {\n const location = readLocation(ctx.meta);\n const shared = sharedMeta(ctx, resolved);\n if (issues.length === 0) {\n // `errors` must hold at least one object (7.2.3), so a validation\n // error without issues renders the summary the detail would carry.\n return {\n errors: [\n errorObject(\n error,\n ctx,\n resolved,\n error.detail ?? VALIDATION_DETAIL,\n undefined,\n { ...shared, location },\n ),\n ],\n };\n }\n return {\n errors: issues.map((issue) =>\n errorObject(\n error,\n ctx,\n resolved,\n issue.message,\n issueSource(issue, location),\n issueMeta(issue, location, shared),\n ),\n ),\n };\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return bodySchema(definition, ctx, resolved);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return bodySchema(definition, ctx, resolved);\n },\n };\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import { t as constant } from "../schema-helpers-bwCFve8i.js";
1
+ import "../constants-rUzQOaX_.js";
2
+ import { t as constant } from "../schema-helpers-B4HL9TmU.js";
2
3
  import { n as readLocation, r as toValidationEntries, t as VALIDATION_ENTRIES_SCHEMA } from "../validation-entries-9R5RK-AZ.js";
3
4
  //#region src/formats/plain/index.ts
4
5
  const PLAIN_CONTENT_TYPE = "application/json";
@@ -1 +1 @@
1
- {"version":3,"file":"plain.js","names":[],"sources":["../../src/formats/plain/index.ts"],"sourcesContent":["/**\n * Plain JSON format (SPEC 7.3): a closed `{ status, code, title, detail, id,\n * instance, traceId, meta, errors }` shape for teams migrating from ad hoc\n * bodies. Not a standard; `problemDetails()` is the default.\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\nimport type { ValidationEntry } from '../validation-entries';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { constant } from '../schema-helpers';\nimport {\n readLocation,\n toValidationEntries,\n VALIDATION_ENTRIES_SCHEMA,\n} from '../validation-entries';\n\n/** A closed JSON shape for teams migrating from ad hoc error bodies (SPEC 7.3). */\nexport interface PlainBody {\n readonly status: number;\n readonly code: string;\n readonly title: string;\n readonly detail?: string;\n readonly id: string;\n readonly instance?: string;\n readonly traceId?: string;\n readonly meta?: Readonly<Record<string, unknown>>;\n readonly stack?: string;\n readonly errors?: ReadonlyArray<ValidationEntry>;\n}\n\nexport const PLAIN_CONTENT_TYPE = 'application/json';\n\nfunction renderBase(error: BanError, ctx: RenderContext): PlainBody {\n return {\n status: error.status,\n code: error.code,\n title: error.title,\n ...(error.detail === undefined ? {} : { detail: error.detail }),\n id: error.id,\n ...(ctx.instance === undefined ? {} : { instance: ctx.instance }),\n ...(ctx.traceId === undefined ? {} : { traceId: ctx.traceId }),\n ...(Object.keys(ctx.meta).length === 0 ? {} : { meta: ctx.meta }),\n ...(ctx.stack === undefined ? {} : { stack: ctx.stack }),\n };\n}\n\nfunction baseSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n): JsonSchema {\n return {\n type: 'object',\n required: ['status', 'code', 'title', 'id'],\n properties: {\n status: constant(definition.status, ctx.dialect),\n code: constant(definition.code, ctx.dialect),\n title: constant(definition.title, ctx.dialect),\n detail: { type: 'string' },\n id: { type: 'string' },\n instance: { type: 'string' },\n traceId: { type: 'string' },\n meta: { type: 'object' },\n stack: { type: 'string' },\n errors: VALIDATION_ENTRIES_SCHEMA,\n },\n additionalProperties: false,\n };\n}\n\nexport function plain(): ErrorFormat<PlainBody> {\n return {\n name: 'plain',\n contentType: PLAIN_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): PlainBody {\n return renderBase(error, ctx);\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): PlainBody {\n return {\n ...renderBase(error, ctx),\n detail: error.detail ?? VALIDATION_DETAIL,\n errors: toValidationEntries(issues, readLocation(ctx.meta)),\n };\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return baseSchema(definition, ctx);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return {\n ...baseSchema(definition, ctx),\n required: ['status', 'code', 'title', 'id', 'errors'],\n };\n },\n };\n}\n"],"mappings":";;;AAmCA,MAAa,qBAAqB;AAElC,SAAS,WAAW,OAAiB,KAA+B;CAClE,OAAO;EACL,QAAQ,MAAM;EACd,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,GAAI,MAAM,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;EAC7D,IAAI,MAAM;EACV,GAAI,IAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS;EAC/D,GAAI,IAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,IAAI,QAAQ;EAC5D,GAAI,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK;EAC/D,GAAI,IAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,IAAI,MAAM;CACxD;AACF;AAEA,SAAS,WACP,YACA,KACY;CACZ,OAAO;EACL,MAAM;EACN,UAAU;GAAC;GAAU;GAAQ;GAAS;EAAI;EAC1C,YAAY;GACV,QAAQ,SAAS,WAAW,QAAQ,IAAI,OAAO;GAC/C,MAAM,SAAS,WAAW,MAAM,IAAI,OAAO;GAC3C,OAAO,SAAS,WAAW,OAAO,IAAI,OAAO;GAC7C,QAAQ,EAAE,MAAM,SAAS;GACzB,IAAI,EAAE,MAAM,SAAS;GACrB,UAAU,EAAE,MAAM,SAAS;GAC3B,SAAS,EAAE,MAAM,SAAS;GAC1B,MAAM,EAAE,MAAM,SAAS;GACvB,OAAO,EAAE,MAAM,SAAS;GACxB,QAAQ;EACV;EACA,sBAAsB;CACxB;AACF;AAEA,SAAgB,QAAgC;CAC9C,OAAO;EACL,MAAM;EACN,aAAa;EACb,OAAO,OAAiB,KAA+B;GACrD,OAAO,WAAW,OAAO,GAAG;EAC9B;EACA,iBACE,OACA,QACA,KACW;GACX,OAAO;IACL,GAAG,WAAW,OAAO,GAAG;IACxB,QAAQ,MAAM,UAAA;IACd,QAAQ,oBAAoB,QAAQ,aAAa,IAAI,IAAI,CAAC;GAC5D;EACF;EACA,OAAO,YAAgC,KAAgC;GACrE,OAAO,WAAW,YAAY,GAAG;EACnC;EACA,iBACE,YACA,KACY;GACZ,OAAO;IACL,GAAG,WAAW,YAAY,GAAG;IAC7B,UAAU;KAAC;KAAU;KAAQ;KAAS;KAAM;IAAQ;GACtD;EACF;CACF;AACF"}
1
+ {"version":3,"file":"plain.js","names":[],"sources":["../../src/formats/plain/index.ts"],"sourcesContent":["/**\n * Plain JSON format (SPEC 7.3): a closed `{ status, code, title, detail, id,\n * instance, traceId, meta, errors }` shape for teams migrating from ad hoc\n * bodies. Not a standard; `problemDetails()` is the default.\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\nimport type { ValidationEntry } from '../validation-entries';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { constant } from '../schema-helpers';\nimport {\n readLocation,\n toValidationEntries,\n VALIDATION_ENTRIES_SCHEMA,\n} from '../validation-entries';\n\n/** A closed JSON shape for teams migrating from ad hoc error bodies (SPEC 7.3). */\nexport interface PlainBody {\n readonly status: number;\n readonly code: string;\n readonly title: string;\n readonly detail?: string;\n readonly id: string;\n readonly instance?: string;\n readonly traceId?: string;\n readonly meta?: Readonly<Record<string, unknown>>;\n readonly stack?: string;\n readonly errors?: ReadonlyArray<ValidationEntry>;\n}\n\nexport const PLAIN_CONTENT_TYPE = 'application/json';\n\nfunction renderBase(error: BanError, ctx: RenderContext): PlainBody {\n return {\n status: error.status,\n code: error.code,\n title: error.title,\n ...(error.detail === undefined ? {} : { detail: error.detail }),\n id: error.id,\n ...(ctx.instance === undefined ? {} : { instance: ctx.instance }),\n ...(ctx.traceId === undefined ? {} : { traceId: ctx.traceId }),\n ...(Object.keys(ctx.meta).length === 0 ? {} : { meta: ctx.meta }),\n ...(ctx.stack === undefined ? {} : { stack: ctx.stack }),\n };\n}\n\nfunction baseSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n): JsonSchema {\n return {\n type: 'object',\n required: ['status', 'code', 'title', 'id'],\n properties: {\n status: constant(definition.status, ctx.dialect),\n code: constant(definition.code, ctx.dialect),\n title: constant(definition.title, ctx.dialect),\n detail: { type: 'string' },\n id: { type: 'string' },\n instance: { type: 'string' },\n traceId: { type: 'string' },\n meta: { type: 'object' },\n stack: { type: 'string' },\n errors: VALIDATION_ENTRIES_SCHEMA,\n },\n additionalProperties: false,\n };\n}\n\nexport function plain(): ErrorFormat<PlainBody> {\n return {\n name: 'plain',\n contentType: PLAIN_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): PlainBody {\n return renderBase(error, ctx);\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): PlainBody {\n return {\n ...renderBase(error, ctx),\n detail: error.detail ?? VALIDATION_DETAIL,\n errors: toValidationEntries(issues, readLocation(ctx.meta)),\n };\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return baseSchema(definition, ctx);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return {\n ...baseSchema(definition, ctx),\n required: ['status', 'code', 'title', 'id', 'errors'],\n };\n },\n };\n}\n"],"mappings":";;;;AAmCA,MAAa,qBAAqB;AAElC,SAAS,WAAW,OAAiB,KAA+B;CAClE,OAAO;EACL,QAAQ,MAAM;EACd,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,GAAI,MAAM,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;EAC7D,IAAI,MAAM;EACV,GAAI,IAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS;EAC/D,GAAI,IAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,IAAI,QAAQ;EAC5D,GAAI,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK;EAC/D,GAAI,IAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,IAAI,MAAM;CACxD;AACF;AAEA,SAAS,WACP,YACA,KACY;CACZ,OAAO;EACL,MAAM;EACN,UAAU;GAAC;GAAU;GAAQ;GAAS;EAAI;EAC1C,YAAY;GACV,QAAQ,SAAS,WAAW,QAAQ,IAAI,OAAO;GAC/C,MAAM,SAAS,WAAW,MAAM,IAAI,OAAO;GAC3C,OAAO,SAAS,WAAW,OAAO,IAAI,OAAO;GAC7C,QAAQ,EAAE,MAAM,SAAS;GACzB,IAAI,EAAE,MAAM,SAAS;GACrB,UAAU,EAAE,MAAM,SAAS;GAC3B,SAAS,EAAE,MAAM,SAAS;GAC1B,MAAM,EAAE,MAAM,SAAS;GACvB,OAAO,EAAE,MAAM,SAAS;GACxB,QAAQ;EACV;EACA,sBAAsB;CACxB;AACF;AAEA,SAAgB,QAAgC;CAC9C,OAAO;EACL,MAAM;EACN,aAAa;EACb,OAAO,OAAiB,KAA+B;GACrD,OAAO,WAAW,OAAO,GAAG;EAC9B;EACA,iBACE,OACA,QACA,KACW;GACX,OAAO;IACL,GAAG,WAAW,OAAO,GAAG;IACxB,QAAQ,MAAM,UAAA;IACd,QAAQ,oBAAoB,QAAQ,aAAa,IAAI,IAAI,CAAC;GAC5D;EACF;EACA,OAAO,YAAgC,KAAgC;GACrE,OAAO,WAAW,YAAY,GAAG;EACnC;EACA,iBACE,YACA,KACY;GACZ,OAAO;IACL,GAAG,WAAW,YAAY,GAAG;IAC7B,UAAU;KAAC;KAAU;KAAQ;KAAS;KAAM;IAAQ;GACtD;EACF;CACF;AACF"}
@@ -1,2 +1,2 @@
1
- import { n as problemDetails, t as PROBLEM_DETAILS_CONTENT_TYPE } from "../problem-details-DeUg_NjG.js";
1
+ import { n as problemDetails, t as PROBLEM_DETAILS_CONTENT_TYPE } from "../problem-details-G3eerc0Q.js";
2
2
  export { PROBLEM_DETAILS_CONTENT_TYPE, problemDetails };
@@ -1,4 +1,5 @@
1
- import { t as constant } from "../schema-helpers-bwCFve8i.js";
1
+ import "../constants-rUzQOaX_.js";
2
+ import { t as constant } from "../schema-helpers-B4HL9TmU.js";
2
3
  //#region src/formats/stripe/index.ts
3
4
  /** Stripe answers errors as plain JSON. */
4
5
  const STRIPE_CONTENT_TYPE = "application/json";
@@ -1 +1 @@
1
- {"version":3,"file":"stripe.js","names":[],"sources":["../../src/formats/stripe/index.ts"],"sourcesContent":["/**\n * Stripe-style error format (SPEC 7.7): `{ error: { code, doc_url, message,\n * param, request_log_url, type } }`, the members of Stripe's `api_errors`\n * object that a general API can fill, in the alphabetical order Stripe\n * serializes them. Stripe's shape is a vendor convention, not a\n * specification; it ships in-tree because it is the most copied error\n * envelope in commercial APIs (ADR 0014).\n * @ref https://docs.stripe.com/api/errors\n * @ref https://github.com/stripe/openapi/blob/master/openapi/spec3.json (components.schemas.api_errors)\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { constant } from '../schema-helpers';\n\n/**\n * The closed `type` enumeration of `api_errors`. Stripe's SDKs classify\n * authentication, permission, and rate limit errors by HTTP status, not by\n * `type`; on the wire those carry `invalid_request_error`.\n * @ref https://docs.stripe.com/api/errors (type)\n * @ref https://github.com/stripe/stripe-node/blob/master/src/Error.ts (generateV1Error)\n */\nexport type StripeErrorType =\n | 'api_error'\n | 'card_error'\n | 'idempotency_error'\n | 'invalid_request_error';\n\nexport interface StripeOptions {\n /** Base for `doc_url`; overrides the instance `docsBaseUrl`. */\n readonly docUrlBaseUrl?: string | undefined;\n /**\n * `type` per catalog code, for entries the status-based default gets wrong\n * (an `idempotency_error` on a 400, a `card_error` on a 400).\n */\n readonly types?: Readonly<Record<string, StripeErrorType>> | undefined;\n /**\n * Produces `request_log_url`, \"a URL to the request log entry in your\n * dashboard\". The one member of Stripe's shape that can carry the error id\n * to the client in the body; the `X-Error-Id` header carries it regardless.\n */\n readonly requestLogUrl?:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n}\n\n/**\n * The `error` member. Members Stripe reserves for card payments\n * (`charge`, `decline_code`, `payment_intent`, ...) are never emitted.\n * @ref https://docs.stripe.com/api/errors\n */\nexport interface StripeErrorObject {\n /** The catalog code in lower snake case, Stripe's spelling. */\n readonly code: string;\n readonly doc_url?: string;\n readonly message: string;\n /** The offending parameter in Stripe's bracket notation, validation only. */\n readonly param?: string;\n readonly request_log_url?: string;\n readonly type: StripeErrorType;\n}\n\nexport interface StripeBody {\n readonly error: StripeErrorObject;\n}\n\n/** Stripe answers errors as plain JSON. */\nexport const STRIPE_CONTENT_TYPE = 'application/json';\n\nconst PAYMENT_REQUIRED = 402;\nconst CLIENT_ERROR = 400;\nconst SERVER_ERROR = 500;\n\ninterface Resolved {\n readonly docUrlBaseUrl: string | undefined;\n readonly types: Readonly<Record<string, StripeErrorType>> | undefined;\n readonly requestLogUrl:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n}\n\n/**\n * Stripe's own classification, as implemented by its SDKs: 402 is a card\n * error, every other 4xx an invalid request, everything else an API error.\n * An unauthenticated request to api.stripe.com answers 401 with\n * `\"type\": \"invalid_request_error\"`.\n * @ref https://github.com/stripe/stripe-node/blob/master/src/Error.ts (generateV1Error)\n * @ref https://docs.stripe.com/api/errors (HTTP status code summary)\n */\nfunction typeFromStatus(status: number): StripeErrorType {\n if (status === PAYMENT_REQUIRED) {\n return 'card_error';\n }\n if (status >= CLIENT_ERROR && status < SERVER_ERROR) {\n return 'invalid_request_error';\n }\n return 'api_error';\n}\n\nfunction resolveType(\n code: string,\n status: number,\n types: Readonly<Record<string, StripeErrorType>> | undefined,\n): StripeErrorType {\n return types?.[code] ?? typeFromStatus(status);\n}\n\n/**\n * Stripe requests are form-encoded with OpenAPI `deepObject` style, so a\n * nested parameter is spelled `items[0][sku]` and `param` echoes that name.\n * @ref https://github.com/stripe/openapi/blob/master/openapi/spec3.json (requestBody encoding: style deepObject)\n * @ref https://spec.openapis.org/oas/v3.0.3#style-values\n */\nfunction paramName(path: ReadonlyArray<string | number>): string | undefined {\n const [first, ...rest] = path;\n if (first === undefined) {\n return undefined;\n }\n let out = String(first);\n for (const segment of rest) {\n out += `[${String(segment)}]`;\n }\n return out;\n}\n\n/**\n * Members in alphabetical order, as Stripe serializes them (SPEC 7.7.1).\n * Stripe reports one problem per response, so a validation error renders its\n * first issue and drops the rest.\n */\nfunction renderBody(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n validation: boolean,\n issue?: ValidationIssue,\n): StripeBody {\n const base = options.docUrlBaseUrl ?? ctx.docsBaseUrl;\n const docUrl =\n error.type ?? (base === undefined ? undefined : `${base}/${error.code}`);\n const param = issue === undefined ? undefined : paramName(issue.path);\n const logUrl = options.requestLogUrl?.(error, ctx);\n return {\n error: {\n code: error.code.toLowerCase(),\n ...(docUrl === undefined ? {} : { doc_url: docUrl }),\n message:\n issue?.message ??\n error.detail ??\n (validation ? VALIDATION_DETAIL : error.title),\n ...(param === undefined ? {} : { param }),\n ...(logUrl === undefined ? {} : { request_log_url: logUrl }),\n type: resolveType(error.code, error.status, options.types),\n },\n };\n}\n\nfunction bodySchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: Resolved,\n validation: boolean,\n): JsonSchema {\n const properties: Record<string, JsonSchema> = {\n code: constant(definition.code.toLowerCase(), ctx.dialect),\n doc_url: { type: 'string', format: 'uri-reference' },\n message: { type: 'string' },\n };\n if (validation) {\n properties['param'] = { type: 'string' };\n }\n if (options.requestLogUrl !== undefined) {\n properties['request_log_url'] = { type: 'string', format: 'uri-reference' };\n }\n properties['type'] = constant(\n resolveType(definition.code, definition.status, options.types),\n ctx.dialect,\n );\n return {\n type: 'object',\n required: ['error'],\n properties: {\n error: {\n type: 'object',\n required: ['code', 'message', 'type'],\n properties,\n additionalProperties: false,\n },\n },\n additionalProperties: false,\n };\n}\n\n/**\n * Stripe-style errors (SPEC 7.7).\n * @ref https://docs.stripe.com/api/errors\n */\nexport function stripe(options: StripeOptions = {}): ErrorFormat<StripeBody> {\n const resolved: Resolved = {\n docUrlBaseUrl: options.docUrlBaseUrl,\n types: options.types,\n requestLogUrl: options.requestLogUrl,\n };\n return {\n name: 'stripe',\n contentType: STRIPE_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): StripeBody {\n return renderBody(error, ctx, resolved, false);\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): StripeBody {\n return renderBody(error, ctx, resolved, true, issues[0]);\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return bodySchema(definition, ctx, resolved, false);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return bodySchema(definition, ctx, resolved, true);\n },\n };\n}\n"],"mappings":";;;AAwEA,MAAa,sBAAsB;AAEnC,MAAM,mBAAmB;AACzB,MAAM,eAAe;AACrB,MAAM,eAAe;;;;;;;;;AAkBrB,SAAS,eAAe,QAAiC;CACvD,IAAI,WAAW,kBACb,OAAO;CAET,IAAI,UAAU,gBAAgB,SAAS,cACrC,OAAO;CAET,OAAO;AACT;AAEA,SAAS,YACP,MACA,QACA,OACiB;CACjB,OAAO,QAAQ,SAAS,eAAe,MAAM;AAC/C;;;;;;;AAQA,SAAS,UAAU,MAA0D;CAC3E,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,MAAM,OAAO,KAAK;CACtB,KAAK,MAAM,WAAW,MACpB,OAAO,IAAI,OAAO,OAAO,EAAE;CAE7B,OAAO;AACT;;;;;;AAOA,SAAS,WACP,OACA,KACA,SACA,YACA,OACY;CACZ,MAAM,OAAO,QAAQ,iBAAiB,IAAI;CAC1C,MAAM,SACJ,MAAM,SAAS,SAAS,KAAA,IAAY,KAAA,IAAY,GAAG,KAAK,GAAG,MAAM;CACnE,MAAM,QAAQ,UAAU,KAAA,IAAY,KAAA,IAAY,UAAU,MAAM,IAAI;CACpE,MAAM,SAAS,QAAQ,gBAAgB,OAAO,GAAG;CACjD,OAAO,EACL,OAAO;EACL,MAAM,MAAM,KAAK,YAAY;EAC7B,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,OAAO;EAClD,SACE,OAAO,WACP,MAAM,WACL,aAAA,8BAAiC,MAAM;EAC1C,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,iBAAiB,OAAO;EAC1D,MAAM,YAAY,MAAM,MAAM,MAAM,QAAQ,QAAQ,KAAK;CAC3D,EACF;AACF;AAEA,SAAS,WACP,YACA,KACA,SACA,YACY;CACZ,MAAM,aAAyC;EAC7C,MAAM,SAAS,WAAW,KAAK,YAAY,GAAG,IAAI,OAAO;EACzD,SAAS;GAAE,MAAM;GAAU,QAAQ;EAAgB;EACnD,SAAS,EAAE,MAAM,SAAS;CAC5B;CACA,IAAI,YACF,WAAW,WAAW,EAAE,MAAM,SAAS;CAEzC,IAAI,QAAQ,kBAAkB,KAAA,GAC5B,WAAW,qBAAqB;EAAE,MAAM;EAAU,QAAQ;CAAgB;CAE5E,WAAW,UAAU,SACnB,YAAY,WAAW,MAAM,WAAW,QAAQ,QAAQ,KAAK,GAC7D,IAAI,OACN;CACA,OAAO;EACL,MAAM;EACN,UAAU,CAAC,OAAO;EAClB,YAAY,EACV,OAAO;GACL,MAAM;GACN,UAAU;IAAC;IAAQ;IAAW;GAAM;GACpC;GACA,sBAAsB;EACxB,EACF;EACA,sBAAsB;CACxB;AACF;;;;;AAMA,SAAgB,OAAO,UAAyB,CAAC,GAA4B;CAC3E,MAAM,WAAqB;EACzB,eAAe,QAAQ;EACvB,OAAO,QAAQ;EACf,eAAe,QAAQ;CACzB;CACA,OAAO;EACL,MAAM;EACN,aAAa;EACb,OAAO,OAAiB,KAAgC;GACtD,OAAO,WAAW,OAAO,KAAK,UAAU,KAAK;EAC/C;EACA,iBACE,OACA,QACA,KACY;GACZ,OAAO,WAAW,OAAO,KAAK,UAAU,MAAM,OAAO,EAAE;EACzD;EACA,OAAO,YAAgC,KAAgC;GACrE,OAAO,WAAW,YAAY,KAAK,UAAU,KAAK;EACpD;EACA,iBACE,YACA,KACY;GACZ,OAAO,WAAW,YAAY,KAAK,UAAU,IAAI;EACnD;CACF;AACF"}
1
+ {"version":3,"file":"stripe.js","names":[],"sources":["../../src/formats/stripe/index.ts"],"sourcesContent":["/**\n * Stripe-style error format (SPEC 7.7): `{ error: { code, doc_url, message,\n * param, request_log_url, type } }`, the members of Stripe's `api_errors`\n * object that a general API can fill, in the alphabetical order Stripe\n * serializes them. Stripe's shape is a vendor convention, not a\n * specification; it ships in-tree because it is the most copied error\n * envelope in commercial APIs (ADR 0014).\n * @ref https://docs.stripe.com/api/errors\n * @ref https://github.com/stripe/openapi/blob/master/openapi/spec3.json (components.schemas.api_errors)\n * @packageDocumentation\n */\nimport type { BanError } from '../../core/ban-error';\nimport type { ResolvedDefinition } from '../../core/definition';\nimport type { ValidationIssue } from '../../validation/issue';\nimport type { JsonSchema, RenderContext, SchemaContext } from '../context';\nimport type { ErrorFormat } from '../types';\n\nimport { VALIDATION_DETAIL } from '../../internal/constants';\nimport { constant } from '../schema-helpers';\n\n/**\n * The closed `type` enumeration of `api_errors`. Stripe's SDKs classify\n * authentication, permission, and rate limit errors by HTTP status, not by\n * `type`; on the wire those carry `invalid_request_error`.\n * @ref https://docs.stripe.com/api/errors (type)\n * @ref https://github.com/stripe/stripe-node/blob/master/src/Error.ts (generateV1Error)\n */\nexport type StripeErrorType =\n | 'api_error'\n | 'card_error'\n | 'idempotency_error'\n | 'invalid_request_error';\n\nexport interface StripeOptions {\n /** Base for `doc_url`; overrides the instance `docsBaseUrl`. */\n readonly docUrlBaseUrl?: string | undefined;\n /**\n * `type` per catalog code, for entries the status-based default gets wrong\n * (an `idempotency_error` on a 400, a `card_error` on a 400).\n */\n readonly types?: Readonly<Record<string, StripeErrorType>> | undefined;\n /**\n * Produces `request_log_url`, \"a URL to the request log entry in your\n * dashboard\". The one member of Stripe's shape that can carry the error id\n * to the client in the body; the `X-Error-Id` header carries it regardless.\n */\n readonly requestLogUrl?:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n}\n\n/**\n * The `error` member. Members Stripe reserves for card payments\n * (`charge`, `decline_code`, `payment_intent`, ...) are never emitted.\n * @ref https://docs.stripe.com/api/errors\n */\nexport interface StripeErrorObject {\n /** The catalog code in lower snake case, Stripe's spelling. */\n readonly code: string;\n readonly doc_url?: string;\n readonly message: string;\n /** The offending parameter in Stripe's bracket notation, validation only. */\n readonly param?: string;\n readonly request_log_url?: string;\n readonly type: StripeErrorType;\n}\n\nexport interface StripeBody {\n readonly error: StripeErrorObject;\n}\n\n/** Stripe answers errors as plain JSON. */\nexport const STRIPE_CONTENT_TYPE = 'application/json';\n\nconst PAYMENT_REQUIRED = 402;\nconst CLIENT_ERROR = 400;\nconst SERVER_ERROR = 500;\n\ninterface Resolved {\n readonly docUrlBaseUrl: string | undefined;\n readonly types: Readonly<Record<string, StripeErrorType>> | undefined;\n readonly requestLogUrl:\n | ((error: BanError, ctx: RenderContext) => string | undefined)\n | undefined;\n}\n\n/**\n * Stripe's own classification, as implemented by its SDKs: 402 is a card\n * error, every other 4xx an invalid request, everything else an API error.\n * An unauthenticated request to api.stripe.com answers 401 with\n * `\"type\": \"invalid_request_error\"`.\n * @ref https://github.com/stripe/stripe-node/blob/master/src/Error.ts (generateV1Error)\n * @ref https://docs.stripe.com/api/errors (HTTP status code summary)\n */\nfunction typeFromStatus(status: number): StripeErrorType {\n if (status === PAYMENT_REQUIRED) {\n return 'card_error';\n }\n if (status >= CLIENT_ERROR && status < SERVER_ERROR) {\n return 'invalid_request_error';\n }\n return 'api_error';\n}\n\nfunction resolveType(\n code: string,\n status: number,\n types: Readonly<Record<string, StripeErrorType>> | undefined,\n): StripeErrorType {\n return types?.[code] ?? typeFromStatus(status);\n}\n\n/**\n * Stripe requests are form-encoded with OpenAPI `deepObject` style, so a\n * nested parameter is spelled `items[0][sku]` and `param` echoes that name.\n * @ref https://github.com/stripe/openapi/blob/master/openapi/spec3.json (requestBody encoding: style deepObject)\n * @ref https://spec.openapis.org/oas/v3.0.3#style-values\n */\nfunction paramName(path: ReadonlyArray<string | number>): string | undefined {\n const [first, ...rest] = path;\n if (first === undefined) {\n return undefined;\n }\n let out = String(first);\n for (const segment of rest) {\n out += `[${String(segment)}]`;\n }\n return out;\n}\n\n/**\n * Members in alphabetical order, as Stripe serializes them (SPEC 7.7.1).\n * Stripe reports one problem per response, so a validation error renders its\n * first issue and drops the rest.\n */\nfunction renderBody(\n error: BanError,\n ctx: RenderContext,\n options: Resolved,\n validation: boolean,\n issue?: ValidationIssue,\n): StripeBody {\n const base = options.docUrlBaseUrl ?? ctx.docsBaseUrl;\n const docUrl =\n error.type ?? (base === undefined ? undefined : `${base}/${error.code}`);\n const param = issue === undefined ? undefined : paramName(issue.path);\n const logUrl = options.requestLogUrl?.(error, ctx);\n return {\n error: {\n code: error.code.toLowerCase(),\n ...(docUrl === undefined ? {} : { doc_url: docUrl }),\n message:\n issue?.message ??\n error.detail ??\n (validation ? VALIDATION_DETAIL : error.title),\n ...(param === undefined ? {} : { param }),\n ...(logUrl === undefined ? {} : { request_log_url: logUrl }),\n type: resolveType(error.code, error.status, options.types),\n },\n };\n}\n\nfunction bodySchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n options: Resolved,\n validation: boolean,\n): JsonSchema {\n const properties: Record<string, JsonSchema> = {\n code: constant(definition.code.toLowerCase(), ctx.dialect),\n doc_url: { type: 'string', format: 'uri-reference' },\n message: { type: 'string' },\n };\n if (validation) {\n properties['param'] = { type: 'string' };\n }\n if (options.requestLogUrl !== undefined) {\n properties['request_log_url'] = { type: 'string', format: 'uri-reference' };\n }\n properties['type'] = constant(\n resolveType(definition.code, definition.status, options.types),\n ctx.dialect,\n );\n return {\n type: 'object',\n required: ['error'],\n properties: {\n error: {\n type: 'object',\n required: ['code', 'message', 'type'],\n properties,\n additionalProperties: false,\n },\n },\n additionalProperties: false,\n };\n}\n\n/**\n * Stripe-style errors (SPEC 7.7).\n * @ref https://docs.stripe.com/api/errors\n */\nexport function stripe(options: StripeOptions = {}): ErrorFormat<StripeBody> {\n const resolved: Resolved = {\n docUrlBaseUrl: options.docUrlBaseUrl,\n types: options.types,\n requestLogUrl: options.requestLogUrl,\n };\n return {\n name: 'stripe',\n contentType: STRIPE_CONTENT_TYPE,\n render(error: BanError, ctx: RenderContext): StripeBody {\n return renderBody(error, ctx, resolved, false);\n },\n renderValidation(\n error: BanError,\n issues: ReadonlyArray<ValidationIssue>,\n ctx: RenderContext,\n ): StripeBody {\n return renderBody(error, ctx, resolved, true, issues[0]);\n },\n schema(definition: ResolvedDefinition, ctx: SchemaContext): JsonSchema {\n return bodySchema(definition, ctx, resolved, false);\n },\n validationSchema(\n definition: ResolvedDefinition,\n ctx: SchemaContext,\n ): JsonSchema {\n return bodySchema(definition, ctx, resolved, true);\n },\n };\n}\n"],"mappings":";;;;AAwEA,MAAa,sBAAsB;AAEnC,MAAM,mBAAmB;AACzB,MAAM,eAAe;AACrB,MAAM,eAAe;;;;;;;;;AAkBrB,SAAS,eAAe,QAAiC;CACvD,IAAI,WAAW,kBACb,OAAO;CAET,IAAI,UAAU,gBAAgB,SAAS,cACrC,OAAO;CAET,OAAO;AACT;AAEA,SAAS,YACP,MACA,QACA,OACiB;CACjB,OAAO,QAAQ,SAAS,eAAe,MAAM;AAC/C;;;;;;;AAQA,SAAS,UAAU,MAA0D;CAC3E,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,MAAM,OAAO,KAAK;CACtB,KAAK,MAAM,WAAW,MACpB,OAAO,IAAI,OAAO,OAAO,EAAE;CAE7B,OAAO;AACT;;;;;;AAOA,SAAS,WACP,OACA,KACA,SACA,YACA,OACY;CACZ,MAAM,OAAO,QAAQ,iBAAiB,IAAI;CAC1C,MAAM,SACJ,MAAM,SAAS,SAAS,KAAA,IAAY,KAAA,IAAY,GAAG,KAAK,GAAG,MAAM;CACnE,MAAM,QAAQ,UAAU,KAAA,IAAY,KAAA,IAAY,UAAU,MAAM,IAAI;CACpE,MAAM,SAAS,QAAQ,gBAAgB,OAAO,GAAG;CACjD,OAAO,EACL,OAAO;EACL,MAAM,MAAM,KAAK,YAAY;EAC7B,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,OAAO;EAClD,SACE,OAAO,WACP,MAAM,WACL,aAAA,8BAAiC,MAAM;EAC1C,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,iBAAiB,OAAO;EAC1D,MAAM,YAAY,MAAM,MAAM,MAAM,QAAQ,QAAQ,KAAK;CAC3D,EACF;AACF;AAEA,SAAS,WACP,YACA,KACA,SACA,YACY;CACZ,MAAM,aAAyC;EAC7C,MAAM,SAAS,WAAW,KAAK,YAAY,GAAG,IAAI,OAAO;EACzD,SAAS;GAAE,MAAM;GAAU,QAAQ;EAAgB;EACnD,SAAS,EAAE,MAAM,SAAS;CAC5B;CACA,IAAI,YACF,WAAW,WAAW,EAAE,MAAM,SAAS;CAEzC,IAAI,QAAQ,kBAAkB,KAAA,GAC5B,WAAW,qBAAqB;EAAE,MAAM;EAAU,QAAQ;CAAgB;CAE5E,WAAW,UAAU,SACnB,YAAY,WAAW,MAAM,WAAW,QAAQ,QAAQ,KAAK,GAC7D,IAAI,OACN;CACA,OAAO;EACL,MAAM;EACN,UAAU,CAAC,OAAO;EAClB,YAAY,EACV,OAAO;GACL,MAAM;GACN,UAAU;IAAC;IAAQ;IAAW;GAAM;GACpC;GACA,sBAAsB;EACxB,EACF;EACA,sBAAsB;CACxB;AACF;;;;;AAMA,SAAgB,OAAO,UAAyB,CAAC,GAA4B;CAC3E,MAAM,WAAqB;EACzB,eAAe,QAAQ;EACvB,OAAO,QAAQ;EACf,eAAe,QAAQ;CACzB;CACA,OAAO;EACL,MAAM;EACN,aAAa;EACb,OAAO,OAAiB,KAAgC;GACtD,OAAO,WAAW,OAAO,KAAK,UAAU,KAAK;EAC/C;EACA,iBACE,OACA,QACA,KACY;GACZ,OAAO,WAAW,OAAO,KAAK,UAAU,MAAM,OAAO,EAAE;EACzD;EACA,OAAO,YAAgC,KAAgC;GACrE,OAAO,WAAW,YAAY,KAAK,UAAU,KAAK;EACpD;EACA,iBACE,YACA,KACY;GACZ,OAAO,WAAW,YAAY,KAAK,UAAU,IAAI;EACnD;CACF;AACF"}
@@ -0,0 +1,76 @@
1
+ import { n as DEFAULT_CACHE_CONTROL } from "./constants-rUzQOaX_.js";
2
+ //#region src/handler/headers.ts
3
+ /**
4
+ * Header handling for `ban.onError()` (SPEC 6.9): the merge order, the
5
+ * construction-time checks on header options, and the last-resort headers
6
+ * of the fallback (SPEC 6.4).
7
+ * @packageDocumentation
8
+ */
9
+ const SET_COOKIE = "set-cookie";
10
+ const CACHE_CONTROL = "cache-control";
11
+ /**
12
+ * Header precedence (SPEC 6.9): `Cache-Control: no-store` as the floor, then
13
+ * options, then the error's, then ours. `Set-Cookie` is the one header whose
14
+ * values never combine: iteration yields each cookie separately, so `set()`
15
+ * would keep only the last one. Cookies are appended instead, from both
16
+ * sources.
17
+ * @ref https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
18
+ * @ref https://fetch.spec.whatwg.org/#dom-headers-getsetcookie
19
+ */
20
+ function mergeHeaders(base, rendered, errorIdHeader, id) {
21
+ const headers = new Headers(base);
22
+ if (!headers.has(CACHE_CONTROL)) headers.set(CACHE_CONTROL, DEFAULT_CACHE_CONTROL);
23
+ rendered.forEach((value, name) => {
24
+ if (name !== SET_COOKIE) headers.set(name, value);
25
+ });
26
+ for (const cookie of rendered.getSetCookie()) headers.append(SET_COOKIE, cookie);
27
+ if (errorIdHeader !== false) headers.set(errorIdHeader, id);
28
+ return headers;
29
+ }
30
+ /**
31
+ * `Headers` rejects an invalid field name or value with a `TypeError`
32
+ * (Fetch, "validate" in the `Headers` constructor and `set()`). Checked once
33
+ * at construction so a misconfigured `errorIdHeader`, `requestIdHeader`, or
34
+ * `headers` fails at startup: inside the handler the same `TypeError` would
35
+ * surface in the header merge both fallback tiers share (SPEC 6.4) and every
36
+ * response, not one, would be affected.
37
+ * @ref https://fetch.spec.whatwg.org/#dom-headers-set
38
+ * @ref https://fetch.spec.whatwg.org/#concept-headers-fill
39
+ */
40
+ function assertHeaderName(option, name) {
41
+ if (name === false) return;
42
+ try {
43
+ new Headers().set(name, "x");
44
+ } catch {
45
+ throw new TypeError(`${option} "${name}" is not a valid HTTP header name`);
46
+ }
47
+ }
48
+ function assertHeadersInit(init) {
49
+ try {
50
+ new Headers(init);
51
+ } catch (cause) {
52
+ throw new TypeError("headers holds an invalid header name or value", { cause });
53
+ }
54
+ }
55
+ /**
56
+ * Third tier of the fallback (SPEC 6.4): the merge itself failed, which
57
+ * only happens when `options.headers` changed or threw after construction,
58
+ * so the response carries only the members the handler owns. The error id
59
+ * header name was validated at construction, so `set()` cannot throw here.
60
+ */
61
+ function lastResortHeaders(base, errorIdHeader, id) {
62
+ try {
63
+ return mergeHeaders(base, new Headers({ "Content-Type": "application/json" }), errorIdHeader, id);
64
+ } catch {
65
+ const headers = new Headers({
66
+ "Content-Type": "application/json",
67
+ [CACHE_CONTROL]: DEFAULT_CACHE_CONTROL
68
+ });
69
+ if (errorIdHeader !== false) headers.set(errorIdHeader, id);
70
+ return headers;
71
+ }
72
+ }
73
+ //#endregion
74
+ export { mergeHeaders as i, assertHeadersInit as n, lastResortHeaders as r, assertHeaderName as t };
75
+
76
+ //# sourceMappingURL=headers-Bnn4uoV4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers-Bnn4uoV4.js","names":[],"sources":["../src/handler/headers.ts"],"sourcesContent":["/**\n * Header handling for `ban.onError()` (SPEC 6.9): the merge order, the\n * construction-time checks on header options, and the last-resort headers\n * of the fallback (SPEC 6.4).\n * @packageDocumentation\n */\nimport { DEFAULT_CACHE_CONTROL } from '../internal/constants';\n\nconst SET_COOKIE = 'set-cookie';\nconst CACHE_CONTROL = 'cache-control';\n\n/**\n * Header precedence (SPEC 6.9): `Cache-Control: no-store` as the floor, then\n * options, then the error's, then ours. `Set-Cookie` is the one header whose\n * values never combine: iteration yields each cookie separately, so `set()`\n * would keep only the last one. Cookies are appended instead, from both\n * sources.\n * @ref https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine\n * @ref https://fetch.spec.whatwg.org/#dom-headers-getsetcookie\n */\nexport function mergeHeaders(\n base: HeadersInit | undefined,\n rendered: Headers,\n errorIdHeader: string | false,\n id: string,\n): Headers {\n const headers = new Headers(base);\n if (!headers.has(CACHE_CONTROL)) {\n headers.set(CACHE_CONTROL, DEFAULT_CACHE_CONTROL);\n }\n rendered.forEach((value, name) => {\n if (name !== SET_COOKIE) {\n headers.set(name, value);\n }\n });\n for (const cookie of rendered.getSetCookie()) {\n headers.append(SET_COOKIE, cookie);\n }\n if (errorIdHeader !== false) {\n headers.set(errorIdHeader, id);\n }\n return headers;\n}\n\n/**\n * `Headers` rejects an invalid field name or value with a `TypeError`\n * (Fetch, \"validate\" in the `Headers` constructor and `set()`). Checked once\n * at construction so a misconfigured `errorIdHeader`, `requestIdHeader`, or\n * `headers` fails at startup: inside the handler the same `TypeError` would\n * surface in the header merge both fallback tiers share (SPEC 6.4) and every\n * response, not one, would be affected.\n * @ref https://fetch.spec.whatwg.org/#dom-headers-set\n * @ref https://fetch.spec.whatwg.org/#concept-headers-fill\n */\nexport function assertHeaderName(option: string, name: string | false): void {\n if (name === false) {\n return;\n }\n try {\n new Headers().set(name, 'x');\n } catch {\n throw new TypeError(`${option} \"${name}\" is not a valid HTTP header name`);\n }\n}\n\nexport function assertHeadersInit(init: HeadersInit | undefined): void {\n try {\n void new Headers(init);\n } catch (cause) {\n throw new TypeError('headers holds an invalid header name or value', {\n cause,\n });\n }\n}\n\n/**\n * Third tier of the fallback (SPEC 6.4): the merge itself failed, which\n * only happens when `options.headers` changed or threw after construction,\n * so the response carries only the members the handler owns. The error id\n * header name was validated at construction, so `set()` cannot throw here.\n */\nexport function lastResortHeaders(\n base: HeadersInit | undefined,\n errorIdHeader: string | false,\n id: string,\n): Headers {\n try {\n return mergeHeaders(\n base,\n new Headers({ 'Content-Type': 'application/json' }),\n errorIdHeader,\n id,\n );\n } catch {\n const headers = new Headers({\n 'Content-Type': 'application/json',\n [CACHE_CONTROL]: DEFAULT_CACHE_CONTROL,\n });\n if (errorIdHeader !== false) {\n headers.set(errorIdHeader, id);\n }\n return headers;\n }\n}\n"],"mappings":";;;;;;;;AAQA,MAAM,aAAa;AACnB,MAAM,gBAAgB;;;;;;;;;;AAWtB,SAAgB,aACd,MACA,UACA,eACA,IACS;CACT,MAAM,UAAU,IAAI,QAAQ,IAAI;CAChC,IAAI,CAAC,QAAQ,IAAI,aAAa,GAC5B,QAAQ,IAAI,eAAe,qBAAqB;CAElD,SAAS,SAAS,OAAO,SAAS;EAChC,IAAI,SAAS,YACX,QAAQ,IAAI,MAAM,KAAK;CAE3B,CAAC;CACD,KAAK,MAAM,UAAU,SAAS,aAAa,GACzC,QAAQ,OAAO,YAAY,MAAM;CAEnC,IAAI,kBAAkB,OACpB,QAAQ,IAAI,eAAe,EAAE;CAE/B,OAAO;AACT;;;;;;;;;;;AAYA,SAAgB,iBAAiB,QAAgB,MAA4B;CAC3E,IAAI,SAAS,OACX;CAEF,IAAI;EACF,IAAI,QAAQ,CAAC,CAAC,IAAI,MAAM,GAAG;CAC7B,QAAQ;EACN,MAAM,IAAI,UAAU,GAAG,OAAO,IAAI,KAAK,kCAAkC;CAC3E;AACF;AAEA,SAAgB,kBAAkB,MAAqC;CACrE,IAAI;EACF,IAAS,QAAQ,IAAI;CACvB,SAAS,OAAO;EACd,MAAM,IAAI,UAAU,iDAAiD,EACnE,MACF,CAAC;CACH;AACF;;;;;;;AAQA,SAAgB,kBACd,MACA,eACA,IACS;CACT,IAAI;EACF,OAAO,aACL,MACA,IAAI,QAAQ,EAAE,gBAAgB,mBAAmB,CAAC,GAClD,eACA,EACF;CACF,QAAQ;EACN,MAAM,UAAU,IAAI,QAAQ;GAC1B,gBAAgB;IACf,gBAAgB;EACnB,CAAC;EACD,IAAI,kBAAkB,OACpB,QAAQ,IAAI,eAAe,EAAE;EAE/B,OAAO;CACT;AACF"}