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,241 +1,318 @@
1
1
  ---
2
- title: "Middleware"
3
- description: "API Reference for ExisJS built-in Middleware functions."
2
+ title: "exisjs/middleware"
3
+ description: "API Reference for ExisJS built-in middleware: Helmet, CORS, Rate Limiting, File Uploads, Idempotency, CIDR IP Filtering, Compression, and Security Controls."
4
+ nextUrl: "/docs/reference/context"
5
+ nextTitle: "Context Reference"
4
6
  ---
5
7
 
6
- # Middleware (`exisjs/middleware`)
8
+ # `exisjs/middleware`
7
9
 
8
- ExisJS ships with an optimized suite of core middleware. Rather than relying on heavy external dependencies, ExisJS implements security and utility middleware directly.
10
+ The `exisjs/middleware` module provides the built-in HTTP middleware pipeline for ExisJS. It includes native Rust-accelerated traffic controls, multipart upload handlers, security header suites, and request context enhancers.
9
11
 
10
- All middlewares can be applied globally in `server.ts`, folder-wide in `boundary.ts`, or locally on specific controllers/routes.
12
+ ---
13
+
14
+ ## Module Exports
15
+
16
+ ```typescript
17
+ import {
18
+ // Core & Security
19
+ cors,
20
+ helmet,
21
+ csrf,
22
+ hpp,
23
+ mongoSanitize,
24
+ blockSuspiciousProbes,
25
+ timingSafeEqual,
26
+ timeout,
27
+ routeTimeout,
28
+
29
+ // Traffic & Reliability
30
+ rateLimit,
31
+ idempotent,
32
+ dedupe,
33
+ ipFilter,
34
+ backpressure,
35
+ compression,
36
+
37
+ // Multipart File Uploads
38
+ fileUpload,
39
+ fromExpress,
40
+
41
+ // Utilities & Observability
42
+ requestId,
43
+ requestLogger,
44
+ serveStatic,
45
+ validate,
46
+ conditionalGet,
47
+ } from 'exisjs/middleware'
48
+
49
+ import type {
50
+ CorsConfig,
51
+ RateLimitOptions,
52
+ IdempotencyOptions,
53
+ IpFilterOptions,
54
+ FileUploadOptions,
55
+ FileUploadLimits,
56
+ UploadedFile,
57
+ BlockProbesOptions,
58
+ TimeoutOptions,
59
+ CompressionOptions,
60
+ } from 'exisjs/middleware'
61
+ ```
11
62
 
12
63
  ---
13
64
 
14
- ## How to Apply Middleware
65
+ ## 1. Security & Header Middlewares
15
66
 
16
- ExisJS provides first-class support for both Object-Oriented and Functional middleware application.
67
+ ### `helmet(options?)`
17
68
 
18
- **Class-Based (OOP)**
19
- ```typescript filename="src/http/users/route.ts"
20
- import { Controller, Get, Use } from 'exisjs/decorators'
21
- import { ipFilter } from 'exisjs/middleware'
69
+ Sets standard HTTP response headers for protection against XSS, clickjacking, MIME sniffing, and protocol downgrades.
22
70
 
23
- @Controller('/users')
24
- @Use(ipFilter({ allow: ['192.168.1.0/24'] })) // Applies to entire controller
25
- export default class UserController {
26
- @Get('/stats')
27
- getStats() {
28
- return { users: 100 }
29
- }
30
- }
71
+ ```typescript
72
+ function helmet(options?: HelmetOptions): Handler
31
73
  ```
32
74
 
33
- **Functional**
34
- ```typescript filename="src/http/users/route.ts"
35
- import { controller, route } from 'exisjs/router'
36
- import { ipFilter } from 'exisjs/middleware'
75
+ | Option | Type | Default | Description |
76
+ | :--- | :--- | :--- | :--- |
77
+ | `contentSecurityPolicy` | `boolean \| object` | `false` | Configures Content Security Policy (`Content-Security-Policy`). |
78
+ | `xFrameOptions` | `'DENY' \| 'SAMEORIGIN'` | `'SAMEORIGIN'` | Protects against clickjacking. |
79
+ | `hsts` | `boolean \| HstsOptions` | `true` (in prod) | Strict Transport Security configuration. |
80
+ | `noSniff` | `boolean` | `true` | Sets `X-Content-Type-Options: nosniff`. |
81
+ | `xssFilter` | `boolean` | `true` | Sets `X-XSS-Protection: 1; mode=block`. |
37
82
 
38
- export default controller({
39
- middleware: [ipFilter({ allow: ['192.168.1.0/24'] })],
83
+ ---
40
84
 
41
- getStats: route.get('/stats', {
42
- async handle() {
43
- return { users: 100 }
44
- }
45
- })
46
- })
85
+ ### `cors(config?)`
86
+
87
+ Manages Cross-Origin Resource Sharing headers, preflight `OPTIONS` responses, and allowed credentials.
88
+
89
+ ```typescript
90
+ function cors(config?: CorsConfig): Handler
47
91
  ```
48
92
 
49
- ---
93
+ | Option | Type | Default | Description |
94
+ | :--- | :--- | :--- | :--- |
95
+ | `origin` | `string \| RegExp \| string[] \| boolean \| CorsOriginFn` | `'*'` | Allowed origin(s) or dynamic resolver function. |
96
+ | `methods` | `string[]` | `['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']` | Allowed HTTP methods. |
97
+ | `allowedHeaders` | `string[]` | `['Content-Type', 'Authorization', 'Accept', 'Origin', ...]` | Allowed request headers. |
98
+ | `exposedHeaders` | `string[]` | `[]` | Headers exposed to client scripts. |
99
+ | `credentials` | `boolean` | `false` | Sets `Access-Control-Allow-Credentials: true`. |
100
+ | `maxAge` | `number` | `86400` | Preflight cache lifetime in seconds. |
50
101
 
51
- ## Middleware Context Inference
102
+ ---
52
103
 
53
- ### `defineMiddleware<TContext>(fn)`
104
+ ### `csrf(options?)`
54
105
 
55
- Creates a strongly-typed middleware function that attaches custom typed properties (like `user`, `session`, or `tenantId`) to `req`. Downstream route handlers (`route.get`, `route.post`, etc.) automatically inherit and infer this context with full IDE autocomplete and zero manual type casts.
106
+ Enforces Cross-Site Request Forgery protection using the Signed Double-Submit Cookie pattern.
56
107
 
57
108
  ```typescript
58
- import { controller, route, defineMiddleware } from 'exisjs/router'
109
+ function csrf(options?: CsrfOptions): Handler
110
+ ```
59
111
 
60
- interface AuthContext {
61
- user: { id: string; role: 'admin' | 'user'; email: string }
62
- }
112
+ ---
63
113
 
64
- const auth = defineMiddleware<AuthContext>((req, res, next) => {
65
- req.user = { id: 'u1', role: 'admin', email: 'alex@example.com' }
66
- next()
67
- })
114
+ ### `blockSuspiciousProbes(options?)`
68
115
 
69
- export default controller({
70
- profile: route.get('/profile', {
71
- middlewares: [auth],
72
- handle({ req, res }) {
73
- // req.user has full autocomplete and strict typing:
74
- return res.json({ id: req.user.id, role: req.user.role })
75
- }
76
- })
77
- })
116
+ Detects and drops malicious vulnerability scanners probing for sensitive assets (`.env`, `.git`, `wp-login.php`) before they hit route logic or flood log streams.
117
+
118
+ ```typescript
119
+ function blockSuspiciousProbes(options?: BlockProbesOptions): Handler
78
120
  ```
79
121
 
80
122
  ---
81
123
 
82
- ## Security Middleware
124
+ ### `hpp(options?)`
83
125
 
84
- ### `helmet(options?)`
85
- Sets 14+ strict security headers (HSTS, CSP, XSS Protection, No Sniff, Frameguard) to protect your application.
126
+ Protects against HTTP Parameter Pollution by normalizing repeated query parameters.
86
127
 
87
128
  ```typescript
88
- import { helmet } from 'exisjs/middleware'
89
-
90
- app.use(helmet())
129
+ function hpp(options?: HppOptions): Handler
91
130
  ```
92
131
 
93
- ### `csrf(options)`
94
- Implements the Signed Double Submit Cookie pattern for Cross-Site Request Forgery (CSRF) protection.
132
+ ---
95
133
 
96
- ### `timeout(options?)`
97
- Automatically times out requests that exceed the specified duration, returning a `503 Service Unavailable` response (or custom status code).
134
+ ### `mongoSanitize(options?)`
98
135
 
99
- - **Default**: `60000` (60 seconds)
100
- - **Options**:
101
- - `ms` (`number`): Timeout duration in milliseconds.
102
- - `statusCode` (`number`): Status code to respond with (default: `503`).
103
- - `message` (`string`): Error message returned to the client.
104
- - `exclude` (`(string | RegExp)[]`): Array of route paths or regex patterns to exempt from timeout checks.
136
+ Strips `$` and `.` prefixes from request parameters and body fields to mitigate NoSQL injection vectors.
105
137
 
106
138
  ```typescript
107
- import { timeout } from 'exisjs/middleware'
108
-
109
- app.use(timeout({
110
- ms: 60000,
111
- exclude: ['/webhooks/*', '/ai/stream'],
112
- }))
139
+ function mongoSanitize(options?: MongoSanitizeOptions): Handler
113
140
  ```
114
141
 
115
- Handlers can dynamically alter the active timeout using `req.setTimeout(ms)` or `req.clearTimeout()`.
142
+ ---
143
+
144
+ ## 2. Traffic, Rate Limiting & Reliability
116
145
 
117
- ### `fileUpload(options?)`
118
- First-party multipart form data parsing and file upload middleware.
146
+ ### `rateLimit(options?)`
119
147
 
120
- - **Methods**:
121
- - `fileUpload.single(fieldName, options?)`: Parses a single file into `req.file`.
122
- - `fileUpload.array(fieldName, maxCount?, options?)`: Parses multiple files with the same field into `req.files` (`UploadedFile[]`).
123
- - `fileUpload.fields([{ name, maxCount }])`: Parses multiple distinct fields into `req.files` (`Record<string, UploadedFile[]>`).
124
- - `fileUpload.any(options?)`: Accepts any uploaded files.
125
- - `fileUpload.none(options?)`: Accepts only text fields; rejects file uploads.
126
- - **Options**:
127
- - `dest` (`string`): Directory path to save uploaded files to disk automatically.
128
- - `maxBytes` (`number`): Maximum file size in bytes (shorthand for `limits.fileSize`).
129
- - `mimeTypes` (`string[]`): Array of permitted MIME types (e.g. `['image/png', 'image/jpeg']`).
130
- - `limits` (`{ fileSize?: number; files?: number }`): Detailed size and count limits.
148
+ In-memory off-heap rate limiter backed by native Rust acceleration (`NativeRateLimiter`).
131
149
 
132
150
  ```typescript
133
- import { fileUpload } from 'exisjs/middleware'
134
-
135
- app.post('/avatar', fileUpload.single('avatar', {
136
- maxBytes: 5 * 1024 * 1024,
137
- mimeTypes: ['image/*'],
138
- }), (req, res) => {
139
- const file = req.file // UploadedFile { filename, originalname, mimetype, size, buffer }
140
- res.json({ success: true, filename: file.filename })
141
- })
151
+ function rateLimit(options?: RateLimitOptions): Handler
142
152
  ```
143
153
 
144
- ### `fromExpress(middleware)`
145
- Seamlessly adapts standard Express/Connect middleware (such as `multer`) to run within the ExisJS pipeline.
154
+ | Option | Type | Default | Description |
155
+ | :--- | :--- | :--- | :--- |
156
+ | `windowMs` | `number` | `60000` (1 min) | Time window in milliseconds. |
157
+ | `max` | `number` | `100` | Maximum allowed requests within the time window. |
158
+ | `keyGenerator` | `(req: Request) => string` | `req => req.ip` | Custom partition key generator. |
159
+ | `message` | `string \| object` | `'Too many requests'` | Response payload on rate limit breach. |
160
+ | `statusCode` | `number` | `429` | HTTP status code for throttled requests. |
146
161
 
147
- ```typescript
148
- import { fromExpress } from 'exisjs/middleware'
149
- import multer from 'multer'
162
+ ---
150
163
 
151
- const upload = multer({ dest: './uploads' })
164
+ ### `timeout(options?)` & `routeTimeout(msOrOptions)`
152
165
 
153
- app.post('/upload', fromExpress(upload.single('file')), (req, res) => {
154
- res.json({ file: (req.raw as any).file })
155
- })
156
- ```
166
+ Terminates long-running requests that exceed the specified threshold, returning `503 Service Unavailable`.
157
167
 
158
- ### `hpp()`
159
- HTTP Parameter Pollution protection.
168
+ ```typescript
169
+ function timeout(options?: TimeoutOptions): Handler
170
+ function routeTimeout(msOrOptions: number | TimeoutOptions): Handler
171
+ ```
160
172
 
161
- ### `dbSanitize(options?)`
162
- Sanitizes query and body payloads from NoSQL injection attempts.
173
+ | Option | Type | Default | Description |
174
+ | :--- | :--- | :--- | :--- |
175
+ | `ms` | `number` | `60000` | Timeout threshold in milliseconds. |
176
+ | `statusCode` | `number` | `503` | Response status code upon timeout. |
177
+ | `message` | `string` | `'Service Unavailable'` | Error message sent to client. |
178
+ | `exclude` | `(string \| RegExp)[]` | `[]` | Path patterns exempt from timeout rules. |
163
179
 
164
180
  ---
165
181
 
166
- ## Traffic & Reliability Middleware
167
-
168
- ### `rateLimit(options?)`
169
- High-performance rate limiter running in-memory and off-heap via Rust native bindings (`NativeRateLimiter`).
182
+ ### `idempotent(options?)`
170
183
 
171
- > [!NOTE]
172
- > Core rate limiting is scoped to in-memory native execution. Distributed multi-instance Redis rate limiting moves to `@exisjs/cache`.
184
+ Caches responses against the `Idempotency-Key` HTTP header in off-heap native memory to prevent duplicate mutations.
173
185
 
174
186
  ```typescript
175
- import { rateLimit } from 'exisjs/middleware'
176
-
177
- app.use(rateLimit({
178
- windowMs: 60000,
179
- max: 100
180
- }))
187
+ function idempotent(options?: IdempotencyOptions): Handler
181
188
  ```
182
189
 
183
- ### `timeout(options?)`
184
- Terminates long-running requests that exceed the specified threshold, responding with `503 Service Unavailable` (or custom status). Defaults to 60,000ms.
190
+ | Option | Type | Default | Description |
191
+ | :--- | :--- | :--- | :--- |
192
+ | `ttlMs` | `number` | `86400000` (24h) | Cache entry time-to-live in milliseconds. |
193
+ | `header` | `string` | `'idempotency-key'` | Target HTTP request header name. |
194
+
195
+ ---
196
+
197
+ ### `dedupe(options?)`
198
+
199
+ Prevents identical concurrent in-flight requests from being computed more than once simultaneously.
185
200
 
186
201
  ```typescript
187
- import { timeout } from 'exisjs/middleware'
202
+ function dedupe(options?: DedupeOptions): Handler
203
+ ```
204
+
205
+ ---
188
206
 
189
- app.use(timeout({
190
- ms: 60000,
191
- statusCode: 504,
192
- message: 'Gateway Timeout',
193
- exclude: ['/webhooks/*', '/ai/stream'],
194
- }))
207
+ ### `ipFilter(options)`
208
+
209
+ Applies CIDR-compatible IP allow-lists or deny-lists to restrict access to trusted networks.
210
+
211
+ ```typescript
212
+ function ipFilter(options: IpFilterOptions): Handler
195
213
  ```
196
214
 
197
- ### `routeTimeout(msOrOptions)`
198
- Applies an endpoint-specific timeout. If a global timeout is already active, dynamically overrides the timer for this route. If no global timeout exists, initializes an isolated timeout timer. Passing `0` disables timeouts for streaming/exports.
215
+ | Option | Type | Description |
216
+ | :--- | :--- | :--- |
217
+ | `allow` | `string[]` | Array of permitted IP addresses or CIDR blocks (e.g. `['10.0.0.0/8', '192.168.1.5']`). |
218
+ | `deny` | `string[]` | Array of blocked IP addresses or CIDR blocks. |
219
+
220
+ ---
221
+
222
+ ### `backpressure(options?)`
223
+
224
+ Monitors Node.js Event Loop lag in real-time, returning `503` when lag exceeds safe thresholds.
199
225
 
200
226
  ```typescript
201
- import { routeTimeout } from 'exisjs/middleware'
227
+ function backpressure(options?: BackpressureOptions): Handler
228
+ ```
229
+
230
+ ---
202
231
 
203
- app.post('/heavy-task', routeTimeout(120000), (req, res) => { ... })
232
+ ### `compression(options?)`
233
+
234
+ Applies Gzip, Deflate, or Brotli compression to response streams when requested by the client `Accept-Encoding` header.
235
+
236
+ ```typescript
237
+ function compression(options?: CompressionOptions): Handler
204
238
  ```
205
239
 
206
- ### `idempotent(options?)`
207
- Caches responses based on the `Idempotency-Key` header into off-heap native memory to prevent duplicate mutations.
240
+ ---
241
+
242
+ ## 3. Multipart File Uploads
243
+
244
+ ### `fileUpload`
245
+
246
+ Streaming multipart/form-data upload middleware providing single, array, and field configurations.
208
247
 
209
248
  ```typescript
210
- import { idempotent } from 'exisjs/middleware'
249
+ // Single file upload
250
+ fileUpload.single(fieldName: string, options?: FileUploadOptions): Handler
251
+
252
+ // Multiple files under the same field name
253
+ fileUpload.array(fieldName: string, maxCount?: number, options?: FileUploadOptions): Handler
211
254
 
212
- export const handlePayment = [
213
- idempotent({ ttlMs: 86400000 }),
214
- async (req, res) => { ... }
215
- ]
255
+ // Multiple distinct fields
256
+ fileUpload.fields(fields: { name: string; maxCount?: number }[], options?: FileUploadOptions): Handler
257
+
258
+ // Any files accepted
259
+ fileUpload.any(options?: FileUploadOptions): Handler
260
+
261
+ // Text fields only
262
+ fileUpload.none(options?: FileUploadOptions): Handler
216
263
  ```
217
264
 
218
- ### `dedupe(options?)`
219
- Prevents duplicate identical in-flight requests from being computed simultaneously.
265
+ #### `FileUploadOptions`
220
266
 
221
- ### `backpressure(options?)`
222
- Monitors the Node.js Event Loop delay in real-time, shedding load when overloaded.
267
+ | Option | Type | Description |
268
+ | :--- | :--- | :--- |
269
+ | `dest` | `string` | Target directory on disk to stream uploaded files to. |
270
+ | `maxBytes` | `number` | Maximum allowed individual file size in bytes. |
271
+ | `mimeTypes` | `string[]` | Permitted MIME types (e.g. `['image/png', 'image/jpeg']`). |
272
+ | `limits` | `FileUploadLimits` | Detailed limits (`fileSize`, `files`, `fieldSize`, `fields`). |
223
273
 
224
- ### `ipFilter(options)`
225
- Fast CIDR-based IP whitelist/blacklist filter.
274
+ #### Example
275
+
276
+ ```typescript filename="src/http/users/route.ts"
277
+ import { controller, route } from 'exisjs/router'
278
+ import { fileUpload } from 'exisjs/middleware'
279
+
280
+ export default controller({
281
+ uploadAvatar: route.post('/avatar', {
282
+ middleware: [fileUpload.single('avatar', {
283
+ maxBytes: 5 * 1024 * 1024,
284
+ mimeTypes: ['image/png', 'image/jpeg'],
285
+ })],
286
+ async handle({ req }) {
287
+ const file = req.file // UploadedFile { filename, originalname, mimetype, size, buffer }
288
+ return { success: true, filename: file.filename }
289
+ },
290
+ }),
291
+ })
292
+ ```
226
293
 
227
294
  ---
228
295
 
229
- ## Utility Middleware
296
+ ### `fromExpress(middleware)`
297
+
298
+ Adapts standard Express/Connect middleware to run within the ExisJS pipeline.
230
299
 
231
- ### `cors(options?)`
232
- Cross-Origin Resource Sharing handler supporting preflight, dynamic origin matching, and credential headers.
300
+ ```typescript
301
+ import { fromExpress } from 'exisjs/middleware'
302
+ import morgan from 'morgan'
303
+
304
+ app.use(fromExpress(morgan('combined')))
305
+ ```
306
+
307
+ ---
233
308
 
234
- ### `requestId()`
235
- Injects a unique `X-Request-Id` into every incoming request and outgoing response header.
309
+ ## 4. Utility Middlewares
236
310
 
237
- ### `requestLogger(options?)`
238
- High-performance request logger powered by Pino.
311
+ | Middleware | Signature | Description |
312
+ | :--- | :--- | :--- |
313
+ | `requestId()` | `() => Handler` | Injects a unique `X-Request-Id` into request and response headers. |
314
+ | `requestLogger(options?)` | `(options?: LoggerConfig) => Handler` | Formats and logs request completion timings and status codes. |
315
+ | `serveStatic(root, options?)` | `(root: string, options?: StaticOptions) => Handler` | Serves static assets from disk with caching headers and streaming backpressure. |
316
+ | `conditionalGet()` | `() => Handler` | Enables ETag validation and `304 Not Modified` responses. |
317
+ | `validate(schema)` | `(schema: ValidateSchema) => Handler` | Validates request parameters against a `TexEngine` schema. |
239
318
 
240
- ### `serveStatic(root, options?)`
241
- Static file server supporting streaming and caching headers.