exisjs 0.7.3 → 0.7.5

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 (162) hide show
  1. package/dist/cli/commands/build.d.ts +4 -2
  2. package/dist/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cli/commands/build.js +80 -22
  4. package/dist/cli/commands/build.js.map +1 -1
  5. package/dist/cli/commands/dev.d.ts.map +1 -1
  6. package/dist/cli/commands/dev.js +121 -27
  7. package/dist/cli/commands/dev.js.map +1 -1
  8. package/dist/cli/commands/doctor.d.ts.map +1 -1
  9. package/dist/cli/commands/doctor.js +5 -2
  10. package/dist/cli/commands/doctor.js.map +1 -1
  11. package/dist/cli/commands/generate.d.ts +5 -0
  12. package/dist/cli/commands/generate.d.ts.map +1 -1
  13. package/dist/cli/commands/generate.js +252 -14
  14. package/dist/cli/commands/generate.js.map +1 -1
  15. package/dist/cli/commands/start.d.ts.map +1 -1
  16. package/dist/cli/commands/start.js +17 -5
  17. package/dist/cli/commands/start.js.map +1 -1
  18. package/dist/cli/index.js +16 -5
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/manifest.d.ts.map +1 -1
  21. package/dist/cli/manifest.js +12 -4
  22. package/dist/cli/manifest.js.map +1 -1
  23. package/dist/config/config.js +1 -1
  24. package/dist/config/config.js.map +1 -1
  25. package/dist/config/env.d.ts.map +1 -1
  26. package/dist/config/env.js +8 -0
  27. package/dist/config/env.js.map +1 -1
  28. package/dist/database/index.d.ts +4 -0
  29. package/dist/database/index.d.ts.map +1 -0
  30. package/dist/database/index.js +20 -0
  31. package/dist/database/index.js.map +1 -0
  32. package/dist/database/lifecycle.d.ts +52 -0
  33. package/dist/database/lifecycle.d.ts.map +1 -0
  34. package/dist/database/lifecycle.js +122 -0
  35. package/dist/database/lifecycle.js.map +1 -0
  36. package/dist/database/mongoose.d.ts +47 -0
  37. package/dist/database/mongoose.d.ts.map +1 -0
  38. package/dist/database/mongoose.js +44 -0
  39. package/dist/database/mongoose.js.map +1 -0
  40. package/dist/database/transaction.d.ts +39 -0
  41. package/dist/database/transaction.d.ts.map +1 -0
  42. package/dist/database/transaction.js +99 -0
  43. package/dist/database/transaction.js.map +1 -0
  44. package/dist/decorators/constants.d.ts +2 -0
  45. package/dist/decorators/constants.d.ts.map +1 -1
  46. package/dist/decorators/index.d.ts +1 -0
  47. package/dist/decorators/index.d.ts.map +1 -1
  48. package/dist/decorators/index.js +1 -0
  49. package/dist/decorators/index.js.map +1 -1
  50. package/dist/decorators/middleware.d.ts +10 -0
  51. package/dist/decorators/middleware.d.ts.map +1 -1
  52. package/dist/decorators/middleware.js +27 -0
  53. package/dist/decorators/middleware.js.map +1 -1
  54. package/dist/decorators/upload.d.ts +37 -0
  55. package/dist/decorators/upload.d.ts.map +1 -0
  56. package/dist/decorators/upload.js +78 -0
  57. package/dist/decorators/upload.js.map +1 -0
  58. package/dist/docs/content/boundaries.mdx +33 -3
  59. package/dist/docs/content/cli/commands.mdx +4 -3
  60. package/dist/docs/content/config.mdx +27 -1
  61. package/dist/docs/content/errors.mdx +81 -11
  62. package/dist/docs/content/middleware.mdx +138 -0
  63. package/dist/docs/content/providers.mdx +89 -0
  64. package/dist/docs/content/requests.mdx +191 -69
  65. package/dist/docs/content/responses.mdx +99 -6
  66. package/dist/docs/content/routing.mdx +117 -0
  67. package/dist/docs/content/security.mdx +17 -4
  68. package/dist/docs/content/structure.mdx +91 -12
  69. package/dist/docs/content/validation.mdx +131 -10
  70. package/dist/docs/reference/database.mdx +152 -0
  71. package/dist/docs/reference/decorators.mdx +4 -0
  72. package/dist/docs/reference/error.mdx +3 -1
  73. package/dist/docs/reference/middleware.mdx +84 -2
  74. package/dist/docs/reference/router.mdx +4 -2
  75. package/dist/docs/reference/validator.mdx +43 -5
  76. package/dist/error/errors.d.ts +10 -0
  77. package/dist/error/errors.d.ts.map +1 -1
  78. package/dist/error/errors.js +156 -25
  79. package/dist/error/errors.js.map +1 -1
  80. package/dist/error/index.d.ts +1 -1
  81. package/dist/error/index.d.ts.map +1 -1
  82. package/dist/error/index.js +3 -1
  83. package/dist/error/index.js.map +1 -1
  84. package/dist/lib/start-server.js +16 -0
  85. package/dist/lib/start-server.js.map +1 -1
  86. package/dist/middleware/index.d.ts +2 -0
  87. package/dist/middleware/index.d.ts.map +1 -0
  88. package/dist/middleware/index.js +18 -0
  89. package/dist/middleware/index.js.map +1 -0
  90. package/dist/middleware/middleware.d.ts +13 -0
  91. package/dist/middleware/middleware.d.ts.map +1 -1
  92. package/dist/middleware/middleware.js +22 -2
  93. package/dist/middleware/middleware.js.map +1 -1
  94. package/dist/middleware/rate-limit.d.ts.map +1 -1
  95. package/dist/middleware/rate-limit.js +9 -0
  96. package/dist/middleware/rate-limit.js.map +1 -1
  97. package/dist/middleware/security.d.ts +13 -3
  98. package/dist/middleware/security.d.ts.map +1 -1
  99. package/dist/middleware/security.js +98 -14
  100. package/dist/middleware/security.js.map +1 -1
  101. package/dist/middleware/upload.d.ts +82 -0
  102. package/dist/middleware/upload.d.ts.map +1 -0
  103. package/dist/middleware/upload.js +387 -0
  104. package/dist/middleware/upload.js.map +1 -0
  105. package/dist/router/boundary.d.ts +12 -0
  106. package/dist/router/boundary.d.ts.map +1 -1
  107. package/dist/router/boundary.js.map +1 -1
  108. package/dist/router/index.d.ts +3 -1
  109. package/dist/router/index.d.ts.map +1 -1
  110. package/dist/router/index.js +6 -1
  111. package/dist/router/index.js.map +1 -1
  112. package/dist/router/route-builder.d.ts +11 -2
  113. package/dist/router/route-builder.d.ts.map +1 -1
  114. package/dist/router/route-builder.js.map +1 -1
  115. package/dist/router/route-scanner.d.ts +1 -0
  116. package/dist/router/route-scanner.d.ts.map +1 -1
  117. package/dist/router/route-scanner.js +219 -8
  118. package/dist/router/route-scanner.js.map +1 -1
  119. package/dist/router/router.d.ts.map +1 -1
  120. package/dist/router/router.js +58 -2
  121. package/dist/router/router.js.map +1 -1
  122. package/dist/router/types.d.ts +33 -1
  123. package/dist/router/types.d.ts.map +1 -1
  124. package/dist/sanitize/index.d.ts +6 -6
  125. package/dist/sanitize/index.d.ts.map +1 -1
  126. package/dist/sanitize/index.js +8 -8
  127. package/dist/sanitize/index.js.map +1 -1
  128. package/dist/server/app.d.ts +1 -0
  129. package/dist/server/app.d.ts.map +1 -1
  130. package/dist/server/app.js +4 -0
  131. package/dist/server/app.js.map +1 -1
  132. package/dist/server/engines/node-engine.d.ts.map +1 -1
  133. package/dist/server/engines/node-engine.js +1 -0
  134. package/dist/server/engines/node-engine.js.map +1 -1
  135. package/dist/server/request-handler.d.ts.map +1 -1
  136. package/dist/server/request-handler.js +15 -1
  137. package/dist/server/request-handler.js.map +1 -1
  138. package/dist/server/request.d.ts +11 -0
  139. package/dist/server/request.d.ts.map +1 -1
  140. package/dist/server/request.js +125 -36
  141. package/dist/server/request.js.map +1 -1
  142. package/dist/server/response.d.ts +3 -1
  143. package/dist/server/response.d.ts.map +1 -1
  144. package/dist/server/response.js +98 -10
  145. package/dist/server/response.js.map +1 -1
  146. package/dist/testing/mocks.d.ts +3 -1
  147. package/dist/testing/mocks.d.ts.map +1 -1
  148. package/dist/testing/mocks.js +7 -1
  149. package/dist/testing/mocks.js.map +1 -1
  150. package/dist/validator/index.d.ts +1 -1
  151. package/dist/validator/index.d.ts.map +1 -1
  152. package/dist/validator/index.js +3 -1
  153. package/dist/validator/index.js.map +1 -1
  154. package/dist/validator/tex-types.d.ts +5 -1
  155. package/dist/validator/tex-types.d.ts.map +1 -1
  156. package/dist/validator/tex-types.js +4 -0
  157. package/dist/validator/tex-types.js.map +1 -1
  158. package/dist/validator/tex.d.ts +45 -7
  159. package/dist/validator/tex.d.ts.map +1 -1
  160. package/dist/validator/tex.js +341 -20
  161. package/dist/validator/tex.js.map +1 -1
  162. package/package.json +12 -8
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/decorators/middleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/decorators/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { type FileUploadOptions } from '../middleware/upload';
2
+ /**
3
+ * Method or parameter decorator for file uploads.
4
+ *
5
+ * When used on a controller method:
6
+ * Automatically applies the multipart file upload middleware for that route before execution.
7
+ * ```ts
8
+ * @Post('/avatar')
9
+ * @Upload('avatar')
10
+ * uploadAvatar(@UploadedFile() file: ExisFile) {
11
+ * return { filename: file.filename }
12
+ * }
13
+ * ```
14
+ *
15
+ * When used on a method parameter:
16
+ * Injects the uploaded file (alias for `@UploadedFile`).
17
+ * ```ts
18
+ * @Post('/avatar')
19
+ * @UseUpload({ field: 'avatar' })
20
+ * uploadAvatar(@Upload('avatar') file: ExisFile) {
21
+ * return { filename: file.filename }
22
+ * }
23
+ * ```
24
+ */
25
+ export declare function Upload(fieldNameOrOptions?: string | FileUploadOptions): any;
26
+ /**
27
+ * Explicit method decorator for file upload middleware.
28
+ *
29
+ * Example:
30
+ * ```ts
31
+ * @Post('/gallery')
32
+ * @UseUpload({ field: 'photos', maxCount: 10, dest: './uploads' })
33
+ * uploadGallery(@UploadedFiles() photos: ExisFile[]) {}
34
+ * ```
35
+ */
36
+ export declare function UseUpload(options?: FileUploadOptions): any;
37
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/decorators/upload.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAEzE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,MAAM,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,GAAG,CAiD3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,GAAG,CAE1D"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Upload = Upload;
4
+ exports.UseUpload = UseUpload;
5
+ const constants_1 = require("./constants");
6
+ const metadata_1 = require("./core/metadata");
7
+ const upload_1 = require("../middleware/upload");
8
+ /**
9
+ * Method or parameter decorator for file uploads.
10
+ *
11
+ * When used on a controller method:
12
+ * Automatically applies the multipart file upload middleware for that route before execution.
13
+ * ```ts
14
+ * @Post('/avatar')
15
+ * @Upload('avatar')
16
+ * uploadAvatar(@UploadedFile() file: ExisFile) {
17
+ * return { filename: file.filename }
18
+ * }
19
+ * ```
20
+ *
21
+ * When used on a method parameter:
22
+ * Injects the uploaded file (alias for `@UploadedFile`).
23
+ * ```ts
24
+ * @Post('/avatar')
25
+ * @UseUpload({ field: 'avatar' })
26
+ * uploadAvatar(@Upload('avatar') file: ExisFile) {
27
+ * return { filename: file.filename }
28
+ * }
29
+ * ```
30
+ */
31
+ function Upload(fieldNameOrOptions) {
32
+ const options = typeof fieldNameOrOptions === 'string'
33
+ ? { field: fieldNameOrOptions }
34
+ : fieldNameOrOptions || {};
35
+ const uploadMiddleware = options.field
36
+ ? upload_1.fileUpload.single(options.field, options)
37
+ : options.fields
38
+ ? upload_1.fileUpload.fields(options.fields, options)
39
+ : (0, upload_1.fileUpload)(options);
40
+ return function (target, propertyKey, descriptorOrIndex) {
41
+ const isParam = typeof descriptorOrIndex === 'number' ||
42
+ (propertyKey &&
43
+ typeof propertyKey === 'object' &&
44
+ propertyKey.kind === 'parameter');
45
+ if (isParam) {
46
+ // Parameter decorator
47
+ const parameterIndex = typeof descriptorOrIndex === 'number'
48
+ ? descriptorOrIndex
49
+ : propertyKey.index;
50
+ const fn = target[propertyKey] || target;
51
+ const paramMeta = metadata_1.MetadataEngine.init(fn, constants_1.PARAM_METADATA_PROP, []);
52
+ paramMeta[parameterIndex] = {
53
+ type: 'uploadedFile',
54
+ name: options.field,
55
+ pipes: [],
56
+ };
57
+ return;
58
+ }
59
+ // Method decorator
60
+ const fn = descriptorOrIndex?.value || target[propertyKey] || target;
61
+ const methodMiddlewares = metadata_1.MetadataEngine.init(fn, constants_1.METHOD_MIDDLEWARES, []);
62
+ methodMiddlewares.push(uploadMiddleware);
63
+ };
64
+ }
65
+ /**
66
+ * Explicit method decorator for file upload middleware.
67
+ *
68
+ * Example:
69
+ * ```ts
70
+ * @Post('/gallery')
71
+ * @UseUpload({ field: 'photos', maxCount: 10, dest: './uploads' })
72
+ * uploadGallery(@UploadedFiles() photos: ExisFile[]) {}
73
+ * ```
74
+ */
75
+ function UseUpload(options) {
76
+ return Upload(options);
77
+ }
78
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/decorators/upload.ts"],"names":[],"mappings":";;AA2BA,wBAiDC;AAYD,8BAEC;AA1FD,2CAAqE;AACrE,8CAAgD;AAChD,iDAAyE;AAEzE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAgB,MAAM,CAAC,kBAA+C;IACpE,MAAM,OAAO,GACX,OAAO,kBAAkB,KAAK,QAAQ;QACpC,CAAC,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE;QAC/B,CAAC,CAAC,kBAAkB,IAAI,EAAE,CAAA;IAE9B,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK;QACpC,CAAC,CAAC,mBAAU,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;QAC3C,CAAC,CAAC,OAAO,CAAC,MAAM;YACd,CAAC,CAAC,mBAAU,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;YAC5C,CAAC,CAAC,IAAA,mBAAU,EAAC,OAAO,CAAC,CAAA;IAEzB,OAAO,UACL,MAAW,EACX,WAAmC,EACnC,iBAAuB;QAEvB,MAAM,OAAO,GACX,OAAO,iBAAiB,KAAK,QAAQ;YACrC,CAAC,WAAW;gBACV,OAAO,WAAW,KAAK,QAAQ;gBAC/B,WAAW,CAAC,IAAI,KAAK,WAAW,CAAC,CAAA;QAErC,IAAI,OAAO,EAAE,CAAC;YACZ,sBAAsB;YACtB,MAAM,cAAc,GAClB,OAAO,iBAAiB,KAAK,QAAQ;gBACnC,CAAC,CAAC,iBAAiB;gBACnB,CAAC,CAAC,WAAW,CAAC,KAAK,CAAA;YAEvB,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,MAAM,CAAA;YACxC,MAAM,SAAS,GAAG,yBAAc,CAAC,IAAI,CAAQ,EAAE,EAAE,+BAAmB,EAAE,EAAE,CAAC,CAAA;YACzE,SAAS,CAAC,cAAc,CAAC,GAAG;gBAC1B,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,OAAO,CAAC,KAAK;gBACnB,KAAK,EAAE,EAAE;aACV,CAAA;YACD,OAAM;QACR,CAAC;QAED,mBAAmB;QACnB,MAAM,EAAE,GAAG,iBAAiB,EAAE,KAAK,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,MAAM,CAAA;QACpE,MAAM,iBAAiB,GAAG,yBAAc,CAAC,IAAI,CAC3C,EAAE,EACF,8BAAkB,EAClB,EAAE,CACH,CAAA;QACD,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IAC1C,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,SAAS,CAAC,OAA2B;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;AACxB,CAAC"}
@@ -21,20 +21,22 @@ A `boundary.ts` has two distinct, independent parts:
21
21
  | Signature | Detected as | Execution timing |
22
22
  |---|---|---|
23
23
  | `(req, res, next)` | Chain Step | Runs in file/declaration order, before the route |
24
+ | `beforeHandle(req, res)` | Boundary Guard Hook | Immediately before the route handler. Short-circuits on `false` or when sending headers |
25
+ | `afterHandle(req, res, data)` | Response Hook | Immediately after the route handler. Mutates returned payload or logs audit data |
24
26
  | `(ctx, next)` — default export (functional) or class method `handle(ctx, next)` (OOP) | Request Wrapper | Wraps around all chain steps and the nested route/boundary |
25
27
 
26
28
  ---
27
29
 
28
30
  ## 1. Functional Paradigm
29
31
 
30
- In functional style, export `config = defineBoundary(...)`, export named middleware functions `(req, res, next)` for chain steps, and optionally provide a `default export` function `(ctx, next)` as an onion-style wrapper.
32
+ In functional style, export `config = defineBoundary(...)`, export named middleware functions `(req, res, next)` for chain steps, and optionally provide a `default export` function `(ctx, next)` as an onion-style wrapper. You can also configure `beforeHandle` and `afterHandle` hooks directly inside `defineBoundary({ ... })`.
31
33
 
32
34
  ```typescript filename="src/http/admin/boundary.ts"
33
35
  import { defineBoundary } from 'exisjs/router'
34
36
  import type { Request, Response, Next, BoundaryContext } from 'exisjs/router'
35
37
  import { UnauthorizedError } from 'exisjs/error'
36
38
 
37
- // 1. Configuration (CORS, Headers, Exclusions, DI Providers)
39
+ // 1. Configuration (CORS, Headers, Exclusions, Hooks, DI Providers)
38
40
  export const config = defineBoundary({
39
41
  cors: {
40
42
  origin: ['https://admin.yourdomain.com'],
@@ -47,6 +49,20 @@ export const config = defineBoundary({
47
49
  '/admin/health',
48
50
  { path: '/admin/public/*', method: 'GET' }
49
51
  ],
52
+
53
+ // Pre-handler hook: Return false to reject with 403, or send custom response
54
+ beforeHandle(req, res) {
55
+ if (!req.headers['x-admin-token']) {
56
+ res.status(401).json({ error: 'Missing admin access token' })
57
+ return false
58
+ }
59
+ },
60
+
61
+ // Post-handler hook: Transform outgoing response payload or perform async audit
62
+ afterHandle(req, res, data) {
63
+ res.setHeader('X-Audited', 'true')
64
+ return { ...data, auditedAt: Date.now() }
65
+ },
50
66
  })
51
67
 
52
68
  // 2. Chain Step (auto-detected by (req, res, next) signature)
@@ -78,7 +94,7 @@ export default async function (ctx: BoundaryContext, next: Next) {
78
94
 
79
95
  ## 2. Class-Based (OOP) Paradigm
80
96
 
81
- In OOP style, decorate a class with `@Boundary(...)`. Named methods taking `(req, res, next)` are auto-detected as chain steps, and a method named `handle(ctx, next)` serves as the request wrapper.
97
+ In OOP style, decorate a class with `@Boundary(...)`. Named methods taking `(req, res, next)` are auto-detected as chain steps, `beforeHandle(req, res)` and `afterHandle(req, res, data)` act as lifecycle hooks, and a method named `handle(ctx, next)` serves as the request wrapper.
82
98
 
83
99
  ```typescript filename="src/http/admin/boundary.ts"
84
100
  import { Boundary } from 'exisjs/decorators'
@@ -96,6 +112,20 @@ import { UnauthorizedError } from 'exisjs/error'
96
112
  exclude: ['/admin/health'],
97
113
  })
98
114
  export default class AdminBoundary {
115
+ // Pre-handler hook
116
+ beforeHandle(req: Request, res: Response) {
117
+ if (!req.headers['x-admin-token']) {
118
+ res.status(401).json({ error: 'Missing admin access token' })
119
+ return false
120
+ }
121
+ }
122
+
123
+ // Post-handler hook
124
+ afterHandle(req: Request, res: Response, data: any) {
125
+ res.setHeader('X-Audited', 'true')
126
+ return { ...data, auditedAt: Date.now() }
127
+ }
128
+
99
129
  // Chain step
100
130
  requireAuth(req: Request, res: Response, next: Next) {
101
131
  if (!req.headers['x-api-key']) {
@@ -92,10 +92,11 @@ $ npx exisjs g <type> <name> [options]
92
92
 
93
93
  | Schematic | Alias | Description | Output Path |
94
94
  | :--- | :--- | :--- | :--- |
95
- | `resource` | | Complete domain slice (`schema.ts`, `service.ts`, `route.ts` or feature-prefixed named files) | `src/http/<name>/` |
95
+ | `crud` | `resource` | Full 4-file CRUD slice (`schema.ts`, `service.ts`, `route.ts`, and `model.ts` entity), 100% database-agnostic | `src/http/<name>/` & `src/models/` |
96
+ | `model` | | Standalone database-agnostic TypeScript entity and input types | `src/models/<Name>.ts` |
96
97
  | `route` | `r`, `c`, `controller` | HTTP route file | `src/http/<name>/route.ts` |
97
- | `service` | `s` | Injectable service / business logic | `src/http/<name>/service.ts` |
98
- | `schema` | `sc` | Validation schemas powered by `tex` | `src/http/<name>/schema.ts` |
98
+ | `service` | `s` | Injectable service / business logic with pagination helpers | `src/http/<name>/service.ts` |
99
+ | `schema` | `sc` | Validation schemas powered by `tex` (includes pagination) | `src/http/<name>/schema.ts` |
99
100
  | `boundary` | `b` | Folder-scoped configuration and request pipeline | `src/http/<name>/boundary.ts` |
100
101
  | `plugin` | `p` | Distributable plugin module | `src/plugins/<name>.ts` |
101
102
  | `middleware` | `m` | Standalone middleware handler | `src/middleware/<name>.ts` |
@@ -155,7 +155,7 @@ Here is a full breakdown of the configuration schema:
155
155
 
156
156
  ### Performance & Security
157
157
 
158
- - `bodyLimit` _(number)_: The maximum allowed size (in bytes) for incoming request bodies. (Default: `1MB`)
158
+ - `bodyLimit` _(number)_: The maximum allowed size (in bytes) for incoming request bodies. (Default: `10MB` / `10485760` bytes, raising HTTP 413 `PayloadTooLargeError` when exceeded)
159
159
  - `trustProxy` _(boolean | number)_: If true, respects `X-Forwarded-For` and `X-Forwarded-Host` headers (essential for apps deployed behind NGINX, Cloudflare, or AWS ELB). If a number, trusts that many hops.
160
160
  - `keepAlive` _(object | boolean)_: Tunes the Keep-Alive timeout and Header timeout limits.
161
161
  - `workers` _(number | 'safe' | 'max')_: Number of CPU workers for cluster mode. Defaults to 1. 'safe' caps to 2. 'max' uses all available cores.
@@ -219,3 +219,29 @@ If you are building a multi-tenant B2B application, do not boot multiple ExisJS
219
219
  1. **Row-Level Tenancy (Recommended)**: Run a single `App` connected to a single database. Use request context or middleware to inject the `tenantId` and scope all queries via Prisma/SQL.
220
220
  2. **Factory-Based Clients**: If you need true database-per-tenant isolation, do not use the zero-config singleton exports (like `import { db } from 'exisjs/prisma'`). Instead, manually construct the client factories inside a tenant-resolution middleware and attach them to the request context (`req.tenantDb`).
221
221
  3. **Containerized Deployments**: Run separate Node.js processes (Docker containers) for each tenant, passing tenant-specific `DATABASE_URL`s to each container.
222
+
223
+ ---
224
+
225
+ ## 9. Graceful Shutdown & Zero-Downtime Deployments
226
+
227
+ When deploying in Kubernetes, Docker Swarm, AWS ECS, or PM2, containers receive `SIGTERM` signals when being replaced. ExisJS handles graceful shutdown out of the box:
228
+
229
+ 1. **Stops Accepting New Connections**: Immediately closes the server listener so load balancers stop routing new traffic to the terminating instance.
230
+ 2. **Closes Idle Keep-Alive Connections**: Closes lingering idle HTTP keep-alive sockets instantly via `server.closeIdleConnections()`, preventing the process from hanging.
231
+ 3. **Drains In-Flight Requests**: Grants in-flight requests time to finish before terminating.
232
+ 4. **Lifecycle Teardown**: Automatically invokes your application's `onStop(app)` hook so you can cleanly disconnect databases, Redis pools, or message brokers.
233
+
234
+ ```typescript filename="src/http/server.ts"
235
+ import { exis } from 'exisjs'
236
+ import { db } from './db'
237
+
238
+ export default exis({
239
+ async onStart(app) {
240
+ await db.connect()
241
+ },
242
+ async onStop(app) {
243
+ // Cleanly close database pools when SIGTERM or SIGINT is received
244
+ await db.disconnect()
245
+ }
246
+ })
247
+ ```
@@ -74,7 +74,9 @@ The `HttpError` class provides static factory methods for standard HTTP status c
74
74
  - `HttpError.forbidden('Message')` - 403
75
75
  - `HttpError.notFound('Resource')` - 404
76
76
  - `HttpError.conflict('Message')` - 409
77
+ - `HttpError.payloadTooLarge('Message')` - 413
77
78
  - `HttpError.unprocessable('Message', details)` - 422
79
+ - `HttpError.rateLimit('Message')` - 429
78
80
  - `HttpError.internal('Message')` - 500
79
81
 
80
82
  ### Direct Error Classes & Exceptions
@@ -82,15 +84,17 @@ The `HttpError` class provides static factory methods for standard HTTP status c
82
84
  If you prefer a class-based approach, ExisJS exports every standard error as its own class. We also provide `Exception` aliases for every error class. You can import and throw them directly:
83
85
 
84
86
  ```typescript filename="example.ts"
85
- import { NotFoundException, UnauthorizedException, BadRequestError } from 'exisjs/error'
86
-
87
- export const deleteBook = (req, res) => {
88
- const book = db.findBook(req.params.id)
89
-
90
- if (!book) throw new NotFoundException('Book not found')
91
- if (book.ownerId !== req.user.id) throw new UnauthorizedException('Unauthorized')
92
-
93
- // ...
87
+ import {
88
+ NotFoundException,
89
+ UnauthorizedException,
90
+ BadRequestError,
91
+ PayloadTooLargeError
92
+ } from 'exisjs/error'
93
+
94
+ export const uploadMedia = (req, res) => {
95
+ if (req.headers['content-length'] > 10 * 1024 * 1024) {
96
+ throw new PayloadTooLargeError('File exceeds 10MB limit')
97
+ }
94
98
  }
95
99
  ```
96
100
 
@@ -108,6 +112,36 @@ When an `HttpError` is thrown, the client will automatically receive a structure
108
112
  }
109
113
  ```
110
114
 
115
+ ### Validation Error Responses & Diagnostic Visibility
116
+
117
+ When schema validation fails (via `tex`, Zod, or Yup), ExisJS produces a typed `400 Bad Request` featuring a clean `errors: Record<string, string>` map for seamless frontend form field binding:
118
+
119
+ ```json filename="HTTP 400 Bad Request Response"
120
+ {
121
+ "statusCode": 400,
122
+ "error": "Bad Request",
123
+ "message": "Validation Error: email: Invalid email format, age: Field must be >= 18",
124
+ "errors": {
125
+ "email": "Invalid email format",
126
+ "age": "Field must be >= 18"
127
+ }
128
+ }
129
+ ```
130
+
131
+ #### Development Terminal Diagnostics
132
+
133
+ In development mode, ExisJS automatically outputs formatted tabular diagnostics to the terminal displaying the exact HTTP part, field, received value, and expected requirement:
134
+
135
+ ```text
136
+ [VALIDATION FAILED] POST /auth/register (part: body)
137
+ ┌─────────────┬───────────────────────────┬──────────────────┐
138
+ │ Field │ Received │ Expected │
139
+ ├─────────────┼───────────────────────────┼──────────────────┤
140
+ │ email │ "alice" │ Valid email │
141
+ │ age │ "16" │ min: 18 │
142
+ └─────────────┴───────────────────────────┴──────────────────┘
143
+ ```
144
+
111
145
  If you throw an unhandled exception (like a database connection failure or a `TypeError`), ExisJS catches it and securely returns a `500 Internal Server Error`, hiding the stack trace from the client in production mode while logging the full trace to your internal logger.
112
146
 
113
147
  ## Error Handling Decision Tree
@@ -125,9 +159,45 @@ To keep your codebase clean and consistent, use this decision tree when deciding
125
159
 
126
160
  ## Extended Error Handling
127
161
 
128
- ExisJS provides mechanisms for granular error handling.
162
+ ExisJS provides mechanisms for granular and centralized error handling.
163
+
164
+ ### 1. Framework-Level Exception Handler (`src/http/error.ts`)
165
+
166
+ Instead of writing manual `try/catch` blocks in every route or calling `app.onError` inside `server.ts`, ExisJS natively discovers and auto-mounts `src/http/error.ts` (or `error.js`).
167
+
168
+ Export an `onError(err, req, res)` function to centrally format, log, and respond to all unhandled exceptions and validation errors:
169
+
170
+ ```typescript filename="src/http/error.ts"
171
+ import type { Request, Response } from 'exisjs'
172
+
173
+ /**
174
+ * Global Exception Handler for ExisJS
175
+ * Auto-mounted at startup to intercept all unhandled exceptions.
176
+ */
177
+ export function onError(err: any, req: Request, res: Response) {
178
+ const status = err.statusCode || err.status || 500
179
+
180
+ // Centralized structured error response
181
+ res.status(status).json({
182
+ success: false,
183
+ error: {
184
+ code: err.code || 'INTERNAL_ERROR',
185
+ message: err.message || 'Internal Server Error',
186
+ path: req.path,
187
+ },
188
+ })
189
+ }
190
+ ```
191
+
192
+ > [!TIP]
193
+ > You can also scaffold this file instantly via the CLI:
194
+ > ```bash
195
+ > exis generate error
196
+ > # or shorthand:
197
+ > exis g error
198
+ > ```
129
199
 
130
- ### 1. Exception Filters (`catchError`)
200
+ ### 2. Exception Filters (`catchError`)
131
201
 
132
202
  ExisJS allows you to create **Exception Filters** to globally intercept specific types of errors.
133
203
 
@@ -213,3 +213,141 @@ const config: ExisConfig = {
213
213
 
214
214
  export default config
215
215
  ```
216
+
217
+ ---
218
+
219
+ ## 9. Request Timeout (`timeout`)
220
+
221
+ The `timeout()` middleware terminates runaway requests and returns `503 Service Unavailable` (or a custom status code).
222
+
223
+ ExisJS defaults to **60 seconds (60000ms)** to provide generous headroom for slow network connections and third-party cloud operations (Cloudinary, AWS S3, OpenAI, Stripe).
224
+
225
+ ```typescript filename="src/http/server.ts"
226
+ import { exis } from 'exisjs'
227
+ import { timeout } from 'exisjs/middleware'
228
+
229
+ export default exis({
230
+ async onStart(app) {
231
+ app.use(timeout({
232
+ ms: 60000,
233
+ statusCode: 504,
234
+ message: 'Gateway Timeout connecting to upstream cloud service',
235
+ // Bypass webhooks or long-lived streaming endpoints
236
+ exclude: ['/webhooks/*', '/ai/stream'],
237
+ }))
238
+ }
239
+ })
240
+ ```
241
+
242
+ Handlers can also dynamically adjust timeouts using `req.setTimeout(ms)` and `req.clearTimeout()`.
243
+
244
+ ### Route-Level Timeout Overrides
245
+
246
+ Long-running routes (file uploads, PDF exports, AI inferences, data migrations) can declare custom timeouts directly in the route definition, overriding any global application timeout:
247
+
248
+ ```typescript filename="src/http/ai/route.ts"
249
+ import { controller, route } from 'exisjs/router'
250
+
251
+ export default controller({
252
+ heavyTask: route.post('/heavy-task', {
253
+ timeoutMs: 120000, // 2 minutes for this endpoint only
254
+ async handle({ body }) {
255
+ return await generateLargeReport(body)
256
+ }
257
+ }),
258
+
259
+ exportStream: route.get('/export', {
260
+ timeoutMs: 0, // 0 disables timeout completely for infinite SSE / streaming
261
+ async handle({ res }) {
262
+ return streamDataToClient(res)
263
+ }
264
+ })
265
+ })
266
+ ```
267
+
268
+ #### Class-Based (OOP) Paradigm
269
+
270
+ Use the `@Timeout(ms)` decorator on any controller method:
271
+
272
+ ```typescript filename="src/http/ai/controller.ts"
273
+ import { Controller, Post, Timeout } from 'exisjs/decorators'
274
+
275
+ @Controller('/ai')
276
+ export default class AiController {
277
+ @Post('/inference')
278
+ @Timeout(120000)
279
+ async runInference() {
280
+ return await computeModel()
281
+ }
282
+ }
283
+ ```
284
+
285
+ ---
286
+
287
+ ### Declarative Route Uploads
288
+
289
+ You can configure file uploads directly within functional route declarations:
290
+
291
+ ```typescript filename="src/http/media/route.ts"
292
+ import { controller, route } from 'exisjs/router'
293
+
294
+ export default controller({
295
+ upload: route.post('/photo', {
296
+ upload: {
297
+ field: 'file',
298
+ maxSize: '10MB',
299
+ allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
300
+ destination: 'memory', // 'memory' | 'disk' | 'stream'
301
+ },
302
+ async handle({ file, fields, req }) {
303
+ // file.buffer, file.mimetype, file.filename are immediately accessible
304
+ return { success: true, filename: file.filename }
305
+ }
306
+ })
307
+ })
308
+ ```
309
+
310
+ ### Class-Based (OOP) Upload Decorators
311
+
312
+ Use `@UseUpload` or `@Upload` to configure file parsing on controller actions:
313
+
314
+ ```typescript filename="src/http/media/controller.ts"
315
+ import { Controller, Post, UseUpload, UploadedFile, Body } from 'exisjs/decorators'
316
+
317
+ @Controller('/media')
318
+ export default class MediaController {
319
+ @Post('/photo')
320
+ @UseUpload({
321
+ field: 'file',
322
+ maxSize: '10MB',
323
+ allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
324
+ destination: 'memory',
325
+ })
326
+ async uploadPhoto(@UploadedFile() file: any, @Body() fields: any) {
327
+ return { filename: file.filename, size: file.size }
328
+ }
329
+ }
330
+ ```
331
+
332
+ ### Express / Connect Multer Bridge (`fromExpress`)
333
+
334
+ Seamlessly run existing Express/Connect middleware such as **Multer** directly in ExisJS without manual Promise wrapping:
335
+
336
+ ```typescript filename="src/http/legacy/route.ts"
337
+ import { controller, route } from 'exisjs/router'
338
+ import { fromExpress } from 'exisjs/middleware'
339
+ import multer from 'multer'
340
+
341
+ const upload = multer({ storage: multer.memoryStorage() })
342
+
343
+ export default controller({
344
+ upload: route.post('/',
345
+ fromExpress(upload.single('file')),
346
+ ({ req }) => {
347
+ const file = (req.raw as any).file || req.file
348
+ return { success: true, originalname: file?.originalname }
349
+ }
350
+ )
351
+ })
352
+ ```
353
+
@@ -177,3 +177,92 @@ export class OperationContext {
177
177
  > [!WARNING]
178
178
  > **Request Scope Constraints**: A provider marked as `scope: 'request'` **must** be resolved within the lifecycle of an active HTTP request. If you try to `inject()` or resolve a request-scoped provider during application startup, inside a background queue worker, or from a cron job, the container will throw a runtime error.
179
179
 
180
+ ---
181
+
182
+ ## Database Providers & Lifecycle Interop (`exisjs/database`)
183
+
184
+ ExisJS provides first-party lifecycle management and transaction coordination for databases (PostgreSQL, SQLite, MySQL, MongoDB, Prisma, Drizzle, Mongoose).
185
+
186
+ ### 1. Registering Database Lifecycle (`registerDatabase`)
187
+
188
+ Registering your database with `registerDatabase` ensures connections are automatically connected on boot and safely closed with zero leaked sockets when the server receives `SIGTERM` / `SIGINT`:
189
+
190
+ ```typescript filename="src/http/server.ts"
191
+ import { exis } from 'exisjs'
192
+ import { registerDatabase } from 'exisjs/database'
193
+ import mongoose from 'mongoose'
194
+
195
+ export default exis({
196
+ async onStart(app) {
197
+ // Automatically handles startup and graceful shutdown
198
+ registerDatabase(app, {
199
+ name: 'mongodb',
200
+ connect: async () => {
201
+ await mongoose.connect(process.env.MONGODB_URI!)
202
+ },
203
+ disconnect: async () => {
204
+ await mongoose.disconnect()
205
+ },
206
+ healthCheck: async () => {
207
+ return mongoose.connection.readyState === 1
208
+ },
209
+ })
210
+ }
211
+ })
212
+ ```
213
+
214
+ ### 2. Universal Transaction Runner (`withTransaction`)
215
+
216
+ `withTransaction` provides a duck-typed transaction runner that automatically coordinates transaction lifecycles, commits, aborts, and session cleanups across different ORMs:
217
+
218
+ ```typescript filename="src/http/orders/service.ts"
219
+ import { withTransaction } from 'exisjs/database'
220
+ import mongoose from 'mongoose'
221
+ import { Order } from '@/models/Order'
222
+ import { Inventory } from '@/models/Inventory'
223
+
224
+ export async function placeOrder(customerId: string, items: { sku: string; qty: number }[]) {
225
+ return withTransaction(mongoose, async (session) => {
226
+ // Automatically attaches session to queries and commits/aborts on error
227
+ const order = await Order.create([{ customerId, items }], { session })
228
+
229
+ for (const item of items) {
230
+ const updated = await Inventory.findOneAndUpdate(
231
+ { sku: item.sku, stock: { $gte: item.qty } },
232
+ { $inc: { stock: -item.qty } },
233
+ { session, returnDocument: 'after' }
234
+ )
235
+ if (!updated) {
236
+ throw new Error(`Insufficient stock for SKU: ${item.sku}`)
237
+ }
238
+ }
239
+
240
+ return order[0]
241
+ })
242
+ }
243
+ ```
244
+
245
+ Works identically with Prisma (`prisma.$transaction`) and Drizzle (`db.transaction`).
246
+
247
+ ### 3. Modern Mongoose 8/9 Interop & Connection Pooling
248
+
249
+ ExisJS exports helpers to prevent deprecation warnings in modern Mongoose:
250
+
251
+ ```typescript filename="src/models/user.ts"
252
+ import { modernUpdateOptions, mongoPoolOptions } from 'exisjs/database'
253
+ import mongoose from 'mongoose'
254
+
255
+ // Cloud-hardened pool options (maxPoolSize, serverSelectionTimeoutMS, etc.)
256
+ export const poolConfig = mongoPoolOptions({ maxPoolSize: 50 })
257
+
258
+ // Automatically maps legacy { new: true } to { returnDocument: 'after' }
259
+ export async function updateUsername(id: string, name: string) {
260
+ return User.findByIdAndUpdate(
261
+ id,
262
+ { $set: { name } },
263
+ modernUpdateOptions({ returnDocument: 'after' })
264
+ )
265
+ }
266
+ ```
267
+
268
+