exisjs 0.7.12 → 0.7.13

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 (116) hide show
  1. package/README.md +195 -39
  2. package/dist/config/types.d.ts +2 -2
  3. package/dist/config/types.d.ts.map +1 -1
  4. package/dist/decorators/params.d.ts +21 -0
  5. package/dist/decorators/params.d.ts.map +1 -1
  6. package/dist/decorators/params.js +21 -1
  7. package/dist/decorators/params.js.map +1 -1
  8. package/dist/di/container.d.ts +15 -6
  9. package/dist/di/container.d.ts.map +1 -1
  10. package/dist/di/container.js +26 -3
  11. package/dist/di/container.js.map +1 -1
  12. package/dist/di/index.d.ts +1 -1
  13. package/dist/di/index.d.ts.map +1 -1
  14. package/dist/di/index.js.map +1 -1
  15. package/dist/di/inject.d.ts +2 -1
  16. package/dist/di/inject.d.ts.map +1 -1
  17. package/dist/di/inject.js +2 -1
  18. package/dist/di/inject.js.map +1 -1
  19. package/dist/docs/BENCHMARKS.md +4 -4
  20. package/dist/docs/content/README.md +43 -44
  21. package/dist/docs/content/boundaries.mdx +138 -61
  22. package/dist/docs/content/cli/commands.mdx +151 -128
  23. package/dist/docs/content/cli/overview.mdx +61 -47
  24. package/dist/docs/content/cli/usage.mdx +107 -30
  25. package/dist/docs/content/config.mdx +145 -158
  26. package/dist/docs/content/controllers.mdx +193 -464
  27. package/dist/docs/content/cron.mdx +183 -69
  28. package/dist/docs/content/decorators.mdx +449 -154
  29. package/dist/docs/content/errors.mdx +202 -305
  30. package/dist/docs/content/exisjs-mcp.mdx +59 -49
  31. package/dist/docs/content/installation.mdx +243 -157
  32. package/dist/docs/content/introduction.mdx +220 -48
  33. package/dist/docs/content/middleware.mdx +171 -497
  34. package/dist/docs/content/modules.mdx +141 -83
  35. package/dist/docs/content/providers.mdx +216 -180
  36. package/dist/docs/content/requests.mdx +168 -488
  37. package/dist/docs/content/responses.mdx +200 -533
  38. package/dist/docs/content/routing.mdx +235 -598
  39. package/dist/docs/content/security.mdx +233 -57
  40. package/dist/docs/content/structure.mdx +151 -240
  41. package/dist/docs/content/swagger.mdx +192 -91
  42. package/dist/docs/content/testing.mdx +205 -74
  43. package/dist/docs/content/validation.mdx +479 -341
  44. package/dist/docs/reference/README.md +34 -2
  45. package/dist/docs/reference/config.mdx +277 -75
  46. package/dist/docs/reference/context.mdx +197 -106
  47. package/dist/docs/reference/cron.mdx +266 -152
  48. package/dist/docs/reference/database.mdx +135 -53
  49. package/dist/docs/reference/decorators.mdx +234 -116
  50. package/dist/docs/reference/di.mdx +146 -112
  51. package/dist/docs/reference/error.mdx +155 -178
  52. package/dist/docs/reference/exis.mdx +141 -70
  53. package/dist/docs/reference/logger.mdx +110 -126
  54. package/dist/docs/reference/middleware.mdx +235 -158
  55. package/dist/docs/reference/plugin.mdx +136 -64
  56. package/dist/docs/reference/router.mdx +275 -293
  57. package/dist/docs/reference/sanitize.mdx +91 -87
  58. package/dist/docs/reference/swagger.mdx +280 -100
  59. package/dist/docs/reference/testing.mdx +223 -89
  60. package/dist/docs/reference/validator.mdx +194 -206
  61. package/dist/lib/start-server.js +3 -8
  62. package/dist/lib/start-server.js.map +1 -1
  63. package/dist/module/module.d.ts +6 -3
  64. package/dist/module/module.d.ts.map +1 -1
  65. package/dist/module/module.js +17 -3
  66. package/dist/module/module.js.map +1 -1
  67. package/dist/router/controller-registrar.d.ts.map +1 -1
  68. package/dist/router/controller-registrar.js +26 -4
  69. package/dist/router/controller-registrar.js.map +1 -1
  70. package/dist/server/app.d.ts +3 -1
  71. package/dist/server/app.d.ts.map +1 -1
  72. package/dist/server/app.js +24 -8
  73. package/dist/server/app.js.map +1 -1
  74. package/dist/server/request.d.ts +2 -0
  75. package/dist/server/request.d.ts.map +1 -1
  76. package/dist/server/request.js +11 -0
  77. package/dist/server/request.js.map +1 -1
  78. package/dist/swagger/generator.d.ts.map +1 -1
  79. package/dist/swagger/generator.js +130 -10
  80. package/dist/swagger/generator.js.map +1 -1
  81. package/dist/telemetry/index.d.ts +12 -0
  82. package/dist/telemetry/index.d.ts.map +1 -0
  83. package/dist/telemetry/index.js +121 -0
  84. package/dist/telemetry/index.js.map +1 -0
  85. package/dist/testing/client.d.ts +1 -0
  86. package/dist/testing/client.d.ts.map +1 -1
  87. package/dist/testing/client.js +4 -1
  88. package/dist/testing/client.js.map +1 -1
  89. package/dist/testing/index.d.ts.map +1 -1
  90. package/dist/testing/index.js +11 -4
  91. package/dist/testing/index.js.map +1 -1
  92. package/dist/validator/builder.d.ts +26 -1
  93. package/dist/validator/builder.d.ts.map +1 -1
  94. package/dist/validator/builder.js +31 -0
  95. package/dist/validator/builder.js.map +1 -1
  96. package/dist/validator/engine.d.ts +23 -0
  97. package/dist/validator/engine.d.ts.map +1 -1
  98. package/dist/validator/engine.js +228 -31
  99. package/dist/validator/engine.js.map +1 -1
  100. package/dist/validator/index.d.ts +8 -4
  101. package/dist/validator/index.d.ts.map +1 -1
  102. package/dist/validator/index.js +4 -1
  103. package/dist/validator/index.js.map +1 -1
  104. package/dist/validator/tex-types.d.ts +15 -0
  105. package/dist/validator/tex-types.d.ts.map +1 -1
  106. package/dist/validator/tex-types.js +102 -0
  107. package/dist/validator/tex-types.js.map +1 -1
  108. package/dist/validator/tex.d.ts +1 -1
  109. package/dist/validator/tex.d.ts.map +1 -1
  110. package/dist/validator/tex.js +3 -1
  111. package/dist/validator/tex.js.map +1 -1
  112. package/dist/validator/types.d.ts +1 -0
  113. package/dist/validator/types.d.ts.map +1 -1
  114. package/package.json +46 -14
  115. package/dist/docs/content/dataloader.mdx +0 -170
  116. package/dist/docs/reference/dataloader.mdx +0 -91
@@ -1,180 +1,214 @@
1
1
  ---
2
- title: "Dependency Injection"
3
- description: "API Reference for ExisJS Dependency Injection (`exisjs/di`)."
2
+ title: "exisjs/di"
3
+ description: "API Reference for ExisJS Inversion of Control (IoC) Container, inject() helper, provider definitions, scopes, and forwardRef."
4
+ nextUrl: "/docs/reference/error"
5
+ nextTitle: "Error Reference"
4
6
  ---
5
7
 
6
- # Dependency Injection (`exisjs/di`)
8
+ # `exisjs/di`
7
9
 
8
- ExisJS ships with a powerful, built-in Inversion of Control (IoC) Container.
9
-
10
- It fully supports standard Class-Based constructor injection (similar to NestJS or Angular) but also introduces a highly optimized `inject()` function that allows perfectly typed, deeply nested dependency injection inside purely functional architectures.
10
+ The `exisjs/di` module provides the Inversion of Control (IoC) dependency injection container for ExisJS. It supports functional context-driven injection (`inject()`), class constructor and property decorators (`@Inject()`, `@Optional()`), circular dependency resolution (`forwardRef()`), and multiple lifecycle scopes.
11
11
 
12
12
  ---
13
13
 
14
- ## Providing Dependencies
14
+ ## Module Exports
15
15
 
16
- Before a dependency can be injected, it must be provided to the application container. This is typically done in your plugins or the global `server.ts` file using `app.provide()`.
16
+ ```typescript
17
+ import {
18
+ Container,
19
+ inject,
20
+ forwardRef,
21
+ isForwardRef,
22
+ Inject,
23
+ Optional,
24
+ INJECT_METADATA,
25
+ PROPERTY_INJECT_METADATA,
26
+ OPTIONAL_METADATA,
27
+ SCOPE_METADATA,
28
+ } from 'exisjs/di'
29
+
30
+ import type {
31
+ ProviderToken,
32
+ ProviderDefinition,
33
+ CustomProvider,
34
+ ValueProvider,
35
+ FactoryProvider,
36
+ ClassProvider,
37
+ ExistingProvider,
38
+ ClassConstructor,
39
+ ForwardReference,
40
+ } from 'exisjs/di'
41
+ ```
17
42
 
18
- ### Provider Types
43
+ ---
19
44
 
20
- ExisJS supports four types of providers:
45
+ ## 1. Provider Definitions & Types
21
46
 
22
- **1. Value Providers**
23
- Provide static, pre-instantiated values or configuration objects.
24
- ```typescript
25
- app.provide('API_KEY', { useValue: 'sk_live_123' })
26
- ```
47
+ Dependencies are registered with the container using tokens (classes, string identifiers, symbols, or forward references):
27
48
 
28
- **2. Class Providers**
29
- Provide a class constructor. ExisJS will automatically instantiate it the first time it is resolved.
30
49
  ```typescript
31
- app.provide('UserService', { useClass: UserService })
50
+ export type ProviderToken<T = any> =
51
+ | string
52
+ | symbol
53
+ | (new (...args: any[]) => T)
54
+ | ForwardReference<T>
32
55
  ```
33
56
 
34
- **3. Factory Providers**
35
- Provide a synchronous or asynchronous function to generate the value dynamically.
36
- ```typescript
37
- app.provide('Database', {
38
- useFactory: async () => {
39
- const db = new DatabaseConnection()
40
- await db.connect()
41
- return db
42
- }
43
- })
44
- ```
57
+ ### Provider Variants
45
58
 
46
- **4. Direct Injection**
47
- If you pass an undecorated Class or object directly, ExisJS will attempt to resolve it automatically.
48
- ```typescript
49
- app.provide(AuthService, AuthService)
50
- ```
59
+ | Provider Type | Interface | Description | Example |
60
+ | :--- | :--- | :--- | :--- |
61
+ | **Value Provider** | `ValueProvider<T>` | Binds a static value, client instance, or configuration object. | `app.provide('CONFIG', { useValue: { env: 'prod' } })` |
62
+ | **Class Provider** | `ClassProvider<T>` | Binds a class constructor instantiated on first resolution. | `app.provide('UserService', { useClass: UserService })` |
63
+ | **Factory Provider** | `FactoryProvider<T>` | Executes a factory function with resolved dependency tokens. | `app.provide({ provide: 'DB', useFactory: (cfg) => connect(cfg), inject: ['CONFIG'] })` |
64
+ | **Existing / Alias Provider** | `ExistingProvider<T>` | Creates an alias pointing to another registered provider token. | `app.provide({ provide: 'DB_ALIAS', useExisting: 'DB' })` |
65
+ | **Direct Class** | `ClassConstructor<T>` | Direct constructor binding without an options wrapper. | `app.provide(AuthService, AuthService)` |
51
66
 
52
67
  ---
53
68
 
54
- ## Scopes (`singleton`, `request`, `transient`)
55
-
56
- By default, all providers in ExisJS are **Singletons**. They are instantiated once and cached for the lifetime of the application.
69
+ ## 2. Provider Scopes
57
70
 
58
- ExisJS supports three provider scopes in the `@Injectable()` decorator and `app.provide()`:
71
+ ExisJS supports three provider lifecycle scopes:
59
72
 
60
- - **`singleton` (Default)**: Instantiated once and cached for the lifetime of the application.
61
- - **`request`**: A new instance is created exclusively for each incoming HTTP request, and garbage collected afterward.
62
- - **`transient`**: A new instance is created every single time the dependency is injected or resolved.
73
+ | Scope | Lifetime | Description |
74
+ | :--- | :--- | :--- |
75
+ | `'singleton'` *(Default)* | Application Lifetime | Instantiated once and cached in memory across all requests. |
76
+ | `'request'` | Request Lifetime | Instantiated once per incoming HTTP request; isolated in request-scoped cache. |
77
+ | `'transient'` | Resolution Lifetime | Re-instantiated every single time the dependency is requested. |
63
78
 
64
79
  ```typescript
65
- app.provide('TraceLogger', {
66
- useClass: RequestScopedLogger,
67
- scope: 'request'
68
- })
69
-
70
- app.provide('OperationContext', {
71
- useClass: OperationContext,
72
- scope: 'transient'
80
+ app.provide('TraceLogger', {
81
+ useClass: RequestScopedLogger,
82
+ scope: 'request',
73
83
  })
74
84
  ```
75
85
 
76
- > [!WARNING]
77
- > Request-scoped providers can severely impact application performance because they force the engine to allocate new memory and construct new classes on every single HTTP request. Only use `request` scope when strictly necessary.
78
-
79
86
  ---
80
87
 
81
- ## Injecting Dependencies
88
+ ## 3. Functional Injection (`inject()`)
82
89
 
83
- ### 1. Functional Injection (`inject()`)
90
+ Resolves dependencies from within active route handlers, middleware functions, or helper routines using `AsyncLocalStorage`.
84
91
 
85
- The true superpower of ExisJS is the `inject()` hook.
92
+ ```typescript
93
+ function inject<T>(token: ProviderToken<T>): T
94
+ ```
86
95
 
87
- Powered by Node.js `AsyncLocalStorage`, `inject()` can be called from **anywhere** within a request lifecycle (Controllers, Middlewares, nested utility functions) without needing to explicitly pass the `app` or `req` objects down the call chain!
96
+ ### Example
88
97
 
89
98
  ```typescript filename="src/http/users/route.ts"
90
- import { route, controller } from 'exisjs/router'
99
+ import { controller, route } from 'exisjs/router'
91
100
  import { inject } from 'exisjs/di'
92
- import { Database } from '../db' // The class definition
101
+ import { DatabaseService } from '../services/database'
93
102
 
94
103
  export default controller({
95
- getUsers: route.get('/', {
104
+ list: route.get('/', {
96
105
  async handle() {
97
- // Automatically resolves the correct instance from the global container!
98
- // Type is automatically inferred as `Database`.
99
- const db = inject(Database)
100
-
106
+ // Resolved from active request execution context
107
+ const db = inject(DatabaseService)
101
108
  const apiKey = inject<string>('API_KEY')
102
-
109
+
103
110
  return db.query('SELECT * FROM users')
104
- }
105
- })
111
+ },
112
+ }),
106
113
  })
107
114
  ```
108
115
 
109
- > [!NOTE]
110
- > `inject()` relies on the active execution context. If you call `inject()` outside of an active HTTP request or application lifecycle hook (e.g., in a background `setInterval` without context), it will throw an error.
116
+ ---
111
117
 
112
- ### 2. Constructor & Property Injection in Classes (OOP)
118
+ ## 4. Class-Based OOP Injection
113
119
 
114
- ExisJS supports full OOP constructor parameter and property field injection with **automatic parameter type reflection**:
115
- - **Automatic Type Reflection**: If `emitDecoratorMetadata: true` is enabled in `tsconfig.json`, ExisJS inspects `design:paramtypes` and automatically maps constructor parameter classes directly to dependencies registered in `INJECTABLE_REGISTRY`. You do not need `@Inject()` on standard service classes!
116
- - **Property-Level `@Inject()`**: Inject dependencies directly onto class properties (`@Inject(Token) public service!: Service`) with automatic `design:type` reflection fallback.
117
- - **Token Injection (`@Inject(token)`)**: Use `@Inject('TOKEN')` when injecting custom strings, config objects, or symbols.
118
- - **Optional Dependencies (`@Optional()`)**: Mark dependencies that can safely resolve to `undefined` if not registered.
119
- - **Forward References (`forwardRef(() => Service)`)**: Resolve circular dependencies between services using lazy forward references and ES6 Proxy delegates.
120
+ ### `@Inject(token)`
121
+ Parameter and property decorator specifying an explicit injection token:
120
122
 
121
- ```typescript filename="src/http/users/route.ts"
122
- import { Controller, Get, Param } from 'exisjs/decorators'
123
- import { Inject, Optional, forwardRef } from 'exisjs/di'
123
+ ```typescript
124
+ import { Controller, Get } from 'exisjs/decorators'
125
+ import { Inject } from 'exisjs/di'
124
126
  import { UserService } from './service'
125
- import { ConfigService } from '../config/service'
126
127
 
127
128
  @Controller('/users')
128
129
  export default class UserController {
129
- // 1. Property-level injection
130
- @Inject(ConfigService)
131
- private config!: ConfigService
132
-
133
- // 2. Optional property injection
134
- @Inject('ANALYTICS')
135
- @Optional()
136
- private analytics?: any
130
+ @Inject('CONFIG')
131
+ private config!: Record<string, any>
137
132
 
138
133
  constructor(
139
- // 3. Automatically resolved from INJECTABLE_REGISTRY via type reflection!
140
134
  private userService: UserService,
141
- // 4. Explicit token injection
142
- @Inject('DATABASE_URL') private dbUrl: string,
143
- // 5. Circular dependency resolution via forwardRef
144
- @Inject(forwardRef(() => UserService)) private circularRef: UserService
135
+ @Inject('DATABASE_URL') private dbUrl: string
145
136
  ) {}
146
-
147
- @Get('/:id')
148
- async getUser(@Param('id') id: string) {
149
- return this.userService.findById(id)
150
- }
151
137
  }
152
138
  ```
153
139
 
140
+ ### `@Optional()`
141
+ Marks a dependency as optional, resolving to `undefined` without throwing if not present in the container:
142
+
143
+ ```typescript
144
+ import { Inject, Optional } from 'exisjs/di'
145
+
146
+ export class NotificationService {
147
+ constructor(
148
+ @Inject('SLACK_WEBHOOK') @Optional() private slackUrl?: string
149
+ ) {}
150
+ }
151
+ ```
154
152
 
155
153
  ---
156
154
 
157
- ## Lifecycle Hooks (`OnInit`, `OnDestroy`)
155
+ ## 5. Circular Dependency Resolution (`forwardRef`)
158
156
 
159
- Providers can implement lifecycle interfaces. When the application container initializes or gracefully closes, ExisJS automatically triggers these hooks:
157
+ Resolves mutually dependent services by deferring token resolution until instantiation time:
160
158
 
161
- - **`OnInit` (`onInit()` / `onModuleInit()`)**: Executed when the container initializes during `app.create()` or `app.listen()`.
162
- - **`OnDestroy` (`onDestroy()` / `onModuleDestroy()`)**: Executed when the application receives a termination signal or `app.close()` is called.
163
- - **`OnApplicationBootstrap` (`onApplicationBootstrap()`)**: Executed after all modules are initialized and before the server begins listening for incoming requests.
159
+ ```typescript
160
+ function forwardRef<T>(fn: () => ProviderToken<T>): ForwardReference<T>
161
+ ```
164
162
 
165
- ```typescript filename="src/http/database/service.ts"
166
- import { Injectable, type OnInit, type OnDestroy } from 'exisjs/decorators'
163
+ ### Example
164
+
165
+ ```typescript filename="src/services/orders.ts"
166
+ import { Injectable } from 'exisjs/decorators'
167
+ import { Inject, forwardRef } from 'exisjs/di'
168
+ import { PaymentService } from './payments'
167
169
 
168
170
  @Injectable()
169
- export class DatabaseService implements OnInit, OnDestroy {
170
- async onInit(): Promise<void> {
171
- await this.pool.connect()
172
- }
173
-
174
- async onDestroy(): Promise<void> {
175
- await this.pool.end()
176
- }
171
+ export class OrderService {
172
+ constructor(
173
+ @Inject(forwardRef(() => PaymentService))
174
+ private paymentService: PaymentService
175
+ ) {}
177
176
  }
178
177
  ```
179
178
 
179
+ ---
180
+
181
+ ## 6. `Container` Class API
182
+
183
+ The core IoC container coordinating provider registration and resolution.
184
+
185
+ ```typescript
186
+ export class Container {
187
+ provide<T>(token: ProviderToken<T>, provider: ProviderDefinition<T>): void
188
+ resolve<T>(token: ProviderToken<T>, requestCache?: Map<any, any>): T
189
+ instantiateClass<T>(TargetClass: ClassConstructor<T>, requestCache?: Map<any, any>): T
190
+ clearCache(): void
191
+ }
192
+ ```
193
+
194
+ | Method | Signature | Description |
195
+ | :--- | :--- | :--- |
196
+ | `provide(token, provider)` | `(token, provider) => void` | Registers a provider definition under a token. |
197
+ | `resolve(token, cache?)` | `(token, cache?) => T` | Resolves an instance matching the token. |
198
+ | `instantiateClass(Target, cache?)` | `(Target, cache?) => T` | Instantiates a class, resolving constructor parameters recursively. |
199
+ | `clearCache()` | `() => void` | Clears all cached singleton instances and in-flight locks. |
200
+
201
+ ---
202
+
203
+ ## 7. Lifecycle Hooks
204
+
205
+ Providers registered in the container can implement standard lifecycle interfaces:
206
+
207
+ | Hook Interface | Method | Triggered When |
208
+ | :--- | :--- | :--- |
209
+ | `OnInit` | `onInit(): Promise<void> \| void` | Application server starts and container boots. |
210
+ | `OnDestroy` | `onDestroy(): Promise<void> \| void` | Server receives termination signal (`SIGTERM`, `SIGINT`) or `app.close()`. |
211
+ | `OnApplicationBootstrap` | `onApplicationBootstrap(): Promise<void> \| void` | All modules have initialized before listening for connections. |
212
+
213
+
180
214