stratal 0.0.14 → 0.0.16

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 (144) hide show
  1. package/dist/application-zG8b-pol.d.mts +116 -0
  2. package/dist/application-zG8b-pol.d.mts.map +1 -0
  3. package/dist/{base-email.provider-bzdAYp8Z.mjs → base-email.provider-Cuw4OAB0.mjs} +1 -1
  4. package/dist/{base-email.provider-bzdAYp8Z.mjs.map → base-email.provider-Cuw4OAB0.mjs.map} +1 -1
  5. package/dist/bin/cloudflare-workers-loader.mjs +34 -0
  6. package/dist/bin/cloudflare-workers-loader.mjs.map +1 -0
  7. package/dist/bin/quarry.mjs +168 -0
  8. package/dist/bin/quarry.mjs.map +1 -0
  9. package/dist/cache/index.d.mts +2 -2
  10. package/dist/cache/index.mjs +11 -6
  11. package/dist/cache/index.mjs.map +1 -1
  12. package/dist/colors-DJaRDXoS.mjs +16 -0
  13. package/dist/colors-DJaRDXoS.mjs.map +1 -0
  14. package/dist/command-B-QH-Vu3.d.mts +120 -0
  15. package/dist/command-B-QH-Vu3.d.mts.map +1 -0
  16. package/dist/command-BvCOD6df.mjs +193 -0
  17. package/dist/command-BvCOD6df.mjs.map +1 -0
  18. package/dist/config/index.d.mts +2 -2
  19. package/dist/config/index.mjs +11 -6
  20. package/dist/config/index.mjs.map +1 -1
  21. package/dist/cron/index.d.mts +1 -1
  22. package/dist/cron/index.mjs +4 -3
  23. package/dist/{cron-manager-CpS_hrDD.mjs → cron-manager-DR7fiG6o.mjs} +3 -3
  24. package/dist/{cron-manager-CpS_hrDD.mjs.map → cron-manager-DR7fiG6o.mjs.map} +1 -1
  25. package/dist/decorate-D5j-d9_z.mjs +171 -0
  26. package/dist/decorate-D5j-d9_z.mjs.map +1 -0
  27. package/dist/di/index.d.mts +1 -1
  28. package/dist/di/index.mjs +3 -2
  29. package/dist/email/index.d.mts +3 -3
  30. package/dist/email/index.mjs +17 -11
  31. package/dist/email/index.mjs.map +1 -1
  32. package/dist/{en-C9U5-ETs.mjs → en-DaewN8hc.mjs} +3 -1
  33. package/dist/en-DaewN8hc.mjs.map +1 -0
  34. package/dist/errors/index.d.mts +1 -1
  35. package/dist/errors/index.mjs +3 -2
  36. package/dist/{errors-BRJgVd5-.mjs → errors-CtCi1wn6.mjs} +6 -3
  37. package/dist/errors-CtCi1wn6.mjs.map +1 -0
  38. package/dist/errors-H3TZnVeX.mjs +67 -0
  39. package/dist/errors-H3TZnVeX.mjs.map +1 -0
  40. package/dist/events/index.d.mts +2 -2
  41. package/dist/events/index.mjs +3 -2
  42. package/dist/{events-CQyvSyrQ.mjs → events-CXl-o1Ad.mjs} +3 -2
  43. package/dist/{events-CQyvSyrQ.mjs.map → events-CXl-o1Ad.mjs.map} +1 -1
  44. package/dist/{gateway-context-D7TFPLi5.mjs → gateway-context-BkZ4UKaX.mjs} +4 -4
  45. package/dist/{gateway-context-D7TFPLi5.mjs.map → gateway-context-BkZ4UKaX.mjs.map} +1 -1
  46. package/dist/guards/index.d.mts +3 -3
  47. package/dist/guards/index.mjs +1 -1
  48. package/dist/{guards-B5o618bL.mjs → guards-DUk_Kzst.mjs} +1 -1
  49. package/dist/{guards-B5o618bL.mjs.map → guards-DUk_Kzst.mjs.map} +1 -1
  50. package/dist/i18n/index.d.mts +2 -2
  51. package/dist/i18n/index.mjs +15 -10
  52. package/dist/i18n/messages/en/index.d.mts +1 -1
  53. package/dist/i18n/messages/en/index.mjs +1 -1
  54. package/dist/i18n/validation/index.d.mts +1 -1
  55. package/dist/i18n/validation/index.mjs +1 -1
  56. package/dist/{i18n.module-C9wQr_2k.mjs → i18n.module-W8OJxg3d.mjs} +10 -11
  57. package/dist/i18n.module-W8OJxg3d.mjs.map +1 -0
  58. package/dist/{index-C9bIk5tt.d.mts → index-BJWm863C.d.mts} +9 -6
  59. package/dist/index-BJWm863C.d.mts.map +1 -0
  60. package/dist/{index-zKURVFOC.d.mts → index-D9iYu2Yc.d.mts} +3 -3
  61. package/dist/{index-zKURVFOC.d.mts.map → index-D9iYu2Yc.d.mts.map} +1 -1
  62. package/dist/{index-Dl4RvzNp.d.mts → index-DVhdhLvE.d.mts} +2 -2
  63. package/dist/{index-Dl4RvzNp.d.mts.map → index-DVhdhLvE.d.mts.map} +1 -1
  64. package/dist/{index-BWEwA_XK.d.mts → index-D_w_Rmtd.d.mts} +3 -1
  65. package/dist/{index-BWEwA_XK.d.mts.map → index-D_w_Rmtd.d.mts.map} +1 -1
  66. package/dist/{index-3TtGtYlJ.d.mts → index-Dp6A5ywM.d.mts} +1 -1
  67. package/dist/{index-3TtGtYlJ.d.mts.map → index-Dp6A5ywM.d.mts.map} +1 -1
  68. package/dist/index.d.mts +3 -106
  69. package/dist/index.d.mts.map +1 -1
  70. package/dist/index.mjs +20 -13
  71. package/dist/is-command-BfCgWAcQ.mjs +14 -0
  72. package/dist/is-command-BfCgWAcQ.mjs.map +1 -0
  73. package/dist/is-seeder-CebjZCDn.mjs +28 -0
  74. package/dist/is-seeder-CebjZCDn.mjs.map +1 -0
  75. package/dist/logger/index.d.mts +1 -1
  76. package/dist/logger/index.mjs +2 -1
  77. package/dist/{logger-Bg-CuidS.mjs → logger-BR1-s1Um.mjs} +4 -169
  78. package/dist/logger-BR1-s1Um.mjs.map +1 -0
  79. package/dist/middleware/index.d.mts +1 -1
  80. package/dist/middleware/index.mjs +5 -4
  81. package/dist/{middleware-B3tx1u1K.mjs → middleware-C0Ebzswy.mjs} +3 -3
  82. package/dist/{middleware-B3tx1u1K.mjs.map → middleware-C0Ebzswy.mjs.map} +1 -1
  83. package/dist/module/index.d.mts +21 -3
  84. package/dist/module/index.d.mts.map +1 -1
  85. package/dist/module/index.mjs +11 -6
  86. package/dist/{module-Dvzm4dhS.mjs → module-BgdxxzBe.mjs} +44 -5
  87. package/dist/module-BgdxxzBe.mjs.map +1 -0
  88. package/dist/openapi/index.d.mts +3 -3
  89. package/dist/openapi/index.mjs +15 -10
  90. package/dist/quarry/index.d.mts +120 -0
  91. package/dist/quarry/index.d.mts.map +1 -0
  92. package/dist/quarry/index.mjs +7 -0
  93. package/dist/quarry-registry-DCwqVcRp.mjs +310 -0
  94. package/dist/quarry-registry-DCwqVcRp.mjs.map +1 -0
  95. package/dist/queue/index.d.mts +1 -1
  96. package/dist/queue/index.mjs +12 -7
  97. package/dist/queue/index.mjs.map +1 -1
  98. package/dist/{queue.module-ZqaZ2iY0.mjs → queue.module-BZvmeAMj.mjs} +4 -4
  99. package/dist/{queue.module-ZqaZ2iY0.mjs.map → queue.module-BZvmeAMj.mjs.map} +1 -1
  100. package/dist/{resend.provider-BFGt6fS4.mjs → resend.provider-BCCACQAU.mjs} +5 -4
  101. package/dist/{resend.provider-BFGt6fS4.mjs.map → resend.provider-BCCACQAU.mjs.map} +1 -1
  102. package/dist/router/index.d.mts +1 -1
  103. package/dist/router/index.mjs +15 -10
  104. package/dist/{router-context-DlTxpJUG.mjs → router-context-BEJe9HEB.mjs} +2 -2
  105. package/dist/{router-context-DlTxpJUG.mjs.map → router-context-BEJe9HEB.mjs.map} +1 -1
  106. package/dist/s3-storage.provider-BLlzQYiJ.mjs +336 -0
  107. package/dist/s3-storage.provider-BLlzQYiJ.mjs.map +1 -0
  108. package/dist/seeder/index.d.mts +77 -0
  109. package/dist/seeder/index.d.mts.map +1 -0
  110. package/dist/seeder/index.mjs +8 -0
  111. package/dist/seeder-Cupi5jl-.mjs +132 -0
  112. package/dist/seeder-Cupi5jl-.mjs.map +1 -0
  113. package/dist/{smtp.provider-BYY-AdmU.mjs → smtp.provider-B8XtOcHU.mjs} +5 -4
  114. package/dist/{smtp.provider-BYY-AdmU.mjs.map → smtp.provider-B8XtOcHU.mjs.map} +1 -1
  115. package/dist/storage/index.d.mts +6 -272
  116. package/dist/storage/index.d.mts.map +1 -1
  117. package/dist/storage/index.mjs +15 -9
  118. package/dist/{storage-dgi7MG6z.mjs → storage-By_ow2o_.mjs} +35 -411
  119. package/dist/storage-By_ow2o_.mjs.map +1 -0
  120. package/dist/{stratal-D4MS_7pI.mjs → stratal-CE0iTz4f.mjs} +44 -9
  121. package/dist/stratal-CE0iTz4f.mjs.map +1 -0
  122. package/dist/types-CLhOhYsQ.d.mts +64 -0
  123. package/dist/types-CLhOhYsQ.d.mts.map +1 -0
  124. package/dist/{types-JUIHSW_a.d.mts → types-DahElfUw.d.mts} +1 -1
  125. package/dist/types-DahElfUw.d.mts.map +1 -0
  126. package/dist/usage-generator-C9hWziY4.mjs +158 -0
  127. package/dist/usage-generator-C9hWziY4.mjs.map +1 -0
  128. package/dist/{validation-DA5nptIp.mjs → validation-Bh875Lyg.mjs} +1 -1
  129. package/dist/{validation-DA5nptIp.mjs.map → validation-Bh875Lyg.mjs.map} +1 -1
  130. package/dist/websocket/index.d.mts +2 -2
  131. package/dist/websocket/index.mjs +5 -4
  132. package/dist/workers/index.d.mts +1 -1
  133. package/dist/workers/index.mjs +20 -13
  134. package/dist/workers/index.mjs.map +1 -1
  135. package/package.json +17 -7
  136. package/dist/en-C9U5-ETs.mjs.map +0 -1
  137. package/dist/errors-BRJgVd5-.mjs.map +0 -1
  138. package/dist/i18n.module-C9wQr_2k.mjs.map +0 -1
  139. package/dist/index-C9bIk5tt.d.mts.map +0 -1
  140. package/dist/logger-Bg-CuidS.mjs.map +0 -1
  141. package/dist/module-Dvzm4dhS.mjs.map +0 -1
  142. package/dist/storage-dgi7MG6z.mjs.map +0 -1
  143. package/dist/stratal-D4MS_7pI.mjs.map +0 -1
  144. package/dist/types-JUIHSW_a.d.mts.map +0 -1
@@ -1,13 +1,19 @@
1
- import { S as ApplicationError, b as ERROR_CODES } from "../errors-BRJgVd5-.mjs";
2
- import { a as __decorate, d as Transient, o as __decorateParam, s as __decorateMetadata, u as LOGGER_TOKENS } from "../logger-Bg-CuidS.mjs";
3
- import { r as Module } from "../module-Dvzm4dhS.mjs";
4
- import "../events-CQyvSyrQ.mjs";
5
- import "../middleware-B3tx1u1K.mjs";
6
- import "../router-context-DlTxpJUG.mjs";
7
- import { a as withI18n, i as z } from "../validation-DA5nptIp.mjs";
8
- import { c as QUEUE_TOKENS } from "../queue.module-ZqaZ2iY0.mjs";
1
+ import { S as ApplicationError, b as ERROR_CODES } from "../errors-CtCi1wn6.mjs";
2
+ import { i as Transient, n as __decorateParam, r as __decorateMetadata, t as __decorate } from "../decorate-D5j-d9_z.mjs";
3
+ import { s as LOGGER_TOKENS } from "../logger-BR1-s1Um.mjs";
4
+ import { r as Module } from "../module-BgdxxzBe.mjs";
5
+ import "../events-CXl-o1Ad.mjs";
6
+ import "../colors-DJaRDXoS.mjs";
7
+ import "../command-BvCOD6df.mjs";
8
+ import "../is-command-BfCgWAcQ.mjs";
9
+ import "../is-seeder-CebjZCDn.mjs";
10
+ import "../middleware-C0Ebzswy.mjs";
11
+ import "../router-context-BEJe9HEB.mjs";
12
+ import { a as withI18n, i as z } from "../validation-Bh875Lyg.mjs";
13
+ import { c as QUEUE_TOKENS } from "../queue.module-BZvmeAMj.mjs";
9
14
  import "../queue/index.mjs";
10
- import { l as STORAGE_TOKENS } from "../storage-dgi7MG6z.mjs";
15
+ import "../errors-H3TZnVeX.mjs";
16
+ import { l as STORAGE_TOKENS } from "../storage-By_ow2o_.mjs";
11
17
  import { inject } from "tsyringe";
12
18
  import { render } from "@react-email/render";
13
19
  //#region src/email/email.tokens.ts
@@ -258,11 +264,11 @@ let EmailProviderFactory = class EmailProviderFactory {
258
264
  async create() {
259
265
  switch (this.options.provider) {
260
266
  case "resend": {
261
- const { ResendProvider } = await import("../resend.provider-BFGt6fS4.mjs");
267
+ const { ResendProvider } = await import("../resend.provider-BCCACQAU.mjs");
262
268
  return new ResendProvider(this.options);
263
269
  }
264
270
  case "smtp": {
265
- const { SmtpProvider } = await import("../smtp.provider-BYY-AdmU.mjs");
271
+ const { SmtpProvider } = await import("../smtp.provider-B8XtOcHU.mjs");
266
272
  return new SmtpProvider(this.options);
267
273
  }
268
274
  default: throw new EmailProviderNotSupportedError(this.options.provider);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/email/email.tokens.ts","../../src/email/consumers/email.consumer.ts","../../src/email/services/email.service.ts","../../src/email/errors/resend-api-key-missing.error.ts","../../src/email/errors/smtp-configuration-missing.error.ts","../../src/email/errors/smtp-host-missing.error.ts","../../src/email/errors/email-smtp-connection-failed.error.ts","../../src/email/errors/email-resend-api-failed.error.ts","../../src/email/errors/email-provider-not-supported.error.ts","../../src/email/services/email-provider-factory.ts","../../src/email/email.module.ts","../../src/email/contracts/email-attachment.ts","../../src/email/contracts/email-message.contract.ts","../../src/email/contracts/send-email.input.ts"],"sourcesContent":["/**\n * Dependency Injection Tokens for Email Module\n *\n * These Symbol-based tokens ensure type-safe dependency injection\n * throughout the email module and prevent naming collisions.\n */\n\n/**\n * Email Module DI Tokens\n */\nexport const EMAIL_TOKENS = {\n /**\n * Email module configuration options\n */\n Options: Symbol.for('stratal:email:options'),\n\n /**\n * Main email service - facade for sending emails via queues\n */\n EmailService: Symbol.for('stratal:email:service'),\n\n /**\n * Factory for creating email provider instances based on configuration\n */\n EmailProviderFactory: Symbol.for('stratal:email:provider:factory'),\n\n /**\n * Email provider interface - abstracts provider implementation\n */\n EmailProvider: Symbol.for('stratal:email:provider'),\n\n /**\n * Queue sender for email dispatch.\n * Bound via EmailModule.forRoot({ queue: 'queue-name' })\n */\n EmailQueue: Symbol.for('stratal:email:queue'),\n} as const\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger'\nimport type { IQueueConsumer, QueueMessage } from '../../queue/queue-consumer'\nimport { STORAGE_TOKENS, type StorageService } from '../../storage'\nimport type { EmailAttachment, ResolvedEmailAttachment, SendEmailInput } from '../contracts'\nimport { EMAIL_TOKENS } from '../email.tokens'\nimport type { EmailProviderFactory } from '../services/email-provider-factory'\n\n/**\n * Email Consumer\n *\n * Generic queue consumer that handles email.send and email.batch.send messages\n * from ANY queue. Message routing is based on message type, not queue name.\n *\n * This consumer:\n * - Resolves storage-based attachments to streams\n * - Creates email provider instances via factory\n * - Sends emails with proper logging (no PII)\n * - Handles errors with retry support\n *\n * @example\n * ```typescript\n * // Registered in EmailModule\n * @Module({\n * consumers: [EmailConsumer]\n * })\n * ```\n */\n@Transient()\nexport class EmailConsumer implements IQueueConsumer<SendEmailInput> {\n readonly messageTypes = ['email.send', 'email.batch.send']\n\n constructor(\n @inject(LOGGER_TOKENS.LoggerService)\n private readonly logger: LoggerService,\n @inject(EMAIL_TOKENS.EmailProviderFactory)\n private readonly providerFactory: EmailProviderFactory,\n @inject(STORAGE_TOKENS.StorageService)\n private readonly storage: StorageService\n ) { }\n\n async handle(message: QueueMessage<SendEmailInput>): Promise<void> {\n const { type, payload } = message\n const recipientCount = Array.isArray(payload.to) ? payload.to.length : 1\n\n this.logger.info('Processing email message', {\n type,\n recipientCount,\n hasHtml: !!payload.html,\n hasText: !!payload.text,\n hasAttachments: !!payload.attachments?.length,\n })\n\n try {\n // Resolve storage-based attachments before sending\n const resolvedAttachments = await this.resolveAttachments(payload.attachments)\n\n const provider = await this.providerFactory.create()\n const result = await provider.send({\n ...payload,\n attachments: resolvedAttachments,\n })\n\n this.logger.info('Email sent successfully', {\n type,\n recipientCount,\n messageId: result.messageId,\n })\n }\n catch (error) {\n this.logger.error('Failed to send email', {\n type,\n recipientCount,\n error: (error as Error).message,\n })\n throw error // Retry via queue\n }\n }\n\n onError(error: Error, message: QueueMessage<SendEmailInput>): Promise<void> {\n const recipientCount = Array.isArray(message.payload.to)\n ? message.payload.to.length\n : 1\n\n this.logger.error('Email send failed after retries', {\n recipientCount,\n error: error.message,\n stack: error.stack,\n })\n\n return Promise.resolve()\n }\n\n /**\n * Resolve email attachments\n *\n * Converts attachment schemas to resolved attachments.\n * - Inline attachments: decode base64 to Buffer\n * - Storage attachments: pass stream directly (providers support streams)\n */\n private async resolveAttachments(\n attachments: EmailAttachment[] | undefined\n ): Promise<ResolvedEmailAttachment[] | undefined> {\n if (!attachments?.length) return undefined\n\n return Promise.all(attachments.map(async (attachment) => {\n // Check for inline attachment (has content property)\n if ('content' in attachment) {\n return {\n filename: attachment.filename,\n content: Buffer.from(attachment.content, 'base64'),\n contentType: attachment.contentType,\n }\n }\n\n // Storage attachment - pass stream directly to provider\n const result = await this.storage.download(\n attachment.storageKey,\n attachment.disk\n )\n\n return {\n filename: attachment.filename,\n content: result.toStream() ?? Buffer.alloc(0),\n contentType: result.contentType,\n }\n }))\n }\n}\n","import { render } from '@react-email/render'\nimport type { ReactElement } from 'react'\nimport { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport type { IQueueSender } from '../../queue'\nimport type { SendBatchEmailInput, SendEmailInput } from '../contracts'\nimport { EMAIL_TOKENS } from '../email.tokens'\n\nexport type SendEmailInputWithTemplate = Omit<SendEmailInput, 'html' | 'text'> & {\n template?: ReactElement\n}\n\nexport type SendBatchEmailInputWithTemplate = Omit<SendBatchEmailInput, 'messages'> & {\n messages: SendEmailInputWithTemplate[]\n}\n\n/**\n * Email Service\n *\n * Main facade for sending emails. Routes emails to queues for async processing.\n * The queue is injected via EMAIL_TOKENS.EmailQueue, configured by the application\n * via EmailModule.forRoot({ queue: 'queue-name' }).\n *\n * @example Basic usage\n * ```typescript\n * @inject(EMAIL_TOKENS.EmailService)\n * private readonly emailService: EmailService\n *\n * await this.emailService.send({\n * to: 'user@example.com',\n * subject: 'Welcome',\n * template: <WelcomeEmail name=\"John\" />\n * })\n * ```\n */\n@Transient(EMAIL_TOKENS.EmailService)\nexport class EmailService {\n constructor(\n @inject(EMAIL_TOKENS.EmailQueue)\n protected readonly queue: IQueueSender\n ) { }\n\n /**\n * Send a single email\n *\n * Dispatches the email to the queue for async processing.\n * Supports optional React template rendering.\n *\n * @param input - Email message details\n */\n async send({ template, ...input }: SendEmailInputWithTemplate): Promise<void> {\n await this.queue.dispatch({\n type: 'email.send',\n payload: { ...input, html: template ? await render(template) : undefined },\n })\n }\n\n /**\n * Send multiple emails in a batch\n *\n * Dispatches all emails to the queue for async processing.\n * Supports React template rendering for each message.\n *\n * @param input - Batch email details\n */\n async sendBatch(input: SendBatchEmailInputWithTemplate): Promise<void> {\n for (const message of input.messages) {\n await this.send(message)\n }\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * ResendApiKeyMissingError\n *\n * Thrown when the Resend API key is not configured in environment variables.\n * This prevents the Resend email provider from initializing.\n *\n * Resolution: Set the RESEND_EMAIL_API_KEY environment variable.\n */\nexport class ResendApiKeyMissingError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.resendApiKeyMissing',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * SmtpConfigurationMissingError\n *\n * Thrown when SMTP configuration is not found in environment variables.\n * This prevents the SMTP email provider from initializing.\n *\n * Resolution: Set the SMTP_URL environment variable with format: smtp://user:pass@host:port\n */\nexport class SmtpConfigurationMissingError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.smtpConfigurationMissing',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * SmtpHostMissingError\n *\n * Thrown when SMTP host could not be parsed from SMTP_URL or is empty.\n * This prevents the SMTP email provider from initializing.\n *\n * Resolution: Ensure SMTP_URL is correctly formatted: smtp://user:pass@host:port\n */\nexport class SmtpHostMissingError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.smtpHostMissing',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * EmailSmtpConnectionFailedError\n *\n * Thrown when connection to SMTP server fails during email sending.\n * This is a runtime error that may be temporary.\n *\n * Resolution: Check SMTP server availability, network connectivity, or wait and retry.\n */\nexport class EmailSmtpConnectionFailedError extends ApplicationError {\n constructor(smtpHost: string, smtpPort: number) {\n super(\n 'errors.email.smtpConnectionFailed',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR,\n { smtpHost, smtpPort }\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * EmailResendApiFailedError\n *\n * Thrown when Resend API returns an error during email sending.\n * This is a runtime error from the Resend service.\n *\n * Resolution: Check Resend API status, API key validity, or wait and retry.\n */\nexport class EmailResendApiFailedError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.resendApiFailed',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR,\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * EmailProviderNotSupportedError\n *\n * Thrown when an unsupported email provider is configured.\n * Only 'resend' and 'smtp' providers are currently supported.\n *\n * Resolution: Set EMAIL_PROVIDER to either 'resend' or 'smtp'.\n */\nexport class EmailProviderNotSupportedError extends ApplicationError {\n constructor(provider: string) {\n super(\n 'errors.email.providerNotSupported',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR,\n { provider }\n )\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport type { EmailModuleOptions } from '../email.module'\nimport { EMAIL_TOKENS } from '../email.tokens'\nimport { EmailProviderNotSupportedError } from '../errors'\nimport type { IEmailProvider } from '../providers/email-provider.interface'\n\n/**\n * Email Provider Factory\n *\n * Creates email provider instances based on configuration.\n * Supports automatic provider selection from module options.\n *\n * Providers are loaded lazily via dynamic imports to avoid pulling in\n * heavy Node.js-only dependencies (e.g. nodemailer) at module parse time,\n * which would break Cloudflare Workers and vitest-pool-workers environments.\n */\n@Transient(EMAIL_TOKENS.EmailProviderFactory)\nexport class EmailProviderFactory {\n constructor(\n @inject(EMAIL_TOKENS.Options)\n private readonly options: EmailModuleOptions\n ) { }\n\n /**\n * Create email provider instance based on configuration\n *\n * @returns Email provider implementation\n * @throws EmailProviderNotSupportedError if provider is not supported\n */\n async create(): Promise<IEmailProvider> {\n switch (this.options.provider) {\n case 'resend': {\n const { ResendProvider } = await import('../providers/resend.provider')\n return new ResendProvider(this.options)\n }\n\n case 'smtp': {\n const { SmtpProvider } = await import('../providers/smtp.provider')\n return new SmtpProvider(this.options)\n }\n\n default:\n throw new EmailProviderNotSupportedError(this.options.provider)\n }\n }\n}\n","/**\n * Email Module\n *\n * Provides email sending capabilities with provider abstraction.\n * Supports multiple email providers (Resend, SMTP) with automatic provider selection.\n * Emails are sent asynchronously via Cloudflare Queues.\n *\n * **Usage:**\n * ```typescript\n * // In AppModule imports with static options\n * EmailModule.forRoot({\n * provider: 'resend',\n * apiKey: 'your-api-key',\n * from: { name: 'App', email: 'noreply@example.com' },\n * queue: 'notifications-queue',\n * })\n *\n * // Or with async options from config namespaces\n * EmailModule.forRootAsync({\n * inject: [emailConfig.KEY],\n * useFactory: (email) => ({\n * provider: email.provider,\n * apiKey: email.apiKey,\n * from: email.from,\n * queue: email.queue,\n * }),\n * })\n *\n * // In your service\n * @inject(EMAIL_TOKENS.EmailService)\n * private readonly emailService: EmailService\n *\n * await this.emailService.send({\n * to: 'user@example.com',\n * subject: 'Welcome',\n * template: <WelcomeEmail name=\"John\" />\n * })\n * ```\n */\n\nimport { Module } from '../module'\nimport type { AsyncModuleOptions, DynamicModule } from '../module/types'\nimport type { QueueName } from '../queue'\nimport { QUEUE_TOKENS, QueueRegistry } from '../queue'\nimport { EmailConsumer } from './consumers/email.consumer'\nimport { EMAIL_TOKENS } from './email.tokens'\nimport { EmailProviderFactory, EmailService } from './services'\n\n/**\n * SMTP configuration options\n */\nexport interface SmtpConfig {\n /** SMTP server host */\n host: string\n /** SMTP server port */\n port: number\n /** Use TLS */\n secure?: boolean\n /** SMTP username */\n username?: string\n /** SMTP password */\n password?: string\n}\n\n/**\n * Email module configuration options\n */\nexport interface EmailModuleOptions {\n /** Email provider type */\n provider: 'resend' | 'smtp'\n\n /** Default from address */\n from: { name: string; email: string }\n\n /** Resend API key (required for resend provider) */\n apiKey?: string\n\n /** SMTP configuration (required for smtp provider) */\n smtp?: SmtpConfig\n\n /** Default reply-to address */\n replyTo?: string\n\n /**\n * Queue name for email dispatch.\n * The queue must be registered via QueueModule.registerQueue(name).\n */\n queue: QueueName\n}\n\n@Module({\n providers: [\n { provide: EMAIL_TOKENS.EmailService, useClass: EmailService },\n { provide: EMAIL_TOKENS.EmailProviderFactory, useClass: EmailProviderFactory },\n ],\n consumers: [EmailConsumer],\n})\nexport class EmailModule {\n /**\n * Configure EmailModule with static options\n *\n * @param options - Email configuration options\n * @returns Dynamic module with email infrastructure\n *\n * @example\n * ```typescript\n * EmailModule.forRoot({\n * provider: 'resend',\n * apiKey: env.RESEND_API_KEY,\n * from: { name: 'App', email: 'noreply@example.com' },\n * queue: 'notifications-queue',\n * })\n * ```\n */\n static forRoot(options: EmailModuleOptions): DynamicModule {\n return {\n module: EmailModule,\n providers: [\n { provide: EMAIL_TOKENS.Options, useValue: options },\n { provide: EMAIL_TOKENS.EmailQueue, useExisting: options.queue },\n ],\n }\n }\n\n /**\n * Configure EmailModule with async factory\n *\n * Use when configuration depends on other services.\n *\n * @param options - Async configuration with factory and inject tokens\n * @returns Dynamic module with email infrastructure\n *\n * @example\n * ```typescript\n * EmailModule.forRootAsync({\n * inject: [emailConfig.KEY],\n * useFactory: (email) => ({\n * provider: email.provider,\n * apiKey: email.apiKey,\n * from: email.from,\n * smtp: email.smtp,\n * queue: email.queue,\n * })\n * })\n * ```\n */\n static forRootAsync(options: AsyncModuleOptions<EmailModuleOptions>): DynamicModule {\n return {\n module: EmailModule,\n providers: [\n {\n provide: EMAIL_TOKENS.Options,\n useFactory: options.useFactory,\n inject: options.inject,\n },\n // Resolve queue from QueueRegistry using the queue name from options\n {\n provide: EMAIL_TOKENS.EmailQueue,\n useFactory: (emailOptions: EmailModuleOptions, registry: QueueRegistry) =>\n registry.getQueue(emailOptions.queue),\n inject: [EMAIL_TOKENS.Options, QUEUE_TOKENS.QueueRegistry],\n },\n ],\n }\n }\n}\n","import { z } from '../../i18n/validation'\n\n/**\n * Inline Email Attachment Schema\n *\n * Attachment with content embedded as base64 string.\n * Use for small files that can fit in queue message.\n */\nexport const inlineEmailAttachmentSchema = z.object({\n /**\n * Filename to display for the attachment\n */\n filename: z.string().min(1).max(255),\n\n /**\n * Base64 encoded content of the attachment\n */\n content: z.string(),\n\n /**\n * MIME type of the attachment (e.g., 'application/pdf', 'image/png')\n */\n contentType: z.string(),\n\n /**\n * Optional size of the attachment in bytes\n */\n size: z.number().positive().optional(),\n})\n\n/**\n * Storage Email Attachment Schema\n *\n * Attachment stored in cloud storage.\n * Content type and size are derived from storage metadata.\n * Use for large files to avoid queue message size limits.\n */\nexport const storageEmailAttachmentSchema = z.object({\n /**\n * Filename to display for the attachment\n */\n filename: z.string().min(1).max(255),\n\n /**\n * Path to the file in storage\n */\n storageKey: z.string(),\n\n /**\n * Optional storage disk name (uses default if not provided)\n */\n disk: z.string().optional(),\n})\n\n/**\n * Email Attachment Schema\n *\n * Union type - type is inferred from presence of `content` vs `storageKey`.\n * - If `content` is present: inline attachment\n * - If `storageKey` is present: storage-based attachment\n */\nexport const emailAttachmentSchema = z.union([\n inlineEmailAttachmentSchema,\n storageEmailAttachmentSchema,\n])\n\n/**\n * Type definitions\n */\nexport type InlineEmailAttachment = z.infer<typeof inlineEmailAttachmentSchema>\nexport type StorageEmailAttachment = z.infer<typeof storageEmailAttachmentSchema>\nexport type EmailAttachment = z.infer<typeof emailAttachmentSchema>\n\n/**\n * Resolved Email Attachment\n *\n * Attachment after resolution, ready for email provider.\n * Content can be Buffer (for inline) or ReadableStream (for storage-based).\n * Both nodemailer and Resend support these formats directly.\n */\nexport interface ResolvedEmailAttachment {\n filename: string\n content: Buffer | ReadableStream\n contentType: string\n}\n","import { withI18n, z } from '../../i18n/validation'\nimport { emailAttachmentSchema, type ResolvedEmailAttachment } from './email-attachment'\n\n/**\n * Email Address Schema\n *\n * Represents an email address with optional name\n */\nexport const emailAddressSchema = z.object({\n name: z.string().optional(),\n email: z.string().email(),\n})\n\n/**\n * Base Email Message Schema\n *\n * Defines the core structure for email messages.\n * Ensures either html or text content is provided.\n */\nexport const emailMessageSchema = z\n .object({\n /**\n * Recipient email address(es)\n * Can be a single email string or array of emails\n */\n to: z.union([z.string().email(), z.array(z.string().email())]),\n\n /**\n * Sender email address with optional name\n * Falls back to default from config if not provided\n */\n from: emailAddressSchema.optional(),\n\n /**\n * Email subject line\n */\n subject: z.string().min(1).max(500),\n\n /**\n * HTML content of the email\n * Either html or text must be provided\n */\n html: z.string().optional(),\n\n /**\n * Plain text content of the email\n * Either html or text must be provided\n */\n text: z.string().optional(),\n\n /**\n * Reply-to email address\n */\n replyTo: z.string().email().optional(),\n\n /**\n * CC recipients\n */\n cc: z.array(z.string().email()).optional(),\n\n /**\n * BCC recipients\n */\n bcc: z.array(z.string().email()).optional(),\n\n /**\n * Email attachments\n */\n attachments: z.array(emailAttachmentSchema).optional(),\n })\n .refine(\n (data) => data.html ?? data.text,\n withI18n('zodI18n.errors.custom.emailOrTextRequired')\n )\n\n/**\n * Type definition for email message\n */\nexport type EmailMessage = z.infer<typeof emailMessageSchema>\n\n/**\n * Type definition for email address\n */\nexport type EmailAddress = z.infer<typeof emailAddressSchema>\n\n/**\n * Resolved Email Message\n *\n * Email message with attachments resolved to Buffer content.\n * Used by providers after the consumer resolves storage-based attachments.\n */\nexport type ResolvedEmailMessage = Omit<EmailMessage, 'attachments'> & {\n attachments?: ResolvedEmailAttachment[]\n}\n","import { z } from '../../i18n/validation'\nimport { emailMessageSchema } from './email-message.contract'\n\n/**\n * Send Email Input Schema\n *\n * Input schema for sending emails through the EmailService.\n * Extends the base email message with optional metadata.\n * Uses safeExtend() because emailMessageSchema contains refinements.\n */\nexport const sendEmailInputSchema = emailMessageSchema.safeExtend({\n /**\n * Optional metadata to include with the email\n * Can be used for tracking, categorization, etc.\n */\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n\n/**\n * Type definition for send email input\n */\nexport type SendEmailInput = z.infer<typeof sendEmailInputSchema>\n\n/**\n * Send Batch Email Input Schema\n *\n * Schema for sending multiple emails in a batch\n */\nexport const sendBatchEmailInputSchema = z.object({\n /**\n * Array of email messages to send\n */\n messages: z.array(sendEmailInputSchema).min(1).max(100),\n})\n\n/**\n * Type definition for send batch email input\n */\nexport type SendBatchEmailInput = z.infer<typeof sendBatchEmailInputSchema>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAUA,MAAa,eAAe;CAI1B,SAAS,OAAO,IAAI,wBAAwB;CAK5C,cAAc,OAAO,IAAI,wBAAwB;CAKjD,sBAAsB,OAAO,IAAI,iCAAiC;CAKlE,eAAe,OAAO,IAAI,yBAAyB;CAMnD,YAAY,OAAO,IAAI,sBAAsB;CAC9C;;;ACNM,IAAA,gBAAA,MAAM,cAAwD;CACnE,eAAwB,CAAC,cAAc,mBAAmB;CAE1D,YACE,QAEA,iBAEA,SAEA;AALiB,OAAA,SAAA;AAEA,OAAA,kBAAA;AAEA,OAAA,UAAA;;CAGnB,MAAM,OAAO,SAAsD;EACjE,MAAM,EAAE,MAAM,YAAY;EAC1B,MAAM,iBAAiB,MAAM,QAAQ,QAAQ,GAAG,GAAG,QAAQ,GAAG,SAAS;AAEvE,OAAK,OAAO,KAAK,4BAA4B;GAC3C;GACA;GACA,SAAS,CAAC,CAAC,QAAQ;GACnB,SAAS,CAAC,CAAC,QAAQ;GACnB,gBAAgB,CAAC,CAAC,QAAQ,aAAa;GACxC,CAAC;AAEF,MAAI;GAEF,MAAM,sBAAsB,MAAM,KAAK,mBAAmB,QAAQ,YAAY;GAG9E,MAAM,SAAS,OADE,MAAM,KAAK,gBAAgB,QAAQ,EACtB,KAAK;IACjC,GAAG;IACH,aAAa;IACd,CAAC;AAEF,QAAK,OAAO,KAAK,2BAA2B;IAC1C;IACA;IACA,WAAW,OAAO;IACnB,CAAC;WAEG,OAAO;AACZ,QAAK,OAAO,MAAM,wBAAwB;IACxC;IACA;IACA,OAAQ,MAAgB;IACzB,CAAC;AACF,SAAM;;;CAIV,QAAQ,OAAc,SAAsD;EAC1E,MAAM,iBAAiB,MAAM,QAAQ,QAAQ,QAAQ,GAAG,GACpD,QAAQ,QAAQ,GAAG,SACnB;AAEJ,OAAK,OAAO,MAAM,mCAAmC;GACnD;GACA,OAAO,MAAM;GACb,OAAO,MAAM;GACd,CAAC;AAEF,SAAO,QAAQ,SAAS;;;;;;;;;CAU1B,MAAc,mBACZ,aACgD;AAChD,MAAI,CAAC,aAAa,OAAQ,QAAO,KAAA;AAEjC,SAAO,QAAQ,IAAI,YAAY,IAAI,OAAO,eAAe;AAEvD,OAAI,aAAa,WACf,QAAO;IACL,UAAU,WAAW;IACrB,SAAS,OAAO,KAAK,WAAW,SAAS,SAAS;IAClD,aAAa,WAAW;IACzB;GAIH,MAAM,SAAS,MAAM,KAAK,QAAQ,SAChC,WAAW,YACX,WAAW,KACZ;AAED,UAAO;IACL,UAAU,WAAW;IACrB,SAAS,OAAO,UAAU,IAAI,OAAO,MAAM,EAAE;IAC7C,aAAa,OAAO;IACrB;IACD,CAAC;;;;CAlGN,WAAW;oBAKP,OAAO,cAAc,cAAc,CAAA;oBAEnC,OAAO,aAAa,qBAAqB,CAAA;oBAEzC,OAAO,eAAe,eAAe,CAAA;;;;;;;;;ACFnC,IAAA,eAAA,MAAM,aAAa;CACxB,YACE,OAEA;AADmB,OAAA,QAAA;;;;;;;;;;CAWrB,MAAM,KAAK,EAAE,UAAU,GAAG,SAAoD;AAC5E,QAAM,KAAK,MAAM,SAAS;GACxB,MAAM;GACN,SAAS;IAAE,GAAG;IAAO,MAAM,WAAW,MAAM,OAAO,SAAS,GAAG,KAAA;IAAW;GAC3E,CAAC;;;;;;;;;;CAWJ,MAAM,UAAU,OAAuD;AACrE,OAAK,MAAM,WAAW,MAAM,SAC1B,OAAM,KAAK,KAAK,QAAQ;;;;CAhC7B,UAAU,aAAa,aAAa;oBAGhC,OAAO,aAAa,WAAW,CAAA;;;;;;;;;;;;;AC5BpC,IAAa,2BAAb,cAA8C,iBAAiB;CAC7D,cAAc;AACZ,QACE,oCACA,YAAY,OAAO,oBACpB;;;;;;;;;;;;;ACLL,IAAa,gCAAb,cAAmD,iBAAiB;CAClE,cAAc;AACZ,QACE,yCACA,YAAY,OAAO,oBACpB;;;;;;;;;;;;;ACLL,IAAa,uBAAb,cAA0C,iBAAiB;CACzD,cAAc;AACZ,QACE,gCACA,YAAY,OAAO,oBACpB;;;;;;;;;;;;;ACLL,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YAAY,UAAkB,UAAkB;AAC9C,QACE,qCACA,YAAY,OAAO,sBACnB;GAAE;GAAU;GAAU,CACvB;;;;;;;;;;;;;ACNL,IAAa,4BAAb,cAA+C,iBAAiB;CAC9D,cAAc;AACZ,QACE,gCACA,YAAY,OAAO,qBACpB;;;;;;;;;;;;;ACLL,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YAAY,UAAkB;AAC5B,QACE,qCACA,YAAY,OAAO,qBACnB,EAAE,UAAU,CACb;;;;;ACEE,IAAA,uBAAA,MAAM,qBAAqB;CAChC,YACE,SAEA;AADiB,OAAA,UAAA;;;;;;;;CASnB,MAAM,SAAkC;AACtC,UAAQ,KAAK,QAAQ,UAArB;GACE,KAAK,UAAU;IACb,MAAM,EAAE,mBAAmB,MAAM,OAAO;AACxC,WAAO,IAAI,eAAe,KAAK,QAAQ;;GAGzC,KAAK,QAAQ;IACX,MAAM,EAAE,iBAAiB,MAAM,OAAO;AACtC,WAAO,IAAI,aAAa,KAAK,QAAQ;;GAGvC,QACE,OAAM,IAAI,+BAA+B,KAAK,QAAQ,SAAS;;;;;CA1BtE,UAAU,aAAa,qBAAqB;oBAGxC,OAAO,aAAa,QAAQ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC6E1B,IAAA,cAAA,eAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;CAiBvB,OAAO,QAAQ,SAA4C;AACzD,SAAO;GACL,QAAA;GACA,WAAW,CACT;IAAE,SAAS,aAAa;IAAS,UAAU;IAAS,EACpD;IAAE,SAAS,aAAa;IAAY,aAAa,QAAQ;IAAO,CACjE;GACF;;;;;;;;;;;;;;;;;;;;;;;;CAyBH,OAAO,aAAa,SAAgE;AAClF,SAAO;GACL,QAAA;GACA,WAAW,CACT;IACE,SAAS,aAAa;IACtB,YAAY,QAAQ;IACpB,QAAQ,QAAQ;IACjB,EAED;IACE,SAAS,aAAa;IACtB,aAAa,cAAkC,aAC7C,SAAS,SAAS,aAAa,MAAM;IACvC,QAAQ,CAAC,aAAa,SAAS,aAAa,cAAc;IAC3D,CACF;GACF;;;yCAzEJ,OAAO;CACN,WAAW,CACT;EAAE,SAAS,aAAa;EAAc,UAAU;EAAc,EAC9D;EAAE,SAAS,aAAa;EAAsB,UAAU;EAAsB,CAC/E;CACD,WAAW,CAAC,cAAc;CAC3B,CAAC,CAAA,EAAA,YAAA;;;;;;;;;ACxFF,MAAa,8BAA8B,EAAE,OAAO;CAIlD,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAKpC,SAAS,EAAE,QAAQ;CAKnB,aAAa,EAAE,QAAQ;CAKvB,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU;CACvC,CAAC;;;;;;;;AASF,MAAa,+BAA+B,EAAE,OAAO;CAInD,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAKpC,YAAY,EAAE,QAAQ;CAKtB,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC5B,CAAC;;;;;;;;AASF,MAAa,wBAAwB,EAAE,MAAM,CAC3C,6BACA,6BACD,CAAC;;;;;;;;ACxDF,MAAa,qBAAqB,EAAE,OAAO;CACzC,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,OAAO,EAAE,QAAQ,CAAC,OAAO;CAC1B,CAAC;;;;;;;AAQF,MAAa,qBAAqB,EAC/B,OAAO;CAKN,IAAI,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;CAM9D,MAAM,mBAAmB,UAAU;CAKnC,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAMnC,MAAM,EAAE,QAAQ,CAAC,UAAU;CAM3B,MAAM,EAAE,QAAQ,CAAC,UAAU;CAK3B,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU;CAKtC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU;CAK1C,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU;CAK3C,aAAa,EAAE,MAAM,sBAAsB,CAAC,UAAU;CACvD,CAAC,CACD,QACE,SAAS,KAAK,QAAQ,KAAK,MAC5B,SAAS,4CAA4C,CACtD;;;;;;;;;;AC/DH,MAAa,uBAAuB,mBAAmB,WAAW,EAKhE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU,EACvD,CAAC;;;;;;AAYF,MAAa,4BAA4B,EAAE,OAAO,EAIhD,UAAU,EAAE,MAAM,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,EACxD,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/email/email.tokens.ts","../../src/email/consumers/email.consumer.ts","../../src/email/services/email.service.ts","../../src/email/errors/resend-api-key-missing.error.ts","../../src/email/errors/smtp-configuration-missing.error.ts","../../src/email/errors/smtp-host-missing.error.ts","../../src/email/errors/email-smtp-connection-failed.error.ts","../../src/email/errors/email-resend-api-failed.error.ts","../../src/email/errors/email-provider-not-supported.error.ts","../../src/email/services/email-provider-factory.ts","../../src/email/email.module.ts","../../src/email/contracts/email-attachment.ts","../../src/email/contracts/email-message.contract.ts","../../src/email/contracts/send-email.input.ts"],"sourcesContent":["/**\n * Dependency Injection Tokens for Email Module\n *\n * These Symbol-based tokens ensure type-safe dependency injection\n * throughout the email module and prevent naming collisions.\n */\n\n/**\n * Email Module DI Tokens\n */\nexport const EMAIL_TOKENS = {\n /**\n * Email module configuration options\n */\n Options: Symbol.for('stratal:email:options'),\n\n /**\n * Main email service - facade for sending emails via queues\n */\n EmailService: Symbol.for('stratal:email:service'),\n\n /**\n * Factory for creating email provider instances based on configuration\n */\n EmailProviderFactory: Symbol.for('stratal:email:provider:factory'),\n\n /**\n * Email provider interface - abstracts provider implementation\n */\n EmailProvider: Symbol.for('stratal:email:provider'),\n\n /**\n * Queue sender for email dispatch.\n * Bound via EmailModule.forRoot({ queue: 'queue-name' })\n */\n EmailQueue: Symbol.for('stratal:email:queue'),\n} as const\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger'\nimport type { IQueueConsumer, QueueMessage } from '../../queue/queue-consumer'\nimport { STORAGE_TOKENS, type StorageService } from '../../storage'\nimport type { EmailAttachment, ResolvedEmailAttachment, SendEmailInput } from '../contracts'\nimport { EMAIL_TOKENS } from '../email.tokens'\nimport type { EmailProviderFactory } from '../services/email-provider-factory'\n\n/**\n * Email Consumer\n *\n * Generic queue consumer that handles email.send and email.batch.send messages\n * from ANY queue. Message routing is based on message type, not queue name.\n *\n * This consumer:\n * - Resolves storage-based attachments to streams\n * - Creates email provider instances via factory\n * - Sends emails with proper logging (no PII)\n * - Handles errors with retry support\n *\n * @example\n * ```typescript\n * // Registered in EmailModule\n * @Module({\n * consumers: [EmailConsumer]\n * })\n * ```\n */\n@Transient()\nexport class EmailConsumer implements IQueueConsumer<SendEmailInput> {\n readonly messageTypes = ['email.send', 'email.batch.send']\n\n constructor(\n @inject(LOGGER_TOKENS.LoggerService)\n private readonly logger: LoggerService,\n @inject(EMAIL_TOKENS.EmailProviderFactory)\n private readonly providerFactory: EmailProviderFactory,\n @inject(STORAGE_TOKENS.StorageService)\n private readonly storage: StorageService\n ) { }\n\n async handle(message: QueueMessage<SendEmailInput>): Promise<void> {\n const { type, payload } = message\n const recipientCount = Array.isArray(payload.to) ? payload.to.length : 1\n\n this.logger.info('Processing email message', {\n type,\n recipientCount,\n hasHtml: !!payload.html,\n hasText: !!payload.text,\n hasAttachments: !!payload.attachments?.length,\n })\n\n try {\n // Resolve storage-based attachments before sending\n const resolvedAttachments = await this.resolveAttachments(payload.attachments)\n\n const provider = await this.providerFactory.create()\n const result = await provider.send({\n ...payload,\n attachments: resolvedAttachments,\n })\n\n this.logger.info('Email sent successfully', {\n type,\n recipientCount,\n messageId: result.messageId,\n })\n }\n catch (error) {\n this.logger.error('Failed to send email', {\n type,\n recipientCount,\n error: (error as Error).message,\n })\n throw error // Retry via queue\n }\n }\n\n onError(error: Error, message: QueueMessage<SendEmailInput>): Promise<void> {\n const recipientCount = Array.isArray(message.payload.to)\n ? message.payload.to.length\n : 1\n\n this.logger.error('Email send failed after retries', {\n recipientCount,\n error: error.message,\n stack: error.stack,\n })\n\n return Promise.resolve()\n }\n\n /**\n * Resolve email attachments\n *\n * Converts attachment schemas to resolved attachments.\n * - Inline attachments: decode base64 to Buffer\n * - Storage attachments: pass stream directly (providers support streams)\n */\n private async resolveAttachments(\n attachments: EmailAttachment[] | undefined\n ): Promise<ResolvedEmailAttachment[] | undefined> {\n if (!attachments?.length) return undefined\n\n return Promise.all(attachments.map(async (attachment) => {\n // Check for inline attachment (has content property)\n if ('content' in attachment) {\n return {\n filename: attachment.filename,\n content: Buffer.from(attachment.content, 'base64'),\n contentType: attachment.contentType,\n }\n }\n\n // Storage attachment - pass stream directly to provider\n const result = await this.storage.download(\n attachment.storageKey,\n attachment.disk\n )\n\n return {\n filename: attachment.filename,\n content: result.toStream() ?? Buffer.alloc(0),\n contentType: result.contentType,\n }\n }))\n }\n}\n","import { render } from '@react-email/render'\nimport type { ReactElement } from 'react'\nimport { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport type { IQueueSender } from '../../queue'\nimport type { SendBatchEmailInput, SendEmailInput } from '../contracts'\nimport { EMAIL_TOKENS } from '../email.tokens'\n\nexport type SendEmailInputWithTemplate = Omit<SendEmailInput, 'html' | 'text'> & {\n template?: ReactElement\n}\n\nexport type SendBatchEmailInputWithTemplate = Omit<SendBatchEmailInput, 'messages'> & {\n messages: SendEmailInputWithTemplate[]\n}\n\n/**\n * Email Service\n *\n * Main facade for sending emails. Routes emails to queues for async processing.\n * The queue is injected via EMAIL_TOKENS.EmailQueue, configured by the application\n * via EmailModule.forRoot({ queue: 'queue-name' }).\n *\n * @example Basic usage\n * ```typescript\n * @inject(EMAIL_TOKENS.EmailService)\n * private readonly emailService: EmailService\n *\n * await this.emailService.send({\n * to: 'user@example.com',\n * subject: 'Welcome',\n * template: <WelcomeEmail name=\"John\" />\n * })\n * ```\n */\n@Transient(EMAIL_TOKENS.EmailService)\nexport class EmailService {\n constructor(\n @inject(EMAIL_TOKENS.EmailQueue)\n protected readonly queue: IQueueSender\n ) { }\n\n /**\n * Send a single email\n *\n * Dispatches the email to the queue for async processing.\n * Supports optional React template rendering.\n *\n * @param input - Email message details\n */\n async send({ template, ...input }: SendEmailInputWithTemplate): Promise<void> {\n await this.queue.dispatch({\n type: 'email.send',\n payload: { ...input, html: template ? await render(template) : undefined },\n })\n }\n\n /**\n * Send multiple emails in a batch\n *\n * Dispatches all emails to the queue for async processing.\n * Supports React template rendering for each message.\n *\n * @param input - Batch email details\n */\n async sendBatch(input: SendBatchEmailInputWithTemplate): Promise<void> {\n for (const message of input.messages) {\n await this.send(message)\n }\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * ResendApiKeyMissingError\n *\n * Thrown when the Resend API key is not configured in environment variables.\n * This prevents the Resend email provider from initializing.\n *\n * Resolution: Set the RESEND_EMAIL_API_KEY environment variable.\n */\nexport class ResendApiKeyMissingError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.resendApiKeyMissing',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * SmtpConfigurationMissingError\n *\n * Thrown when SMTP configuration is not found in environment variables.\n * This prevents the SMTP email provider from initializing.\n *\n * Resolution: Set the SMTP_URL environment variable with format: smtp://user:pass@host:port\n */\nexport class SmtpConfigurationMissingError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.smtpConfigurationMissing',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * SmtpHostMissingError\n *\n * Thrown when SMTP host could not be parsed from SMTP_URL or is empty.\n * This prevents the SMTP email provider from initializing.\n *\n * Resolution: Ensure SMTP_URL is correctly formatted: smtp://user:pass@host:port\n */\nexport class SmtpHostMissingError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.smtpHostMissing',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * EmailSmtpConnectionFailedError\n *\n * Thrown when connection to SMTP server fails during email sending.\n * This is a runtime error that may be temporary.\n *\n * Resolution: Check SMTP server availability, network connectivity, or wait and retry.\n */\nexport class EmailSmtpConnectionFailedError extends ApplicationError {\n constructor(smtpHost: string, smtpPort: number) {\n super(\n 'errors.email.smtpConnectionFailed',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR,\n { smtpHost, smtpPort }\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * EmailResendApiFailedError\n *\n * Thrown when Resend API returns an error during email sending.\n * This is a runtime error from the Resend service.\n *\n * Resolution: Check Resend API status, API key validity, or wait and retry.\n */\nexport class EmailResendApiFailedError extends ApplicationError {\n constructor() {\n super(\n 'errors.email.resendApiFailed',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR,\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * EmailProviderNotSupportedError\n *\n * Thrown when an unsupported email provider is configured.\n * Only 'resend' and 'smtp' providers are currently supported.\n *\n * Resolution: Set EMAIL_PROVIDER to either 'resend' or 'smtp'.\n */\nexport class EmailProviderNotSupportedError extends ApplicationError {\n constructor(provider: string) {\n super(\n 'errors.email.providerNotSupported',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR,\n { provider }\n )\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport type { EmailModuleOptions } from '../email.module'\nimport { EMAIL_TOKENS } from '../email.tokens'\nimport { EmailProviderNotSupportedError } from '../errors'\nimport type { IEmailProvider } from '../providers/email-provider.interface'\n\n/**\n * Email Provider Factory\n *\n * Creates email provider instances based on configuration.\n * Supports automatic provider selection from module options.\n *\n * Providers are loaded lazily via dynamic imports to avoid pulling in\n * heavy Node.js-only dependencies (e.g. nodemailer) at module parse time,\n * which would break Cloudflare Workers and vitest-pool-workers environments.\n */\n@Transient(EMAIL_TOKENS.EmailProviderFactory)\nexport class EmailProviderFactory {\n constructor(\n @inject(EMAIL_TOKENS.Options)\n private readonly options: EmailModuleOptions\n ) { }\n\n /**\n * Create email provider instance based on configuration\n *\n * @returns Email provider implementation\n * @throws EmailProviderNotSupportedError if provider is not supported\n */\n async create(): Promise<IEmailProvider> {\n switch (this.options.provider) {\n case 'resend': {\n const { ResendProvider } = await import('../providers/resend.provider')\n return new ResendProvider(this.options)\n }\n\n case 'smtp': {\n const { SmtpProvider } = await import('../providers/smtp.provider')\n return new SmtpProvider(this.options)\n }\n\n default:\n throw new EmailProviderNotSupportedError(this.options.provider)\n }\n }\n}\n","/**\n * Email Module\n *\n * Provides email sending capabilities with provider abstraction.\n * Supports multiple email providers (Resend, SMTP) with automatic provider selection.\n * Emails are sent asynchronously via Cloudflare Queues.\n *\n * **Usage:**\n * ```typescript\n * // In AppModule imports with static options\n * EmailModule.forRoot({\n * provider: 'resend',\n * apiKey: 'your-api-key',\n * from: { name: 'App', email: 'noreply@example.com' },\n * queue: 'notifications-queue',\n * })\n *\n * // Or with async options from config namespaces\n * EmailModule.forRootAsync({\n * inject: [emailConfig.KEY],\n * useFactory: (email) => ({\n * provider: email.provider,\n * apiKey: email.apiKey,\n * from: email.from,\n * queue: email.queue,\n * }),\n * })\n *\n * // In your service\n * @inject(EMAIL_TOKENS.EmailService)\n * private readonly emailService: EmailService\n *\n * await this.emailService.send({\n * to: 'user@example.com',\n * subject: 'Welcome',\n * template: <WelcomeEmail name=\"John\" />\n * })\n * ```\n */\n\nimport { Module } from '../module'\nimport type { AsyncModuleOptions, DynamicModule } from '../module/types'\nimport type { QueueName } from '../queue'\nimport { QUEUE_TOKENS, QueueRegistry } from '../queue'\nimport { EmailConsumer } from './consumers/email.consumer'\nimport { EMAIL_TOKENS } from './email.tokens'\nimport { EmailProviderFactory, EmailService } from './services'\n\n/**\n * SMTP configuration options\n */\nexport interface SmtpConfig {\n /** SMTP server host */\n host: string\n /** SMTP server port */\n port: number\n /** Use TLS */\n secure?: boolean\n /** SMTP username */\n username?: string\n /** SMTP password */\n password?: string\n}\n\n/**\n * Email module configuration options\n */\nexport interface EmailModuleOptions {\n /** Email provider type */\n provider: 'resend' | 'smtp'\n\n /** Default from address */\n from: { name: string; email: string }\n\n /** Resend API key (required for resend provider) */\n apiKey?: string\n\n /** SMTP configuration (required for smtp provider) */\n smtp?: SmtpConfig\n\n /** Default reply-to address */\n replyTo?: string\n\n /**\n * Queue name for email dispatch.\n * The queue must be registered via QueueModule.registerQueue(name).\n */\n queue: QueueName\n}\n\n@Module({\n providers: [\n { provide: EMAIL_TOKENS.EmailService, useClass: EmailService },\n { provide: EMAIL_TOKENS.EmailProviderFactory, useClass: EmailProviderFactory },\n ],\n consumers: [EmailConsumer],\n})\nexport class EmailModule {\n /**\n * Configure EmailModule with static options\n *\n * @param options - Email configuration options\n * @returns Dynamic module with email infrastructure\n *\n * @example\n * ```typescript\n * EmailModule.forRoot({\n * provider: 'resend',\n * apiKey: env.RESEND_API_KEY,\n * from: { name: 'App', email: 'noreply@example.com' },\n * queue: 'notifications-queue',\n * })\n * ```\n */\n static forRoot(options: EmailModuleOptions): DynamicModule {\n return {\n module: EmailModule,\n providers: [\n { provide: EMAIL_TOKENS.Options, useValue: options },\n { provide: EMAIL_TOKENS.EmailQueue, useExisting: options.queue },\n ],\n }\n }\n\n /**\n * Configure EmailModule with async factory\n *\n * Use when configuration depends on other services.\n *\n * @param options - Async configuration with factory and inject tokens\n * @returns Dynamic module with email infrastructure\n *\n * @example\n * ```typescript\n * EmailModule.forRootAsync({\n * inject: [emailConfig.KEY],\n * useFactory: (email) => ({\n * provider: email.provider,\n * apiKey: email.apiKey,\n * from: email.from,\n * smtp: email.smtp,\n * queue: email.queue,\n * })\n * })\n * ```\n */\n static forRootAsync(options: AsyncModuleOptions<EmailModuleOptions>): DynamicModule {\n return {\n module: EmailModule,\n providers: [\n {\n provide: EMAIL_TOKENS.Options,\n useFactory: options.useFactory,\n inject: options.inject,\n },\n // Resolve queue from QueueRegistry using the queue name from options\n {\n provide: EMAIL_TOKENS.EmailQueue,\n useFactory: (emailOptions: EmailModuleOptions, registry: QueueRegistry) =>\n registry.getQueue(emailOptions.queue),\n inject: [EMAIL_TOKENS.Options, QUEUE_TOKENS.QueueRegistry],\n },\n ],\n }\n }\n}\n","import { z } from '../../i18n/validation'\n\n/**\n * Inline Email Attachment Schema\n *\n * Attachment with content embedded as base64 string.\n * Use for small files that can fit in queue message.\n */\nexport const inlineEmailAttachmentSchema = z.object({\n /**\n * Filename to display for the attachment\n */\n filename: z.string().min(1).max(255),\n\n /**\n * Base64 encoded content of the attachment\n */\n content: z.string(),\n\n /**\n * MIME type of the attachment (e.g., 'application/pdf', 'image/png')\n */\n contentType: z.string(),\n\n /**\n * Optional size of the attachment in bytes\n */\n size: z.number().positive().optional(),\n})\n\n/**\n * Storage Email Attachment Schema\n *\n * Attachment stored in cloud storage.\n * Content type and size are derived from storage metadata.\n * Use for large files to avoid queue message size limits.\n */\nexport const storageEmailAttachmentSchema = z.object({\n /**\n * Filename to display for the attachment\n */\n filename: z.string().min(1).max(255),\n\n /**\n * Path to the file in storage\n */\n storageKey: z.string(),\n\n /**\n * Optional storage disk name (uses default if not provided)\n */\n disk: z.string().optional(),\n})\n\n/**\n * Email Attachment Schema\n *\n * Union type - type is inferred from presence of `content` vs `storageKey`.\n * - If `content` is present: inline attachment\n * - If `storageKey` is present: storage-based attachment\n */\nexport const emailAttachmentSchema = z.union([\n inlineEmailAttachmentSchema,\n storageEmailAttachmentSchema,\n])\n\n/**\n * Type definitions\n */\nexport type InlineEmailAttachment = z.infer<typeof inlineEmailAttachmentSchema>\nexport type StorageEmailAttachment = z.infer<typeof storageEmailAttachmentSchema>\nexport type EmailAttachment = z.infer<typeof emailAttachmentSchema>\n\n/**\n * Resolved Email Attachment\n *\n * Attachment after resolution, ready for email provider.\n * Content can be Buffer (for inline) or ReadableStream (for storage-based).\n * Both nodemailer and Resend support these formats directly.\n */\nexport interface ResolvedEmailAttachment {\n filename: string\n content: Buffer | ReadableStream\n contentType: string\n}\n","import { withI18n, z } from '../../i18n/validation'\nimport { emailAttachmentSchema, type ResolvedEmailAttachment } from './email-attachment'\n\n/**\n * Email Address Schema\n *\n * Represents an email address with optional name\n */\nexport const emailAddressSchema = z.object({\n name: z.string().optional(),\n email: z.string().email(),\n})\n\n/**\n * Base Email Message Schema\n *\n * Defines the core structure for email messages.\n * Ensures either html or text content is provided.\n */\nexport const emailMessageSchema = z\n .object({\n /**\n * Recipient email address(es)\n * Can be a single email string or array of emails\n */\n to: z.union([z.string().email(), z.array(z.string().email())]),\n\n /**\n * Sender email address with optional name\n * Falls back to default from config if not provided\n */\n from: emailAddressSchema.optional(),\n\n /**\n * Email subject line\n */\n subject: z.string().min(1).max(500),\n\n /**\n * HTML content of the email\n * Either html or text must be provided\n */\n html: z.string().optional(),\n\n /**\n * Plain text content of the email\n * Either html or text must be provided\n */\n text: z.string().optional(),\n\n /**\n * Reply-to email address\n */\n replyTo: z.string().email().optional(),\n\n /**\n * CC recipients\n */\n cc: z.array(z.string().email()).optional(),\n\n /**\n * BCC recipients\n */\n bcc: z.array(z.string().email()).optional(),\n\n /**\n * Email attachments\n */\n attachments: z.array(emailAttachmentSchema).optional(),\n })\n .refine(\n (data) => data.html ?? data.text,\n withI18n('zodI18n.errors.custom.emailOrTextRequired')\n )\n\n/**\n * Type definition for email message\n */\nexport type EmailMessage = z.infer<typeof emailMessageSchema>\n\n/**\n * Type definition for email address\n */\nexport type EmailAddress = z.infer<typeof emailAddressSchema>\n\n/**\n * Resolved Email Message\n *\n * Email message with attachments resolved to Buffer content.\n * Used by providers after the consumer resolves storage-based attachments.\n */\nexport type ResolvedEmailMessage = Omit<EmailMessage, 'attachments'> & {\n attachments?: ResolvedEmailAttachment[]\n}\n","import { z } from '../../i18n/validation'\nimport { emailMessageSchema } from './email-message.contract'\n\n/**\n * Send Email Input Schema\n *\n * Input schema for sending emails through the EmailService.\n * Extends the base email message with optional metadata.\n * Uses safeExtend() because emailMessageSchema contains refinements.\n */\nexport const sendEmailInputSchema = emailMessageSchema.safeExtend({\n /**\n * Optional metadata to include with the email\n * Can be used for tracking, categorization, etc.\n */\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n\n/**\n * Type definition for send email input\n */\nexport type SendEmailInput = z.infer<typeof sendEmailInputSchema>\n\n/**\n * Send Batch Email Input Schema\n *\n * Schema for sending multiple emails in a batch\n */\nexport const sendBatchEmailInputSchema = z.object({\n /**\n * Array of email messages to send\n */\n messages: z.array(sendEmailInputSchema).min(1).max(100),\n})\n\n/**\n * Type definition for send batch email input\n */\nexport type SendBatchEmailInput = z.infer<typeof sendBatchEmailInputSchema>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,MAAa,eAAe;CAI1B,SAAS,OAAO,IAAI,wBAAwB;CAK5C,cAAc,OAAO,IAAI,wBAAwB;CAKjD,sBAAsB,OAAO,IAAI,iCAAiC;CAKlE,eAAe,OAAO,IAAI,yBAAyB;CAMnD,YAAY,OAAO,IAAI,sBAAsB;CAC9C;;;ACNM,IAAA,gBAAA,MAAM,cAAwD;CACnE,eAAwB,CAAC,cAAc,mBAAmB;CAE1D,YACE,QAEA,iBAEA,SAEA;AALiB,OAAA,SAAA;AAEA,OAAA,kBAAA;AAEA,OAAA,UAAA;;CAGnB,MAAM,OAAO,SAAsD;EACjE,MAAM,EAAE,MAAM,YAAY;EAC1B,MAAM,iBAAiB,MAAM,QAAQ,QAAQ,GAAG,GAAG,QAAQ,GAAG,SAAS;AAEvE,OAAK,OAAO,KAAK,4BAA4B;GAC3C;GACA;GACA,SAAS,CAAC,CAAC,QAAQ;GACnB,SAAS,CAAC,CAAC,QAAQ;GACnB,gBAAgB,CAAC,CAAC,QAAQ,aAAa;GACxC,CAAC;AAEF,MAAI;GAEF,MAAM,sBAAsB,MAAM,KAAK,mBAAmB,QAAQ,YAAY;GAG9E,MAAM,SAAS,OADE,MAAM,KAAK,gBAAgB,QAAQ,EACtB,KAAK;IACjC,GAAG;IACH,aAAa;IACd,CAAC;AAEF,QAAK,OAAO,KAAK,2BAA2B;IAC1C;IACA;IACA,WAAW,OAAO;IACnB,CAAC;WAEG,OAAO;AACZ,QAAK,OAAO,MAAM,wBAAwB;IACxC;IACA;IACA,OAAQ,MAAgB;IACzB,CAAC;AACF,SAAM;;;CAIV,QAAQ,OAAc,SAAsD;EAC1E,MAAM,iBAAiB,MAAM,QAAQ,QAAQ,QAAQ,GAAG,GACpD,QAAQ,QAAQ,GAAG,SACnB;AAEJ,OAAK,OAAO,MAAM,mCAAmC;GACnD;GACA,OAAO,MAAM;GACb,OAAO,MAAM;GACd,CAAC;AAEF,SAAO,QAAQ,SAAS;;;;;;;;;CAU1B,MAAc,mBACZ,aACgD;AAChD,MAAI,CAAC,aAAa,OAAQ,QAAO,KAAA;AAEjC,SAAO,QAAQ,IAAI,YAAY,IAAI,OAAO,eAAe;AAEvD,OAAI,aAAa,WACf,QAAO;IACL,UAAU,WAAW;IACrB,SAAS,OAAO,KAAK,WAAW,SAAS,SAAS;IAClD,aAAa,WAAW;IACzB;GAIH,MAAM,SAAS,MAAM,KAAK,QAAQ,SAChC,WAAW,YACX,WAAW,KACZ;AAED,UAAO;IACL,UAAU,WAAW;IACrB,SAAS,OAAO,UAAU,IAAI,OAAO,MAAM,EAAE;IAC7C,aAAa,OAAO;IACrB;IACD,CAAC;;;;CAlGN,WAAW;oBAKP,OAAO,cAAc,cAAc,CAAA;oBAEnC,OAAO,aAAa,qBAAqB,CAAA;oBAEzC,OAAO,eAAe,eAAe,CAAA;;;;;;;;;ACFnC,IAAA,eAAA,MAAM,aAAa;CACxB,YACE,OAEA;AADmB,OAAA,QAAA;;;;;;;;;;CAWrB,MAAM,KAAK,EAAE,UAAU,GAAG,SAAoD;AAC5E,QAAM,KAAK,MAAM,SAAS;GACxB,MAAM;GACN,SAAS;IAAE,GAAG;IAAO,MAAM,WAAW,MAAM,OAAO,SAAS,GAAG,KAAA;IAAW;GAC3E,CAAC;;;;;;;;;;CAWJ,MAAM,UAAU,OAAuD;AACrE,OAAK,MAAM,WAAW,MAAM,SAC1B,OAAM,KAAK,KAAK,QAAQ;;;;CAhC7B,UAAU,aAAa,aAAa;oBAGhC,OAAO,aAAa,WAAW,CAAA;;;;;;;;;;;;;AC5BpC,IAAa,2BAAb,cAA8C,iBAAiB;CAC7D,cAAc;AACZ,QACE,oCACA,YAAY,OAAO,oBACpB;;;;;;;;;;;;;ACLL,IAAa,gCAAb,cAAmD,iBAAiB;CAClE,cAAc;AACZ,QACE,yCACA,YAAY,OAAO,oBACpB;;;;;;;;;;;;;ACLL,IAAa,uBAAb,cAA0C,iBAAiB;CACzD,cAAc;AACZ,QACE,gCACA,YAAY,OAAO,oBACpB;;;;;;;;;;;;;ACLL,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YAAY,UAAkB,UAAkB;AAC9C,QACE,qCACA,YAAY,OAAO,sBACnB;GAAE;GAAU;GAAU,CACvB;;;;;;;;;;;;;ACNL,IAAa,4BAAb,cAA+C,iBAAiB;CAC9D,cAAc;AACZ,QACE,gCACA,YAAY,OAAO,qBACpB;;;;;;;;;;;;;ACLL,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YAAY,UAAkB;AAC5B,QACE,qCACA,YAAY,OAAO,qBACnB,EAAE,UAAU,CACb;;;;;ACEE,IAAA,uBAAA,MAAM,qBAAqB;CAChC,YACE,SAEA;AADiB,OAAA,UAAA;;;;;;;;CASnB,MAAM,SAAkC;AACtC,UAAQ,KAAK,QAAQ,UAArB;GACE,KAAK,UAAU;IACb,MAAM,EAAE,mBAAmB,MAAM,OAAO;AACxC,WAAO,IAAI,eAAe,KAAK,QAAQ;;GAGzC,KAAK,QAAQ;IACX,MAAM,EAAE,iBAAiB,MAAM,OAAO;AACtC,WAAO,IAAI,aAAa,KAAK,QAAQ;;GAGvC,QACE,OAAM,IAAI,+BAA+B,KAAK,QAAQ,SAAS;;;;;CA1BtE,UAAU,aAAa,qBAAqB;oBAGxC,OAAO,aAAa,QAAQ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC6E1B,IAAA,cAAA,eAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;CAiBvB,OAAO,QAAQ,SAA4C;AACzD,SAAO;GACL,QAAA;GACA,WAAW,CACT;IAAE,SAAS,aAAa;IAAS,UAAU;IAAS,EACpD;IAAE,SAAS,aAAa;IAAY,aAAa,QAAQ;IAAO,CACjE;GACF;;;;;;;;;;;;;;;;;;;;;;;;CAyBH,OAAO,aAAa,SAAgE;AAClF,SAAO;GACL,QAAA;GACA,WAAW,CACT;IACE,SAAS,aAAa;IACtB,YAAY,QAAQ;IACpB,QAAQ,QAAQ;IACjB,EAED;IACE,SAAS,aAAa;IACtB,aAAa,cAAkC,aAC7C,SAAS,SAAS,aAAa,MAAM;IACvC,QAAQ,CAAC,aAAa,SAAS,aAAa,cAAc;IAC3D,CACF;GACF;;;yCAzEJ,OAAO;CACN,WAAW,CACT;EAAE,SAAS,aAAa;EAAc,UAAU;EAAc,EAC9D;EAAE,SAAS,aAAa;EAAsB,UAAU;EAAsB,CAC/E;CACD,WAAW,CAAC,cAAc;CAC3B,CAAC,CAAA,EAAA,YAAA;;;;;;;;;ACxFF,MAAa,8BAA8B,EAAE,OAAO;CAIlD,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAKpC,SAAS,EAAE,QAAQ;CAKnB,aAAa,EAAE,QAAQ;CAKvB,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU;CACvC,CAAC;;;;;;;;AASF,MAAa,+BAA+B,EAAE,OAAO;CAInD,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAKpC,YAAY,EAAE,QAAQ;CAKtB,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC5B,CAAC;;;;;;;;AASF,MAAa,wBAAwB,EAAE,MAAM,CAC3C,6BACA,6BACD,CAAC;;;;;;;;ACxDF,MAAa,qBAAqB,EAAE,OAAO;CACzC,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,OAAO,EAAE,QAAQ,CAAC,OAAO;CAC1B,CAAC;;;;;;;AAQF,MAAa,qBAAqB,EAC/B,OAAO;CAKN,IAAI,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;CAM9D,MAAM,mBAAmB,UAAU;CAKnC,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAMnC,MAAM,EAAE,QAAQ,CAAC,UAAU;CAM3B,MAAM,EAAE,QAAQ,CAAC,UAAU;CAK3B,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU;CAKtC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU;CAK1C,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU;CAK3C,aAAa,EAAE,MAAM,sBAAsB,CAAC,UAAU;CACvD,CAAC,CACD,QACE,SAAS,KAAK,QAAQ,KAAK,MAC5B,SAAS,4CAA4C,CACtD;;;;;;;;;;AC/DH,MAAa,uBAAuB,mBAAmB,WAAW,EAKhE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU,EACvD,CAAC;;;;;;AAYF,MAAa,4BAA4B,EAAE,OAAO,EAIhD,UAAU,EAAE,MAAM,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,EACxD,CAAC"}
@@ -123,6 +123,8 @@ const errors = {
123
123
  emailCannotBeUpdated: "Email address cannot be updated at this time",
124
124
  tokenExpired: "The verification token has expired. Please request a new verification email."
125
125
  },
126
+ seederNameCollision: "Seeder name collision: \"{name}\" is already registered. Use distinct class names for each seeder.",
127
+ seederNotRegistered: "Seeder \"{name}\" is not registered",
126
128
  migration: {
127
129
  failed: "Migration {migrationName} failed: {error}",
128
130
  checksumMismatch: "Migration {migrationName} checksum mismatch (expected: {expected}, actual: {actual})",
@@ -314,4 +316,4 @@ var en_exports = /* @__PURE__ */ __exportAll({
314
316
  //#endregion
315
317
  export { errors as a, emails as i, zodI18n as n, common as o, validation as r, en_exports as t };
316
318
 
317
- //# sourceMappingURL=en-C9U5-ETs.mjs.map
319
+ //# sourceMappingURL=en-DaewN8hc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"en-DaewN8hc.mjs","names":[],"sources":["../src/i18n/messages/en/common.ts","../src/i18n/messages/en/errors.ts","../src/i18n/messages/en/emails.ts","../src/i18n/messages/en/validation.ts","../src/i18n/messages/en/zod.ts","../src/i18n/messages/en/index.ts"],"sourcesContent":["/**\n * System Common Messages - English\n *\n * Common messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nexport const common = {\n api: {\n title: 'Stratal API',\n description: 'Platform API',\n serverDescription: 'API server',\n security: {\n bearerAuth: 'JWT Bearer token authentication',\n apiKey: 'API key for service authentication',\n sessionCookie: 'Session cookie for browser authentication'\n }\n }\n} as const\n","/**\n * System Error Messages - English\n *\n * Error messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nexport const errors = {\n // Generic errors\n internalError: 'An internal error occurred',\n notFound: 'Resource not found',\n unauthorized: 'Unauthorized. Please sign in.',\n forbidden: 'Access denied',\n\n // Router errors\n honoAppAlreadyConfigured: 'HonoApp has already been configured and can only be configured once',\n routeNotFound: 'Route not found: {method} {path}',\n routeAccessDenied: 'Resource not found',\n controllerMethodNotFound: 'Method {methodName} not found on {controllerName}',\n controllerRegistration: 'Failed to register controller {controllerName}: {reason}',\n\n // WebSocket errors\n websocketBodyNotAvailable: 'body() is not available in WebSocket gateways. Use WebSocket messages instead.',\n websocketDuplicateEventHandler: '@{decorator}() is already applied to \\'{existingMethod}\\'. Only one method per gateway can handle this event.',\n\n // Context errors\n contextNotInitialized: 'Context has not been initialized',\n userNotAuthenticated: 'User is not authenticated',\n insufficientPermissions: 'Insufficient permissions to perform this action',\n requestContainerNotInitialized: 'Request container has not been initialized',\n requestScopeOperationNotAllowed: '{methodName}() cannot be called on this container scope. Check if you are calling it on the correct container (global vs request-scoped).',\n conditionalBindingFallback: 'Conditional binding predicate returned false for token \"{token}\" but no fallback was provided and no existing registration exists.',\n\n // Configuration errors\n configNotInitialized: 'Configuration service has not been initialized',\n configModuleNotInitialized: 'ConfigModule.forRoot() was not called before module initialization',\n stratalNotInitialized: 'Stratal has not been instantiated. Ensure you export a Stratal instance as the default export.',\n\n // Module errors\n moduleAlreadyRegistered: 'Module {moduleName} is already registered',\n moduleDependencyNotFound: 'Module dependency {dependency} not found for module {moduleName}',\n moduleCircularDependency: 'Circular dependency detected: {cycle}',\n invalidModuleProvider: 'Invalid module provider configuration: {provider}',\n\n // Database errors\n databaseGeneric: 'Database error occurred',\n databaseRecordNotFound: 'Record not found in database',\n databaseUniqueConstraint: 'Record already exists',\n databaseForeignKeyConstraint: 'Related record not found',\n databaseConnectionFailed: 'Failed to connect to database',\n databaseTimeout: 'Database query timeout',\n databaseNullConstraint: 'Required field is missing',\n databaseTooManyConnections: 'Too many database connections',\n databaseTransactionConflict: 'Transaction conflict or deadlock',\n databaseConstraintFailed: 'A database constraint was violated',\n databaseTableNotFound: 'The specified table does not exist in the database',\n databaseColumnNotFound: 'The specified column does not exist in the table',\n databaseInvalidQuery: 'The database query is invalid or malformed',\n invalidErrorCodeRange: 'Invalid error code range: {code}',\n\n // Queue errors\n queueBindingNotFound: 'Queue binding {queueName} not found in environment',\n queueProviderNotSupported: 'Queue provider \"{provider}\" is not supported. Valid providers: cloudflare, sync',\n\n // Cron errors\n cronExecutionFailed: '{count} cron job(s) failed for schedule \"{schedule}\": {jobs}',\n\n // i18n errors\n localeNotSupported: \"Locale '{locale}' is not supported. Supported locales: {supportedLocales}\",\n translationMissing: \"Translation missing for key '{key}' in locale '{locale}'\",\n\n // Schema validation errors\n schemaValidation: 'Schema validation failed',\n\n // OpenAPI errors\n openapiValidation: 'OpenAPI validation failed: {details}',\n openapiRouteRegistration: 'Failed to register OpenAPI route {path}: {reason}',\n\n // Email errors\n email: {\n resendApiKeyMissing: 'Resend API key not configured. Set RESEND_EMAIL_API_KEY environment variable.',\n smtpConfigurationMissing: 'SMTP configuration missing. Set SMTP_URL environment variable.',\n smtpHostMissing: 'SMTP host not configured. Check SMTP_URL format (smtp://user:pass@host:port).',\n smtpConnectionFailed: 'Failed to connect to SMTP server {smtpHost}:{smtpPort}',\n resendApiFailed: 'Resend API error',\n providerNotSupported: 'Unsupported email provider: {provider}. Supported providers: resend, smtp'\n },\n\n // Storage errors\n storage: {\n fileNotFound: 'File at path \"{path}\" was not found',\n invalidDisk: 'Storage disk \"{disk}\" is not configured',\n invalidFileType: 'File type \"{mimeType}\" is not allowed',\n fileTooLarge: 'File size {size} exceeds maximum allowed size of {maxSize}',\n presignedUrlInvalidExpiry: 'Expiry must be between {min} and {max} seconds',\n diskNotConfigured: 'Disk \"{disk}\" is not configured',\n providerNotSupported: 'Storage provider \"{provider}\" is not supported',\n responseBodyMissing: 'No body in storage response for path: {path}'\n },\n\n // Cache errors\n cache: {\n getFailed: \"Failed to retrieve value from cache for key '{key}'\",\n putFailed: \"Failed to store value in cache for key '{key}'\",\n deleteFailed: \"Failed to delete value from cache for key '{key}'\",\n listFailed: 'Failed to list cache keys'\n },\n\n // Authentication errors\n auth: {\n tokenRequired: 'Verification token is required',\n invalidToken: 'Invalid or expired verification token',\n verificationFailed: 'Verification failed. Please try again.',\n userNotFound: 'User not found. Please check your credentials.',\n invalidCredentials: 'Invalid email or password',\n invalidPassword: 'Invalid password',\n invalidEmail: 'Invalid email address',\n sessionExpired: 'Your session has expired. Please sign in again.',\n emailNotVerified: 'Please verify your email address before signing in',\n passwordTooShort: 'Password must be at least {minLength} characters',\n passwordTooLong: 'Password must be at most {maxLength} characters',\n accountAlreadyExists: 'An account with this email already exists',\n failedToCreateUser: 'Failed to create user account. Please try again.',\n failedToCreateSession: 'Failed to create session. Please try again.',\n failedToGetSession: 'Failed to retrieve session. Please try again.',\n failedToUpdateUser: 'Failed to update user information. Please try again.',\n failedToGetUserInfo: 'Failed to retrieve user information. Please try again.',\n socialAccountLinked: 'This social account is already linked to another user',\n providerNotFound: 'Authentication provider not found',\n userEmailNotFound: 'User email address not found',\n accountNotFound: 'Account not found',\n credentialAccountNotFound: 'Credential account not found',\n cannotUnlinkLastAccount: 'Cannot unlink your last account',\n userAlreadyHasPassword: 'User already has a password set',\n emailCannotBeUpdated: 'Email address cannot be updated at this time',\n tokenExpired: 'The verification token has expired. Please request a new verification email.'\n },\n\n // Seeder errors\n seederNameCollision: 'Seeder name collision: \"{name}\" is already registered. Use distinct class names for each seeder.',\n seederNotRegistered: 'Seeder \"{name}\" is not registered',\n\n // Migration errors\n migration: {\n failed: 'Migration {migrationName} failed: {error}',\n checksumMismatch: 'Migration {migrationName} checksum mismatch (expected: {expected}, actual: {actual})',\n alreadyApplied: 'Migration {migrationName} has already been applied',\n notFound: 'Migration {migrationName} not found',\n },\n} as const\n","/**\n * System Email Messages - English\n *\n * Email-related messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nexport const emails = {\n magicLink: {\n subject: 'Your sign-in link'\n }\n} as const\n","/**\n * Form validation messages - English\n */\n\nexport const validation = {\n required: 'This field is required',\n email: 'Invalid email address',\n minLength: 'Must be at least {min} characters',\n maxLength: 'Must not exceed {max} characters',\n min: 'Must be at least {min}',\n max: 'Must not exceed {max}',\n pattern: 'Invalid format',\n numeric: 'Must be a number',\n url: 'Invalid URL',\n date: 'Invalid date',\n passwordStrength: 'Password must contain at least one uppercase letter, one lowercase letter, and one number',\n passwordMatch: 'Passwords do not match',\n unique: 'This value already exists',\n phone: 'Invalid phone number',\n fileRequired: 'Please upload a file',\n fileTooLarge: 'File must be smaller than {max}',\n invalidFileType: 'Please upload a PDF, JPG, or PNG file',\n schoolTypes: {\n required: 'School type is required',\n atLeastOne: 'Please select at least one school type',\n invalidCode: 'Invalid school type: {code}',\n notAvailableInCountry: '{schoolType} is not available in {country}',\n countryNotSupported: 'Country {country} is not supported'\n },\n timezone: {\n required: 'Timezone is required',\n invalid: 'Invalid timezone. Please select a valid IANA timezone.'\n },\n locale: {\n required: 'Language is required',\n invalid: 'Invalid language. Supported languages: {locales}'\n }\n} as const\n","/**\n * Zod validation error messages - English\n *\n * Comprehensive messages for all Zod validation error codes\n * Structured to match Zod's issue types and validation contexts\n */\n\nexport const zodI18n = {\n errors: {\n // General errors\n required: 'Required',\n invalid_type: 'Expected {expected}, received {received}',\n invalid_literal: 'Invalid literal value, expected {expected}',\n custom: {\n default: 'Invalid value',\n // Email validation\n emailOrTextRequired: 'Either html or text content must be provided',\n invalidFromEmail: 'Invalid from email address',\n // Storage validation\n fileInstanceRequired: 'File must be a File instance',\n filePathRequired: 'File path is required',\n diskNameRequired: 'Disk name is required',\n endpointRequired: 'Endpoint URL is required for S3',\n bucketNameRequired: 'Bucket name is required',\n accessKeyRequired: 'Access key ID is required',\n secretKeyRequired: 'Secret access key is required',\n storageDiskRequired: 'At least one storage disk is required',\n // Database validation\n databaseUrlRequired: 'Database URL is required',\n // Domain validation\n domainRequired: 'Domain is required',\n domainTooLong: 'Domain too long',\n invalidDomainFormat: 'Invalid domain format',\n },\n invalid_union: 'Invalid input',\n invalid_union_discriminator: 'Invalid discriminator value. Expected {options}',\n invalid_enum_value: 'Invalid enum value. Expected {options}, received {received}',\n unrecognized_keys: 'Unrecognized key(s) in object: {keys}',\n invalid_arguments: 'Invalid function arguments',\n invalid_return_type: 'Invalid function return type',\n invalid_date: 'Invalid date',\n invalid_intersection_types: 'Intersection results could not be merged',\n not_multiple_of: 'Number must be a multiple of {multipleOf}',\n not_finite: 'Number must be finite',\n\n // String-specific validation errors\n invalid_string: {\n email: 'Invalid email address',\n url: 'Invalid URL',\n uuid: 'Invalid UUID',\n cuid: 'Invalid CUID',\n cuid2: 'Invalid CUID2',\n ulid: 'Invalid ULID',\n regex: 'Invalid format',\n datetime: 'Invalid datetime',\n ip: 'Invalid IP address',\n emoji: 'Invalid emoji',\n startsWith: 'Must start with \"{startsWith}\"',\n endsWith: 'Must end with \"{endsWith}\"',\n includes: 'Must include \"{includes}\"',\n base64: 'Invalid Base64',\n nanoid: 'Invalid NanoID',\n cidr: 'Invalid CIDR',\n jwt: 'Invalid JWT',\n time: 'Invalid time',\n },\n\n // Size validation errors (strings, arrays, numbers)\n too_small: {\n string: {\n exact: 'Must be exactly {minimum} characters',\n inclusive: 'Must be at least {minimum} characters',\n not_inclusive: 'Must be more than {minimum} characters',\n },\n number: {\n exact: 'Must be exactly {minimum}',\n inclusive: 'Must be at least {minimum}',\n not_inclusive: 'Must be greater than {minimum}',\n },\n array: {\n exact: 'Must contain exactly {minimum} item(s)',\n inclusive: 'Must contain at least {minimum} item(s)',\n not_inclusive: 'Must contain more than {minimum} item(s)',\n },\n set: {\n exact: 'Must contain exactly {minimum} item(s)',\n inclusive: 'Must contain at least {minimum} item(s)',\n not_inclusive: 'Must contain more than {minimum} item(s)',\n },\n date: {\n exact: 'Date must be {minimum}',\n inclusive: 'Date must be {minimum} or later',\n not_inclusive: 'Date must be after {minimum}',\n },\n bigint: {\n exact: 'Must be exactly {minimum}',\n inclusive: 'Must be at least {minimum}',\n not_inclusive: 'Must be greater than {minimum}',\n },\n },\n\n too_big: {\n string: {\n exact: 'Must be exactly {maximum} characters',\n inclusive: 'Must be at most {maximum} characters',\n not_inclusive: 'Must be less than {maximum} characters',\n },\n number: {\n exact: 'Must be exactly {maximum}',\n inclusive: 'Must be at most {maximum}',\n not_inclusive: 'Must be less than {maximum}',\n },\n array: {\n exact: 'Must contain exactly {maximum} item(s)',\n inclusive: 'Must contain at most {maximum} item(s)',\n not_inclusive: 'Must contain less than {maximum} item(s)',\n },\n set: {\n exact: 'Must contain exactly {maximum} item(s)',\n inclusive: 'Must contain at most {maximum} item(s)',\n not_inclusive: 'Must contain less than {maximum} item(s)',\n },\n date: {\n exact: 'Date must be {maximum}',\n inclusive: 'Date must be {maximum} or earlier',\n not_inclusive: 'Date must be before {maximum}',\n },\n bigint: {\n exact: 'Must be exactly {maximum}',\n inclusive: 'Must be at most {maximum}',\n not_inclusive: 'Must be less than {maximum}',\n },\n },\n },\n} as const\n","/**\n * System Messages - English\n *\n * Re-exports all system message categories.\n * These messages are used by packages/modules infrastructure\n * and are automatically merged with application-specific messages.\n */\n\nexport { common } from './common'\nexport { errors } from './errors'\nexport { emails } from './emails'\nexport { validation } from './validation'\nexport { zodI18n } from './zod'\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { Cn as isErrorResponse, Sn as ErrorResponse, a as GlobalErrorHandler, c as ERROR_CODES, i as InternalError, l as ErrorCode, n as RequestContainerNotInitializedError, o as getHttpStatus, r as isApplicationError, s as ApplicationError, t as StratalNotInitializedError, xn as Environment } from "../index-C9bIk5tt.mjs";
1
+ import { Cn as isErrorResponse, Sn as ErrorResponse, a as GlobalErrorHandler, c as ERROR_CODES, i as InternalError, l as ErrorCode, n as RequestContainerNotInitializedError, o as getHttpStatus, r as isApplicationError, s as ApplicationError, t as StratalNotInitializedError, xn as Environment } from "../index-BJWm863C.mjs";
2
2
  export { ApplicationError, ERROR_CODES, Environment, ErrorCode, ErrorResponse, GlobalErrorHandler, InternalError, RequestContainerNotInitializedError, StratalNotInitializedError, getHttpStatus, isApplicationError, isErrorResponse };
@@ -1,3 +1,4 @@
1
- import { S as ApplicationError, a as InternalError, b as ERROR_CODES, i as isApplicationError, n as RequestContainerNotInitializedError, r as GlobalErrorHandler, t as StratalNotInitializedError, x as isErrorResponse, y as getHttpStatus } from "../errors-BRJgVd5-.mjs";
2
- import "../logger-Bg-CuidS.mjs";
1
+ import { S as ApplicationError, a as InternalError, b as ERROR_CODES, i as isApplicationError, n as RequestContainerNotInitializedError, r as GlobalErrorHandler, t as StratalNotInitializedError, x as isErrorResponse, y as getHttpStatus } from "../errors-CtCi1wn6.mjs";
2
+ import "../decorate-D5j-d9_z.mjs";
3
+ import "../logger-BR1-s1Um.mjs";
3
4
  export { ApplicationError, ERROR_CODES, GlobalErrorHandler, InternalError, RequestContainerNotInitializedError, StratalNotInitializedError, getHttpStatus, isApplicationError, isErrorResponse };
@@ -1,4 +1,5 @@
1
- import { a as __decorate, d as Transient, g as DI_TOKENS, h as CONTAINER_TOKEN, o as __decorateParam, s as __decorateMetadata, u as LOGGER_TOKENS } from "./logger-Bg-CuidS.mjs";
1
+ import { c as CONTAINER_TOKEN, i as Transient, l as DI_TOKENS, n as __decorateParam, r as __decorateMetadata, t as __decorate } from "./decorate-D5j-d9_z.mjs";
2
+ import { s as LOGGER_TOKENS } from "./logger-BR1-s1Um.mjs";
2
3
  import { Lifecycle, container as container$1, delay, inject, inject as inject$1, injectable as injectable$1, instancePerContainerCachingFactory as instancePerContainerCachingFactory$1, predicateAwareClassFactory, singleton } from "tsyringe";
3
4
  //#region src/errors/application-error.ts
4
5
  /**
@@ -215,7 +216,9 @@ const ERROR_CODES = {
215
216
  CRON_EXECUTION_FAILED: 9204,
216
217
  QUEUE_PROVIDER_NOT_SUPPORTED: 9205,
217
218
  WEBSOCKET_BODY_NOT_AVAILABLE: 9206,
218
- WEBSOCKET_DUPLICATE_EVENT_HANDLER: 9207
219
+ WEBSOCKET_DUPLICATE_EVENT_HANDLER: 9207,
220
+ SEEDER_NAME_COLLISION: 9208,
221
+ SEEDER_NOT_REGISTERED: 9209
219
222
  }
220
223
  };
221
224
  //#endregion
@@ -701,4 +704,4 @@ var StratalNotInitializedError = class extends ApplicationError {
701
704
  //#endregion
702
705
  export { ApplicationError as S, ConditionalBindingFallbackError as _, InternalError as a, ERROR_CODES as b, Container as c, inject$1 as d, injectable$1 as f, RequestScopeOperationNotAllowedError as g, ConditionalBindingBuilderImpl as h, isApplicationError as i, container$1 as l, singleton as m, RequestContainerNotInitializedError as n, I18N_TOKENS as o, instancePerContainerCachingFactory$1 as p, GlobalErrorHandler as r, Scope as s, StratalNotInitializedError as t, delay as u, ROUTER_TOKENS as v, isErrorResponse as x, getHttpStatus as y };
703
706
 
704
- //# sourceMappingURL=errors-BRJgVd5-.mjs.map
707
+ //# sourceMappingURL=errors-CtCi1wn6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-CtCi1wn6.mjs","names":[],"sources":["../src/errors/application-error.ts","../src/errors/error-response.ts","../src/errors/error-codes.ts","../src/errors/get-http-status.ts","../src/router/router.tokens.ts","../src/di/errors/conditional-binding-fallback.error.ts","../src/di/errors/request-scope-operation-not-allowed.error.ts","../src/di/conditional-binding-builder.ts","../src/di/container.ts","../src/di/types.ts","../src/i18n/i18n.tokens.ts","../src/errors/internal-error.ts","../src/errors/is-application-error.ts","../src/errors/global-error-handler.ts","../src/errors/request-container-not-initialized.error.ts","../src/errors/stratal-not-initialized.error.ts"],"sourcesContent":["import type { Environment, ErrorResponse } from './error-response'\nimport type { MessageKeys } from '../i18n'\nimport type { ErrorCode } from './error-codes'\n\n/**\n * ApplicationError\n *\n * Abstract base class for all application errors.\n * This class should never be used directly - always extend it to create specific error types.\n *\n * Features:\n * - Type-safe error codes from ERROR_CODES registry\n * - Type-safe message keys from i18n module\n * - Localized message keys (translated by GlobalErrorHandler)\n * - Structured metadata for logging and interpolation\n * - Proper Error prototype chain\n * - Automatic timestamp generation\n * - Serialization for RPC transmission\n *\n * Message Localization:\n * - Each error class passes an i18n key (e.g., 'errors.userNotFound') to super()\n * - `Error.message` contains the i18n key for useful stack traces and fallback display\n * - Metadata provides interpolation parameters (e.g., { userId: '123' })\n * - GlobalErrorHandler translates the message key using I18nService before sending response\n * - This ensures errors are localized based on the user's locale (from X-Locale header)\n */\nexport abstract class ApplicationError extends Error {\n /**\n * Controls whether stack traces are captured.\n * Set to false in production to skip the expensive Error.captureStackTrace() call,\n * since stack traces are stripped from responses in production anyway.\n */\n static captureStackTraces = true\n\n /**\n * Type-safe error code from ERROR_CODES registry\n * See error-codes.ts for the complete registry\n */\n public readonly code: ErrorCode\n\n /**\n * ISO timestamp when the error was created\n */\n public readonly timestamp: string\n\n /**\n * Additional structured data about the error\n * Used for:\n * 1. Logging and debugging\n * 2. Message interpolation (e.g., { userId: '123', email: 'user@example.com' })\n */\n public readonly metadata?: Record<string, unknown>\n\n /**\n * @param i18nKey - Type-safe i18n message key (e.g., 'errors.userNotFound')\n * @param code - Type-safe error code from ERROR_CODES registry\n * @param metadata - Optional data for logging and interpolation\n */\n constructor(\n i18nKey: MessageKeys,\n code: ErrorCode,\n metadata?: Record<string, unknown>\n ) {\n // Pass i18nKey to Error.message for useful stack traces (e.g., \"InternalError: errors.internalError\")\n super(i18nKey)\n\n // Maintains proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, new.target.prototype)\n\n this.name = this.constructor.name\n this.code = code\n this.timestamp = new Date().toISOString()\n this.metadata = metadata\n\n // Capture stack trace, excluding constructor call from it\n // Skip in production where stack traces are stripped from responses anyway\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- captureStackTrace is V8-specific, not always present\n if (ApplicationError.captureStackTraces && Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor)\n }\n }\n\n /**\n * Filter metadata to include only user-facing properties\n *\n * User-facing properties (validation/constraint errors):\n * - issues: Validation errors from SchemaValidationError\n * - fields: Constraint violation fields\n * - field: Single field constraint/foreign key\n *\n * Internal properties (excluded from response):\n * - path, method: Route debugging\n * - controllerName, reason: Controller errors\n * - details, etc.: Internal debugging info\n *\n * @param metadata - Raw metadata object\n * @returns Filtered metadata with only whitelisted properties\n */\n private static filterMetadata(\n metadata?: Record<string, unknown>\n ): Record<string, unknown> | undefined {\n if (!metadata) return undefined\n\n // Whitelist of user-facing metadata properties\n const whitelist = ['issues', 'fields', 'field']\n\n const filtered: Record<string, unknown> = {}\n let hasUserFacingData = false\n\n for (const key of whitelist) {\n if (key in metadata && metadata[key] !== undefined) {\n filtered[key] = metadata[key]\n hasUserFacingData = true\n }\n }\n\n // Only return metadata if there's actual user-facing data\n return hasUserFacingData ? filtered : undefined\n }\n\n /**\n * Serialize error to ErrorResponse format for RPC transmission\n *\n * @param env - Environment (development | production)\n * @param translatedMessage - Optional translated message (from GlobalErrorHandler)\n * @returns ErrorResponse object suitable for JSON serialization\n */\n toErrorResponse(env: Environment, translatedMessage?: string): ErrorResponse {\n const message = translatedMessage ?? this.message\n\n return {\n code: this.code,\n message,\n timestamp: this.timestamp,\n // Include filtered user-facing metadata in all environments\n metadata: ApplicationError.filterMetadata(this.metadata),\n // Stack trace only in development for debugging\n // Rewrite first line with translated message for readable debugging\n stack: env === 'development'\n ? this.stack?.replace(this.message, message)\n : undefined,\n }\n }\n\n /**\n * JSON serialization (used by JSON.stringify)\n * Defaults to development mode for backward compatibility\n * Note: This will use the untranslated message key - use GlobalErrorHandler for proper localization\n */\n toJSON(): ErrorResponse {\n return this.toErrorResponse('development')\n }\n}\n","export type Environment = 'development' | 'staging' | 'production'\n\nexport interface ErrorResponse {\n /**\n * Numeric error code for identification and escalation\n * See error-codes.ts for the complete registry\n */\n code: number\n\n /**\n * Human-readable error message\n * Fixed per error type, not customizable\n */\n message: string\n\n /**\n * ISO timestamp when the error occurred\n */\n timestamp: string\n\n /**\n * Additional structured data about the error\n * Only included in development environment\n */\n metadata?: Record<string, unknown>\n\n /**\n * Stack trace for debugging\n * Only included in development environment\n */\n stack?: string\n}\n\n/**\n * Type guard to check if an object is an ErrorResponse\n */\nexport function isErrorResponse(obj: unknown): obj is ErrorResponse {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n 'code' in obj &&\n typeof (obj as ErrorResponse).code === 'number' &&\n 'message' in obj &&\n typeof (obj as ErrorResponse).message === 'string' &&\n 'timestamp' in obj &&\n typeof (obj as ErrorResponse).timestamp === 'string'\n )\n}\n","/**\n * Centralized Error Code Registry\n *\n * Error codes are organized by category with specific ranges:\n * - 1000-1999: Validation errors\n * - 2000-2999: Database errors (generic)\n * - 3000-3999: Authentication & Authorization\n * - 4000-4999: Resource errors\n * - 5000-5999: Domain-specific business logic (per module)\n * - 9000-9999: System/Internal errors\n * - 9000-9099: Router errors\n * - 9100-9199: Configuration errors\n * - 9200-9299: Infrastructure errors\n * - 9300-9399: I18n errors\n */\n\nexport const ERROR_CODES = {\n /**\n * Database Errors (2000-2999)\n * Generic database errors thrown by Prisma client extensions\n */\n DATABASE: {\n /** Generic database error */\n GENERIC: 2000,\n /** Record not found in database */\n RECORD_NOT_FOUND: 2001,\n /** Unique constraint violation */\n UNIQUE_CONSTRAINT: 2002,\n /** Foreign key constraint violation */\n FOREIGN_KEY_CONSTRAINT: 2003,\n /** Database connection failed */\n CONNECTION_FAILED: 2004,\n /** Database timeout */\n TIMEOUT: 2005,\n /** Null constraint violation */\n NULL_CONSTRAINT: 2006,\n /** Too many database connections */\n TOO_MANY_CONNECTIONS: 2007,\n /** Transaction conflict or deadlock */\n TRANSACTION_CONFLICT: 2008,\n },\n\n /**\n * Authentication Errors (3000-3099)\n * Authentication-related failures\n */\n AUTH: {\n /** Invalid credentials provided */\n INVALID_CREDENTIALS: 3000,\n /** Session expired or invalid */\n SESSION_EXPIRED: 3001,\n /** Account locked or disabled */\n ACCOUNT_LOCKED: 3002,\n /** Invalid or expired token */\n INVALID_TOKEN: 3003,\n /** Context not initialized */\n CONTEXT_NOT_INITIALIZED: 3004,\n /** User not authenticated */\n USER_NOT_AUTHENTICATED: 3005,\n /** Email verification required before login */\n EMAIL_NOT_VERIFIED: 3007,\n /** Password doesn't meet minimum length */\n PASSWORD_TOO_SHORT: 3008,\n /** Password exceeds maximum length */\n PASSWORD_TOO_LONG: 3009,\n /** Account with email already exists */\n ACCOUNT_ALREADY_EXISTS: 3010,\n /** User creation failed */\n FAILED_TO_CREATE_USER: 3011,\n /** Session creation failed */\n FAILED_TO_CREATE_SESSION: 3012,\n /** User update failed */\n FAILED_TO_UPDATE_USER: 3013,\n /** Social account already linked */\n SOCIAL_ACCOUNT_LINKED: 3014,\n /** Last account cannot be unlinked */\n CANNOT_UNLINK_LAST_ACCOUNT: 3015,\n },\n\n /**\n * Authorization Errors (3100-3199)\n * Permission and access control failures\n */\n AUTHZ: {\n /** Insufficient permissions */\n FORBIDDEN: 3100,\n /** Resource access denied */\n ACCESS_DENIED: 3101,\n /** User lacks required role */\n INSUFFICIENT_PERMISSIONS: 3102,\n },\n\n /**\n * Resource Errors (4000-4999)\n * Generic resource-related errors\n */\n RESOURCE: {\n /** Generic resource not found */\n NOT_FOUND: 4000,\n /** Route/endpoint not found */\n ROUTE_NOT_FOUND: 4004,\n /** Resource conflict or duplicate */\n CONFLICT: 4100,\n /** Resource already exists */\n ALREADY_EXISTS: 4101,\n },\n\n /**\n * Validation Errors (1000-1999)\n * Input validation failures\n */\n VALIDATION: {\n /** Generic validation error */\n GENERIC: 1000,\n /** Required field missing */\n REQUIRED_FIELD: 1001,\n /** Invalid format */\n INVALID_FORMAT: 1002,\n /** Schema validation failed */\n SCHEMA_VALIDATION: 1003,\n /** Request validation failed (OpenAPI, etc.) */\n REQUEST_VALIDATION: 1004,\n },\n\n /**\n * Router Errors (9000-9099)\n * Router and controller-related INTERNAL errors\n */\n ROUTER: {\n /** Controller registration error */\n CONTROLLER_REGISTRATION_ERROR: 9005,\n /** Controller method not found */\n CONTROLLER_METHOD_NOT_FOUND: 9006,\n /** OpenAPI route registration failed */\n OPENAPI_ROUTE_REGISTRATION: 9008,\n },\n\n /**\n * I18n Errors (9300-9399)\n * Internationalization and localization errors\n */\n I18N: {\n /** Translation key missing from all locales */\n TRANSLATION_MISSING: 9300,\n /** Requested locale not supported */\n LOCALE_NOT_SUPPORTED: 9301,\n },\n\n /**\n * System Errors (9000-9999)\n * Internal system errors and unexpected failures\n */\n SYSTEM: {\n /** Internal server error */\n INTERNAL_ERROR: 9000,\n\n // Configuration Errors (9100-9199)\n /** Generic configuration error */\n CONFIGURATION_ERROR: 9100,\n /** ConfigService not initialized */\n CONFIG_NOT_INITIALIZED: 9101,\n /** Module already registered */\n MODULE_ALREADY_REGISTERED: 9102,\n /** Circular module dependency detected */\n MODULE_CIRCULAR_DEPENDENCY: 9103,\n /** Module dependency not found */\n MODULE_DEPENDENCY_NOT_FOUND: 9104,\n /** Invalid error code range */\n INVALID_ERROR_CODE_RANGE: 9105,\n /** Invalid module provider configuration */\n INVALID_MODULE_PROVIDER: 9106,\n /** ConfigModule.forRoot() was not called */\n CONFIG_MODULE_NOT_INITIALIZED: 9107,\n\n // Infrastructure Errors (9200-9299)\n /** Generic infrastructure error */\n INFRASTRUCTURE_ERROR: 9200,\n /** Execution context not initialized */\n EXECUTION_CONTEXT_NOT_INITIALIZED: 9201,\n /** Request container not initialized */\n REQUEST_CONTAINER_NOT_INITIALIZED: 9202,\n /** Queue binding not found */\n QUEUE_BINDING_NOT_FOUND: 9203,\n /** Cron job execution failed */\n CRON_EXECUTION_FAILED: 9204,\n /** Queue provider not supported */\n QUEUE_PROVIDER_NOT_SUPPORTED: 9205,\n /** body() called on WebSocket gateway context */\n WEBSOCKET_BODY_NOT_AVAILABLE: 9206,\n /** Duplicate WebSocket event decorator on a gateway */\n WEBSOCKET_DUPLICATE_EVENT_HANDLER: 9207,\n /** Seeder name collision — two seeders share the same class name */\n SEEDER_NAME_COLLISION: 9208,\n /** Seeder not registered in the SeederRegistry */\n SEEDER_NOT_REGISTERED: 9209,\n },\n} as const\n\n/**\n * Recursively extract all leaf values from a nested object type\n * Similar to DeepKeys but extracts values instead of keys\n *\n * Example:\n * { DATABASE: { GENERIC: 2000, NOT_FOUND: 2001 }, AUTH: { INVALID: 3000 } }\n * becomes\n * 2000 | 2001 | 3000\n */\ntype DeepValues<T> = T extends object\n ? { [K in keyof T]: DeepValues<T[K]> }[keyof T]\n : T\n\n/**\n * Type helper to extract all error code values\n * Union type of all numeric error codes defined in ERROR_CODES\n *\n * Type: 2000 | 2001 | 2002 | ... | 9203\n */\nexport type ErrorCode = DeepValues<typeof ERROR_CODES>\n","import type { ContentfulStatusCode } from 'hono/utils/http-status'\nimport { ERROR_CODES } from './error-codes'\n\n/**\n * Maps error codes to HTTP status codes\n *\n * This utility is used by the frontend to set appropriate HTTP status codes\n * when returning errors from API routes.\n *\n * @param code - Numeric error code from ERROR_CODES registry\n * @returns HTTP status code (200-599)\n */\nexport function getHttpStatus(code: number): ContentfulStatusCode {\n // Validation errors (1000-1999) → 400 Bad Request\n if (code >= 1000 && code < 2000) {\n return 400\n }\n\n // Database errors (2000-2999)\n if (code >= 2000 && code < 3000) {\n // Record not found → 404\n if (code === ERROR_CODES.DATABASE.RECORD_NOT_FOUND) return 404\n // Unique constraint / conflict → 409\n if (code === ERROR_CODES.DATABASE.UNIQUE_CONSTRAINT) return 409\n // Other database errors → 500\n return 500\n }\n\n // Authentication errors (3000-3099) → 401 Unauthorized\n if (code >= 3000 && code < 3100) {\n return 401\n }\n\n // Authorization errors (3100-3199) → 403 Forbidden\n if (code >= 3100 && code < 3200) {\n return 403\n }\n\n // Resource not found (4000-4099) → 404 Not Found\n if (code >= 4000 && code < 4100) {\n return 404\n }\n\n // Resource conflict (4100-4199) → 409 Conflict\n if (code >= 4100 && code < 4200) {\n return 409\n }\n\n // Business logic errors (5000-5999)\n if (code >= 5000 && code < 6000) {\n // Domain-specific NOT_FOUND errors → 404\n // 5000: NOTES.NOT_FOUND\n // 5100: USERS.NOT_FOUND\n // 5200: APPLICATIONS.NOT_FOUND\n if (code === 5000 || code === 5100 || code === 5200) {\n return 404\n }\n // Other business logic errors → 422 Unprocessable Entity\n return 422\n }\n\n // System errors (9000-9999) → 500 Internal Server Error\n if (code >= 9000) {\n return 500\n }\n\n // Default to 500 for unknown codes\n return 500\n}\n","/**\n * Dependency injection tokens for the router system\n */\nexport const ROUTER_TOKENS = {\n /**\n * Token for RouterContext (request-scoped)\n * Contains Hono context wrapper with helper methods\n */\n RouterContext: Symbol.for('stratal:router:context'),\n} as const\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * ConditionalBindingFallbackError\n *\n * Thrown when a conditional binding predicate returns false but no fallback\n * implementation was provided and no existing registration exists for the token.\n *\n * This typically indicates a misconfiguration in the DI setup where:\n * - A `when().use().give()` chain was used without `otherwise()`\n * - AND the token wasn't previously registered\n * - AND the predicate evaluated to false at resolution time\n */\nexport class ConditionalBindingFallbackError extends ApplicationError {\n constructor(token: string) {\n super(\n 'errors.conditionalBindingFallback',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR,\n { token }\n )\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * RequestScopeOperationNotAllowedError\n *\n * Thrown when attempting to call a method that is not allowed on the current container scope.\n * - `createRequestScope()` and `runInRequestScope()` can only be called on global containers\n */\nexport class RequestScopeOperationNotAllowedError extends ApplicationError {\n constructor(methodName: string) {\n super(\n 'errors.requestScopeOperationNotAllowed',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR,\n { methodName }\n )\n }\n}\n","/**\n * Conditional Binding Builder\n *\n * Provides a fluent API for predicate-based service registration.\n * The predicate is evaluated lazily at resolution time using tsyringe's\n * predicateAwareClassFactory.\n *\n * @example With explicit fallback\n * ```typescript\n * container\n * .when((c) => c.resolve(CONFIG_TOKEN).get('env') === 'development')\n * .use(FORMATTER_TOKEN)\n * .give(PrettyFormatter)\n * .otherwise(JsonFormatter)\n * ```\n *\n * @example Without fallback (uses existing registration)\n * ```typescript\n * container\n * .when((c) => c.resolve(FEATURE_FLAG_TOKEN).isEnabled('newFeature'))\n * .use(SERVICE_TOKEN)\n * .give(NewServiceImpl) // Falls back to existing if predicate is false\n * ```\n */\n\nimport type { DependencyContainer } from 'tsyringe'\nimport { predicateAwareClassFactory } from 'tsyringe'\nimport type InjectionToken from 'tsyringe/dist/typings/providers/injection-token'\nimport type { Constructor } from '../types'\nimport { ConditionalBindingFallbackError } from './errors'\nimport type { WhenOptions } from './types'\n\n/**\n * Container interface for predicate functions\n * Using a minimal interface to avoid circular imports\n */\nexport interface PredicateContainer {\n resolve<T>(token: InjectionToken<T>): T\n isRegistered<T>(token: InjectionToken<T>): boolean\n}\n\n/**\n * Initial builder returned by container.when()\n */\nexport interface ConditionalBindingBuilder {\n /**\n * Specify the token to conditionally bind\n *\n * @param token - DI token for the service\n * @returns Builder for specifying implementations\n */\n use<T extends object>(token: InjectionToken<T>): ConditionalBindingUse<T>\n}\n\n/**\n * Builder after specifying token with use()\n */\nexport interface ConditionalBindingUse<T extends object> {\n /**\n * Specify the implementation when predicate returns true.\n * Registration is completed immediately.\n *\n * If predicate is false at resolution time:\n * - Uses `otherwise()` implementation if provided\n * - Falls back to existing registration if available\n * - Throws error if no fallback exists\n *\n * @param implementation - Service class to use when predicate is true\n * @returns Builder for optional fallback specification\n */\n give(implementation: Constructor<T>): ConditionalBindingGive<T>\n}\n\n/**\n * Builder after specifying true implementation with give()\n * Registration is already complete at this point.\n */\nexport interface ConditionalBindingGive<T extends object> {\n /**\n * Optionally specify a fallback implementation when predicate returns false.\n * This re-registers with the explicit fallback instead of existing registration.\n *\n * @param implementation - Service class to use when predicate is false\n */\n otherwise(implementation: Constructor<T>): void\n}\n\n/**\n * Implementation of ConditionalBindingBuilder\n *\n * @internal\n */\nexport class ConditionalBindingBuilderImpl implements ConditionalBindingBuilder {\n constructor(\n private readonly tsyringeContainer: DependencyContainer,\n private readonly predicateContainer: PredicateContainer,\n private readonly predicate: (container: PredicateContainer) => boolean,\n private readonly options: WhenOptions\n ) { }\n\n use<T extends object>(token: InjectionToken<T>): ConditionalBindingUse<T> {\n return new ConditionalBindingUseImpl<T>(\n this.tsyringeContainer,\n this.predicateContainer,\n this.predicate,\n this.options,\n token\n )\n }\n}\n\n/**\n * Implementation of ConditionalBindingUse\n *\n * @internal\n */\nclass ConditionalBindingUseImpl<T extends object> implements ConditionalBindingUse<T> {\n constructor(\n private readonly tsyringeContainer: DependencyContainer,\n private readonly predicateContainer: PredicateContainer,\n private readonly predicate: (container: PredicateContainer) => boolean,\n private readonly options: WhenOptions,\n private readonly token: InjectionToken<T>\n ) { }\n\n give(trueImplementation: Constructor<T>): ConditionalBindingGive<T> {\n // Get fallback: existing registration or a class that throws\n const falseImplementation = this.getFallbackImplementation()\n\n // Register using predicateAwareClassFactory\n this.registerWithPredicate(trueImplementation, falseImplementation)\n\n // Return builder for optional otherwise()\n return {\n otherwise: (implementation: Constructor<T>) => {\n this.registerWithPredicate(trueImplementation, implementation,)\n },\n }\n }\n\n /**\n * Get fallback implementation: existing registration or throw-on-resolve class\n */\n private getFallbackImplementation(): Constructor<T> {\n // Check if token is already registered\n if (this.tsyringeContainer.isRegistered(this.token)) {\n // Create a class that resolves the existing registration\n // We need to capture the current registration before we overwrite it\n const existingInstance = this.tsyringeContainer.resolve<T>(this.token)\n\n // Return a \"class\" that just returns the existing instance\n // Using a factory wrapper since predicateAwareClassFactory expects a constructor\n return class ExistingInstanceWrapper {\n static instance = existingInstance\n constructor() {\n return ExistingInstanceWrapper.instance as unknown as ExistingInstanceWrapper\n }\n } as unknown as Constructor<T>\n }\n\n // No existing registration - create a class that throws\n const tokenStr = typeof this.token === 'symbol'\n ? (this.token.description ?? 'unknown')\n : typeof this.token === 'function'\n ? this.token.name\n // eslint-disable-next-line @typescript-eslint/no-base-to-string -- token can be string or object; String() is intentional fallback\n : String(this.token)\n return class NoFallbackError {\n constructor() {\n throw new ConditionalBindingFallbackError(tokenStr)\n }\n } as unknown as Constructor<T>\n }\n\n private registerWithPredicate(\n trueImplementation: Constructor<T>,\n falseImplementation: Constructor<T>\n ): void {\n const { predicate, predicateContainer, options } = this\n\n this.tsyringeContainer.register(this.token, {\n useFactory: predicateAwareClassFactory<T>(\n () => predicate(predicateContainer),\n trueImplementation,\n falseImplementation,\n options.cache ?? false\n )\n })\n }\n}\n","/**\n * Unified DI Container\n *\n * Provides a developer-friendly wrapper around tsyringe with:\n * - Auto-token extraction from decorator metadata\n * - Auto-scope detection from decorator metadata\n * - Seamless global/request scope interoperability\n * - Request scope lifecycle management\n *\n * **Two-Tier Container Architecture:**\n * ```\n * Global Container (managed by Container)\n * ↓\n * All services registered here\n * (singletons + container-scoped)\n * ↓\n * Request Container (child, per request)\n * ↓\n * Fresh instances for ContainerScoped services\n * RouterContext registered per request\n * ```\n */\nimport { type DependencyContainer, type Lifecycle } from 'tsyringe'\nimport type InjectionToken from 'tsyringe/dist/typings/providers/injection-token'\nimport type { RouterContext } from '../router/router-context'\nimport { ROUTER_TOKENS } from '../router/router.tokens'\nimport type { Constructor } from '../types'\nimport { ConditionalBindingBuilderImpl, type ConditionalBindingBuilder, type PredicateContainer } from './conditional-binding-builder'\nimport { RequestScopeOperationNotAllowedError } from './errors/request-scope-operation-not-allowed.error'\nimport { CONTAINER_TOKEN } from './tokens'\nimport type { ExtensionDecorator, Scope, WhenOptions } from './types'\n\n/**\n * Options for creating a Container instance\n */\nexport interface ContainerOptions {\n /** Pre-created DependencyContainer */\n container: DependencyContainer\n /** Whether this is a request-scoped container */\n isRequestScoped?: boolean\n}\n\n/**\n * Unified Container for DI management\n *\n * Manages the two-tier container hierarchy:\n * - Global scope: Singletons, base instances of request-scoped services\n * - Request scope: Context-enriched instances per HTTP request\n *\n * @example Basic registration\n * ```typescript\n * import { container as tsyringeRootContainer } from 'tsyringe'\n *\n * const container = new Container({\n * container: tsyringeRootContainer.createChildContainer()\n * })\n *\n * container.register(I18nService)\n * container.register(MY_TOKEN, MyService)\n * container.registerSingleton(ConfigService)\n * container.registerValue(MY_TOKEN, myInstance)\n * ```\n *\n * @example Request scope (automatic lifecycle)\n * ```typescript\n * await container.runInRequestScope(routerContext, async (requestContainer) => {\n * const i18n = requestContainer.resolve(I18N_TOKEN)\n * })\n * ```\n */\nexport class Container {\n private readonly container: DependencyContainer\n private readonly isRequestScoped: boolean\n\n constructor(options: ContainerOptions) {\n this.isRequestScoped = options.isRequestScoped ?? false\n this.container = options.container\n\n // Only register CONTAINER_TOKEN for global container (not request-scoped)\n if (!this.isRequestScoped) {\n this.container.register(CONTAINER_TOKEN, { useValue: this })\n }\n }\n\n // ============================================================\n // Registration Methods\n // ============================================================\n\n /**\n * Register a service with optional explicit token and scope\n */\n register<T extends object>(serviceClass: Constructor<T>, scope?: Scope): void\n register<T extends object>(token: InjectionToken<T>, serviceClass: Constructor<T>, scope?: Scope): void\n register<T extends object>(\n tokenOrClass: InjectionToken<T> | Constructor<T>,\n serviceClassOrScope?: Constructor<T> | Scope,\n scope?: Scope\n ): void {\n let token: InjectionToken<T>\n let serviceClass: Constructor<T>\n let lifecycle: Lifecycle | undefined\n\n if (typeof serviceClassOrScope === 'function') {\n // Called as register(token, class, scope?)\n token = tokenOrClass as InjectionToken<T>\n serviceClass = serviceClassOrScope\n lifecycle = scope as Lifecycle | undefined\n } else {\n // Called as register(class, scope?)\n token = tokenOrClass as Constructor<T>\n serviceClass = tokenOrClass as Constructor<T>\n lifecycle = serviceClassOrScope as Lifecycle | undefined\n }\n\n if (lifecycle !== undefined) {\n this.container.register(token, { useClass: serviceClass }, { lifecycle })\n } else {\n this.container.register(token, { useClass: serviceClass })\n }\n }\n\n /**\n * Register a service as singleton\n */\n registerSingleton<T extends object>(serviceClass: Constructor<T>): void\n registerSingleton<T extends object>(token: InjectionToken<T>, serviceClass: Constructor<T>): void\n registerSingleton<T extends object>(\n tokenOrClass: InjectionToken<T> | Constructor<T>,\n serviceClass?: Constructor<T>\n ): void {\n if (serviceClass !== undefined) {\n this.container.registerSingleton(tokenOrClass as InjectionToken<T>, serviceClass)\n } else {\n const targetClass = tokenOrClass as Constructor<T>\n this.container.registerSingleton(targetClass, targetClass)\n }\n }\n\n /**\n * Register a value (instance) directly\n */\n registerValue<T>(token: InjectionToken<T>, value: T): void {\n this.container.register(token, { useValue: value })\n }\n\n /**\n * Register with factory function\n */\n registerFactory<T>(\n token: InjectionToken<T>,\n factory: (container: Container) => T\n ): void {\n this.container.register(token, { useFactory: () => factory(this) })\n }\n\n /**\n * Register an alias to an existing token\n */\n registerExisting<T>(alias: InjectionToken<T>, target: InjectionToken<T>): void {\n this.container.register(alias, { useToken: target })\n }\n\n // ============================================================\n // Resolution Methods\n // ============================================================\n\n /**\n * Resolve a service from the container\n */\n resolve<T>(token: InjectionToken<T>): T {\n return this.container.resolve<T>(token)\n }\n\n /**\n * Check if a token is registered\n */\n isRegistered<T>(token: InjectionToken<T>): boolean {\n return this.container.isRegistered(token)\n }\n\n // ============================================================\n // Conditional Registration Methods\n // ============================================================\n\n /**\n * Start a conditional binding with predicate evaluation\n */\n when(\n predicate: (container: PredicateContainer) => boolean,\n options: WhenOptions = {}\n ): ConditionalBindingBuilder {\n return new ConditionalBindingBuilderImpl(\n this.container,\n this,\n predicate,\n options\n )\n }\n\n /**\n * Replace a service registration with a decorated version\n */\n extend<T>(token: InjectionToken<T>, decorator: ExtensionDecorator<T>): void {\n const currentInstance = this.container.resolve<T>(token)\n const decoratedInstance = decorator(currentInstance, this)\n this.container.register(token, { useValue: decoratedInstance })\n }\n\n // ============================================================\n // Request Scope Management\n // ============================================================\n\n /**\n * Run callback within request scope\n *\n * Creates a child container with fresh instances for services registered with `scope: Scope.Request`.\n * Callback receives the request-scoped container as argument.\n *\n * Can only be called on global container (not request-scoped).\n */\n async runInRequestScope<T>(\n routerContext: RouterContext,\n callback: (requestContainer: Container) => T | Promise<T>\n ): Promise<T> {\n if (this.isRequestScoped) {\n throw new RequestScopeOperationNotAllowedError('runInRequestScope')\n }\n\n const requestContainer = this.createRequestScope(routerContext)\n try {\n return await callback(requestContainer)\n } finally {\n await requestContainer.dispose()\n }\n }\n\n /**\n * Create request scope container\n *\n * Can only be called on global container (not request-scoped).\n */\n createRequestScope(routerContext: RouterContext): Container {\n if (this.isRequestScoped) {\n throw new RequestScopeOperationNotAllowedError('createRequestScope')\n }\n\n const childContainer = this.container.createChildContainer()\n childContainer.register(ROUTER_TOKENS.RouterContext, { useValue: routerContext })\n\n return new Container({ container: childContainer, isRequestScoped: true })\n }\n\n // ============================================================\n // Escape Hatches\n // ============================================================\n\n /**\n * Get underlying tsyringe container\n */\n getTsyringeContainer(): DependencyContainer {\n return this.container\n }\n\n dispose() {\n return this.container.dispose()\n }\n}\n\n// Re-export tsyringe utilities for convenience\nexport { container, delay, inject, injectable, instancePerContainerCachingFactory, singleton } from 'tsyringe'\nexport type { DependencyContainer } from 'tsyringe'\n\n","/**\n * DI Type Definitions\n *\n * Core type definitions for the dependency injection system.\n * Simplified after removing LazyProxy - no more type wrappers needed.\n */\n\nimport { Lifecycle } from 'tsyringe'\nimport type InjectionToken from 'tsyringe/dist/typings/providers/injection-token'\n\n/**\n * Service scope for DI registration\n *\n * Maps directly to tsyringe's Lifecycle enum.\n * Scope is specified at registration time via provider configuration,\n * not at class decoration time.\n *\n * @example\n * ```typescript\n * // In module providers:\n * { provide: MY_TOKEN, useClass: MyService, scope: Scope.Singleton }\n *\n * // In Application.ts:\n * container.register(MY_TOKEN, MyService, Scope.Request)\n * ```\n */\n/* eslint-disable @typescript-eslint/prefer-literal-enum-member -- values must stay in sync with tsyringe Lifecycle */\nexport enum Scope {\n /** New instance per resolution (default) */\n Transient = Lifecycle.Transient,\n /** Single instance shared globally */\n Singleton = Lifecycle.Singleton,\n /** New instance per child container (per request) */\n Request = Lifecycle.ContainerScoped,\n}\n/* eslint-enable @typescript-eslint/prefer-literal-enum-member */\n\n/**\n * Options for conditional binding with `when()` method\n */\nexport interface WhenOptions {\n /**\n * Cache predicate result after first evaluation.\n * When true, the predicate is evaluated once and the result is reused.\n * When false (default), predicate is evaluated on each resolution.\n */\n cache?: boolean\n}\n\n/**\n * Decorator function type for extend() method\n *\n * @template T The service type being decorated\n */\nexport type ExtensionDecorator<T> = (service: T, container: ContainerLike) => T\n\n/**\n * Minimal container interface for decorator functions\n * Avoids circular dependency with Container class\n */\nexport interface ContainerLike {\n resolve<T>(token: InjectionToken<T>): T\n}\n\n","/**\n * I18n Module DI Tokens\n * Symbol-based tokens to avoid string collisions\n */\n\nexport const I18N_TOKENS = {\n /** MessageLoaderService - loads and caches locale messages */\n MessageLoader: Symbol.for('stratal:i18n:message:loader'),\n /** I18nService - request-scoped translation service */\n I18nService: Symbol.for('stratal:i18n:service'),\n /** I18nModuleOptions - configuration options from forRoot() */\n Options: Symbol.for('stratal:i18n:options')\n} as const\n","import { ERROR_CODES } from './error-codes'\nimport { ApplicationError } from './application-error'\n\n/**\n * InternalError\n *\n * Represents an unexpected internal server error.\n * Used to wrap unknown errors that don't fit into specific error categories.\n *\n * This error is thrown when:\n * - An unexpected exception occurs\n * - An error type is not recognized\n * - A system-level failure happens\n */\nexport class InternalError extends ApplicationError {\n constructor(metadata?: Record<string, unknown>) {\n super(\n 'errors.internalError',\n ERROR_CODES.SYSTEM.INTERNAL_ERROR,\n metadata\n )\n }\n}\n","import { ApplicationError } from './application-error'\n\n/**\n * Type guard to check if an error is an ApplicationError\n *\n * @param error - The error to check\n * @returns True if the error is an ApplicationError instance\n */\nexport function isApplicationError(error: unknown): error is ApplicationError {\n return error instanceof ApplicationError\n}\n","import { inject } from 'tsyringe'\nimport { DI_TOKENS } from '../di'\nimport { Transient } from '../di/decorators'\nimport { type StratalEnv } from '../env'\nimport { I18N_TOKENS } from '../i18n/i18n.tokens'\nimport type { II18nService, MessageKeys } from '../i18n/i18n.types'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport { ApplicationError } from './application-error'\nimport type { Environment, ErrorResponse } from './error-response'\nimport { InternalError } from './internal-error'\nimport { isApplicationError } from './is-application-error'\n\n/**\n * Log severity levels\n */\ntype LogSeverity = 'error' | 'warn' | 'info'\n\n/**\n * GlobalErrorHandler\n *\n * Centralized error handler registered in the DI container.\n * Responsible for:\n * - Intercepting all errors in the application\n * - Logging errors with appropriate severity via Logger service\n * - Translating error message keys using I18nService (when available)\n * - Serializing errors for RPC transmission\n * - Wrapping unexpected errors in InternalError\n *\n * **Translation Availability by Context:**\n *\n * ✅ **HTTP Requests**: Errors are fully translated\n * - GlobalErrorHandler resolved from request container\n * - I18nService available via AsyncLocalStorage with user's locale\n * - Full translation with parameter interpolation\n *\n * ✅ **Queue Processing**: Errors are fully translated\n * - Error handling executes inside AsyncLocalStorage scope\n * - Locale extracted from queue message metadata\n * - Request container created with mock RouterContext\n * - I18nService available with correct locale\n *\n * ⚠️ **RPC/Startup**: Message keys returned as-is (i18n unavailable)\n * - No request context available during service binding or startup\n * - No locale information available\n * - Frontend can translate message keys using its own i18n if needed\n * - This is expected behavior, not a bug\n *\n * **Implementation Note:**\n * The `isAvailable()` check exists to gracefully handle RPC/startup contexts\n * where no request container exists. For HTTP and Queue contexts, i18n is\n * always available thanks to AsyncLocalStorage scope propagation. This follows\n * the \"Laravel philosophy\" - transparent dependency injection for request contexts,\n * with explicit handling only for legitimate non-request edge cases.\n */\n@Transient()\nexport class GlobalErrorHandler {\n private readonly environment: Environment\n constructor(\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService,\n @inject(I18N_TOKENS.I18nService) private readonly i18n: II18nService,\n @inject(DI_TOKENS.CloudflareEnv)\n private readonly env: StratalEnv,\n ) {\n this.environment = this.env.ENVIRONMENT as Environment\n }\n\n /**\n * Handle an error, log it, and serialize for response\n *\n * @param error - The error to handle\n * @returns Serialized ErrorResponse for RPC transmission\n */\n handle(error: unknown): ErrorResponse {\n // Check if it's an ApplicationError\n if (isApplicationError(error)) {\n // Translate once, use for both logging and response\n const translatedMessage = this.translateError(error)\n\n this.log(error, translatedMessage)\n\n return error.toErrorResponse(this.environment, translatedMessage)\n }\n\n // Unexpected error - wrap in InternalError\n this.logUnexpectedError(error)\n\n const internalError = new InternalError({\n originalError: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n\n const translatedMessage = this.translateError(internalError)\n\n return internalError.toErrorResponse(this.environment, translatedMessage)\n }\n\n /**\n * Translate error message key using I18nService\n * Uses error metadata as interpolation parameters\n *\n * No try/catch - if translation fails, it's a bug that should fail loudly\n *\n * **Note**: This method is only called when isAvailable() returns true,\n * so the service is guaranteed to be resolved.\n *\n * @param error - ApplicationError with messageKey and metadata\n * @returns Translated message string\n */\n private translateError(error: ApplicationError): string {\n // Cast metadata to MessageParams (assuming values are string | number)\n const params = error.metadata as Record<string, string | number> | undefined\n return this.i18n.t(error.message as MessageKeys, params)\n }\n\n /**\n * Log an ApplicationError with appropriate severity\n */\n private log(error: ApplicationError, translatedMessage: string): void {\n const severity = this.getSeverity(error.code)\n\n const logData = {\n code: error.code,\n message: translatedMessage,\n timestamp: error.timestamp,\n metadata: error.metadata,\n name: error.name,\n }\n\n switch (severity) {\n case 'error':\n this.logger.error('[ApplicationError]', logData)\n break\n case 'warn':\n this.logger.warn('[ApplicationError]', logData)\n break\n case 'info':\n this.logger.info('[ApplicationError]', logData)\n break\n }\n }\n\n /**\n * Log an unexpected error\n */\n private logUnexpectedError(error: unknown): void {\n this.logger.error('[UnexpectedError]', {\n error: error instanceof Error ? {\n message: error.message,\n stack: error.stack,\n name: error.name,\n } : String(error),\n timestamp: new Date().toISOString(),\n })\n }\n\n /**\n * Determine log severity based on error code\n */\n private getSeverity(code: number): LogSeverity {\n // System errors (9000+) are critical\n if (code >= 9000) return 'error'\n\n // Database errors (2000-2999) are errors\n if (code >= 2000 && code < 3000) return 'error'\n\n // Business logic errors (5000-5999) are warnings\n if (code >= 5000 && code < 6000) return 'warn'\n\n // Validation errors (1000-1999) are info\n if (code >= 1000 && code < 2000) return 'info'\n\n // Auth/Resource errors (3000-4999) are warnings\n if (code >= 3000 && code < 5000) return 'warn'\n\n // Default to error\n return 'error'\n }\n}\n","import { ApplicationError } from './application-error'\nimport { ERROR_CODES } from './error-codes'\n\n/**\n * RequestContainerNotInitializedError\n *\n * Thrown when attempting to access the request-scoped container before it has been initialized.\n * This typically indicates that the RouterService middleware hasn't run yet,\n * or the router context is being accessed outside of a request lifecycle.\n */\nexport class RequestContainerNotInitializedError extends ApplicationError {\n constructor() {\n super(\n 'errors.requestContainerNotInitialized',\n ERROR_CODES.SYSTEM.REQUEST_CONTAINER_NOT_INITIALIZED\n )\n }\n}\n","import { ApplicationError } from './application-error'\nimport { ERROR_CODES } from './error-codes'\n\n/**\n * StratalNotInitializedError\n *\n * Thrown when attempting to resolve the Application instance before Stratal has been instantiated.\n * This typically indicates that the Stratal instance is not exported as the default export.\n */\nexport class StratalNotInitializedError extends ApplicationError {\n constructor() {\n super(\n 'errors.stratalNotInitialized',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR\n )\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { S as ApplicationError, b as ERROR_CODES } from "./errors-CtCi1wn6.mjs";
2
+ //#region src/storage/errors/disk-not-configured.error.ts
3
+ var DiskNotConfiguredError = class extends ApplicationError {
4
+ constructor(disk) {
5
+ super("errors.storage.diskNotConfigured", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, { disk });
6
+ }
7
+ };
8
+ //#endregion
9
+ //#region src/storage/errors/file-not-found.error.ts
10
+ var FileNotFoundError = class extends ApplicationError {
11
+ constructor(path) {
12
+ super("errors.storage.fileNotFound", ERROR_CODES.RESOURCE.NOT_FOUND, { path });
13
+ }
14
+ };
15
+ //#endregion
16
+ //#region src/storage/errors/file-too-large.error.ts
17
+ var FileTooLargeError = class extends ApplicationError {
18
+ constructor(size, maxSize) {
19
+ super("errors.storage.fileTooLarge", ERROR_CODES.VALIDATION.INVALID_FORMAT, {
20
+ size,
21
+ maxSize
22
+ });
23
+ }
24
+ };
25
+ //#endregion
26
+ //#region src/storage/errors/invalid-disk.error.ts
27
+ var InvalidDiskError = class extends ApplicationError {
28
+ constructor(disk) {
29
+ super("errors.storage.invalidDisk", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, { disk });
30
+ }
31
+ };
32
+ //#endregion
33
+ //#region src/storage/errors/invalid-file-type.error.ts
34
+ var InvalidFileTypeError = class extends ApplicationError {
35
+ constructor(mimeType) {
36
+ super("errors.storage.invalidFileType", ERROR_CODES.VALIDATION.INVALID_FORMAT, { mimeType });
37
+ }
38
+ };
39
+ //#endregion
40
+ //#region src/storage/errors/presigned-url-invalid-expiry.error.ts
41
+ var PresignedUrlInvalidExpiryError = class extends ApplicationError {
42
+ constructor(expiresIn, min, max) {
43
+ super("errors.storage.presignedUrlInvalidExpiry", ERROR_CODES.VALIDATION.INVALID_FORMAT, {
44
+ expiresIn,
45
+ min,
46
+ max
47
+ });
48
+ }
49
+ };
50
+ //#endregion
51
+ //#region src/storage/errors/storage-provider-not-supported.error.ts
52
+ var StorageProviderNotSupportedError = class extends ApplicationError {
53
+ constructor(provider) {
54
+ super("errors.storage.providerNotSupported", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, { provider });
55
+ }
56
+ };
57
+ //#endregion
58
+ //#region src/storage/errors/storage-response-body-missing.error.ts
59
+ var StorageResponseBodyMissingError = class extends ApplicationError {
60
+ constructor(path) {
61
+ super("errors.storage.responseBodyMissing", ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { path });
62
+ }
63
+ };
64
+ //#endregion
65
+ export { InvalidDiskError as a, DiskNotConfiguredError as c, InvalidFileTypeError as i, StorageProviderNotSupportedError as n, FileTooLargeError as o, PresignedUrlInvalidExpiryError as r, FileNotFoundError as s, StorageResponseBodyMissingError as t };
66
+
67
+ //# sourceMappingURL=errors-H3TZnVeX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-H3TZnVeX.mjs","names":[],"sources":["../src/storage/errors/disk-not-configured.error.ts","../src/storage/errors/file-not-found.error.ts","../src/storage/errors/file-too-large.error.ts","../src/storage/errors/invalid-disk.error.ts","../src/storage/errors/invalid-file-type.error.ts","../src/storage/errors/presigned-url-invalid-expiry.error.ts","../src/storage/errors/storage-provider-not-supported.error.ts","../src/storage/errors/storage-response-body-missing.error.ts"],"sourcesContent":["import { ApplicationError, ERROR_CODES } from '../../errors'\n\nexport class DiskNotConfiguredError extends ApplicationError {\n constructor(disk: string) {\n super('errors.storage.diskNotConfigured', ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, { disk })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class FileNotFoundError extends ApplicationError {\n constructor(path: string) {\n super('errors.storage.fileNotFound', ERROR_CODES.RESOURCE.NOT_FOUND, { path })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class FileTooLargeError extends ApplicationError {\n constructor(size: number, maxSize: number) {\n super('errors.storage.fileTooLarge', ERROR_CODES.VALIDATION.INVALID_FORMAT, {\n size,\n maxSize,\n })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class InvalidDiskError extends ApplicationError {\n constructor(disk: string) {\n super('errors.storage.invalidDisk', ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, { disk })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class InvalidFileTypeError extends ApplicationError {\n constructor(mimeType: string) {\n super('errors.storage.invalidFileType', ERROR_CODES.VALIDATION.INVALID_FORMAT, {\n mimeType,\n })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class PresignedUrlInvalidExpiryError extends ApplicationError {\n constructor(expiresIn: number, min: number, max: number) {\n super('errors.storage.presignedUrlInvalidExpiry', ERROR_CODES.VALIDATION.INVALID_FORMAT, {\n expiresIn,\n min,\n max,\n })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class StorageProviderNotSupportedError extends ApplicationError {\n constructor(provider: string) {\n super('errors.storage.providerNotSupported', ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, { provider })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class StorageResponseBodyMissingError extends ApplicationError {\n constructor(path: string) {\n super(\n 'errors.storage.responseBodyMissing',\n ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR,\n { path }\n )\n }\n}\n"],"mappings":";;AAEA,IAAa,yBAAb,cAA4C,iBAAiB;CAC3D,YAAY,MAAc;AACxB,QAAM,oCAAoC,YAAY,OAAO,qBAAqB,EAAE,MAAM,CAAC;;;;;ACD/F,IAAa,oBAAb,cAAuC,iBAAiB;CACtD,YAAY,MAAc;AACxB,QAAM,+BAA+B,YAAY,SAAS,WAAW,EAAE,MAAM,CAAC;;;;;ACFlF,IAAa,oBAAb,cAAuC,iBAAiB;CACtD,YAAY,MAAc,SAAiB;AACzC,QAAM,+BAA+B,YAAY,WAAW,gBAAgB;GAC1E;GACA;GACD,CAAC;;;;;ACLN,IAAa,mBAAb,cAAsC,iBAAiB;CACrD,YAAY,MAAc;AACxB,QAAM,8BAA8B,YAAY,OAAO,qBAAqB,EAAE,MAAM,CAAC;;;;;ACFzF,IAAa,uBAAb,cAA0C,iBAAiB;CACzD,YAAY,UAAkB;AAC5B,QAAM,kCAAkC,YAAY,WAAW,gBAAgB,EAC7E,UACD,CAAC;;;;;ACJN,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YAAY,WAAmB,KAAa,KAAa;AACvD,QAAM,4CAA4C,YAAY,WAAW,gBAAgB;GACvF;GACA;GACA;GACD,CAAC;;;;;ACNN,IAAa,mCAAb,cAAsD,iBAAiB;CACrE,YAAY,UAAkB;AAC5B,QAAM,uCAAuC,YAAY,OAAO,qBAAqB,EAAE,UAAU,CAAC;;;;;ACFtG,IAAa,kCAAb,cAAqD,iBAAiB;CACpE,YAAY,MAAc;AACxB,QACE,sCACA,YAAY,OAAO,sBACnB,EAAE,MAAM,CACT"}
@@ -1,5 +1,5 @@
1
- import { t as Constructor } from "../types-JUIHSW_a.mjs";
2
- import { i as LoggerService } from "../index-3TtGtYlJ.mjs";
1
+ import { t as Constructor } from "../types-DahElfUw.mjs";
2
+ import { i as LoggerService } from "../index-Dp6A5ywM.mjs";
3
3
 
4
4
  //#region src/events/constants.d.ts
5
5
  /**
@@ -1,3 +1,4 @@
1
- import "../logger-Bg-CuidS.mjs";
2
- import { a as isListener, i as Listener, n as On, o as LISTENER_METADATA_KEYS, r as getListenerHandlers, t as EventRegistry } from "../events-CQyvSyrQ.mjs";
1
+ import "../decorate-D5j-d9_z.mjs";
2
+ import "../logger-BR1-s1Um.mjs";
3
+ import { a as isListener, i as Listener, n as On, o as LISTENER_METADATA_KEYS, r as getListenerHandlers, t as EventRegistry } from "../events-CXl-o1Ad.mjs";
3
4
  export { EventRegistry, LISTENER_METADATA_KEYS, Listener, On, getListenerHandlers, isListener };
@@ -1,4 +1,5 @@
1
- import { a as __decorate, d as Transient, g as DI_TOKENS, o as __decorateParam, s as __decorateMetadata, u as LOGGER_TOKENS } from "./logger-Bg-CuidS.mjs";
1
+ import { i as Transient, l as DI_TOKENS, n as __decorateParam, r as __decorateMetadata, t as __decorate } from "./decorate-D5j-d9_z.mjs";
2
+ import { s as LOGGER_TOKENS } from "./logger-BR1-s1Um.mjs";
2
3
  import { inject } from "tsyringe";
3
4
  //#region src/events/constants.ts
4
5
  /**
@@ -187,4 +188,4 @@ EventRegistry = __decorate([
187
188
  //#endregion
188
189
  export { isListener as a, Listener as i, On as n, LISTENER_METADATA_KEYS as o, getListenerHandlers as r, EventRegistry as t };
189
190
 
190
- //# sourceMappingURL=events-CQyvSyrQ.mjs.map
191
+ //# sourceMappingURL=events-CXl-o1Ad.mjs.map