exisjs 0.7.5 → 0.7.7

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 (321) hide show
  1. package/dist/cli/commands/build.d.ts.map +1 -1
  2. package/dist/cli/commands/build.js +12 -0
  3. package/dist/cli/commands/build.js.map +1 -1
  4. package/dist/cli/commands/clean.d.ts +5 -0
  5. package/dist/cli/commands/clean.d.ts.map +1 -0
  6. package/dist/cli/commands/clean.js +30 -0
  7. package/dist/cli/commands/clean.js.map +1 -0
  8. package/dist/cli/commands/dev.d.ts.map +1 -1
  9. package/dist/cli/commands/dev.js +171 -86
  10. package/dist/cli/commands/dev.js.map +1 -1
  11. package/dist/cli/commands/generate.d.ts +6 -1
  12. package/dist/cli/commands/generate.d.ts.map +1 -1
  13. package/dist/cli/commands/generate.js +57 -2
  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 +54 -16
  17. package/dist/cli/commands/start.js.map +1 -1
  18. package/dist/cli/index.js +26 -3
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/manifest.d.ts +1 -0
  21. package/dist/cli/manifest.d.ts.map +1 -1
  22. package/dist/cli/manifest.js +264 -33
  23. package/dist/cli/manifest.js.map +1 -1
  24. package/dist/cli/resolve-aliases.d.ts +1 -1
  25. package/dist/cli/resolve-aliases.d.ts.map +1 -1
  26. package/dist/cli/resolve-aliases.js +30 -13
  27. package/dist/cli/resolve-aliases.js.map +1 -1
  28. package/dist/config/config.d.ts +3 -1
  29. package/dist/config/config.d.ts.map +1 -1
  30. package/dist/config/config.js +9 -0
  31. package/dist/config/config.js.map +1 -1
  32. package/dist/config/types.d.ts +6 -0
  33. package/dist/config/types.d.ts.map +1 -1
  34. package/dist/cron/expressions.d.ts +45 -0
  35. package/dist/cron/expressions.d.ts.map +1 -0
  36. package/dist/cron/expressions.js +87 -0
  37. package/dist/cron/expressions.js.map +1 -0
  38. package/dist/cron/index.d.ts +6 -0
  39. package/dist/cron/index.d.ts.map +1 -0
  40. package/dist/cron/index.js +22 -0
  41. package/dist/cron/index.js.map +1 -0
  42. package/dist/cron/job.d.ts +50 -0
  43. package/dist/cron/job.d.ts.map +1 -0
  44. package/dist/cron/job.js +247 -0
  45. package/dist/cron/job.js.map +1 -0
  46. package/dist/cron/manager.d.ts +105 -0
  47. package/dist/cron/manager.d.ts.map +1 -0
  48. package/dist/cron/manager.js +245 -0
  49. package/dist/cron/manager.js.map +1 -0
  50. package/dist/cron/parser.d.ts +22 -0
  51. package/dist/cron/parser.d.ts.map +1 -0
  52. package/dist/cron/parser.js +269 -0
  53. package/dist/cron/parser.js.map +1 -0
  54. package/dist/cron/types.d.ts +76 -0
  55. package/dist/cron/types.d.ts.map +1 -0
  56. package/dist/cron/types.js +3 -0
  57. package/dist/cron/types.js.map +1 -0
  58. package/dist/decorators/constants.d.ts +2 -0
  59. package/dist/decorators/constants.d.ts.map +1 -1
  60. package/dist/decorators/constants.js +3 -1
  61. package/dist/decorators/constants.js.map +1 -1
  62. package/dist/decorators/core.d.ts +29 -11
  63. package/dist/decorators/core.d.ts.map +1 -1
  64. package/dist/decorators/core.js +49 -11
  65. package/dist/decorators/core.js.map +1 -1
  66. package/dist/decorators/cron.d.ts +57 -0
  67. package/dist/decorators/cron.d.ts.map +1 -0
  68. package/dist/decorators/cron.js +143 -0
  69. package/dist/decorators/cron.js.map +1 -0
  70. package/dist/decorators/index.d.ts +2 -0
  71. package/dist/decorators/index.d.ts.map +1 -1
  72. package/dist/decorators/index.js +2 -0
  73. package/dist/decorators/index.js.map +1 -1
  74. package/dist/decorators/middleware.d.ts +65 -2
  75. package/dist/decorators/middleware.d.ts.map +1 -1
  76. package/dist/decorators/middleware.js +148 -62
  77. package/dist/decorators/middleware.js.map +1 -1
  78. package/dist/decorators/params.d.ts +102 -2
  79. package/dist/decorators/params.d.ts.map +1 -1
  80. package/dist/decorators/params.js +105 -3
  81. package/dist/decorators/params.js.map +1 -1
  82. package/dist/decorators/response.d.ts.map +1 -1
  83. package/dist/decorators/response.js +32 -22
  84. package/dist/decorators/response.js.map +1 -1
  85. package/dist/decorators/routing.d.ts +81 -16
  86. package/dist/decorators/routing.d.ts.map +1 -1
  87. package/dist/decorators/routing.js +81 -16
  88. package/dist/decorators/routing.js.map +1 -1
  89. package/dist/di/container.d.ts.map +1 -1
  90. package/dist/di/container.js +6 -1
  91. package/dist/di/container.js.map +1 -1
  92. package/dist/docs/content/cli/commands.mdx +1 -1
  93. package/dist/docs/content/controllers.mdx +127 -10
  94. package/dist/docs/content/cron.mdx +196 -0
  95. package/dist/docs/content/decorators.mdx +22 -4
  96. package/dist/docs/content/errors.mdx +58 -9
  97. package/dist/docs/content/introduction.mdx +7 -7
  98. package/dist/docs/content/middleware.mdx +269 -6
  99. package/dist/docs/content/requests.mdx +180 -6
  100. package/dist/docs/content/responses.mdx +283 -32
  101. package/dist/docs/content/routing.mdx +46 -0
  102. package/dist/docs/content/swagger.mdx +228 -0
  103. package/dist/docs/content/validation.mdx +190 -11
  104. package/dist/docs/reference/context.mdx +11 -0
  105. package/dist/docs/reference/cron.mdx +300 -0
  106. package/dist/docs/reference/decorators.mdx +22 -4
  107. package/dist/docs/reference/error.mdx +88 -0
  108. package/dist/docs/reference/logger.mdx +175 -43
  109. package/dist/docs/reference/middleware.mdx +31 -0
  110. package/dist/docs/reference/router.mdx +22 -0
  111. package/dist/docs/reference/swagger.mdx +143 -0
  112. package/dist/docs/reference/validator.mdx +83 -23
  113. package/dist/error/errors.d.ts.map +1 -1
  114. package/dist/error/errors.js +95 -43
  115. package/dist/error/errors.js.map +1 -1
  116. package/dist/error/index.d.ts +1 -0
  117. package/dist/error/index.d.ts.map +1 -1
  118. package/dist/error/index.js +11 -1
  119. package/dist/error/index.js.map +1 -1
  120. package/dist/error/overlay.d.ts +42 -0
  121. package/dist/error/overlay.d.ts.map +1 -0
  122. package/dist/error/overlay.js +306 -0
  123. package/dist/error/overlay.js.map +1 -0
  124. package/dist/index.d.ts +1 -0
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +22 -1
  127. package/dist/index.js.map +1 -1
  128. package/dist/lib/start-server.js +33 -7
  129. package/dist/lib/start-server.js.map +1 -1
  130. package/dist/logger/index.d.ts +1 -1
  131. package/dist/logger/index.d.ts.map +1 -1
  132. package/dist/logger/index.js +9 -1
  133. package/dist/logger/index.js.map +1 -1
  134. package/dist/middleware/guard.d.ts +2 -2
  135. package/dist/middleware/guard.d.ts.map +1 -1
  136. package/dist/middleware/guard.js.map +1 -1
  137. package/dist/middleware/ip-filter.d.ts +1 -0
  138. package/dist/middleware/ip-filter.d.ts.map +1 -1
  139. package/dist/middleware/ip-filter.js +2 -0
  140. package/dist/middleware/ip-filter.js.map +1 -1
  141. package/dist/middleware/middleware.d.ts +2 -2
  142. package/dist/middleware/middleware.d.ts.map +1 -1
  143. package/dist/middleware/middleware.js +20 -2
  144. package/dist/middleware/middleware.js.map +1 -1
  145. package/dist/middleware/security.d.ts +43 -1
  146. package/dist/middleware/security.d.ts.map +1 -1
  147. package/dist/middleware/security.js +101 -0
  148. package/dist/middleware/security.js.map +1 -1
  149. package/dist/response/index.d.ts +229 -6
  150. package/dist/response/index.d.ts.map +1 -1
  151. package/dist/response/index.js +272 -2
  152. package/dist/response/index.js.map +1 -1
  153. package/dist/router/boundary.d.ts +41 -11
  154. package/dist/router/boundary.d.ts.map +1 -1
  155. package/dist/router/boundary.js +24 -2
  156. package/dist/router/boundary.js.map +1 -1
  157. package/dist/router/controller-registrar.d.ts.map +1 -1
  158. package/dist/router/controller-registrar.js +108 -4
  159. package/dist/router/controller-registrar.js.map +1 -1
  160. package/dist/router/index.d.ts +2 -2
  161. package/dist/router/index.d.ts.map +1 -1
  162. package/dist/router/index.js +2 -1
  163. package/dist/router/index.js.map +1 -1
  164. package/dist/router/route-builder.d.ts +262 -65
  165. package/dist/router/route-builder.d.ts.map +1 -1
  166. package/dist/router/route-builder.js +181 -23
  167. package/dist/router/route-builder.js.map +1 -1
  168. package/dist/router/route-scanner.d.ts +6 -0
  169. package/dist/router/route-scanner.d.ts.map +1 -1
  170. package/dist/router/route-scanner.js +71 -792
  171. package/dist/router/route-scanner.js.map +1 -1
  172. package/dist/router/router.d.ts.map +1 -1
  173. package/dist/router/router.js +62 -17
  174. package/dist/router/router.js.map +1 -1
  175. package/dist/router/scanner/boundary-loader.d.ts +18 -0
  176. package/dist/router/scanner/boundary-loader.d.ts.map +1 -0
  177. package/dist/router/scanner/boundary-loader.js +539 -0
  178. package/dist/router/scanner/boundary-loader.js.map +1 -0
  179. package/dist/router/scanner/cron-mounter.d.ts +15 -0
  180. package/dist/router/scanner/cron-mounter.d.ts.map +1 -0
  181. package/dist/router/scanner/cron-mounter.js +216 -0
  182. package/dist/router/scanner/cron-mounter.js.map +1 -0
  183. package/dist/router/scanner/error-mounter.d.ts +14 -0
  184. package/dist/router/scanner/error-mounter.d.ts.map +1 -0
  185. package/dist/router/scanner/error-mounter.js +200 -0
  186. package/dist/router/scanner/error-mounter.js.map +1 -0
  187. package/dist/router/scanner/fs-scanner.d.ts +25 -0
  188. package/dist/router/scanner/fs-scanner.d.ts.map +1 -0
  189. package/dist/router/scanner/fs-scanner.js +115 -0
  190. package/dist/router/scanner/fs-scanner.js.map +1 -0
  191. package/dist/router/scanner/functional-compiler.d.ts +9 -0
  192. package/dist/router/scanner/functional-compiler.d.ts.map +1 -0
  193. package/dist/router/scanner/functional-compiler.js +233 -0
  194. package/dist/router/scanner/functional-compiler.js.map +1 -0
  195. package/dist/router/scanner/index.d.ts +9 -0
  196. package/dist/router/scanner/index.d.ts.map +1 -0
  197. package/dist/router/scanner/index.js +19 -0
  198. package/dist/router/scanner/index.js.map +1 -0
  199. package/dist/router/types.d.ts +23 -0
  200. package/dist/router/types.d.ts.map +1 -1
  201. package/dist/server/app.d.ts +3 -0
  202. package/dist/server/app.d.ts.map +1 -1
  203. package/dist/server/app.js +13 -0
  204. package/dist/server/app.js.map +1 -1
  205. package/dist/server/bootstrapper.d.ts.map +1 -1
  206. package/dist/server/bootstrapper.js +91 -30
  207. package/dist/server/bootstrapper.js.map +1 -1
  208. package/dist/server/cluster.d.ts.map +1 -1
  209. package/dist/server/cluster.js +13 -2
  210. package/dist/server/cluster.js.map +1 -1
  211. package/dist/server/context.d.ts +8 -0
  212. package/dist/server/context.d.ts.map +1 -1
  213. package/dist/server/context.js +50 -6
  214. package/dist/server/context.js.map +1 -1
  215. package/dist/server/helpers/body-parser.d.ts +18 -0
  216. package/dist/server/helpers/body-parser.d.ts.map +1 -0
  217. package/dist/server/helpers/body-parser.js +246 -0
  218. package/dist/server/helpers/body-parser.js.map +1 -0
  219. package/dist/server/helpers/cookie.d.ts +4 -0
  220. package/dist/server/helpers/cookie.d.ts.map +1 -0
  221. package/dist/server/helpers/cookie.js +61 -0
  222. package/dist/server/helpers/cookie.js.map +1 -0
  223. package/dist/server/helpers/etag.d.ts +3 -0
  224. package/dist/server/helpers/etag.d.ts.map +1 -0
  225. package/dist/server/helpers/etag.js +25 -0
  226. package/dist/server/helpers/etag.js.map +1 -0
  227. package/dist/server/helpers/index.d.ts +6 -0
  228. package/dist/server/helpers/index.d.ts.map +1 -0
  229. package/dist/server/helpers/index.js +21 -0
  230. package/dist/server/helpers/index.js.map +1 -0
  231. package/dist/server/helpers/ip.d.ts +9 -0
  232. package/dist/server/helpers/ip.d.ts.map +1 -0
  233. package/dist/server/helpers/ip.js +62 -0
  234. package/dist/server/helpers/ip.js.map +1 -0
  235. package/dist/server/helpers/stream.d.ts +4 -0
  236. package/dist/server/helpers/stream.d.ts.map +1 -0
  237. package/dist/server/helpers/stream.js +193 -0
  238. package/dist/server/helpers/stream.js.map +1 -0
  239. package/dist/server/lifecycle.d.ts +22 -0
  240. package/dist/server/lifecycle.d.ts.map +1 -0
  241. package/dist/server/lifecycle.js +106 -0
  242. package/dist/server/lifecycle.js.map +1 -0
  243. package/dist/server/request-handler.d.ts +1 -0
  244. package/dist/server/request-handler.d.ts.map +1 -1
  245. package/dist/server/request-handler.js +27 -17
  246. package/dist/server/request-handler.js.map +1 -1
  247. package/dist/server/request.d.ts +1 -139
  248. package/dist/server/request.d.ts.map +1 -1
  249. package/dist/server/request.js +37 -433
  250. package/dist/server/request.js.map +1 -1
  251. package/dist/server/response.d.ts +112 -156
  252. package/dist/server/response.d.ts.map +1 -1
  253. package/dist/server/response.js +129 -279
  254. package/dist/server/response.js.map +1 -1
  255. package/dist/swagger/decorators.d.ts +81 -0
  256. package/dist/swagger/decorators.d.ts.map +1 -0
  257. package/dist/swagger/decorators.js +172 -0
  258. package/dist/swagger/decorators.js.map +1 -0
  259. package/dist/swagger/generator.d.ts +19 -0
  260. package/dist/swagger/generator.d.ts.map +1 -0
  261. package/dist/swagger/generator.js +344 -0
  262. package/dist/swagger/generator.js.map +1 -0
  263. package/dist/swagger/index.d.ts +31 -0
  264. package/dist/swagger/index.d.ts.map +1 -0
  265. package/dist/swagger/index.js +53 -0
  266. package/dist/swagger/index.js.map +1 -0
  267. package/dist/swagger/mounter.d.ts +7 -0
  268. package/dist/swagger/mounter.d.ts.map +1 -0
  269. package/dist/swagger/mounter.js +56 -0
  270. package/dist/swagger/mounter.js.map +1 -0
  271. package/dist/swagger/types.d.ts +190 -0
  272. package/dist/swagger/types.d.ts.map +1 -0
  273. package/dist/swagger/types.js +3 -0
  274. package/dist/swagger/types.js.map +1 -0
  275. package/dist/swagger/ui.d.ts +6 -0
  276. package/dist/swagger/ui.d.ts.map +1 -0
  277. package/dist/swagger/ui.js +118 -0
  278. package/dist/swagger/ui.js.map +1 -0
  279. package/dist/testing/index.d.ts.map +1 -1
  280. package/dist/testing/index.js +6 -1
  281. package/dist/testing/index.js.map +1 -1
  282. package/dist/testing/mocks.d.ts.map +1 -1
  283. package/dist/testing/mocks.js +15 -3
  284. package/dist/testing/mocks.js.map +1 -1
  285. package/dist/utils/logger.d.ts +8 -0
  286. package/dist/utils/logger.d.ts.map +1 -1
  287. package/dist/utils/logger.js +184 -1
  288. package/dist/utils/logger.js.map +1 -1
  289. package/dist/validator/builder.d.ts +223 -0
  290. package/dist/validator/builder.d.ts.map +1 -0
  291. package/dist/validator/builder.js +517 -0
  292. package/dist/validator/builder.js.map +1 -0
  293. package/dist/validator/engine.d.ts +19 -0
  294. package/dist/validator/engine.d.ts.map +1 -0
  295. package/dist/validator/engine.js +568 -0
  296. package/dist/validator/engine.js.map +1 -0
  297. package/dist/validator/error.d.ts +12 -0
  298. package/dist/validator/error.d.ts.map +1 -0
  299. package/dist/validator/error.js +63 -0
  300. package/dist/validator/error.js.map +1 -0
  301. package/dist/validator/pagination.d.ts +40 -0
  302. package/dist/validator/pagination.d.ts.map +1 -0
  303. package/dist/validator/pagination.js +60 -0
  304. package/dist/validator/pagination.js.map +1 -0
  305. package/dist/validator/tex-types.d.ts +2 -1
  306. package/dist/validator/tex-types.d.ts.map +1 -1
  307. package/dist/validator/tex-types.js +2 -1
  308. package/dist/validator/tex-types.js.map +1 -1
  309. package/dist/validator/tex.d.ts +6 -142
  310. package/dist/validator/tex.d.ts.map +1 -1
  311. package/dist/validator/tex.js +14 -733
  312. package/dist/validator/tex.js.map +1 -1
  313. package/dist/validator/types.d.ts +83 -0
  314. package/dist/validator/types.d.ts.map +1 -0
  315. package/dist/validator/types.js +3 -0
  316. package/dist/validator/types.js.map +1 -0
  317. package/package.json +8 -4
  318. package/dist/dev/error-overlay.d.ts +0 -3
  319. package/dist/dev/error-overlay.d.ts.map +0 -1
  320. package/dist/dev/error-overlay.js +0 -118
  321. package/dist/dev/error-overlay.js.map +0 -1
@@ -1,47 +1,97 @@
1
1
  ---
2
2
  title: "Logger"
3
- description: "API Reference for the ExisJS structured logger (exisjs/logger)."
3
+ description: "API Reference and Architecture Guide for the ExisJS structured logger (exisjs/logger)."
4
4
  ---
5
5
 
6
6
  # Logger (`exisjs/logger`)
7
7
 
8
- ExisJS includes a built-in, high-performance structured logger powered by Pino. It provides colored, pretty-printed logs in development and fast, structured JSON in production.
9
-
10
- All logger APIs are imported directly from the dedicated subpath `exisjs/logger`.
8
+ ExisJS includes a high-performance, zero-overhead structured logging engine powered by Pino. It provides an **industry-standard single-line terminal format** in development and **ultra-fast structured NDJSON** in production for cloud observability platforms (Datadog, Loki, CloudWatch, OpenTelemetry).
11
9
 
12
10
  ```typescript
13
- import { logger, configureLogger, setLogger } from 'exisjs/logger'
11
+ import {
12
+ logger,
13
+ configureLogger,
14
+ setLogger,
15
+ createLogger,
16
+ createSilentLogger,
17
+ isLogger,
18
+ formatBytes,
19
+ formatLatency,
20
+ formatMethod,
21
+ formatStatus,
22
+ formatUrl,
23
+ formatIp,
24
+ } from 'exisjs/logger'
14
25
  ```
15
26
 
16
27
  ---
17
28
 
18
- ## 1. Global Logger Singleton (`logger`)
29
+ ## 1. Terminal Request Logging (Development DX)
30
+
31
+ When running your application in development mode (`exis dev` or `pretty: true`), ExisJS automatically formats every incoming HTTP request into a clean, concise, single-line terminal log:
32
+
33
+ ```text
34
+ [22:50:17] [exis] GET / 304 Not Modified 18ms
35
+ [22:50:55] [exis] GET /api/v1/profile 200 OK 1.2ms 240 B
36
+ [22:51:02] [exis] POST /api/v1/users 201 Created 14.5ms 1.4 KB
37
+ [22:51:10] [exis] PATCH /api/v1/users/42 400 Bad Request 3.1ms 120 B
38
+ └─ ⚠ Validation [body]: Field "email" must be a valid email format
39
+ [22:51:15] [exis] GET /api/v1/unknown 404 Not Found 0.8ms 45 B
40
+ [22:51:22] [exis] POST /api/v1/checkout 500 Internal Error 320ms 82 B
41
+ └─ ✖ Error: Database connection timeout
42
+ ```
19
43
 
20
- The `logger` singleton can be imported and called anywhere in your application:
44
+ ### Visual Features & Formatting Elements
45
+
46
+ | Element | Description | Behavior / Color Coding |
47
+ | :--- | :--- | :--- |
48
+ | **Timestamp** | `[HH:MM:SS]` | Dimmed gray for non-intrusive readability |
49
+ | **Brand Badge** | `[exis]` | Framework brand color (`\x1b[38;2;160;70;255m`), `[warn]` (yellow), `[error]` (red) |
50
+ | **HTTP Method** | `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `QUERY`, `SEARCH`, `OPTIONS`, `HEAD`, `WS`, `SSE`, `CONNECT`, `TRACE`, `PURGE` | Fixed-width padded badge with distinct colors (`GET`/`SEARCH` cyan, `POST` green, `PUT`/`PATCH` yellow, `DELETE`/`PURGE` red, `QUERY` blue, `OPTIONS`/`HEAD`/`WS` magenta) |
51
+ | **Path & Query** | `/api/v1/items?page=1` | Path in bright white, query parameters in dimmed gray |
52
+ | **Status Code** | `101 Switching Protocols`, `200 OK`, `201 Created`, `400 Bad Request`, `404 Not Found`, `500 Internal Error` | Color-coded by range: `101` magenta, `2xx` green, `3xx` cyan, `4xx` yellow, `5xx` red |
53
+ | **Response Latency** | `1.2ms`, `18ms`, `1.45s` | Dynamic threshold color coding: `< 50ms` (green), `50ms - 250ms` (yellow), `> 250ms` (red) |
54
+ | **Content Size** | `120 B`, `1.4 KB`, `2.8 MB` | Formatted human-readable byte sizes from `Content-Length` |
55
+ | **Client IP** | `192.168.1.5` | Localhost (`127.0.0.1` / `::1`) is suppressed by default for minimal noise; remote client IPs are cleanly displayed |
56
+ | **Diagnostic Sublines** | `└─ ⚠ Validation: ...` / `└─ ✖ Error: ...` | Indented warning and error summaries printed directly below failed requests |
57
+
58
+ ---
59
+
60
+ ## 2. Structured Logging in Production (NDJSON)
61
+
62
+ In production (`NODE_ENV === 'production'` or `pretty: false`), the logger outputs single-line structured JSON (NDJSON) directly to `stdout` with zero serialization overhead:
63
+
64
+ ```json
65
+ {"level":30,"time":1774286390000,"pid":1234,"hostname":"prod-app-01","requestId":"req-42","method":"GET","url":"/api/v1/profile","statusCode":200,"responseTime":1.2,"contentLength":240,"ip":"10.0.0.4","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","span_id":"00f067aa0ba902b7","msg":"GET /api/v1/profile"}
66
+ ```
67
+
68
+ ---
69
+
70
+ ## 3. Global Logger Singleton (`logger`)
71
+
72
+ The `logger` singleton is a high-performance proxy that can be imported and used anywhere in your services, repositories, workers, and controllers:
21
73
 
22
74
  ```typescript
23
75
  import { logger } from 'exisjs/logger'
24
76
 
25
- logger.info('Server boot sequence initiated')
26
- logger.warn({ origin: req.headers.origin }, 'Untrusted origin detected')
27
- logger.error({ err }, 'Failed to persist record to database')
28
- logger.debug({ payload }, 'Parsing incoming request payload')
77
+ // Standard level methods
78
+ logger.info('Payment service initialized')
79
+ logger.warn({ ip: req.ip, attempts: 3 }, 'Multiple failed login attempts')
80
+ logger.error({ err, orderId: 'ord_123' }, 'Stripe webhook processing failed')
81
+ logger.debug({ payload }, 'Parsed RPC frame')
82
+ logger.trace('Entering database connection pool checkout')
83
+ logger.fatal({ err }, 'Unrecoverable process state')
84
+
85
+ // Child loggers with bound context
86
+ const workerLogger = logger.child({ workerId: 'worker-1', queue: 'emails' })
87
+ workerLogger.info('Processing email batch')
29
88
  ```
30
89
 
31
- ### Methods
32
- - `logger.info([obj], msg, ...args)`
33
- - `logger.warn([obj], msg, ...args)`
34
- - `logger.error([obj], msg, ...args)`
35
- - `logger.debug([obj], msg, ...args)`
36
- - `logger.trace([obj], msg, ...args)`
37
- - `logger.fatal([obj], msg, ...args)`
38
- - `logger.child(bindings)`: Creates a child logger with bound metadata (e.g. `{ requestId: '123' }`).
39
-
40
90
  ---
41
91
 
42
- ## 2. Configuration (`configureLogger`)
92
+ ## 4. Configuration (`configureLogger`)
43
93
 
44
- Use `configureLogger()` to adjust log levels, toggle pretty printing, and customize sensitive field redactions across the entire application:
94
+ Use `configureLogger()` to adjust log levels, toggle pretty printing, and customize sensitive field redactions across your entire application:
45
95
 
46
96
  ```typescript filename="src/http/server.ts"
47
97
  import { configureLogger } from 'exisjs/logger'
@@ -49,21 +99,87 @@ import { configureLogger } from 'exisjs/logger'
49
99
  configureLogger({
50
100
  level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
51
101
  pretty: process.env.NODE_ENV !== 'production',
52
- redact: ['*.password', '*.token', '*.secret', 'req.headers.cookie'],
102
+ redact: ['*.password', '*.token', '*.secret', 'req.headers.cookie', '*.creditCard'],
103
+ })
104
+ ```
105
+
106
+ ### Options Reference
107
+
108
+ | Option | Type | Default | Description |
109
+ | :--- | :--- | :--- | :--- |
110
+ | `level` | `'fatal' \| 'error' \| 'warn' \| 'info' \| 'debug' \| 'trace' \| 'silent'` | `'info'` | Minimum log level to emit |
111
+ | `pretty` | `boolean` | `NODE_ENV !== 'production'` | Whether to use colored single-line terminal formatting |
112
+ | `redact` | `string[]` | *See Redaction section* | Array of object paths to automatically censor from logs |
113
+ | `replaceRedact` | `boolean` | `false` | When `true`, overrides default redact paths instead of merging |
114
+
115
+ ---
116
+
117
+ ## 5. Security & Sensitive Data Redaction
118
+
119
+ By default, ExisJS automatically censors sensitive fields in all log payloads before they are serialized to disk or terminal:
120
+
121
+ ```typescript
122
+ // Built-in default redacted paths:
123
+ [
124
+ 'req.headers.authorization',
125
+ 'req.headers.cookie',
126
+ 'req.body.password',
127
+ 'req.body.token',
128
+ 'req.body.secret',
129
+ '*.password',
130
+ '*.token',
131
+ '*.secret',
132
+ 'password',
133
+ 'token',
134
+ 'secret'
135
+ ]
136
+ ```
137
+
138
+ When logging objects containing these keys (e.g. `{ username: 'alex', password: 'supersecretpassword' }`), the value is replaced with `"[Redacted]"`.
139
+
140
+ ---
141
+
142
+ ## 6. Request-Scoped Logger (`req.log` / `ctx.log`)
143
+
144
+ Every incoming HTTP request in ExisJS provides a zero-allocation lazy child logger bound to `req.log`. It automatically inherits and binds:
145
+ - `requestId` (`req.requestId`)
146
+ - `method` (`req.method`)
147
+ - `url` (`req.path`)
148
+
149
+ ```typescript filename="src/http/orders/route.ts"
150
+ import { route, controller } from 'exisjs/router'
151
+
152
+ export default controller({
153
+ create: route.post('/', {
154
+ async handle({ req, body }) {
155
+ // req.log automatically includes { requestId, method, url }
156
+ req.log.info({ orderId: body.id }, 'Creating order record')
157
+ return { success: true }
158
+ }
159
+ })
53
160
  })
54
161
  ```
55
162
 
56
- ### Options
57
- - `level` (`'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'silent'`): Minimum level to output (default: `'info'`).
58
- - `pretty` (`boolean`): Whether to format log lines with bracketed timestamp and colorized labels (`[HH:MM:ss] LEVEL: message`). Default is `true` in development and `false` in production.
59
- - `redact` (`string[]`): Property paths to censor automatically from log payloads.
60
- - `replaceRedact` (`boolean`): When `true`, replaces default redact paths instead of merging with them.
163
+ ---
164
+
165
+ ## 7. OpenTelemetry & Distributed Tracing
166
+
167
+ ExisJS automatically integrates with `@opentelemetry/api` when present in your environment. Every log entry emitted via `logger` or `req.log` automatically receives the active `trace_id` and `span_id`:
168
+
169
+ ```json
170
+ {
171
+ "level": 30,
172
+ "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
173
+ "span_id": "00f067aa0ba902b7",
174
+ "msg": "Order created successfully"
175
+ }
176
+ ```
61
177
 
62
178
  ---
63
179
 
64
- ## 3. Custom Logger Instance (`setLogger`)
180
+ ## 8. Custom Logger Integration (`setLogger`)
65
181
 
66
- If you want to plug in your own custom Pino instance or transport (e.g., streaming logs directly to Loki, Datadog, or Elasticsearch), pass it to `setLogger()`:
182
+ To route ExisJS logs directly into custom transports (such as `pino-loki`, `@google-cloud/logging`, or Elasticsearch), supply your custom instance to `setLogger()`:
67
183
 
68
184
  ```typescript filename="src/http/server.ts"
69
185
  import { setLogger } from 'exisjs/logger'
@@ -82,19 +198,35 @@ setLogger(customPino)
82
198
 
83
199
  ---
84
200
 
85
- ## 4. Request-Scoped Logger (`req.log`)
86
-
87
- Every incoming HTTP request in ExisJS automatically receives a child logger bound to `req.log`. It automatically includes request context such as `req.requestId`:
201
+ ## 9. Formatting Helper Utilities
88
202
 
89
- ```typescript filename="src/http/users/route.ts"
90
- import { route, controller } from 'exisjs/router'
203
+ ExisJS exports all terminal formatting helpers from `exisjs/logger` so you can use them in custom CLI tools, workers, and plugins:
91
204
 
92
- export default controller({
93
- profile: route.get('/profile', {
94
- async handle({ req }) {
95
- req.log.info('Fetching user profile')
96
- return { ok: true }
97
- }
98
- })
99
- })
205
+ ```typescript
206
+ import {
207
+ formatBytes,
208
+ formatLatency,
209
+ formatMethod,
210
+ formatStatus,
211
+ formatUrl,
212
+ formatIp,
213
+ extractValidationSummary,
214
+ extractErrorMessage,
215
+ } from 'exisjs/logger'
216
+
217
+ // Byte formatting
218
+ formatBytes(1420) // "1.4 KB"
219
+
220
+ // Latency with color threshold
221
+ formatLatency(14.5) // "\x1b[32m14.5ms\x1b[0m"
222
+
223
+ // Padded color-coded method
224
+ formatMethod('GET') // "\x1b[1;36mGET \x1b[0m"
225
+
226
+ // Status code with standard phrase
227
+ formatStatus(200) // "\x1b[1;32m200 OK\x1b[0m"
228
+
229
+ // Localhost suppression
230
+ formatIp('127.0.0.1') // "" (suppressed)
231
+ formatIp('192.168.1.10') // "\x1b[90m192.168.1.10\x1b[0m"
100
232
  ```
@@ -48,6 +48,37 @@ export default controller({
48
48
 
49
49
  ---
50
50
 
51
+ ## Middleware Context Inference
52
+
53
+ ### `defineMiddleware<TContext>(fn)`
54
+
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.
56
+
57
+ ```typescript
58
+ import { controller, route, defineMiddleware } from 'exisjs/router'
59
+
60
+ interface AuthContext {
61
+ user: { id: string; role: 'admin' | 'user'; email: string }
62
+ }
63
+
64
+ const auth = defineMiddleware<AuthContext>((req, res, next) => {
65
+ req.user = { id: 'u1', role: 'admin', email: 'alex@example.com' }
66
+ next()
67
+ })
68
+
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
+ })
78
+ ```
79
+
80
+ ---
81
+
51
82
  ## Security Middleware
52
83
 
53
84
  ### `helmet(options?)`
@@ -248,3 +248,25 @@ ExisJS provides a rich ecosystem of decorators to apply middleware, configure re
248
248
  - `@Returns(schema)`: Explicitly defines the response schema for OpenAPI generation.
249
249
  - `@Idempotent()`: Enforces idempotency keys for mutations (e.g., checkout/payments).
250
250
 
251
+ ---
252
+
253
+ ## 3. Streaming & Backpressure Pipeline
254
+
255
+ The response object supports universal streaming with backpressure management across all route types:
256
+
257
+ - `res.sendStream(source)`: Streams a Node.js `stream.Readable`, Web `ReadableStream`, or `AsyncIterable` directly to the client socket. Pauses consumption when socket buffers fill up and terminates source readers upon client disconnection.
258
+ - `res.stream(source)`: Alias for `sendStream()`.
259
+ - **Automatic Handler Auto-Piping**: Returning a Node.js stream, Web standard `ReadableStream`, or `AsyncIterable` generator directly from `handle()` automatically delegates to `res.sendStream()`.
260
+
261
+ ---
262
+
263
+ ## 4. `AppRouter` Client Manifest Contract
264
+
265
+ ExisJS generates a compile-time route manifest in `.exis/types.d.ts` and `.exis/types/index.d.ts`:
266
+
267
+ - `AppRouterPaths`: Flat dictionary mapping URL route patterns (e.g. `'/users/:id'`) to their strongly-typed handler contracts (`(payload?: B, options?: { query?: Q; params?: P }) => Promise<R>`).
268
+ - `AppRouterTree`: Hierarchical dot-notation tree mapping nested folder paths (`users: { ':id': ... }`) for `@exisjs/fetch`'s `createClient<AppRouter>()`.
269
+ - `AppRouter`: Combined intersection type `AppRouterPaths & AppRouterTree`.
270
+ - `RouteDefinition.__type`: Phantom type property on every route definition preserving exact inferred return types, DTO schemas, and Drizzle/Prisma models.
271
+
272
+
@@ -0,0 +1,143 @@
1
+ ---
2
+ title: "Swagger (exisjs/swagger)"
3
+ description: "API Reference for ExisJS Swagger & OpenAPI 3.1 Documentation Subsystem"
4
+ ---
5
+
6
+ # Swagger Reference (`exisjs/swagger`)
7
+
8
+ The `exisjs/swagger` module provides tools and decorators for auto-generating OpenAPI 3.1 specifications and serving interactive documentation UIs.
9
+
10
+ ```typescript
11
+ import {
12
+ swagger,
13
+ defineSwagger,
14
+ generateOpenApiSpec,
15
+ renderDocumentationHtml,
16
+ mountDocumentation,
17
+ ApiTags,
18
+ ApiOperation,
19
+ ApiResponse,
20
+ ApiBearerAuth,
21
+ ApiSecurity,
22
+ ApiExclude,
23
+ ApiProperty,
24
+ } from 'exisjs/swagger'
25
+ ```
26
+
27
+ ---
28
+
29
+ ## Configuration (`SwaggerConfig`)
30
+
31
+ | Property | Type | Default | Description |
32
+ |---|---|---|---|
33
+ | `enabled` | `boolean` | `false` | Whether to enable documentation routes |
34
+ | `path` | `string` | `'/docs'` | URL path for the interactive HTML UI |
35
+ | `specPath` | `string` | `'/docs/json'` | URL path for OpenAPI 3.1 JSON specification |
36
+ | `title` | `string` | `'ExisJS API Documentation'` | API Title displayed in documentation |
37
+ | `version` | `string` | `'1.0.0'` | API Version string |
38
+ | `description` | `string` | `undefined` | Overview markdown or description |
39
+ | `ui` | `'swagger-ui' \| 'scalar'` | `'swagger-ui'` | Documentation UI renderer |
40
+ | `servers` | `OpenApiServer[]` | `[{ url: '/' }]` | Target server list |
41
+ | `tags` | `OpenApiTag[]` | `[]` | Group tags with descriptions |
42
+ | `security` | `Record<string, string[]>[]` | `[]` | Global security requirements |
43
+ | `securitySchemes` | `Record<string, SecurityScheme>` | `{}` | Reusable security scheme definitions |
44
+ | `customCss` | `string` | `undefined` | Custom CSS injected into the UI |
45
+ | `customFavicon` | `string` | `undefined` | Custom favicon image URL |
46
+ | `transformSpec` | `(spec: OpenApiSpec) => OpenApiSpec` | `undefined` | Hook to mutate OpenAPI spec before serving |
47
+
48
+ ---
49
+
50
+ ## Decorators
51
+
52
+ ### `@ApiTags(...tags: string[])`
53
+ Assigns one or more tags to a controller class or method handler.
54
+ *(Alias: `@Tags()`)*
55
+
56
+ ```typescript
57
+ @ApiTags('Users', 'Authentication')
58
+ @Controller('/users')
59
+ export class UserController {}
60
+ ```
61
+
62
+ ### `@ApiOperation(options)`
63
+ Attaches summary, description, operationId, and deprecated status to a route method.
64
+ *(Alias: `@Operation()`)*
65
+
66
+ ```typescript
67
+ @Get('/:id')
68
+ @ApiOperation({
69
+ summary: 'Get user by UUID',
70
+ description: 'Fetches user details from database',
71
+ deprecated: false,
72
+ })
73
+ getUser() {}
74
+ ```
75
+
76
+ ### `@ApiResponse(options)`
77
+ Defines an expected HTTP response status code and optional schema.
78
+
79
+ ```typescript
80
+ @ApiResponse({
81
+ status: 200,
82
+ description: 'User details found',
83
+ schema: UserResponseSchema,
84
+ })
85
+ @ApiResponse({ status: 404, description: 'User not found' })
86
+ getUser() {}
87
+ ```
88
+
89
+ ### `@ApiBearerAuth(name?: string)`
90
+ Requires Bearer JWT authentication for this endpoint or controller.
91
+ *(Alias: `@BearerAuth()`)*
92
+
93
+ ```typescript
94
+ @ApiBearerAuth()
95
+ @Get('/me')
96
+ getMe() {}
97
+ ```
98
+
99
+ ### `@ApiSecurity(name: string, scopes?: string[])`
100
+ Requires custom security scheme authentication for this endpoint or controller.
101
+
102
+ ```typescript
103
+ @ApiSecurity('apiKeyAuth')
104
+ @Get('/metrics')
105
+ getMetrics() {}
106
+ ```
107
+
108
+ ### `@ApiExclude()`
109
+ Excludes an endpoint or controller class from OpenAPI and Swagger generation.
110
+
111
+ ```typescript
112
+ @Get('/internal')
113
+ @ApiExclude()
114
+ getInternal() {}
115
+ ```
116
+
117
+ ### `@ApiProperty(options?: { description?: string; example?: any; required?: boolean })`
118
+ Annotates a class property with metadata for OpenAPI schema models.
119
+
120
+ ---
121
+
122
+ ## Functions
123
+
124
+ ### `swagger(config?: SwaggerConfig)`
125
+ Convenience helper to mount Swagger/OpenAPI documentation on an ExisJS App instance.
126
+
127
+ ```typescript
128
+ import { App } from 'exisjs'
129
+ import { swagger } from 'exisjs/swagger'
130
+
131
+ const app = new App()
132
+ swagger({ title: 'My API', path: '/docs' })(app)
133
+ ```
134
+
135
+ ### `generateOpenApiSpec(routesOrApp, config)`
136
+ Pure generator function that introspects routes, parameters, Tex/Zod schemas, and returns an `OpenApiSpec` object.
137
+
138
+ ```typescript
139
+ const spec = generateOpenApiSpec(app, { title: 'My API', version: '1.0.0' })
140
+ ```
141
+
142
+ ### `renderDocumentationHtml(config)`
143
+ Renders standalone HTML markup for Swagger UI or Scalar API reference.
@@ -11,13 +11,23 @@ ExisJS ships with a efficient, integrated validation library out of the box, exp
11
11
 
12
12
  ## Core Types
13
13
 
14
- The `tex` object provides factory functions for every common primitive and data structure.
15
-
16
- - `tex.string()`: Validates a string.
17
- - `tex.number()`: Validates a number.
18
- - `tex.boolean()`: Validates a boolean.
19
- - `tex.email()`: Validates standard email formatting.
20
- - `tex.enum(['A', 'B'])`: Validates against a specific set of allowed strings.
14
+ The `tex` object provides factory functions for every common primitive and data structure:
15
+
16
+ - `tex.string(options?)`: Validates a string (supports min, max, trim, sanitizers, masking, SQL injection prevention, defaults).
17
+ - `tex.number(options?)`: Validates a numeric value (supports min, max, coercion, defaults).
18
+ - `tex.boolean(options?)`: Validates a boolean value (supports coercion, defaults).
19
+ - `tex.email(options?)`: Validates standard email formatting.
20
+ - `tex.uuid(options?)`: Validates UUID v1 or v4 strings (`{ version: 1 | 4 }`).
21
+ - `tex.cuid(options?)`: Validates CUID identifiers.
22
+ - `tex.password(options?)`: Enforces password complexity rules (`requireNumbers`, `requireSymbols`, `requireUppercase`, `requireLowercase`).
23
+ - `tex.creditCard(options?)`: Validates credit card number format with optional masking (`{ mask: true }`).
24
+ - `tex.date(options?)`: Validates Date instances, or coerces ISO 8601 strings and UNIX timestamps with `minDate` / `maxDate` bounds.
25
+ - `tex.enum(values, options?)`: Validates against a specific set of allowed strings.
26
+ - `tex.literal(value)`: Validates against an exact literal value (`string | number | boolean`).
27
+ - `tex.record(schema)`: Validates a dictionary / map of key-value pairs matching the given value schema.
28
+ - `tex.union(schemas)`: Validates that the input matches at least one of the provided schemas.
29
+ - `tex.any()`: Allows any arbitrary payload value without constraints.
30
+ - `tex.file(options?)`: Validates multipart file uploads (`maxSize`, `mimeTypes`).
21
31
 
22
32
  ### Objects & Arrays
23
33
 
@@ -114,8 +124,24 @@ All validators accept an options object that allows you to configure validation
114
124
  - `optional` / `.optional()`: Marks the field as optional (allows `undefined`).
115
125
  - `nullable` / `.nullable()`: Marks the field as nullable (allows `null`).
116
126
  - `nullish` / `.nullish()`: Marks the field as nullish (allows both `null` and `undefined`).
127
+ - `default`: Accepts a static literal value (`string | number | boolean | ...`) or a lazy factory function (`() => value`). Automatically marks the field as optional in schemas while inferring a non-optional concrete TypeScript return type.
117
128
  - `coerce`: Instructs the Rust engine to automatically convert types when possible before validating. For example, converting `"123"` into a number, or `3000` into a string.
118
129
 
130
+ > [!TIP]
131
+ > **Static vs. Dynamic Defaults**:
132
+ > ```typescript
133
+ > const ConfigSchema = tex.object({
134
+ > // Static defaults
135
+ > PORT: tex.number({ coerce: true, default: 3000 }),
136
+ > THEME: tex.enum(['light', 'dark'] as const, { default: 'light' }),
137
+ > TAGS: tex.array(tex.string(), { default: ['exis', 'framework'] }),
138
+ >
139
+ > // Dynamic defaults (evaluated per parse call)
140
+ > createdAt: tex.date({ default: () => new Date() }),
141
+ > requestId: tex.string({ default: () => crypto.randomUUID() }),
142
+ > })
143
+ > ```
144
+
119
145
  > [!NOTE]
120
146
  > **Empty String Interop**: If an incoming string is empty (`""`), and the field is configured as `optional`, `nullable`, or `nullish`, ExisJS automatically converts it to `undefined` or `null` before running type checks. This cleanly handles form submissions and query strings without requiring ad-hoc pre-processors.
121
147
 
@@ -133,20 +159,28 @@ const EnvSchema = tex.object({
133
159
  })
134
160
  ```
135
161
 
136
- ### String Options
137
- - `min`: Enforces a minimum string length.
138
- - `max`: Enforces a maximum string length.
139
-
140
- ### Number Options
141
- - `min`: Enforces a minimum numeric value.
142
- - `max`: Enforces a maximum numeric value.
162
+ ### Primitive Options Summary
163
+
164
+ | Primitive | Available Options |
165
+ | :--- | :--- |
166
+ | `tex.string(opts?)` | `min`, `max`, `trim`, `collapseWhitespace`, `toLowerCase`, `toUpperCase`, `escapeHtml`, `stripHtml`, `slugify`, `mask`, `preventSql`, `preventTraversal`, `default`, `optional`, `nullable`, `nullish` |
167
+ | `tex.number(opts?)` | `min`, `max`, `coerce`, `default`, `optional`, `nullable`, `nullish` |
168
+ | `tex.boolean(opts?)` | `coerce`, `default`, `optional`, `nullable`, `nullish` |
169
+ | `tex.date(opts?)` | `coerce`, `minDate`, `maxDate`, `default`, `optional`, `nullable`, `nullish` |
170
+ | `tex.array(schema, opts?)` | `min`, `max`, `dedupe`, `coerce`, `default`, `optional`, `nullable`, `nullish` |
171
+ | `tex.enum(values, opts?)` | `default`, `optional`, `nullable`, `nullish` |
172
+ | `tex.uuid(opts?)` | `version: 1 \| 4`, `default`, `optional`, `nullable`, `nullish` |
173
+ | `tex.password(opts?)` | `min`, `max`, `requireNumbers`, `requireSymbols`, `requireUppercase`, `requireLowercase`, `optional`, `nullable`, `nullish` |
174
+ | `tex.creditCard(opts?)` | `mask: boolean`, `optional`, `nullable`, `nullish` |
175
+ | `tex.file(opts?)` | `maxSize`, `mimeTypes: string[]`, `optional`, `nullable`, `nullish` |
143
176
 
144
177
  ```typescript
145
178
  const User = tex.object({
146
179
  id: tex.string(),
147
180
  email: tex.email(),
148
181
  password: tex.string({ min: 8, max: 100 }),
149
- age: tex.number({ min: 13, optional: true })
182
+ age: tex.number({ min: 13, optional: true }),
183
+ role: tex.enum(['admin', 'member'], { default: 'member' })
150
184
  })
151
185
  ```
152
186
 
@@ -204,18 +238,44 @@ The `TexEngine` automatically converts validation schemas into strictly complian
204
238
 
205
239
  ---
206
240
 
207
- ## Environment Validation
241
+ ## Environment Validation (`tex.env`)
208
242
 
209
- You can safely parse and validate your environment variables at startup using the standard `.parse()` method.
243
+ Because `process.env` always supplies raw string values (e.g. `"4000"`, `"true"`, `"1"`), ExisJS provides a dedicated `tex.env()` schema parser that automatically applies type coercion (`number`, `boolean`, `date`, `array`) and parses string representations without requiring verbose `{ coerce: true }` flags on every field.
210
244
 
211
- ```typescript filename="env.ts"
245
+ ```typescript filename="src/config/env.ts"
212
246
  import { tex } from 'exisjs/validator'
213
247
 
214
- // Validates process.env synchronously. Crashes the app on boot with a
215
- // beautiful error message if validation fails.
216
- export const env = tex.object({
217
- PORT: tex.number({ coerce: true, optional: true }),
248
+ // Validates process.env synchronously with automatic type coercion on boot.
249
+ export const env = tex.env({
250
+ PORT: tex.number({ default: 3000 }), // Automatically coerced from "3000" -> 3000
251
+ DEBUG: tex.boolean({ default: false }), // Parsed from "true" | "1" | "false" | "0"
218
252
  DATABASE_URL: tex.string(),
219
- JWT_SECRET: tex.string({ min: 32 })
253
+ JWT_SECRET: tex.string({ min: 32 }),
254
+ ALLOWED_ORIGINS: tex.array(tex.string()), // Parsed from "http://localhost:3000,https://app.com"
255
+ NODE_ENV: tex.enum(['development', 'production', 'test'] as const, {
256
+ default: 'development',
257
+ }),
220
258
  }).parse(process.env)
221
259
  ```
260
+
261
+ > [!TIP]
262
+ > `tex.env` automatically applies defaults and lazy factories (`default: () => ...`) when environment variables are omitted, while throwing structured `ValidatorError` diagnostics on boot if required keys are missing.
263
+
264
+ ---
265
+
266
+ ## Validation Error Descriptors (`ValidationErrorDescriptor`)
267
+
268
+ When validation fails, ExisJS emits structured error descriptors passed across the FFI boundary:
269
+
270
+ ```typescript
271
+ export interface ValidationErrorDescriptor {
272
+ path: string // e.g. "email" or "items[0].sku"
273
+ message: string // Human-readable failure description
274
+ expected: string // Expected constraint or type rule
275
+ received: string // Received value representation
276
+ code: string // Machine-readable code (e.g. MISSING_REQUIRED_FIELD, INVALID_TYPE, VALUE_TOO_SMALL)
277
+ }
278
+ ```
279
+
280
+ In HTTP 400 responses, the envelope contains both a legacy `errors: Record<string, string>` dictionary for backward compatibility and a structured `details: ValidationErrorDescriptor[]` array for modern form libraries.
281
+
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/error/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/error/errors.ts"],"names":[],"mappings":"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"}