better-ship 0.7.0 → 0.8.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 (48) 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 +1 -1
  6. package/dist/better-auth/apple-client-secret.js +1 -1
  7. package/dist/better-auth/auth-client.js +1 -1
  8. package/dist/better-auth/rate-limit.d.ts +1 -1
  9. package/dist/better-auth/rate-limit.js +1 -1
  10. package/dist/better-auth.js +1 -1
  11. package/dist/cloudflare/auth-secondary-storage.d.ts +1 -1
  12. package/dist/cloudflare/auth-secondary-storage.js +1 -1
  13. package/dist/cloudflare/queue.d.ts +175 -0
  14. package/dist/cloudflare/queue.d.ts.map +1 -0
  15. package/dist/cloudflare/queue.js +419 -0
  16. package/dist/cloudflare/queue.js.map +1 -0
  17. package/dist/cloudflare.d.ts +3 -3
  18. package/dist/cloudflare.js +3 -3
  19. package/dist/{core-Cx5SeyKV.js → core-DC_4pOrI.js} +92 -2
  20. package/dist/core-DC_4pOrI.js.map +1 -0
  21. package/dist/core.d.ts +2 -2
  22. package/dist/core.js +2 -2
  23. package/dist/{index-BStnggQO.d.ts → index-6XMPJu7u.d.ts} +49 -2
  24. package/dist/index-6XMPJu7u.d.ts.map +1 -0
  25. package/dist/{index-DWIRrJMP.d.ts → index-_Cihfq1J.d.ts} +2 -2
  26. package/dist/{index-DWIRrJMP.d.ts.map → index-_Cihfq1J.d.ts.map} +1 -1
  27. package/dist/postgres.d.ts +3 -3
  28. package/dist/postgres.js +3 -3
  29. package/dist/tanstack.d.ts +1 -1
  30. package/dist/tanstack.js +1 -1
  31. package/dist/{unit-of-work-context-DToDpAkv.js → unit-of-work-context-BFCmU92Z.js} +2 -2
  32. package/dist/{unit-of-work-context-DToDpAkv.js.map → unit-of-work-context-BFCmU92Z.js.map} +1 -1
  33. package/dist/{unit-of-work-context-CPz9rdSS.d.ts → unit-of-work-context-BWTJfYPW.d.ts} +3 -3
  34. package/dist/{unit-of-work-context-CPz9rdSS.d.ts.map → unit-of-work-context-BWTJfYPW.d.ts.map} +1 -1
  35. package/package.json +2 -1
  36. package/src/core/backoff.ts +29 -0
  37. package/src/core/classify-failure.ts +60 -0
  38. package/src/core/cloudflare-classification.ts +45 -0
  39. package/src/core/index.ts +14 -0
  40. package/src/infrastructure/cloudflare/queue/index.ts +25 -0
  41. package/src/infrastructure/cloudflare/queue/queue-client.ts +177 -0
  42. package/src/infrastructure/cloudflare/queue/queue-consumer.ts +146 -0
  43. package/src/infrastructure/cloudflare/queue/queue-limits.ts +54 -0
  44. package/src/infrastructure/cloudflare/queue/queue-message.ts +4 -0
  45. package/src/infrastructure/cloudflare/queue/queue.errors.ts +105 -0
  46. package/src/infrastructure/cloudflare/queue/redelivery-policy.ts +64 -0
  47. package/dist/core-Cx5SeyKV.js.map +0 -1
  48. package/dist/index-BStnggQO.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { N as AppError, a as createLogger, g as DatabaseError, h as unreachable } from "./core-Cx5SeyKV.js";
1
+ import { E as DatabaseError, T as unreachable, U as AppError, a as createLogger } from "./core-DC_4pOrI.js";
2
2
  import { panic } from "better-result";
3
3
 
4
4
  //#region src/application/message-already-processed.error.ts
@@ -128,4 +128,4 @@ var UnitOfWorkAlreadyActiveError = class extends AppError {
128
128
 
129
129
  //#endregion
130
130
  export { MessageAlreadyProcessedError as i, UnitOfWork as n, MessageBus as r, UnitOfWorkAlreadyActiveError as t };
131
- //# sourceMappingURL=application-DjsQtpgw.js.map
131
+ //# sourceMappingURL=application-DYfcAy-Q.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"application-DjsQtpgw.js","names":[],"sources":["../src/application/message-already-processed.error.ts","../src/application/message-bus.ts","../src/application/unit-of-work.ts","../src/application/unit-of-work.errors.ts"],"sourcesContent":["import { AppError, DatabaseError, type MessageId } from '@/core'\n\n/** The message's effects already committed. A caller can skip duplicate delivery without repeating those effects. */\nexport class MessageAlreadyProcessedError extends AppError {\n readonly _tag = 'MessageAlreadyProcessedError'\n readonly classification = 'terminal'\n\n constructor(\n readonly messageId: MessageId,\n options?: { readonly cause: unknown },\n ) {\n super(`message ${messageId} already processed`, options)\n }\n\n /** Recognize only the processed-message primary key; preserve other failures unchanged at the call site. */\n static from(cause: unknown, messageId: MessageId): MessageAlreadyProcessedError | undefined {\n if (cause instanceof MessageAlreadyProcessedError) return cause\n if (!(cause instanceof DatabaseError)) return undefined\n const details = cause.details\n const duplicate =\n details.database === 'd1'\n ? details.kind === 'unique' &&\n details.table === 'processed_messages' &&\n details.column === 'message_id'\n : details.code === '23505' &&\n details.table_name === 'processed_messages' &&\n details.constraint_name === 'processed_messages_pkey'\n if (!duplicate) return undefined\n return new MessageAlreadyProcessedError(messageId, { cause })\n }\n}\n","import { panic } from 'better-result'\n\nimport {\n createLogger,\n unreachable,\n type DomainCommand,\n type DomainEvent,\n type DomainMessage,\n type DomainQuery,\n} from '@/core'\n\nimport { MessageAlreadyProcessedError } from './message-already-processed.error.ts'\nimport type { Handlers, MessageResult, RegistryMessage } from './registry.ts'\n\nconst logger = createLogger('message-bus')\n\n/** The port an entrypoint dispatches through. `AppDeps` names this as `IMessageBus<typeof registry>`. */\nexport interface IMessageBus<TRegistry extends Handlers<never>> {\n handle<TMessage extends DomainMessage & RegistryMessage<TRegistry>>(\n message: TMessage,\n ): Promise<MessageResult<TMessage, TRegistry>>\n}\n\n/**\n * Routes one message to its slot. The bus opens no transaction and keeps no outbox:\n * a handler that writes opens the unit of work itself.\n */\nexport class MessageBus<Deps, TRegistry extends Handlers<Deps>> implements IMessageBus<TRegistry> {\n constructor(\n private readonly deps: Deps,\n private readonly registry: TRegistry,\n ) {}\n\n /** Resolves to the handler's own value for a command or query, and to void for an event. */\n async handle<TMessage extends DomainMessage & RegistryMessage<TRegistry>>(\n message: TMessage,\n ): Promise<MessageResult<TMessage, TRegistry>> {\n // SAFETY: the slot for this name is what `MessageResult` names, and dispatch returns its value.\n return (await this.dispatch(message)) as MessageResult<TMessage, TRegistry>\n }\n\n // oxlint-disable-next-line anti-slop/no-unknown-returns -- one table holds every slot's value; `handle` names it.\n private dispatch(message: DomainMessage): Promise<unknown> {\n if (message.type === 'command') return this.handleCommand(message)\n if (message.type === 'query') return this.handleQuery(message)\n if (message.type === 'event') return this.handleEvent(message)\n // A message parsed at a boundary cannot reach here; one that does must not resolve silently.\n return unreachable(message)\n }\n\n // oxlint-disable-next-line anti-slop/no-unknown-returns -- see dispatch.\n private handleCommand(command: DomainCommand): Promise<unknown> {\n // `satisfies` proved the registry complete, so a missing slot is a broken registry object.\n const handler = this.registry.commands[command.name]\n if (handler === undefined) return panic(`No handler for command ${command.name}`)\n logger.debug('handling_command', { name: command.name, id: command.id })\n return handler(command, this.deps)\n }\n\n // oxlint-disable-next-line anti-slop/no-unknown-returns -- see dispatch.\n private handleQuery(query: DomainQuery): Promise<unknown> {\n const handler = this.registry.queries[query.name]\n if (handler === undefined) return panic(`No handler for query ${query.name}`)\n return handler(query, this.deps)\n }\n\n /**\n * Every subscriber runs to completion. One failure is rethrown as is. Several are thrown as\n * one `AggregateError`. A `MessageAlreadyProcessedError` means that subscriber already committed on\n * an earlier delivery, so it counts as delivered.\n */\n private async handleEvent(event: DomainEvent): Promise<void> {\n const subscriptions = this.registry.events[event.name] ?? []\n const outcomes = await Promise.allSettled(\n subscriptions.map((subscription) => subscription(event, this.deps)),\n )\n const failures: unknown[] = []\n for (const [subscriber, outcome] of outcomes.entries()) {\n if (outcome.status === 'fulfilled') continue\n if (outcome.reason instanceof MessageAlreadyProcessedError) {\n // The bus swallows this error, so this line is the only record that the skip happened.\n logger.info('duplicate_subscriber_ignored', { event: event.name, id: event.id, subscriber })\n continue\n }\n failures.push(outcome.reason)\n }\n if (failures.length === 1) throw failures[0]\n if (failures.length > 1) {\n throw new AggregateError(failures, `${event.name}: ${failures.length} subscribers failed`)\n }\n }\n}\n","import type { MessageId } from '@/core'\n\nimport type { IEventCollector } from './event-collector.ts'\nimport { MessageAlreadyProcessedError } from './message-already-processed.error.ts'\nimport type { IMessageStore } from './message-store.ts'\nimport type { IOutboxRelay } from './outbox-relay.ts'\nimport type { ITransaction } from './transaction.ts'\n\n/**\n * Commits the processed-message record, repository writes, and emitted events together before resolving.\n * An existing record rejects with `MessageAlreadyProcessedError`; external effects must run through the outbox after commit.\n * Nested calls reject with `UnitOfWorkAlreadyActiveError`; independent concurrent calls are allowed.\n */\nexport interface IUnitOfWork<Repos> {\n run<T>(messageId: MessageId, work: (repos: Repos) => Promise<T>): Promise<T>\n}\n\nexport type UnitOfWorkDeps<Tx, Repos> = {\n readonly transaction: ITransaction<Tx>\n /** The processed-messages and outbox repository for this transaction. */\n readonly messageStore: (tx: Tx) => IMessageStore\n /** Repositories participate in the current transaction. */\n readonly createRepositories: (tx: Tx) => Repos\n readonly eventCollector: IEventCollector\n readonly relay: IOutboxRelay\n}\n\n/** The unit of work: the boundary, the repositories, the events. Every database call is a port. */\nexport class UnitOfWork<Tx, Repos> implements IUnitOfWork<Repos> {\n constructor(private readonly deps: UnitOfWorkDeps<Tx, Repos>) {}\n\n async run<T>(messageId: MessageId, work: (repos: Repos) => Promise<T>): Promise<T> {\n const { transaction, messageStore, createRepositories, eventCollector, relay } = this.deps\n let written = 0\n\n let value: T\n try {\n value = await transaction.transaction(async (tx) => {\n const store = messageStore(tx)\n await store.claim(messageId)\n const repos = createRepositories(tx)\n const result = await work(repos)\n const pending = eventCollector.collect()\n await store.persistEvents(pending)\n written = pending.length\n return result\n })\n } catch (error) {\n throw MessageAlreadyProcessedError.from(error, messageId) ?? error\n }\n\n if (written > 0) relay.wake()\n return value\n }\n}\n","import { AppError } from '@/core'\n\n/** A boundary was opened inside another. One message, one atomic scope. */\nexport class UnitOfWorkAlreadyActiveError extends AppError {\n readonly _tag = 'UnitOfWorkAlreadyActiveError'\n readonly classification = 'terminal'\n\n constructor() {\n super('a unit of work is already active')\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"application-DYfcAy-Q.js","names":[],"sources":["../src/application/message-already-processed.error.ts","../src/application/message-bus.ts","../src/application/unit-of-work.ts","../src/application/unit-of-work.errors.ts"],"sourcesContent":["import { AppError, DatabaseError, type MessageId } from '@/core'\n\n/** The message's effects already committed. A caller can skip duplicate delivery without repeating those effects. */\nexport class MessageAlreadyProcessedError extends AppError {\n readonly _tag = 'MessageAlreadyProcessedError'\n readonly classification = 'terminal'\n\n constructor(\n readonly messageId: MessageId,\n options?: { readonly cause: unknown },\n ) {\n super(`message ${messageId} already processed`, options)\n }\n\n /** Recognize only the processed-message primary key; preserve other failures unchanged at the call site. */\n static from(cause: unknown, messageId: MessageId): MessageAlreadyProcessedError | undefined {\n if (cause instanceof MessageAlreadyProcessedError) return cause\n if (!(cause instanceof DatabaseError)) return undefined\n const details = cause.details\n const duplicate =\n details.database === 'd1'\n ? details.kind === 'unique' &&\n details.table === 'processed_messages' &&\n details.column === 'message_id'\n : details.code === '23505' &&\n details.table_name === 'processed_messages' &&\n details.constraint_name === 'processed_messages_pkey'\n if (!duplicate) return undefined\n return new MessageAlreadyProcessedError(messageId, { cause })\n }\n}\n","import { panic } from 'better-result'\n\nimport {\n createLogger,\n unreachable,\n type DomainCommand,\n type DomainEvent,\n type DomainMessage,\n type DomainQuery,\n} from '@/core'\n\nimport { MessageAlreadyProcessedError } from './message-already-processed.error.ts'\nimport type { Handlers, MessageResult, RegistryMessage } from './registry.ts'\n\nconst logger = createLogger('message-bus')\n\n/** The port an entrypoint dispatches through. `AppDeps` names this as `IMessageBus<typeof registry>`. */\nexport interface IMessageBus<TRegistry extends Handlers<never>> {\n handle<TMessage extends DomainMessage & RegistryMessage<TRegistry>>(\n message: TMessage,\n ): Promise<MessageResult<TMessage, TRegistry>>\n}\n\n/**\n * Routes one message to its slot. The bus opens no transaction and keeps no outbox:\n * a handler that writes opens the unit of work itself.\n */\nexport class MessageBus<Deps, TRegistry extends Handlers<Deps>> implements IMessageBus<TRegistry> {\n constructor(\n private readonly deps: Deps,\n private readonly registry: TRegistry,\n ) {}\n\n /** Resolves to the handler's own value for a command or query, and to void for an event. */\n async handle<TMessage extends DomainMessage & RegistryMessage<TRegistry>>(\n message: TMessage,\n ): Promise<MessageResult<TMessage, TRegistry>> {\n // SAFETY: the slot for this name is what `MessageResult` names, and dispatch returns its value.\n return (await this.dispatch(message)) as MessageResult<TMessage, TRegistry>\n }\n\n // oxlint-disable-next-line anti-slop/no-unknown-returns -- one table holds every slot's value; `handle` names it.\n private dispatch(message: DomainMessage): Promise<unknown> {\n if (message.type === 'command') return this.handleCommand(message)\n if (message.type === 'query') return this.handleQuery(message)\n if (message.type === 'event') return this.handleEvent(message)\n // A message parsed at a boundary cannot reach here; one that does must not resolve silently.\n return unreachable(message)\n }\n\n // oxlint-disable-next-line anti-slop/no-unknown-returns -- see dispatch.\n private handleCommand(command: DomainCommand): Promise<unknown> {\n // `satisfies` proved the registry complete, so a missing slot is a broken registry object.\n const handler = this.registry.commands[command.name]\n if (handler === undefined) return panic(`No handler for command ${command.name}`)\n logger.debug('handling_command', { name: command.name, id: command.id })\n return handler(command, this.deps)\n }\n\n // oxlint-disable-next-line anti-slop/no-unknown-returns -- see dispatch.\n private handleQuery(query: DomainQuery): Promise<unknown> {\n const handler = this.registry.queries[query.name]\n if (handler === undefined) return panic(`No handler for query ${query.name}`)\n return handler(query, this.deps)\n }\n\n /**\n * Every subscriber runs to completion. One failure is rethrown as is. Several are thrown as\n * one `AggregateError`. A `MessageAlreadyProcessedError` means that subscriber already committed on\n * an earlier delivery, so it counts as delivered.\n */\n private async handleEvent(event: DomainEvent): Promise<void> {\n const subscriptions = this.registry.events[event.name] ?? []\n const outcomes = await Promise.allSettled(\n subscriptions.map((subscription) => subscription(event, this.deps)),\n )\n const failures: unknown[] = []\n for (const [subscriber, outcome] of outcomes.entries()) {\n if (outcome.status === 'fulfilled') continue\n if (outcome.reason instanceof MessageAlreadyProcessedError) {\n // The bus swallows this error, so this line is the only record that the skip happened.\n logger.info('duplicate_subscriber_ignored', { event: event.name, id: event.id, subscriber })\n continue\n }\n failures.push(outcome.reason)\n }\n if (failures.length === 1) throw failures[0]\n if (failures.length > 1) {\n throw new AggregateError(failures, `${event.name}: ${failures.length} subscribers failed`)\n }\n }\n}\n","import type { MessageId } from '@/core'\n\nimport type { IEventCollector } from './event-collector.ts'\nimport { MessageAlreadyProcessedError } from './message-already-processed.error.ts'\nimport type { IMessageStore } from './message-store.ts'\nimport type { IOutboxRelay } from './outbox-relay.ts'\nimport type { ITransaction } from './transaction.ts'\n\n/**\n * Commits the processed-message record, repository writes, and emitted events together before resolving.\n * An existing record rejects with `MessageAlreadyProcessedError`; external effects must run through the outbox after commit.\n * Nested calls reject with `UnitOfWorkAlreadyActiveError`; independent concurrent calls are allowed.\n */\nexport interface IUnitOfWork<Repos> {\n run<T>(messageId: MessageId, work: (repos: Repos) => Promise<T>): Promise<T>\n}\n\nexport type UnitOfWorkDeps<Tx, Repos> = {\n readonly transaction: ITransaction<Tx>\n /** The processed-messages and outbox repository for this transaction. */\n readonly messageStore: (tx: Tx) => IMessageStore\n /** Repositories participate in the current transaction. */\n readonly createRepositories: (tx: Tx) => Repos\n readonly eventCollector: IEventCollector\n readonly relay: IOutboxRelay\n}\n\n/** The unit of work: the boundary, the repositories, the events. Every database call is a port. */\nexport class UnitOfWork<Tx, Repos> implements IUnitOfWork<Repos> {\n constructor(private readonly deps: UnitOfWorkDeps<Tx, Repos>) {}\n\n async run<T>(messageId: MessageId, work: (repos: Repos) => Promise<T>): Promise<T> {\n const { transaction, messageStore, createRepositories, eventCollector, relay } = this.deps\n let written = 0\n\n let value: T\n try {\n value = await transaction.transaction(async (tx) => {\n const store = messageStore(tx)\n await store.claim(messageId)\n const repos = createRepositories(tx)\n const result = await work(repos)\n const pending = eventCollector.collect()\n await store.persistEvents(pending)\n written = pending.length\n return result\n })\n } catch (error) {\n throw MessageAlreadyProcessedError.from(error, messageId) ?? error\n }\n\n if (written > 0) relay.wake()\n return value\n }\n}\n","import { AppError } from '@/core'\n\n/** A boundary was opened inside another. One message, one atomic scope. */\nexport class UnitOfWorkAlreadyActiveError extends AppError {\n readonly _tag = 'UnitOfWorkAlreadyActiveError'\n readonly classification = 'terminal'\n\n constructor() {\n super('a unit of work is already active')\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { F as DomainQuery, I as MessageId, M as DomainCommand, N as DomainEvent, P as DomainMessage } from "./index-BStnggQO.js";
2
- import { _ as RegistryMessage, a as UnitOfWorkDeps, b as EventHandler, c as IOutboxRelay, d as CommandRegistry, f as EventRegistry, g as QueryRegistry, h as MessageResult, i as UnitOfWork, l as IMessageBus, m as MessageRegistry, n as MessageAlreadyProcessedError, o as IEventCollector, p as Handlers, r as IUnitOfWork, s as ITransaction, t as UnitOfWorkAlreadyActiveError, u as MessageBus, v as IMessageStore, x as QueryHandler, y as CommandHandler } from "./index-DWIRrJMP.js";
1
+ import { G as DomainMessage, K as DomainQuery, U as DomainCommand, W as DomainEvent, q as MessageId } from "./index-6XMPJu7u.js";
2
+ import { _ as RegistryMessage, a as UnitOfWorkDeps, b as EventHandler, c as IOutboxRelay, d as CommandRegistry, f as EventRegistry, g as QueryRegistry, h as MessageResult, i as UnitOfWork, l as IMessageBus, m as MessageRegistry, n as MessageAlreadyProcessedError, o as IEventCollector, p as Handlers, r as IUnitOfWork, s as ITransaction, t as UnitOfWorkAlreadyActiveError, u as MessageBus, v as IMessageStore, x as QueryHandler, y as CommandHandler } from "./index-_Cihfq1J.js";
3
3
  export { type CommandHandler, type CommandRegistry, type DomainCommand, type DomainEvent, type DomainMessage, type DomainQuery, type EventHandler, type EventRegistry, type Handlers, type IEventCollector, type IMessageBus, type IMessageStore, type IOutboxRelay, type ITransaction, type IUnitOfWork, MessageAlreadyProcessedError, MessageBus, type MessageId, type MessageRegistry, type MessageResult, type QueryHandler, type QueryRegistry, type RegistryMessage, UnitOfWork, UnitOfWorkAlreadyActiveError, type UnitOfWorkDeps };
@@ -1,3 +1,3 @@
1
- import { i as MessageAlreadyProcessedError, n as UnitOfWork, r as MessageBus, t as UnitOfWorkAlreadyActiveError } from "./application-DjsQtpgw.js";
1
+ import { i as MessageAlreadyProcessedError, n as UnitOfWork, r as MessageBus, t as UnitOfWorkAlreadyActiveError } from "./application-DYfcAy-Q.js";
2
2
 
3
3
  export { MessageAlreadyProcessedError, MessageBus, UnitOfWork, UnitOfWorkAlreadyActiveError };
@@ -1,4 +1,4 @@
1
- import { vt as AppError } from "../index-BStnggQO.js";
1
+ import { kt as AppError } from "../index-6XMPJu7u.js";
2
2
  //#region src/infrastructure/better-auth/apple-client-secret.d.ts
3
3
  /** Apple sends its OAuth callback from this origin. Include it in trustedOrigins when enabling Apple. */
4
4
  export declare const APPLE_ORIGIN = "https://appleid.apple.com";
@@ -1,4 +1,4 @@
1
- import { N as AppError, a as createLogger } from "../core-Cx5SeyKV.js";
1
+ import { U as AppError, a as createLogger } from "../core-DC_4pOrI.js";
2
2
  import { SignJWT, importPKCS8 } from "jose";
3
3
 
4
4
  //#region src/infrastructure/better-auth/apple-client-secret.ts
@@ -1,4 +1,4 @@
1
- import { j as RateLimitError } from "../core-Cx5SeyKV.js";
1
+ import { V as RateLimitError } from "../core-DC_4pOrI.js";
2
2
  import { createAuthClient } from "better-auth/client";
3
3
 
4
4
  //#region src/infrastructure/better-auth/auth-client.ts
@@ -1,4 +1,4 @@
1
- import { vt as AppError } from "../index-BStnggQO.js";
1
+ import { kt as AppError } from "../index-6XMPJu7u.js";
2
2
  import { BetterAuthRateLimitStorage } from "better-auth";
3
3
  //#region src/infrastructure/better-auth/rate-limit.d.ts
4
4
  /** Each rule must match its binding's deployed limit and period. Cloudflare accepts only 10 or 60 seconds. */
@@ -1,4 +1,4 @@
1
- import { N as AppError, a as createLogger } from "../core-Cx5SeyKV.js";
1
+ import { U as AppError, a as createLogger } from "../core-DC_4pOrI.js";
2
2
 
3
3
  //#region src/infrastructure/better-auth/rate-limit.ts
4
4
  /** A binding failure with no known retry classification. The cause preserves the original failure. */
@@ -1,4 +1,4 @@
1
- import { a as createLogger } from "./core-Cx5SeyKV.js";
1
+ import { a as createLogger } from "./core-DC_4pOrI.js";
2
2
  import { v7 } from "uuid";
3
3
  import { isAPIError } from "better-auth/api";
4
4
  import { anonymous, bearer, captcha, deviceAuthorization, emailOTP, lastLoginMethod, magicLink, openAPI } from "better-auth/plugins";
@@ -1,4 +1,4 @@
1
- import { vt as AppError } from "../index-BStnggQO.js";
1
+ import { kt as AppError } from "../index-6XMPJu7u.js";
2
2
  import { DurableObject } from "cloudflare:workers";
3
3
  //#region src/infrastructure/cloudflare/auth-secondary-storage.d.ts
4
4
  /** The supplied TTL cannot produce a valid expiry timestamp. Retrying the same input cannot fix it. */
@@ -1,4 +1,4 @@
1
- import { N as AppError } from "../core-Cx5SeyKV.js";
1
+ import { U as AppError } from "../core-DC_4pOrI.js";
2
2
  import { DurableObject } from "cloudflare:workers";
3
3
 
4
4
  //#region src/infrastructure/cloudflare/auth-secondary-storage.ts
@@ -0,0 +1,175 @@
1
+ import { At as FailureClassification, U as DomainCommand, W as DomainEvent, kt as AppError } from "../index-6XMPJu7u.js";
2
+ import { z } from "zod";
3
+ //#region src/infrastructure/cloudflare/queue/queue-message.d.ts
4
+ /** A message a queue carries: a command from outside the request, or an event from the outbox. */
5
+ type QueueMessage = DomainCommand | DomainEvent;
6
+ //#endregion
7
+ //#region src/infrastructure/cloudflare/queue/queue-client.d.ts
8
+ /** Cloudflare's delivery delay, in seconds. */
9
+ type QueueSendOptions = {
10
+ readonly delaySeconds: number;
11
+ };
12
+ /** The two calls the client makes on a queue binding. */
13
+ type QueueBinding<Body> = Pick<Queue<Body>, 'send' | 'sendBatch'>;
14
+ /**
15
+ * The lanes and the dead letter of one application. A lane is a queue with its own consumer
16
+ * settings; `laneOf` is the product's routing rule, written once at the composition root.
17
+ */
18
+ type QueueClientOptions<TMessage extends QueueMessage, Lane extends string> = {
19
+ readonly queues: Readonly<Record<Lane, QueueBinding<TMessage>>>;
20
+ /** Where the consumer parks poison bodies. Cloudflare also routes exhausted retries here. */
21
+ readonly deadLetter: Pick<Queue, 'send'>;
22
+ readonly laneOf: (message: TMessage) => Lane;
23
+ };
24
+ /** The port an entrypoint, a relay, or a consumer sends through. */
25
+ interface IQueueClient<TMessage extends QueueMessage> {
26
+ send(message: TMessage, options?: QueueSendOptions): Promise<void>;
27
+ sendBatch(messages: ReadonlyArray<TMessage>): Promise<void>;
28
+ /** Sends every message within the limits and returns the oversized ones. */
29
+ sendBatchPartial(messages: ReadonlyArray<TMessage>): Promise<ReadonlyArray<TMessage>>;
30
+ /** Parks a delivered message's body as it arrived. */
31
+ sendToDlq(message: Message): Promise<void>;
32
+ }
33
+ /**
34
+ * Sends messages to the application's queues. Checks the size limits before a send, retries a
35
+ * transient binding failure a bounded number of times, and converts the final failure to `QueueSendError`.
36
+ */
37
+ export declare class QueueClient<TMessage extends QueueMessage, Lane extends string> implements IQueueClient<TMessage> {
38
+ private readonly options;
39
+ constructor(options: QueueClientOptions<TMessage, Lane>);
40
+ /** @throws OversizedMessageError before the send. @throws QueueSendError after the retries. */
41
+ send(message: TMessage, options?: QueueSendOptions): Promise<void>;
42
+ /** Rejects the whole batch before any send when one message is oversized. */
43
+ sendBatch(messages: ReadonlyArray<TMessage>): Promise<void>;
44
+ sendBatchPartial(messages: ReadonlyArray<TMessage>): Promise<ReadonlyArray<TMessage>>;
45
+ sendToDlq(message: Message): Promise<void>;
46
+ /** Each lane's chunks retry on their own, so one failed chunk does not resend the others. */
47
+ private sendSizedBatch;
48
+ private queueFor;
49
+ private callQueue;
50
+ }
51
+ //#endregion
52
+ //#region src/infrastructure/cloudflare/queue/queue-consumer.d.ts
53
+ /** Wraps one dispatch: an error-tracking scope, an analytics context. The default runs it as is. */
54
+ type DispatchWrapper<TMessage extends QueueMessage> = (message: TMessage, attempt: number, run: () => Promise<void>) => Promise<void>;
55
+ /** The one call the consumer makes on the bus. */
56
+ type DispatchBus<TMessage extends QueueMessage> = {
57
+ handle(message: TMessage): Promise<unknown>;
58
+ };
59
+ /**
60
+ * Parses and dispatches each queue message, then selects acknowledgement or retry.
61
+ * Cloudflare owns the retry limit and sends exhausted messages to the configured dead letter.
62
+ * The consumer logs each failure once; handlers do not.
63
+ */
64
+ export declare class QueueConsumer<TMessage extends QueueMessage> {
65
+ private readonly bus;
66
+ private readonly queueClient;
67
+ private readonly schema;
68
+ private readonly wrapDispatch;
69
+ /**
70
+ * @param bus - Where a parsed message goes.
71
+ * @param queueClient - Parks an unparseable body in the dead letter.
72
+ * @param schema - What a body may be: the application's `messages.queueSchema`.
73
+ * @param wrapDispatch - Wraps one dispatch in the application's context. Default: run it as is.
74
+ */
75
+ constructor(bus: DispatchBus<TMessage>, queueClient: Pick<IQueueClient<TMessage>, 'sendToDlq'>, schema: z.ZodType<TMessage>, wrapDispatch?: DispatchWrapper<TMessage>);
76
+ /** Every message settles on its own. A settlement that throws rejects the batch after its siblings settle. */
77
+ processBatch(batch: MessageBatch): Promise<void>;
78
+ private processMessage;
79
+ /** Returns null on failure; the caller owns the single log point. */
80
+ private parseMessage;
81
+ /** Park an unparseable message in the dead letter, then acknowledge its source delivery. */
82
+ private parkPoison;
83
+ /**
84
+ * Retry declared transient and unknown failures so Cloudflare can enforce the attempt ceiling.
85
+ * Acknowledge only declared terminal failures.
86
+ */
87
+ private handleFailure;
88
+ }
89
+ //#endregion
90
+ //#region src/infrastructure/cloudflare/queue/queue-limits.d.ts
91
+ /**
92
+ * The Cloudflare Queues producer limits with metadata headroom, checked before each send so a
93
+ * violation never reaches the binding. The dead letter has the same per-message limit.
94
+ * https://developers.cloudflare.com/queues/platform/limits/
95
+ */
96
+ export declare const QUEUE_LIMITS: {
97
+ readonly messageBytes: 127000;
98
+ readonly batchBytes: 250000;
99
+ readonly batchCount: 100;
100
+ };
101
+ /** The size the binding measures: the JSON encoding of the body, in UTF-8 bytes. */
102
+ export declare function messageByteLength(message: QueueMessage): number;
103
+ /** A message with its measured size. */
104
+ type SizedMessage<TMessage> = {
105
+ readonly message: TMessage;
106
+ readonly bytes: number;
107
+ };
108
+ /** Measure every message once. */
109
+ export declare function sizeMessages<TMessage extends QueueMessage>(messages: ReadonlyArray<TMessage>): SizedMessage<TMessage>[];
110
+ /** Whether one message is over the per-message limit. */
111
+ export declare function isOversized(sized: SizedMessage<QueueMessage>): boolean;
112
+ /** Split a batch at the message-count and byte limits, keeping the order. */
113
+ export declare function chunkByLimits<TMessage>(sized: ReadonlyArray<SizedMessage<TMessage>>): TMessage[][];
114
+ //#endregion
115
+ //#region src/infrastructure/cloudflare/queue/queue.errors.d.ts
116
+ /** The Queue binding calls the client makes. Each is safe to repeat. */
117
+ type QueueOperation = 'send' | 'send_batch' | 'send_dlq';
118
+ /** Classify a raw Queue binding failure: the code table first, then Cloudflare's signals, then transport. */
119
+ export declare function classifyQueueError(cause: unknown): FailureClassification;
120
+ /** A send through a Queue binding failed. The classification says whether an immediate retry may help. */
121
+ export declare class QueueSendError extends AppError {
122
+ readonly _tag = "QueueSendError";
123
+ readonly classification: FailureClassification;
124
+ readonly operation: QueueOperation;
125
+ constructor(args: {
126
+ readonly operation: QueueOperation;
127
+ readonly cause: unknown;
128
+ });
129
+ }
130
+ /**
131
+ * A message over the per-message cap can never be sent on any queue; the dead letter has the
132
+ * same cap. The client detects it before the send, so it never comes from a platform error.
133
+ */
134
+ export declare class OversizedMessageError extends AppError {
135
+ readonly _tag = "OversizedMessageError";
136
+ readonly classification = "terminal";
137
+ readonly messageName: string;
138
+ readonly bytes: number;
139
+ readonly limit: number;
140
+ constructor(args: {
141
+ readonly messageName: string;
142
+ readonly bytes: number;
143
+ readonly limit: number;
144
+ });
145
+ }
146
+ /**
147
+ * The dead letter did not accept an unparseable message. Always transient, whatever the send
148
+ * failure was, so the source delivery retries instead of acknowledging and losing the body.
149
+ */
150
+ export declare class DeadLetterUnavailableError extends AppError {
151
+ readonly _tag = "DeadLetterUnavailableError";
152
+ readonly classification = "transient";
153
+ constructor(cause: unknown);
154
+ }
155
+ //#endregion
156
+ //#region src/infrastructure/cloudflare/queue/redelivery-policy.d.ts
157
+ /** How the consumer settles one failed message: acknowledge it, or have Cloudflare redeliver it after a delay. */
158
+ type RedeliveryDecision = {
159
+ readonly action: 'ack';
160
+ readonly classification: 'terminal';
161
+ } | {
162
+ readonly action: 'retry';
163
+ readonly classification: Exclude<FailureClassification, 'terminal'>;
164
+ readonly delaySeconds: number;
165
+ };
166
+ /**
167
+ * Decide whether the consumer acknowledges a failed message or asks Cloudflare to redeliver it.
168
+ * A terminal failure acknowledges. Transient and unknown failures redeliver: after the advertised
169
+ * wait plus a spread when the error carries one, else with exponential equal-jitter backoff.
170
+ * An `AggregateError` from event delivery redelivers when any member does, after the longest wait.
171
+ */
172
+ export declare function decideRedelivery(cause: unknown, attempt: number): RedeliveryDecision;
173
+ //#endregion
174
+ export type { DispatchBus, DispatchWrapper, IQueueClient, QueueBinding, QueueClientOptions, QueueMessage, QueueOperation, QueueSendOptions, RedeliveryDecision, SizedMessage };
175
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","names":[],"sources":["../../src/infrastructure/cloudflare/queue/queue-message.ts","../../src/infrastructure/cloudflare/queue/queue-client.ts","../../src/infrastructure/cloudflare/queue/queue-consumer.ts","../../src/infrastructure/cloudflare/queue/queue-limits.ts","../../src/infrastructure/cloudflare/queue/queue.errors.ts","../../src/infrastructure/cloudflare/queue/redelivery-policy.ts"],"mappings":";;;;KAGY,eAAe,gBAAgB;;;;KCa/B;WAA8B;;;KAG9B,aAAa,QAAQ,KAAK,MAAM;;;;;KAMhC,mBAAmB,iBAAiB,cAAc;WACnD,QAAQ,SAAS,OAAO,MAAM,aAAa;;WAE3C,YAAY,KAAK;WACjB,SAAS,SAAS,aAAa;;;UAIzB,aAAa,iBAAiB;EAC7C,KAAK,SAAS,UAAU,UAAU,mBAAmB;EACrD,UAAU,UAAU,cAAc,YAAY;;EAE9C,iBAAiB,UAAU,cAAc,YAAY,QAAQ,cAAc;;EAE3E,UAAU,SAAS,UAAU;;;;;;qBA8BlB,YACX,iBAAiB,cACjB,gCACW,aAAa;mBACK;EAA7B,YAA6B,SAAS,mBAAmB,UAAU;;EAG7D,KAAK,SAAS,UAAU,UAAU,mBAAmB;;EA4BrD,UAAU,UAAU,cAAc,YAAY;EAO9C,iBAAiB,UAAU,cAAc,YAAY,QAAQ,cAAc;EAM3E,UAAU,SAAS,UAAU;;UAQrB;UA4BN;UAIM;;;;;KChJJ,gBAAgB,iBAAiB,iBAC3C,SAAS,UACT,iBACA,WAAW,kBACR;;KAGO,YAAY,iBAAiB;EAEvC,OAAO,SAAS,WAAW;;;;;;;qBAQhB,cAAc,iBAAiB;mBAQvB;mBACA;mBACA;mBACA;;;;;;;EAJnB,YACmB,KAAK,YAAY,WACjB,aAAa,KAAK,aAAa,yBAC/B,QAAQ,EAAE,QAAQ,WAClB,eAAc,gBAAgB;;EAI3C,aAAa,OAAO,eAAe;UAc3B;;UA0BA;;UAMA;;;;;UAaN;;;;;;;;;qBCjGG;WACX;WACA;WACA;;;wBAIc,kBAAkB,SAAS;;KAK/B,aAAa;WAAuB,SAAS;WAAmB;;;wBAG5D,aAAa,iBAAiB,cAC5C,UAAU,cAAc,YACvB,aAAa;;wBAKA,YAAY,OAAO,aAAa;;wBAKhC,cAAc,UAC5B,OAAO,cAAc,aAAa,aACjC;;;;KCjCS;;wBA4CI,mBAAmB,iBAAiB;;qBASvC,uBAAuB;WACzB;WACA,gBAAgB;WAChB,WAAW;EAEpB,YAAY;aAAiB,WAAW;aAAyB;;;;;;;qBAWtD,8BAA8B;WAChC;WACA;WACA;WACA;WACA;EAET,YAAY;aACD;aACA;aACA;;;;;;;qBAeA,mCAAmC;WACrC;WACA;EAET,YAAY;;;;;KCrFF;WACG;WAAwB;;WAExB;WACA,gBAAgB,QAAQ;WACxB;;;;;;;;wBASC,iBAAiB,gBAAgB,kBAAkB"}