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
@@ -0,0 +1,196 @@
1
+ ---
2
+ nextUrl: "/docs/queues"
3
+ nextTitle: "Queues & Background Jobs"
4
+ ---
5
+
6
+ # Cron & Task Scheduling
7
+
8
+ ExisJS includes a built-in Cron and Task Scheduling system designed for reliability and developer ergonomic efficiency. It resolves common Node.js scheduling challenges such as timer drift, concurrent execution overlap, unhandled exceptions crashing the process, timezone/DST inaccuracies, and zombie timers during hot reload or process shutdown.
9
+
10
+ Both **Functional** and **Class-Based (OOP)** paradigms are fully supported with complete feature parity.
11
+
12
+ ---
13
+
14
+ ## File Conventions & Auto-Discovery
15
+
16
+ ExisJS auto-mounts cron jobs using two straightforward conventions:
17
+
18
+ 1. **Single-File Management (`src/http/cron.ts` or `src/http/cron.js`)**:
19
+ Define and manage all your scheduled tasks in a single file located at `src/http/cron.ts` (or inside route slices such as `src/http/admin/cron.ts`). Multiple jobs can be exported using named exports, a default export, or an array of jobs.
20
+
21
+ 2. **Dedicated Directory (`src/cron/*`)**:
22
+ Organize distinct tasks into separate files inside `src/cron/` (e.g. `src/cron/sync.ts`, `src/cron/reports.ts`). Every file inside `src/cron/` is automatically registered upon application boot.
23
+
24
+ ---
25
+
26
+ ## 1. Functional Paradigm (`cron`)
27
+
28
+ Import `cron` from `exisjs/cron` to define scheduled tasks.
29
+
30
+ ### Single-File Multi-Job Example
31
+
32
+ Manage multiple jobs within `src/http/cron.ts`:
33
+
34
+ ```typescript filename="src/http/cron.ts"
35
+ import { cron, CronExpression } from 'exisjs/cron'
36
+
37
+ // Job 1: Nightly synchronization
38
+ export const syncJob = cron({
39
+ name: 'nightly-sync',
40
+ schedule: CronExpression.EVERY_DAY_AT_MIDNIGHT,
41
+ timezone: 'UTC',
42
+ preventOverlap: true,
43
+ retries: 2,
44
+ retryDelayMs: 3000,
45
+ async run({ app, log }) {
46
+ log.info('Executing nightly sync...')
47
+ },
48
+ onError(err, { log }) {
49
+ log.error({ err }, 'Nightly sync failed after retries')
50
+ }
51
+ })
52
+
53
+ // Job 2: Frequent polling using human-readable duration
54
+ export const pollJob = cron.every('5 minutes', async ({ log }) => {
55
+ log.info('Checking external queue...')
56
+ })
57
+
58
+ // Job 3: Recurring millisecond interval
59
+ export const heartbeat = cron.interval(30_000, async ({ log }) => {
60
+ log.info('System heartbeat active')
61
+ })
62
+
63
+ // Job 4: Startup delayed task (runs 5 seconds after server boots)
64
+ export const warmup = cron.timeout(5_000, async ({ app, log }) => {
65
+ log.info('Pre-warming cache...')
66
+ })
67
+ ```
68
+
69
+ ### Dedicated File Example
70
+
71
+ ```typescript filename="src/cron/cleanup.ts"
72
+ import { cron, CronExpression } from 'exisjs/cron'
73
+
74
+ export default cron({
75
+ name: 'db-cleanup',
76
+ schedule: CronExpression.EVERY_DAY_AT_2AM,
77
+ timezone: 'America/New_York',
78
+ preventOverlap: true,
79
+ async run({ log }) {
80
+ log.info('Purging stale database records...')
81
+ }
82
+ })
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 2. Class-Based (OOP) Paradigm (`@Cron`)
88
+
89
+ In the OOP paradigm, methods on any `@Injectable()` service or class can be scheduled using decorators from `exisjs/decorators` with full **Dependency Injection** support.
90
+
91
+ ```typescript filename="src/cron/cleanup.ts"
92
+ import { Injectable, Cron, Interval, TimeoutTask, CronExpression } from 'exisjs/decorators'
93
+ import { DatabaseService } from '../services/database.service'
94
+ import { LoggerService } from '../services/logger.service'
95
+
96
+ @Injectable()
97
+ export default class CleanupService {
98
+ constructor(
99
+ private db: DatabaseService,
100
+ private logger: LoggerService
101
+ ) {}
102
+
103
+ @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT, {
104
+ name: 'nightly-purge',
105
+ timezone: 'UTC',
106
+ preventOverlap: true,
107
+ })
108
+ async purgeOldSessions() {
109
+ this.logger.info('Purging expired user sessions...')
110
+ await this.db.deleteExpiredSessions()
111
+ }
112
+
113
+ @Interval(60_000, { name: 'health-ping' })
114
+ async checkDatabaseHealth() {
115
+ await this.db.ping()
116
+ }
117
+
118
+ @TimeoutTask(5_000, { name: 'cache-warmup' })
119
+ async warmupCache() {
120
+ this.logger.info('Pre-warming cache...')
121
+ }
122
+ }
123
+ ```
124
+
125
+ ---
126
+
127
+ ## 3. Core Reliability Features
128
+
129
+ ### Overlap Prevention (`preventOverlap: true`)
130
+ Standard timers trigger subsequent ticks even if the current execution is stalled, leading to connection exhaustion and database lock contention. With `preventOverlap: true` (default: `true`), ExisJS locks execution during active jobs and skips overlapping executions until the current run completes.
131
+
132
+ ### Error Isolation Sandbox
133
+ Exceptions thrown inside cron handlers are caught within an isolated execution boundary. An error in a background task will never crash the HTTP server or stop subsequent cron triggers. Errors are logged and forwarded to an optional `onError(err, context)` hook for monitoring integration (e.g. Sentry, Datadog).
134
+
135
+ ### IANA Timezones & Daylight Saving Time (DST)
136
+ Supports standard IANA timezones (e.g. `'America/New_York'`, `'Asia/Kolkata'`, `'Europe/London'`, `'UTC'`). Next execution dates are computed accurately across DST transitions using cached native `Intl.DateTimeFormat` evaluations.
137
+
138
+ ---
139
+
140
+ ## 4. Programmatic Runtime Management (`app.cron`)
141
+
142
+ You can inspect, pause, resume, or trigger jobs dynamically at runtime via `app.cron`:
143
+
144
+ ```typescript filename="src/http/admin/cron/route.ts"
145
+ import { controller, route } from 'exisjs/router'
146
+
147
+ export default controller({
148
+ // Query status and metrics of all registered jobs
149
+ listJobs: route.get('/', async ({ app }) => {
150
+ return {
151
+ jobs: app.cron.status()
152
+ }
153
+ }),
154
+
155
+ // Manually trigger a scheduled job on demand
156
+ triggerJob: route.post('/:name/trigger', async ({ app, params }) => {
157
+ const result = await app.cron.trigger(params.name)
158
+ return { success: true, result }
159
+ }),
160
+
161
+ // Pause a job
162
+ pauseJob: route.post('/:name/pause', async ({ app, params }) => {
163
+ app.cron.pause(params.name)
164
+ return { success: true, message: `Job ${params.name} paused` }
165
+ }),
166
+
167
+ // Resume a paused job
168
+ resumeJob: route.post('/:name/resume', async ({ app, params }) => {
169
+ app.cron.resume(params.name)
170
+ return { success: true, message: `Job ${params.name} resumed` }
171
+ }),
172
+ })
173
+ ```
174
+
175
+ ---
176
+
177
+ ## 5. Graceful Shutdown & Draining
178
+
179
+ When the application receives a shutdown signal (`SIGINT`, `SIGTERM`, or `app.close()`):
180
+ 1. The scheduler stops scheduling future ticks immediately.
181
+ 2. Active timers are unreferenced (`unref()`).
182
+ 3. Running tasks are allowed to finish within the configured drain window (default: 5000ms) before the process terminates.
183
+
184
+ ---
185
+
186
+ ## 6. CLI Scaffolding
187
+
188
+ Generate cron job files using the ExisJS CLI:
189
+
190
+ ```bash
191
+ # Functional Job (generates src/cron/cleanup.ts)
192
+ npx exis generate cron cleanup
193
+
194
+ # Class-Based Job (generates src/cron/cleanup.ts with @Injectable & @Cron)
195
+ npx exis generate cron cleanup --oop
196
+ ```
@@ -134,6 +134,12 @@ export default class UsersController {
134
134
  - `@Param(nameOrPipe?)` — Extracts a route path param (e.g. `:id`).
135
135
  - `@QueryParam(nameOrPipe?)` / `@Query(nameOrPipe?)` — Extracts a query parameter from the URL query string.
136
136
  - `@Headers(nameOrPipe?)` — Extracts a request header by name.
137
+ - `@Cookies(nameOrPipe?)` / `@Cookie(nameOrPipe?)` — Injects incoming parsed cookies or a specific cookie value.
138
+ - `@State(keyOrPipe?)` — Injects request state from execution context or middleware.
139
+ - `@AppCtx()` — Injects the root ExisJS Application instance.
140
+ - `@Fields(nameOrPipe?)` — Injects non-file multipart form fields.
141
+ - `@UploadedFile(nameOrPipe?)` — Injects a single uploaded file.
142
+ - `@UploadedFiles(nameOrPipe?)` — Injects multiple uploaded files.
137
143
  - `@HostParam(nameOrPipe?)` — Extracts a host subdomain parameter.
138
144
  - `@Req()` — Injects the raw request object.
139
145
  - `@Res(options?)` — Injects the response object (e.g. `{ passthrough: true }`).
@@ -150,16 +156,19 @@ export default class UsersController {
150
156
 
151
157
  ## 4. Middleware & Pipeline Decorators
152
158
 
153
- You can bind middlewares, guards, interceptors, and exception filters to controllers or route methods using the unified `@Use()` decorator:
159
+ You can bind middlewares, guards, interceptors, and exception filters to controllers or route methods using first-class decorators:
154
160
 
155
161
  ```typescript filename="src/http/checkout/route.ts"
156
- import { Controller, Post, Use, Idempotent } from 'exisjs/decorators'
162
+ import { Controller, Post, Use, Idempotent, RateLimit, Cors, Timeout } from 'exisjs/decorators'
157
163
  import { requireAuth } from '../../middleware/auth'
158
164
 
159
165
  @Controller('/checkout')
160
166
  @Use(requireAuth) // Applies to all routes in this controller
167
+ @Cors({ origin: 'https://app.yourdomain.com' })
168
+ @RateLimit({ max: 10, windowMs: 60000 })
161
169
  export default class CheckoutController {
162
170
  @Post('/')
171
+ @Timeout(30000)
163
172
  @Idempotent({ ttlMs: 86400000 }) // In-memory off-heap idempotency protection
164
173
  async processPayment() {
165
174
  return { success: true }
@@ -169,7 +178,15 @@ export default class CheckoutController {
169
178
 
170
179
  ### Available Lifecycle & Middleware Decorators
171
180
  - `@Use(...items)` — Unified decorator that attaches middlewares, guards (`canActivate`), interceptors (`intercept`), or exception filters (`catch`) to a class or method.
172
- - `@Idempotent(options?)` — Caches responses based on the `Idempotency-Key` header using off-heap native memory.
181
+ - `@Timeout(ms: number | TimeoutOptions)` — Overrides the request timeout for a class or method.
182
+ - `@Idempotent(options?)` — Caches responses based on the `Idempotency-Key` header using native in-memory off-heap storage.
183
+ - `@RateLimit(options?)` — Enforces request rate limits on a controller class or route method.
184
+ - `@Cors(options?)` — Configures Cross-Origin Resource Sharing rules on a controller class or route method.
185
+ - `@IpFilter(options)` — Enforces IP/CIDR allowlist and denylist.
186
+ - `@Compress()` — Enables automatic response compression (Gzip/Brotli).
187
+ - `@Dedupe(options)` — Deduplicates concurrent identical requests sharing the same key.
188
+ - `@UseUpload(options)` / `@Upload(options)` — Configures multipart file upload handling.
189
+ - `@BlockProbes(options?)` — Intercepts scanner exploit probes (`.env`, `/.git`, `/.DS_Store`) and blackholes them without log noise.
173
190
 
174
191
  ---
175
192
 
@@ -229,7 +246,8 @@ export class UserService {
229
246
  You can inject dependencies using tokens or classes, and mark optional dependencies with `@Optional()`:
230
247
 
231
248
  ```typescript filename="src/http/users/route.ts"
232
- import { Controller, Get, Param, Inject, Optional } from 'exisjs/decorators'
249
+ import { Controller, Get, Param } from 'exisjs/decorators'
250
+ import { Inject, Optional } from 'exisjs/di'
233
251
  import { UserService } from './service'
234
252
 
235
253
  @Controller('/users')
@@ -163,40 +163,89 @@ ExisJS provides mechanisms for granular and centralized error handling.
163
163
 
164
164
  ### 1. Framework-Level Exception Handler (`src/http/error.ts`)
165
165
 
166
- Instead of writing manual `try/catch` blocks in every route or calling `app.onError` inside `server.ts`, ExisJS natively discovers and auto-mounts `src/http/error.ts` (or `error.js`).
166
+ Instead of writing manual `try/catch` blocks in every route or wiring `app.onError` inside `server.ts`, ExisJS provides a dedicated file convention: **`src/http/error.ts`** (or `src/http/*.error.ts`).
167
167
 
168
- Export an `onError(err, req, res)` function to centrally format, log, and respond to all unhandled exceptions and validation errors:
168
+ When `src/http/error.ts` is present, ExisJS automatically discovers and mounts it during application boot as the global exception interceptor. Any uncaught exception, thrown `HttpError`, or validation failure anywhere in your application is routed to this file.
169
+
170
+ #### Functional Paradigm
169
171
 
170
172
  ```typescript filename="src/http/error.ts"
171
173
  import type { Request, Response } from 'exisjs'
174
+ import { isDev } from 'exisjs/config'
172
175
 
173
176
  /**
174
- * Global Exception Handler for ExisJS
175
- * Auto-mounted at startup to intercept all unhandled exceptions.
177
+ * Global Framework Exception Handler
178
+ * Auto-mounted at startup to intercept all unhandled exceptions and validation errors.
176
179
  */
177
180
  export function onError(err: any, req: Request, res: Response) {
178
181
  const status = err.statusCode || err.status || 500
182
+ const isOperational = Boolean(err.isOperational || err.statusCode < 500)
183
+
184
+ // 1. Log unexpected crashes in production to external APM (Sentry, Datadog, Axiom)
185
+ if (!isOperational && !isDev) {
186
+ // e.g. Sentry.captureException(err, { extra: { path: req.path, method: req.method } })
187
+ req.log.error({ err }, '[Fatal] Unhandled Server Exception')
188
+ }
179
189
 
180
- // Centralized structured error response
190
+ // 2. Format a unified, standard error envelope for client applications
181
191
  res.status(status).json({
182
192
  success: false,
183
193
  error: {
184
- code: err.code || 'INTERNAL_ERROR',
194
+ code: err.code || (status === 500 ? 'INTERNAL_SERVER_ERROR' : 'ERROR'),
185
195
  message: err.message || 'Internal Server Error',
196
+ ...(err.details ? { details: err.details } : {}),
197
+ ...(err.errors ? { errors: err.errors } : {}),
186
198
  path: req.path,
199
+ timestamp: new Date().toISOString(),
187
200
  },
188
201
  })
189
202
  }
190
203
  ```
191
204
 
205
+ #### Class-Based (OOP) Paradigm
206
+
207
+ ```typescript filename="src/http/error.ts"
208
+ import type { Request, Response } from 'exisjs'
209
+ import { isDev } from 'exisjs/config'
210
+
211
+ export default class GlobalErrorHandler {
212
+ onError(err: any, req: Request, res: Response) {
213
+ const status = err.statusCode || err.status || 500
214
+ const isOperational = Boolean(err.isOperational || err.statusCode < 500)
215
+
216
+ if (!isOperational && !isDev) {
217
+ req.log.error({ err }, '[Fatal] Unhandled Server Exception')
218
+ }
219
+
220
+ res.status(status).json({
221
+ success: false,
222
+ error: {
223
+ code: err.code || (status === 500 ? 'INTERNAL_SERVER_ERROR' : 'ERROR'),
224
+ message: err.message || 'Internal Server Error',
225
+ ...(err.details ? { details: err.details } : {}),
226
+ path: req.path,
227
+ timestamp: new Date().toISOString(),
228
+ },
229
+ })
230
+ }
231
+ }
232
+ ```
233
+
192
234
  > [!TIP]
193
- > You can also scaffold this file instantly via the CLI:
235
+ > **Scaffold with CLI**: You can generate this file instantly using the ExisJS CLI:
194
236
  > ```bash
195
- > exis generate error
237
+ > npx exis generate error
196
238
  > # or shorthand:
197
- > exis g error
239
+ > npx exis g error
198
240
  > ```
199
241
 
242
+ #### What `src/http/error.ts` Intercepts:
243
+ - **`HttpError` instances**: (e.g. `throw HttpError.notFound()`, `throw HttpError.unauthorized()`).
244
+ - **Validation failures**: Zod, Tex, or Yup validation rejections automatically pass structured `err.errors` and `err.details`.
245
+ - **Database / Network exceptions**: Postgres connection failures, timeout rejections, and third-party API errors.
246
+ - **Syntax errors**: Malformed JSON bodies or bad request payloads.
247
+
248
+
200
249
  ### 2. Exception Filters (`catchError`)
201
250
 
202
251
  ExisJS allows you to create **Exception Filters** to globally intercept specific types of errors.
@@ -20,7 +20,7 @@ Exis aims to provide that out-of-the-box application architecture for backends:
20
20
  The fastest way to start is the Exis CLI, which scaffolds a new project directory with the core files and a conventional base structure already in place. This is the recommended path for first-time users.
21
21
 
22
22
  <div className="my-6 max-w-lg">
23
- <CopyCommand command="npx @exisjs/create@latest my-backend" />
23
+ <CopyCommand command="npm create exisjs@latest my-backend" />
24
24
  </div>
25
25
 
26
26
  <Hint>
@@ -43,12 +43,12 @@ export default controller({
43
43
  getUsers: route.get('/', {
44
44
  handle(req) {
45
45
  // Return a realistic response structure
46
- return {
46
+ return {
47
47
  data: [
48
48
  { id: 1, name: 'Alice' },
49
- { id: 2, name: 'Bob' }
49
+ { id: 2, name: 'Bob' },
50
50
  ],
51
- total: 2
51
+ total: 2,
52
52
  }
53
53
  },
54
54
  }),
@@ -66,12 +66,12 @@ export default class UsersController {
66
66
  @Get('/')
67
67
  getUsers(@Req() req: Request) {
68
68
  // Return a realistic response structure
69
- return {
69
+ return {
70
70
  data: [
71
71
  { id: 1, name: 'Alice' },
72
- { id: 2, name: 'Bob' }
72
+ { id: 2, name: 'Bob' },
73
73
  ],
74
- total: 2
74
+ total: 2,
75
75
  }
76
76
  }
77
77
  }