@vercel/error
Advanced tools
| //#region src/format/index.ts | ||
| /** | ||
| * Render a Unicode tree frame with auto-detected formatting. | ||
| * | ||
| * Terminal control sequences in `header` and `sections` are stripped | ||
| * (see {@link sanitize}). | ||
| * | ||
| * @param header - The main error message line | ||
| * @param sections - Detail lines (falsy values are filtered out) | ||
| */ | ||
| function frame(header, sections) { | ||
| const { tree, color } = detectFormat(); | ||
| return renderFrame({ | ||
| color, | ||
| header: sanitize(header), | ||
| sections: sections?.map((s) => typeof s === "string" ? sanitize(s) : s), | ||
| tree | ||
| }); | ||
| } | ||
| /** | ||
| * Format a string as a hint. Nil-safe. Returns `undefined` if falsy. | ||
| * | ||
| * Terminal control sequences in `text` are stripped (see {@link sanitize}). | ||
| */ | ||
| function hint(text) { | ||
| if (!text) return; | ||
| return `hint: ${sanitize(text)}`; | ||
| } | ||
| /** | ||
| * Format a string as a fix suggestion. Nil-safe. Returns `undefined` if falsy. | ||
| * | ||
| * Terminal control sequences in `text` are stripped (see {@link sanitize}). | ||
| */ | ||
| function fix(text) { | ||
| if (!text) return; | ||
| return `fix: ${sanitize(text)}`; | ||
| } | ||
| /** | ||
| * Format a URL as a link. Nil-safe. Returns `undefined` if falsy. | ||
| * | ||
| * Terminal control sequences in `url` are stripped (see {@link sanitize}). | ||
| */ | ||
| function link(url) { | ||
| if (!url) return; | ||
| return `read more: ${sanitize(url)}`; | ||
| } | ||
| /** | ||
| * Detect formatting capabilities of the current environment. | ||
| * | ||
| * - `tree`: use Unicode box-drawing characters (├──, ╰──) | ||
| * - `color`: use ANSI escape codes (red, green, bold, underline) | ||
| * | ||
| * Detection: | ||
| * 1. Non-Node (no `process`) → plain (no tree, no color) | ||
| * 2. `NO_COLOR` env var → tree only, no color | ||
| * 3. `FORCE_COLOR` env var → tree + color | ||
| * 4. TTY → tree + color | ||
| * 5. Browser → plain | ||
| * 6. Fallback (piped, CI) → plain | ||
| */ | ||
| function detectFormat() { | ||
| try { | ||
| if (typeof process === "undefined") return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| if (process.env?.["NO_COLOR"] !== void 0) return { | ||
| color: false, | ||
| tree: true | ||
| }; | ||
| if (process.env?.["FORCE_COLOR"] !== void 0) return { | ||
| color: true, | ||
| tree: true | ||
| }; | ||
| if (process.stdout && "isTTY" in process.stdout && process.stdout.isTTY) return { | ||
| color: true, | ||
| tree: true | ||
| }; | ||
| } catch { | ||
| return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| } | ||
| if (typeof window !== "undefined") return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| } | ||
| /** | ||
| * Auto-format an error based on environment detection. | ||
| * Used by `VercelError.toString()` for zero-config output. | ||
| */ | ||
| function formatAuto(error) { | ||
| const { tree, color } = detectFormat(); | ||
| return renderFrame({ | ||
| color, | ||
| header: buildHeader(error, color), | ||
| sections: [ | ||
| error.reason !== void 0 ? sanitize(error.reason) : void 0, | ||
| hint(error.hint), | ||
| fix(error.fix), | ||
| link(error.link) | ||
| ], | ||
| tree | ||
| }); | ||
| } | ||
| /** | ||
| * Matches complete ANSI escape sequences introduced by `ESC` (0x1b): CSI | ||
| * (`ESC [ … final`), OSC (`ESC ] … BEL/ST`, e.g. OSC 8 hyperlinks and OSC 52 | ||
| * clipboard), and other two/three-byte escapes. Removing the whole sequence, | ||
| * rather than only the `ESC` byte, keeps the visible text clean. | ||
| */ | ||
| const ANSI_ESCAPE = /\x1b(?:\[[0-?]*[ -/]*[@-~]|\][\s\S]*?(?:\x07|\x1b\\)|[@-Z\\-_])/g; | ||
| /** | ||
| * Matches standalone terminal control characters left after ANSI sequences are | ||
| * removed: C0 controls (except `\t`, `\n`, `\r`), the C1 range, and `DEL`. | ||
| */ | ||
| const CONTROL_CHARS = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/g; | ||
| /** | ||
| * Strip terminal control sequences from caller-controlled text before it is | ||
| * rendered to a terminal. Error fields can originate from an untrusted upstream | ||
| * (e.g. an HTTP error body parsed by `parseErrorResponse`); without this a | ||
| * malicious upstream could inject escape sequences that rewrite the screen, | ||
| * forge log lines, or abuse terminal features (OSC 8 links, OSC 52 clipboard). | ||
| * Full ANSI sequences are removed first, then any leftover control bytes. | ||
| * Preserves `\t`, `\n`, `\r`. | ||
| */ | ||
| function sanitize(text) { | ||
| return text.replace(ANSI_ESCAPE, "").replace(CONTROL_CHARS, ""); | ||
| } | ||
| const ANSI = { | ||
| bold: "\x1B[1m", | ||
| dim: "\x1B[2m", | ||
| green: "\x1B[32m", | ||
| red: "\x1B[31m", | ||
| reset: "\x1B[0m", | ||
| resetBold: "\x1B[22m", | ||
| underline: "\x1B[4m", | ||
| yellow: "\x1B[33m" | ||
| }; | ||
| const BOX = { | ||
| corner: "╰──", | ||
| cornerArrow: "╰─▸", | ||
| pipe: "│", | ||
| tee: "├──", | ||
| teeArrow: "├─▸" | ||
| }; | ||
| const ACTIONABLE_PREFIXES = [ | ||
| "hint: ", | ||
| "fix: ", | ||
| "read more: " | ||
| ]; | ||
| /** | ||
| * Build the error header line. | ||
| * | ||
| * With qualifier: `error: VercelError [scope:code] message` | ||
| * Without: `error: VercelError: message` | ||
| * Stripped message: `error: VercelError [scope:code]` (qualifier only) | ||
| * No message at all: `error: VercelError` | ||
| * ANSI: `error:` red+bold, name red, `[qualifier]` red, message red+bold | ||
| * | ||
| * When `message` is empty, such as after production stripping, the qualifier | ||
| * stands in for it so the error still identifies itself by `scope` and `code`. | ||
| */ | ||
| function buildHeader(error, color) { | ||
| const parts = { | ||
| name: sanitize(error.name), | ||
| message: sanitize(error.message), | ||
| qualifier: [error.scope, error.code].filter((part) => Boolean(part)).map(sanitize).join(":") | ||
| }; | ||
| return color ? buildColorHeader(parts) : buildPlainHeader(parts); | ||
| } | ||
| function buildPlainHeader({ name, qualifier, message }) { | ||
| if (qualifier) return message ? `error: ${name} [${qualifier}] ${message}` : `error: ${name} [${qualifier}]`; | ||
| return message ? `error: ${name}: ${message}` : `error: ${name}`; | ||
| } | ||
| function buildColorHeader({ name, qualifier, message }) { | ||
| const label = `${ANSI.red}${ANSI.bold}error:${ANSI.resetBold}`; | ||
| if (qualifier) { | ||
| const head = `${label} ${ANSI.red}${name} [${qualifier}]`; | ||
| return message ? `${head} ${ANSI.bold}${message}${ANSI.reset}` : `${head}${ANSI.reset}`; | ||
| } | ||
| return message ? `${label} ${ANSI.red}${name}: ${ANSI.bold}${message}${ANSI.reset}` : `${label} ${ANSI.red}${name}${ANSI.reset}`; | ||
| } | ||
| function filterSections(sections) { | ||
| const items = sections?.filter((s) => typeof s === "string" && s.length > 0); | ||
| return items && items.length > 0 ? items : void 0; | ||
| } | ||
| function colorizeLine(line) { | ||
| if (line.startsWith("hint: ")) return `${ANSI.yellow}${ANSI.bold}hint:${ANSI.reset} ${line.slice(6)}`; | ||
| if (line.startsWith("fix: ")) return `${ANSI.green}${ANSI.bold}fix:${ANSI.reset} ${line.slice(5)}`; | ||
| if (line.startsWith("read more: ")) return `${ANSI.bold}read more:${ANSI.reset} ${ANSI.underline}${line.slice(11)}${ANSI.reset}`; | ||
| return line; | ||
| } | ||
| function isActionable(line) { | ||
| return ACTIONABLE_PREFIXES.some((prefix) => line.startsWith(prefix)); | ||
| } | ||
| /** | ||
| * Render the final framed output. Inputs must already be {@link sanitize}d: | ||
| * this stage applies the library's own ANSI styling (`colorizeLine`, | ||
| * connectors), so it cannot strip control characters without destroying that | ||
| * styling. Callers (`frame`, `formatAuto`) own sanitization of untrusted text. | ||
| */ | ||
| function renderFrame({ header, sections, tree, color }) { | ||
| const items = filterSections(sections); | ||
| if (!items) return header; | ||
| if (!tree) return [header, ...items.map((item) => ` ${item}`)].join("\n"); | ||
| const isLast = (i) => i === items.length - 1; | ||
| const lines = [header, color ? `${ANSI.dim}${BOX.pipe}${ANSI.reset}` : BOX.pipe]; | ||
| for (const [i, item] of items.entries()) { | ||
| const actionable = isActionable(item); | ||
| const connector = isLast(i) ? actionable ? BOX.cornerArrow : BOX.corner : actionable ? BOX.teeArrow : BOX.tee; | ||
| const content = color ? colorizeLine(item) : item; | ||
| const styledConnector = color ? `${ANSI.dim}${connector}${ANSI.reset}` : connector; | ||
| lines.push(`${styledConnector} ${content}`); | ||
| } | ||
| return lines.join("\n"); | ||
| } | ||
| //#endregion | ||
| export { link as a, hint as i, formatAuto as n, frame as r, fix as t }; | ||
| //# sourceMappingURL=format-CQYRTqAc.js.map |
| {"version":3,"file":"format-CQYRTqAc.js","names":[],"sources":["../src/format/index.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Render a Unicode tree frame with auto-detected formatting.\n *\n * Terminal control sequences in `header` and `sections` are stripped\n * (see {@link sanitize}).\n *\n * @param header - The main error message line\n * @param sections - Detail lines (falsy values are filtered out)\n */\nexport function frame(\n header: string,\n sections?: (string | undefined | null | false)[],\n): string {\n const { tree, color } = detectFormat();\n return renderFrame({\n color,\n header: sanitize(header),\n sections: sections?.map((s) => (typeof s === 'string' ? sanitize(s) : s)),\n tree,\n });\n}\n\n/**\n * Format a string as a hint. Nil-safe. Returns `undefined` if falsy.\n *\n * Terminal control sequences in `text` are stripped (see {@link sanitize}).\n */\nexport function hint(text: string | undefined | null): string | undefined {\n if (!text) {\n return undefined;\n }\n return `hint: ${sanitize(text)}`;\n}\n\n/**\n * Format a string as a fix suggestion. Nil-safe. Returns `undefined` if falsy.\n *\n * Terminal control sequences in `text` are stripped (see {@link sanitize}).\n */\nexport function fix(text: string | undefined | null): string | undefined {\n if (!text) {\n return undefined;\n }\n return `fix: ${sanitize(text)}`;\n}\n\n/**\n * Format a URL as a link. Nil-safe. Returns `undefined` if falsy.\n *\n * Terminal control sequences in `url` are stripped (see {@link sanitize}).\n */\nexport function link(url: string | undefined | null): string | undefined {\n if (!url) {\n return undefined;\n }\n return `read more: ${sanitize(url)}`;\n}\n\n// ---------------------------------------------------------------------------\n// Internal API (used by VercelError.toString)\n// ---------------------------------------------------------------------------\n\n/**\n * Detect formatting capabilities of the current environment.\n *\n * - `tree`: use Unicode box-drawing characters (├──, ╰──)\n * - `color`: use ANSI escape codes (red, green, bold, underline)\n *\n * Detection:\n * 1. Non-Node (no `process`) → plain (no tree, no color)\n * 2. `NO_COLOR` env var → tree only, no color\n * 3. `FORCE_COLOR` env var → tree + color\n * 4. TTY → tree + color\n * 5. Browser → plain\n * 6. Fallback (piped, CI) → plain\n */\nexport function detectFormat(): { tree: boolean; color: boolean } {\n try {\n if (typeof process === 'undefined') {\n return { color: false, tree: false };\n }\n if (process.env?.['NO_COLOR'] !== undefined) {\n return { color: false, tree: true };\n }\n if (process.env?.['FORCE_COLOR'] !== undefined) {\n return { color: true, tree: true };\n }\n if (process.stdout && 'isTTY' in process.stdout && process.stdout.isTTY) {\n return { color: true, tree: true };\n }\n } catch {\n return { color: false, tree: false };\n }\n\n if (typeof window !== 'undefined') {\n return { color: false, tree: false };\n }\n\n return { color: false, tree: false };\n}\n\n/**\n * Auto-format an error based on environment detection.\n * Used by `VercelError.toString()` for zero-config output.\n */\nexport function formatAuto(error: ErrorShape): string {\n const { tree, color } = detectFormat();\n const header = buildHeader(error, color);\n\n const reason =\n error.reason !== undefined ? sanitize(error.reason) : undefined;\n\n const sections = [reason, hint(error.hint), fix(error.fix), link(error.link)];\n\n return renderFrame({ color, header, sections, tree });\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface ErrorShape {\n name: string;\n message: string;\n code?: string;\n scope?: string;\n reason?: string;\n hint?: string;\n fix?: string;\n link?: string;\n}\n\n/**\n * Matches complete ANSI escape sequences introduced by `ESC` (0x1b): CSI\n * (`ESC [ … final`), OSC (`ESC ] … BEL/ST`, e.g. OSC 8 hyperlinks and OSC 52\n * clipboard), and other two/three-byte escapes. Removing the whole sequence,\n * rather than only the `ESC` byte, keeps the visible text clean.\n */\n/* oxlint-disable no-control-regex -- intentional terminal control-char matching */\nconst ANSI_ESCAPE =\n /\\x1b(?:\\[[0-?]*[ -/]*[@-~]|\\][\\s\\S]*?(?:\\x07|\\x1b\\\\)|[@-Z\\\\-_])/g;\n\n/**\n * Matches standalone terminal control characters left after ANSI sequences are\n * removed: C0 controls (except `\\t`, `\\n`, `\\r`), the C1 range, and `DEL`.\n */\nconst CONTROL_CHARS = /[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/g;\n/* oxlint-enable no-control-regex */\n\n/**\n * Strip terminal control sequences from caller-controlled text before it is\n * rendered to a terminal. Error fields can originate from an untrusted upstream\n * (e.g. an HTTP error body parsed by `parseErrorResponse`); without this a\n * malicious upstream could inject escape sequences that rewrite the screen,\n * forge log lines, or abuse terminal features (OSC 8 links, OSC 52 clipboard).\n * Full ANSI sequences are removed first, then any leftover control bytes.\n * Preserves `\\t`, `\\n`, `\\r`.\n */\nfunction sanitize(text: string): string {\n return text.replace(ANSI_ESCAPE, '').replace(CONTROL_CHARS, '');\n}\n\nconst ANSI = {\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n green: '\\x1b[32m',\n red: '\\x1b[31m',\n reset: '\\x1b[0m',\n resetBold: '\\x1b[22m',\n underline: '\\x1b[4m',\n yellow: '\\x1b[33m',\n} as const;\n\nconst BOX = {\n corner: '╰──',\n cornerArrow: '╰─▸',\n pipe: '│',\n tee: '├──',\n teeArrow: '├─▸',\n} as const;\n\nconst ACTIONABLE_PREFIXES = ['hint: ', 'fix: ', 'read more: '] as const;\n\n/**\n * Build the error header line.\n *\n * With qualifier: `error: VercelError [scope:code] message`\n * Without: `error: VercelError: message`\n * Stripped message: `error: VercelError [scope:code]` (qualifier only)\n * No message at all: `error: VercelError`\n * ANSI: `error:` red+bold, name red, `[qualifier]` red, message red+bold\n *\n * When `message` is empty, such as after production stripping, the qualifier\n * stands in for it so the error still identifies itself by `scope` and `code`.\n */\nfunction buildHeader(error: ErrorShape, color: boolean): string {\n const parts: HeaderParts = {\n name: sanitize(error.name),\n message: sanitize(error.message),\n qualifier: [error.scope, error.code]\n .filter((part): part is string => Boolean(part))\n .map(sanitize)\n .join(':'),\n };\n\n return color ? buildColorHeader(parts) : buildPlainHeader(parts);\n}\n\ninterface HeaderParts {\n name: string;\n qualifier: string;\n message: string;\n}\n\nfunction buildPlainHeader({ name, qualifier, message }: HeaderParts): string {\n if (qualifier) {\n return message\n ? `error: ${name} [${qualifier}] ${message}`\n : `error: ${name} [${qualifier}]`;\n }\n return message ? `error: ${name}: ${message}` : `error: ${name}`;\n}\n\nfunction buildColorHeader({ name, qualifier, message }: HeaderParts): string {\n const label = `${ANSI.red}${ANSI.bold}error:${ANSI.resetBold}`;\n\n if (qualifier) {\n const head = `${label} ${ANSI.red}${name} [${qualifier}]`;\n return message\n ? `${head} ${ANSI.bold}${message}${ANSI.reset}`\n : `${head}${ANSI.reset}`;\n }\n\n return message\n ? `${label} ${ANSI.red}${name}: ${ANSI.bold}${message}${ANSI.reset}`\n : `${label} ${ANSI.red}${name}${ANSI.reset}`;\n}\n\nfunction filterSections(\n sections: (string | undefined | null | false)[] | undefined,\n): string[] | undefined {\n const items = sections?.filter(\n (s): s is string => typeof s === 'string' && s.length > 0,\n );\n return items && items.length > 0 ? items : undefined;\n}\n\nfunction colorizeLine(line: string): string {\n if (line.startsWith('hint: ')) {\n return `${ANSI.yellow}${ANSI.bold}hint:${ANSI.reset} ${line.slice(6)}`;\n }\n if (line.startsWith('fix: ')) {\n return `${ANSI.green}${ANSI.bold}fix:${ANSI.reset} ${line.slice(5)}`;\n }\n if (line.startsWith('read more: ')) {\n return `${ANSI.bold}read more:${ANSI.reset} ${ANSI.underline}${line.slice(11)}${ANSI.reset}`;\n }\n return line;\n}\n\ninterface RenderFrameOptions {\n header: string;\n sections?: (string | undefined | null | false)[];\n tree: boolean;\n color: boolean;\n}\n\nfunction isActionable(line: string): boolean {\n return ACTIONABLE_PREFIXES.some((prefix) => line.startsWith(prefix));\n}\n\n/**\n * Render the final framed output. Inputs must already be {@link sanitize}d:\n * this stage applies the library's own ANSI styling (`colorizeLine`,\n * connectors), so it cannot strip control characters without destroying that\n * styling. Callers (`frame`, `formatAuto`) own sanitization of untrusted text.\n */\nfunction renderFrame({\n header,\n sections,\n tree,\n color,\n}: RenderFrameOptions): string {\n const items = filterSections(sections);\n if (!items) {\n return header;\n }\n\n if (!tree) {\n return [header, ...items.map((item) => ` ${item}`)].join('\\n');\n }\n\n const isLast = (i: number) => i === items.length - 1;\n const spacer = color ? `${ANSI.dim}${BOX.pipe}${ANSI.reset}` : BOX.pipe;\n const lines = [header, spacer];\n\n for (const [i, item] of items.entries()) {\n const actionable = isActionable(item);\n const connector = isLast(i)\n ? actionable\n ? BOX.cornerArrow\n : BOX.corner\n : actionable\n ? BOX.teeArrow\n : BOX.tee;\n const content = color ? colorizeLine(item) : item;\n const styledConnector = color\n ? `${ANSI.dim}${connector}${ANSI.reset}`\n : connector;\n lines.push(`${styledConnector} ${content}`);\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"} |
| //#region src/types.d.ts | ||
| /** | ||
| * Recursive type for structured metadata values. | ||
| * Supports arbitrary nesting for domain-specific context. | ||
| */ | ||
| type SerializableValue = string | number | boolean | null | undefined | SerializableValue[] | { | ||
| [key: string]: SerializableValue; | ||
| }; | ||
| /** | ||
| * Domain-specific structured context for debugging and logging. | ||
| * Can contain arbitrarily nested values. Server-side only, so it is excluded | ||
| * from HTTP error responses. | ||
| * | ||
| * Route to: serialization, logging, debugging tools. | ||
| * | ||
| * @example { userId: '123', query: { table: 'users', limit: 50 } } | ||
| */ | ||
| type ErrorMetadata = Record<string, SerializableValue>; | ||
| /** | ||
| * Flat key-value pairs for observability and telemetry. | ||
| * Compatible with OpenTelemetry's AttributeValue type. | ||
| * | ||
| * Route to: tracing spans, Sentry tags, metrics dashboards. | ||
| * | ||
| * @example { 'http.method': 'POST', 'db.system': 'postgresql', 'retry.count': 3 } | ||
| */ | ||
| type ErrorAttributes = Record<string, string | number | boolean | string[] | number[] | boolean[] | undefined>; | ||
| /** | ||
| * Minimal interface for error-like objects with a message property. | ||
| */ | ||
| interface ErrorLike { | ||
| message: string; | ||
| name?: string; | ||
| stack?: string; | ||
| } | ||
| /** | ||
| * Configuration options for creating a VercelError instance. | ||
| */ | ||
| interface VercelErrorOptions<TCode extends string = string> { | ||
| /** Flat OTel-compatible tags for traces, metrics, and error trackers. */ | ||
| attributes?: ErrorAttributes; | ||
| /** The underlying error or value that triggered this one, for chaining. */ | ||
| cause?: unknown; | ||
| /** | ||
| * Stable, machine-readable identifier for this error. Keep it constant even | ||
| * when you reword the message, so users can search it and docs can link to | ||
| * it. Pick whatever style fits your registry: semantic names | ||
| * (`pool_exhausted`), numeric codes (`E1001`), or namespaced numbers | ||
| * (`B2011`). Numbering is optional, so use words when you prefer them. | ||
| */ | ||
| code?: TCode; | ||
| /** Actionable step that resolves the error, such as a command or config change. */ | ||
| fix?: string; | ||
| /** Advisory tip that helps the developer, shown before `fix`. */ | ||
| hint?: string; | ||
| /** URL to documentation for this error. Derivable from `code` via `docsBaseUrl`. */ | ||
| link?: string; | ||
| /** Nested domain context for debugging and logging. Never sent to clients. */ | ||
| metadata?: ErrorMetadata; | ||
| /** Why the error happened, the root-cause explanation behind the message. */ | ||
| reason?: string; | ||
| /** Correlation ID for tracing this error across services. */ | ||
| requestId?: string; | ||
| /** Namespace that produced the error, such as a service or subsystem. */ | ||
| scope?: string; | ||
| /** HTTP status code for the response. Defaults to 500 on the wire. */ | ||
| statusCode?: number; | ||
| /** Client-safe message sent over the wire instead of the developer `message`. */ | ||
| userMessage?: string; | ||
| /** Reserved. Automatically captured from Error */ | ||
| stack?: never; | ||
| /** Reserved. Pass message as the first constructor argument */ | ||
| message?: never; | ||
| /** Reserved. Hardcoded to "VercelError" for minification safety */ | ||
| name?: never; | ||
| } | ||
| /** | ||
| * The canonical wire format for all Vercel HTTP error responses. | ||
| * | ||
| * `message` maps to `userMessage` from VercelError, falling back to `message`. | ||
| */ | ||
| interface ErrorResponse { | ||
| error: { | ||
| code?: string; | ||
| message: string; | ||
| reason?: string; | ||
| hint?: string; | ||
| fix?: string; | ||
| link?: string; | ||
| }; | ||
| } | ||
| /** | ||
| * Minimal interface for any object that can look up headers by name. | ||
| * Compatible with `Headers`, `ReadonlyHeaders` (Next.js), and plain objects. | ||
| */ | ||
| interface HeadersLike { | ||
| get(name: string): string | null; | ||
| } | ||
| //#endregion | ||
| //#region src/vercel-error/index.d.ts | ||
| /** | ||
| * Structured error class for Vercel. | ||
| * | ||
| * Every error should answer: | ||
| * 1. **What** happened? → `message` | ||
| * 2. **Why** did it happen? → `reason` | ||
| * 3. **What** could help? → `hint` | ||
| * 4. **How** to fix it? → `fix` | ||
| * 5. **Where** to learn more? → `link` | ||
| * | ||
| * Key features: | ||
| * - Zero runtime dependencies | ||
| * - Human + agent readable context (`reason`, `hint`, `fix`, `link`, `userMessage`) | ||
| * - Type-safe error codes via generics | ||
| * - Separate `metadata` (domain context) and `attributes` (OTel observability) | ||
| * - Error chaining with proper cause tracking | ||
| * - Environment-aware `toString()` (auto-detects ANSI) | ||
| * - Cross-realm compatibility via stable Symbol tag | ||
| * | ||
| * @template TCode - Strongly typed error code union | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new VercelError('Database connection pool exhausted', { | ||
| * code: 'pool_exhausted', | ||
| * scope: 'database', | ||
| * reason: 'All 20 connections are in use and none have been released.', | ||
| * hint: 'Consider using pgBouncer for connection pooling.', | ||
| * fix: 'Increase max_connections or add pgBouncer.', | ||
| * link: 'https://vercel.com/docs/storage/neon#connection-pooling', | ||
| * }); | ||
| * ``` | ||
| */ | ||
| declare class VercelError<TCode extends string = string> extends Error { | ||
| readonly code?: TCode; | ||
| readonly scope?: string; | ||
| statusCode?: number; | ||
| reason?: string; | ||
| hint?: string; | ||
| fix?: string; | ||
| link?: string; | ||
| userMessage?: string; | ||
| requestId?: string; | ||
| metadata?: ErrorMetadata; | ||
| attributes?: ErrorAttributes; | ||
| constructor(message: string, options?: VercelErrorOptions<TCode>); | ||
| private static readonly JSON_EXCLUDE; | ||
| /** | ||
| * JSON representation for `JSON.stringify`. | ||
| * | ||
| * Surfaces non-enumerable Error properties (`name`, `message`, `stack`) | ||
| * alongside all VercelError fields. Omits `cause` (may be circular or | ||
| * contain sensitive internals) and any `undefined` values. | ||
| */ | ||
| toJSON(): Record<string, unknown>; | ||
| /** | ||
| * Environment-aware string representation. | ||
| * Auto-detects ANSI support and renders accordingly. | ||
| */ | ||
| override toString(): string; | ||
| } | ||
| //#endregion | ||
| export { ErrorResponse as a, ErrorMetadata as i, ErrorAttributes as n, HeadersLike as o, ErrorLike as r, VercelErrorOptions as s, VercelError as t }; | ||
| //# sourceMappingURL=index-DmYEPWgi.d.ts.map |
| {"version":3,"file":"index-DmYEPWgi.d.ts","names":[],"sources":["../src/types.ts","../src/vercel-error/index.ts"],"mappings":";;AAIA;;;KAAY,iBAAA,kDAMR,iBAAA;EAAA,eACiB,iBAAA;AAAA;;;;AAWrB;;;;;AAUA;KAVY,aAAA,GAAgB,MAAA,SAAe,iBAAA;;;;AAkB3C;;;;;KARY,eAAA,GAAkB,MAAA;;;;UAQb,SAAA;EACf,OAAA;EACA,IAAA;EACA,KAAA;AAAA;;;;UAMe,kBAAA;;EAEf,UAAA,GAAa,eAAA;;EAGb,KAAA;;;;;;;;EASA,IAAA,GAAO,KAAA;;EAGP,GAAA;;EAGA,IAAA;;EAGA,IAAA;;EAGA,QAAA,GAAW,aAAA;EA8Bb;EA3BE,MAAA;;EAGA,SAAA;;EAGA,KAAA;;EAGA,UAAA;;EAGA,WAAA;;EAGA,KAAA;EAmBE;EAjBF,OAAA;EAyBe;EAvBf,IAAA;AAAA;;;;;ACxDF;UDgEiB,aAAA;EACf,KAAA;IACE,IAAA;IACA,OAAA;IACA,MAAA;IACA,IAAA;IACA,GAAA;IACA,IAAA;EAAA;AAAA;;;;;UAQa,WAAA;EACf,GAAA,CAAI,IAAA;AAAA;;;AArHN;;;;;;;;;AAkBA;;;;;AAUA;;;;;AAQA;;;;;;;;;AASA;;;;;AA7CA,cCqCa,WAAA,wCAAmD,KAAA;EAAA,SACrD,IAAA,GAAO,KAAA;EAAA,SACP,KAAA;EAET,UAAA;EAEA,MAAA;EACA,IAAA;EACA,GAAA;EACA,IAAA;EACA,WAAA;EAEA,SAAA;EACA,QAAA,GAAW,aAAA;EACX,UAAA,GAAa,eAAA;EAEb,WAAA,CAAY,OAAA,UAAiB,OAAA,GAAS,kBAAA,CAAmB,KAAA;EAAA,wBAyBjC,YAAA;;;;;;;;EASxB,MAAA,CAAA,GAAU,MAAA;;;ADcZ;;WCIW,QAAA,CAAA;AAAA"} |
| import { n as VERCEL_ERROR_TAG, r as isObject, t as VercelError } from "./vercel-error-CMeW90il.js"; | ||
| //#region src/is-vercel-error/index.ts | ||
| /** | ||
| * Check if a value is a VercelError instance. | ||
| * | ||
| * Uses a dual-strategy approach for reliable cross-realm detection: | ||
| * 1. Fast path: `instanceof` check for same-realm objects | ||
| * 2. Fallback: Symbol-based tag verification for cross-realm compatibility | ||
| */ | ||
| function isVercelError(error) { | ||
| if (error instanceof VercelError) return true; | ||
| return isObject(error) && VERCEL_ERROR_TAG in error && error[VERCEL_ERROR_TAG] === true; | ||
| } | ||
| //#endregion | ||
| export { isVercelError as t }; | ||
| //# sourceMappingURL=is-vercel-error-5aSp5Azf.js.map |
| {"version":3,"file":"is-vercel-error-5aSp5Azf.js","names":[],"sources":["../src/is-vercel-error/index.ts"],"sourcesContent":["import { isObject } from '../_internal';\nimport { VERCEL_ERROR_TAG } from '../constants';\nimport { VercelError } from '../vercel-error';\n\n/**\n * Check if a value is a VercelError instance.\n *\n * Uses a dual-strategy approach for reliable cross-realm detection:\n * 1. Fast path: `instanceof` check for same-realm objects\n * 2. Fallback: Symbol-based tag verification for cross-realm compatibility\n */\nexport function isVercelError(error: unknown): error is VercelError {\n if (error instanceof VercelError) {\n return true;\n }\n\n return (\n isObject(error) &&\n VERCEL_ERROR_TAG in error &&\n error[VERCEL_ERROR_TAG] === true\n );\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,cAAc,OAAsC;AAClE,KAAI,iBAAiB,YACnB,QAAO;AAGT,QACE,SAAS,MAAM,IACf,oBAAoB,SACpB,MAAM,sBAAsB"} |
| import { n as formatAuto } from "./format-CQYRTqAc.js"; | ||
| //#region src/_internal/index.ts | ||
| function isObject(value) { | ||
| return value !== null && typeof value === "object" && !Array.isArray(value); | ||
| } | ||
| //#endregion | ||
| //#region src/constants.ts | ||
| /** Stable tag to identify VercelError instances across realms */ | ||
| const VERCEL_ERROR_TAG = Symbol.for("__vercel_error"); | ||
| //#endregion | ||
| //#region src/vercel-error/index.ts | ||
| /** | ||
| * Structured error class for Vercel. | ||
| * | ||
| * Every error should answer: | ||
| * 1. **What** happened? → `message` | ||
| * 2. **Why** did it happen? → `reason` | ||
| * 3. **What** could help? → `hint` | ||
| * 4. **How** to fix it? → `fix` | ||
| * 5. **Where** to learn more? → `link` | ||
| * | ||
| * Key features: | ||
| * - Zero runtime dependencies | ||
| * - Human + agent readable context (`reason`, `hint`, `fix`, `link`, `userMessage`) | ||
| * - Type-safe error codes via generics | ||
| * - Separate `metadata` (domain context) and `attributes` (OTel observability) | ||
| * - Error chaining with proper cause tracking | ||
| * - Environment-aware `toString()` (auto-detects ANSI) | ||
| * - Cross-realm compatibility via stable Symbol tag | ||
| * | ||
| * @template TCode - Strongly typed error code union | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new VercelError('Database connection pool exhausted', { | ||
| * code: 'pool_exhausted', | ||
| * scope: 'database', | ||
| * reason: 'All 20 connections are in use and none have been released.', | ||
| * hint: 'Consider using pgBouncer for connection pooling.', | ||
| * fix: 'Increase max_connections or add pgBouncer.', | ||
| * link: 'https://vercel.com/docs/storage/neon#connection-pooling', | ||
| * }); | ||
| * ``` | ||
| */ | ||
| var VercelError = class VercelError extends Error { | ||
| code; | ||
| scope; | ||
| statusCode; | ||
| reason; | ||
| hint; | ||
| fix; | ||
| link; | ||
| userMessage; | ||
| requestId; | ||
| metadata; | ||
| attributes; | ||
| constructor(message, options = {}) { | ||
| super(message, { cause: options.cause }); | ||
| this.name = "VercelError"; | ||
| this.code = options.code; | ||
| this.scope = options.scope; | ||
| this.statusCode = options.statusCode; | ||
| this.reason = options.reason; | ||
| this.hint = options.hint; | ||
| this.fix = options.fix; | ||
| this.link = options.link; | ||
| this.userMessage = options.userMessage; | ||
| this.requestId = options.requestId; | ||
| this.metadata = options.metadata; | ||
| this.attributes = options.attributes; | ||
| Object.defineProperty(this, VERCEL_ERROR_TAG, { | ||
| configurable: false, | ||
| enumerable: false, | ||
| value: true, | ||
| writable: false | ||
| }); | ||
| } | ||
| static JSON_EXCLUDE = new Set(["name", "cause"]); | ||
| /** | ||
| * JSON representation for `JSON.stringify`. | ||
| * | ||
| * Surfaces non-enumerable Error properties (`name`, `message`, `stack`) | ||
| * alongside all VercelError fields. Omits `cause` (may be circular or | ||
| * contain sensitive internals) and any `undefined` values. | ||
| */ | ||
| toJSON() { | ||
| return { | ||
| message: this.message, | ||
| name: this.name, | ||
| ...this.stack ? { stack: this.stack } : {}, | ||
| ...Object.fromEntries(Object.entries(this).filter(([key, value]) => !VercelError.JSON_EXCLUDE.has(key) && value !== void 0)) | ||
| }; | ||
| } | ||
| /** | ||
| * Environment-aware string representation. | ||
| * Auto-detects ANSI support and renders accordingly. | ||
| */ | ||
| toString() { | ||
| return formatAuto(this); | ||
| } | ||
| }; | ||
| //#endregion | ||
| export { VERCEL_ERROR_TAG as n, isObject as r, VercelError as t }; | ||
| //# sourceMappingURL=vercel-error-CMeW90il.js.map |
| {"version":3,"file":"vercel-error-CMeW90il.js","names":[],"sources":["../src/_internal/index.ts","../src/constants.ts","../src/vercel-error/index.ts"],"sourcesContent":["export function isObject(\n value: unknown,\n): value is Record<PropertyKey, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n","/** Stable tag to identify VercelError instances across realms */\nexport const VERCEL_ERROR_TAG: unique symbol = Symbol.for('__vercel_error');\n","import { VERCEL_ERROR_TAG } from '../constants';\nimport { formatAuto } from '../format/index';\nimport type {\n ErrorAttributes,\n ErrorMetadata,\n VercelErrorOptions,\n} from '../types';\n\n/**\n * Structured error class for Vercel.\n *\n * Every error should answer:\n * 1. **What** happened? → `message`\n * 2. **Why** did it happen? → `reason`\n * 3. **What** could help? → `hint`\n * 4. **How** to fix it? → `fix`\n * 5. **Where** to learn more? → `link`\n *\n * Key features:\n * - Zero runtime dependencies\n * - Human + agent readable context (`reason`, `hint`, `fix`, `link`, `userMessage`)\n * - Type-safe error codes via generics\n * - Separate `metadata` (domain context) and `attributes` (OTel observability)\n * - Error chaining with proper cause tracking\n * - Environment-aware `toString()` (auto-detects ANSI)\n * - Cross-realm compatibility via stable Symbol tag\n *\n * @template TCode - Strongly typed error code union\n *\n * @example\n * ```ts\n * throw new VercelError('Database connection pool exhausted', {\n * code: 'pool_exhausted',\n * scope: 'database',\n * reason: 'All 20 connections are in use and none have been released.',\n * hint: 'Consider using pgBouncer for connection pooling.',\n * fix: 'Increase max_connections or add pgBouncer.',\n * link: 'https://vercel.com/docs/storage/neon#connection-pooling',\n * });\n * ```\n */\nexport class VercelError<TCode extends string = string> extends Error {\n readonly code?: TCode;\n readonly scope?: string;\n\n statusCode?: number;\n\n reason?: string;\n hint?: string;\n fix?: string;\n link?: string;\n userMessage?: string;\n\n requestId?: string;\n metadata?: ErrorMetadata;\n attributes?: ErrorAttributes;\n\n constructor(message: string, options: VercelErrorOptions<TCode> = {}) {\n super(message, { cause: options.cause });\n\n this.name = 'VercelError';\n\n this.code = options.code;\n this.scope = options.scope;\n this.statusCode = options.statusCode;\n this.reason = options.reason;\n this.hint = options.hint;\n this.fix = options.fix;\n this.link = options.link;\n this.userMessage = options.userMessage;\n this.requestId = options.requestId;\n this.metadata = options.metadata;\n this.attributes = options.attributes;\n\n Object.defineProperty(this, VERCEL_ERROR_TAG, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n }\n\n private static readonly JSON_EXCLUDE = new Set(['name', 'cause']);\n\n /**\n * JSON representation for `JSON.stringify`.\n *\n * Surfaces non-enumerable Error properties (`name`, `message`, `stack`)\n * alongside all VercelError fields. Omits `cause` (may be circular or\n * contain sensitive internals) and any `undefined` values.\n */\n toJSON(): Record<string, unknown> {\n return {\n message: this.message,\n name: this.name,\n ...(this.stack ? { stack: this.stack } : {}),\n ...Object.fromEntries(\n Object.entries(this).filter(\n ([key, value]) =>\n !VercelError.JSON_EXCLUDE.has(key) && value !== undefined,\n ),\n ),\n };\n }\n\n /**\n * Environment-aware string representation.\n * Auto-detects ANSI support and renders accordingly.\n */\n override toString(): string {\n return formatAuto(this);\n }\n}\n"],"mappings":";;AAAA,SAAgB,SACd,OACuC;AACvC,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;;;;ACF7E,MAAa,mBAAkC,OAAO,IAAI,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwC3E,IAAa,cAAb,MAAa,oBAAmD,MAAM;CACpE;CACA;CAEA;CAEA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CAEA,YAAY,SAAiB,UAAqC,EAAE,EAAE;AACpE,QAAM,SAAS,EAAE,OAAO,QAAQ,OAAO,CAAC;AAExC,OAAK,OAAO;AAEZ,OAAK,OAAO,QAAQ;AACpB,OAAK,QAAQ,QAAQ;AACrB,OAAK,aAAa,QAAQ;AAC1B,OAAK,SAAS,QAAQ;AACtB,OAAK,OAAO,QAAQ;AACpB,OAAK,MAAM,QAAQ;AACnB,OAAK,OAAO,QAAQ;AACpB,OAAK,cAAc,QAAQ;AAC3B,OAAK,YAAY,QAAQ;AACzB,OAAK,WAAW,QAAQ;AACxB,OAAK,aAAa,QAAQ;AAE1B,SAAO,eAAe,MAAM,kBAAkB;GAC5C,cAAc;GACd,YAAY;GACZ,OAAO;GACP,UAAU;GACX,CAAC;;CAGJ,OAAwB,eAAe,IAAI,IAAI,CAAC,QAAQ,QAAQ,CAAC;;;;;;;;CASjE,SAAkC;AAChC,SAAO;GACL,SAAS,KAAK;GACd,MAAM,KAAK;GACX,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,OAAO,GAAG,EAAE;GAC3C,GAAG,OAAO,YACR,OAAO,QAAQ,KAAK,CAAC,QAClB,CAAC,KAAK,WACL,CAAC,YAAY,aAAa,IAAI,IAAI,IAAI,UAAU,KAAA,EACnD,CACF;GACF;;;;;;CAOH,WAA4B;AAC1B,SAAO,WAAW,KAAK"} |
+2
-2
@@ -1,2 +0,2 @@ | ||
| import { a as ErrorResponse, s as VercelErrorOptions, t as VercelError } from "./index-ZJPGDfSQ.js"; | ||
| import { a as ErrorResponse, s as VercelErrorOptions, t as VercelError } from "./index-DmYEPWgi.js"; | ||
@@ -18,3 +18,3 @@ //#region src/parse-error-response/index.d.ts | ||
| * Fields already provided by the ErrorResponse (`code`, `reason`, `hint`, | ||
| * `fix`, `link`, `userMessage`) are excluded — the wire values always win. | ||
| * `fix`, `link`, `userMessage`) are excluded, so the wire values always win. | ||
| */ | ||
@@ -21,0 +21,0 @@ type FromErrorResponseOptions = Omit<VercelErrorOptions, "code" | "reason" | "hint" | "fix" | "link" | "userMessage">; |
+1
-1
@@ -1,2 +0,2 @@ | ||
| import { r as isObject, t as VercelError } from "./vercel-error-BARO-T1l.js"; | ||
| import { r as isObject, t as VercelError } from "./vercel-error-CMeW90il.js"; | ||
| //#region src/parse-error-response/index.ts | ||
@@ -3,0 +3,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"client.js","names":[],"sources":["../src/parse-error-response/index.ts","../src/from-error-response/index.ts"],"sourcesContent":["import { isObject } from '../_internal';\nimport type { ErrorResponse } from '../types';\n\n/**\n * Parse and validate unknown data as an ErrorResponse.\n *\n * Validates that `message` is a non-empty string.\n * Optional fields (`code`, `reason`, `hint`, `fix`, `link`) are included only if they are non-empty strings.\n *\n * @returns The validated ErrorResponse if valid, `undefined` otherwise.\n */\nexport function parseErrorResponse(data?: unknown): ErrorResponse | undefined {\n if (!data || !isObject(data) || !('error' in data) || !isObject(data.error)) {\n return undefined;\n }\n\n const { error } = data;\n\n if (typeof error.message !== 'string' || error.message.trim().length === 0) {\n return undefined;\n }\n\n const result: ErrorResponse = {\n error: {\n message: error.message,\n },\n };\n\n for (const key of ['code', 'reason', 'hint', 'fix', 'link'] as const) {\n const value = error[key];\n if (typeof value === 'string' && value.trim().length > 0) {\n result.error[key] = value;\n }\n }\n\n return result;\n}\n","import type { ErrorResponse, VercelErrorOptions } from '../types';\nimport { VercelError } from '../vercel-error';\n\n/**\n * Additional options when reconstructing a VercelError from an ErrorResponse.\n * Fields already provided by the ErrorResponse (`code`, `reason`, `hint`,\n * `fix`, `link`, `userMessage`) are excluded — the wire values always win.\n */\nexport type FromErrorResponseOptions = Omit<\n VercelErrorOptions,\n 'code' | 'reason' | 'hint' | 'fix' | 'link' | 'userMessage'\n>;\n\n/**\n * Reconstruct a VercelError from a validated ErrorResponse.\n *\n * Use this at service boundaries when you receive an error from an upstream\n * service and want to re-throw, enrich, or chain it as a VercelError.\n *\n * The ErrorResponse `message` becomes both the VercelError `message` and\n * `userMessage` (since it was already client-safe on the wire).\n *\n * @param response - A validated ErrorResponse (from `parseErrorResponse`)\n * @param options - Additional VercelError options (statusCode, cause, scope, etc.)\n *\n * @example\n * ```ts\n * import { parseErrorResponse, fromErrorResponse } from '@vercel/error/client';\n *\n * const res = await fetch('https://api.vercel.com/v1/deployments');\n * if (!res.ok) {\n * const parsed = parseErrorResponse(await res.json());\n * if (parsed) {\n * throw fromErrorResponse(parsed, {\n * statusCode: res.status,\n * scope: 'upstream',\n * cause: new Error(`${res.url} returned ${res.status}`),\n * });\n * }\n * }\n * ```\n */\nexport function fromErrorResponse(\n response: ErrorResponse,\n options: FromErrorResponseOptions = {},\n): VercelError {\n return new VercelError(response.error.message, {\n ...options,\n code: response.error.code,\n fix: response.error.fix,\n hint: response.error.hint,\n link: response.error.link,\n reason: response.error.reason,\n userMessage: response.error.message,\n });\n}\n"],"mappings":";;;;;;;;;;AAWA,SAAgB,mBAAmB,MAA2C;AAC5E,KAAI,CAAC,QAAQ,CAAC,SAAS,KAAK,IAAI,EAAE,WAAW,SAAS,CAAC,SAAS,KAAK,MAAM,CACzE;CAGF,MAAM,EAAE,UAAU;AAElB,KAAI,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,MAAM,CAAC,WAAW,EACvE;CAGF,MAAM,SAAwB,EAC5B,OAAO,EACL,SAAS,MAAM,SAChB,EACF;AAED,MAAK,MAAM,OAAO;EAAC;EAAQ;EAAU;EAAQ;EAAO;EAAO,EAAW;EACpE,MAAM,QAAQ,MAAM;AACpB,MAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACrD,QAAO,MAAM,OAAO;;AAIxB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACOT,SAAgB,kBACd,UACA,UAAoC,EAAE,EACzB;AACb,QAAO,IAAI,YAAY,SAAS,MAAM,SAAS;EAC7C,GAAG;EACH,MAAM,SAAS,MAAM;EACrB,KAAK,SAAS,MAAM;EACpB,MAAM,SAAS,MAAM;EACrB,MAAM,SAAS,MAAM;EACrB,QAAQ,SAAS,MAAM;EACvB,aAAa,SAAS,MAAM;EAC7B,CAAC"} | ||
| {"version":3,"file":"client.js","names":[],"sources":["../src/parse-error-response/index.ts","../src/from-error-response/index.ts"],"sourcesContent":["import { isObject } from '../_internal';\nimport type { ErrorResponse } from '../types';\n\n/**\n * Parse and validate unknown data as an ErrorResponse.\n *\n * Validates that `message` is a non-empty string.\n * Optional fields (`code`, `reason`, `hint`, `fix`, `link`) are included only if they are non-empty strings.\n *\n * @returns The validated ErrorResponse if valid, `undefined` otherwise.\n */\nexport function parseErrorResponse(data?: unknown): ErrorResponse | undefined {\n if (!data || !isObject(data) || !('error' in data) || !isObject(data.error)) {\n return undefined;\n }\n\n const { error } = data;\n\n if (typeof error.message !== 'string' || error.message.trim().length === 0) {\n return undefined;\n }\n\n const result: ErrorResponse = {\n error: {\n message: error.message,\n },\n };\n\n for (const key of ['code', 'reason', 'hint', 'fix', 'link'] as const) {\n const value = error[key];\n if (typeof value === 'string' && value.trim().length > 0) {\n result.error[key] = value;\n }\n }\n\n return result;\n}\n","import type { ErrorResponse, VercelErrorOptions } from '../types';\nimport { VercelError } from '../vercel-error';\n\n/**\n * Additional options when reconstructing a VercelError from an ErrorResponse.\n * Fields already provided by the ErrorResponse (`code`, `reason`, `hint`,\n * `fix`, `link`, `userMessage`) are excluded, so the wire values always win.\n */\nexport type FromErrorResponseOptions = Omit<\n VercelErrorOptions,\n 'code' | 'reason' | 'hint' | 'fix' | 'link' | 'userMessage'\n>;\n\n/**\n * Reconstruct a VercelError from a validated ErrorResponse.\n *\n * Use this at service boundaries when you receive an error from an upstream\n * service and want to re-throw, enrich, or chain it as a VercelError.\n *\n * The ErrorResponse `message` becomes both the VercelError `message` and\n * `userMessage` (since it was already client-safe on the wire).\n *\n * @param response - A validated ErrorResponse (from `parseErrorResponse`)\n * @param options - Additional VercelError options (statusCode, cause, scope, etc.)\n *\n * @example\n * ```ts\n * import { parseErrorResponse, fromErrorResponse } from '@vercel/error/client';\n *\n * const res = await fetch('https://api.vercel.com/v1/deployments');\n * if (!res.ok) {\n * const parsed = parseErrorResponse(await res.json());\n * if (parsed) {\n * throw fromErrorResponse(parsed, {\n * statusCode: res.status,\n * scope: 'upstream',\n * cause: new Error(`${res.url} returned ${res.status}`),\n * });\n * }\n * }\n * ```\n */\nexport function fromErrorResponse(\n response: ErrorResponse,\n options: FromErrorResponseOptions = {},\n): VercelError {\n return new VercelError(response.error.message, {\n ...options,\n code: response.error.code,\n fix: response.error.fix,\n hint: response.error.hint,\n link: response.error.link,\n reason: response.error.reason,\n userMessage: response.error.message,\n });\n}\n"],"mappings":";;;;;;;;;;AAWA,SAAgB,mBAAmB,MAA2C;AAC5E,KAAI,CAAC,QAAQ,CAAC,SAAS,KAAK,IAAI,EAAE,WAAW,SAAS,CAAC,SAAS,KAAK,MAAM,CACzE;CAGF,MAAM,EAAE,UAAU;AAElB,KAAI,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,MAAM,CAAC,WAAW,EACvE;CAGF,MAAM,SAAwB,EAC5B,OAAO,EACL,SAAS,MAAM,SAChB,EACF;AAED,MAAK,MAAM,OAAO;EAAC;EAAQ;EAAU;EAAQ;EAAO;EAAO,EAAW;EACpE,MAAM,QAAQ,MAAM;AACpB,MAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACrD,QAAO,MAAM,OAAO;;AAIxB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACOT,SAAgB,kBACd,UACA,UAAoC,EAAE,EACzB;AACb,QAAO,IAAI,YAAY,SAAS,MAAM,SAAS;EAC7C,GAAG;EACH,MAAM,SAAS,MAAM;EACrB,KAAK,SAAS,MAAM;EACpB,MAAM,SAAS,MAAM;EACrB,MAAM,SAAS,MAAM;EACrB,QAAQ,SAAS,MAAM;EACvB,aAAa,SAAS,MAAM;EAC7B,CAAC"} |
+12
-3
@@ -5,2 +5,5 @@ //#region src/format/index.d.ts | ||
| * | ||
| * Terminal control sequences in `header` and `sections` are stripped | ||
| * (see {@link sanitize}). | ||
| * | ||
| * @param header - The main error message line | ||
@@ -11,11 +14,17 @@ * @param sections - Detail lines (falsy values are filtered out) | ||
| /** | ||
| * Format a string as a hint. Nil-safe — returns `undefined` if falsy. | ||
| * Format a string as a hint. Nil-safe. Returns `undefined` if falsy. | ||
| * | ||
| * Terminal control sequences in `text` are stripped (see {@link sanitize}). | ||
| */ | ||
| declare function hint(text: string | undefined | null): string | undefined; | ||
| /** | ||
| * Format a string as a fix suggestion. Nil-safe — returns `undefined` if falsy. | ||
| * Format a string as a fix suggestion. Nil-safe. Returns `undefined` if falsy. | ||
| * | ||
| * Terminal control sequences in `text` are stripped (see {@link sanitize}). | ||
| */ | ||
| declare function fix(text: string | undefined | null): string | undefined; | ||
| /** | ||
| * Format a URL as a link. Nil-safe — returns `undefined` if falsy. | ||
| * Format a URL as a link. Nil-safe. Returns `undefined` if falsy. | ||
| * | ||
| * Terminal control sequences in `url` are stripped (see {@link sanitize}). | ||
| */ | ||
@@ -22,0 +31,0 @@ declare function link(url: string | undefined | null): string | undefined; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"format.d.ts","names":[],"sources":["../src/format/index.ts"],"mappings":";;AAUA;;;;;iBAAgB,KAAA,CACd,MAAA,UACA,QAAA;;;;iBASc,IAAA,CAAK,IAAA;AAUrB;;;AAAA,iBAAgB,GAAA,CAAI,IAAA;;AAUpB;;iBAAgB,IAAA,CAAK,GAAA"} | ||
| {"version":3,"file":"format.d.ts","names":[],"sources":["../src/format/index.ts"],"mappings":";;AAaA;;;;;AAkBA;;;iBAlBgB,KAAA,CACd,MAAA,UACA,QAAA;;AA4BF;;;;iBAZgB,IAAA,CAAK,IAAA;AAwBrB;;;;;AAAA,iBAZgB,GAAA,CAAI,IAAA;;;;;;iBAYJ,IAAA,CAAK,GAAA"} |
+1
-1
@@ -1,2 +0,2 @@ | ||
| import { a as link, i as hint, r as frame, t as fix } from "./format-DX87UrE2.js"; | ||
| import { a as link, i as hint, r as frame, t as fix } from "./format-CQYRTqAc.js"; | ||
| export { fix, frame, hint, link }; |
+35
-20
@@ -1,2 +0,2 @@ | ||
| import { a as ErrorResponse, i as ErrorMetadata, n as ErrorAttributes, r as ErrorLike, s as VercelErrorOptions, t as VercelError } from "./index-ZJPGDfSQ.js"; | ||
| import { a as ErrorResponse, i as ErrorMetadata, n as ErrorAttributes, r as ErrorLike, s as VercelErrorOptions, t as VercelError } from "./index-DmYEPWgi.js"; | ||
@@ -20,3 +20,21 @@ //#region src/create-errors/index.d.ts | ||
| interface CreateErrorsOptions<TCode extends string = string, TError extends VercelError<TCode> = VercelError<TCode>> { | ||
| scope: string; | ||
| /** | ||
| * Namespace injected into every error this factory produces. | ||
| * Optional. Provide it only when a scope is useful, such as grouping errors | ||
| * by service or subsystem. When omitted, errors have no `scope`. | ||
| */ | ||
| scope?: string; | ||
| /** | ||
| * Base URL or resolver for documentation links. When a string, the error's | ||
| * `code` is appended verbatim as a path segment | ||
| * (e.g. `"https://vercel.com/docs/errors"` plus code `"pool_exhausted"` gives | ||
| * `"https://vercel.com/docs/errors/pool_exhausted"`). The code is not | ||
| * transformed, so use a function base if you need to change its case or shape. | ||
| * When a function, it receives the `code` and returns a URL, or `undefined` | ||
| * to skip. | ||
| * | ||
| * Applied only when an error has a `code` and no explicit `link`. A | ||
| * per-error `link` always wins. | ||
| */ | ||
| docsBaseUrl?: string | ((code: TCode) => string | undefined); | ||
| ErrorClass?: ErrorConstructor<TCode, TError>; | ||
@@ -28,22 +46,13 @@ attributes?: ErrorAttributes; | ||
| /** | ||
| * Create a scoped error namespace with type-safe error codes. | ||
| * Create an error factory with type-safe error codes. | ||
| * | ||
| * Always returns `{ create, raise, report }`. | ||
| * If no `report` callback is provided, `report` defaults to `console.error`. | ||
| * If `ErrorClass` is provided, all errors are instances of that class. | ||
| * `scope` is optional. Provide it only when you want to group errors by a | ||
| * namespace. When `docsBaseUrl` is set, each error's `link` is derived from | ||
| * its `code`, unless you pass an explicit `link`. | ||
| * When no `report` callback is provided, `report` defaults to `console.error`. | ||
| * When `ErrorClass` is provided, all errors are instances of that class. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const errors = createErrors({ | ||
| * scope: 'database', | ||
| * report: (error) => sentry.captureException(error), | ||
| * }); | ||
| * | ||
| * const error = errors.create('Connection failed', { code: 'conn_failed' }); | ||
| * errors.raise('Timeout', { code: 'timeout' }); // throws | ||
| * errors.report('Pool exhausted', { code: 'pool_exhausted' }); // reports + returns | ||
| * ``` | ||
| * | ||
| * @example Custom error class | ||
| * ```ts | ||
| * class DatabaseError extends VercelError { | ||
@@ -56,9 +65,15 @@ * readonly retryable = true; | ||
| * ErrorClass: DatabaseError, | ||
| * docsBaseUrl: 'https://vercel.com/docs/errors/database', | ||
| * report: (error) => sentry.captureException(error), | ||
| * }); | ||
| * | ||
| * const err = errors.create('Pool exhausted'); // DatabaseError | ||
| * err.retryable; // true — fully typed | ||
| * const error = errors.create('Connection failed', { code: 'conn_failed' }); | ||
| * error.retryable; // true, fully typed | ||
| * error.link; // 'https://vercel.com/docs/errors/database/conn_failed' | ||
| * | ||
| * errors.raise('Timeout', { code: 'timeout' }); // throws | ||
| * errors.report('Pool exhausted', { code: 'pool_exhausted' }); // reports + returns | ||
| * ``` | ||
| */ | ||
| declare function createErrors<TCode extends string = string, TError extends VercelError<TCode> = VercelError<TCode>>(options: CreateErrorsOptions<TCode, TError>): ErrorFactory<TCode, TError>; | ||
| declare function createErrors<TCode extends string = string, TError extends VercelError<TCode> = VercelError<TCode>>(options?: CreateErrorsOptions<TCode, TError>): ErrorFactory<TCode, TError>; | ||
| //#endregion | ||
@@ -65,0 +80,0 @@ //#region src/is-vercel-error/index.d.ts |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","names":[],"sources":["../src/create-errors/index.ts","../src/is-vercel-error/index.ts","../src/is-error/index.ts","../src/is-error-like/index.ts","../src/has-code/index.ts","../src/get-message/index.ts","../src/get-root-cause/index.ts"],"mappings":";;;;AAWA;;;KAAY,kBAAA,kCAAoD,IAAA,CAC9D,kBAAA,CAAmB,KAAA;;;;;KAQT,gBAAA,+CAEK,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA,UACzC,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA,MAAW,MAAA;AAAA,UAEjD,YAAA,+CAEA,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA;EAEhD,MAAA,CAAO,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA,IAAS,MAAA;EAC9D,KAAA,CAAM,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA;EACpD,MAAA,CAAO,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA,IAAS,MAAA;AAAA;AAAA,UAG/C,mBAAA,+CAEA,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA;EAEhD,KAAA;EACA,UAAA,GAAa,gBAAA,CAAiB,KAAA,EAAO,MAAA;EACrC,UAAA,GAAa,eAAA;EACb,QAAA,GAAW,aAAA;EACX,MAAA,IAAU,KAAA,EAAO,MAAA;AAAA;;;;;;;;;;AAjBnB;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDgB,YAAA,+CAEC,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA,EAAA,CAChD,OAAA,EAAS,mBAAA,CAAoB,KAAA,EAAO,MAAA,IAAU,YAAA,CAAa,KAAA,EAAO,MAAA;;;;;AAvEpE;;;;;iBCAgB,aAAA,CAAc,KAAA,YAAiB,KAAA,IAAS,WAAA;;;;;;ADAxD;;;iBEHgB,OAAA,CAAQ,KAAA,YAAiB,KAAA,IAAS,KAAA;;;;;AFGlD;iBGLgB,WAAA,CAAY,KAAA,YAAiB,KAAA,IAAS,SAAA;;;;;;iBCDtC,OAAA,sBAAA,CACd,KAAA,WACA,IAAA,EAAM,KAAA,GACL,KAAA;EAAW,IAAA,EAAM,KAAA;AAAA;;;;iBAKJ,OAAA,sBAAA,CACd,KAAA,WACA,KAAA,WAAgB,KAAA,KACf,KAAA;EAAW,IAAA,EAAM,KAAA;AAAA;;;;;;AJLpB;;;iBKFgB,UAAA,CACd,KAAA,WACA,QAAA;;;;;;ALAF;;;iBMHgB,YAAA,CAAa,KAAA"} | ||
| {"version":3,"file":"index.d.ts","names":[],"sources":["../src/create-errors/index.ts","../src/is-vercel-error/index.ts","../src/is-error/index.ts","../src/is-error-like/index.ts","../src/has-code/index.ts","../src/get-message/index.ts","../src/get-root-cause/index.ts"],"mappings":";;;;AAyBA;;;KAAY,kBAAA,kCAAoD,IAAA,CAC9D,kBAAA,CAAmB,KAAA;;;;;KAQT,gBAAA,+CAEK,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA,UACzC,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA,MAAW,MAAA;AAAA,UAEjD,YAAA,+CAEA,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA;EAEhD,MAAA,CAAO,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA,IAAS,MAAA;EAC9D,KAAA,CAAM,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA;EACpD,MAAA,CAAO,OAAA,UAAiB,OAAA,GAAU,kBAAA,CAAmB,KAAA,IAAS,MAAA;AAAA;AAAA,UAG/C,mBAAA,+CAEA,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA;;;;;;EAOhD,KAAA;;;;;;;;;;AAlBF;;;EAgCE,WAAA,cAAyB,IAAA,EAAM,KAAA;EAE/B,UAAA,GAAa,gBAAA,CAAiB,KAAA,EAAO,MAAA;EACrC,UAAA,GAAa,eAAA;EACb,QAAA,GAAW,aAAA;EACX,MAAA,IAAU,KAAA,EAAO,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkCH,YAAA,+CAEC,WAAA,CAAY,KAAA,IAAS,WAAA,CAAY,KAAA,EAAA,CAEhD,OAAA,GAAS,mBAAA,CAAoB,KAAA,EAAO,MAAA,IACnC,YAAA,CAAa,KAAA,EAAO,MAAA;;;;;AA1FvB;;;;;iBCdgB,aAAA,CAAc,KAAA,YAAiB,KAAA,IAAS,WAAA;;;;;;ADcxD;;;iBEjBgB,OAAA,CAAQ,KAAA,YAAiB,KAAA,IAAS,KAAA;;;;;AFiBlD;iBGnBgB,WAAA,CAAY,KAAA,YAAiB,KAAA,IAAS,SAAA;;;;;;iBCDtC,OAAA,sBAAA,CACd,KAAA,WACA,IAAA,EAAM,KAAA,GACL,KAAA;EAAW,IAAA,EAAM,KAAA;AAAA;;;;iBAKJ,OAAA,sBAAA,CACd,KAAA,WACA,KAAA,WAAgB,KAAA,KACf,KAAA;EAAW,IAAA,EAAM,KAAA;AAAA;;;;;;AJSpB;;;iBKhBgB,UAAA,CACd,KAAA,WACA,QAAA;;;;;;ALcF;;;iBMjBgB,YAAA,CAAa,KAAA"} |
+39
-28
@@ -1,25 +0,26 @@ | ||
| import { r as isObject, t as VercelError } from "./vercel-error-BARO-T1l.js"; | ||
| import { t as isVercelError } from "./is-vercel-error-ODrWmu1P.js"; | ||
| import { r as isObject, t as VercelError } from "./vercel-error-CMeW90il.js"; | ||
| import { t as isVercelError } from "./is-vercel-error-5aSp5Azf.js"; | ||
| //#region src/create-errors/index.ts | ||
| /** | ||
| * Create a scoped error namespace with type-safe error codes. | ||
| * Resolve a documentation URL for a code from a base URL. | ||
| * A string base appends the code verbatim as a path segment. A function | ||
| * base is called with the code. Returns `undefined` when no URL applies. | ||
| */ | ||
| function resolveDocsUrl(docsBaseUrl, code) { | ||
| if (!docsBaseUrl) return void 0; | ||
| if (typeof docsBaseUrl === "function") return docsBaseUrl(code); | ||
| return `${docsBaseUrl.replace(/\/+$/, "")}/${code}`; | ||
| } | ||
| /** | ||
| * Create an error factory with type-safe error codes. | ||
| * | ||
| * Always returns `{ create, raise, report }`. | ||
| * If no `report` callback is provided, `report` defaults to `console.error`. | ||
| * If `ErrorClass` is provided, all errors are instances of that class. | ||
| * `scope` is optional. Provide it only when you want to group errors by a | ||
| * namespace. When `docsBaseUrl` is set, each error's `link` is derived from | ||
| * its `code`, unless you pass an explicit `link`. | ||
| * When no `report` callback is provided, `report` defaults to `console.error`. | ||
| * When `ErrorClass` is provided, all errors are instances of that class. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const errors = createErrors({ | ||
| * scope: 'database', | ||
| * report: (error) => sentry.captureException(error), | ||
| * }); | ||
| * | ||
| * const error = errors.create('Connection failed', { code: 'conn_failed' }); | ||
| * errors.raise('Timeout', { code: 'timeout' }); // throws | ||
| * errors.report('Pool exhausted', { code: 'pool_exhausted' }); // reports + returns | ||
| * ``` | ||
| * | ||
| * @example Custom error class | ||
| * ```ts | ||
| * class DatabaseError extends VercelError { | ||
@@ -32,9 +33,15 @@ * readonly retryable = true; | ||
| * ErrorClass: DatabaseError, | ||
| * docsBaseUrl: 'https://vercel.com/docs/errors/database', | ||
| * report: (error) => sentry.captureException(error), | ||
| * }); | ||
| * | ||
| * const err = errors.create('Pool exhausted'); // DatabaseError | ||
| * err.retryable; // true — fully typed | ||
| * const error = errors.create('Connection failed', { code: 'conn_failed' }); | ||
| * error.retryable; // true, fully typed | ||
| * error.link; // 'https://vercel.com/docs/errors/database/conn_failed' | ||
| * | ||
| * errors.raise('Timeout', { code: 'timeout' }); // throws | ||
| * errors.report('Pool exhausted', { code: 'pool_exhausted' }); // reports + returns | ||
| * ``` | ||
| */ | ||
| function createErrors(options) { | ||
| function createErrors(options = {}) { | ||
| const ErrorClass = options.ErrorClass ?? VercelError; | ||
@@ -51,2 +58,3 @@ const reportFn = options.report ?? ((error) => console.error(error)); | ||
| } : void 0; | ||
| const link = itemOptions.link ?? (itemOptions.code !== void 0 ? resolveDocsUrl(options.docsBaseUrl, itemOptions.code) : void 0); | ||
| return new ErrorClass(message, { | ||
@@ -56,15 +64,18 @@ ...itemOptions, | ||
| metadata: mergedMetadata, | ||
| link, | ||
| scope: options.scope | ||
| }); | ||
| } | ||
| function raise(message, itemOptions) { | ||
| throw create(message, itemOptions); | ||
| } | ||
| function report(message, itemOptions) { | ||
| const error = create(message, itemOptions); | ||
| reportFn(error); | ||
| return error; | ||
| } | ||
| return { | ||
| create, | ||
| raise(message, itemOptions) { | ||
| throw create(message, itemOptions); | ||
| }, | ||
| report(message, itemOptions) { | ||
| const error = create(message, itemOptions); | ||
| reportFn(error); | ||
| return error; | ||
| } | ||
| raise, | ||
| report | ||
| }; | ||
@@ -71,0 +82,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/create-errors/index.ts","../src/is-error/index.ts","../src/is-error-like/index.ts","../src/has-code/index.ts","../src/get-message/index.ts","../src/get-root-cause/index.ts"],"sourcesContent":["import type {\n ErrorAttributes,\n ErrorMetadata,\n VercelErrorOptions,\n} from '../types';\nimport { VercelError } from '../vercel-error';\n\n/**\n * Per-error options passed to create/raise/report.\n * `scope` is omitted because it's the factory's identity.\n */\nexport type CreateErrorOptions<TCode extends string = string> = Omit<\n VercelErrorOptions<TCode>,\n 'scope'\n>;\n\n/**\n * Constructor constraint for custom error classes.\n * Any class that extends VercelError and accepts `(message, options?)` is valid.\n */\nexport type ErrorConstructor<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n> = new (message: string, options?: VercelErrorOptions<TCode>) => TError;\n\nexport interface ErrorFactory<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n> {\n create(message: string, options?: CreateErrorOptions<TCode>): TError;\n raise(message: string, options?: CreateErrorOptions<TCode>): never;\n report(message: string, options?: CreateErrorOptions<TCode>): TError;\n}\n\nexport interface CreateErrorsOptions<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n> {\n scope: string;\n ErrorClass?: ErrorConstructor<TCode, TError>;\n attributes?: ErrorAttributes;\n metadata?: ErrorMetadata;\n report?: (error: TError) => void;\n}\n\n/**\n * Create a scoped error namespace with type-safe error codes.\n *\n * Always returns `{ create, raise, report }`.\n * If no `report` callback is provided, `report` defaults to `console.error`.\n * If `ErrorClass` is provided, all errors are instances of that class.\n *\n * @example\n * ```ts\n * const errors = createErrors({\n * scope: 'database',\n * report: (error) => sentry.captureException(error),\n * });\n *\n * const error = errors.create('Connection failed', { code: 'conn_failed' });\n * errors.raise('Timeout', { code: 'timeout' }); // throws\n * errors.report('Pool exhausted', { code: 'pool_exhausted' }); // reports + returns\n * ```\n *\n * @example Custom error class\n * ```ts\n * class DatabaseError extends VercelError {\n * readonly retryable = true;\n * }\n *\n * const errors = createErrors({\n * scope: 'database',\n * ErrorClass: DatabaseError,\n * });\n *\n * const err = errors.create('Pool exhausted'); // DatabaseError\n * err.retryable; // true — fully typed\n * ```\n */\nexport function createErrors<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n>(options: CreateErrorsOptions<TCode, TError>): ErrorFactory<TCode, TError> {\n const ErrorClass = (options.ErrorClass ?? VercelError) as ErrorConstructor<\n TCode,\n TError\n >;\n const reportFn = options.report ?? ((error: TError) => console.error(error));\n\n function create(\n message: string,\n itemOptions: CreateErrorOptions<TCode> = {},\n ): TError {\n const mergedAttributes =\n options.attributes || itemOptions.attributes\n ? { ...options.attributes, ...itemOptions.attributes }\n : undefined;\n\n const mergedMetadata =\n options.metadata || itemOptions.metadata\n ? { ...options.metadata, ...itemOptions.metadata }\n : undefined;\n\n const mergedOptions: VercelErrorOptions<TCode> = {\n ...itemOptions,\n attributes: mergedAttributes,\n metadata: mergedMetadata,\n scope: options.scope,\n };\n\n return new ErrorClass(message, mergedOptions);\n }\n\n return {\n create,\n raise(message: string, itemOptions?: CreateErrorOptions<TCode>): never {\n throw create(message, itemOptions);\n },\n report(message: string, itemOptions?: CreateErrorOptions<TCode>): TError {\n const error = create(message, itemOptions);\n reportFn(error);\n return error;\n },\n };\n}\n","import { isObject } from '../_internal';\n\n/**\n * Check if a value is a standard JavaScript Error object.\n *\n * Handles cross-realm errors where `Error` objects from different execution\n * contexts (iframes, web workers, VM contexts) may not pass `instanceof Error`.\n */\nexport function isError(error: unknown): error is Error {\n if (!isObject(error)) {\n return false;\n }\n\n if (error instanceof Error) {\n return true;\n }\n\n return walkPrototypeForError(error);\n}\n\nfunction walkPrototypeForError<T extends object>(error: T): boolean {\n if (Object.prototype.toString.call(error) === '[object Error]') {\n return true;\n }\n\n const prototype = Object.getPrototypeOf(error) as T | null;\n return prototype === null ? false : walkPrototypeForError(prototype);\n}\n","import { isObject } from '../_internal';\nimport type { ErrorLike } from '../types';\n\n/**\n * Check if a value is an error-like object (has a `message` string property).\n */\nexport function isErrorLike(error: unknown): error is ErrorLike {\n return (\n isObject(error) && 'message' in error && typeof error.message === 'string'\n );\n}\n","import { isObject } from '../_internal';\n\n/**\n * Check if an error has a specific error code.\n */\nexport function hasCode<TCode extends string>(\n error: unknown,\n code: TCode,\n): error is { code: TCode };\n\n/**\n * Check if an error has any of the specified error codes.\n */\nexport function hasCode<TCode extends string>(\n error: unknown,\n codes: readonly TCode[],\n): error is { code: TCode };\n\n/**\n * Check if an error has a specific error code or any of the specified error codes.\n */\nexport function hasCode<TCode extends string>(\n error: unknown,\n codeOrCodes: TCode | readonly TCode[],\n): error is { code: TCode } {\n if (\n !isObject(error) ||\n !('code' in error) ||\n typeof error.code !== 'string'\n ) {\n return false;\n }\n\n if (Array.isArray(codeOrCodes)) {\n return codeOrCodes.includes(error.code as TCode);\n }\n\n return error.code === codeOrCodes;\n}\n","import { isObject } from '../_internal';\nimport { isErrorLike } from '../is-error-like';\n\n/**\n * Safely extract a message from any error value.\n *\n * Handles Error instances, error-like objects, plain objects (JSON stringified),\n * strings, and unknown values with a configurable fallback.\n */\nexport function getMessage(\n error: unknown,\n fallback?: string,\n): string | undefined {\n if (isErrorLike(error)) {\n return error.message;\n }\n\n if (typeof error === 'string') {\n return error;\n }\n\n if (isObject(error)) {\n try {\n return JSON.stringify(error);\n } catch {\n const constructorName =\n (error.constructor as { name?: string } | undefined)?.name ?? 'Object';\n return `[${constructorName} - Unable to Stringify Error Object]`;\n }\n }\n\n return fallback;\n}\n","import { isObject } from '../_internal';\n\n/**\n * Traverse the error cause chain to find the root cause.\n *\n * Walks down the chain following `cause` properties until it finds a value\n * without a cause. Uses a `WeakSet` to detect cycles.\n */\nexport function getRootCause(error: unknown): unknown {\n if (!isObject(error) || !('cause' in error)) {\n return error;\n }\n\n const visited = new WeakSet<object>();\n let current: unknown = error;\n\n while (\n isObject(current) &&\n 'cause' in current &&\n current.cause !== undefined\n ) {\n if (visited.has(current)) {\n break;\n }\n visited.add(current);\n current = current.cause;\n }\n\n return current;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+EA,SAAgB,aAGd,SAA0E;CAC1E,MAAM,aAAc,QAAQ,cAAc;CAI1C,MAAM,WAAW,QAAQ,YAAY,UAAkB,QAAQ,MAAM,MAAM;CAE3E,SAAS,OACP,SACA,cAAyC,EAAE,EACnC;EACR,MAAM,mBACJ,QAAQ,cAAc,YAAY,aAC9B;GAAE,GAAG,QAAQ;GAAY,GAAG,YAAY;GAAY,GACpD,KAAA;EAEN,MAAM,iBACJ,QAAQ,YAAY,YAAY,WAC5B;GAAE,GAAG,QAAQ;GAAU,GAAG,YAAY;GAAU,GAChD,KAAA;AASN,SAAO,IAAI,WAAW,SAP2B;GAC/C,GAAG;GACH,YAAY;GACZ,UAAU;GACV,OAAO,QAAQ;GAChB,CAE4C;;AAG/C,QAAO;EACL;EACA,MAAM,SAAiB,aAAgD;AACrE,SAAM,OAAO,SAAS,YAAY;;EAEpC,OAAO,SAAiB,aAAiD;GACvE,MAAM,QAAQ,OAAO,SAAS,YAAY;AAC1C,YAAS,MAAM;AACf,UAAO;;EAEV;;;;;;;;;;ACnHH,SAAgB,QAAQ,OAAgC;AACtD,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO;AAGT,KAAI,iBAAiB,MACnB,QAAO;AAGT,QAAO,sBAAsB,MAAM;;AAGrC,SAAS,sBAAwC,OAAmB;AAClE,KAAI,OAAO,UAAU,SAAS,KAAK,MAAM,KAAK,iBAC5C,QAAO;CAGT,MAAM,YAAY,OAAO,eAAe,MAAM;AAC9C,QAAO,cAAc,OAAO,QAAQ,sBAAsB,UAAU;;;;;;;ACpBtE,SAAgB,YAAY,OAAoC;AAC9D,QACE,SAAS,MAAM,IAAI,aAAa,SAAS,OAAO,MAAM,YAAY;;;;;;;ACatE,SAAgB,QACd,OACA,aAC0B;AAC1B,KACE,CAAC,SAAS,MAAM,IAChB,EAAE,UAAU,UACZ,OAAO,MAAM,SAAS,SAEtB,QAAO;AAGT,KAAI,MAAM,QAAQ,YAAY,CAC5B,QAAO,YAAY,SAAS,MAAM,KAAc;AAGlD,QAAO,MAAM,SAAS;;;;;;;;;;AC5BxB,SAAgB,WACd,OACA,UACoB;AACpB,KAAI,YAAY,MAAM,CACpB,QAAO,MAAM;AAGf,KAAI,OAAO,UAAU,SACnB,QAAO;AAGT,KAAI,SAAS,MAAM,CACjB,KAAI;AACF,SAAO,KAAK,UAAU,MAAM;SACtB;AAGN,SAAO,IADJ,MAAM,aAA+C,QAAQ,SACrC;;AAI/B,QAAO;;;;;;;;;;ACvBT,SAAgB,aAAa,OAAyB;AACpD,KAAI,CAAC,SAAS,MAAM,IAAI,EAAE,WAAW,OACnC,QAAO;CAGT,MAAM,0BAAU,IAAI,SAAiB;CACrC,IAAI,UAAmB;AAEvB,QACE,SAAS,QAAQ,IACjB,WAAW,WACX,QAAQ,UAAU,KAAA,GAClB;AACA,MAAI,QAAQ,IAAI,QAAQ,CACtB;AAEF,UAAQ,IAAI,QAAQ;AACpB,YAAU,QAAQ;;AAGpB,QAAO"} | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/create-errors/index.ts","../src/is-error/index.ts","../src/is-error-like/index.ts","../src/has-code/index.ts","../src/get-message/index.ts","../src/get-root-cause/index.ts"],"sourcesContent":["import type {\n ErrorAttributes,\n ErrorMetadata,\n VercelErrorOptions,\n} from '../types';\nimport { VercelError } from '../vercel-error';\n\n/**\n * Resolve a documentation URL for a code from a base URL.\n * A string base appends the code verbatim as a path segment. A function\n * base is called with the code. Returns `undefined` when no URL applies.\n */\nfunction resolveDocsUrl<TCode extends string>(\n docsBaseUrl: string | ((code: TCode) => string | undefined) | undefined,\n code: TCode,\n): string | undefined {\n if (!docsBaseUrl) return undefined;\n if (typeof docsBaseUrl === 'function') return docsBaseUrl(code);\n return `${docsBaseUrl.replace(/\\/+$/, '')}/${code}`;\n}\n\n/**\n * Per-error options passed to create/raise/report.\n * `scope` is omitted because it's the factory's identity.\n */\nexport type CreateErrorOptions<TCode extends string = string> = Omit<\n VercelErrorOptions<TCode>,\n 'scope'\n>;\n\n/**\n * Constructor constraint for custom error classes.\n * Any class that extends VercelError and accepts `(message, options?)` is valid.\n */\nexport type ErrorConstructor<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n> = new (message: string, options?: VercelErrorOptions<TCode>) => TError;\n\nexport interface ErrorFactory<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n> {\n create(message: string, options?: CreateErrorOptions<TCode>): TError;\n raise(message: string, options?: CreateErrorOptions<TCode>): never;\n report(message: string, options?: CreateErrorOptions<TCode>): TError;\n}\n\nexport interface CreateErrorsOptions<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n> {\n /**\n * Namespace injected into every error this factory produces.\n * Optional. Provide it only when a scope is useful, such as grouping errors\n * by service or subsystem. When omitted, errors have no `scope`.\n */\n scope?: string;\n\n /**\n * Base URL or resolver for documentation links. When a string, the error's\n * `code` is appended verbatim as a path segment\n * (e.g. `\"https://vercel.com/docs/errors\"` plus code `\"pool_exhausted\"` gives\n * `\"https://vercel.com/docs/errors/pool_exhausted\"`). The code is not\n * transformed, so use a function base if you need to change its case or shape.\n * When a function, it receives the `code` and returns a URL, or `undefined`\n * to skip.\n *\n * Applied only when an error has a `code` and no explicit `link`. A\n * per-error `link` always wins.\n */\n docsBaseUrl?: string | ((code: TCode) => string | undefined);\n\n ErrorClass?: ErrorConstructor<TCode, TError>;\n attributes?: ErrorAttributes;\n metadata?: ErrorMetadata;\n report?: (error: TError) => void;\n}\n\n/**\n * Create an error factory with type-safe error codes.\n *\n * Always returns `{ create, raise, report }`.\n * `scope` is optional. Provide it only when you want to group errors by a\n * namespace. When `docsBaseUrl` is set, each error's `link` is derived from\n * its `code`, unless you pass an explicit `link`.\n * When no `report` callback is provided, `report` defaults to `console.error`.\n * When `ErrorClass` is provided, all errors are instances of that class.\n *\n * @example\n * ```ts\n * class DatabaseError extends VercelError {\n * readonly retryable = true;\n * }\n *\n * const errors = createErrors({\n * scope: 'database',\n * ErrorClass: DatabaseError,\n * docsBaseUrl: 'https://vercel.com/docs/errors/database',\n * report: (error) => sentry.captureException(error),\n * });\n *\n * const error = errors.create('Connection failed', { code: 'conn_failed' });\n * error.retryable; // true, fully typed\n * error.link; // 'https://vercel.com/docs/errors/database/conn_failed'\n *\n * errors.raise('Timeout', { code: 'timeout' }); // throws\n * errors.report('Pool exhausted', { code: 'pool_exhausted' }); // reports + returns\n * ```\n */\nexport function createErrors<\n TCode extends string = string,\n TError extends VercelError<TCode> = VercelError<TCode>,\n>(\n options: CreateErrorsOptions<TCode, TError> = {},\n): ErrorFactory<TCode, TError> {\n const ErrorClass = (options.ErrorClass ?? VercelError) as ErrorConstructor<\n TCode,\n TError\n >;\n const reportFn = options.report ?? ((error: TError) => console.error(error));\n\n function create(\n message: string,\n itemOptions: CreateErrorOptions<TCode> = {},\n ): TError {\n const mergedAttributes =\n options.attributes || itemOptions.attributes\n ? { ...options.attributes, ...itemOptions.attributes }\n : undefined;\n\n const mergedMetadata =\n options.metadata || itemOptions.metadata\n ? { ...options.metadata, ...itemOptions.metadata }\n : undefined;\n\n const link =\n itemOptions.link ??\n (itemOptions.code !== undefined\n ? resolveDocsUrl(options.docsBaseUrl, itemOptions.code)\n : undefined);\n\n const mergedOptions: VercelErrorOptions<TCode> = {\n ...itemOptions,\n attributes: mergedAttributes,\n metadata: mergedMetadata,\n link,\n scope: options.scope,\n };\n\n return new ErrorClass(message, mergedOptions);\n }\n\n function raise(\n message: string,\n itemOptions?: CreateErrorOptions<TCode>,\n ): never {\n throw create(message, itemOptions);\n }\n\n function report(\n message: string,\n itemOptions?: CreateErrorOptions<TCode>,\n ): TError {\n const error = create(message, itemOptions);\n reportFn(error);\n return error;\n }\n\n return {\n create,\n raise,\n report,\n };\n}\n","import { isObject } from '../_internal';\n\n/**\n * Check if a value is a standard JavaScript Error object.\n *\n * Handles cross-realm errors where `Error` objects from different execution\n * contexts (iframes, web workers, VM contexts) may not pass `instanceof Error`.\n */\nexport function isError(error: unknown): error is Error {\n if (!isObject(error)) {\n return false;\n }\n\n if (error instanceof Error) {\n return true;\n }\n\n return walkPrototypeForError(error);\n}\n\nfunction walkPrototypeForError<T extends object>(error: T): boolean {\n if (Object.prototype.toString.call(error) === '[object Error]') {\n return true;\n }\n\n const prototype = Object.getPrototypeOf(error) as T | null;\n return prototype === null ? false : walkPrototypeForError(prototype);\n}\n","import { isObject } from '../_internal';\nimport type { ErrorLike } from '../types';\n\n/**\n * Check if a value is an error-like object (has a `message` string property).\n */\nexport function isErrorLike(error: unknown): error is ErrorLike {\n return (\n isObject(error) && 'message' in error && typeof error.message === 'string'\n );\n}\n","import { isObject } from '../_internal';\n\n/**\n * Check if an error has a specific error code.\n */\nexport function hasCode<TCode extends string>(\n error: unknown,\n code: TCode,\n): error is { code: TCode };\n\n/**\n * Check if an error has any of the specified error codes.\n */\nexport function hasCode<TCode extends string>(\n error: unknown,\n codes: readonly TCode[],\n): error is { code: TCode };\n\n/**\n * Check if an error has a specific error code or any of the specified error codes.\n */\nexport function hasCode<TCode extends string>(\n error: unknown,\n codeOrCodes: TCode | readonly TCode[],\n): error is { code: TCode } {\n if (\n !isObject(error) ||\n !('code' in error) ||\n typeof error.code !== 'string'\n ) {\n return false;\n }\n\n if (Array.isArray(codeOrCodes)) {\n return codeOrCodes.includes(error.code as TCode);\n }\n\n return error.code === codeOrCodes;\n}\n","import { isObject } from '../_internal';\nimport { isErrorLike } from '../is-error-like';\n\n/**\n * Safely extract a message from any error value.\n *\n * Handles Error instances, error-like objects, plain objects (JSON stringified),\n * strings, and unknown values with a configurable fallback.\n */\nexport function getMessage(\n error: unknown,\n fallback?: string,\n): string | undefined {\n if (isErrorLike(error)) {\n return error.message;\n }\n\n if (typeof error === 'string') {\n return error;\n }\n\n if (isObject(error)) {\n try {\n return JSON.stringify(error);\n } catch {\n const constructorName =\n (error.constructor as { name?: string } | undefined)?.name ?? 'Object';\n return `[${constructorName} - Unable to Stringify Error Object]`;\n }\n }\n\n return fallback;\n}\n","import { isObject } from '../_internal';\n\n/**\n * Traverse the error cause chain to find the root cause.\n *\n * Walks down the chain following `cause` properties until it finds a value\n * without a cause. Uses a `WeakSet` to detect cycles.\n */\nexport function getRootCause(error: unknown): unknown {\n if (!isObject(error) || !('cause' in error)) {\n return error;\n }\n\n const visited = new WeakSet<object>();\n let current: unknown = error;\n\n while (\n isObject(current) &&\n 'cause' in current &&\n current.cause !== undefined\n ) {\n if (visited.has(current)) {\n break;\n }\n visited.add(current);\n current = current.cause;\n }\n\n return current;\n}\n"],"mappings":";;;;;;;;AAYA,SAAS,eACP,aACA,MACoB;AACpB,KAAI,CAAC,YAAa,QAAO,KAAA;AACzB,KAAI,OAAO,gBAAgB,WAAY,QAAO,YAAY,KAAK;AAC/D,QAAO,GAAG,YAAY,QAAQ,QAAQ,GAAG,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4F/C,SAAgB,aAId,UAA8C,EAAE,EACnB;CAC7B,MAAM,aAAc,QAAQ,cAAc;CAI1C,MAAM,WAAW,QAAQ,YAAY,UAAkB,QAAQ,MAAM,MAAM;CAE3E,SAAS,OACP,SACA,cAAyC,EAAE,EACnC;EACR,MAAM,mBACJ,QAAQ,cAAc,YAAY,aAC9B;GAAE,GAAG,QAAQ;GAAY,GAAG,YAAY;GAAY,GACpD,KAAA;EAEN,MAAM,iBACJ,QAAQ,YAAY,YAAY,WAC5B;GAAE,GAAG,QAAQ;GAAU,GAAG,YAAY;GAAU,GAChD,KAAA;EAEN,MAAM,OACJ,YAAY,SACX,YAAY,SAAS,KAAA,IAClB,eAAe,QAAQ,aAAa,YAAY,KAAK,GACrD,KAAA;AAUN,SAAO,IAAI,WAAW,SAR2B;GAC/C,GAAG;GACH,YAAY;GACZ,UAAU;GACV;GACA,OAAO,QAAQ;GAChB,CAE4C;;CAG/C,SAAS,MACP,SACA,aACO;AACP,QAAM,OAAO,SAAS,YAAY;;CAGpC,SAAS,OACP,SACA,aACQ;EACR,MAAM,QAAQ,OAAO,SAAS,YAAY;AAC1C,WAAS,MAAM;AACf,SAAO;;AAGT,QAAO;EACL;EACA;EACA;EACD;;;;;;;;;;ACrKH,SAAgB,QAAQ,OAAgC;AACtD,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO;AAGT,KAAI,iBAAiB,MACnB,QAAO;AAGT,QAAO,sBAAsB,MAAM;;AAGrC,SAAS,sBAAwC,OAAmB;AAClE,KAAI,OAAO,UAAU,SAAS,KAAK,MAAM,KAAK,iBAC5C,QAAO;CAGT,MAAM,YAAY,OAAO,eAAe,MAAM;AAC9C,QAAO,cAAc,OAAO,QAAQ,sBAAsB,UAAU;;;;;;;ACpBtE,SAAgB,YAAY,OAAoC;AAC9D,QACE,SAAS,MAAM,IAAI,aAAa,SAAS,OAAO,MAAM,YAAY;;;;;;;ACatE,SAAgB,QACd,OACA,aAC0B;AAC1B,KACE,CAAC,SAAS,MAAM,IAChB,EAAE,UAAU,UACZ,OAAO,MAAM,SAAS,SAEtB,QAAO;AAGT,KAAI,MAAM,QAAQ,YAAY,CAC5B,QAAO,YAAY,SAAS,MAAM,KAAc;AAGlD,QAAO,MAAM,SAAS;;;;;;;;;;AC5BxB,SAAgB,WACd,OACA,UACoB;AACpB,KAAI,YAAY,MAAM,CACpB,QAAO,MAAM;AAGf,KAAI,OAAO,UAAU,SACnB,QAAO;AAGT,KAAI,SAAS,MAAM,CACjB,KAAI;AACF,SAAO,KAAK,UAAU,MAAM;SACtB;AAGN,SAAO,IADJ,MAAM,aAA+C,QAAQ,SACrC;;AAI/B,QAAO;;;;;;;;;;ACvBT,SAAgB,aAAa,OAAyB;AACpD,KAAI,CAAC,SAAS,MAAM,IAAI,EAAE,WAAW,OACnC,QAAO;CAGT,MAAM,0BAAU,IAAI,SAAiB;CACrC,IAAI,UAAmB;AAEvB,QACE,SAAS,QAAQ,IACjB,WAAW,WACX,QAAQ,UAAU,KAAA,GAClB;AACA,MAAI,QAAQ,IAAI,QAAQ,CACtB;AAEF,UAAQ,IAAI,QAAQ;AACpB,YAAU,QAAQ;;AAGpB,QAAO"} |
+13
-3
@@ -1,2 +0,2 @@ | ||
| import { o as HeadersLike, t as VercelError } from "./index-ZJPGDfSQ.js"; | ||
| import { o as HeadersLike, t as VercelError } from "./index-DmYEPWgi.js"; | ||
@@ -8,13 +8,23 @@ //#region src/to-error-response/index.d.ts | ||
| interface ErrorResponseParams { | ||
| /** HTTP status code for the response. Defaults to 500. */ | ||
| status?: number; | ||
| /** Stable, machine-readable identifier for this error. */ | ||
| code?: string; | ||
| /** Client-safe message describing what happened. */ | ||
| message: string; | ||
| /** Why the error happened, the root-cause explanation. */ | ||
| reason?: string; | ||
| /** Advisory tip that helps the developer, shown before `fix`. */ | ||
| hint?: string; | ||
| /** Actionable step that resolves the error. */ | ||
| fix?: string; | ||
| /** URL to documentation for this error. */ | ||
| link?: string; | ||
| } | ||
| interface ErrorResponseResult { | ||
| /** HTTP status code to send. */ | ||
| status: number; | ||
| /** Serialized response body, either JSON or structured text. */ | ||
| body: string; | ||
| /** Content-Type and any other headers to spread into the response. */ | ||
| headers: Record<string, string>; | ||
@@ -25,3 +35,3 @@ } | ||
| * | ||
| * Returns `{ status, body, headers }` — spread `headers` directly into your | ||
| * Returns `{ status, body, headers }`. Spread `headers` directly into your | ||
| * framework's response constructor. Content negotiation is handled internally | ||
@@ -40,3 +50,3 @@ * when a request or headers object is provided. | ||
| * ```ts | ||
| * // Minimal — always JSON | ||
| * // Minimal: always JSON | ||
| * const { status, body, headers } = errorResponse(error); | ||
@@ -43,0 +53,0 @@ * return new Response(body, { status, headers }); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"server.d.ts","names":[],"sources":["../src/to-error-response/index.ts","../src/wants-ansi/index.ts"],"mappings":";;;;AASA;;UAAiB,mBAAA;EACf,MAAA;EACA,IAAA;EACA,OAAA;EACA,MAAA;EACA,IAAA;EACA,GAAA;EACA,IAAA;AAAA;AAAA,UAGe,mBAAA;EACf,MAAA;EACA,IAAA;EACA,OAAA,EAAS,MAAA;AAAA;;;;;;;;AAoCX;;;;;;;;;;;;;;;;;;;;;;AC3CA;iBD2CgB,aAAA,CACd,KAAA,EAAO,WAAA,GAAc,mBAAA,EACrB,gBAAA,GAAmB,OAAA,GAAU,WAAA,GAC5B,mBAAA;;;;;AApDH;;;;;;;;;;;iBCMgB,SAAA,CACd,gBAAA,GAAmB,OAAA,GAAU,WAAA"} | ||
| {"version":3,"file":"server.d.ts","names":[],"sources":["../src/to-error-response/index.ts","../src/wants-ansi/index.ts"],"mappings":";;;;AASA;;UAAiB,mBAAA;EAAA;EAEf,MAAA;;EAEA,IAAA;;EAEA,OAAA;;EAEA,MAAA;;EAEA,IAAA;EAOF;EALE,GAAA;;EAEA,IAAA;AAAA;AAAA,UAGe,mBAAA;;EAEf,MAAA;;EAEA,IAAA;EAsCF;EApCE,OAAA,EAAS,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;ACjBX;;;;;;;;;;;iBDqDgB,aAAA,CACd,KAAA,EAAO,WAAA,GAAc,mBAAA,EACrB,gBAAA,GAAmB,OAAA,GAAU,WAAA,GAC5B,mBAAA;;;;;AA9DH;;;;;;;;;;;iBCMgB,SAAA,CACd,gBAAA,GAAmB,OAAA,GAAU,WAAA"} |
+25
-6
@@ -1,3 +0,3 @@ | ||
| import { a as link, i as hint, r as frame, t as fix } from "./format-DX87UrE2.js"; | ||
| import { t as isVercelError } from "./is-vercel-error-ODrWmu1P.js"; | ||
| import { a as link, i as hint, r as frame, t as fix } from "./format-CQYRTqAc.js"; | ||
| import { t as isVercelError } from "./is-vercel-error-5aSp5Azf.js"; | ||
| //#region src/wants-ansi/index.ts | ||
@@ -44,3 +44,3 @@ /** | ||
| * | ||
| * Returns `{ status, body, headers }` — spread `headers` directly into your | ||
| * Returns `{ status, body, headers }`. Spread `headers` directly into your | ||
| * framework's response constructor. Content negotiation is handled internally | ||
@@ -59,3 +59,3 @@ * when a request or headers object is provided. | ||
| * ```ts | ||
| * // Minimal — always JSON | ||
| * // Minimal: always JSON | ||
| * const { status, body, headers } = errorResponse(error); | ||
@@ -92,8 +92,24 @@ * return new Response(body, { status, headers }); | ||
| function buildPlainHeader(error) { | ||
| if (!error.message) return error.code ? `error: [${error.code}]` : "error:"; | ||
| return error.code ? `error: [${error.code}] ${error.message}` : `error: ${error.message}`; | ||
| } | ||
| /** | ||
| * Resolve the client-facing wire message. After production stripping the | ||
| * message can be empty, so fall back to a `[scope:code]` identifier built from | ||
| * whatever structured fields survive. The wire format omits `scope`, so it is | ||
| * folded into the message here. | ||
| */ | ||
| function resolveWireMessage({ message, scope, code }) { | ||
| if (message) return message; | ||
| const qualifier = [scope, code].filter(Boolean).join(":"); | ||
| return qualifier ? `[${qualifier}]` : ""; | ||
| } | ||
| function extractResponseData(error) { | ||
| if (isVercelError(error)) return { | ||
| error: { | ||
| message: error.userMessage ?? error.message, | ||
| message: resolveWireMessage({ | ||
| message: error.userMessage ?? error.message, | ||
| scope: error.scope, | ||
| code: error.code | ||
| }), | ||
| ...error.code ? { code: error.code } : {}, | ||
@@ -109,3 +125,6 @@ ...error.reason ? { reason: error.reason } : {}, | ||
| error: { | ||
| message: error.message, | ||
| message: resolveWireMessage({ | ||
| message: error.message, | ||
| code: error.code | ||
| }), | ||
| ...error.code ? { code: error.code } : {}, | ||
@@ -112,0 +131,0 @@ ...error.reason ? { reason: error.reason } : {}, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"server.js","names":[],"sources":["../src/wants-ansi/index.ts","../src/to-error-response/index.ts"],"sourcesContent":["import type { HeadersLike } from '../types';\n\n/**\n * Detect whether an HTTP request wants ANSI-formatted error responses.\n *\n * Accepts a `Request` or `HeadersLike` object: any object with a `get(name)` method\n * (e.g. Next.js `ReadonlyHeaders`, `Headers`, etc).\n *\n * Checks (in order):\n * 1. `X-Error-Format: ansi` header\n * 2. `Accept: text/plain+ansi` header\n * 3. `User-Agent` containing `curl/` (curl users get ANSI by default)\n *\n * Returns `false` if no input is provided or none of the checks match.\n */\nexport function wantsAnsi(\n requestOrHeaders?: Request | HeadersLike | null,\n): boolean {\n if (!requestOrHeaders) {\n return false;\n }\n\n const headers = _getHeadersLike(requestOrHeaders);\n\n const errorFormat = headers.get('x-error-format');\n if (errorFormat === 'ansi') {\n return true;\n }\n\n const accept = headers.get('accept');\n if (accept?.includes('text/plain+ansi')) {\n return true;\n }\n\n const userAgent = headers.get('user-agent');\n if (userAgent?.includes('curl/')) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Helper function to get a HeadersLike object from a Request or HeadersLike.\n *\n * If `input` has a `.headers` property with a `.get()` method, treat it as\n * a Request-like object and unwrap its headers.\n *\n * Otherwise assume `input` itself is already a HeadersLike (e.g. `Headers`, `ReadonlyHeaders`, etc).\n */\nfunction _getHeadersLike(input: Request | HeadersLike): HeadersLike {\n if (\n 'headers' in input &&\n typeof input.headers === 'object' &&\n input.headers !== null &&\n typeof (input.headers as HeadersLike).get === 'function'\n ) {\n return input.headers as HeadersLike;\n }\n return input as HeadersLike;\n}\n","import { fix, frame, hint, link } from '../format/index';\nimport { isVercelError } from '../is-vercel-error';\nimport type { ErrorResponse, HeadersLike } from '../types';\nimport type { VercelError } from '../vercel-error';\nimport { wantsAnsi } from '../wants-ansi';\n\n/**\n * Plain error parameters for building a response without a VercelError instance.\n */\nexport interface ErrorResponseParams {\n status?: number;\n code?: string;\n message: string;\n reason?: string;\n hint?: string;\n fix?: string;\n link?: string;\n}\n\nexport interface ErrorResponseResult {\n status: number;\n body: string;\n headers: Record<string, string>;\n}\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' } as const;\nconst TEXT_HEADERS = { 'Content-Type': 'text/plain; charset=utf-8' } as const;\n\n/**\n * Build a complete HTTP error response from a VercelError or plain parameters.\n *\n * Returns `{ status, body, headers }` — spread `headers` directly into your\n * framework's response constructor. Content negotiation is handled internally\n * when a request or headers object is provided.\n *\n * When given a VercelError, uses `userMessage` for the client-facing output.\n * Falls back to `message` if `userMessage` is not set.\n *\n * @param error - A VercelError instance or plain `{ message, code?, status? }` params\n * @param requestOrHeaders - Optional Request or HeadersLike for content negotiation.\n * When present and the client signals ANSI preference (curl, `X-Error-Format: ansi`),\n * the body is rendered as structured text. When absent, always returns JSON.\n *\n * @example\n * ```ts\n * // Minimal — always JSON\n * const { status, body, headers } = errorResponse(error);\n * return new Response(body, { status, headers });\n *\n * // With content negotiation\n * const { status, body, headers } = errorResponse(error, req);\n * return new Response(body, { status, headers });\n *\n * // Express\n * const { status, body, headers } = errorResponse(error, req);\n * res.status(status).set(headers).send(body);\n * ```\n */\nexport function errorResponse(\n error: VercelError | ErrorResponseParams,\n requestOrHeaders?: Request | HeadersLike,\n): ErrorResponseResult {\n const data = extractResponseData(error);\n\n if (wantsAnsi(requestOrHeaders)) {\n const text = isVercelError(error)\n ? error.toString()\n : frame(buildPlainHeader(data.error), [\n data.error.reason,\n hint(data.error.hint),\n fix(data.error.fix),\n link(data.error.link),\n ]);\n\n return {\n body: text,\n headers: { ...TEXT_HEADERS },\n status: data.status,\n };\n }\n\n return {\n body: JSON.stringify({ error: data.error }),\n headers: { ...JSON_HEADERS },\n status: data.status,\n };\n}\n\ninterface ExtractedData {\n status: number;\n error: ErrorResponse['error'];\n}\n\nfunction buildPlainHeader(error: ErrorResponse['error']): string {\n return error.code\n ? `error: [${error.code}] ${error.message}`\n : `error: ${error.message}`;\n}\n\nfunction extractResponseData(\n error: VercelError | ErrorResponseParams,\n): ExtractedData {\n if (isVercelError(error)) {\n return {\n error: {\n message: error.userMessage ?? error.message,\n ...(error.code ? { code: error.code } : {}),\n ...(error.reason ? { reason: error.reason } : {}),\n ...(error.hint ? { hint: error.hint } : {}),\n ...(error.fix ? { fix: error.fix } : {}),\n ...(error.link ? { link: error.link } : {}),\n },\n status: error.statusCode ?? 500,\n };\n }\n\n return {\n error: {\n message: error.message,\n ...(error.code ? { code: error.code } : {}),\n ...(error.reason ? { reason: error.reason } : {}),\n ...(error.hint ? { hint: error.hint } : {}),\n ...(error.fix ? { fix: error.fix } : {}),\n ...(error.link ? { link: error.link } : {}),\n },\n status: error.status ?? 500,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,SAAgB,UACd,kBACS;AACT,KAAI,CAAC,iBACH,QAAO;CAGT,MAAM,UAAU,gBAAgB,iBAAiB;AAGjD,KADoB,QAAQ,IAAI,iBAAiB,KAC7B,OAClB,QAAO;AAIT,KADe,QAAQ,IAAI,SAAS,EACxB,SAAS,kBAAkB,CACrC,QAAO;AAIT,KADkB,QAAQ,IAAI,aAAa,EAC5B,SAAS,QAAQ,CAC9B,QAAO;AAGT,QAAO;;;;;;;;;;AAWT,SAAS,gBAAgB,OAA2C;AAClE,KACE,aAAa,SACb,OAAO,MAAM,YAAY,YACzB,MAAM,YAAY,QAClB,OAAQ,MAAM,QAAwB,QAAQ,WAE9C,QAAO,MAAM;AAEf,QAAO;;;;AClCT,MAAM,eAAe,EAAE,gBAAgB,oBAAoB;AAC3D,MAAM,eAAe,EAAE,gBAAgB,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCpE,SAAgB,cACd,OACA,kBACqB;CACrB,MAAM,OAAO,oBAAoB,MAAM;AAEvC,KAAI,UAAU,iBAAiB,CAU7B,QAAO;EACL,MAVW,cAAc,MAAM,GAC7B,MAAM,UAAU,GAChB,MAAM,iBAAiB,KAAK,MAAM,EAAE;GAClC,KAAK,MAAM;GACX,KAAK,KAAK,MAAM,KAAK;GACrB,IAAI,KAAK,MAAM,IAAI;GACnB,KAAK,KAAK,MAAM,KAAK;GACtB,CAAC;EAIJ,SAAS,EAAE,GAAG,cAAc;EAC5B,QAAQ,KAAK;EACd;AAGH,QAAO;EACL,MAAM,KAAK,UAAU,EAAE,OAAO,KAAK,OAAO,CAAC;EAC3C,SAAS,EAAE,GAAG,cAAc;EAC5B,QAAQ,KAAK;EACd;;AAQH,SAAS,iBAAiB,OAAuC;AAC/D,QAAO,MAAM,OACT,WAAW,MAAM,KAAK,IAAI,MAAM,YAChC,UAAU,MAAM;;AAGtB,SAAS,oBACP,OACe;AACf,KAAI,cAAc,MAAM,CACtB,QAAO;EACL,OAAO;GACL,SAAS,MAAM,eAAe,MAAM;GACpC,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GAC1C,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,QAAQ,GAAG,EAAE;GAChD,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GAC1C,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,KAAK,GAAG,EAAE;GACvC,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GAC3C;EACD,QAAQ,MAAM,cAAc;EAC7B;AAGH,QAAO;EACL,OAAO;GACL,SAAS,MAAM;GACf,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GAC1C,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,QAAQ,GAAG,EAAE;GAChD,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GAC1C,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,KAAK,GAAG,EAAE;GACvC,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GAC3C;EACD,QAAQ,MAAM,UAAU;EACzB"} | ||
| {"version":3,"file":"server.js","names":[],"sources":["../src/wants-ansi/index.ts","../src/to-error-response/index.ts"],"sourcesContent":["import type { HeadersLike } from '../types';\n\n/**\n * Detect whether an HTTP request wants ANSI-formatted error responses.\n *\n * Accepts a `Request` or `HeadersLike` object: any object with a `get(name)` method\n * (e.g. Next.js `ReadonlyHeaders`, `Headers`, etc).\n *\n * Checks (in order):\n * 1. `X-Error-Format: ansi` header\n * 2. `Accept: text/plain+ansi` header\n * 3. `User-Agent` containing `curl/` (curl users get ANSI by default)\n *\n * Returns `false` if no input is provided or none of the checks match.\n */\nexport function wantsAnsi(\n requestOrHeaders?: Request | HeadersLike | null,\n): boolean {\n if (!requestOrHeaders) {\n return false;\n }\n\n const headers = _getHeadersLike(requestOrHeaders);\n\n const errorFormat = headers.get('x-error-format');\n if (errorFormat === 'ansi') {\n return true;\n }\n\n const accept = headers.get('accept');\n if (accept?.includes('text/plain+ansi')) {\n return true;\n }\n\n const userAgent = headers.get('user-agent');\n if (userAgent?.includes('curl/')) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Helper function to get a HeadersLike object from a Request or HeadersLike.\n *\n * If `input` has a `.headers` property with a `.get()` method, treat it as\n * a Request-like object and unwrap its headers.\n *\n * Otherwise assume `input` itself is already a HeadersLike (e.g. `Headers`, `ReadonlyHeaders`, etc).\n */\nfunction _getHeadersLike(input: Request | HeadersLike): HeadersLike {\n if (\n 'headers' in input &&\n typeof input.headers === 'object' &&\n input.headers !== null &&\n typeof (input.headers as HeadersLike).get === 'function'\n ) {\n return input.headers as HeadersLike;\n }\n return input as HeadersLike;\n}\n","import { fix, frame, hint, link } from '../format/index';\nimport { isVercelError } from '../is-vercel-error';\nimport type { ErrorResponse, HeadersLike } from '../types';\nimport type { VercelError } from '../vercel-error';\nimport { wantsAnsi } from '../wants-ansi';\n\n/**\n * Plain error parameters for building a response without a VercelError instance.\n */\nexport interface ErrorResponseParams {\n /** HTTP status code for the response. Defaults to 500. */\n status?: number;\n /** Stable, machine-readable identifier for this error. */\n code?: string;\n /** Client-safe message describing what happened. */\n message: string;\n /** Why the error happened, the root-cause explanation. */\n reason?: string;\n /** Advisory tip that helps the developer, shown before `fix`. */\n hint?: string;\n /** Actionable step that resolves the error. */\n fix?: string;\n /** URL to documentation for this error. */\n link?: string;\n}\n\nexport interface ErrorResponseResult {\n /** HTTP status code to send. */\n status: number;\n /** Serialized response body, either JSON or structured text. */\n body: string;\n /** Content-Type and any other headers to spread into the response. */\n headers: Record<string, string>;\n}\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' } as const;\nconst TEXT_HEADERS = { 'Content-Type': 'text/plain; charset=utf-8' } as const;\n\n/**\n * Build a complete HTTP error response from a VercelError or plain parameters.\n *\n * Returns `{ status, body, headers }`. Spread `headers` directly into your\n * framework's response constructor. Content negotiation is handled internally\n * when a request or headers object is provided.\n *\n * When given a VercelError, uses `userMessage` for the client-facing output.\n * Falls back to `message` if `userMessage` is not set.\n *\n * @param error - A VercelError instance or plain `{ message, code?, status? }` params\n * @param requestOrHeaders - Optional Request or HeadersLike for content negotiation.\n * When present and the client signals ANSI preference (curl, `X-Error-Format: ansi`),\n * the body is rendered as structured text. When absent, always returns JSON.\n *\n * @example\n * ```ts\n * // Minimal: always JSON\n * const { status, body, headers } = errorResponse(error);\n * return new Response(body, { status, headers });\n *\n * // With content negotiation\n * const { status, body, headers } = errorResponse(error, req);\n * return new Response(body, { status, headers });\n *\n * // Express\n * const { status, body, headers } = errorResponse(error, req);\n * res.status(status).set(headers).send(body);\n * ```\n */\nexport function errorResponse(\n error: VercelError | ErrorResponseParams,\n requestOrHeaders?: Request | HeadersLike,\n): ErrorResponseResult {\n const data = extractResponseData(error);\n\n if (wantsAnsi(requestOrHeaders)) {\n const text = isVercelError(error)\n ? error.toString()\n : frame(buildPlainHeader(data.error), [\n data.error.reason,\n hint(data.error.hint),\n fix(data.error.fix),\n link(data.error.link),\n ]);\n\n return {\n body: text,\n headers: { ...TEXT_HEADERS },\n status: data.status,\n };\n }\n\n return {\n body: JSON.stringify({ error: data.error }),\n headers: { ...JSON_HEADERS },\n status: data.status,\n };\n}\n\ninterface ExtractedData {\n status: number;\n error: ErrorResponse['error'];\n}\n\nfunction buildPlainHeader(error: ErrorResponse['error']): string {\n if (!error.message) {\n return error.code ? `error: [${error.code}]` : 'error:';\n }\n return error.code\n ? `error: [${error.code}] ${error.message}`\n : `error: ${error.message}`;\n}\n\ninterface WireMessageParts {\n message: string;\n scope?: string;\n code?: string;\n}\n\n/**\n * Resolve the client-facing wire message. After production stripping the\n * message can be empty, so fall back to a `[scope:code]` identifier built from\n * whatever structured fields survive. The wire format omits `scope`, so it is\n * folded into the message here.\n */\nfunction resolveWireMessage({\n message,\n scope,\n code,\n}: WireMessageParts): string {\n if (message) return message;\n const qualifier = [scope, code].filter(Boolean).join(':');\n return qualifier ? `[${qualifier}]` : '';\n}\n\nfunction extractResponseData(\n error: VercelError | ErrorResponseParams,\n): ExtractedData {\n if (isVercelError(error)) {\n return {\n error: {\n message: resolveWireMessage({\n message: error.userMessage ?? error.message,\n scope: error.scope,\n code: error.code,\n }),\n ...(error.code ? { code: error.code } : {}),\n ...(error.reason ? { reason: error.reason } : {}),\n ...(error.hint ? { hint: error.hint } : {}),\n ...(error.fix ? { fix: error.fix } : {}),\n ...(error.link ? { link: error.link } : {}),\n },\n status: error.statusCode ?? 500,\n };\n }\n\n return {\n error: {\n message: resolveWireMessage({ message: error.message, code: error.code }),\n ...(error.code ? { code: error.code } : {}),\n ...(error.reason ? { reason: error.reason } : {}),\n ...(error.hint ? { hint: error.hint } : {}),\n ...(error.fix ? { fix: error.fix } : {}),\n ...(error.link ? { link: error.link } : {}),\n },\n status: error.status ?? 500,\n };\n}\n"],"mappings":"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"} |
+3
-3
| { | ||
| "name": "@vercel/error", | ||
| "version": "0.0.1", | ||
| "version": "0.0.2", | ||
| "description": "A lightweight toolkit for structured, actionable errors for humans and agents", | ||
| "author": "Vercel", | ||
| "repository": { | ||
| "url": "git+https://github.com/vercel/error.git" | ||
| "url": "git+https://github.com/vercel-labs/error.git" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "restricted" | ||
| "access": "public" | ||
| }, | ||
@@ -12,0 +12,0 @@ "type": "module", |
| //#region src/format/index.ts | ||
| /** | ||
| * Render a Unicode tree frame with auto-detected formatting. | ||
| * | ||
| * @param header - The main error message line | ||
| * @param sections - Detail lines (falsy values are filtered out) | ||
| */ | ||
| function frame(header, sections) { | ||
| const { tree, color } = detectFormat(); | ||
| return renderFrame({ | ||
| color, | ||
| header, | ||
| sections, | ||
| tree | ||
| }); | ||
| } | ||
| /** | ||
| * Format a string as a hint. Nil-safe — returns `undefined` if falsy. | ||
| */ | ||
| function hint(text) { | ||
| if (!text) return; | ||
| return `hint: ${text}`; | ||
| } | ||
| /** | ||
| * Format a string as a fix suggestion. Nil-safe — returns `undefined` if falsy. | ||
| */ | ||
| function fix(text) { | ||
| if (!text) return; | ||
| return `fix: ${text}`; | ||
| } | ||
| /** | ||
| * Format a URL as a link. Nil-safe — returns `undefined` if falsy. | ||
| */ | ||
| function link(url) { | ||
| if (!url) return; | ||
| return `read more: ${url}`; | ||
| } | ||
| /** | ||
| * Detect formatting capabilities of the current environment. | ||
| * | ||
| * - `tree`: use Unicode box-drawing characters (├──, ╰──) | ||
| * - `color`: use ANSI escape codes (red, green, bold, underline) | ||
| * | ||
| * Detection: | ||
| * 1. Non-Node (no `process`) → plain (no tree, no color) | ||
| * 2. `NO_COLOR` env var → tree only, no color | ||
| * 3. `FORCE_COLOR` env var → tree + color | ||
| * 4. TTY → tree + color | ||
| * 5. Browser → plain | ||
| * 6. Fallback (piped, CI) → plain | ||
| */ | ||
| function detectFormat() { | ||
| try { | ||
| if (typeof process === "undefined") return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| if (process.env?.["NO_COLOR"] !== void 0) return { | ||
| color: false, | ||
| tree: true | ||
| }; | ||
| if (process.env?.["FORCE_COLOR"] !== void 0) return { | ||
| color: true, | ||
| tree: true | ||
| }; | ||
| if (process.stdout && "isTTY" in process.stdout && process.stdout.isTTY) return { | ||
| color: true, | ||
| tree: true | ||
| }; | ||
| } catch { | ||
| return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| } | ||
| if (typeof window !== "undefined") return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| return { | ||
| color: false, | ||
| tree: false | ||
| }; | ||
| } | ||
| /** | ||
| * Auto-format an error based on environment detection. | ||
| * Used by `VercelError.toString()` for zero-config output. | ||
| */ | ||
| function formatAuto(error) { | ||
| const { tree, color } = detectFormat(); | ||
| return renderFrame({ | ||
| color, | ||
| header: buildHeader(error, color), | ||
| sections: [ | ||
| error.reason, | ||
| hint(error.hint), | ||
| fix(error.fix), | ||
| link(error.link) | ||
| ], | ||
| tree | ||
| }); | ||
| } | ||
| const ANSI = { | ||
| bold: "\x1B[1m", | ||
| dim: "\x1B[2m", | ||
| green: "\x1B[32m", | ||
| red: "\x1B[31m", | ||
| reset: "\x1B[0m", | ||
| resetBold: "\x1B[22m", | ||
| underline: "\x1B[4m", | ||
| yellow: "\x1B[33m" | ||
| }; | ||
| const BOX = { | ||
| corner: "╰──", | ||
| cornerArrow: "╰─▸", | ||
| pipe: "│", | ||
| tee: "├──", | ||
| teeArrow: "├─▸" | ||
| }; | ||
| const ACTIONABLE_PREFIXES = [ | ||
| "hint: ", | ||
| "fix: ", | ||
| "read more: " | ||
| ]; | ||
| /** | ||
| * Build the error header line. | ||
| * | ||
| * With qualifier: `error: VercelError [scope:code] message` | ||
| * Without: `error: VercelError: message` | ||
| * ANSI: `error:` red+bold, name red, `[qualifier]` red, message red+bold | ||
| */ | ||
| function buildHeader(error, color) { | ||
| const qualifier = [error.scope, error.code].filter(Boolean).join(":"); | ||
| const plain = qualifier ? `error: ${error.name} [${qualifier}] ${error.message}` : `error: ${error.name}: ${error.message}`; | ||
| if (!color) return plain; | ||
| return `${`${ANSI.red}${ANSI.bold}error:${ANSI.resetBold}`} ${`${ANSI.red}${error.name}`}${qualifier ? ` [${qualifier}]` : ":"} ${`${ANSI.bold}${error.message}${ANSI.reset}`}`; | ||
| } | ||
| function filterSections(sections) { | ||
| const items = sections?.filter((s) => typeof s === "string" && s.length > 0); | ||
| return items && items.length > 0 ? items : void 0; | ||
| } | ||
| function colorizeLine(line) { | ||
| if (line.startsWith("hint: ")) return `${ANSI.yellow}${ANSI.bold}hint:${ANSI.reset} ${line.slice(6)}`; | ||
| if (line.startsWith("fix: ")) return `${ANSI.green}${ANSI.bold}fix:${ANSI.reset} ${line.slice(5)}`; | ||
| if (line.startsWith("read more: ")) return `${ANSI.bold}read more:${ANSI.reset} ${ANSI.underline}${line.slice(11)}${ANSI.reset}`; | ||
| return line; | ||
| } | ||
| function isActionable(line) { | ||
| return ACTIONABLE_PREFIXES.some((prefix) => line.startsWith(prefix)); | ||
| } | ||
| function renderFrame({ header, sections, tree, color }) { | ||
| const items = filterSections(sections); | ||
| if (!items) return header; | ||
| if (!tree) return [header, ...items.map((item) => ` ${item}`)].join("\n"); | ||
| const isLast = (i) => i === items.length - 1; | ||
| const lines = [header, color ? `${ANSI.dim}${BOX.pipe}${ANSI.reset}` : BOX.pipe]; | ||
| for (const [i, item] of items.entries()) { | ||
| const actionable = isActionable(item); | ||
| const connector = isLast(i) ? actionable ? BOX.cornerArrow : BOX.corner : actionable ? BOX.teeArrow : BOX.tee; | ||
| const content = color ? colorizeLine(item) : item; | ||
| const styledConnector = color ? `${ANSI.dim}${connector}${ANSI.reset}` : connector; | ||
| lines.push(`${styledConnector} ${content}`); | ||
| } | ||
| return lines.join("\n"); | ||
| } | ||
| //#endregion | ||
| export { link as a, hint as i, formatAuto as n, frame as r, fix as t }; | ||
| //# sourceMappingURL=format-DX87UrE2.js.map |
| {"version":3,"file":"format-DX87UrE2.js","names":[],"sources":["../src/format/index.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Render a Unicode tree frame with auto-detected formatting.\n *\n * @param header - The main error message line\n * @param sections - Detail lines (falsy values are filtered out)\n */\nexport function frame(\n header: string,\n sections?: (string | undefined | null | false)[],\n): string {\n const { tree, color } = detectFormat();\n return renderFrame({ color, header, sections, tree });\n}\n\n/**\n * Format a string as a hint. Nil-safe — returns `undefined` if falsy.\n */\nexport function hint(text: string | undefined | null): string | undefined {\n if (!text) {\n return undefined;\n }\n return `hint: ${text}`;\n}\n\n/**\n * Format a string as a fix suggestion. Nil-safe — returns `undefined` if falsy.\n */\nexport function fix(text: string | undefined | null): string | undefined {\n if (!text) {\n return undefined;\n }\n return `fix: ${text}`;\n}\n\n/**\n * Format a URL as a link. Nil-safe — returns `undefined` if falsy.\n */\nexport function link(url: string | undefined | null): string | undefined {\n if (!url) {\n return undefined;\n }\n return `read more: ${url}`;\n}\n\n// ---------------------------------------------------------------------------\n// Internal API (used by VercelError.toString)\n// ---------------------------------------------------------------------------\n\n/**\n * Detect formatting capabilities of the current environment.\n *\n * - `tree`: use Unicode box-drawing characters (├──, ╰──)\n * - `color`: use ANSI escape codes (red, green, bold, underline)\n *\n * Detection:\n * 1. Non-Node (no `process`) → plain (no tree, no color)\n * 2. `NO_COLOR` env var → tree only, no color\n * 3. `FORCE_COLOR` env var → tree + color\n * 4. TTY → tree + color\n * 5. Browser → plain\n * 6. Fallback (piped, CI) → plain\n */\nexport function detectFormat(): { tree: boolean; color: boolean } {\n try {\n if (typeof process === 'undefined') {\n return { color: false, tree: false };\n }\n if (process.env?.['NO_COLOR'] !== undefined) {\n return { color: false, tree: true };\n }\n if (process.env?.['FORCE_COLOR'] !== undefined) {\n return { color: true, tree: true };\n }\n if (process.stdout && 'isTTY' in process.stdout && process.stdout.isTTY) {\n return { color: true, tree: true };\n }\n } catch {\n return { color: false, tree: false };\n }\n\n if (typeof window !== 'undefined') {\n return { color: false, tree: false };\n }\n\n return { color: false, tree: false };\n}\n\n/**\n * Auto-format an error based on environment detection.\n * Used by `VercelError.toString()` for zero-config output.\n */\nexport function formatAuto(error: ErrorShape): string {\n const { tree, color } = detectFormat();\n const header = buildHeader(error, color);\n\n const sections = [\n error.reason,\n hint(error.hint),\n fix(error.fix),\n link(error.link),\n ];\n\n return renderFrame({ color, header, sections, tree });\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ninterface ErrorShape {\n name: string;\n message: string;\n code?: string;\n scope?: string;\n reason?: string;\n hint?: string;\n fix?: string;\n link?: string;\n}\n\nconst ANSI = {\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n green: '\\x1b[32m',\n red: '\\x1b[31m',\n reset: '\\x1b[0m',\n resetBold: '\\x1b[22m',\n underline: '\\x1b[4m',\n yellow: '\\x1b[33m',\n} as const;\n\nconst BOX = {\n corner: '╰──',\n cornerArrow: '╰─▸',\n pipe: '│',\n tee: '├──',\n teeArrow: '├─▸',\n} as const;\n\nconst ACTIONABLE_PREFIXES = ['hint: ', 'fix: ', 'read more: '] as const;\n\n/**\n * Build the error header line.\n *\n * With qualifier: `error: VercelError [scope:code] message`\n * Without: `error: VercelError: message`\n * ANSI: `error:` red+bold, name red, `[qualifier]` red, message red+bold\n */\nfunction buildHeader(error: ErrorShape, color: boolean): string {\n const qualifier = [error.scope, error.code].filter(Boolean).join(':');\n const plain = qualifier\n ? `error: ${error.name} [${qualifier}] ${error.message}`\n : `error: ${error.name}: ${error.message}`;\n\n if (!color) {\n return plain;\n }\n\n const label = `${ANSI.red}${ANSI.bold}error:${ANSI.resetBold}`;\n const name = `${ANSI.red}${error.name}`;\n const tag = qualifier ? ` [${qualifier}]` : ':';\n const message = `${ANSI.bold}${error.message}${ANSI.reset}`;\n\n return `${label} ${name}${tag} ${message}`;\n}\n\nfunction filterSections(\n sections: (string | undefined | null | false)[] | undefined,\n): string[] | undefined {\n const items = sections?.filter(\n (s): s is string => typeof s === 'string' && s.length > 0,\n );\n return items && items.length > 0 ? items : undefined;\n}\n\nfunction colorizeLine(line: string): string {\n if (line.startsWith('hint: ')) {\n return `${ANSI.yellow}${ANSI.bold}hint:${ANSI.reset} ${line.slice(6)}`;\n }\n if (line.startsWith('fix: ')) {\n return `${ANSI.green}${ANSI.bold}fix:${ANSI.reset} ${line.slice(5)}`;\n }\n if (line.startsWith('read more: ')) {\n return `${ANSI.bold}read more:${ANSI.reset} ${ANSI.underline}${line.slice(11)}${ANSI.reset}`;\n }\n return line;\n}\n\ninterface RenderFrameOptions {\n header: string;\n sections?: (string | undefined | null | false)[];\n tree: boolean;\n color: boolean;\n}\n\nfunction isActionable(line: string): boolean {\n return ACTIONABLE_PREFIXES.some((prefix) => line.startsWith(prefix));\n}\n\nfunction renderFrame({\n header,\n sections,\n tree,\n color,\n}: RenderFrameOptions): string {\n const items = filterSections(sections);\n if (!items) {\n return header;\n }\n\n if (!tree) {\n return [header, ...items.map((item) => ` ${item}`)].join('\\n');\n }\n\n const isLast = (i: number) => i === items.length - 1;\n const spacer = color ? `${ANSI.dim}${BOX.pipe}${ANSI.reset}` : BOX.pipe;\n const lines = [header, spacer];\n\n for (const [i, item] of items.entries()) {\n const actionable = isActionable(item);\n const connector = isLast(i)\n ? actionable\n ? BOX.cornerArrow\n : BOX.corner\n : actionable\n ? BOX.teeArrow\n : BOX.tee;\n const content = color ? colorizeLine(item) : item;\n const styledConnector = color\n ? `${ANSI.dim}${connector}${ANSI.reset}`\n : connector;\n lines.push(`${styledConnector} ${content}`);\n }\n\n return lines.join('\\n');\n}\n"],"mappings":";;;;;;;AAUA,SAAgB,MACd,QACA,UACQ;CACR,MAAM,EAAE,MAAM,UAAU,cAAc;AACtC,QAAO,YAAY;EAAE;EAAO;EAAQ;EAAU;EAAM,CAAC;;;;;AAMvD,SAAgB,KAAK,MAAqD;AACxE,KAAI,CAAC,KACH;AAEF,QAAO,SAAS;;;;;AAMlB,SAAgB,IAAI,MAAqD;AACvE,KAAI,CAAC,KACH;AAEF,QAAO,QAAQ;;;;;AAMjB,SAAgB,KAAK,KAAoD;AACvE,KAAI,CAAC,IACH;AAEF,QAAO,cAAc;;;;;;;;;;;;;;;;AAqBvB,SAAgB,eAAkD;AAChE,KAAI;AACF,MAAI,OAAO,YAAY,YACrB,QAAO;GAAE,OAAO;GAAO,MAAM;GAAO;AAEtC,MAAI,QAAQ,MAAM,gBAAgB,KAAA,EAChC,QAAO;GAAE,OAAO;GAAO,MAAM;GAAM;AAErC,MAAI,QAAQ,MAAM,mBAAmB,KAAA,EACnC,QAAO;GAAE,OAAO;GAAM,MAAM;GAAM;AAEpC,MAAI,QAAQ,UAAU,WAAW,QAAQ,UAAU,QAAQ,OAAO,MAChE,QAAO;GAAE,OAAO;GAAM,MAAM;GAAM;SAE9B;AACN,SAAO;GAAE,OAAO;GAAO,MAAM;GAAO;;AAGtC,KAAI,OAAO,WAAW,YACpB,QAAO;EAAE,OAAO;EAAO,MAAM;EAAO;AAGtC,QAAO;EAAE,OAAO;EAAO,MAAM;EAAO;;;;;;AAOtC,SAAgB,WAAW,OAA2B;CACpD,MAAM,EAAE,MAAM,UAAU,cAAc;AAUtC,QAAO,YAAY;EAAE;EAAO,QATb,YAAY,OAAO,MAAM;EASJ,UAPnB;GACf,MAAM;GACN,KAAK,MAAM,KAAK;GAChB,IAAI,MAAM,IAAI;GACd,KAAK,MAAM,KAAK;GACjB;EAE6C;EAAM,CAAC;;AAkBvD,MAAM,OAAO;CACX,MAAM;CACN,KAAK;CACL,OAAO;CACP,KAAK;CACL,OAAO;CACP,WAAW;CACX,WAAW;CACX,QAAQ;CACT;AAED,MAAM,MAAM;CACV,QAAQ;CACR,aAAa;CACb,MAAM;CACN,KAAK;CACL,UAAU;CACX;AAED,MAAM,sBAAsB;CAAC;CAAU;CAAS;CAAc;;;;;;;;AAS9D,SAAS,YAAY,OAAmB,OAAwB;CAC9D,MAAM,YAAY,CAAC,MAAM,OAAO,MAAM,KAAK,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;CACrE,MAAM,QAAQ,YACV,UAAU,MAAM,KAAK,IAAI,UAAU,IAAI,MAAM,YAC7C,UAAU,MAAM,KAAK,IAAI,MAAM;AAEnC,KAAI,CAAC,MACH,QAAO;AAQT,QAAO,GALO,GAAG,KAAK,MAAM,KAAK,KAAK,QAAQ,KAAK,YAKnC,GAJH,GAAG,KAAK,MAAM,MAAM,SACrB,YAAY,KAAK,UAAU,KAAK,IAGd,GAFd,GAAG,KAAK,OAAO,MAAM,UAAU,KAAK;;AAKtD,SAAS,eACP,UACsB;CACtB,MAAM,QAAQ,UAAU,QACrB,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS,EACzD;AACD,QAAO,SAAS,MAAM,SAAS,IAAI,QAAQ,KAAA;;AAG7C,SAAS,aAAa,MAAsB;AAC1C,KAAI,KAAK,WAAW,SAAS,CAC3B,QAAO,GAAG,KAAK,SAAS,KAAK,KAAK,OAAO,KAAK,MAAM,GAAG,KAAK,MAAM,EAAE;AAEtE,KAAI,KAAK,WAAW,QAAQ,CAC1B,QAAO,GAAG,KAAK,QAAQ,KAAK,KAAK,MAAM,KAAK,MAAM,GAAG,KAAK,MAAM,EAAE;AAEpE,KAAI,KAAK,WAAW,cAAc,CAChC,QAAO,GAAG,KAAK,KAAK,YAAY,KAAK,MAAM,GAAG,KAAK,YAAY,KAAK,MAAM,GAAG,GAAG,KAAK;AAEvF,QAAO;;AAUT,SAAS,aAAa,MAAuB;AAC3C,QAAO,oBAAoB,MAAM,WAAW,KAAK,WAAW,OAAO,CAAC;;AAGtE,SAAS,YAAY,EACnB,QACA,UACA,MACA,SAC6B;CAC7B,MAAM,QAAQ,eAAe,SAAS;AACtC,KAAI,CAAC,MACH,QAAO;AAGT,KAAI,CAAC,KACH,QAAO,CAAC,QAAQ,GAAG,MAAM,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,KAAK,KAAK;CAGjE,MAAM,UAAU,MAAc,MAAM,MAAM,SAAS;CAEnD,MAAM,QAAQ,CAAC,QADA,QAAQ,GAAG,KAAK,MAAM,IAAI,OAAO,KAAK,UAAU,IAAI,KACrC;AAE9B,MAAK,MAAM,CAAC,GAAG,SAAS,MAAM,SAAS,EAAE;EACvC,MAAM,aAAa,aAAa,KAAK;EACrC,MAAM,YAAY,OAAO,EAAE,GACvB,aACE,IAAI,cACJ,IAAI,SACN,aACE,IAAI,WACJ,IAAI;EACV,MAAM,UAAU,QAAQ,aAAa,KAAK,GAAG;EAC7C,MAAM,kBAAkB,QACpB,GAAG,KAAK,MAAM,YAAY,KAAK,UAC/B;AACJ,QAAM,KAAK,GAAG,gBAAgB,GAAG,UAAU;;AAG7C,QAAO,MAAM,KAAK,KAAK"} |
| //#region src/types.d.ts | ||
| /** | ||
| * Recursive type for structured metadata values. | ||
| * Supports arbitrary nesting for domain-specific context. | ||
| */ | ||
| type SerializableValue = string | number | boolean | null | undefined | SerializableValue[] | { | ||
| [key: string]: SerializableValue; | ||
| }; | ||
| /** | ||
| * Domain-specific structured context for debugging and logging. | ||
| * Can contain arbitrarily nested values. Server-side only — excluded from HTTP error responses. | ||
| * | ||
| * Route to: serialization, logging, debugging tools. | ||
| * | ||
| * @example { userId: '123', query: { table: 'users', limit: 50 } } | ||
| */ | ||
| type ErrorMetadata = Record<string, SerializableValue>; | ||
| /** | ||
| * Flat key-value pairs for observability and telemetry. | ||
| * Compatible with OpenTelemetry's AttributeValue type. | ||
| * | ||
| * Route to: tracing spans, Sentry tags, metrics dashboards. | ||
| * | ||
| * @example { 'http.method': 'POST', 'db.system': 'postgresql', 'retry.count': 3 } | ||
| */ | ||
| type ErrorAttributes = Record<string, string | number | boolean | string[] | number[] | boolean[] | undefined>; | ||
| /** | ||
| * Minimal interface for error-like objects with a message property. | ||
| */ | ||
| interface ErrorLike { | ||
| message: string; | ||
| name?: string; | ||
| stack?: string; | ||
| } | ||
| /** | ||
| * Configuration options for creating a VercelError instance. | ||
| */ | ||
| interface VercelErrorOptions<TCode extends string = string> { | ||
| attributes?: ErrorAttributes; | ||
| cause?: unknown; | ||
| code?: TCode; | ||
| fix?: string; | ||
| hint?: string; | ||
| link?: string; | ||
| metadata?: ErrorMetadata; | ||
| reason?: string; | ||
| requestId?: string; | ||
| scope?: string; | ||
| statusCode?: number; | ||
| userMessage?: string; | ||
| /** Reserved — automatically captured from Error */ | ||
| stack?: never; | ||
| /** Reserved — pass message as first constructor argument */ | ||
| message?: never; | ||
| /** Reserved — hardcoded to "VercelError" for minification safety */ | ||
| name?: never; | ||
| } | ||
| /** | ||
| * The canonical wire format for all Vercel HTTP error responses. | ||
| * | ||
| * `message` maps to `userMessage` from VercelError, falling back to `message`. | ||
| */ | ||
| interface ErrorResponse { | ||
| error: { | ||
| code?: string; | ||
| message: string; | ||
| reason?: string; | ||
| hint?: string; | ||
| fix?: string; | ||
| link?: string; | ||
| }; | ||
| } | ||
| /** | ||
| * Minimal interface for any object that can look up headers by name. | ||
| * Compatible with `Headers`, `ReadonlyHeaders` (Next.js), and plain objects. | ||
| */ | ||
| interface HeadersLike { | ||
| get(name: string): string | null; | ||
| } | ||
| //#endregion | ||
| //#region src/vercel-error/index.d.ts | ||
| /** | ||
| * Structured error class for Vercel. | ||
| * | ||
| * Every error should answer: | ||
| * 1. **What** happened? → `message` | ||
| * 2. **Why** did it happen? → `reason` | ||
| * 3. **What** could help? → `hint` | ||
| * 4. **How** to fix it? → `fix` | ||
| * 5. **Where** to learn more? → `link` | ||
| * | ||
| * Key features: | ||
| * - Zero runtime dependencies | ||
| * - Human + agent readable context (`reason`, `hint`, `fix`, `link`, `userMessage`) | ||
| * - Type-safe error codes via generics | ||
| * - Separate `metadata` (domain context) and `attributes` (OTel observability) | ||
| * - Error chaining with proper cause tracking | ||
| * - Environment-aware `toString()` (auto-detects ANSI) | ||
| * - Cross-realm compatibility via stable Symbol tag | ||
| * | ||
| * @template TCode - Strongly typed error code union | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new VercelError('Database connection pool exhausted', { | ||
| * code: 'pool_exhausted', | ||
| * scope: 'database', | ||
| * reason: 'All 20 connections are in use and none have been released.', | ||
| * hint: 'Consider using pgBouncer for connection pooling.', | ||
| * fix: 'Increase max_connections or add pgBouncer.', | ||
| * link: 'https://vercel.com/docs/storage/neon#connection-pooling', | ||
| * }); | ||
| * ``` | ||
| */ | ||
| declare class VercelError<TCode extends string = string> extends Error { | ||
| readonly code?: TCode; | ||
| readonly scope?: string; | ||
| statusCode?: number; | ||
| reason?: string; | ||
| hint?: string; | ||
| fix?: string; | ||
| link?: string; | ||
| userMessage?: string; | ||
| requestId?: string; | ||
| metadata?: ErrorMetadata; | ||
| attributes?: ErrorAttributes; | ||
| constructor(message: string, options?: VercelErrorOptions<TCode>); | ||
| private static readonly JSON_EXCLUDE; | ||
| /** | ||
| * JSON representation for `JSON.stringify`. | ||
| * | ||
| * Surfaces non-enumerable Error properties (`name`, `message`, `stack`) | ||
| * alongside all VercelError fields. Omits `cause` (may be circular or | ||
| * contain sensitive internals) and any `undefined` values. | ||
| */ | ||
| toJSON(): Record<string, unknown>; | ||
| /** | ||
| * Environment-aware string representation. | ||
| * Auto-detects ANSI support and renders accordingly. | ||
| */ | ||
| override toString(): string; | ||
| } | ||
| //#endregion | ||
| export { ErrorResponse as a, ErrorMetadata as i, ErrorAttributes as n, HeadersLike as o, ErrorLike as r, VercelErrorOptions as s, VercelError as t }; | ||
| //# sourceMappingURL=index-ZJPGDfSQ.d.ts.map |
| {"version":3,"file":"index-ZJPGDfSQ.d.ts","names":[],"sources":["../src/types.ts","../src/vercel-error/index.ts"],"mappings":";;AAIA;;;KAAY,iBAAA,kDAMR,iBAAA;EAAA,eACiB,iBAAA;AAAA;;;;AAUrB;;;;;KAAY,aAAA,GAAgB,MAAA,SAAe,iBAAA;;;;;AAkB3C;;;;KARY,eAAA,GAAkB,MAAA;;;;UAQb,SAAA;EACf,OAAA;EACA,IAAA;EACA,KAAA;AAAA;;;;UAMe,kBAAA;EACf,UAAA,GAAa,eAAA;EACb,KAAA;EACA,IAAA,GAAO,KAAA;EACP,GAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA,GAAW,aAAA;EACX,MAAA;EACA,SAAA;EACA,KAAA;EACA,UAAA;EACA,WAAA;;EAGA,KAAA;;EAEA,OAAA;;EAEA,IAAA;AAAA;;;AAQF;;;UAAiB,aAAA;EACf,KAAA;IACE,IAAA;IACA,OAAA;IACA,MAAA;IACA,IAAA;IACA,GAAA;IACA,IAAA;EAAA;AAAA;AAQJ;;;;AAAA,UAAiB,WAAA;EACf,GAAA,CAAI,IAAA;AAAA;;;AAvFN;;;;;;;;;AAiBA;;;;;AAUA;;;;;AAQA;;;;;;;;;AASA;;;;;AA5CA,cCqCa,WAAA,wCAAmD,KAAA;EAAA,SACrD,IAAA,GAAO,KAAA;EAAA,SACP,KAAA;EAET,UAAA;EAEA,MAAA;EACA,IAAA;EACA,GAAA;EACA,IAAA;EACA,WAAA;EAEA,SAAA;EACA,QAAA,GAAW,aAAA;EACX,UAAA,GAAa,eAAA;EAEb,WAAA,CAAY,OAAA,UAAiB,OAAA,GAAS,kBAAA,CAAmB,KAAA;EAAA,wBAyBjC,YAAA;;;;;;;;EASxB,MAAA,CAAA,GAAU,MAAA;;;ADhBZ;;WCkCW,QAAA,CAAA;AAAA"} |
| import { n as VERCEL_ERROR_TAG, r as isObject, t as VercelError } from "./vercel-error-BARO-T1l.js"; | ||
| //#region src/is-vercel-error/index.ts | ||
| /** | ||
| * Check if a value is a VercelError instance. | ||
| * | ||
| * Uses a dual-strategy approach for reliable cross-realm detection: | ||
| * 1. Fast path: `instanceof` check for same-realm objects | ||
| * 2. Fallback: Symbol-based tag verification for cross-realm compatibility | ||
| */ | ||
| function isVercelError(error) { | ||
| if (error instanceof VercelError) return true; | ||
| return isObject(error) && VERCEL_ERROR_TAG in error && error[VERCEL_ERROR_TAG] === true; | ||
| } | ||
| //#endregion | ||
| export { isVercelError as t }; | ||
| //# sourceMappingURL=is-vercel-error-ODrWmu1P.js.map |
| {"version":3,"file":"is-vercel-error-ODrWmu1P.js","names":[],"sources":["../src/is-vercel-error/index.ts"],"sourcesContent":["import { isObject } from '../_internal';\nimport { VERCEL_ERROR_TAG } from '../constants';\nimport { VercelError } from '../vercel-error';\n\n/**\n * Check if a value is a VercelError instance.\n *\n * Uses a dual-strategy approach for reliable cross-realm detection:\n * 1. Fast path: `instanceof` check for same-realm objects\n * 2. Fallback: Symbol-based tag verification for cross-realm compatibility\n */\nexport function isVercelError(error: unknown): error is VercelError {\n if (error instanceof VercelError) {\n return true;\n }\n\n return (\n isObject(error) &&\n VERCEL_ERROR_TAG in error &&\n error[VERCEL_ERROR_TAG] === true\n );\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,cAAc,OAAsC;AAClE,KAAI,iBAAiB,YACnB,QAAO;AAGT,QACE,SAAS,MAAM,IACf,oBAAoB,SACpB,MAAM,sBAAsB"} |
| import { n as formatAuto } from "./format-DX87UrE2.js"; | ||
| //#region src/_internal/index.ts | ||
| function isObject(value) { | ||
| return value !== null && typeof value === "object" && !Array.isArray(value); | ||
| } | ||
| //#endregion | ||
| //#region src/constants.ts | ||
| /** Stable tag to identify VercelError instances across realms */ | ||
| const VERCEL_ERROR_TAG = Symbol.for("__vercel_error"); | ||
| //#endregion | ||
| //#region src/vercel-error/index.ts | ||
| /** | ||
| * Structured error class for Vercel. | ||
| * | ||
| * Every error should answer: | ||
| * 1. **What** happened? → `message` | ||
| * 2. **Why** did it happen? → `reason` | ||
| * 3. **What** could help? → `hint` | ||
| * 4. **How** to fix it? → `fix` | ||
| * 5. **Where** to learn more? → `link` | ||
| * | ||
| * Key features: | ||
| * - Zero runtime dependencies | ||
| * - Human + agent readable context (`reason`, `hint`, `fix`, `link`, `userMessage`) | ||
| * - Type-safe error codes via generics | ||
| * - Separate `metadata` (domain context) and `attributes` (OTel observability) | ||
| * - Error chaining with proper cause tracking | ||
| * - Environment-aware `toString()` (auto-detects ANSI) | ||
| * - Cross-realm compatibility via stable Symbol tag | ||
| * | ||
| * @template TCode - Strongly typed error code union | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * throw new VercelError('Database connection pool exhausted', { | ||
| * code: 'pool_exhausted', | ||
| * scope: 'database', | ||
| * reason: 'All 20 connections are in use and none have been released.', | ||
| * hint: 'Consider using pgBouncer for connection pooling.', | ||
| * fix: 'Increase max_connections or add pgBouncer.', | ||
| * link: 'https://vercel.com/docs/storage/neon#connection-pooling', | ||
| * }); | ||
| * ``` | ||
| */ | ||
| var VercelError = class VercelError extends Error { | ||
| code; | ||
| scope; | ||
| statusCode; | ||
| reason; | ||
| hint; | ||
| fix; | ||
| link; | ||
| userMessage; | ||
| requestId; | ||
| metadata; | ||
| attributes; | ||
| constructor(message, options = {}) { | ||
| super(message, { cause: options.cause }); | ||
| this.name = "VercelError"; | ||
| this.code = options.code; | ||
| this.scope = options.scope; | ||
| this.statusCode = options.statusCode; | ||
| this.reason = options.reason; | ||
| this.hint = options.hint; | ||
| this.fix = options.fix; | ||
| this.link = options.link; | ||
| this.userMessage = options.userMessage; | ||
| this.requestId = options.requestId; | ||
| this.metadata = options.metadata; | ||
| this.attributes = options.attributes; | ||
| Object.defineProperty(this, VERCEL_ERROR_TAG, { | ||
| configurable: false, | ||
| enumerable: false, | ||
| value: true, | ||
| writable: false | ||
| }); | ||
| } | ||
| static JSON_EXCLUDE = new Set(["name", "cause"]); | ||
| /** | ||
| * JSON representation for `JSON.stringify`. | ||
| * | ||
| * Surfaces non-enumerable Error properties (`name`, `message`, `stack`) | ||
| * alongside all VercelError fields. Omits `cause` (may be circular or | ||
| * contain sensitive internals) and any `undefined` values. | ||
| */ | ||
| toJSON() { | ||
| return { | ||
| message: this.message, | ||
| name: this.name, | ||
| ...this.stack ? { stack: this.stack } : {}, | ||
| ...Object.fromEntries(Object.entries(this).filter(([key, value]) => !VercelError.JSON_EXCLUDE.has(key) && value !== void 0)) | ||
| }; | ||
| } | ||
| /** | ||
| * Environment-aware string representation. | ||
| * Auto-detects ANSI support and renders accordingly. | ||
| */ | ||
| toString() { | ||
| return formatAuto(this); | ||
| } | ||
| }; | ||
| //#endregion | ||
| export { VERCEL_ERROR_TAG as n, isObject as r, VercelError as t }; | ||
| //# sourceMappingURL=vercel-error-BARO-T1l.js.map |
| {"version":3,"file":"vercel-error-BARO-T1l.js","names":[],"sources":["../src/_internal/index.ts","../src/constants.ts","../src/vercel-error/index.ts"],"sourcesContent":["export function isObject(\n value: unknown,\n): value is Record<PropertyKey, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n","/** Stable tag to identify VercelError instances across realms */\nexport const VERCEL_ERROR_TAG: unique symbol = Symbol.for('__vercel_error');\n","import { VERCEL_ERROR_TAG } from '../constants';\nimport { formatAuto } from '../format/index';\nimport type {\n ErrorAttributes,\n ErrorMetadata,\n VercelErrorOptions,\n} from '../types';\n\n/**\n * Structured error class for Vercel.\n *\n * Every error should answer:\n * 1. **What** happened? → `message`\n * 2. **Why** did it happen? → `reason`\n * 3. **What** could help? → `hint`\n * 4. **How** to fix it? → `fix`\n * 5. **Where** to learn more? → `link`\n *\n * Key features:\n * - Zero runtime dependencies\n * - Human + agent readable context (`reason`, `hint`, `fix`, `link`, `userMessage`)\n * - Type-safe error codes via generics\n * - Separate `metadata` (domain context) and `attributes` (OTel observability)\n * - Error chaining with proper cause tracking\n * - Environment-aware `toString()` (auto-detects ANSI)\n * - Cross-realm compatibility via stable Symbol tag\n *\n * @template TCode - Strongly typed error code union\n *\n * @example\n * ```ts\n * throw new VercelError('Database connection pool exhausted', {\n * code: 'pool_exhausted',\n * scope: 'database',\n * reason: 'All 20 connections are in use and none have been released.',\n * hint: 'Consider using pgBouncer for connection pooling.',\n * fix: 'Increase max_connections or add pgBouncer.',\n * link: 'https://vercel.com/docs/storage/neon#connection-pooling',\n * });\n * ```\n */\nexport class VercelError<TCode extends string = string> extends Error {\n readonly code?: TCode;\n readonly scope?: string;\n\n statusCode?: number;\n\n reason?: string;\n hint?: string;\n fix?: string;\n link?: string;\n userMessage?: string;\n\n requestId?: string;\n metadata?: ErrorMetadata;\n attributes?: ErrorAttributes;\n\n constructor(message: string, options: VercelErrorOptions<TCode> = {}) {\n super(message, { cause: options.cause });\n\n this.name = 'VercelError';\n\n this.code = options.code;\n this.scope = options.scope;\n this.statusCode = options.statusCode;\n this.reason = options.reason;\n this.hint = options.hint;\n this.fix = options.fix;\n this.link = options.link;\n this.userMessage = options.userMessage;\n this.requestId = options.requestId;\n this.metadata = options.metadata;\n this.attributes = options.attributes;\n\n Object.defineProperty(this, VERCEL_ERROR_TAG, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n }\n\n private static readonly JSON_EXCLUDE = new Set(['name', 'cause']);\n\n /**\n * JSON representation for `JSON.stringify`.\n *\n * Surfaces non-enumerable Error properties (`name`, `message`, `stack`)\n * alongside all VercelError fields. Omits `cause` (may be circular or\n * contain sensitive internals) and any `undefined` values.\n */\n toJSON(): Record<string, unknown> {\n return {\n message: this.message,\n name: this.name,\n ...(this.stack ? { stack: this.stack } : {}),\n ...Object.fromEntries(\n Object.entries(this).filter(\n ([key, value]) =>\n !VercelError.JSON_EXCLUDE.has(key) && value !== undefined,\n ),\n ),\n };\n }\n\n /**\n * Environment-aware string representation.\n * Auto-detects ANSI support and renders accordingly.\n */\n override toString(): string {\n return formatAuto(this);\n }\n}\n"],"mappings":";;AAAA,SAAgB,SACd,OACuC;AACvC,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;;;;ACF7E,MAAa,mBAAkC,OAAO,IAAI,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACwC3E,IAAa,cAAb,MAAa,oBAAmD,MAAM;CACpE;CACA;CAEA;CAEA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CAEA,YAAY,SAAiB,UAAqC,EAAE,EAAE;AACpE,QAAM,SAAS,EAAE,OAAO,QAAQ,OAAO,CAAC;AAExC,OAAK,OAAO;AAEZ,OAAK,OAAO,QAAQ;AACpB,OAAK,QAAQ,QAAQ;AACrB,OAAK,aAAa,QAAQ;AAC1B,OAAK,SAAS,QAAQ;AACtB,OAAK,OAAO,QAAQ;AACpB,OAAK,MAAM,QAAQ;AACnB,OAAK,OAAO,QAAQ;AACpB,OAAK,cAAc,QAAQ;AAC3B,OAAK,YAAY,QAAQ;AACzB,OAAK,WAAW,QAAQ;AACxB,OAAK,aAAa,QAAQ;AAE1B,SAAO,eAAe,MAAM,kBAAkB;GAC5C,cAAc;GACd,YAAY;GACZ,OAAO;GACP,UAAU;GACX,CAAC;;CAGJ,OAAwB,eAAe,IAAI,IAAI,CAAC,QAAQ,QAAQ,CAAC;;;;;;;;CASjE,SAAkC;AAChC,SAAO;GACL,SAAS,KAAK;GACd,MAAM,KAAK;GACX,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,OAAO,GAAG,EAAE;GAC3C,GAAG,OAAO,YACR,OAAO,QAAQ,KAAK,CAAC,QAClB,CAAC,KAAK,WACL,CAAC,YAAY,aAAa,IAAI,IAAI,IAAI,UAAU,KAAA,EACnD,CACF;GACF;;;;;;CAOH,WAA4B;AAC1B,SAAO,WAAW,KAAK"} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
111002
15.93%1163
13.8%