better-ship 0.7.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/{application-DjsQtpgw.js → application-DYfcAy-Q.js} +2 -2
  2. package/dist/{application-DjsQtpgw.js.map → application-DYfcAy-Q.js.map} +1 -1
  3. package/dist/application.d.ts +2 -2
  4. package/dist/application.js +1 -1
  5. package/dist/better-auth/apple-client-secret.d.ts +11 -4
  6. package/dist/better-auth/apple-client-secret.d.ts.map +1 -1
  7. package/dist/better-auth/apple-client-secret.js +39 -11
  8. package/dist/better-auth/apple-client-secret.js.map +1 -1
  9. package/dist/better-auth/auth-client.js +1 -1
  10. package/dist/better-auth/rate-limit.d.ts +21 -2
  11. package/dist/better-auth/rate-limit.d.ts.map +1 -1
  12. package/dist/better-auth/rate-limit.js +38 -2
  13. package/dist/better-auth/rate-limit.js.map +1 -1
  14. package/dist/better-auth.js +1 -1
  15. package/dist/cloudflare/auth-secondary-storage.d.ts +1 -1
  16. package/dist/cloudflare/auth-secondary-storage.js +1 -1
  17. package/dist/cloudflare/queue.d.ts +175 -0
  18. package/dist/cloudflare/queue.d.ts.map +1 -0
  19. package/dist/cloudflare/queue.js +419 -0
  20. package/dist/cloudflare/queue.js.map +1 -0
  21. package/dist/cloudflare/scheduled.d.ts +36 -0
  22. package/dist/cloudflare/scheduled.d.ts.map +1 -0
  23. package/dist/cloudflare/scheduled.js +37 -0
  24. package/dist/cloudflare/scheduled.js.map +1 -0
  25. package/dist/cloudflare.d.ts +3 -3
  26. package/dist/cloudflare.js +3 -3
  27. package/dist/{core-Cx5SeyKV.js → core-DC_4pOrI.js} +92 -2
  28. package/dist/core-DC_4pOrI.js.map +1 -0
  29. package/dist/core.d.ts +2 -2
  30. package/dist/core.js +2 -2
  31. package/dist/{index-BStnggQO.d.ts → index-6XMPJu7u.d.ts} +49 -2
  32. package/dist/index-6XMPJu7u.d.ts.map +1 -0
  33. package/dist/{index-DWIRrJMP.d.ts → index-_Cihfq1J.d.ts} +2 -2
  34. package/dist/{index-DWIRrJMP.d.ts.map → index-_Cihfq1J.d.ts.map} +1 -1
  35. package/dist/postgres.d.ts +3 -3
  36. package/dist/postgres.js +3 -3
  37. package/dist/tanstack.d.ts +18 -7
  38. package/dist/tanstack.d.ts.map +1 -1
  39. package/dist/tanstack.js +3 -3
  40. package/dist/tanstack.js.map +1 -1
  41. package/dist/{unit-of-work-context-DToDpAkv.js → unit-of-work-context-BFCmU92Z.js} +2 -2
  42. package/dist/{unit-of-work-context-DToDpAkv.js.map → unit-of-work-context-BFCmU92Z.js.map} +1 -1
  43. package/dist/{unit-of-work-context-CPz9rdSS.d.ts → unit-of-work-context-BWTJfYPW.d.ts} +3 -3
  44. package/dist/{unit-of-work-context-CPz9rdSS.d.ts.map → unit-of-work-context-BWTJfYPW.d.ts.map} +1 -1
  45. package/package.json +3 -6
  46. package/src/core/backoff.ts +29 -0
  47. package/src/core/classify-failure.ts +60 -0
  48. package/src/core/cloudflare-classification.ts +45 -0
  49. package/src/core/index.ts +14 -0
  50. package/src/infrastructure/better-auth/apple-client-secret.ts +41 -14
  51. package/src/infrastructure/better-auth/rate-limit.ts +44 -1
  52. package/src/infrastructure/cloudflare/queue/index.ts +25 -0
  53. package/src/infrastructure/cloudflare/queue/queue-client.ts +177 -0
  54. package/src/infrastructure/cloudflare/queue/queue-consumer.ts +146 -0
  55. package/src/infrastructure/cloudflare/queue/queue-limits.ts +54 -0
  56. package/src/infrastructure/cloudflare/queue/queue-message.ts +4 -0
  57. package/src/infrastructure/cloudflare/queue/queue.errors.ts +105 -0
  58. package/src/infrastructure/cloudflare/queue/redelivery-policy.ts +64 -0
  59. package/src/infrastructure/cloudflare/scheduled/index.ts +8 -0
  60. package/src/infrastructure/cloudflare/scheduled/scheduled-handler.ts +62 -0
  61. package/src/infrastructure/tanstack/auth.middleware.ts +5 -3
  62. package/src/infrastructure/tanstack/error.middleware.ts +6 -7
  63. package/src/infrastructure/tanstack/request-context.ts +11 -0
  64. package/dist/core-Cx5SeyKV.js.map +0 -1
  65. package/dist/index-BStnggQO.d.ts.map +0 -1
@@ -488,6 +488,96 @@ function isTransientTransportError(cause) {
488
488
  return TRANSIENT_TRANSPORT_PATTERNS.some((pattern) => pattern.test(message));
489
489
  }
490
490
 
491
+ //#endregion
492
+ //#region src/core/cloudflare-classification.ts
493
+ /** Stable Cloudflare messages that mean the runtime failed, not our code, and a repeat may pass. */
494
+ const CLOUDFLARE_TRANSIENT_ERROR_PATTERNS = {
495
+ networkConnectionLost: /network connection lost/,
496
+ objectReset: /caused object to be reset/,
497
+ codeUpdateReset: /reset because its code was updated/,
498
+ objectMoved: /object has moved to a different machine/,
499
+ internalWorkflows: /internal workflows error/
500
+ };
501
+ const TRANSIENT_PLATFORM_PATTERNS = [
502
+ CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.objectReset,
503
+ CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.codeUpdateReset,
504
+ CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.objectMoved,
505
+ CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.internalWorkflows
506
+ ];
507
+ const RetryableFlagSchema = z.object({ retryable: z.literal(true) });
508
+ const OverloadedFlagSchema = z.object({ overloaded: z.literal(true) });
509
+ const ObjectResetFlagSchema = z.object({ durableObjectReset: z.literal(true) });
510
+ /** workerd stamps `retryable` on a failure it judged safe to repeat. */
511
+ function isCloudflareRetryableError(cause) {
512
+ return RetryableFlagSchema.validate(cause);
513
+ }
514
+ /** workerd stamps `overloaded` when the target could not take the call. */
515
+ function isCloudflareOverloadedError(cause) {
516
+ return OverloadedFlagSchema.validate(cause);
517
+ }
518
+ /** workerd stamps `durableObjectReset` when the object restarted during the call. */
519
+ function isCloudflareObjectResetError(cause) {
520
+ return ObjectResetFlagSchema.validate(cause);
521
+ }
522
+ /** Match transient Cloudflare runtime evidence without the general transport patterns. */
523
+ function isTransientCloudflareRuntimeError(cause) {
524
+ if (isCloudflareObjectResetError(cause)) return true;
525
+ if (!(cause instanceof Error)) return false;
526
+ const message = cause.message.toLowerCase();
527
+ return TRANSIENT_PLATFORM_PATTERNS.some((pattern) => pattern.test(message));
528
+ }
529
+
530
+ //#endregion
531
+ //#region src/core/classify-failure.ts
532
+ /**
533
+ * Classify one raw external error: the boundary's own rule first, then Cloudflare's signals,
534
+ * then the transport patterns. Cancellation is terminal even when Cloudflare marks it retryable.
535
+ */
536
+ function classifyBoundaryError(args) {
537
+ const boundary = args.classifyBoundary(args.cause);
538
+ if (boundary !== void 0) return boundary;
539
+ if (isAbortError(args.cause)) return "terminal";
540
+ if (args.includeCloudflare && (isCloudflareOverloadedError(args.cause) || isCloudflareRetryableError(args.cause) || isTransientCloudflareRuntimeError(args.cause))) return "transient";
541
+ if (isTransientTransportError(args.cause)) return "transient";
542
+ return "unknown";
543
+ }
544
+ /**
545
+ * Judge a final failure for its durable retry owner. An `AppError` carries its own answer.
546
+ * A raw throw nobody judged is unknown, so an immediate owner stops and a durable one may repeat.
547
+ */
548
+ function classifyFailure(cause) {
549
+ if (cause instanceof AppError) return cause.classification;
550
+ if (isAbortError(cause)) return "terminal";
551
+ if (isTransientCloudflareRuntimeError(cause)) return "transient";
552
+ return "unknown";
553
+ }
554
+ const RetryAfterSchema = z.object({ retryAfter: z.number().positive() });
555
+ /** Read a positive server-advertised retry delay in seconds, such as `RateLimitError.retryAfter`. */
556
+ function retryAfterSecondsOf(cause) {
557
+ const result = RetryAfterSchema.safeParse(cause);
558
+ return result.success ? result.data.retryAfter : null;
559
+ }
560
+
561
+ //#endregion
562
+ //#region src/core/backoff.ts
563
+ /** Uniform jitter within one fixed window. */
564
+ function spreadJitterMs(spreadMs) {
565
+ if (!Number.isFinite(spreadMs) || spreadMs < 0) return panic("spreadMs must be a non-negative number");
566
+ return Math.floor(Math.random() * spreadMs);
567
+ }
568
+ /**
569
+ * Half the capped exponential delay, plus jitter over the other half. Decorrelates concurrent
570
+ * repeats like full jitter, but keeps a floor: use it when few attempts remain before work is dropped.
571
+ */
572
+ function exponentialEqualJitterMs(baseDelayMs, maxDelayMs, attempt) {
573
+ const halfCapMs = exponentialDelayCapMs(baseDelayMs, maxDelayMs, attempt) / 2;
574
+ return Math.floor(halfCapMs) + spreadJitterMs(halfCapMs);
575
+ }
576
+ function exponentialDelayCapMs(baseDelayMs, maxDelayMs, attempt) {
577
+ if (!Number.isSafeInteger(attempt) || attempt < 1) return panic("attempt must be a positive integer");
578
+ return Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs);
579
+ }
580
+
491
581
  //#endregion
492
582
  //#region src/core/logger.ts
493
583
  /**
@@ -705,5 +795,5 @@ function createLogger(module, config) {
705
795
  }
706
796
 
707
797
  //#endregion
708
- export { StaleSessionError as A, RequestTimeoutError as C, InternalServerError as D, ValidationError as E, AuthenticationError as M, AppError as N, ServiceUnavailableError as O, MalformedRequestError as S, UpgradeRequiredError as T, defineErrors as _, createLogger as a, ValidationProblemDetailsSchema as b, isAbortError as c, Entity as d, defineMessages as f, DatabaseError as g, unreachable as h, consoleSink as i, RateLimitError as j, NotAuthorizedError as k, isTransientTransportError as l, notImplemented as m, Logger as n, setLogSink as o, defineId as p, configureLogger as r, setLoggerErrorHook as s, LogLevel as t, shouldRetryFailure as u, sharedErrors as v, ResourceNotFoundError as w, ValidationProblemErrorSchema as x, ProblemDetailsSchema as y };
709
- //# sourceMappingURL=core-Cx5SeyKV.js.map
798
+ export { ValidationProblemDetailsSchema as A, StaleSessionError as B, defineId as C, defineErrors as D, DatabaseError as E, UpgradeRequiredError as F, AuthenticationError as H, ValidationError as I, InternalServerError as L, MalformedRequestError as M, RequestTimeoutError as N, sharedErrors as O, ResourceNotFoundError as P, ServiceUnavailableError as R, defineMessages as S, unreachable as T, AppError as U, RateLimitError as V, isTransientCloudflareRuntimeError as _, createLogger as a, shouldRetryFailure as b, exponentialEqualJitterMs as c, classifyFailure as d, retryAfterSecondsOf as f, isCloudflareRetryableError as g, isCloudflareOverloadedError as h, consoleSink as i, ValidationProblemErrorSchema as j, ProblemDetailsSchema as k, spreadJitterMs as l, isCloudflareObjectResetError as m, Logger as n, setLogSink as o, CLOUDFLARE_TRANSIENT_ERROR_PATTERNS as p, configureLogger as r, setLoggerErrorHook as s, LogLevel as t, classifyBoundaryError as u, isAbortError as v, notImplemented as w, Entity as x, isTransientTransportError as y, NotAuthorizedError as z };
799
+ //# sourceMappingURL=core-DC_4pOrI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-DC_4pOrI.js","names":["uuidv7","uuidv7"],"sources":["../src/core/app-error.ts","../src/core/authentication.error.ts","../src/core/rate-limit.error.ts","../src/core/stale-session.error.ts","../src/core/not-authorized.error.ts","../src/core/internal.errors.ts","../src/core/request.errors.ts","../src/core/problem-details.ts","../src/core/error-table.ts","../src/core/database.error.ts","../src/core/defects.ts","../src/core/identity.ts","../src/core/define-messages.ts","../src/core/entity.ts","../src/core/failure-classification.ts","../src/core/transport-classification.ts","../src/core/cloudflare-classification.ts","../src/core/classify-failure.ts","../src/core/backoff.ts","../src/core/logger.ts"],"sourcesContent":["import type { FailureClassification } from './failure-classification.ts'\n\n/**\n * The base of every expected failure. A subclass declares its tag and its classification,\n * so no boundary has to guess what kind of failure it holds. A boundary tells our errors from\n * raw throws with `instanceof AppError`; a value that fails it was never judged.\n *\n * A `readonly` field with a literal initializer keeps the literal type, so\n * `readonly _tag = 'StoreUnavailable'` is enough for `Result` unions and `matchError`.\n */\nexport abstract class AppError extends Error {\n abstract readonly _tag: string\n abstract readonly classification: FailureClassification\n\n override get name(): string {\n return this._tag\n }\n}\n","import { AppError } from './app-error.ts'\n\n/** A protected operation requires a session that the caller did not provide. */\nexport class AuthenticationError extends AppError {\n readonly _tag = 'AuthenticationError'\n readonly classification = 'terminal'\n\n constructor() {\n super('Authentication required')\n }\n}\n","import { AppError } from './app-error.ts'\n\n/** HTTP 429 with a retry delay in seconds. A null delay means the response supplies no valid duration. */\nexport class RateLimitError extends AppError {\n readonly _tag = 'RateLimitError'\n readonly classification = 'transient'\n readonly status = 429\n\n constructor(readonly retryAfter: number | null) {\n super('Too many requests')\n }\n}\n","import { AppError } from './app-error.ts'\n\n/** A presented session cookie no longer resolves; the application owns cleanup and redirect policy. */\nexport class StaleSessionError extends AppError {\n readonly _tag = 'StaleSessionError'\n readonly classification = 'terminal'\n\n constructor() {\n super('Session is no longer valid. Sign in again.')\n }\n}\n","import { AppError } from './app-error.ts'\n\n/** The authenticated caller cannot perform this operation. Ported from Porte's auth.errors.ts. */\nexport class NotAuthorizedError extends AppError {\n readonly _tag = 'NotAuthorizedError'\n readonly classification = 'terminal'\n\n constructor() {\n super('Not allowed')\n }\n}\n","import { AppError } from './app-error.ts'\n\n/** Safe public replacement for an unknown failure, ported from Porte's internal.errors.ts. */\nexport class InternalServerError extends AppError {\n readonly _tag = 'InternalServerError'\n readonly classification = 'unknown'\n\n constructor() {\n super('Something went wrong')\n }\n}\n\n/** Safe public replacement for a classified transient failure. */\nexport class ServiceUnavailableError extends AppError {\n readonly _tag = 'ServiceUnavailableError'\n readonly classification = 'transient'\n\n constructor() {\n super('Try again shortly')\n }\n}\n","import { z } from 'zod'\n\nimport { AppError } from './app-error.ts'\nimport type { ValidationProblemError } from './problem-details.ts'\n\n/** One invalid value as a validator reports it: a message and a path of keys. */\nexport type ValidationIssue = {\n readonly message: string\n readonly path: readonly PropertyKey[]\n}\n\n/** Invalid user input, one entry per invalid value in the RFC 9457 shape. Technical failures use another error. */\nexport class ValidationError extends AppError {\n readonly _tag = 'ValidationError'\n readonly classification = 'terminal'\n\n constructor(\n readonly errors: readonly ValidationProblemError[],\n message = 'The request was not valid',\n ) {\n super(message)\n }\n\n /** Convert a Zod error. Each issue path becomes a JSON Pointer. */\n static fromZod(error: z.ZodError, message?: string): ValidationError {\n return ValidationError.fromIssues(error.issues, message)\n }\n\n /** Convert issues from any validator, such as issues TanStack serialized into an error message. */\n static fromIssues(issues: readonly ValidationIssue[], message?: string): ValidationError {\n return new ValidationError(\n issues.map((issue) => ({ detail: issue.message, pointer: jsonPointer(issue.path) })),\n message,\n )\n }\n}\n\n/** The server cannot parse the request syntax. */\nexport class MalformedRequestError extends AppError {\n readonly _tag = 'MalformedRequestError'\n readonly classification = 'terminal'\n\n constructor(args: { cause: unknown }) {\n super('The request was malformed', args)\n }\n}\n\n/** No resource matches the requested HTTP path. */\nexport class ResourceNotFoundError extends AppError {\n readonly _tag = 'ResourceNotFoundError'\n readonly classification = 'terminal'\n\n constructor() {\n super('Resource not found')\n }\n}\n\n/** A WebSocket route received a request without an upgrade. */\nexport class UpgradeRequiredError extends AppError {\n readonly _tag = 'UpgradeRequiredError'\n readonly classification = 'terminal'\n\n constructor() {\n super('WebSocket upgrade required')\n }\n}\n\n/** The requested operation did not answer before its deadline. */\nexport class RequestTimeoutError extends AppError {\n readonly _tag = 'RequestTimeoutError'\n readonly classification = 'transient'\n\n constructor() {\n super('The request timed out')\n }\n}\n\nconst readablePathSchema = z.array(z.union([z.string(), z.number()]))\n\n// A symbol step cannot be shown, so the pointer keeps only the steps a person can read.\nfunction jsonPointer(path: readonly PropertyKey[]): string {\n const parsed = readablePathSchema.safeParse(path)\n const steps = parsed.success ? parsed.data : []\n if (steps.length === 0) return '#'\n return `#/${steps.map((step) => String(step).replaceAll('~', '~0').replaceAll('/', '~1')).join('/')}`\n}\n","import { z } from 'zod'\n\n/**\n * The standard RFC 9457 body for a failed HTTP response.\n * The HTTP response status remains authoritative; extensions may add problem-specific data.\n * @see https://http.dev/problem-details\n */\nexport const ProblemDetailsSchema = z.looseObject({\n /**\n * Stable URI for the problem type; use `about:blank` when the HTTP status is sufficient.\n * @example \"about:blank\"\n */\n type: z.string(),\n /**\n * Stable human-readable name for the problem type.\n * @example \"Service Unavailable\"\n */\n title: z.string(),\n /**\n * Safe human-readable explanation for this occurrence; clients must not parse it.\n * @example \"The service is unavailable.\"\n */\n detail: z.string().optional(),\n /**\n * URI reference for this occurrence; omit it when no correlation resource exists.\n * @example \"/problems/occurrences/01K5F6Y7\"\n */\n instance: z.string().optional(),\n})\n\n/** An RFC 9457 problem body for a failed HTTP response. */\nexport type ProblemDetails = z.infer<typeof ProblemDetailsSchema>\n\n/** One invalid value in a `422` validation problem. */\nexport const ValidationProblemErrorSchema = z.object({\n /**\n * Safe explanation of why this value is invalid.\n * @example \"Must be a positive integer.\"\n */\n detail: z.string(),\n /**\n * RFC 6901 JSON Pointer fragment for the invalid value.\n * @example \"#/age\"\n */\n pointer: z.string().regex(/^#(?:\\/(?:[^~]|~[01])*)*$/u),\n})\n\n/** One invalid value in a `422` validation problem. */\nexport type ValidationProblemError = z.infer<typeof ValidationProblemErrorSchema>\n\n/** An RFC 9457 validation problem with one or more invalid content values. */\nexport const ValidationProblemDetailsSchema = ProblemDetailsSchema.extend({\n errors: z.array(ValidationProblemErrorSchema).min(1),\n})\n\n/** An RFC 9457 validation problem with one or more invalid content values. */\nexport type ValidationProblemDetails = z.infer<typeof ValidationProblemDetailsSchema>\n","import { panic } from 'better-result'\nimport { z } from 'zod'\n\nimport { AppError } from './app-error.ts'\nimport { AuthenticationError } from './authentication.error.ts'\nimport { InternalServerError, ServiceUnavailableError } from './internal.errors.ts'\nimport { NotAuthorizedError } from './not-authorized.error.ts'\nimport { ValidationProblemErrorSchema } from './problem-details.ts'\nimport { RateLimitError } from './rate-limit.error.ts'\nimport {\n MalformedRequestError,\n RequestTimeoutError,\n ResourceNotFoundError,\n UpgradeRequiredError,\n ValidationError,\n} from './request.errors.ts'\nimport { StaleSessionError } from './stale-session.error.ts'\n\ntype PublicFields = z.ZodObject\n\n/**\n * One public error: its class, its HTTP status, and the extra properties a client may read.\n * `fields` strips the thrown error on the server and parses the payload in the browser.\n */\nexport type ErrorEntry<Tag extends string, Fields extends PublicFields = PublicFields> = {\n readonly error: abstract new (...args: never[]) => AppError & { readonly _tag: Tag }\n readonly status: number\n readonly fields?: Fields\n}\n\ntype AnyErrorEntry = ErrorEntry<string>\n\n/** Entries keyed by tag. The compiler rejects a key that differs from the class's `_tag`. */\nexport type ErrorEntries<Entries> = {\n readonly [Tag in keyof Entries & string]: ErrorEntry<Tag>\n}\n\ntype EntryPayload<Tag extends string, Entry> = Entry extends {\n readonly fields: infer Fields extends z.ZodType\n}\n ? { readonly _tag: Tag; readonly message: string } & z.output<Fields>\n : { readonly _tag: Tag; readonly message: string }\n\ntype PayloadOfEntries<Entries> = {\n [Tag in keyof Entries & string]: EntryPayload<Tag, Entries[Tag]>\n}[keyof Entries & string]\n\n/** The HTTP status and public payload for one resolved failure. */\nexport type ResolvedError<Payload> = {\n readonly status: number\n readonly payload: Payload\n}\n\n/**\n * One application's public errors, shared by every transport boundary and the browser.\n * `resolve` and `fallback` serve boundaries. `parse` and `generic` serve screens.\n */\nexport type ErrorTable<Entries> = {\n readonly entries: Entries\n /** The discriminated union of every entry's `_tag`, `message`, and fields. */\n readonly payloadSchema: z.ZodType<PayloadOfEntries<Entries>>\n /** The `InternalServerError` payload, for screens that must show something. */\n readonly generic: PayloadOfEntries<Entries>\n /** Read a rejection value. Null means no known tag, so the request never reached the Worker. */\n parse(cause: unknown): PayloadOfEntries<Entries> | null\n /** Narrow a rejection value to one tag's payload, for a caller that acts on that one error. */\n is<Tag extends keyof Entries & string>(\n cause: unknown,\n tag: Tag,\n ): cause is Extract<PayloadOfEntries<Entries>, { readonly _tag: Tag }>\n /** Match a local instance or a remote error by tag. Null means the failure is not public. */\n resolve(cause: unknown): ResolvedError<PayloadOfEntries<Entries>> | null\n /** The replacement for an unmapped failure: 503 when it declared itself transient, else 500. */\n fallback(cause: unknown): ResolvedError<PayloadOfEntries<Entries>>\n}\n\n/** The union of payloads a table can produce. */\nexport type ErrorPayloadOf<Table> =\n Table extends ErrorTable<infer Entries> ? PayloadOfEntries<Entries> : never\n\n/** The union of tags a table contains. */\nexport type ErrorTagOf<Table> =\n Table extends ErrorTable<infer Entries> ? keyof Entries & string : never\n\nfunction entriesOf<const Entries extends ErrorEntries<Entries>>(entries: Entries): Entries {\n return entries\n}\n\nconst ValidationFields = z.object({ errors: z.array(ValidationProblemErrorSchema) })\nconst RateLimitFields = z.object({ retryAfter: z.number().nullable() })\n\n/** The errors every application can throw, with their statuses. `defineErrors` includes them. */\nexport const sharedErrors = entriesOf({\n MalformedRequestError: { error: MalformedRequestError, status: 400 },\n AuthenticationError: { error: AuthenticationError, status: 401 },\n StaleSessionError: { error: StaleSessionError, status: 401 },\n NotAuthorizedError: { error: NotAuthorizedError, status: 403 },\n ResourceNotFoundError: { error: ResourceNotFoundError, status: 404 },\n ValidationError: { error: ValidationError, status: 422, fields: ValidationFields },\n UpgradeRequiredError: { error: UpgradeRequiredError, status: 426 },\n RateLimitError: { error: RateLimitError, status: 429, fields: RateLimitFields },\n InternalServerError: { error: InternalServerError, status: 500 },\n ServiceUnavailableError: { error: ServiceUnavailableError, status: 503 },\n RequestTimeoutError: { error: RequestTimeoutError, status: 504 },\n})\n\ntype MergedEntries<Entries> = Omit<typeof sharedErrors, keyof Entries> & Entries\n\n// Workers RPC drops the prototype but keeps own properties and marks the error as remote.\nconst RemoteErrorSchema = z.object({\n _tag: z.string(),\n message: z.string(),\n remote: z.literal(true),\n})\n\ntype Match = { readonly tag: string; readonly entry: AnyErrorEntry; readonly error: Error }\n\nfunction match(byTag: ReadonlyMap<string, AnyErrorEntry>, cause: unknown): Match | null {\n if (cause instanceof AppError) {\n const entry = byTag.get(cause._tag)\n if (entry === undefined || !(cause instanceof entry.error)) return null\n return { tag: cause._tag, entry, error: cause }\n }\n if (!(cause instanceof Error)) return null\n const remote = RemoteErrorSchema.safeParse(cause)\n if (!remote.success) return null\n const entry = byTag.get(remote.data._tag)\n return entry === undefined ? null : { tag: remote.data._tag, entry, error: cause }\n}\n\n/**\n * Build the application's error table. The shared entries are always included;\n * an entry with the same key replaces the shared one.\n */\nexport function defineErrors<const Entries extends ErrorEntries<Entries>>(\n entries: Entries,\n): ErrorTable<MergedEntries<Entries>> {\n type Payload = PayloadOfEntries<MergedEntries<Entries>>\n const merged = { ...sharedErrors, ...entries }\n const byTag: ReadonlyMap<string, AnyErrorEntry> = new Map(Object.entries<AnyErrorEntry>(merged))\n\n const resolve = (cause: unknown): ResolvedError<Payload> | null => {\n const found = match(byTag, cause)\n if (found === null) return null\n const fields = found.entry.fields?.safeParse(found.error)\n if (fields !== undefined && !fields.success) return null\n // SAFETY: The entry's own `fields` schema produced these properties, so the payload has the shape declared for this tag.\n const payload = { _tag: found.tag, message: found.error.message, ...fields?.data } as Payload\n return { status: found.entry.status, payload }\n }\n\n const resolveShared = (error: AppError): ResolvedError<Payload> =>\n resolve(error) ?? panic(`Error table cannot resolve shared error ${error._tag}`)\n const generic = resolveShared(new InternalServerError())\n const unavailable = resolveShared(new ServiceUnavailableError())\n\n const variants = [...byTag].map(([tag, entry]) =>\n // oxlint-disable-next-line anti-slop/no-shape-in-symbol-names -- Zod names an object schema's property map `shape`.\n z.strictObject({ _tag: z.literal(tag), message: z.string(), ...entry.fields?.shape }),\n )\n const [first, ...rest] = variants\n if (first === undefined) return panic('Error table has no entries')\n // Each variant is one entry's `_tag`, `message`, and fields, which is the union `PayloadOfEntries` describes.\n const payloadSchema = z.discriminatedUnion('_tag', [first, ...rest]).pipe(z.custom<Payload>())\n\n // No return annotation: TypeScript resolves the deferred payload union differently in that position.\n const parse = (cause: unknown) => {\n const parsed = payloadSchema.safeParse(cause)\n return parsed.success ? parsed.data : null\n }\n\n return {\n entries: merged,\n payloadSchema,\n generic: generic.payload,\n parse,\n is<Tag extends keyof MergedEntries<Entries> & string>(\n cause: unknown,\n tag: Tag,\n ): cause is Extract<Payload, { readonly _tag: Tag }> {\n const parsed = parse(cause)\n return parsed !== null && parsed._tag === tag\n },\n resolve,\n fallback: (cause) =>\n cause instanceof AppError && cause.classification === 'transient' ? unavailable : generic,\n }\n}\n","import { AppError } from './app-error.ts'\nimport type { FailureClassification } from './failure-classification.ts'\n\n/** SQLite reports these constraint categories through D1. */\nexport type D1ConstraintKind = 'unique' | 'not_null' | 'foreign_key' | 'check'\n\n/** Database evidence for callers that interpret a specific code or constraint. */\nexport type DatabaseFailure =\n | {\n readonly database: 'd1'\n readonly code: string | undefined\n readonly kind: D1ConstraintKind | undefined\n readonly table: string | undefined\n readonly column: string | undefined\n readonly constraintName: string | undefined\n }\n | {\n readonly database: 'postgres'\n readonly code: string | undefined\n readonly table_name: string | undefined\n readonly column_name: string | undefined\n readonly constraint_name: string | undefined\n }\n\n/** Classification describes the failure; callers must separately establish whether repetition is safe. */\nexport class DatabaseError extends AppError {\n readonly _tag = 'DatabaseError'\n\n constructor(\n readonly operation: string,\n readonly classification: FailureClassification,\n readonly details: DatabaseFailure,\n options: { readonly cause: unknown },\n ) {\n super(`Database operation failed: ${operation}`, options)\n }\n}\n","import { panic } from 'better-result'\n\n/**\n * Mark a line the types say cannot run. A union member without a branch stops compilation here.\n *\n * @throws Panic when a value outside the union arrives at runtime.\n */\nexport function unreachable(value: never): never {\n return panic(`Unreachable: ${String(value)}`)\n}\n\n/**\n * Mark a body that is not written yet. A defect, not an expected failure.\n *\n * @param what - The behavior the body will provide, such as `invoice export`.\n * @throws Panic always.\n */\nexport function notImplemented(what: string): never {\n return panic(`Not implemented: ${what}`)\n}\n","import { v7 as uuidv7 } from 'uuid'\nimport { z } from 'zod'\n\n/** A string only `create()` or `schema.parse()` of the same kind can produce. */\nexport type Id<Brand extends string> = string & z.core.$brand<Brand>\n\n/** One id kind the application mints. `schema` parses untrusted input; `create` mints a uuid v7. */\nexport type IdDefinition<Brand extends string> = {\n readonly schema: z.core.$ZodBranded<z.ZodUUID, Brand>\n /** Mint a new time-ordered id. No parse: we produced it, so it is valid by construction. */\n create(): Id<Brand>\n}\n\n/** The id type of a definition: `type CallId = IdOf<typeof CallId>`. */\nexport type IdOf<Definition extends IdDefinition<string>> = z.output<Definition['schema']>\n\n/**\n * Define an id kind the application mints: `export const CallId = defineId('CallId')`.\n * An id another system mints, such as a provider's call id, stays a plain branded schema.\n */\nexport function defineId<const Brand extends string>(brand: Brand): IdDefinition<Brand> {\n const schema = z.uuidv7({ error: `Invalid ${brand}` })\n return {\n // SAFETY: `brand()` is type-only and returns a conditional TypeScript cannot reduce for a generic brand; for every literal it is this branded schema.\n schema: schema.brand<Brand>() as z.core.$ZodBranded<z.ZodUUID, Brand>,\n // SAFETY: uuidv7() always yields a valid v7 uuid, and the brand is a compile-time mark only.\n create: () => uuidv7() as Id<Brand>,\n }\n}\n","import { v7 as uuidv7 } from 'uuid'\nimport { z } from 'zod'\n\nimport type { DomainCommand, DomainEvent, DomainQuery, MessageId } from './messages.ts'\n\n/** Payload schemas keyed by message name. A payload never carries `type`, `name`, or `id`. */\nexport type PayloadSchemas = Readonly<Record<string, z.ZodType<object>>>\n\n/** An application's messages: one list of payload schemas per kind. */\nexport type MessageDefinition = {\n readonly commands: PayloadSchemas\n readonly events: PayloadSchemas\n readonly queries: PayloadSchemas\n}\n\ntype AnyMessages = { readonly definition: MessageDefinition }\ntype Def<Messages extends AnyMessages> = Messages['definition']\ntype Payload<Schemas extends PayloadSchemas, Name extends keyof Schemas> = z.output<Schemas[Name]>\n\n/** Every command of an application: `CommandOf<typeof messages>`. */\nexport type CommandOf<Messages extends AnyMessages> = {\n [Name in keyof Def<Messages>['commands'] & string]: DomainCommand<Name> &\n Payload<Def<Messages>['commands'], Name>\n}[keyof Def<Messages>['commands'] & string]\n\n/** Every event of an application: `EventOf<typeof messages>`. */\nexport type EventOf<Messages extends AnyMessages> = {\n [Name in keyof Def<Messages>['events'] & string]: DomainEvent<Name> &\n Payload<Def<Messages>['events'], Name>\n}[keyof Def<Messages>['events'] & string]\n\n/** Every query of an application: `QueryOf<typeof messages>`. */\nexport type QueryOf<Messages extends AnyMessages> = {\n [Name in keyof Def<Messages>['queries'] & string]: DomainQuery<Name> &\n Payload<Def<Messages>['queries'], Name>\n}[keyof Def<Messages>['queries'] & string]\n\n/** Every message of an application: what the registry and the bus are typed with. */\nexport type MessageOf<Messages extends AnyMessages> =\n | CommandOf<Messages>\n | EventOf<Messages>\n | QueryOf<Messages>\n\n/**\n * What `defineMessages` returns. The factories build messages for in-process dispatch without\n * parsing; the data is already typed. The schemas parse untrusted input at a boundary.\n */\nexport type AppMessages<Definition extends MessageDefinition> = {\n readonly definition: Definition\n /** Build a command. `id` defaults to a uuid v7; a webhook passes the provider's key, `stripe:event:evt_123`. */\n createCommand<Name extends keyof Definition['commands'] & string>(\n name: Name,\n payload: Payload<Definition['commands'], Name>,\n id?: MessageId,\n ): DomainCommand<Name> & Payload<Definition['commands'], Name>\n /** Build an event. `id` defaults to a uuid v7, which also orders it in time. */\n createEvent<Name extends keyof Definition['events'] & string>(\n name: Name,\n payload: Payload<Definition['events'], Name>,\n id?: MessageId,\n ): DomainEvent<Name> & Payload<Definition['events'], Name>\n /** Build a query. No id: nothing claims a read. */\n createQuery<Name extends keyof Definition['queries'] & string>(\n name: Name,\n payload: Payload<Definition['queries'], Name>,\n ): DomainQuery<Name> & Payload<Definition['queries'], Name>\n readonly commandSchema: z.ZodType<CommandOf<AppMessages<Definition>>>\n readonly eventSchema: z.ZodType<EventOf<AppMessages<Definition>>>\n readonly querySchema: z.ZodType<QueryOf<AppMessages<Definition>>>\n /** What a queue body may be: a command or an event. Queries never cross a queue. */\n readonly queueSchema: z.ZodType<\n CommandOf<AppMessages<Definition>> | EventOf<AppMessages<Definition>>\n >\n}\n\ntype RoutingField = 'type' | 'name' | 'id'\n\n/** A payload that declares a routing field maps to `never`, so `defineMessages` rejects it. */\ntype WithoutRoutingFields<Schemas extends PayloadSchemas> = {\n readonly [Name in keyof Schemas]: keyof z.output<Schemas[Name]> & RoutingField extends never\n ? Schemas[Name]\n : never\n}\n\n/** The compile-time rule: no payload of any kind declares `type`, `name`, or `id`. */\ntype ValidDefinition<Definition extends MessageDefinition> = {\n readonly commands: WithoutRoutingFields<Definition['commands']>\n readonly events: WithoutRoutingFields<Definition['events']>\n readonly queries: WithoutRoutingFields<Definition['queries']>\n}\n\nconst MessageIdSchema = z.string().min(1)\n\n/** One full message schema: the routing fields joined to the payload. */\nfunction messageSchema(\n type: 'command' | 'event' | 'query',\n name: string,\n payload: z.ZodType<object>,\n) {\n const routing =\n type === 'query'\n ? z.object({ type: z.literal(type), name: z.literal(name) })\n : z.object({ type: z.literal(type), name: z.literal(name), id: MessageIdSchema })\n return routing.and(payload)\n}\n\n/** A union over every message of one kind. Empty when the application has none of that kind. */\nfunction unionOf(type: 'command' | 'event' | 'query', schemas: PayloadSchemas) {\n return z.union(\n Object.entries(schemas).map(([name, payload]) => messageSchema(type, name, payload)),\n )\n}\n\n/**\n * Define an application's messages once. The key is the name; the factories add the routing\n * fields `type`, `name`, and `id`. A payload that declares one of them is a compile error.\n */\nexport function defineMessages<const Definition extends MessageDefinition>(\n definition: Definition & ValidDefinition<Definition>,\n): AppMessages<Definition> {\n const commandSchema = unionOf('command', definition.commands)\n const eventSchema = unionOf('event', definition.events)\n const querySchema = unionOf('query', definition.queries)\n return {\n definition,\n createCommand: (name, payload, id = uuidv7()) => ({ ...payload, type: 'command', name, id }),\n createEvent: (name, payload, id = uuidv7()) => ({ ...payload, type: 'event', name, id }),\n createQuery: (name, payload) => ({ ...payload, type: 'query', name }),\n commandSchema: commandSchema.pipe(z.custom<CommandOf<AppMessages<Definition>>>()),\n eventSchema: eventSchema.pipe(z.custom<EventOf<AppMessages<Definition>>>()),\n querySchema: querySchema.pipe(z.custom<QueryOf<AppMessages<Definition>>>()),\n queueSchema: z\n .union([commandSchema, eventSchema])\n .pipe(z.custom<CommandOf<AppMessages<Definition>> | EventOf<AppMessages<Definition>>>()),\n }\n}\n","import type { DomainEvent } from './messages.ts'\n\n/** What an aggregate's plain data must have: an identity. A branded id keeps its brand. */\nexport type EntityData = { readonly id: string }\n\n/**\n * The base of an aggregate: its identity, the events it raised, and the plain data a repository\n * stores. The subclass keeps its constructor private and declares `static restore(data: Data)`,\n * the one door a repository rebuilds it through. A repository drains the events after `save`.\n */\nexport abstract class Entity<Data extends EntityData, TEvent extends DomainEvent = DomainEvent> {\n private events: TEvent[] = []\n\n abstract readonly id: Data['id']\n\n /** Record one event with the state change that caused it. The unit of work commits both. */\n protected addEvent(event: TEvent): void {\n this.events.push(event)\n }\n\n /** A copy of the events raised since the last `clearEvents`. */\n collectEvents(): ReadonlyArray<TEvent> {\n return [...this.events]\n }\n\n /** Forget the raised events once the boundary has taken them. */\n clearEvents(): void {\n this.events = []\n }\n\n /** Plain data for the repository. The subclass's `restore(data)` accepts exactly this. */\n abstract toPlainObject(): Data\n}\n","/**\n * What one failure is, before any policy decides what to do about it.\n *\n * `transient`: the world may differ on the next attempt. `terminal`: repeating gives the\n * same answer. `unknown`: nobody judged this error, so it came from outside unwrapped.\n */\nexport type FailureClassification = 'transient' | 'terminal' | 'unknown'\n\n/**\n * Who is asking to repeat the work.\n *\n * An immediate owner holds a caller and a socket open. A durable owner already stored the\n * work, so it can afford to try again on a failure nobody classified.\n */\nexport type RetryOwner = 'immediate' | 'durable'\n\n/** Decide whether one retry owner may repeat a failed operation. */\nexport function shouldRetryFailure(args: {\n readonly classification: FailureClassification\n readonly repeatSafe: boolean\n readonly owner: RetryOwner\n}): boolean {\n if (!args.repeatSafe) return false\n if (args.classification === 'transient') return true\n if (args.classification === 'terminal') return false\n return args.owner === 'durable'\n}\n","/**\n * Messages that the platform-neutral transports raise for a failure that may pass.\n *\n * A boundary that knows its own runtime adds its own patterns before these.\n */\nconst TRANSIENT_TRANSPORT_PATTERNS = [\n /network/,\n /fetch failed/,\n /timeout/,\n /timed?\\s*out/,\n /connection.*(lost|reset|refused|closed|aborted)/,\n /econnreset/,\n /econnrefused/,\n /etimedout/,\n /eai_again/,\n]\n\n/** Cancellation is a decision, not a failure to repeat. */\nexport function isAbortError(cause: unknown): boolean {\n return cause instanceof Error && cause.name === 'AbortError'\n}\n\n/** Match known transient transport messages while excluding explicit cancellation. */\nexport function isTransientTransportError(cause: unknown): boolean {\n if (!(cause instanceof Error) || isAbortError(cause)) return false\n const message = cause.message.toLowerCase()\n return TRANSIENT_TRANSPORT_PATTERNS.some((pattern) => pattern.test(message))\n}\n","import { z } from 'zod'\n\n/** Stable Cloudflare messages that mean the runtime failed, not our code, and a repeat may pass. */\nexport const CLOUDFLARE_TRANSIENT_ERROR_PATTERNS = {\n networkConnectionLost: /network connection lost/,\n objectReset: /caused object to be reset/,\n codeUpdateReset: /reset because its code was updated/,\n objectMoved: /object has moved to a different machine/,\n internalWorkflows: /internal workflows error/,\n} as const\n\nconst TRANSIENT_PLATFORM_PATTERNS = [\n CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.objectReset,\n CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.codeUpdateReset,\n CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.objectMoved,\n CLOUDFLARE_TRANSIENT_ERROR_PATTERNS.internalWorkflows,\n]\n\n// workerd stamps these flags as own properties on the error it throws across a binding.\nconst RetryableFlagSchema = z.object({ retryable: z.literal(true) })\nconst OverloadedFlagSchema = z.object({ overloaded: z.literal(true) })\nconst ObjectResetFlagSchema = z.object({ durableObjectReset: z.literal(true) })\n\n/** workerd stamps `retryable` on a failure it judged safe to repeat. */\nexport function isCloudflareRetryableError(cause: unknown): boolean {\n return RetryableFlagSchema.validate(cause)\n}\n\n/** workerd stamps `overloaded` when the target could not take the call. */\nexport function isCloudflareOverloadedError(cause: unknown): boolean {\n return OverloadedFlagSchema.validate(cause)\n}\n\n/** workerd stamps `durableObjectReset` when the object restarted during the call. */\nexport function isCloudflareObjectResetError(cause: unknown): boolean {\n return ObjectResetFlagSchema.validate(cause)\n}\n\n/** Match transient Cloudflare runtime evidence without the general transport patterns. */\nexport function isTransientCloudflareRuntimeError(cause: unknown): boolean {\n if (isCloudflareObjectResetError(cause)) return true\n if (!(cause instanceof Error)) return false\n const message = cause.message.toLowerCase()\n return TRANSIENT_PLATFORM_PATTERNS.some((pattern) => pattern.test(message))\n}\n","import { z } from 'zod'\n\nimport { AppError } from './app-error.ts'\nimport {\n isCloudflareOverloadedError,\n isCloudflareRetryableError,\n isTransientCloudflareRuntimeError,\n} from './cloudflare-classification.ts'\nimport type { FailureClassification } from './failure-classification.ts'\nimport { isAbortError, isTransientTransportError } from './transport-classification.ts'\n\n/** A boundary's own rule for its raw errors. `undefined` means the boundary has no opinion. */\nexport type BoundaryErrorClassifier = (cause: unknown) => FailureClassification | undefined\n\n/**\n * Classify one raw external error: the boundary's own rule first, then Cloudflare's signals,\n * then the transport patterns. Cancellation is terminal even when Cloudflare marks it retryable.\n */\nexport function classifyBoundaryError(args: {\n readonly cause: unknown\n readonly classifyBoundary: BoundaryErrorClassifier\n readonly includeCloudflare: boolean\n}): FailureClassification {\n const boundary = args.classifyBoundary(args.cause)\n if (boundary !== undefined) return boundary\n\n if (isAbortError(args.cause)) return 'terminal'\n\n if (\n args.includeCloudflare &&\n (isCloudflareOverloadedError(args.cause) ||\n isCloudflareRetryableError(args.cause) ||\n isTransientCloudflareRuntimeError(args.cause))\n ) {\n return 'transient'\n }\n\n if (isTransientTransportError(args.cause)) return 'transient'\n\n return 'unknown'\n}\n\n/**\n * Judge a final failure for its durable retry owner. An `AppError` carries its own answer.\n * A raw throw nobody judged is unknown, so an immediate owner stops and a durable one may repeat.\n */\nexport function classifyFailure(cause: unknown): FailureClassification {\n if (cause instanceof AppError) return cause.classification\n if (isAbortError(cause)) return 'terminal'\n if (isTransientCloudflareRuntimeError(cause)) return 'transient'\n return 'unknown'\n}\n\nconst RetryAfterSchema = z.object({ retryAfter: z.number().positive() })\n\n/** Read a positive server-advertised retry delay in seconds, such as `RateLimitError.retryAfter`. */\nexport function retryAfterSecondsOf(cause: unknown): number | null {\n const result = RetryAfterSchema.safeParse(cause)\n return result.success ? result.data.retryAfter : null\n}\n","import { panic } from 'better-result'\n\n/** Uniform jitter within one fixed window. */\nexport function spreadJitterMs(spreadMs: number): number {\n if (!Number.isFinite(spreadMs) || spreadMs < 0) {\n return panic('spreadMs must be a non-negative number')\n }\n return Math.floor(Math.random() * spreadMs)\n}\n\n/**\n * Half the capped exponential delay, plus jitter over the other half. Decorrelates concurrent\n * repeats like full jitter, but keeps a floor: use it when few attempts remain before work is dropped.\n */\nexport function exponentialEqualJitterMs(\n baseDelayMs: number,\n maxDelayMs: number,\n attempt: number,\n): number {\n const halfCapMs = exponentialDelayCapMs(baseDelayMs, maxDelayMs, attempt) / 2\n return Math.floor(halfCapMs) + spreadJitterMs(halfCapMs)\n}\n\nfunction exponentialDelayCapMs(baseDelayMs: number, maxDelayMs: number, attempt: number): number {\n if (!Number.isSafeInteger(attempt) || attempt < 1) {\n return panic('attempt must be a positive integer')\n }\n return Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs)\n}\n","/**\n * Module-scoped logging for every host.\n *\n * A logger emits one plain-data entry per log. The default sink hands it to `console` as an\n * entry object for a log service or as a colored line for a person, selected at startup.\n */\n\n/** A value a log entry may carry. Errors enter only through `Logger.error`. */\nexport type LogValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ReadonlyArray<LogValue>\n | LogFields\n\n/** Named log values. */\nexport type LogFields = { readonly [key: string]: LogValue }\n\n/**\n * The supported log severity levels, in ascending order.\n *\n * A const object, not an enum, so a parsed environment value typed `'INFO'` is a `LogLevel`.\n */\nexport const LogLevel = {\n DEBUG: 'DEBUG',\n INFO: 'INFO',\n WARN: 'WARN',\n ERROR: 'ERROR',\n} as const\nexport type LogLevel = (typeof LogLevel)[keyof typeof LogLevel]\n\n/** An error as plain data, including diagnostics, causes, and aggregate members. */\nexport type SerializedError = {\n readonly name: string\n readonly message: string\n readonly stack?: string\n readonly fields?: LogFields\n readonly cause?: SerializedError\n readonly errors?: ReadonlyArray<SerializedError>\n}\n\n/** One log, as the sink receives it. Plain data, safe to stringify. */\nexport type LogEntry = {\n readonly timestamp: string\n readonly level: LogLevel\n readonly module: string\n readonly message: string\n readonly details: LogFields\n readonly userId?: string\n /** Present on `Logger.error` entries that carried an error. */\n readonly error?: SerializedError\n}\n\n/** The context an error log carries. */\nexport type ErrorLogContext = {\n readonly error?: unknown\n readonly userId?: string\n readonly details?: LogFields\n}\n\n/** What a logger lets through: a level and everything above it, or nothing. */\nexport type LogThreshold = LogLevel | 'OFF'\n\n/** Overrides the application settings for one logger. */\nexport interface LoggerConfig {\n readonly level?: LogThreshold\n}\n\n/** `json` writes the entry object. `pretty` writes one readable line for a person. */\nexport type LogFormat = 'json' | 'pretty'\n\n/**\n * The application settings, set once at the composition root.\n *\n * An omitted field keeps its default. An explicit `undefined` is a compile error, so the root\n * parses an environment value before passing it. The logger reads no environment itself.\n */\nexport interface LoggerSettings extends LoggerConfig {\n readonly format?: LogFormat\n}\n\n// The production server setting, so a root that never configures still logs safely.\nconst DEFAULT_SETTINGS: Required<LoggerSettings> = {\n level: LogLevel.INFO,\n format: 'json',\n}\n\n// The application configures once at startup; loggers can exist before startup completes.\nlet settings = DEFAULT_SETTINGS\n\n/**\n * Set application settings, including for existing loggers. Per-logger overrides take priority.\n * Call at startup, never per request. An omitted field resets to INFO and JSON output.\n */\nexport function configureLogger(config: LoggerSettings): void {\n settings = {\n level: config.level ?? DEFAULT_SETTINGS.level,\n format: config.format ?? DEFAULT_SETTINGS.format,\n }\n}\n\n/** The error data sent to the configured error hook. */\nexport interface ErrorCaptureEntry {\n readonly error: unknown\n readonly distinctId: string | undefined\n readonly context: LogFields\n}\n\n/** A function that forwards one logged error to an error service. */\nexport type LoggerErrorHook = (entry: ErrorCaptureEntry) => void\n\n/** Where every log entry goes. */\nexport type LogSink = (entry: LogEntry) => void\n\nlet errorHook: LoggerErrorHook | null = null\n\n/**\n * Register the function that receives each logged error.\n *\n * Set once at the process entry point. A later call replaces the earlier hook.\n */\nexport function setLoggerErrorHook(fn: LoggerErrorHook): void {\n errorHook = fn\n}\n\n// One console method per level, so a host that filters by method can tell them apart.\nconst CONSOLE_METHOD = {\n [LogLevel.DEBUG]: 'debug',\n [LogLevel.INFO]: 'info',\n [LogLevel.WARN]: 'warn',\n [LogLevel.ERROR]: 'error',\n} as const satisfies Record<LogLevel, 'debug' | 'info' | 'warn' | 'error'>\n\n// Built from the code point so no raw control character sits in the source.\nconst ESC = String.fromCharCode(27)\nconst ANSI_RESET = `${ESC}[0m`\nconst ANSI_GRAY = `${ESC}[90m`\nconst ANSI_BLUE = `${ESC}[34m`\n\n// Severity reads at a glance: quiet levels stay dim, and an error is the only bold line.\nconst LEVEL_ANSI = {\n DEBUG: `${ESC}[2;36m`,\n INFO: ANSI_BLUE,\n WARN: `${ESC}[33m`,\n ERROR: `${ESC}[1;31m`,\n} satisfies Record<LogLevel, string>\n\nfunction prettyLine(entry: LogEntry): string {\n // Node prints debug and info exactly like log, so the level must be in the text too.\n const level = `[${entry.level}]`\n const module = `[${entry.module}]`\n // A browser console colors by method on its own; a terminal needs ANSI to do the same.\n if ('window' in globalThis) return `${entry.timestamp} ${level} ${module} ${entry.message}`\n const timestamp = `${ANSI_GRAY}${entry.timestamp}${ANSI_RESET}`\n const coloredLevel = `${LEVEL_ANSI[entry.level]}${level}${ANSI_RESET}`\n const coloredModule = `${ANSI_BLUE}${module}${ANSI_RESET}`\n return `${timestamp} ${coloredLevel} ${coloredModule} ${entry.message}`\n}\n\n/**\n * JSON format writes the entry object. Pretty format writes one line, then the details,\n * the error, and the stack as separate console arguments.\n */\nexport const consoleSink: LogSink = (entry) => {\n // Resolved per call, so a console replaced after import still receives the output.\n const write = console[CONSOLE_METHOD[entry.level]]\n if (settings.format === 'json') {\n write(entry)\n return\n }\n const line = prettyLine(entry)\n const fields =\n entry.userId === undefined ? entry.details : { ...entry.details, userId: entry.userId }\n const details = Object.keys(fields).length === 0 ? [] : [fields]\n if (entry.error === undefined) {\n write(line, ...details)\n return\n }\n // A stack inside an object prints as one quoted string; as its own argument it prints as lines.\n const { stack, ...error } = entry.error\n if (stack === undefined) write(line, ...details, error)\n else write(line, ...details, error, `\\n${stack}`)\n}\n\nlet logSink: LogSink = consoleSink\n\n/**\n * Send every log entry somewhere other than `console`.\n *\n * Set once at the process entry point, never per module. A logger is created\n * by name and nothing else, so its destination is a fact about the process.\n */\nexport function setLogSink(fn: LogSink): void {\n logSink = fn\n}\n\nconst LOG_LEVELS = Object.values(LogLevel)\nconst MAX_ERROR_DEPTH = 3\n\n/**\n * Diagnostics worth keeping off an error, named one by one.\n *\n * An allowlist rather than every own property: an error raised by a library we\n * do not control may hang a request or a user payload off itself, and a log is\n * the wrong place to discover that. `_tag` and `classification` are what every `AppError`\n * declares. `remote` and the three flags after it are the ones workerd sets itself.\n */\nconst KEPT_ERROR_FIELDS = [\n '_tag',\n 'classification',\n 'code',\n 'operation',\n 'status',\n 'statusCode',\n 'remote',\n 'retryable',\n 'overloaded',\n 'durableObjectReset',\n] as const\n\ntype ErrorDiagnostics = Error & { readonly [K in (typeof KEPT_ERROR_FIELDS)[number]]?: LogValue }\n\ntype MutableSerializedError = { -readonly [K in keyof SerializedError]: SerializedError[K] }\n\nconst serializeError = (error: Error, depth = 0): SerializedError => {\n if (depth > MAX_ERROR_DEPTH) return { name: 'Error', message: '[error nesting truncated]' }\n\n // Every field is optional, so an `Error` is already one of these.\n const carrier: ErrorDiagnostics = error\n const kept = KEPT_ERROR_FIELDS.filter((key) => carrier[key] !== undefined)\n const serialized: MutableSerializedError = { name: error.name, message: error.message }\n if (error.stack !== undefined) serialized.stack = error.stack\n if (kept.length > 0)\n serialized.fields = Object.fromEntries(kept.map((key) => [key, carrier[key]]))\n if (error.cause instanceof Error) serialized.cause = serializeError(error.cause, depth + 1)\n else if (error.cause !== undefined)\n serialized.cause = { name: 'Error', message: '[non-error cause]' }\n if (error instanceof AggregateError) {\n // oxlint-disable-next-line anti-slop/no-unknown-parameters -- AggregateError accepts arbitrary values; instanceof Error validates each member.\n serialized.errors = error.errors.map((failure: unknown) =>\n failure instanceof Error\n ? serializeError(failure, depth + 1)\n : { name: 'NonError', message: '[non-error aggregate member]' },\n )\n }\n return serialized\n}\n\n/** Write module-scoped logs with application defaults and optional overrides. */\nexport class Logger {\n private readonly config: LoggerConfig\n\n /** Create a logger for one module. */\n constructor(\n private readonly module: string,\n overrideConfig?: LoggerConfig,\n ) {\n this.config = { ...overrideConfig }\n }\n\n private log(\n level: LogLevel,\n message: string,\n details: LogFields,\n error?: SerializedError,\n userId?: string,\n ): void {\n const threshold = this.config.level ?? settings.level\n if (threshold === 'OFF') return\n if (LOG_LEVELS.indexOf(level) < LOG_LEVELS.indexOf(threshold)) return\n\n let entry: LogEntry = {\n timestamp: new Date().toISOString(),\n level,\n module: this.module,\n message,\n details,\n }\n if (userId !== undefined) entry = { ...entry, userId }\n logSink(error === undefined ? entry : { ...entry, error })\n }\n\n /** Write a debug log. */\n debug(message: string, details: LogFields = {}): void {\n this.log(LogLevel.DEBUG, message, details)\n }\n\n /** Write an information log. */\n info(message: string, details: LogFields = {}): void {\n this.log(LogLevel.INFO, message, details)\n }\n\n /** Write a warning log. */\n warn(message: string, details: LogFields = {}): void {\n this.log(LogLevel.WARN, message, details)\n }\n\n /**\n * Write an error log and send the error to the configured hook.\n *\n * The details say which call this was, and the error says what went wrong\n * inside it. Both the entry and the error hook receive the supplied user ID.\n */\n error(message: string, context: ErrorLogContext = {}): void {\n const details = context.details ?? {}\n const thrown = context.error\n let error: SerializedError | undefined\n if (thrown instanceof Error) {\n error = serializeError(thrown)\n } else if (thrown !== undefined) {\n // Not an `Error`, so there is no name or stack to keep, only its JSON form.\n let json: string\n try {\n json = JSON.stringify(thrown)\n } catch {\n json = '[non-serializable error]'\n }\n error = { name: 'NonError', message: json }\n }\n this.log(LogLevel.ERROR, message, details, error, context.userId)\n\n if (errorHook !== null && thrown !== undefined) {\n errorHook({ error: thrown, distinctId: context.userId, context: details })\n }\n }\n}\n\n/** Create a logger for one module. */\nexport function createLogger(module: string, config?: LoggerConfig): Logger {\n return new Logger(module, config)\n}\n"],"mappings":"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"}
package/dist/core.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as sharedErrors, A as QueryOf, B as defineId, C as EntityData, D as MessageDefinition, E as EventOf, F as DomainQuery, G as DatabaseFailure, H as unreachable, I as MessageId, J as ErrorPayloadOf, K as ErrorEntries, L as Id, M as DomainCommand, N as DomainEvent, O as MessageOf, P as DomainMessage, Q as defineErrors, R as IdDefinition, S as Entity, T as CommandOf, U as D1ConstraintKind, V as notImplemented, W as DatabaseError, X as ErrorTagOf, Y as ErrorTable, Z as ResolvedError, _ as createLogger, _t as AuthenticationError, a as LogFormat, at as ValidationIssue, b as isAbortError, bt as RetryOwner, c as LogThreshold, ct as ValidationProblemDetails, d as LoggerConfig, dt as ValidationProblemErrorSchema, et as MalformedRequestError, f as LoggerErrorHook, ft as InternalServerError, g as consoleSink, gt as RateLimitError, h as configureLogger, ht as StaleSessionError, i as LogFields, it as ValidationError, j as defineMessages, k as PayloadSchemas, l as LogValue, lt as ValidationProblemDetailsSchema, m as SerializedError, mt as NotAuthorizedError, n as ErrorLogContext, nt as ResourceNotFoundError, o as LogLevel, ot as ProblemDetails, p as LoggerSettings, pt as ServiceUnavailableError, q as ErrorEntry, r as LogEntry, rt as UpgradeRequiredError, s as LogSink, st as ProblemDetailsSchema, t as ErrorCaptureEntry, tt as RequestTimeoutError, u as Logger, ut as ValidationProblemError, v as setLogSink, vt as AppError, w as AppMessages, x as isTransientTransportError, xt as shouldRetryFailure, y as setLoggerErrorHook, yt as FailureClassification, z as IdOf } from "./index-BStnggQO.js";
2
- export { AppError, type AppMessages, AuthenticationError, type CommandOf, type D1ConstraintKind, DatabaseError, type DatabaseFailure, type DomainCommand, type DomainEvent, type DomainMessage, type DomainQuery, Entity, type EntityData, type ErrorCaptureEntry, type ErrorEntries, type ErrorEntry, type ErrorLogContext, type ErrorPayloadOf, type ErrorTable, type ErrorTagOf, type EventOf, type FailureClassification, type Id, type IdDefinition, type IdOf, InternalServerError, type LogEntry, type LogFields, type LogFormat, LogLevel, type LogSink, type LogThreshold, type LogValue, Logger, type LoggerConfig, type LoggerErrorHook, type LoggerSettings, MalformedRequestError, type MessageDefinition, type MessageId, type MessageOf, NotAuthorizedError, type PayloadSchemas, type ProblemDetails, ProblemDetailsSchema, type QueryOf, RateLimitError, RequestTimeoutError, type ResolvedError, ResourceNotFoundError, type RetryOwner, type SerializedError, ServiceUnavailableError, StaleSessionError, UpgradeRequiredError, ValidationError, type ValidationIssue, type ValidationProblemDetails, ValidationProblemDetailsSchema, type ValidationProblemError, ValidationProblemErrorSchema, configureLogger, consoleSink, createLogger, defineErrors, defineId, defineMessages, isAbortError, isTransientTransportError, notImplemented, setLogSink, setLoggerErrorHook, sharedErrors, shouldRetryFailure, unreachable };
1
+ import { $ as unreachable, A as isTransientCloudflareRuntimeError, At as FailureClassification, B as PayloadSchemas, C as classifyBoundaryError, Ct as InternalServerError, D as isCloudflareObjectResetError, Dt as RateLimitError, E as CLOUDFLARE_TRANSIENT_ERROR_PATTERNS, Et as StaleSessionError, F as AppMessages, G as DomainMessage, H as defineMessages, I as CommandOf, J as Id, K as DomainQuery, L as EventOf, M as isTransientTransportError, Mt as shouldRetryFailure, N as Entity, O as isCloudflareOverloadedError, Ot as AuthenticationError, P as EntityData, Q as notImplemented, R as MessageDefinition, S as BoundaryErrorClassifier, St as ValidationProblemErrorSchema, T as retryAfterSecondsOf, Tt as NotAuthorizedError, U as DomainCommand, V as QueryOf, W as DomainEvent, X as IdOf, Y as IdDefinition, Z as defineId, _ as createLogger, _t as ProblemDetails, a as LogFormat, at as ErrorPayloadOf, b as exponentialEqualJitterMs, bt as ValidationProblemDetailsSchema, c as LogThreshold, ct as ResolvedError, d as LoggerConfig, dt as MalformedRequestError, et as D1ConstraintKind, f as LoggerErrorHook, ft as RequestTimeoutError, g as consoleSink, gt as ValidationIssue, h as configureLogger, ht as ValidationError, i as LogFields, it as ErrorEntry, j as isAbortError, jt as RetryOwner, k as isCloudflareRetryableError, kt as AppError, l as LogValue, lt as defineErrors, m as SerializedError, mt as UpgradeRequiredError, n as ErrorLogContext, nt as DatabaseFailure, o as LogLevel, ot as ErrorTable, p as LoggerSettings, pt as ResourceNotFoundError, q as MessageId, r as LogEntry, rt as ErrorEntries, s as LogSink, st as ErrorTagOf, t as ErrorCaptureEntry, tt as DatabaseError, u as Logger, ut as sharedErrors, v as setLogSink, vt as ProblemDetailsSchema, w as classifyFailure, wt as ServiceUnavailableError, x as spreadJitterMs, xt as ValidationProblemError, y as setLoggerErrorHook, yt as ValidationProblemDetails, z as MessageOf } from "./index-6XMPJu7u.js";
2
+ export { AppError, type AppMessages, AuthenticationError, type BoundaryErrorClassifier, CLOUDFLARE_TRANSIENT_ERROR_PATTERNS, type CommandOf, type D1ConstraintKind, DatabaseError, type DatabaseFailure, type DomainCommand, type DomainEvent, type DomainMessage, type DomainQuery, Entity, type EntityData, type ErrorCaptureEntry, type ErrorEntries, type ErrorEntry, type ErrorLogContext, type ErrorPayloadOf, type ErrorTable, type ErrorTagOf, type EventOf, type FailureClassification, type Id, type IdDefinition, type IdOf, InternalServerError, type LogEntry, type LogFields, type LogFormat, LogLevel, type LogSink, type LogThreshold, type LogValue, Logger, type LoggerConfig, type LoggerErrorHook, type LoggerSettings, MalformedRequestError, type MessageDefinition, type MessageId, type MessageOf, NotAuthorizedError, type PayloadSchemas, type ProblemDetails, ProblemDetailsSchema, type QueryOf, RateLimitError, RequestTimeoutError, type ResolvedError, ResourceNotFoundError, type RetryOwner, type SerializedError, ServiceUnavailableError, StaleSessionError, UpgradeRequiredError, ValidationError, type ValidationIssue, type ValidationProblemDetails, ValidationProblemDetailsSchema, type ValidationProblemError, ValidationProblemErrorSchema, classifyBoundaryError, classifyFailure, configureLogger, consoleSink, createLogger, defineErrors, defineId, defineMessages, exponentialEqualJitterMs, isAbortError, isCloudflareObjectResetError, isCloudflareOverloadedError, isCloudflareRetryableError, isTransientCloudflareRuntimeError, isTransientTransportError, notImplemented, retryAfterSecondsOf, setLogSink, setLoggerErrorHook, sharedErrors, shouldRetryFailure, spreadJitterMs, unreachable };
package/dist/core.js CHANGED
@@ -1,3 +1,3 @@
1
- import { A as StaleSessionError, C as RequestTimeoutError, D as InternalServerError, E as ValidationError, M as AuthenticationError, N as AppError, O as ServiceUnavailableError, S as MalformedRequestError, T as UpgradeRequiredError, _ as defineErrors, a as createLogger, b as ValidationProblemDetailsSchema, c as isAbortError, d as Entity, f as defineMessages, g as DatabaseError, h as unreachable, i as consoleSink, j as RateLimitError, k as NotAuthorizedError, l as isTransientTransportError, m as notImplemented, n as Logger, o as setLogSink, p as defineId, r as configureLogger, s as setLoggerErrorHook, t as LogLevel, u as shouldRetryFailure, v as sharedErrors, w as ResourceNotFoundError, x as ValidationProblemErrorSchema, y as ProblemDetailsSchema } from "./core-Cx5SeyKV.js";
1
+ import { A as ValidationProblemDetailsSchema, B as StaleSessionError, C as defineId, D as defineErrors, E as DatabaseError, F as UpgradeRequiredError, H as AuthenticationError, I as ValidationError, L as InternalServerError, M as MalformedRequestError, N as RequestTimeoutError, O as sharedErrors, P as ResourceNotFoundError, R as ServiceUnavailableError, S as defineMessages, T as unreachable, U as AppError, V as RateLimitError, _ as isTransientCloudflareRuntimeError, a as createLogger, b as shouldRetryFailure, c as exponentialEqualJitterMs, d as classifyFailure, f as retryAfterSecondsOf, g as isCloudflareRetryableError, h as isCloudflareOverloadedError, i as consoleSink, j as ValidationProblemErrorSchema, k as ProblemDetailsSchema, l as spreadJitterMs, m as isCloudflareObjectResetError, n as Logger, o as setLogSink, p as CLOUDFLARE_TRANSIENT_ERROR_PATTERNS, r as configureLogger, s as setLoggerErrorHook, t as LogLevel, u as classifyBoundaryError, v as isAbortError, w as notImplemented, x as Entity, y as isTransientTransportError, z as NotAuthorizedError } from "./core-DC_4pOrI.js";
2
2
 
3
- export { AppError, AuthenticationError, DatabaseError, Entity, InternalServerError, LogLevel, Logger, MalformedRequestError, NotAuthorizedError, ProblemDetailsSchema, RateLimitError, RequestTimeoutError, ResourceNotFoundError, ServiceUnavailableError, StaleSessionError, UpgradeRequiredError, ValidationError, ValidationProblemDetailsSchema, ValidationProblemErrorSchema, configureLogger, consoleSink, createLogger, defineErrors, defineId, defineMessages, isAbortError, isTransientTransportError, notImplemented, setLogSink, setLoggerErrorHook, sharedErrors, shouldRetryFailure, unreachable };
3
+ export { AppError, AuthenticationError, CLOUDFLARE_TRANSIENT_ERROR_PATTERNS, DatabaseError, Entity, InternalServerError, LogLevel, Logger, MalformedRequestError, NotAuthorizedError, ProblemDetailsSchema, RateLimitError, RequestTimeoutError, ResourceNotFoundError, ServiceUnavailableError, StaleSessionError, UpgradeRequiredError, ValidationError, ValidationProblemDetailsSchema, ValidationProblemErrorSchema, classifyBoundaryError, classifyFailure, configureLogger, consoleSink, createLogger, defineErrors, defineId, defineMessages, exponentialEqualJitterMs, isAbortError, isCloudflareObjectResetError, isCloudflareOverloadedError, isCloudflareRetryableError, isTransientCloudflareRuntimeError, isTransientTransportError, notImplemented, retryAfterSecondsOf, setLogSink, setLoggerErrorHook, sharedErrors, shouldRetryFailure, spreadJitterMs, unreachable };
@@ -455,6 +455,53 @@ declare function isAbortError(cause: unknown): boolean;
455
455
  /** Match known transient transport messages while excluding explicit cancellation. */
456
456
  declare function isTransientTransportError(cause: unknown): boolean;
457
457
  //#endregion
458
+ //#region src/core/cloudflare-classification.d.ts
459
+ /** Stable Cloudflare messages that mean the runtime failed, not our code, and a repeat may pass. */
460
+ declare const CLOUDFLARE_TRANSIENT_ERROR_PATTERNS: {
461
+ readonly networkConnectionLost: RegExp;
462
+ readonly objectReset: RegExp;
463
+ readonly codeUpdateReset: RegExp;
464
+ readonly objectMoved: RegExp;
465
+ readonly internalWorkflows: RegExp;
466
+ };
467
+ /** workerd stamps `retryable` on a failure it judged safe to repeat. */
468
+ declare function isCloudflareRetryableError(cause: unknown): boolean;
469
+ /** workerd stamps `overloaded` when the target could not take the call. */
470
+ declare function isCloudflareOverloadedError(cause: unknown): boolean;
471
+ /** workerd stamps `durableObjectReset` when the object restarted during the call. */
472
+ declare function isCloudflareObjectResetError(cause: unknown): boolean;
473
+ /** Match transient Cloudflare runtime evidence without the general transport patterns. */
474
+ declare function isTransientCloudflareRuntimeError(cause: unknown): boolean;
475
+ //#endregion
476
+ //#region src/core/classify-failure.d.ts
477
+ /** A boundary's own rule for its raw errors. `undefined` means the boundary has no opinion. */
478
+ type BoundaryErrorClassifier = (cause: unknown) => FailureClassification | undefined;
479
+ /**
480
+ * Classify one raw external error: the boundary's own rule first, then Cloudflare's signals,
481
+ * then the transport patterns. Cancellation is terminal even when Cloudflare marks it retryable.
482
+ */
483
+ declare function classifyBoundaryError(args: {
484
+ readonly cause: unknown;
485
+ readonly classifyBoundary: BoundaryErrorClassifier;
486
+ readonly includeCloudflare: boolean;
487
+ }): FailureClassification;
488
+ /**
489
+ * Judge a final failure for its durable retry owner. An `AppError` carries its own answer.
490
+ * A raw throw nobody judged is unknown, so an immediate owner stops and a durable one may repeat.
491
+ */
492
+ declare function classifyFailure(cause: unknown): FailureClassification;
493
+ /** Read a positive server-advertised retry delay in seconds, such as `RateLimitError.retryAfter`. */
494
+ declare function retryAfterSecondsOf(cause: unknown): number | null;
495
+ //#endregion
496
+ //#region src/core/backoff.d.ts
497
+ /** Uniform jitter within one fixed window. */
498
+ declare function spreadJitterMs(spreadMs: number): number;
499
+ /**
500
+ * Half the capped exponential delay, plus jitter over the other half. Decorrelates concurrent
501
+ * repeats like full jitter, but keeps a floor: use it when few attempts remain before work is dropped.
502
+ */
503
+ declare function exponentialEqualJitterMs(baseDelayMs: number, maxDelayMs: number, attempt: number): number;
504
+ //#endregion
458
505
  //#region src/core/logger.d.ts
459
506
  /**
460
507
  * Module-scoped logging for every host.
@@ -580,5 +627,5 @@ declare class Logger {
580
627
  /** Create a logger for one module. */
581
628
  declare function createLogger(module: string, config?: LoggerConfig): Logger;
582
629
  //#endregion
583
- export { sharedErrors as $, QueryOf as A, defineId as B, EntityData as C, MessageDefinition as D, EventOf as E, DomainQuery as F, DatabaseFailure as G, unreachable as H, MessageId as I, ErrorPayloadOf as J, ErrorEntries as K, Id as L, DomainCommand as M, DomainEvent as N, MessageOf as O, DomainMessage as P, defineErrors as Q, IdDefinition as R, Entity as S, CommandOf as T, D1ConstraintKind as U, notImplemented as V, DatabaseError as W, ErrorTagOf as X, ErrorTable as Y, ResolvedError as Z, createLogger as _, AuthenticationError as _t, LogFormat as a, ValidationIssue as at, isAbortError as b, RetryOwner as bt, LogThreshold as c, ValidationProblemDetails as ct, LoggerConfig as d, ValidationProblemErrorSchema as dt, MalformedRequestError as et, LoggerErrorHook as f, InternalServerError as ft, consoleSink as g, RateLimitError as gt, configureLogger as h, StaleSessionError as ht, LogFields as i, ValidationError as it, defineMessages as j, PayloadSchemas as k, LogValue as l, ValidationProblemDetailsSchema as lt, SerializedError as m, NotAuthorizedError as mt, ErrorLogContext as n, ResourceNotFoundError as nt, LogLevel as o, ProblemDetails as ot, LoggerSettings as p, ServiceUnavailableError as pt, ErrorEntry as q, LogEntry as r, UpgradeRequiredError as rt, LogSink as s, ProblemDetailsSchema as st, ErrorCaptureEntry as t, RequestTimeoutError as tt, Logger as u, ValidationProblemError as ut, setLogSink as v, AppError as vt, AppMessages as w, isTransientTransportError as x, shouldRetryFailure as xt, setLoggerErrorHook as y, FailureClassification as yt, IdOf as z };
584
- //# sourceMappingURL=index-BStnggQO.d.ts.map
630
+ export { unreachable as $, isTransientCloudflareRuntimeError as A, FailureClassification as At, PayloadSchemas as B, classifyBoundaryError as C, InternalServerError as Ct, isCloudflareObjectResetError as D, RateLimitError as Dt, CLOUDFLARE_TRANSIENT_ERROR_PATTERNS as E, StaleSessionError as Et, AppMessages as F, DomainMessage as G, defineMessages as H, CommandOf as I, Id as J, DomainQuery as K, EventOf as L, isTransientTransportError as M, shouldRetryFailure as Mt, Entity as N, isCloudflareOverloadedError as O, AuthenticationError as Ot, EntityData as P, notImplemented as Q, MessageDefinition as R, BoundaryErrorClassifier as S, ValidationProblemErrorSchema as St, retryAfterSecondsOf as T, NotAuthorizedError as Tt, DomainCommand as U, QueryOf as V, DomainEvent as W, IdOf as X, IdDefinition as Y, defineId as Z, createLogger as _, ProblemDetails as _t, LogFormat as a, ErrorPayloadOf as at, exponentialEqualJitterMs as b, ValidationProblemDetailsSchema as bt, LogThreshold as c, ResolvedError as ct, LoggerConfig as d, MalformedRequestError as dt, D1ConstraintKind as et, LoggerErrorHook as f, RequestTimeoutError as ft, consoleSink as g, ValidationIssue as gt, configureLogger as h, ValidationError as ht, LogFields as i, ErrorEntry as it, isAbortError as j, RetryOwner as jt, isCloudflareRetryableError as k, AppError as kt, LogValue as l, defineErrors as lt, SerializedError as m, UpgradeRequiredError as mt, ErrorLogContext as n, DatabaseFailure as nt, LogLevel as o, ErrorTable as ot, LoggerSettings as p, ResourceNotFoundError as pt, MessageId as q, LogEntry as r, ErrorEntries as rt, LogSink as s, ErrorTagOf as st, ErrorCaptureEntry as t, DatabaseError as tt, Logger as u, sharedErrors as ut, setLogSink as v, ProblemDetailsSchema as vt, classifyFailure as w, ServiceUnavailableError as wt, spreadJitterMs as x, ValidationProblemError as xt, setLoggerErrorHook as y, ValidationProblemDetails as yt, MessageOf as z };
631
+ //# sourceMappingURL=index-6XMPJu7u.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-6XMPJu7u.d.ts","names":[],"sources":["../src/core/failure-classification.ts","../src/core/app-error.ts","../src/core/authentication.error.ts","../src/core/rate-limit.error.ts","../src/core/stale-session.error.ts","../src/core/not-authorized.error.ts","../src/core/internal.errors.ts","../src/core/problem-details.ts","../src/core/request.errors.ts","../src/core/error-table.ts","../src/core/database.error.ts","../src/core/defects.ts","../src/core/identity.ts","../src/core/messages.ts","../src/core/define-messages.ts","../src/core/entity.ts","../src/core/transport-classification.ts","../src/core/cloudflare-classification.ts","../src/core/classify-failure.ts","../src/core/backoff.ts","../src/core/logger.ts"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { F as DomainQuery, I as MessageId, M as DomainCommand, N as DomainEvent, P as DomainMessage, vt as AppError } from "./index-BStnggQO.js";
1
+ import { G as DomainMessage, K as DomainQuery, U as DomainCommand, W as DomainEvent, kt as AppError, q as MessageId } from "./index-6XMPJu7u.js";
2
2
  //#region src/application/handlers.d.ts
3
3
  /**
4
4
  * Handles one command with the dependency container and returns the caller's value.
@@ -168,4 +168,4 @@ declare class UnitOfWorkAlreadyActiveError extends AppError {
168
168
  }
169
169
  //#endregion
170
170
  export { RegistryMessage as _, UnitOfWorkDeps as a, EventHandler as b, IOutboxRelay as c, CommandRegistry as d, EventRegistry as f, QueryRegistry as g, MessageResult as h, UnitOfWork as i, IMessageBus as l, MessageRegistry as m, MessageAlreadyProcessedError as n, IEventCollector as o, Handlers as p, IUnitOfWork as r, ITransaction as s, UnitOfWorkAlreadyActiveError as t, MessageBus as u, IMessageStore as v, QueryHandler as x, CommandHandler as y };
171
- //# sourceMappingURL=index-DWIRrJMP.d.ts.map
171
+ //# sourceMappingURL=index-_Cihfq1J.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-DWIRrJMP.d.ts","names":[],"sources":["../src/application/handlers.ts","../src/application/message-store.ts","../src/application/registry.ts","../src/application/message-bus.ts","../src/application/outbox-relay.ts","../src/application/transaction.ts","../src/application/event-collector.ts","../src/application/unit-of-work.ts","../src/application/message-already-processed.error.ts","../src/application/unit-of-work.errors.ts"],"mappings":";;;;;;KAMY,eAAe,iBAAiB,eAAe,MAAM,UAC/D,SAAS,UACT,MAAM,SACH,QAAQ;;;;;KAMD,aAAa,eAAe,aAAa,WAAW,UAC9D,OAAO,QACP,MAAM,cACH,QAAQ;;KAGD,aAAa,eAAe,aAAa,SACnD,OAAO,QACP,MAAM,SACH;;;;;;;UClBY;;EAEf,MAAM,WAAW,YAAY;;EAE7B,cAAc,QAAQ,cAAc,eAAe;;;;;KCLzC,gBAAgB,iBAAiB,eAAe,oBAChD,KAAK,YAAY,YAAY,eAAe,GAAG;;KAI/C,cAAc,eAAe,aAAa,yBAC1C,KAAK,UAAU,YAAY,aAAa,GAAG;;;;;KAO3C,cAAc,eAAe,aAAa,oBAC1C,KAAK,UAAU,aAAa,cAAc,aAAa,GAAG;;;;;;KAQ1D,gBAAgB,iBAAiB,eAAe,aAAa,WAAW;WACzE,UAAU,gBAAgB,QAAQ,UAAU,gBAAgB;WAC5D,SAAS,cAAc,QAAQ,UAAU,cAAc;WACvD,QAAQ,cAAc,QAAQ,UAAU,cAAc;;KAK5D,KAAK;EAAU,OAAO,SAAS,eAAe,MAAM,OAAO;;KAC3D,aAAa;EAAU,OAAO,OAAO,aAAa,MAAM,OAAO;;;;;;KAMxD,SAAS;WACV,UAAU,SAAS,eAAe,KAAK;WACvC,SAAS,SAAS,eAAe,KAAK;WACtC,QAAQ,SAAS,QAAQ,eAAe,cAAc,aAAa;;KAGzE,YAAY,UAAU,WAAW,QAAQ,aAAa,SAAS;KAE/D,oBAAoB,UACvB,YAAY,aAAa,iBAAiB,oBAAoB,iBAC1D,WAAW,QAAQ,eAAe;;KAI5B,gBAAgB,kBAAkB,mBAC1C,YAAY,yBACZ,YAAY,wBACZ,oBAAoB;KAEnB,UAAU,QAAQ,wBAAwB,oBAAoB,SAC/D,QAAQ,WAAW,QAAQ,OAAO,QAAQ;;KAIlC,cACV,iBAAiB,eACjB,kBAAkB,mBAChB,iBAAiB,gBACjB,UAAU,uBAAuB,oBACjC,iBAAiB,cACf,UAAU,sBAAsB;;;;UCvDrB,YAAY,kBAAkB;EAC7C,OAAO,iBAAiB,gBAAgB,gBAAgB,YACtD,SAAS,WACR,QAAQ,cAAc,UAAU;;;;;;cAOxB,WAAW,MAAM,kBAAkB,SAAS,kBAAkB,YAAY;mBAElE;mBACA;EAFnB,YACmB,MAAM,MACN,UAAU;;EAIvB,OAAO,iBAAiB,gBAAgB,gBAAgB,YAC5D,SAAS,WACR,QAAQ,cAAc,UAAU;UAM3B;UASA;UASA;;;;;;UAWM;;;;;;;;;UClEC;EACf;;;;;;;;;UCDe,aAAa;EAC5B,YAAY,GAAG,OAAO,IAAI,OAAO,QAAQ,KAAK,QAAQ;;;;;UCHvC;EACf,KAAK,OAAO;EACZ,WAAW,cAAc;;;;;;;;;UCQV,YAAY;EAC3B,IAAI,GAAG,WAAW,WAAW,OAAO,OAAO,UAAU,QAAQ,KAAK,QAAQ;;KAGhE,eAAe,IAAI;WACpB,aAAa,aAAa;;WAE1B,eAAe,IAAI,OAAO;;WAE1B,qBAAqB,IAAI,OAAO;WAChC,gBAAgB;WAChB,OAAO;;;cAIL,WAAW,IAAI,kBAAkB,YAAY;mBAC3B;EAA7B,YAA6B,MAAM,eAAe,IAAI;EAEhD,IAAI,GAAG,WAAW,WAAW,OAAO,OAAO,UAAU,QAAQ,KAAK,QAAQ;;;;;cC5BrE,qCAAqC;WAKrC,WAAW;WAJb;WACA;EAET,YACW,WAAW,WACpB;aAAqB;;;SAMhB,KAAK,gBAAgB,WAAW,YAAY;;;;;cCZxC,qCAAqC;WACvC;WACA;EAET"}
1
+ {"version":3,"file":"index-_Cihfq1J.d.ts","names":[],"sources":["../src/application/handlers.ts","../src/application/message-store.ts","../src/application/registry.ts","../src/application/message-bus.ts","../src/application/outbox-relay.ts","../src/application/transaction.ts","../src/application/event-collector.ts","../src/application/unit-of-work.ts","../src/application/message-already-processed.error.ts","../src/application/unit-of-work.errors.ts"],"mappings":";;;;;;KAMY,eAAe,iBAAiB,eAAe,MAAM,UAC/D,SAAS,UACT,MAAM,SACH,QAAQ;;;;;KAMD,aAAa,eAAe,aAAa,WAAW,UAC9D,OAAO,QACP,MAAM,cACH,QAAQ;;KAGD,aAAa,eAAe,aAAa,SACnD,OAAO,QACP,MAAM,SACH;;;;;;;UClBY;;EAEf,MAAM,WAAW,YAAY;;EAE7B,cAAc,QAAQ,cAAc,eAAe;;;;;KCLzC,gBAAgB,iBAAiB,eAAe,oBAChD,KAAK,YAAY,YAAY,eAAe,GAAG;;KAI/C,cAAc,eAAe,aAAa,yBAC1C,KAAK,UAAU,YAAY,aAAa,GAAG;;;;;KAO3C,cAAc,eAAe,aAAa,oBAC1C,KAAK,UAAU,aAAa,cAAc,aAAa,GAAG;;;;;;KAQ1D,gBAAgB,iBAAiB,eAAe,aAAa,WAAW;WACzE,UAAU,gBAAgB,QAAQ,UAAU,gBAAgB;WAC5D,SAAS,cAAc,QAAQ,UAAU,cAAc;WACvD,QAAQ,cAAc,QAAQ,UAAU,cAAc;;KAK5D,KAAK;EAAU,OAAO,SAAS,eAAe,MAAM,OAAO;;KAC3D,aAAa;EAAU,OAAO,OAAO,aAAa,MAAM,OAAO;;;;;;KAMxD,SAAS;WACV,UAAU,SAAS,eAAe,KAAK;WACvC,SAAS,SAAS,eAAe,KAAK;WACtC,QAAQ,SAAS,QAAQ,eAAe,cAAc,aAAa;;KAGzE,YAAY,UAAU,WAAW,QAAQ,aAAa,SAAS;KAE/D,oBAAoB,UACvB,YAAY,aAAa,iBAAiB,oBAAoB,iBAC1D,WAAW,QAAQ,eAAe;;KAI5B,gBAAgB,kBAAkB,mBAC1C,YAAY,yBACZ,YAAY,wBACZ,oBAAoB;KAEnB,UAAU,QAAQ,wBAAwB,oBAAoB,SAC/D,QAAQ,WAAW,QAAQ,OAAO,QAAQ;;KAIlC,cACV,iBAAiB,eACjB,kBAAkB,mBAChB,iBAAiB,gBACjB,UAAU,uBAAuB,oBACjC,iBAAiB,cACf,UAAU,sBAAsB;;;;UCvDrB,YAAY,kBAAkB;EAC7C,OAAO,iBAAiB,gBAAgB,gBAAgB,YACtD,SAAS,WACR,QAAQ,cAAc,UAAU;;;;;;cAOxB,WAAW,MAAM,kBAAkB,SAAS,kBAAkB,YAAY;mBAElE;mBACA;EAFnB,YACmB,MAAM,MACN,UAAU;;EAIvB,OAAO,iBAAiB,gBAAgB,gBAAgB,YAC5D,SAAS,WACR,QAAQ,cAAc,UAAU;UAM3B;UASA;UASA;;;;;;UAWM;;;;;;;;;UClEC;EACf;;;;;;;;;UCDe,aAAa;EAC5B,YAAY,GAAG,OAAO,IAAI,OAAO,QAAQ,KAAK,QAAQ;;;;;UCHvC;EACf,KAAK,OAAO;EACZ,WAAW,cAAc;;;;;;;;;UCQV,YAAY;EAC3B,IAAI,GAAG,WAAW,WAAW,OAAO,OAAO,UAAU,QAAQ,KAAK,QAAQ;;KAGhE,eAAe,IAAI;WACpB,aAAa,aAAa;;WAE1B,eAAe,IAAI,OAAO;;WAE1B,qBAAqB,IAAI,OAAO;WAChC,gBAAgB;WAChB,OAAO;;;cAIL,WAAW,IAAI,kBAAkB,YAAY;mBAC3B;EAA7B,YAA6B,MAAM,eAAe,IAAI;EAEhD,IAAI,GAAG,WAAW,WAAW,OAAO,OAAO,UAAU,QAAQ,KAAK,QAAQ;;;;;cC5BrE,qCAAqC;WAKrC,WAAW;WAJb;WACA;EAET,YACW,WAAW,WACpB;aAAqB;;;SAMhB,KAAK,gBAAgB,WAAW,YAAY;;;;;cCZxC,qCAAqC;WACvC;WACA;EAET"}
@@ -1,6 +1,6 @@
1
- import { G as DatabaseFailure, I as MessageId, N as DomainEvent, W as DatabaseError } from "./index-BStnggQO.js";
2
- import { s as ITransaction, v as IMessageStore } from "./index-DWIRrJMP.js";
3
- import { n as DrizzleSchema, t as eventCollector } from "./unit-of-work-context-CPz9rdSS.js";
1
+ import { W as DomainEvent, nt as DatabaseFailure, q as MessageId, tt as DatabaseError } from "./index-6XMPJu7u.js";
2
+ import { s as ITransaction, v as IMessageStore } from "./index-_Cihfq1J.js";
3
+ import { n as DrizzleSchema, t as eventCollector } from "./unit-of-work-context-BWTJfYPW.js";
4
4
  import { ExtractTablesWithRelations } from "drizzle-orm";
5
5
  import { PostgresJsDatabase, PostgresJsTransaction, drizzle } from "drizzle-orm/postgres-js";
6
6
  //#region src/infrastructure/postgres/postgres-database-types.d.ts
package/dist/postgres.js CHANGED
@@ -1,6 +1,6 @@
1
- import { N as AppError, g as DatabaseError } from "./core-Cx5SeyKV.js";
2
- import { i as MessageAlreadyProcessedError } from "./application-DjsQtpgw.js";
3
- import { n as eventCollector, r as runWithUnitOfWorkContext } from "./unit-of-work-context-DToDpAkv.js";
1
+ import { E as DatabaseError, U as AppError } from "./core-DC_4pOrI.js";
2
+ import { i as MessageAlreadyProcessedError } from "./application-DYfcAy-Q.js";
3
+ import { n as eventCollector, r as runWithUnitOfWorkContext } from "./unit-of-work-context-BFCmU92Z.js";
4
4
  import { DrizzleQueryError } from "drizzle-orm/errors";
5
5
  import { isNull } from "drizzle-orm";
6
6
  import { index, integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
@@ -1,7 +1,19 @@
1
- import { Y as ErrorTable } from "./index-BStnggQO.js";
2
- import { Register, RequestServerOptions } from "@tanstack/react-start";
3
- import { AnyRedirect } from "@tanstack/react-router";
1
+ import { ot as ErrorTable } from "./index-6XMPJu7u.js";
2
+ import { Register } from "@tanstack/react-start";
4
3
  import { BetterAuthCookies } from "better-auth";
4
+ //#region src/infrastructure/tanstack/request-context.d.ts
5
+ /**
6
+ * The request context an application registers as `Register.server.requestContext`.
7
+ * TanStack's own request context type also reads `Register.config`, which lists the middleware
8
+ * whose options carry this type, so using it here would make every application's types circular.
9
+ * Without a registration TanStack passes no context, so the fallback is `undefined`.
10
+ */
11
+ type RequestContext = Register extends {
12
+ server: {
13
+ requestContext: infer Context;
14
+ };
15
+ } ? Context : undefined;
16
+ //#endregion
5
17
  //#region src/infrastructure/tanstack/auth.middleware.d.ts
6
18
  /** The fields middleware reads; generic callers retain every additional session and user field. */
7
19
  type AuthSession = {
@@ -24,7 +36,7 @@ type AuthContext<Session extends AuthSession> = RequiredAuthContext<Session> | {
24
36
  };
25
37
  /** Select the current request's Better Auth instance from TanStack's registered context. */
26
38
  type AuthMiddlewareOptions<Session extends AuthSession> = {
27
- readonly getAuth: (context: RequestServerOptions<Register, undefined>['context']) => {
39
+ readonly getAuth: (context: RequestContext) => {
28
40
  readonly api: {
29
41
  readonly getSession: (options: {
30
42
  headers: Headers;
@@ -43,7 +55,6 @@ export declare function createAuthMiddleware<Session extends AuthSession>(option
43
55
  };
44
56
  //#endregion
45
57
  //#region src/infrastructure/tanstack/error.middleware.d.ts
46
- type RequestContext = RequestServerOptions<Register, undefined>['context'];
47
58
  /** The part of a Better Auth instance the boundary reads: its computed cookie definitions. */
48
59
  type AuthCookieSource = {
49
60
  readonly $context: Promise<{
@@ -53,8 +64,8 @@ type AuthCookieSource = {
53
64
  /** The application's error table, its stale-session redirect, and its Better Auth instance. */
54
65
  type ErrorMiddlewareOptions<Entries> = {
55
66
  readonly errors: ErrorTable<Entries>;
56
- /** Build the redirect a server function throws for a stale session. */
57
- readonly signIn: () => AnyRedirect;
67
+ /** The path a server function redirects to for a stale session, with any search string. */
68
+ readonly signIn: string;
58
69
  /** Select the request's Better Auth instance; its cookie definitions say what to clear. */
59
70
  readonly getAuth: (context: RequestContext) => AuthCookieSource;
60
71
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack.d.ts","names":[],"sources":["../src/infrastructure/tanstack/auth.middleware.ts","../src/infrastructure/tanstack/error.middleware.ts","../src/infrastructure/tanstack/last-login-method.ts"],"mappings":";;;;;;KASY;WACD;aAAiB;;WACjB;aAAoB;;;;KAInB,oBAAoB,gBAAgB;WACrC,MAAM;WACN,SAAS;;;KAIR,YAAY,gBAAgB,eACpC,oBAAoB;WAET;WACA;;;KAIH,sBAAsB,gBAAgB;WACvC,UAAU,SAAS,qBAAqB;aACtC;eACE,aAAa;QAAW,SAAS;YAAc,QAAQ;;;;;;;;wBAStD,qBAAqB,gBAAgB,aACnD,SAAS,sBAAsB;;;;;;;KChC5B,iBAAiB,qBAAqB;;KAG/B;WACD,UAAU;aAAmB,aAAa;;;;KAIzC,uBAAuB;WACxB,QAAQ,WAAW;;WAEnB,cAAc;;WAEd,UAAU,SAAS,mBAAmB;;;;;;wBAOjC,sBAAsB,SAAS,SAAS,uBAAuB;;;;;;;;;;;;;;;;;;;;wBCpB/D,uBAAuB"}
1
+ {"version":3,"file":"tanstack.d.ts","names":[],"sources":["../src/infrastructure/tanstack/request-context.ts","../src/infrastructure/tanstack/auth.middleware.ts","../src/infrastructure/tanstack/error.middleware.ts","../src/infrastructure/tanstack/last-login-method.ts"],"mappings":";;;;;;;;;;KAQY,iBAAiB;EAAmB;IAAU,sBAAsB;;IAC5E;;;;KCEQ;WACD;aAAiB;;WACjB;aAAoB;;;;KAInB,oBAAoB,gBAAgB;WACrC,MAAM;WACN,SAAS;;;KAIR,YAAY,gBAAgB,eACpC,oBAAoB;WAET;WACA;;;KAIH,sBAAsB,gBAAgB;WACvC,UAAU,SAAS;aACjB;eACE,aAAa;QAAW,SAAS;YAAc,QAAQ;;;;;;;;wBAStD,qBAAqB,gBAAgB,aACnD,SAAS,sBAAsB;;;;;;;;KChCrB;WACD,UAAU;aAAmB,aAAa;;;;KAIzC,uBAAuB;WACxB,QAAQ,WAAW;;WAEnB;;WAEA,UAAU,SAAS,mBAAmB;;;;;;wBAOjC,sBAAsB,SAAS,SAAS,uBAAuB;;;;;;;;;;;;;;;;;;;;wBCnB/D,uBAAuB"}
package/dist/tanstack.js CHANGED
@@ -1,9 +1,9 @@
1
- import { A as StaleSessionError, E as ValidationError, M as AuthenticationError, N as AppError, a as createLogger } from "./core-Cx5SeyKV.js";
1
+ import { B as StaleSessionError, H as AuthenticationError, I as ValidationError, U as AppError, a as createLogger } from "./core-DC_4pOrI.js";
2
2
  import { z } from "zod";
3
3
  import { createMiddleware } from "@tanstack/react-start";
4
4
  import { deleteCookie, getRequestHeaders } from "@tanstack/react-start/server";
5
5
  import { getSessionCookie, parseCookies } from "better-auth/cookies";
6
- import { isNotFound, isRedirect } from "@tanstack/react-router";
6
+ import { isNotFound, isRedirect, redirect } from "@tanstack/react-router";
7
7
  import { getReasonPhrase } from "http-status-codes";
8
8
 
9
9
  //#region src/infrastructure/tanstack/auth.middleware.ts
@@ -180,7 +180,7 @@ function createErrorMiddleware(options) {
180
180
  if (isNotFound(cause) || isRedirect(cause)) throw cause;
181
181
  if (cause instanceof StaleSessionError) {
182
182
  await clearSession(context);
183
- throw options.signIn();
183
+ throw redirect({ href: options.signIn });
184
184
  }
185
185
  throw toErrorPayload(cause);
186
186
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tanstack.js","names":["logger"],"sources":["../src/infrastructure/tanstack/auth.middleware.ts","../src/infrastructure/tanstack/resolve-failure.ts","../src/infrastructure/tanstack/http-error-response.ts","../src/infrastructure/tanstack/session-cookies.ts","../src/infrastructure/tanstack/to-error-payload.ts","../src/infrastructure/tanstack/error.middleware.ts","../src/infrastructure/tanstack/last-login-method.ts"],"sourcesContent":["import { createMiddleware, type Register, type RequestServerOptions } from '@tanstack/react-start'\nimport { getRequestHeaders } from '@tanstack/react-start/server'\nimport { getSessionCookie } from 'better-auth/cookies'\n\nimport { AuthenticationError, StaleSessionError, createLogger } from '@/core'\n\nconst logger = createLogger('auth-middleware')\n\n/** The fields middleware reads; generic callers retain every additional session and user field. */\nexport type AuthSession = {\n readonly user: { readonly id: string }\n readonly session: { readonly id: string }\n}\n\n/** Authenticated context retains the application's complete user and session types. */\nexport type RequiredAuthContext<Session extends AuthSession> = {\n readonly user: Session['user']\n readonly session: Session['session']\n}\n\n/** Optional authentication supplies both fields together or neither field. */\nexport type AuthContext<Session extends AuthSession> =\n | RequiredAuthContext<Session>\n | {\n readonly user: undefined\n readonly session: undefined\n }\n\n/** Select the current request's Better Auth instance from TanStack's registered context. */\nexport type AuthMiddlewareOptions<Session extends AuthSession> = {\n readonly getAuth: (context: RequestServerOptions<Register, undefined>['context']) => {\n readonly api: {\n readonly getSession: (options: { headers: Headers }) => Promise<Session | null>\n }\n }\n}\n\n/**\n * Preserve Porte's function and request middleware contracts with application-owned services.\n * Optional lookup failures log once and continue as guests. Required lookup failures propagate.\n */\nexport function createAuthMiddleware<Session extends AuthSession>(\n options: AuthMiddlewareOptions<Session>,\n) {\n const extractAuth = createMiddleware({ type: 'function' }).server<AuthContext<Session>>(\n async ({ next, context }) => {\n let resolved: Session | null\n try {\n resolved = await options.getAuth(context).api.getSession({ headers: getRequestHeaders() })\n } catch (error) {\n logger.error('get_session_failed', { error })\n resolved = null\n }\n if (resolved === null)\n return next<AuthContext<Session>>({ context: { user: undefined, session: undefined } })\n return next<AuthContext<Session>>({\n context: { user: resolved.user, session: resolved.session },\n })\n },\n )\n\n async function resolveRequiredSession(\n context: RequestServerOptions<Register, undefined>['context'],\n headers: Headers,\n ): Promise<Session> {\n const resolved = await options.getAuth(context).api.getSession({ headers })\n if (resolved === null) {\n if (getSessionCookie(headers)) throw new StaleSessionError()\n throw new AuthenticationError()\n }\n return resolved\n }\n\n const requireAuth = createMiddleware({ type: 'function' }).server(async ({ next, context }) => {\n const resolved = await resolveRequiredSession(context, getRequestHeaders())\n return next<RequiredAuthContext<Session>>({\n context: { user: resolved.user, session: resolved.session },\n })\n })\n const requireAuthRequest = createMiddleware({ type: 'request' }).server(\n async ({ request, next, context }) => {\n const resolved = await resolveRequiredSession(context, request.headers)\n return next<RequiredAuthContext<Session>>({\n context: { user: resolved.user, session: resolved.session },\n })\n },\n )\n return { extractAuth, requireAuth, requireAuthRequest }\n}\n","import { AppError, createLogger, type ErrorTable, type ResolvedError } from '@/core'\nimport type { ErrorPayloadOf } from '@/core'\n\nconst logger = createLogger('error-boundary')\n\n/**\n * Resolve one failure through the table or fall back to the generic replacement, and log it once.\n * Both transport converters call this, so one rule decides the log level: mapped is a warning, unmapped is an error with the cause.\n */\nexport function resolveFailure<Entries>(\n table: ErrorTable<Entries>,\n cause: unknown,\n): ResolvedError<ErrorPayloadOf<ErrorTable<Entries>>> {\n const resolved = table.resolve(cause)\n if (resolved !== null) {\n logger.warn('handled_error', {\n details: { tag: resolved.payload._tag, status: resolved.status },\n })\n return resolved\n }\n const classification = cause instanceof AppError ? cause.classification : 'unknown'\n logger.error('unexpected_error', { error: cause, details: { classification } })\n return table.fallback(cause)\n}\n","import { getReasonPhrase } from 'http-status-codes'\nimport { z } from 'zod'\n\nimport type { ErrorTable, ProblemDetails } from '@/core'\n\nimport { resolveFailure } from './resolve-failure.ts'\n\n// A known delay becomes the header; a null delay sends no header.\nconst RetryAfterSchema = z.object({ retryAfter: z.number() })\n\n/**\n * Build the API route converter for one error table.\n * The body is RFC 9457 problem details; public fields become extension members.\n */\nexport function createHttpErrorResponseConverter<Entries>(table: ErrorTable<Entries>) {\n return function toHttpErrorResponse(cause: unknown): Response {\n const { status, payload } = resolveFailure(table, cause)\n const { _tag, message, ...fields } = payload\n const body: ProblemDetails = {\n type: 'about:blank',\n title: getReasonPhrase(status),\n detail: message,\n ...fields,\n }\n const headers = new Headers({ 'Content-Type': 'application/problem+json' })\n const retry = RetryAfterSchema.safeParse(payload)\n if (retry.success) headers.set('Retry-After', String(retry.data.retryAfter))\n return Response.json(body, { status, headers })\n }\n}\n","import { deleteCookie, getRequestHeaders } from '@tanstack/react-start/server'\nimport type { BetterAuthCookies } from 'better-auth'\nimport { parseCookies } from 'better-auth/cookies'\n\ntype AuthCookie = BetterAuthCookies['sessionToken']\ntype DeleteCookieOptions = NonNullable<Parameters<typeof deleteCookie>[1]>\n\n/**\n * Delete the session, session cache, account cache, and remember-me cookies of one instance.\n * Chunks present on the request go too. Names and attributes come from the instance, so custom prefixes and domain cookies clear.\n */\nexport function clearStaleSessionCookies(cookies: BetterAuthCookies): void {\n const present = [...parseCookies(getRequestHeaders().get('cookie') ?? '').keys()]\n const definitions = [\n cookies.sessionToken,\n cookies.sessionData,\n cookies.accountData,\n cookies.dontRememberToken,\n ]\n for (const cookie of definitions) {\n // Better Auth names a chunk `${name}.${index}`, so a missed chunk would resurrect the value.\n const chunks = present.filter((name) => name.startsWith(`${cookie.name}.`))\n for (const name of new Set([cookie.name, ...chunks]))\n deleteCookie(name, deletionOf(cookie.attributes))\n }\n}\n\nfunction deletionOf(attributes: AuthCookie['attributes']): DeleteCookieOptions {\n // Better Auth sets `/` and the secure flag at runtime; the types leave both optional.\n const options: DeleteCookieOptions = {\n path: attributes.path ?? '/',\n secure: attributes.secure ?? false,\n }\n if (attributes.domain !== undefined) options.domain = attributes.domain\n return options\n}\n","import { z } from 'zod'\n\nimport { ValidationError, type ErrorPayloadOf, type ErrorTable } from '@/core'\n\nimport { resolveFailure } from './resolve-failure.ts'\n\n// TanStack serializes a validator's issues into `Error.message` as JSON.\nconst SerializedIssuesSchema = z\n .array(z.object({ message: z.string(), path: z.array(z.union([z.string(), z.number()])) }))\n .min(1)\n\nfunction reconstructValidationError(cause: unknown): ValidationError | null {\n if (!(cause instanceof Error)) return null\n let message: unknown\n try {\n message = JSON.parse(cause.message)\n } catch {\n return null\n }\n const parsed = SerializedIssuesSchema.safeParse(message)\n return parsed.success ? ValidationError.fromIssues(parsed.data) : null\n}\n\n/**\n * Build the server-function converter for one error table.\n * The result is a plain object, because only own data survives serialization.\n */\nexport function createErrorPayloadConverter<Entries>(table: ErrorTable<Entries>) {\n return function toErrorPayload(cause: unknown): ErrorPayloadOf<ErrorTable<Entries>> {\n return resolveFailure(table, reconstructValidationError(cause) ?? cause).payload\n }\n}\n","import { isNotFound, isRedirect, type AnyRedirect } from '@tanstack/react-router'\nimport { createMiddleware, type Register, type RequestServerOptions } from '@tanstack/react-start'\nimport type { BetterAuthCookies } from 'better-auth'\n\nimport { StaleSessionError, type ErrorTable } from '@/core'\n\nimport { createHttpErrorResponseConverter } from './http-error-response.ts'\nimport { clearStaleSessionCookies } from './session-cookies.ts'\nimport { createErrorPayloadConverter } from './to-error-payload.ts'\n\ntype RequestContext = RequestServerOptions<Register, undefined>['context']\n\n/** The part of a Better Auth instance the boundary reads: its computed cookie definitions. */\nexport type AuthCookieSource = {\n readonly $context: Promise<{ readonly authCookies: BetterAuthCookies }>\n}\n\n/** The application's error table, its stale-session redirect, and its Better Auth instance. */\nexport type ErrorMiddlewareOptions<Entries> = {\n readonly errors: ErrorTable<Entries>\n /** Build the redirect a server function throws for a stale session. */\n readonly signIn: () => AnyRedirect\n /** Select the request's Better Auth instance; its cookie definitions say what to clear. */\n readonly getAuth: (context: RequestContext) => AuthCookieSource\n}\n\n/**\n * Build both transport boundaries from one error table.\n * Register `functionErrorMiddleware` globally. Put `routeErrorMiddleware` first in an API route's `server.middleware`.\n */\nexport function createErrorMiddleware<Entries>(options: ErrorMiddlewareOptions<Entries>) {\n const toErrorPayload = createErrorPayloadConverter(options.errors)\n const toHttpErrorResponse = createHttpErrorResponseConverter(options.errors)\n\n async function clearSession(context: RequestContext): Promise<void> {\n const { authCookies } = await options.getAuth(context).$context\n clearStaleSessionCookies(authCookies)\n }\n\n async function handleFunctionError(cause: unknown, context: RequestContext): Promise<never> {\n // oxlint-disable-next-line typescript/only-throw-error -- TanStack uses throwable control-flow objects.\n if (isNotFound(cause) || isRedirect(cause)) throw cause\n if (cause instanceof StaleSessionError) {\n await clearSession(context)\n // oxlint-disable-next-line typescript/only-throw-error -- Router redirects by throwing this.\n throw options.signIn()\n }\n // oxlint-disable-next-line typescript/only-throw-error -- The client rejects with this and reads its tag.\n throw toErrorPayload(cause)\n }\n\n // A route answers 401 instead of a redirect because fetch would follow it into the HTML shell.\n async function handleRouteError(cause: unknown, context: RequestContext): Promise<Response> {\n // oxlint-disable-next-line typescript/only-throw-error -- TanStack uses throwable control-flow objects.\n if (isNotFound(cause) || isRedirect(cause)) throw cause\n if (cause instanceof StaleSessionError) await clearSession(context)\n return toHttpErrorResponse(cause)\n }\n\n const functionErrorMiddleware = createMiddleware({ type: 'function' }).server(\n async ({ next, context }) => {\n try {\n return await next()\n } catch (cause) {\n return handleFunctionError(cause, context)\n }\n },\n )\n\n const routeErrorMiddleware = createMiddleware({ type: 'request' }).server(\n async ({ next, context }) => {\n try {\n return await next()\n } catch (cause) {\n return handleRouteError(cause, context)\n }\n },\n )\n\n return { functionErrorMiddleware, routeErrorMiddleware, toErrorPayload, toHttpErrorResponse }\n}\n","import { getRequestHeaders } from '@tanstack/react-start/server'\nimport { parseCookies } from 'better-auth/cookies'\n\n// Better Auth keeps the plugin default private; this is the value LastLoginMethodOptions.cookieName documents.\nconst DEFAULT_COOKIE_NAME = 'better-auth.last_used_login_method'\n\n/**\n * Read the method this browser last signed in with from the current request, for the sign-in loader on the server.\n * Pass `cookieName` only when `integrations.lastLoginMethod.cookieName` is set. Returns `null` when the cookie is absent.\n */\nexport function getLastUsedLoginMethod(cookieName = DEFAULT_COOKIE_NAME): string | null {\n return parseCookies(getRequestHeaders().get('cookie') ?? '').get(cookieName) ?? null\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tanstack.js","names":["logger"],"sources":["../src/infrastructure/tanstack/auth.middleware.ts","../src/infrastructure/tanstack/resolve-failure.ts","../src/infrastructure/tanstack/http-error-response.ts","../src/infrastructure/tanstack/session-cookies.ts","../src/infrastructure/tanstack/to-error-payload.ts","../src/infrastructure/tanstack/error.middleware.ts","../src/infrastructure/tanstack/last-login-method.ts"],"sourcesContent":["import { createMiddleware } from '@tanstack/react-start'\nimport { getRequestHeaders } from '@tanstack/react-start/server'\nimport { getSessionCookie } from 'better-auth/cookies'\n\nimport { AuthenticationError, StaleSessionError, createLogger } from '@/core'\n\nimport type { RequestContext } from './request-context.ts'\n\nconst logger = createLogger('auth-middleware')\n\n/** The fields middleware reads; generic callers retain every additional session and user field. */\nexport type AuthSession = {\n readonly user: { readonly id: string }\n readonly session: { readonly id: string }\n}\n\n/** Authenticated context retains the application's complete user and session types. */\nexport type RequiredAuthContext<Session extends AuthSession> = {\n readonly user: Session['user']\n readonly session: Session['session']\n}\n\n/** Optional authentication supplies both fields together or neither field. */\nexport type AuthContext<Session extends AuthSession> =\n | RequiredAuthContext<Session>\n | {\n readonly user: undefined\n readonly session: undefined\n }\n\n/** Select the current request's Better Auth instance from TanStack's registered context. */\nexport type AuthMiddlewareOptions<Session extends AuthSession> = {\n readonly getAuth: (context: RequestContext) => {\n readonly api: {\n readonly getSession: (options: { headers: Headers }) => Promise<Session | null>\n }\n }\n}\n\n/**\n * Preserve Porte's function and request middleware contracts with application-owned services.\n * Optional lookup failures log once and continue as guests. Required lookup failures propagate.\n */\nexport function createAuthMiddleware<Session extends AuthSession>(\n options: AuthMiddlewareOptions<Session>,\n) {\n const extractAuth = createMiddleware({ type: 'function' }).server<AuthContext<Session>>(\n async ({ next, context }) => {\n let resolved: Session | null\n try {\n resolved = await options.getAuth(context).api.getSession({ headers: getRequestHeaders() })\n } catch (error) {\n logger.error('get_session_failed', { error })\n resolved = null\n }\n if (resolved === null)\n return next<AuthContext<Session>>({ context: { user: undefined, session: undefined } })\n return next<AuthContext<Session>>({\n context: { user: resolved.user, session: resolved.session },\n })\n },\n )\n\n async function resolveRequiredSession(\n context: RequestContext,\n headers: Headers,\n ): Promise<Session> {\n const resolved = await options.getAuth(context).api.getSession({ headers })\n if (resolved === null) {\n if (getSessionCookie(headers)) throw new StaleSessionError()\n throw new AuthenticationError()\n }\n return resolved\n }\n\n const requireAuth = createMiddleware({ type: 'function' }).server(async ({ next, context }) => {\n const resolved = await resolveRequiredSession(context, getRequestHeaders())\n return next<RequiredAuthContext<Session>>({\n context: { user: resolved.user, session: resolved.session },\n })\n })\n const requireAuthRequest = createMiddleware({ type: 'request' }).server(\n async ({ request, next, context }) => {\n const resolved = await resolveRequiredSession(context, request.headers)\n return next<RequiredAuthContext<Session>>({\n context: { user: resolved.user, session: resolved.session },\n })\n },\n )\n return { extractAuth, requireAuth, requireAuthRequest }\n}\n","import { AppError, createLogger, type ErrorTable, type ResolvedError } from '@/core'\nimport type { ErrorPayloadOf } from '@/core'\n\nconst logger = createLogger('error-boundary')\n\n/**\n * Resolve one failure through the table or fall back to the generic replacement, and log it once.\n * Both transport converters call this, so one rule decides the log level: mapped is a warning, unmapped is an error with the cause.\n */\nexport function resolveFailure<Entries>(\n table: ErrorTable<Entries>,\n cause: unknown,\n): ResolvedError<ErrorPayloadOf<ErrorTable<Entries>>> {\n const resolved = table.resolve(cause)\n if (resolved !== null) {\n logger.warn('handled_error', {\n details: { tag: resolved.payload._tag, status: resolved.status },\n })\n return resolved\n }\n const classification = cause instanceof AppError ? cause.classification : 'unknown'\n logger.error('unexpected_error', { error: cause, details: { classification } })\n return table.fallback(cause)\n}\n","import { getReasonPhrase } from 'http-status-codes'\nimport { z } from 'zod'\n\nimport type { ErrorTable, ProblemDetails } from '@/core'\n\nimport { resolveFailure } from './resolve-failure.ts'\n\n// A known delay becomes the header; a null delay sends no header.\nconst RetryAfterSchema = z.object({ retryAfter: z.number() })\n\n/**\n * Build the API route converter for one error table.\n * The body is RFC 9457 problem details; public fields become extension members.\n */\nexport function createHttpErrorResponseConverter<Entries>(table: ErrorTable<Entries>) {\n return function toHttpErrorResponse(cause: unknown): Response {\n const { status, payload } = resolveFailure(table, cause)\n const { _tag, message, ...fields } = payload\n const body: ProblemDetails = {\n type: 'about:blank',\n title: getReasonPhrase(status),\n detail: message,\n ...fields,\n }\n const headers = new Headers({ 'Content-Type': 'application/problem+json' })\n const retry = RetryAfterSchema.safeParse(payload)\n if (retry.success) headers.set('Retry-After', String(retry.data.retryAfter))\n return Response.json(body, { status, headers })\n }\n}\n","import { deleteCookie, getRequestHeaders } from '@tanstack/react-start/server'\nimport type { BetterAuthCookies } from 'better-auth'\nimport { parseCookies } from 'better-auth/cookies'\n\ntype AuthCookie = BetterAuthCookies['sessionToken']\ntype DeleteCookieOptions = NonNullable<Parameters<typeof deleteCookie>[1]>\n\n/**\n * Delete the session, session cache, account cache, and remember-me cookies of one instance.\n * Chunks present on the request go too. Names and attributes come from the instance, so custom prefixes and domain cookies clear.\n */\nexport function clearStaleSessionCookies(cookies: BetterAuthCookies): void {\n const present = [...parseCookies(getRequestHeaders().get('cookie') ?? '').keys()]\n const definitions = [\n cookies.sessionToken,\n cookies.sessionData,\n cookies.accountData,\n cookies.dontRememberToken,\n ]\n for (const cookie of definitions) {\n // Better Auth names a chunk `${name}.${index}`, so a missed chunk would resurrect the value.\n const chunks = present.filter((name) => name.startsWith(`${cookie.name}.`))\n for (const name of new Set([cookie.name, ...chunks]))\n deleteCookie(name, deletionOf(cookie.attributes))\n }\n}\n\nfunction deletionOf(attributes: AuthCookie['attributes']): DeleteCookieOptions {\n // Better Auth sets `/` and the secure flag at runtime; the types leave both optional.\n const options: DeleteCookieOptions = {\n path: attributes.path ?? '/',\n secure: attributes.secure ?? false,\n }\n if (attributes.domain !== undefined) options.domain = attributes.domain\n return options\n}\n","import { z } from 'zod'\n\nimport { ValidationError, type ErrorPayloadOf, type ErrorTable } from '@/core'\n\nimport { resolveFailure } from './resolve-failure.ts'\n\n// TanStack serializes a validator's issues into `Error.message` as JSON.\nconst SerializedIssuesSchema = z\n .array(z.object({ message: z.string(), path: z.array(z.union([z.string(), z.number()])) }))\n .min(1)\n\nfunction reconstructValidationError(cause: unknown): ValidationError | null {\n if (!(cause instanceof Error)) return null\n let message: unknown\n try {\n message = JSON.parse(cause.message)\n } catch {\n return null\n }\n const parsed = SerializedIssuesSchema.safeParse(message)\n return parsed.success ? ValidationError.fromIssues(parsed.data) : null\n}\n\n/**\n * Build the server-function converter for one error table.\n * The result is a plain object, because only own data survives serialization.\n */\nexport function createErrorPayloadConverter<Entries>(table: ErrorTable<Entries>) {\n return function toErrorPayload(cause: unknown): ErrorPayloadOf<ErrorTable<Entries>> {\n return resolveFailure(table, reconstructValidationError(cause) ?? cause).payload\n }\n}\n","import { isNotFound, isRedirect, redirect } from '@tanstack/react-router'\nimport { createMiddleware } from '@tanstack/react-start'\nimport type { BetterAuthCookies } from 'better-auth'\n\nimport { StaleSessionError, type ErrorTable } from '@/core'\n\nimport { createHttpErrorResponseConverter } from './http-error-response.ts'\nimport type { RequestContext } from './request-context.ts'\nimport { clearStaleSessionCookies } from './session-cookies.ts'\nimport { createErrorPayloadConverter } from './to-error-payload.ts'\n\n/** The part of a Better Auth instance the boundary reads: its computed cookie definitions. */\nexport type AuthCookieSource = {\n readonly $context: Promise<{ readonly authCookies: BetterAuthCookies }>\n}\n\n/** The application's error table, its stale-session redirect, and its Better Auth instance. */\nexport type ErrorMiddlewareOptions<Entries> = {\n readonly errors: ErrorTable<Entries>\n /** The path a server function redirects to for a stale session, with any search string. */\n readonly signIn: string\n /** Select the request's Better Auth instance; its cookie definitions say what to clear. */\n readonly getAuth: (context: RequestContext) => AuthCookieSource\n}\n\n/**\n * Build both transport boundaries from one error table.\n * Register `functionErrorMiddleware` globally. Put `routeErrorMiddleware` first in an API route's `server.middleware`.\n */\nexport function createErrorMiddleware<Entries>(options: ErrorMiddlewareOptions<Entries>) {\n const toErrorPayload = createErrorPayloadConverter(options.errors)\n const toHttpErrorResponse = createHttpErrorResponseConverter(options.errors)\n\n async function clearSession(context: RequestContext): Promise<void> {\n const { authCookies } = await options.getAuth(context).$context\n clearStaleSessionCookies(authCookies)\n }\n\n async function handleFunctionError(cause: unknown, context: RequestContext): Promise<never> {\n // oxlint-disable-next-line typescript/only-throw-error -- TanStack uses throwable control-flow objects.\n if (isNotFound(cause) || isRedirect(cause)) throw cause\n if (cause instanceof StaleSessionError) {\n await clearSession(context)\n // oxlint-disable-next-line typescript/only-throw-error -- Router redirects by throwing this.\n throw redirect({ href: options.signIn })\n }\n // oxlint-disable-next-line typescript/only-throw-error -- The client rejects with this and reads its tag.\n throw toErrorPayload(cause)\n }\n\n // A route answers 401 instead of a redirect because fetch would follow it into the HTML shell.\n async function handleRouteError(cause: unknown, context: RequestContext): Promise<Response> {\n // oxlint-disable-next-line typescript/only-throw-error -- TanStack uses throwable control-flow objects.\n if (isNotFound(cause) || isRedirect(cause)) throw cause\n if (cause instanceof StaleSessionError) await clearSession(context)\n return toHttpErrorResponse(cause)\n }\n\n const functionErrorMiddleware = createMiddleware({ type: 'function' }).server(\n async ({ next, context }) => {\n try {\n return await next()\n } catch (cause) {\n return handleFunctionError(cause, context)\n }\n },\n )\n\n const routeErrorMiddleware = createMiddleware({ type: 'request' }).server(\n async ({ next, context }) => {\n try {\n return await next()\n } catch (cause) {\n return handleRouteError(cause, context)\n }\n },\n )\n\n return { functionErrorMiddleware, routeErrorMiddleware, toErrorPayload, toHttpErrorResponse }\n}\n","import { getRequestHeaders } from '@tanstack/react-start/server'\nimport { parseCookies } from 'better-auth/cookies'\n\n// Better Auth keeps the plugin default private; this is the value LastLoginMethodOptions.cookieName documents.\nconst DEFAULT_COOKIE_NAME = 'better-auth.last_used_login_method'\n\n/**\n * Read the method this browser last signed in with from the current request, for the sign-in loader on the server.\n * Pass `cookieName` only when `integrations.lastLoginMethod.cookieName` is set. Returns `null` when the cookie is absent.\n */\nexport function getLastUsedLoginMethod(cookieName = DEFAULT_COOKIE_NAME): string | null {\n return parseCookies(getRequestHeaders().get('cookie') ?? '').get(cookieName) ?? null\n}\n"],"mappings":";;;;;;;;;AAQA,MAAMA,WAAS,aAAa,iBAAiB;;;;;AAmC7C,SAAgB,qBACd,SACA;CACA,MAAM,cAAc,iBAAiB,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,OACzD,OAAO,EAAE,MAAM,cAAc;EAC3B,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,QAAQ,QAAQ,OAAO,CAAC,CAAC,IAAI,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;EAC3F,SAAS,OAAO;GACd,SAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC;GAC5C,WAAW;EACb;EACA,IAAI,aAAa,MACf,OAAO,KAA2B,EAAE,SAAS;GAAE,MAAM;GAAW,SAAS;EAAU,EAAE,CAAC;EACxF,OAAO,KAA2B,EAChC,SAAS;GAAE,MAAM,SAAS;GAAM,SAAS,SAAS;EAAQ,EAC5D,CAAC;CACH,CACF;CAEA,eAAe,uBACb,SACA,SACkB;EAClB,MAAM,WAAW,MAAM,QAAQ,QAAQ,OAAO,CAAC,CAAC,IAAI,WAAW,EAAE,QAAQ,CAAC;EAC1E,IAAI,aAAa,MAAM;GACrB,IAAI,iBAAiB,OAAO,GAAG,MAAM,IAAI,kBAAkB;GAC3D,MAAM,IAAI,oBAAoB;EAChC;EACA,OAAO;CACT;CAgBA,OAAO;EAAE;EAAa,aAdF,iBAAiB,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,OAAO,OAAO,EAAE,MAAM,cAAc;GAC7F,MAAM,WAAW,MAAM,uBAAuB,SAAS,kBAAkB,CAAC;GAC1E,OAAO,KAAmC,EACxC,SAAS;IAAE,MAAM,SAAS;IAAM,SAAS,SAAS;GAAQ,EAC5D,CAAC;EACH,CASgC;EAAG,oBARR,iBAAiB,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,OAC/D,OAAO,EAAE,SAAS,MAAM,cAAc;GACpC,MAAM,WAAW,MAAM,uBAAuB,SAAS,QAAQ,OAAO;GACtE,OAAO,KAAmC,EACxC,SAAS;IAAE,MAAM,SAAS;IAAM,SAAS,SAAS;GAAQ,EAC5D,CAAC;EACH,CAEkD;CAAE;AACxD;;;;ACvFA,MAAM,SAAS,aAAa,gBAAgB;;;;;AAM5C,SAAgB,eACd,OACA,OACoD;CACpD,MAAM,WAAW,MAAM,QAAQ,KAAK;CACpC,IAAI,aAAa,MAAM;EACrB,OAAO,KAAK,iBAAiB,EAC3B,SAAS;GAAE,KAAK,SAAS,QAAQ;GAAM,QAAQ,SAAS;EAAO,EACjE,CAAC;EACD,OAAO;CACT;CACA,MAAM,iBAAiB,iBAAiB,WAAW,MAAM,iBAAiB;CAC1E,OAAO,MAAM,oBAAoB;EAAE,OAAO;EAAO,SAAS,EAAE,eAAe;CAAE,CAAC;CAC9E,OAAO,MAAM,SAAS,KAAK;AAC7B;;;;ACfA,MAAM,mBAAmB,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;;;;;AAM5D,SAAgB,iCAA0C,OAA4B;CACpF,OAAO,SAAS,oBAAoB,OAA0B;EAC5D,MAAM,EAAE,QAAQ,YAAY,eAAe,OAAO,KAAK;EACvD,MAAM,EAAE,MAAM,SAAS,GAAG,WAAW;EACrC,MAAM,OAAuB;GAC3B,MAAM;GACN,OAAO,gBAAgB,MAAM;GAC7B,QAAQ;GACR,GAAG;EACL;EACA,MAAM,UAAU,IAAI,QAAQ,EAAE,gBAAgB,2BAA2B,CAAC;EAC1E,MAAM,QAAQ,iBAAiB,UAAU,OAAO;EAChD,IAAI,MAAM,SAAS,QAAQ,IAAI,eAAe,OAAO,MAAM,KAAK,UAAU,CAAC;EAC3E,OAAO,SAAS,KAAK,MAAM;GAAE;GAAQ;EAAQ,CAAC;CAChD;AACF;;;;;;;;AClBA,SAAgB,yBAAyB,SAAkC;CACzE,MAAM,UAAU,CAAC,GAAG,aAAa,kBAAkB,CAAC,CAAC,IAAI,QAAQ,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC;CAChF,MAAM,cAAc;EAClB,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;CACV;CACA,KAAK,MAAM,UAAU,aAAa;EAEhC,MAAM,SAAS,QAAQ,QAAQ,SAAS,KAAK,WAAW,GAAG,OAAO,KAAK,EAAE,CAAC;EAC1E,KAAK,MAAM,wBAAQ,IAAI,IAAI,CAAC,OAAO,MAAM,GAAG,MAAM,CAAC,GACjD,aAAa,MAAM,WAAW,OAAO,UAAU,CAAC;CACpD;AACF;AAEA,SAAS,WAAW,YAA2D;CAE7E,MAAM,UAA+B;EACnC,MAAM,WAAW,QAAQ;EACzB,QAAQ,WAAW,UAAU;CAC/B;CACA,IAAI,WAAW,WAAW,QAAW,QAAQ,SAAS,WAAW;CACjE,OAAO;AACT;;;;AC5BA,MAAM,yBAAyB,EAC5B,MAAM,EAAE,OAAO;CAAE,SAAS,EAAE,OAAO;CAAG,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAAE,CAAC,CAAC,CAAC,CAC1F,IAAI,CAAC;AAER,SAAS,2BAA2B,OAAwC;CAC1E,IAAI,EAAE,iBAAiB,QAAQ,OAAO;CACtC,IAAI;CACJ,IAAI;EACF,UAAU,KAAK,MAAM,MAAM,OAAO;CACpC,QAAQ;EACN,OAAO;CACT;CACA,MAAM,SAAS,uBAAuB,UAAU,OAAO;CACvD,OAAO,OAAO,UAAU,gBAAgB,WAAW,OAAO,IAAI,IAAI;AACpE;;;;;AAMA,SAAgB,4BAAqC,OAA4B;CAC/E,OAAO,SAAS,eAAe,OAAqD;EAClF,OAAO,eAAe,OAAO,2BAA2B,KAAK,KAAK,KAAK,CAAC,CAAC;CAC3E;AACF;;;;;;;;ACFA,SAAgB,sBAA+B,SAA0C;CACvF,MAAM,iBAAiB,4BAA4B,QAAQ,MAAM;CACjE,MAAM,sBAAsB,iCAAiC,QAAQ,MAAM;CAE3E,eAAe,aAAa,SAAwC;EAClE,MAAM,EAAE,gBAAgB,MAAM,QAAQ,QAAQ,OAAO,CAAC,CAAC;EACvD,yBAAyB,WAAW;CACtC;CAEA,eAAe,oBAAoB,OAAgB,SAAyC;EAE1F,IAAI,WAAW,KAAK,KAAK,WAAW,KAAK,GAAG,MAAM;EAClD,IAAI,iBAAiB,mBAAmB;GACtC,MAAM,aAAa,OAAO;GAE1B,MAAM,SAAS,EAAE,MAAM,QAAQ,OAAO,CAAC;EACzC;EAEA,MAAM,eAAe,KAAK;CAC5B;CAGA,eAAe,iBAAiB,OAAgB,SAA4C;EAE1F,IAAI,WAAW,KAAK,KAAK,WAAW,KAAK,GAAG,MAAM;EAClD,IAAI,iBAAiB,mBAAmB,MAAM,aAAa,OAAO;EAClE,OAAO,oBAAoB,KAAK;CAClC;CAsBA,OAAO;EAAE,yBApBuB,iBAAiB,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,OACrE,OAAO,EAAE,MAAM,cAAc;GAC3B,IAAI;IACF,OAAO,MAAM,KAAK;GACpB,SAAS,OAAO;IACd,OAAO,oBAAoB,OAAO,OAAO;GAC3C;EACF,CAa6B;EAAG,sBAVL,iBAAiB,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,OACjE,OAAO,EAAE,MAAM,cAAc;GAC3B,IAAI;IACF,OAAO,MAAM,KAAK;GACpB,SAAS,OAAO;IACd,OAAO,iBAAiB,OAAO,OAAO;GACxC;EACF,CAGmD;EAAG;EAAgB;CAAoB;AAC9F;;;;AC3EA,MAAM,sBAAsB;;;;;AAM5B,SAAgB,uBAAuB,aAAa,qBAAoC;CACtF,OAAO,aAAa,kBAAkB,CAAC,CAAC,IAAI,QAAQ,KAAK,EAAE,CAAC,CAAC,IAAI,UAAU,KAAK;AAClF"}