stratal 0.0.22 → 0.0.24
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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exception-context-B4kM-M53.mjs","names":["honoGetCookie","honoDeleteCookie","honoStream","honoStreamText","honoStreamSSE"],"sources":["../src/router/constants.ts","../src/router/router-context.ts","../src/errors/exception-context.ts"],"sourcesContent":["/**\n * Type-safe context keys for Hono router variables\n * Using symbols to avoid string collisions\n */\nexport const ROUTER_CONTEXT_KEYS = {\n REQUEST_CONTAINER: 'requestContainer',\n LOCALE: 'locale'\n} as const satisfies Record<string, string>\n\n/**\n * Metadata keys for storing route and controller configuration\n * Using symbols to avoid collisions with other decorators\n */\nexport const ROUTE_METADATA_KEYS = {\n CONTROLLER_ROUTE: Symbol.for('stratal:controller:route'),\n CONTROLLER_OPTIONS: Symbol.for('stratal:controller:options'),\n CONTROLLER_MIDDLEWARES: Symbol.for('stratal:controller:middlewares'),\n ROUTE_CONFIG: Symbol.for('stratal:route:config'),\n DECORATED_METHODS: Symbol.for('stratal:decorated:methods'),\n AUTH_GUARD: Symbol.for('stratal:auth:guard'),\n GATEWAY_MARKER: Symbol.for('stratal:gateway:marker'),\n WS_ON_MESSAGE: Symbol.for('stratal:ws:on-message'),\n WS_ON_CLOSE: Symbol.for('stratal:ws:on-close'),\n WS_ON_ERROR: Symbol.for('stratal:ws:on-error'),\n RATE_LIMIT: Symbol.for('stratal:route:rate-limit'),\n} as const\n\n/**\n * Security scheme identifiers for OpenAPI\n * These reference the security scheme definitions in security.schemas.ts\n */\nexport const SECURITY_SCHEMES = {\n BEARER_AUTH: 'bearerAuth',\n API_KEY: 'apiKey',\n SESSION_COOKIE: 'sessionCookie'\n} as const\n\n/**\n * HTTP method mapping for RESTful controller methods\n * Maps controller method names to HTTP verbs and path patterns\n */\nexport const HTTP_METHODS = {\n index: { method: 'get', path: '' } as const,\n show: { method: 'get', path: '/:id' } as const,\n create: { method: 'post', path: '' } as const,\n update: { method: 'put', path: '/:id' } as const,\n patch: { method: 'patch', path: '/:id' } as const,\n destroy: { method: 'delete', path: '/:id' } as const\n} as const\n\n/**\n * Default success status codes for RESTful controller methods\n * Used by @Route() decorator to auto-derive response status\n */\nexport const METHOD_STATUS_CODES = {\n index: 200,\n show: 200,\n create: 201,\n update: 200,\n patch: 200,\n destroy: 200\n} as const\n\n/**\n * Sentinel symbol to opt a controller out of versioning.\n * When used as the version, no prefix is applied even when defaultVersion is set.\n */\nexport const VERSION_NEUTRAL = Symbol.for('stratal:version:neutral')\n\n/**\n * Default content type for request bodies and responses\n */\nexport const DEFAULT_CONTENT_TYPE = 'application/json'\n","import type { Context } from 'hono'\nimport {\n deleteCookie as honoDeleteCookie,\n getCookie as honoGetCookie,\n setCookie as honoSetCookie,\n} from 'hono/cookie'\nimport type { SSEStreamingApi } from 'hono/streaming'\nimport { stream as honoStream, streamSSE as honoStreamSSE, streamText as honoStreamText } from 'hono/streaming'\nimport type { CookieOptions } from 'hono/utils/cookie'\nimport type { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status'\nimport type { StreamingApi } from 'hono/utils/stream'\nimport type { Container } from '../di/container'\nimport { ContainerError } from '../di/container.error'\nimport { Macroable } from '../macroable'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport type { RouteName, RouteParams } from './route-map'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { RouterEnv } from './types'\nimport type { SignedUriOptions, Uri, UriOptions } from './uri'\n\nexport type ContextQueryResult<R extends Record<string, unknown> | undefined, K extends string | undefined> = K extends string ? string : R extends undefined ? Record<string, unknown> : R\n\n/**\n * Router context wrapper with helper methods\n *\n * Provides convenient access to Hono's context and common request/response operations.\n * The native Hono context is available via the `c` property for advanced use cases.\n *\n * @example\n * ```typescript\n * async index(ctx: RouterContext): Promise<Response> {\n * // Use helper methods\n * const users = await this.service.findAll()\n * return ctx.json(users)\n * }\n *\n * async show(ctx: RouterContext): Promise<Response> {\n * // Access route params\n * const id = ctx.param('id')\n * const user = await this.service.findById(id)\n * return ctx.json(user)\n * }\n *\n * async create(ctx: RouterContext): Promise<Response> {\n * // Parse request body\n * const body = await ctx.body<CreateUserInput>()\n * const user = await this.service.create(body)\n * return ctx.json(user, 201)\n * }\n * ```\n */\nexport class RouterContext<T extends RouterEnv = RouterEnv> extends Macroable {\n /**\n * Native Hono context\n * Access for advanced use cases not covered by helper methods\n */\n constructor(\n public readonly c: Context<T>\n ) {\n super()\n }\n\n /**\n * Cloudflare-provided request properties (geo, TLS, bot management, etc.).\n * Always available on Cloudflare Workers requests via `c.req.raw.cf`.\n */\n get cf(): CfProperties {\n return this.c.req.raw.cf!\n }\n\n /**\n * Get request-scoped DI container\n * Contains request-specific services and context (AuthContext)\n *\n * @throws Error if container not initialized\n */\n getContainer(): Container {\n const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n if (!container) {\n throw new ContainerError('Request container has not been initialized')\n }\n return container as Container\n }\n\n /**\n * Set locale for the current request\n *\n * @param locale - Locale code (e.g., 'en', 'fr')\n */\n setLocale(locale: string): void {\n this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale)\n }\n\n /**\n * Get locale for the current request\n *\n * @returns Current locale code\n */\n getLocale(): string {\n const locale = this.c.get(ROUTER_CONTEXT_KEYS.LOCALE)\n return (locale as string) || 'en'\n }\n\n /**\n * Return JSON response\n *\n * When data is null, automatically returns 204 No Content (configurable via status param).\n *\n * @param data - Data to serialize as JSON, or null for 204\n * @param status - HTTP status code (default: 200, or 204 when data is null)\n */\n json(data: object | null, status?: ContentfulStatusCode): Response {\n if (data === null) {\n return this.c.body(null, status ?? 204)\n }\n return this.c.json(data, status)\n }\n\n /**\n * Get route parameter value(s).\n *\n * Reads the validated, Zod-coerced param record from `c.req.valid('param')`,\n * which is what `@hono/zod-openapi` populates for every route registered\n * via `app.openapi(...)`. Bare `c.req.param()` returns `undefined` for those\n * routes — always go through the validated record.\n *\n * - With a key → returns the single string value.\n * - With no args → returns the full `Record<string, string>` (or `{}` when\n * the matched route has no path params).\n *\n * @param key - Parameter name (e.g., 'id' for /users/:id)\n */\n param(): Record<string, string>\n param(key: string): string\n param(key?: string): string | Record<string, string> {\n const all = (this.c.req as unknown as { valid(target: 'param'): Record<string, string> | undefined }).valid('param') ?? {}\n return key === undefined ? all : all[key]\n }\n\n /**\n * Get query parameter value\n *\n * @param key - Query parameter name\n */\n query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n const validated = (this.c.req as unknown as { valid(target: 'query'): Record<string, unknown> }).valid('query')\n return key ? validated[key] as ContextQueryResult<R, K> : validated as ContextQueryResult<R, K>\n }\n\n /**\n * Get request header value\n *\n * @param name - Header name (case-insensitive)\n */\n header(name: string): string | undefined {\n return this.c.req.header(name)\n }\n\n /**\n * Read a cookie value from the current request.\n *\n * @param name - Cookie name\n * @returns The cookie value, or `undefined` if the cookie is not present\n *\n * @example\n * ```typescript\n * const redirectTo = ctx.getCookie('redirectTo')\n * ```\n */\n getCookie(name: string): string | undefined {\n return honoGetCookie(this.c, name)\n }\n\n /**\n * Set a cookie on the response.\n *\n * Cookie operations must run while the response is mutable — call this\n * before returning the final `Response` from the handler.\n *\n * @param name - Cookie name\n * @param value - Cookie value\n * @param options - Cookie attributes (httpOnly, secure, sameSite, path, etc.)\n *\n * @example\n * ```typescript\n * ctx.setCookie('redirectTo', '/app/', {\n * httpOnly: true,\n * secure: true,\n * sameSite: 'lax',\n * path: '/',\n * })\n * ```\n */\n setCookie(name: string, value: string, options?: CookieOptions): void {\n honoSetCookie(this.c, name, value, options)\n }\n\n /**\n * Delete a cookie from the response.\n *\n * Pass the same `path` and `domain` options that were used when the cookie\n * was set, otherwise the browser will not clear the matching cookie.\n *\n * @param name - Cookie name\n * @param options - Cookie attributes used at set time (path, domain, etc.)\n * @returns The deleted cookie's previous value, or `undefined`\n *\n * @example\n * ```typescript\n * ctx.deleteCookie('redirectTo', { path: '/' })\n * ```\n */\n deleteCookie(name: string, options?: CookieOptions): string | undefined {\n return honoDeleteCookie(this.c, name, options)\n }\n\n /**\n * Get validated request body from OpenAPI route\n * Returns pre-validated data that has passed schema validation\n *\n * @returns Validated JSON body\n */\n body<T>(): Promise<T> {\n // Type assertion needed because req.valid() is type-safe per route\n // but this is a generic helper method that works across all routes\n return (this.c.req as unknown as { valid(target: 'json'): Promise<T> }).valid('json')\n }\n\n /**\n * Return text response\n *\n * @param text - Text content\n * @param status - HTTP status code (default: 200)\n */\n text(text: string, status?: ContentfulStatusCode): Response {\n return this.c.text(text, status)\n }\n\n /**\n * Return HTML response\n *\n * @param html - HTML content\n * @param status - HTTP status code (default: 200)\n */\n html(html: string, status?: ContentfulStatusCode): Response {\n return this.c.html(html, status)\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params are consumed from the same object.\n * Extra keys become query string parameters.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options (e.g., `{ absolute: true }`)\n *\n * @example\n * ```typescript\n * ctx.route('users.show', { id: '1' }) // '/v1/users/1'\n * ctx.route('users.show', { id: '1', q: 'test' }) // '/v1/users/1?q=test'\n * ```\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n return this.resolveUri().route(name, params, options)\n }\n\n /**\n * Get a domain parameter value from the current request.\n * Domain params are set by the domain matching middleware.\n *\n * @param key - Domain parameter name (e.g., 'tenant' from '{tenant}.myapp.com')\n *\n * @example\n * ```typescript\n * const tenant = ctx.domain('tenant')\n * ```\n */\n domain(key: string): string {\n return this.c.get(`domain:${key}`) as string\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params (same as route())\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n */\n async signedUrl<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n return this.resolveUri().signedRoute(name, params, options)\n }\n\n /**\n * Check if the current request has a valid signature.\n *\n * @returns true if the URL signature is valid and not expired\n */\n async hasValidSignature(): Promise<boolean> {\n return this.resolveUri().hasValidSignature()\n }\n\n /**\n * Redirect to another URL\n *\n * @param url - Target URL\n * @param status - HTTP status code (default: 302)\n */\n redirect(url: string, status?: RedirectStatusCode): Response {\n return this.c.redirect(url, status)\n }\n\n /**\n * Return a streaming response (binary/generic)\n *\n * @param callback - Async function that writes to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n stream(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n return honoStream(this.c, callback, onError)\n }\n\n /**\n * Return a streaming text response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes text to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamText(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamText(this.c, callback, onError)\n }\n\n /**\n * Return a Server-Sent Events (SSE) streaming response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes SSE events to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamSSE(callback: (stream: SSEStreamingApi) => Promise<void>, onError?: (err: Error, stream: SSEStreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamSSE(this.c, callback, onError)\n }\n\n private resolveUri(): Uri {\n return this.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n }\n}\n","import type { Context } from 'hono'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\n\n/**\n * Exception context for errors occurring during HTTP request handling.\n *\n * Provides access to the full {@link RouterContext} for building responses\n * with `ctx.json()`, `ctx.text()`, `ctx.html()`, etc.\n */\nexport interface HttpExceptionContext {\n readonly type: 'http'\n /** Stratal RouterContext — use for building HTTP responses */\n readonly ctx: RouterContext\n}\n\n/**\n * Exception context for errors occurring during queue message processing.\n */\nexport interface QueueExceptionContext {\n readonly type: 'queue'\n /** Name of the queue being processed */\n readonly queueName: string\n}\n\n/**\n * Exception context for errors occurring during scheduled cron execution.\n */\nexport interface CronExceptionContext {\n readonly type: 'cron'\n}\n\n/**\n * Exception context for errors occurring during CLI command execution.\n */\nexport interface CliExceptionContext {\n readonly type: 'cli'\n /** Name of the command that threw */\n readonly commandName: string\n}\n\n/**\n * Discriminated union of all exception context types.\n *\n * Narrow via `ctx.type` to access context-specific properties:\n *\n * @example\n * ```typescript\n * handler.renderable(MyError, (error, ctx) => {\n * if (ctx.type === 'http') {\n * return ctx.ctx.json({ message: 'Something went wrong' }, 500)\n * }\n * // Non-HTTP contexts: return undefined to use default rendering\n * })\n * ```\n */\nexport type ExceptionContext =\n | HttpExceptionContext\n | QueueExceptionContext\n | CronExceptionContext\n | CliExceptionContext\n\n/**\n * Create an HTTP exception context from a Hono context.\n *\n * @param c - The raw Hono context from the request\n * @returns An {@link HttpExceptionContext} wrapping a RouterContext\n */\nexport function createHttpExceptionContext(c: Context<RouterEnv>): HttpExceptionContext {\n return { type: 'http', ctx: new RouterContext(c) }\n}\n\n/**\n * Create a queue exception context.\n *\n * @param queueName - The name of the queue being processed\n * @returns A {@link QueueExceptionContext}\n */\nexport function createQueueExceptionContext(queueName: string): QueueExceptionContext {\n return { type: 'queue', queueName }\n}\n\n/**\n * Create a cron exception context.\n *\n * @returns A {@link CronExceptionContext}\n */\nexport function createCronExceptionContext(): CronExceptionContext {\n return { type: 'cron' }\n}\n\n/**\n * Create a CLI command exception context.\n *\n * @param commandName - The name of the command that threw\n * @returns A {@link CliExceptionContext}\n */\nexport function createCliExceptionContext(commandName: string): CliExceptionContext {\n return { type: 'cli', commandName }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"exception-context-kEoMFwze.mjs","names":["honoGetCookie","honoDeleteCookie","honoStream","honoStreamText","honoStreamSSE"],"sources":["../src/router/constants.ts","../src/router/router-context.ts","../src/errors/exception-context.ts"],"sourcesContent":["/**\n * Type-safe context keys for Hono router variables\n * Using symbols to avoid string collisions\n */\nexport const ROUTER_CONTEXT_KEYS = {\n REQUEST_CONTAINER: 'requestContainer',\n LOCALE: 'locale'\n} as const satisfies Record<string, string>\n\n/**\n * Metadata keys for storing route and controller configuration\n * Using symbols to avoid collisions with other decorators\n */\nexport const ROUTE_METADATA_KEYS = {\n CONTROLLER_ROUTE: Symbol.for('stratal:controller:route'),\n CONTROLLER_OPTIONS: Symbol.for('stratal:controller:options'),\n CONTROLLER_MIDDLEWARES: Symbol.for('stratal:controller:middlewares'),\n ROUTE_CONFIG: Symbol.for('stratal:route:config'),\n DECORATED_METHODS: Symbol.for('stratal:decorated:methods'),\n AUTH_GUARD: Symbol.for('stratal:auth:guard'),\n GATEWAY_MARKER: Symbol.for('stratal:gateway:marker'),\n WS_ON_MESSAGE: Symbol.for('stratal:ws:on-message'),\n WS_ON_CLOSE: Symbol.for('stratal:ws:on-close'),\n WS_ON_ERROR: Symbol.for('stratal:ws:on-error'),\n RATE_LIMIT: Symbol.for('stratal:route:rate-limit'),\n} as const\n\n/**\n * Security scheme identifiers for OpenAPI\n * These reference the security scheme definitions in security.schemas.ts\n */\nexport const SECURITY_SCHEMES = {\n BEARER_AUTH: 'bearerAuth',\n API_KEY: 'apiKey',\n SESSION_COOKIE: 'sessionCookie'\n} as const\n\n/**\n * HTTP method mapping for RESTful controller methods\n * Maps controller method names to HTTP verbs and path patterns\n */\nexport const HTTP_METHODS = {\n index: { method: 'get', path: '' } as const,\n show: { method: 'get', path: '/:id' } as const,\n create: { method: 'post', path: '' } as const,\n update: { method: 'put', path: '/:id' } as const,\n patch: { method: 'patch', path: '/:id' } as const,\n destroy: { method: 'delete', path: '/:id' } as const\n} as const\n\n/**\n * Default success status codes for RESTful controller methods\n * Used by @Route() decorator to auto-derive response status\n */\nexport const METHOD_STATUS_CODES = {\n index: 200,\n show: 200,\n create: 201,\n update: 200,\n patch: 200,\n destroy: 200\n} as const\n\n/**\n * Sentinel symbol to opt a controller out of versioning.\n * When used as the version, no prefix is applied even when defaultVersion is set.\n */\nexport const VERSION_NEUTRAL = Symbol.for('stratal:version:neutral')\n\n/**\n * Default content type for request bodies and responses\n */\nexport const DEFAULT_CONTENT_TYPE = 'application/json'\n","import type { Context } from 'hono'\nimport {\n deleteCookie as honoDeleteCookie,\n getCookie as honoGetCookie,\n setCookie as honoSetCookie,\n} from 'hono/cookie'\nimport type { SSEStreamingApi } from 'hono/streaming'\nimport { stream as honoStream, streamSSE as honoStreamSSE, streamText as honoStreamText } from 'hono/streaming'\nimport type { CookieOptions } from 'hono/utils/cookie'\nimport type { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status'\nimport type { StreamingApi } from 'hono/utils/stream'\nimport type { Container } from '../di/container'\nimport { ContainerError } from '../di/container.error'\nimport { Macroable } from '../macroable'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport type { RouteName, RouteParams } from './route-map'\nimport { ROUTER_TOKENS } from './router.tokens'\nimport type { RouterEnv } from './types'\nimport type { SignedUriOptions, Uri, UriOptions } from './uri'\n\nexport type ContextQueryResult<R extends Record<string, unknown> | undefined, K extends string | undefined> = K extends string ? string : R extends undefined ? Record<string, unknown> : R\n\n/**\n * Router context wrapper with helper methods\n *\n * Provides convenient access to Hono's context and common request/response operations.\n * The native Hono context is available via the `c` property for advanced use cases.\n *\n * @example\n * ```typescript\n * async index(ctx: RouterContext): Promise<Response> {\n * // Use helper methods\n * const users = await this.service.findAll()\n * return ctx.json(users)\n * }\n *\n * async show(ctx: RouterContext): Promise<Response> {\n * // Access route params\n * const id = ctx.param('id')\n * const user = await this.service.findById(id)\n * return ctx.json(user)\n * }\n *\n * async create(ctx: RouterContext): Promise<Response> {\n * // Parse request body\n * const body = await ctx.body<CreateUserInput>()\n * const user = await this.service.create(body)\n * return ctx.json(user, 201)\n * }\n * ```\n */\nexport class RouterContext<T extends RouterEnv = RouterEnv> extends Macroable {\n /**\n * Native Hono context\n * Access for advanced use cases not covered by helper methods\n */\n constructor(\n public readonly c: Context<T>\n ) {\n super()\n }\n\n /**\n * Cloudflare-provided request properties (geo, TLS, bot management, etc.).\n * Always available on Cloudflare Workers requests via `c.req.raw.cf`.\n */\n get cf(): CfProperties {\n return this.c.req.raw.cf!\n }\n\n /**\n * Get request-scoped DI container\n * Contains request-specific services and context (AuthContext)\n *\n * @throws Error if container not initialized\n */\n getContainer(): Container {\n const container = this.c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER)\n if (!container) {\n throw new ContainerError('Request container has not been initialized')\n }\n return container as Container\n }\n\n /**\n * Set locale for the current request\n *\n * @param locale - Locale code (e.g., 'en', 'fr')\n */\n setLocale(locale: string): void {\n this.c.set(ROUTER_CONTEXT_KEYS.LOCALE, locale)\n }\n\n /**\n * Get locale for the current request\n *\n * @returns Current locale code\n */\n getLocale(): string {\n const locale = this.c.get(ROUTER_CONTEXT_KEYS.LOCALE)\n return (locale as string) || 'en'\n }\n\n /**\n * Return JSON response\n *\n * When data is null, automatically returns 204 No Content (configurable via status param).\n *\n * @param data - Data to serialize as JSON, or null for 204\n * @param status - HTTP status code (default: 200, or 204 when data is null)\n */\n json(data: object | null, status?: ContentfulStatusCode): Response {\n if (data === null) {\n return this.c.body(null, status ?? 204)\n }\n return this.c.json(data, status)\n }\n\n /**\n * Get route parameter value(s).\n *\n * Reads the validated, Zod-coerced param record from `c.req.valid('param')`,\n * which is what `@hono/zod-openapi` populates for every route registered\n * via `app.openapi(...)`. Bare `c.req.param()` returns `undefined` for those\n * routes — always go through the validated record.\n *\n * - With a key → returns the single string value.\n * - With no args → returns the full `Record<string, string>` (or `{}` when\n * the matched route has no path params).\n *\n * @param key - Parameter name (e.g., 'id' for /users/:id)\n */\n param(): Record<string, string>\n param(key: string): string\n param(key?: string): string | Record<string, string> {\n const all = (this.c.req as unknown as { valid(target: 'param'): Record<string, string> | undefined }).valid('param') ?? {}\n return key === undefined ? all : all[key]\n }\n\n /**\n * Get query parameter value\n *\n * @param key - Query parameter name\n */\n query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n const validated = (this.c.req as unknown as { valid(target: 'query'): Record<string, unknown> }).valid('query')\n return key ? validated[key] as ContextQueryResult<R, K> : validated as ContextQueryResult<R, K>\n }\n\n /**\n * Get request header value\n *\n * @param name - Header name (case-insensitive)\n */\n header(name: string): string | undefined {\n return this.c.req.header(name)\n }\n\n /**\n * Read a cookie value from the current request.\n *\n * @param name - Cookie name\n * @returns The cookie value, or `undefined` if the cookie is not present\n *\n * @example\n * ```typescript\n * const redirectTo = ctx.getCookie('redirectTo')\n * ```\n */\n getCookie(name: string): string | undefined {\n return honoGetCookie(this.c, name)\n }\n\n /**\n * Set a cookie on the response.\n *\n * Cookie operations must run while the response is mutable — call this\n * before returning the final `Response` from the handler.\n *\n * @param name - Cookie name\n * @param value - Cookie value\n * @param options - Cookie attributes (httpOnly, secure, sameSite, path, etc.)\n *\n * @example\n * ```typescript\n * ctx.setCookie('redirectTo', '/app/', {\n * httpOnly: true,\n * secure: true,\n * sameSite: 'lax',\n * path: '/',\n * })\n * ```\n */\n setCookie(name: string, value: string, options?: CookieOptions): void {\n honoSetCookie(this.c, name, value, options)\n }\n\n /**\n * Delete a cookie from the response.\n *\n * Pass the same `path` and `domain` options that were used when the cookie\n * was set, otherwise the browser will not clear the matching cookie.\n *\n * @param name - Cookie name\n * @param options - Cookie attributes used at set time (path, domain, etc.)\n * @returns The deleted cookie's previous value, or `undefined`\n *\n * @example\n * ```typescript\n * ctx.deleteCookie('redirectTo', { path: '/' })\n * ```\n */\n deleteCookie(name: string, options?: CookieOptions): string | undefined {\n return honoDeleteCookie(this.c, name, options)\n }\n\n /**\n * Get validated request body from OpenAPI route\n * Returns pre-validated data that has passed schema validation\n *\n * @returns Validated JSON body\n */\n body<T>(): Promise<T> {\n // Type assertion needed because req.valid() is type-safe per route\n // but this is a generic helper method that works across all routes\n return (this.c.req as unknown as { valid(target: 'json'): Promise<T> }).valid('json')\n }\n\n /**\n * Return text response\n *\n * @param text - Text content\n * @param status - HTTP status code (default: 200)\n */\n text(text: string, status?: ContentfulStatusCode): Response {\n return this.c.text(text, status)\n }\n\n /**\n * Return HTML response\n *\n * @param html - HTML content\n * @param status - HTTP status code (default: 200)\n */\n html(html: string, status?: ContentfulStatusCode): Response {\n return this.c.html(html, status)\n }\n\n /**\n * Generate a URL from a named route.\n *\n * Keys matching `:param` placeholders fill the path.\n * Domain params are consumed from the same object.\n * Extra keys become query string parameters.\n *\n * @param name - Named route identifier\n * @param params - Route params + domain params + extra query params\n * @param options - URL generation options (e.g., `{ absolute: true }`)\n *\n * @example\n * ```typescript\n * ctx.route('users.show', { id: '1' }) // '/v1/users/1'\n * ctx.route('users.show', { id: '1', q: 'test' }) // '/v1/users/1?q=test'\n * ```\n */\n route<N extends RouteName>(name: N, params?: RouteParams<N>, options?: UriOptions): string {\n return this.resolveUri().route(name, params, options)\n }\n\n /**\n * Get a domain parameter value from the current request.\n * Domain params are set by the domain matching middleware.\n *\n * @param key - Domain parameter name (e.g., 'tenant' from '{tenant}.myapp.com')\n *\n * @example\n * ```typescript\n * const tenant = ctx.domain('tenant')\n * ```\n */\n domain(key: string): string {\n return this.c.get(`domain:${key}`) as string\n }\n\n /**\n * Generate a signed URL from a named route.\n *\n * @param name - Named route identifier\n * @param params - Route params (same as route())\n * @param options - Signing options (e.g., expiresIn) and URL options\n * @returns Signed URL string with signature query param\n */\n async signedUrl<N extends RouteName>(name: N, params?: RouteParams<N>, options?: SignedUriOptions): Promise<string> {\n return this.resolveUri().signedRoute(name, params, options)\n }\n\n /**\n * Check if the current request has a valid signature.\n *\n * @returns true if the URL signature is valid and not expired\n */\n async hasValidSignature(): Promise<boolean> {\n return this.resolveUri().hasValidSignature()\n }\n\n /**\n * Redirect to another URL\n *\n * @param url - Target URL\n * @param status - HTTP status code (default: 302)\n */\n redirect(url: string, status?: RedirectStatusCode): Response {\n return this.c.redirect(url, status)\n }\n\n /**\n * Return a streaming response (binary/generic)\n *\n * @param callback - Async function that writes to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n stream(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n return honoStream(this.c, callback, onError)\n }\n\n /**\n * Return a streaming text response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes text to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamText(callback: (stream: StreamingApi) => Promise<void>, onError?: (err: Error, stream: StreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamText(this.c, callback, onError)\n }\n\n /**\n * Return a Server-Sent Events (SSE) streaming response\n *\n * Automatically sets `Content-Encoding: Identity` for Cloudflare Workers compatibility.\n *\n * @param callback - Async function that writes SSE events to the stream\n * @param onError - Optional error handler called if an error occurs during streaming\n */\n streamSSE(callback: (stream: SSEStreamingApi) => Promise<void>, onError?: (err: Error, stream: SSEStreamingApi) => Promise<void>): Response {\n this.c.header('Content-Encoding', 'Identity')\n return honoStreamSSE(this.c, callback, onError)\n }\n\n private resolveUri(): Uri {\n return this.getContainer().resolve<Uri>(ROUTER_TOKENS.Uri)\n }\n}\n","import type { Context } from 'hono'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\n\n/**\n * Exception context for errors occurring during HTTP request handling.\n *\n * Provides access to the full {@link RouterContext} for building responses\n * with `ctx.json()`, `ctx.text()`, `ctx.html()`, etc.\n */\nexport interface HttpExceptionContext {\n readonly type: 'http'\n /** Stratal RouterContext — use for building HTTP responses */\n readonly ctx: RouterContext\n}\n\n/**\n * Exception context for errors occurring during queue message processing.\n */\nexport interface QueueExceptionContext {\n readonly type: 'queue'\n /** Name of the queue being processed */\n readonly queueName: string\n}\n\n/**\n * Exception context for errors occurring during scheduled cron execution.\n */\nexport interface CronExceptionContext {\n readonly type: 'cron'\n}\n\n/**\n * Exception context for errors occurring during CLI command execution.\n */\nexport interface CliExceptionContext {\n readonly type: 'cli'\n /** Name of the command that threw */\n readonly commandName: string\n}\n\n/**\n * Discriminated union of all exception context types.\n *\n * Narrow via `ctx.type` to access context-specific properties:\n *\n * @example\n * ```typescript\n * handler.renderable(MyError, (error, ctx) => {\n * if (ctx.type === 'http') {\n * return ctx.ctx.json({ message: 'Something went wrong' }, 500)\n * }\n * // Non-HTTP contexts: return undefined to use default rendering\n * })\n * ```\n */\nexport type ExceptionContext =\n | HttpExceptionContext\n | QueueExceptionContext\n | CronExceptionContext\n | CliExceptionContext\n\n/**\n * Create an HTTP exception context from a Hono context.\n *\n * @param c - The raw Hono context from the request\n * @returns An {@link HttpExceptionContext} wrapping a RouterContext\n */\nexport function createHttpExceptionContext(c: Context<RouterEnv>): HttpExceptionContext {\n return { type: 'http', ctx: new RouterContext(c) }\n}\n\n/**\n * Create a queue exception context.\n *\n * @param queueName - The name of the queue being processed\n * @returns A {@link QueueExceptionContext}\n */\nexport function createQueueExceptionContext(queueName: string): QueueExceptionContext {\n return { type: 'queue', queueName }\n}\n\n/**\n * Create a cron exception context.\n *\n * @returns A {@link CronExceptionContext}\n */\nexport function createCronExceptionContext(): CronExceptionContext {\n return { type: 'cron' }\n}\n\n/**\n * Create a CLI command exception context.\n *\n * @param commandName - The name of the command that threw\n * @returns A {@link CliExceptionContext}\n */\nexport function createCliExceptionContext(commandName: string): CliExceptionContext {\n return { type: 'cli', commandName }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { a as ApplicationError } from "./container-storage-
|
|
2
|
-
import { n as getMetadata, t as defineMetadata } from "./metadata-
|
|
3
|
-
import "./
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
1
|
+
import { a as ApplicationError } from "./container-storage-BmOJ4_Na.mjs";
|
|
2
|
+
import { n as getMetadata, t as defineMetadata } from "./metadata-DzzprcID.mjs";
|
|
3
|
+
import { LOGGER_TOKENS } from "./logger/index.mjs";
|
|
4
|
+
import "./errors-mXYxG0XB.mjs";
|
|
5
|
+
import { a as RouterContext, u as ROUTE_METADATA_KEYS } from "./exception-context-kEoMFwze.mjs";
|
|
6
|
+
import { t as Controller } from "./controller.decorator-C5UVeJS3.mjs";
|
|
6
7
|
//#region src/websocket/decorators/gateway.decorator.ts
|
|
7
8
|
const GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER;
|
|
8
9
|
/**
|
|
@@ -143,6 +144,8 @@ function getWsOnErrorMethod(target) {
|
|
|
143
144
|
}
|
|
144
145
|
//#endregion
|
|
145
146
|
//#region src/websocket/gateway-context.ts
|
|
147
|
+
/** WebSocket OPEN ready state (`WSReadyState` is a type-only union in hono/ws). */
|
|
148
|
+
const WS_OPEN = 1;
|
|
146
149
|
/**
|
|
147
150
|
* WebSocket gateway context
|
|
148
151
|
*
|
|
@@ -170,6 +173,22 @@ var GatewayContext = class extends RouterContext {
|
|
|
170
173
|
send(data) {
|
|
171
174
|
this.ws.send(data);
|
|
172
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Send only if the socket is still open. Returns `false` (and logs a warning)
|
|
178
|
+
* when the socket is closing/closed — e.g. inside `@OnError`, which fires on a
|
|
179
|
+
* transport error after the socket is already dead, or after an `await` in
|
|
180
|
+
* `@OnMessage` when the client disconnected mid-handler. Use this for
|
|
181
|
+
* fire-and-forget acks/errors instead of `send()`, which throws on a closed
|
|
182
|
+
* socket ("Can't call WebSocket send() after close()").
|
|
183
|
+
*/
|
|
184
|
+
trySend(data) {
|
|
185
|
+
if (this.ws.readyState !== WS_OPEN) {
|
|
186
|
+
this.getContainer().resolve(LOGGER_TOKENS.LoggerService).warn("Skipped WebSocket send on non-open socket", { readyState: this.ws.readyState });
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
this.ws.send(data);
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
173
192
|
/** Close the WebSocket connection */
|
|
174
193
|
close(code, reason) {
|
|
175
194
|
this.ws.close(code, reason);
|
|
@@ -203,4 +222,4 @@ var GatewayContext = class extends RouterContext {
|
|
|
203
222
|
//#endregion
|
|
204
223
|
export { getWsOnCloseMethod as a, WebSocketError as c, OnMessage as i, Gateway as l, OnClose as n, getWsOnErrorMethod as o, OnError as r, getWsOnMessageMethod as s, GatewayContext as t, isGateway as u };
|
|
205
224
|
|
|
206
|
-
//# sourceMappingURL=gateway-context-
|
|
225
|
+
//# sourceMappingURL=gateway-context-TMu_AlJt.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-context-CFe6a9gz.mjs","names":[],"sources":["../src/websocket/decorators/gateway.decorator.ts","../src/websocket/websocket.error.ts","../src/websocket/decorators/ws-event.decorator.ts","../src/websocket/gateway-context.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport { Controller } from '../../router/decorators/controller.decorator'\nimport { type Constructor } from '../../types'\nimport type { GatewayOptions } from '../../websocket/types'\n\nconst GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER\n\n/**\n * Gateway decorator for WebSocket route registration\n *\n * Marks a class as a WebSocket gateway and stores route metadata.\n * Reuses the same metadata key as @Controller for middleware compatibility —\n * `getControllerRoute()`, `forRoutes()`, and the entire middleware system work\n * with zero changes.\n *\n * @param route - WebSocket route path (e.g., '/ws/chat')\n *\n * @example\n * ```typescript\n * import { type GatewayContext, Gateway, OnMessage, OnClose } from 'stratal/websocket'\n *\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack')\n * }\n *\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function Gateway(route: string, options?: GatewayOptions) {\n return function <T extends Constructor>(target: T) {\n Controller(route, options)(target)\n defineMetadata(GATEWAY_MARKER_KEY, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is a WebSocket gateway\n *\n * @param target - Class constructor or instance\n * @returns true if the class is decorated with @Gateway\n */\nexport function isGateway(target: object): boolean {\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return getMetadata(GATEWAY_MARKER_KEY, metadataTarget) === true\n}\n","import { ApplicationError } from '../errors'\n\nexport class WebSocketError extends ApplicationError {}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport type { Constructor } from '../../types'\nimport { WebSocketError } from '../websocket.error'\n\nconst WS_ON_MESSAGE_KEY = ROUTE_METADATA_KEYS.WS_ON_MESSAGE\nconst WS_ON_CLOSE_KEY = ROUTE_METADATA_KEYS.WS_ON_CLOSE\nconst WS_ON_ERROR_KEY = ROUTE_METADATA_KEYS.WS_ON_ERROR\n\n/**\n * Define a single-handler metadata key on the prototype.\n * Throws if a different method already owns this key (prevents silent override).\n */\nfunction defineSingleHandlerMetadata(key: symbol, propertyKey: string | symbol, target: object, decoratorName: string): void {\n const existing = getMetadata<string | symbol>(key, target)\n if (existing !== undefined && existing !== propertyKey) {\n throw new WebSocketError(`Duplicate @${decoratorName} handler: method \"${String(existing)}\" is already registered`)\n }\n defineMetadata(key, propertyKey, target)\n}\n\n/**\n * Marks a method as the WebSocket message handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send(evt.data)\n * }\n * }\n * ```\n */\nexport function OnMessage(): MethodDecorator {\n // `_target` is the class prototype (method decorator convention).\n // The getter functions below read from `target.prototype` symmetrically.\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_MESSAGE_KEY, propertyKey, _target, 'OnMessage')\n }\n}\n\n/**\n * Marks a method as the WebSocket close handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function OnClose(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_CLOSE_KEY, propertyKey, _target, 'OnClose')\n }\n}\n\n/**\n * Marks a method as the WebSocket error handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnError()\n * handleError(evt: Event, ctx: GatewayContext) {\n * console.error('WebSocket error', evt)\n * }\n * }\n * ```\n */\nexport function OnError(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_ERROR_KEY, propertyKey, _target, 'OnError')\n }\n}\n\n/**\n * Get the method name decorated with @OnMessage\n */\nexport function getWsOnMessageMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_MESSAGE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnClose\n */\nexport function getWsOnCloseMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_CLOSE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnError\n */\nexport function getWsOnErrorMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_ERROR_KEY, target.prototype as object)\n}\n","import type { Context } from 'hono'\nimport type { WSContext, WSReadyState } from 'hono/ws'\nimport type { ContextQueryResult } from '../router/router-context'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\nimport { WebSocketError } from './websocket.error'\n\n/**\n * WebSocket gateway context\n *\n * Extends RouterContext with WebSocket-specific methods.\n * Inherits `getContainer()`, `param()`, `query()`, `header()`, `getLocale()`\n * from RouterContext. HTTP response methods (`json()`, `redirect()`, etc.) are\n * inherited but harmless post-upgrade.\n *\n * @example\n * ```typescript\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack') // convenience method\n * ctx.header('Authorization') // upgrade request headers\n * }\n * ```\n */\nexport class GatewayContext extends RouterContext {\n constructor(c: Context<RouterEnv>, public readonly ws: WSContext) {\n super(c)\n }\n\n /** Send data through the WebSocket connection */\n send(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): void {\n this.ws.send(data)\n }\n\n /** Close the WebSocket connection */\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason)\n }\n\n /** Current WebSocket ready state */\n get readyState(): WSReadyState {\n return this.ws.readyState\n }\n\n /**\n * Get route parameter value(s) from the raw request — WebSocket gateways are\n * not OpenAPI-registered, so reads come straight from Hono's matcher.\n *\n * - With a key → single string value.\n * - With no args → full `Record<string, string>` (or `{}` when none).\n *\n * @param key - Parameter name (e.g., 'id' for /ws/chat/:id)\n */\n override param(): Record<string, string>\n override param(key: string): string\n override param(key?: string): string | Record<string, string> {\n if (key === undefined) return this.c.req.param() ?? {}\n return this.c.req.param(key)!\n }\n\n /**\n * Get query parameter value from the raw request (no OpenAPI validation)\n *\n * @param key - Query parameter name\n */\n override query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n if (key) {\n return this.c.req.query(key) as ContextQueryResult<R, K>\n }\n return this.c.req.query() as ContextQueryResult<R, K>\n }\n\n /**\n * Request body is not available in WebSocket gateways\n *\n * @throws WebSocketError always — WebSocket upgrade requests do not have a body\n */\n override body<T>(): Promise<T> {\n throw new WebSocketError('Request body is not available in WebSocket gateways')\n }\n}\n"],"mappings":";;;;;;AAMA,MAAM,qBAAqB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B/C,SAAgB,QAAQ,OAAe,SAA0B;CAC/D,OAAO,SAAiC,QAAW;EACjD,WAAW,OAAO,QAAQ,CAAC,OAAO;EAClC,eAAe,oBAAoB,MAAM,OAAO;EAChD,OAAO;;;;;;;;;AAUX,SAAgB,UAAU,QAAyB;CAEjD,OAAO,YAAY,oBADI,OAAO,WAAW,aAAa,SAAU,OAAmC,YAC7C,KAAK;;;;AClD7D,IAAa,iBAAb,cAAoC,iBAAiB;;;ACGrD,MAAM,oBAAoB,oBAAoB;AAC9C,MAAM,kBAAkB,oBAAoB;AAC5C,MAAM,kBAAkB,oBAAoB;;;;;AAM5C,SAAS,4BAA4B,KAAa,aAA8B,QAAgB,eAA6B;CAC3H,MAAM,WAAW,YAA6B,KAAK,OAAO;CAC1D,IAAI,aAAa,KAAA,KAAa,aAAa,aACzC,MAAM,IAAI,eAAe,cAAc,cAAc,oBAAoB,OAAO,SAAS,CAAC,yBAAyB;CAErH,eAAe,KAAK,aAAa,OAAO;;;;;;;;;;;;;;;;AAiB1C,SAAgB,YAA6B;CAG3C,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,mBAAmB,aAAa,SAAS,YAAY;;;;;;;;;;;;;;;;;AAkBrF,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,UAAU;;;;;;;;;;;;;;;;;AAkBjF,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,UAAU;;;;;;AAOjF,SAAgB,qBAAqB,QAAyC;CAC5E,OAAO,YAAoB,mBAAmB,OAAO,UAAoB;;;;;AAM3E,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,UAAoB;;;;;AAMzE,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,UAAoB;;;;;;;;;;;;;;;;;;;;;AC7EzE,IAAa,iBAAb,cAAoC,cAAc;CACG;CAAnD,YAAY,GAAuB,IAA+B;EAChE,MAAM,EAAE;EADyC,KAAA,KAAA;;;CAKnD,KAAK,MAA4D;EAC/D,KAAK,GAAG,KAAK,KAAK;;;CAIpB,MAAM,MAAe,QAAuB;EAC1C,KAAK,GAAG,MAAM,MAAM,OAAO;;;CAI7B,IAAI,aAA2B;EAC7B,OAAO,KAAK,GAAG;;CAcjB,MAAe,KAA+C;EAC5D,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAK,EAAE,IAAI,OAAO,IAAI,EAAE;EACtD,OAAO,KAAK,EAAE,IAAI,MAAM,IAAI;;;;;;;CAQ9B,MAAoH,KAAmC;EACrJ,IAAI,KACF,OAAO,KAAK,EAAE,IAAI,MAAM,IAAI;EAE9B,OAAO,KAAK,EAAE,IAAI,OAAO;;;;;;;CAQ3B,OAA+B;EAC7B,MAAM,IAAI,eAAe,sDAAsD"}
|
|
1
|
+
{"version":3,"file":"gateway-context-TMu_AlJt.mjs","names":[],"sources":["../src/websocket/decorators/gateway.decorator.ts","../src/websocket/websocket.error.ts","../src/websocket/decorators/ws-event.decorator.ts","../src/websocket/gateway-context.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport { Controller } from '../../router/decorators/controller.decorator'\nimport { type Constructor } from '../../types'\nimport type { GatewayOptions } from '../../websocket/types'\n\nconst GATEWAY_MARKER_KEY = ROUTE_METADATA_KEYS.GATEWAY_MARKER\n\n/**\n * Gateway decorator for WebSocket route registration\n *\n * Marks a class as a WebSocket gateway and stores route metadata.\n * Reuses the same metadata key as @Controller for middleware compatibility —\n * `getControllerRoute()`, `forRoutes()`, and the entire middleware system work\n * with zero changes.\n *\n * @param route - WebSocket route path (e.g., '/ws/chat')\n *\n * @example\n * ```typescript\n * import { type GatewayContext, Gateway, OnMessage, OnClose } from 'stratal/websocket'\n *\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack')\n * }\n *\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function Gateway(route: string, options?: GatewayOptions) {\n return function <T extends Constructor>(target: T) {\n Controller(route, options)(target)\n defineMetadata(GATEWAY_MARKER_KEY, true, target)\n return target\n }\n}\n\n/**\n * Check if a class is a WebSocket gateway\n *\n * @param target - Class constructor or instance\n * @returns true if the class is decorated with @Gateway\n */\nexport function isGateway(target: object): boolean {\n const metadataTarget = typeof target === 'function' ? target : (target as { constructor: object }).constructor\n return getMetadata(GATEWAY_MARKER_KEY, metadataTarget) === true\n}\n","import { ApplicationError } from '../errors'\n\nexport class WebSocketError extends ApplicationError {}\n","import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { ROUTE_METADATA_KEYS } from '../../router/constants'\nimport type { Constructor } from '../../types'\nimport { WebSocketError } from '../websocket.error'\n\nconst WS_ON_MESSAGE_KEY = ROUTE_METADATA_KEYS.WS_ON_MESSAGE\nconst WS_ON_CLOSE_KEY = ROUTE_METADATA_KEYS.WS_ON_CLOSE\nconst WS_ON_ERROR_KEY = ROUTE_METADATA_KEYS.WS_ON_ERROR\n\n/**\n * Define a single-handler metadata key on the prototype.\n * Throws if a different method already owns this key (prevents silent override).\n */\nfunction defineSingleHandlerMetadata(key: symbol, propertyKey: string | symbol, target: object, decoratorName: string): void {\n const existing = getMetadata<string | symbol>(key, target)\n if (existing !== undefined && existing !== propertyKey) {\n throw new WebSocketError(`Duplicate @${decoratorName} handler: method \"${String(existing)}\" is already registered`)\n }\n defineMetadata(key, propertyKey, target)\n}\n\n/**\n * Marks a method as the WebSocket message handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send(evt.data)\n * }\n * }\n * ```\n */\nexport function OnMessage(): MethodDecorator {\n // `_target` is the class prototype (method decorator convention).\n // The getter functions below read from `target.prototype` symmetrically.\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_MESSAGE_KEY, propertyKey, _target, 'OnMessage')\n }\n}\n\n/**\n * Marks a method as the WebSocket close handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnClose()\n * handleClose(evt: CloseEvent, ctx: GatewayContext) {\n * console.log('closed')\n * }\n * }\n * ```\n */\nexport function OnClose(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_CLOSE_KEY, propertyKey, _target, 'OnClose')\n }\n}\n\n/**\n * Marks a method as the WebSocket error handler\n *\n * @example\n * ```typescript\n * @Gateway('/ws/chat')\n * class ChatGateway {\n * @OnError()\n * handleError(evt: Event, ctx: GatewayContext) {\n * console.error('WebSocket error', evt)\n * }\n * }\n * ```\n */\nexport function OnError(): MethodDecorator {\n return (_target: object, propertyKey: string | symbol) => {\n defineSingleHandlerMetadata(WS_ON_ERROR_KEY, propertyKey, _target, 'OnError')\n }\n}\n\n/**\n * Get the method name decorated with @OnMessage\n */\nexport function getWsOnMessageMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_MESSAGE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnClose\n */\nexport function getWsOnCloseMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_CLOSE_KEY, target.prototype as object)\n}\n\n/**\n * Get the method name decorated with @OnError\n */\nexport function getWsOnErrorMethod(target: Constructor): string | undefined {\n return getMetadata<string>(WS_ON_ERROR_KEY, target.prototype as object)\n}\n","import type { Context } from 'hono'\nimport type { WSContext, WSReadyState } from 'hono/ws'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport type { ContextQueryResult } from '../router/router-context'\nimport { RouterContext } from '../router/router-context'\nimport type { RouterEnv } from '../router/types'\nimport { WebSocketError } from './websocket.error'\n\n/** WebSocket OPEN ready state (`WSReadyState` is a type-only union in hono/ws). */\nconst WS_OPEN = 1\n\n/**\n * WebSocket gateway context\n *\n * Extends RouterContext with WebSocket-specific methods.\n * Inherits `getContainer()`, `param()`, `query()`, `header()`, `getLocale()`\n * from RouterContext. HTTP response methods (`json()`, `redirect()`, etc.) are\n * inherited but harmless post-upgrade.\n *\n * @example\n * ```typescript\n * @OnMessage()\n * handleMessage(evt: MessageEvent, ctx: GatewayContext) {\n * ctx.send('ack') // convenience method\n * ctx.header('Authorization') // upgrade request headers\n * }\n * ```\n */\nexport class GatewayContext extends RouterContext {\n constructor(c: Context<RouterEnv>, public readonly ws: WSContext) {\n super(c)\n }\n\n /** Send data through the WebSocket connection */\n send(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): void {\n this.ws.send(data)\n }\n\n /**\n * Send only if the socket is still open. Returns `false` (and logs a warning)\n * when the socket is closing/closed — e.g. inside `@OnError`, which fires on a\n * transport error after the socket is already dead, or after an `await` in\n * `@OnMessage` when the client disconnected mid-handler. Use this for\n * fire-and-forget acks/errors instead of `send()`, which throws on a closed\n * socket (\"Can't call WebSocket send() after close()\").\n */\n trySend(data: string | ArrayBuffer | Uint8Array<ArrayBuffer>): boolean {\n if (this.ws.readyState !== WS_OPEN) {\n this.getContainer()\n .resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n .warn('Skipped WebSocket send on non-open socket', { readyState: this.ws.readyState })\n return false\n }\n this.ws.send(data)\n return true\n }\n\n /** Close the WebSocket connection */\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason)\n }\n\n /** Current WebSocket ready state */\n get readyState(): WSReadyState {\n return this.ws.readyState\n }\n\n /**\n * Get route parameter value(s) from the raw request — WebSocket gateways are\n * not OpenAPI-registered, so reads come straight from Hono's matcher.\n *\n * - With a key → single string value.\n * - With no args → full `Record<string, string>` (or `{}` when none).\n *\n * @param key - Parameter name (e.g., 'id' for /ws/chat/:id)\n */\n override param(): Record<string, string>\n override param(key: string): string\n override param(key?: string): string | Record<string, string> {\n if (key === undefined) return this.c.req.param() ?? {}\n return this.c.req.param(key)!\n }\n\n /**\n * Get query parameter value from the raw request (no OpenAPI validation)\n *\n * @param key - Query parameter name\n */\n override query<R extends Record<string, unknown> | undefined = undefined, K extends string | undefined = undefined>(key?: K): ContextQueryResult<R, K> {\n if (key) {\n return this.c.req.query(key) as ContextQueryResult<R, K>\n }\n return this.c.req.query() as ContextQueryResult<R, K>\n }\n\n /**\n * Request body is not available in WebSocket gateways\n *\n * @throws WebSocketError always — WebSocket upgrade requests do not have a body\n */\n override body<T>(): Promise<T> {\n throw new WebSocketError('Request body is not available in WebSocket gateways')\n }\n}\n"],"mappings":";;;;;;;AAMA,MAAM,qBAAqB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B/C,SAAgB,QAAQ,OAAe,SAA0B;CAC/D,OAAO,SAAiC,QAAW;EACjD,WAAW,OAAO,OAAO,EAAE,MAAM;EACjC,eAAe,oBAAoB,MAAM,MAAM;EAC/C,OAAO;CACT;AACF;;;;;;;AAQA,SAAgB,UAAU,QAAyB;CAEjD,OAAO,YAAY,oBADI,OAAO,WAAW,aAAa,SAAU,OAAmC,WAC9C,MAAM;AAC7D;;;ACnDA,IAAa,iBAAb,cAAoC,iBAAiB,CAAC;;;ACGtD,MAAM,oBAAoB,oBAAoB;AAC9C,MAAM,kBAAkB,oBAAoB;AAC5C,MAAM,kBAAkB,oBAAoB;;;;;AAM5C,SAAS,4BAA4B,KAAa,aAA8B,QAAgB,eAA6B;CAC3H,MAAM,WAAW,YAA6B,KAAK,MAAM;CACzD,IAAI,aAAa,KAAA,KAAa,aAAa,aACzC,MAAM,IAAI,eAAe,cAAc,cAAc,oBAAoB,OAAO,QAAQ,EAAE,wBAAwB;CAEpH,eAAe,KAAK,aAAa,MAAM;AACzC;;;;;;;;;;;;;;;AAgBA,SAAgB,YAA6B;CAG3C,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,mBAAmB,aAAa,SAAS,WAAW;CAClF;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAA2B;CACzC,QAAQ,SAAiB,gBAAiC;EACxD,4BAA4B,iBAAiB,aAAa,SAAS,SAAS;CAC9E;AACF;;;;AAKA,SAAgB,qBAAqB,QAAyC;CAC5E,OAAO,YAAoB,mBAAmB,OAAO,SAAmB;AAC1E;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AAKA,SAAgB,mBAAmB,QAAyC;CAC1E,OAAO,YAAoB,iBAAiB,OAAO,SAAmB;AACxE;;;;AC7FA,MAAM,UAAU;;;;;;;;;;;;;;;;;;AAmBhB,IAAa,iBAAb,cAAoC,cAAc;CACG;CAAnD,YAAY,GAAuB,IAA+B;EAChE,MAAM,CAAC;EAD0C,KAAA,KAAA;CAEnD;;CAGA,KAAK,MAA4D;EAC/D,KAAK,GAAG,KAAK,IAAI;CACnB;;;;;;;;;CAUA,QAAQ,MAA+D;EACrE,IAAI,KAAK,GAAG,eAAe,SAAS;GAClC,KAAK,aAAa,EACf,QAAuB,cAAc,aAAa,EAClD,KAAK,6CAA6C,EAAE,YAAY,KAAK,GAAG,WAAW,CAAC;GACvF,OAAO;EACT;EACA,KAAK,GAAG,KAAK,IAAI;EACjB,OAAO;CACT;;CAGA,MAAM,MAAe,QAAuB;EAC1C,KAAK,GAAG,MAAM,MAAM,MAAM;CAC5B;;CAGA,IAAI,aAA2B;EAC7B,OAAO,KAAK,GAAG;CACjB;CAaA,MAAe,KAA+C;EAC5D,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAK,EAAE,IAAI,MAAM,KAAK,CAAC;EACrD,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;CAC7B;;;;;;CAOA,MAAoH,KAAmC;EACrJ,IAAI,KACF,OAAO,KAAK,EAAE,IAAI,MAAM,GAAG;EAE7B,OAAO,KAAK,EAAE,IAAI,MAAM;CAC1B;;;;;;CAOA,OAA+B;EAC7B,MAAM,IAAI,eAAe,qDAAqD;CAChF;AACF"}
|
package/dist/guards/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Y as Container, rt as RouterContext } from "../index-
|
|
2
|
-
import { r as LoggerService } from "../index-
|
|
3
|
-
import { t as Constructor } from "../types-
|
|
1
|
+
import { Y as Container, rt as RouterContext } from "../index-B_JoEl3V.mjs";
|
|
2
|
+
import { r as LoggerService } from "../index-BUt92sAE.mjs";
|
|
3
|
+
import { t as Constructor } from "../types-CmV_9xBD.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/guards/types.d.ts
|
|
6
6
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/guards/types.ts","../../src/guards/use-guards.decorator.ts","../../src/guards/guard-execution.service.ts"],"mappings":";;;;;;;;AAqBA
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/guards/types.ts","../../src/guards/use-guards.decorator.ts","../../src/guards/guard-execution.service.ts"],"mappings":";;;;;;;;AAqBA;;;;;;;;;AAOwD;AAMxD;;;;AAAgD;UAb/B,WAAA;EAmBA;;;AAA2B;AAK5C;;EAjBE,WAAA,CAAY,OAAA,EAAS,aAAA,aAA0B,OAAO;AAAA;AAgC3C;AAMb;;AANa,KA1BD,UAAA,GAAa,WAAW,CAAC,WAAA;;AAiCtB;AAMf;;KAjCY,KAAA,GAAQ,UAAA,GAAa,WAAW;;AAiCkB;;UA5B7C,gBAAA;;ACajB;;;;;;;;;;;;;EDEE,WAAW;AAAA;;;;UAMI,aAAA;EACf,MAAA,EAAQ,KAAK;AAAA;;;;cAMF,kBAAA;;;;;;;AApDb;;;;;;;;;AAOwD;AAMxD;;;;AAAgD;AAMhD;;;;AAA4C;AAK5C;;;;AAea;AAMb;;;;AACe;AAMf;;;;AAA8D;;;;ACf9D;;;;;;;;;;;;;iBAAgB,SAAA,IAAa,MAAA,EAAQ,KAAA,KAAU,cAAA,GAAiB,eAAA;AAoBhE;;;;AAAkE;AAWlE;AAXA,iBAAgB,mBAAA,CAAoB,MAAA,WAAiB,aAAa;;;;;;;AAW0B;iBAA5E,eAAA,CAAgB,MAAA,UAAgB,WAAA,oBAA+B,aAAa;;;;ADpE5F;;;;;cEVa,qBAAA;EAAA,iBACkB,MAAA;cAAA,MAAA,EAAQ,aAAA;EFgBiB;AAAA;AAMxD;;;;AAAgD;AAMhD;;EEjBQ,aAAA,CACJ,MAAA,EAAQ,KAAA,IACR,OAAA,EAAS,aAAA,EACT,SAAA,EAAW,SAAA,GACV,OAAA;EFae;AAAwB;AAK5C;;;;AAea;EApBO,QE2BV,YAAA;EFDoB;;;EAAA,QEcpB,eAAA;AAAA"}
|
package/dist/guards/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as GUARD_METADATA_KEY, i as getMethodGuards, n as UseGuards, r as getControllerGuards, t as GuardExecutionService } from "../guards-
|
|
1
|
+
import { a as GUARD_METADATA_KEY, i as getMethodGuards, n as UseGuards, r as getControllerGuards, t as GuardExecutionService } from "../guards-DALPXy3_.mjs";
|
|
2
2
|
export { GUARD_METADATA_KEY, GuardExecutionService, UseGuards, getControllerGuards, getMethodGuards };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as getMetadata, t as defineMetadata } from "./metadata-
|
|
1
|
+
import { n as getMetadata, t as defineMetadata } from "./metadata-DzzprcID.mjs";
|
|
2
2
|
//#region src/guards/types.ts
|
|
3
3
|
/**
|
|
4
4
|
* Metadata key for guard storage
|
|
@@ -150,4 +150,4 @@ var GuardExecutionService = class {
|
|
|
150
150
|
//#endregion
|
|
151
151
|
export { GUARD_METADATA_KEY as a, getMethodGuards as i, UseGuards as n, getControllerGuards as r, GuardExecutionService as t };
|
|
152
152
|
|
|
153
|
-
//# sourceMappingURL=guards-
|
|
153
|
+
//# sourceMappingURL=guards-DALPXy3_.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guards-
|
|
1
|
+
{"version":3,"file":"guards-DALPXy3_.mjs","names":[],"sources":["../src/guards/types.ts","../src/guards/use-guards.decorator.ts","../src/guards/guard-execution.service.ts"],"sourcesContent":["import type { RouterContext } from '../router'\nimport type { Constructor } from '../types'\n\n/**\n * Interface for guards that control access to routes\n *\n * Guards are executed after middlewares but before route handlers.\n * They determine if a request should be allowed to proceed.\n *\n * @example\n * ```typescript\n * class RoleGuard implements CanActivate {\n * constructor(private readonly role: string) {}\n *\n * async canActivate(context: RouterContext): Promise<boolean> {\n * const user = context.getUser()\n * return user?.roles.includes(this.role) ?? false\n * }\n * }\n * ```\n */\nexport interface CanActivate {\n /**\n * Determine if the request should be allowed\n *\n * @param context - Router context with request/response helpers\n * @returns true to allow, false to deny (throws 403)\n */\n canActivate(context: RouterContext): boolean | Promise<boolean>\n}\n\n/**\n * Type for guard class constructors\n */\nexport type GuardClass = Constructor<CanActivate>\n\n/**\n * Guard can be a class constructor or an instance\n * Instances are used for factory-created guards with configuration\n */\nexport type Guard = GuardClass | CanActivate\n\n/**\n * Options for AuthGuard factory\n */\nexport interface AuthGuardOptions {\n /**\n * Required permissions for authorization as `\"resource:action\"` strings.\n * If provided, permission check is performed after authentication.\n * If omitted, only authentication is required.\n *\n * Multiple permissions are combined with AND logic (all must be satisfied).\n *\n * @example\n * ```typescript\n * @UseGuards(AuthGuard({ permissions: 'posts:update' }))\n * @UseGuards(AuthGuard({ permissions: ['posts:update', 'posts:delete'] }))\n * @UseGuards(AuthGuard({ permissions: 'admin:access' }))\n * ```\n */\n permissions?: string | string[]\n}\n\n/**\n * Metadata stored by `@UseGuards` decorator\n */\nexport interface GuardMetadata {\n guards: Guard[]\n}\n\n/**\n * Metadata key for guard storage\n */\nexport const GUARD_METADATA_KEY = Symbol.for('stratal:guards')\n","import { defineMetadata, getMetadata } from '../di/metadata'\nimport { GUARD_METADATA_KEY, type Guard, type GuardMetadata } from './types'\n\n/**\n * UseGuards Decorator\n *\n * Applies one or more guards to a controller or method.\n * Guards are executed in order and all must pass for the request to proceed.\n *\n * **Execution Order:**\n * 1. Request → Global Middlewares → Route Middlewares\n * 2. **Guards (controller-level, then method-level)**\n * 3. Route Handler\n *\n * **Guard Resolution:**\n * - Guard classes are resolved from the request-scoped DI container\n * - Guard instances (from factory functions) are used directly\n *\n * @param guards - Guard classes or instances to apply\n *\n * @example Authentication only\n * ```typescript\n * @Controller('/api/v1/profile')\n * @UseGuards(AuthGuard())\n * export class ProfileController {\n * show() { } // Requires authentication\n * }\n * ```\n *\n * @example Authentication with permissions\n * ```typescript\n * @Controller('/api/v1/students')\n * @UseGuards(AuthGuard({ scopes: ['students:read'] }))\n * export class StudentsController {\n * index() { } // Requires 'students:read' permission\n * }\n * ```\n *\n * @example Method-level guards\n * ```typescript\n * @Controller('/api/v1/students')\n * @UseGuards(AuthGuard()) // Controller-level: auth only\n * export class StudentsController {\n * index() { } // Auth only (inherited)\n *\n * @UseGuards(AuthGuard({ scopes: ['students:create'] }))\n * create() { } // Auth + 'students:create' permission\n * }\n * ```\n *\n * @example Multiple guards\n * ```typescript\n * @UseGuards(AuthGuard(), RateLimitGuard(), CustomGuard())\n * export class SecureController {\n * // All guards must pass\n * }\n * ```\n */\nexport function UseGuards(...guards: Guard[]): ClassDecorator & MethodDecorator {\n return (target: object, propertyKey?: string | symbol) => {\n const metadata: GuardMetadata = { guards }\n\n if (propertyKey !== undefined) {\n // Method decorator - store on method\n defineMetadata(GUARD_METADATA_KEY, metadata, target, propertyKey)\n } else {\n // Class decorator - store on class\n defineMetadata(GUARD_METADATA_KEY, metadata, target)\n }\n }\n}\n\n/**\n * Get controller-level guard metadata\n *\n * @param target - Controller class\n * @returns Guard metadata or undefined if not decorated\n */\nexport function getControllerGuards(target: object): GuardMetadata | undefined {\n return getMetadata<GuardMetadata>(GUARD_METADATA_KEY, target)\n}\n\n/**\n * Get method-level guard metadata\n *\n * @param target - Controller prototype\n * @param propertyKey - Method name\n * @returns Guard metadata or undefined if not decorated\n */\nexport function getMethodGuards(target: object, propertyKey: string | symbol): GuardMetadata | undefined {\n return getMetadata<GuardMetadata>(GUARD_METADATA_KEY, target, propertyKey)\n}\n","import type { Container } from '../di'\nimport type { LoggerService } from '../logger'\nimport type { RouterContext } from '../router'\nimport type { CanActivate, Guard } from './types'\n\n/**\n * Guard Execution Service\n *\n * Executes guards for a route and determines if the request should proceed.\n * Guards are executed in order; all must pass for the request to proceed.\n */\nexport class GuardExecutionService {\n constructor(private readonly logger: LoggerService) { }\n\n /**\n * Execute all guards for a route\n *\n * @param guards - Array of guards (classes or instances)\n * @param context - Router context\n * @param container - Request-scoped DI container\n * @returns true if all guards pass\n * @throws Error from first failing guard\n */\n async executeGuards(\n guards: Guard[],\n context: RouterContext,\n container: Container\n ): Promise<boolean> {\n if (guards.length === 0) {\n return true\n }\n\n this.logger.debug('Executing guards', {\n guardCount: guards.length,\n path: context.c.req.path,\n method: context.c.req.method,\n })\n\n for (const guard of guards) {\n const guardInstance = this.resolveGuard(guard, container)\n const canActivate = await guardInstance.canActivate(context)\n\n if (!canActivate) {\n this.logger.debug('Guard denied access', {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- guard.constructor may be null at runtime\n guard: guard.constructor?.name || 'AnonymousGuard',\n path: context.c.req.path,\n })\n return false\n }\n }\n\n this.logger.debug('All guards passed', {\n guardCount: guards.length,\n path: context.c.req.path,\n })\n\n return true\n }\n\n /**\n * Resolve a guard to an instance\n *\n * @param guard - Guard class or instance\n * @param container - Request-scoped DI container\n * @returns Guard instance\n */\n private resolveGuard(guard: Guard, container: Container): CanActivate {\n // If already an instance (has canActivate method), use directly\n if (this.isGuardInstance(guard)) {\n return guard\n }\n\n // Otherwise, resolve from container\n return container.resolve<CanActivate>(guard)\n }\n\n /**\n * Type guard to check if value is a guard instance\n */\n private isGuardInstance(guard: Guard): guard is CanActivate {\n return (\n typeof guard === 'object' &&\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typeof null === 'object', null check is required\n guard !== null &&\n 'canActivate' in guard &&\n typeof guard.canActivate === 'function'\n )\n }\n}\n"],"mappings":";;;;;AAyEA,MAAa,qBAAqB,OAAO,IAAI,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACf7D,SAAgB,UAAU,GAAG,QAAmD;CAC9E,QAAQ,QAAgB,gBAAkC;EACxD,MAAM,WAA0B,EAAE,OAAO;EAEzC,IAAI,gBAAgB,KAAA,GAElB,eAAe,oBAAoB,UAAU,QAAQ,WAAW;OAGhE,eAAe,oBAAoB,UAAU,MAAM;CAEvD;AACF;;;;;;;AAQA,SAAgB,oBAAoB,QAA2C;CAC7E,OAAO,YAA2B,oBAAoB,MAAM;AAC9D;;;;;;;;AASA,SAAgB,gBAAgB,QAAgB,aAAyD;CACvG,OAAO,YAA2B,oBAAoB,QAAQ,WAAW;AAC3E;;;;;;;;;AChFA,IAAa,wBAAb,MAAmC;CACJ;CAA7B,YAAY,QAAwC;EAAvB,KAAA,SAAA;CAAyB;;;;;;;;;;CAWtD,MAAM,cACJ,QACA,SACA,WACkB;EAClB,IAAI,OAAO,WAAW,GACpB,OAAO;EAGT,KAAK,OAAO,MAAM,oBAAoB;GACpC,YAAY,OAAO;GACnB,MAAM,QAAQ,EAAE,IAAI;GACpB,QAAQ,QAAQ,EAAE,IAAI;EACxB,CAAC;EAED,KAAK,MAAM,SAAS,QAIlB,IAAI,CAAC,MAHiB,KAAK,aAAa,OAAO,SACT,EAAE,YAAY,OAAO,GAEzC;GAChB,KAAK,OAAO,MAAM,uBAAuB;IAEvC,OAAO,MAAM,aAAa,QAAQ;IAClC,MAAM,QAAQ,EAAE,IAAI;GACtB,CAAC;GACD,OAAO;EACT;EAGF,KAAK,OAAO,MAAM,qBAAqB;GACrC,YAAY,OAAO;GACnB,MAAM,QAAQ,EAAE,IAAI;EACtB,CAAC;EAED,OAAO;CACT;;;;;;;;CASA,aAAqB,OAAc,WAAmC;EAEpE,IAAI,KAAK,gBAAgB,KAAK,GAC5B,OAAO;EAIT,OAAO,UAAU,QAAqB,KAAK;CAC7C;;;;CAKA,gBAAwB,OAAoC;EAC1D,OACE,OAAO,UAAU,YAEjB,UAAU,QACV,iBAAiB,SACjB,OAAO,MAAM,gBAAgB;CAEjC;AACF"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-BBjsoOtd.mjs";
|
|
2
|
+
import { d as inject, n as CONTAINER_TOKEN, r as DI_TOKENS, s as Singleton } from "./di-DseMn-z9.mjs";
|
|
3
|
+
import { r as runWithContainer } from "./container-storage-BmOJ4_Na.mjs";
|
|
4
|
+
import { n as __decorateParam, t as __decorate } from "./decorate-CuAoSZvs.mjs";
|
|
5
|
+
import { LOGGER_TOKENS } from "./logger/index.mjs";
|
|
6
|
+
import { a as RouterContext, l as ROUTER_CONTEXT_KEYS, r as createHttpExceptionContext } from "./exception-context-kEoMFwze.mjs";
|
|
7
|
+
import { o as RouterError } from "./module-registry-Dm-pqHd3.mjs";
|
|
8
|
+
import { t as OpenAPIHono } from "./zod-eKqqhZ5_.mjs";
|
|
9
|
+
import { n as OPENAPI_TOKENS } from "./openapi-tools.service-BC5EC3R3.mjs";
|
|
10
|
+
import "./openapi-CstuTM8S.mjs";
|
|
11
|
+
import { p as createMiddlewareChain, t as RouteRegistrationService, v as SchemaValidationError, y as RouteNotFoundError } from "./route-registration.service-D6vSwiKP.mjs";
|
|
12
|
+
import { t as applyTrailingSlash } from "./trailing-slash-CFyw8nYu.mjs";
|
|
13
|
+
//#region src/router/middleware/logger.middleware.ts
|
|
14
|
+
/**
|
|
15
|
+
* Create a Hono middleware that logs HTTP requests using our Logger service
|
|
16
|
+
*
|
|
17
|
+
* Logs request method, path, status code, and duration in milliseconds.
|
|
18
|
+
* Format: [HTTP] METHOD /path -> STATUS (duration ms)
|
|
19
|
+
*
|
|
20
|
+
* @param logger - Logger service instance
|
|
21
|
+
* @returns Hono middleware handler
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const logger = container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)
|
|
26
|
+
* app.use('*', createLoggerMiddleware(logger))
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
function createLoggerMiddleware(logger) {
|
|
30
|
+
return async (c, next) => {
|
|
31
|
+
const start = Date.now();
|
|
32
|
+
const method = c.req.method;
|
|
33
|
+
const path = c.req.path;
|
|
34
|
+
await next();
|
|
35
|
+
const duration = Date.now() - start;
|
|
36
|
+
const status = c.res.status;
|
|
37
|
+
logger.info(`[HTTP] ${method} ${path} -> ${status}`, {
|
|
38
|
+
method,
|
|
39
|
+
path,
|
|
40
|
+
status,
|
|
41
|
+
duration
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/router/middleware/trailing-slash-redirect.ts
|
|
47
|
+
const REDIRECT_STATUS = 308;
|
|
48
|
+
/**
|
|
49
|
+
* Create a Hono middleware that canonicalises trailing slashes via 308 redirects.
|
|
50
|
+
*
|
|
51
|
+
* - `'ignore'` — returns `null`; routes match both `/foo` and `/foo/` natively
|
|
52
|
+
* (Hono handles this when constructed with `strict: false`).
|
|
53
|
+
* - `'always'` — non-trailing requests redirect to the trailing-slash form.
|
|
54
|
+
* Paths whose last segment contains `.` (e.g. `/api/openapi.json`) are skipped.
|
|
55
|
+
* - `'never'` — trailing requests redirect to the non-trailing form.
|
|
56
|
+
*
|
|
57
|
+
* Root (`/`) is always passed through unchanged.
|
|
58
|
+
*
|
|
59
|
+
* 308 is used so that POST/PUT/PATCH bodies survive the redirect.
|
|
60
|
+
*
|
|
61
|
+
* Location headers are emitted as path-relative URIs so the user agent
|
|
62
|
+
* resolves them against the effective request URI — sidestepping scheme
|
|
63
|
+
* mismatches behind HTTPS-terminating proxies that proxy HTTPS pages to an
|
|
64
|
+
* HTTP-speaking backend (which would otherwise produce a mixed-content block).
|
|
65
|
+
*/
|
|
66
|
+
function createTrailingSlashRedirect(mode) {
|
|
67
|
+
if (mode === "ignore") return null;
|
|
68
|
+
return async (c, next) => {
|
|
69
|
+
const url = new URL(c.req.url);
|
|
70
|
+
const canonicalPath = applyTrailingSlash(url.pathname, mode);
|
|
71
|
+
if (canonicalPath === url.pathname) return next();
|
|
72
|
+
return c.redirect(`${canonicalPath}${url.search}`, REDIRECT_STATUS);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/router/hono-app.ts
|
|
77
|
+
var hono_app_exports = /* @__PURE__ */ __exportAll({ HonoApp: () => HonoApp });
|
|
78
|
+
const isMiddlewareClass = (arg) => typeof arg === "function" && arg.prototype && "handle" in arg.prototype;
|
|
79
|
+
let HonoApp = class HonoApp extends OpenAPIHono {
|
|
80
|
+
configured = false;
|
|
81
|
+
_container;
|
|
82
|
+
_logger;
|
|
83
|
+
/**
|
|
84
|
+
* Reference to the original Hono `use` implementation.
|
|
85
|
+
* Captured in constructor after super() sets it as an instance property.
|
|
86
|
+
* Used by private methods to register middleware without going through the override.
|
|
87
|
+
*/
|
|
88
|
+
nativeUse;
|
|
89
|
+
constructor(container, logger, application) {
|
|
90
|
+
const trailingSlash = application.config.trailingSlash ?? "ignore";
|
|
91
|
+
super({
|
|
92
|
+
strict: false,
|
|
93
|
+
defaultHook: (result) => {
|
|
94
|
+
if (!result.success) throw new SchemaValidationError(result.error);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
this._container = container;
|
|
98
|
+
this._logger = logger;
|
|
99
|
+
this.nativeUse = this.use;
|
|
100
|
+
this.use = ((...args) => {
|
|
101
|
+
if (isMiddlewareClass(args[0])) {
|
|
102
|
+
this.nativeUse("*", createMiddlewareChain(args));
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
if (typeof args[0] === "string" && args.length > 1 && isMiddlewareClass(args[1])) {
|
|
106
|
+
this.nativeUse(args[0], createMiddlewareChain(args.slice(1)));
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
return this.nativeUse(...args);
|
|
110
|
+
});
|
|
111
|
+
const trailingSlashRedirect = createTrailingSlashRedirect(trailingSlash);
|
|
112
|
+
if (trailingSlashRedirect) this.nativeUse("*", trailingSlashRedirect);
|
|
113
|
+
this.setupRequestScope();
|
|
114
|
+
this.applyGlobalMiddleware();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Apply global middleware (logger + error handler).
|
|
118
|
+
* Called by Application after locale middleware is applied by LocalePathService.
|
|
119
|
+
*/
|
|
120
|
+
applyGlobalMiddleware() {
|
|
121
|
+
this.nativeUse("*", createLoggerMiddleware(this._logger));
|
|
122
|
+
this.onError((err, c) => this.handleException(c, err));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Configure OpenAPI endpoints, controller routes, and 404 handler.
|
|
126
|
+
* Called once by Application.initialize().
|
|
127
|
+
*/
|
|
128
|
+
async configure() {
|
|
129
|
+
if (this.configured) throw new RouterError("HonoApp has already been configured");
|
|
130
|
+
this._container.resolve(OPENAPI_TOKENS.OpenAPIService).setupEndpoints(this, this._container);
|
|
131
|
+
await this._container.resolve(RouteRegistrationService).configure();
|
|
132
|
+
this.notFound((c) => {
|
|
133
|
+
throw new RouteNotFoundError(c.req.path, c.req.method);
|
|
134
|
+
});
|
|
135
|
+
this.configured = true;
|
|
136
|
+
}
|
|
137
|
+
setupRequestScope() {
|
|
138
|
+
this.nativeUse("*", async (c, next) => {
|
|
139
|
+
const routerContext = new RouterContext(c);
|
|
140
|
+
const requestContainer = this._container.createRequestScope(routerContext);
|
|
141
|
+
c.set(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER, requestContainer);
|
|
142
|
+
await runWithContainer(requestContainer, next);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
handleException(c, err) {
|
|
146
|
+
const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER) ?? this._container;
|
|
147
|
+
const handler = requestContainer.resolve(DI_TOKENS.ExceptionHandler);
|
|
148
|
+
const ctx = createHttpExceptionContext(c);
|
|
149
|
+
return runWithContainer(requestContainer, () => handler.handle(err, ctx));
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
HonoApp = __decorate([
|
|
153
|
+
Singleton(),
|
|
154
|
+
__decorateParam(0, inject(CONTAINER_TOKEN)),
|
|
155
|
+
__decorateParam(1, inject(LOGGER_TOKENS.LoggerService)),
|
|
156
|
+
__decorateParam(2, inject(DI_TOKENS.Application))
|
|
157
|
+
], HonoApp);
|
|
158
|
+
//#endregion
|
|
159
|
+
export { hono_app_exports as n, HonoApp as t };
|
|
160
|
+
|
|
161
|
+
//# sourceMappingURL=hono-app-CvV3hOfT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono-app-CvV3hOfT.mjs","names":[],"sources":["../src/router/middleware/logger.middleware.ts","../src/router/middleware/trailing-slash-redirect.ts","../src/router/hono-app.ts"],"sourcesContent":["import type { MiddlewareHandler } from 'hono'\nimport type { LoggerService } from '../../logger'\n\n/**\n * Create a Hono middleware that logs HTTP requests using our Logger service\n *\n * Logs request method, path, status code, and duration in milliseconds.\n * Format: [HTTP] METHOD /path -> STATUS (duration ms)\n *\n * @param logger - Logger service instance\n * @returns Hono middleware handler\n *\n * @example\n * ```typescript\n * const logger = container.resolve<LoggerService>(LOGGER_TOKENS.LoggerService)\n * app.use('*', createLoggerMiddleware(logger))\n * ```\n */\nexport function createLoggerMiddleware(logger: LoggerService): MiddlewareHandler {\n return async (c, next) => {\n const start = Date.now()\n const method = c.req.method\n const path = c.req.path\n\n await next()\n\n const duration = Date.now() - start\n const status = c.res.status\n\n logger.info(`[HTTP] ${method} ${path} -> ${status}`, {\n method,\n path,\n status,\n duration,\n })\n }\n}\n","import type { MiddlewareHandler } from 'hono'\nimport { applyTrailingSlash } from '../trailing-slash'\nimport type { RouterEnv, TrailingSlashMode } from '../types'\n\nconst REDIRECT_STATUS = 308\n\n/**\n * Create a Hono middleware that canonicalises trailing slashes via 308 redirects.\n *\n * - `'ignore'` — returns `null`; routes match both `/foo` and `/foo/` natively\n * (Hono handles this when constructed with `strict: false`).\n * - `'always'` — non-trailing requests redirect to the trailing-slash form.\n * Paths whose last segment contains `.` (e.g. `/api/openapi.json`) are skipped.\n * - `'never'` — trailing requests redirect to the non-trailing form.\n *\n * Root (`/`) is always passed through unchanged.\n *\n * 308 is used so that POST/PUT/PATCH bodies survive the redirect.\n *\n * Location headers are emitted as path-relative URIs so the user agent\n * resolves them against the effective request URI — sidestepping scheme\n * mismatches behind HTTPS-terminating proxies that proxy HTTPS pages to an\n * HTTP-speaking backend (which would otherwise produce a mixed-content block).\n */\nexport function createTrailingSlashRedirect(\n mode: TrailingSlashMode,\n): MiddlewareHandler<RouterEnv> | null {\n if (mode === 'ignore') return null\n\n return async (c, next) => {\n const url = new URL(c.req.url)\n const canonicalPath = applyTrailingSlash(url.pathname, mode)\n if (canonicalPath === url.pathname) return next()\n return c.redirect(`${canonicalPath}${url.search}`, REDIRECT_STATUS)\n }\n}\n","import type { Context, MiddlewareHandler } from 'hono'\nimport { inject } from '../di'\nimport type { Application } from '../application'\nimport type { Container } from '../di/container'\nimport { runWithContainer } from '../di/container-storage'\nimport { Singleton } from '../di/decorators'\nimport { CONTAINER_TOKEN, DI_TOKENS } from '../di/tokens'\nimport { createHttpExceptionContext } from '../errors/exception-context'\nimport type { ExceptionHandler } from '../errors/exception-handler'\nimport { OpenAPIHono } from '../i18n/validation/zod'\nimport { LOGGER_TOKENS, type LoggerService } from '../logger'\nimport { OPENAPI_TOKENS, type OpenAPIService } from '../openapi'\nimport type { Constructor } from '../types'\nimport { ROUTER_CONTEXT_KEYS } from './constants'\nimport { RouteNotFoundError, SchemaValidationError } from './errors'\nimport { RouterError } from './router.error'\nimport { createLoggerMiddleware, createMiddlewareChain, createTrailingSlashRedirect } from './middleware'\nimport type { Middleware } from './middleware.interface'\nimport { RouterContext } from './router-context'\nimport { RouteRegistrationService } from './services/route-registration.service'\nimport type { RouterEnv, TrailingSlashMode } from './types'\n\nconst isMiddlewareClass = (arg: unknown): arg is Constructor<Middleware> =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n typeof arg === 'function' && arg.prototype && 'handle' in arg.prototype\n\n\n/**\n * HonoApp — extends OpenAPIHono with Stratal-specific setup\n *\n * - Request scope middleware (child container per request)\n * - Global middleware (CORS, logging, error handling)\n * - defaultHook for validation errors\n * - `use()` overload for Stratal middleware classes\n * - `configure()` for OpenAPI, routes, and 404\n */\n@Singleton()\nexport class HonoApp extends OpenAPIHono<RouterEnv> {\n private configured = false\n private readonly _container: Container\n private readonly _logger: LoggerService\n\n /**\n * Reference to the original Hono `use` implementation.\n * Captured in constructor after super() sets it as an instance property.\n * Used by private methods to register middleware without going through the override.\n */\n private nativeUse!: typeof this.use\n\n constructor(\n @inject(CONTAINER_TOKEN) container: Container,\n @inject(LOGGER_TOKENS.LoggerService) logger: LoggerService,\n @inject(DI_TOKENS.Application) application: Application,\n ) {\n const trailingSlash: TrailingSlashMode = application.config.trailingSlash ?? 'ignore'\n\n super({\n // Always non-strict: a registered `/foo` route matches both `/foo` and `/foo/`.\n // For the redirect modes, the trailing-slash middleware runs first and\n // canonicalises via 308 before matching reaches the registered route.\n strict: false,\n defaultHook: (result) => {\n if (!result.success) {\n throw new SchemaValidationError(result.error)\n }\n },\n })\n\n this._container = container\n this._logger = logger\n\n // Capture Hono's original `use` (set by super() as an instance property)\n this.nativeUse = this.use\n\n // Override `use` to support Stratal middleware classes alongside Hono-native handlers\n this.use = ((...args: unknown[]) => {\n if (isMiddlewareClass(args[0])) {\n this.nativeUse('*', createMiddlewareChain(args as Constructor<Middleware>[]))\n return this\n }\n\n if (typeof args[0] === 'string' && args.length > 1 && isMiddlewareClass(args[1])) {\n this.nativeUse(args[0], createMiddlewareChain(args.slice(1) as Constructor<Middleware>[]))\n return this\n }\n\n return (this.nativeUse as (...a: unknown[]) => unknown)(...args)\n }) as typeof this.use\n\n // Trailing-slash redirect runs first so redirected requests skip request-scope\n // and logger overhead.\n const trailingSlashRedirect = createTrailingSlashRedirect(trailingSlash)\n if (trailingSlashRedirect) {\n this.nativeUse('*', trailingSlashRedirect)\n }\n\n // Internal setup — uses nativeUse to bypass the override\n this.setupRequestScope()\n this.applyGlobalMiddleware()\n }\n\n /**\n * Apply global middleware (logger + error handler).\n * Called by Application after locale middleware is applied by LocalePathService.\n */\n private applyGlobalMiddleware(): void {\n this.nativeUse('*', createLoggerMiddleware(this._logger) as MiddlewareHandler<RouterEnv>)\n this.onError((err, c) => this.handleException(c, err))\n }\n\n /**\n * Configure OpenAPI endpoints, controller routes, and 404 handler.\n * Called once by Application.initialize().\n */\n async configure(): Promise<void> {\n if (this.configured) throw new RouterError('HonoApp has already been configured')\n\n // OpenAPI endpoints\n const openAPIService = this._container.resolve<OpenAPIService>(OPENAPI_TOKENS.OpenAPIService)\n openAPIService.setupEndpoints(this, this._container)\n\n // Controller routes + global middleware\n const routeRegistrationService = this._container.resolve<RouteRegistrationService>(RouteRegistrationService)\n await routeRegistrationService.configure()\n\n // 404 handler (must be last)\n this.notFound((c) => { throw new RouteNotFoundError(c.req.path, c.req.method) })\n\n this.configured = true\n }\n\n private setupRequestScope(): void {\n this.nativeUse('*', async (c: Context<RouterEnv>, next: () => Promise<void>) => {\n const routerContext = new RouterContext(c)\n const requestContainer = this._container.createRequestScope(routerContext)\n c.set(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER, requestContainer)\n\n await runWithContainer(requestContainer, next)\n })\n }\n\n private handleException(c: Context<RouterEnv>, err: unknown) {\n // Fallback to global container if request scope setup failed before storing REQUEST_CONTAINER\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard: REQUEST_CONTAINER may be unset if request scope middleware throws\n const requestContainer = c.get(ROUTER_CONTEXT_KEYS.REQUEST_CONTAINER) ?? this._container\n const handler = requestContainer.resolve<ExceptionHandler>(DI_TOKENS.ExceptionHandler)\n const ctx = createHttpExceptionContext(c)\n // Run the handler within the request container's async context so standalone\n // helpers like `route()` (which read the ambient container via getContainer)\n // resolve correctly. Errors thrown before the request-scope middleware's\n // `runWithContainer` body — e.g. route-param validation failures — otherwise\n // reach here outside any container scope, breaking redirect-back rendering.\n return runWithContainer(requestContainer, () => handler.handle(err, ctx))\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as getMetadata, t as defineMetadata } from "./metadata-
|
|
2
|
-
import { u as ROUTE_METADATA_KEYS } from "./exception-context-
|
|
3
|
-
import { r as z } from "./zod-
|
|
1
|
+
import { n as getMetadata, t as defineMetadata } from "./metadata-DzzprcID.mjs";
|
|
2
|
+
import { u as ROUTE_METADATA_KEYS } from "./exception-context-kEoMFwze.mjs";
|
|
3
|
+
import { r as z } from "./zod-eKqqhZ5_.mjs";
|
|
4
4
|
//#region src/router/decorators/http-method.decorator.ts
|
|
5
5
|
/**
|
|
6
6
|
* Creates an HTTP method decorator factory for the given HTTP method.
|
|
@@ -94,4 +94,4 @@ const All = createHttpMethodDecorator("all");
|
|
|
94
94
|
//#endregion
|
|
95
95
|
export { Post as a, Patch as i, Delete as n, Put as o, Get as r, All as t };
|
|
96
96
|
|
|
97
|
-
//# sourceMappingURL=http-method.decorator-
|
|
97
|
+
//# sourceMappingURL=http-method.decorator-ByWZb9DO.mjs.map
|
package/dist/{http-method.decorator-CdjKFJZZ.mjs.map → http-method.decorator-ByWZb9DO.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-method.decorator-
|
|
1
|
+
{"version":3,"file":"http-method.decorator-ByWZb9DO.mjs","names":[],"sources":["../src/router/decorators/http-method.decorator.ts"],"sourcesContent":["import { defineMetadata, getMetadata } from '../../di/metadata'\nimport { z } from '../../i18n/validation/zod'\nimport { ROUTE_METADATA_KEYS } from '../constants'\nimport type { ExplicitRouteMetadata, HttpMethod, RouteConfig } from '../types'\n\n/**\n * Creates an HTTP method decorator factory for the given HTTP method.\n *\n * The returned decorator stores {@link ExplicitRouteMetadata} on the method and\n * tracks the method name under {@link ROUTE_METADATA_KEYS.DECORATED_METHODS}\n * on the controller prototype so they can be discovered at registration time.\n */\nfunction createHttpMethodDecorator(method: HttpMethod) {\n return function (path: string, config?: RouteConfig) {\n return function (\n target: object,\n propertyKey: string,\n descriptor: PropertyDescriptor\n ) {\n const metadata: ExplicitRouteMetadata = {\n type: 'explicit',\n method,\n path,\n config: config ?? { response: z.any() },\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/**\n * Registers a GET route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (response schema, body, params, etc.)\n *\n * @example\n * ```typescript\n * @Controller('/api/v1/users')\n * class UsersController {\n * @Get('/', { response: z.array(userSchema), summary: 'List users' })\n * async list(ctx: RouterContext) { ... }\n *\n * @Get('/:id', { params: z.object({ id: z.string().uuid() }), response: userSchema })\n * async getUser(ctx: RouterContext) { ... }\n * }\n * ```\n */\nexport const Get = createHttpMethodDecorator('get')\n\n/**\n * Registers a POST route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration (response schema, body, params, etc.)\n *\n * @example\n * ```typescript\n * @Controller('/api/v1/users')\n * class UsersController {\n * @Post('/', { body: createUserSchema, response: userSchema, statusCode: 201 })\n * async createUser(ctx: RouterContext) { ... }\n * }\n * ```\n */\nexport const Post = createHttpMethodDecorator('post')\n\n/**\n * Registers a PUT route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const Put = createHttpMethodDecorator('put')\n\n/**\n * Registers a PATCH route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const Patch = createHttpMethodDecorator('patch')\n\n/**\n * Registers a DELETE route on the controller method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const Delete = createHttpMethodDecorator('delete')\n\n/**\n * Registers an ALL (any HTTP method) route on the controller method.\n * Routes using @All are registered without OpenAPI validation\n * since OpenAPI does not support a catch-all HTTP method.\n *\n * @param path - Route path relative to the controller base path\n * @param config - Optional route configuration\n */\nexport const All = createHttpMethodDecorator('all')\n"],"mappings":";;;;;;;;;;;AAYA,SAAS,0BAA0B,QAAoB;CACrD,OAAO,SAAU,MAAc,QAAsB;EACnD,OAAO,SACL,QACA,aACA,YACA;GACA,MAAM,WAAkC;IACtC,MAAM;IACN;IACA;IACA,QAAQ,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE;GACxC;GAEA,eACE,oBAAoB,cACpB,UACA,QACA,WACF;GAGA,MAAM,WACJ,YAAsB,oBAAoB,mBAAmB,MAAM,KAAK,CAAC;GAC3E,SAAS,KAAK,WAAW;GACzB,eAAe,oBAAoB,mBAAmB,UAAU,MAAM;GAEtE,OAAO;EACT;CACF;AACF;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,MAAM,0BAA0B,KAAK;;;;;;;;;;;;;;;;AAiBlD,MAAa,OAAO,0BAA0B,MAAM;;;;;;;AAQpD,MAAa,MAAM,0BAA0B,KAAK;;;;;;;AAQlD,MAAa,QAAQ,0BAA0B,OAAO;;;;;;;AAQtD,MAAa,SAAS,0BAA0B,QAAQ;;;;;;;;;AAUxD,MAAa,MAAM,0BAA0B,KAAK"}
|
package/dist/i18n/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { _ as
|
|
3
|
-
import { t as index_d_exports } from "../index-
|
|
1
|
+
import { Dr as ApplicationError, In as OnInitialize, Nn as ModuleContext, kn as DynamicModule } from "../index-B_JoEl3V.mjs";
|
|
2
|
+
import { _ as MessageParams, d as AppMessages, f as DeepKeys, g as MessageKeys, h as MessageKeyPrefix, l as AppMessageKeys, m as II18nService, p as FilterByPrefix, u as AppMessageNamespaces, v as Prefixes, y as SystemMessageKeys } from "../zod-wecrEVAs.mjs";
|
|
3
|
+
import { t as index_d_exports } from "../index-HgOLNruQ.mjs";
|
|
4
4
|
import { DetectorOptions } from "hono/language";
|
|
5
5
|
|
|
6
6
|
//#region src/i18n/i18n.error.d.ts
|
|
@@ -234,5 +234,5 @@ declare class MessageLoaderService {
|
|
|
234
234
|
*/
|
|
235
235
|
declare function withI18n(key: MessageKeys, params?: MessageParams): string;
|
|
236
236
|
//#endregion
|
|
237
|
-
export { AppMessageKeys, AppMessageNamespaces, AppMessages, DeepKeys, DetectionStrategy, I18N_TOKENS, I18nError, I18nModule, I18nModuleOptions, II18nService, LanguageDetectionOptions, MessageKeyPrefix, MessageKeys, MessageLoaderService, MessageParams, MessageRegistry, type Messages, Prefixes, ResolvedI18nOptions, SystemMessageKeys, buildDetectorOptions, getLocales, getMessages, messages, resolveI18nOptions, withI18n };
|
|
237
|
+
export { AppMessageKeys, AppMessageNamespaces, AppMessages, DeepKeys, DetectionStrategy, FilterByPrefix, I18N_TOKENS, I18nError, I18nModule, I18nModuleOptions, II18nService, LanguageDetectionOptions, MessageKeyPrefix, MessageKeys, MessageLoaderService, MessageParams, MessageRegistry, type Messages, Prefixes, ResolvedI18nOptions, SystemMessageKeys, buildDetectorOptions, getLocales, getMessages, messages, resolveI18nOptions, withI18n };
|
|
238
238
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/i18n/i18n.error.ts","../../src/i18n/i18n.options.ts","../../src/i18n/i18n.module.ts","../../src/i18n/i18n.tokens.ts","../../src/i18n/messages/index.ts","../../src/i18n/services/message-registry.ts","../../src/i18n/services/message-loader.service.ts","../../src/i18n/with-i18n.ts"],"mappings":";;;;;;cAEa,SAAA,SAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/i18n/i18n.error.ts","../../src/i18n/i18n.options.ts","../../src/i18n/i18n.module.ts","../../src/i18n/i18n.tokens.ts","../../src/i18n/messages/index.ts","../../src/i18n/services/message-registry.ts","../../src/i18n/services/message-loader.service.ts","../../src/i18n/with-i18n.ts"],"mappings":";;;;;;cAEa,SAAA,SAAkB,gBAAgB;;;;;AAAA;;;;ACgB/C;;KAAY,iBAAA;AAAA,UAEF,aAAA;EAFmB;EAI3B,OAAO;AAAA;;;AAAA;AA0BT;;;;;;;;;;;;;;;;;;;;KAAY,wBAAA,IACP,aAAA;EAAkB,QAAA;EAAqB,aAAA,GAAgB,eAAA;AAAA,MACvD,aAAA;EAAkB,QAAA;AAAA,MAClB,aAAA;EAAkB,QAAA;AAAA,MAClB,aAAA;EACD,QAAA;EAwCF;;;;;AAYoC;AAOtC;;;;;EA/CI,mBAAA;AAAA;EAEE,OAAA;AAAA;;;;;AAqDiB;AAOvB;;;;;;;;UA7CiB,iBAAA;EAiED;;;;EA5Dd,aAAA;EA4DiE;;;;EAtDjE,cAAA;EAsDiE;;;AAAuB;EAhDxF,OAAA;;;ACzFF;;ED+FE,SAAA,GAAY,wBAAwB;AAAA;;;;;UAOrB,mBAAA;EACf,aAAA;EACA,cAAA;EACA,OAAA;EACA,SAAA;IACE,OAAA;IACA,QAAA,EAAU,iBAAiB,ECpGhB;IDsGX,mBAAA;EAAA;AAAA;;;;iBAOY,kBAAA,CAAmB,OAAA,GAAU,iBAAA,GAAoB,mBAAmB;;;;iBAoBpE,oBAAA,CAAqB,OAAA,GAAU,iBAAA,GAAoB,OAAA,CAAQ,eAAA;;;cClI9D,UAAA,YAAsB,YAAA;EACjC,YAAA,CAAa,QAAA,EAAU,aAAA;EAAA,OAIhB,OAAA,CAAQ,OAAA,GAAS,iBAAA,GAAyB,aAAA;EAAA,OAS1C,gBAAA,CAAiB,QAAA,EAAU,MAAA,SAAe,MAAA,qBAA2B,aAAA;AAAA;;;;;;;cC1BjE,WAAA;gGHHU;EAAA,8BAAwB;EAAA;;;;;;;;AAAA;cIWlC,QAAA;EAAA,oBAA0B,eAAA;AAAA;AHKvC;;;AAAA,KGAY,QAAA,UAAkB,QAAQ;AHAT;AAA+C;;AAA/C,iBGKb,WAAA,IAAe,MAAM,SAAS,MAAA;;AHDrC;AA0BT;iBGlBgB,UAAA;;;;;;;;;AJ5BhB;;;cK+Ba,eAAA;EL/BkC;;;EAAA,OKmCtC,WAAA,CAAY,QAAA,EAAU,MAAA,SAAe,MAAA;EJnBlC;;;EI4BV,iBAAA,IAAqB,MAAA,SAAe,MAAA;EJ5BT;AAA+C;;;EAA/C,OI+CpB,KAAA;AAAA;;;cCpDI,oBAAA;EAAA,iBAO6C,QAAA;EAAA,iBAErC,OAAA;EAAA,iBARF,KAAA;EAAA,iBACA,aAAA;EAAA,iBACA,OAAA;EAAA,iBACA,aAAA;cAGuC,QAAA,EAAU,eAAA,EAE/C,OAAA,GAAU,iBAAA;EAwB7B,SAAA,CAAU,MAAA,UAAgB,GAAA,UAAa,MAAA,GAAS,MAAA;EAOhD,WAAA,CAAY,MAAA,WAAiB,MAAA;EAI7B,mBAAA;EAIA,iBAAA,CAAkB,MAAA;EAIlB,gBAAA;EAIA,mBAAA,CACE,MAAA,UACA,OAAA;IAAY,IAAA,GAAO,gBAAA;EAAA,IAClB,MAAA;EAAA,QAeK,mBAAA;EAAA,QAmBA,eAAA;AAAA;;;;;;;;ANxGV;;;;AAA+C;;;;ACgB/C;;;;AAA6B;AAA+C;iBMK5D,QAAA,CAAS,GAAA,EAAK,WAAA,EAAa,MAAA,GAAS,aAAa"}
|
package/dist/i18n/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as ApplicationError, n as getContainer } from "../container-storage-
|
|
2
|
-
import "../errors-
|
|
3
|
-
import { t as I18N_TOKENS } from "../i18n.tokens-
|
|
4
|
-
import {
|
|
5
|
-
import { a as
|
|
1
|
+
import { a as ApplicationError, n as getContainer } from "../container-storage-BmOJ4_Na.mjs";
|
|
2
|
+
import "../errors-mXYxG0XB.mjs";
|
|
3
|
+
import { t as I18N_TOKENS } from "../i18n.tokens-CZ_v8oyS.mjs";
|
|
4
|
+
import { i as resolveI18nOptions, r as buildDetectorOptions } from "../locale-path.service-D-dHiIPc.mjs";
|
|
5
|
+
import { a as getLocales, i as MessageLoaderService, o as getMessages, r as MessageRegistry, s as messages, t as I18nModule } from "../i18n.module-DRQAZoSZ.mjs";
|
|
6
6
|
//#region src/i18n/i18n.error.ts
|
|
7
7
|
var I18nError = class extends ApplicationError {};
|
|
8
8
|
//#endregion
|
package/dist/i18n/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/i18n/i18n.error.ts","../../src/i18n/with-i18n.ts"],"sourcesContent":["import { ApplicationError } from '../errors'\n\nexport class I18nError extends ApplicationError {}\n","import { getContainer } from '../di/container-storage'\nimport { I18N_TOKENS } from './i18n.tokens'\nimport type { II18nService, MessageKeys, MessageParams } from './i18n.types'\n\n/**\n * Translate a message key using I18nService from the DI container.\n *\n * Works in both request scope (uses the request's detected locale) and\n * global scope (defaults to 'en'). Can be used anywhere — services,\n * middleware, error handlers, cron jobs, queue consumers, etc.\n *\n * @param key - Message key (e.g., 'common.welcome', 'errors.notFound')\n * @param params - Optional interpolation parameters\n * @returns Translated string, or the key itself if no container is available\n *\n * @example\n * ```typescript\n * import { withI18n } from 'stratal/i18n'\n *\n * const message = withI18n('errors.notFound')\n * const greeting = withI18n('common.welcome', { name: 'Alice' })\n * ```\n */\nexport function withI18n(key: MessageKeys, params?: MessageParams): string {\n try {\n const container = getContainer()\n const i18n = container.resolve<II18nService>(I18N_TOKENS.I18nService)\n return i18n.t(key, params)\n } catch {\n return key\n }\n}\n"],"mappings":";;;;;;AAEA,IAAa,YAAb,cAA+B,iBAAiB;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/i18n/i18n.error.ts","../../src/i18n/with-i18n.ts"],"sourcesContent":["import { ApplicationError } from '../errors'\n\nexport class I18nError extends ApplicationError {}\n","import { getContainer } from '../di/container-storage'\nimport { I18N_TOKENS } from './i18n.tokens'\nimport type { II18nService, MessageKeys, MessageParams } from './i18n.types'\n\n/**\n * Translate a message key using I18nService from the DI container.\n *\n * Works in both request scope (uses the request's detected locale) and\n * global scope (defaults to 'en'). Can be used anywhere — services,\n * middleware, error handlers, cron jobs, queue consumers, etc.\n *\n * @param key - Message key (e.g., 'common.welcome', 'errors.notFound')\n * @param params - Optional interpolation parameters\n * @returns Translated string, or the key itself if no container is available\n *\n * @example\n * ```typescript\n * import { withI18n } from 'stratal/i18n'\n *\n * const message = withI18n('errors.notFound')\n * const greeting = withI18n('common.welcome', { name: 'Alice' })\n * ```\n */\nexport function withI18n(key: MessageKeys, params?: MessageParams): string {\n try {\n const container = getContainer()\n const i18n = container.resolve<II18nService>(I18N_TOKENS.I18nService)\n return i18n.t(key, params)\n } catch {\n return key\n }\n}\n"],"mappings":";;;;;;AAEA,IAAa,YAAb,cAA+B,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;ACqBjD,SAAgB,SAAS,KAAkB,QAAgC;CACzE,IAAI;EAGF,OAFkB,aACG,EAAE,QAAsB,YAAY,WAC/C,EAAE,EAAE,KAAK,MAAM;CAC3B,QAAQ;EACN,OAAO;CACT;AACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as common, i as emails, n as zodI18n, r as validation } from "../../../index-
|
|
1
|
+
import { a as common, i as emails, n as zodI18n, r as validation } from "../../../index-HgOLNruQ.mjs";
|
|
2
2
|
export { common, emails, validation, zodI18n };
|