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,67 +1,98 @@
1
1
  ---
2
- nextUrl: "/docs/cache"
3
- nextTitle: "Caching"
2
+ title: "Modules and Plugins"
3
+ description: "Encapsulate domain services, sub-modules, controllers, and framework plugins across Functional and OOP architectures in ExisJS."
4
+ nextUrl: "/docs/security"
5
+ nextTitle: "Security & Auth"
4
6
  ---
5
7
 
6
- # Modules & Plugins
8
+ # Modules and Plugins
7
9
 
8
- ExisJS provides a modular architecture. The framework is built on a Plugin Engine that allows you to encapsulate functionality, inject dependencies, and distribute reusable packages across your organization.
9
-
10
- ExisJS offers two distinct primitives for extension:
11
- 1. **Modules (`defineModule`)**: Used for grouping domain-level business logic (e.g., `AuthModule`, `UsersModule`).
12
- 2. **Plugins (`definePlugin`)**: Used for building framework-level extensions that often require configuration options (e.g., `StripePlugin({ apiKey })`).
10
+ ExisJS provides modular architecture primitives to structure code into reusable, encapsulated domains. You can organize features using two approaches:
11
+ 1. **Domain Modules (`defineModule` / `@Module`)**: Group related providers, sub-modules, controllers, and lifecycle hooks into domain boundaries.
12
+ 2. **Framework Plugins (`definePlugin`)**: Build configurable, distributable extensions and third-party integrations with option passing.
13
13
 
14
14
  ---
15
15
 
16
- ## 1. Domain Modules (`defineModule`)
16
+ ## Domain Modules Overview
17
+
18
+ Modules create logical boundaries around specific business domains (such as `AuthModule`, `UsersModule`, or `BillingModule`), managing their dependencies, routes, and lifecycles.
17
19
 
18
- When building large-scale applications, you should avoid placing all your logic into a single file. Modules allow you to encapsulate related dependencies (Providers), sub-modules (Imports), and Routes into a single unit.
20
+ | Concept | Functional Paradigm | Class-Based (OOP) Paradigm |
21
+ | :--- | :--- | :--- |
22
+ | **Module Definition** | `defineModule({ name, imports, providers, routes, onStart, onClose })` | `@Module({ imports, controllers, providers, exports })` |
23
+ | **Global Scope** | `app.register(module)` or `exis.config.ts` | `@Global()` decorator on `@Module()` class |
24
+ | **Provider Encapsulation** | `providers: [[token, definition]]` | `providers: [Service, [token, definition], { provide, useValue }]` |
25
+
26
+ ---
19
27
 
20
- ### Defining a Module
28
+ ## Functional Domain Modules (`defineModule`)
21
29
 
22
- Let's build an `AuthModule` that encapsulates an authentication provider:
30
+ In the functional paradigm, use `defineModule` from `exisjs/module` to declare encapsulated domain units.
31
+
32
+ ### 1. Defining a Functional Module
23
33
 
24
34
  ```typescript filename="src/modules/auth.module.ts"
25
35
  import { defineModule } from 'exisjs/module'
36
+ import { DatabaseModule } from './database.module'
37
+ import { AuthService } from '../services/auth.service'
26
38
 
27
39
  export const AuthModule = defineModule({
28
- name: 'auth-module',
29
-
30
- // 1. Inject Dependencies
31
- providers: [
32
- ['AuthService', { useClass: class AuthService { login() {} } }]
33
- ],
40
+ name: 'AuthModule',
41
+
42
+ // 1. Sub-modules required by this module
43
+ imports: [DatabaseModule],
34
44
 
35
- // 2. Import other modules
36
- imports: [
37
- DatabaseModule
45
+ // 2. Providers registered into the DI container
46
+ providers: [
47
+ ['AuthService', { useClass: AuthService }],
38
48
  ],
39
49
 
40
- // 3. Register lifecycle hooks
50
+ // 3. Optional lifecycle hooks
41
51
  async onStart(app) {
42
- console.log("AuthModule has initialized")
43
- }
52
+ console.log('[AuthModule] Initialized successfully')
53
+ },
54
+
55
+ async onClose(app) {
56
+ console.log('[AuthModule] Teardown complete')
57
+ },
44
58
  })
45
59
  ```
46
60
 
47
- ### Registering Modules
61
+ ### 2. Registering Modules in Server Configuration
62
+
63
+ You can register modules in `exis.config.ts` (using either `defineConfig` or typed `const config: ExisConfig`) or directly in `src/http/server.ts`:
48
64
 
49
- Once your module is defined, you can register it globally. The recommended place to register core modules is inside your `exis.config.ts` file, ensuring they boot up synchronously before your server starts accepting traffic.
65
+ #### In `exis.config.ts`
50
66
 
51
67
  ```typescript filename="exis.config.ts"
52
- import { defineExisConfig } from 'exisjs/config'
68
+ import { defineConfig } from 'exisjs/config'
53
69
  import { AuthModule } from './src/modules/auth.module'
54
70
 
55
- export default defineExisConfig({
71
+ export default defineConfig({
72
+ port: 4000,
56
73
  plugins: [
57
- AuthModule
58
- ]
74
+ AuthModule,
75
+ ],
59
76
  })
60
77
  ```
61
78
 
62
- Alternatively, you can register it manually inside your `src/http/server.ts`:
79
+ Alternatively, you can export a typed `ExisConfig` object directly:
80
+
81
+ ```typescript filename="exis.config.ts"
82
+ import type { ExisConfig } from 'exisjs/config'
83
+ import { AuthModule } from './src/modules/auth.module'
84
+
85
+ const config: ExisConfig = {
86
+ port: 4000,
87
+ plugins: [
88
+ AuthModule,
89
+ ],
90
+ }
91
+
92
+ export default config
93
+ ```
63
94
 
64
- #### Functional Paradigm
95
+ #### In `src/http/server.ts`
65
96
 
66
97
  ```typescript filename="src/http/server.ts"
67
98
  import { exis } from 'exisjs'
@@ -70,115 +101,142 @@ import { AuthModule } from '../modules/auth.module'
70
101
  export default exis({
71
102
  async onStart(app) {
72
103
  await app.register(AuthModule)
73
- }
104
+ },
74
105
  })
75
106
  ```
76
107
 
77
- ```
108
+ ---
78
109
 
79
- #### Class-Based (OOP) Paradigm (`@Module` & `@Global`)
110
+ ## Class-Based (OOP) Modules (`@Module` & `@Global`)
80
111
 
81
- For applications following the OOP paradigm, you can define modules using the `@Module` class decorator:
112
+ In class-based architectures, import `Module` from `exisjs/module` (or `exisjs/decorators`) to configure imported modules, controllers, providers, and exported dependencies.
82
113
 
83
- ```typescript filename="src/modules/auth.module.ts"
114
+ ### 1. Module Definition with Controllers and Providers
115
+
116
+ ```typescript filename="src/modules/users.module.ts"
84
117
  import { Module } from 'exisjs/module'
85
- import { AuthService } from './auth.service'
86
- import { AuthController } from './auth.controller'
118
+ import { UsersController } from '../http/users/controller'
119
+ import { UsersService } from '../services/users.service'
87
120
  import { DatabaseModule } from './database.module'
88
121
 
89
122
  @Module({
90
123
  imports: [DatabaseModule],
91
- controllers: [AuthController],
92
- providers: [AuthService],
93
- exports: [AuthService]
124
+ controllers: [UsersController],
125
+ providers: [UsersService],
126
+ exports: [UsersService],
94
127
  })
95
- export class AuthModule {}
128
+ export class UsersModule {}
96
129
  ```
97
130
 
98
- #### Global Modules (`@Global`)
131
+ ### 2. Global Modules (`@Global`)
99
132
 
100
- If you have utility services, audit loggers, or database connections that should be globally available across all modules without having to list the module in every `imports: [...]` array, decorate the module with `@Global()`:
133
+ Utility providers, audit loggers, or database connections needed across all modules can be decorated with `@Global()`. Global modules make their exported providers available across the entire application without needing to be re-imported into every `@Module({ imports: [...] })` declaration:
101
134
 
102
135
  ```typescript filename="src/modules/core.module.ts"
103
- import { Global, Module } from 'exisjs/decorators'
104
- import { AuditService } from './audit.service'
105
- import { LoggerService } from './logger.service'
136
+ import { Module } from 'exisjs/module'
137
+ import { Global } from 'exisjs/decorators'
138
+ import { LoggerService } from '../services/logger.service'
139
+ import { AuditService } from '../services/audit.service'
106
140
 
107
141
  @Global()
108
142
  @Module({
109
- providers: [AuditService, LoggerService],
110
- exports: [AuditService, LoggerService],
143
+ providers: [LoggerService, AuditService],
144
+ exports: [LoggerService, AuditService],
111
145
  })
112
146
  export class CoreModule {}
113
147
  ```
114
148
 
115
- You can then register it into your server or root module once:
149
+ ### 3. Root Server Registration
150
+
151
+ Register root modules and global modules using the `@Server` decorator in `src/http/server.ts`:
116
152
 
117
153
  ```typescript filename="src/http/server.ts"
118
154
  import { Server } from 'exisjs/decorators'
119
- import { AuthModule } from '../modules/auth.module'
120
155
  import { CoreModule } from '../modules/core.module'
121
- import type { App } from 'exisjs'
156
+ import { UsersModule } from '../modules/users.module'
157
+ import { AuthModule } from '../modules/auth.module'
122
158
 
123
159
  @Server({
124
- plugins: [CoreModule, AuthModule]
160
+ plugins: [CoreModule, UsersModule, AuthModule],
125
161
  })
126
- export default class RootServer {
127
- async onStart(app: App) {
128
- console.log("Server with Global CoreModule and AuthModule booted")
129
- }
130
- }
162
+ export default class RootServer {}
131
163
  ```
132
164
 
133
-
134
165
  ---
135
166
 
136
- ## 2. Framework Plugins (`definePlugin`)
137
-
138
- While `defineModule` is great for internal business logic, `definePlugin` is designed for building distributable, third-party packages that require configuration options.
167
+ ## Framework Plugins (`definePlugin`)
139
168
 
140
- When you use `definePlugin`, ExisJS returns a **Hybrid Object**. This means the plugin can be registered directly if it doesn't need options, or it can be called as a function if you need to pass a configuration object.
169
+ When creating reusable plugins, libraries, or third-party integrations (e.g. Stripe, Redis, S3), use `definePlugin` from `exisjs/plugin`.
141
170
 
142
- ### Building a Plugin
171
+ `definePlugin` returns a hybrid object that can be passed directly to `app.register()` without arguments or invoked as a function to receive configuration parameters.
143
172
 
144
- Let's build a `StripePlugin` that requires an API key:
173
+ ### 1. Authoring a Configurable Plugin
145
174
 
146
175
  ```typescript filename="src/plugins/stripe.plugin.ts"
147
176
  import { definePlugin } from 'exisjs/plugin'
177
+ import Stripe from 'stripe'
148
178
 
149
- interface StripeOptions {
179
+ export interface StripePluginOptions {
150
180
  apiKey: string
181
+ apiVersion?: Stripe.LatestApiVersion
151
182
  }
152
183
 
153
- export const StripePlugin = definePlugin<StripeOptions>({
184
+ export const StripePlugin = definePlugin<StripePluginOptions>({
154
185
  name: 'stripe-plugin',
155
-
186
+
156
187
  async register(app, options) {
157
188
  if (!options?.apiKey) {
158
- throw new Error("Stripe API Key is required")
189
+ throw new Error('[StripePlugin] "apiKey" is required')
159
190
  }
160
191
 
161
- // Initialize Stripe client and inject it globally
162
- const stripeClient = new Stripe(options.apiKey)
163
-
164
- app.provide('StripeClient', { useValue: stripeClient })
165
- }
192
+ const client = new Stripe(options.apiKey, {
193
+ apiVersion: options.apiVersion || '2023-10-16',
194
+ })
195
+
196
+ // Register provider into the application container
197
+ app.provide('StripeClient', { useValue: client })
198
+ },
166
199
  })
167
200
  ```
168
201
 
169
- ### Using the Plugin
202
+ ### 2. Registering Plugins with Configuration Options
170
203
 
171
- Because we used `definePlugin`, the framework allows us to pass configuration options directly:
204
+ Pass the plugin with custom options into `exis.config.ts` (via `defineConfig` or `const config: ExisConfig`) or via `app.register()`:
172
205
 
173
206
  ```typescript filename="exis.config.ts"
174
- import { defineExisConfig } from 'exisjs/config'
207
+ import { defineConfig } from 'exisjs/config'
175
208
  import { StripePlugin } from './src/plugins/stripe.plugin'
176
- import { env } from './src/env'
177
209
 
178
- export default defineExisConfig({
210
+ export default defineConfig({
179
211
  plugins: [
180
- // We call the plugin as a function to pass options
181
- StripePlugin({ apiKey: env.STRIPE_SECRET_KEY })
182
- ]
212
+ StripePlugin({
213
+ apiKey: process.env.STRIPE_SECRET_KEY!,
214
+ }),
215
+ ],
183
216
  })
184
217
  ```
218
+
219
+ ```typescript filename="src/http/server.ts"
220
+ import { exis } from 'exisjs'
221
+ import { StripePlugin } from '../plugins/stripe.plugin'
222
+
223
+ export default exis({
224
+ async onStart(app) {
225
+ await app.register(
226
+ StripePlugin({ apiKey: process.env.STRIPE_SECRET_KEY! })
227
+ )
228
+ },
229
+ })
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Module and Plugin Lifecycle Hooks
235
+
236
+ Both `defineModule` and `definePlugin` support application lifecycle coordination:
237
+
238
+ | Hook | Invocation Phase | Typical Use Case |
239
+ | :--- | :--- | :--- |
240
+ | `register(app, options)` | Server initialization during `app.register()` | Registering DI providers, registering custom routes, configuring middleware. |
241
+ | `onStart(app)` | Triggered after all plugins and routes are loaded, right before the server starts listening | Establishing persistent background connections, pre-warming caches. |
242
+ | `onClose(app)` | Triggered upon graceful shutdown signals (`SIGINT`, `SIGTERM`) | Draining connection pools, flushing queues, terminating worker threads. |