🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@vercel/error

Package Overview
Dependencies
Maintainers
4
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vercel/error - npm Package Compare versions

Comparing version
0.0.1
to
0.0.2
+227
dist/format-CQYRTqAc.js
//#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,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"}

@@ -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,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 };

@@ -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"}

@@ -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"}

@@ -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"}

@@ -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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"}
{
"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":"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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 — 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"}