exisjs 0.7.12 → 0.7.14

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 (132) hide show
  1. package/README.md +195 -39
  2. package/dist/cli/commands/run.d.ts.map +1 -1
  3. package/dist/cli/commands/run.js +3 -1
  4. package/dist/cli/commands/run.js.map +1 -1
  5. package/dist/config/types.d.ts +2 -2
  6. package/dist/config/types.d.ts.map +1 -1
  7. package/dist/decorators/params.d.ts +21 -0
  8. package/dist/decorators/params.d.ts.map +1 -1
  9. package/dist/decorators/params.js +21 -1
  10. package/dist/decorators/params.js.map +1 -1
  11. package/dist/di/container.d.ts +15 -6
  12. package/dist/di/container.d.ts.map +1 -1
  13. package/dist/di/container.js +26 -3
  14. package/dist/di/container.js.map +1 -1
  15. package/dist/di/index.d.ts +1 -1
  16. package/dist/di/index.d.ts.map +1 -1
  17. package/dist/di/index.js.map +1 -1
  18. package/dist/di/inject.d.ts +2 -1
  19. package/dist/di/inject.d.ts.map +1 -1
  20. package/dist/di/inject.js +2 -1
  21. package/dist/di/inject.js.map +1 -1
  22. package/dist/docs/ARCHITECTURE.md +130 -78
  23. package/dist/docs/BENCHMARKS.md +4 -4
  24. package/dist/docs/content/README.md +43 -44
  25. package/dist/docs/content/boundaries.mdx +138 -61
  26. package/dist/docs/content/cli/commands.mdx +151 -128
  27. package/dist/docs/content/cli/overview.mdx +61 -47
  28. package/dist/docs/content/cli/usage.mdx +107 -30
  29. package/dist/docs/content/config.mdx +145 -158
  30. package/dist/docs/content/controllers.mdx +193 -464
  31. package/dist/docs/content/cron.mdx +183 -69
  32. package/dist/docs/content/decorators.mdx +449 -154
  33. package/dist/docs/content/errors.mdx +202 -305
  34. package/dist/docs/content/exisjs-mcp.mdx +59 -49
  35. package/dist/docs/content/installation.mdx +243 -157
  36. package/dist/docs/content/introduction.mdx +220 -48
  37. package/dist/docs/content/middleware.mdx +171 -497
  38. package/dist/docs/content/modules.mdx +141 -83
  39. package/dist/docs/content/providers.mdx +216 -180
  40. package/dist/docs/content/requests.mdx +168 -488
  41. package/dist/docs/content/responses.mdx +200 -533
  42. package/dist/docs/content/routing.mdx +235 -598
  43. package/dist/docs/content/security.mdx +233 -57
  44. package/dist/docs/content/structure.mdx +151 -240
  45. package/dist/docs/content/swagger.mdx +192 -91
  46. package/dist/docs/content/testing.mdx +205 -74
  47. package/dist/docs/content/validation.mdx +479 -341
  48. package/dist/docs/reference/README.md +34 -2
  49. package/dist/docs/reference/config.mdx +277 -75
  50. package/dist/docs/reference/context.mdx +197 -106
  51. package/dist/docs/reference/cron.mdx +266 -152
  52. package/dist/docs/reference/database.mdx +135 -53
  53. package/dist/docs/reference/decorators.mdx +234 -116
  54. package/dist/docs/reference/di.mdx +146 -112
  55. package/dist/docs/reference/error.mdx +155 -178
  56. package/dist/docs/reference/exis.mdx +141 -70
  57. package/dist/docs/reference/logger.mdx +110 -126
  58. package/dist/docs/reference/middleware.mdx +235 -158
  59. package/dist/docs/reference/plugin.mdx +136 -64
  60. package/dist/docs/reference/router.mdx +275 -293
  61. package/dist/docs/reference/sanitize.mdx +91 -87
  62. package/dist/docs/reference/swagger.mdx +280 -100
  63. package/dist/docs/reference/testing.mdx +223 -89
  64. package/dist/docs/reference/validator.mdx +194 -206
  65. package/dist/lib/start-server.js +22 -8
  66. package/dist/lib/start-server.js.map +1 -1
  67. package/dist/module/module.d.ts +6 -3
  68. package/dist/module/module.d.ts.map +1 -1
  69. package/dist/module/module.js +17 -3
  70. package/dist/module/module.js.map +1 -1
  71. package/dist/router/controller-registrar.d.ts.map +1 -1
  72. package/dist/router/controller-registrar.js +26 -4
  73. package/dist/router/controller-registrar.js.map +1 -1
  74. package/dist/router/scanner/fs-scanner.d.ts.map +1 -1
  75. package/dist/router/scanner/fs-scanner.js +22 -0
  76. package/dist/router/scanner/fs-scanner.js.map +1 -1
  77. package/dist/router/types.d.ts +6 -4
  78. package/dist/router/types.d.ts.map +1 -1
  79. package/dist/server/app.d.ts +3 -1
  80. package/dist/server/app.d.ts.map +1 -1
  81. package/dist/server/app.js +24 -8
  82. package/dist/server/app.js.map +1 -1
  83. package/dist/server/bootstrapper.d.ts.map +1 -1
  84. package/dist/server/bootstrapper.js +19 -0
  85. package/dist/server/bootstrapper.js.map +1 -1
  86. package/dist/server/request.d.ts +2 -0
  87. package/dist/server/request.d.ts.map +1 -1
  88. package/dist/server/request.js +11 -0
  89. package/dist/server/request.js.map +1 -1
  90. package/dist/server/response.d.ts +10 -5
  91. package/dist/server/response.d.ts.map +1 -1
  92. package/dist/server/response.js +65 -18
  93. package/dist/server/response.js.map +1 -1
  94. package/dist/swagger/generator.d.ts.map +1 -1
  95. package/dist/swagger/generator.js +130 -10
  96. package/dist/swagger/generator.js.map +1 -1
  97. package/dist/telemetry/index.d.ts +12 -0
  98. package/dist/telemetry/index.d.ts.map +1 -0
  99. package/dist/telemetry/index.js +121 -0
  100. package/dist/telemetry/index.js.map +1 -0
  101. package/dist/testing/client.d.ts +1 -0
  102. package/dist/testing/client.d.ts.map +1 -1
  103. package/dist/testing/client.js +4 -1
  104. package/dist/testing/client.js.map +1 -1
  105. package/dist/testing/index.d.ts.map +1 -1
  106. package/dist/testing/index.js +11 -4
  107. package/dist/testing/index.js.map +1 -1
  108. package/dist/validator/builder.d.ts +26 -1
  109. package/dist/validator/builder.d.ts.map +1 -1
  110. package/dist/validator/builder.js +31 -0
  111. package/dist/validator/builder.js.map +1 -1
  112. package/dist/validator/engine.d.ts +23 -0
  113. package/dist/validator/engine.d.ts.map +1 -1
  114. package/dist/validator/engine.js +228 -31
  115. package/dist/validator/engine.js.map +1 -1
  116. package/dist/validator/index.d.ts +8 -4
  117. package/dist/validator/index.d.ts.map +1 -1
  118. package/dist/validator/index.js +4 -1
  119. package/dist/validator/index.js.map +1 -1
  120. package/dist/validator/tex-types.d.ts +19 -4
  121. package/dist/validator/tex-types.d.ts.map +1 -1
  122. package/dist/validator/tex-types.js +102 -0
  123. package/dist/validator/tex-types.js.map +1 -1
  124. package/dist/validator/tex.d.ts +1 -1
  125. package/dist/validator/tex.d.ts.map +1 -1
  126. package/dist/validator/tex.js +3 -1
  127. package/dist/validator/tex.js.map +1 -1
  128. package/dist/validator/types.d.ts +1 -0
  129. package/dist/validator/types.d.ts.map +1 -1
  130. package/package.json +46 -14
  131. package/dist/docs/content/dataloader.mdx +0 -170
  132. package/dist/docs/reference/dataloader.mdx +0 -91
@@ -1,86 +1,88 @@
1
1
  ---
2
- nextUrl: "/docs/validation"
3
- nextTitle: "Validation"
2
+ title: 'Boundaries & Middleware Cascading'
3
+ description: 'Folder-scoped middleware cascading, security guards, CORS inheritance hierarchy, exclusion rules, and error handling with boundary.ts.'
4
+ nextUrl: '/docs/validation'
5
+ nextTitle: 'Validation & Schemas'
4
6
  ---
5
7
 
6
- # Boundaries (Config & Request Pipeline)
8
+ # Boundaries & Middleware Cascading (`boundary.ts`)
7
9
 
8
- A `boundary.ts` acts as a folder-scoped configuration and request pipeline in your file-system routing architecture.
10
+ A `boundary.ts` (or `<name>.boundary.ts`) file defines a folder-scoped request pipeline and configuration module in the ExisJS file-system routing hierarchy.
9
11
 
10
- Any `boundary.ts` applies to every route in its folder and all subfolders recursively. Instead of manually registering middleware chains or route guards, placing a `boundary.ts` configures **CORS**, **Headers**, **Excluded Paths**, **Dependency Injection**, and an **auto-detected request pipeline** cleanly scoped to that sub-tree.
12
+ Any `boundary.ts` automatically applies to every route within its directory and all descendant subdirectories recursively, providing scoped **CORS policies**, **custom headers**, **security guards**, **lifecycle hooks**, **route exclusions**, and **dependency injection scoping**.
11
13
 
12
14
  ---
13
15
 
14
16
  ## Anatomy of a Boundary
15
17
 
16
- A `boundary.ts` has two distinct, independent parts:
18
+ A `boundary.ts` consists of two distinct components:
17
19
 
18
- 1. **Config** — pure data, declared via `defineBoundary()` (functional) or the `@Boundary()` class decorator (OOP). It configures CORS, headers, DI providers, timeout, and exclusion rules.
19
- 2. **Pipeline** — real code, auto-detected by function signature. No manual pipeline registration is needed.
20
+ 1. **Configuration**: Pure declarative options declared via `defineBoundary()` (functional) or `@Boundary()` (OOP). It sets CORS, response headers, timeout limits, exclusion patterns, probe blackholing, and DI providers.
21
+ 2. **Pipeline Handlers**: Functions and lifecycle hooks that run before, during, or after request execution:
20
22
 
21
- | Signature | Detected as | Execution timing |
22
- |---|---|---|
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 |
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 |
23
+ | Handler Type | Signature | Description |
24
+ | :--- | :--- | :--- |
25
+ | **Chain Step** | `(req, res, next)` | Standard middleware step running in declaration order before route handlers |
26
+ | **Guard Hook** | `beforeHandle(req, res)` | Runs immediately before route handler execution; aborts if returning `false` |
27
+ | **Audit Hook** | `afterHandle(req, res, data)` | Runs immediately after route handler returns; can transform response data |
28
+ | **Pipeline Wrapper** | `(ctx, next)` / `handle(ctx, next)` | Onion-style wrapper around all steps and downstream routes in the boundary |
27
29
 
28
30
  ---
29
31
 
30
32
  ## 1. Functional Paradigm
31
33
 
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({ ... })`.
34
+ Export `config = defineBoundary(...)`, named middleware functions `(req, res, next)`, and optionally a default export `(ctx, next)` as a request wrapper:
33
35
 
34
36
  ```typescript filename="src/http/admin/boundary.ts"
35
37
  import { defineBoundary } from 'exisjs/router'
36
38
  import type { Request, Response, Next, BoundaryContext } from 'exisjs/router'
37
39
  import { UnauthorizedError } from 'exisjs/error'
38
40
 
39
- // 1. Configuration (CORS, Headers, Exclusions, Hooks, DI Providers)
41
+ // 1. Declarative Boundary Configuration
40
42
  export const config = defineBoundary({
41
43
  cors: {
42
- origin: ['https://admin.yourdomain.com'],
44
+ origin: ['https://admin.example.com'],
43
45
  credentials: true,
44
46
  },
45
47
  headers: {
46
- 'X-Admin-Api-Version': '2.0',
48
+ 'X-Admin-Scope': 'active',
47
49
  },
48
50
  exclude: [
49
51
  '/admin/health',
50
- { path: '/admin/public/*', method: 'GET' }
52
+ { path: '/admin/public/*', method: 'GET' },
51
53
  ],
52
54
 
53
- // Pre-handler hook: Return false to reject with 403, or send custom response
55
+ // Pre-handler guard hook
54
56
  beforeHandle(req, res) {
55
57
  if (!req.headers['x-admin-token']) {
56
58
  res.status(401).json({ error: 'Missing admin access token' })
57
- return false
59
+ return false // Aborts downstream execution
58
60
  }
59
61
  },
60
62
 
61
- // Post-handler hook: Transform outgoing response payload or perform async audit
63
+ // Post-handler response transformation hook
62
64
  afterHandle(req, res, data) {
63
- res.setHeader('X-Audited', 'true')
64
- return { ...data, auditedAt: Date.now() }
65
+ res.setHeader('X-Audited-At', new Date().toISOString())
66
+ return { ...data, audited: true }
65
67
  },
66
68
  })
67
69
 
68
- // 2. Chain Step (auto-detected by (req, res, next) signature)
69
- export function requireAuth(req: Request, res: Response, next: Next) {
70
+ // 2. Named Chain Step Middleware
71
+ export function verifyApiKey(req: Request, res: Response, next: Next) {
70
72
  if (!req.headers['x-api-key']) {
71
- throw new UnauthorizedError('Missing API key')
73
+ throw new UnauthorizedError('Missing required API key')
72
74
  }
73
75
  next()
74
76
  }
75
77
 
76
- // 3. Wrapper (auto-detected as default export with (ctx, next) signature)
78
+ // 3. Pipeline Wrapper (Default Export)
77
79
  export default async function (ctx: BoundaryContext, next: Next) {
78
80
  const start = Date.now()
79
81
  try {
80
82
  const result = await next()
81
83
  const duration = Date.now() - start
82
84
  ctx.res.setHeader('X-Response-Time', `${duration}ms`)
83
- return { success: true, data: result }
85
+ return result
84
86
  } catch (err: any) {
85
87
  return {
86
88
  success: false,
@@ -94,7 +96,7 @@ export default async function (ctx: BoundaryContext, next: Next) {
94
96
 
95
97
  ## 2. Class-Based (OOP) Paradigm
96
98
 
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.
99
+ Decorate a class with `@Boundary(...)`. Class methods taking `(req, res, next)` become chain steps, `beforeHandle` / `afterHandle` serve as lifecycle hooks, and a method named `handle(ctx, next)` acts as the pipeline wrapper:
98
100
 
99
101
  ```typescript filename="src/http/admin/boundary.ts"
100
102
  import { Boundary } from 'exisjs/decorators'
@@ -103,11 +105,11 @@ import { UnauthorizedError } from 'exisjs/error'
103
105
 
104
106
  @Boundary({
105
107
  cors: {
106
- origin: ['https://admin.yourdomain.com'],
108
+ origin: ['https://admin.example.com'],
107
109
  credentials: true,
108
110
  },
109
111
  headers: {
110
- 'X-Admin-Api-Version': '2.0',
112
+ 'X-Admin-Scope': 'active',
111
113
  },
112
114
  exclude: ['/admin/health'],
113
115
  })
@@ -122,19 +124,19 @@ export default class AdminBoundary {
122
124
 
123
125
  // Post-handler hook
124
126
  afterHandle(req: Request, res: Response, data: any) {
125
- res.setHeader('X-Audited', 'true')
126
- return { ...data, auditedAt: Date.now() }
127
+ res.setHeader('X-Audited-At', new Date().toISOString())
128
+ return { ...data, audited: true }
127
129
  }
128
130
 
129
- // Chain step
130
- requireAuth(req: Request, res: Response, next: Next) {
131
+ // Named chain step
132
+ verifyApiKey(req: Request, res: Response, next: Next) {
131
133
  if (!req.headers['x-api-key']) {
132
- throw new UnauthorizedError('Missing API key')
134
+ throw new UnauthorizedError('Missing required API key')
133
135
  }
134
136
  next()
135
137
  }
136
138
 
137
- // Wrapper
139
+ // Pipeline wrapper
138
140
  async handle(ctx: BoundaryContext, next: Next) {
139
141
  const start = Date.now()
140
142
  const result = await next()
@@ -146,44 +148,110 @@ export default class AdminBoundary {
146
148
 
147
149
  ---
148
150
 
149
- ## Cascading & Inheritance
151
+ ## Boundary Cascading & Execution Order
150
152
 
151
- Boundaries cascade down the directory tree. For instance:
153
+ Boundaries cascade top-down through the folder structure:
152
154
 
153
155
  ```text
154
156
  src/http/
155
- ├── boundary.ts # Root Boundary (applies to /api/*)
157
+ ├── boundary.ts # Root Boundary (applies to all routes)
156
158
  └── admin/
157
- ├── boundary.ts # Admin Boundary (applies to /api/admin/*)
159
+ ├── boundary.ts # Admin Boundary (applies to /admin/*)
158
160
  └── users/
159
- └── route.ts # Handled by both Root Boundary and Admin Boundary
161
+ └── route.ts # Handled by both Root Boundary and Admin Boundary
160
162
  ```
161
163
 
162
- 1. **Wrappers & Chain Steps**: Outer boundaries execute first. Root wrappers wrap nested wrappers, and root chain steps run before nested chain steps top-down.
163
- 2. **CORS Precedence & Inheritance**:
164
- - **Innermost Boundary Wins**: If a nested boundary specifies `cors`, it overrides any CORS configuration set in parent boundaries or `exis.config.ts`.
165
- - **Inheritance**: If a sub-boundary omits `cors`, it seamlessly inherits the parent boundary's CORS configuration (or global config).
166
- - **Per-Route Overrides**: A `route.ts` handler can define its own `cors` setting to override boundary settings for that single endpoint.
167
- - **Disabling CORS**: Setting `cors: false` on a boundary or route explicitly disables CORS headers and preflight handling for that sub-tree or route.
168
- 3. **Headers Merging**: Headers are deep-merged from root to child. Child headers override parent headers if keys collide.
169
- 4. **Exclusions**: When a route matches an exclusion pattern (e.g. `/admin/health` in `exclude`), that boundary's chain steps and wrappers are bypassed for the request.
164
+ ### Execution Order
165
+
166
+ 1. **Wrappers**: Outer wrappers wrap inner wrappers (onion architecture).
167
+ 2. **Chain Steps**: Root chain steps run before nested boundary chain steps.
168
+ 3. **Guard Hooks (`beforeHandle`)**: Run immediately before the route handler, evaluated from root boundary down to the innermost boundary.
169
+ 4. **Response Hooks (`afterHandle`)**: Run in reverse order (innermost boundary up to root boundary).
170
+
171
+ ---
172
+
173
+ ## CORS Inheritance & Precedence
174
+
175
+ CORS configuration follows a 4-tier hierarchy:
176
+
177
+ | Priority | Level | Where Defined | Description |
178
+ | :---: | :--- | :--- | :--- |
179
+ | 1 | **Route Override** | `route.get('/', { cors: ... })` or `@Cors(...)` | Specific to a single endpoint; overrides all boundaries and global configs |
180
+ | 2 | **Innermost Boundary** | `src/http/admin/boundary.ts` | Scoped to subfolder tree; overrides parent boundaries |
181
+ | 3 | **Parent / Root Boundary** | `src/http/boundary.ts` | Scoped to all routes in `src/http/`; overrides global defaults |
182
+ | 4 | **Global Configuration** | `exis.config.ts` (`cors`) | Fallback baseline for endpoints without boundary or route CORS |
183
+
184
+ > [!NOTE]
185
+ > If a sub-boundary omits `cors`, it inherits the CORS settings of the nearest ancestor boundary (or `exis.config.ts`). Setting `cors: false` on a boundary explicitly disables CORS for that entire subtree.
186
+
187
+ ---
188
+
189
+ ## Headers Merging
170
190
 
171
- ### CORS Resolution Hierarchy
191
+ Response headers defined across boundaries are deep-merged from root to child. If header keys conflict, the innermost boundary value takes precedence:
172
192
 
173
- ExisJS resolves CORS in a 3-tier precedence order:
193
+ ```typescript
194
+ // src/http/boundary.ts (Root)
195
+ export const config = defineBoundary({
196
+ headers: { 'X-Framework': 'ExisJS', 'X-Environment': 'production' },
197
+ })
198
+
199
+ // src/http/v2/boundary.ts (Nested)
200
+ export const config = defineBoundary({
201
+ headers: { 'X-Api-Version': 'v2', 'X-Environment': 'v2-canary' },
202
+ })
174
203
 
175
- | Level | Where to Define | Priority | Description |
176
- |---|---|---|---|
177
- | **Route** | `route.get('/', { cors: ... })` or `@Cors(...)` | 🥇 **Highest** | Specific to a single endpoint. Overrides boundary and global config. |
178
- | **Nested Boundary** | `src/http/admin/boundary.ts` | 🥈 **High** | Scoped to the subfolder tree. Overrides parent boundaries and global config. |
179
- | **Parent / Root Boundary** | `src/http/boundary.ts` | 🥉 **Medium** | Scoped to all API routes under the folder. Overrides global config. |
180
- | **Global Config** | `exis.config.ts` (`defineConfig({ cors })`) | **Base** | Fallback baseline for any route not covered by a boundary or route override. |
204
+ // Endpoints under /v2 receive:
205
+ // X-Framework: ExisJS
206
+ // X-Api-Version: v2
207
+ // X-Environment: v2-canary (overwritten by nested boundary)
208
+ ```
181
209
 
182
210
  ---
183
211
 
184
- ## Dependency Injection via Providers
212
+ ## Route Exclusion Rules
213
+
214
+ To bypass boundary middleware for specific routes (e.g. public webhooks or health checks), add rules to `exclude`:
215
+
216
+ ```typescript filename="src/http/boundary.ts"
217
+ import { defineBoundary } from 'exisjs/router'
218
+
219
+ export const config = defineBoundary({
220
+ exclude: [
221
+ // 1. Exact path string
222
+ '/health',
185
223
 
186
- Boundaries also act as IoC module scopes. You can scope providers to a directory tree using `providers`:
224
+ // 2. Wildcard pattern matching any HTTP method
225
+ '/public/*',
226
+
227
+ // 3. Path with specific HTTP method restriction
228
+ { path: '/webhooks/stripe', method: 'POST' },
229
+ { path: '/docs/*', methods: ['GET', 'HEAD'] },
230
+ ],
231
+ })
232
+ ```
233
+
234
+ When an incoming request matches an exclusion rule, the boundary's chain steps and `beforeHandle` hooks are bypassed.
235
+
236
+ ---
237
+
238
+ ## Noise Suppression & Exploit Probe Blackholing
239
+
240
+ ExisJS can automatically intercept and drop automated vulnerability scanner probes (e.g. `/.env`, `/.git`, `/.DS_Store`, `/wp-admin`) at the boundary level without flooding application logs:
241
+
242
+ ```typescript filename="src/http/boundary.ts"
243
+ import { defineBoundary } from 'exisjs/router'
244
+
245
+ export const config = defineBoundary({
246
+ blockSuspiciousProbes: true, // Blackholes malicious probe paths immediately
247
+ })
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Dependency Injection Scoping
253
+
254
+ Boundaries can register scoped providers into the IoC container for all routes within their sub-tree:
187
255
 
188
256
  ```typescript filename="src/http/users/boundary.ts"
189
257
  import { defineBoundary } from 'exisjs/router'
@@ -195,3 +263,12 @@ export const config = defineBoundary({
195
263
  ],
196
264
  })
197
265
  ```
266
+
267
+ ---
268
+
269
+ ## Next Steps
270
+
271
+ - **[Validation Guide](/docs/validation)**: Building request schemas with `tex`.
272
+ - **[Dependency Injection](/docs/providers)**: IoC containers, tokens, and provider lifecycles.
273
+ - **[Routing](/docs/routing)**: File-system route parameters and handler definitions.
274
+ - **[Controllers](/docs/controllers)**: Class-based routing and parameter decorators.