stratal 0.0.20 → 0.0.22
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/{base-email.provider-CfQCA08m.mjs → base-email.provider-BWZHIjt8.mjs} +1 -1
- package/dist/{base-email.provider-CfQCA08m.mjs.map → base-email.provider-BWZHIjt8.mjs.map} +1 -1
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs +46 -109
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +6 -46
- package/dist/cache/index.d.mts.map +1 -1
- package/dist/cache/index.mjs +22 -67
- package/dist/cache/index.mjs.map +1 -1
- package/dist/{cache.service-DsnKuNyO.d.mts → cache.service-e34gV6tz.d.mts} +8 -8
- package/dist/{cache.service-DsnKuNyO.d.mts.map → cache.service-e34gV6tz.d.mts.map} +1 -1
- package/dist/{cache.tokens-B7Rw1C9Q.mjs → cache.tokens-ovi_c52J.mjs} +1 -1
- package/dist/{cache.tokens-B7Rw1C9Q.mjs.map → cache.tokens-ovi_c52J.mjs.map} +1 -1
- package/dist/{colors-DJaRDXoS.mjs → colors-axmupKdp.mjs} +1 -1
- package/dist/{colors-DJaRDXoS.mjs.map → colors-axmupKdp.mjs.map} +1 -1
- package/dist/{command-BgSlsS4M.mjs → command-BU4ApTo5.mjs} +2 -3
- package/dist/command-BU4ApTo5.mjs.map +1 -0
- package/dist/{command-Bu-PjJrX.d.mts → command-wXfvHbBZ.d.mts} +3 -2
- package/dist/command-wXfvHbBZ.d.mts.map +1 -0
- package/dist/config/index.d.mts +24 -11
- package/dist/config/index.d.mts.map +1 -1
- package/dist/config/index.mjs +33 -57
- package/dist/config/index.mjs.map +1 -1
- package/dist/{consumer-registry-B7yUNh0q.d.mts → consumer-registry-DHQtypr1.d.mts} +1 -1
- package/dist/{consumer-registry-B7yUNh0q.d.mts.map → consumer-registry-DHQtypr1.d.mts.map} +1 -1
- package/dist/container-storage-GpNNz79X.mjs +52 -0
- package/dist/container-storage-GpNNz79X.mjs.map +1 -0
- package/dist/{controller.decorator-DQzenvSN.mjs → controller.decorator-DIUazNU7.mjs} +8 -8
- package/dist/controller.decorator-DIUazNU7.mjs.map +1 -0
- package/dist/cron/index.d.mts +26 -5
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +1 -1
- package/dist/{cron-manager-7Symz_TE.mjs → cron-manager-9bpN9bu4.mjs} +42 -16
- package/dist/cron-manager-9bpN9bu4.mjs.map +1 -0
- package/dist/{cron-manager-BEsH1mjW.d.mts → cron-manager-CSTIBPcM.d.mts} +6 -13
- package/dist/cron-manager-CSTIBPcM.d.mts.map +1 -0
- package/dist/decorate-HgTKAYK8.mjs +16 -0
- package/dist/deep-merge-C8NgcXw4.mjs +18 -0
- package/dist/deep-merge-C8NgcXw4.mjs.map +1 -0
- package/dist/di/index.d.mts +2 -2
- package/dist/di/index.mjs +4 -3
- package/dist/di-BO1QIb5H.mjs +415 -0
- package/dist/di-BO1QIb5H.mjs.map +1 -0
- package/dist/email/index.d.mts +14 -89
- package/dist/email/index.d.mts.map +1 -1
- package/dist/email/index.mjs +30 -125
- package/dist/email/index.mjs.map +1 -1
- package/dist/en-BPP6h6y5.mjs +202 -0
- package/dist/en-BPP6h6y5.mjs.map +1 -0
- package/dist/{env-D1rcZ8_r.d.mts → env-DKSbuBi5.d.mts} +1 -1
- package/dist/env-DKSbuBi5.d.mts.map +1 -0
- package/dist/errors/index.d.mts +2 -2
- package/dist/errors/index.mjs +4 -2
- package/dist/errors-BBZTnjdq.mjs +333 -0
- package/dist/errors-BBZTnjdq.mjs.map +1 -0
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.d.mts.map +1 -1
- package/dist/events/index.mjs +1 -1
- package/dist/{events-COKixqnG.mjs → events-D1KdDaiP.mjs} +13 -11
- package/dist/events-D1KdDaiP.mjs.map +1 -0
- package/dist/exception-context-B4kM-M53.mjs +429 -0
- package/dist/exception-context-B4kM-M53.mjs.map +1 -0
- package/dist/{gateway-context-CdJjpUCW.mjs → gateway-context-CFe6a9gz.mjs} +20 -31
- package/dist/gateway-context-CFe6a9gz.mjs.map +1 -0
- 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-DUk_Kzst.mjs → guards-Ced-uNIF.mjs} +7 -5
- package/dist/guards-Ced-uNIF.mjs.map +1 -0
- package/dist/{http-method.decorator-DXwxAfb_.mjs → http-method.decorator-CdjKFJZZ.mjs} +7 -6
- package/dist/http-method.decorator-CdjKFJZZ.mjs.map +1 -0
- package/dist/i18n/index.d.mts +238 -3
- package/dist/i18n/index.d.mts.map +1 -0
- package/dist/i18n/index.mjs +39 -3
- package/dist/i18n/index.mjs.map +1 -0
- package/dist/i18n/messages/en/index.d.mts +2 -2
- package/dist/i18n/messages/en/index.mjs +2 -2
- package/dist/i18n/utils/index.d.mts +4 -26
- package/dist/i18n/utils/index.d.mts.map +1 -1
- package/dist/i18n/utils/index.mjs +2 -2
- package/dist/i18n/validation/index.d.mts +3 -2
- package/dist/i18n/validation/index.mjs +4 -2
- package/dist/i18n.module-BlXrtAlV.mjs +219 -0
- package/dist/i18n.module-BlXrtAlV.mjs.map +1 -0
- package/dist/i18n.tokens-hwRpmjRq.mjs +19 -0
- package/dist/i18n.tokens-hwRpmjRq.mjs.map +1 -0
- package/dist/{index-7-hU3GTV.d.mts → index-B4UBK-2T.d.mts} +1 -1
- package/dist/{index-7-hU3GTV.d.mts.map → index-B4UBK-2T.d.mts.map} +1 -1
- package/dist/index-BtlE9RuO.d.mts +124 -0
- package/dist/index-BtlE9RuO.d.mts.map +1 -0
- package/dist/{index-CjaQ6_tZ.d.mts → index-CW1YHSft.d.mts} +71 -167
- package/dist/index-CW1YHSft.d.mts.map +1 -0
- package/dist/{index-D0US0X14.d.mts → index-DEncMcC6.d.mts} +559 -2239
- package/dist/index-DEncMcC6.d.mts.map +1 -0
- package/dist/index-Dj5IMwtr.d.mts +44 -0
- package/dist/index-Dj5IMwtr.d.mts.map +1 -0
- package/dist/{index-C1KvMncZ.d.mts → index-KMgSCSM7.d.mts} +3 -108
- package/dist/index-KMgSCSM7.d.mts.map +1 -0
- package/dist/index.d.mts +5 -43
- package/dist/index.mjs +1 -1
- package/dist/{is-command-C6a7WTPw.mjs → is-command-CX5rAfZW.mjs} +2 -2
- package/dist/{is-command-C6a7WTPw.mjs.map → is-command-CX5rAfZW.mjs.map} +1 -1
- package/dist/{is-seeder-CebjZCDn.mjs → is-seeder-CYCtELlm.mjs} +1 -1
- package/dist/{is-seeder-CebjZCDn.mjs.map → is-seeder-CYCtELlm.mjs.map} +1 -1
- package/dist/logger/index.d.mts +2 -2
- package/dist/logger/index.mjs +170 -2
- package/dist/logger/index.mjs.map +1 -0
- package/dist/macroable/index.d.mts +1 -1
- package/dist/macroable/index.mjs +1 -1
- package/dist/{macroable-BmufBshB.mjs → macroable-DzlfzT50.mjs} +1 -1
- package/dist/{macroable-BmufBshB.mjs.map → macroable-DzlfzT50.mjs.map} +1 -1
- package/dist/metadata-BVkc4aUu.mjs +39 -0
- package/dist/metadata-BVkc4aUu.mjs.map +1 -0
- package/dist/module/index.d.mts +6 -24
- package/dist/module/index.d.mts.map +1 -1
- package/dist/module/index.mjs +2 -2
- package/dist/module-xYoHba6B.mjs +422 -0
- package/dist/module-xYoHba6B.mjs.map +1 -0
- package/dist/openapi/index.d.mts +3 -3
- package/dist/openapi/index.d.mts.map +1 -1
- package/dist/openapi/index.mjs +1 -2
- package/dist/openapi-C6lm0RmV.mjs +483 -0
- package/dist/openapi-C6lm0RmV.mjs.map +1 -0
- package/dist/{openapi.service-BLgvn3hJ.d.mts → openapi.service-CrLlsXAd.d.mts} +3 -3
- package/dist/openapi.service-CrLlsXAd.d.mts.map +1 -0
- package/dist/quarry/index.d.mts +5 -163
- package/dist/quarry/index.d.mts.map +1 -1
- package/dist/quarry/index.mjs +5 -5
- package/dist/quarry/runner.d.mts +184 -0
- package/dist/quarry/runner.d.mts.map +1 -0
- package/dist/quarry/runner.mjs +775 -0
- package/dist/quarry/runner.mjs.map +1 -0
- package/dist/quarry-registry-D4hIGScf.d.mts +69 -0
- package/dist/quarry-registry-D4hIGScf.d.mts.map +1 -0
- package/dist/quarry-registry-DkraZNwn.mjs +311 -0
- package/dist/quarry-registry-DkraZNwn.mjs.map +1 -0
- package/dist/queue/index.d.mts +3 -3
- package/dist/queue/index.mjs +27 -28
- package/dist/queue/index.mjs.map +1 -1
- package/dist/{queue.module-BCdCiySt.mjs → queue.module-DeWJ0tQM.mjs} +67 -112
- package/dist/queue.module-DeWJ0tQM.mjs.map +1 -0
- package/dist/{r2-storage.provider-Co6F0ZYV.mjs → r2-storage.provider-Hfm6LdZQ.mjs} +8 -5
- package/dist/r2-storage.provider-Hfm6LdZQ.mjs.map +1 -0
- package/dist/{rate-limit.decorator--o6Q6p9w.mjs → rate-limit.decorator-D69zdZbp.mjs} +6 -11
- package/dist/rate-limit.decorator-D69zdZbp.mjs.map +1 -0
- package/dist/rate-limiter/index.d.mts +11 -50
- package/dist/rate-limiter/index.d.mts.map +1 -1
- package/dist/rate-limiter/index.mjs +25 -30
- package/dist/rate-limiter/index.mjs.map +1 -1
- package/dist/{resend.provider-M6qRLrcy.mjs → resend.provider-Ur6tU7fK.mjs} +8 -7
- package/dist/resend.provider-Ur6tU7fK.mjs.map +1 -0
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +8 -7
- package/dist/{i18n.module-BBlNNlcG.mjs → router-Cy6DjkvP.mjs} +215 -855
- package/dist/router-Cy6DjkvP.mjs.map +1 -0
- package/dist/seeder/index.d.mts +6 -11
- package/dist/seeder/index.d.mts.map +1 -1
- package/dist/seeder/index.mjs +3 -3
- package/dist/{seeder-CJAOHEIo.mjs → seeder-BADTig4n.mjs} +17 -22
- package/dist/seeder-BADTig4n.mjs.map +1 -0
- package/dist/{signed-url-BQPbv2In.mjs → signed-url-BqUqt5dF.mjs} +1 -1
- package/dist/{signed-url-BQPbv2In.mjs.map → signed-url-BqUqt5dF.mjs.map} +1 -1
- package/dist/{smtp.provider-w0Ve52Xg.mjs → smtp.provider-C129sNBT.mjs} +7 -6
- package/dist/smtp.provider-C129sNBT.mjs.map +1 -0
- package/dist/storage/index.d.mts +15 -39
- package/dist/storage/index.d.mts.map +1 -1
- package/dist/storage/index.mjs +3 -3
- package/dist/storage/providers/index.d.mts +2 -2
- package/dist/storage/providers/index.mjs +1 -1
- package/dist/{storage-1zw-6Yiz.mjs → storage-BA3ppVYM.mjs} +70 -59
- package/dist/storage-BA3ppVYM.mjs.map +1 -0
- package/dist/{storage-provider.interface-Bd6vA4ak.d.mts → storage-provider.interface-DQMtT42e.d.mts} +2 -3
- package/dist/storage-provider.interface-DQMtT42e.d.mts.map +1 -0
- package/dist/storage.error-C6FY037a.mjs +8 -0
- package/dist/storage.error-C6FY037a.mjs.map +1 -0
- package/dist/{stratal-DeEcGgdq.mjs → stratal-Bdq4IdB3.mjs} +31 -183
- package/dist/stratal-Bdq4IdB3.mjs.map +1 -0
- package/dist/stratal-BsKmvP6J.d.mts +43 -0
- package/dist/stratal-BsKmvP6J.d.mts.map +1 -0
- package/dist/{types-cySNS_lp.d.mts → types-BaeHi67f.d.mts} +1 -1
- package/dist/types-BaeHi67f.d.mts.map +1 -0
- package/dist/{usage-generator-BUdlhnCK.mjs → usage-generator-DTqaUMR9.mjs} +6 -3
- package/dist/usage-generator-DTqaUMR9.mjs.map +1 -0
- package/dist/validation-DUzcjb8Q.mjs +49 -0
- package/dist/validation-DUzcjb8Q.mjs.map +1 -0
- package/dist/validation.context-XTysWJ3b.mjs +117 -0
- package/dist/validation.context-XTysWJ3b.mjs.map +1 -0
- package/dist/websocket/index.d.mts +7 -14
- package/dist/websocket/index.d.mts.map +1 -1
- package/dist/websocket/index.mjs +2 -2
- package/dist/workers/index.d.mts +2 -2
- package/dist/workers/index.mjs +3 -2
- package/dist/workers/index.mjs.map +1 -1
- package/dist/{index-Bnpfq6uk.d.mts → zod-DvWTfRpI.d.mts} +58 -133
- package/dist/zod-DvWTfRpI.d.mts.map +1 -0
- package/dist/zod-hMa3rSHV.mjs +72 -0
- package/dist/zod-hMa3rSHV.mjs.map +1 -0
- package/package.json +20 -20
- package/dist/command-BgSlsS4M.mjs.map +0 -1
- package/dist/command-Bu-PjJrX.d.mts.map +0 -1
- package/dist/controller.decorator-DQzenvSN.mjs.map +0 -1
- package/dist/cron-manager-7Symz_TE.mjs.map +0 -1
- package/dist/cron-manager-BEsH1mjW.d.mts.map +0 -1
- package/dist/en-DSH_bhh6.mjs +0 -308
- package/dist/en-DSH_bhh6.mjs.map +0 -1
- package/dist/env-D1rcZ8_r.d.mts.map +0 -1
- package/dist/errors-BdyV5PnY.mjs +0 -1725
- package/dist/errors-BdyV5PnY.mjs.map +0 -1
- package/dist/errors-Da3Pz2X7.mjs +0 -74
- package/dist/errors-Da3Pz2X7.mjs.map +0 -1
- package/dist/events-COKixqnG.mjs.map +0 -1
- package/dist/gateway-context-CdJjpUCW.mjs.map +0 -1
- package/dist/guards-DUk_Kzst.mjs.map +0 -1
- package/dist/http-method.decorator-DXwxAfb_.mjs.map +0 -1
- package/dist/i18n.module-BBlNNlcG.mjs.map +0 -1
- package/dist/index-Bnpfq6uk.d.mts.map +0 -1
- package/dist/index-C1KvMncZ.d.mts.map +0 -1
- package/dist/index-CjaQ6_tZ.d.mts.map +0 -1
- package/dist/index-D0US0X14.d.mts.map +0 -1
- package/dist/index-DBd_2wv8.d.mts +0 -263
- package/dist/index-DBd_2wv8.d.mts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/logger-V6Ms3QnQ.mjs +0 -436
- package/dist/logger-V6Ms3QnQ.mjs.map +0 -1
- package/dist/module-Dk2qTa77.mjs +0 -860
- package/dist/module-Dk2qTa77.mjs.map +0 -1
- package/dist/openapi-tools.service-Zs-Ewv7F.mjs +0 -200
- package/dist/openapi-tools.service-Zs-Ewv7F.mjs.map +0 -1
- package/dist/openapi.service-BLgvn3hJ.d.mts.map +0 -1
- package/dist/quarry-registry-DNEej-Db.mjs +0 -688
- package/dist/quarry-registry-DNEej-Db.mjs.map +0 -1
- package/dist/queue.module-BCdCiySt.mjs.map +0 -1
- package/dist/r2-storage.provider-Co6F0ZYV.mjs.map +0 -1
- package/dist/rate-limit.decorator--o6Q6p9w.mjs.map +0 -1
- package/dist/resend.provider-M6qRLrcy.mjs.map +0 -1
- package/dist/seeder-CJAOHEIo.mjs.map +0 -1
- package/dist/setup-CefZKV_e.mjs +0 -37
- package/dist/setup-CefZKV_e.mjs.map +0 -1
- package/dist/smtp.provider-w0Ve52Xg.mjs.map +0 -1
- package/dist/storage-1zw-6Yiz.mjs.map +0 -1
- package/dist/storage-provider.interface-Bd6vA4ak.d.mts.map +0 -1
- package/dist/stratal-DeEcGgdq.mjs.map +0 -1
- package/dist/types-cySNS_lp.d.mts.map +0 -1
- package/dist/usage-generator-BUdlhnCK.mjs.map +0 -1
- package/dist/validation-DtJwAv7O.mjs +0 -248
- package/dist/validation-DtJwAv7O.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"module-Dk2qTa77.mjs","names":["internal.getDefaultEntry","internal.getGroups","internal.getGlobalMiddleware"],"sources":["../src/module/errors/invalid-module-provider.error.ts","../src/module/module.decorator.ts","../src/rate-limiter/errors.ts","../src/rate-limiter/rate-limiter.tokens.ts","../src/rate-limiter/throttle.middleware.ts","../src/router/errors/controller-method-not-found.error.ts","../src/router/errors/controller-registration.error.ts","../src/router/errors/hono-app-already-configured.error.ts","../src/router/errors/openapi-route-registration.error.ts","../src/router/errors/openapi-validation.error.ts","../src/router/errors/route-not-found.error.ts","../src/router/errors/schema-validation.error.ts","../src/router/errors/index.ts","../src/router/router.internals.ts","../src/router/router.ts","../src/module/module-registry.ts"],"sourcesContent":["import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * InvalidModuleProviderError\n *\n * Thrown when a module provider configuration is invalid.\n * This indicates a misconfiguration in the @Module decorator providers array.\n */\nexport class InvalidModuleProviderError extends ApplicationError {\n constructor(provider: unknown) {\n super(\n 'errors.invalidModuleProvider',\n ERROR_CODES.SYSTEM.INVALID_MODULE_PROVIDER,\n { provider: JSON.stringify(provider) }\n )\n }\n}\n","/**\n * Module Decorator\n *\n * NestJS-style @Module decorator for defining modules with providers, controllers, etc.\n * Encapsulates tsyringe's @registry decorator for auto-registration.\n */\n\nimport type { DependencyContainer, Provider as TsyringeProvider } from 'tsyringe'\nimport { instancePerContainerCachingFactory, type Lifecycle, registry } from 'tsyringe'\nimport type InjectionToken from 'tsyringe/dist/typings/providers/injection-token'\nimport type RegistrationOptions from 'tsyringe/dist/typings/types/registration-options'\nimport type { Constructor } from '../types'\nimport { InvalidModuleProviderError } from './errors'\nimport type { ModuleOptions, Provider } from './types'\n\nexport const MODULE_OPTIONS_KEY = Symbol.for('stratal:module:options')\n\n/**\n * Tsyringe registry entry format\n */\ntype RegistryEntry = {\n token: InjectionToken\n options?: RegistrationOptions\n} & TsyringeProvider\n\n/**\n * `@Module` decorator - defines a module with imports, providers, controllers, consumers, jobs\n *\n * Uses tsyringe's `@registry` internally to auto-register providers when module is imported.\n *\n * @example\n * ```typescript\n * @Module({\n * imports: [OtherModule],\n * providers: [MyService, MyRepository],\n * controllers: [MyController],\n * })\n * export class MyModule {}\n * ```\n */\nexport function Module(options: ModuleOptions) {\n return <TFunction extends abstract new (...args: never[]) => unknown>(target: TFunction): TFunction => {\n // Store module options for runtime access\n Reflect.defineMetadata(MODULE_OPTIONS_KEY, options, target)\n\n // Build tsyringe registry entries from providers\n const registryEntries = buildRegistryEntries(options.providers ?? [])\n\n // Apply tsyringe @registry decorator (encapsulated)\n if (registryEntries.length > 0) {\n registry(registryEntries)(target)\n }\n\n return target\n }\n}\n\n/**\n * Get module options from decorated class\n */\nexport function getModuleOptions(target: Constructor): ModuleOptions | undefined {\n return Reflect.getMetadata(MODULE_OPTIONS_KEY, target) as ModuleOptions | undefined\n}\n\n/**\n * Check if a class is decorated with `@Module`\n */\nexport function isModuleClass(target: unknown): target is Constructor {\n return (\n typeof target === 'function' &&\n Reflect.hasMetadata(MODULE_OPTIONS_KEY, target)\n )\n}\n\n/**\n * Convert our Provider types to tsyringe registry format\n *\n * Maps provider scope to tsyringe's lifecycle option.\n * Scope enum values map directly to Lifecycle enum values.\n */\nfunction buildRegistryEntries(providers: Provider[]): RegistryEntry[] {\n return providers.map((provider): RegistryEntry => {\n // Class-only provider - transient by default\n if (typeof provider === 'function') {\n return {\n token: provider as InjectionToken,\n useClass: provider,\n }\n }\n\n // ClassProvider with optional scope\n if ('useClass' in provider) {\n return {\n token: provider.provide as InjectionToken,\n useClass: provider.useClass,\n options: provider.scope !== undefined\n ? { lifecycle: provider.scope as unknown as Lifecycle }\n : undefined,\n }\n }\n\n // ValueProvider - no scope needed (values are inherently singleton)\n if ('useValue' in provider) {\n return {\n token: provider.provide as InjectionToken,\n useValue: provider.useValue,\n }\n }\n\n // FactoryProvider - use instancePerContainerCachingFactory to:\n // 1. Get the actual container at resolution time (global vs request)\n // 2. Cache result per container\n if ('useFactory' in provider) {\n const { provide, useFactory, inject = [] } = provider\n return {\n token: provide as InjectionToken,\n useFactory: instancePerContainerCachingFactory((dependencyContainer: DependencyContainer): object => {\n const deps = inject.map((token) => dependencyContainer.resolve(token))\n return useFactory(...deps) as object\n }),\n }\n }\n\n // ExistingProvider - alias to another token (uses tsyringe's useToken)\n if ('useExisting' in provider) {\n return {\n token: provider.provide as InjectionToken,\n useToken: provider.useExisting as InjectionToken,\n }\n }\n\n // Fallback (should not reach here with proper types)\n throw new InvalidModuleProviderError(provider)\n })\n}\n","// eslint-disable-next-line @typescript-eslint/no-deprecated -- ApplicationError remains the canonical base for non-HTTP errors that need i18n metadata interpolation; matches MissingEnvironmentVariableError pattern.\nimport { ApplicationError, ERROR_CODES, HttpException } from '../errors'\n\n/**\n * Thrown when a request exceeds a configured rate limit.\n *\n * HTTP Status: 429 Too Many Requests\n * Error Code: 4290\n *\n * The {@link ExceptionHandler} renders the body via content negotiation\n * (HTML for HTML clients, JSON for everything else). Standard rate-limit\n * headers (`Retry-After`, `X-RateLimit-*`) are injected by the\n * `respond()` callback registered via `RateLimiterModule.onException`.\n */\nexport class TooManyRequestsError extends HttpException {\n constructor(\n public readonly info: { retryAfter: number; limit: number; resetAt: number },\n ) {\n super(429, 'errors.rateLimit.tooManyRequests')\n }\n}\n\n/**\n * Thrown when `RateLimiterRegistry.handle(name, ...)` is invoked for a\n * name that was never registered via `.for()`.\n *\n * Most likely cause: a typo in `router.throttle('foo')` or `@RateLimit('foo')`,\n * or the module that registers the limiter is missing from imports.\n */\n// eslint-disable-next-line @typescript-eslint/no-deprecated -- needs metadata interpolation\nexport class RateLimiterNotDefinedError extends ApplicationError {\n constructor(public readonly limiterName: string) {\n super(\n 'errors.rateLimit.notDefined',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR,\n { name: limiterName },\n )\n }\n}\n\n/**\n * Thrown by `RateLimiterStoreFactory.create()` (during the module's eager\n * `onInitialize` validation) when the user imported `RateLimiterModule`\n * without calling `.forRoot({ store: ... })`. There is no implicit default\n * store — the user must pick one.\n */\nexport class RateLimiterNotConfiguredError extends HttpException {\n constructor() {\n super(500, 'errors.rateLimit.notConfigured')\n }\n}\n\n/**\n * Thrown when a throttled route fires but `RateLimiterModule` was never\n * imported in the user's AppModule (so the registry token is unbound).\n *\n * Distinct from {@link RateLimiterNotConfiguredError}, which fires when\n * the module IS imported but `forRoot` was not called.\n */\n// eslint-disable-next-line @typescript-eslint/no-deprecated -- needs metadata interpolation\nexport class RateLimiterModuleNotImportedError extends ApplicationError {\n constructor(public readonly limiterName: string) {\n super(\n 'errors.rateLimit.moduleNotImported',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR,\n { name: limiterName },\n )\n }\n}\n\n","export const RATE_LIMITER_TOKENS = {\n Registry: Symbol.for('stratal:rate-limiter:registry'),\n Store: Symbol.for('stratal:rate-limiter:store'),\n StoreFactory: Symbol.for('stratal:rate-limiter:store-factory'),\n Options: Symbol.for('stratal:rate-limiter:options'),\n /**\n * Per-app marker registered by RateLimiterModule.onInitialize. Used by\n * ThrottleMiddleware to detect \"module not imported\" — the @Module\n * decorator globally registers providers via tsyringe's registry(),\n * so the Registry/Store tokens are globally bound the moment the module\n * file is loaded. The only way to confirm the module was actually wired\n * into the *user's* AppModule is to look for an artifact registered\n * inside the user's app container (not the root container).\n */\n ModuleMarker: Symbol.for('stratal:rate-limiter:module-marker'),\n} as const\n\nexport type RateLimiterToken = (typeof RATE_LIMITER_TOKENS)[keyof typeof RATE_LIMITER_TOKENS]\n","import { inject } from 'tsyringe'\nimport { CONTAINER_TOKEN, type Container } from '../di'\nimport { Transient } from '../di/decorators'\nimport type { Middleware, Next } from '../router/middleware.interface'\nimport type { RouterContext } from '../router/router-context'\nimport type { Constructor } from '../types'\nimport { RateLimiterModuleNotImportedError } from './errors'\nimport type { RateLimiterRegistry } from './rate-limiter-registry'\nimport { RATE_LIMITER_TOKENS } from './rate-limiter.tokens'\n\nconst cache = new Map<string, Constructor<Middleware>>()\n\n/**\n * Memoized factory that produces a Stratal `Middleware` class bound to a\n * named limiter. Calling twice with the same name returns the *same* class\n * — important for `Router.middleware` deduplication via class identity.\n *\n * Detection of \"module not imported\" works against a per-app marker\n * registered by `RateLimiterModule.onInitialize` (NOT via inject decorator,\n * because tsyringe would still try to construct Registry — whose Store\n * inject would explode with a less-actionable tsyringe wrapping). We hold\n * the user's container, then check `isRegistered(marker, recursive=true)`\n * at request time before resolving Registry.\n */\nexport function createThrottleMiddleware(name: string): Constructor<Middleware> {\n const existing = cache.get(name)\n if (existing) return existing\n\n @Transient()\n class ThrottleMiddleware implements Middleware {\n constructor(\n @inject(CONTAINER_TOKEN) private readonly container: Container,\n ) {}\n\n handle(ctx: RouterContext, next: Next): Promise<Response | void> {\n // Walk the parent chain — marker lives in the app container, not the\n // request-scoped child. `isRegistered(token, true)` is recursive.\n const tsyringe = this.container.getTsyringeContainer()\n if (!tsyringe.isRegistered(RATE_LIMITER_TOKENS.ModuleMarker, true)) {\n throw new RateLimiterModuleNotImportedError(name)\n }\n const registry = this.container.resolve<RateLimiterRegistry>(RATE_LIMITER_TOKENS.Registry)\n return registry.handle(name, ctx, next)\n }\n }\n\n Object.defineProperty(ThrottleMiddleware, 'name', { value: `Throttle(${name})` })\n cache.set(name, ThrottleMiddleware)\n return ThrottleMiddleware\n}\n\n/**\n * Test-only escape hatch: clear the per-name middleware class cache.\n * Production code never needs this.\n */\nexport function _resetThrottleMiddlewareCache(): void {\n cache.clear()\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * ControllerMethodNotFoundError\n *\n * Thrown when a controller method is registered but doesn't exist on the controller instance.\n * This typically indicates a mismatch between route registration and controller implementation.\n */\nexport class ControllerMethodNotFoundError extends ApplicationError {\n constructor(methodName: string, controllerName: string) {\n super(\n 'errors.controllerMethodNotFound',\n ERROR_CODES.ROUTER.CONTROLLER_METHOD_NOT_FOUND,\n { methodName, controllerName }\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * Error thrown when a controller fails to register\n *\n * This typically happens when:\n * - Controller is missing the `@Controller` decorator\n * - Controller route metadata is not set\n * - Controller class name is invalid\n *\n * Error Code: 9005\n */\nexport class ControllerRegistrationError extends ApplicationError {\n constructor(controllerName: string, reason?: string) {\n super('errors.controllerRegistration', ERROR_CODES.ROUTER.CONTROLLER_REGISTRATION_ERROR, {\n controllerName,\n reason,\n })\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * Error thrown when HonoApp.configure() is called more than once.\n *\n * HonoApp can only be configured a single time during application bootstrap.\n */\nexport class HonoAppAlreadyConfiguredError extends ApplicationError {\n constructor() {\n super(\n 'errors.honoAppAlreadyConfigured',\n ERROR_CODES.SYSTEM.CONFIGURATION_ERROR\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * OpenAPIRouteRegistrationError\n *\n * Thrown when an OpenAPI route fails to register properly\n * This indicates a configuration issue with route decorators or metadata\n * Uses i18n key for localized error messages\n *\n * @example\n * ```typescript\n * throw new OpenAPIRouteRegistrationError('/api/v1/users', 'Missing response schema')\n * ```\n */\nexport class OpenAPIRouteRegistrationError extends ApplicationError {\n constructor(path: string, reason: string) {\n super(\n 'errors.openapiRouteRegistration',\n ERROR_CODES.ROUTER.OPENAPI_ROUTE_REGISTRATION,\n { path, reason }\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * OpenAPIValidationError\n *\n * Thrown when OpenAPI request/response validation fails\n * Uses i18n key for localized error messages\n *\n * HTTP Status: 400 Bad Request\n * Error Code: 1004\n *\n * @example\n * ```typescript\n * throw new OpenAPIValidationError('Request body missing required field: email')\n * ```\n */\nexport class OpenAPIValidationError extends ApplicationError {\n constructor(details: string) {\n super(\n 'errors.openapiValidation',\n ERROR_CODES.VALIDATION.REQUEST_VALIDATION,\n { details }\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors'\n\n/**\n * Error thrown when a requested route is not found\n *\n * HTTP Status: 404 Not Found\n * Error Code: 4004\n */\nexport class RouteNotFoundError extends ApplicationError {\n constructor(path: string, method: string) {\n super(\n 'errors.routeNotFound',\n ERROR_CODES.RESOURCE.ROUTE_NOT_FOUND,\n { path, method }\n )\n }\n}\n","import { ApplicationError, ERROR_CODES } from '../../errors';\nimport type { ZodError } from '../../i18n/validation';\nimport { type z } from '../../i18n/validation';\n/**\n * SchemaValidationError\n *\n * Thrown when Zod schema validation fails\n */\nexport class SchemaValidationError extends ApplicationError {\n constructor(zodError: ZodError) {\n const issues = zodError.issues.map((err: z.core.$ZodIssue) => ({\n path: err.path.join('.'),\n message: err.message,\n code: err.code\n }))\n\n super(\n 'errors.schemaValidation',\n ERROR_CODES.VALIDATION.SCHEMA_VALIDATION,\n { issues }\n )\n }\n}\n","import { ApplicationError, ERROR_CODES, HttpException } from '../../errors'\nimport { type z, type ZodError } from '../../i18n/validation'\n\nexport { ControllerMethodNotFoundError } from './controller-method-not-found.error'\n\nexport { ControllerRegistrationError } from './controller-registration.error'\n\n/**\n * Error thrown when a request's host header does not match the expected domain pattern.\n *\n * HTTP Status: 404 Not Found\n */\nexport class DomainMismatchError extends HttpException {\n constructor() {\n super(404, 'errors.domainMismatch')\n }\n}\n\n/**\n * Thrown when registering a named route that conflicts with an existing route name.\n *\n * Error Code: 9010\n */\nexport class DuplicateRouteNameError extends ApplicationError {\n constructor(name: string, existingHandler: string, newHandler: string) {\n super('errors.duplicateRouteName', ERROR_CODES.ROUTER.DUPLICATE_ROUTE_NAME, {\n name,\n existingHandler,\n newHandler,\n })\n }\n}\n\nexport { HonoAppAlreadyConfiguredError } from './hono-app-already-configured.error'\n\n/**\n * Error thrown when a signed URL has an invalid or expired signature.\n *\n * HTTP Status: 403 Forbidden\n */\nexport class InvalidSignatureError extends HttpException {\n constructor() {\n super(403, 'errors.invalidSignature')\n }\n}\n\n/**\n * Thrown when a required environment variable is not set.\n *\n * Maps to HTTP 500 via error code range (9xxx → 500).\n */\nexport class MissingEnvironmentVariableError extends ApplicationError {\n constructor(variable: string) {\n super('errors.missingEnvironmentVariable', ERROR_CODES.SYSTEM.MISSING_ENVIRONMENT_VARIABLE, {\n variable,\n })\n }\n}\n\n/**\n * Thrown when a required path or domain parameter is missing during URL generation.\n *\n * Error Code: 9012\n */\nexport class MissingRouteParamError extends ApplicationError {\n constructor(param: string, name: string, path: string) {\n super('errors.missingRouteParam', ERROR_CODES.ROUTER.MISSING_ROUTE_PARAM, {\n param,\n name,\n path,\n })\n }\n}\n\nexport { OpenAPIRouteRegistrationError } from './openapi-route-registration.error'\nexport { OpenAPIValidationError } from './openapi-validation.error'\n\n/**\n * ResponseValidationError\n *\n * Thrown when a controller's response body does not match the declared Zod response schema.\n * Indicates a server-side schema mismatch — the controller is returning data that\n * violates its own API contract.\n */\nexport class ResponseValidationError extends ApplicationError {\n constructor(zodError: ZodError) {\n const issues = zodError.issues.map((err: z.core.$ZodIssue) => ({\n path: err.path.join('.'),\n message: err.message,\n code: err.code,\n }))\n\n super(\n 'errors.responseValidation',\n ERROR_CODES.VALIDATION.RESPONSE_VALIDATION,\n { issues }\n )\n }\n}\n\n/**\n * Thrown when attempting to generate a URL for a route name that doesn't exist in the registry.\n *\n * Error Code: 9011\n */\nexport class RouteNameNotFoundError extends ApplicationError {\n constructor(name: string) {\n super('errors.routeNameNotFound', ERROR_CODES.ROUTER.ROUTE_NAME_NOT_FOUND, {\n name,\n })\n }\n}\n\nexport { RouteNotFoundError } from './route-not-found.error'\n\n/**\n * Thrown when `router.use()` is called inside a `group()` callback.\n * `use()` registers global middleware and is only allowed on the root Router.\n *\n * Error Code: 9013\n */\nexport class RouterUseScopeError extends ApplicationError {\n constructor() {\n super('errors.routerUseScopeViolation', ERROR_CODES.ROUTER.USE_SCOPE_VIOLATION)\n }\n}\n\n/**\n * Thrown when a middleware calls next() more than once.\n * This is a programming error — each middleware must call next() at most once.\n *\n * Error Code: 9014\n */\nexport class MiddlewareNextCalledMultipleTimesError extends ApplicationError {\n constructor(middlewareName: string) {\n super('errors.middlewareNextCalledMultipleTimes', ERROR_CODES.ROUTER.MIDDLEWARE_NEXT_CALLED_MULTIPLE_TIMES, {\n middlewareName,\n })\n }\n}\n\nexport { SchemaValidationError } from './schema-validation.error'\n","/**\n * Symbol keys for Router internal accessors.\n *\n * These symbols are NOT exported from the public `stratal/router` barrel.\n * Only internal modules (RouterResolver) import them, keeping the Router's\n * public API clean — users never see these methods.\n *\n * Declared as individual unique symbols so TypeScript can distinguish\n * their return types in computed property access.\n *\n * @internal\n */\n\n/** @internal */\nexport const getDefaultEntry: unique symbol = Symbol('Router.getDefaultEntry')\n/** @internal */\nexport const getGroups: unique symbol = Symbol('Router.getGroups')\n/** @internal */\nexport const getGlobalMiddleware: unique symbol = Symbol('Router.getGlobalMiddleware')\n","import type { ZodObject } from '../i18n/validation'\nimport { createThrottleMiddleware } from '../rate-limiter/throttle.middleware'\nimport type { Constructor } from '../types'\nimport { RouterUseScopeError } from './errors'\nimport type { Middleware } from './middleware.interface'\nimport * as internal from './router.internals'\n\n/**\n * Configuration for a sub-group created via `router.group()`.\n */\nexport interface RouterGroupConfig {\n prefix?: string\n domain?: string\n name?: string\n middleware?: Constructor<Middleware>[]\n version?: string | string[]\n hideFromDocs?: boolean\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ZodObject generics require any for flexible shape parameter\n params?: ZodObject<any>\n}\n\n/**\n * Internal entry representing a sub-group or the default scope.\n * @internal — used by RouterResolver, not exported publicly.\n */\nexport interface RouterEntry {\n prefix?: string\n domain?: string\n name?: string\n middleware: Constructor<Middleware>[]\n version?: string | string[]\n hideFromDocs?: boolean\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ZodObject generics require any for flexible shape parameter\n params?: ZodObject<any>\n /** Controllers in this entry. undefined = all controllers not in any sub-group */\n controllers?: Constructor[]\n}\n\n/**\n * Modules implement this to configure routes and middleware.\n * Replaces `MiddlewareConfigurable`.\n *\n * @example\n * ```typescript\n * @Module({ controllers: [UsersController, PostsController] })\n * export class ApiModule implements RouteConfigurable {\n * configureRoutes(router: Router): void {\n * router\n * .name('api.')\n * .middleware(CorsMiddleware)\n * .version('1')\n * }\n * }\n * ```\n */\nexport interface RouteConfigurable {\n configureRoutes(router: Router): void\n}\n\n/**\n * Fluent builder for route and middleware configuration.\n *\n * Scoped methods (`middleware()`, `prefix()`, `domain()`, `name()`, `version()`, `hideFromDocs()`)\n * apply only to this module's controllers or the sub-group's controllers.\n *\n * `use()` registers global middleware (all routes in the entire app).\n * Only callable on the root Router — throws inside `group()` callbacks.\n *\n * `group()` creates sub-groups for specific controllers with a callback.\n * Controllers in a sub-group are excluded from the parent scope.\n */\nexport class Router {\n private readonly _isChild: boolean\n private readonly _defaultEntry: RouterEntry = { middleware: [] }\n private readonly _groups: RouterEntry[] = []\n private readonly _globalMiddleware: Constructor<Middleware>[] = []\n\n constructor(isChild = false) {\n this._isChild = isChild\n }\n\n /** Dynamic path prefix. For shared segments like `/:companyId` */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ZodObject generics require any for flexible shape parameter\n prefix(path: string, params?: ZodObject<any>): this {\n this._defaultEntry.prefix = path\n this._defaultEntry.params = params\n return this\n }\n\n /** Domain pattern for controllers in this scope */\n domain(pattern: string): this {\n this._defaultEntry.domain = pattern\n return this\n }\n\n /** Name prefix for routes in this scope */\n name(prefix: string): this {\n this._defaultEntry.name = prefix\n return this\n }\n\n /** Middleware applied to controllers in this scope */\n middleware(...middlewares: Constructor<Middleware>[]): this {\n this._defaultEntry.middleware.push(...middlewares)\n return this\n }\n\n /**\n * Apply a named rate limiter to controllers in this scope.\n *\n * The named limiter must be registered via `RateLimiterRegistry.for(name, ...)`\n * (typically inside a module's `onInitialize` hook), and the user must\n * import `RateLimiterModule.forRoot({ store: ... })` in their AppModule.\n *\n * @example\n * ```typescript\n * router.prefix('/uploads').throttle('uploads')\n * router.group([AdminController], (admin) => admin.throttle('admin'))\n * ```\n */\n throttle(name: string): this {\n this._defaultEntry.middleware.push(createThrottleMiddleware(name))\n return this\n }\n\n /** API version for controllers in this scope */\n version(version: string | string[]): this {\n this._defaultEntry.version = version\n return this\n }\n\n /** Hide/show routes in this scope from OpenAPI docs */\n hideFromDocs(hide = true): this {\n this._defaultEntry.hideFromDocs = hide\n return this\n }\n\n /**\n * Global middleware — applied to ALL routes in the entire app.\n * Only callable on the root Router. Throws if called inside `group()`.\n */\n use(...middlewares: Constructor<Middleware>[]): this {\n if (this._isChild) {\n throw new RouterUseScopeError()\n }\n this._globalMiddleware.push(...middlewares)\n return this\n }\n\n /**\n * Create a sub-group for specific controllers/gateways.\n * Controllers in a sub-group are excluded from the parent (default) scope.\n * The callback receives a new Router (without `use()`) for fluent configuration.\n */\n group(controllers: Constructor[], callback: (router: Omit<Router, 'use'>) => void): this {\n const childRouter = new Router(true)\n callback(childRouter)\n\n this._groups.push({\n ...childRouter._defaultEntry,\n controllers,\n })\n return this\n }\n\n // --- Internal accessors via symbol keys (invisible to consumers) ---\n\n [internal.getDefaultEntry](): RouterEntry {\n return this._defaultEntry\n }\n\n [internal.getGroups](): RouterEntry[] {\n return this._groups\n }\n\n [internal.getGlobalMiddleware](): Constructor<Middleware>[] {\n return this._globalMiddleware\n }\n}\n","/**\n * Module Registry\n *\n * Manages module lifecycle for the @Module decorator pattern.\n * Simplified for tsyringe's flat container model:\n * - Imports are traversed for registration (organization only)\n * - Modules registered in declaration order\n * - Lifecycle hooks: onInitialize, onShutdown\n */\n\nimport { injectable, instancePerContainerCachingFactory } from 'tsyringe'\nimport type { Container } from '../di/container'\nimport { Scope } from '../di/types'\nimport { isListener } from '../events'\nimport type { LoggerService } from '../logger'\nimport { Router, type RouteConfigurable } from '../router/router'\nimport { isCommand } from '../quarry/is-command'\nimport { isSeeder } from '../seeder/is-seeder'\nimport type { Constructor } from '../types'\nimport { getModuleOptions } from './module.decorator'\nimport type { ExceptionHandler } from '../errors/exception-handler'\nimport type {\n DynamicModule,\n ModuleClass,\n ModuleContext,\n ModuleOptions,\n OnException,\n OnInitialize,\n OnShutdown,\n Provider,\n} from './types'\n\n\ninterface RegisteredModule {\n moduleClass: Constructor\n options: ModuleOptions\n instance: object | null\n}\n\n/**\n * ModuleRegistry - manages module lifecycle\n *\n * @example\n * ```typescript\n * const registry = new ModuleRegistry(container, logger)\n * registry.register(AppModule) // Traverses imports recursively\n * await registry.initialize()\n * // ... application running ...\n * await registry.shutdown()\n * ```\n */\nexport class ModuleRegistry {\n private modules: RegisteredModule[] = []\n private registeredClasses = new Set<Constructor>()\n private initialized = false\n\n // Collected items from all modules for Application to use\n private allControllers: Constructor[] = []\n private allConsumers: Constructor[] = []\n private allJobs: Constructor[] = []\n private allListeners: Constructor[] = []\n private allCommands: Constructor[] = []\n private allSeeders: Constructor[] = []\n private allRouterConfigs: { router: Router; controllers: Constructor[] }[] = []\n\n constructor(\n private readonly container: Container,\n private readonly logger: LoggerService\n ) { }\n\n /**\n * Register a module (static or dynamic)\n *\n * @param moduleOrDynamic - Module class decorated with `@Module` or DynamicModule from configure()\n */\n register(moduleOrDynamic: ModuleClass | DynamicModule): void {\n const { moduleClass, options } = this.resolveModule(moduleOrDynamic)\n const isDynamic = this.isDynamicModule(moduleOrDynamic)\n\n // Check for duplicate registration\n if (this.registeredClasses.has(moduleClass)) {\n // For DynamicModules: Still register the additional providers\n // This allows forRoot() to add configuration even if base module is registered\n if (isDynamic) {\n this.logger.debug(`Module ${moduleClass.name} already registered, registering DynamicModule providers`)\n const { module: _, ...dynamicRest } = moduleOrDynamic\n for (const provider of dynamicRest.providers ?? []) {\n this.registerProvider(provider)\n }\n } else {\n this.logger.debug(`Module ${moduleClass.name} already registered, skipping`)\n }\n return\n }\n\n this.registeredClasses.add(moduleClass)\n this.logger.info(`Registering module: ${moduleClass.name}`)\n\n // First, register imported modules recursively\n for (const ImportedModule of options.imports ?? []) {\n this.register(ImportedModule)\n }\n\n // Register providers in container\n for (const provider of options.providers ?? []) {\n this.registerProvider(provider)\n }\n\n // Register controllers and collect them\n for (const controller of options.controllers ?? []) {\n this.container.register(controller)\n this.allControllers.push(controller)\n }\n\n // Register consumers as singletons by default and collect them\n for (const consumer of options.consumers ?? []) {\n this.container.register(consumer, Scope.Singleton)\n this.allConsumers.push(consumer)\n this.logger.info(`Collected consumer: ${consumer.name}`, { queueCount: this.allConsumers.length })\n }\n\n // Register jobs as singletons by default and collect them\n for (const job of options.jobs ?? []) {\n this.container.register(job, Scope.Singleton)\n this.allJobs.push(job)\n }\n\n this.modules.push({ moduleClass, options, instance: null })\n }\n\n /**\n * Register multiple modules in order\n */\n registerAll(modules: (ModuleClass | DynamicModule)[]): void {\n for (const module of modules) {\n this.register(module)\n }\n }\n\n /**\n * Initialize all modules (call configure and onInitialize hooks)\n */\n async initialize(): Promise<void> {\n if (this.initialized) return\n\n this.logger.info('Initializing modules...')\n\n const context: ModuleContext = {\n container: this.container,\n logger: this.logger,\n }\n\n for (const registered of this.modules) {\n // Instantiate module class\n const instance = new registered.moduleClass()\n registered.instance = instance\n\n // Call onInitialize if implemented\n if (this.hasOnInitialize(instance)) {\n this.logger.info(`Initializing: ${registered.moduleClass.name}`)\n await instance.onInitialize(context)\n }\n }\n\n this.initialized = true\n this.logger.info('All modules initialized')\n }\n\n /**\n * Get all controllers registered from all modules\n */\n getAllControllers(): Constructor[] {\n return this.allControllers\n }\n\n /**\n * Get all consumers registered from all modules\n */\n getAllConsumers(): Constructor[] {\n return this.allConsumers\n }\n\n /**\n * Get all jobs registered from all modules\n */\n getAllJobs(): Constructor[] {\n return this.allJobs\n }\n\n /**\n * Get all listeners registered from all modules\n */\n getAllListeners(): Constructor[] {\n return this.allListeners\n }\n\n /**\n * Get all commands registered from all modules\n */\n getAllCommands(): Constructor[] {\n return this.allCommands\n }\n\n /**\n * Get all seeders registered from all modules\n */\n getAllSeeders(): Constructor[] {\n return this.allSeeders\n }\n\n /**\n * Get all Router configurations from modules implementing RouteConfigurable.\n * Runs configureRoutes() lazily on first call (deferred from initialize()).\n */\n getAllRouterConfigs(): { router: Router; controllers: Constructor[] }[] {\n if (this.allRouterConfigs.length === 0) {\n for (const { moduleClass, options, instance } of this.modules) {\n if (instance && this.hasRouteConfigurable(instance)) {\n this.logger.debug(`Configuring routes for: ${moduleClass.name}`)\n const router = new Router()\n instance.configureRoutes(router)\n const moduleControllers = options.controllers ?? []\n this.allRouterConfigs.push({ router, controllers: moduleControllers })\n }\n }\n }\n return this.allRouterConfigs\n }\n\n /**\n * Call `onException()` on all modules that implement the OnException interface.\n * Invoked by Application after the ExceptionHandler is resolved and `register()` is called.\n *\n * @param handler - The resolved ExceptionHandler instance\n */\n configureExceptionHandlers(handler: ExceptionHandler): void {\n for (const { moduleClass, instance } of this.modules) {\n if (instance && this.hasOnException(instance)) {\n this.logger.debug(`Configuring exception handlers for: ${moduleClass.name}`)\n instance.onException(handler)\n }\n }\n }\n\n /**\n * Shutdown all modules (call onShutdown hooks in reverse order)\n */\n async shutdown(): Promise<void> {\n this.logger.info('Shutting down modules...')\n\n const context: ModuleContext = {\n container: this.container,\n logger: this.logger,\n }\n\n // Reverse order for shutdown\n const reversed = [...this.modules].reverse()\n\n for (const { moduleClass, instance } of reversed) {\n if (instance && this.hasOnShutdown(instance)) {\n try {\n await instance.onShutdown(context)\n } catch (error) {\n this.logger.error(`Error shutting down ${moduleClass.name}:`, error as Error)\n }\n }\n }\n\n this.logger.info('All modules shut down')\n }\n\n /**\n * Type guard for RouteConfigurable\n */\n private hasRouteConfigurable(instance: unknown): instance is RouteConfigurable {\n return (\n typeof instance === 'object' &&\n instance !== null &&\n 'configureRoutes' in instance &&\n typeof (instance as RouteConfigurable).configureRoutes === 'function'\n )\n }\n\n /**\n * Type guard for OnInitialize\n */\n private hasOnInitialize(instance: unknown): instance is OnInitialize {\n return (\n typeof instance === 'object' &&\n instance !== null &&\n 'onInitialize' in instance &&\n typeof (instance as OnInitialize).onInitialize === 'function'\n )\n }\n\n /**\n * Type guard for OnShutdown\n */\n private hasOnShutdown(instance: unknown): instance is OnShutdown {\n return (\n typeof instance === 'object' &&\n instance !== null &&\n 'onShutdown' in instance &&\n typeof (instance as OnShutdown).onShutdown === 'function'\n )\n }\n\n /**\n * Type guard for OnException\n */\n private hasOnException(instance: unknown): instance is OnException {\n return (\n typeof instance === 'object' &&\n instance !== null &&\n 'onException' in instance &&\n typeof (instance as OnException).onException === 'function'\n )\n }\n\n /**\n * Resolve module class and options from static or dynamic module\n *\n * For DynamicModules, merges the decorator metadata (consumers, controllers, jobs)\n * with the DynamicModule options (providers, imports). This ensures modules using\n * forRoot/forRootAsync patterns still have their decorator-defined consumers registered.\n */\n private resolveModule(moduleOrDynamic: ModuleClass | DynamicModule): {\n moduleClass: Constructor\n options: ModuleOptions\n } {\n // DynamicModule (from forRoot/forRootAsync) - has module property\n if (this.isDynamicModule(moduleOrDynamic)) {\n const { module: moduleClass, ...dynamicRest } = moduleOrDynamic\n\n // Get decorator options and merge with dynamic options\n // This ensures consumers/controllers/jobs from @Module decorator are included\n const decoratorOptions = getModuleOptions(moduleClass) ?? {}\n const mergedOptions: ModuleOptions = {\n ...decoratorOptions,\n ...dynamicRest,\n // Merge arrays: decorator providers first, then dynamic providers\n providers: [...(decoratorOptions.providers ?? []), ...(dynamicRest.providers ?? [])],\n imports: [...(decoratorOptions.imports ?? [])],\n }\n\n return { moduleClass: moduleClass, options: mergedOptions }\n }\n\n // Static module (decorated with @Module)\n const moduleClass = moduleOrDynamic as Constructor\n const options = getModuleOptions(moduleClass) ?? {}\n return { moduleClass, options }\n }\n\n /**\n * Type guard for DynamicModule\n */\n private isDynamicModule(value: unknown): value is DynamicModule {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'module' in value && // Required property for dynamic modules\n typeof (value as DynamicModule).module === 'function'\n )\n }\n\n /**\n * Register a single provider in the container\n */\n private registerProvider(provider: Provider): void {\n if (typeof provider === 'function') {\n // Class-only provider - transient by default\n this.container.register(provider as Constructor)\n this.collectIfListener(provider as Constructor)\n this.collectIfCommand(provider as Constructor)\n this.collectIfSeeder(provider as Constructor)\n } else if ('useClass' in provider) {\n // ClassProvider with optional scope\n this.container.register(provider.provide, provider.useClass as Constructor, provider.scope)\n this.collectIfListener(provider.useClass as Constructor)\n this.collectIfCommand(provider.useClass as Constructor)\n this.collectIfSeeder(provider.useClass as Constructor)\n } else if ('useValue' in provider) {\n // ValueProvider - no scope needed (values are inherently singleton)\n this.container.registerValue(provider.provide, provider.useValue)\n } else if ('useFactory' in provider) {\n // FactoryProvider - use instancePerContainerCachingFactory to:\n // 1. Get the actual container at resolution time (global vs request)\n // 2. Cache result per container\n const { provide, useFactory, inject = [] } = provider\n this.container.getTsyringeContainer().register(provide, {\n useFactory: instancePerContainerCachingFactory((dependencyContainer) => {\n const deps = inject.map((token) => dependencyContainer.resolve(token))\n return useFactory(...deps)\n })\n })\n } else if ('useExisting' in provider) {\n // ExistingProvider - alias to another token\n this.container.registerExisting(provider.provide, provider.useExisting)\n }\n }\n\n /**\n * Check if a class is a `Command` and collect it for auto-wiring\n */\n private collectIfCommand(providerClass: Constructor): void {\n if (isCommand(providerClass) && !this.allCommands.includes(providerClass)) {\n injectable()(providerClass)\n this.allCommands.push(providerClass)\n this.logger.debug(`Collected command: ${providerClass.name}`)\n }\n }\n\n /**\n * Check if a class is a `Seeder` and collect it for auto-wiring\n */\n private collectIfSeeder(providerClass: Constructor): void {\n if (isSeeder(providerClass) && !this.allSeeders.includes(providerClass)) {\n this.allSeeders.push(providerClass)\n this.logger.debug(`Collected seeder: ${providerClass.name}`)\n }\n }\n\n /**\n * Check if a class is a `@Listener()` and collect it for auto-wiring\n */\n private collectIfListener(providerClass: Constructor): void {\n if (isListener(providerClass)) {\n // Re-register as singleton so the same instance is used across all event registrations\n this.container.register(providerClass, providerClass, Scope.Singleton)\n this.allListeners.push(providerClass)\n this.logger.debug(`Collected listener: ${providerClass.name}`)\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
//#region src/openapi/openapi.tokens.ts
|
|
2
|
-
/**
|
|
3
|
-
* OpenAPI Module DI Tokens
|
|
4
|
-
*/
|
|
5
|
-
const OPENAPI_TOKENS = {
|
|
6
|
-
/** Static options provided via forRoot() */
|
|
7
|
-
Options: Symbol.for("stratal:openapi:options"),
|
|
8
|
-
/** Request-scoped config service that supports runtime overrides */
|
|
9
|
-
ConfigService: Symbol.for("stratal:openapi:config:service"),
|
|
10
|
-
/** OpenAPI service that generates specs and serves endpoints */
|
|
11
|
-
OpenAPIService: Symbol.for("stratal:openapi:service")
|
|
12
|
-
};
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region src/openapi/services/openapi-tools.service.ts
|
|
15
|
-
/**
|
|
16
|
-
* Converts an OpenAPI 3.0 spec into callable tool definitions.
|
|
17
|
-
*
|
|
18
|
-
* Plain class (no DI) — reusable across MCP, CLI, and custom tooling.
|
|
19
|
-
*/
|
|
20
|
-
var OpenApiToolsService = class OpenApiToolsService {
|
|
21
|
-
static HTTP_METHODS = new Set([
|
|
22
|
-
"get",
|
|
23
|
-
"post",
|
|
24
|
-
"put",
|
|
25
|
-
"delete",
|
|
26
|
-
"patch",
|
|
27
|
-
"head",
|
|
28
|
-
"options",
|
|
29
|
-
"trace"
|
|
30
|
-
]);
|
|
31
|
-
tools = [];
|
|
32
|
-
toolMap = /* @__PURE__ */ new Map();
|
|
33
|
-
dispatcher;
|
|
34
|
-
spec;
|
|
35
|
-
constructor(spec, options) {
|
|
36
|
-
this.spec = spec;
|
|
37
|
-
this.dispatcher = options?.dispatcher;
|
|
38
|
-
this.tools = this.buildTools();
|
|
39
|
-
for (const tool of this.tools) this.toolMap.set(tool.name, tool);
|
|
40
|
-
}
|
|
41
|
-
getTools(filter) {
|
|
42
|
-
let tools = this.tools;
|
|
43
|
-
if (filter?.tags?.length) {
|
|
44
|
-
const tagSet = new Set(filter.tags);
|
|
45
|
-
tools = tools.filter((t) => {
|
|
46
|
-
return this.getOperation(t.method, t.path)?.tags?.some((tag) => tagSet.has(tag)) ?? false;
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
if (filter?.pathPrefix) {
|
|
50
|
-
const prefix = filter.pathPrefix;
|
|
51
|
-
tools = tools.filter((t) => t.path.startsWith(prefix));
|
|
52
|
-
}
|
|
53
|
-
return tools;
|
|
54
|
-
}
|
|
55
|
-
getTool(name) {
|
|
56
|
-
return this.toolMap.get(name);
|
|
57
|
-
}
|
|
58
|
-
async executeTool(name, args) {
|
|
59
|
-
const tool = this.toolMap.get(name);
|
|
60
|
-
if (!tool) throw new Error(`Tool not found: ${name}`);
|
|
61
|
-
if (!this.dispatcher) throw new Error("No dispatcher configured");
|
|
62
|
-
let url = tool.path;
|
|
63
|
-
for (const param of tool.pathParams) {
|
|
64
|
-
const value = args[`path_${param}`];
|
|
65
|
-
if (value === void 0) throw new Error(`Missing required path parameter: ${param}`);
|
|
66
|
-
url = url.replace(`{${param}}`, encodeURIComponent(value != null && typeof value === "object" ? JSON.stringify(value) : String(value)));
|
|
67
|
-
}
|
|
68
|
-
const queryParts = [];
|
|
69
|
-
for (const key of Object.keys(args)) if (key.startsWith("query_")) {
|
|
70
|
-
const paramName = key.slice(6);
|
|
71
|
-
const value = args[key];
|
|
72
|
-
queryParts.push(`${encodeURIComponent(paramName)}=${encodeURIComponent(value != null && typeof value === "object" ? JSON.stringify(value) : String(value))}`);
|
|
73
|
-
}
|
|
74
|
-
if (queryParts.length > 0) url += `?${queryParts.join("&")}`;
|
|
75
|
-
const body = args.body;
|
|
76
|
-
const response = await this.dispatcher(tool.method.toUpperCase(), url, body !== void 0 ? { body } : void 0);
|
|
77
|
-
const responseHeaders = {};
|
|
78
|
-
response.headers.forEach((value, key) => {
|
|
79
|
-
responseHeaders[key] = value;
|
|
80
|
-
});
|
|
81
|
-
return {
|
|
82
|
-
status: response.status,
|
|
83
|
-
body: await response.text(),
|
|
84
|
-
headers: responseHeaders
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
buildTools() {
|
|
88
|
-
const tools = [];
|
|
89
|
-
const paths = this.spec.paths;
|
|
90
|
-
for (const [path, pathItem] of Object.entries(paths)) for (const [method, operation] of Object.entries(pathItem)) {
|
|
91
|
-
if (!operation || typeof operation !== "object") continue;
|
|
92
|
-
if (!OpenApiToolsService.HTTP_METHODS.has(method.toLowerCase())) continue;
|
|
93
|
-
const op = operation;
|
|
94
|
-
const name = op.operationId ?? this.generateName(method, path);
|
|
95
|
-
const description = this.buildDescription(op, method, path);
|
|
96
|
-
const pathItemParams = pathItem.parameters;
|
|
97
|
-
const mergedParameters = this.mergeParameters(pathItemParams, op.parameters);
|
|
98
|
-
const { schema, pathParams } = this.buildInputSchema({
|
|
99
|
-
...op,
|
|
100
|
-
parameters: mergedParameters
|
|
101
|
-
});
|
|
102
|
-
tools.push({
|
|
103
|
-
name,
|
|
104
|
-
description,
|
|
105
|
-
inputSchema: schema,
|
|
106
|
-
method: method.toUpperCase(),
|
|
107
|
-
path,
|
|
108
|
-
pathParams
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
return tools;
|
|
112
|
-
}
|
|
113
|
-
generateName(method, path) {
|
|
114
|
-
const snake = path.replace(/[{}]/g, "").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
115
|
-
return `${method.toLowerCase()}_${snake}`;
|
|
116
|
-
}
|
|
117
|
-
buildDescription(op, method, path) {
|
|
118
|
-
if (op.summary && op.description) return `${op.summary} — ${op.description}`;
|
|
119
|
-
return op.summary ?? op.description ?? `${method.toUpperCase()} ${path}`;
|
|
120
|
-
}
|
|
121
|
-
buildInputSchema(op) {
|
|
122
|
-
const properties = {};
|
|
123
|
-
const required = [];
|
|
124
|
-
const pathParams = [];
|
|
125
|
-
for (const param of op.parameters ?? []) {
|
|
126
|
-
const resolvedParam = this.resolveRef(param);
|
|
127
|
-
const paramSchema = resolvedParam.schema ? this.resolveRef(resolvedParam.schema) : { type: "string" };
|
|
128
|
-
if (resolvedParam.in === "path") {
|
|
129
|
-
pathParams.push(resolvedParam.name);
|
|
130
|
-
const key = `path_${resolvedParam.name}`;
|
|
131
|
-
properties[key] = { ...paramSchema };
|
|
132
|
-
if (resolvedParam.description) properties[key].description = resolvedParam.description;
|
|
133
|
-
required.push(key);
|
|
134
|
-
} else if (resolvedParam.in === "query") {
|
|
135
|
-
const key = `query_${resolvedParam.name}`;
|
|
136
|
-
properties[key] = { ...paramSchema };
|
|
137
|
-
if (resolvedParam.description) properties[key].description = resolvedParam.description;
|
|
138
|
-
if (resolvedParam.required) required.push(key);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
const resolvedBody = op.requestBody ? this.resolveRef(op.requestBody) : void 0;
|
|
142
|
-
if (resolvedBody) {
|
|
143
|
-
const jsonContent = resolvedBody.content?.["application/json"];
|
|
144
|
-
if (jsonContent?.schema) properties.body = this.resolveRef(jsonContent.schema);
|
|
145
|
-
else properties.body = { type: "object" };
|
|
146
|
-
if (resolvedBody.required === true) required.push("body");
|
|
147
|
-
}
|
|
148
|
-
const schema = {
|
|
149
|
-
type: "object",
|
|
150
|
-
properties
|
|
151
|
-
};
|
|
152
|
-
if (required.length > 0) schema.required = required;
|
|
153
|
-
return {
|
|
154
|
-
schema,
|
|
155
|
-
pathParams
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
mergeParameters(pathLevel, opLevel) {
|
|
159
|
-
const resolvedPathLevel = pathLevel?.map((p) => this.resolveRef(p));
|
|
160
|
-
const resolvedOpLevel = opLevel?.map((p) => this.resolveRef(p));
|
|
161
|
-
if (!resolvedPathLevel?.length) return resolvedOpLevel ?? [];
|
|
162
|
-
if (!resolvedOpLevel?.length) return resolvedPathLevel;
|
|
163
|
-
const opKeys = new Set(resolvedOpLevel.map((p) => `${p.in}:${p.name}`));
|
|
164
|
-
return [...resolvedPathLevel.filter((p) => !opKeys.has(`${p.in}:${p.name}`)), ...resolvedOpLevel];
|
|
165
|
-
}
|
|
166
|
-
resolveRef(obj, seen = /* @__PURE__ */ new Set()) {
|
|
167
|
-
if (!obj || typeof obj !== "object") return obj;
|
|
168
|
-
const record = obj;
|
|
169
|
-
if (typeof record.$ref === "string") {
|
|
170
|
-
const refPath = record.$ref;
|
|
171
|
-
if (seen.has(refPath)) return obj;
|
|
172
|
-
seen.add(refPath);
|
|
173
|
-
const resolved = this.lookupRef(refPath);
|
|
174
|
-
if (!resolved) return obj;
|
|
175
|
-
return this.resolveRef(resolved, seen);
|
|
176
|
-
}
|
|
177
|
-
const result = {};
|
|
178
|
-
for (const [key, value] of Object.entries(record)) if (Array.isArray(value)) result[key] = value.map((item) => this.resolveRef(item, seen));
|
|
179
|
-
else if (value && typeof value === "object") result[key] = this.resolveRef(value, seen);
|
|
180
|
-
else result[key] = value;
|
|
181
|
-
return result;
|
|
182
|
-
}
|
|
183
|
-
lookupRef(refPath) {
|
|
184
|
-
const components = this.spec.components;
|
|
185
|
-
if (!components) return void 0;
|
|
186
|
-
const match = /^#\/components\/(\w+)\/(.+)$/.exec(refPath);
|
|
187
|
-
if (!match) return void 0;
|
|
188
|
-
const [, section, name] = match;
|
|
189
|
-
const sectionObj = components[section];
|
|
190
|
-
if (typeof sectionObj !== "object") return void 0;
|
|
191
|
-
return sectionObj[name];
|
|
192
|
-
}
|
|
193
|
-
getOperation(method, path) {
|
|
194
|
-
return this.spec.paths?.[path]?.[method.toLowerCase()];
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
//#endregion
|
|
198
|
-
export { OPENAPI_TOKENS as n, OpenApiToolsService as t };
|
|
199
|
-
|
|
200
|
-
//# sourceMappingURL=openapi-tools.service-Zs-Ewv7F.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-tools.service-Zs-Ewv7F.mjs","names":[],"sources":["../src/openapi/openapi.tokens.ts","../src/openapi/services/openapi-tools.service.ts"],"sourcesContent":["/**\n * OpenAPI Module DI Tokens\n */\nexport const OPENAPI_TOKENS = {\n /** Static options provided via forRoot() */\n Options: Symbol.for('stratal:openapi:options'),\n\n /** Request-scoped config service that supports runtime overrides */\n ConfigService: Symbol.for('stratal:openapi:config:service'),\n\n /** OpenAPI service that generates specs and serves endpoints */\n OpenAPIService: Symbol.for('stratal:openapi:service'),\n} as const\n","import { type OpenAPIObject } from \"../../i18n/validation\"\nimport type { HttpMethod } from '../../router/types'\n\ntype JsonSchema = Record<string, unknown>\n\nexport interface ToolDefinition {\n name: string\n description: string\n inputSchema: JsonSchema\n method: string\n path: string\n pathParams: string[]\n}\n\nexport interface ToolExecutionResult {\n status: number\n body: string\n headers: Record<string, string>\n}\n\nexport interface ToolFilter {\n tags?: string[]\n pathPrefix?: string\n}\n\nexport type Dispatcher = (method: string, url: string, options?: {\n body?: unknown\n headers?: Record<string, string>\n}) => Promise<Response>\n\ninterface OperationObject {\n operationId?: string\n summary?: string\n description?: string\n tags?: string[]\n parameters?: ParameterObject[]\n requestBody?: RequestBodyObject\n}\n\ninterface ParameterObject {\n name: string\n in: string\n required?: boolean\n schema?: JsonSchema\n description?: string\n}\n\ninterface RequestBodyObject {\n required?: boolean\n content?: Record<string, { schema?: JsonSchema }>\n}\n\n/**\n * Converts an OpenAPI 3.0 spec into callable tool definitions.\n *\n * Plain class (no DI) — reusable across MCP, CLI, and custom tooling.\n */\nexport class OpenApiToolsService {\n private static readonly HTTP_METHODS: Set<string> = new Set<HttpMethod>(['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace'])\n\n private tools: ToolDefinition[] = []\n private toolMap = new Map<string, ToolDefinition>()\n private dispatcher?: Dispatcher\n\n private spec: OpenAPIObject\n\n constructor(spec: OpenAPIObject, options?: { dispatcher?: Dispatcher }) {\n this.spec = spec\n this.dispatcher = options?.dispatcher\n this.tools = this.buildTools()\n for (const tool of this.tools) {\n this.toolMap.set(tool.name, tool)\n }\n }\n\n getTools(filter?: ToolFilter): ToolDefinition[] {\n let tools = this.tools\n\n if (filter?.tags?.length) {\n const tagSet = new Set(filter.tags)\n tools = tools.filter((t) => {\n const op = this.getOperation(t.method, t.path)\n return op?.tags?.some((tag) => tagSet.has(tag)) ?? false\n })\n }\n\n if (filter?.pathPrefix) {\n const prefix = filter.pathPrefix\n tools = tools.filter((t) => t.path.startsWith(prefix))\n }\n\n return tools\n }\n\n getTool(name: string): ToolDefinition | undefined {\n return this.toolMap.get(name)\n }\n\n async executeTool(name: string, args: Record<string, unknown>): Promise<ToolExecutionResult> {\n const tool = this.toolMap.get(name)\n if (!tool) {\n throw new Error(`Tool not found: ${name}`)\n }\n if (!this.dispatcher) {\n throw new Error('No dispatcher configured')\n }\n\n // Interpolate path params\n let url = tool.path\n for (const param of tool.pathParams) {\n const value = args[`path_${param}`]\n if (value === undefined) {\n throw new Error(`Missing required path parameter: ${param}`)\n }\n url = url.replace(`{${param}}`, encodeURIComponent(value != null && typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean)))\n }\n\n // Collect query params\n const queryParts: string[] = []\n for (const key of Object.keys(args)) {\n if (key.startsWith('query_')) {\n const paramName = key.slice(6)\n const value = args[key]\n queryParts.push(`${encodeURIComponent(paramName)}=${encodeURIComponent(value != null && typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean))}`)\n }\n }\n if (queryParts.length > 0) {\n url += `?${queryParts.join('&')}`\n }\n\n const body = args.body\n const response = await this.dispatcher(\n tool.method.toUpperCase(),\n url,\n body !== undefined ? { body } : undefined,\n )\n\n const responseHeaders: Record<string, string> = {}\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value\n })\n\n return {\n status: response.status,\n body: await response.text(),\n headers: responseHeaders,\n }\n }\n\n private buildTools(): ToolDefinition[] {\n const tools: ToolDefinition[] = []\n const paths = this.spec.paths\n\n for (const [path, pathItem] of Object.entries(paths)) {\n for (const [method, operation] of Object.entries(pathItem)) {\n if (!operation || typeof operation !== 'object') continue\n if (!OpenApiToolsService.HTTP_METHODS.has(method.toLowerCase())) continue\n\n const op = operation as OperationObject\n const name = op.operationId ?? this.generateName(method, path)\n const description = this.buildDescription(op, method, path)\n const pathItemParams = (pathItem as Record<string, unknown>).parameters as ParameterObject[] | undefined\n const mergedParameters = this.mergeParameters(pathItemParams, op.parameters)\n const { schema, pathParams } = this.buildInputSchema({ ...op, parameters: mergedParameters })\n\n tools.push({ name, description, inputSchema: schema, method: method.toUpperCase(), path, pathParams })\n }\n }\n\n return tools\n }\n\n private generateName(method: string, path: string): string {\n const snake = path\n .replace(/[{}]/g, '')\n .replace(/[^a-zA-Z0-9]+/g, '_')\n .replace(/^_|_$/g, '')\n .toLowerCase()\n return `${method.toLowerCase()}_${snake}`\n }\n\n private buildDescription(op: OperationObject, method: string, path: string): string {\n if (op.summary && op.description) {\n return `${op.summary} — ${op.description}`\n }\n return op.summary ?? op.description ?? `${method.toUpperCase()} ${path}`\n }\n\n private buildInputSchema(op: OperationObject): { schema: JsonSchema; pathParams: string[] } {\n const properties: Record<string, JsonSchema> = {}\n const required: string[] = []\n const pathParams: string[] = []\n\n // Parameters (path + query)\n for (const param of op.parameters ?? []) {\n const resolvedParam = this.resolveRef(param) as ParameterObject\n const paramSchema = resolvedParam.schema ? this.resolveRef(resolvedParam.schema) as JsonSchema : { type: 'string' }\n\n if (resolvedParam.in === 'path') {\n pathParams.push(resolvedParam.name)\n const key = `path_${resolvedParam.name}`\n properties[key] = { ...paramSchema }\n if (resolvedParam.description) properties[key].description = resolvedParam.description\n required.push(key)\n } else if (resolvedParam.in === 'query') {\n const key = `query_${resolvedParam.name}`\n properties[key] = { ...paramSchema }\n if (resolvedParam.description) properties[key].description = resolvedParam.description\n if (resolvedParam.required) required.push(key)\n }\n }\n\n // Request body\n const resolvedBody = op.requestBody ? this.resolveRef(op.requestBody) as RequestBodyObject : undefined\n if (resolvedBody) {\n const jsonContent = resolvedBody.content?.['application/json']\n if (jsonContent?.schema) {\n properties.body = this.resolveRef(jsonContent.schema) as JsonSchema\n } else {\n properties.body = { type: 'object' }\n }\n const needsBody = resolvedBody.required === true\n if (needsBody) {\n required.push('body')\n }\n }\n\n const schema: JsonSchema = { type: 'object', properties }\n if (required.length > 0) {\n schema.required = required\n }\n\n return { schema, pathParams }\n }\n\n private mergeParameters(pathLevel?: ParameterObject[], opLevel?: ParameterObject[]): ParameterObject[] {\n const resolvedPathLevel = pathLevel?.map((p) => this.resolveRef(p) as ParameterObject)\n const resolvedOpLevel = opLevel?.map((p) => this.resolveRef(p) as ParameterObject)\n\n if (!resolvedPathLevel?.length) return resolvedOpLevel ?? []\n if (!resolvedOpLevel?.length) return resolvedPathLevel\n\n const opKeys = new Set(resolvedOpLevel.map((p) => `${p.in}:${p.name}`))\n const inherited = resolvedPathLevel.filter((p) => !opKeys.has(`${p.in}:${p.name}`))\n return [...inherited, ...resolvedOpLevel]\n }\n\n private resolveRef(obj: unknown, seen = new Set<string>()): unknown {\n if (!obj || typeof obj !== 'object') return obj\n const record = obj as Record<string, unknown>\n\n if (typeof record.$ref === 'string') {\n const refPath = record.$ref\n if (seen.has(refPath)) return obj\n seen.add(refPath)\n\n const resolved = this.lookupRef(refPath)\n if (!resolved) return obj\n return this.resolveRef(resolved, seen)\n }\n\n // Recursively walk all properties and resolve nested $refs\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(record)) {\n if (Array.isArray(value)) {\n result[key] = value.map((item) => this.resolveRef(item, seen))\n } else if (value && typeof value === 'object') {\n result[key] = this.resolveRef(value, seen)\n } else {\n result[key] = value\n }\n }\n return result\n }\n\n private lookupRef(refPath: string): unknown {\n const components = this.spec.components as Record<string, Record<string, unknown>> | undefined\n if (!components) return undefined\n\n const match = /^#\\/components\\/(\\w+)\\/(.+)$/.exec(refPath)\n if (!match) return undefined\n\n const [, section, name] = match\n const sectionObj = components[section]\n if (typeof sectionObj !== 'object') return undefined\n return sectionObj[name]\n }\n\n private getOperation(method: string, path: string): OperationObject | undefined {\n const paths = this.spec.paths as Record<string, Record<string, unknown>> | undefined\n return paths?.[path]?.[method.toLowerCase()] as OperationObject | undefined\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.service-BLgvn3hJ.d.mts","names":[],"sources":["../src/openapi/services/openapi.service.ts"],"mappings":";;;;;AA0BA;;;;;;;;;;;;;;cACa,cAAA;EAMH;;;;EAAR,OAAA,CAAQ,GAAA,EAAK,WAAA,CAAY,SAAA,GAAY,SAAA,EAAW,SAAA,GAAY,aAAA;EAqCxC;;;EAApB,cAAA,CAAe,GAAA,EAAK,WAAA,CAAY,SAAA,GAAY,SAAA,EAAW,SAAA;EAAA,QA4C/C,eAAA;EAAA;;;EAAA,QAQA,4BAAA;EA2EA;;;EAAA,QAjDA,YAAA;;;;UAoBA,aAAA;;;;UA6BA,iBAAA;AAAA"}
|