@weconjs/core 1.2.3 → 1.2.6

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 (30) hide show
  1. package/README.md +460 -259
  2. package/dist/config.d.ts +7 -7
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +21 -43
  5. package/dist/config.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/server/index.d.ts.map +1 -1
  9. package/dist/server/index.js +5 -0
  10. package/dist/server/index.js.map +1 -1
  11. package/dist/types.d.ts +10 -12
  12. package/dist/types.d.ts.map +1 -1
  13. package/package.json +2 -2
  14. package/dist/devtools/client/assets/CopyButton-DIdtJD4_.js +0 -6
  15. package/dist/devtools/client/assets/ModuleDetail-Dx6eU87l.js +0 -1
  16. package/dist/devtools/client/assets/TranslationEditor-Bj654a_E.js +0 -11
  17. package/dist/devtools/client/assets/chevron-right-E9DzkOHY.js +0 -6
  18. package/dist/devtools/client/assets/copy-BvbhBv2y.js +0 -6
  19. package/dist/devtools/client/assets/index-B42p6IVr.js +0 -6
  20. package/dist/devtools/client/assets/index-CSkGspzD.js +0 -1
  21. package/dist/devtools/client/assets/index-CnAObNgT.js +0 -16
  22. package/dist/devtools/client/assets/index-CwJHaaYT.css +0 -1
  23. package/dist/devtools/client/assets/index-Dfe66IW7.js +0 -1
  24. package/dist/devtools/client/assets/index-DoHRi03N.js +0 -201
  25. package/dist/devtools/client/assets/index-DvvGoEUv.js +0 -1
  26. package/dist/devtools/client/assets/loader-circle-DoOjJ8vr.js +0 -6
  27. package/dist/devtools/client/assets/plus-Ca-xq8y8.js +0 -6
  28. package/dist/devtools/client/assets/save-CV1xmSXO.js +0 -11
  29. package/dist/devtools/client/assets/search-CpTZ4fXm.js +0 -6
  30. package/dist/devtools/client/index.html +0 -15
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @weconjs/core
2
2
 
3
- > Core framework package for Wecon - A convention-over-configuration Node.js framework.
3
+ > Convention-over-configuration Node.js framework built on Express.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@weconjs/core.svg)](https://www.npmjs.com/package/@weconjs/core)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -8,64 +8,56 @@
8
8
  ## Table of Contents
9
9
 
10
10
  - [Installation](#installation)
11
- - [Features](#features)
12
11
  - [Quick Start](#quick-start)
13
- - [Configuration System](#configuration-system)
14
- - [Module System](#module-system)
15
- - [Server Factory](#server-factory)
16
- - [Database Integration](#database-integration)
12
+ - [Configuration](#configuration)
13
+ - [Modules](#modules)
14
+ - [Routing & RBAC](#routing--rbac)
15
+ - [Database](#database)
17
16
  - [Logging](#logging)
17
+ - [i18n](#i18n)
18
+ - [Socket.IO](#socketio)
19
+ - [Context & Services](#context--services)
20
+ - [Authentication](#authentication)
18
21
  - [API Reference](#api-reference)
19
22
  - [Testing](#testing)
23
+ - [Requirements](#requirements)
24
+ - [License](#license)
20
25
 
21
26
  ## Installation
22
27
 
23
28
  ```bash
24
29
  npm install @weconjs/core
25
- # or
26
- yarn add @weconjs/core
27
30
  ```
28
31
 
29
- ### Optional Dependencies
32
+ Express and Mongoose are peer dependencies:
33
+
34
+ ```bash
35
+ npm install express mongoose
36
+ ```
37
+
38
+ Optional peer dependencies:
30
39
 
31
40
  ```bash
32
41
  # Winston logging with daily file rotation
33
42
  npm install winston winston-daily-rotate-file
34
43
 
44
+ # Socket.IO real-time support
45
+ npm install socket.io
46
+
35
47
  # Field-level access control for Mongoose
36
48
  npm install @weconjs/mongoose-field-shield
37
49
  ```
38
50
 
39
- ## Features
40
-
41
- | Feature | Description |
42
- |---------|-------------|
43
- | **Configuration System** | Mode-based configuration with inheritance (development, staging, production) |
44
- | **Module System** | Auto-discovery, dependency resolution, and lifecycle hooks |
45
- | **i18n Support** | Automatic translation file loading from module directories |
46
- | **Socket.IO Integration** | Auto-discover and register socket handlers and middleware |
47
- | **Database Connection** | MongoDB/Mongoose with URI builders, plugins, retry logic |
48
- | **Server Factory** | Complete Express bootstrap with HTTPS, graceful shutdown |
49
- | **Winston Logger** | Production-ready logging with console and file rotation |
50
- | **Response Helpers** | Standardized API responses via `res.respond()` |
51
- | **HTTPS Support** | Built-in SSL/TLS certificate loading and validation |
52
- | **Graceful Shutdown** | Proper SIGTERM/SIGINT handling with cleanup hooks |
53
-
54
- ---
55
-
56
51
  ## Quick Start
57
52
 
58
- ### 1. Create Configuration File
53
+ ### 1. Define your configuration
59
54
 
60
55
  ```typescript
61
56
  // wecon.config.ts
62
57
  import { defineConfig } from '@weconjs/core';
63
58
 
64
59
  export default defineConfig({
65
- app: {
66
- name: 'my-api',
67
- version: '1.0.0',
68
- },
60
+ app: { name: 'my-api', version: '1.0.0' },
69
61
  modes: {
70
62
  development: {
71
63
  port: 3000,
@@ -86,53 +78,50 @@ export default defineConfig({
86
78
  protocol: 'mongodb+srv',
87
79
  host: process.env.DB_HOST,
88
80
  database: 'myapp',
89
- username: process.env.DB_USER,
90
- password: process.env.DB_PASSWORD,
81
+ auth: {
82
+ username: process.env.DB_USER,
83
+ password: process.env.DB_PASSWORD,
84
+ },
91
85
  },
92
86
  },
93
- logging: {
94
- level: 'info',
95
- enableFile: true,
96
- directory: './logs',
97
- },
98
- https: {
99
- enabled: true,
100
- keyPath: './certs/privkey.pem',
101
- certPath: './certs/fullchain.pem',
102
- },
103
- },
104
- },
105
- modules: ['./src/modules/users', './src/modules/auth'],
106
- features: {
107
- i18n: {
108
- enabled: true,
109
- defaultLocale: 'en',
110
- supported: ['en', 'es', 'fr'],
111
- },
112
- fieldShield: {
113
- enabled: true,
114
- strict: true,
87
+ logging: { level: 'info', enableFile: true },
115
88
  },
116
89
  },
90
+ modules: ['./src/modules/auth', './src/modules/users'],
117
91
  });
118
92
  ```
119
93
 
120
- ### 2. Define a Module
94
+ ### 2. Define a module
121
95
 
122
96
  ```typescript
123
97
  // src/modules/users/users.module.ts
124
- import { defineModule } from '@weconjs/core';
125
- import { Routes, Route } from '@weconjs/lib';
98
+ import { defineModule, Routes, Route } from '@weconjs/core';
126
99
  import { userController } from './controllers/user.controller.js';
127
100
 
128
101
  const usersRoutes = new Routes({
129
102
  prefix: '/users',
130
103
  routes: [
131
- new Route({ method: 'get', path: '/', handler: userController.findAll }),
132
- new Route({ method: 'get', path: '/:id', handler: userController.findById }),
133
- new Route({ method: 'post', path: '/', handler: userController.create }),
134
- new Route({ method: 'put', path: '/:id', handler: userController.update }),
135
- new Route({ method: 'delete', path: '/:id', handler: userController.delete }),
104
+ new Route({
105
+ method: 'GET',
106
+ path: '/',
107
+ rai: 'users:list',
108
+ roles: ['admin', 'user'],
109
+ middlewares: [userController.findAll],
110
+ }),
111
+ new Route({
112
+ method: 'GET',
113
+ path: '/:id',
114
+ rai: 'users:read',
115
+ roles: ['admin', 'user'],
116
+ middlewares: [userController.findById],
117
+ }),
118
+ new Route({
119
+ method: 'POST',
120
+ path: '/',
121
+ rai: 'users:create',
122
+ roles: ['admin'],
123
+ middlewares: [userController.create],
124
+ }),
136
125
  ],
137
126
  });
138
127
 
@@ -140,75 +129,60 @@ export default defineModule({
140
129
  name: 'users',
141
130
  description: 'User management module',
142
131
  routes: usersRoutes,
143
- dependencies: ['auth'], // Load auth module first
132
+ imports: ['auth'],
144
133
  onInit: async (ctx) => {
145
134
  ctx.logger.info('Users module initialized');
146
- // Setup module-specific resources
147
135
  },
148
136
  });
149
137
  ```
150
138
 
151
- ### 3. Create Application Entry Point
139
+ ### 3. Set up routing with RBAC
152
140
 
153
141
  ```typescript
154
- // src/main.ts
155
- import path from 'path';
156
- import {
157
- createWecon,
158
- loadConfig,
159
- buildUriFromConfig,
160
- type WeconContext
161
- } from '@weconjs/core';
142
+ // src/bootstrap.ts
143
+ import { Wecon, Routes } from '@weconjs/core';
144
+ import usersModule from './modules/users/users.module.js';
145
+ import authModule from './modules/auth/auth.module.js';
146
+
147
+ const roles = ['admin', 'user', 'guest'] as const;
148
+
149
+ export const wecon = new Wecon()
150
+ .roles(roles)
151
+ .guestRole('guest')
152
+ .routes(
153
+ new Routes({
154
+ prefix: '/api',
155
+ routes: [authModule.routes!, usersModule.routes!],
156
+ })
157
+ )
158
+ .dev({ helpfulErrors: true, logRoutes: true })
159
+ .build();
160
+
161
+ export const modules = [authModule, usersModule];
162
+ ```
162
163
 
163
- async function main() {
164
- // Load configuration with mode resolution
165
- const config = await loadConfig(
166
- path.resolve(process.cwd(), 'wecon.config.ts'),
167
- process.env.NODE_ENV
168
- );
164
+ ### 4. Create the application entry point
169
165
 
170
- console.log(`Starting ${config.app.name} v${config.app.version}`);
171
- console.log(`Mode: ${config.mode}`);
166
+ ```typescript
167
+ // src/main.ts
168
+ import { createWecon, loadConfig, buildUriFromConfig } from '@weconjs/core';
169
+ import { wecon, modules } from './bootstrap.js';
172
170
 
173
- // Dynamic import after config is loaded
174
- const { wecon, modules } = await import('./bootstrap.js');
171
+ async function main() {
172
+ const config = await loadConfig('./wecon.config.ts', process.env.NODE_ENV);
175
173
 
176
- // Create and configure the application
177
174
  const app = await createWecon({
178
175
  config,
179
- modules: [...modules],
176
+ modules,
180
177
  wecon,
181
- middleware: [], // Your custom middleware array
182
178
  database: {
183
179
  enabled: true,
184
180
  uri: buildUriFromConfig(config.database),
185
- plugins: [], // Global Mongoose plugins
186
- debug: config.mode === 'development',
187
- },
188
- plugins: {
189
- fieldShield: config.features?.fieldShield?.enabled
190
- ? { strict: config.features.fieldShield.strict ?? true }
191
- : false,
192
- },
193
- i18n: {
194
- enabled: config.features?.i18n?.enabled ?? false,
195
- modulesDir: './src/modules',
196
- },
197
- logger: {
198
- useWinston: true,
199
- level: config.logging?.level ?? 'info',
200
- appName: config.app.name,
201
- enableFile: config.logging?.enableFile ?? false,
202
- logsDir: config.logging?.directory ?? './logs',
203
181
  },
182
+ logger: { useWinston: true, enableFile: false },
204
183
  hooks: {
205
- onBoot: async (ctx: WeconContext) => {
206
- ctx.logger.info('Application ready to receive requests');
207
- },
208
- onShutdown: async (ctx: WeconContext) => {
209
- ctx.logger.info('Application shutting down...');
210
- // Cleanup resources, close connections
211
- },
184
+ onBoot: (ctx) => ctx.logger.info('Server ready'),
185
+ onShutdown: (ctx) => ctx.logger.info('Shutting down...'),
212
186
  },
213
187
  });
214
188
 
@@ -216,98 +190,124 @@ async function main() {
216
190
  }
217
191
 
218
192
  main().catch((err) => {
219
- console.error('Failed to start application:', err);
193
+ console.error('Failed to start:', err);
220
194
  process.exit(1);
221
195
  });
222
196
  ```
223
197
 
224
- ---
225
-
226
- ## Configuration System
198
+ ## Configuration
227
199
 
228
- ### Mode-Based Configuration
200
+ ### Mode-based configuration
229
201
 
230
- Define environment-specific settings that inherit from a base configuration:
202
+ Define environment-specific settings that deep-merge with a base configuration. Modes can inherit from other modes with `extends`:
231
203
 
232
204
  ```typescript
233
205
  import { defineConfig } from '@weconjs/core';
234
206
 
235
207
  export default defineConfig({
236
- // Base configuration (shared across all modes)
237
208
  app: { name: 'my-api', version: '1.0.0' },
238
-
239
- // Mode-specific overrides
240
209
  modes: {
241
210
  development: {
242
211
  port: 3000,
243
212
  logging: { level: 'debug' },
244
213
  },
245
214
  staging: {
215
+ extends: 'development',
246
216
  port: 3000,
247
217
  logging: { level: 'info' },
248
218
  },
249
219
  production: {
250
220
  port: 8080,
251
221
  logging: { level: 'warn', enableFile: true },
222
+ https: {
223
+ enabled: true,
224
+ keyPath: './certs/privkey.pem',
225
+ certPath: './certs/fullchain.pem',
226
+ },
252
227
  },
253
228
  },
254
229
  });
255
230
  ```
256
231
 
257
- ### Loading Configuration
232
+ ### Loading & resolving configuration
258
233
 
259
234
  ```typescript
260
235
  import { loadConfig, resolveConfig } from '@weconjs/core';
261
236
 
262
- // Load and resolve for current environment
237
+ // Load and resolve for the current environment
263
238
  const config = await loadConfig('./wecon.config.ts', process.env.NODE_ENV);
264
239
 
265
- // Or load and resolve separately
240
+ // Or resolve separately
266
241
  const rawConfig = await loadConfig('./wecon.config.ts');
267
242
  const resolved = resolveConfig(rawConfig, 'production');
268
243
  ```
269
244
 
270
- ---
245
+ ### Per-module configuration
271
246
 
272
- ## Module System
247
+ Modules can declare a Zod schema for their configuration. Values are validated at startup and accessible at runtime through the context:
273
248
 
274
- ### Module Definition
249
+ ```typescript
250
+ import { z } from 'zod';
251
+ import { defineModule } from '@weconjs/core';
252
+
253
+ export default defineModule({
254
+ name: 'mail',
255
+ config: {
256
+ schema: z.object({
257
+ from: z.string().email(),
258
+ provider: z.enum(['ses', 'sendgrid']),
259
+ }),
260
+ defaults: { provider: 'ses' },
261
+ },
262
+ onInit: async (ctx) => {
263
+ const mailConfig = ctx.getModuleConfig<{ from: string; provider: string }>('mail');
264
+ ctx.logger.info(`Mail provider: ${mailConfig.provider}`);
265
+ },
266
+ });
267
+ ```
268
+
269
+ Provide values in your config file:
270
+
271
+ ```typescript
272
+ export default defineConfig({
273
+ app: { name: 'my-api' },
274
+ moduleConfigs: {
275
+ mail: { from: 'hello@example.com' },
276
+ },
277
+ // ...
278
+ });
279
+ ```
280
+
281
+ ## Modules
282
+
283
+ ### Defining modules
275
284
 
276
285
  ```typescript
277
- import { defineModule, type WeconContext } from '@weconjs/core';
286
+ import { defineModule } from '@weconjs/core';
278
287
 
279
288
  export default defineModule({
280
289
  name: 'auth',
281
290
  description: 'Authentication and authorization',
282
- routes: authRoutes,
283
-
284
- // Declare dependencies (loaded first)
285
- dependencies: ['database-seeds'],
286
-
287
- // Lifecycle hooks
288
- onInit: async (module, ctx: WeconContext) => {
289
- // Called when module is registered
290
- ctx.logger.debug(`${module.name} module initializing`);
291
- },
292
-
293
- onBoot: async (module, ctx: WeconContext) => {
294
- // Called after all modules initialized, before server starts
295
- await seedDefaultRoles(ctx);
291
+ routes: authRoutes, // Routes instance
292
+ imports: ['database-seeds'], // Dependencies (loaded first)
293
+ exports: ['authService'], // Exported services
294
+ path: __dirname, // Enables per-module package.json
295
+
296
+ onInit: async (ctx) => {
297
+ // Called when the module is initialized
296
298
  },
297
-
298
- onShutdown: async (module, ctx: WeconContext) => {
299
+ onDestroy: async (ctx) => {
299
300
  // Called on graceful shutdown
300
- await cleanupSessions();
301
301
  },
302
302
  });
303
303
  ```
304
304
 
305
- ### Module Discovery
305
+ ### Dependency resolution
306
306
 
307
- The framework automatically resolves dependencies using topological sorting:
307
+ Modules are sorted using topological sort, with circular dependency detection:
308
308
 
309
309
  ```typescript
310
- import { resolveModuleDependencies, loadModule } from '@weconjs/core';
310
+ import { loadModule, resolveModuleDependencies } from '@weconjs/core';
311
311
 
312
312
  const modules = await Promise.all([
313
313
  loadModule('./src/modules/users'),
@@ -319,110 +319,132 @@ const modules = await Promise.all([
319
319
  const sorted = resolveModuleDependencies(modules);
320
320
  ```
321
321
 
322
- ---
322
+ ### Per-module dependencies
323
323
 
324
- ## Server Factory
325
-
326
- ### Basic Usage
324
+ Each module can have its own `package.json` for isolated dependencies. The framework can auto-install missing dependencies in development:
327
325
 
328
326
  ```typescript
329
- import { createWecon } from '@weconjs/core';
330
-
331
327
  const app = await createWecon({
332
328
  config,
333
329
  modules,
334
- wecon, // @weconjs/lib instance
330
+ moduleDeps: {
331
+ autoInstall: true,
332
+ rootDir: process.cwd(),
333
+ paths: {
334
+ auth: './src/modules/auth',
335
+ users: './src/modules/users',
336
+ },
337
+ },
335
338
  });
339
+ ```
340
+
341
+ ## Routing & RBAC
342
+
343
+ Wecon uses a two-layer architecture for request processing:
344
+
345
+ 1. **Intelligence Layer** — `RaiMatcher` resolves the request to a RAI (Route Access Identifier) and checks authorization against the user's roles
346
+ 2. **Execution Layer** — a single compiled Express Router handles the request
347
+
348
+ ### Route Access Identifiers (RAI)
349
+
350
+ Every route has a unique RAI string (e.g. `users:list`, `orders:create`). The RAI is used for authorization checks and route introspection.
336
351
 
337
- await app.start();
352
+ ### Defining routes
353
+
354
+ ```typescript
355
+ import { Route, Routes, RoutesParam } from '@weconjs/core';
356
+
357
+ const routes = new Routes({
358
+ prefix: '/api/orders',
359
+ middlewares: [authMiddleware],
360
+ routes: [
361
+ new Route({
362
+ method: 'GET',
363
+ path: '/',
364
+ rai: 'orders:list',
365
+ roles: ['admin', 'user'],
366
+ middlewares: [orderController.list],
367
+ }),
368
+ new Route({
369
+ method: 'POST',
370
+ path: '/',
371
+ rai: 'orders:create',
372
+ roles: ['admin', 'user'],
373
+ middlewares: [validateOrder, orderController.create],
374
+ }),
375
+ new Route({
376
+ method: 'DELETE',
377
+ path: '/:id',
378
+ rai: 'orders:delete',
379
+ roles: ['admin'],
380
+ middlewares: [orderController.delete],
381
+ meta: { audit: true },
382
+ }),
383
+ ],
384
+ });
338
385
  ```
339
386
 
340
- ### Full Configuration
387
+ Routes can be nested. Prefixes, middleware, and params accumulate from parent groups:
341
388
 
342
389
  ```typescript
343
- const app = await createWecon({
344
- config,
345
- modules,
346
- wecon,
347
-
348
- // Custom Express middleware
349
- middleware: [cors(), helmet(), rateLimit()],
350
-
351
- // Database configuration
352
- database: {
353
- enabled: true,
354
- uri: 'mongodb://localhost/myapp',
355
- plugins: [timestampPlugin, auditPlugin],
356
- debug: true,
357
- retryAttempts: 5,
358
- retryDelay: 2000,
359
- },
360
-
361
- // FieldShield integration
362
- plugins: {
363
- fieldShield: { strict: true },
364
- },
365
-
366
- // i18n configuration
367
- i18n: {
368
- enabled: true,
369
- modulesDir: './src/modules',
370
- },
371
-
372
- // Logger configuration
373
- logger: {
374
- useWinston: true,
375
- level: 'info',
376
- appName: 'my-api',
377
- enableFile: true,
378
- logsDir: './logs',
379
- },
380
-
381
- // Lifecycle hooks
382
- hooks: {
383
- onBoot: async (ctx) => { /* Server starting */ },
384
- onShutdown: async (ctx) => { /* Cleanup */ },
385
- onModuleInit: async (module, ctx) => { /* Module loaded */ },
386
- },
390
+ const apiRoutes = new Routes({
391
+ prefix: '/api',
392
+ middlewares: [corsMiddleware, rateLimiter],
393
+ routes: [authRoutes, userRoutes, orderRoutes],
387
394
  });
388
395
  ```
389
396
 
390
- ### Response Helpers
397
+ ### Building the Wecon instance
391
398
 
392
- The server factory installs `res.respond()` on all Express responses:
399
+ ```typescript
400
+ import { Wecon } from '@weconjs/core';
401
+
402
+ const wecon = new Wecon()
403
+ .roles(['admin', 'user', 'guest'] as const)
404
+ .guestRole('guest')
405
+ .routes(apiRoutes)
406
+ .dev({
407
+ debugMode: true,
408
+ helpfulErrors: true, // Detailed 401/404 messages in development
409
+ logRoutes: true,
410
+ })
411
+ .onRoutesPrepared((routes) => {
412
+ console.log(`Registered ${routes.length} routes`);
413
+ })
414
+ .build();
415
+
416
+ // Mount as Express middleware
417
+ app.use(wecon.handler());
418
+ ```
419
+
420
+ ### Type-safe roles
421
+
422
+ Augment the global `Wecon.Roles` type for compile-time role checking:
393
423
 
394
424
  ```typescript
395
- // Controller example
396
- async findAll(req: Request, res: Response) {
397
- const users = await userService.findAll();
398
-
399
- res.respond({
400
- success: true,
401
- data: users,
402
- meta: { total: users.length },
403
- });
425
+ // wecon.d.ts
426
+ declare global {
427
+ namespace Wecon {
428
+ type Roles = 'admin' | 'user' | 'guest';
429
+ }
404
430
  }
405
-
406
- // Error response
407
- res.respond({
408
- success: false,
409
- message: req.t('user_not_found'),
410
- errors: [{ code: 'NOT_FOUND', field: 'id' }],
411
- }, 404);
431
+ export {};
412
432
  ```
413
433
 
414
- ---
434
+ ### Route introspection
415
435
 
416
- ## Database Integration
436
+ ```typescript
437
+ const allRoutes = wecon.getRoutes();
438
+ const route = wecon.getRoute('users:read');
439
+ ```
417
440
 
418
- ### URI Builder
441
+ ## Database
419
442
 
420
- Build MongoDB connection strings from configuration:
443
+ ### URI builder
421
444
 
422
445
  ```typescript
423
446
  import { buildMongoUri, buildUriFromConfig } from '@weconjs/core';
424
447
 
425
- // From individual parts
426
448
  const uri = buildMongoUri({
427
449
  protocol: 'mongodb+srv',
428
450
  host: 'cluster.mongodb.net',
@@ -432,11 +454,11 @@ const uri = buildMongoUri({
432
454
  options: { retryWrites: 'true', w: 'majority' },
433
455
  });
434
456
 
435
- // From config object
457
+ // Or build from a resolved config
436
458
  const uri = buildUriFromConfig(config.database);
437
459
  ```
438
460
 
439
- ### Database Connection
461
+ ### Connection with retry logic
440
462
 
441
463
  ```typescript
442
464
  import { createDatabaseConnection } from '@weconjs/core';
@@ -445,103 +467,282 @@ const db = await createDatabaseConnection({
445
467
  uri: 'mongodb://localhost/myapp',
446
468
  plugins: [timestampPlugin],
447
469
  debug: process.env.NODE_ENV === 'development',
448
- retryAttempts: 5,
449
- retryDelay: 2000,
470
+ fieldShield: { enabled: true, strict: true },
450
471
  });
472
+
473
+ await db.connect();
451
474
  ```
452
475
 
453
- ---
476
+ The connection retries with configurable exponential backoff on failure.
454
477
 
455
478
  ## Logging
456
479
 
457
- ### Winston Logger
480
+ Two logging backends are supported: Winston (with daily file rotation) and a console-only fallback.
458
481
 
459
482
  ```typescript
460
483
  import { createWinstonLogger, createConsoleLogger } from '@weconjs/core';
461
484
 
462
- // Winston with file rotation (requires winston + winston-daily-rotate-file)
485
+ // Winston (requires winston + winston-daily-rotate-file)
463
486
  const logger = await createWinstonLogger({
464
487
  level: 'info',
465
488
  appName: 'my-api',
466
489
  enableFile: true,
467
- logsDir: './logs',
490
+ logDir: './logs',
468
491
  });
469
492
 
470
- // Console-only fallback
493
+ // Console fallback (zero dependencies)
471
494
  const logger = createConsoleLogger({
472
495
  level: 'debug',
473
496
  appName: 'my-api',
474
497
  });
475
498
 
476
499
  logger.info('Server started', { port: 3000 });
477
- logger.error('Database connection failed', { error: err.message });
500
+ logger.error('Connection failed', { error: err.message });
501
+ ```
502
+
503
+ When creating an app with `createWecon`, the framework tries Winston first and falls back to the console logger automatically.
504
+
505
+ ## i18n
506
+
507
+ Translation files are auto-discovered from module directories. Each module can have a `locales/` folder with JSON files:
508
+
509
+ ```
510
+ src/modules/users/locales/en.json
511
+ src/modules/users/locales/es.json
512
+ ```
513
+
514
+ Enable i18n in your config:
515
+
516
+ ```typescript
517
+ const app = await createWecon({
518
+ config,
519
+ modules,
520
+ i18n: { enabled: true, modulesDir: './src/modules' },
521
+ });
522
+ ```
523
+
524
+ Use translations in handlers via `req.t()`:
525
+
526
+ ```typescript
527
+ app.get('/greeting', (req, res) => {
528
+ res.json({ message: req.t('users:welcome', { name: 'Alice' }) });
529
+ });
530
+ ```
531
+
532
+ Interpolation uses `{{key}}` syntax in translation files:
533
+
534
+ ```json
535
+ { "welcome": "Welcome, {{name}}!" }
536
+ ```
537
+
538
+ ## Socket.IO
539
+
540
+ Socket handlers and middleware are auto-discovered from module directories:
541
+
542
+ ```typescript
543
+ import { setupSocketIO, createSocketServer } from '@weconjs/core';
544
+
545
+ // Attach to existing HTTP server
546
+ const io = createSocketServer(httpServer, {
547
+ cors: { origin: 'http://localhost:3000' },
548
+ });
549
+
550
+ // Auto-discover handlers from modules
551
+ await setupSocketIO(io, './src/modules');
552
+ ```
553
+
554
+ Convention: place socket handlers in `src/modules/<name>/sockets/` and middleware in `src/modules/<name>/sockets/middleware/`.
555
+
556
+ ## Context & Services
557
+
558
+ The `WeconContext` is passed to all module hooks, handlers, and middleware. It provides access to configuration, logging, and a service registry.
559
+
560
+ ```typescript
561
+ // Register a service
562
+ ctx.registerService('mailer', new MailerService());
563
+
564
+ // Retrieve a service
565
+ const mailer = ctx.getService<MailerService>('mailer');
566
+
567
+ // Access module config (validated at startup)
568
+ const mailConfig = ctx.getModuleConfig<MailConfig>('mail');
569
+
570
+ // Update module config at runtime (re-validates against Zod schema)
571
+ ctx.setModuleConfig('mail', { from: 'new@example.com', provider: 'sendgrid' });
572
+ ```
573
+
574
+ ## Authentication
575
+
576
+ Wecon provides an `Authenticable` interface for any model used in authentication. The `WeconRequest` generic lets you type `req.user`:
577
+
578
+ ```typescript
579
+ import type { Authenticable, WeconRequest, WeconResponse } from '@weconjs/core';
580
+
581
+ interface User extends Authenticable {
582
+ email: string;
583
+ name: { first: string; last: string };
584
+ }
585
+
586
+ function getProfile(req: WeconRequest<User>, res: WeconResponse) {
587
+ const user = req.user!;
588
+ res.respond({ data: { email: user.email, roles: user.roles } });
589
+ }
478
590
  ```
479
591
 
480
- ---
592
+ ### Response helpers
593
+
594
+ The `res.respond()` helper produces standardized API responses:
595
+
596
+ ```typescript
597
+ // Success
598
+ res.respond({ data: users, meta: { total: users.length } });
599
+ // → { success: true, data: [...], errors: null, meta: { total: 10 } }
600
+
601
+ // Error
602
+ res.status(404).respond({
603
+ errors: [{ code: 'NOT_FOUND', message: 'User not found' }],
604
+ });
605
+ // → { success: false, data: null, errors: [...], meta: null }
606
+ ```
607
+
608
+ ## Server Factory
609
+
610
+ `createWecon` is the main entry point. It wires together all framework features and returns a `WeconApp` instance:
611
+
612
+ ```typescript
613
+ import { createWecon } from '@weconjs/core';
614
+
615
+ const app = await createWecon({
616
+ config,
617
+ modules,
618
+ wecon, // Wecon routing instance (optional)
619
+ middleware: [cors(), helmet()], // Custom Express middleware
620
+ database: { enabled: true, uri: '...' },
621
+ plugins: { fieldShield: { strict: true } },
622
+ i18n: { enabled: true, modulesDir: './src/modules' },
623
+ logger: { useWinston: true, enableFile: true, logDir: './logs' },
624
+ moduleDeps: { autoInstall: true, paths: { auth: './src/modules/auth' } },
625
+ hooks: {
626
+ onBoot: async (ctx) => { /* before server starts */ },
627
+ onShutdown: async (ctx) => { /* cleanup */ },
628
+ onModuleInit: async (module, ctx) => { /* after each module init */ },
629
+ },
630
+ });
631
+
632
+ const server = await app.start(); // Start listening
633
+ await app.shutdown(); // Graceful shutdown
634
+ ```
635
+
636
+ Features included automatically:
637
+ - `express.json()` and `express.urlencoded()` parsing
638
+ - `/health` endpoint
639
+ - HTTPS support (falls back to HTTP if certs are missing)
640
+ - Graceful shutdown on SIGTERM, SIGINT, SIGUSR2
641
+ - Global error handler with standardized responses
481
642
 
482
643
  ## API Reference
483
644
 
484
645
  ### Configuration
485
646
 
486
- | Function | Description |
487
- |----------|-------------|
647
+ | Export | Description |
648
+ |--------|-------------|
488
649
  | `defineConfig(config)` | Define application configuration with TypeScript support |
489
650
  | `resolveConfig(config, mode)` | Resolve configuration for a specific mode |
490
651
  | `loadConfig(path, mode?)` | Load configuration file and optionally resolve mode |
491
652
 
492
653
  ### Modules
493
654
 
494
- | Function | Description |
495
- |----------|-------------|
655
+ | Export | Description |
656
+ |--------|-------------|
496
657
  | `defineModule(definition)` | Define a module with routes and lifecycle hooks |
497
658
  | `loadModule(path)` | Load a module from file path |
498
- | `resolveModuleDependencies(modules)` | Sort modules by dependencies |
659
+ | `resolveModuleDependencies(modules)` | Sort modules by dependencies (topological sort) |
660
+ | `readModulePackageJson(path)` | Read a module's package.json |
661
+ | `checkModuleDeps(path, rootDir)` | Check if module dependencies are installed |
662
+ | `installModuleDeps(path, rootDir)` | Install missing module dependencies |
663
+ | `resolveAllModuleDeps(modules, rootDir, logger, autoInstall)` | Check/install deps for all modules |
664
+ | `detectPackageManager()` | Detect npm/yarn/pnpm |
499
665
 
500
666
  ### Server
501
667
 
502
- | Function | Description |
503
- |----------|-------------|
504
- | `createWecon(options)` | Create and configure Wecon application |
668
+ | Export | Description |
669
+ |--------|-------------|
670
+ | `createWecon(options)` | Create and configure the application |
671
+
672
+ ### Routing
673
+
674
+ | Export | Description |
675
+ |--------|-------------|
676
+ | `Wecon` | Main routing class with fluent API and RBAC |
677
+ | `Route` | Single endpoint definition (method, path, RAI, roles, middlewares) |
678
+ | `Routes` | Hierarchical route group with prefix, middleware, and params |
679
+ | `RoutesParam` | Route parameter definition with validation |
680
+ | `RaiMatcher` | RAI resolution engine (maps request path + method to a RAI) |
681
+ | `ErrorCatcher` | Base class for configuration error reporting |
505
682
 
506
683
  ### Database
507
684
 
508
- | Function | Description |
509
- |----------|-------------|
685
+ | Export | Description |
686
+ |--------|-------------|
510
687
  | `createDatabaseConnection(options)` | Create MongoDB connection with retry logic |
511
688
  | `buildMongoUri(parts)` | Build MongoDB URI from parts |
512
689
  | `buildUriFromConfig(config)` | Build URI from database config object |
513
690
 
514
691
  ### Logging
515
692
 
516
- | Function | Description |
517
- |----------|-------------|
693
+ | Export | Description |
694
+ |--------|-------------|
518
695
  | `createWinstonLogger(options)` | Create Winston logger with file rotation |
519
- | `createConsoleLogger(options)` | Create console-based logger |
696
+ | `createConsoleLogger(options)` | Create console-based fallback logger |
697
+
698
+ ### i18n
699
+
700
+ | Export | Description |
701
+ |--------|-------------|
702
+ | `initI18n(modulesDir, defaultLocale)` | Initialize i18n and return Express middleware |
703
+ | `loadI18nResources(modulesDir)` | Load translation files from module directories |
704
+ | `createI18nMiddleware(resources, defaultLocale)` | Create the Express middleware |
520
705
 
521
706
  ### Socket.IO
522
707
 
523
- | Function | Description |
524
- |----------|-------------|
525
- | `setupSocketIO(server, modulesDir, options)` | Setup Socket.IO with auto-discovery |
526
- | `discoverSocketHandlers(modulesDir)` | Find socket handlers in modules |
527
- | `discoverSocketMiddleware(modulesDir)` | Find socket middleware in modules |
708
+ | Export | Description |
709
+ |--------|-------------|
710
+ | `createSocketServer(httpServer, options)` | Create Socket.IO server |
711
+ | `setupSocketIO(io, modulesDir)` | Auto-discover and register handlers |
712
+ | `initializeSocket(server, modulesDir, options)` | Combined setup helper |
713
+ | `discoverSocketHandlers(modulesDir)` | Find socket handler files in modules |
714
+ | `discoverSocketMiddleware(modulesDir)` | Find socket middleware files in modules |
715
+
716
+ ### Context
717
+
718
+ | Export | Description |
719
+ |--------|-------------|
720
+ | `createContext(options)` | Create application context with service registry |
721
+ | `createLogger(options)` | Create a logger instance |
722
+
723
+ ### Errors
528
724
 
529
- ---
725
+ | Export | Description |
726
+ |--------|-------------|
727
+ | `ConfigError` | Configuration error with code and metadata |
728
+ | `RequestError` | Request error with code and metadata |
530
729
 
531
730
  ## Testing
532
731
 
533
732
  ```bash
534
- yarn test # Run all 82 unit tests
535
- yarn build # Build TypeScript to dist/
733
+ npm test # Run all tests
734
+ npm run test:watch # Watch mode
735
+ npm run test:coverage # With coverage report
736
+ npm run build # Build TypeScript to dist/
536
737
  ```
537
738
 
538
739
  ## Requirements
539
740
 
540
741
  - Node.js >= 18.0.0
541
742
  - TypeScript >= 5.0.0
542
- - Express 5.x
543
- - Mongoose 8.x
743
+ - Express 5.x (peer dependency)
744
+ - Mongoose 8.x (peer dependency)
544
745
 
545
746
  ## License
546
747
 
547
- MIT © [weconjs](https://github.com/weconjs)
748
+ MIT