stratal 0.0.22 → 0.0.23
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 +1 -1
- package/dist/bin/cloudflare-workers-loader.mjs +80 -7
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs +41 -54
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +5 -3
- package/dist/cache/index.d.mts.map +1 -1
- package/dist/cache/index.mjs +123 -39
- package/dist/cache/index.mjs.map +1 -1
- package/dist/{cache.service-e34gV6tz.d.mts → cache.service-uElmBtdS.d.mts} +24 -34
- package/dist/cache.service-uElmBtdS.d.mts.map +1 -0
- package/dist/{command-BU4ApTo5.mjs → command-BvmUAPPQ.mjs} +15 -3
- package/dist/command-BvmUAPPQ.mjs.map +1 -0
- package/dist/{command-wXfvHbBZ.d.mts → command-CPhFHjG3.d.mts} +2 -2
- package/dist/command-CPhFHjG3.d.mts.map +1 -0
- package/dist/command-not-found.error-ONAZ2Bpk.mjs +14 -0
- package/dist/command-not-found.error-ONAZ2Bpk.mjs.map +1 -0
- package/dist/config/index.d.mts +3 -3
- package/dist/config/index.d.mts.map +1 -1
- package/dist/config/index.mjs +7 -6
- package/dist/config/index.mjs.map +1 -1
- package/dist/{consumer-registry-DHQtypr1.d.mts → consumer-registry-D3iMTSdy.d.mts} +54 -22
- package/dist/consumer-registry-D3iMTSdy.d.mts.map +1 -0
- package/dist/{container-storage-GpNNz79X.mjs → container-storage-BmOJ4_Na.mjs} +1 -1
- package/dist/{container-storage-GpNNz79X.mjs.map → container-storage-BmOJ4_Na.mjs.map} +1 -1
- package/dist/{controller.decorator-DIUazNU7.mjs → controller.decorator-C5UVeJS3.mjs} +4 -4
- package/dist/{controller.decorator-DIUazNU7.mjs.map → controller.decorator-C5UVeJS3.mjs.map} +1 -1
- package/dist/cron/index.d.mts +79 -4
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +2 -2
- package/dist/cron-job-NesZRk8F.d.mts +58 -0
- package/dist/cron-job-NesZRk8F.d.mts.map +1 -0
- package/dist/{cron-manager-9bpN9bu4.mjs → cron.module-Bgzq5hiT.mjs} +17 -7
- package/dist/cron.module-Bgzq5hiT.mjs.map +1 -0
- package/dist/{decorate-HgTKAYK8.mjs → decorate-CuAoSZvs.mjs} +2 -2
- package/dist/{deep-merge-C8NgcXw4.mjs → deep-merge-ByiAOZ3r.mjs} +1 -1
- package/dist/{deep-merge-C8NgcXw4.mjs.map → deep-merge-ByiAOZ3r.mjs.map} +1 -1
- package/dist/di/index.d.mts +2 -2
- package/dist/di/index.mjs +3 -3
- package/dist/{di-BO1QIb5H.mjs → di-DseMn-z9.mjs} +244 -135
- package/dist/di-DseMn-z9.mjs.map +1 -0
- package/dist/email/index.d.mts +33 -40
- package/dist/email/index.d.mts.map +1 -1
- package/dist/email/index.mjs +456 -41
- package/dist/email/index.mjs.map +1 -1
- package/dist/{en-BPP6h6y5.mjs → en-CDZBMcc1.mjs} +2 -2
- package/dist/{en-BPP6h6y5.mjs.map → en-CDZBMcc1.mjs.map} +1 -1
- package/dist/{env-DKSbuBi5.d.mts → env-ug22bJj7.d.mts} +1 -1
- package/dist/env-ug22bJj7.d.mts.map +1 -0
- package/dist/errors/index.d.mts +1 -1
- package/dist/errors/index.mjs +3 -3
- package/dist/{errors-BBZTnjdq.mjs → errors-mXYxG0XB.mjs} +5 -5
- package/dist/{errors-BBZTnjdq.mjs.map → errors-mXYxG0XB.mjs.map} +1 -1
- package/dist/events/index.d.mts +14 -3
- package/dist/events/index.d.mts.map +1 -1
- package/dist/events/index.mjs +2 -2
- package/dist/{events-D1KdDaiP.mjs → events-BXJGZjpG.mjs} +16 -6
- package/dist/events-BXJGZjpG.mjs.map +1 -0
- package/dist/{exception-context-B4kM-M53.mjs → exception-context-kEoMFwze.mjs} +3 -3
- package/dist/{exception-context-B4kM-M53.mjs.map → exception-context-kEoMFwze.mjs.map} +1 -1
- package/dist/{gateway-context-CFe6a9gz.mjs → gateway-context-TMu_AlJt.mjs} +25 -6
- package/dist/{gateway-context-CFe6a9gz.mjs.map → gateway-context-TMu_AlJt.mjs.map} +1 -1
- package/dist/guards/index.d.mts +3 -3
- package/dist/guards/index.d.mts.map +1 -1
- package/dist/guards/index.mjs +1 -1
- package/dist/{guards-Ced-uNIF.mjs → guards-DALPXy3_.mjs} +2 -2
- package/dist/{guards-Ced-uNIF.mjs.map → guards-DALPXy3_.mjs.map} +1 -1
- package/dist/hono-app-CvV3hOfT.mjs +161 -0
- package/dist/hono-app-CvV3hOfT.mjs.map +1 -0
- package/dist/{http-method.decorator-CdjKFJZZ.mjs → http-method.decorator-ByWZb9DO.mjs} +4 -4
- package/dist/{http-method.decorator-CdjKFJZZ.mjs.map → http-method.decorator-ByWZb9DO.mjs.map} +1 -1
- package/dist/i18n/index.d.mts +4 -4
- package/dist/i18n/index.d.mts.map +1 -1
- package/dist/i18n/index.mjs +5 -5
- package/dist/i18n/index.mjs.map +1 -1
- package/dist/i18n/messages/en/index.d.mts +1 -1
- package/dist/i18n/messages/en/index.mjs +1 -1
- package/dist/i18n/utils/index.mjs +1 -1
- package/dist/i18n/validation/index.d.mts +3 -3
- package/dist/i18n/validation/index.mjs +3 -3
- package/dist/{i18n.module-BlXrtAlV.mjs → i18n.module-DRQAZoSZ.mjs} +14 -11
- package/dist/{i18n.module-BlXrtAlV.mjs.map → i18n.module-DRQAZoSZ.mjs.map} +1 -1
- package/dist/{i18n.tokens-hwRpmjRq.mjs → i18n.tokens-CZ_v8oyS.mjs} +1 -1
- package/dist/{i18n.tokens-hwRpmjRq.mjs.map → i18n.tokens-CZ_v8oyS.mjs.map} +1 -1
- package/dist/{index-B4UBK-2T.d.mts → index-0ItCjaqw.d.mts} +1 -1
- package/dist/index-0ItCjaqw.d.mts.map +1 -0
- package/dist/{index-CW1YHSft.d.mts → index-B5JBRcWD.d.mts} +249 -103
- package/dist/index-B5JBRcWD.d.mts.map +1 -0
- package/dist/{index-BtlE9RuO.d.mts → index-BUt92sAE.d.mts} +1 -1
- package/dist/index-BUt92sAE.d.mts.map +1 -0
- package/dist/{index-DEncMcC6.d.mts → index-B_JoEl3V.d.mts} +221 -16
- package/dist/index-B_JoEl3V.d.mts.map +1 -0
- package/dist/{index-Dj5IMwtr.d.mts → index-DtBNIFuP.d.mts} +4 -6
- package/dist/index-DtBNIFuP.d.mts.map +1 -0
- package/dist/{index-KMgSCSM7.d.mts → index-HgOLNruQ.d.mts} +1 -1
- package/dist/{index-KMgSCSM7.d.mts.map → index-HgOLNruQ.d.mts.map} +1 -1
- package/dist/index.d.mts +6 -5
- package/dist/index.mjs +3 -2
- package/dist/{is-command-CX5rAfZW.mjs → is-command-CEPO9n8c.mjs} +2 -2
- package/dist/{is-command-CX5rAfZW.mjs.map → is-command-CEPO9n8c.mjs.map} +1 -1
- package/dist/{is-seeder-CYCtELlm.mjs → is-seeder-Gvh_AM71.mjs} +1 -1
- package/dist/{is-seeder-CYCtELlm.mjs.map → is-seeder-Gvh_AM71.mjs.map} +1 -1
- package/dist/lazy-module-loader-Ib383jH_.d.mts +60 -0
- package/dist/lazy-module-loader-Ib383jH_.d.mts.map +1 -0
- package/dist/locale-path.service-D-dHiIPc.mjs +165 -0
- package/dist/locale-path.service-D-dHiIPc.mjs.map +1 -0
- package/dist/locale-url-nZrZxqJP.mjs +44 -0
- package/dist/locale-url-nZrZxqJP.mjs.map +1 -0
- package/dist/locale-url.service-C2EWmGdq.mjs +41 -0
- package/dist/locale-url.service-C2EWmGdq.mjs.map +1 -0
- package/dist/logger/index.d.mts +1 -1
- package/dist/logger/index.mjs +2 -2
- package/dist/logger/index.mjs.map +1 -1
- package/dist/macroable/index.d.mts +2 -2
- package/dist/macroable/index.mjs +1 -1
- package/dist/{macroable-DzlfzT50.mjs → macroable-cvDTFZ_A.mjs} +1 -1
- package/dist/{macroable-DzlfzT50.mjs.map → macroable-cvDTFZ_A.mjs.map} +1 -1
- package/dist/{metadata-BVkc4aUu.mjs → metadata-DzzprcID.mjs} +1 -1
- package/dist/{metadata-BVkc4aUu.mjs.map → metadata-DzzprcID.mjs.map} +1 -1
- package/dist/module/index.d.mts +4 -3
- package/dist/module/index.d.mts.map +1 -1
- package/dist/module/index.mjs +10 -2
- package/dist/module/index.mjs.map +1 -0
- package/dist/{module-xYoHba6B.mjs → module-registry-Dm-pqHd3.mjs} +189 -57
- package/dist/module-registry-Dm-pqHd3.mjs.map +1 -0
- package/dist/module.decorator-CYHY6pG5.mjs +19 -0
- package/dist/module.decorator-CYHY6pG5.mjs.map +1 -0
- package/dist/openapi/index.d.mts +44 -8
- package/dist/openapi/index.d.mts.map +1 -1
- package/dist/openapi/index.mjs +3 -2
- package/dist/{openapi-C6lm0RmV.mjs → openapi-CstuTM8S.mjs} +55 -229
- package/dist/openapi-CstuTM8S.mjs.map +1 -0
- package/dist/openapi-tools.service-BC5EC3R3.mjs +206 -0
- package/dist/openapi-tools.service-BC5EC3R3.mjs.map +1 -0
- package/dist/{openapi.service-CrLlsXAd.d.mts → openapi.service-YhTiJ1bO.d.mts} +3 -3
- package/dist/{openapi.service-CrLlsXAd.d.mts.map → openapi.service-YhTiJ1bO.d.mts.map} +1 -1
- package/dist/quarry/index.d.mts +14 -5
- package/dist/quarry/index.d.mts.map +1 -1
- package/dist/quarry/index.mjs +6 -5
- package/dist/quarry/runner.d.mts +11 -11
- package/dist/quarry/runner.d.mts.map +1 -1
- package/dist/quarry/runner.mjs +192 -22
- package/dist/quarry/runner.mjs.map +1 -1
- package/dist/{quarry-registry-D4hIGScf.d.mts → quarry-registry-CXg0RFXq.d.mts} +4 -4
- package/dist/quarry-registry-CXg0RFXq.d.mts.map +1 -0
- package/dist/{quarry-registry-DkraZNwn.mjs → quarry.module-BuRPGMDm.mjs} +22 -21
- package/dist/quarry.module-BuRPGMDm.mjs.map +1 -0
- package/dist/queue/index.d.mts +3 -3
- package/dist/queue/index.mjs +42 -31
- package/dist/queue/index.mjs.map +1 -1
- package/dist/queue.module-nddvxzCB.mjs +613 -0
- package/dist/queue.module-nddvxzCB.mjs.map +1 -0
- package/dist/queue.tokens-DjHnFmre.mjs +11 -0
- package/dist/queue.tokens-DjHnFmre.mjs.map +1 -0
- package/dist/{r2-storage.provider-Hfm6LdZQ.mjs → r2-storage.provider-DCxQt9dD.mjs} +4 -4
- package/dist/{r2-storage.provider-Hfm6LdZQ.mjs.map → r2-storage.provider-DCxQt9dD.mjs.map} +1 -1
- package/dist/{rate-limit.decorator-D69zdZbp.mjs → rate-limit.decorator-BPAie_p3.mjs} +3 -3
- package/dist/{rate-limit.decorator-D69zdZbp.mjs.map → rate-limit.decorator-BPAie_p3.mjs.map} +1 -1
- package/dist/rate-limiter/index.d.mts +5 -5
- package/dist/rate-limiter/index.d.mts.map +1 -1
- package/dist/rate-limiter/index.mjs +26 -21
- package/dist/rate-limiter/index.mjs.map +1 -1
- package/dist/route-name-DGoBOfPg.mjs +171 -0
- package/dist/route-name-DGoBOfPg.mjs.map +1 -0
- package/dist/route-registration.service-D6vSwiKP.mjs +918 -0
- package/dist/route-registration.service-D6vSwiKP.mjs.map +1 -0
- package/dist/route-registry-CYqLp2Nj.mjs +123 -0
- package/dist/route-registry-CYqLp2Nj.mjs.map +1 -0
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +18 -8
- package/dist/router-CWGBD-Bg.mjs +78 -0
- package/dist/router-CWGBD-Bg.mjs.map +1 -0
- package/dist/router-resolver-D4YlPNlm.mjs +88 -0
- package/dist/router-resolver-D4YlPNlm.mjs.map +1 -0
- package/dist/seeder/index.d.mts +14 -4
- package/dist/seeder/index.d.mts.map +1 -1
- package/dist/seeder/index.mjs +5 -3
- package/dist/{seeder-BADTig4n.mjs → seeder-7ubkms-Y.mjs} +7 -56
- package/dist/seeder-7ubkms-Y.mjs.map +1 -0
- package/dist/seeder-registry-CyUmKsJq.mjs +57 -0
- package/dist/seeder-registry-CyUmKsJq.mjs.map +1 -0
- package/dist/seeder.module-CYYwk3Qk.mjs +15 -0
- package/dist/seeder.module-CYYwk3Qk.mjs.map +1 -0
- package/dist/{signed-url-BqUqt5dF.mjs → signed-url-DIU0sK_6.mjs} +1 -1
- package/dist/{signed-url-BqUqt5dF.mjs.map → signed-url-DIU0sK_6.mjs.map} +1 -1
- package/dist/storage/index.d.mts +3 -3
- package/dist/storage/index.d.mts.map +1 -1
- package/dist/storage/index.mjs +2 -2
- package/dist/storage/providers/index.d.mts +2 -2
- package/dist/storage/providers/index.d.mts.map +1 -1
- package/dist/storage/providers/index.mjs +1 -1
- package/dist/{storage-BA3ppVYM.mjs → storage-MDZypIE9.mjs} +12 -11
- package/dist/{storage-BA3ppVYM.mjs.map → storage-MDZypIE9.mjs.map} +1 -1
- package/dist/{storage-provider.interface-DQMtT42e.d.mts → storage-provider.interface-ClUwxz4S.d.mts} +2 -2
- package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +1 -0
- package/dist/storage.error-Dnib4VHc.mjs +8 -0
- package/dist/{storage.error-C6FY037a.mjs.map → storage.error-Dnib4VHc.mjs.map} +1 -1
- package/dist/{stratal-Bdq4IdB3.mjs → stratal-DL9M38_s.mjs} +142 -140
- package/dist/stratal-DL9M38_s.mjs.map +1 -0
- package/dist/{stratal-BsKmvP6J.d.mts → stratal-DwDJPY9N.d.mts} +3 -3
- package/dist/{stratal-BsKmvP6J.d.mts.map → stratal-DwDJPY9N.d.mts.map} +1 -1
- package/dist/tiered-cache.service-Dv3BhxxE.d.mts +79 -0
- package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +1 -0
- package/dist/trailing-slash-CFyw8nYu.mjs +34 -0
- package/dist/trailing-slash-CFyw8nYu.mjs.map +1 -0
- package/dist/{types-BaeHi67f.d.mts → types-CmV_9xBD.d.mts} +1 -1
- package/dist/types-CmV_9xBD.d.mts.map +1 -0
- package/dist/uri-h7Q8Jug9.mjs +251 -0
- package/dist/uri-h7Q8Jug9.mjs.map +1 -0
- package/dist/{usage-generator-DTqaUMR9.mjs → usage-generator-DAWYasuP.mjs} +4 -4
- package/dist/usage-generator-DAWYasuP.mjs.map +1 -0
- package/dist/{validation-DUzcjb8Q.mjs → validation-CpOjviyT.mjs} +6 -6
- package/dist/{validation-DUzcjb8Q.mjs.map → validation-CpOjviyT.mjs.map} +1 -1
- package/dist/{validation.context-XTysWJ3b.mjs → validation.context-CRvmrhq7.mjs} +3 -3
- package/dist/{validation.context-XTysWJ3b.mjs.map → validation.context-CRvmrhq7.mjs.map} +1 -1
- package/dist/versioning.service-C6aHky8-.mjs +36 -0
- package/dist/versioning.service-C6aHky8-.mjs.map +1 -0
- package/dist/websocket/index.d.mts +11 -2
- package/dist/websocket/index.d.mts.map +1 -1
- package/dist/websocket/index.mjs +1 -1
- package/dist/workers/index.d.mts +2 -2
- package/dist/workers/index.d.mts.map +1 -1
- package/dist/workers/index.mjs +3 -3
- package/dist/workers/index.mjs.map +1 -1
- package/dist/{zod-hMa3rSHV.mjs → zod-eKqqhZ5_.mjs} +2 -2
- package/dist/{zod-hMa3rSHV.mjs.map → zod-eKqqhZ5_.mjs.map} +1 -1
- package/dist/{zod-DvWTfRpI.d.mts → zod-wecrEVAs.d.mts} +8 -3
- package/dist/zod-wecrEVAs.d.mts.map +1 -0
- package/package.json +19 -30
- package/dist/base-email.provider-BWZHIjt8.mjs +0 -42
- package/dist/base-email.provider-BWZHIjt8.mjs.map +0 -1
- package/dist/cache.service-e34gV6tz.d.mts.map +0 -1
- package/dist/cache.tokens-ovi_c52J.mjs +0 -6
- package/dist/cache.tokens-ovi_c52J.mjs.map +0 -1
- package/dist/colors-axmupKdp.mjs +0 -16
- package/dist/colors-axmupKdp.mjs.map +0 -1
- package/dist/command-BU4ApTo5.mjs.map +0 -1
- package/dist/command-wXfvHbBZ.d.mts.map +0 -1
- package/dist/consumer-registry-DHQtypr1.d.mts.map +0 -1
- package/dist/cron-manager-9bpN9bu4.mjs.map +0 -1
- package/dist/cron-manager-CSTIBPcM.d.mts +0 -124
- package/dist/cron-manager-CSTIBPcM.d.mts.map +0 -1
- package/dist/di-BO1QIb5H.mjs.map +0 -1
- package/dist/env-DKSbuBi5.d.mts.map +0 -1
- package/dist/events-D1KdDaiP.mjs.map +0 -1
- package/dist/index-B4UBK-2T.d.mts.map +0 -1
- package/dist/index-BtlE9RuO.d.mts.map +0 -1
- package/dist/index-CW1YHSft.d.mts.map +0 -1
- package/dist/index-DEncMcC6.d.mts.map +0 -1
- package/dist/index-Dj5IMwtr.d.mts.map +0 -1
- package/dist/module-xYoHba6B.mjs.map +0 -1
- package/dist/openapi-C6lm0RmV.mjs.map +0 -1
- package/dist/quarry-registry-D4hIGScf.d.mts.map +0 -1
- package/dist/quarry-registry-DkraZNwn.mjs.map +0 -1
- package/dist/queue.module-DeWJ0tQM.mjs +0 -355
- package/dist/queue.module-DeWJ0tQM.mjs.map +0 -1
- package/dist/resend.provider-Ur6tU7fK.mjs +0 -68
- package/dist/resend.provider-Ur6tU7fK.mjs.map +0 -1
- package/dist/router-Cy6DjkvP.mjs +0 -1852
- package/dist/router-Cy6DjkvP.mjs.map +0 -1
- package/dist/seeder-BADTig4n.mjs.map +0 -1
- package/dist/smtp.provider-C129sNBT.mjs +0 -76
- package/dist/smtp.provider-C129sNBT.mjs.map +0 -1
- package/dist/storage-provider.interface-DQMtT42e.d.mts.map +0 -1
- package/dist/storage.error-C6FY037a.mjs +0 -8
- package/dist/stratal-Bdq4IdB3.mjs.map +0 -1
- package/dist/types-BaeHi67f.d.mts.map +0 -1
- package/dist/usage-generator-DTqaUMR9.mjs.map +0 -1
- package/dist/zod-DvWTfRpI.d.mts.map +0 -1
- /package/dist/{chunk-D1SwGrFN.mjs → chunk-BBjsoOtd.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-registration.service-D6vSwiKP.mjs","names":[],"sources":["../src/router/errors/route-not-found.error.ts","../src/router/errors/schema-validation.error.ts","../src/router/errors/index.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/services/route-registration.service.ts"],"sourcesContent":["import { HttpException } from '../../errors'\n\nexport class RouteNotFoundError extends HttpException {\n public readonly path: string\n public readonly method: string\n\n constructor(path: string, method: string) {\n super(404, `Route not found: ${method} ${path}`)\n this.path = path\n this.method = method\n }\n}\n","import { HttpException } from '../../errors'\nimport type { ZodError, z } from '../../i18n/validation/zod'\n\nexport class SchemaValidationError extends HttpException {\n public readonly issues: { path: string; message: string; code: string }[]\n\n constructor(zodError: ZodError) {\n super(400, 'Schema validation failed')\n this.issues = zodError.issues.map((err: z.core.$ZodIssue) => ({\n path: err.path.join('.'),\n message: err.message,\n code: err.code,\n }))\n }\n}\n","import { HttpException } from '../../errors';\nimport type { z, ZodError } from '../../i18n/validation/zod';\n\n/**\n * Error thrown when a signed URL has an invalid or expired signature.\n *\n * HTTP Status: 403 Forbidden\n */\nexport class InvalidSignatureError extends HttpException {\n constructor() {\n super(403, 'Invalid or expired signature')\n }\n}\n\n/**\n * ResponseValidationError\n *\n * Thrown when a controller's response body does not match the declared Zod response schema.\n * Indicates a server-side schema mismatch — the controller is returning data that\n * violates its own API contract.\n */\nexport class ResponseValidationError extends HttpException {\n public readonly issues: { path: string; message: string; code: string }[]\n\n constructor(zodError: ZodError) {\n super(500, 'Response validation failed')\n this.issues = zodError.issues.map((err: z.core.$ZodIssue) => ({\n path: err.path.join('.'),\n message: err.message,\n code: err.code,\n }))\n }\n}\n\nexport { RouteNotFoundError } from './route-not-found.error';\n\nexport { SchemaValidationError } from './schema-validation.error';\n","import type { Context, MiddlewareHandler } from 'hono';\nimport { abort } 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, aborts with 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 abort(404, 'Domain mismatch')\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 { RouterError } from '../router.error'\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 return Promise.reject(\n new RouterError(`Middleware \"${middlewareClass.name ?? 'anonymous'}\" called next() multiple times`)\n )\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 { defineMetadata, getMetadata } from '../../di/metadata'\nimport { 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 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 getMetadata<string[]>(ROUTE_METADATA_KEYS.DECORATED_METHODS, target) ?? []\n existing.push(propertyKey)\n 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 getMetadata<RouteMetadata>(ROUTE_METADATA_KEYS.ROUTE_CONFIG, target, methodName)\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 = getMetadata<string[]>(ROUTE_METADATA_KEYS.DECORATED_METHODS, proto)\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/zod'\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 the ErrorResponse shape produced by ExceptionHandler\n */\nexport const errorResponseSchema = z.object({\n message: z.string().describe('Human-readable error message'),\n timestamp: z.string().datetime().describe('ISO timestamp when error occurred'),\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 the ErrorResponse shape produced by ExceptionHandler\n */\nexport const validationErrorResponseSchema = errorResponseSchema.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","import type { Context, MiddlewareHandler } from 'hono';\nimport type { UpgradeWebSocket, WSContext, WSEvents } from 'hono/ws';\nimport { type Container, getMethodInjections, inject } from '../../di';\nimport { Singleton } 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/zod';\nimport { createRoute, z } from '../../i18n/validation/zod';\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger';\nimport type { ModuleRegistry } from '../../module/module-registry';\nimport { getRateLimits } from '../../rate-limiter/decorators/rate-limit.decorator';\nimport { createThrottleMiddleware } from '../../rate-limiter/throttle.middleware';\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 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 { RouterError } from '../router.error';\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@Singleton()\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, { isOptional: true }) 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 RouterError(\n `Controller \"${ControllerClass.name}\" registration failed: ${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 // Class-level @RateLimit decorators — same for every method on this controller.\n // Throttle middleware classes are memoized by name in createThrottleMiddleware,\n // so two `@RateLimit('a')` decorators yield the same class — Set dedupes them.\n const classThrottleMiddleware = Array.from(\n new Set(getRateLimits(ControllerClass).map(createThrottleMiddleware)),\n )\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 // Class-level @RateLimit applies; methods on a gateway aren't decorated routes.\n const wsMiddleware = [...routerConfig.middleware, ...classThrottleMiddleware]\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: wsMiddleware.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 (wsMiddleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(wsMiddleware))\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 // No method-level @RateLimit on wildcard handle() — only class-level applies.\n const wildcardMiddleware = [...routerConfig.middleware, ...classThrottleMiddleware]\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: wildcardMiddleware.map(m => m.name),\n })\n\n for (const route of expandedRoutes) {\n actions.set(route, () => {\n if (wildcardMiddleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(wildcardMiddleware))\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 RouterError(\n `Controller \"${ControllerClass.name}\" registration failed: 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 RouterError(\n `Controller \"${ControllerClass.name}\" registration failed: 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 for (const { method: methodName, meta } of methodMetadata) {\n const resolved = this.resolveMethodAndPath(meta, methodName, basePath, className)\n if (!resolved) continue\n\n // Compose per-method middleware: scope (router.throttle/.middleware)\n // → class-level @RateLimit → method-level @RateLimit. Throttle classes\n // are memoized by name, so duplicates across class + method (e.g.\n // `@RateLimit('api')` on both) collapse to a single middleware.\n const methodThrottleMiddleware = getRateLimits(prototype, methodName).map(createThrottleMiddleware)\n const effectiveMiddleware = Array.from(\n new Set([...routerConfig.middleware, ...classThrottleMiddleware, ...methodThrottleMiddleware]),\n )\n const middlewareNames = effectiveMiddleware.map(m => m.name)\n\n const { httpMethod, fullPath, routeConfig: rawRouteConfig, statusCodeOverride } = resolved\n\n // Compose prefix params with route-level params WITHOUT mutating the\n // route's metadata — `meta.config` lives on the controller prototype\n // and is shared across every Application/RouteRegistry instance that\n // resolves this controller. Mutating it leaks state across test runs\n // (and any other multi-app setup), causing later registrations to\n // re-extend an already-injected prefix from a previous run.\n let mergedParams = rawRouteConfig.params\n if (routerConfig.params) {\n const prefixShape = (routerConfig.params as z.ZodObject).shape\n mergedParams = mergedParams\n ? (mergedParams as z.ZodObject).extend(prefixShape)\n : (routerConfig.params as z.ZodObject).extend({})\n }\n const routeConfig: RouteConfig = mergedParams === rawRouteConfig.params\n ? rawRouteConfig\n : { ...rawRouteConfig, params: mergedParams }\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 (effectiveMiddleware.length > 0) {\n this.app.use(route.path, createMiddlewareChain(effectiveMiddleware))\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, effectiveMiddleware, 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`, err as Error, {\n gateway: GatewayClass.name,\n })\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 } else {\n // Cloudflare Workers (pre-2026-04-07 compat date) requires the server\n // to complete the WebSocket close handshake explicitly. Without a close\n // listener, Hono never calls server.addEventListener('close', ...),\n // leaving the Worker alive until the runtime kills it with\n // \"script will never generate a response\".\n events.onClose = (_evt: CloseEvent, ws: WSContext) => {\n ws.close()\n }\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, string>): 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 RouterError(\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 RouterError(`OpenAPI route registration failed for \"${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 // Precognition short-circuit: HandlePrecognitiveRequests middleware\n // sets `validationSuccessResponse` for `Precognition: true` requests.\n // If we reach here, every request validator has passed — return the\n // 204 without invoking the controller body.\n const override = c.get('validationSuccessResponse')\n if (override) return override\n\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 RouterError(`Method \"${methodName}\" not found on controller \"${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"],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
|
|
2
|
+
import { d as inject, s as Singleton, v as ROUTER_TOKENS } from "./di-DseMn-z9.mjs";
|
|
3
|
+
import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
|
|
4
|
+
import { o as RouterError } from "./module-registry-Dm-pqHd3.mjs";
|
|
5
|
+
import { a as sortRoutesBySpecificity, n as extractParamNames, t as extractDomainParamNames } from "./route-name-DGoBOfPg.mjs";
|
|
6
|
+
//#region src/router/route-registry.ts
|
|
7
|
+
var route_registry_exports = /* @__PURE__ */ __exportAll({ RouteRegistry: () => RouteRegistry });
|
|
8
|
+
const CONCRETE_HTTP_METHODS = [
|
|
9
|
+
"get",
|
|
10
|
+
"post",
|
|
11
|
+
"put",
|
|
12
|
+
"delete",
|
|
13
|
+
"patch",
|
|
14
|
+
"head",
|
|
15
|
+
"options",
|
|
16
|
+
"trace"
|
|
17
|
+
];
|
|
18
|
+
let RouteRegistry = class RouteRegistry {
|
|
19
|
+
versioningService;
|
|
20
|
+
localePathService;
|
|
21
|
+
routes = [];
|
|
22
|
+
namedRoutes = /* @__PURE__ */ new Map();
|
|
23
|
+
_sortedCache = null;
|
|
24
|
+
_routeToNameCache = null;
|
|
25
|
+
constructor(versioningService, localePathService) {
|
|
26
|
+
this.versioningService = versioningService;
|
|
27
|
+
this.localePathService = localePathService;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Register a route. Expands via VersioningService + LocalePathService.
|
|
31
|
+
* Named routes must have unique names.
|
|
32
|
+
*
|
|
33
|
+
* @returns Array of expanded RegisteredRoute entries (primary + locale variants)
|
|
34
|
+
* @throws RouterError if a named route with the same name already exists
|
|
35
|
+
*/
|
|
36
|
+
register(input) {
|
|
37
|
+
const domainParamNames = input.domainParamNames ?? (input.domain ? extractDomainParamNames(input.domain) : []);
|
|
38
|
+
const versionedPaths = this.versioningService.resolve(input.basePath, input.version);
|
|
39
|
+
const expandedRoutes = [];
|
|
40
|
+
const localeEnabled = this.localePathService.enabled;
|
|
41
|
+
for (const versionedPath of versionedPaths) {
|
|
42
|
+
const resolvedPaths = this.localePathService.resolve(versionedPath);
|
|
43
|
+
let localeVariantPaths;
|
|
44
|
+
if (localeEnabled) {
|
|
45
|
+
const variants = resolvedPaths.filter((p) => p.isLocaleVariant);
|
|
46
|
+
localeVariantPaths = variants.length > 0 ? variants.map((p) => p.path) : void 0;
|
|
47
|
+
}
|
|
48
|
+
for (const resolved of resolvedPaths) {
|
|
49
|
+
const route = {
|
|
50
|
+
name: resolved.isLocaleVariant ? void 0 : input.name,
|
|
51
|
+
method: input.method,
|
|
52
|
+
path: resolved.path,
|
|
53
|
+
localePaths: resolved.isLocaleVariant ? void 0 : localeVariantPaths,
|
|
54
|
+
paramNames: extractParamNames(resolved.path),
|
|
55
|
+
domain: input.domain,
|
|
56
|
+
domainParamNames,
|
|
57
|
+
controller: input.controller,
|
|
58
|
+
action: input.action,
|
|
59
|
+
hidden: input.hidden,
|
|
60
|
+
middleware: input.middleware,
|
|
61
|
+
isLocaleVariant: resolved.isLocaleVariant || void 0
|
|
62
|
+
};
|
|
63
|
+
if (route.name) {
|
|
64
|
+
if (this.namedRoutes.has(route.name)) {
|
|
65
|
+
const existing = this.namedRoutes.get(route.name);
|
|
66
|
+
throw new RouterError(`Duplicate route name "${route.name}": already registered by ${existing.controller}.${existing.action}, cannot register ${route.controller}.${route.action}`);
|
|
67
|
+
}
|
|
68
|
+
this.namedRoutes.set(route.name, route);
|
|
69
|
+
}
|
|
70
|
+
this.routes.push(route);
|
|
71
|
+
expandedRoutes.push(route);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
this._sortedCache = null;
|
|
75
|
+
this._routeToNameCache = null;
|
|
76
|
+
return expandedRoutes;
|
|
77
|
+
}
|
|
78
|
+
/** Get a named route by name */
|
|
79
|
+
get(name) {
|
|
80
|
+
return this.namedRoutes.get(name);
|
|
81
|
+
}
|
|
82
|
+
/** Check if a named route exists */
|
|
83
|
+
has(name) {
|
|
84
|
+
return this.namedRoutes.has(name);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Resolve a Hono-style route path pattern (e.g. as exposed by `c.req.routePath`)
|
|
88
|
+
* back to its registered name, scoped to the request's HTTP method. Locale variant
|
|
89
|
+
* paths resolve to the canonical primary route name. Method matching is
|
|
90
|
+
* case-insensitive; routes registered with `'all'` resolve under any verb.
|
|
91
|
+
*/
|
|
92
|
+
findNameByRoute(method, path) {
|
|
93
|
+
this._routeToNameCache ??= this.buildRouteToNameCache();
|
|
94
|
+
return this._routeToNameCache.get(`${method.toLowerCase()}:${path}`);
|
|
95
|
+
}
|
|
96
|
+
buildRouteToNameCache() {
|
|
97
|
+
const cache = /* @__PURE__ */ new Map();
|
|
98
|
+
for (const route of this.namedRoutes.values()) {
|
|
99
|
+
const methods = route.method === "all" ? CONCRETE_HTTP_METHODS : [route.method];
|
|
100
|
+
const paths = route.localePaths ? [route.path, ...route.localePaths] : [route.path];
|
|
101
|
+
for (const m of methods) for (const p of paths) cache.set(`${m}:${p}`, route.name);
|
|
102
|
+
}
|
|
103
|
+
return cache;
|
|
104
|
+
}
|
|
105
|
+
/** Get all routes sorted by specificity (static > param > wildcard, locale variant before its primary) */
|
|
106
|
+
all() {
|
|
107
|
+
this._sortedCache ??= sortRoutesBySpecificity(this.routes);
|
|
108
|
+
return this._sortedCache;
|
|
109
|
+
}
|
|
110
|
+
/** Get only named routes */
|
|
111
|
+
named() {
|
|
112
|
+
return [...this.namedRoutes.values()];
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
RouteRegistry = __decorate([
|
|
116
|
+
Singleton(),
|
|
117
|
+
__decorateParam(0, inject(ROUTER_TOKENS.VersioningService)),
|
|
118
|
+
__decorateParam(1, inject(ROUTER_TOKENS.LocalePathService))
|
|
119
|
+
], RouteRegistry);
|
|
120
|
+
//#endregion
|
|
121
|
+
export { route_registry_exports as n, RouteRegistry as t };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=route-registry-CYqLp2Nj.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-registry-CYqLp2Nj.mjs","names":[],"sources":["../src/router/route-registry.ts"],"sourcesContent":["import { inject } from '../di'\nimport { Singleton } from '../di/decorators'\nimport { type VERSION_NEUTRAL } from './constants'\nimport { RouterError } from './router.error'\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\nconst CONCRETE_HTTP_METHODS = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace'] as const\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@Singleton()\nexport class RouteRegistry {\n private readonly routes: RegisteredRoute[] = []\n private readonly namedRoutes = new Map<string, RegisteredRoute>()\n private _sortedCache: RegisteredRoute[] | null = null\n private _routeToNameCache: Map<string, string> | 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 RouterError 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 RouterError(\n `Duplicate route name \"${route.name}\": already registered by ${existing.controller}.${existing.action}, cannot register ${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 caches once per register() call, not per route\n this._sortedCache = null\n this._routeToNameCache = 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 /**\n * Resolve a Hono-style route path pattern (e.g. as exposed by `c.req.routePath`)\n * back to its registered name, scoped to the request's HTTP method. Locale variant\n * paths resolve to the canonical primary route name. Method matching is\n * case-insensitive; routes registered with `'all'` resolve under any verb.\n */\n findNameByRoute(method: string, path: string): string | undefined {\n this._routeToNameCache ??= this.buildRouteToNameCache()\n return this._routeToNameCache.get(`${method.toLowerCase()}:${path}`)\n }\n\n private buildRouteToNameCache(): Map<string, string> {\n const cache = new Map<string, string>()\n for (const route of this.namedRoutes.values()) {\n const methods = route.method === 'all' ? CONCRETE_HTTP_METHODS : [route.method]\n const paths = route.localePaths ? [route.path, ...route.localePaths] : [route.path]\n for (const m of methods) {\n for (const p of paths) {\n cache.set(`${m}:${p}`, route.name!)\n }\n }\n }\n return cache\n }\n\n /** Get all routes sorted by specificity (static > param > wildcard, locale variant before its primary) */\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"],"mappings":"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"}
|
package/dist/router/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $n as
|
|
2
|
-
export { All, Controller, ControllerOptions, ConventionRouteMetadata, CurrentRoute, Delete, ExplicitRouteMetadata, Get, HTTP_METHODS, HonoApp, IController, InvalidSignatureError, LocalePathConfig, LocalePathService, Middleware, Next, Patch, Post, Put, ROUTER_CONTEXT_KEYS, ROUTER_TOKENS, ROUTE_METADATA_KEYS, RegisteredRoute, ResolvedPath, ResponseValidationError, Route, RouteBody, RouteBodyObject, RouteConfig, RouteConfigurable, RouteMatcher, RouteMetadata, RouteName, RouteNotFoundError, RouteParams, RoutePrefixes, RouteRegistrationInput, RouteRegistrationService, RouteRegistry, RouteResponse, RouteResponseObject, Router, RouterContext, RouterEnv, RouterError, RouterGroupConfig, RouterVariables, SECURITY_SCHEMES, SSEMessage, SSEStreamingApi, SchemaValidationError, SecurityScheme, SerializedRoute, SerializedRoutes, SignedUriOptions, SignedUrlOptions, StratalRouteMap, StreamingApi, TrailingSlashMode, Uri, UriOptions, VERSION_NEUTRAL, VerifySignatureMiddleware, VersioningOptions, VersioningService, buildRouteUrl, commonErrorSchemas, createDomainMiddleware, createMiddlewareChain, errorResponseSchema, extractDomainParamNames, extractParamNames, generateConventionRouteName, getControllerOptions, getControllerRoute, getControllerVersion, getPathSpecificityScore, getRouteDecoratedMethods, getRouteMetadata, paginatedResponseSchema, paginationQuerySchema, parseDomainPattern, route, signUrl, sortRoutesBySpecificity, successMessageSchema, toOpenAPIPath, uuidParamSchema, validationErrorResponseSchema, verifySignedUrl };
|
|
1
|
+
import { $n as LocaleUrlConfig, $t as applyLocalePrefix, At as uuidParamSchema, Bt as Put, Cr as StratalRouteMap, Ct as createDomainMiddleware, Dt as paginatedResponseSchema, Et as errorResponseSchema, Ft as All, Gt as createMiddlewareChain, Ht as getControllerOptions, It as Delete, Jt as generateConventionRouteName, Kt as extractDomainParamNames, Lt as Get, Mt as Route, Nt as getRouteDecoratedMethods, Ot as paginationQuerySchema, Pt as getRouteMetadata, Qn as LocalePathConfig, Qt as applyTrailingSlash, Rt as Patch, Sr as SerializedRoutes, St as VerifySignatureMiddleware, Tt as commonErrorSchemas, Ut as getControllerRoute, Vt as Controller, Wt as getControllerVersion, Xn as ConventionRouteMetadata, Xt as sortRoutesBySpecificity, Yn as ControllerOptions, Yt as getPathSpecificityScore, Zn as ExplicitRouteMetadata, Zt as toOpenAPIPath, _n as Middleware, _r as RouteMatcher, _t as RouteNotFoundError, an as RegisteredRoute, ar as RouteResponseObject, at as Uri, br as RoutePrefixes, bt as signUrl, cn as VersioningService, cr as SecurityScheme, dn as Router, dr as HTTP_METHODS, dt as SSEMessage, en as shouldPrefixLocale, er as RouteBody, fn as RouterGroupConfig, fr as ROUTER_CONTEXT_KEYS, ft as SSEStreamingApi, gn as HonoApp, gr as CurrentRoute, gt as SchemaValidationError, hn as ResolvedPath, hr as VERSION_NEUTRAL, ht as ResponseValidationError, in as RouteRegistrationService, ir as RouteResponse, it as SignedUriOptions, jt as validationErrorResponseSchema, kt as successMessageSchema, lr as TrailingSlashMode, mn as LocalePathService, mr as SECURITY_SCHEMES, mt as InvalidSignatureError, nn as route, nr as RouteConfig, on as RouteRegistrationInput, or as RouterEnv, ot as UriOptions, pn as LocaleUrlService, pr as ROUTE_METADATA_KEYS, pt as StreamingApi, qt as extractParamNames, rn as ROUTER_TOKENS, rr as RouteMetadata, rt as RouterContext, sn as RouteRegistry, sr as RouterVariables, st as buildRouteUrl, tn as stripLocalePrefix, tr as RouteBodyObject, un as RouteConfigurable, ur as VersioningOptions, vn as Next, vr as RouteName, vt as RouterError, wt as parseDomainPattern, xr as SerializedRoute, xt as verifySignedUrl, yn as IController, yr as RouteParams, yt as SignedUrlOptions, zt as Post } from "../index-B_JoEl3V.mjs";
|
|
2
|
+
export { All, Controller, type ControllerOptions, type ConventionRouteMetadata, type CurrentRoute, Delete, type ExplicitRouteMetadata, Get, HTTP_METHODS, HonoApp, type IController, InvalidSignatureError, type LocalePathConfig, LocalePathService, type LocaleUrlConfig, LocaleUrlService, type Middleware, type Next, Patch, Post, Put, ROUTER_CONTEXT_KEYS, ROUTER_TOKENS, ROUTE_METADATA_KEYS, type RegisteredRoute, type ResolvedPath, ResponseValidationError, Route, type RouteBody, type RouteBodyObject, type RouteConfig, type RouteConfigurable, type RouteMatcher, type RouteMetadata, type RouteName, RouteNotFoundError, type RouteParams, type RoutePrefixes, type RouteRegistrationInput, RouteRegistrationService, RouteRegistry, type RouteResponse, type RouteResponseObject, Router, RouterContext, type RouterEnv, RouterError, type RouterGroupConfig, type RouterVariables, SECURITY_SCHEMES, type SSEMessage, type SSEStreamingApi, SchemaValidationError, type SecurityScheme, type SerializedRoute, type SerializedRoutes, type SignedUriOptions, type SignedUrlOptions, type StratalRouteMap, type StreamingApi, type TrailingSlashMode, Uri, type UriOptions, VERSION_NEUTRAL, VerifySignatureMiddleware, type VersioningOptions, VersioningService, applyLocalePrefix, applyTrailingSlash, buildRouteUrl, commonErrorSchemas, createDomainMiddleware, createMiddlewareChain, errorResponseSchema, extractDomainParamNames, extractParamNames, generateConventionRouteName, getControllerOptions, getControllerRoute, getControllerVersion, getPathSpecificityScore, getRouteDecoratedMethods, getRouteMetadata, paginatedResponseSchema, paginationQuerySchema, parseDomainPattern, route, shouldPrefixLocale, signUrl, sortRoutesBySpecificity, stripLocalePrefix, successMessageSchema, toOpenAPIPath, uuidParamSchema, validationErrorResponseSchema, verifySignedUrl };
|
package/dist/router/index.mjs
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as RouterContext, d as SECURITY_SCHEMES, f as VERSION_NEUTRAL, l as ROUTER_CONTEXT_KEYS, s as HTTP_METHODS, u as ROUTE_METADATA_KEYS } from "../exception-context-
|
|
3
|
-
import { n as Router, o as RouterError } from "../module-
|
|
4
|
-
import {
|
|
5
|
-
import { i as
|
|
6
|
-
import { a as
|
|
7
|
-
import {
|
|
8
|
-
|
|
1
|
+
import { v as ROUTER_TOKENS } from "../di-DseMn-z9.mjs";
|
|
2
|
+
import { a as RouterContext, d as SECURITY_SCHEMES, f as VERSION_NEUTRAL, l as ROUTER_CONTEXT_KEYS, s as HTTP_METHODS, u as ROUTE_METADATA_KEYS } from "../exception-context-kEoMFwze.mjs";
|
|
3
|
+
import { n as Router, o as RouterError } from "../module-registry-Dm-pqHd3.mjs";
|
|
4
|
+
import { i as getControllerVersion, n as getControllerOptions, r as getControllerRoute, t as Controller } from "../controller.decorator-C5UVeJS3.mjs";
|
|
5
|
+
import { a as Post, i as Patch, n as Delete, o as Put, r as Get, t as All } from "../http-method.decorator-ByWZb9DO.mjs";
|
|
6
|
+
import { _ as ResponseValidationError, a as paginatedResponseSchema, c as uuidParamSchema, d as getRouteDecoratedMethods, f as getRouteMetadata, g as InvalidSignatureError, h as parseDomainPattern, i as errorResponseSchema, l as validationErrorResponseSchema, m as createDomainMiddleware, o as paginationQuerySchema, p as createMiddlewareChain, r as commonErrorSchemas, s as successMessageSchema, t as RouteRegistrationService, u as Route, v as SchemaValidationError, y as RouteNotFoundError } from "../route-registration.service-D6vSwiKP.mjs";
|
|
7
|
+
import { t as HonoApp } from "../hono-app-CvV3hOfT.mjs";
|
|
8
|
+
import { t as applyTrailingSlash } from "../trailing-slash-CFyw8nYu.mjs";
|
|
9
|
+
import { a as sortRoutesBySpecificity, i as getPathSpecificityScore, n as extractParamNames, o as toOpenAPIPath, r as generateConventionRouteName, t as extractDomainParamNames } from "../route-name-DGoBOfPg.mjs";
|
|
10
|
+
import { t as LocalePathService } from "../locale-path.service-D-dHiIPc.mjs";
|
|
11
|
+
import { n as shouldPrefixLocale, r as stripLocalePrefix, t as applyLocalePrefix } from "../locale-url-nZrZxqJP.mjs";
|
|
12
|
+
import { t as LocaleUrlService } from "../locale-url.service-C2EWmGdq.mjs";
|
|
13
|
+
import { t as VersioningService } from "../versioning.service-C6aHky8-.mjs";
|
|
14
|
+
import { n as route, t as VerifySignatureMiddleware } from "../router-CWGBD-Bg.mjs";
|
|
15
|
+
import { t as RouteRegistry } from "../route-registry-CYqLp2Nj.mjs";
|
|
16
|
+
import { n as verifySignedUrl, t as signUrl } from "../signed-url-DIU0sK_6.mjs";
|
|
17
|
+
import { n as buildRouteUrl, t as Uri } from "../uri-h7Q8Jug9.mjs";
|
|
18
|
+
export { All, Controller, Delete, Get, HTTP_METHODS, HonoApp, InvalidSignatureError, LocalePathService, LocaleUrlService, Patch, Post, Put, ROUTER_CONTEXT_KEYS, ROUTER_TOKENS, ROUTE_METADATA_KEYS, ResponseValidationError, Route, RouteNotFoundError, RouteRegistrationService, RouteRegistry, Router, RouterContext, RouterError, SECURITY_SCHEMES, SchemaValidationError, Uri, VERSION_NEUTRAL, VerifySignatureMiddleware, VersioningService, applyLocalePrefix, applyTrailingSlash, buildRouteUrl, commonErrorSchemas, createDomainMiddleware, createMiddlewareChain, errorResponseSchema, extractDomainParamNames, extractParamNames, generateConventionRouteName, getControllerOptions, getControllerRoute, getControllerVersion, getPathSpecificityScore, getRouteDecoratedMethods, getRouteMetadata, paginatedResponseSchema, paginationQuerySchema, parseDomainPattern, route, shouldPrefixLocale, signUrl, sortRoutesBySpecificity, stripLocalePrefix, successMessageSchema, toOpenAPIPath, uuidParamSchema, validationErrorResponseSchema, verifySignedUrl };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { v as ROUTER_TOKENS } from "./di-DseMn-z9.mjs";
|
|
2
|
+
import { n as getContainer } from "./container-storage-BmOJ4_Na.mjs";
|
|
3
|
+
import "./exception-context-kEoMFwze.mjs";
|
|
4
|
+
import { o as RouterError } from "./module-registry-Dm-pqHd3.mjs";
|
|
5
|
+
import "./controller.decorator-C5UVeJS3.mjs";
|
|
6
|
+
import "./http-method.decorator-ByWZb9DO.mjs";
|
|
7
|
+
import { g as InvalidSignatureError } from "./route-registration.service-D6vSwiKP.mjs";
|
|
8
|
+
import "./hono-app-CvV3hOfT.mjs";
|
|
9
|
+
import "./locale-path.service-D-dHiIPc.mjs";
|
|
10
|
+
import "./locale-url.service-C2EWmGdq.mjs";
|
|
11
|
+
import "./versioning.service-C6aHky8-.mjs";
|
|
12
|
+
import "./route-registry-CYqLp2Nj.mjs";
|
|
13
|
+
import { n as verifySignedUrl } from "./signed-url-DIU0sK_6.mjs";
|
|
14
|
+
import "./uri-h7Q8Jug9.mjs";
|
|
15
|
+
//#region src/router/route-url.ts
|
|
16
|
+
/**
|
|
17
|
+
* Generate a URL from a named route.
|
|
18
|
+
*
|
|
19
|
+
* Keys in `params` matching `:param` placeholders fill the path.
|
|
20
|
+
* Domain params (`{tenant}`) are also consumed from `params`.
|
|
21
|
+
* Extra keys become query string parameters.
|
|
22
|
+
*
|
|
23
|
+
* Resolves RouteRegistry from the application container via AsyncLocalStorage.
|
|
24
|
+
* Available after `Application.initialize()` has been called.
|
|
25
|
+
*
|
|
26
|
+
* @param name - Named route identifier
|
|
27
|
+
* @param params - Route params + domain params + extra query params
|
|
28
|
+
* @returns Generated URL string
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // In a controller (preferred):
|
|
33
|
+
* ctx.route('users.show', { id: '1' })
|
|
34
|
+
*
|
|
35
|
+
* // Outside controllers (standalone function):
|
|
36
|
+
* import { route } from 'stratal/router'
|
|
37
|
+
*
|
|
38
|
+
* route('users.show', { id: '1' })
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
function route(name, params, options) {
|
|
42
|
+
return getContainer().resolve(ROUTER_TOKENS.Uri).route(name, params, options);
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/router/middleware/verify-signature.middleware.ts
|
|
46
|
+
/**
|
|
47
|
+
* Middleware that verifies signed URLs.
|
|
48
|
+
*
|
|
49
|
+
* Checks the `signature` (and optionally `expires`) query params against the
|
|
50
|
+
* request URL using HMAC-SHA256 via `crypto.subtle.verify()`.
|
|
51
|
+
*
|
|
52
|
+
* Requires `APP_SECRET` in the Cloudflare Workers environment bindings.
|
|
53
|
+
*
|
|
54
|
+
* @throws InvalidSignatureError (403) if signature is missing, invalid, or expired
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* @Module({ controllers: [UnsubscribeController], providers: [VerifySignatureMiddleware] })
|
|
59
|
+
* export class EmailModule implements RouteConfigurable {
|
|
60
|
+
* configureRoutes(router: Router): void {
|
|
61
|
+
* router.middleware(VerifySignatureMiddleware)
|
|
62
|
+
* }
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
var VerifySignatureMiddleware = class {
|
|
67
|
+
async handle(ctx, next) {
|
|
68
|
+
const url = ctx.c.req.url;
|
|
69
|
+
const secret = ctx.c.env.APP_SECRET;
|
|
70
|
+
if (!secret) throw new RouterError("Missing required environment variable \"APP_SECRET\"");
|
|
71
|
+
if (!await verifySignedUrl(url, secret)) throw new InvalidSignatureError();
|
|
72
|
+
await next();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { route as n, VerifySignatureMiddleware as t };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=router-CWGBD-Bg.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-CWGBD-Bg.mjs","names":[],"sources":["../src/router/route-url.ts","../src/router/middleware/verify-signature.middleware.ts"],"sourcesContent":["import { getContainer } from '../di/container-storage';\nimport type { RouteName, RouteParams } from './route-map';\nimport { ROUTER_TOKENS } from './router.tokens';\nimport { type Uri, type UriOptions } 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 options?: UriOptions\n): string {\n const container = getContainer()\n const uri = container.resolve<Uri>(ROUTER_TOKENS.Uri)\n\n return uri.route(name, params, options)\n}\n","import { InvalidSignatureError } from '../errors'\nimport { RouterError } from '../router.error'\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 RouterError('Missing required environment variable \"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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,MACd,MACA,QACA,SACQ;CAIR,OAHkB,aACE,EAAE,QAAa,cAAc,GAExC,EAAE,MAAM,MAAM,QAAQ,OAAO;AACxC;;;;;;;;;;;;;;;;;;;;;;;ACbA,IAAa,4BAAb,MAA6D;CAC3D,MAAM,OAAO,KAAoB,MAA2B;EAC1D,MAAM,MAAM,IAAI,EAAE,IAAI;EAEtB,MAAM,SADM,IAAI,EAAE,IACwC;EAE1D,IAAI,CAAC,QACH,MAAM,IAAI,YAAY,sDAAoD;EAI5E,IAAI,CAAC,MADiB,gBAAgB,KAAK,MAAM,GAE/C,MAAM,IAAI,sBAAsB;EAGlC,MAAM,KAAK;CACb;AACF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { a as getGroups, i as getGlobalMiddleware, r as getDefaultEntry } from "./module-registry-Dm-pqHd3.mjs";
|
|
2
|
+
//#region src/router/router-resolver.ts
|
|
3
|
+
/**
|
|
4
|
+
* Internal resolver that computes the effective Router config for each controller.
|
|
5
|
+
*
|
|
6
|
+
* Inheritance rules:
|
|
7
|
+
* - `middleware`: parent middleware runs first, then child (concatenated)
|
|
8
|
+
* - `prefix`: concatenated (parent + child)
|
|
9
|
+
* - `name`: concatenated (parent + child)
|
|
10
|
+
* - `domain`: child overrides parent
|
|
11
|
+
* - `version`: child overrides parent
|
|
12
|
+
* - `hideFromDocs`: child overrides parent
|
|
13
|
+
*
|
|
14
|
+
* @internal — not exported from stratal/router
|
|
15
|
+
*/
|
|
16
|
+
var RouterResolver = class {
|
|
17
|
+
routers;
|
|
18
|
+
constructor(routers) {
|
|
19
|
+
this.routers = routers;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the effective config for a given controller class.
|
|
23
|
+
* Searches through all module routers to find the one owning this controller.
|
|
24
|
+
*/
|
|
25
|
+
resolveForController(controller) {
|
|
26
|
+
for (const { router, controllers: moduleControllers } of this.routers) {
|
|
27
|
+
if (!moduleControllers.includes(controller)) continue;
|
|
28
|
+
for (const group of router[getGroups]()) if (group.controllers?.includes(controller)) return this.mergeEntries(router[getDefaultEntry](), group);
|
|
29
|
+
if (!new Set(router[getGroups]().flatMap((g) => g.controllers ?? [])).has(controller)) return this.entryToConfig(router[getDefaultEntry]());
|
|
30
|
+
}
|
|
31
|
+
return { middleware: [] };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Collect all global middleware registered via `router.use()` across all modules.
|
|
35
|
+
*/
|
|
36
|
+
getGlobalMiddleware() {
|
|
37
|
+
const global = [];
|
|
38
|
+
for (const { router } of this.routers) global.push(...router[getGlobalMiddleware]());
|
|
39
|
+
return global;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Merge parent default entry with child group entry following inheritance rules.
|
|
43
|
+
*/
|
|
44
|
+
mergeEntries(parent, child) {
|
|
45
|
+
return {
|
|
46
|
+
prefix: this.concatPrefixes(parent.prefix, child.prefix),
|
|
47
|
+
domain: child.domain ?? parent.domain,
|
|
48
|
+
name: this.concatNames(parent.name, child.name),
|
|
49
|
+
middleware: [...parent.middleware, ...child.middleware],
|
|
50
|
+
version: child.version ?? parent.version,
|
|
51
|
+
hideFromDocs: child.hideFromDocs ?? parent.hideFromDocs,
|
|
52
|
+
params: this.mergeParams(parent.params, child.params)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
entryToConfig(entry) {
|
|
56
|
+
return {
|
|
57
|
+
prefix: entry.prefix,
|
|
58
|
+
domain: entry.domain,
|
|
59
|
+
name: entry.name,
|
|
60
|
+
middleware: [...entry.middleware],
|
|
61
|
+
version: entry.version,
|
|
62
|
+
hideFromDocs: entry.hideFromDocs,
|
|
63
|
+
params: entry.params
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
mergeParams(parent, child) {
|
|
67
|
+
if (!parent && !child) return void 0;
|
|
68
|
+
if (!parent) return child;
|
|
69
|
+
if (!child) return parent;
|
|
70
|
+
return parent.extend(child.shape);
|
|
71
|
+
}
|
|
72
|
+
concatPrefixes(parent, child) {
|
|
73
|
+
if (!parent && !child) return void 0;
|
|
74
|
+
if (!parent) return child;
|
|
75
|
+
if (!child) return parent;
|
|
76
|
+
return `${parent.endsWith("/") ? parent.slice(0, -1) : parent}${child.startsWith("/") ? child : `/${child}`}`;
|
|
77
|
+
}
|
|
78
|
+
concatNames(parent, child) {
|
|
79
|
+
if (!parent && !child) return void 0;
|
|
80
|
+
if (!parent) return child;
|
|
81
|
+
if (!child) return parent;
|
|
82
|
+
return `${parent}${child}`;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
export { RouterResolver };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=router-resolver-D4YlPNlm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-resolver-D4YlPNlm.mjs","names":["internal.getGroups","internal.getDefaultEntry","internal.getGlobalMiddleware"],"sources":["../src/router/router-resolver.ts"],"sourcesContent":["import type { ZodObject } from '../i18n/validation/zod'\nimport type { Constructor } from '../types'\nimport type { Middleware } from './middleware.interface'\nimport type { Router, RouterEntry } from './router'\nimport * as internal from './router.internals'\n\n/**\n * Resolved configuration for a single controller.\n * Merges Router default entry, sub-group overrides, and inheritance rules.\n */\nexport interface ResolvedRouterConfig {\n prefix?: string\n domain?: string\n name?: string\n middleware: Constructor<Middleware>[]\n version?: string | string[]\n hideFromDocs?: boolean\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ZodObject generics require any for flexible shape parameter\n params?: ZodObject<any>\n}\n\n/**\n * Internal resolver that computes the effective Router config for each controller.\n *\n * Inheritance rules:\n * - `middleware`: parent middleware runs first, then child (concatenated)\n * - `prefix`: concatenated (parent + child)\n * - `name`: concatenated (parent + child)\n * - `domain`: child overrides parent\n * - `version`: child overrides parent\n * - `hideFromDocs`: child overrides parent\n *\n * @internal — not exported from stratal/router\n */\nexport class RouterResolver {\n private readonly routers: { router: Router; controllers: Constructor[] }[]\n\n constructor(routers: { router: Router; controllers: Constructor[] }[]) {\n this.routers = routers\n }\n\n /**\n * Resolve the effective config for a given controller class.\n * Searches through all module routers to find the one owning this controller.\n */\n resolveForController(controller: Constructor): ResolvedRouterConfig {\n for (const { router, controllers: moduleControllers } of this.routers) {\n if (!moduleControllers.includes(controller)) continue\n\n // Check if controller is in a sub-group\n for (const group of router[internal.getGroups]()) {\n if (group.controllers?.includes(controller)) {\n return this.mergeEntries(router[internal.getDefaultEntry](), group)\n }\n }\n\n // Controller is in the default scope (not in any sub-group)\n // But only if it's not claimed by any sub-group in this module\n const groupedControllers = new Set(\n router[internal.getGroups]().flatMap(g => g.controllers ?? [])\n )\n if (!groupedControllers.has(controller)) {\n return this.entryToConfig(router[internal.getDefaultEntry]())\n }\n }\n\n // Controller not found in any module's router — return empty config\n return { middleware: [] }\n }\n\n /**\n * Collect all global middleware registered via `router.use()` across all modules.\n */\n getGlobalMiddleware(): Constructor<Middleware>[] {\n const global: Constructor<Middleware>[] = []\n for (const { router } of this.routers) {\n global.push(...router[internal.getGlobalMiddleware]())\n }\n return global\n }\n\n /**\n * Merge parent default entry with child group entry following inheritance rules.\n */\n private mergeEntries(parent: RouterEntry, child: RouterEntry): ResolvedRouterConfig {\n return {\n // Concatenate: parent prefix + child prefix\n prefix: this.concatPrefixes(parent.prefix, child.prefix),\n // Override: child domain wins\n domain: child.domain ?? parent.domain,\n // Concatenate: parent name + child name\n name: this.concatNames(parent.name, child.name),\n // Concatenate: parent middleware first, then child\n middleware: [...parent.middleware, ...child.middleware],\n // Override: child version wins\n version: child.version ?? parent.version,\n // Override: child hideFromDocs wins\n hideFromDocs: child.hideFromDocs ?? parent.hideFromDocs,\n // Extend: parent params extended with child params\n params: this.mergeParams(parent.params, child.params),\n }\n }\n\n private entryToConfig(entry: RouterEntry): ResolvedRouterConfig {\n return {\n prefix: entry.prefix,\n domain: entry.domain,\n name: entry.name,\n middleware: [...entry.middleware],\n version: entry.version,\n hideFromDocs: entry.hideFromDocs,\n params: entry.params,\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ZodObject generics require any for flexible shape parameter\n private mergeParams(parent?: ZodObject<any>, child?: ZodObject<any>): ZodObject<any> | undefined {\n if (!parent && !child) return undefined\n if (!parent) return child\n if (!child) return parent\n // oxlint-disable-next-line typescript/no-explicit-any\n return parent.extend(child.shape) as ZodObject<any>\n }\n\n private concatPrefixes(parent?: string, child?: string): string | undefined {\n if (!parent && !child) return undefined\n if (!parent) return child\n if (!child) return parent\n // Normalize: remove trailing slash from parent, ensure child starts with /\n const p = parent.endsWith('/') ? parent.slice(0, -1) : parent\n const c = child.startsWith('/') ? child : `/${child}`\n return `${p}${c}`\n }\n\n private concatNames(parent?: string, child?: string): string | undefined {\n if (!parent && !child) return undefined\n if (!parent) return child\n if (!child) return parent\n return `${parent}${child}`\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAkCA,IAAa,iBAAb,MAA4B;CAC1B;CAEA,YAAY,SAA2D;EACrE,KAAK,UAAU;CACjB;;;;;CAMA,qBAAqB,YAA+C;EAClE,KAAK,MAAM,EAAE,QAAQ,aAAa,uBAAuB,KAAK,SAAS;GACrE,IAAI,CAAC,kBAAkB,SAAS,UAAU,GAAG;GAG7C,KAAK,MAAM,SAAS,OAAOA,WAAoB,GAC7C,IAAI,MAAM,aAAa,SAAS,UAAU,GACxC,OAAO,KAAK,aAAa,OAAOC,iBAA0B,GAAG,KAAK;GAStE,IAAI,CAAC,IAH0B,IAC7B,OAAOD,WAAoB,EAAE,SAAQ,MAAK,EAAE,eAAe,CAAC,CAAC,CAEzC,EAAE,IAAI,UAAU,GACpC,OAAO,KAAK,cAAc,OAAOC,iBAA0B,CAAC;EAEhE;EAGA,OAAO,EAAE,YAAY,CAAC,EAAE;CAC1B;;;;CAKA,sBAAiD;EAC/C,MAAM,SAAoC,CAAC;EAC3C,KAAK,MAAM,EAAE,YAAY,KAAK,SAC5B,OAAO,KAAK,GAAG,OAAOC,qBAA8B,CAAC;EAEvD,OAAO;CACT;;;;CAKA,aAAqB,QAAqB,OAA0C;EAClF,OAAO;GAEL,QAAQ,KAAK,eAAe,OAAO,QAAQ,MAAM,MAAM;GAEvD,QAAQ,MAAM,UAAU,OAAO;GAE/B,MAAM,KAAK,YAAY,OAAO,MAAM,MAAM,IAAI;GAE9C,YAAY,CAAC,GAAG,OAAO,YAAY,GAAG,MAAM,UAAU;GAEtD,SAAS,MAAM,WAAW,OAAO;GAEjC,cAAc,MAAM,gBAAgB,OAAO;GAE3C,QAAQ,KAAK,YAAY,OAAO,QAAQ,MAAM,MAAM;EACtD;CACF;CAEA,cAAsB,OAA0C;EAC9D,OAAO;GACL,QAAQ,MAAM;GACd,QAAQ,MAAM;GACd,MAAM,MAAM;GACZ,YAAY,CAAC,GAAG,MAAM,UAAU;GAChC,SAAS,MAAM;GACf,cAAc,MAAM;GACpB,QAAQ,MAAM;EAChB;CACF;CAGA,YAAoB,QAAyB,OAAoD;EAC/F,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,KAAA;EAC9B,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,CAAC,OAAO,OAAO;EAEnB,OAAO,OAAO,OAAO,MAAM,KAAK;CAClC;CAEA,eAAuB,QAAiB,OAAoC;EAC1E,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,KAAA;EAC9B,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,CAAC,OAAO,OAAO;EAInB,OAAO,GAFG,OAAO,SAAS,GAAG,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,SAC7C,MAAM,WAAW,GAAG,IAAI,QAAQ,IAAI;CAEhD;CAEA,YAAoB,QAAiB,OAAoC;EACvE,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO,KAAA;EAC9B,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,CAAC,OAAO,OAAO;EACnB,OAAO,GAAG,SAAS;CACrB;AACF"}
|
package/dist/seeder/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as Constructor } from "../types-
|
|
3
|
-
import { t as Command } from "../command-
|
|
1
|
+
import { Dr as ApplicationError, Y as Container, ct as Application } from "../index-B_JoEl3V.mjs";
|
|
2
|
+
import { t as Constructor } from "../types-CmV_9xBD.mjs";
|
|
3
|
+
import { t as Command } from "../command-CPhFHjG3.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/seeder/seeder.d.ts
|
|
6
6
|
declare const SEEDER_INTERNALS: unique symbol;
|
|
@@ -67,5 +67,15 @@ declare class SeederError extends ApplicationError {}
|
|
|
67
67
|
*/
|
|
68
68
|
declare function isSeeder(target: Constructor): boolean;
|
|
69
69
|
//#endregion
|
|
70
|
-
|
|
70
|
+
//#region src/seeder/seeder.module.d.ts
|
|
71
|
+
/**
|
|
72
|
+
* Registers the seeder registry (`SEEDER_TOKENS.SeederRegistry`).
|
|
73
|
+
*
|
|
74
|
+
* Eager: resolved synchronously at bootstrap (`registerSeeders`) and by the
|
|
75
|
+
* test harness (`@stratal/testing`), so it cannot be lazily loaded.
|
|
76
|
+
* {@link SeederRegistry} injects the `Application` via `DI_TOKENS.Application`.
|
|
77
|
+
*/
|
|
78
|
+
declare class SeederModule {}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { DbSeedCommand, DbSeedListCommand, SEEDER_INTERNALS, SEEDER_TOKENS, Seeder, type SeederContext, SeederError, SeederModule, SeederRegistry, isSeeder };
|
|
71
81
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/seeder/seeder.ts","../../src/seeder/seeder-registry.ts","../../src/seeder/commands/db-seed-list.command.ts","../../src/seeder/commands/db-seed.command.ts","../../src/seeder/seeder.error.ts","../../src/seeder/is-seeder.ts"],"mappings":";;;;;cAGa,gBAAA;AAAA,UAEI,aAAA;EACf,GAAA,CAAI,WAAA,EAAa,WAAA,CAAY,MAAA,IAAU,OAAA;EACvC,SAAA,EAAW,SAAA;AAAA;AAAA,uBAGS,MAAA;EAAA,CACnB,gBAAA,GAAmB,aAAA;EAAA,SAKX,GAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/seeder/seeder.ts","../../src/seeder/seeder-registry.ts","../../src/seeder/commands/db-seed-list.command.ts","../../src/seeder/commands/db-seed.command.ts","../../src/seeder/seeder.error.ts","../../src/seeder/is-seeder.ts","../../src/seeder/seeder.module.ts"],"mappings":";;;;;cAGa,gBAAA;AAAA,UAEI,aAAA;EACf,GAAA,CAAI,WAAA,EAAa,WAAA,CAAY,MAAA,IAAU,OAAA;EACvC,SAAA,EAAW,SAAA;AAAA;AAAA,uBAGS,MAAA;EAAA,CACnB,gBAAA,GAAmB,aAAA;EAAA,SAKX,GAAA,IAAO,OAAA;EAXD;EAAA,UAcC,IAAA,CAAK,WAAA,EAAa,WAAA,CAAY,MAAA,IAAU,OAAA;AAAA;;;cCX7C,aAAA;EAAA,SAEH,cAAA;AAAA;AAAA,cAGG,cAAA;EAAA,QAIwC,GAAA;EAAA,QAH3C,OAAA;EAAA,QACA,SAAA;cAE2C,GAAA,EAAK,WAAA;EAExD,QAAA,CAAS,WAAA,EAAa,WAAA,CAAY,MAAA;EAS5B,GAAA,CAAI,WAAA,EAAa,WAAA,CAAY,MAAA,GAAS,OAAA;IAAY,SAAA,GAAY,SAAA;EAAA,IAAc,OAAA;EAsB5E,MAAA,CAAO,OAAA;IAAY,SAAA,GAAY,SAAA;EAAA,IAAc,OAAA;EAMnD,IAAA,CAAK,IAAA,WAAe,WAAA,CAAY,MAAA;EAIhC,GAAA,CAAI,WAAA,EAAa,WAAA,CAAY,MAAA;EAI7B,IAAA;IAAU,SAAA;EAAA;AAAA;;;cC5DC,iBAAA,SAA0B,OAAO;EAAA,QAIc,OAAA;EAAA,OAHnD,OAAA;EAAA,OACA,WAAA;cAEmD,OAAA,EAAS,cAAA;EAInE,MAAA;AAAA;;;cCRW,aAAA,SAAsB,OAAA;EAAA,QAIyB,OAAA;EAAA,OAHnD,OAAA;EAAA,OACA,WAAA;cAEmD,OAAA,EAAS,cAAA;EAI7D,MAAA,IAAU,OAAA;AAAA;;;cCVL,WAAA,SAAoB,gBAAgB;;;;;;;AJCjD;iBKKgB,QAAA,CAAS,MAAmB,EAAX,WAAW;;;;;;;;ALL5C;;cMYa,YAAA"}
|