stratal 0.0.17 → 0.0.19
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.
- package/README.md +8 -8
- package/dist/{base-email.provider-DypUAfWm.mjs → base-email.provider-mjynzewK.mjs} +1 -1
- package/dist/{base-email.provider-DypUAfWm.mjs.map → base-email.provider-mjynzewK.mjs.map} +1 -1
- package/dist/bin/cloudflare-workers-loader.mjs +33 -1
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs +169 -7
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +3 -2
- package/dist/cache/index.d.mts.map +1 -1
- package/dist/cache/index.mjs +3 -10
- package/dist/cache/index.mjs.map +1 -1
- package/dist/{colors-Y7WIFXs7.mjs → colors-DJaRDXoS.mjs} +1 -1
- package/dist/{colors-Y7WIFXs7.mjs.map → colors-DJaRDXoS.mjs.map} +1 -1
- package/dist/{command-B1CPgsrU.mjs → command-BgSlsS4M.mjs} +3 -3
- package/dist/command-BgSlsS4M.mjs.map +1 -0
- package/dist/{command-TnkPYWta.d.mts → command-DsQq56Lp.d.mts} +2 -2
- package/dist/{command-TnkPYWta.d.mts.map → command-DsQq56Lp.d.mts.map} +1 -1
- package/dist/config/index.d.mts +81 -37
- package/dist/config/index.d.mts.map +1 -1
- package/dist/config/index.mjs +135 -61
- package/dist/config/index.mjs.map +1 -1
- package/dist/{consumer-registry-Bymm6ff4.d.mts → consumer-registry-Doom7BEh.d.mts} +1 -1
- package/dist/{consumer-registry-Bymm6ff4.d.mts.map → consumer-registry-Doom7BEh.d.mts.map} +1 -1
- package/dist/controller.decorator-LZY9aHYG.mjs +66 -0
- package/dist/controller.decorator-LZY9aHYG.mjs.map +1 -0
- package/dist/cron/index.d.mts +4 -3
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +1 -3
- package/dist/{cron-manager-CFBamKKk.mjs → cron-manager-C30t9UZM.mjs} +29 -19
- package/dist/cron-manager-C30t9UZM.mjs.map +1 -0
- package/dist/{cron-manager-D7imGwUT.d.mts → cron-manager-RuPtFVLy.d.mts} +28 -14
- package/dist/cron-manager-RuPtFVLy.d.mts.map +1 -0
- package/dist/di/index.d.mts +2 -2
- package/dist/di/index.mjs +3 -3
- package/dist/email/index.d.mts +3 -3
- package/dist/email/index.mjs +87 -18
- package/dist/email/index.mjs.map +1 -1
- package/dist/{en-DaewN8hc.mjs → en-rHmW6vD9.mjs} +14 -31
- package/dist/en-rHmW6vD9.mjs.map +1 -0
- package/dist/env-CamWD-U1.d.mts +25 -0
- package/dist/env-CamWD-U1.d.mts.map +1 -0
- package/dist/errors/index.d.mts +2 -2
- package/dist/errors/index.mjs +2 -3
- package/dist/errors-B4pYgYON.mjs +1714 -0
- package/dist/errors-B4pYgYON.mjs.map +1 -0
- package/dist/{errors-DuAR5Wke.mjs → errors-BUyUfr2Z.mjs} +14 -7
- package/dist/errors-BUyUfr2Z.mjs.map +1 -0
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +1 -2
- package/dist/{events-CvUSgEuN.mjs → events-COKixqnG.mjs} +2 -2
- package/dist/{events-CvUSgEuN.mjs.map → events-COKixqnG.mjs.map} +1 -1
- package/dist/{gateway-context-CNOLkLUC.mjs → gateway-context-cqZ8wMoi.mjs} +4 -9
- package/dist/gateway-context-cqZ8wMoi.mjs.map +1 -0
- package/dist/guards/index.d.mts +14 -5
- package/dist/guards/index.d.mts.map +1 -1
- package/dist/guards/index.mjs +1 -1
- package/dist/{guards-DUk_Kzst.mjs → guards-DMbsAxSX.mjs} +1 -1
- package/dist/guards-DMbsAxSX.mjs.map +1 -0
- package/dist/http-method.decorator-BT3ufnz8.mjs +96 -0
- package/dist/http-method.decorator-BT3ufnz8.mjs.map +1 -0
- package/dist/i18n/index.d.mts +3 -3
- package/dist/i18n/index.mjs +3 -16
- package/dist/i18n/messages/en/index.d.mts +1 -1
- package/dist/i18n/messages/en/index.mjs +1 -1
- package/dist/i18n/utils/index.d.mts +30 -0
- package/dist/i18n/utils/index.d.mts.map +1 -0
- package/dist/i18n/utils/index.mjs +2 -0
- package/dist/i18n/validation/index.d.mts +1 -1
- package/dist/i18n/validation/index.mjs +1 -1
- package/dist/i18n.module-CI_prYFD.mjs +2340 -0
- package/dist/i18n.module-CI_prYFD.mjs.map +1 -0
- package/dist/{index-NGxg-KP_.d.mts → index-B437eK7p.d.mts} +59 -16
- package/dist/index-B437eK7p.d.mts.map +1 -0
- package/dist/{index-Dp6A5ywM.d.mts → index-CWRS7Ri3.d.mts} +1 -1
- package/dist/{index-Dp6A5ywM.d.mts.map → index-CWRS7Ri3.d.mts.map} +1 -1
- package/dist/{index-D_w_Rmtd.d.mts → index-DFhEeFfC.d.mts} +13 -30
- package/dist/{index-D_w_Rmtd.d.mts.map → index-DFhEeFfC.d.mts.map} +1 -1
- package/dist/index-DPFqRs8L.d.mts +4318 -0
- package/dist/index-DPFqRs8L.d.mts.map +1 -0
- package/dist/{index-DGRe6Yoa.d.mts → index-Dnqm9ZB6.d.mts} +5 -4
- package/dist/index-Dnqm9ZB6.d.mts.map +1 -0
- package/dist/index-SHx31sBJ.d.mts +101 -0
- package/dist/index-SHx31sBJ.d.mts.map +1 -0
- package/dist/index.d.mts +5 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -20
- package/dist/{is-command-DJVI6wEJ.mjs → is-command-C6a7WTPw.mjs} +2 -2
- package/dist/{is-command-DJVI6wEJ.mjs.map → is-command-C6a7WTPw.mjs.map} +1 -1
- package/dist/{is-seeder-D5MIEcdz.mjs → is-seeder-CebjZCDn.mjs} +1 -1
- package/dist/{is-seeder-D5MIEcdz.mjs.map → is-seeder-CebjZCDn.mjs.map} +1 -1
- package/dist/logger/index.d.mts +1 -1
- package/dist/logger/index.mjs +1 -1
- package/dist/{logger-CGT91VY6.mjs → logger-V6Ms3QnQ.mjs} +63 -45
- package/dist/logger-V6Ms3QnQ.mjs.map +1 -0
- package/dist/macroable/index.d.mts +2 -0
- package/dist/macroable/index.mjs +2 -0
- package/dist/macroable-BmufBshB.mjs +122 -0
- package/dist/macroable-BmufBshB.mjs.map +1 -0
- package/dist/module/index.d.mts +3 -4
- package/dist/module/index.d.mts.map +1 -1
- package/dist/module/index.mjs +1 -10
- package/dist/module-qGE_1duv.mjs +732 -0
- package/dist/module-qGE_1duv.mjs.map +1 -0
- package/dist/openapi/index.d.mts +3 -3
- package/dist/openapi/index.mjs +2 -15
- package/dist/{openapi-tools.service-B3TxYKoQ.mjs → openapi-tools.service-CYWGuhue.mjs} +4 -1
- package/dist/{openapi-tools.service-B3TxYKoQ.mjs.map → openapi-tools.service-CYWGuhue.mjs.map} +1 -1
- package/dist/{openapi.service-DGnX3Fc4.d.mts → openapi.service-Bv_NioM9.d.mts} +9 -17
- package/dist/openapi.service-Bv_NioM9.d.mts.map +1 -0
- package/dist/quarry/index.d.mts +26 -12
- package/dist/quarry/index.d.mts.map +1 -1
- package/dist/quarry/index.mjs +4 -8
- package/dist/{quarry-registry-B2rkO-JS.mjs → quarry-registry-DFfRRkA7.mjs} +45 -40
- package/dist/quarry-registry-DFfRRkA7.mjs.map +1 -0
- package/dist/queue/index.d.mts +2 -2
- package/dist/queue/index.mjs +3 -13
- package/dist/queue/index.mjs.map +1 -1
- package/dist/{queue.module-BtI8f4Jo.mjs → queue.module-P-G-nCYz.mjs} +39 -42
- package/dist/queue.module-P-G-nCYz.mjs.map +1 -0
- package/dist/r2-storage.provider-LdzK9tfG.mjs +244 -0
- package/dist/r2-storage.provider-LdzK9tfG.mjs.map +1 -0
- package/dist/{resend.provider-bXMEkdRJ.mjs → resend.provider-bwILp0WI.mjs} +2 -4
- package/dist/{resend.provider-bXMEkdRJ.mjs.map → resend.provider-bwILp0WI.mjs.map} +1 -1
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +7 -16
- package/dist/seeder/index.d.mts +3 -4
- package/dist/seeder/index.d.mts.map +1 -1
- package/dist/seeder/index.mjs +2 -6
- package/dist/{seeder-R7RXJC35.mjs → seeder-BcqIFa2X.mjs} +5 -5
- package/dist/{seeder-R7RXJC35.mjs.map → seeder-BcqIFa2X.mjs.map} +1 -1
- package/dist/setup-CtekcwuO.mjs +37 -0
- package/dist/setup-CtekcwuO.mjs.map +1 -0
- package/dist/signed-url-COX7cCWR.mjs +74 -0
- package/dist/signed-url-COX7cCWR.mjs.map +1 -0
- package/dist/{smtp.provider-DrbHQztF.mjs → smtp.provider-B07yuARi.mjs} +2 -4
- package/dist/{smtp.provider-DrbHQztF.mjs.map → smtp.provider-B07yuARi.mjs.map} +1 -1
- package/dist/storage/index.d.mts +39 -17
- package/dist/storage/index.d.mts.map +1 -1
- package/dist/storage/index.mjs +3 -14
- package/dist/storage/providers/index.d.mts +30 -69
- package/dist/storage/providers/index.d.mts.map +1 -1
- package/dist/storage/providers/index.mjs +2 -5
- package/dist/{storage-CZKHOhci.mjs → storage-P6X4h9So.mjs} +102 -29
- package/dist/storage-P6X4h9So.mjs.map +1 -0
- package/dist/{storage-provider.interface-0IqcdhBf.d.mts → storage-provider.interface-CC1nniHk.d.mts} +20 -15
- package/dist/storage-provider.interface-CC1nniHk.d.mts.map +1 -0
- package/dist/stratal-BCiwCFN9.mjs +533 -0
- package/dist/stratal-BCiwCFN9.mjs.map +1 -0
- package/dist/{types-DahElfUw.d.mts → types-DIWemRad.d.mts} +2 -2
- package/dist/types-DIWemRad.d.mts.map +1 -0
- package/dist/{usage-generator-CVIsENuE.mjs → usage-generator-MBcRo0Q2.mjs} +2 -2
- package/dist/{usage-generator-CVIsENuE.mjs.map → usage-generator-MBcRo0Q2.mjs.map} +1 -1
- package/dist/{validation-DQTC259A.mjs → validation-Dbg3ehdP.mjs} +2 -2
- package/dist/{validation-DQTC259A.mjs.map → validation-Dbg3ehdP.mjs.map} +1 -1
- package/dist/websocket/index.d.mts +3 -3
- package/dist/websocket/index.d.mts.map +1 -1
- package/dist/websocket/index.mjs +1 -4
- package/dist/workers/index.d.mts +2 -1
- package/dist/workers/index.d.mts.map +1 -1
- package/dist/workers/index.mjs +2 -20
- package/dist/workers/index.mjs.map +1 -1
- package/package.json +41 -50
- package/dist/application-DfPtIzxF.d.mts +0 -177
- package/dist/application-DfPtIzxF.d.mts.map +0 -1
- package/dist/command-B1CPgsrU.mjs.map +0 -1
- package/dist/cron-manager-CFBamKKk.mjs.map +0 -1
- package/dist/cron-manager-D7imGwUT.d.mts.map +0 -1
- package/dist/en-DaewN8hc.mjs.map +0 -1
- package/dist/errors-DSKapqD8.mjs +0 -707
- package/dist/errors-DSKapqD8.mjs.map +0 -1
- package/dist/errors-DuAR5Wke.mjs.map +0 -1
- package/dist/gateway-context-CNOLkLUC.mjs.map +0 -1
- package/dist/guards-DUk_Kzst.mjs.map +0 -1
- package/dist/i18n.module-Dn9SrFdS.mjs +0 -1841
- package/dist/i18n.module-Dn9SrFdS.mjs.map +0 -1
- package/dist/index-BFCxSp_f.d.mts +0 -2625
- package/dist/index-BFCxSp_f.d.mts.map +0 -1
- package/dist/index-DGRe6Yoa.d.mts.map +0 -1
- package/dist/index-NGxg-KP_.d.mts.map +0 -1
- package/dist/logger-CGT91VY6.mjs.map +0 -1
- package/dist/middleware/index.d.mts +0 -2
- package/dist/middleware/index.mjs +0 -5
- package/dist/middleware-Bl-b5pkt.mjs +0 -362
- package/dist/middleware-Bl-b5pkt.mjs.map +0 -1
- package/dist/module-registry-CmjBX6ol.d.mts +0 -121
- package/dist/module-registry-CmjBX6ol.d.mts.map +0 -1
- package/dist/module-tUtyVJ5E.mjs +0 -371
- package/dist/module-tUtyVJ5E.mjs.map +0 -1
- package/dist/openapi.service-DGnX3Fc4.d.mts.map +0 -1
- package/dist/quarry-registry-B2rkO-JS.mjs.map +0 -1
- package/dist/queue.module-BtI8f4Jo.mjs.map +0 -1
- package/dist/router-context-D9R1v2Ac.mjs +0 -267
- package/dist/router-context-D9R1v2Ac.mjs.map +0 -1
- package/dist/s3-storage.provider-CttzNnDR.mjs +0 -335
- package/dist/s3-storage.provider-CttzNnDR.mjs.map +0 -1
- package/dist/storage-CZKHOhci.mjs.map +0 -1
- package/dist/storage-provider.interface-0IqcdhBf.d.mts.map +0 -1
- package/dist/stratal-D5smIU1y.mjs +0 -315
- package/dist/stratal-D5smIU1y.mjs.map +0 -1
- package/dist/types-DahElfUw.d.mts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.module-CI_prYFD.mjs","names":[],"sources":["../src/i18n/middleware/i18n-context.middleware.ts","../src/openapi/services/openapi-config.service.ts","../src/i18n/errors/locale-not-supported.error.ts","../src/i18n/errors/translation-missing.error.ts","../src/i18n/i18n.options.ts","../src/i18n/messages/index.ts","../src/i18n/utils/deep-merge.ts","../src/i18n/services/message-loader.service.ts","../src/i18n/services/message-registry.ts","../src/openapi/services/openapi.service.ts","../src/openapi/openapi.module.ts","../src/router/middleware/logger.middleware.ts","../src/router/middleware/domain.middleware.ts","../src/router/middleware/middleware-chain.ts","../src/router/decorators/route.decorator.ts","../src/router/schemas/common.schemas.ts","../src/router/utils/path.ts","../src/router/utils/route-name.ts","../src/router/services/route-registration.service.ts","../src/router/hono-app.ts","../src/router/services/locale-path.service.ts","../src/router/services/versioning.service.ts","../src/router/route-registry.ts","../src/router/uri.ts","../src/router/route-url.ts","../src/router/middleware/verify-signature.middleware.ts","../src/i18n/services/i18n.service.ts","../src/i18n/i18n.module.ts"],"sourcesContent":["/**\n * I18n Context Middleware\n *\n * Sets up AsyncLocalStorage context for Zod i18n validation.\n * Must run after LocaleExtractionMiddleware sets the locale.\n */\n\nimport { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport type { Middleware, Next } from '../../router/middleware.interface'\nimport type { RouterContext } from '../../router/router-context'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport type { I18nService } from '../services/i18n.service'\nimport { runWithErrorMapContext } from '../validation'\n\n@Transient()\nexport class I18nContextMiddleware implements Middleware {\n constructor(\n @inject(I18N_TOKENS.I18nService) private readonly i18n: I18nService\n ) { }\n\n async handle(ctx: RouterContext, next: Next) {\n const locale = ctx.getLocale()\n\n await runWithErrorMapContext(\n {\n t: (key, params) => this.i18n.t(key, params as Record<string, string | number> | undefined),\n locale,\n },\n () => next()\n )\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { OPENAPI_TOKENS } from '../openapi.tokens'\nimport type {\n IOpenAPIConfigService,\n OpenAPIConfigOverride,\n OpenAPIEffectiveConfig,\n OpenAPIModuleOptions\n} from '../types'\n\n/**\n * OpenAPI Config Service\n *\n * Request-scoped service that manages OpenAPI configuration for the current request.\n * Supports runtime overrides via middleware while preserving base configuration.\n *\n * @example\n * ```typescript\n * // In middleware (e.g., RouteAccessMiddleware)\n * constructor(\n * @inject(OPENAPI_TOKENS.ConfigService) private openAPIConfig: IOpenAPIConfigService\n * ) {}\n *\n * async handle(ctx, next) {\n * this.openAPIConfig.override({\n * info: { title: 'Custom API' },\n * routeFilter: (path) => shouldInclude(path)\n * })\n * await next()\n * }\n * ```\n */\n@Transient(OPENAPI_TOKENS.ConfigService)\nexport class OpenAPIConfigService implements IOpenAPIConfigService {\n private overrides: OpenAPIConfigOverride[] = []\n\n constructor(\n @inject(OPENAPI_TOKENS.Options, { isOptional: true }) private baseOptions?: OpenAPIModuleOptions\n ) { }\n\n /**\n * Add configuration override for this request.\n * Overrides are merged in the order they are added.\n */\n override(config: OpenAPIConfigOverride): void {\n this.overrides.push(config)\n }\n\n /** Get effective configuration (base merged with all overrides) */\n getEffectiveConfig(): OpenAPIEffectiveConfig {\n let effective: OpenAPIEffectiveConfig = {\n jsonPath: this.baseOptions?.jsonPath ?? '/api/openapi.json',\n ui: this.baseOptions?.ui,\n info: {\n title: this.baseOptions?.info?.title ?? 'API',\n version: this.baseOptions?.info?.version ?? '1.0.0',\n description: this.baseOptions?.info?.description\n },\n securitySchemes: this.baseOptions?.securitySchemes\n }\n\n for (const override of this.overrides) {\n effective = this.mergeConfig(effective, override)\n }\n\n return effective\n }\n\n /**\n * Merge override into effective config.\n * Info is shallow-merged, routeFilter is replaced.\n */\n private mergeConfig(\n base: OpenAPIEffectiveConfig,\n override: OpenAPIConfigOverride\n ): OpenAPIEffectiveConfig {\n return {\n ...base,\n info: {\n ...base.info,\n ...(override.info && {\n title: override.info.title ?? base.info.title,\n version: override.info.version ?? base.info.version,\n description: override.info.description ?? base.info.description\n })\n },\n routeFilter: override.routeFilter ?? base.routeFilter\n }\n }\n}\n","/**\n * Locale Not Supported Error\n * Thrown when an unsupported locale is requested\n *\n * HTTP Status: 500 Internal Server Error\n * Error Code: 9301\n */\n\nimport { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\nexport class LocaleNotSupportedError extends ApplicationError {\n constructor(locale: string, supportedLocales: string[]) {\n super(\n 'errors.localeNotSupported',\n ERROR_CODES.I18N.LOCALE_NOT_SUPPORTED,\n { locale, supportedLocales: supportedLocales.join(', ') }\n )\n }\n}\n","/**\n * Translation Missing Error\n * Thrown when a translation key is missing from all locales\n *\n * HTTP Status: 500 Internal Server Error\n * Error Code: 9300\n */\n\nimport { ApplicationError, ERROR_CODES } from '../../errors'\n\nexport class TranslationMissingError extends ApplicationError {\n constructor(key: string, locale: string) {\n super(\n 'errors.translationMissing',\n ERROR_CODES.I18N.TRANSLATION_MISSING,\n { key, locale }\n )\n }\n}\n","/**\n * I18n Module Options\n *\n * Configuration options for the I18n dynamic module.\n * Use with I18nModule.forRoot() to configure locale settings.\n * Use I18nModule.registerMessages() to add translations.\n */\n\nimport type { DetectorOptions } from 'hono/language';\n\n/**\n * Detection strategy for locale resolution\n *\n * - `'cookie'` — reads from the `locale` cookie (default)\n * - `'header'` — reads from the `Accept-Language` header\n * - `'querystring'` — reads from the `?locale=` query parameter\n * - `'path'` — reads from the first URL path segment (e.g., `/en/api/users`)\n */\nexport type DetectionStrategy = 'cookie' | 'header' | 'querystring' | 'path'\n\ninterface BaseDetection {\n /** Set to false to disable language detection entirely. @default true */\n enabled?: boolean\n}\n\n/**\n * Language detection options (discriminated by strategy)\n *\n * @example Cookie detection (default)\n * ```typescript\n * { strategy: 'cookie' }\n * ```\n *\n * @example Header detection\n * ```typescript\n * { strategy: 'header' }\n * ```\n *\n * @example Path detection\n * ```typescript\n * { strategy: 'path' }\n * ```\n *\n * @example Disable detection\n * ```typescript\n * { enabled: false }\n * ```\n */\nexport type LanguageDetectionOptions =\n | (BaseDetection & { strategy?: 'cookie'; cookieOptions?: DetectorOptions['cookieOptions'] })\n | (BaseDetection & { strategy: 'header' })\n | (BaseDetection & { strategy: 'querystring' })\n | (BaseDetection & {\n strategy: 'path'\n /**\n * Controls whether the default locale gets a URL path prefix.\n *\n * - `false` (default) — The default locale has no prefix (`/users`), other locales\n * are prefixed (`/fr/users`). Requests to the prefixed default locale (`/en/users`) return 404.\n * - `'redirect'` — Same as `false`, but requests to the prefixed default locale\n * (`/en/users`) are 301-redirected to the unprefixed path (`/users`).\n * - `true` — All locales are prefixed (`/en/users`, `/fr/users`).\n *\n * @default false\n */\n prefixDefaultLocale?: false | true | 'redirect'\n })\n | { enabled: false }\n\n/**\n * Options for configuring the I18n module\n *\n * @example\n * ```typescript\n * I18nModule.forRoot({\n * defaultLocale: 'en',\n * fallbackLocale: 'en',\n * locales: ['en', 'fr'],\n * detection: { strategy: 'header' },\n * })\n * ```\n */\nexport interface I18nModuleOptions {\n /**\n * Default locale for the application\n * @default 'en'\n */\n defaultLocale?: string\n\n /**\n * Fallback locale when translation is missing\n * @default 'en'\n */\n fallbackLocale?: string\n\n /**\n * List of supported locales\n * Request locales not in this list will fall back to defaultLocale\n */\n locales?: string[]\n\n /**\n * Language detection configuration\n * Controls how the locale is extracted from incoming requests\n */\n detection?: LanguageDetectionOptions\n}\n\n/**\n * Resolved options with all defaults applied\n * Used internally by I18n services\n */\nexport interface ResolvedI18nOptions {\n defaultLocale: string\n fallbackLocale: string\n locales: string[]\n detection: {\n enabled: boolean\n strategy: DetectionStrategy\n /** Resolved value of the path detection `prefixDefaultLocale` option. Only meaningful when `strategy` is `'path'`. */\n prefixDefaultLocale: false | true | 'redirect'\n }\n}\n\n/**\n * Resolve I18n options with defaults\n */\nexport function resolveI18nOptions(options?: I18nModuleOptions): ResolvedI18nOptions {\n const detection = options?.detection\n const enabled = detection ? (detection.enabled !== false) : true\n const strategy: DetectionStrategy = (detection && 'strategy' in detection) ? detection.strategy ?? 'cookie' : 'cookie'\n const prefixDefaultLocale: false | true | 'redirect' =\n (detection && 'prefixDefaultLocale' in detection && detection.prefixDefaultLocale !== undefined)\n ? detection.prefixDefaultLocale\n : false\n\n return {\n defaultLocale: options?.defaultLocale ?? 'en',\n fallbackLocale: options?.fallbackLocale ?? 'en',\n locales: options?.locales ?? ['en'],\n detection: { enabled, strategy, prefixDefaultLocale },\n }\n}\n\n/**\n * Build Hono languageDetector options from I18n module options\n */\nexport function buildDetectorOptions(options?: I18nModuleOptions): Partial<DetectorOptions> {\n const resolved = resolveI18nOptions(options)\n const strategy = resolved.detection.strategy\n\n const detectorOptions: Partial<DetectorOptions> = {\n order: [strategy],\n fallbackLanguage: resolved.defaultLocale,\n supportedLanguages: resolved.locales,\n lookupCookie: 'locale',\n lookupQueryString: 'locale',\n lookupFromPathIndex: 0,\n ignoreCase: true,\n }\n\n if (strategy === 'cookie') {\n detectorOptions.caches = ['cookie']\n if (options?.detection && 'cookieOptions' in options.detection && options.detection.cookieOptions) {\n detectorOptions.cookieOptions = options.detection.cookieOptions\n }\n } else {\n detectorOptions.caches = false\n }\n\n return detectorOptions\n}\n","/**\n * Core Messages\n *\n * Messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nimport * as en from './en'\n\n/**\n * All locale messages\n * Explicitly import and export (no filesystem scanning - Cloudflare Workers compatible)\n */\nexport const messages = { en } as const\n\n/**\n * Type for all messages\n */\nexport type Messages = typeof messages\n\n/**\n * Get messages for all locales\n */\nexport function getMessages(): Record<string, Record<string, unknown>> {\n return messages\n}\n\n/**\n * Get available locales\n */\nexport function getLocales(): string[] {\n return Object.keys(messages)\n}\n","/**\n * Deep merge two objects. Source values override target at leaf level.\n */\nexport function deepMerge(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target }\n\n for (const key of Object.keys(source)) {\n const targetValue = target[key]\n const sourceValue = source[key]\n\n if (\n typeof targetValue === 'object'\n && targetValue !== null\n && !Array.isArray(targetValue)\n && typeof sourceValue === 'object'\n && sourceValue !== null\n && !Array.isArray(sourceValue)\n ) {\n result[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>,\n )\n } else {\n result[key] = sourceValue\n }\n }\n\n return result\n}\n","/**\n * Message Loader Service\n *\n * Singleton service that loads and caches all locale messages at startup.\n * Merges core messages with registry messages (from registerMessages() calls).\n * Lazily builds and caches CoreContext per locale on first access.\n */\n\nimport type { CoreContext } from '@intlify/core-base'\nimport { createCoreContext } from '@intlify/core-base'\nimport { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport type { I18nModuleOptions } from '../i18n.options'\nimport type { MessageKeyPrefix } from '../i18n.types'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport { getLocales, getMessages } from '../messages'\nimport { deepMerge } from '../utils/deep-merge'\nimport type { MessageRegistry } from './message-registry'\n\n@Transient(I18N_TOKENS.MessageLoader)\nexport class MessageLoaderService {\n private readonly cache: Map<string, Record<string, unknown>>\n private readonly contextCache: Map<string, CoreContext>\n private readonly locales: string[]\n private readonly defaultLocale: string\n\n constructor(\n @inject(I18N_TOKENS.MessageRegistry) private readonly registry: MessageRegistry,\n @inject(I18N_TOKENS.Options, { isOptional: true })\n private readonly options?: I18nModuleOptions\n ) {\n this.defaultLocale = this.options?.defaultLocale ?? 'en'\n this.cache = new Map()\n this.contextCache = new Map()\n\n // Core messages (always available)\n const coreMessages = getMessages()\n const coreLocales = getLocales()\n\n // Registry messages (accumulated from all registerMessages() calls)\n const registryMessages = this.registry.getMergedMessages()\n const registryLocales = Object.keys(registryMessages)\n\n // Union of all locales\n const allLocales = [...new Set([...coreLocales, ...registryLocales])]\n this.locales = allLocales\n\n // Merge messages for each locale: core defaults + registry contributions\n for (const locale of allLocales) {\n const coreLocaleMessages = coreMessages[locale] ?? {}\n const registryLocaleMessages = registryMessages[locale] ?? {}\n\n const merged = deepMerge(coreLocaleMessages, registryLocaleMessages)\n this.cache.set(locale, merged)\n }\n }\n\n /**\n * Get CoreContext for a locale (lazily built and cached on first access)\n * Falls back to default locale if locale not found\n */\n getCoreContext(locale: string): CoreContext {\n const cached = this.contextCache.get(locale)\n if (cached) return cached\n\n const effectiveLocale = this.cache.has(locale) ? locale : this.defaultLocale\n\n const cachedEffective = this.contextCache.get(effectiveLocale)\n if (cachedEffective) return cachedEffective\n\n const messages = this.cache.get(effectiveLocale) ?? {}\n const flattened = this.flattenMessages(messages)\n const ctx = createCoreContext({\n locale: effectiveLocale,\n messages: { [effectiveLocale]: flattened },\n missingWarn: false,\n fallbackWarn: false,\n })\n this.contextCache.set(effectiveLocale, ctx)\n return ctx\n }\n\n /**\n * Get messages for a specific locale.\n * Falls back to default locale if not found.\n */\n getMessages(locale: string): Record<string, unknown> {\n return this.cache.get(locale) ?? this.cache.get(this.defaultLocale) ?? {}\n }\n\n /** Get list of available locale codes */\n getAvailableLocales(): string[] {\n return this.locales\n }\n\n /** Check if a locale is supported */\n isLocaleSupported(locale: string): boolean {\n return this.cache.has(locale)\n }\n\n /** Get default locale */\n getDefaultLocale(): string {\n return this.defaultLocale\n }\n\n /**\n * Get flattened (dot-notation) messages for a locale, optionally filtered by namespace prefixes.\n *\n * Returns flat key-value pairs matching the format used by `@intlify/core-base`'s\n * `createCoreContext`. Requires `registerMessageCompiler(compile)` to be called\n * before `translate()` can resolve these flat keys.\n *\n * @param locale - Locale code (falls back to default locale if not found)\n * @param options - Optional filter configuration\n * @param options.only - Dot-notation prefixes to include (e.g., `['common', 'nav.sidebar']`)\n * @returns Flattened messages as `{ 'key.path': 'translated value' }`\n *\n * @example\n * ```typescript\n * // All messages for the locale\n * loader.getFilteredMessages('en')\n *\n * // Only 'common' and 'nav' namespaces\n * loader.getFilteredMessages('en', { only: ['common', 'nav'] })\n *\n * // Deeply nested prefix\n * loader.getFilteredMessages('en', { only: ['common.actions'] })\n * ```\n */\n getFilteredMessages(\n locale: string,\n options?: { only?: MessageKeyPrefix[] }\n ): Record<string, string> {\n const messages = this.getMessages(locale)\n const flattened = this.flattenMessages(messages)\n\n if (!options?.only?.length) return flattened\n\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(flattened)) {\n if (options.only.some((prefix) => key === prefix || key.startsWith(`${prefix}.`))) {\n result[key] = value\n }\n }\n return result\n }\n\n /**\n * Flatten nested messages to dot-notation.\n * e.g. `{ a: { b: 'hello' } }` → `{ 'a.b': 'hello' }`\n */\n private flattenMessages(\n messages: Record<string, unknown>,\n prefix = ''\n ): Record<string, string> {\n const result: Record<string, string> = {}\n\n for (const key of Object.keys(messages)) {\n const value = messages[key]\n const newKey = prefix ? `${prefix}.${key}` : key\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n Object.assign(result, this.flattenMessages(value as Record<string, unknown>, newKey))\n } else {\n result[newKey] = String(value)\n }\n }\n\n return result\n }\n\n}\n","import { Transient } from '../../di/decorators'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport { deepMerge } from '../utils/deep-merge'\n\n/**\n * Global key for the shared contributions array.\n *\n * When stratal is installed via portal/symlink (e.g., in monorepos), bundlers\n * like esbuild may inline multiple copies of this module. Each copy gets its\n * own static class fields, so messages registered by one copy are invisible\n * to another. Using a `Symbol.for()` key on `globalThis` ensures all copies\n * share the same contributions array.\n */\nconst CONTRIBUTIONS_KEY = Symbol.for('stratal:i18n:message-registry:contributions')\n\ntype Contributions = Record<string, Record<string, unknown>>[]\n\nfunction getContributions(): Contributions {\n const g = globalThis as Record<symbol, unknown>\n g[CONTRIBUTIONS_KEY] ??= [];\n return g[CONTRIBUTIONS_KEY] as Contributions\n}\n\n/**\n * Message Registry\n *\n * Accumulates i18n messages from multiple `I18nModule.registerMessages()` calls.\n * Messages are collected statically (at module import time) and deep-merged\n * when `getMergedMessages()` is called by `MessageLoaderService`.\n *\n * Later registrations override earlier ones at leaf level.\n */\n@Transient(I18N_TOKENS.MessageRegistry)\nexport class MessageRegistry {\n /**\n * Add messages (called statically by I18nModule.registerMessages)\n */\n static addMessages(messages: Record<string, Record<string, unknown>>): void {\n if (Boolean(messages) && typeof messages === 'object' && Object.keys(messages).length > 0) {\n getContributions().push(messages)\n }\n }\n\n /**\n * Get all messages deep-merged in registration order\n */\n getMergedMessages(): Record<string, Record<string, unknown>> {\n const merged: Record<string, Record<string, unknown>> = {}\n\n for (const contribution of getContributions()) {\n for (const locale of Object.keys(contribution)) {\n merged[locale] = deepMerge(\n (merged[locale] ?? {}),\n contribution[locale],\n )\n }\n }\n\n return merged\n }\n\n /**\n * Reset registry (for testing)\n * @internal\n */\n static reset(): void {\n (globalThis as Record<symbol, unknown>)[CONTRIBUTIONS_KEY] = []\n }\n}\n","import { swaggerUI } from '@hono/swagger-ui'\nimport type { Container } from '../../di/container'\nimport { Transient } from '../../di/decorators'\nimport type { II18nService } from '../../i18n'\nimport { I18N_TOKENS } from '../../i18n'\nimport type { OpenAPIHono, OpenAPIObject, PathItemObject } from '../../i18n/validation'\nimport { ROUTER_CONTEXT_KEYS, SECURITY_SCHEMES } from '../../router/constants'\nimport type { RouterEnv } from '../../router/types'\nimport { OPENAPI_TOKENS } from '../openapi.tokens'\nimport type { IOpenAPIConfigService, OpenAPIEffectiveConfig } from '../types'\n\n/**\n * OpenAPI Service\n *\n * Generates OpenAPI specifications with support for:\n * - Runtime configuration via OpenAPIConfigService\n * - Route filtering via custom routeFilter\n * - i18n support for titles and descriptions\n * - Security scheme definitions\n *\n * Hidden routes (hideFromDocs) are excluded at registration time via\n * @hono/zod-openapi's `hide` option and don't appear in the spec.\n *\n * Configuration is resolved per-request from OpenAPIConfigService,\n * allowing middleware to override config based on domain context.\n */\n@Transient(OPENAPI_TOKENS.OpenAPIService)\nexport class OpenAPIService {\n\n /**\n * Generate a filtered OpenAPI spec using the user's config.\n * Usable from both HTTP handlers and CLI commands.\n */\n getSpec(app: OpenAPIHono<RouterEnv>, container: Container): OpenAPIObject {\n const configService = container.resolve<IOpenAPIConfigService>(OPENAPI_TOKENS.ConfigService)\n const i18n = container.resolve<II18nService>(I18N_TOKENS.I18nService)\n const config = configService.getEffectiveConfig()\n\n const fullSpec = app.getOpenAPIDocument({\n openapi: '3.0.0',\n info: {\n version: config.info.version,\n title: config.info.title,\n description: config.info.description,\n },\n })\n\n // Security schemes\n fullSpec.components ??= {}\n fullSpec.components.securitySchemes = this.getSecuritySchemeDefinitions(i18n)\n\n // Apply custom routeFilter if provided\n if (config.routeFilter) {\n fullSpec.paths = this.filterRoutes(\n fullSpec.paths as Record<string, PathItemObject>,\n config,\n )\n }\n\n // Filter unreferenced schemas\n if (fullSpec.components.schemas) {\n fullSpec.components.schemas = this.filterSchemas(fullSpec as unknown as Record<string, unknown>) as typeof fullSpec.components.schemas\n }\n\n return fullSpec\n }\n\n /**\n * Setup OpenAPI documentation endpoints\n */\n setupEndpoints(app: OpenAPIHono<RouterEnv>, container: Container): void {\n const configService = container.resolve<IOpenAPIConfigService>(OPENAPI_TOKENS.ConfigService)\n const config = configService.getEffectiveConfig()\n\n // OpenAPI JSON spec endpoint\n app.get(config.jsonPath, (c) => {\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n const fullSpec = this.getSpec(app, requestContainer)\n\n // Add servers (HTTP-specific — needs request URL context)\n const url = new URL(c.req.raw.url)\n const i18n = requestContainer.resolve<II18nService>(I18N_TOKENS.I18nService)\n fullSpec.servers = [{\n url: `${url.protocol}//${url.host}`,\n description: i18n.t('common.api.serverDescription'),\n }]\n\n return c.json(fullSpec)\n })\n this.nameLastHandler(app, 'OpenAPI', 'spec')\n\n // Docs UI endpoint\n if (config.ui !== false) {\n const uiPath = config.ui?.path ?? '/api/docs'\n const uiRenderer = config.ui?.renderer\n\n app.get(uiPath, (c, next) => {\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n const requestConfigService = requestContainer.resolve<IOpenAPIConfigService>(\n OPENAPI_TOKENS.ConfigService\n )\n const effectiveConfig = requestConfigService.getEffectiveConfig()\n const uiContext = { specUrl: effectiveConfig.jsonPath, title: effectiveConfig.info.title }\n\n if (uiRenderer) {\n return uiRenderer(uiContext)(c, next)\n }\n\n return swaggerUI<RouterEnv>({ url: uiContext.specUrl })(c, next)\n })\n this.nameLastHandler(app, 'OpenAPI', 'docs')\n }\n }\n\n private nameLastHandler(app: OpenAPIHono<RouterEnv>, controller: string, method: string): void {\n const last = app.routes[app.routes.length - 1]\n Object.defineProperty(last.handler, 'name', { value: `http:${controller}.${method}` })\n }\n\n /**\n * Get localized security scheme definitions\n */\n private getSecuritySchemeDefinitions(i18n: II18nService) {\n return {\n [SECURITY_SCHEMES.BEARER_AUTH]: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: i18n.t('common.api.security.bearerAuth')\n },\n [SECURITY_SCHEMES.API_KEY]: {\n type: 'apiKey',\n in: 'header',\n name: 'X-API-Key',\n description: i18n.t('common.api.security.apiKey')\n },\n [SECURITY_SCHEMES.SESSION_COOKIE]: {\n type: 'apiKey',\n in: 'cookie',\n name: 'session',\n description: i18n.t('common.api.security.sessionCookie')\n }\n } as const\n }\n\n /**\n * Filter OpenAPI paths using custom routeFilter\n */\n private filterRoutes(\n paths: Record<string, PathItemObject>,\n config: OpenAPIEffectiveConfig\n ): Record<string, PathItemObject> {\n const filteredPaths: Record<string, PathItemObject> = {}\n\n for (const [path, pathItem] of Object.entries(paths)) {\n if (config.routeFilter && !config.routeFilter(path, pathItem)) {\n continue\n }\n\n filteredPaths[path] = pathItem\n }\n\n return filteredPaths\n }\n\n /**\n * Filter unreferenced schemas from OpenAPI spec\n */\n private filterSchemas(spec: Record<string, unknown>): Record<string, unknown> {\n const referencedSchemas = new Set<string>()\n\n // Collect all schema references from paths\n this.collectSchemaRefs(spec.paths, referencedSchemas)\n\n // Filter schemas to only include referenced ones\n const filteredSchemas: Record<string, unknown> = {}\n const components = spec.components as Record<string, unknown> | undefined\n if (components?.schemas) {\n const allSchemas = components.schemas as Record<string, unknown>\n let prevSize = 0\n while (referencedSchemas.size > prevSize) {\n prevSize = referencedSchemas.size\n for (const [schemaName, schemaValue] of Object.entries(allSchemas)) {\n if (referencedSchemas.has(schemaName) && !filteredSchemas[schemaName]) {\n filteredSchemas[schemaName] = schemaValue\n this.collectSchemaRefs(schemaValue, referencedSchemas)\n }\n }\n }\n }\n\n return filteredSchemas\n }\n\n /**\n * Recursively collect all schema references from an object\n */\n private collectSchemaRefs(obj: unknown, refs: Set<string>): void {\n if (!obj || typeof obj !== 'object') {\n return\n }\n\n const record = obj as Record<string, unknown>\n\n // Check if this object has a $ref property\n if (record.$ref && typeof record.$ref === 'string') {\n // Extract schema name from $ref (format: #/components/schemas/SchemaName)\n const match = /^#\\/components\\/schemas\\/(.+)$/.exec(record.$ref)\n if (match) {\n refs.add(match[1])\n }\n }\n\n // Recursively check all properties\n if (Array.isArray(obj)) {\n for (const item of obj) {\n this.collectSchemaRefs(item, refs)\n }\n } else {\n for (const value of Object.values(record)) {\n this.collectSchemaRefs(value, refs)\n }\n }\n }\n}\n","/**\n * OpenAPI Module\n *\n * Provides configurable OpenAPI documentation endpoints with runtime override support.\n *\n * Features:\n * - Configurable paths for /openapi.json and /docs\n * - Runtime config overrides via middleware\n * - i18n support for titles and descriptions\n * - Route filtering via hideFromDocs and custom routeFilter\n *\n * @example Basic usage\n * ```typescript\n * @Module({\n * imports: [\n * OpenAPIModule.forRoot({\n * info: { title: 'My API', version: '1.0.0' }\n * })\n * ]\n * })\n * export class AppModule {}\n * ```\n *\n * @example With runtime override in middleware\n * ```typescript\n * // In RouteAccessMiddleware\n * constructor(\n * @inject(OPENAPI_TOKENS.ConfigService) private openAPIConfig: IOpenAPIConfigService\n * ) {}\n *\n * async handle(ctx, next) {\n * this.openAPIConfig.override({\n * info: { title: 'Custom API' },\n * routeFilter: (path) => this.shouldInclude(path)\n * })\n * await next()\n * }\n * ```\n */\n\nimport { Scope } from '../di'\nimport { Module } from '../module'\nimport type { AsyncModuleOptions, DynamicModule } from '../module/types'\nimport { OPENAPI_TOKENS } from './openapi.tokens'\nimport { OpenAPIConfigService, OpenAPIService } from './services'\nimport type { OpenAPIModuleOptions } from './types'\n\n/** Default options when none provided */\nconst DEFAULT_OPTIONS: OpenAPIModuleOptions = {\n jsonPath: '/api/openapi.json',\n info: {\n title: 'API',\n version: '1.0.0'\n }\n}\n\n@Module({\n providers: [\n // OpenAPI config service (request-scoped, supports runtime overrides)\n { provide: OPENAPI_TOKENS.ConfigService, useClass: OpenAPIConfigService, scope: Scope.Request },\n // OpenAPI service (singleton — serves spec and docs endpoints)\n { provide: OPENAPI_TOKENS.OpenAPIService, useClass: OpenAPIService, scope: Scope.Singleton },\n ],\n})\nexport class OpenAPIModule {\n /**\n * Configure OpenAPI module with static options\n *\n * @param options - OpenAPI configuration (paths, info, security schemes)\n * @returns DynamicModule with options provider\n */\n static forRoot(options: OpenAPIModuleOptions = {}): DynamicModule {\n // Merge with defaults\n const mergedOptions: OpenAPIModuleOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n info: {\n ...DEFAULT_OPTIONS.info,\n ...options.info,\n title: options.info?.title ?? DEFAULT_OPTIONS.info?.title ?? 'API',\n version: options.info?.version ?? DEFAULT_OPTIONS.info?.version ?? '1.0.0',\n }\n }\n\n return {\n module: OpenAPIModule,\n providers: [\n { provide: OPENAPI_TOKENS.Options, useValue: mergedOptions }\n ]\n }\n }\n\n static forRootAsync(options: AsyncModuleOptions<OpenAPIModuleOptions>): DynamicModule {\n return {\n module: OpenAPIModule,\n providers: [\n {\n provide: OPENAPI_TOKENS.Options,\n useFactory: options.useFactory,\n inject: options.inject\n },\n ]\n }\n }\n}\n","import type { MiddlewareHandler } from 'hono'\nimport type { LoggerService } from '../../logger'\n\n/**\n * Create a Hono middleware that logs HTTP requests using our Logger service\n *\n * Logs request method, path, status code, and duration in milliseconds.\n * Format: [HTTP] METHOD /path -> STATUS (duration ms)\n *\n * @param logger - Logger service instance\n * @returns Hono middleware handler\n *\n * @example\n * ```typescript\n * const logger = container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n * app.use('*', createLoggerMiddleware(logger))\n * ```\n */\nexport function createLoggerMiddleware(logger: LoggerService): MiddlewareHandler {\n return async (c, next) => {\n const start = Date.now()\n const method = c.req.method\n const path = c.req.path\n\n await next()\n\n const duration = Date.now() - start\n const status = c.res.status\n\n logger.info(`[HTTP] ${method} ${path} -> ${status}`, {\n method,\n path,\n status,\n duration,\n })\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono';\nimport { DomainMismatchError } from '../errors';\nimport type { RouterEnv } from '../types';\n\n/**\n * Parse a domain pattern into a regex and extract parameter names.\n *\n * @example\n * parseDomainPattern('{tenant}.example.com')\n * // => { regex: /^([^.]+)\\.example\\.com$/, paramNames: ['tenant'] }\n *\n * parseDomainPattern('{region}.{tenant}.example.com')\n * // => { regex: /^([^.]+)\\.([^.]+)\\.example\\.com$/, paramNames: ['region', 'tenant'] }\n */\nexport function parseDomainPattern(pattern: string): { regex: RegExp; paramNames: string[] } {\n const paramNames: string[] = []\n\n const regexStr = pattern.replace(\n /\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g,\n (_match, paramName: string) => {\n paramNames.push(paramName)\n return '([^.]+)'\n }\n )\n\n // Escape dots in the remaining static parts\n const escaped = regexStr.replace(/\\./g, '\\\\.')\n return { regex: new RegExp(`^${escaped}$`), paramNames }\n}\n\n/**\n * Strip port number from a host header value.\n * 'example.com:8787' => 'example.com'\n */\nfunction stripPort(host: string): string {\n const colonIdx = host.lastIndexOf(':')\n if (colonIdx === -1) return host\n // Check if it's actually a port (digits after the colon)\n const afterColon = host.slice(colonIdx + 1)\n return /^\\d+$/.test(afterColon) ? host.slice(0, colonIdx) : host\n}\n\n/**\n * Create a Hono middleware that matches the request host against a domain pattern.\n *\n * When the host matches, domain parameters are extracted and stored in context\n * variables accessible via `ctx.domain(key)`.\n *\n * When the host does NOT match, throws `DomainMismatchError` (404).\n *\n * @param pattern - Domain pattern with `{param}` placeholders (e.g., '{tenant}.myapp.com')\n *\n * @example\n * ```typescript\n * // Applied automatically by RouteRegistrationService for controllers with domain config\n * @Controller('/dashboard', { domain: '{tenant}.myapp.com' })\n * export class DashboardController {\n * async index(ctx: RouterContext) {\n * const tenant = ctx.domain('tenant')\n * }\n * }\n * ```\n */\nexport function createDomainMiddleware(pattern: string): MiddlewareHandler<RouterEnv> {\n const { regex, paramNames } = parseDomainPattern(pattern)\n\n return async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const host = stripPort(c.req.header('host') ?? '')\n const match = regex.exec(host)\n\n if (!match) {\n throw new DomainMismatchError()\n }\n\n // Store domain params as context variables\n for (let i = 0; i < paramNames.length; i++) {\n c.set(`domain:${paramNames[i]}`, match[i + 1])\n }\n\n await next()\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport type { Constructor } from '../../types'\nimport { ROUTER_CONTEXT_KEYS } from '../constants'\nimport { MiddlewareNextCalledMultipleTimesError } from '../errors'\nimport type { Middleware, Next } from '../middleware.interface'\nimport { RouterContext } from '../router-context'\nimport type { RouterEnv } from '../types'\n\n/**\n * Create a Hono middleware handler that executes a chain of Stratal middleware classes.\n *\n * Each middleware is resolved from the request-scoped container per request,\n * then executed in order (first registered = outermost in the chain).\n *\n * @param classes - Middleware classes to chain\n * @returns Hono middleware handler\n */\nexport function createMiddlewareChain(\n classes: Constructor<Middleware>[]\n): MiddlewareHandler<RouterEnv> {\n return async (c: Context<RouterEnv>, next: () => Promise<Response | void>) => {\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n const ctx = new RouterContext(c)\n\n // Build chain from end to start\n let current = next\n for (let i = classes.length - 1; i >= 0; i--) {\n const prevNext = current\n const middlewareClass = classes[i]\n current = () => {\n const middleware = requestContainer.resolve<Middleware>(middlewareClass)\n let called = false\n const guardedNext: Next = () => {\n if (called) {\n const err = new MiddlewareNextCalledMultipleTimesError(middlewareClass.name ?? 'anonymous')\n console.error('[STRATAL DEBUG] next() called multiple times for ' + middlewareClass.name)\n console.error('[STRATAL DEBUG] Stack trace:', new Error().stack)\n return Promise.reject(err)\n }\n called = true\n return prevNext() as Promise<void>\n }\n return middleware.handle(ctx, guardedNext) as Promise<void>\n }\n }\n\n const result = await current()\n\n if (result instanceof Response) {\n return result // return to Hono\n }\n }\n}\n","import { ROUTE_METADATA_KEYS } from '../constants'\nimport type { ConventionRouteMetadata, RouteConfig, RouteMetadata } from '../types'\n\n/**\n * Decorator to add OpenAPI metadata to a controller method using convention-based routing.\n *\n * **Cannot be mixed with HTTP method decorators** (`@Get`, `@Post`, `@Put`, `@Patch`,\n * `@Delete`, `@All`) in the same controller. Use one pattern or the other.\n *\n * Stores route configuration (schemas, response, tags, security) in metadata.\n * HTTP method, path, and success status code are auto-derived from the method name:\n * - index() → GET /base-path → 200\n * - show() → GET /base-path/:id → 200\n * - create() → POST /base-path → 201\n * - update() → PUT /base-path/:id → 200\n * - patch() → PATCH /base-path/:id → 200\n * - destroy() → DELETE /base-path/:id → 200\n *\n * @param config - Route configuration (schemas, response, tags, security)\n *\n * @example\n * ```typescript\n * @Controller('/api/v1/notes', {\n * tags: ['Notes'],\n * security: ['bearerAuth']\n * })\n * export class NotesController implements Controller {\n * @Route({\n * body: createNoteSchema,\n * response: noteSchema, // 201 auto-derived from 'create' method\n * tags: ['Mutations'],\n * description: 'Create a new note'\n * })\n * async create(ctx: RouterContext): Promise<Response> {\n * // POST /api/v1/notes (auto-derived from method name)\n * // Body schema: createNoteSchema (auto-validated)\n * // Response: 201 → noteSchema (status auto-derived)\n * // Tags: ['Notes', 'Mutations'] (merged with controller)\n * // Security: ['bearerAuth'] (inherited from controller)\n * const body = ctx.body()\n * const note = await this.notesService.create(body)\n * return ctx.json(note, 201)\n * }\n *\n * @Route({\n * query: paginationSchema,\n * response: z.array(noteSchema) // 200 auto-derived from 'index' method\n * })\n * async index(ctx: RouterContext): Promise<Response> {\n * // GET /api/v1/notes (auto-derived)\n * // Query params auto-validated\n * const notes = await this.notesService.list()\n * return ctx.json(notes)\n * }\n *\n * @Route({\n * params: z.object({ id: z.string().uuid() }),\n * response: {\n * schema: noteSchema,\n * description: 'Note details'\n * },\n * security: [] // Override to make public\n * })\n * async show(ctx: RouterContext): Promise<Response> {\n * // GET /api/v1/notes/:id (auto-derived)\n * // URL params auto-validated\n * // Response: 200 → noteSchema (status auto-derived)\n * // Security: [] (public route, override controller security)\n * const id = ctx.param('id')\n * const note = await this.notesService.findById(id)\n * return ctx.json(note)\n * }\n * }\n * ```\n */\nexport function Route(config: Omit<RouteConfig, 'statusCode'>) {\n return function (\n target: object,\n propertyKey: string,\n descriptor: PropertyDescriptor\n ) {\n const metadata: ConventionRouteMetadata = {\n type: 'convention',\n config,\n }\n\n Reflect.defineMetadata(\n ROUTE_METADATA_KEYS.ROUTE_CONFIG,\n metadata,\n target,\n propertyKey\n )\n\n // Track this method as decorated on the prototype\n const existing: string[] =\n (Reflect.getOwnMetadata(ROUTE_METADATA_KEYS.DECORATED_METHODS, target) as string[] | undefined) ?? []\n existing.push(propertyKey)\n Reflect.defineMetadata(ROUTE_METADATA_KEYS.DECORATED_METHODS, existing, target)\n\n return descriptor\n }\n}\n\n/**\n * Get the route metadata from a controller method\n *\n * @param target - Controller instance or prototype\n * @param methodName - Name of the method\n * @returns Route metadata or undefined if not decorated\n */\nexport function getRouteMetadata(target: object, methodName: string): RouteMetadata | undefined {\n return Reflect.getMetadata(ROUTE_METADATA_KEYS.ROUTE_CONFIG, target, methodName) as RouteMetadata | undefined\n}\n\n/**\n * Get all methods with route decorators (@Route, @Get, @Post, etc.) from a controller\n *\n * @param ControllerClass - Controller class\n * @returns Array of method names that have route metadata\n */\nexport function getRouteDecoratedMethods(ControllerClass: new (...args: unknown[]) => object): string[] {\n const methods = new Set<string>()\n let proto: object | null = ControllerClass.prototype as object\n\n while (proto && proto !== Object.prototype) {\n const own = Reflect.getOwnMetadata(ROUTE_METADATA_KEYS.DECORATED_METHODS, proto) as string[] | undefined\n if (own) {\n for (const m of own) methods.add(m)\n }\n proto = Object.getPrototypeOf(proto) as object | null\n }\n\n return [...methods]\n}\n","import { z } from '../../i18n/validation'\n\n/**\n * Common OpenAPI Schemas\n *\n * Reusable schema definitions for common API patterns:\n * - Error responses\n * - Pagination\n * - Common parameters\n */\n\n/**\n * Generic error response schema\n * Used for all error responses (4xx, 5xx)\n * Matches ApplicationError.toErrorResponse() structure\n */\nexport const errorResponseSchema = z.object({\n code: z.number().int().describe('Application error code'),\n message: z.string().describe('Human-readable error message'),\n timestamp: z.string().datetime().describe('ISO timestamp when error occurred'),\n metadata: z.record(z.string(), z.unknown()).optional().describe('Additional error context'),\n stack: z.string().optional().describe('Stack trace (development only)')\n}).openapi('ErrorResponse')\n\n/**\n * Validation error response schema\n * Used for 400 Bad Request with validation failures\n * Matches ApplicationError.toErrorResponse() structure with validation-specific metadata\n */\nexport const validationErrorResponseSchema = z.object({\n code: z.number().int().describe('Application error code'),\n message: z.string().describe('Human-readable error message'),\n timestamp: z.string().datetime().describe('ISO timestamp when error occurred'),\n metadata: z.object({\n issues: z.array(z.object({\n path: z.string().describe('Field path that failed validation'),\n message: z.string().describe('Validation failure message'),\n code: z.string().describe('Zod validation error code')\n }))\n }).describe('Validation error details'),\n stack: z.string().optional().describe('Stack trace (development only)')\n}).openapi('ValidationErrorResponse')\n\n/**\n * Pagination query parameters schema\n * Used for list endpoints\n */\nexport const paginationQuerySchema = z.object({\n page: z.coerce.number().int().positive().default(1).describe('Page number (1-indexed)'),\n limit: z.coerce.number().int().positive().max(100).default(20).describe('Items per page (max 100)')\n}).openapi('PaginationQuery')\n\n/**\n * Paginated response wrapper schema\n * Generic wrapper for paginated list responses\n */\nexport const paginatedResponseSchema = <T extends z.ZodType>(itemSchema: T) =>\n z.object({\n data: z.array(itemSchema).describe('Array of items for current page'),\n pagination: z.object({\n page: z.number().int().positive().describe('Current page number'),\n limit: z.number().int().positive().describe('Items per page'),\n total: z.number().int().nonnegative().describe('Total number of items'),\n totalPages: z.number().int().nonnegative().describe('Total number of pages')\n })\n })\n\n/**\n * UUID parameter schema\n * Used for :id parameters in RESTful routes\n */\nexport const uuidParamSchema = z.object({\n id: z.string().uuid().describe('Resource UUID')\n}).openapi('UUIDParam')\n\n/**\n * Success message response schema\n * Used for operations that don't return data (e.g., DELETE)\n */\nexport const successMessageSchema = z.object({\n message: z.string().describe('Success message'),\n data: z.record(z.string(), z.unknown()).optional().describe('Optional additional data')\n}).openapi('SuccessMessage')\n\n/**\n * Common HTTP status error schemas\n * Pre-configured for standard error responses\n */\nexport const commonErrorSchemas = {\n 400: { schema: validationErrorResponseSchema, description: 'Validation error' },\n 401: { schema: errorResponseSchema, description: 'Unauthorized' },\n 403: { schema: errorResponseSchema, description: 'Forbidden' },\n 404: { schema: errorResponseSchema, description: 'Not found' },\n 409: { schema: errorResponseSchema, description: 'Conflict' },\n 500: { schema: errorResponseSchema, description: 'Internal server error' }\n} as const\n","/**\n * Path normalization and route ordering utilities.\n *\n * Users always write Hono-style `:param` paths (`:companyId`, `:id`).\n * OpenAPI requires `{param}` style — conversion happens only at registration time.\n */\n\n/**\n * Convert Hono-style `:param` path segments to OpenAPI-style `{param}`.\n * Strips regex constraints (e.g., `:locale{sw}` → `{locale}`).\n *\n * @example\n * toOpenAPIPath('/users/:id') // '/users/{id}'\n * toOpenAPIPath('/:companyId/users/:userId') // '/{companyId}/users/{userId}'\n * toOpenAPIPath('/users/:id/posts') // '/users/{id}/posts'\n * toOpenAPIPath('/:locale{en|fr}/users') // '/{locale}/users'\n */\nexport function toOpenAPIPath(path: string): string {\n return path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\\{[^}]*\\})?/g, '{$1}')\n}\n\n/**\n * Convert Hono-style `:param` path segments to OpenAPI-style `{param}`,\n * preserving regex constraints.\n *\n * Used for Hono route registration via `app.openapi()`. The non-greedy\n * regex in `@hono/zod-openapi` (`\\/{(.+?)}/g`) converts `{param}` back\n * to `:param` while leaving the constraint suffix intact.\n *\n * @example\n * toRoutingOpenAPIPath('/:locale{sw}/users/:id') // '/{locale}{sw}/users/{id}'\n * toRoutingOpenAPIPath('/users/:id') // '/users/{id}'\n */\nexport function toRoutingOpenAPIPath(path: string): string {\n return path.replace(\n /:([a-zA-Z_][a-zA-Z0-9_]*)(\\{[^}]*\\})?/g,\n (_, name: string, constraint?: string) => constraint ? `{${name}}${constraint}` : `{${name}}`,\n )\n}\n\n/**\n * Compute a packed specificity key for route ordering.\n * Encodes both score and segment count into a single number to avoid object allocation.\n *\n * Lower score = higher priority (registered first in Hono).\n * Scoring: static = 0, `:param{constraint}` = 5, `:param` = 10, wildcard `{.+}` / `{.*}` = 100.\n *\n * Packed as: score * 10000 - segmentCount (negative segment count so more segments = lower key = higher priority)\n */\nfunction getPathSpecificityKey(path: string): number {\n let score = 0\n let segmentCount = 0\n let i = 0\n\n while (i < path.length) {\n if (path.charCodeAt(i) === 47 /* '/' */) { i++; continue }\n\n let end = path.indexOf('/', i)\n if (end === -1) end = path.length\n\n segmentCount++\n const segment = path.substring(i, end)\n\n if (segment.includes('{.+}') || segment.includes('{.*}')) {\n score += 100\n } else if (segment.charCodeAt(0) === 58 /* ':' */) {\n score += segment.includes('{') ? 5 : 10\n }\n\n i = end\n }\n\n return score * 10000 - segmentCount\n}\n\n/**\n * Compute a specificity score for route ordering.\n * Lower score = higher priority (registered first in Hono).\n *\n * Scoring: static = 0, `:param{constraint}` = 5, `:param` = 10, wildcard `{.+}` / `{.*}` = 100.\n */\nexport function getPathSpecificityScore(path: string): number {\n const segments = path.split('/').filter(Boolean)\n let score = 0\n for (const segment of segments) {\n if (segment.includes('{.+}') || segment.includes('{.*}')) {\n score += 100\n } else if (segment.startsWith(':') && segment.includes('{')) {\n score += 5\n } else if (segment.startsWith(':')) {\n score += 10\n }\n }\n return score\n}\n\n/**\n * Sort routes by specificity so Hono registers them in the correct order.\n *\n * 1. Static paths before parameterized before wildcards\n * 2. More segments = more specific (tie-breaker)\n * 3. Primary paths before locale-prefixed variants\n */\nexport function sortRoutesBySpecificity<T extends { path: string }>(routes: T[]): T[] {\n // Pre-compute packed specificity keys (avoids object allocation per route)\n const keys = new Map<T, number>()\n for (const route of routes) {\n keys.set(route, getPathSpecificityKey(route.path))\n }\n\n const copy = routes.slice()\n copy.sort((a, b) => keys.get(a)! - keys.get(b)!)\n return copy\n}\n","/**\n * Route naming utilities.\n *\n * Extracts parameter names from paths and domains,\n * and generates convention-based route names.\n */\n\n/**\n * Extract parameter names from a Hono-style path.\n *\n * @example\n * extractParamNames('/users/:id') // ['id']\n * extractParamNames('/:companyId/users/:userId') // ['companyId', 'userId']\n * extractParamNames('/users') // []\n */\nexport function extractParamNames(path: string): string[] {\n if (!path.includes(':')) return []\n const matches = path.matchAll(/:([a-zA-Z_][a-zA-Z0-9_]*)/g)\n return [...matches].map(m => m[1])\n}\n\n/**\n * Extract parameter names from a domain pattern.\n *\n * @example\n * extractDomainParamNames('{tenant}.example.com') // ['tenant']\n * extractDomainParamNames('{region}.{tenant}.example.com') // ['region', 'tenant']\n * extractDomainParamNames('example.com') // []\n */\nexport function extractDomainParamNames(domain: string): string[] {\n if (!domain.includes('{')) return []\n const matches = domain.matchAll(/\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g)\n return [...matches].map(m => m[1])\n}\n\n/**\n * Auto-generate a route name for convention-based `@Route` methods.\n *\n * Strips common prefixes (`/api/`, `/v{N}/`) and parameter segments,\n * then joins remaining static segments with dots and appends the method name.\n *\n * @example\n * generateConventionRouteName('/users', 'index') // 'users.index'\n * generateConventionRouteName('/users', 'show') // 'users.show'\n * generateConventionRouteName('/api/v1/users', 'create') // 'users.create'\n * generateConventionRouteName('/api/v1/users/:userId/notes', 'index') // 'users.notes.index'\n * generateConventionRouteName('/:companyId/users', 'index') // 'users.index'\n * generateConventionRouteName('/users/:userId/notes/:noteId/tags', 'index') // 'users.notes.tags.index'\n */\nexport function generateConventionRouteName(basePath: string, methodName: string): string {\n // Single-pass: split and filter in one loop (avoids 4 intermediate arrays)\n const parts = basePath.split('/')\n const segments: string[] = []\n for (const s of parts) {\n if (s && s !== 'api' && !s.startsWith(':') && !/^v\\d+$/.test(s)) {\n segments.push(s)\n }\n }\n\n if (segments.length === 0) {\n return methodName\n }\n\n return `${segments.join('.')}.${methodName}`\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport type { UpgradeWebSocket, WSContext, WSEvents } from 'hono/ws'\nimport { inject } from 'tsyringe'\nimport { type Container, getMethodInjections } from '../../di'\nimport { Transient } from '../../di/decorators'\nimport { DI_TOKENS } from '../../di/tokens'\nimport {\n type Guard,\n GuardExecutionService,\n getControllerGuards,\n getMethodGuards,\n} from '../../guards'\nimport type { ZodType } from '../../i18n/validation'\nimport { createRoute, z } from '../../i18n/validation'\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger'\nimport type { ModuleRegistry } from '../../module/module-registry'\nimport type { Constructor } from '../../types'\nimport { getWsOnCloseMethod, getWsOnErrorMethod, getWsOnMessageMethod, isGateway } from '../../websocket/decorators'\nimport { GatewayContext } from '../../websocket/gateway-context'\nimport { DEFAULT_CONTENT_TYPE, HTTP_METHODS, METHOD_STATUS_CODES, SECURITY_SCHEMES } from '../constants'\nimport type { IController } from '../controller'\nimport {\n getControllerOptions,\n getControllerRoute,\n getRouteDecoratedMethods,\n getRouteMetadata,\n} from '../decorators'\nimport {\n ControllerMethodNotFoundError,\n ControllerRegistrationError,\n OpenAPIRouteRegistrationError,\n ResponseValidationError,\n} from '../errors'\nimport type { HonoApp } from '../hono-app'\nimport type { Middleware } from '../middleware.interface'\nimport { createDomainMiddleware } from '../middleware/domain.middleware'\nimport { createMiddlewareChain } from '../middleware/middleware-chain'\nimport { type RegisteredRoute, type RouteRegistry } from '../route-registry'\nimport { RouterContext } from '../router-context'\nimport type { RouterResolver } from '../router-resolver'\nimport { ROUTER_TOKENS } from '../router.tokens'\nimport { commonErrorSchemas } from '../schemas/common.schemas'\nimport type {\n ControllerOptions,\n HttpMethod,\n OpenAPIRouteConfig,\n RouteBodyObject,\n RouteConfig,\n RouteMetadata,\n RouteResponseObject,\n RouterEnv,\n SecuritySchemeRecord,\n} from '../types'\nimport { toOpenAPIPath, toRoutingOpenAPIPath } from '../utils/path'\nimport { generateConventionRouteName } from '../utils/route-name'\nimport type { LocalePathService } from './locale-path.service'\n\nconst invokeHandler = (instance: Record<string, (...args: unknown[]) => unknown>, method: string, ...args: unknown[]): Promise<unknown> => {\n try {\n return Promise.resolve(instance[method](...args))\n } catch (err: unknown) {\n return Promise.reject(err as Error)\n }\n}\n\n/**\n * Route registration service\n * Manages controller and route registration with OpenAPI support\n *\n * Responsibilities:\n * - Register RESTful controllers with OpenAPI metadata\n * - Auto-derive HTTP methods/paths from controller method names\n * - Build OpenAPI route configurations with guard execution\n * - Validate all controllers have access decorators (strict mode)\n * - Create controller handlers with DI resolution\n *\n * Two-pass strategy:\n * 1. Collect: iterate controllers, register in RouteRegistry, store Hono actions\n * 2. Register: iterate registry.all() (sorted), execute stored actions in Hono\n */\n@Transient()\nexport class RouteRegistrationService {\n private controllerClasses = new Map<string, Constructor>()\n private upgradeWebSocketFn: UpgradeWebSocket | null = null\n\n constructor(\n @inject(LOGGER_TOKENS.LoggerService) private logger: LoggerService,\n @inject(ROUTER_TOKENS.RouteRegistry) private registry: RouteRegistry,\n @inject(ROUTER_TOKENS.RouterResolver) private routerResolver: RouterResolver | null,\n @inject(ROUTER_TOKENS.LocalePathService) private localePathService: LocalePathService,\n @inject(ROUTER_TOKENS.HonoApp) private app: HonoApp,\n @inject(DI_TOKENS.ModuleRegistry) private moduleRegistry: ModuleRegistry,\n ) { }\n\n /**\n * Configure router with controllers and global middleware.\n * Resolves controllers from ModuleRegistry and global middleware from RouterResolver.\n */\n async configure(): Promise<void> {\n const controllers = this.moduleRegistry.getAllControllers()\n const globalMiddleware = this.routerResolver?.getGlobalMiddleware() ?? []\n\n this.logger.info('Registering controllers', {\n controllerCount: controllers.length,\n })\n\n // Global middleware from Router.use() (applies to ALL routes)\n if (globalMiddleware.length > 0) {\n this.app.use('*', createMiddlewareChain(globalMiddleware))\n }\n\n // Eagerly load upgradeWebSocket once if any gateway exists\n if (controllers.some(isGateway)) {\n const { upgradeWebSocket } = await import('hono/cloudflare-workers')\n this.upgradeWebSocketFn = upgradeWebSocket\n }\n\n // Pass 1: Collect routes into registry + store Hono registration actions\n const actions = new WeakMap<RegisteredRoute, () => void>()\n for (const ControllerClass of controllers) {\n this.collectRoutes(ControllerClass, actions)\n }\n\n // Pass 2: Register in Hono in specificity order from registry\n for (const route of this.registry.all()) {\n actions.get(route)?.()\n }\n\n this.logger.info('Controller registration complete')\n }\n\n /**\n * Pass 1: Collect routes from a controller into RouteRegistry and store Hono actions.\n * Versioning and locale expansion are handled by RouteRegistry.register().\n */\n private collectRoutes(\n ControllerClass: Constructor,\n actions: WeakMap<RegisteredRoute, () => void>,\n ): void {\n const isWsGateway = isGateway(ControllerClass)\n const controllerRoute = getControllerRoute(ControllerClass)\n\n if (!controllerRoute) {\n throw new ControllerRegistrationError(\n ControllerClass.name,\n isWsGateway\n ? 'Missing @Gateway decorator or route metadata'\n : 'Missing @Controller decorator or route metadata'\n )\n }\n\n const controllerOpts = getControllerOptions(ControllerClass)\n const controllerGuards = getControllerGuards(ControllerClass)?.guards ?? []\n\n // Resolve Router config for this controller (prefix, domain, name, middleware, version, hideFromDocs)\n const routerConfig = this.routerResolver?.resolveForController(ControllerClass) ?? { middleware: [] }\n\n // Apply Router prefix to controller base path\n const basePath = routerConfig.prefix\n ? this.joinPaths(routerConfig.prefix, controllerRoute)\n : controllerRoute\n\n // Version resolution: controller version > Router version\n const effectiveVersion = controllerOpts?.version ?? routerConfig.version\n\n // Apply domain middleware if controller or router has a domain pattern\n const effectiveDomain = controllerOpts?.domain ?? routerConfig.domain\n\n // WebSocket gateway\n if (isWsGateway) {\n const expandedRoutes = this.registry.register({\n method: 'ws',\n basePath,\n version: effectiveVersion,\n domain: effectiveDomain,\n controller: ControllerClass.name,\n action: 'ws',\n hidden: routerConfig.hideFromDocs ?? false,\n middleware: routerConfig.middleware.map(m => m.name),\n })\n\n for (const route of expandedRoutes) {\n actions.set(route, () => {\n // Apply scoped middleware at the exact route path so it runs\n // for this specific route (including the root of the group) —\n // not via a `/*` sub-path wildcard, which would miss the exact\n // path match.\n if (routerConfig.middleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(routerConfig.middleware))\n }\n // Apply domain middleware\n if (effectiveDomain) {\n const domainHandler = createDomainMiddleware(effectiveDomain)\n this.app.use(route.path, domainHandler)\n this.app.use(`${route.path}/*`, domainHandler)\n }\n this.registerGatewayForPath(ControllerClass, route.path, controllerGuards)\n })\n }\n return\n }\n\n const className = ControllerClass.name\n this.controllerClasses.set(className, ControllerClass)\n\n const prototype = ControllerClass.prototype as IController\n\n // Wildcard routes (non-RESTful controllers with handle())\n if (prototype.handle) {\n const expandedRoutes = this.registry.register({\n method: 'all',\n basePath,\n version: effectiveVersion,\n domain: effectiveDomain,\n controller: className,\n action: 'handle',\n hidden: routerConfig.hideFromDocs ?? false,\n middleware: routerConfig.middleware.map(m => m.name),\n })\n\n for (const route of expandedRoutes) {\n actions.set(route, () => {\n if (routerConfig.middleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(routerConfig.middleware))\n }\n this.registerWildcardRoute(ControllerClass, route.path)\n })\n }\n return\n }\n\n // Standard HTTP routes — validate decorated methods\n const decoratedMethods = getRouteDecoratedMethods(ControllerClass)\n\n if (decoratedMethods.length === 0) {\n throw new ControllerRegistrationError(\n ControllerClass.name,\n 'No route decorators found. Use @Route() or HTTP method decorators (@Get, @Post, etc.) on controller methods.'\n )\n }\n\n // Pre-cache metadata for all decorated methods (avoids double getRouteMetadata lookup)\n const methodMetadata: { method: string; meta: RouteMetadata }[] = []\n let hasConvention = false\n let hasExplicit = false\n for (const m of decoratedMethods) {\n const meta = getRouteMetadata(prototype, m)\n if (!meta) continue\n methodMetadata.push({ method: m, meta })\n if (meta.type === 'convention') hasConvention = true\n else if (meta.type === 'explicit') hasExplicit = true\n }\n\n // Enforce mutual exclusivity: no mixing @Route() with @Get/@Post/etc.\n if (hasConvention && hasExplicit) {\n throw new ControllerRegistrationError(\n ControllerClass.name,\n 'Cannot mix @Route() with HTTP method decorators (@Get, @Post, etc.) in the same controller. Use one pattern or the other.'\n )\n }\n\n const routerHidden = routerConfig.hideFromDocs\n const controllerHidden = controllerOpts?.hideFromDocs ?? false\n\n // Resolve effective name prefix: router-level name (module + group merged by\n // RouterResolver) concatenates with the controller-level name, mirroring how\n // prefixes compose. A controller's `{ name: 'dashboard.' }` inside a module\n // that calls `router.name('admin.')` becomes `admin.dashboard.*` — not\n // `dashboard.*`.\n const routerName = routerConfig.name\n const controllerName = controllerOpts?.name\n const effectiveNamePrefix =\n routerName && controllerName\n ? `${routerName}${controllerName}`\n : (routerName ?? controllerName)\n\n // Hoist middleware name computation (same for all methods in this controller)\n const middlewareNames = routerConfig.middleware.map(m => m.name)\n\n for (const { method: methodName, meta } of methodMetadata) {\n const resolved = this.resolveMethodAndPath(meta, methodName, basePath, className)\n if (!resolved) continue\n\n const { httpMethod, fullPath, routeConfig, statusCodeOverride } = resolved\n\n // Auto-inject prefix params from Router.prefix() into route params\n if (routerConfig.params) {\n routeConfig.params = routeConfig.params\n ? (routerConfig.params as z.ZodObject).extend((routeConfig.params as z.ZodObject).shape)\n : routerConfig.params\n }\n\n const hideFromDocs = routeConfig.hideFromDocs ?? (routerHidden ?? controllerHidden)\n\n // Compute route name\n let routeName: string | undefined\n if (routeConfig.name) {\n routeName = effectiveNamePrefix ? `${effectiveNamePrefix}${routeConfig.name}` : routeConfig.name\n } else if (meta.type === 'convention') {\n const autoName = generateConventionRouteName(basePath, methodName)\n routeName = effectiveNamePrefix ? `${effectiveNamePrefix}${autoName}` : autoName\n }\n\n // Register in RouteRegistry (handles versioning + locale expansion)\n const expandedRoutes = this.registry.register({\n name: routeName,\n method: httpMethod,\n basePath: fullPath,\n version: effectiveVersion,\n domain: effectiveDomain,\n controller: className,\n action: methodName,\n hidden: hideFromDocs,\n middleware: middlewareNames,\n })\n\n // Collect guards — avoid spread when no method-level guards (common case)\n const methodGuards = getMethodGuards(prototype, methodName)?.guards ?? []\n const allGuards: Guard[] = methodGuards.length > 0\n ? [...controllerGuards, ...methodGuards]\n : controllerGuards\n\n const responseSchema = httpMethod !== 'all'\n ? this.extractResponseSchema(routeConfig)\n : null\n\n const handler = this.createControllerHandler(ControllerClass, methodName, responseSchema)\n\n for (const route of expandedRoutes) {\n actions.set(route, () => {\n // Apply domain middleware\n if (effectiveDomain) {\n const domainHandler = createDomainMiddleware(effectiveDomain)\n this.app.use(route.path, domainHandler)\n this.app.use(`${route.path}/*`, domainHandler)\n }\n\n if (allGuards.length > 0) {\n this.logger.info(`Route guards`, {\n controller: className,\n method: httpMethod.toUpperCase(),\n path: route.path,\n methodName,\n guardCount: allGuards.length,\n })\n }\n\n // @All routes can't use OpenAPI — register directly with\n // scoped middleware (if any) + guard middleware + handler.\n if (httpMethod === 'all') {\n this.logger.info(`Registering @All route`, {\n controller: className,\n path: route.path,\n methodName,\n })\n\n if (routerConfig.middleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(routerConfig.middleware))\n }\n if (allGuards.length > 0) {\n this.app.use(route.path, this.createGuardMiddleware(allGuards))\n }\n this.app.all(route.path, handler)\n return\n }\n\n // Build and register OpenAPI route\n const metadata = this.mergeMetadata(controllerOpts, routeConfig, ControllerClass, methodName)\n const openApiRoute = this.buildOpenAPIRoute(\n httpMethod,\n route.path,\n routeConfig,\n metadata,\n meta.type === 'convention' ? methodName : undefined,\n statusCodeOverride,\n route.isLocaleVariant ?? false,\n )\n\n this.logger.info(`Registering route`, {\n controller: className,\n method: httpMethod.toUpperCase(),\n path: route.path,\n methodName,\n tags: metadata.tags,\n hidden: route.hidden,\n })\n\n // Wrap the controller handler so scoped middleware and guards\n // run AFTER Hono's request validators. @hono/zod-openapi\n // composes a route as `...routeMiddleware, ...validators, handler`\n // (see node_modules/@hono/zod-openapi/dist/index.js), which means\n // anything attached via `route.middleware` runs *before*\n // validation — and therefore can't read `c.req.valid('param')`.\n // Wrapping the handler is the only place we can run middleware\n // after validators in this Hono pipeline.\n //\n // Final order: global app.use → request validators → scoped\n // middleware → guards → controller handler.\n const wrappedHandler = this.wrapHandlerWithChain(handler, routerConfig.middleware, allGuards)\n this.app.openapi(openApiRoute, wrappedHandler)\n\n // Register clean path in OpenAPI spec (strips regex constraints from params)\n if (!route.hidden) {\n const { hide: _, ...specRoute } = openApiRoute\n this.app.openAPIRegistry.registerPath({\n ...specRoute,\n path: toOpenAPIPath(route.path),\n })\n }\n })\n }\n }\n }\n\n\n /**\n * Register a single WebSocket gateway route\n */\n private registerGatewayForPath(\n GatewayClass: Constructor,\n fullPath: string,\n guards: Guard[],\n ): void {\n // Route already registered in RouteRegistry during collectRoutes()\n // Cache WS metadata once at registration time (not per-connection)\n const onMsgMethod = getWsOnMessageMethod(GatewayClass)\n const onCloseMethod = getWsOnCloseMethod(GatewayClass)\n const onErrMethod = getWsOnErrorMethod(GatewayClass)\n\n const wsHandler: MiddlewareHandler<RouterEnv> = this.upgradeWebSocketFn!((c) => {\n const routerCtx = new RouterContext(c as Context<RouterEnv>)\n const container = routerCtx.getContainer()\n const gateway = container.resolve(GatewayClass)\n\n // Cloudflare Workers doesn't support the `onOpen` WebSocket event;\n // the upgrade callback itself serves as the open context.\n const events: Omit<WSEvents, 'onOpen'> = {}\n\n const bindWsHandler = (\n method: string,\n onCatch?: (err: unknown, ws: WSContext) => void\n ) => {\n return (evt: MessageEvent | CloseEvent | Event, ws: WSContext) => {\n const ctx = new GatewayContext(c as Context<RouterEnv>, ws)\n invokeHandler(gateway as Record<string, (...args: unknown[]) => unknown>, method, evt, ctx).catch((err: unknown) => {\n this.logger.error(`WebSocket ${method} handler error`, { gateway: GatewayClass.name, error: err instanceof Error ? err.message : String(err) })\n onCatch?.(err, ws)\n })\n }\n }\n\n if (onMsgMethod) {\n events.onMessage = bindWsHandler(onMsgMethod, (_err, ws) => ws.close(1011, 'Internal Error'))\n }\n if (onCloseMethod) {\n events.onClose = bindWsHandler(onCloseMethod)\n }\n if (onErrMethod) {\n events.onError = bindWsHandler(onErrMethod)\n }\n\n return events\n }) as MiddlewareHandler<RouterEnv>\n\n this.nameHandler(wsHandler, GatewayClass.name, onMsgMethod ?? '[anonymous]', 'ws')\n\n this.logger.info('Registering WebSocket gateway', {\n gateway: GatewayClass.name,\n path: fullPath,\n })\n\n const handlers: MiddlewareHandler<RouterEnv>[] = []\n\n if (guards.length > 0) {\n this.logger.info('Gateway guards', {\n gateway: GatewayClass.name,\n path: fullPath,\n guardCount: guards.length,\n })\n handlers.push(this.createGuardMiddleware(guards))\n }\n\n handlers.push(wsHandler)\n\n // Type assertion needed because Hono's overloaded .get() signatures\n // don't accept a spread of MiddlewareHandler[] alongside upgradeWebSocket's output type\n this.app.get(fullPath, ...(handlers as [MiddlewareHandler<RouterEnv>]))\n }\n\n\n /**\n * Create a guard execution middleware\n *\n * This middleware executes all guards for a route before the handler.\n * Guards are executed in order; all must pass for the request to proceed.\n *\n * @param guards - Array of guards to execute\n * @returns Hono middleware function\n */\n private createGuardMiddleware(guards: Guard[]) {\n const guardService = new GuardExecutionService(this.logger)\n\n return async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const ctx = new RouterContext(c)\n const container = ctx.getContainer()\n\n // Execute all guards - throws on failure\n await guardService.executeGuards(guards, ctx, container)\n\n // All guards passed, continue to handler\n await next()\n }\n }\n\n /**\n * Wrap a controller handler with a `scopedMiddleware → guards → handler`\n * chain that runs *inside* the Hono route handler — after request\n * validators have populated `c.req.valid(...)`. This is the only place\n * we can run user middleware after `@hono/zod-openapi`'s validators in\n * the same pipeline.\n *\n * Returns a Hono handler with the same signature as the original so\n * `app.openapi(route, wrapped)` works transparently.\n */\n private wrapHandlerWithChain(\n handler: (c: Context<RouterEnv>) => Promise<Response>,\n scopedMiddleware: Constructor<Middleware>[],\n guards: Guard[],\n ) {\n if (scopedMiddleware.length === 0 && guards.length === 0) {\n return handler\n }\n\n const scopedChain = scopedMiddleware.length > 0\n ? createMiddlewareChain(scopedMiddleware)\n : null\n const guardChain = guards.length > 0\n ? this.createGuardMiddleware(guards)\n : null\n\n return async (c: Context<RouterEnv>): Promise<Response> => {\n let captured: Response | undefined\n\n const runHandler = async () => {\n captured = await handler(c)\n }\n const runGuards = guardChain\n ? () => guardChain(c, runHandler)\n : runHandler\n const runScoped = scopedChain\n ? () => scopedChain(c, runGuards)\n : runGuards\n\n const result = await runScoped()\n // A middleware (scoped or guard) may short-circuit by returning a\n // Response from its createMiddlewareChain — surface that. Otherwise\n // the handler always sets `captured`.\n if (result instanceof Response) return result\n return captured!\n }\n }\n\n /**\n * Register wildcard route for non-RESTful controllers\n */\n private registerWildcardRoute(\n ControllerClass: Constructor,\n route: string\n ): void {\n this.logger.info(`Registering wildcard route`, {\n controller: ControllerClass.name,\n route: `${route}/:path{.+}`,\n method: 'ALL',\n })\n\n const handler = this.createControllerHandler(ControllerClass, 'handle')\n // Match base route exactly\n this.app.all(route, handler)\n // Match all sub-paths using named regex wildcard\n this.app.all(`${route}/:path{.+}`, handler)\n }\n\n\n /**\n * Resolve HTTP method, path, route config, and status code from route metadata.\n */\n private resolveMethodAndPath(\n meta: RouteMetadata,\n methodName: string,\n basePath: string,\n className: string\n ): { httpMethod: HttpMethod; fullPath: string; routeConfig: RouteConfig; statusCodeOverride?: number } | null {\n if (meta.type === 'convention') {\n const derived = this.deriveHttpMethodAndPath(methodName, basePath)\n if (!derived) {\n throw new ControllerRegistrationError(\n `Cannot derive HTTP method/path for convention-based route \"${className}.${methodName}\". ` +\n `Ensure the method name follows the naming convention (e.g., index, create, show).`\n )\n }\n return { httpMethod: derived.method, fullPath: derived.path, routeConfig: meta.config, statusCodeOverride: meta.config.statusCode }\n }\n\n return {\n httpMethod: meta.method,\n fullPath: this.joinPaths(basePath, meta.path),\n routeConfig: meta.config,\n statusCodeOverride: meta.config.statusCode,\n }\n }\n\n /**\n * Join a base path and a route path, normalizing slashes\n */\n private joinPaths(basePath: string, routePath: string): string {\n if (basePath.endsWith('/')) basePath = basePath.slice(0, -1)\n if (routePath === '/' || routePath === '') return basePath || '/'\n if (!routePath.startsWith('/')) routePath = '/' + routePath\n return basePath + routePath\n }\n\n\n /**\n * Auto-derive HTTP method and path from controller method name\n * Uses HTTP_METHODS constant for RESTful convention mapping\n */\n private deriveHttpMethodAndPath(methodName: string, basePath: string): { method: Exclude<HttpMethod, 'all'>; path: string } | null {\n if (!(methodName in HTTP_METHODS)) return null\n const mapping = HTTP_METHODS[methodName as keyof typeof HTTP_METHODS]\n\n return {\n method: mapping.method as Exclude<HttpMethod, 'all'>,\n path: basePath + mapping.path,\n }\n }\n\n /**\n * Merge controller-level and route-level metadata\n * Tags are merged (appended), security is merged (union)\n * Guards automatically add sessionCookie security if present\n */\n private mergeMetadata(\n controllerOpts: ControllerOptions | undefined,\n routeConfig: RouteConfig,\n ControllerClass: Constructor,\n methodName: string\n ): { tags: string[]; security: SecuritySchemeRecord[] } {\n const tags = [...(controllerOpts?.tags ?? []), ...(routeConfig.tags ?? [])]\n\n // Check if guards are present (indicates authentication is required)\n const prototype = ControllerClass.prototype as IController\n const hasMethodGuards = (getMethodGuards(prototype, methodName)?.guards.length ?? 0) > 0\n const hasControllerGuards = (getControllerGuards(ControllerClass)?.guards.length ?? 0) > 0\n const requiresAuth = hasMethodGuards || hasControllerGuards\n\n // Merge security: if route explicitly sets security (even empty array), use it\n // Otherwise inherit from controller\n let security: string[] = []\n if (routeConfig.security !== undefined) {\n // Route has explicit security (could be empty for public routes)\n security = [...(controllerOpts?.security ?? []), ...routeConfig.security]\n } else if (controllerOpts?.security) {\n // Inherit controller security\n security = controllerOpts.security\n }\n\n // Auto-add sessionCookie security if guards are present\n if (requiresAuth && !security.includes(SECURITY_SCHEMES.SESSION_COOKIE)) {\n security.push(SECURITY_SCHEMES.SESSION_COOKIE)\n }\n\n // Convert security array to OpenAPI security format\n const securityArray: SecuritySchemeRecord[] =\n security.length > 0\n ? (security.map<SecuritySchemeRecord>((scheme) => ({ [scheme]: [] }) as unknown as SecuritySchemeRecord))\n : ([] as SecuritySchemeRecord[])\n\n return { tags, security: securityArray }\n }\n\n /**\n * Build OpenAPI route configuration from metadata\n * Creates a route definition compatible with @hono/zod-openapi.\n *\n * Scoped middleware and guards are NOT attached to `route.middleware`\n * here — they're composed into a wrapped handler in `collectRoutes` so\n * they run after Hono's request validators. See `wrapHandlerWithChain`.\n */\n private buildOpenAPIRoute(\n method: Exclude<HttpMethod, 'all'>,\n path: string,\n routeConfig: RouteConfig,\n metadata: { tags: string[]; security: Record<string, string[]>[] },\n methodName?: string,\n statusCodeOverride?: number,\n hasLocaleParam = false,\n ): OpenAPIRouteConfig {\n try {\n const route: Partial<OpenAPIRouteConfig> & { hide?: boolean } = {\n method,\n path: toRoutingOpenAPIPath(path),\n request: {},\n responses: {},\n // Always hide from OpenAPI registry — clean paths are registered separately via registerPath()\n hide: true,\n }\n\n // Add request body if defined\n if (routeConfig.body) {\n const bodySchema = this.isRouteBodyObject(routeConfig.body) ? routeConfig.body.schema : routeConfig.body\n const bodyContentType = this.isRouteBodyObject(routeConfig.body) ? routeConfig.body.contentType ?? DEFAULT_CONTENT_TYPE : DEFAULT_CONTENT_TYPE\n\n route.request = {\n ...route.request,\n body: {\n content: {\n [bodyContentType]: {\n schema: bodySchema,\n },\n },\n },\n }\n }\n\n // Add query parameters if defined\n if (routeConfig.query) {\n route.request = {\n ...route.request,\n query: routeConfig.query,\n }\n }\n\n // Add URL parameters if defined\n if (routeConfig.params) {\n route.request = {\n ...route.request,\n params: routeConfig.params,\n }\n }\n\n // Auto-inject locale path parameter for locale-prefixed routes\n const localeConfig = this.localePathService.localePathConfig\n if (hasLocaleParam && localeConfig) {\n const localeParam = z.object({\n locale: z.enum(localeConfig.prefixedLocales as [string, ...string[]]).openapi({\n param: {\n name: 'locale',\n in: 'path',\n },\n }).optional(),\n })\n\n route.request = {\n ...route.request,\n params: route.request!.params\n ? (route.request!.params as z.ZodObject).extend(localeParam.shape)\n : localeParam,\n }\n }\n\n // Derive success status code from method name or use override\n const successStatus = statusCodeOverride\n ?? (methodName && METHOD_STATUS_CODES[methodName as keyof typeof METHOD_STATUS_CODES])\n ?? 200\n\n // Build responses object with auto-derived status\n const responses: NonNullable<OpenAPIRouteConfig['responses']> = {}\n\n // Add success response with derived status code\n const responseDef = routeConfig.response\n if (responseDef) {\n if (typeof responseDef === 'object' && 'schema' in responseDef) {\n const responseContentType = responseDef.contentType ?? DEFAULT_CONTENT_TYPE\n responses[successStatus] = {\n content: {\n [responseContentType]: { schema: responseDef.schema },\n },\n description: responseDef.description ?? `Response ${successStatus}`,\n }\n } else {\n responses[successStatus] = {\n content: {\n [DEFAULT_CONTENT_TYPE]: { schema: responseDef },\n },\n description: `Response ${successStatus}`,\n }\n }\n }\n\n // Auto-merge common error schemas (400, 401, 403, 404, 409, 500)\n // Controllers only need to define success response; error responses are added automatically\n for (const [statusStr, schema] of Object.entries(commonErrorSchemas)) {\n const status = parseInt(statusStr)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- defensive: avoid overwriting success response status\n responses[status] ??= schema\n }\n\n route.responses = responses\n\n // Add tags if provided\n if (metadata.tags.length > 0) {\n route.tags = metadata.tags\n }\n\n // Add security if provided\n if (metadata.security.length > 0) {\n route.security = metadata.security\n }\n\n // Add description and summary\n if (routeConfig.description) {\n route.description = routeConfig.description\n }\n if (routeConfig.summary) {\n route.summary = routeConfig.summary\n }\n\n return createRoute(route as OpenAPIRouteConfig)\n } catch (error) {\n throw new OpenAPIRouteRegistrationError(path, error instanceof Error ? error.message : String(error))\n }\n }\n\n /**\n * Check if a body definition is a RouteBodyObject (has schema key) vs bare ZodType\n */\n private isRouteBodyObject(body: RouteConfig['body']): body is RouteBodyObject {\n return typeof body === 'object' && 'schema' in body\n }\n\n /**\n * Resolve method parameter injections from the container\n *\n * @param prototype - Controller prototype\n * @param methodName - Method name to get injections for\n * @param container - Request-scoped container\n * @returns Array of resolved dependencies in parameter order\n */\n private resolveMethodInjections(\n prototype: object,\n methodName: string,\n container: Container\n ): unknown[] {\n const injections = getMethodInjections(prototype, methodName)\n if (!injections.length) return []\n\n return injections.map((inj): unknown => container.resolve(inj.token))\n }\n\n /**\n * Name a handler function so Hono's inspectRoutes() can identify it.\n * Format: `{type}:{Controller}.{method}` (e.g. `http:UsersController.create`)\n */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -- intentionally accepting any function to set its name\n private nameHandler(fn: Function, controller: string, method: string, type: 'http' | 'ws' = 'http'): void {\n Object.defineProperty(fn, 'name', { value: `${type}:${controller}.${method}` })\n }\n\n /**\n * Create controller handler that resolves controller from request-scoped container\n * This ensures each request gets a fresh controller with request-scoped context\n */\n private createControllerHandler(\n ControllerClass: new (...args: unknown[]) => IController,\n methodName: string,\n responseSchema: ZodType | null = null,\n ): (c: Context<RouterEnv>) => Promise<Response> {\n const handler = async (c: Context<RouterEnv>) => {\n const ctx = new RouterContext(c)\n const requestContainer = ctx.getContainer()\n const controller = requestContainer.resolve<IController>(ControllerClass)\n\n const method = controller[methodName as keyof IController]\n if (typeof method === 'function') {\n const injectedArgs = this.resolveMethodInjections(ControllerClass.prototype as object, methodName, requestContainer)\n const response = await (method as (...args: unknown[]) => Promise<Response>).apply(controller, [ctx, ...injectedArgs])\n\n if (responseSchema && c.env.ENVIRONMENT !== 'production') {\n return this.validateResponse(response, responseSchema)\n }\n\n return response\n }\n\n throw new ControllerMethodNotFoundError(methodName, ControllerClass.name)\n }\n\n this.nameHandler(handler, ControllerClass.name, methodName)\n return handler\n }\n\n /**\n * Extract the Zod schema from a RouteResponse definition.\n * Returns null for non-JSON content types or when no response is defined.\n */\n private extractResponseSchema(routeConfig: RouteConfig): ZodType | null {\n const responseDef = routeConfig.response\n if (!responseDef) return null\n\n if (this.isRouteResponseObject(responseDef)) {\n const contentType = responseDef.contentType ?? DEFAULT_CONTENT_TYPE\n if (!contentType.includes('application/json')) return null\n return responseDef.schema\n }\n\n return responseDef\n }\n\n /**\n * Check if a response definition is a RouteResponseObject (has schema key) vs bare ZodType\n */\n private isRouteResponseObject(response: RouteConfig['response']): response is RouteResponseObject {\n return typeof response === 'object' && 'schema' in response\n }\n\n /**\n * Validate a Response body against its declared Zod schema.\n *\n * Skips validation for:\n * - Non-JSON content types\n * - Empty bodies (204 No Content, 304 Not Modified)\n *\n * Clones the response to read the body without consuming the original stream.\n */\n private async validateResponse(response: Response, schema: ZodType): Promise<Response> {\n const contentType = response.headers.get('content-type')\n if (!contentType || !contentType.includes('application/json')) {\n return response\n }\n\n if (response.status === 204 || response.status === 304) {\n return response\n }\n\n const cloned = response.clone()\n\n let body: unknown\n try {\n body = await cloned.json()\n } catch {\n return response\n }\n\n const result = schema.safeParse(body)\n if (!result.success) {\n throw new ResponseValidationError(result.error)\n }\n\n return response\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { inject } from 'tsyringe'\nimport type { Container } from '../di/container'\nimport { runWithContainer } from '../di/container-storage'\nimport { Transient } from '../di/decorators'\nimport { CONTAINER_TOKEN, DI_TOKENS } from '../di/tokens'\nimport { createHttpExceptionContext } from '../errors/exception-context'\nimport type { ExceptionHandler } from '../errors/exception-handler'\nimport { OpenAPIHono } from '../i18n/validation'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport { OPENAPI_TOKENS, type OpenAPIService } from '../openapi'\nimport type { Constructor } from '../types'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport { HonoAppAlreadyConfiguredError, RouteNotFoundError, SchemaValidationError } from './errors'\nimport { createLoggerMiddleware, createMiddlewareChain } from './middleware'\nimport type { Middleware } from './middleware.interface'\nimport { RouterContext } from './router-context'\nimport { RouteRegistrationService } from './services/route-registration.service'\nimport type { RouterEnv } from './types'\n\nconst isMiddlewareClass = (arg: unknown): arg is Constructor<Middleware> =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n typeof arg === 'function' && arg.prototype && 'handle' in arg.prototype\n\n\n/**\n * HonoApp — extends OpenAPIHono with Stratal-specific setup\n *\n * - Request scope middleware (child container per request)\n * - Global middleware (CORS, logging, error handling)\n * - defaultHook for validation errors\n * - `use()` overload for Stratal middleware classes\n * - `configure()` for OpenAPI, routes, and 404\n */\n@Transient()\nexport class HonoApp extends OpenAPIHono<RouterEnv> {\n private configured = false\n private readonly _container: Container\n private readonly _logger: LoggerService\n\n /**\n * Reference to the original Hono `use` implementation.\n * Captured in constructor after super() sets it as an instance property.\n * Used by private methods to register middleware without going through the override.\n */\n private nativeUse!: typeof this.use\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(LOGGER_TOKENS.LoggerService) logger: LoggerService,\n ) {\n super({\n defaultHook: (result, c) => {\n if (!result.success) {\n throw new SchemaValidationError(result.error)\n }\n const override = c.get('validationSuccessResponse')\n if (override) return override\n },\n })\n\n this._container = container\n this._logger = logger\n\n // Capture Hono's original `use` (set by super() as an instance property)\n this.nativeUse = this.use\n\n // Override `use` to support Stratal middleware classes alongside Hono-native handlers\n this.use = ((...args: unknown[]) => {\n if (isMiddlewareClass(args[0])) {\n this.nativeUse('*', createMiddlewareChain(args as Constructor<Middleware>[]))\n return this\n }\n\n if (typeof args[0] === 'string' && args.length > 1 && isMiddlewareClass(args[1])) {\n this.nativeUse(args[0], createMiddlewareChain(args.slice(1) as Constructor<Middleware>[]))\n return this\n }\n\n return (this.nativeUse as (...a: unknown[]) => unknown)(...args)\n }) as typeof this.use\n\n // Internal setup — uses nativeUse to bypass the override\n this.setupRequestScope()\n this.applyGlobalMiddleware()\n }\n\n /**\n * Apply global middleware (logger + error handler).\n * Called by Application after locale middleware is applied by LocalePathService.\n */\n private applyGlobalMiddleware(): void {\n this.nativeUse('*', createLoggerMiddleware(this._logger) as MiddlewareHandler<RouterEnv>)\n this.onError((err, c) => this.handleException(c, err))\n }\n\n /**\n * Configure OpenAPI endpoints, controller routes, and 404 handler.\n * Called once by Application.initialize().\n */\n async configure(): Promise<void> {\n if (this.configured) throw new HonoAppAlreadyConfiguredError()\n\n // OpenAPI endpoints\n const openAPIService = this._container.resolve<OpenAPIService>(OPENAPI_TOKENS.OpenAPIService)\n openAPIService.setupEndpoints(this, this._container)\n\n // Controller routes + global middleware\n const routeRegistrationService = this._container.resolve<RouteRegistrationService>(RouteRegistrationService)\n await routeRegistrationService.configure()\n\n // 404 handler (must be last)\n this.notFound((c) => { throw new RouteNotFoundError(c.req.path, c.req.method) })\n\n this.configured = true\n }\n\n private setupRequestScope(): void {\n this.nativeUse('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const routerContext = new RouterContext(c)\n const requestContainer = this._container.createRequestScope(routerContext)\n c.set(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER, requestContainer)\n\n await runWithContainer(requestContainer, next)\n })\n }\n\n private handleException(c: Context<RouterEnv>, err: unknown) {\n // Fallback to global container if request scope setup failed before storing REQUEST_CONTAINER\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard: REQUEST_CONTAINER may be unset if request scope middleware throws\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER) ?? this._container\n const handler = requestContainer.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n const ctx = createHttpExceptionContext(c)\n return handler.handle(err, ctx)\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { languageDetector } from 'hono/language'\nimport { inject } from 'tsyringe'\nimport type { Container } from '../../di/container'\nimport { Transient } from '../../di/decorators'\nimport { CONTAINER_TOKEN } from '../../di/tokens'\nimport { buildDetectorOptions, type I18nModuleOptions } from '../../i18n/i18n.options'\nimport { I18N_TOKENS } from '../../i18n/i18n.tokens'\nimport { ROUTER_CONTEXT_KEYS } from '../constants'\nimport type { HonoApp } from '../hono-app'\nimport { ROUTER_TOKENS } from '../router.tokens'\nimport type { LocalePathConfig, RouterEnv } from '../types'\n\n/**\n * A resolved path with locale variant metadata.\n */\nexport interface ResolvedPath {\n /** The fully resolved path (may include /:locale prefix) */\n path: string\n /** Whether this path is a locale-prefixed variant */\n isLocaleVariant: boolean\n}\n\n/**\n * Resolves locale path variants for route paths.\n *\n * Computes `LocalePathConfig` from `I18nModuleOptions` and provides\n * path expansion for locale-prefixed route variants.\n *\n * Also applies language detection and default locale redirect middleware\n * to HonoApp when resolved from the container.\n *\n * Registered as a singleton in the container.\n */\n@Transient()\nexport class LocalePathService {\n private readonly _config: LocalePathConfig | null\n private readonly _pathDetectionEnabled: boolean\n private readonly _prefixDefaultLocale: false | true | 'redirect'\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(ROUTER_TOKENS.HonoApp) private readonly honoApp: HonoApp,\n ) {\n const i18nOptions = container.isRegistered(I18N_TOKENS.Options)\n ? container.resolve<I18nModuleOptions>(I18N_TOKENS.Options)\n : undefined\n\n const detection = i18nOptions?.detection\n const detectionEnabled = detection ? detection.enabled !== false : true\n const strategy = (detection && 'strategy' in detection && detection.strategy) ?? 'cookie'\n\n this._pathDetectionEnabled = detectionEnabled && strategy === 'path'\n this._prefixDefaultLocale = (detection && 'prefixDefaultLocale' in detection && detection.prefixDefaultLocale !== undefined)\n ? detection.prefixDefaultLocale\n : false\n\n if (this._pathDetectionEnabled) {\n const allLocales = i18nOptions?.locales ?? ['en']\n const defaultLocale = i18nOptions?.defaultLocale ?? 'en'\n\n this._config = this._prefixDefaultLocale === true\n ? { allLocales, prefixedLocales: allLocales, defaultLocale: null }\n : { allLocales, prefixedLocales: allLocales.filter(l => l !== defaultLocale), defaultLocale }\n } else {\n this._config = null\n }\n\n // Apply locale middleware to HonoApp\n if (detectionEnabled) {\n this.setupLanguageDetection(i18nOptions)\n }\n if (this._config?.defaultLocale && this._prefixDefaultLocale === 'redirect') {\n this.setupDefaultLocaleRedirect(this._config.defaultLocale)\n }\n }\n\n /** Whether path-based locale detection is enabled */\n get enabled(): boolean {\n return this._pathDetectionEnabled\n }\n\n /** The computed locale path config, or null if path detection is disabled */\n get localePathConfig(): LocalePathConfig | null {\n return this._config\n }\n\n /** The prefixDefaultLocale setting (false, true, or 'redirect') */\n get prefixDefaultLocale(): false | true | 'redirect' {\n return this._prefixDefaultLocale\n }\n\n /**\n * Expand a path into primary + locale-prefixed variants.\n *\n * @param path - The base path to expand\n * @returns Array of resolved paths with locale metadata\n */\n resolve(path: string): ResolvedPath[] {\n if (!this._config) {\n return [{ path, isLocaleVariant: false }]\n }\n\n const constraint = this.buildLocaleConstraint()\n const suffix = path === '/' ? '' : path\n\n // All locales prefixed (prefixDefaultLocale: true)\n if (this._config.defaultLocale === null) {\n return [{ path: `/:locale${constraint}${suffix}`, isLocaleVariant: true }]\n }\n\n // Default locale unprefixed, other locales prefixed\n const result: ResolvedPath[] = [{ path, isLocaleVariant: false }]\n\n // Only add /:locale route when there are non-default locales to match\n // (z.enum requires at least one value)\n if (this._config.prefixedLocales.length > 0) {\n result.push({ path: `/:locale${constraint}${suffix}`, isLocaleVariant: true })\n }\n\n return result\n }\n\n /**\n * Build a Hono regex constraint from prefixed locales.\n * e.g., `{en|de|fr}` — restricts `:locale` to only match known values.\n */\n private buildLocaleConstraint(): string {\n const locales = this._config!.defaultLocale === null\n ? this._config!.allLocales\n : this._config!.prefixedLocales\n return `{${locales.join('|')}}`\n }\n\n /**\n * Apply Hono's languageDetector middleware and bridge the detected language\n * to Stratal's LOCALE context variable.\n */\n private setupLanguageDetection(i18nOptions?: I18nModuleOptions): void {\n const detectorOptions = buildDetectorOptions(i18nOptions)\n\n // Apply Hono's languageDetector\n this.honoApp.use('*', languageDetector(detectorOptions) as MiddlewareHandler<RouterEnv>)\n\n // Bridge: sync Hono's 'language' variable to Stratal's LOCALE context key\n this.honoApp.use('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const language = c.get('language')\n if (language) {\n c.set(ROUTER_CONTEXT_KEYS.LOCALE, language)\n }\n await next()\n })\n }\n\n /**\n * Redirect requests that include the default locale prefix to the unprefixed path.\n * For example, `/en/users` → 301 redirect to `/users`.\n *\n * Only active when `prefixDefaultLocale` is `'redirect'`.\n */\n private setupDefaultLocaleRedirect(defaultLocale: string): void {\n const prefix = `/${defaultLocale}`\n this.honoApp.use('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const path = new URL(c.req.url).pathname\n if (path === prefix || path.startsWith(`${prefix}/`)) {\n const stripped = path.slice(prefix.length) || '/'\n return c.redirect(stripped, 301)\n }\n await next()\n })\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { DI_TOKENS } from '../../di/tokens'\nimport type { Application } from '../../application'\nimport { VERSION_NEUTRAL } from '../constants'\nimport type { VersioningOptions } from '../types'\n\n/**\n * Resolves version prefixes for route paths.\n *\n * Handles VERSION_NEUTRAL, multi-version arrays, default version fallback,\n * and configurable prefix (default: 'v').\n *\n * Registered as a singleton in the container.\n */\n@Transient()\nexport class VersioningService {\n private readonly options: VersioningOptions | null\n\n constructor(@inject(DI_TOKENS.Application) app: Application) {\n this.options = app.config.versioning ?? null\n }\n\n /** Whether versioning is enabled */\n get enabled(): boolean {\n return this.options !== null\n }\n\n /**\n * Resolve versioned paths for a base path.\n *\n * @param basePath - The base path (e.g., '/users')\n * @param version - Explicit version from controller/router config\n * @returns Array of versioned path strings (e.g., ['/v1/users', '/v2/users'])\n */\n resolve(basePath: string, version?: string | string[] | typeof VERSION_NEUTRAL): string[] {\n // Versioning disabled — return base path as-is\n if (!this.options) {\n return [basePath]\n }\n\n // VERSION_NEUTRAL — explicitly opt out of versioning\n if (version === VERSION_NEUTRAL) {\n return [basePath]\n }\n\n const prefix = this.options.prefix ?? 'v'\n\n // Explicit version(s) on the controller/router\n if (version !== undefined) {\n const versions = Array.isArray(version) ? version : [version]\n return versions.map(v => `/${prefix}${v}${basePath}`)\n }\n\n // No explicit version — apply defaultVersion if set\n if (this.options.defaultVersion !== undefined) {\n const defaults = Array.isArray(this.options.defaultVersion)\n ? this.options.defaultVersion\n : [this.options.defaultVersion]\n return defaults.map(v => `/${prefix}${v}${basePath}`)\n }\n\n // Versioning enabled but no version and no default — no prefix\n return [basePath]\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../di/decorators'\nimport { type VERSION_NEUTRAL } from './constants'\nimport { DuplicateRouteNameError } from './errors'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { LocalePathService } from './services/locale-path.service'\nimport type { VersioningService } from './services/versioning.service'\nimport type { HttpMethod } from './types'\nimport { sortRoutesBySpecificity } from './utils/path'\nimport { extractDomainParamNames, extractParamNames } from './utils/route-name'\n\n/**\n * A single registered route in the application.\n * Tracks both named and unnamed routes, HTTP and WebSocket.\n */\nexport interface RegisteredRoute {\n /** Route name for URL generation (undefined = unnamed, still tracked) */\n name?: string\n /** HTTP method or 'ws' for WebSocket gateways */\n method: HttpMethod | 'ws'\n /** Primary path in Hono-style :param format */\n path: string\n /** Locale-prefixed path variants (e.g., '/:locale/users/:id') */\n localePaths?: string[]\n /** Parameter names extracted from path */\n paramNames: string[]\n /** Domain pattern (e.g., '{tenant}.example.com') */\n domain?: string\n /** Parameter names extracted from domain */\n domainParamNames: string[]\n /** Controller class name */\n controller: string\n /** Controller method name */\n action: string\n /** Whether the route is hidden from OpenAPI docs */\n hidden: boolean\n /** Middleware class names applied to this route */\n middleware: string[]\n /** Whether this is a locale-prefixed variant */\n isLocaleVariant?: boolean\n}\n\n/**\n * Input for registering a route. The registry auto-extracts param names\n * and expands versioned/locale paths via injected services.\n */\nexport type RouteRegistrationInput = Omit<RegisteredRoute, 'paramNames' | 'domainParamNames' | 'path' | 'localePaths' | 'isLocaleVariant'> & {\n /** Base path before versioning/locale expansion */\n basePath: string\n /** Version from controller/router config (used by VersioningService). Accepts VERSION_NEUTRAL symbol. */\n version?: string | string[] | typeof VERSION_NEUTRAL\n /** Pre-computed param names (optional, auto-extracted if omitted) */\n paramNames?: string[]\n /** Pre-computed domain param names (optional, auto-extracted if omitted) */\n domainParamNames?: string[]\n}\n\n/**\n * Central registry for all application routes.\n * Single source of truth — used by `route:list`, `route:types`, and URL generation.\n *\n * Routes are automatically expanded via VersioningService and LocalePathService\n * during registration, and sorted by specificity when retrieved via `all()`.\n *\n * Registered as a singleton in the container.\n */\n@Transient()\nexport class RouteRegistry {\n private readonly routes: RegisteredRoute[] = []\n private readonly namedRoutes = new Map<string, RegisteredRoute>()\n private _sortedCache: RegisteredRoute[] | null = null\n\n constructor(\n @inject(ROUTER_TOKENS.VersioningService) private readonly versioningService: VersioningService,\n @inject(ROUTER_TOKENS.LocalePathService) private readonly localePathService: LocalePathService,\n ) { }\n\n /**\n * Register a route. Expands via VersioningService + LocalePathService.\n * Named routes must have unique names.\n *\n * @returns Array of expanded RegisteredRoute entries (primary + locale variants)\n * @throws DuplicateRouteNameError if a named route with the same name already exists\n */\n register(input: RouteRegistrationInput): RegisteredRoute[] {\n const domainParamNames = input.domainParamNames ?? (input.domain ? extractDomainParamNames(input.domain) : [])\n\n // Expand via VersioningService\n const versionedPaths = this.versioningService.resolve(input.basePath, input.version)\n\n const expandedRoutes: RegisteredRoute[] = []\n const localeEnabled = this.localePathService.enabled\n\n for (const versionedPath of versionedPaths) {\n // Expand via LocalePathService\n const resolvedPaths = this.localePathService.resolve(versionedPath)\n\n // Collect locale variant paths only when locale paths are enabled\n let localeVariantPaths: string[] | undefined\n if (localeEnabled) {\n const variants = resolvedPaths.filter(p => p.isLocaleVariant)\n localeVariantPaths = variants.length > 0 ? variants.map(p => p.path) : undefined\n }\n\n for (const resolved of resolvedPaths) {\n const route: RegisteredRoute = {\n name: resolved.isLocaleVariant ? undefined : input.name,\n method: input.method,\n path: resolved.path,\n localePaths: resolved.isLocaleVariant ? undefined : localeVariantPaths,\n paramNames: extractParamNames(resolved.path),\n domain: input.domain,\n domainParamNames,\n controller: input.controller,\n action: input.action,\n hidden: input.hidden,\n middleware: input.middleware,\n isLocaleVariant: resolved.isLocaleVariant || undefined,\n }\n\n // Register name only for primary routes (not locale variants)\n if (route.name) {\n if (this.namedRoutes.has(route.name)) {\n const existing = this.namedRoutes.get(route.name)!\n throw new DuplicateRouteNameError(\n route.name,\n `${existing.controller}.${existing.action}`,\n `${route.controller}.${route.action}`,\n )\n }\n this.namedRoutes.set(route.name, route)\n }\n\n this.routes.push(route)\n expandedRoutes.push(route)\n }\n }\n\n // Invalidate sort cache once per register() call, not per route\n this._sortedCache = null\n\n return expandedRoutes\n }\n\n /** Get a named route by name */\n get(name: string): RegisteredRoute | undefined {\n return this.namedRoutes.get(name)\n }\n\n /** Check if a named route exists */\n has(name: string): boolean {\n return this.namedRoutes.has(name)\n }\n\n /** Get all routes sorted by specificity (static > param > wildcard, primary before locale) */\n all(): RegisteredRoute[] {\n this._sortedCache ??= sortRoutesBySpecificity(this.routes);\n return this._sortedCache\n }\n\n /** Get only named routes */\n named(): RegisteredRoute[] {\n return [...this.namedRoutes.values()]\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../di/decorators'\nimport { MissingRouteParamError, RouteNameNotFoundError } from './errors'\nimport type { RouteName, RouteParams } from './route-map'\nimport type { RegisteredRoute, RouteRegistry } from './route-registry'\nimport type { RouterContext } from './router-context'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport { signUrl, verifySignedUrl, type SignedUrlOptions } from './signed-url'\n\n/**\n * Options for URL generation methods.\n */\nexport interface UriOptions {\n /** Generate absolute URL (scheme + host). Defaults to false. */\n absolute?: boolean\n}\n\n/**\n * Options for signed URL generation methods.\n */\nexport interface SignedUriOptions extends UriOptions, SignedUrlOptions { }\n\n/**\n * Build a URL from a registered route, filling path/domain params and appending extras as query string.\n *\n * Pure function — no request context needed. Used by both the `Uri` class and the standalone `route()` function.\n *\n * @param route - The registered route to build a URL for\n * @param name - Route name (used in error messages)\n * @param params - Path params, domain params, and extra query params\n * @returns Relative URL string (or absolute with domain prefix if route has a domain pattern)\n *\n * @throws MissingRouteParamError if a required path or domain param is missing\n */\nexport function buildRouteUrl(\n route: RegisteredRoute,\n name: string,\n params?: Record<string, string>,\n): string {\n const allParams = { ...params }\n const consumedKeys = new Set<string>()\n let url = route.path\n\n // When locale is provided and route has locale variants, prepend locale segment\n if (allParams.locale && route.localePaths?.length) {\n url = `/${allParams.locale}${url === '/' ? '' : url}`\n consumedKeys.add('locale')\n }\n\n // Fill path :param placeholders (handles optional regex constraints like :locale{en|de|fr})\n for (const paramName of route.paramNames) {\n const value = allParams[paramName]\n if (value === undefined) {\n throw new MissingRouteParamError(paramName, name, route.path)\n }\n url = url.replace(\n new RegExp(`:${paramName}(\\\\{[^}]*\\\\})?`),\n encodeURIComponent(value),\n )\n consumedKeys.add(paramName)\n }\n\n // Build domain if present\n let domain: string | undefined\n if (route.domain) {\n domain = route.domain\n for (const domainParam of route.domainParamNames) {\n const value = allParams[domainParam]\n if (value === undefined) {\n throw new MissingRouteParamError(domainParam, name, route.domain)\n }\n domain = domain.replace(`{${domainParam}}`, encodeURIComponent(value))\n consumedKeys.add(domainParam)\n }\n }\n\n // Remaining params (not consumed by path or domain) become query string\n const queryEntries = Object.entries(allParams).filter(([key]) => !consumedKeys.has(key))\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .filter(([, value]) => Boolean(value))\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&')\n url = `${url}${queryString.length ? `?${queryString}` : ''}`\n }\n\n // Prepend domain if present\n if (domain) {\n url = `https://${domain}${url}`\n }\n\n return url\n}\n\n/**\n * URL generation service for named routes, signed URLs, and request URL access.\n *\n * Registered as request-scoped in the container — has access to the current request\n * via RouterContext for features like `current()`, `full()`, and signed URLs.\n *\n * @example\n * ```typescript\n * // In a controller:\n * const uri = ctx.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n * uri.route('users.show', { id: '1' })\n * uri.current()\n * await uri.signedRoute('unsubscribe', { user: '1' }, { expiresIn: 3600 })\n *\n * // Set defaults (e.g., in middleware):\n * uri.defaults({ locale: 'en' })\n * uri.route('posts.index') // auto-fills :locale param\n * ```\n */\n@Transient()\nexport class Uri {\n private _defaults: Record<string, string> = {}\n\n constructor(\n @inject(ROUTER_TOKENS.RouteRegistry) private readonly registry: RouteRegistry,\n @inject(ROUTER_TOKENS.RouterContext) private readonly routerContext: RouterContext,\n ) { }\n\n /**\n * Set default URL parameters for this request.\n * Applied to all subsequent `route()` calls — explicit params override defaults.\n *\n * @param params - Default parameters (e.g., `{ locale: 'en' }`)\n */\n defaults(params: Record<string, string>): void {\n this._defaults = { ...this._defaults, ...params }\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params (`{tenant}`) are consumed from the same object.\n * Extra keys become query string parameters.\n * Default params (from `defaults()`) are merged — explicit params override.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options\n * @returns Generated URL string\n *\n * @throws RouteNameNotFoundError if route name not found\n * @throws MissingRouteParamError if required params missing\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n const registeredRoute = this.registry.get(name)\n if (!registeredRoute) {\n throw new RouteNameNotFoundError(name)\n }\n\n const mergedParams = { ...this._defaults, ...params } as Record<string, string>\n let url = buildRouteUrl(registeredRoute, name, mergedParams)\n\n if (options?.absolute && !url.startsWith('http')) {\n const origin = new URL(this.routerContext.c.req.url).origin\n url = `${origin}${url}`\n }\n\n return url\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n *\n * @throws Error if APP_SECRET environment variable is not set\n */\n async signedRoute<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n const url = this.route(name, params, options)\n const secret = this.getAppSecret()\n return signUrl(url, secret, options)\n }\n\n /**\n * Generate a temporary signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param expiresIn - Time-to-live in seconds\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options\n * @returns Signed URL string with signature and expires query params\n *\n * @throws Error if APP_SECRET environment variable is not set\n */\n async temporarySignedRoute<N extends RouteName>(name: N, expiresIn: number, params?: RouteParams<N>, options?: UriOptions): Promise<string> {\n return this.signedRoute(name, params, { ...options, expiresIn })\n }\n\n /**\n * Check if the current request has a valid signature.\n *\n * @returns true if the URL signature is valid and not expired\n */\n async hasValidSignature(): Promise<boolean> {\n const secret = (this.routerContext.c.env as unknown as Record<string, string>).APP_SECRET\n if (!secret) return false\n return verifySignedUrl(this.routerContext.c.req.url, secret)\n }\n\n /**\n * Get the current request URL pathname (without query string).\n */\n current(): string {\n const parsed = new URL(this.routerContext.c.req.url)\n return parsed.pathname\n }\n\n /**\n * Get the current request URL with query string (pathname + search).\n */\n full(): string {\n const parsed = new URL(this.routerContext.c.req.url)\n return `${parsed.pathname}${parsed.search}`\n }\n\n /**\n * Get the previous request URL from the Referer header.\n *\n * @param fallback - URL to return if no Referer header (default: '/')\n */\n previous(fallback = '/'): string {\n return this.routerContext.c.req.header('referer') ?? fallback\n }\n\n /**\n * Get the previous request URL pathname (no query string or host) from the Referer header.\n *\n * @param fallback - Path to return if no Referer header (default: '/')\n */\n previousPath(fallback = '/'): string {\n const referer = this.routerContext.c.req.header('referer')\n if (!referer) return fallback\n\n try {\n const parsed = new URL(referer)\n return parsed.pathname\n } catch {\n return referer\n }\n }\n\n /**\n * Build a URL to a raw path (not a named route) with optional query params.\n *\n * @param path - URL path (e.g., '/users')\n * @param queryParams - Query parameters to append\n * @param options - URL generation options\n */\n to(path: string, queryParams?: Record<string, string>, options?: UriOptions): string {\n let url = path\n\n if (queryParams) {\n const entries = Object.entries(queryParams)\n if (entries.length > 0) {\n const queryString = entries\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&')\n url = url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`\n }\n }\n\n if (options?.absolute && !url.startsWith('http')) {\n const origin = new URL(this.routerContext.c.req.url).origin\n url = `${origin}${url}`\n }\n\n return url\n }\n\n /**\n * Build a URL with query string parameters. Merges with existing query params in path.\n *\n * @param path - URL path, may already contain query params\n * @param queryParams - Query parameters to merge (new values override existing)\n */\n query(path: string, queryParams: Record<string, string>): string {\n const parsed = new URL(path, 'https://placeholder.local')\n for (const [key, value] of Object.entries(queryParams)) {\n parsed.searchParams.set(key, value)\n }\n return `${parsed.pathname}${parsed.search}`\n }\n\n private getAppSecret(): string {\n const secret = (this.routerContext.c.env as unknown as Record<string, string>).APP_SECRET\n if (!secret) {\n throw new Error('APP_SECRET environment variable is required for signed URLs')\n }\n return secret\n }\n}\n","import { getContainer } from '../di/container-storage'\nimport { RouteNameNotFoundError } from './errors'\nimport type { RouteName, RouteParams } from './route-map'\nimport type { RouteRegistry } from './route-registry'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport { buildRouteUrl } from './uri'\n\n/**\n * Generate a URL from a named route.\n *\n * Keys in `params` matching `:param` placeholders fill the path.\n * Domain params (`{tenant}`) are also consumed from `params`.\n * Extra keys become query string parameters.\n *\n * Resolves RouteRegistry from the application container via AsyncLocalStorage.\n * Available after `Application.initialize()` has been called.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @returns Generated URL string\n *\n * @example\n * ```typescript\n * // In a controller (preferred):\n * ctx.route('users.show', { id: '1' })\n *\n * // Outside controllers (standalone function):\n * import { route } from 'stratal/router'\n *\n * route('users.show', { id: '1' })\n * ```\n */\nexport function route<N extends RouteName>(\n name: N,\n params?: RouteParams<N>,\n): string {\n const container = getContainer()\n const registry = container.resolve<RouteRegistry>(ROUTER_TOKENS.RouteRegistry)\n const registeredRoute = registry.get(name)\n if (!registeredRoute) {\n throw new RouteNameNotFoundError(name)\n }\n return buildRouteUrl(registeredRoute, name, params)\n}\n","import { InvalidSignatureError, MissingEnvironmentVariableError } from '../errors'\nimport type { Middleware, Next } from '../middleware.interface'\nimport type { RouterContext } from '../router-context'\nimport { verifySignedUrl } from '../signed-url'\n\n/**\n * Middleware that verifies signed URLs.\n *\n * Checks the `signature` (and optionally `expires`) query params against the\n * request URL using HMAC-SHA256 via `crypto.subtle.verify()`.\n *\n * Requires `APP_SECRET` in the Cloudflare Workers environment bindings.\n *\n * @throws InvalidSignatureError (403) if signature is missing, invalid, or expired\n *\n * @example\n * ```typescript\n * @Module({ controllers: [UnsubscribeController], providers: [VerifySignatureMiddleware] })\n * export class EmailModule implements RouteConfigurable {\n * configureRoutes(router: Router): void {\n * router.middleware(VerifySignatureMiddleware)\n * }\n * }\n * ```\n */\nexport class VerifySignatureMiddleware implements Middleware {\n async handle(ctx: RouterContext, next: Next): Promise<void> {\n const url = ctx.c.req.url\n const env = ctx.c.env\n const secret = (env as unknown as Record<string, string>).APP_SECRET\n\n if (!secret) {\n throw new MissingEnvironmentVariableError('APP_SECRET')\n }\n\n const isValid = await verifySignedUrl(url, secret)\n if (!isValid) {\n throw new InvalidSignatureError()\n }\n\n await next()\n }\n}\n","/**\n * I18n Service\n *\n * Request-scoped service for translations.\n * Injects RouterContext to access request-specific locale.\n * Uses pre-built CoreContext from MessageLoaderService (singleton) for zero-cost lookups.\n */\n\nimport { translate } from '@intlify/core-base'\nimport { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { ROUTER_TOKENS, type RouterContext } from '../../router'\nimport { I18N_TOKENS } from '../i18n.tokens'\nimport type { II18nService, MessageKeys, MessageParams } from '../i18n.types'\nimport type { MessageLoaderService } from './message-loader.service'\n\n/**\n * I18n Service\n *\n * Provides internationalization (i18n) support for the application.\n * Injects RouterContext to access request-specific locale.\n *\n * @example Usage in services\n * ```typescript\n * @Transient(MY_TOKENS.UserService)\n * export class UserService {\n * constructor(\n * @inject(I18N_TOKENS.I18nService) private readonly i18n: II18nService\n * ) {}\n *\n * getWelcomeMessage(): string {\n * return this.i18n.t('common.welcome')\n * }\n * }\n * ```\n */\n@Transient(I18N_TOKENS.I18nService)\nexport class I18nService implements II18nService {\n constructor(\n @inject(I18N_TOKENS.MessageLoader) private readonly loader: MessageLoaderService,\n @inject(ROUTER_TOKENS.RouterContext, { isOptional: true }) private readonly routerContext?: RouterContext\n ) {\n }\n\n /**\n * Translate a message key\n *\n * @param key - Message key (e.g., 'common.actions.save')\n * @param params - Optional parameters for interpolation\n * @returns Translated string\n */\n t(key: MessageKeys, params?: MessageParams): string {\n const context = this.loader.getCoreContext(this.getLocale())\n\n const result = params !== undefined\n ? translate(context, key, params)\n : translate(context, key)\n\n return typeof result === 'string' ? result : key\n }\n\n /**\n * Get current locale\n *\n * @returns Current locale code from RouterContext or default locale\n */\n getLocale(): string {\n return this.routerContext?.getLocale() ?? 'en'\n }\n}\n","/**\n * I18n Module\n *\n * Core infrastructure module for internationalization.\n * Provides message translation and locale handling.\n *\n * - `forRoot()` configures locale settings (call once in root module)\n * - `registerMessages()` adds translations (call from any module, as many times as needed)\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [\n * I18nModule.forRoot({ defaultLocale: 'en', locales: ['en', 'fr'] }),\n * I18nModule.registerMessages(appMessages),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * @example Package contributing messages\n * ```typescript\n * @Module({\n * imports: [\n * I18nModule.registerMessages(tenancyMessages),\n * ],\n * })\n * export class TenancyModule {}\n * ```\n */\n\nimport { Scope } from '../di'\nimport type { RouteConfigurable } from '../router/router'\nimport type { Router } from '../router/router'\nimport { Module } from '../module'\nimport type { DynamicModule } from '../module/types'\nimport type { I18nModuleOptions } from './i18n.options'\nimport { I18N_TOKENS } from './i18n.tokens'\nimport { I18nContextMiddleware } from './middleware/i18n-context.middleware'\nimport { I18nService } from './services/i18n.service'\nimport { MessageLoaderService } from './services/message-loader.service'\nimport { MessageRegistry } from './services/message-registry'\nimport { setupI18nCompiler } from './utils/setup'\nimport { backendErrorMap, z } from './validation'\n\n// Setup i18n JIT compiler once at module load time\nsetupI18nCompiler()\n\n// Set global Zod error map for i18n support\nz.config({ customError: backendErrorMap })\n\n@Module({\n providers: [\n // Singleton: Message registry (accumulates all registerMessages contributions)\n { provide: I18N_TOKENS.MessageRegistry, useClass: MessageRegistry, scope: Scope.Singleton },\n // Singleton: Message loader (loaded once at startup)\n { provide: I18N_TOKENS.MessageLoader, useClass: MessageLoaderService, scope: Scope.Singleton },\n // Request-scoped: I18n service (per request)\n { provide: I18N_TOKENS.I18nService, useClass: I18nService },\n ],\n})\nexport class I18nModule implements RouteConfigurable {\n /**\n * Configure I18n locale settings\n *\n * Call once in the root module. Does not accept messages —\n * use `registerMessages()` to add translations.\n *\n * @param options - Locale configuration (defaultLocale, fallbackLocale, locales)\n */\n static forRoot(options: I18nModuleOptions = {}): DynamicModule {\n return {\n module: I18nModule,\n providers: [\n { provide: I18N_TOKENS.Options, useValue: options },\n ],\n }\n }\n\n /**\n * Register i18n messages\n *\n * Can be called from any module, as many times as needed.\n * Messages are deep-merged in registration order — later calls override earlier ones at leaf level.\n *\n * @param messages - Messages keyed by locale code\n *\n * @example App-level messages\n * ```typescript\n * I18nModule.registerMessages({\n * en: { common: { hello: 'Hello' }, errors: { notFound: 'Not found' } },\n * fr: { common: { hello: 'Bonjour' }, errors: { notFound: 'Introuvable' } },\n * })\n * ```\n *\n * @example Package-level messages\n * ```typescript\n * I18nModule.registerMessages({\n * en: { tenancy: { tenantNotFound: 'Tenant not found' } },\n * })\n * ```\n */\n static registerMessages(messages: Record<string, Record<string, unknown>>): DynamicModule {\n MessageRegistry.addMessages(messages)\n return {\n module: I18nModule,\n providers: [],\n }\n }\n\n configureRoutes(router: Router): void {\n router.use(I18nContextMiddleware)\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { t as index_d_exports$1 } from "./index-
|
|
1
|
+
import { t as index_d_exports$1 } from "./index-DFhEeFfC.mjs";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
3
|
import { OpenAPIHono, z as z$1 } from "@hono/zod-openapi";
|
|
3
|
-
import * as zod from "zod";
|
|
4
|
+
import * as _$zod from "zod";
|
|
4
5
|
import { ZodError } from "zod";
|
|
5
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { OpenAPIObject, PathItemObject } from "openapi3-ts/oas30";
|
|
7
|
-
import * as zod_v4_core0 from "zod/v4/core";
|
|
7
|
+
import * as _$zod_v4_core0 from "zod/v4/core";
|
|
8
8
|
import { $ZodIssueCustom } from "zod/v4/core";
|
|
9
9
|
|
|
10
10
|
//#region src/i18n/i18n.types.d.ts
|
|
@@ -26,24 +26,38 @@ type DeepKeys<T, Prefix extends string = ''> = T extends object ? { [K in keyof
|
|
|
26
26
|
*/
|
|
27
27
|
type SystemMessageKeys = DeepKeys<typeof index_d_exports$1>;
|
|
28
28
|
/**
|
|
29
|
-
* Augmentable
|
|
29
|
+
* Augmentable registry for app-specific message namespaces.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
31
|
+
* Each module owns ONE top-level key here. Two modules CANNOT augment the same
|
|
32
|
+
* key with different shapes — TypeScript requires same-named interface properties
|
|
33
|
+
* across declarations to be structurally identical. By giving every module its
|
|
34
|
+
* own distinct key, interface merging is safe.
|
|
32
35
|
*
|
|
33
|
-
* @example
|
|
36
|
+
* @example Module declares its own namespace
|
|
34
37
|
* ```typescript
|
|
35
|
-
* //
|
|
36
|
-
*
|
|
38
|
+
* // packages/framework/src/auth/i18n/en.ts
|
|
39
|
+
* export const authMessages = {
|
|
40
|
+
* en: { auth: { errors: { invalidCredentials: '...' }, org: { ... } } },
|
|
41
|
+
* } as const
|
|
37
42
|
*
|
|
38
|
-
* declare module 'stratal' {
|
|
39
|
-
* interface
|
|
43
|
+
* declare module 'stratal/i18n' {
|
|
44
|
+
* interface AppMessageNamespaces {
|
|
45
|
+
* auth: typeof authMessages['en']['auth']
|
|
46
|
+
* }
|
|
40
47
|
* }
|
|
41
48
|
* ```
|
|
49
|
+
*
|
|
50
|
+
* Access with flat dot-notation: `i18n.t('auth.errors.invalidCredentials')`.
|
|
51
|
+
*/
|
|
52
|
+
interface AppMessageNamespaces {}
|
|
53
|
+
/**
|
|
54
|
+
* Composed app messages tree, derived from AppMessageNamespaces.
|
|
55
|
+
* Each module contributes one property; the union forms the full tree.
|
|
42
56
|
*/
|
|
43
|
-
|
|
57
|
+
type AppMessages = { [K in keyof AppMessageNamespaces]: AppMessageNamespaces[K] };
|
|
44
58
|
/**
|
|
45
59
|
* Auto-derive app keys from AppMessages
|
|
46
|
-
* When
|
|
60
|
+
* When AppMessageNamespaces is augmented, this type automatically includes all app message keys
|
|
47
61
|
*/
|
|
48
62
|
type AppMessageKeys = DeepKeys<AppMessages>;
|
|
49
63
|
/**
|
|
@@ -51,6 +65,35 @@ type AppMessageKeys = DeepKeys<AppMessages>;
|
|
|
51
65
|
* Combines system message keys with app-specific message keys
|
|
52
66
|
*/
|
|
53
67
|
type MessageKeys = SystemMessageKeys | AppMessageKeys;
|
|
68
|
+
/**
|
|
69
|
+
* Recursively extract all dot-notation prefixes from a string union
|
|
70
|
+
*
|
|
71
|
+
* Given `'common.actions.save'`, produces `'common' | 'common.actions' | 'common.actions.save'`.
|
|
72
|
+
* Used to type-check namespace filters so only valid prefixes are accepted at compile time.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* type Keys = 'auth.login.title' | 'auth.login.subtitle' | 'nav.home'
|
|
77
|
+
* type Result = Prefixes<Keys>
|
|
78
|
+
* // 'auth' | 'auth.login' | 'auth.login.title' | 'auth.login.subtitle' | 'nav' | 'nav.home'
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
type Prefixes<T extends string> = T extends `${infer Head}.${infer Tail}` ? Head | `${Head}.${Prefixes<Tail>}` : T;
|
|
82
|
+
/**
|
|
83
|
+
* Valid dot-notation prefixes for message keys
|
|
84
|
+
*
|
|
85
|
+
* Used to filter which message namespaces are shared with the frontend.
|
|
86
|
+
* Accepts both full keys (`'common.hello'`) and namespace prefixes (`'common'`).
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // In InertiaModule config — only 'common' and 'nav' namespaces are sent to the frontend
|
|
91
|
+
* InertiaModule.forRoot({
|
|
92
|
+
* i18n: { only: ['common', 'nav'] },
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
type MessageKeyPrefix = Prefixes<MessageKeys>;
|
|
54
97
|
/**
|
|
55
98
|
* Type for translation parameters
|
|
56
99
|
* Used for string interpolation in messages
|
|
@@ -153,7 +196,7 @@ type ZodCustomIssue = $ZodIssueCustom & {
|
|
|
153
196
|
* Backend error map that accesses I18nService from AsyncLocalStorage
|
|
154
197
|
* Must be initialized in router middleware after locale detection
|
|
155
198
|
*/
|
|
156
|
-
declare const backendErrorMap: zod.ZodErrorMap<zod_v4_core0.$ZodIssue>;
|
|
199
|
+
declare const backendErrorMap: _$zod.ZodErrorMap<_$zod_v4_core0.$ZodIssue>;
|
|
157
200
|
/**
|
|
158
201
|
* Runs a function within an error map context
|
|
159
202
|
* Used by router middleware to provide I18nService to validation
|
|
@@ -181,5 +224,5 @@ declare namespace index_d_exports {
|
|
|
181
224
|
import * as import_zod from "zod";
|
|
182
225
|
import * as import__hono_zod_openapi from "@hono/zod-openapi";
|
|
183
226
|
//#endregion
|
|
184
|
-
export {
|
|
185
|
-
//# sourceMappingURL=index-
|
|
227
|
+
export { SystemMessageKeys as C, Prefixes as S, DeepKeys as _, index_d_exports as a, MessageKeys as b, runWithErrorMapContext as c, LocaleProvider as d, ZodCustomIssue as f, AppMessages as g, AppMessageNamespaces as h, ZodError as i, ErrorMapContext as l, AppMessageKeys as m, OpenAPIObject as n, z$1 as o, withI18n as p, PathItemObject as r, backendErrorMap as s, OpenAPIHono as t, I18nErrorMetadata as u, II18nService as v, MessageParams as x, MessageKeyPrefix as y };
|
|
228
|
+
//# sourceMappingURL=index-B437eK7p.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-B437eK7p.d.mts","names":[],"sources":["../src/i18n/i18n.types.ts","../src/i18n/validation/with-i18n.ts","../src/i18n/validation/validation.types.ts","../src/i18n/validation/validation.context.ts","../src/i18n/validation/index.ts"],"mappings":";;;;;;;;;;;;;;AAoBA;;;;;;;KAAY,QAAA,kCAA0C,CAAA,gCAEtC,CAAA,YAAa,CAAA,CAAE,CAAA,mBACzB,QAAA,CAAS,CAAA,CAAE,CAAA,MAAO,MAAA,GAAS,CAAA,UACxB,MAAA,GAAS,CAAA,WACR,CAAA;;;;;KAOE,iBAAA,GAAoB,QAAA,QAAgB,iBAAA;;;;;;;;;;;;;;;;;;;;AAAhD;;;;;UA0BiB,oBAAA;;;;AAMjB;KAAY,WAAA,iBAA4B,oBAAA,GAAuB,oBAAA,CAAqB,CAAA;;;;;KAMxE,cAAA,GAAiB,QAAA,CAAS,WAAA;;;;;KAO1B,WAAA,GAAc,iBAAA,GAAoB,cAAA;AAP9C;;;;;AAOA;;;;;AAeA;;;AAtBA,KAsBY,QAAA,qBAA6B,CAAA,yCACrC,IAAA,MAAU,IAAA,IAAQ,QAAA,CAAS,IAAA,MAC3B,CAAA;;;;;;;;;;;;;;;KAgBQ,gBAAA,GAAmB,QAAA,CAAS,WAAA;;;;AAAxC;KAMY,aAAA,GAAgB,MAAA;;;;UAKX,YAAA;EALQ;;;;AAKzB;;;EAQE,CAAA,CAAE,GAAA,EAAK,WAAA,EAAa,MAAA,GAAS,aAAA;EAA7B;;;;;EAOA,SAAA;AAAA;;;;;;;;;;;;;AApHF;;;;;;;;;;;;;;iBCOgB,QAAA,CACd,GAAA,EAAK,WAAA,EACL,MAAA,GAAS,MAAA;EACN,KAAA;AAAA;;;;;;UCxBY,eAAA;;;;EAIf,CAAA,GAAI,GAAA,EAAK,WAAA,EAAa,MAAA,GAAS,MAAA;;AFUjC;;EELE,MAAA;AAAA;;;;;KAOU,cAAA,SAAuB,eAAA;;;;UAKlB,iBAAA;EFHC;;;EEOhB,GAAA,EAAK,WAAA;EFXc;;;EEgBnB,MAAA,GAAS,MAAA;AAAA;;;;;KAOC,cAAA,GAAiB,eAAA;EAC3B,MAAA;IACE,IAAA,GAAO,iBAAA;IAAA,CACN,GAAA;EAAA;AAAA;;;;;;;cCzBQ,eAAA,EAAe,KAAA,CAAA,WAAA,CAAyC,cAAA,CAAzC,SAAA;;;;;;;;;;;;;;;;;;;;;iBAsBZ,sBAAA,GAAA,CACd,OAAA,EAAS,eAAA,EACT,EAAA,QAAU,CAAA,GACT,CAAA;AAAA"}
|
|
@@ -260,4 +260,4 @@ declare class ConsoleTransport extends BaseTransport {
|
|
|
260
260
|
}
|
|
261
261
|
//#endregion
|
|
262
262
|
export { LogEntry as a, LOG_LEVEL_PRIORITY as c, LoggerService as i, LogLevel as l, PrettyFormatter as n, InternalLogContext as o, JsonFormatter as r, LogContext as s, ConsoleTransport as t, LOGGER_TOKENS as u };
|
|
263
|
-
//# sourceMappingURL=index-
|
|
263
|
+
//# sourceMappingURL=index-CWRS7Ri3.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-CWRS7Ri3.d.mts","names":[],"sources":["../src/logger/logger.tokens.ts","../src/logger/contracts/log-level.ts","../src/logger/contracts/log-context.ts","../src/logger/contracts/log-entry.ts","../src/logger/formatters/formatter.interface.ts","../src/logger/transports/transport.interface.ts","../src/logger/services/logger.service.ts","../src/logger/formatters/json-formatter.ts","../src/logger/formatters/pretty-formatter.ts","../src/logger/transports/base-transport.ts","../src/logger/transports/console-transport.ts"],"mappings":";;AAMA;;;;;cAAa,aAAA;;;;;;;;;ECFD;;;EAAA;EACV;;;EAAA;EAGK;;AAOP;EAPO;;;;;ADFP;;;aCFY,QAAA;EACV,KAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;AAAA;;;;;cAOW,kBAAA,EAAoB,MAAA,CAAO,QAAA;;;;ADTxC;;;KEFY,UAAA,GAAa,MAAA;;;;;UAMR,kBAAA,SAA2B,UAAA;EAC1C,MAAA;EACA,SAAA;AAAA;;;;;;;UCLe,QAAA;EACf,KAAA,EAAO,QAAA;EACP,OAAA;EACA,OAAA,EAAS,kBAAA;EACT,KAAA;IACE,OAAA;IACA,KAAA;IACA,IAAA;EAAA;AAAA;;;AHRJ;;;;AAAA,UIAiB,aAAA;;;;;;EAMf,MAAA,CAAO,KAAA,EAAO,QAAA;AAAA;;;AJNhB;;;;AAAA,UKAiB,aAAA;;;;WAIN,IAAA;;;;;;AJNX;;;EIgBE,KAAA,CAAM,KAAA,EAAO,QAAA,EAAU,SAAA,WAAoB,OAAA;AAAA;;;;;;;;;;;;;;AJhB7C;;;;;;;;;;AAWA;;;;;;;;cKwBa,aAAA;EAAA,iBAGQ,QAAA;EAAA,iBAGA,gBAAA;EAAA,iBAGA,SAAA;EAAA,iBAGA,UAAA;cATA,QAAA,EAAU,QAAA,EAGV,gBAAA,EAAkB,UAAA,CAAW,gBAAA,EAG7B,SAAA,EAAW,aAAA,EAGX,UAAA,EAAY,aAAA;EJzCG;;;EI+ClC,KAAA,CAAM,OAAA,UAAiB,OAAA,GAAU,UAAA;EJ9CjC;;;EIqDA,IAAA,CAAK,OAAA,UAAiB,OAAA,GAAU,UAAA;;;;EAOhC,IAAA,CAAK,OAAA,UAAiB,OAAA,GAAU,UAAA;EHhET;;;;EGwEvB,KAAA,CAAM,OAAA,UAAiB,cAAA,GAAiB,UAAA,GAAa,KAAA;EHtErD;;;;;EAAA,QGwFQ,GAAA;EHnFN;;;;EAAA,QGgIM,aAAA;;AFxIV;;UEkJU,cAAA;AAAA;;;;;;;;;;;;;;;;ALpJV;;cMca,aAAA,YAAyB,aAAA;EACpC,MAAA,CAAO,KAAA,EAAO,QAAA;AAAA;;;;;;;;;;;;;cCLH,eAAA,YAA2B,aAAA;EAAA,iBACrB,MAAA;EAAA,iBAOA,KAAA;EAEjB,MAAA,CAAO,KAAA,EAAO,QAAA;AAAA;;;;;;;;;uBCfM,aAAA,YAAyB,aAAA;EAAA,kBAC3B,IAAA;;;;WAKT,KAAA,CAAM,KAAA,EAAO,QAAA,EAAU,SAAA,WAAoB,OAAA;;ARXtD;;;;;;YQoBY,WAAA,CAAY,KAAA,WAAgB,KAAA,EAAO,QAAA;AAAA;;;;;;;;;;;cCTlC,gBAAA,SAAyB,aAAA;EAAA,SAC3B,IAAA;EAET,KAAA,CAAM,KAAA,EAAO,QAAA,EAAU,SAAA,WAAoB,OAAA;;;ATd7C;US4BU,gBAAA;AAAA"}
|