UNPKG

@hirosystems/api-toolkit

Version:
135 lines 4.82 kB
"use strict"; /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ Object.defineProperty(exports, "__esModule", { value: true }); exports.addKnownErrorConstructor = addKnownErrorConstructor; exports.isErrorLike = isErrorLike; exports.serializeError = serializeError; exports.deserializeError = deserializeError; const errorConstructors = new Map([ // Native ES errors https://262.ecma-international.org/12.0/#sec-well-known-intrinsic-objects Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateError, // Built-in errors globalThis.DOMException, // Node-specific errors https://nodejs.org/api/errors.html globalThis.AssertionError, globalThis.SystemError, ] // Non-native Errors are used with `globalThis` because they might be missing. This filter drops them when undefined. .filter(Boolean) .map(constructor => [constructor.name, constructor])); /** * Custom errors can only be deserialized correctly if they are registered here. */ function addKnownErrorConstructor(constructor) { try { new constructor(); } catch (error) { throw new Error(`The error constructor "${constructor.name}" is not compatible`, { cause: error, }); } errorConstructors.set(constructor.name, constructor); } const commonProperties = { name: false, message: false, stack: false, code: true, cause: false, errors: false, }; function isErrorLike(value) { return (typeof value === 'object' && value !== null && 'name' in value && 'message' in value && 'stack' in value && typeof value.name === 'string' && typeof value.message === 'string' && typeof value.stack === 'string'); } function serializeError(subject) { if (!isErrorLike(subject)) { // If the subject is not an error, for example `throw "boom", then we throw. // This function should only be passed error objects, callers can use `isErrorLike`. throw new TypeError('Failed to serialize error, expected an error object'); } const data = { constructorName: subject.constructor.name ?? 'Error', // new field name: subject.name, message: '', stack: '', }; for (const key of Object.keys(commonProperties)) { if (key in subject) data[key] = deepSerialize(subject[key]); } // Include any other enumerable own properties for (const key of Object.keys(subject)) { if (!(key in data)) data[key] = deepSerialize(subject[key]); } return data; } function deserializeError(subject) { if (!isErrorLike(subject)) { // If the subject is not an error, for example `throw "boom", then we throw. // This function should only be passed error objects, callers can use `isErrorLike`. throw new TypeError('Failed to desserialize error, expected an error object'); } let con = errorConstructors.get(subject.constructorName ?? subject.name); if (!con) { // If the constructor is not found, use the generic Error constructor con = Error; console.error(`Error constructor "${subject.name}" not found during worker error deserialization, using generic Error constructor`); } const output = Object.create(con.prototype); for (const [key, enumerable] of Object.entries(commonProperties)) { if (key in subject) { Object.defineProperty(output, key, { enumerable, configurable: true, writable: true, value: deepDeserialize(subject[key]), }); } } // Add any other properties (custom props not in commonProperties) for (const key of Object.keys(subject)) { if (!(key in commonProperties)) { output[key] = deepDeserialize(subject[key]); } } return output; } function deepSerialize(value) { if (Array.isArray(value)) return value.map(deepSerialize); if (isErrorLike(value)) return serializeError(value); if (value && typeof value === 'object') { return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, deepSerialize(v)])); } return value; } function deepDeserialize(value) { if (Array.isArray(value)) return value.map(deepDeserialize); if (isErrorLike(value)) return deserializeError(value); if (value && typeof value === 'object') { return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, deepDeserialize(v)])); } return value; } //# sourceMappingURL=serialize-error.js.map