life
Version:
Life.js is the first fullstack framework to build agentic web applications. It is minimal, extensible, and typesafe. Well, everything you love.
1 lines • 34.3 kB
Source Map (JSON)
{"version":3,"sources":["../shared/error.ts","../shared/prefixed-id.ts","../shared/operation.ts"],"sourcesContent":["import z from \"zod\";\nimport type { SerializableValue } from \"./canon\";\nimport { newId } from \"./prefixed-id\";\n\n// Codes\ninterface LifeErrorCodeDefinition {\n retriable: boolean;\n defaultMessage: string;\n httpEquivalent: number;\n}\n\nexport const lifeErrorCodes = {\n /**\n * Used when the user sends or the server returns invalid data.\n */\n Validation: {\n retriable: false,\n defaultMessage: \"Invalid data provided.\",\n httpEquivalent: 400,\n },\n /**\n * Used when the user is not authorized to access a resource\n */\n Forbidden: {\n retriable: false,\n defaultMessage: \"Not allowed to access this resource.\",\n httpEquivalent: 403,\n },\n /**\n * Used when an operation took too long and timed out.\n */\n Timeout: {\n retriable: true,\n defaultMessage: \"Operation timed out.\",\n httpEquivalent: 504,\n },\n /**\n * Used when the user has exceeded the rate limit for a resource.\n */\n RateLimit: {\n retriable: true,\n defaultMessage: \"Rate limit exceeded.\",\n httpEquivalent: 429,\n },\n /**\n * Used when a resource was not found or missing.\n */\n NotFound: {\n retriable: false,\n defaultMessage: \"Resource not found.\",\n httpEquivalent: 404,\n },\n /**\n * Used when an operation is about to conflict with another.\n * E.g., a version mismatch, a unique constraint violation, etc.\n */\n Conflict: {\n retriable: false,\n defaultMessage: \"Operation conflicted.\",\n httpEquivalent: 409,\n },\n /**\n * Used when an upstream service or resource fails.\n * E.g., a database connection error, an OpenAI API downtime, etc.\n */\n Upstream: {\n retriable: true,\n defaultMessage: \"Upstream error.\",\n httpEquivalent: 502,\n },\n /**\n * Used when an unexpected error is thrown.\n */\n Unknown: {\n retriable: false,\n defaultMessage: \"Unknown error.\",\n httpEquivalent: 500,\n },\n /**\n * Used to obfuscate internal errors publicly.\n * Prevents leaking sensitive informations to public consumers.\n */\n Internal: {\n retriable: true,\n defaultMessage: \"Internal error.\",\n httpEquivalent: 500,\n },\n} as const satisfies Record<string, LifeErrorCodeDefinition>;\n\nexport type LifeErrorCode = keyof typeof lifeErrorCodes;\n\n// Parameters\nexport type LifeErrorParameters<Code extends LifeErrorCode> = {\n code: Code;\n message?: string;\n attributes?: LifeErrorAttributes;\n retryAfterMs?: number;\n isPublic?: boolean;\n cause?: unknown;\n};\n\n// Attributes\nexport type LifeErrorAttributes = Record<string, SerializableValue>;\n\n/**\n * @internal Use `lifeError()` instead.\n */\nexport class LifeErrorClass extends Error {\n readonly name = \"LifeError\";\n\n /**\n * The unique identifier of the error.\n */\n readonly id: string = newId(\"error\");\n /**\n * The error code.\n * Can be one of:\n * - Validation\n * - Forbidden\n * - Timeout\n * - RateLimit\n * - NotFound\n * - Conflict\n * - Upstream\n * - Unknown\n * - Internal\n */\n readonly code: LifeErrorCode;\n /**\n * Additional pieces of evidence attached to the error.\n */\n readonly attributes: LifeErrorAttributes;\n /**\n * Used to indicate whether the operation that caused the error can be retried.\n */\n readonly retriable: boolean;\n /**\n * The suggested time (in ms) to wait before retrying the operation that caused the error.\n * Check `.retriable` first to ensure the operation can be retried.\n */\n readonly retryAfterMs?: number;\n /**\n * The HTTP status code equivalent to the error code.\n */\n readonly httpEquivalent: number;\n /**\n * Used to indicate whether this error is public and can be safely sent to external clients.\n */\n readonly isPublic: boolean;\n\n constructor({\n code,\n message,\n attributes,\n retryAfterMs,\n cause,\n isPublic = false,\n }: LifeErrorParameters<LifeErrorCode>) {\n const definition = lifeErrorCodes[code];\n super(message ?? definition.defaultMessage);\n this.code = code;\n this.retriable = definition.retriable;\n this.attributes = attributes ?? {};\n this.retryAfterMs = retryAfterMs;\n this.httpEquivalent = definition.httpEquivalent;\n this.isPublic = isPublic;\n this.cause = cause;\n\n // Clean stack capture\n if (Error.captureStackTrace) Error.captureStackTrace(this, LifeErrorClass);\n }\n\n toJSON() {\n return {\n id: this.id,\n code: this.code,\n message: this.message,\n retriable: this.retriable,\n attributes: this.attributes,\n retryAfterMs: this.retryAfterMs,\n httpEquivalent: this.httpEquivalent,\n stack: this.stack,\n cause: this.cause,\n };\n }\n}\n\n/**\n * Error emitted by the Life.js framework.\n * Check attributes documentation for more information.\n */\nexport type LifeError<Code extends LifeErrorCode = LifeErrorCode> = LifeErrorClass & {\n code: Code;\n}; // & z.output<(typeof lifeErrorCodes)[Code][\"extraSchema\"]>;\n\n/**\n * Union of all LifeError types.\n */\nexport type LifeErrorUnion<Code extends LifeErrorCode = LifeErrorCode> = Code extends LifeErrorCode\n ? LifeError<Code>\n : never;\n\n/**\n * Creates a new LifeError instance.\n * @param params\n * @returns\n */\nexport function lifeError<Code extends LifeErrorCode>(params: LifeErrorParameters<Code>) {\n // If the cause is a LifeError and it's an \"Unknown\" error, use the cause instead\n if (params.code === \"Unknown\" && isLifeError(params.cause)) {\n return params.cause as LifeError<Code>;\n }\n // Else, create a new LifeError instance\n return new LifeErrorClass(params) as LifeError<Code>;\n}\n\n/**\n * Check whether an unknown value is a LifeError instance.\n * @param error - The unknown value to check.\n * @returns\n */\nexport function isLifeError(error: unknown): error is LifeErrorUnion {\n return error instanceof LifeErrorClass;\n}\n\n// LifeError serialization schema\nconst serializedLifeErrorSchema = z.object({\n _isLifeError: z.literal(true),\n id: z.string(),\n code: z.string(),\n stack: z.string().optional(),\n message: z.string(),\n attributes: z.object().optional(),\n retryAfterMs: z.number().optional(),\n isPublic: z.boolean().optional(),\n cause: z.any().optional(),\n});\n\n/**\n * Transforms a LifeError into a JSON-serializable object.\n * @param error - The LifeError to serialize.\n * @returns - The JSON-serializable object.\n */\nexport function lifeErrorToObject(error: LifeError): Record<string, unknown> {\n if (!(error instanceof LifeErrorClass))\n throw lifeError({\n code: \"Validation\",\n message: \"The provided object is not a LifeError instance.\",\n });\n return {\n _isLifeError: true,\n id: error.id,\n code: error.code,\n stack: error.stack,\n message: error.message,\n attributes: error.attributes,\n retryAfterMs: error.retryAfterMs,\n cause: error.cause,\n };\n}\n\n/**\n * Transforms a JSON-serializable object produced by serializeLifeError()\n * back into a LifeError instance.\n * @param obj - The JSON-serializable object.\n * @returns - The LifeError instance.\n */\nexport function lifeErrorFromObject(obj: Record<string, unknown>): LifeErrorUnion {\n const { success, data } = serializedLifeErrorSchema.safeParse(obj);\n if (!success)\n throw lifeError({\n code: \"Validation\",\n message: \"The provided object is not a serialized LifeError.\",\n });\n const err = lifeError({\n code: data.code as LifeErrorCode,\n message: data.message,\n retryAfterMs: data.retryAfterMs,\n attributes: data.attributes as LifeErrorAttributes,\n cause: data.cause,\n isPublic: data.isPublic,\n });\n // @ts-expect-error - runtime only\n err.id = data.id;\n err.stack = data.stack;\n return err as LifeErrorUnion;\n}\n\n/**\n * When a LifeError has to be sent to an external client, this function ensures that the\n * error is obfuscated (free from any sensitive information) by removing the stack,\n * and even all other attributes if the error wasn't explicitly set as public.\n * @param error - The LifeError to make public.\n * @returns - The public LifeError.\n */\nexport function obfuscateLifeError<Code extends LifeErrorCode = LifeErrorCode>(\n error: LifeError<Code>,\n): LifeErrorUnion {\n // Return raw error in development\n if (process.env.NODE_ENV === \"development\") return error as LifeErrorUnion;\n\n let publicError: LifeError;\n\n // If the error is already public, just clone it to avoid mutating the original error\n if (error.isPublic) {\n publicError = lifeError({\n code: error.code,\n message: error.message,\n attributes: error.attributes,\n retryAfterMs: error.retryAfterMs,\n cause: error.cause,\n });\n }\n\n // Else, create an obfuscated error\n else publicError = lifeError({ code: \"Internal\" });\n\n // Set the error as public\n // @ts-expect-error - runtime only\n publicError.isPublic = true;\n\n // Restore the original id (for telemetry purposes)\n // @ts-expect-error - runtime only\n publicError.id = error.id;\n\n // Ensure no stack trace is leaked\n publicError.stack = undefined;\n\n // Return the public error\n return publicError as LifeErrorUnion;\n}\n","import { init as initCuid2, isCuid } from \"@paralleldrive/cuid2\";\n\n// Base functions\nexport function newId(prefix: string, length = 12) {\n const cuid2 = initCuid2({ length });\n return `${prefix}_${cuid2()}`;\n}\n\nexport function isValidId(id: string, length = 12) {\n const parts = id.split(\"_\") as [string, string];\n if (parts.length !== 2) return false;\n if (parts[1].length !== length) return false;\n return isCuid(parts[1]);\n}\n","// biome-ignore-all lint/style/useUnifiedTypeSignatures: fine\n\n/**\n * The 'operation' library (usually imported as 'op') is a minimal and type-safe\n * helper to enforce return type consistency across the entire codebase.\n *\n *\n * ## Why not using something like Effect.js or NeverThrow?\n *\n * While powerful, those libraries come with significant learning curves. We want\n * the Life.js codebase to remain accessible, so the community can easily engage,\n * learn, and contribute to it. Those libraries were incompatible with this goal.\n *\n * Also, we wanted the solution to be unnoticeable on the public API. The Life.js\n * SDKs shouldn't force developers to think differently about their program design.\n * Complex libraries like Effect.js or NeverThrow were again challenging with that\n * goal, this library solves that in ~100 LOC with the `toPublic()` helper.\n *\n * Still, 'operation' is not a perfect alternative to more complex libraries.\n * For example, it doesn't provide error-level type safety, yet it enforces errors\n * to be narrowed to LifeError (a 9 error codes surface), and strongly encourages\n * contributors to handle them properly. We found it being a good compromise.\n *\n *\n * ## Why 'error' comes first in the result tuple?\n *\n * We use `[error, data]` instead of `[data, error]` for two main reasons:\n *\n * 1. A function doesn't always return data, while it will always return a potential\n * error. When there is no data, with error first we can simply do:\n * ```ts\n * const [err] = op.attempt(...)\n * // instead of the more verbose\n * const [_, err] = op.attempt(...)\n * ```\n *\n * 2. With error first, the developer explicitly acknowledges the potential error\n * before destructuring the data. If `data` was first, it would be easy to:\n * ```ts\n * const [data] = op.attempt(...) // <-- Easy to forget to destructure the error here!\n * if (data) { ... }\n * ```\n */\n\nimport z from \"zod\";\nimport {\n isLifeError,\n LifeErrorClass,\n type LifeErrorCode,\n type LifeErrorParameters,\n type LifeErrorUnion,\n lifeError,\n} from \"./error\";\nimport type {\n Any,\n ClassShape,\n IsClass,\n IsFunction,\n IsInstance,\n MaybePromise,\n Opaque,\n Prettify,\n} from \"./types\";\n\nexport type OperationData = unknown;\n\nconst OPERATION_RESULT = Symbol(\"OperationResult\");\nexport const isResult = (value: unknown): value is OperationResult<OperationData> =>\n Array.isArray(value) && OPERATION_RESULT in value;\n\ntype OperationSuccess<D extends OperationData> = readonly [error: undefined, data: D];\ntype OperationFailure<_ extends OperationData = never> = readonly [\n error: LifeErrorUnion,\n data: undefined,\n];\nexport type OperationResult<D extends OperationData> = OperationSuccess<D> | OperationFailure<D>;\n\n/**\n * To be returned by functions to indicate success.\n *\n * @param data - (Optional) The return type of the function.\n * @returns An OperationResult tuple containing `[null, data]`.\n *\n * The 'data' argument can also be an OperationResult, in which case it will\n * automatically be unwrapped. This allows seamless chaining of operations.\n *\n * @example\n * ```typescript\n * // Simple value\n * const result = success({ id: 1, name: \"Alice\" });\n * // result: [null, { id: 1, name: \"Alice\" }]\n *\n * // Prevents double-wrapping\n * const nested = success(result);\n * // nested: [null, { id: 1, name: \"Alice\" }] (not double-wrapped)\n * ```\n */\nexport const success = <const D extends OperationData = void>(data?: D): OperationSuccess<D> => {\n const result = Object.assign([undefined, isResult(data) ? data[1] : data] as const, {\n [OPERATION_RESULT]: true as const,\n }) as OperationSuccess<D>;\n return result;\n};\n\n/**\n * To be returned by functions to indicate failure.\n *\n * @param errorOrDef - A LifeError instance or lifeError()-like input object\n * @returns An OperationResult tuple containing `[error, null]`.\n *\n * @example\n * ```typescript\n * // Simple failure\n * const result = failure({ code: \"NotFound\" });\n * // result: [LifeError, null]\n * ```\n */\nexport const failure = <Code extends LifeErrorCode, D extends OperationData = never>(\n errorOrDef: LifeErrorParameters<Code>,\n): OperationFailure<D> => {\n const error = isLifeError(errorOrDef) ? errorOrDef : lifeError(errorOrDef);\n const result = Object.assign([error, undefined] as const, {\n [OPERATION_RESULT]: true as const,\n }) as OperationFailure<D>;\n return result;\n};\n\n/**\n * To be used to execute any function/promise.\n *\n * In case any `throw` happen, or unknown Error or data is returned, those\n * will be swallowed and converted to a compliant OperationResult.\n *\n * @param task - Can be:\n * - A synchronous function: `() => T`\n * - An async function: `() => Promise<T>`\n * - A promise directly: `Promise<T>`\n * @returns An OperationResult or Promise<OperationResult>.\n *\n *\n * @example\n * ```typescript\n * // Sync function - immediate result\n * const [error, parsed] = attempt(() => JSON.parse(jsonString));\n * if (error) {\n * console.error('Parse failed:', error.code);\n * return;\n * }\n * console.log('Parsed:', parsed);\n *\n * // Async function - await the result\n * const [err, user] = await attempt(async () => {\n * const response = await fetch(`/api/users/${id}`);\n * if (!response.ok) throw new Error('Failed to fetch');\n * return response.json();\n * });\n *\n * // Direct promise - cleaner for existing promises\n * const [err2, data] = await attempt(fetchUserProfile(userId));\n *\n * // Chaining operations\n * const [err3] = await attempt(async () => {\n * await validateUser(user);\n * await saveUser(user);\n * await notifyUser(user);\n * });\n * if (err3) return failure(err3);\n * ```\n */\nexport function attempt(task: () => never): OperationResult<never>;\nexport function attempt(task: () => Promise<never>): Promise<OperationResult<never>>;\nexport function attempt(task: Promise<never>): Promise<OperationResult<never>>;\nexport function attempt<D extends OperationData>(\n task: () => Promise<D>,\n): Promise<OperationResult<D>>;\nexport function attempt<D extends OperationData>(task: () => D): OperationResult<D>;\nexport function attempt<D extends OperationData>(task: Promise<D>): Promise<OperationResult<D>>;\n\nexport function attempt<const D extends OperationData>(\n task: (() => D) | Promise<D> | (() => Promise<D>),\n): Promise<OperationResult<D>> | OperationResult<D> {\n const handleError = (error: unknown) => {\n if (isLifeError(error)) return failure(error);\n return failure({ code: \"Unknown\", cause: error });\n };\n const handleResult = (result: D) => {\n if (isResult(result)) return result as OperationResult<D>;\n return success(result) as OperationResult<D>;\n };\n if (task instanceof Promise)\n return task.then(handleResult).catch(handleError) as Promise<OperationResult<D>>;\n try {\n const result = task();\n if (result instanceof Promise)\n return result.then(handleResult).catch(handleError) as Promise<OperationResult<D>>;\n return handleResult(result);\n } catch (error) {\n return handleError(error) as OperationResult<D>;\n }\n}\n\n/**\n * Extracts the data from an OperationResult, throwing an error if the result is a failure.\n *\n * @param result - The OperationResult to extract the data from.\n * @returns The data.\n */\nexport const dataOrThrow = <D extends OperationData>(result: OperationResult<D>): D => {\n if (!isResult(result)) return result;\n const [error, data] = result;\n if (error) throw error;\n return data;\n};\n\n// biome-ignore lint/suspicious/noConfusingVoidType: usage of void type is intentional\ntype VoidIfNever<T> = [T] extends [never] ? void : T;\n\ntype IsOpFunction<T> = T extends (...args: Any) => MaybePromise<OperationResult<Any>>\n ? true\n : false;\n\ntype IsOpInstance<T> = {\n [K in keyof T]: IsFunction<T[K]> extends true ? IsOpFunction<T[K]> : false;\n} extends { [K in keyof T]: false }\n ? false\n : true;\n\n/**\n * In some rare cases where a types produces another type itself containing generics,\n * Typescript won't be able to infer the precise branch and ToPublic will incorreclty\n * match the type and produce broken results.\n * This helper is used to assert that a type is already public and avoid the issue.\n */\nexport type AssertPublic<T> = T & { [__public]: [T] };\ndeclare const __public: unique symbol;\ntype IsAsserted<T> = T extends { [__public]: Any } ? true : false;\ntype UnwrapAssert<T> = T extends { [__public]: [infer U] } ? U : never;\n\ntype FunctionToPublic<T> = T extends (\n ...args: infer Args\n) => MaybePromise<OperationResult<infer Data>>\n ? Opaque<(...args: Args) => VoidIfNever<Data>>\n : T;\n\ntype InstanceToPublic<T> = IsInstance<T> extends true\n ? Prettify<\n {\n [K in keyof T]: ToPublic<T[K]>;\n } & (IsOpInstance<T> extends true\n ? Opaque<{\n safe: {\n [K in keyof T as IsOpFunction<T[K]> extends true ? K : never]: T[K];\n };\n }>\n : unknown)\n >\n : T;\n\ntype ClassToPublic<T> = IsClass<T> extends true\n ? Opaque<new (...args: Any) => InstanceToPublic<InstanceType<T extends ClassShape ? T : never>>>\n : T;\n\nexport type ToPublic<T> = IsAsserted<T> extends true\n ? UnwrapAssert<T>\n : T extends z.ZodType // Skip any zod type\n ? T\n : IsClass<T> extends true\n ? ClassToPublic<T>\n : IsFunction<T> extends true\n ? FunctionToPublic<T>\n : IsInstance<T> extends true\n ? InstanceToPublic<T>\n : T;\n\n/**\n * Converts an internal function type (returning an OperationResult) into\n * a public function (returning the unwrapped data type).\n *\n * @param func - The internal function to convert.\n * @returns The public function.\n */\nconst functionToPublic = <\n Func extends (\n ...args: never[]\n ) => OperationResult<OperationData> | Promise<OperationResult<OperationData>>,\n>(\n func: Func,\n) => {\n const unsafeFunc = (...args: Parameters<Func>) => {\n try {\n const result = func(...args);\n\n // Handle async functions\n if (result instanceof Promise) {\n return result\n .then((awaitedResult) => {\n if (isResult(awaitedResult)) {\n const [errAsync, dataAsync] = awaitedResult;\n if (errAsync) throw errAsync;\n return dataAsync;\n }\n return awaitedResult;\n })\n .catch((error) => {\n throw error;\n });\n }\n\n // Handle sync functions\n if (isResult(result)) {\n const [errorSync, dataSync] = result as OperationResult<OperationData>;\n if (errorSync) throw errorSync;\n return dataSync;\n }\n return result;\n } catch (error) {\n if (error instanceof Error) throw error;\n throw error;\n }\n };\n\n return unsafeFunc as FunctionToPublic<Func>;\n};\n\n/**\n * Converts an internal instance/object type (with methods returning OperationResult)\n * into a public instance (with methods returning the unwrapped data types).\n *\n * The original instance/object is kept under the `.safe` property.\n *\n * @param instance - The internal instance to convert.\n * @returns The public instance.\n */\nconst instanceToPublic = <Instance extends object>(instance: Instance) => {\n // Cache to prevent circular references and redundant wrapping\n const wrappedCache = new WeakMap<object, object>();\n\n const createProxy = (target: object): object => {\n // Return cached version if already wrapped\n if (wrappedCache.has(target)) return wrappedCache.get(target) as object;\n\n const proxy = new Proxy(target, {\n get(innerTarget, prop) {\n // Preserve access to original unwrapped instance (entire tree)\n if (prop === \"safe\") return innerTarget;\n\n const value = innerTarget[prop as keyof typeof innerTarget] as unknown;\n\n // Wrap functions at any depth\n if (typeof value === \"function\") {\n return functionToPublic(value.bind(innerTarget));\n }\n\n // Recursively wrap objects and class instances\n if (value !== null && typeof value === \"object\") {\n // Skip built-in types that could break if proxied\n const shouldSkip =\n value instanceof Date ||\n value instanceof RegExp ||\n value instanceof Promise ||\n Array.isArray(value) ||\n value instanceof Map ||\n value instanceof Set ||\n value instanceof WeakMap ||\n value instanceof WeakSet ||\n ArrayBuffer.isView(value); // typed arrays, DataView, etc.\n\n if (shouldSkip) return value;\n\n // Recursively wrap plain objects and custom class instances\n return createProxy(value);\n }\n\n // Primitives and other values returned as-is\n return value;\n },\n });\n\n wrappedCache.set(target, proxy);\n return proxy;\n };\n\n return createProxy(instance) as InstanceToPublic<Instance>;\n};\n\n/**\n * Converts an internal class type (with methods returning OperationResult)\n * into a public class type (with methods returning the unwrapped data types).\n *\n * The original class type is kept under the `.safe` property.\n *\n * @param InternalClass - The internal class to convert.\n * @returns The public class.\n */\nconst classToPublic = <Class extends ClassShape>(InternalClass: Class): ClassToPublic<Class> =>\n new Proxy(InternalClass, {\n construct(target, args) {\n const instance = new target(...args);\n return instanceToPublic(instance);\n },\n }) as ClassToPublic<Class>;\n\n/**\n * Converts any internal types (functions, instances, objects, or classes)\n * to use unwrapped data types instead of OperationResult.\n *\n * @param input - The internal implementation to convert (class, function, or instance)\n * @returns The public equivalent\n */\nexport function toPublic<T>(input: T) {\n // Check if it's a class constructor\n if (typeof input === \"function\" && input.prototype && input.prototype.constructor === input) {\n // biome-ignore lint/suspicious/noExplicitAny: needed for type routing\n return classToPublic(input as any) as ToPublic<T>;\n }\n\n // Check if it's a regular function\n if (typeof input === \"function\") {\n // biome-ignore lint/suspicious/noExplicitAny: needed for type routing\n return functionToPublic(input as any) as ToPublic<T>;\n }\n\n // Check if it's an object instance\n if (typeof input === \"object\" && input !== null) {\n return instanceToPublic(input) as ToPublic<T>;\n }\n\n // Return as-is for primitive types\n return input as ToPublic<T>;\n}\n\n// Export a Zod schema for the OperationResult type\nexport const resultSchema = z\n .tuple([z.null().or(z.undefined()), z.unknown()])\n .or(z.tuple([z.instanceof(LifeErrorClass), z.null().or(z.undefined())]))\n .transform((val): OperationResult<OperationData> => {\n // Restore the OPERATION_RESULT symbol that Zod parsing strips\n const [error, data] = val;\n if (error) return failure(error);\n return success(data);\n });\n\n/**\n * Serializes an OperationResult into a plain object for transport.\n *\n * @param result - The OperationResult to serialize\n * @returns A plain object with _isOperationResult marker and the result data\n *\n * @example\n * ```typescript\n * const result = success({ id: 1, name: \"Alice\" });\n * const serialized = serializeResult(result);\n * // serialized: { _isOperationResult: true, result: [undefined, { id: 1, name: \"Alice\" }] }\n * ```\n */\nexport function serializeResult<D extends OperationData>(\n result: OperationResult<D>,\n): { _isOperationResult: true; result: [LifeErrorUnion | undefined, D | undefined] } {\n if (!isResult(result)) {\n throw new Error(\"The provided value is not an OperationResult\");\n }\n return {\n _isOperationResult: true,\n // Extract the tuple without the symbol to avoid recursive serialization\n result: [result?.[0], result?.[1]],\n };\n}\n\n/**\n * Deserializes a plain object back into an OperationResult with the proper symbol.\n *\n * @param obj - The serialized object to deserialize\n * @returns An OperationResult with the OPERATION_RESULT symbol attached\n *\n * @example\n * ```typescript\n * const serialized = { _isOperationResult: true, result: [undefined, { id: 1, name: \"Alice\" }] };\n * const result = deserializeResult(serialized);\n * // result is now a proper OperationResult that will pass isResult() check\n * ```\n */\nexport function deserializeResult<D extends OperationData>(obj: {\n _isOperationResult: true;\n result: readonly [LifeErrorUnion | undefined, D | undefined];\n}): OperationResult<D> {\n if (!obj._isOperationResult) {\n throw new Error(\"The provided object is not a serialized OperationResult\");\n }\n if (!Array.isArray(obj.result) || obj.result.length !== 2) {\n throw new Error(\"The provided object is not a serialized OperationResult\");\n }\n\n const [error, data] = obj.result;\n\n // Reconstruct the OperationResult with the symbol\n if (error) return failure(error) as OperationResult<D>;\n return success(data) as OperationResult<D>;\n}\n"],"mappings":"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","names":["success","z","z"]}