UNPKG

life

Version:

Life.js is the first fullstack framework to build agentic web applications. It is minimal, extensible, and typesafe. Well, everything you love.

412 lines (407 loc) 11.7 kB
import { __name } from "./chunk-2D3UJWOA.mjs"; // shared/error.ts import z from "zod"; // shared/prefixed-id.ts import { init as initCuid2, isCuid } from "@paralleldrive/cuid2"; function newId(prefix, length = 12) { const cuid2 = initCuid2({ length }); return `${prefix}_${cuid2()}`; } __name(newId, "newId"); // shared/error.ts var lifeErrorCodes = { /** * Used when the user sends or the server returns invalid data. */ Validation: { retriable: false, defaultMessage: "Invalid data provided.", httpEquivalent: 400 }, /** * Used when the user is not authorized to access a resource */ Forbidden: { retriable: false, defaultMessage: "Not allowed to access this resource.", httpEquivalent: 403 }, /** * Used when an operation took too long and timed out. */ Timeout: { retriable: true, defaultMessage: "Operation timed out.", httpEquivalent: 504 }, /** * Used when the user has exceeded the rate limit for a resource. */ RateLimit: { retriable: true, defaultMessage: "Rate limit exceeded.", httpEquivalent: 429 }, /** * Used when a resource was not found or missing. */ NotFound: { retriable: false, defaultMessage: "Resource not found.", httpEquivalent: 404 }, /** * Used when an operation is about to conflict with another. * E.g., a version mismatch, a unique constraint violation, etc. */ Conflict: { retriable: false, defaultMessage: "Operation conflicted.", httpEquivalent: 409 }, /** * Used when an upstream service or resource fails. * E.g., a database connection error, an OpenAI API downtime, etc. */ Upstream: { retriable: true, defaultMessage: "Upstream error.", httpEquivalent: 502 }, /** * Used when an unexpected error is thrown. */ Unknown: { retriable: false, defaultMessage: "Unknown error.", httpEquivalent: 500 }, /** * Used to obfuscate internal errors publicly. * Prevents leaking sensitive informations to public consumers. */ Internal: { retriable: true, defaultMessage: "Internal error.", httpEquivalent: 500 } }; var LifeErrorClass = class _LifeErrorClass extends Error { static { __name(this, "LifeErrorClass"); } name = "LifeError"; /** * The unique identifier of the error. */ id = newId("error"); /** * The error code. * Can be one of: * - Validation * - Forbidden * - Timeout * - RateLimit * - NotFound * - Conflict * - Upstream * - Unknown * - Internal */ code; /** * Additional pieces of evidence attached to the error. */ attributes; /** * Used to indicate whether the operation that caused the error can be retried. */ retriable; /** * The suggested time (in ms) to wait before retrying the operation that caused the error. * Check `.retriable` first to ensure the operation can be retried. */ retryAfterMs; /** * The HTTP status code equivalent to the error code. */ httpEquivalent; /** * Used to indicate whether this error is public and can be safely sent to external clients. */ isPublic; constructor({ code, message, attributes, retryAfterMs, cause, isPublic = false }) { const definition = lifeErrorCodes[code]; super(message ?? definition.defaultMessage); this.code = code; this.retriable = definition.retriable; this.attributes = attributes ?? {}; this.retryAfterMs = retryAfterMs; this.httpEquivalent = definition.httpEquivalent; this.isPublic = isPublic; this.cause = cause; if (Error.captureStackTrace) Error.captureStackTrace(this, _LifeErrorClass); } toJSON() { return { id: this.id, code: this.code, message: this.message, retriable: this.retriable, attributes: this.attributes, retryAfterMs: this.retryAfterMs, httpEquivalent: this.httpEquivalent, stack: this.stack, cause: this.cause }; } }; function lifeError(params) { if (params.code === "Unknown" && isLifeError(params.cause)) { return params.cause; } return new LifeErrorClass(params); } __name(lifeError, "lifeError"); function isLifeError(error) { return error instanceof LifeErrorClass; } __name(isLifeError, "isLifeError"); var serializedLifeErrorSchema = z.object({ _isLifeError: z.literal(true), id: z.string(), code: z.string(), stack: z.string().optional(), message: z.string(), attributes: z.object().optional(), retryAfterMs: z.number().optional(), isPublic: z.boolean().optional(), cause: z.any().optional() }); function lifeErrorToObject(error) { if (!(error instanceof LifeErrorClass)) throw lifeError({ code: "Validation", message: "The provided object is not a LifeError instance." }); return { _isLifeError: true, id: error.id, code: error.code, stack: error.stack, message: error.message, attributes: error.attributes, retryAfterMs: error.retryAfterMs, cause: error.cause }; } __name(lifeErrorToObject, "lifeErrorToObject"); function lifeErrorFromObject(obj) { const { success: success2, data } = serializedLifeErrorSchema.safeParse(obj); if (!success2) throw lifeError({ code: "Validation", message: "The provided object is not a serialized LifeError." }); const err = lifeError({ code: data.code, message: data.message, retryAfterMs: data.retryAfterMs, attributes: data.attributes, cause: data.cause, isPublic: data.isPublic }); err.id = data.id; err.stack = data.stack; return err; } __name(lifeErrorFromObject, "lifeErrorFromObject"); function obfuscateLifeError(error) { if (process.env.NODE_ENV === "development") return error; let publicError; if (error.isPublic) { publicError = lifeError({ code: error.code, message: error.message, attributes: error.attributes, retryAfterMs: error.retryAfterMs, cause: error.cause }); } else publicError = lifeError({ code: "Internal" }); publicError.isPublic = true; publicError.id = error.id; publicError.stack = void 0; return publicError; } __name(obfuscateLifeError, "obfuscateLifeError"); // shared/operation.ts import z2 from "zod"; var OPERATION_RESULT = Symbol("OperationResult"); var isResult = /* @__PURE__ */ __name((value) => Array.isArray(value) && OPERATION_RESULT in value, "isResult"); var success = /* @__PURE__ */ __name((data) => { const result = Object.assign([void 0, isResult(data) ? data[1] : data], { [OPERATION_RESULT]: true }); return result; }, "success"); var failure = /* @__PURE__ */ __name((errorOrDef) => { const error = isLifeError(errorOrDef) ? errorOrDef : lifeError(errorOrDef); const result = Object.assign([error, void 0], { [OPERATION_RESULT]: true }); return result; }, "failure"); function attempt(task) { const handleError = /* @__PURE__ */ __name((error) => { if (isLifeError(error)) return failure(error); return failure({ code: "Unknown", cause: error }); }, "handleError"); const handleResult = /* @__PURE__ */ __name((result) => { if (isResult(result)) return result; return success(result); }, "handleResult"); if (task instanceof Promise) return task.then(handleResult).catch(handleError); try { const result = task(); if (result instanceof Promise) return result.then(handleResult).catch(handleError); return handleResult(result); } catch (error) { return handleError(error); } } __name(attempt, "attempt"); var dataOrThrow = /* @__PURE__ */ __name((result) => { if (!isResult(result)) return result; const [error, data] = result; if (error) throw error; return data; }, "dataOrThrow"); var functionToPublic = /* @__PURE__ */ __name((func) => { const unsafeFunc = /* @__PURE__ */ __name((...args) => { try { const result = func(...args); if (result instanceof Promise) { return result.then((awaitedResult) => { if (isResult(awaitedResult)) { const [errAsync, dataAsync] = awaitedResult; if (errAsync) throw errAsync; return dataAsync; } return awaitedResult; }).catch((error) => { throw error; }); } if (isResult(result)) { const [errorSync, dataSync] = result; if (errorSync) throw errorSync; return dataSync; } return result; } catch (error) { if (error instanceof Error) throw error; throw error; } }, "unsafeFunc"); return unsafeFunc; }, "functionToPublic"); var instanceToPublic = /* @__PURE__ */ __name((instance) => { const wrappedCache = /* @__PURE__ */ new WeakMap(); const createProxy = /* @__PURE__ */ __name((target) => { if (wrappedCache.has(target)) return wrappedCache.get(target); const proxy = new Proxy(target, { get(innerTarget, prop) { if (prop === "safe") return innerTarget; const value = innerTarget[prop]; if (typeof value === "function") { return functionToPublic(value.bind(innerTarget)); } if (value !== null && typeof value === "object") { const shouldSkip = value instanceof Date || value instanceof RegExp || value instanceof Promise || Array.isArray(value) || value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet || ArrayBuffer.isView(value); if (shouldSkip) return value; return createProxy(value); } return value; } }); wrappedCache.set(target, proxy); return proxy; }, "createProxy"); return createProxy(instance); }, "instanceToPublic"); var classToPublic = /* @__PURE__ */ __name((InternalClass) => new Proxy(InternalClass, { construct(target, args) { const instance = new target(...args); return instanceToPublic(instance); } }), "classToPublic"); function toPublic(input) { if (typeof input === "function" && input.prototype && input.prototype.constructor === input) { return classToPublic(input); } if (typeof input === "function") { return functionToPublic(input); } if (typeof input === "object" && input !== null) { return instanceToPublic(input); } return input; } __name(toPublic, "toPublic"); var resultSchema = z2.tuple([z2.null().or(z2.undefined()), z2.unknown()]).or(z2.tuple([z2.instanceof(LifeErrorClass), z2.null().or(z2.undefined())])).transform((val) => { const [error, data] = val; if (error) return failure(error); return success(data); }); function serializeResult(result) { if (!isResult(result)) { throw new Error("The provided value is not an OperationResult"); } return { _isOperationResult: true, // Extract the tuple without the symbol to avoid recursive serialization result: [result?.[0], result?.[1]] }; } __name(serializeResult, "serializeResult"); function deserializeResult(obj) { if (!obj._isOperationResult) { throw new Error("The provided object is not a serialized OperationResult"); } if (!Array.isArray(obj.result) || obj.result.length !== 2) { throw new Error("The provided object is not a serialized OperationResult"); } const [error, data] = obj.result; if (error) return failure(error); return success(data); } __name(deserializeResult, "deserializeResult"); export { newId, lifeError, isLifeError, lifeErrorToObject, lifeErrorFromObject, obfuscateLifeError, isResult, success, failure, attempt, dataOrThrow, toPublic, resultSchema, serializeResult, deserializeResult }; //# sourceMappingURL=chunk-ZHBK6UTM.mjs.map