Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@block65/custom-error

Package Overview
Dependencies
Maintainers
2
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@block65/custom-error - npm Package Compare versions

Comparing version
13.0.0-rc.0
to
14.0.0
+241
lib/custom-error.ts
import { isErrorLike } from "serialize-error";
import type { ErrorDetail, LocalisedMessage } from "./types.ts";
import { withNullProto } from "./utils.ts";
export type DebugData = Record<string, unknown>;
const StatusCode = {
OK: 0 as const,
CANCELLED: 1 as const,
UNKNOWN: 2 as const,
INVALID_ARGUMENT: 3 as const,
DEADLINE_EXCEEDED: 4 as const,
NOT_FOUND: 5 as const,
ALREADY_EXISTS: 6 as const,
PERMISSION_DENIED: 7 as const,
RESOURCE_EXHAUSTED: 8 as const,
FAILED_PRECONDITION: 9 as const,
ABORTED: 10 as const,
OUT_OF_RANGE: 11 as const,
UNIMPLEMENTED: 12 as const,
INTERNAL: 13 as const,
UNAVAILABLE: 14 as const,
DATA_LOSS: 15 as const,
UNAUTHENTICATED: 16 as const,
}
// just export the type, we CustomError.XX should be used for the actual code
export type StatusCode = typeof StatusCode[keyof typeof StatusCode];
const statusCodes: ReadonlySet<number> = new Set(Object.values(StatusCode));
export function isStatusCode(value: unknown): value is StatusCode {
return typeof value === 'number' && statusCodes.has(value);
}
export type SerializedError<T extends StatusCode> = {
readonly debug?: DebugData;
readonly stack?: string;
readonly cause?: SerializedError<StatusCode>[];
readonly details?: ErrorDetail[];
readonly name: string;
readonly message: string;
readonly code: T;
};
const kCustomError = Symbol.for("CustomError");
export class CustomError extends Error {
static readonly OK = StatusCode.OK;
static readonly CANCELLED = StatusCode.CANCELLED;
static readonly UNKNOWN = StatusCode.UNKNOWN;
static readonly INVALID_ARGUMENT = StatusCode.INVALID_ARGUMENT;
static readonly DEADLINE_EXCEEDED = StatusCode.DEADLINE_EXCEEDED;
static readonly NOT_FOUND = StatusCode.NOT_FOUND;
static readonly ALREADY_EXISTS = StatusCode.ALREADY_EXISTS;
static readonly PERMISSION_DENIED = StatusCode.PERMISSION_DENIED;
static readonly RESOURCE_EXHAUSTED = StatusCode.RESOURCE_EXHAUSTED;
static readonly FAILED_PRECONDITION = StatusCode.FAILED_PRECONDITION;
static readonly ABORTED = StatusCode.ABORTED;
static readonly OUT_OF_RANGE = StatusCode.OUT_OF_RANGE;
static readonly UNIMPLEMENTED = StatusCode.UNIMPLEMENTED;
static readonly INTERNAL = StatusCode.INTERNAL;
static readonly UNAVAILABLE = StatusCode.UNAVAILABLE;
static readonly DATA_LOSS = StatusCode.DATA_LOSS;
static readonly UNAUTHENTICATED = StatusCode.UNAUTHENTICATED;
static http = Object.freeze({
[CustomError.OK]: 200,
[CustomError.CANCELLED]: 499,
[CustomError.UNKNOWN]: 500,
[CustomError.INVALID_ARGUMENT]: 400,
[CustomError.DEADLINE_EXCEEDED]: 504,
[CustomError.NOT_FOUND]: 404,
[CustomError.ALREADY_EXISTS]: 409,
[CustomError.PERMISSION_DENIED]: 403,
[CustomError.RESOURCE_EXHAUSTED]: 429,
[CustomError.FAILED_PRECONDITION]: 400,
[CustomError.ABORTED]: 409,
[CustomError.OUT_OF_RANGE]: 422,
[CustomError.UNIMPLEMENTED]: 501,
[CustomError.INTERNAL]: 500,
[CustomError.UNAVAILABLE]: 503,
[CustomError.DATA_LOSS]: 500,
[CustomError.UNAUTHENTICATED]: 401,
} as const);
/**
* The previous error that occurred, useful if "wrapping" an error to hide
* sensitive details
* @type {Error | CustomError | unknown}
*/
public override readonly cause?: Error | CustomError | unknown;
/**
* Further error details suitable for end user consumption
* @type {ErrorDetail[]}
*/
public details?: ErrorDetail[];
/**
* Status code suitable to coarsely determine the reason for error
*/
readonly code: StatusCode = CustomError.UNKNOWN;
/**
* Contains arbitrary debug data for developer troubleshooting
* @type {DebugData}
* @private
*/
#debug?: DebugData;
/**
*
* @param {string} message Developer facing message, in English.
* @param {Error | CustomError | unknown} cause
*/
constructor(message?: string, cause?: Error | CustomError | unknown) {
super(message, { cause });
this.cause = cause;
// FF doesnt have captureStackTrace
if ('captureStackTrace' in Error) {
Error.captureStackTrace(this, this.constructor);
}
Object.setPrototypeOf(this, new.target.prototype);
}
public static isCustomError(value: unknown): value is CustomError {
return !!value && typeof value === "object" && kCustomError in value;
}
/**
* Add arbitrary debug data to the error object for developer troubleshooting
*/
public debug(data: DebugData): this {
this.#debug = withNullProto({
...this.#debug,
...data,
});
return this;
}
/**
* Adds further error details suitable for end user consumption
* @param {ErrorDetail} details
* @return {this}
*/
public addDetail(...details: ErrorDetail[]) {
this.details = (this.details || []).concat(details);
return this;
}
/**
* A "safe" serialised version of the error designed for end user consumption
*/
public toJSONSummary() {
const localised = this.details?.find(
(detail): detail is LocalisedMessage => "locale" in detail,
);
return {
...(localised?.message && {
message: localised.message,
}),
code: this.code,
...(this.details && { details: this.details }),
};
}
/**
* JSON representation of the error object that can be "hydrated" later
*/
public toJSON() {
return withNullProto({
name: this.name,
message: this.message,
code: this.code,
...(this.details && { details: this.details }),
...(isErrorLike(this.cause) && {
cause:
"toJSON" in this.cause && typeof this.cause.toJSON === "function"
? this.cause.toJSON()
: {
message: this.cause.message,
name: "Error",
},
}),
...(this.stack && { stack: this.stack }),
...(this.#debug && { debug: this.#debug }),
});
}
/**
* "Hydrates" a previously serialised error object
*/
public static fromJSON<const T extends StatusCode>(
params: SerializedError<T>,
) {
const { message, details, code } = params;
class ImportedError extends CustomError {
override readonly code = code as StatusCode;
}
const err = new ImportedError(message).debug({
params,
});
if (details) {
err.addDetail(...details);
}
return err;
}
/**
* An automatically determined HTTP status code
*/
public static suggestHttpResponseCode(err: Error | CustomError | unknown) {
return (
(CustomError.isCustomError(err) && CustomError.http[err.code]) ||
CustomError.http[CustomError.UNKNOWN] ||
500
);
}
}
// Mark all instances of 'CustomError'
Object.defineProperty(CustomError.prototype, kCustomError, {
value: true,
enumerable: false,
writable: false,
});
// allow enumeration of status getter
Object.defineProperty(CustomError.prototype, "status", {
enumerable: true,
});
import { addKnownErrorConstructor } from "serialize-error";
import { CustomError } from "./custom-error.ts";
try {
addKnownErrorConstructor(CustomError);
} catch{}
export * from "./custom-error.ts";
export * from "./serialize.ts";
export type * from "./types.ts";
import {
type ErrorLike,
type ErrorObject,
isErrorLike,
serializeError,
} from "serialize-error";
import { CustomError } from "./custom-error.ts";
function flatten(
err: unknown | ErrorLike | Error | CustomError,
accum: (Error | CustomError)[] = [],
): (Error | CustomError)[] {
if (isErrorLike(err)) {
if ("cause" in err && err.cause) {
return flatten(err.cause, [...accum, err]);
}
return [...accum, err];
}
return accum;
}
function recursiveSerializeError(
err: unknown | ErrorLike | Error | CustomError,
): ErrorObject {
if (CustomError.isCustomError(err)) {
const { cause, ...rest } = serializeError(err);
const causes = cause ? flatten(cause) : undefined;
return {
...rest,
...(causes && {
cause: causes.map(recursiveSerializeError),
}),
} satisfies ErrorObject;
}
if (isErrorLike(err)) {
const { name, message, stack, cause, code, ...rest } = serializeError(err);
return {
...(name && { name }),
...(message && { message }),
...(code && { code }),
...(stack && { stack }),
...(!!cause && { cause: [recursiveSerializeError(cause)] }),
...(rest && { debug: rest }),
};
}
// Not an error object, maybe primitive or null, undefined
return {
name: "Error",
message: String(err),
debug: {
typeofErr: typeof err,
err: String(err),
},
};
}
export { recursiveSerializeError as serializeError };
export interface ErrorInfo {
reason: string;
metadata: Record<string, string | number>;
}
export interface RetryInfo {
delay: number;
}
export interface BadRequest {
violations: { field: string; description: string }[];
}
export interface LocalisedMessage {
locale: "en";
message: string;
}
export interface Help {
url: string;
description: string;
}
export interface QuotaFailure {
violations: {
/**
* subject of which quota check failed ie: `account:1234567`
*/
subject: string;
/**
* description of quota failure
*/
description: string;
}[];
}
export type ErrorDetail =
| ErrorInfo
| RetryInfo
| QuotaFailure
| BadRequest
| LocalisedMessage
| Help;
export function withNullProto<const T extends Record<PropertyKey, unknown>>(
obj: T,
) {
return Object.assign<T, T>(Object.create(null), obj);
}
+15
-18
{
"name": "@block65/custom-error",
"version": "13.0.0-rc.0",
"version": "14.0.0",
"private": false,
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/block65/custom-error"
},
"type": "module",
"exports": {
".": {
"types": "./dist/lib/index.d.ts",
"default": "./dist/lib/index.js"
}
},
"exports": "./lib/main.ts",
"files": [
"dist/lib/*.js",
"dist/lib/*.d.ts"
"lib"
],
"dependencies": {
"serialize-error": "^12.0.0"
"serialize-error": "^13.0.1"
},
"devDependencies": {
"@tsconfig/node18": "^18.2.4",
"@tsconfig/strictest": "^2.0.5",
"vitest": "^2.1.8",
"@biomejs/biome": "^1.9.4",
"@types/node": "^20.17.12",
"typescript": "^5.7.3"
"@tsconfig/node24": "^24.0.4",
"@tsconfig/strictest": "^2.0.8",
"@types/node": "^24.0.0",
"typescript": "^5.8.0",
"vitest": "^3.0.0"
},
"engines": {
"node": ">=20.0.0"
"node": ">=24.0.0"
},
"scripts": {
"preversion": "make clean && make test && make"
"preversion": "make test && make"
}
}
import type { ErrorDetail } from "./types.js";
export type DebugData = Record<string, unknown>;
declare enum StatusCode {
OK = 0,
CANCELLED = 1,
UNKNOWN = 2,
INVALID_ARGUMENT = 3,
DEADLINE_EXCEEDED = 4,
NOT_FOUND = 5,
ALREADY_EXISTS = 6,
PERMISSION_DENIED = 7,
RESOURCE_EXHAUSTED = 8,
FAILED_PRECONDITION = 9,
ABORTED = 10,
OUT_OF_RANGE = 11,
UNIMPLEMENTED = 12,
INTERNAL = 13,
UNAVAILABLE = 14,
DATA_LOSS = 15,
UNAUTHENTICATED = 16
}
export type { StatusCode };
type SerializedError<T extends StatusCode | number> = {
readonly debug?: DebugData;
readonly stack?: string;
readonly cause?: SerializedError<StatusCode>[];
readonly details?: ErrorDetail[];
readonly name: string;
readonly message: string;
readonly code: T;
};
export declare class CustomError extends Error {
#private;
static readonly OK = StatusCode.OK;
static readonly CANCELLED = StatusCode.CANCELLED;
static readonly UNKNOWN = StatusCode.UNKNOWN;
static readonly INVALID_ARGUMENT = StatusCode.INVALID_ARGUMENT;
static readonly DEADLINE_EXCEEDED = StatusCode.DEADLINE_EXCEEDED;
static readonly NOT_FOUND = StatusCode.NOT_FOUND;
static readonly ALREADY_EXISTS = StatusCode.ALREADY_EXISTS;
static readonly PERMISSION_DENIED = StatusCode.PERMISSION_DENIED;
static readonly RESOURCE_EXHAUSTED = StatusCode.RESOURCE_EXHAUSTED;
static readonly FAILED_PRECONDITION = StatusCode.FAILED_PRECONDITION;
static readonly ABORTED = StatusCode.ABORTED;
static readonly OUT_OF_RANGE = StatusCode.OUT_OF_RANGE;
static readonly UNIMPLEMENTED = StatusCode.UNIMPLEMENTED;
static readonly INTERNAL = StatusCode.INTERNAL;
static readonly UNAVAILABLE = StatusCode.UNAVAILABLE;
static readonly DATA_LOSS = StatusCode.DATA_LOSS;
static readonly UNAUTHENTICATED = StatusCode.UNAUTHENTICATED;
static http: Readonly<{
readonly 0: 200;
readonly 1: 299;
readonly 2: 500;
readonly 3: 400;
readonly 4: 504;
readonly 5: 404;
readonly 6: 409;
readonly 7: 403;
readonly 8: 403;
readonly 9: 400;
readonly 10: 299;
readonly 11: 400;
readonly 12: 501;
readonly 13: 500;
readonly 14: 503;
readonly 15: 500;
readonly 16: 401;
}>;
/**
* The previous error that occurred, useful if "wrapping" an error to hide
* sensitive details
* @type {Error | CustomError | unknown}
*/
readonly cause?: Error | CustomError | unknown;
/**
* Further error details suitable for end user consumption
* @type {ErrorDetail[]}
*/
details?: ErrorDetail[];
/**
* Status code suitable to coarsely determine the reason for error
*/
readonly code: StatusCode;
/**
*
* @param {string} message Developer facing message, in English.
* @param {Error | CustomError | unknown} cause
*/
constructor(message?: string, cause?: Error | CustomError | unknown);
static isCustomError(value: unknown): value is CustomError;
/**
* Add arbitrary debug data to the error object for developer troubleshooting
*/
debug(data: DebugData): this;
/**
* Adds further error details suitable for end user consumption
* @param {ErrorDetail} details
* @return {this}
*/
addDetail(...details: ErrorDetail[]): this;
/**
* A "safe" serialised version of the error designed for end user consumption
*/
toJSONSummary(): {
details?: ErrorDetail[];
code: StatusCode;
message?: string;
};
/**
* JSON representation of the error object that can be "hydrated" later
*/
toJSON(): {
readonly debug?: DebugData;
readonly stack?: string;
readonly cause?: any;
readonly details?: ErrorDetail[];
readonly name: string;
readonly message: string;
readonly code: StatusCode;
};
/**
* "Hydrates" a previously serialised error object
*/
static fromJSON<const T extends StatusCode | number>(params: SerializedError<T>): {
readonly code: T;
/**
* The previous error that occurred, useful if "wrapping" an error to hide
* sensitive details
* @type {Error | CustomError | unknown}
*/
readonly cause?: Error | CustomError | unknown;
/**
* Further error details suitable for end user consumption
* @type {ErrorDetail[]}
*/
details?: ErrorDetail[];
/**
* Contains arbitrary debug data for developer troubleshooting
* @type {DebugData}
* @private
*/
"__#1@#debug"?: DebugData;
/**
* Add arbitrary debug data to the error object for developer troubleshooting
*/
debug(data: DebugData): /*elided*/ any;
/**
* Adds further error details suitable for end user consumption
* @param {ErrorDetail} details
* @return {this}
*/
addDetail(...details: ErrorDetail[]): /*elided*/ any;
/**
* A "safe" serialised version of the error designed for end user consumption
*/
toJSONSummary(): {
details?: ErrorDetail[];
code: StatusCode;
message?: string;
};
/**
* JSON representation of the error object that can be "hydrated" later
*/
toJSON(): {
readonly debug?: DebugData;
readonly stack?: string;
readonly cause?: any;
readonly details?: ErrorDetail[];
readonly name: string;
readonly message: string;
readonly code: StatusCode;
};
name: string;
message: string;
stack?: string;
};
/**
* An automatically determined HTTP status code
*/
static suggestHttpResponseCode(err: Error | CustomError | unknown): 200 | 299 | 500 | 400 | 504 | 404 | 409 | 403 | 501 | 503 | 401;
}
import { isErrorLike } from "serialize-error";
import { withNullProto } from "./utils.js";
var StatusCode;
(function (StatusCode) {
StatusCode[StatusCode["OK"] = 0] = "OK";
StatusCode[StatusCode["CANCELLED"] = 1] = "CANCELLED";
StatusCode[StatusCode["UNKNOWN"] = 2] = "UNKNOWN";
StatusCode[StatusCode["INVALID_ARGUMENT"] = 3] = "INVALID_ARGUMENT";
StatusCode[StatusCode["DEADLINE_EXCEEDED"] = 4] = "DEADLINE_EXCEEDED";
StatusCode[StatusCode["NOT_FOUND"] = 5] = "NOT_FOUND";
StatusCode[StatusCode["ALREADY_EXISTS"] = 6] = "ALREADY_EXISTS";
StatusCode[StatusCode["PERMISSION_DENIED"] = 7] = "PERMISSION_DENIED";
StatusCode[StatusCode["RESOURCE_EXHAUSTED"] = 8] = "RESOURCE_EXHAUSTED";
StatusCode[StatusCode["FAILED_PRECONDITION"] = 9] = "FAILED_PRECONDITION";
StatusCode[StatusCode["ABORTED"] = 10] = "ABORTED";
StatusCode[StatusCode["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
StatusCode[StatusCode["UNIMPLEMENTED"] = 12] = "UNIMPLEMENTED";
StatusCode[StatusCode["INTERNAL"] = 13] = "INTERNAL";
StatusCode[StatusCode["UNAVAILABLE"] = 14] = "UNAVAILABLE";
StatusCode[StatusCode["DATA_LOSS"] = 15] = "DATA_LOSS";
StatusCode[StatusCode["UNAUTHENTICATED"] = 16] = "UNAUTHENTICATED";
})(StatusCode || (StatusCode = {}));
const kCustomError = Symbol.for("CustomError");
export class CustomError extends Error {
static OK = StatusCode.OK;
static CANCELLED = StatusCode.CANCELLED;
static UNKNOWN = StatusCode.UNKNOWN;
static INVALID_ARGUMENT = StatusCode.INVALID_ARGUMENT;
static DEADLINE_EXCEEDED = StatusCode.DEADLINE_EXCEEDED;
static NOT_FOUND = StatusCode.NOT_FOUND;
static ALREADY_EXISTS = StatusCode.ALREADY_EXISTS;
static PERMISSION_DENIED = StatusCode.PERMISSION_DENIED;
static RESOURCE_EXHAUSTED = StatusCode.RESOURCE_EXHAUSTED;
static FAILED_PRECONDITION = StatusCode.FAILED_PRECONDITION;
static ABORTED = StatusCode.ABORTED;
static OUT_OF_RANGE = StatusCode.OUT_OF_RANGE;
static UNIMPLEMENTED = StatusCode.UNIMPLEMENTED;
static INTERNAL = StatusCode.INTERNAL;
static UNAVAILABLE = StatusCode.UNAVAILABLE;
static DATA_LOSS = StatusCode.DATA_LOSS;
static UNAUTHENTICATED = StatusCode.UNAUTHENTICATED;
static http = Object.freeze({
[CustomError.OK]: 200,
[CustomError.CANCELLED]: 299,
[CustomError.UNKNOWN]: 500,
[CustomError.INVALID_ARGUMENT]: 400,
[CustomError.DEADLINE_EXCEEDED]: 504,
[CustomError.NOT_FOUND]: 404,
[CustomError.ALREADY_EXISTS]: 409,
[CustomError.PERMISSION_DENIED]: 403,
[CustomError.RESOURCE_EXHAUSTED]: 403,
[CustomError.FAILED_PRECONDITION]: 400,
[CustomError.ABORTED]: 299,
[CustomError.OUT_OF_RANGE]: 400,
[CustomError.UNIMPLEMENTED]: 501,
[CustomError.INTERNAL]: 500,
[CustomError.UNAVAILABLE]: 503,
[CustomError.DATA_LOSS]: 500,
[CustomError.UNAUTHENTICATED]: 401,
});
/**
* The previous error that occurred, useful if "wrapping" an error to hide
* sensitive details
* @type {Error | CustomError | unknown}
*/
cause;
/**
* Further error details suitable for end user consumption
* @type {ErrorDetail[]}
*/
details;
/**
* Status code suitable to coarsely determine the reason for error
*/
code = CustomError.UNKNOWN;
/**
* Contains arbitrary debug data for developer troubleshooting
* @type {DebugData}
* @private
*/
#debug;
/**
*
* @param {string} message Developer facing message, in English.
* @param {Error | CustomError | unknown} cause
*/
constructor(message, cause) {
super(message, { cause });
this.cause = cause;
// FF doesnt have captureStackTrace
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
Object.setPrototypeOf(this, new.target.prototype);
}
static isCustomError(value) {
return !!value && typeof value === "object" && kCustomError in value;
}
/**
* Add arbitrary debug data to the error object for developer troubleshooting
*/
debug(data) {
this.#debug = withNullProto({
...this.#debug,
...data,
});
return this;
}
/**
* Adds further error details suitable for end user consumption
* @param {ErrorDetail} details
* @return {this}
*/
addDetail(...details) {
this.details = (this.details || []).concat(details);
return this;
}
/**
* A "safe" serialised version of the error designed for end user consumption
*/
toJSONSummary() {
const localised = this.details?.find((detail) => "locale" in detail);
return {
...(localised?.message && {
message: localised.message,
}),
code: this.code,
...(this.details && { details: this.details }),
};
}
/**
* JSON representation of the error object that can be "hydrated" later
*/
toJSON() {
return withNullProto({
name: this.name,
message: this.message,
code: this.code,
...(this.details && { details: this.details }),
...(isErrorLike(this.cause) && {
cause: "toJSON" in this.cause && typeof this.cause.toJSON === "function"
? this.cause.toJSON()
: {
message: this.cause.message,
name: "Error",
},
}),
...(this.stack && { stack: this.stack }),
...(this.#debug && { debug: this.#debug }),
});
}
/**
* "Hydrates" a previously serialised error object
*/
static fromJSON(params) {
const { message, details, code } = params;
class ImportedError extends CustomError {
code = code;
}
const err = new ImportedError(message).debug({
params,
});
if (details) {
err.addDetail(...details);
}
return err;
}
/**
* An automatically determined HTTP status code
*/
static suggestHttpResponseCode(err) {
return ((CustomError.isCustomError(err) && CustomError.http[err.code]) ||
CustomError.http[CustomError.UNKNOWN]);
}
}
// Mark all instances of 'CustomError'
Object.defineProperty(CustomError.prototype, kCustomError, {
value: true,
enumerable: false,
writable: false,
});
// allow enumeration of status getter
Object.defineProperty(CustomError.prototype, "status", {
enumerable: true,
});
export * from "./custom-error.js";
export * from "./serialize.js";
export type * from "./types.js";
import { addKnownErrorConstructor } from "serialize-error";
import { CustomError } from "./custom-error.js";
addKnownErrorConstructor(CustomError);
export * from "./custom-error.js";
export * from "./serialize.js";
import { type ErrorLike, type ErrorObject } from "serialize-error";
import { CustomError } from "./custom-error.js";
declare function recursiveSerializeError(err: unknown | ErrorLike | Error | CustomError): ErrorObject;
export { recursiveSerializeError as serializeError };
import { isErrorLike, serializeError, } from "serialize-error";
import { CustomError } from "./custom-error.js";
function flatten(err, accum = []) {
if (isErrorLike(err)) {
if ("cause" in err && err.cause) {
return flatten(err.cause, [...accum, err]);
}
return [...accum, err];
}
return accum;
}
function recursiveSerializeError(err) {
if (CustomError.isCustomError(err)) {
const { cause, ...rest } = serializeError(err);
const causes = cause ? flatten(cause) : undefined;
return {
...rest,
...(causes && {
cause: causes.map(recursiveSerializeError),
}),
};
}
if (isErrorLike(err)) {
const { name, message, stack, cause, code, ...rest } = serializeError(err);
return {
...(name && { name }),
...(message && { message }),
...(code && { code }),
...(stack && { stack }),
...(!!cause && { cause: [recursiveSerializeError(cause)] }),
...(rest && { debug: rest }),
};
}
// Not an error object, maybe primitive or null, undefined
return {
name: "Error",
message: String(err),
debug: {
typeofErr: typeof err,
err: String(err),
},
};
}
export { recursiveSerializeError as serializeError };
export interface ErrorInfo {
reason: string;
metadata: Record<string, string | number>;
}
export interface RetryInfo {
delay: number;
}
export interface BadRequest {
violations: {
field: string;
description: string;
}[];
}
export interface LocalisedMessage {
locale: "en";
message: string;
}
export interface Help {
url: string;
description: string;
}
export interface QuotaFailure {
violations: {
/**
* subject of which quota check failed ie: `account:1234567`
*/
subject: string;
/**
* description of quota failure
*/
description: string;
}[];
}
export type ErrorDetail = ErrorInfo | RetryInfo | QuotaFailure | BadRequest | LocalisedMessage | Help;
export {};
export declare function withNullProto<const T extends Record<PropertyKey, unknown>>(obj: T): T;
export function withNullProto(obj) {
return Object.assign(Object.create(null), obj);
}