@smounters/imperium 1.0.0

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.
Files changed (78) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +227 -0
  4. package/dist/core/app-tokens.d.ts +5 -0
  5. package/dist/core/app-tokens.js +4 -0
  6. package/dist/core/application.d.ts +34 -0
  7. package/dist/core/application.js +252 -0
  8. package/dist/core/config.d.ts +1 -0
  9. package/dist/core/config.js +1 -0
  10. package/dist/core/container.d.ts +76 -0
  11. package/dist/core/container.js +687 -0
  12. package/dist/core/errors.d.ts +31 -0
  13. package/dist/core/errors.js +169 -0
  14. package/dist/core/index.d.ts +5 -0
  15. package/dist/core/index.js +4 -0
  16. package/dist/core/logger.d.ts +7 -0
  17. package/dist/core/logger.js +12 -0
  18. package/dist/core/reflector.d.ts +9 -0
  19. package/dist/core/reflector.js +39 -0
  20. package/dist/core/server.d.ts +10 -0
  21. package/dist/core/server.js +296 -0
  22. package/dist/core/types.d.ts +25 -0
  23. package/dist/core/types.js +1 -0
  24. package/dist/decorators/di.decorators.d.ts +10 -0
  25. package/dist/decorators/di.decorators.js +15 -0
  26. package/dist/decorators/filters.decorators.d.ts +6 -0
  27. package/dist/decorators/filters.decorators.js +16 -0
  28. package/dist/decorators/guards.decorators.d.ts +4 -0
  29. package/dist/decorators/guards.decorators.js +8 -0
  30. package/dist/decorators/http.decorators.d.ts +16 -0
  31. package/dist/decorators/http.decorators.js +60 -0
  32. package/dist/decorators/index.d.ts +8 -0
  33. package/dist/decorators/index.js +8 -0
  34. package/dist/decorators/interceptors.decorators.d.ts +4 -0
  35. package/dist/decorators/interceptors.decorators.js +8 -0
  36. package/dist/decorators/metadata.decorators.d.ts +4 -0
  37. package/dist/decorators/metadata.decorators.js +22 -0
  38. package/dist/decorators/pipes.decorators.d.ts +4 -0
  39. package/dist/decorators/pipes.decorators.js +8 -0
  40. package/dist/decorators/rpc.decorators.d.ts +11 -0
  41. package/dist/decorators/rpc.decorators.js +50 -0
  42. package/dist/http/adapter.d.ts +4 -0
  43. package/dist/http/adapter.js +199 -0
  44. package/dist/http/index.d.ts +3 -0
  45. package/dist/http/index.js +3 -0
  46. package/dist/http/router-builder.d.ts +4 -0
  47. package/dist/http/router-builder.js +30 -0
  48. package/dist/http/utils.d.ts +6 -0
  49. package/dist/http/utils.js +46 -0
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.js +1 -0
  52. package/dist/pipes/index.d.ts +1 -0
  53. package/dist/pipes/index.js +1 -0
  54. package/dist/pipes/zod.pipe.d.ts +7 -0
  55. package/dist/pipes/zod.pipe.js +8 -0
  56. package/dist/rpc/adapter.d.ts +7 -0
  57. package/dist/rpc/adapter.js +186 -0
  58. package/dist/rpc/index.d.ts +3 -0
  59. package/dist/rpc/index.js +3 -0
  60. package/dist/rpc/router-builder.d.ts +4 -0
  61. package/dist/rpc/router-builder.js +28 -0
  62. package/dist/rpc/utils.d.ts +6 -0
  63. package/dist/rpc/utils.js +46 -0
  64. package/dist/services/config.service.d.ts +10 -0
  65. package/dist/services/config.service.js +41 -0
  66. package/dist/services/index.d.ts +2 -0
  67. package/dist/services/index.js +2 -0
  68. package/dist/services/logger.service.d.ts +30 -0
  69. package/dist/services/logger.service.js +52 -0
  70. package/dist/types.d.ts +167 -0
  71. package/dist/types.js +1 -0
  72. package/dist/validation/app-config.d.ts +30 -0
  73. package/dist/validation/app-config.js +25 -0
  74. package/dist/validation/common.d.ts +8 -0
  75. package/dist/validation/common.js +57 -0
  76. package/dist/validation/index.d.ts +2 -0
  77. package/dist/validation/index.js +2 -0
  78. package/package.json +98 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@smounters/imperium` are documented in this file.
4
+
5
+ ## 0.1.0 - 2026-02-22
6
+
7
+ - Initial public package setup.
8
+ - Unified HTTP + ConnectRPC runtime on Fastify.
9
+ - NestJS-inspired module/decorator/DI API.
10
+ - Typed `Application` bootstrap with pre-start `configureConfig` and `configureLogger`.
11
+ - Multi provider intent metadata (`multi`) and array resolution via `InjectAll` / `resolveAll`.
12
+ - VitePress documentation and GitHub Pages workflow.
13
+ - npm publish workflow with `pnpm`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CryppEX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # @smounters/imperium
2
+
3
+ `@smounters/imperium` is **inspired by NestJS** and provides a modular DI-first runtime for TypeScript services using Fastify + ConnectRPC.
4
+
5
+ It is designed for teams that want Nest-like architecture but with explicit control over runtime wiring and exported API surface.
6
+
7
+ ## Key Features
8
+
9
+ - Nest-like modules and decorators (`@Module`, `@Injectable`, guards/pipes/interceptors/filters).
10
+ - Unified HTTP + RPC server on one Fastify instance.
11
+ - Request-scoped handler execution.
12
+ - Typed runtime config via `zod` + `ConfigService`.
13
+ - Built-in `LoggerService` (tslog-based).
14
+ - Global enhancer tokens (`APP_GUARD`, `APP_PIPE`, `APP_INTERCEPTOR`, `APP_FILTER`).
15
+ - Multi-provider array injection (`InjectAll`) and manual array resolution (`resolveAll`).
16
+
17
+ ## Public Imports
18
+
19
+ Root import is intentionally disabled.
20
+
21
+ Use subpaths only:
22
+
23
+ - `@smounters/imperium/core`
24
+ - `@smounters/imperium/decorators`
25
+ - `@smounters/imperium/services`
26
+ - `@smounters/imperium/pipes`
27
+ - `@smounters/imperium/validation`
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pnpm add @smounters/imperium reflect-metadata tsyringe fastify @connectrpc/connect @connectrpc/connect-fastify zod
33
+ ```
34
+
35
+ TypeScript requirements:
36
+
37
+ ```json
38
+ {
39
+ "compilerOptions": {
40
+ "experimentalDecorators": true,
41
+ "emitDecoratorMetadata": true
42
+ }
43
+ }
44
+ ```
45
+
46
+ Entry point must import metadata:
47
+
48
+ ```ts
49
+ import "reflect-metadata";
50
+ ```
51
+
52
+ ## Quick Start
53
+
54
+ ```ts
55
+ import "reflect-metadata";
56
+
57
+ import { Application } from "@smounters/imperium/core";
58
+ import { Body, HttpController, Injectable, Module, Post } from "@smounters/imperium/decorators";
59
+
60
+ @Injectable()
61
+ class AuthService {
62
+ signIn(email: string) {
63
+ return { ok: true, email };
64
+ }
65
+ }
66
+
67
+ @HttpController("/auth")
68
+ class AuthHttpController {
69
+ constructor(private readonly authService: AuthService) {}
70
+
71
+ @Post("/sign-in")
72
+ signIn(@Body("email") email: string) {
73
+ return this.authService.signIn(email);
74
+ }
75
+ }
76
+
77
+ @Module({
78
+ providers: [AuthService],
79
+ httpControllers: [AuthHttpController],
80
+ })
81
+ class AppModule {}
82
+
83
+ const app = new Application(AppModule, {
84
+ host: "0.0.0.0",
85
+ accessLogs: true,
86
+ });
87
+
88
+ await app.start({ port: 3000 });
89
+ ```
90
+
91
+ ## Recommended Bootstrap Flow
92
+
93
+ ```ts
94
+ import { Application } from "@smounters/imperium/core";
95
+ import { ConfigService, LoggerService } from "@smounters/imperium/services";
96
+ import { z } from "zod";
97
+
98
+ const appConfigSchema = z.object({
99
+ APP_PORT: z.coerce.number().default(8000),
100
+ APP_GLOBAL_PREFIX: z.string().default(""),
101
+ });
102
+
103
+ type AppConfig = z.infer<typeof appConfigSchema>;
104
+
105
+ const app = new Application(AppModule, {
106
+ host: "0.0.0.0",
107
+ accessLogs: true,
108
+ });
109
+
110
+ app.configureConfig(appConfigSchema, process.env);
111
+
112
+ const config = app.resolve(ConfigService<AppConfig>).getAll();
113
+
114
+ app.configureLogger({
115
+ name: "backend",
116
+ minLevel: 3,
117
+ });
118
+
119
+ await app.start({
120
+ port: config.APP_PORT,
121
+ prefix: config.APP_GLOBAL_PREFIX,
122
+ });
123
+
124
+ app.resolve(LoggerService).info({ event: "app.started", port: config.APP_PORT });
125
+ ```
126
+
127
+ ## Multi Providers
128
+
129
+ ```ts
130
+ import { InjectAll, Injectable, Module } from "@smounters/imperium/decorators";
131
+
132
+ const AML_RULES = Symbol("AML_RULES");
133
+
134
+ @Module({
135
+ providers: [
136
+ { provide: AML_RULES, multi: true, useClass: SanctionsRule },
137
+ { provide: AML_RULES, multi: true, useClass: MixerRule },
138
+ { provide: AML_RULES, multi: true, useClass: FreshAddressRule },
139
+ ],
140
+ exports: [AML_RULES],
141
+ })
142
+ class AmlModule {}
143
+
144
+ @Injectable()
145
+ class AmlEngine {
146
+ constructor(@InjectAll(AML_RULES) private readonly rules: AmlRule[]) {}
147
+ }
148
+ ```
149
+
150
+ Manual resolution is also available:
151
+
152
+ ```ts
153
+ const rules = app.resolveAll<AmlRule>(AML_RULES);
154
+ ```
155
+
156
+ ## HTTP and RPC
157
+
158
+ Use decorators from `@smounters/imperium/decorators`:
159
+
160
+ - HTTP: `HttpController`, `Get`, `Post`, `Put`, `Patch`, `Delete`, `Body`, `Query`, `Param`, `Header`, `Req`, `Res`
161
+ - RPC: `RpcService`, `RpcMethod`, `RpcData`, `RpcContext`, `RpcHeaders`, `RpcHeader`
162
+
163
+ Imperium auto-detects registered HTTP/RPC handlers and serves both protocols from one server.
164
+
165
+ ## Services
166
+
167
+ From `@smounters/imperium/services`:
168
+
169
+ - `ConfigService`
170
+ - `LoggerService`
171
+
172
+ ## Pipes and Validation
173
+
174
+ - `ZodPipe` from `@smounters/imperium/pipes`
175
+ - validation helpers from `@smounters/imperium/validation`
176
+ - `booleanSchema`
177
+ - `numberSchema`
178
+ - `nativeEnumSchema`
179
+ - `stringArraySchema`
180
+ - `enumArraySchema`
181
+
182
+ ## Error Classes
183
+
184
+ From `@smounters/imperium/core`:
185
+
186
+ - `HttpException`
187
+ - `BadRequestException`
188
+ - `UnauthorizedException`
189
+ - `ForbiddenException`
190
+ - `NotFoundException`
191
+ - `InternalServerErrorException`
192
+
193
+ ## Documentation
194
+
195
+ Full docs (VitePress) are located in:
196
+
197
+ - `docs`
198
+
199
+ Local docs commands:
200
+
201
+ ```bash
202
+ pnpm run docs:dev
203
+ pnpm run docs:build
204
+ ```
205
+
206
+ GitHub Pages deployment is configured via `.github/workflows/publish.yml`.
207
+
208
+ ## Publish to npm
209
+
210
+ ```bash
211
+ pnpm install
212
+ pnpm run typecheck
213
+ pnpm run build
214
+ pnpm publish --access public --no-git-checks
215
+ ```
216
+
217
+ Automated npm publishing workflow:
218
+
219
+ - `.github/workflows/publish.yml`
220
+
221
+ Required secret:
222
+
223
+ - `NPM_TOKEN`
224
+
225
+ ## License
226
+
227
+ MIT
@@ -0,0 +1,5 @@
1
+ import type { ExceptionFilterLike, GuardLike, InjectionToken, InterceptorLike, PipeLike } from "../types";
2
+ export declare const APP_GUARD: InjectionToken<GuardLike>;
3
+ export declare const APP_INTERCEPTOR: InjectionToken<InterceptorLike>;
4
+ export declare const APP_PIPE: InjectionToken<PipeLike>;
5
+ export declare const APP_FILTER: InjectionToken<ExceptionFilterLike>;
@@ -0,0 +1,4 @@
1
+ export const APP_GUARD = Symbol("app:guard");
2
+ export const APP_INTERCEPTOR = Symbol("app:interceptor");
3
+ export const APP_PIPE = Symbol("app:pipe");
4
+ export const APP_FILTER = Symbol("app:filter");
@@ -0,0 +1,34 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import type { InjectionToken, LoggerOptions, ModuleImport, ServerOptions } from "../types";
3
+ import type { ZodType, output } from "zod";
4
+ import { AppContainer } from "./container";
5
+ export declare class Application {
6
+ private static readonly DEFAULT_SHUTDOWN_SIGNALS;
7
+ private static readonly DEFAULT_SHUTDOWN_TIMEOUT_MS;
8
+ private readonly moduleImport;
9
+ private readonly di;
10
+ private options;
11
+ private readonly signalHandlers;
12
+ private moduleLoaded;
13
+ private loggerConfiguredExplicitly;
14
+ private server;
15
+ private startPromise;
16
+ private shutdownInProgress;
17
+ constructor(moduleClass: ModuleImport, options?: ServerOptions);
18
+ getContainer(): AppContainer;
19
+ resolve<T>(token: InjectionToken<T>): T;
20
+ resolveAll<T>(token: InjectionToken<T>): T[];
21
+ getServerOptions(): Readonly<ServerOptions>;
22
+ setServerOptions(options: ServerOptions): this;
23
+ configureLogger(options?: LoggerOptions): this;
24
+ configureConfig<TSchema extends ZodType>(schema: TSchema, source?: unknown): output<TSchema>;
25
+ getServer(): FastifyInstance;
26
+ start(options?: ServerOptions): Promise<FastifyInstance>;
27
+ close(signal?: string): Promise<void>;
28
+ private resolveGracefulShutdownOptions;
29
+ private installSignalHandlers;
30
+ private removeSignalHandlers;
31
+ private handleShutdownSignal;
32
+ private assertConfigurable;
33
+ private ensureModuleLoaded;
34
+ }
@@ -0,0 +1,252 @@
1
+ import { AppContainer } from "./container";
2
+ import { startServer } from "./server";
3
+ export class Application {
4
+ static { this.DEFAULT_SHUTDOWN_SIGNALS = ["SIGINT", "SIGTERM"]; }
5
+ static { this.DEFAULT_SHUTDOWN_TIMEOUT_MS = 15_000; }
6
+ constructor(moduleClass, options = {}) {
7
+ this.signalHandlers = new Map();
8
+ this.moduleLoaded = false;
9
+ this.loggerConfiguredExplicitly = false;
10
+ this.server = null;
11
+ this.startPromise = null;
12
+ this.shutdownInProgress = false;
13
+ this.moduleImport = moduleClass;
14
+ this.di = new AppContainer();
15
+ this.options = options;
16
+ }
17
+ getContainer() {
18
+ return this.di;
19
+ }
20
+ resolve(token) {
21
+ try {
22
+ return this.di.resolve(token);
23
+ }
24
+ catch (initialError) {
25
+ if (!this.moduleLoaded) {
26
+ this.ensureModuleLoaded();
27
+ return this.di.resolve(token);
28
+ }
29
+ throw initialError;
30
+ }
31
+ }
32
+ resolveAll(token) {
33
+ try {
34
+ return this.di.resolveAll(token);
35
+ }
36
+ catch (initialError) {
37
+ if (!this.moduleLoaded) {
38
+ this.ensureModuleLoaded();
39
+ return this.di.resolveAll(token);
40
+ }
41
+ throw initialError;
42
+ }
43
+ }
44
+ getServerOptions() {
45
+ return { ...this.options };
46
+ }
47
+ setServerOptions(options) {
48
+ this.assertConfigurable("set server options");
49
+ this.options = {
50
+ ...this.options,
51
+ ...options,
52
+ };
53
+ return this;
54
+ }
55
+ configureLogger(options) {
56
+ this.assertConfigurable("configure logger");
57
+ this.di.configureLogger(options);
58
+ this.loggerConfiguredExplicitly = true;
59
+ return this;
60
+ }
61
+ configureConfig(schema, source = process.env) {
62
+ this.assertConfigurable("configure config");
63
+ return this.di.configureConfig(schema, source);
64
+ }
65
+ getServer() {
66
+ if (!this.server) {
67
+ throw new Error("Application is not started");
68
+ }
69
+ return this.server;
70
+ }
71
+ async start(options = {}) {
72
+ if (this.server) {
73
+ return this.server;
74
+ }
75
+ if (this.startPromise) {
76
+ return this.startPromise;
77
+ }
78
+ const resolvedOptions = {
79
+ ...this.options,
80
+ ...options,
81
+ };
82
+ this.options = resolvedOptions;
83
+ const startOptions = this.loggerConfiguredExplicitly && resolvedOptions.loggerOptions !== undefined
84
+ ? {
85
+ ...resolvedOptions,
86
+ loggerOptions: undefined,
87
+ }
88
+ : resolvedOptions;
89
+ this.startPromise = (async () => {
90
+ this.ensureModuleLoaded();
91
+ const server = await startServer(this.di, startOptions);
92
+ this.server = server;
93
+ this.installSignalHandlers(startOptions);
94
+ return server;
95
+ })();
96
+ try {
97
+ return await this.startPromise;
98
+ }
99
+ finally {
100
+ this.startPromise = null;
101
+ }
102
+ }
103
+ async close(signal = "application.close") {
104
+ if (this.startPromise && !this.server) {
105
+ try {
106
+ await this.startPromise;
107
+ }
108
+ catch {
109
+ // Ignore startup failures here: startServer() already performs cleanup.
110
+ }
111
+ }
112
+ if (this.server) {
113
+ const server = this.server;
114
+ try {
115
+ await server.close();
116
+ this.server = null;
117
+ this.removeSignalHandlers();
118
+ return;
119
+ }
120
+ catch (error) {
121
+ this.server = server;
122
+ throw error;
123
+ }
124
+ }
125
+ await this.di.close(signal);
126
+ this.removeSignalHandlers();
127
+ }
128
+ resolveGracefulShutdownOptions(serverOptions) {
129
+ const raw = serverOptions.gracefulShutdown;
130
+ if (raw === false) {
131
+ return {
132
+ enabled: false,
133
+ signals: Application.DEFAULT_SHUTDOWN_SIGNALS,
134
+ timeoutMs: Application.DEFAULT_SHUTDOWN_TIMEOUT_MS,
135
+ forceExitOnFailure: false,
136
+ };
137
+ }
138
+ if (raw === undefined || raw === true) {
139
+ return {
140
+ enabled: true,
141
+ signals: Application.DEFAULT_SHUTDOWN_SIGNALS,
142
+ timeoutMs: Application.DEFAULT_SHUTDOWN_TIMEOUT_MS,
143
+ forceExitOnFailure: false,
144
+ };
145
+ }
146
+ const options = raw;
147
+ const timeoutMs = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0
148
+ ? options.timeoutMs
149
+ : Application.DEFAULT_SHUTDOWN_TIMEOUT_MS;
150
+ return {
151
+ enabled: options.enabled ?? true,
152
+ signals: options.signals?.length ? options.signals : Application.DEFAULT_SHUTDOWN_SIGNALS,
153
+ timeoutMs,
154
+ forceExitOnFailure: options.forceExitOnFailure ?? false,
155
+ };
156
+ }
157
+ installSignalHandlers(serverOptions) {
158
+ if (this.signalHandlers.size > 0) {
159
+ return;
160
+ }
161
+ const shutdown = this.resolveGracefulShutdownOptions(serverOptions);
162
+ if (!shutdown.enabled) {
163
+ return;
164
+ }
165
+ for (const signal of shutdown.signals) {
166
+ const handler = () => {
167
+ void this.handleShutdownSignal(signal, shutdown.timeoutMs, shutdown.forceExitOnFailure);
168
+ };
169
+ process.on(signal, handler);
170
+ this.signalHandlers.set(signal, handler);
171
+ }
172
+ }
173
+ removeSignalHandlers() {
174
+ if (this.signalHandlers.size === 0) {
175
+ return;
176
+ }
177
+ for (const [signal, handler] of this.signalHandlers) {
178
+ if (typeof process.off === "function") {
179
+ process.off(signal, handler);
180
+ }
181
+ else {
182
+ process.removeListener(signal, handler);
183
+ }
184
+ }
185
+ this.signalHandlers.clear();
186
+ }
187
+ async handleShutdownSignal(signal, timeoutMs, forceExitOnFailure) {
188
+ if (this.shutdownInProgress) {
189
+ return;
190
+ }
191
+ this.shutdownInProgress = true;
192
+ const logger = this.di.getLogger();
193
+ let timeoutId;
194
+ let shutdownFailed = false;
195
+ logger.info({
196
+ type: "shutdown",
197
+ stage: "received",
198
+ signal,
199
+ timeoutMs,
200
+ forceExitOnFailure,
201
+ });
202
+ const timeoutPromise = new Promise((_, reject) => {
203
+ timeoutId = setTimeout(() => {
204
+ reject(new Error(`Graceful shutdown timed out after ${timeoutMs}ms`));
205
+ }, timeoutMs);
206
+ if (typeof timeoutId.unref === "function") {
207
+ timeoutId.unref();
208
+ }
209
+ });
210
+ try {
211
+ await Promise.race([this.close(`signal:${signal}`), timeoutPromise]);
212
+ logger.info({
213
+ type: "shutdown",
214
+ stage: "completed",
215
+ signal,
216
+ });
217
+ }
218
+ catch (error) {
219
+ shutdownFailed = true;
220
+ logger.error({
221
+ type: "shutdown",
222
+ stage: "failed",
223
+ signal,
224
+ forceExitOnFailure,
225
+ }, error);
226
+ process.exitCode = 1;
227
+ }
228
+ finally {
229
+ if (timeoutId) {
230
+ clearTimeout(timeoutId);
231
+ }
232
+ if (shutdownFailed) {
233
+ if (forceExitOnFailure) {
234
+ process.exit(1);
235
+ }
236
+ this.shutdownInProgress = false;
237
+ }
238
+ }
239
+ }
240
+ assertConfigurable(action) {
241
+ if (this.server || this.startPromise) {
242
+ throw new Error(`Cannot ${action} after application start`);
243
+ }
244
+ }
245
+ ensureModuleLoaded() {
246
+ if (this.moduleLoaded) {
247
+ return;
248
+ }
249
+ this.di.loadModule(this.moduleImport);
250
+ this.moduleLoaded = true;
251
+ }
252
+ }
@@ -0,0 +1 @@
1
+ export declare const CONFIG_TOKEN: unique symbol;
@@ -0,0 +1 @@
1
+ export const CONFIG_TOKEN = Symbol("app:config");
@@ -0,0 +1,76 @@
1
+ import "reflect-metadata";
2
+ import { type DependencyContainer } from "tsyringe";
3
+ import type { Constructor, ExceptionFilterLike, GuardLike, InjectionToken, InterceptorLike, LoggerOptions, ModuleImport, PipeLike } from "../types";
4
+ import type { ZodType, output } from "zod";
5
+ import { type AppLogger } from "./logger";
6
+ export declare class AppContainer {
7
+ private readonly root;
8
+ private readonly loadedModules;
9
+ private readonly dynamicModuleSignatures;
10
+ private readonly globalExportOwners;
11
+ private readonly loadingModules;
12
+ private readonly rpcControllerSet;
13
+ private readonly httpControllerSet;
14
+ private readonly rpcControllerModules;
15
+ private readonly httpControllerModules;
16
+ private readonly lifecycleTargets;
17
+ private readonly requestScopeOwners;
18
+ private readonly requestScopeLinkedScopes;
19
+ private readonly requestContextStorage;
20
+ private rootModuleRef;
21
+ private controllers;
22
+ private httpControllers;
23
+ private lifecycleInstances;
24
+ private initialized;
25
+ private closed;
26
+ private exposeInternalErrors;
27
+ private globalGuards;
28
+ private globalInterceptors;
29
+ private globalPipes;
30
+ private globalFilters;
31
+ constructor();
32
+ private addLifecycleTarget;
33
+ private getLifecycleInstances;
34
+ private normalizeModuleImport;
35
+ private readModuleMetadata;
36
+ private mergeModuleMetadata;
37
+ private collectProviderTokens;
38
+ private linkImportedExports;
39
+ private resolveAppEnhancerInstance;
40
+ private registerAppEnhancerProvider;
41
+ private registerProvider;
42
+ private resolveModuleExports;
43
+ private registerGlobalExports;
44
+ private resolveControllerModule;
45
+ private getOrCreateLinkedScopes;
46
+ private getModuleScopeForRequest;
47
+ private resolveTokenFromModuleScope;
48
+ private assertRuntimeConfigMutable;
49
+ private loadModuleRef;
50
+ loadModule(moduleImport: ModuleImport): void;
51
+ resolve<T>(token: InjectionToken<T>): T;
52
+ resolveAll<T>(token: InjectionToken<T>): T[];
53
+ setLogger(logger: AppLogger): void;
54
+ configureLogger(options?: LoggerOptions): AppLogger;
55
+ getLogger(): AppLogger;
56
+ setExposeInternalErrors(value: boolean): void;
57
+ shouldExposeInternalErrors(): boolean;
58
+ setConfig<TConfig extends Record<string, unknown>>(config: TConfig): void;
59
+ configureConfig<TSchema extends ZodType>(schema: TSchema, source?: unknown): output<TSchema>;
60
+ getConfig<TConfig extends Record<string, unknown> = Record<string, unknown>>(): Readonly<TConfig>;
61
+ init(): Promise<void>;
62
+ close(signal?: string): Promise<void>;
63
+ runInRequestScope<T>(scope: DependencyContainer, execute: () => Promise<T> | T): Promise<T>;
64
+ disposeRequestScope(scope: DependencyContainer): Promise<void>;
65
+ createRequestScope(controller?: Constructor): DependencyContainer;
66
+ getControllers(): Constructor[];
67
+ getHttpControllers(): Constructor[];
68
+ setGlobalGuards(guards: GuardLike[]): void;
69
+ getGlobalGuards(): GuardLike[];
70
+ setGlobalInterceptors(inters: InterceptorLike[]): void;
71
+ getGlobalInterceptors(): InterceptorLike[];
72
+ setGlobalPipes(pipes: PipeLike[]): void;
73
+ getGlobalPipes(): PipeLike[];
74
+ setGlobalFilters(filters: ExceptionFilterLike[]): void;
75
+ getGlobalFilters(): ExceptionFilterLike[];
76
+ }