stratal 0.0.16 → 0.0.17

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 (145) hide show
  1. package/README.md +4 -0
  2. package/dist/{application-zG8b-pol.d.mts → application-DfPtIzxF.d.mts} +65 -4
  3. package/dist/application-DfPtIzxF.d.mts.map +1 -0
  4. package/dist/{base-email.provider-Cuw4OAB0.mjs → base-email.provider-DypUAfWm.mjs} +1 -1
  5. package/dist/{base-email.provider-Cuw4OAB0.mjs.map → base-email.provider-DypUAfWm.mjs.map} +1 -1
  6. package/dist/bin/cloudflare-workers-loader.mjs +0 -0
  7. package/dist/bin/quarry.mjs +1 -50
  8. package/dist/bin/quarry.mjs.map +1 -1
  9. package/dist/cache/index.d.mts +1 -1
  10. package/dist/cache/index.mjs +10 -11
  11. package/dist/cache/index.mjs.map +1 -1
  12. package/dist/{colors-DJaRDXoS.mjs → colors-Y7WIFXs7.mjs} +1 -1
  13. package/dist/{colors-DJaRDXoS.mjs.map → colors-Y7WIFXs7.mjs.map} +1 -1
  14. package/dist/{command-BvCOD6df.mjs → command-B1CPgsrU.mjs} +6 -3
  15. package/dist/{command-BvCOD6df.mjs.map → command-B1CPgsrU.mjs.map} +1 -1
  16. package/dist/{command-B-QH-Vu3.d.mts → command-TnkPYWta.d.mts} +2 -2
  17. package/dist/{command-B-QH-Vu3.d.mts.map → command-TnkPYWta.d.mts.map} +1 -1
  18. package/dist/config/index.d.mts +2 -2
  19. package/dist/config/index.mjs +10 -11
  20. package/dist/config/index.mjs.map +1 -1
  21. package/dist/consumer-registry-Bymm6ff4.d.mts +142 -0
  22. package/dist/consumer-registry-Bymm6ff4.d.mts.map +1 -0
  23. package/dist/cron/index.d.mts +3 -116
  24. package/dist/cron/index.d.mts.map +1 -1
  25. package/dist/cron/index.mjs +3 -4
  26. package/dist/{cron-manager-DR7fiG6o.mjs → cron-manager-CFBamKKk.mjs} +3 -3
  27. package/dist/{cron-manager-DR7fiG6o.mjs.map → cron-manager-CFBamKKk.mjs.map} +1 -1
  28. package/dist/cron-manager-D7imGwUT.d.mts +117 -0
  29. package/dist/cron-manager-D7imGwUT.d.mts.map +1 -0
  30. package/dist/di/index.d.mts +1 -1
  31. package/dist/di/index.mjs +2 -3
  32. package/dist/email/index.d.mts +3 -3
  33. package/dist/email/index.mjs +16 -17
  34. package/dist/email/index.mjs.map +1 -1
  35. package/dist/errors/index.d.mts +1 -1
  36. package/dist/errors/index.mjs +2 -3
  37. package/dist/{errors-CtCi1wn6.mjs → errors-DSKapqD8.mjs} +4 -4
  38. package/dist/{errors-CtCi1wn6.mjs.map → errors-DSKapqD8.mjs.map} +1 -1
  39. package/dist/{errors-H3TZnVeX.mjs → errors-DuAR5Wke.mjs} +2 -2
  40. package/dist/{errors-H3TZnVeX.mjs.map → errors-DuAR5Wke.mjs.map} +1 -1
  41. package/dist/events/index.mjs +2 -3
  42. package/dist/{events-CXl-o1Ad.mjs → events-CvUSgEuN.mjs} +2 -3
  43. package/dist/{events-CXl-o1Ad.mjs.map → events-CvUSgEuN.mjs.map} +1 -1
  44. package/dist/{gateway-context-BkZ4UKaX.mjs → gateway-context-CNOLkLUC.mjs} +4 -4
  45. package/dist/{gateway-context-BkZ4UKaX.mjs.map → gateway-context-CNOLkLUC.mjs.map} +1 -1
  46. package/dist/guards/index.d.mts +1 -1
  47. package/dist/i18n/index.d.mts +3 -3
  48. package/dist/i18n/index.mjs +15 -15
  49. package/dist/i18n/validation/index.d.mts +1 -1
  50. package/dist/i18n/validation/index.mjs +1 -1
  51. package/dist/{i18n.module-W8OJxg3d.mjs → i18n.module-Dn9SrFdS.mjs} +210 -160
  52. package/dist/i18n.module-Dn9SrFdS.mjs.map +1 -0
  53. package/dist/{index-BJWm863C.d.mts → index-BFCxSp_f.d.mts} +82 -73
  54. package/dist/index-BFCxSp_f.d.mts.map +1 -0
  55. package/dist/{index-D9iYu2Yc.d.mts → index-DGRe6Yoa.d.mts} +5 -144
  56. package/dist/index-DGRe6Yoa.d.mts.map +1 -0
  57. package/dist/{index-DVhdhLvE.d.mts → index-NGxg-KP_.d.mts} +4 -4
  58. package/dist/{index-DVhdhLvE.d.mts.map → index-NGxg-KP_.d.mts.map} +1 -1
  59. package/dist/index.d.mts +2 -2
  60. package/dist/index.mjs +19 -19
  61. package/dist/{is-command-BfCgWAcQ.mjs → is-command-DJVI6wEJ.mjs} +2 -2
  62. package/dist/{is-command-BfCgWAcQ.mjs.map → is-command-DJVI6wEJ.mjs.map} +1 -1
  63. package/dist/{is-seeder-CebjZCDn.mjs → is-seeder-D5MIEcdz.mjs} +1 -1
  64. package/dist/{is-seeder-CebjZCDn.mjs.map → is-seeder-D5MIEcdz.mjs.map} +1 -1
  65. package/dist/logger/index.mjs +1 -2
  66. package/dist/{logger-BR1-s1Um.mjs → logger-CGT91VY6.mjs} +170 -4
  67. package/dist/logger-CGT91VY6.mjs.map +1 -0
  68. package/dist/middleware/index.d.mts +1 -1
  69. package/dist/middleware/index.mjs +4 -5
  70. package/dist/{middleware-C0Ebzswy.mjs → middleware-Bl-b5pkt.mjs} +3 -3
  71. package/dist/{middleware-C0Ebzswy.mjs.map → middleware-Bl-b5pkt.mjs.map} +1 -1
  72. package/dist/module/index.d.mts +2 -117
  73. package/dist/module/index.d.mts.map +1 -1
  74. package/dist/module/index.mjs +10 -11
  75. package/dist/module-registry-CmjBX6ol.d.mts +121 -0
  76. package/dist/module-registry-CmjBX6ol.d.mts.map +1 -0
  77. package/dist/{module-BgdxxzBe.mjs → module-tUtyVJ5E.mjs} +9 -8
  78. package/dist/module-tUtyVJ5E.mjs.map +1 -0
  79. package/dist/openapi/index.d.mts +54 -54
  80. package/dist/openapi/index.d.mts.map +1 -1
  81. package/dist/openapi/index.mjs +15 -15
  82. package/dist/openapi-tools.service-B3TxYKoQ.mjs +197 -0
  83. package/dist/openapi-tools.service-B3TxYKoQ.mjs.map +1 -0
  84. package/dist/openapi.service-DGnX3Fc4.d.mts +58 -0
  85. package/dist/openapi.service-DGnX3Fc4.d.mts.map +1 -0
  86. package/dist/quarry/index.d.mts +109 -28
  87. package/dist/quarry/index.d.mts.map +1 -1
  88. package/dist/quarry/index.mjs +9 -7
  89. package/dist/quarry-registry-B2rkO-JS.mjs +683 -0
  90. package/dist/quarry-registry-B2rkO-JS.mjs.map +1 -0
  91. package/dist/queue/index.d.mts +2 -1
  92. package/dist/queue/index.mjs +11 -12
  93. package/dist/queue/index.mjs.map +1 -1
  94. package/dist/{queue.module-BZvmeAMj.mjs → queue.module-BtI8f4Jo.mjs} +4 -4
  95. package/dist/{queue.module-BZvmeAMj.mjs.map → queue.module-BtI8f4Jo.mjs.map} +1 -1
  96. package/dist/{resend.provider-BCCACQAU.mjs → resend.provider-bXMEkdRJ.mjs} +4 -5
  97. package/dist/{resend.provider-BCCACQAU.mjs.map → resend.provider-bXMEkdRJ.mjs.map} +1 -1
  98. package/dist/router/index.d.mts +1 -1
  99. package/dist/router/index.mjs +14 -14
  100. package/dist/{router-context-BEJe9HEB.mjs → router-context-D9R1v2Ac.mjs} +7 -4
  101. package/dist/router-context-D9R1v2Ac.mjs.map +1 -0
  102. package/dist/{s3-storage.provider-BLlzQYiJ.mjs → s3-storage.provider-CttzNnDR.mjs} +5 -6
  103. package/dist/{s3-storage.provider-BLlzQYiJ.mjs.map → s3-storage.provider-CttzNnDR.mjs.map} +1 -1
  104. package/dist/seeder/index.d.mts +3 -3
  105. package/dist/seeder/index.mjs +6 -7
  106. package/dist/{seeder-Cupi5jl-.mjs → seeder-R7RXJC35.mjs} +20 -17
  107. package/dist/seeder-R7RXJC35.mjs.map +1 -0
  108. package/dist/{smtp.provider-B8XtOcHU.mjs → smtp.provider-DrbHQztF.mjs} +4 -5
  109. package/dist/{smtp.provider-B8XtOcHU.mjs.map → smtp.provider-DrbHQztF.mjs.map} +1 -1
  110. package/dist/storage/index.d.mts +2 -195
  111. package/dist/storage/index.d.mts.map +1 -1
  112. package/dist/storage/index.mjs +13 -14
  113. package/dist/storage/providers/index.d.mts +272 -0
  114. package/dist/storage/providers/index.d.mts.map +1 -0
  115. package/dist/storage/providers/index.mjs +5 -0
  116. package/dist/{storage-By_ow2o_.mjs → storage-CZKHOhci.mjs} +7 -7
  117. package/dist/{storage-By_ow2o_.mjs.map → storage-CZKHOhci.mjs.map} +1 -1
  118. package/dist/storage-provider.interface-0IqcdhBf.d.mts +197 -0
  119. package/dist/storage-provider.interface-0IqcdhBf.d.mts.map +1 -0
  120. package/dist/{stratal-CE0iTz4f.mjs → stratal-D5smIU1y.mjs} +22 -12
  121. package/dist/stratal-D5smIU1y.mjs.map +1 -0
  122. package/dist/{usage-generator-C9hWziY4.mjs → usage-generator-CVIsENuE.mjs} +2 -2
  123. package/dist/{usage-generator-C9hWziY4.mjs.map → usage-generator-CVIsENuE.mjs.map} +1 -1
  124. package/dist/{validation-Bh875Lyg.mjs → validation-DQTC259A.mjs} +4 -4
  125. package/dist/{validation-Bh875Lyg.mjs.map → validation-DQTC259A.mjs.map} +1 -1
  126. package/dist/websocket/index.d.mts +1 -1
  127. package/dist/websocket/index.mjs +4 -5
  128. package/dist/workers/index.d.mts +1 -1
  129. package/dist/workers/index.mjs +19 -19
  130. package/package.json +13 -8
  131. package/dist/application-zG8b-pol.d.mts.map +0 -1
  132. package/dist/decorate-D5j-d9_z.mjs +0 -171
  133. package/dist/decorate-D5j-d9_z.mjs.map +0 -1
  134. package/dist/i18n.module-W8OJxg3d.mjs.map +0 -1
  135. package/dist/index-BJWm863C.d.mts.map +0 -1
  136. package/dist/index-D9iYu2Yc.d.mts.map +0 -1
  137. package/dist/logger-BR1-s1Um.mjs.map +0 -1
  138. package/dist/module-BgdxxzBe.mjs.map +0 -1
  139. package/dist/quarry-registry-DCwqVcRp.mjs +0 -310
  140. package/dist/quarry-registry-DCwqVcRp.mjs.map +0 -1
  141. package/dist/router-context-BEJe9HEB.mjs.map +0 -1
  142. package/dist/seeder-Cupi5jl-.mjs.map +0 -1
  143. package/dist/stratal-CE0iTz4f.mjs.map +0 -1
  144. package/dist/types-CLhOhYsQ.d.mts +0 -64
  145. package/dist/types-CLhOhYsQ.d.mts.map +0 -1
@@ -1,14 +1,13 @@
1
- import { S as ApplicationError, c as Container, r as GlobalErrorHandler, s as Scope, t as StratalNotInitializedError } from "./errors-CtCi1wn6.mjs";
2
- import { l as DI_TOKENS } from "./decorate-D5j-d9_z.mjs";
3
- import { i as LoggerService, n as PrettyFormatter, o as LogLevel, r as JsonFormatter, s as LOGGER_TOKENS, t as ConsoleTransport } from "./logger-BR1-s1Um.mjs";
4
- import { t as ModuleRegistry } from "./module-BgdxxzBe.mjs";
5
- import { r as getListenerHandlers, t as EventRegistry } from "./events-CXl-o1Ad.mjs";
1
+ import { S as ApplicationError, c as Container, r as GlobalErrorHandler, s as Scope, t as StratalNotInitializedError } from "./errors-DSKapqD8.mjs";
2
+ import { g as DI_TOKENS, i as LoggerService, l as LogLevel, n as PrettyFormatter, r as JsonFormatter, t as ConsoleTransport, u as LOGGER_TOKENS } from "./logger-CGT91VY6.mjs";
3
+ import { t as ModuleRegistry } from "./module-tUtyVJ5E.mjs";
4
+ import { r as getListenerHandlers, t as EventRegistry } from "./events-CvUSgEuN.mjs";
6
5
  import { CacheModule } from "./cache/index.mjs";
7
- import { t as CronManager } from "./cron-manager-DR7fiG6o.mjs";
8
- import { g as OpenAPIModule, n as HonoApp, t as I18nModule } from "./i18n.module-W8OJxg3d.mjs";
9
- import { t as QuarryRegistry } from "./quarry-registry-DCwqVcRp.mjs";
10
- import { t as QueueModule } from "./queue.module-BZvmeAMj.mjs";
11
- import { i as SeederRegistry, n as DbSeedListCommand, r as SEEDER_TOKENS, t as DbSeedCommand } from "./seeder-Cupi5jl-.mjs";
6
+ import { t as CronManager } from "./cron-manager-CFBamKKk.mjs";
7
+ import { g as OpenAPIModule, n as HonoApp, t as I18nModule } from "./i18n.module-Dn9SrFdS.mjs";
8
+ import { a as QueueListCommand, c as HelpCommand, d as ApiCommand, i as RouteListCommand, o as McpToolsCommand, r as ScheduleListCommand, s as McpServeCommand, t as QuarryRegistry, u as EventListCommand } from "./quarry-registry-B2rkO-JS.mjs";
9
+ import { t as QueueModule } from "./queue.module-BtI8f4Jo.mjs";
10
+ import { i as SeederRegistry, n as DbSeedListCommand, r as SEEDER_TOKENS, t as DbSeedCommand } from "./seeder-R7RXJC35.mjs";
12
11
  import { container, injectable } from "tsyringe";
13
12
  import "reflect-metadata";
14
13
  //#region src/application.ts
@@ -162,7 +161,18 @@ var Application = class {
162
161
  });
163
162
  }
164
163
  registerCommands() {
165
- const builtinCommands = [DbSeedCommand, DbSeedListCommand];
164
+ const builtinCommands = [
165
+ HelpCommand,
166
+ DbSeedCommand,
167
+ DbSeedListCommand,
168
+ RouteListCommand,
169
+ EventListCommand,
170
+ ScheduleListCommand,
171
+ QueueListCommand,
172
+ McpServeCommand,
173
+ McpToolsCommand,
174
+ ApiCommand
175
+ ];
166
176
  for (const Cmd of builtinCommands) {
167
177
  injectable()(Cmd);
168
178
  this._container.register(Cmd, Cmd, Scope.Singleton);
@@ -302,4 +312,4 @@ var Stratal = class Stratal {
302
312
  //#endregion
303
313
  export { Application as n, Stratal as t };
304
314
 
305
- //# sourceMappingURL=stratal-CE0iTz4f.mjs.map
315
+ //# sourceMappingURL=stratal-D5smIU1y.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stratal-D5smIU1y.mjs","names":["tsyringeRootContainer"],"sources":["../src/application.ts","../src/stratal.ts"],"sourcesContent":["import { injectable, container as tsyringeRootContainer } from 'tsyringe'\nimport { CacheModule } from './cache'\nimport type { CronJob } from './cron/cron-job'\nimport { CronManager } from './cron/cron-manager'\nimport { Container } from './di/container'\nimport { DI_TOKENS } from './di/tokens'\nimport { Scope } from './di/types'\nimport { type StratalEnv } from './env'\nimport { ApplicationError, GlobalErrorHandler } from './errors'\nimport type { EventHandler } from './events'\nimport { EventRegistry, getListenerHandlers } from './events'\nimport type { StratalExecutionContext } from './execution-context'\nimport { I18nModule } from './i18n/i18n.module'\nimport { ConsoleTransport, JsonFormatter, LOGGER_TOKENS, LoggerService, LogLevel, PrettyFormatter } from './logger'\nimport { ModuleRegistry } from './module/module-registry'\nimport type { DynamicModule, ModuleClass } from './module/types'\nimport { OpenAPIModule } from './openapi'\nimport type { Command } from './quarry/command'\nimport { ApiCommand } from './quarry/commands/api.command'\nimport { EventListCommand } from './quarry/commands/event-list.command'\nimport { HelpCommand } from './quarry/commands/help.command'\nimport { McpServeCommand } from './quarry/commands/mcp-serve.command'\nimport { McpToolsCommand } from './quarry/commands/mcp-tools.command'\nimport { QueueListCommand } from './quarry/commands/queue-list.command'\nimport { RouteListCommand } from './quarry/commands/route-list.command'\nimport { ScheduleListCommand } from './quarry/commands/schedule-list.command'\nimport { QuarryRegistry } from './quarry/quarry-registry'\nimport type { CommandInput, CommandResult } from './quarry/types'\nimport { type ConsumerRegistry } from './queue/consumer-registry'\nimport type { IQueueConsumer, QueueMessage } from './queue/queue-consumer'\nimport { type QueueManager } from './queue/queue-manager'\nimport { QueueModule } from './queue/queue.module'\nimport { type IController, type RouterContext } from './router'\nimport { HonoApp } from './router/hono-app'\nimport type { VersioningOptions } from './router/types'\nimport { DbSeedCommand, DbSeedListCommand, SEEDER_TOKENS, SeederRegistry, type Seeder } from './seeder'\nimport type { Constructor } from './types'\n\nexport interface ApplicationConfig {\n /** Root application module */\n module: ModuleClass | DynamicModule\n /** Logging configuration. Defaults: level=INFO, formatter='json' */\n logging?: {\n level?: LogLevel\n formatter?: 'json' | 'pretty'\n }\n /**\n * API versioning configuration.\n * When provided, enables URI-based versioning for controllers.\n */\n versioning?: VersioningOptions\n}\n\nexport interface ApplicationOptions extends ApplicationConfig {\n env: StratalEnv\n ctx: StratalExecutionContext\n}\n\n/**\n * Application\n *\n * Main application class managing the two-tier container hierarchy:\n * - Global Container: All services (singletons via tsyringe native)\n * - Request Container: Child of global, context-enriched instances per request\n *\n * @example\n * ```typescript\n * const app = new Application({ module: AppModule, env, ctx })\n * await app.initialize()\n *\n * // Access container via getter\n * const service = app.container.resolve(MY_TOKEN)\n *\n * // Handle HTTP request (via HonoApp)\n * // Handle queue batch\n * await app.handleQueue(batch, 'my-queue')\n * ```\n */\nexport class Application {\n /**\n * Unified Container - manages all DI operations\n */\n private _container: Container\n\n private honoApp!: HonoApp\n private moduleRegistry: ModuleRegistry\n private consumerRegistry!: ConsumerRegistry\n private cronManager!: CronManager\n private quarry!: QuarryRegistry\n private initialized = false\n\n readonly env: StratalEnv\n private readonly appConfig: ApplicationConfig\n\n constructor({ env, ctx, ...config }: ApplicationOptions) {\n this.env = env\n this.appConfig = config\n\n ApplicationError.captureStackTraces = env.ENVIRONMENT !== 'production'\n\n // Create unified Container with explicit child container\n this._container = new Container({\n container: tsyringeRootContainer.createChildContainer()\n })\n\n // Register globally — env and ctx always available\n this._container.registerValue(DI_TOKENS.Application, this)\n this._container.registerValue(DI_TOKENS.CloudflareEnv, env)\n this._container.registerValue(DI_TOKENS.ExecutionContext, ctx)\n\n // Register core infrastructure inline\n this.registerLoggerService()\n this.registerCoreServices()\n\n // Create ModuleRegistry with our Container\n const logger = this._container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n this.moduleRegistry = new ModuleRegistry(this._container, logger)\n\n // Register ModuleRegistry in container so modules can access it in onInitialize\n this._container.registerValue(DI_TOKENS.ModuleRegistry, this.moduleRegistry)\n }\n\n /**\n * Get the Container instance\n */\n get container(): Container {\n return this._container\n }\n\n /**\n * Get the HonoApp instance\n */\n get hono(): HonoApp {\n return this.honoApp\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return\n }\n\n // Phase 1: Register core infrastructure modules (internal)\n this.moduleRegistry.registerAll([\n I18nModule,\n OpenAPIModule,\n QueueModule,\n CacheModule,\n ])\n\n // Phase 2: Register user's root module (traverses imports)\n this.moduleRegistry.register(this.appConfig.module)\n\n // Phase 3: Initialize all modules\n await this.moduleRegistry.initialize()\n\n // Phase 4: Resolve managers from container\n this.consumerRegistry = this._container.resolve<ConsumerRegistry>(DI_TOKENS.ConsumerRegistry)\n this.cronManager = this._container.resolve<CronManager>(DI_TOKENS.Cron)\n this.quarry = this._container.resolve<QuarryRegistry>(DI_TOKENS.Quarry)\n\n // Phase 5: Create & configure HonoApp\n const logger = this._container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n this.honoApp = new HonoApp(this._container, logger)\n const middlewareConfigs = this.moduleRegistry.getAllMiddlewareConfigs()\n const controllers = this.moduleRegistry.getAllControllers() as Constructor<IController>[]\n await this.honoApp.configure(middlewareConfigs, controllers, this.appConfig.versioning)\n\n // Phase 6: Configure queues, cron, events, commands, seeders\n this.registerQueueConsumers()\n this.registerCronJobs()\n this.registerEventListeners()\n this.registerSeeders()\n this.registerCommands()\n\n this.initialized = true\n }\n\n /**\n * Resolve a service from the container\n */\n resolve<T>(token: symbol): T {\n try {\n return this._container.resolve(token)\n } catch (error) {\n const errorHandler = this._container.resolve<GlobalErrorHandler>(DI_TOKENS.ErrorHandler)\n const errorResponse = errorHandler.handle(error)\n throw errorResponse as unknown as Error\n }\n }\n\n /**\n * Handle queue batch processing\n */\n async handleQueue(batch: MessageBatch, queueName: string): Promise<void> {\n const firstMessage = batch.messages[0]?.body as QueueMessage | undefined\n const locale = firstMessage?.metadata?.locale ?? 'en'\n const mockRouterContext = this.createMockRouterContext(locale)\n\n await this._container.runInRequestScope(mockRouterContext, async (requestContainer) => {\n try {\n const queueManager = requestContainer.resolve<QueueManager>(DI_TOKENS.Queue)\n await queueManager.processBatch(queueName, batch)\n } catch (error) {\n const errorHandler = requestContainer.resolve<GlobalErrorHandler>(DI_TOKENS.ErrorHandler)\n errorHandler.handle(error)\n throw error\n }\n })\n }\n\n /**\n * Handle scheduled cron trigger\n */\n async handleScheduled(controller: ScheduledController): Promise<void> {\n const mockRouterContext = this.createMockRouterContext('en')\n\n await this._container.runInRequestScope(mockRouterContext, async (requestContainer) => {\n try {\n await this.cronManager.executeScheduled(controller)\n } catch (error) {\n const errorHandler = requestContainer.resolve<GlobalErrorHandler>(DI_TOKENS.ErrorHandler)\n errorHandler.handle(error)\n throw error\n }\n })\n }\n\n /**\n * Create mock RouterContext for queue/cron/seeder processing\n */\n createMockRouterContext(locale = 'en'): RouterContext {\n return {\n getLocale: () => locale,\n setLocale: () => { /* no-op */ },\n getContainer: () => this._container,\n } as unknown as RouterContext\n }\n\n async shutdown(): Promise<void> {\n if (!this.initialized) return\n this.initialized = false\n\n await this.moduleRegistry.shutdown()\n\n const logger = this._container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n logger.info('Disposing container...')\n\n await this._container.dispose()\n }\n\n /**\n * Execute a command by name in a request-scoped container.\n */\n async handleCommand(name: string, input?: CommandInput): Promise<CommandResult> {\n const mockContext = this.createMockRouterContext('en')\n return this._container.runInRequestScope(mockContext, async () => {\n return this.quarry.call(name, input)\n })\n }\n\n private registerCommands(): void {\n // Built-in commands (always available)\n const builtinCommands: Constructor<Command>[] = [\n HelpCommand,\n DbSeedCommand, DbSeedListCommand,\n RouteListCommand, EventListCommand,\n ScheduleListCommand, QueueListCommand,\n McpServeCommand, McpToolsCommand, ApiCommand,\n ]\n for (const Cmd of builtinCommands) {\n injectable()(Cmd)\n this._container.register(Cmd, Cmd, Scope.Singleton)\n this.quarry.register(Cmd)\n }\n\n // User commands from modules\n const commands = this.moduleRegistry.getAllCommands()\n if (commands.length === 0) {\n return\n }\n\n for (const CommandClass of commands) {\n this.quarry.register(CommandClass as Constructor<Command>)\n }\n }\n\n private registerSeeders(): void {\n const seeders = this.moduleRegistry.getAllSeeders()\n if (seeders.length === 0) return\n const registry = this._container.resolve<SeederRegistry>(SEEDER_TOKENS.SeederRegistry)\n for (const SeederClass of seeders) {\n registry.register(SeederClass as Constructor<Seeder>)\n }\n }\n\n private registerQueueConsumers(): void {\n for (const ConsumerClass of this.moduleRegistry.getAllConsumers()) {\n const consumer = this._container.resolve(ConsumerClass) as IQueueConsumer\n this.consumerRegistry.register(consumer)\n }\n }\n\n private registerCronJobs(): void {\n for (const JobClass of this.moduleRegistry.getAllJobs()) {\n const job = this._container.resolve(JobClass) as CronJob\n this.cronManager.registerJob(job)\n }\n }\n\n /**\n * Auto-wire `@Listener()` classes with the EventRegistry.\n */\n private registerEventListeners(): void {\n const listeners = this.moduleRegistry.getAllListeners()\n if (listeners.length === 0) {\n return\n }\n\n const eventRegistry = this._container.resolve<EventRegistry>(DI_TOKENS.EventRegistry)\n\n for (const ListenerClass of listeners) {\n const instance = this._container.resolve(ListenerClass) as Record<string, ((...args: unknown[]) => unknown)>\n const handlers = getListenerHandlers(ListenerClass)\n\n for (const { methodName, event, options } of handlers) {\n eventRegistry.on(event, instance[methodName].bind(instance) as EventHandler, options)\n }\n }\n }\n\n /**\n * Register LoggerService and dependencies\n */\n private registerLoggerService(): void {\n const logLevel = this.appConfig.logging?.level ?? LogLevel.INFO\n const formatter = this.appConfig.logging?.formatter ?? 'json'\n\n this._container.registerValue(LOGGER_TOKENS.LogLevelOptions, logLevel)\n\n this._container\n .when(() => formatter === 'pretty')\n .use(LOGGER_TOKENS.Formatter)\n .give(PrettyFormatter)\n .otherwise(JsonFormatter)\n\n this._container.registerSingleton(LOGGER_TOKENS.ConsoleTransport, ConsoleTransport)\n this._container.registerFactory(LOGGER_TOKENS.Transports, (c) => [c.resolve(LOGGER_TOKENS.ConsoleTransport)])\n this._container.registerSingleton(LOGGER_TOKENS.LoggerService, LoggerService)\n }\n\n /**\n * Register core services with explicit scope\n */\n private registerCoreServices(): void {\n this._container.registerSingleton(DI_TOKENS.Cron, CronManager)\n this._container.register(DI_TOKENS.ErrorHandler, GlobalErrorHandler)\n this._container.registerSingleton(DI_TOKENS.EventRegistry, EventRegistry)\n this._container.registerSingleton(DI_TOKENS.Quarry, QuarryRegistry)\n this._container.registerValue(SEEDER_TOKENS.SeederRegistry, new SeederRegistry(this))\n }\n}\n","import 'reflect-metadata'\n\nimport { Application, type ApplicationConfig } from './application'\nimport type { StratalEnv } from './env'\nimport { StratalNotInitializedError } from './errors'\nimport type { HonoApp } from './router/hono-app'\n\n/**\n * Stratal — Hono-style entry point for Cloudflare Workers.\n *\n * Eagerly bootstraps the Application at construction time, dynamically\n * importing `cloudflare:workers` for env and waitUntil.\n *\n * @example\n * ```typescript\n * import { Stratal } from 'stratal'\n * import { AppModule } from './app.module'\n *\n * export default new Stratal({ module: AppModule })\n * ```\n */\nexport class Stratal<Env extends StratalEnv = StratalEnv> {\n private app: Application | null = null\n private initPromise: Promise<Application>\n\n private static _application: Promise<Application> | null = null\n\n constructor(config: ApplicationConfig) {\n this.fetch = this.fetch.bind(this)\n this.queue = this.queue.bind(this)\n this.scheduled = this.scheduled.bind(this)\n\n this.initPromise = this.prepareApp(config)\n Stratal._application = this.initPromise\n }\n\n async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {\n const app = await this.ensureReady()\n return app.hono.fetch(request, env, ctx)\n }\n\n async queue(batch: MessageBatch): Promise<void> {\n const app = await this.ensureReady()\n return app.handleQueue(batch, batch.queue)\n }\n\n async scheduled(controller: ScheduledController): Promise<void> {\n const app = await this.ensureReady()\n return app.handleScheduled(controller)\n }\n\n get hono(): Promise<HonoApp> {\n return this.initPromise.then(app => app.hono)\n }\n\n async shutdown(): Promise<void> {\n try { this.app = await this.initPromise } catch { /* ignore */ }\n if (this.app) {\n await this.app.shutdown()\n this.app = null\n }\n }\n\n /**\n * @internal\n * Resolves the Application instance from the static singleton.\n * Used by worker base classes (DurableObject, Workflow, WorkerEntrypoint)\n * to access the DI container without going through Cloudflare RPC.\n */\n static resolveApplication(): Promise<Application> {\n if (!Stratal._application) {\n throw new StratalNotInitializedError()\n }\n return Stratal._application\n }\n\n private async ensureReady(): Promise<Application> {\n this.app ??= await this.initPromise;\n return this.app\n }\n\n private async prepareApp(config: ApplicationConfig): Promise<Application> {\n const { env, waitUntil } = await import('cloudflare:workers')\n const app = new Application({ ...config, env: env as Env, ctx: { waitUntil } })\n await app.initialize()\n return app\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./chunk-D1SwGrFN.mjs";
2
- import { i as dimWhite, n as cyan, r as dim, s as yellow, t as bold } from "./colors-DJaRDXoS.mjs";
2
+ import { i as dimWhite, n as cyan, r as dim, s as yellow, t as bold } from "./colors-Y7WIFXs7.mjs";
3
3
  //#region src/quarry/usage-generator.ts
4
4
  var usage_generator_exports = /* @__PURE__ */ __exportAll({
5
5
  generateListing: () => generateListing,
@@ -155,4 +155,4 @@ function formatTable(rows) {
155
155
  //#endregion
156
156
  export { usage_generator_exports as n, generateUsage as t };
157
157
 
158
- //# sourceMappingURL=usage-generator-C9hWziY4.mjs.map
158
+ //# sourceMappingURL=usage-generator-CVIsENuE.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"usage-generator-C9hWziY4.mjs","names":[],"sources":["../src/quarry/usage-generator.ts"],"sourcesContent":["import { bold, cyan, dim, dimWhite, yellow } from './colors'\nimport type { ParsedSignature } from './types'\n\n/**\n * Generate formatted help/usage text from a parsed signature.\n *\n * Pure function, edge-compatible.\n */\nexport function generateUsage(signature: ParsedSignature, description?: string): string {\n const lines: string[] = []\n\n // Usage line\n lines.push(`${bold('Usage:')} ${bold(cyan('quarry ' + buildUsageLine(signature)))}`)\n\n // Description\n if (description) {\n lines.push('')\n lines.push(description)\n }\n\n // Arguments section\n if (signature.arguments.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Arguments:')))\n const argRows = signature.arguments.map((arg) => {\n const label = arg.name\n const parts: string[] = []\n\n if (arg.description) parts.push(arg.description)\n\n if (arg.isArray) {\n parts.push('(variadic)')\n } else if (arg.required) {\n parts.push('(required)')\n } else if (arg.default !== undefined) {\n parts.push(dim(`(default: ${arg.default})`))\n } else {\n parts.push('(optional)')\n }\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(argRows))\n }\n\n // Options section\n if (signature.options.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Options:')))\n const optRows = signature.options.map((opt) => {\n const flagParts: string[] = []\n if (opt.alias) flagParts.push(`-${opt.alias},`)\n flagParts.push(`--${opt.name}`)\n\n const label = flagParts.join(' ')\n const parts: string[] = []\n\n if (opt.description) parts.push(opt.description)\n if (!opt.isFlag && !opt.description) parts.push('Accepts a value')\n if (opt.isFlag && !opt.description) parts.push('Boolean flag')\n if (opt.isArray) parts.push('(multiple)')\n if (opt.default !== undefined) parts.push(dim(`(default: ${opt.default})`))\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(optRows))\n }\n\n return lines.join('\\n')\n}\n\nexport interface ListingOptions {\n binaryName?: string\n binaryLabel?: string\n binaryVersion?: string\n}\n\n/**\n * Generate a compact command listing with visual hierarchy.\n */\nexport function generateListing(\n commands: { name: string; description?: string; aliases: string[] }[],\n signatures: Map<string, ParsedSignature>,\n options?: ListingOptions,\n): string {\n const bin = options?.binaryName ?? 'quarry'\n const label = options?.binaryLabel ?? 'Quarry CLI'\n const version = options?.binaryVersion\n\n const lines: string[] = []\n\n // Header\n lines.push(bold(`${label}${version ? ` v${version}` : ''}`))\n lines.push('')\n\n // Usage\n lines.push(bold(yellow('Usage')))\n lines.push(` $ ${bin} <command> [options]`)\n lines.push('')\n\n // Commands\n if (commands.length === 0) {\n lines.push('No registered commands.')\n return lines.join('\\n')\n }\n\n lines.push(bold(yellow('Commands')))\n\n const termWidth = typeof process !== 'undefined'\n ? (process.stdout.columns as number | undefined) ?? 80\n : 80\n\n for (let i = 0; i < commands.length; i++) {\n const cmd = commands[i]\n const sig = signatures.get(cmd.name)\n const sigParts: string[] = [cyan(cmd.name)]\n\n if (cmd.aliases.length > 0) {\n sigParts.push(cyan(`(alias: ${cmd.aliases.join(', ')})`))\n }\n\n if (sig) {\n const inlineParts: string[] = []\n for (const arg of sig.arguments) {\n inlineParts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of sig.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n inlineParts.push(`[${flagStr}]`)\n }\n\n if (inlineParts.length > 0) {\n sigParts.push(dim(inlineParts.join(' ')))\n }\n }\n\n const sigLine = ' ' + sigParts.join(' ')\n lines.push(...wrapLine(sigLine, termWidth, ' '))\n\n if (cmd.description) {\n lines.push(` ${dimWhite(cmd.description)}`)\n }\n\n if (i < commands.length - 1) {\n lines.push('')\n }\n }\n\n lines.push('')\n\n // Footer\n lines.push(dimWhite(`Run ${bin} help <command> for detailed information.`))\n\n return lines.join('\\n')\n}\n\n/** Format a single argument into its placeholder representation (e.g. `<name>`, `[name=default]`). */\nfunction formatArgPlaceholder(arg: ParsedSignature['arguments'][number]): string {\n if (arg.isArray) return `<${arg.name}...>`\n if (arg.required) return `<${arg.name}>`\n if (arg.default !== undefined) return `[${arg.name}=${arg.default}]`\n return `[${arg.name}]`\n}\n\n/** Build the inline usage line showing the command name with argument and option placeholders. */\nfunction buildUsageLine(signature: ParsedSignature): string {\n const parts = [signature.name]\n\n for (const arg of signature.arguments) {\n parts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of signature.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n\n if (opt.isFlag) {\n parts.push(`[${flagStr}]`)\n } else if (opt.isArray) {\n parts.push(`[${flagStr} <value...>]`)\n } else {\n parts.push(`[${flagStr} <value>]`)\n }\n }\n\n return parts.join(' ')\n}\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;]*m/g\n\n/** Remove ANSI escape sequences from a string. */\nfunction stripAnsi(s: string): string {\n return s.replace(ANSI_RE, '')\n}\n\n// eslint-disable-next-line no-control-regex\nconst TOKEN_RE = /(?:\\x1b\\[[0-9;]*m)*[^\\s\\x1b]+(?:\\x1b\\[[0-9;]*m)*/g\n\n/** Wrap a single line at word boundaries, preserving ANSI codes across wrapped segments. */\nfunction wrapLine(text: string, maxWidth: number, continuationIndent: string): string[] {\n const visibleLen = stripAnsi(text).length\n if (visibleLen <= maxWidth) return [text]\n\n const tokens = text.match(TOKEN_RE) ?? [text]\n\n const lines: string[] = []\n let currentLine = ''\n let currentVisibleLen = 0\n\n for (const token of tokens) {\n const tokenVisible = stripAnsi(token).length\n const separator = currentLine === '' ? '' : ' '\n const separatorLen = separator.length\n\n if (currentLine !== '' && currentVisibleLen + separatorLen + tokenVisible > maxWidth) {\n lines.push(currentLine)\n currentLine = continuationIndent + token\n currentVisibleLen = continuationIndent.length + tokenVisible\n } else {\n currentLine += separator + token\n currentVisibleLen += separatorLen + tokenVisible\n }\n }\n\n if (currentLine !== '') {\n lines.push(currentLine)\n }\n\n return lines\n}\n\n/** Format label/description pairs into aligned two-column table rows. */\nfunction formatTable(rows: readonly (readonly [string, string])[]): string[] {\n if (rows.length === 0) return []\n\n const maxLabel = Math.max(...rows.map(([label]) => stripAnsi(label).length))\n const padding = 4\n\n return rows.map(([label, desc]) => {\n const visibleLen = stripAnsi(label).length\n const pad = ' '.repeat(maxLabel - visibleLen + padding)\n return ` ${label}${pad}${desc}`\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"usage-generator-CVIsENuE.mjs","names":[],"sources":["../src/quarry/usage-generator.ts"],"sourcesContent":["import { bold, cyan, dim, dimWhite, yellow } from './colors'\nimport type { ParsedSignature } from './types'\n\n/**\n * Generate formatted help/usage text from a parsed signature.\n *\n * Pure function, edge-compatible.\n */\nexport function generateUsage(signature: ParsedSignature, description?: string): string {\n const lines: string[] = []\n\n // Usage line\n lines.push(`${bold('Usage:')} ${bold(cyan('quarry ' + buildUsageLine(signature)))}`)\n\n // Description\n if (description) {\n lines.push('')\n lines.push(description)\n }\n\n // Arguments section\n if (signature.arguments.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Arguments:')))\n const argRows = signature.arguments.map((arg) => {\n const label = arg.name\n const parts: string[] = []\n\n if (arg.description) parts.push(arg.description)\n\n if (arg.isArray) {\n parts.push('(variadic)')\n } else if (arg.required) {\n parts.push('(required)')\n } else if (arg.default !== undefined) {\n parts.push(dim(`(default: ${arg.default})`))\n } else {\n parts.push('(optional)')\n }\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(argRows))\n }\n\n // Options section\n if (signature.options.length > 0) {\n lines.push('')\n lines.push(bold(yellow('Options:')))\n const optRows = signature.options.map((opt) => {\n const flagParts: string[] = []\n if (opt.alias) flagParts.push(`-${opt.alias},`)\n flagParts.push(`--${opt.name}`)\n\n const label = flagParts.join(' ')\n const parts: string[] = []\n\n if (opt.description) parts.push(opt.description)\n if (!opt.isFlag && !opt.description) parts.push('Accepts a value')\n if (opt.isFlag && !opt.description) parts.push('Boolean flag')\n if (opt.isArray) parts.push('(multiple)')\n if (opt.default !== undefined) parts.push(dim(`(default: ${opt.default})`))\n\n return [label, parts.join(' ')] as const\n })\n lines.push(...formatTable(optRows))\n }\n\n return lines.join('\\n')\n}\n\nexport interface ListingOptions {\n binaryName?: string\n binaryLabel?: string\n binaryVersion?: string\n}\n\n/**\n * Generate a compact command listing with visual hierarchy.\n */\nexport function generateListing(\n commands: { name: string; description?: string; aliases: string[] }[],\n signatures: Map<string, ParsedSignature>,\n options?: ListingOptions,\n): string {\n const bin = options?.binaryName ?? 'quarry'\n const label = options?.binaryLabel ?? 'Quarry CLI'\n const version = options?.binaryVersion\n\n const lines: string[] = []\n\n // Header\n lines.push(bold(`${label}${version ? ` v${version}` : ''}`))\n lines.push('')\n\n // Usage\n lines.push(bold(yellow('Usage')))\n lines.push(` $ ${bin} <command> [options]`)\n lines.push('')\n\n // Commands\n if (commands.length === 0) {\n lines.push('No registered commands.')\n return lines.join('\\n')\n }\n\n lines.push(bold(yellow('Commands')))\n\n const termWidth = typeof process !== 'undefined'\n ? (process.stdout.columns as number | undefined) ?? 80\n : 80\n\n for (let i = 0; i < commands.length; i++) {\n const cmd = commands[i]\n const sig = signatures.get(cmd.name)\n const sigParts: string[] = [cyan(cmd.name)]\n\n if (cmd.aliases.length > 0) {\n sigParts.push(cyan(`(alias: ${cmd.aliases.join(', ')})`))\n }\n\n if (sig) {\n const inlineParts: string[] = []\n for (const arg of sig.arguments) {\n inlineParts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of sig.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n inlineParts.push(`[${flagStr}]`)\n }\n\n if (inlineParts.length > 0) {\n sigParts.push(dim(inlineParts.join(' ')))\n }\n }\n\n const sigLine = ' ' + sigParts.join(' ')\n lines.push(...wrapLine(sigLine, termWidth, ' '))\n\n if (cmd.description) {\n lines.push(` ${dimWhite(cmd.description)}`)\n }\n\n if (i < commands.length - 1) {\n lines.push('')\n }\n }\n\n lines.push('')\n\n // Footer\n lines.push(dimWhite(`Run ${bin} help <command> for detailed information.`))\n\n return lines.join('\\n')\n}\n\n/** Format a single argument into its placeholder representation (e.g. `<name>`, `[name=default]`). */\nfunction formatArgPlaceholder(arg: ParsedSignature['arguments'][number]): string {\n if (arg.isArray) return `<${arg.name}...>`\n if (arg.required) return `<${arg.name}>`\n if (arg.default !== undefined) return `[${arg.name}=${arg.default}]`\n return `[${arg.name}]`\n}\n\n/** Build the inline usage line showing the command name with argument and option placeholders. */\nfunction buildUsageLine(signature: ParsedSignature): string {\n const parts = [signature.name]\n\n for (const arg of signature.arguments) {\n parts.push(formatArgPlaceholder(arg))\n }\n\n for (const opt of signature.options) {\n const flagStr = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n\n if (opt.isFlag) {\n parts.push(`[${flagStr}]`)\n } else if (opt.isArray) {\n parts.push(`[${flagStr} <value...>]`)\n } else {\n parts.push(`[${flagStr} <value>]`)\n }\n }\n\n return parts.join(' ')\n}\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;]*m/g\n\n/** Remove ANSI escape sequences from a string. */\nfunction stripAnsi(s: string): string {\n return s.replace(ANSI_RE, '')\n}\n\n// eslint-disable-next-line no-control-regex\nconst TOKEN_RE = /(?:\\x1b\\[[0-9;]*m)*[^\\s\\x1b]+(?:\\x1b\\[[0-9;]*m)*/g\n\n/** Wrap a single line at word boundaries, preserving ANSI codes across wrapped segments. */\nfunction wrapLine(text: string, maxWidth: number, continuationIndent: string): string[] {\n const visibleLen = stripAnsi(text).length\n if (visibleLen <= maxWidth) return [text]\n\n const tokens = text.match(TOKEN_RE) ?? [text]\n\n const lines: string[] = []\n let currentLine = ''\n let currentVisibleLen = 0\n\n for (const token of tokens) {\n const tokenVisible = stripAnsi(token).length\n const separator = currentLine === '' ? '' : ' '\n const separatorLen = separator.length\n\n if (currentLine !== '' && currentVisibleLen + separatorLen + tokenVisible > maxWidth) {\n lines.push(currentLine)\n currentLine = continuationIndent + token\n currentVisibleLen = continuationIndent.length + tokenVisible\n } else {\n currentLine += separator + token\n currentVisibleLen += separatorLen + tokenVisible\n }\n }\n\n if (currentLine !== '') {\n lines.push(currentLine)\n }\n\n return lines\n}\n\n/** Format label/description pairs into aligned two-column table rows. */\nfunction formatTable(rows: readonly (readonly [string, string])[]): string[] {\n if (rows.length === 0) return []\n\n const maxLabel = Math.max(...rows.map(([label]) => stripAnsi(label).length))\n const padding = 4\n\n return rows.map(([label, desc]) => {\n const visibleLen = stripAnsi(label).length\n const pad = ' '.repeat(maxLabel - visibleLen + padding)\n return ` ${label}${pad}${desc}`\n })\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { n as __reExport, t as __exportAll } from "./chunk-D1SwGrFN.mjs";
2
- import { OpenAPIHono, z } from "@hono/zod-openapi";
2
+ import { OpenAPIHono, z as z$1 } from "@hono/zod-openapi";
3
3
  import { ZodError } from "zod";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  //#region src/i18n/validation/validation.error-map.ts
@@ -184,11 +184,11 @@ var validation_exports = /* @__PURE__ */ __exportAll({
184
184
  backendErrorMap: () => backendErrorMap,
185
185
  runWithErrorMapContext: () => runWithErrorMapContext,
186
186
  withI18n: () => withI18n,
187
- z: () => z
187
+ z: () => z$1
188
188
  });
189
189
  import * as import__hono_zod_openapi from "@hono/zod-openapi";
190
190
  __reExport(validation_exports, import__hono_zod_openapi);
191
191
  //#endregion
192
- export { withI18n as a, z as i, ZodError as n, backendErrorMap as o, validation_exports as r, runWithErrorMapContext as s, OpenAPIHono as t };
192
+ export { withI18n as a, z$1 as i, ZodError as n, backendErrorMap as o, validation_exports as r, runWithErrorMapContext as s, OpenAPIHono as t };
193
193
 
194
- //# sourceMappingURL=validation-Bh875Lyg.mjs.map
194
+ //# sourceMappingURL=validation-DQTC259A.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation-Bh875Lyg.mjs","names":[],"sources":["../src/i18n/validation/validation.error-map.ts","../src/i18n/validation/validation.context.ts","../src/i18n/validation/with-i18n.ts","../src/i18n/validation/index.ts"],"sourcesContent":["import type {\n $ZodErrorMap,\n $ZodIssueInvalidKey,\n $ZodIssueInvalidStringFormat,\n $ZodIssueInvalidType,\n $ZodIssueInvalidUnion,\n $ZodIssueNotMultipleOf,\n $ZodIssueTooBig,\n $ZodIssueTooSmall,\n $ZodIssueUnrecognizedKeys,\n $ZodRawIssue,\n} from 'zod/v4/core'\nimport type { MessageKeys } from '../i18n.types'\nimport type { ErrorMapContext } from './validation.types'\n\n/**\n * Type guards for narrowing Zod v4 issue types\n */\nfunction isInvalidType(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidType> {\n return issue.code === 'invalid_type'\n}\n\nfunction isTooBig(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueTooBig> {\n return issue.code === 'too_big'\n}\n\nfunction isTooSmall(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueTooSmall> {\n return issue.code === 'too_small'\n}\n\nfunction isInvalidFormat(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidStringFormat> {\n return issue.code === 'invalid_format'\n}\n\nfunction isNotMultipleOf(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueNotMultipleOf> {\n return issue.code === 'not_multiple_of'\n}\n\nfunction isUnrecognizedKeys(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueUnrecognizedKeys> {\n return issue.code === 'unrecognized_keys'\n}\n\nfunction isInvalidUnion(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidUnion> {\n return issue.code === 'invalid_union'\n}\n\nfunction isInvalidKey(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidKey> {\n return issue.code === 'invalid_key'\n}\n\n/**\n * Maps Zod issue codes to zodI18n message keys\n * Adapted for Zod v4's simpler issue code system\n */\nfunction getMessageKey(issue: $ZodRawIssue): MessageKeys {\n if (isInvalidType(issue)) {\n if (issue.input === undefined) {\n return 'zodI18n.errors.required'\n }\n return 'zodI18n.errors.invalid_type'\n }\n\n if (isTooSmall(issue)) {\n const typeKey = issue.origin || 'string'\n const exactKey = issue.exact\n ? 'exact'\n : issue.inclusive\n ? 'inclusive'\n : 'not_inclusive'\n return `zodI18n.errors.too_small.${typeKey}.${exactKey}` as MessageKeys\n }\n\n if (isTooBig(issue)) {\n const typeKey = issue.origin || 'string'\n const exactKey = issue.exact\n ? 'exact'\n : issue.inclusive\n ? 'inclusive'\n : 'not_inclusive'\n return `zodI18n.errors.too_big.${typeKey}.${exactKey}` as MessageKeys\n }\n\n if (isInvalidFormat(issue)) {\n // Map v4's format to v3-style validation keys\n return `zodI18n.errors.invalid_string.${issue.format}` as MessageKeys\n }\n\n if (isNotMultipleOf(issue)) {\n return 'zodI18n.errors.not_multiple_of'\n }\n\n if (isUnrecognizedKeys(issue)) {\n return 'zodI18n.errors.unrecognized_keys'\n }\n\n if (isInvalidUnion(issue)) {\n return 'zodI18n.errors.invalid_union'\n }\n\n if (isInvalidKey(issue)) {\n // v4: Replaces invalid_enum_value, invalid_literal\n return 'zodI18n.errors.invalid_enum_value'\n }\n\n // invalid_element, invalid_value, or unknown codes\n return 'zodI18n.errors.custom.default'\n}\n\n/**\n * Extracts interpolation parameters from Zod issue\n * Uses proper type narrowing for v4\n */\nfunction getMessageParams(issue: $ZodRawIssue): Record<string, unknown> {\n const params: Record<string, unknown> = {}\n\n if (isInvalidType(issue)) {\n params.expected = issue.expected\n params.received = String(issue.input)\n return params\n }\n\n if (isUnrecognizedKeys(issue)) {\n params.keys = issue.keys.join(', ')\n return params\n }\n\n if (isInvalidKey(issue)) {\n // v4: For enums and records\n // Since v4 doesn't have options field, we'll use generic message\n return params\n }\n\n if (isInvalidFormat(issue)) {\n params.validation = issue.format\n\n // Check for specific string format issues with additional fields\n if ('prefix' in issue) {\n params.startsWith = (issue as { prefix?: string }).prefix\n }\n if ('suffix' in issue) {\n params.endsWith = (issue as { suffix?: string }).suffix\n }\n if ('includes' in issue) {\n params.includes = (issue as { includes?: string }).includes\n }\n if (issue.pattern) {\n params.pattern = issue.pattern\n }\n\n return params\n }\n\n if (isTooSmall(issue)) {\n params.minimum = issue.minimum\n params.type = issue.origin\n if (issue.origin === 'date') {\n params.minimum = new Date(Number(issue.minimum)).toLocaleDateString()\n }\n return params\n }\n\n if (isTooBig(issue)) {\n params.maximum = issue.maximum\n params.type = issue.origin\n if (issue.origin === 'date') {\n params.maximum = new Date(Number(issue.maximum)).toLocaleDateString()\n }\n return params\n }\n\n if (isNotMultipleOf(issue)) {\n params.multipleOf = issue.divisor\n return params\n }\n\n return params\n}\n\n/**\n * Creates a Zod error map that uses i18n for translation\n * Uses Zod v4 native $ZodErrorMap signature (no ctx parameter)\n */\nexport function createI18nErrorMap(getContext: () => ErrorMapContext | undefined): $ZodErrorMap {\n return (issue: $ZodRawIssue): { message: string } => {\n // Get message key and params for this issue\n const messageKey = getMessageKey(issue)\n const messageParams = getMessageParams(issue)\n\n // Get translation context\n const context = getContext()\n\n if (!context) {\n // Fallback: Use English messages directly\n // This handles config validation at startup, tests, etc.\n return { message: 'Invalid input' }\n }\n\n // Normal flow: Use context-aware i18n (respects user locale)\n return {\n message: context.t(messageKey, messageParams),\n }\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { ErrorMapContext } from './validation.types'\nimport { createI18nErrorMap } from './validation.error-map'\n\n/**\n * AsyncLocalStorage for storing request-scoped ErrorMapContext\n * Allows error map to access I18nService without passing through function calls\n */\nexport const errorMapContextStorage = new AsyncLocalStorage<ErrorMapContext>()\n\n/**\n * Gets the current error map context from AsyncLocalStorage\n */\nfunction getErrorMapContext(): ErrorMapContext | undefined {\n return errorMapContextStorage.getStore()\n}\n\n/**\n * Backend error map that accesses I18nService from AsyncLocalStorage\n * Must be initialized in router middleware after locale detection\n */\nexport const backendErrorMap = createI18nErrorMap(getErrorMapContext)\n\n/**\n * Runs a function within an error map context\n * Used by router middleware to provide I18nService to validation\n *\n * @example\n * ```typescript\n * router.use('*', async (c, next) => {\n * const i18nService = c.get('i18nService')\n * const locale = c.get('locale')\n *\n * return runWithErrorMapContext(\n * {\n * t: (key, params) => i18nService.t(key, params),\n * locale,\n * },\n * () => next()\n * )\n * })\n * ```\n */\nexport function runWithErrorMapContext<T>(\n context: ErrorMapContext,\n fn: () => T\n): T {\n return errorMapContextStorage.run(context, fn)\n}\n","import type { MessageKeys } from '../i18n.types'\nimport { errorMapContextStorage } from './validation.context'\n\n/**\n * Type-safe helper for creating custom Zod error messages with i18n support (Backend)\n *\n * Usage with .refine():\n * ```typescript\n * const schema = z.string().refine(\n * (val) => val.length > 5,\n * withI18n('validation.minLength', { min: 5 })\n * )\n * ```\n *\n * Usage with built-in validators:\n * ```typescript\n * const schema = z.string().min(5, withI18n('validation.minLength', { min: 5 }))\n * const schema = z.string().email(withI18n('validation.email'))\n * ```\n *\n * Note: This is the backend version using AsyncLocalStorage.\n * For frontend, use withI18nFrontend from the frontend validation module\n *\n * @param key - Message key from shared i18n messages (type-safe via MessageKeys)\n * @param params - Optional interpolation parameters for the message\n * @returns Zod error configuration object with translated message\n */\nexport function withI18n(\n key: MessageKeys,\n params?: Record<string, unknown>\n): { error: () => string } {\n return {\n error: () => {\n // Get i18n context from AsyncLocalStorage (backend)\n // This is set by the router middleware before validation\n const context = errorMapContextStorage.getStore()\n\n // Translate using context if available, otherwise fallback to generic message\n const message = context\n ? context.t(key, params as Record<string, string | number> | undefined)\n : 'Invalid input'\n\n return message\n },\n }\n}\n","// Consolidated zod - single source from @hono/zod-openapi (superset of zod)\nexport { OpenAPIHono, z } from '@hono/zod-openapi'\nexport type * from 'zod'\nexport { ZodError } from 'zod'\n\n// OpenAPI utilities\nexport * from '@hono/zod-openapi'\nexport type { OpenAPIObject, PathItemObject } from 'openapi3-ts/oas30'\n\n// Helpers\nexport { withI18n } from './with-i18n'\n\n// Backend utilities\nexport { backendErrorMap, runWithErrorMapContext } from './validation.context'\n\n// Types\nexport type { ErrorMapContext, I18nErrorMetadata, LocaleProvider, ZodCustomIssue } from './validation.types'\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"validation-DQTC259A.mjs","names":[],"sources":["../src/i18n/validation/validation.error-map.ts","../src/i18n/validation/validation.context.ts","../src/i18n/validation/with-i18n.ts","../src/i18n/validation/index.ts"],"sourcesContent":["import type {\n $ZodErrorMap,\n $ZodIssueInvalidKey,\n $ZodIssueInvalidStringFormat,\n $ZodIssueInvalidType,\n $ZodIssueInvalidUnion,\n $ZodIssueNotMultipleOf,\n $ZodIssueTooBig,\n $ZodIssueTooSmall,\n $ZodIssueUnrecognizedKeys,\n $ZodRawIssue,\n} from 'zod/v4/core'\nimport type { MessageKeys } from '../i18n.types'\nimport type { ErrorMapContext } from './validation.types'\n\n/**\n * Type guards for narrowing Zod v4 issue types\n */\nfunction isInvalidType(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidType> {\n return issue.code === 'invalid_type'\n}\n\nfunction isTooBig(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueTooBig> {\n return issue.code === 'too_big'\n}\n\nfunction isTooSmall(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueTooSmall> {\n return issue.code === 'too_small'\n}\n\nfunction isInvalidFormat(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidStringFormat> {\n return issue.code === 'invalid_format'\n}\n\nfunction isNotMultipleOf(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueNotMultipleOf> {\n return issue.code === 'not_multiple_of'\n}\n\nfunction isUnrecognizedKeys(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueUnrecognizedKeys> {\n return issue.code === 'unrecognized_keys'\n}\n\nfunction isInvalidUnion(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidUnion> {\n return issue.code === 'invalid_union'\n}\n\nfunction isInvalidKey(issue: $ZodRawIssue): issue is $ZodRawIssue<$ZodIssueInvalidKey> {\n return issue.code === 'invalid_key'\n}\n\n/**\n * Maps Zod issue codes to zodI18n message keys\n * Adapted for Zod v4's simpler issue code system\n */\nfunction getMessageKey(issue: $ZodRawIssue): MessageKeys {\n if (isInvalidType(issue)) {\n if (issue.input === undefined) {\n return 'zodI18n.errors.required'\n }\n return 'zodI18n.errors.invalid_type'\n }\n\n if (isTooSmall(issue)) {\n const typeKey = issue.origin || 'string'\n const exactKey = issue.exact\n ? 'exact'\n : issue.inclusive\n ? 'inclusive'\n : 'not_inclusive'\n return `zodI18n.errors.too_small.${typeKey}.${exactKey}` as MessageKeys\n }\n\n if (isTooBig(issue)) {\n const typeKey = issue.origin || 'string'\n const exactKey = issue.exact\n ? 'exact'\n : issue.inclusive\n ? 'inclusive'\n : 'not_inclusive'\n return `zodI18n.errors.too_big.${typeKey}.${exactKey}` as MessageKeys\n }\n\n if (isInvalidFormat(issue)) {\n // Map v4's format to v3-style validation keys\n return `zodI18n.errors.invalid_string.${issue.format}` as MessageKeys\n }\n\n if (isNotMultipleOf(issue)) {\n return 'zodI18n.errors.not_multiple_of'\n }\n\n if (isUnrecognizedKeys(issue)) {\n return 'zodI18n.errors.unrecognized_keys'\n }\n\n if (isInvalidUnion(issue)) {\n return 'zodI18n.errors.invalid_union'\n }\n\n if (isInvalidKey(issue)) {\n // v4: Replaces invalid_enum_value, invalid_literal\n return 'zodI18n.errors.invalid_enum_value'\n }\n\n // invalid_element, invalid_value, or unknown codes\n return 'zodI18n.errors.custom.default'\n}\n\n/**\n * Extracts interpolation parameters from Zod issue\n * Uses proper type narrowing for v4\n */\nfunction getMessageParams(issue: $ZodRawIssue): Record<string, unknown> {\n const params: Record<string, unknown> = {}\n\n if (isInvalidType(issue)) {\n params.expected = issue.expected\n params.received = String(issue.input)\n return params\n }\n\n if (isUnrecognizedKeys(issue)) {\n params.keys = issue.keys.join(', ')\n return params\n }\n\n if (isInvalidKey(issue)) {\n // v4: For enums and records\n // Since v4 doesn't have options field, we'll use generic message\n return params\n }\n\n if (isInvalidFormat(issue)) {\n params.validation = issue.format\n\n // Check for specific string format issues with additional fields\n if ('prefix' in issue) {\n params.startsWith = (issue as { prefix?: string }).prefix\n }\n if ('suffix' in issue) {\n params.endsWith = (issue as { suffix?: string }).suffix\n }\n if ('includes' in issue) {\n params.includes = (issue as { includes?: string }).includes\n }\n if (issue.pattern) {\n params.pattern = issue.pattern\n }\n\n return params\n }\n\n if (isTooSmall(issue)) {\n params.minimum = issue.minimum\n params.type = issue.origin\n if (issue.origin === 'date') {\n params.minimum = new Date(Number(issue.minimum)).toLocaleDateString()\n }\n return params\n }\n\n if (isTooBig(issue)) {\n params.maximum = issue.maximum\n params.type = issue.origin\n if (issue.origin === 'date') {\n params.maximum = new Date(Number(issue.maximum)).toLocaleDateString()\n }\n return params\n }\n\n if (isNotMultipleOf(issue)) {\n params.multipleOf = issue.divisor\n return params\n }\n\n return params\n}\n\n/**\n * Creates a Zod error map that uses i18n for translation\n * Uses Zod v4 native $ZodErrorMap signature (no ctx parameter)\n */\nexport function createI18nErrorMap(getContext: () => ErrorMapContext | undefined): $ZodErrorMap {\n return (issue: $ZodRawIssue): { message: string } => {\n // Get message key and params for this issue\n const messageKey = getMessageKey(issue)\n const messageParams = getMessageParams(issue)\n\n // Get translation context\n const context = getContext()\n\n if (!context) {\n // Fallback: Use English messages directly\n // This handles config validation at startup, tests, etc.\n return { message: 'Invalid input' }\n }\n\n // Normal flow: Use context-aware i18n (respects user locale)\n return {\n message: context.t(messageKey, messageParams),\n }\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { ErrorMapContext } from './validation.types'\nimport { createI18nErrorMap } from './validation.error-map'\n\n/**\n * AsyncLocalStorage for storing request-scoped ErrorMapContext\n * Allows error map to access I18nService without passing through function calls\n */\nexport const errorMapContextStorage = new AsyncLocalStorage<ErrorMapContext>()\n\n/**\n * Gets the current error map context from AsyncLocalStorage\n */\nfunction getErrorMapContext(): ErrorMapContext | undefined {\n return errorMapContextStorage.getStore()\n}\n\n/**\n * Backend error map that accesses I18nService from AsyncLocalStorage\n * Must be initialized in router middleware after locale detection\n */\nexport const backendErrorMap = createI18nErrorMap(getErrorMapContext)\n\n/**\n * Runs a function within an error map context\n * Used by router middleware to provide I18nService to validation\n *\n * @example\n * ```typescript\n * router.use('*', async (c, next) => {\n * const i18nService = c.get('i18nService')\n * const locale = c.get('locale')\n *\n * return runWithErrorMapContext(\n * {\n * t: (key, params) => i18nService.t(key, params),\n * locale,\n * },\n * () => next()\n * )\n * })\n * ```\n */\nexport function runWithErrorMapContext<T>(\n context: ErrorMapContext,\n fn: () => T\n): T {\n return errorMapContextStorage.run(context, fn)\n}\n","import type { MessageKeys } from '../i18n.types'\nimport { errorMapContextStorage } from './validation.context'\n\n/**\n * Type-safe helper for creating custom Zod error messages with i18n support (Backend)\n *\n * Usage with .refine():\n * ```typescript\n * const schema = z.string().refine(\n * (val) => val.length > 5,\n * withI18n('validation.minLength', { min: 5 })\n * )\n * ```\n *\n * Usage with built-in validators:\n * ```typescript\n * const schema = z.string().min(5, withI18n('validation.minLength', { min: 5 }))\n * const schema = z.string().email(withI18n('validation.email'))\n * ```\n *\n * Note: This is the backend version using AsyncLocalStorage.\n * For frontend, use withI18nFrontend from the frontend validation module\n *\n * @param key - Message key from shared i18n messages (type-safe via MessageKeys)\n * @param params - Optional interpolation parameters for the message\n * @returns Zod error configuration object with translated message\n */\nexport function withI18n(\n key: MessageKeys,\n params?: Record<string, unknown>\n): { error: () => string } {\n return {\n error: () => {\n // Get i18n context from AsyncLocalStorage (backend)\n // This is set by the router middleware before validation\n const context = errorMapContextStorage.getStore()\n\n // Translate using context if available, otherwise fallback to generic message\n const message = context\n ? context.t(key, params as Record<string, string | number> | undefined)\n : 'Invalid input'\n\n return message\n },\n }\n}\n","// Consolidated zod - single source from @hono/zod-openapi (superset of zod)\nexport { OpenAPIHono, z } from '@hono/zod-openapi'\nexport type * from 'zod'\nexport { ZodError } from 'zod'\n\n// OpenAPI utilities\nexport * from '@hono/zod-openapi'\nexport type { OpenAPIObject, PathItemObject } from 'openapi3-ts/oas30'\n\n// Helpers\nexport { withI18n } from './with-i18n'\n\n// Backend utilities\nexport { backendErrorMap, runWithErrorMapContext } from './validation.context'\n\n// Types\nexport type { ErrorMapContext, I18nErrorMetadata, LocaleProvider, ZodCustomIssue } from './validation.types'\n\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Et as ControllerOptions, Nt as RouterEnv, Tt as RouterContext, s as ApplicationError, wt as ContextQueryResult } from "../index-BJWm863C.mjs";
1
+ import { Dt as ControllerOptions, Et as RouterContext, Pt as RouterEnv, Tt as ContextQueryResult, s as ApplicationError } from "../index-BFCxSp_f.mjs";
2
2
  import { t as Constructor } from "../types-DahElfUw.mjs";
3
3
  import { Context } from "hono";
4
4
  import { WSContext, WSContext as WSContext$1, WSEvents, WSMessageReceive, WSReadyState, WSReadyState as WSReadyState$1 } from "hono/ws";
@@ -1,6 +1,5 @@
1
- import "../errors-CtCi1wn6.mjs";
2
- import "../decorate-D5j-d9_z.mjs";
3
- import "../logger-BR1-s1Um.mjs";
4
- import "../router-context-BEJe9HEB.mjs";
5
- import { a as OnMessage, c as getWsOnMessageMethod, d as isGateway, i as OnError, l as WebSocketDuplicateEventHandlerError, n as WebSocketBodyNotAvailableError, o as getWsOnCloseMethod, r as OnClose, s as getWsOnErrorMethod, t as GatewayContext, u as Gateway } from "../gateway-context-BkZ4UKaX.mjs";
1
+ import "../errors-DSKapqD8.mjs";
2
+ import "../logger-CGT91VY6.mjs";
3
+ import "../router-context-D9R1v2Ac.mjs";
4
+ import { a as OnMessage, c as getWsOnMessageMethod, d as isGateway, i as OnError, l as WebSocketDuplicateEventHandlerError, n as WebSocketBodyNotAvailableError, o as getWsOnCloseMethod, r as OnClose, s as getWsOnErrorMethod, t as GatewayContext, u as Gateway } from "../gateway-context-CNOLkLUC.mjs";
6
5
  export { Gateway, GatewayContext, OnClose, OnError, OnMessage, WebSocketBodyNotAvailableError, WebSocketDuplicateEventHandlerError, getWsOnCloseMethod, getWsOnErrorMethod, getWsOnMessageMethod, isGateway };
@@ -1,4 +1,4 @@
1
- import { $t as Container, Ht as StratalEnv } from "../index-BJWm863C.mjs";
1
+ import { Ut as StratalEnv, en as Container } from "../index-BFCxSp_f.mjs";
2
2
  import { DurableObject, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
3
3
 
4
4
  //#region src/workers/run-in-scope.d.ts
@@ -1,23 +1,23 @@
1
- import "../errors-CtCi1wn6.mjs";
2
- import { l as DI_TOKENS } from "../decorate-D5j-d9_z.mjs";
3
- import "../logger-BR1-s1Um.mjs";
4
- import "../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 "../cron-manager-DR7fiG6o.mjs";
13
- import "../validation-Bh875Lyg.mjs";
14
- import "../i18n.module-W8OJxg3d.mjs";
1
+ import "../errors-DSKapqD8.mjs";
2
+ import { g as DI_TOKENS } from "../logger-CGT91VY6.mjs";
3
+ import "../module-tUtyVJ5E.mjs";
4
+ import "../events-CvUSgEuN.mjs";
5
+ import "../middleware-Bl-b5pkt.mjs";
6
+ import "../router-context-D9R1v2Ac.mjs";
7
+ import "../colors-Y7WIFXs7.mjs";
8
+ import "../command-B1CPgsrU.mjs";
9
+ import "../is-command-DJVI6wEJ.mjs";
10
+ import "../is-seeder-D5MIEcdz.mjs";
11
+ import "../cron-manager-CFBamKKk.mjs";
12
+ import "../validation-DQTC259A.mjs";
13
+ import "../i18n.module-Dn9SrFdS.mjs";
14
+ import "../openapi-tools.service-B3TxYKoQ.mjs";
15
15
  import "../guards-DUk_Kzst.mjs";
16
- import "../gateway-context-BkZ4UKaX.mjs";
17
- import "../quarry-registry-DCwqVcRp.mjs";
18
- import "../queue.module-BZvmeAMj.mjs";
19
- import "../seeder-Cupi5jl-.mjs";
20
- import { t as Stratal } from "../stratal-CE0iTz4f.mjs";
16
+ import "../gateway-context-CNOLkLUC.mjs";
17
+ import "../quarry-registry-B2rkO-JS.mjs";
18
+ import "../queue.module-BtI8f4Jo.mjs";
19
+ import "../seeder-R7RXJC35.mjs";
20
+ import { t as Stratal } from "../stratal-D5smIU1y.mjs";
21
21
  import { DurableObject, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
22
22
  //#region src/workers/run-in-scope.ts
23
23
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stratal",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "A modular Cloudflare Workers framework with dependency injection, queue-based events, and type-safe configuration",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -121,6 +121,10 @@
121
121
  "types": "./dist/storage/index.d.mts",
122
122
  "import": "./dist/storage/index.mjs"
123
123
  },
124
+ "./storage/providers": {
125
+ "types": "./dist/storage/providers/index.d.mts",
126
+ "import": "./dist/storage/providers/index.mjs"
127
+ },
124
128
  "./websocket": {
125
129
  "types": "./dist/websocket/index.d.mts",
126
130
  "import": "./dist/websocket/index.mjs"
@@ -151,11 +155,12 @@
151
155
  },
152
156
  "dependencies": {
153
157
  "@hono/swagger-ui": "^0.6.1",
154
- "@hono/zod-openapi": "^1.2.2",
158
+ "@hono/zod-openapi": "^1.2.3",
155
159
  "@intlify/core-base": "^11.3.0",
156
160
  "@intlify/message-compiler": "^11.3.0",
161
+ "@modelcontextprotocol/sdk": "^1.27.1",
157
162
  "@swc-node/register": "^1.11.1",
158
- "@swc/core": "^1.11.29",
163
+ "@swc/core": "^1.15.18",
159
164
  "@xmldom/xmldom": "^0.8.11",
160
165
  "clipanion": "^4.0.0-rc.4",
161
166
  "hono": "^4.12.8",
@@ -200,10 +205,10 @@
200
205
  }
201
206
  },
202
207
  "devDependencies": {
203
- "@aws-sdk/client-s3": "3.1011.0",
204
- "@aws-sdk/lib-storage": "^3.1011.0",
205
- "@aws-sdk/s3-request-presigner": "3.1011.0",
206
- "@cloudflare/vitest-pool-workers": "^0.13.2",
208
+ "@aws-sdk/client-s3": "3.1014.0",
209
+ "@aws-sdk/lib-storage": "^3.1014.0",
210
+ "@aws-sdk/s3-request-presigner": "3.1014.0",
211
+ "@cloudflare/vitest-pool-workers": "^0.13.3",
207
212
  "@cloudflare/workers-types": "4.20260317.1",
208
213
  "@react-email/components": "^1.0.10",
209
214
  "@stratal/testing": "workspace:*",
@@ -214,7 +219,7 @@
214
219
  "@vitest/coverage-v8": "^4.1.0",
215
220
  "@vitest/runner": "~4.1.0",
216
221
  "@vitest/snapshot": "~4.1.0",
217
- "nodemailer": "^8.0.2",
222
+ "nodemailer": "^8.0.3",
218
223
  "react": "^19.2.4",
219
224
  "react-dom": "^19.2.4",
220
225
  "reflect-metadata": "^0.2.2",
@@ -1 +0,0 @@
1
- {"version":3,"file":"application-zG8b-pol.d.mts","names":[],"sources":["../src/execution-context.ts","../src/application.ts"],"mappings":";;;;;UAAiB,uBAAA;EACf,SAAA,CAAU,OAAA,EAAS,OAAA;AAAA;;;UC6BJ,iBAAA;ED7BI;EC+BnB,MAAA,EAAQ,WAAA,GAAc,aAAA;ED/Ba;ECiCnC,OAAA;IACE,KAAA,GAAQ,QAAA;IACR,SAAA;EAAA;EANa;;;;EAYf,UAAA,GAAa,iBAAA;AAAA;AAAA,UAGE,kBAAA,SAA2B,iBAAA;EAC1C,GAAA,EAAK,UAAA;EACL,GAAA,EAAK,uBAAA;AAAA;;;;;;;;;;;AAFP;;;;;;;;;;cAyBa,WAAA;EAvBX;;;EAAA,QA2BQ,UAAA;EAAA,QAEA,OAAA;EAAA,QACA,cAAA;EAAA,QACA,gBAAA;EAAA,QACA,WAAA;EAAA,QACA,MAAA;EAAA,QACA,WAAA;EAAA,SAEC,GAAA,EAAK,UAAA;EAAA,iBACG,SAAA;;IAEH,GAAA;IAAK,GAAA;IAAA,GAAQ;EAAA,GAAU,kBAAA;EA0CjB;;;EAAA,IAXhB,SAAA,CAAA,GAAa,SAAA;EAwFiB;;;EAAA,IAjF9B,IAAA,CAAA,GAAQ,OAAA;EAIN,UAAA,CAAA,GAAc,OAAA;EAqH6C;;;EAzEjE,OAAA,GAAA,CAAW,KAAA,WAAgB,CAAA;EAlGnB;;;EA+GF,WAAA,CAAY,KAAA,EAAO,YAAA,EAAc,SAAA,WAAoB,OAAA;EA1GnD;;;EA8HF,eAAA,CAAgB,UAAA,EAAY,mBAAA,GAAsB,OAAA;EA1H1C;;;EA2Id,uBAAA,CAAwB,MAAA,YAAgB,aAAA;EAQlC,QAAA,CAAA,GAAY,OAAA;EAhJC;;;EA+Jb,aAAA,CAAc,IAAA,UAAc,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,aAAA;EAAA,QAOzD,gBAAA;EAAA,QAoBA,eAAA;EAAA,QASA,sBAAA;EAAA,QAOA,gBAAA;EAhKF;;;EAAA,QA0KE,sBAAA;EA9HG;;;EAAA,QAmJH,qBAAA;EAtIU;;;EAAA,QA0JV,oBAAA;AAAA"}
@@ -1,171 +0,0 @@
1
- import { injectable } from "tsyringe";
2
- //#region src/di/tokens.ts
3
- /**
4
- * Token for the Container instance
5
- * Used for injecting the Container into services that need dynamic resolution
6
- */
7
- const CONTAINER_TOKEN = Symbol.for("stratal:di:container");
8
- const DI_TOKENS = {
9
- CloudflareEnv: Symbol.for("stratal:cloudflare:env"),
10
- ExecutionContext: Symbol.for("stratal:execution:context"),
11
- Container: CONTAINER_TOKEN,
12
- Application: Symbol.for("stratal:application"),
13
- ModuleRegistry: Symbol.for("stratal:module:registry"),
14
- ErrorHandler: Symbol.for("stratal:error:handler"),
15
- Database: Symbol.for("stratal:database:service"),
16
- Queue: Symbol.for("stratal:queue:manager"),
17
- ConsumerRegistry: Symbol.for("stratal:consumer:registry"),
18
- Cron: Symbol.for("stratal:cron:manager"),
19
- EventRegistry: Symbol.for("stratal:event:registry"),
20
- Quarry: Symbol.for("stratal:quarry"),
21
- AuthContext: Symbol.for("stratal:auth:context"),
22
- DurableObjectState: Symbol.for("stratal:durable:object:state"),
23
- DurableObjectId: Symbol.for("stratal:durable:object:id")
24
- };
25
- //#endregion
26
- //#region src/di/decorators/inject-param.decorator.ts
27
- /**
28
- * Metadata key for storing parameter injection information
29
- */
30
- const INJECT_PARAM_METADATA_KEY = Symbol.for("stratal:inject:param");
31
- /**
32
- * Mark a method parameter for DI injection
33
- *
34
- * The parameter will be resolved from the request-scoped container
35
- * when the controller method is invoked.
36
- *
37
- * @param token - DI token to resolve (class or symbol)
38
- *
39
- * @example With class token
40
- * ```typescript
41
- * async show(
42
- * ctx: RouterContext,
43
- * @InjectParam(UserService) userService: UserService
44
- * ) { }
45
- * ```
46
- *
47
- * @example With symbol token
48
- * ```typescript
49
- * async show(
50
- * ctx: RouterContext,
51
- * @InjectParam(DI_TOKENS.Cache) cache: ICacheService
52
- * ) { }
53
- * ```
54
- */
55
- function InjectParam(token) {
56
- return (target, propertyKey, parameterIndex) => {
57
- if (propertyKey === void 0) throw new Error("@InjectParam can only be used on method parameters, not constructor parameters");
58
- const existingInjections = Reflect.getMetadata(INJECT_PARAM_METADATA_KEY, target, propertyKey) ?? [];
59
- existingInjections.push({
60
- index: parameterIndex,
61
- token
62
- });
63
- Reflect.defineMetadata(INJECT_PARAM_METADATA_KEY, existingInjections, target, propertyKey);
64
- };
65
- }
66
- /**
67
- * Get method parameter injections
68
- *
69
- * @param target - Controller prototype
70
- * @param propertyKey - Method name
71
- * @returns Array of parameter injections sorted by index
72
- */
73
- function getMethodInjections(target, propertyKey) {
74
- return (Reflect.getMetadata(INJECT_PARAM_METADATA_KEY, target, propertyKey) ?? []).sort((a, b) => a.index - b.index);
75
- }
76
- //#endregion
77
- //#region src/di/decorators.ts
78
- /**
79
- * DI Decorators
80
- *
81
- * Provides decorators for dependency injection:
82
- * - @Transient: Mark classes as injectable (lifecycle controlled at registration)
83
- * - @InjectParam: Inject dependencies into method parameters
84
- *
85
- * Lifecycle (Singleton, Request, Transient) is controlled at registration time
86
- * via the `scope` property in module providers or Container.register().
87
- */
88
- /**
89
- * Mark a class as injectable
90
- *
91
- * This decorator wraps tsyringe's `@injectable` decorator and optionally
92
- * associates a token with the class. The actual lifecycle (Singleton, Request,
93
- * Transient) is determined at registration time, not decoration time.
94
- *
95
- * **Lifecycle Control:**
96
- * - Use `scope: Scope.Singleton` in module providers for singleton
97
- * - Use `scope: Scope.Request` in module providers for request-scoped
98
- * - Default is Transient (new instance per resolution)
99
- *
100
- * @param token - Optional DI token for service resolution
101
- *
102
- * @example Basic usage (no token)
103
- * ```typescript
104
- * @Transient()
105
- * export class UserService {
106
- * constructor(@inject(DI_TOKENS.Database) private db: DatabaseService) {}
107
- * }
108
- *
109
- * // In module:
110
- * @Module({
111
- * providers: [UserService] // Transient by default
112
- * })
113
- * ```
114
- *
115
- * @example With token
116
- * ```typescript
117
- * @Transient(DI_TOKENS.ConnectionManager)
118
- * export class ConnectionManager implements Disposable {
119
- * // ...
120
- * }
121
- *
122
- * // In Application.ts:
123
- * container.register(DI_TOKENS.ConnectionManager, ConnectionManager, Scope.Request)
124
- * ```
125
- *
126
- * @example Singleton via provider scope
127
- * ```typescript
128
- * @Transient()
129
- * export class ConsumerRegistry {
130
- * // ...
131
- * }
132
- *
133
- * // In module:
134
- * @Module({
135
- * providers: [
136
- * { provide: DI_TOKENS.ConsumerRegistry, useClass: ConsumerRegistry, scope: Scope.Singleton }
137
- * ]
138
- * })
139
- * ```
140
- */
141
- function Transient(token) {
142
- return function(target) {
143
- const targetConstructor = target;
144
- injectable({ token })(targetConstructor);
145
- return target;
146
- };
147
- }
148
- //#endregion
149
- //#region \0@oxc-project+runtime@0.115.0/helpers/decorateMetadata.js
150
- function __decorateMetadata(k, v) {
151
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
152
- }
153
- //#endregion
154
- //#region \0@oxc-project+runtime@0.115.0/helpers/decorateParam.js
155
- function __decorateParam(paramIndex, decorator) {
156
- return function(target, key) {
157
- decorator(target, key, paramIndex);
158
- };
159
- }
160
- //#endregion
161
- //#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
162
- function __decorate(decorators, target, key, desc) {
163
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
164
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
165
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
166
- return c > 3 && r && Object.defineProperty(target, key, r), r;
167
- }
168
- //#endregion
169
- export { INJECT_PARAM_METADATA_KEY as a, CONTAINER_TOKEN as c, Transient as i, DI_TOKENS as l, __decorateParam as n, InjectParam as o, __decorateMetadata as r, getMethodInjections as s, __decorate as t };
170
-
171
- //# sourceMappingURL=decorate-D5j-d9_z.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decorate-D5j-d9_z.mjs","names":[],"sources":["../src/di/tokens.ts","../src/di/decorators/inject-param.decorator.ts","../src/di/decorators.ts"],"sourcesContent":["/**\n * Token for the Container instance\n * Used for injecting the Container into services that need dynamic resolution\n */\nexport const CONTAINER_TOKEN = Symbol.for('stratal:di:container')\n\nexport const DI_TOKENS = {\n // Cloudflare\n CloudflareEnv: Symbol.for('stratal:cloudflare:env'),\n ExecutionContext: Symbol.for('stratal:execution:context'),\n\n // Infrastructure\n Container: CONTAINER_TOKEN,\n Application: Symbol.for('stratal:application'),\n ModuleRegistry: Symbol.for('stratal:module:registry'),\n ErrorHandler: Symbol.for('stratal:error:handler'),\n Database: Symbol.for('stratal:database:service'),\n Queue: Symbol.for('stratal:queue:manager'),\n ConsumerRegistry: Symbol.for('stratal:consumer:registry'),\n Cron: Symbol.for('stratal:cron:manager'),\n EventRegistry: Symbol.for('stratal:event:registry'),\n Quarry: Symbol.for('stratal:quarry'),\n\n // Context\n /**\n * AuthContext: Use for services that need user authentication (userId).\n */\n AuthContext: Symbol.for('stratal:auth:context'),\n\n // Workers\n DurableObjectState: Symbol.for('stratal:durable:object:state'),\n DurableObjectId: Symbol.for('stratal:durable:object:id'),\n} as const\n\nexport type DIToken = typeof DI_TOKENS[keyof typeof DI_TOKENS]\n","/**\n * Method Parameter Injection Decorator\n *\n * Enables DI for controller method parameters. Parameters marked with\n * @InjectParam(token) are resolved from the request-scoped container\n * at method invocation time.\n *\n * @example\n * ```typescript\n * @Route({ response: userSchema })\n * async show(\n * ctx: RouterContext,\n * @InjectParam(UserService) userService: UserService,\n * @InjectParam(CacheService) cache: CacheService\n * ): Promise<Response> {\n * // userService and cache auto-resolved from request container\n * }\n * ```\n */\nimport type InjectionToken from 'tsyringe/dist/typings/providers/injection-token'\n\n/**\n * Metadata key for storing parameter injection information\n */\nexport const INJECT_PARAM_METADATA_KEY = Symbol.for('stratal:inject:param')\n\n/**\n * Describes a parameter injection\n */\nexport interface ParamInjection {\n /** Parameter index in the method signature (0-based) */\n index: number\n /** DI token to resolve */\n token: InjectionToken\n}\n\n/**\n * Mark a method parameter for DI injection\n *\n * The parameter will be resolved from the request-scoped container\n * when the controller method is invoked.\n *\n * @param token - DI token to resolve (class or symbol)\n *\n * @example With class token\n * ```typescript\n * async show(\n * ctx: RouterContext,\n * @InjectParam(UserService) userService: UserService\n * ) { }\n * ```\n *\n * @example With symbol token\n * ```typescript\n * async show(\n * ctx: RouterContext,\n * @InjectParam(DI_TOKENS.Cache) cache: ICacheService\n * ) { }\n * ```\n */\nexport function InjectParam<T>(token: InjectionToken<T>): ParameterDecorator {\n return (target: object, propertyKey: string | symbol | undefined, parameterIndex: number) => {\n if (propertyKey === undefined) {\n throw new Error('@InjectParam can only be used on method parameters, not constructor parameters')\n }\n\n const existingInjections: ParamInjection[] =\n (Reflect.getMetadata(INJECT_PARAM_METADATA_KEY, target, propertyKey) as ParamInjection[] | undefined) ?? []\n\n existingInjections.push({\n index: parameterIndex,\n token,\n })\n\n Reflect.defineMetadata(INJECT_PARAM_METADATA_KEY, existingInjections, target, propertyKey)\n }\n}\n\n/**\n * Get method parameter injections\n *\n * @param target - Controller prototype\n * @param propertyKey - Method name\n * @returns Array of parameter injections sorted by index\n */\nexport function getMethodInjections(target: object, propertyKey: string | symbol): ParamInjection[] {\n const injections: ParamInjection[] =\n (Reflect.getMetadata(INJECT_PARAM_METADATA_KEY, target, propertyKey) as ParamInjection[] | undefined) ?? []\n\n return injections.sort((a, b) => a.index - b.index)\n}\n","/**\n * DI Decorators\n *\n * Provides decorators for dependency injection:\n * - @Transient: Mark classes as injectable (lifecycle controlled at registration)\n * - @InjectParam: Inject dependencies into method parameters\n *\n * Lifecycle (Singleton, Request, Transient) is controlled at registration time\n * via the `scope` property in module providers or Container.register().\n */\nimport { injectable } from 'tsyringe'\nimport type InjectionToken from 'tsyringe/dist/typings/providers/injection-token'\n\n// Re-export method parameter injection\nexport {\n InjectParam,\n getMethodInjections,\n type ParamInjection,\n INJECT_PARAM_METADATA_KEY,\n} from './decorators/inject-param.decorator'\n\n/**\n * Mark a class as injectable\n *\n * This decorator wraps tsyringe's `@injectable` decorator and optionally\n * associates a token with the class. The actual lifecycle (Singleton, Request,\n * Transient) is determined at registration time, not decoration time.\n *\n * **Lifecycle Control:**\n * - Use `scope: Scope.Singleton` in module providers for singleton\n * - Use `scope: Scope.Request` in module providers for request-scoped\n * - Default is Transient (new instance per resolution)\n *\n * @param token - Optional DI token for service resolution\n *\n * @example Basic usage (no token)\n * ```typescript\n * @Transient()\n * export class UserService {\n * constructor(@inject(DI_TOKENS.Database) private db: DatabaseService) {}\n * }\n *\n * // In module:\n * @Module({\n * providers: [UserService] // Transient by default\n * })\n * ```\n *\n * @example With token\n * ```typescript\n * @Transient(DI_TOKENS.ConnectionManager)\n * export class ConnectionManager implements Disposable {\n * // ...\n * }\n *\n * // In Application.ts:\n * container.register(DI_TOKENS.ConnectionManager, ConnectionManager, Scope.Request)\n * ```\n *\n * @example Singleton via provider scope\n * ```typescript\n * @Transient()\n * export class ConsumerRegistry {\n * // ...\n * }\n *\n * // In module:\n * @Module({\n * providers: [\n * { provide: DI_TOKENS.ConsumerRegistry, useClass: ConsumerRegistry, scope: Scope.Singleton }\n * ]\n * })\n * ```\n */\nexport function Transient<T>(token?: InjectionToken<T>) {\n return function <TFunction extends abstract new (...args: never[]) => unknown>(target: TFunction): TFunction {\n const targetConstructor = target as unknown as new (...args: unknown[]) => T\n injectable<T>({ token })(targetConstructor)\n return target\n }\n}\n"],"mappings":";;;;;;AAIA,MAAa,kBAAkB,OAAO,IAAI,uBAAuB;AAEjE,MAAa,YAAY;CAEvB,eAAe,OAAO,IAAI,yBAAyB;CACnD,kBAAkB,OAAO,IAAI,4BAA4B;CAGzD,WAAW;CACX,aAAa,OAAO,IAAI,sBAAsB;CAC9C,gBAAgB,OAAO,IAAI,0BAA0B;CACrD,cAAc,OAAO,IAAI,wBAAwB;CACjD,UAAU,OAAO,IAAI,2BAA2B;CAChD,OAAO,OAAO,IAAI,wBAAwB;CAC1C,kBAAkB,OAAO,IAAI,4BAA4B;CACzD,MAAM,OAAO,IAAI,uBAAuB;CACxC,eAAe,OAAO,IAAI,yBAAyB;CACnD,QAAQ,OAAO,IAAI,iBAAiB;CAMpC,aAAa,OAAO,IAAI,uBAAuB;CAG/C,oBAAoB,OAAO,IAAI,+BAA+B;CAC9D,iBAAiB,OAAO,IAAI,4BAA4B;CACzD;;;;;;ACRD,MAAa,4BAA4B,OAAO,IAAI,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;AAoC3E,SAAgB,YAAe,OAA8C;AAC3E,SAAQ,QAAgB,aAA0C,mBAA2B;AAC3F,MAAI,gBAAgB,KAAA,EAClB,OAAM,IAAI,MAAM,iFAAiF;EAGnG,MAAM,qBACH,QAAQ,YAAY,2BAA2B,QAAQ,YAAY,IAAqC,EAAE;AAE7G,qBAAmB,KAAK;GACtB,OAAO;GACP;GACD,CAAC;AAEF,UAAQ,eAAe,2BAA2B,oBAAoB,QAAQ,YAAY;;;;;;;;;;AAW9F,SAAgB,oBAAoB,QAAgB,aAAgD;AAIlG,SAFG,QAAQ,YAAY,2BAA2B,QAAQ,YAAY,IAAqC,EAAE,EAE3F,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACfrD,SAAgB,UAAa,OAA2B;AACtD,QAAO,SAAwE,QAA8B;EAC3G,MAAM,oBAAoB;AAC1B,aAAc,EAAE,OAAO,CAAC,CAAC,kBAAkB;AAC3C,SAAO"}