stratal 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/{base-email.provider-DypUAfWm.mjs → base-email.provider-mjynzewK.mjs} +1 -1
- package/dist/{base-email.provider-DypUAfWm.mjs.map → base-email.provider-mjynzewK.mjs.map} +1 -1
- package/dist/bin/cloudflare-workers-loader.mjs +33 -1
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs +169 -7
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +3 -2
- package/dist/cache/index.d.mts.map +1 -1
- package/dist/cache/index.mjs +3 -10
- package/dist/cache/index.mjs.map +1 -1
- package/dist/{colors-Y7WIFXs7.mjs → colors-DJaRDXoS.mjs} +1 -1
- package/dist/{colors-Y7WIFXs7.mjs.map → colors-DJaRDXoS.mjs.map} +1 -1
- package/dist/{command-B1CPgsrU.mjs → command-BgSlsS4M.mjs} +3 -3
- package/dist/command-BgSlsS4M.mjs.map +1 -0
- package/dist/{command-TnkPYWta.d.mts → command-DsQq56Lp.d.mts} +2 -2
- package/dist/{command-TnkPYWta.d.mts.map → command-DsQq56Lp.d.mts.map} +1 -1
- package/dist/config/index.d.mts +81 -37
- package/dist/config/index.d.mts.map +1 -1
- package/dist/config/index.mjs +135 -61
- package/dist/config/index.mjs.map +1 -1
- package/dist/{consumer-registry-Bymm6ff4.d.mts → consumer-registry-Doom7BEh.d.mts} +1 -1
- package/dist/{consumer-registry-Bymm6ff4.d.mts.map → consumer-registry-Doom7BEh.d.mts.map} +1 -1
- package/dist/controller.decorator-LZY9aHYG.mjs +66 -0
- package/dist/controller.decorator-LZY9aHYG.mjs.map +1 -0
- package/dist/cron/index.d.mts +4 -3
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +1 -3
- package/dist/{cron-manager-CFBamKKk.mjs → cron-manager-C30t9UZM.mjs} +29 -19
- package/dist/cron-manager-C30t9UZM.mjs.map +1 -0
- package/dist/{cron-manager-D7imGwUT.d.mts → cron-manager-RuPtFVLy.d.mts} +28 -14
- package/dist/cron-manager-RuPtFVLy.d.mts.map +1 -0
- package/dist/di/index.d.mts +2 -2
- package/dist/di/index.mjs +3 -3
- package/dist/email/index.d.mts +3 -3
- package/dist/email/index.mjs +87 -18
- package/dist/email/index.mjs.map +1 -1
- package/dist/{en-DaewN8hc.mjs → en-rHmW6vD9.mjs} +14 -31
- package/dist/en-rHmW6vD9.mjs.map +1 -0
- package/dist/env-CamWD-U1.d.mts +25 -0
- package/dist/env-CamWD-U1.d.mts.map +1 -0
- package/dist/errors/index.d.mts +2 -2
- package/dist/errors/index.mjs +2 -3
- package/dist/errors-B4pYgYON.mjs +1714 -0
- package/dist/errors-B4pYgYON.mjs.map +1 -0
- package/dist/{errors-DuAR5Wke.mjs → errors-BUyUfr2Z.mjs} +14 -7
- package/dist/errors-BUyUfr2Z.mjs.map +1 -0
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +1 -2
- package/dist/{events-CvUSgEuN.mjs → events-COKixqnG.mjs} +2 -2
- package/dist/{events-CvUSgEuN.mjs.map → events-COKixqnG.mjs.map} +1 -1
- package/dist/{gateway-context-CNOLkLUC.mjs → gateway-context-cqZ8wMoi.mjs} +4 -9
- package/dist/gateway-context-cqZ8wMoi.mjs.map +1 -0
- package/dist/guards/index.d.mts +14 -5
- package/dist/guards/index.d.mts.map +1 -1
- package/dist/guards/index.mjs +1 -1
- package/dist/{guards-DUk_Kzst.mjs → guards-DMbsAxSX.mjs} +1 -1
- package/dist/guards-DMbsAxSX.mjs.map +1 -0
- package/dist/http-method.decorator-BT3ufnz8.mjs +96 -0
- package/dist/http-method.decorator-BT3ufnz8.mjs.map +1 -0
- package/dist/i18n/index.d.mts +3 -3
- package/dist/i18n/index.mjs +3 -16
- package/dist/i18n/messages/en/index.d.mts +1 -1
- package/dist/i18n/messages/en/index.mjs +1 -1
- package/dist/i18n/utils/index.d.mts +30 -0
- package/dist/i18n/utils/index.d.mts.map +1 -0
- package/dist/i18n/utils/index.mjs +2 -0
- package/dist/i18n/validation/index.d.mts +1 -1
- package/dist/i18n/validation/index.mjs +1 -1
- package/dist/i18n.module-CI_prYFD.mjs +2340 -0
- package/dist/i18n.module-CI_prYFD.mjs.map +1 -0
- package/dist/{index-NGxg-KP_.d.mts → index-B437eK7p.d.mts} +59 -16
- package/dist/index-B437eK7p.d.mts.map +1 -0
- package/dist/{index-Dp6A5ywM.d.mts → index-CWRS7Ri3.d.mts} +1 -1
- package/dist/{index-Dp6A5ywM.d.mts.map → index-CWRS7Ri3.d.mts.map} +1 -1
- package/dist/{index-D_w_Rmtd.d.mts → index-DFhEeFfC.d.mts} +13 -30
- package/dist/{index-D_w_Rmtd.d.mts.map → index-DFhEeFfC.d.mts.map} +1 -1
- package/dist/index-DPFqRs8L.d.mts +4318 -0
- package/dist/index-DPFqRs8L.d.mts.map +1 -0
- package/dist/{index-DGRe6Yoa.d.mts → index-Dnqm9ZB6.d.mts} +5 -4
- package/dist/index-Dnqm9ZB6.d.mts.map +1 -0
- package/dist/index-SHx31sBJ.d.mts +101 -0
- package/dist/index-SHx31sBJ.d.mts.map +1 -0
- package/dist/index.d.mts +5 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -20
- package/dist/{is-command-DJVI6wEJ.mjs → is-command-C6a7WTPw.mjs} +2 -2
- package/dist/{is-command-DJVI6wEJ.mjs.map → is-command-C6a7WTPw.mjs.map} +1 -1
- package/dist/{is-seeder-D5MIEcdz.mjs → is-seeder-CebjZCDn.mjs} +1 -1
- package/dist/{is-seeder-D5MIEcdz.mjs.map → is-seeder-CebjZCDn.mjs.map} +1 -1
- package/dist/logger/index.d.mts +1 -1
- package/dist/logger/index.mjs +1 -1
- package/dist/{logger-CGT91VY6.mjs → logger-V6Ms3QnQ.mjs} +63 -45
- package/dist/logger-V6Ms3QnQ.mjs.map +1 -0
- package/dist/macroable/index.d.mts +2 -0
- package/dist/macroable/index.mjs +2 -0
- package/dist/macroable-BmufBshB.mjs +122 -0
- package/dist/macroable-BmufBshB.mjs.map +1 -0
- package/dist/module/index.d.mts +3 -4
- package/dist/module/index.d.mts.map +1 -1
- package/dist/module/index.mjs +1 -10
- package/dist/module-qGE_1duv.mjs +732 -0
- package/dist/module-qGE_1duv.mjs.map +1 -0
- package/dist/openapi/index.d.mts +3 -3
- package/dist/openapi/index.mjs +2 -15
- package/dist/{openapi-tools.service-B3TxYKoQ.mjs → openapi-tools.service-CYWGuhue.mjs} +4 -1
- package/dist/{openapi-tools.service-B3TxYKoQ.mjs.map → openapi-tools.service-CYWGuhue.mjs.map} +1 -1
- package/dist/{openapi.service-DGnX3Fc4.d.mts → openapi.service-Bv_NioM9.d.mts} +9 -17
- package/dist/openapi.service-Bv_NioM9.d.mts.map +1 -0
- package/dist/quarry/index.d.mts +26 -12
- package/dist/quarry/index.d.mts.map +1 -1
- package/dist/quarry/index.mjs +4 -8
- package/dist/{quarry-registry-B2rkO-JS.mjs → quarry-registry-DFfRRkA7.mjs} +45 -40
- package/dist/quarry-registry-DFfRRkA7.mjs.map +1 -0
- package/dist/queue/index.d.mts +2 -2
- package/dist/queue/index.mjs +3 -13
- package/dist/queue/index.mjs.map +1 -1
- package/dist/{queue.module-BtI8f4Jo.mjs → queue.module-P-G-nCYz.mjs} +39 -42
- package/dist/queue.module-P-G-nCYz.mjs.map +1 -0
- package/dist/r2-storage.provider-LdzK9tfG.mjs +244 -0
- package/dist/r2-storage.provider-LdzK9tfG.mjs.map +1 -0
- package/dist/{resend.provider-bXMEkdRJ.mjs → resend.provider-bwILp0WI.mjs} +2 -4
- package/dist/{resend.provider-bXMEkdRJ.mjs.map → resend.provider-bwILp0WI.mjs.map} +1 -1
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +7 -16
- package/dist/seeder/index.d.mts +3 -4
- package/dist/seeder/index.d.mts.map +1 -1
- package/dist/seeder/index.mjs +2 -6
- package/dist/{seeder-R7RXJC35.mjs → seeder-BcqIFa2X.mjs} +5 -5
- package/dist/{seeder-R7RXJC35.mjs.map → seeder-BcqIFa2X.mjs.map} +1 -1
- package/dist/setup-CtekcwuO.mjs +37 -0
- package/dist/setup-CtekcwuO.mjs.map +1 -0
- package/dist/signed-url-COX7cCWR.mjs +74 -0
- package/dist/signed-url-COX7cCWR.mjs.map +1 -0
- package/dist/{smtp.provider-DrbHQztF.mjs → smtp.provider-B07yuARi.mjs} +2 -4
- package/dist/{smtp.provider-DrbHQztF.mjs.map → smtp.provider-B07yuARi.mjs.map} +1 -1
- package/dist/storage/index.d.mts +39 -17
- package/dist/storage/index.d.mts.map +1 -1
- package/dist/storage/index.mjs +3 -14
- package/dist/storage/providers/index.d.mts +30 -69
- package/dist/storage/providers/index.d.mts.map +1 -1
- package/dist/storage/providers/index.mjs +2 -5
- package/dist/{storage-CZKHOhci.mjs → storage-P6X4h9So.mjs} +102 -29
- package/dist/storage-P6X4h9So.mjs.map +1 -0
- package/dist/{storage-provider.interface-0IqcdhBf.d.mts → storage-provider.interface-CC1nniHk.d.mts} +20 -15
- package/dist/storage-provider.interface-CC1nniHk.d.mts.map +1 -0
- package/dist/stratal-BCiwCFN9.mjs +533 -0
- package/dist/stratal-BCiwCFN9.mjs.map +1 -0
- package/dist/{types-DahElfUw.d.mts → types-DIWemRad.d.mts} +2 -2
- package/dist/types-DIWemRad.d.mts.map +1 -0
- package/dist/{usage-generator-CVIsENuE.mjs → usage-generator-MBcRo0Q2.mjs} +2 -2
- package/dist/{usage-generator-CVIsENuE.mjs.map → usage-generator-MBcRo0Q2.mjs.map} +1 -1
- package/dist/{validation-DQTC259A.mjs → validation-Dbg3ehdP.mjs} +2 -2
- package/dist/{validation-DQTC259A.mjs.map → validation-Dbg3ehdP.mjs.map} +1 -1
- package/dist/websocket/index.d.mts +3 -3
- package/dist/websocket/index.d.mts.map +1 -1
- package/dist/websocket/index.mjs +1 -4
- package/dist/workers/index.d.mts +2 -1
- package/dist/workers/index.d.mts.map +1 -1
- package/dist/workers/index.mjs +2 -20
- package/dist/workers/index.mjs.map +1 -1
- package/package.json +41 -50
- package/dist/application-DfPtIzxF.d.mts +0 -177
- package/dist/application-DfPtIzxF.d.mts.map +0 -1
- package/dist/command-B1CPgsrU.mjs.map +0 -1
- package/dist/cron-manager-CFBamKKk.mjs.map +0 -1
- package/dist/cron-manager-D7imGwUT.d.mts.map +0 -1
- package/dist/en-DaewN8hc.mjs.map +0 -1
- package/dist/errors-DSKapqD8.mjs +0 -707
- package/dist/errors-DSKapqD8.mjs.map +0 -1
- package/dist/errors-DuAR5Wke.mjs.map +0 -1
- package/dist/gateway-context-CNOLkLUC.mjs.map +0 -1
- package/dist/guards-DUk_Kzst.mjs.map +0 -1
- package/dist/i18n.module-Dn9SrFdS.mjs +0 -1841
- package/dist/i18n.module-Dn9SrFdS.mjs.map +0 -1
- package/dist/index-BFCxSp_f.d.mts +0 -2625
- package/dist/index-BFCxSp_f.d.mts.map +0 -1
- package/dist/index-DGRe6Yoa.d.mts.map +0 -1
- package/dist/index-NGxg-KP_.d.mts.map +0 -1
- package/dist/logger-CGT91VY6.mjs.map +0 -1
- package/dist/middleware/index.d.mts +0 -2
- package/dist/middleware/index.mjs +0 -5
- package/dist/middleware-Bl-b5pkt.mjs +0 -362
- package/dist/middleware-Bl-b5pkt.mjs.map +0 -1
- package/dist/module-registry-CmjBX6ol.d.mts +0 -121
- package/dist/module-registry-CmjBX6ol.d.mts.map +0 -1
- package/dist/module-tUtyVJ5E.mjs +0 -371
- package/dist/module-tUtyVJ5E.mjs.map +0 -1
- package/dist/openapi.service-DGnX3Fc4.d.mts.map +0 -1
- package/dist/quarry-registry-B2rkO-JS.mjs.map +0 -1
- package/dist/queue.module-BtI8f4Jo.mjs.map +0 -1
- package/dist/router-context-D9R1v2Ac.mjs +0 -267
- package/dist/router-context-D9R1v2Ac.mjs.map +0 -1
- package/dist/s3-storage.provider-CttzNnDR.mjs +0 -335
- package/dist/s3-storage.provider-CttzNnDR.mjs.map +0 -1
- package/dist/storage-CZKHOhci.mjs.map +0 -1
- package/dist/storage-provider.interface-0IqcdhBf.d.mts.map +0 -1
- package/dist/stratal-D5smIU1y.mjs +0 -315
- package/dist/stratal-D5smIU1y.mjs.map +0 -1
- package/dist/types-DahElfUw.d.mts.map +0 -1
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
import { A as Scope, H as ApplicationError, S as HttpException, k as ERROR_CODES } from "./errors-B4pYgYON.mjs";
|
|
2
|
+
import { a as isListener } from "./events-COKixqnG.mjs";
|
|
3
|
+
import { t as isCommand } from "./is-command-C6a7WTPw.mjs";
|
|
4
|
+
import { t as isSeeder } from "./is-seeder-CebjZCDn.mjs";
|
|
5
|
+
import { injectable, instancePerContainerCachingFactory, registry } from "tsyringe";
|
|
6
|
+
//#region src/module/errors/invalid-module-provider.error.ts
|
|
7
|
+
/**
|
|
8
|
+
* InvalidModuleProviderError
|
|
9
|
+
*
|
|
10
|
+
* Thrown when a module provider configuration is invalid.
|
|
11
|
+
* This indicates a misconfiguration in the @Module decorator providers array.
|
|
12
|
+
*/
|
|
13
|
+
var InvalidModuleProviderError = class extends ApplicationError {
|
|
14
|
+
constructor(provider) {
|
|
15
|
+
super("errors.invalidModuleProvider", ERROR_CODES.SYSTEM.INVALID_MODULE_PROVIDER, { provider: JSON.stringify(provider) });
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/module/module.decorator.ts
|
|
20
|
+
const MODULE_OPTIONS_KEY = Symbol.for("stratal:module:options");
|
|
21
|
+
/**
|
|
22
|
+
* `@Module` decorator - defines a module with imports, providers, controllers, consumers, jobs
|
|
23
|
+
*
|
|
24
|
+
* Uses tsyringe's `@registry` internally to auto-register providers when module is imported.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* @Module({
|
|
29
|
+
* imports: [OtherModule],
|
|
30
|
+
* providers: [MyService, MyRepository],
|
|
31
|
+
* controllers: [MyController],
|
|
32
|
+
* })
|
|
33
|
+
* export class MyModule {}
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function Module(options) {
|
|
37
|
+
return (target) => {
|
|
38
|
+
Reflect.defineMetadata(MODULE_OPTIONS_KEY, options, target);
|
|
39
|
+
const registryEntries = buildRegistryEntries(options.providers ?? []);
|
|
40
|
+
if (registryEntries.length > 0) registry(registryEntries)(target);
|
|
41
|
+
return target;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get module options from decorated class
|
|
46
|
+
*/
|
|
47
|
+
function getModuleOptions(target) {
|
|
48
|
+
return Reflect.getMetadata(MODULE_OPTIONS_KEY, target);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if a class is decorated with `@Module`
|
|
52
|
+
*/
|
|
53
|
+
function isModuleClass(target) {
|
|
54
|
+
return typeof target === "function" && Reflect.hasMetadata(MODULE_OPTIONS_KEY, target);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Convert our Provider types to tsyringe registry format
|
|
58
|
+
*
|
|
59
|
+
* Maps provider scope to tsyringe's lifecycle option.
|
|
60
|
+
* Scope enum values map directly to Lifecycle enum values.
|
|
61
|
+
*/
|
|
62
|
+
function buildRegistryEntries(providers) {
|
|
63
|
+
return providers.map((provider) => {
|
|
64
|
+
if (typeof provider === "function") return {
|
|
65
|
+
token: provider,
|
|
66
|
+
useClass: provider
|
|
67
|
+
};
|
|
68
|
+
if ("useClass" in provider) return {
|
|
69
|
+
token: provider.provide,
|
|
70
|
+
useClass: provider.useClass,
|
|
71
|
+
options: provider.scope !== void 0 ? { lifecycle: provider.scope } : void 0
|
|
72
|
+
};
|
|
73
|
+
if ("useValue" in provider) return {
|
|
74
|
+
token: provider.provide,
|
|
75
|
+
useValue: provider.useValue
|
|
76
|
+
};
|
|
77
|
+
if ("useFactory" in provider) {
|
|
78
|
+
const { provide, useFactory, inject = [] } = provider;
|
|
79
|
+
return {
|
|
80
|
+
token: provide,
|
|
81
|
+
useFactory: instancePerContainerCachingFactory((dependencyContainer) => {
|
|
82
|
+
return useFactory(...inject.map((token) => dependencyContainer.resolve(token)));
|
|
83
|
+
})
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if ("useExisting" in provider) return {
|
|
87
|
+
token: provider.provide,
|
|
88
|
+
useToken: provider.useExisting
|
|
89
|
+
};
|
|
90
|
+
throw new InvalidModuleProviderError(provider);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/router/errors/controller-method-not-found.error.ts
|
|
95
|
+
/**
|
|
96
|
+
* ControllerMethodNotFoundError
|
|
97
|
+
*
|
|
98
|
+
* Thrown when a controller method is registered but doesn't exist on the controller instance.
|
|
99
|
+
* This typically indicates a mismatch between route registration and controller implementation.
|
|
100
|
+
*/
|
|
101
|
+
var ControllerMethodNotFoundError = class extends ApplicationError {
|
|
102
|
+
constructor(methodName, controllerName) {
|
|
103
|
+
super("errors.controllerMethodNotFound", ERROR_CODES.ROUTER.CONTROLLER_METHOD_NOT_FOUND, {
|
|
104
|
+
methodName,
|
|
105
|
+
controllerName
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/router/errors/controller-registration.error.ts
|
|
111
|
+
/**
|
|
112
|
+
* Error thrown when a controller fails to register
|
|
113
|
+
*
|
|
114
|
+
* This typically happens when:
|
|
115
|
+
* - Controller is missing the `@Controller` decorator
|
|
116
|
+
* - Controller route metadata is not set
|
|
117
|
+
* - Controller class name is invalid
|
|
118
|
+
*
|
|
119
|
+
* Error Code: 9005
|
|
120
|
+
*/
|
|
121
|
+
var ControllerRegistrationError = class extends ApplicationError {
|
|
122
|
+
constructor(controllerName, reason) {
|
|
123
|
+
super("errors.controllerRegistration", ERROR_CODES.ROUTER.CONTROLLER_REGISTRATION_ERROR, {
|
|
124
|
+
controllerName,
|
|
125
|
+
reason
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/router/errors/hono-app-already-configured.error.ts
|
|
131
|
+
/**
|
|
132
|
+
* Error thrown when HonoApp.configure() is called more than once.
|
|
133
|
+
*
|
|
134
|
+
* HonoApp can only be configured a single time during application bootstrap.
|
|
135
|
+
*/
|
|
136
|
+
var HonoAppAlreadyConfiguredError = class extends ApplicationError {
|
|
137
|
+
constructor() {
|
|
138
|
+
super("errors.honoAppAlreadyConfigured", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/router/errors/openapi-route-registration.error.ts
|
|
143
|
+
/**
|
|
144
|
+
* OpenAPIRouteRegistrationError
|
|
145
|
+
*
|
|
146
|
+
* Thrown when an OpenAPI route fails to register properly
|
|
147
|
+
* This indicates a configuration issue with route decorators or metadata
|
|
148
|
+
* Uses i18n key for localized error messages
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* throw new OpenAPIRouteRegistrationError('/api/v1/users', 'Missing response schema')
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
var OpenAPIRouteRegistrationError = class extends ApplicationError {
|
|
156
|
+
constructor(path, reason) {
|
|
157
|
+
super("errors.openapiRouteRegistration", ERROR_CODES.ROUTER.OPENAPI_ROUTE_REGISTRATION, {
|
|
158
|
+
path,
|
|
159
|
+
reason
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region src/router/errors/openapi-validation.error.ts
|
|
165
|
+
/**
|
|
166
|
+
* OpenAPIValidationError
|
|
167
|
+
*
|
|
168
|
+
* Thrown when OpenAPI request/response validation fails
|
|
169
|
+
* Uses i18n key for localized error messages
|
|
170
|
+
*
|
|
171
|
+
* HTTP Status: 400 Bad Request
|
|
172
|
+
* Error Code: 1004
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* throw new OpenAPIValidationError('Request body missing required field: email')
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
var OpenAPIValidationError = class extends ApplicationError {
|
|
180
|
+
constructor(details) {
|
|
181
|
+
super("errors.openapiValidation", ERROR_CODES.VALIDATION.REQUEST_VALIDATION, { details });
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/router/errors/route-not-found.error.ts
|
|
186
|
+
/**
|
|
187
|
+
* Error thrown when a requested route is not found
|
|
188
|
+
*
|
|
189
|
+
* HTTP Status: 404 Not Found
|
|
190
|
+
* Error Code: 4004
|
|
191
|
+
*/
|
|
192
|
+
var RouteNotFoundError = class extends ApplicationError {
|
|
193
|
+
constructor(path, method) {
|
|
194
|
+
super("errors.routeNotFound", ERROR_CODES.RESOURCE.ROUTE_NOT_FOUND, {
|
|
195
|
+
path,
|
|
196
|
+
method
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/router/errors/schema-validation.error.ts
|
|
202
|
+
/**
|
|
203
|
+
* SchemaValidationError
|
|
204
|
+
*
|
|
205
|
+
* Thrown when Zod schema validation fails
|
|
206
|
+
*/
|
|
207
|
+
var SchemaValidationError = class extends ApplicationError {
|
|
208
|
+
constructor(zodError) {
|
|
209
|
+
const issues = zodError.issues.map((err) => ({
|
|
210
|
+
path: err.path.join("."),
|
|
211
|
+
message: err.message,
|
|
212
|
+
code: err.code
|
|
213
|
+
}));
|
|
214
|
+
super("errors.schemaValidation", ERROR_CODES.VALIDATION.SCHEMA_VALIDATION, { issues });
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/router/errors/index.ts
|
|
219
|
+
/**
|
|
220
|
+
* Error thrown when a request's host header does not match the expected domain pattern.
|
|
221
|
+
*
|
|
222
|
+
* HTTP Status: 404 Not Found
|
|
223
|
+
*/
|
|
224
|
+
var DomainMismatchError = class extends HttpException {
|
|
225
|
+
constructor() {
|
|
226
|
+
super(404, "errors.domainMismatch");
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Thrown when registering a named route that conflicts with an existing route name.
|
|
231
|
+
*
|
|
232
|
+
* Error Code: 9010
|
|
233
|
+
*/
|
|
234
|
+
var DuplicateRouteNameError = class extends ApplicationError {
|
|
235
|
+
constructor(name, existingHandler, newHandler) {
|
|
236
|
+
super("errors.duplicateRouteName", ERROR_CODES.ROUTER.DUPLICATE_ROUTE_NAME, {
|
|
237
|
+
name,
|
|
238
|
+
existingHandler,
|
|
239
|
+
newHandler
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
* Error thrown when a signed URL has an invalid or expired signature.
|
|
245
|
+
*
|
|
246
|
+
* HTTP Status: 403 Forbidden
|
|
247
|
+
*/
|
|
248
|
+
var InvalidSignatureError = class extends HttpException {
|
|
249
|
+
constructor() {
|
|
250
|
+
super(403, "errors.invalidSignature");
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Thrown when a required environment variable is not set.
|
|
255
|
+
*
|
|
256
|
+
* Maps to HTTP 500 via error code range (9xxx → 500).
|
|
257
|
+
*/
|
|
258
|
+
var MissingEnvironmentVariableError = class extends ApplicationError {
|
|
259
|
+
constructor(variable) {
|
|
260
|
+
super("errors.missingEnvironmentVariable", ERROR_CODES.SYSTEM.MISSING_ENVIRONMENT_VARIABLE, { variable });
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Thrown when a required path or domain parameter is missing during URL generation.
|
|
265
|
+
*
|
|
266
|
+
* Error Code: 9012
|
|
267
|
+
*/
|
|
268
|
+
var MissingRouteParamError = class extends ApplicationError {
|
|
269
|
+
constructor(param, name, path) {
|
|
270
|
+
super("errors.missingRouteParam", ERROR_CODES.ROUTER.MISSING_ROUTE_PARAM, {
|
|
271
|
+
param,
|
|
272
|
+
name,
|
|
273
|
+
path
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* ResponseValidationError
|
|
279
|
+
*
|
|
280
|
+
* Thrown when a controller's response body does not match the declared Zod response schema.
|
|
281
|
+
* Indicates a server-side schema mismatch — the controller is returning data that
|
|
282
|
+
* violates its own API contract.
|
|
283
|
+
*/
|
|
284
|
+
var ResponseValidationError = class extends ApplicationError {
|
|
285
|
+
constructor(zodError) {
|
|
286
|
+
const issues = zodError.issues.map((err) => ({
|
|
287
|
+
path: err.path.join("."),
|
|
288
|
+
message: err.message,
|
|
289
|
+
code: err.code
|
|
290
|
+
}));
|
|
291
|
+
super("errors.responseValidation", ERROR_CODES.VALIDATION.RESPONSE_VALIDATION, { issues });
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* Thrown when attempting to generate a URL for a route name that doesn't exist in the registry.
|
|
296
|
+
*
|
|
297
|
+
* Error Code: 9011
|
|
298
|
+
*/
|
|
299
|
+
var RouteNameNotFoundError = class extends ApplicationError {
|
|
300
|
+
constructor(name) {
|
|
301
|
+
super("errors.routeNameNotFound", ERROR_CODES.ROUTER.ROUTE_NAME_NOT_FOUND, { name });
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
/**
|
|
305
|
+
* Thrown when `router.use()` is called inside a `group()` callback.
|
|
306
|
+
* `use()` registers global middleware and is only allowed on the root Router.
|
|
307
|
+
*
|
|
308
|
+
* Error Code: 9013
|
|
309
|
+
*/
|
|
310
|
+
var RouterUseScopeError = class extends ApplicationError {
|
|
311
|
+
constructor() {
|
|
312
|
+
super("errors.routerUseScopeViolation", ERROR_CODES.ROUTER.USE_SCOPE_VIOLATION);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Thrown when a middleware calls next() more than once.
|
|
317
|
+
* This is a programming error — each middleware must call next() at most once.
|
|
318
|
+
*
|
|
319
|
+
* Error Code: 9014
|
|
320
|
+
*/
|
|
321
|
+
var MiddlewareNextCalledMultipleTimesError = class extends ApplicationError {
|
|
322
|
+
constructor(middlewareName) {
|
|
323
|
+
super("errors.middlewareNextCalledMultipleTimes", ERROR_CODES.ROUTER.MIDDLEWARE_NEXT_CALLED_MULTIPLE_TIMES, { middlewareName });
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
//#endregion
|
|
327
|
+
//#region src/router/router.internals.ts
|
|
328
|
+
/**
|
|
329
|
+
* Symbol keys for Router internal accessors.
|
|
330
|
+
*
|
|
331
|
+
* These symbols are NOT exported from the public `stratal/router` barrel.
|
|
332
|
+
* Only internal modules (RouterResolver) import them, keeping the Router's
|
|
333
|
+
* public API clean — users never see these methods.
|
|
334
|
+
*
|
|
335
|
+
* Declared as individual unique symbols so TypeScript can distinguish
|
|
336
|
+
* their return types in computed property access.
|
|
337
|
+
*
|
|
338
|
+
* @internal
|
|
339
|
+
*/
|
|
340
|
+
/** @internal */
|
|
341
|
+
const getDefaultEntry = Symbol("Router.getDefaultEntry");
|
|
342
|
+
/** @internal */
|
|
343
|
+
const getGroups = Symbol("Router.getGroups");
|
|
344
|
+
/** @internal */
|
|
345
|
+
const getGlobalMiddleware = Symbol("Router.getGlobalMiddleware");
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/router/router.ts
|
|
348
|
+
/**
|
|
349
|
+
* Fluent builder for route and middleware configuration.
|
|
350
|
+
*
|
|
351
|
+
* Scoped methods (`middleware()`, `prefix()`, `domain()`, `name()`, `version()`, `hideFromDocs()`)
|
|
352
|
+
* apply only to this module's controllers or the sub-group's controllers.
|
|
353
|
+
*
|
|
354
|
+
* `use()` registers global middleware (all routes in the entire app).
|
|
355
|
+
* Only callable on the root Router — throws inside `group()` callbacks.
|
|
356
|
+
*
|
|
357
|
+
* `group()` creates sub-groups for specific controllers with a callback.
|
|
358
|
+
* Controllers in a sub-group are excluded from the parent scope.
|
|
359
|
+
*/
|
|
360
|
+
var Router = class Router {
|
|
361
|
+
_isChild;
|
|
362
|
+
_defaultEntry = { middleware: [] };
|
|
363
|
+
_groups = [];
|
|
364
|
+
_globalMiddleware = [];
|
|
365
|
+
constructor(isChild = false) {
|
|
366
|
+
this._isChild = isChild;
|
|
367
|
+
}
|
|
368
|
+
/** Dynamic path prefix. For shared segments like `/:companyId` */
|
|
369
|
+
prefix(path, params) {
|
|
370
|
+
this._defaultEntry.prefix = path;
|
|
371
|
+
this._defaultEntry.params = params;
|
|
372
|
+
return this;
|
|
373
|
+
}
|
|
374
|
+
/** Domain pattern for controllers in this scope */
|
|
375
|
+
domain(pattern) {
|
|
376
|
+
this._defaultEntry.domain = pattern;
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
/** Name prefix for routes in this scope */
|
|
380
|
+
name(prefix) {
|
|
381
|
+
this._defaultEntry.name = prefix;
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
384
|
+
/** Middleware applied to controllers in this scope */
|
|
385
|
+
middleware(...middlewares) {
|
|
386
|
+
this._defaultEntry.middleware.push(...middlewares);
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
/** API version for controllers in this scope */
|
|
390
|
+
version(version) {
|
|
391
|
+
this._defaultEntry.version = version;
|
|
392
|
+
return this;
|
|
393
|
+
}
|
|
394
|
+
/** Hide/show routes in this scope from OpenAPI docs */
|
|
395
|
+
hideFromDocs(hide = true) {
|
|
396
|
+
this._defaultEntry.hideFromDocs = hide;
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Global middleware — applied to ALL routes in the entire app.
|
|
401
|
+
* Only callable on the root Router. Throws if called inside `group()`.
|
|
402
|
+
*/
|
|
403
|
+
use(...middlewares) {
|
|
404
|
+
if (this._isChild) throw new RouterUseScopeError();
|
|
405
|
+
this._globalMiddleware.push(...middlewares);
|
|
406
|
+
return this;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Create a sub-group for specific controllers/gateways.
|
|
410
|
+
* Controllers in a sub-group are excluded from the parent (default) scope.
|
|
411
|
+
* The callback receives a new Router (without `use()`) for fluent configuration.
|
|
412
|
+
*/
|
|
413
|
+
group(controllers, callback) {
|
|
414
|
+
const childRouter = new Router(true);
|
|
415
|
+
callback(childRouter);
|
|
416
|
+
this._groups.push({
|
|
417
|
+
...childRouter._defaultEntry,
|
|
418
|
+
controllers
|
|
419
|
+
});
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
[getDefaultEntry]() {
|
|
423
|
+
return this._defaultEntry;
|
|
424
|
+
}
|
|
425
|
+
[getGroups]() {
|
|
426
|
+
return this._groups;
|
|
427
|
+
}
|
|
428
|
+
[getGlobalMiddleware]() {
|
|
429
|
+
return this._globalMiddleware;
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/module/module-registry.ts
|
|
434
|
+
/**
|
|
435
|
+
* Module Registry
|
|
436
|
+
*
|
|
437
|
+
* Manages module lifecycle for the @Module decorator pattern.
|
|
438
|
+
* Simplified for tsyringe's flat container model:
|
|
439
|
+
* - Imports are traversed for registration (organization only)
|
|
440
|
+
* - Modules registered in declaration order
|
|
441
|
+
* - Lifecycle hooks: onInitialize, onShutdown
|
|
442
|
+
*/
|
|
443
|
+
/**
|
|
444
|
+
* ModuleRegistry - manages module lifecycle
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```typescript
|
|
448
|
+
* const registry = new ModuleRegistry(container, logger)
|
|
449
|
+
* registry.register(AppModule) // Traverses imports recursively
|
|
450
|
+
* await registry.initialize()
|
|
451
|
+
* // ... application running ...
|
|
452
|
+
* await registry.shutdown()
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
var ModuleRegistry = class {
|
|
456
|
+
modules = [];
|
|
457
|
+
registeredClasses = /* @__PURE__ */ new Set();
|
|
458
|
+
initialized = false;
|
|
459
|
+
allControllers = [];
|
|
460
|
+
allConsumers = [];
|
|
461
|
+
allJobs = [];
|
|
462
|
+
allListeners = [];
|
|
463
|
+
allCommands = [];
|
|
464
|
+
allSeeders = [];
|
|
465
|
+
allRouterConfigs = [];
|
|
466
|
+
constructor(container, logger) {
|
|
467
|
+
this.container = container;
|
|
468
|
+
this.logger = logger;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Register a module (static or dynamic)
|
|
472
|
+
*
|
|
473
|
+
* @param moduleOrDynamic - Module class decorated with `@Module` or DynamicModule from configure()
|
|
474
|
+
*/
|
|
475
|
+
register(moduleOrDynamic) {
|
|
476
|
+
const { moduleClass, options } = this.resolveModule(moduleOrDynamic);
|
|
477
|
+
const isDynamic = this.isDynamicModule(moduleOrDynamic);
|
|
478
|
+
if (this.registeredClasses.has(moduleClass)) {
|
|
479
|
+
if (isDynamic) {
|
|
480
|
+
this.logger.debug(`Module ${moduleClass.name} already registered, registering DynamicModule providers`);
|
|
481
|
+
const { module: _, ...dynamicRest } = moduleOrDynamic;
|
|
482
|
+
for (const provider of dynamicRest.providers ?? []) this.registerProvider(provider);
|
|
483
|
+
} else this.logger.debug(`Module ${moduleClass.name} already registered, skipping`);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
this.registeredClasses.add(moduleClass);
|
|
487
|
+
this.logger.info(`Registering module: ${moduleClass.name}`);
|
|
488
|
+
for (const ImportedModule of options.imports ?? []) this.register(ImportedModule);
|
|
489
|
+
for (const provider of options.providers ?? []) this.registerProvider(provider);
|
|
490
|
+
for (const controller of options.controllers ?? []) {
|
|
491
|
+
this.container.register(controller);
|
|
492
|
+
this.allControllers.push(controller);
|
|
493
|
+
}
|
|
494
|
+
for (const consumer of options.consumers ?? []) {
|
|
495
|
+
this.container.register(consumer, Scope.Singleton);
|
|
496
|
+
this.allConsumers.push(consumer);
|
|
497
|
+
this.logger.info(`Collected consumer: ${consumer.name}`, { queueCount: this.allConsumers.length });
|
|
498
|
+
}
|
|
499
|
+
for (const job of options.jobs ?? []) {
|
|
500
|
+
this.container.register(job, Scope.Singleton);
|
|
501
|
+
this.allJobs.push(job);
|
|
502
|
+
}
|
|
503
|
+
this.modules.push({
|
|
504
|
+
moduleClass,
|
|
505
|
+
options,
|
|
506
|
+
instance: null
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Register multiple modules in order
|
|
511
|
+
*/
|
|
512
|
+
registerAll(modules) {
|
|
513
|
+
for (const module of modules) this.register(module);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Initialize all modules (call configure and onInitialize hooks)
|
|
517
|
+
*/
|
|
518
|
+
async initialize() {
|
|
519
|
+
if (this.initialized) return;
|
|
520
|
+
this.logger.info("Initializing modules...");
|
|
521
|
+
const context = {
|
|
522
|
+
container: this.container,
|
|
523
|
+
logger: this.logger
|
|
524
|
+
};
|
|
525
|
+
for (const registered of this.modules) {
|
|
526
|
+
const instance = new registered.moduleClass();
|
|
527
|
+
registered.instance = instance;
|
|
528
|
+
if (this.hasOnInitialize(instance)) {
|
|
529
|
+
this.logger.info(`Initializing: ${registered.moduleClass.name}`);
|
|
530
|
+
await instance.onInitialize(context);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
this.initialized = true;
|
|
534
|
+
this.logger.info("All modules initialized");
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Get all controllers registered from all modules
|
|
538
|
+
*/
|
|
539
|
+
getAllControllers() {
|
|
540
|
+
return this.allControllers;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Get all consumers registered from all modules
|
|
544
|
+
*/
|
|
545
|
+
getAllConsumers() {
|
|
546
|
+
return this.allConsumers;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Get all jobs registered from all modules
|
|
550
|
+
*/
|
|
551
|
+
getAllJobs() {
|
|
552
|
+
return this.allJobs;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Get all listeners registered from all modules
|
|
556
|
+
*/
|
|
557
|
+
getAllListeners() {
|
|
558
|
+
return this.allListeners;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Get all commands registered from all modules
|
|
562
|
+
*/
|
|
563
|
+
getAllCommands() {
|
|
564
|
+
return this.allCommands;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Get all seeders registered from all modules
|
|
568
|
+
*/
|
|
569
|
+
getAllSeeders() {
|
|
570
|
+
return this.allSeeders;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Get all Router configurations from modules implementing RouteConfigurable.
|
|
574
|
+
* Runs configureRoutes() lazily on first call (deferred from initialize()).
|
|
575
|
+
*/
|
|
576
|
+
getAllRouterConfigs() {
|
|
577
|
+
if (this.allRouterConfigs.length === 0) {
|
|
578
|
+
for (const { moduleClass, options, instance } of this.modules) if (instance && this.hasRouteConfigurable(instance)) {
|
|
579
|
+
this.logger.debug(`Configuring routes for: ${moduleClass.name}`);
|
|
580
|
+
const router = new Router();
|
|
581
|
+
instance.configureRoutes(router);
|
|
582
|
+
const moduleControllers = options.controllers ?? [];
|
|
583
|
+
this.allRouterConfigs.push({
|
|
584
|
+
router,
|
|
585
|
+
controllers: moduleControllers
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return this.allRouterConfigs;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Call `onException()` on all modules that implement the OnException interface.
|
|
593
|
+
* Invoked by Application after the ExceptionHandler is resolved and `register()` is called.
|
|
594
|
+
*
|
|
595
|
+
* @param handler - The resolved ExceptionHandler instance
|
|
596
|
+
*/
|
|
597
|
+
configureExceptionHandlers(handler) {
|
|
598
|
+
for (const { moduleClass, instance } of this.modules) if (instance && this.hasOnException(instance)) {
|
|
599
|
+
this.logger.debug(`Configuring exception handlers for: ${moduleClass.name}`);
|
|
600
|
+
instance.onException(handler);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Shutdown all modules (call onShutdown hooks in reverse order)
|
|
605
|
+
*/
|
|
606
|
+
async shutdown() {
|
|
607
|
+
this.logger.info("Shutting down modules...");
|
|
608
|
+
const context = {
|
|
609
|
+
container: this.container,
|
|
610
|
+
logger: this.logger
|
|
611
|
+
};
|
|
612
|
+
const reversed = [...this.modules].reverse();
|
|
613
|
+
for (const { moduleClass, instance } of reversed) if (instance && this.hasOnShutdown(instance)) try {
|
|
614
|
+
await instance.onShutdown(context);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
this.logger.error(`Error shutting down ${moduleClass.name}:`, error);
|
|
617
|
+
}
|
|
618
|
+
this.logger.info("All modules shut down");
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Type guard for RouteConfigurable
|
|
622
|
+
*/
|
|
623
|
+
hasRouteConfigurable(instance) {
|
|
624
|
+
return typeof instance === "object" && instance !== null && "configureRoutes" in instance && typeof instance.configureRoutes === "function";
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Type guard for OnInitialize
|
|
628
|
+
*/
|
|
629
|
+
hasOnInitialize(instance) {
|
|
630
|
+
return typeof instance === "object" && instance !== null && "onInitialize" in instance && typeof instance.onInitialize === "function";
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Type guard for OnShutdown
|
|
634
|
+
*/
|
|
635
|
+
hasOnShutdown(instance) {
|
|
636
|
+
return typeof instance === "object" && instance !== null && "onShutdown" in instance && typeof instance.onShutdown === "function";
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Type guard for OnException
|
|
640
|
+
*/
|
|
641
|
+
hasOnException(instance) {
|
|
642
|
+
return typeof instance === "object" && instance !== null && "onException" in instance && typeof instance.onException === "function";
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Resolve module class and options from static or dynamic module
|
|
646
|
+
*
|
|
647
|
+
* For DynamicModules, merges the decorator metadata (consumers, controllers, jobs)
|
|
648
|
+
* with the DynamicModule options (providers, imports). This ensures modules using
|
|
649
|
+
* forRoot/forRootAsync patterns still have their decorator-defined consumers registered.
|
|
650
|
+
*/
|
|
651
|
+
resolveModule(moduleOrDynamic) {
|
|
652
|
+
if (this.isDynamicModule(moduleOrDynamic)) {
|
|
653
|
+
const { module: moduleClass, ...dynamicRest } = moduleOrDynamic;
|
|
654
|
+
const decoratorOptions = getModuleOptions(moduleClass) ?? {};
|
|
655
|
+
return {
|
|
656
|
+
moduleClass,
|
|
657
|
+
options: {
|
|
658
|
+
...decoratorOptions,
|
|
659
|
+
...dynamicRest,
|
|
660
|
+
providers: [...decoratorOptions.providers ?? [], ...dynamicRest.providers ?? []],
|
|
661
|
+
imports: [...decoratorOptions.imports ?? []]
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
const moduleClass = moduleOrDynamic;
|
|
666
|
+
return {
|
|
667
|
+
moduleClass,
|
|
668
|
+
options: getModuleOptions(moduleClass) ?? {}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Type guard for DynamicModule
|
|
673
|
+
*/
|
|
674
|
+
isDynamicModule(value) {
|
|
675
|
+
return typeof value === "object" && value !== null && "module" in value && typeof value.module === "function";
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Register a single provider in the container
|
|
679
|
+
*/
|
|
680
|
+
registerProvider(provider) {
|
|
681
|
+
if (typeof provider === "function") {
|
|
682
|
+
this.container.register(provider);
|
|
683
|
+
this.collectIfListener(provider);
|
|
684
|
+
this.collectIfCommand(provider);
|
|
685
|
+
this.collectIfSeeder(provider);
|
|
686
|
+
} else if ("useClass" in provider) {
|
|
687
|
+
this.container.register(provider.provide, provider.useClass, provider.scope);
|
|
688
|
+
this.collectIfListener(provider.useClass);
|
|
689
|
+
this.collectIfCommand(provider.useClass);
|
|
690
|
+
this.collectIfSeeder(provider.useClass);
|
|
691
|
+
} else if ("useValue" in provider) this.container.registerValue(provider.provide, provider.useValue);
|
|
692
|
+
else if ("useFactory" in provider) {
|
|
693
|
+
const { provide, useFactory, inject = [] } = provider;
|
|
694
|
+
this.container.getTsyringeContainer().register(provide, { useFactory: instancePerContainerCachingFactory((dependencyContainer) => {
|
|
695
|
+
return useFactory(...inject.map((token) => dependencyContainer.resolve(token)));
|
|
696
|
+
}) });
|
|
697
|
+
} else if ("useExisting" in provider) this.container.registerExisting(provider.provide, provider.useExisting);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Check if a class is a `Command` and collect it for auto-wiring
|
|
701
|
+
*/
|
|
702
|
+
collectIfCommand(providerClass) {
|
|
703
|
+
if (isCommand(providerClass) && !this.allCommands.includes(providerClass)) {
|
|
704
|
+
injectable()(providerClass);
|
|
705
|
+
this.allCommands.push(providerClass);
|
|
706
|
+
this.logger.debug(`Collected command: ${providerClass.name}`);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Check if a class is a `Seeder` and collect it for auto-wiring
|
|
711
|
+
*/
|
|
712
|
+
collectIfSeeder(providerClass) {
|
|
713
|
+
if (isSeeder(providerClass) && !this.allSeeders.includes(providerClass)) {
|
|
714
|
+
this.allSeeders.push(providerClass);
|
|
715
|
+
this.logger.debug(`Collected seeder: ${providerClass.name}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Check if a class is a `@Listener()` and collect it for auto-wiring
|
|
720
|
+
*/
|
|
721
|
+
collectIfListener(providerClass) {
|
|
722
|
+
if (isListener(providerClass)) {
|
|
723
|
+
this.container.register(providerClass, providerClass, Scope.Singleton);
|
|
724
|
+
this.allListeners.push(providerClass);
|
|
725
|
+
this.logger.debug(`Collected listener: ${providerClass.name}`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
//#endregion
|
|
730
|
+
export { Module as C, MODULE_OPTIONS_KEY as S, isModuleClass as T, OpenAPIValidationError as _, getGroups as a, ControllerRegistrationError as b, InvalidSignatureError as c, MissingRouteParamError as d, ResponseValidationError as f, RouteNotFoundError as g, SchemaValidationError as h, getGlobalMiddleware as i, MiddlewareNextCalledMultipleTimesError as l, RouterUseScopeError as m, Router as n, DomainMismatchError as o, RouteNameNotFoundError as p, getDefaultEntry as r, DuplicateRouteNameError as s, ModuleRegistry as t, MissingEnvironmentVariableError as u, OpenAPIRouteRegistrationError as v, getModuleOptions as w, ControllerMethodNotFoundError as x, HonoAppAlreadyConfiguredError as y };
|
|
731
|
+
|
|
732
|
+
//# sourceMappingURL=module-qGE_1duv.mjs.map
|