@nest-batch/core 0.2.0

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 (476) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +368 -0
  3. package/dist/src/adapters/in-process.adapter.d.ts +140 -0
  4. package/dist/src/adapters/in-process.adapter.d.ts.map +1 -0
  5. package/dist/src/adapters/in-process.adapter.js +86 -0
  6. package/dist/src/adapters/in-process.adapter.js.map +1 -0
  7. package/dist/src/adapters/index.d.ts +18 -0
  8. package/dist/src/adapters/index.d.ts.map +1 -0
  9. package/dist/src/adapters/index.js +35 -0
  10. package/dist/src/adapters/index.js.map +1 -0
  11. package/dist/src/builder/batch-builder.d.ts +26 -0
  12. package/dist/src/builder/batch-builder.d.ts.map +1 -0
  13. package/dist/src/builder/batch-builder.js +25 -0
  14. package/dist/src/builder/batch-builder.js.map +1 -0
  15. package/dist/src/builder/flow-builder.d.ts +59 -0
  16. package/dist/src/builder/flow-builder.d.ts.map +1 -0
  17. package/dist/src/builder/flow-builder.js +115 -0
  18. package/dist/src/builder/flow-builder.js.map +1 -0
  19. package/dist/src/builder/index.d.ts +5 -0
  20. package/dist/src/builder/index.d.ts.map +1 -0
  21. package/dist/src/builder/index.js +23 -0
  22. package/dist/src/builder/index.js.map +1 -0
  23. package/dist/src/builder/job-builder.d.ts +76 -0
  24. package/dist/src/builder/job-builder.d.ts.map +1 -0
  25. package/dist/src/builder/job-builder.js +166 -0
  26. package/dist/src/builder/job-builder.js.map +1 -0
  27. package/dist/src/builder/step-builder.d.ts +74 -0
  28. package/dist/src/builder/step-builder.d.ts.map +1 -0
  29. package/dist/src/builder/step-builder.js +144 -0
  30. package/dist/src/builder/step-builder.js.map +1 -0
  31. package/dist/src/compiler/builder-types.d.ts +20 -0
  32. package/dist/src/compiler/builder-types.d.ts.map +1 -0
  33. package/dist/src/compiler/builder-types.js +6 -0
  34. package/dist/src/compiler/builder-types.js.map +1 -0
  35. package/dist/src/compiler/definition-compiler.d.ts +99 -0
  36. package/dist/src/compiler/definition-compiler.d.ts.map +1 -0
  37. package/dist/src/compiler/definition-compiler.js +257 -0
  38. package/dist/src/compiler/definition-compiler.js.map +1 -0
  39. package/dist/src/compiler/index.d.ts +3 -0
  40. package/dist/src/compiler/index.d.ts.map +1 -0
  41. package/dist/src/compiler/index.js +21 -0
  42. package/dist/src/compiler/index.js.map +1 -0
  43. package/dist/src/core/errors.d.ts +77 -0
  44. package/dist/src/core/errors.d.ts.map +1 -0
  45. package/dist/src/core/errors.js +170 -0
  46. package/dist/src/core/errors.js.map +1 -0
  47. package/dist/src/core/execution-context/index.d.ts +4 -0
  48. package/dist/src/core/execution-context/index.d.ts.map +1 -0
  49. package/dist/src/core/execution-context/index.js +22 -0
  50. package/dist/src/core/execution-context/index.js.map +1 -0
  51. package/dist/src/core/execution-context/json-value.d.ts +5 -0
  52. package/dist/src/core/execution-context/json-value.d.ts.map +1 -0
  53. package/dist/src/core/execution-context/json-value.js +6 -0
  54. package/dist/src/core/execution-context/json-value.js.map +1 -0
  55. package/dist/src/core/execution-context/serializer.d.ts +4 -0
  56. package/dist/src/core/execution-context/serializer.d.ts.map +1 -0
  57. package/dist/src/core/execution-context/serializer.js +34 -0
  58. package/dist/src/core/execution-context/serializer.js.map +1 -0
  59. package/dist/src/core/execution-context/validator.d.ts +18 -0
  60. package/dist/src/core/execution-context/validator.d.ts.map +1 -0
  61. package/dist/src/core/execution-context/validator.js +90 -0
  62. package/dist/src/core/execution-context/validator.js.map +1 -0
  63. package/dist/src/core/index.d.ts +8 -0
  64. package/dist/src/core/index.d.ts.map +1 -0
  65. package/dist/src/core/index.js +26 -0
  66. package/dist/src/core/index.js.map +1 -0
  67. package/dist/src/core/ir/decider-definition.d.ts +20 -0
  68. package/dist/src/core/ir/decider-definition.d.ts.map +1 -0
  69. package/dist/src/core/ir/decider-definition.js +6 -0
  70. package/dist/src/core/ir/decider-definition.js.map +1 -0
  71. package/dist/src/core/ir/index.d.ts +8 -0
  72. package/dist/src/core/ir/index.d.ts.map +1 -0
  73. package/dist/src/core/ir/index.js +26 -0
  74. package/dist/src/core/ir/index.js.map +1 -0
  75. package/dist/src/core/ir/job-definition.d.ts +15 -0
  76. package/dist/src/core/ir/job-definition.d.ts.map +1 -0
  77. package/dist/src/core/ir/job-definition.js +6 -0
  78. package/dist/src/core/ir/job-definition.js.map +1 -0
  79. package/dist/src/core/ir/listener-definition.d.ts +10 -0
  80. package/dist/src/core/ir/listener-definition.d.ts.map +1 -0
  81. package/dist/src/core/ir/listener-definition.js +6 -0
  82. package/dist/src/core/ir/listener-definition.js.map +1 -0
  83. package/dist/src/core/ir/policy-config.d.ts +24 -0
  84. package/dist/src/core/ir/policy-config.d.ts.map +1 -0
  85. package/dist/src/core/ir/policy-config.js +6 -0
  86. package/dist/src/core/ir/policy-config.js.map +1 -0
  87. package/dist/src/core/ir/refs.d.ts +42 -0
  88. package/dist/src/core/ir/refs.d.ts.map +1 -0
  89. package/dist/src/core/ir/refs.js +18 -0
  90. package/dist/src/core/ir/refs.js.map +1 -0
  91. package/dist/src/core/ir/step-definition.d.ts +59 -0
  92. package/dist/src/core/ir/step-definition.d.ts.map +1 -0
  93. package/dist/src/core/ir/step-definition.js +6 -0
  94. package/dist/src/core/ir/step-definition.js.map +1 -0
  95. package/dist/src/core/ir/transition-definition.d.ts +8 -0
  96. package/dist/src/core/ir/transition-definition.d.ts.map +1 -0
  97. package/dist/src/core/ir/transition-definition.js +6 -0
  98. package/dist/src/core/ir/transition-definition.js.map +1 -0
  99. package/dist/src/core/item/index.d.ts +2 -0
  100. package/dist/src/core/item/index.d.ts.map +1 -0
  101. package/dist/src/core/item/index.js +20 -0
  102. package/dist/src/core/item/index.js.map +1 -0
  103. package/dist/src/core/item/interfaces.d.ts +64 -0
  104. package/dist/src/core/item/interfaces.d.ts.map +1 -0
  105. package/dist/src/core/item/interfaces.js +6 -0
  106. package/dist/src/core/item/interfaces.js.map +1 -0
  107. package/dist/src/core/repository/index.d.ts +3 -0
  108. package/dist/src/core/repository/index.d.ts.map +1 -0
  109. package/dist/src/core/repository/index.js +21 -0
  110. package/dist/src/core/repository/index.js.map +1 -0
  111. package/dist/src/core/repository/job-repository.d.ts +60 -0
  112. package/dist/src/core/repository/job-repository.d.ts.map +1 -0
  113. package/dist/src/core/repository/job-repository.js +27 -0
  114. package/dist/src/core/repository/job-repository.js.map +1 -0
  115. package/dist/src/core/repository/types.d.ts +84 -0
  116. package/dist/src/core/repository/types.d.ts.map +1 -0
  117. package/dist/src/core/repository/types.js +6 -0
  118. package/dist/src/core/repository/types.js.map +1 -0
  119. package/dist/src/core/status.d.ts +29 -0
  120. package/dist/src/core/status.d.ts.map +1 -0
  121. package/dist/src/core/status.js +58 -0
  122. package/dist/src/core/status.js.map +1 -0
  123. package/dist/src/core/transaction/index.d.ts +2 -0
  124. package/dist/src/core/transaction/index.d.ts.map +1 -0
  125. package/dist/src/core/transaction/index.js +20 -0
  126. package/dist/src/core/transaction/index.js.map +1 -0
  127. package/dist/src/core/transaction/transaction-manager.d.ts +8 -0
  128. package/dist/src/core/transaction/transaction-manager.d.ts.map +1 -0
  129. package/dist/src/core/transaction/transaction-manager.js +14 -0
  130. package/dist/src/core/transaction/transaction-manager.js.map +1 -0
  131. package/dist/src/core/validation/definition-validator.d.ts +46 -0
  132. package/dist/src/core/validation/definition-validator.d.ts.map +1 -0
  133. package/dist/src/core/validation/definition-validator.js +177 -0
  134. package/dist/src/core/validation/definition-validator.js.map +1 -0
  135. package/dist/src/core/validation/index.d.ts +2 -0
  136. package/dist/src/core/validation/index.d.ts.map +1 -0
  137. package/dist/src/core/validation/index.js +20 -0
  138. package/dist/src/core/validation/index.js.map +1 -0
  139. package/dist/src/decorators/constants.d.ts +10 -0
  140. package/dist/src/decorators/constants.d.ts.map +1 -0
  141. package/dist/src/decorators/constants.js +50 -0
  142. package/dist/src/decorators/constants.js.map +1 -0
  143. package/dist/src/decorators/flow.decorator.d.ts +25 -0
  144. package/dist/src/decorators/flow.decorator.d.ts.map +1 -0
  145. package/dist/src/decorators/flow.decorator.js +19 -0
  146. package/dist/src/decorators/flow.decorator.js.map +1 -0
  147. package/dist/src/decorators/index.d.ts +8 -0
  148. package/dist/src/decorators/index.d.ts.map +1 -0
  149. package/dist/src/decorators/index.js +26 -0
  150. package/dist/src/decorators/index.js.map +1 -0
  151. package/dist/src/decorators/item.decorators.d.ts +32 -0
  152. package/dist/src/decorators/item.decorators.d.ts.map +1 -0
  153. package/dist/src/decorators/item.decorators.js +40 -0
  154. package/dist/src/decorators/item.decorators.js.map +1 -0
  155. package/dist/src/decorators/job.decorator.d.ts +11 -0
  156. package/dist/src/decorators/job.decorator.d.ts.map +1 -0
  157. package/dist/src/decorators/job.decorator.js +17 -0
  158. package/dist/src/decorators/job.decorator.js.map +1 -0
  159. package/dist/src/decorators/listener.decorators.d.ts +56 -0
  160. package/dist/src/decorators/listener.decorators.d.ts.map +1 -0
  161. package/dist/src/decorators/listener.decorators.js +157 -0
  162. package/dist/src/decorators/listener.decorators.js.map +1 -0
  163. package/dist/src/decorators/step.decorator.d.ts +25 -0
  164. package/dist/src/decorators/step.decorator.d.ts.map +1 -0
  165. package/dist/src/decorators/step.decorator.js +21 -0
  166. package/dist/src/decorators/step.decorator.js.map +1 -0
  167. package/dist/src/decorators/tasklet.decorator.d.ts +7 -0
  168. package/dist/src/decorators/tasklet.decorator.d.ts.map +1 -0
  169. package/dist/src/decorators/tasklet.decorator.js +21 -0
  170. package/dist/src/decorators/tasklet.decorator.js.map +1 -0
  171. package/dist/src/execution/batch-worker-runner.d.ts +27 -0
  172. package/dist/src/execution/batch-worker-runner.d.ts.map +1 -0
  173. package/dist/src/execution/batch-worker-runner.js +147 -0
  174. package/dist/src/execution/batch-worker-runner.js.map +1 -0
  175. package/dist/src/execution/chunk-step-executor.d.ts +86 -0
  176. package/dist/src/execution/chunk-step-executor.d.ts.map +1 -0
  177. package/dist/src/execution/chunk-step-executor.js +482 -0
  178. package/dist/src/execution/chunk-step-executor.js.map +1 -0
  179. package/dist/src/execution/execution-strategy.d.ts +110 -0
  180. package/dist/src/execution/execution-strategy.d.ts.map +1 -0
  181. package/dist/src/execution/execution-strategy.js +13 -0
  182. package/dist/src/execution/execution-strategy.js.map +1 -0
  183. package/dist/src/execution/external-task-execution-strategy.d.ts +36 -0
  184. package/dist/src/execution/external-task-execution-strategy.d.ts.map +1 -0
  185. package/dist/src/execution/external-task-execution-strategy.js +97 -0
  186. package/dist/src/execution/external-task-execution-strategy.js.map +1 -0
  187. package/dist/src/execution/in-process-execution-strategy.d.ts +129 -0
  188. package/dist/src/execution/in-process-execution-strategy.d.ts.map +1 -0
  189. package/dist/src/execution/in-process-execution-strategy.js +141 -0
  190. package/dist/src/execution/in-process-execution-strategy.js.map +1 -0
  191. package/dist/src/execution/index.d.ts +14 -0
  192. package/dist/src/execution/index.d.ts.map +1 -0
  193. package/dist/src/execution/index.js +32 -0
  194. package/dist/src/execution/index.js.map +1 -0
  195. package/dist/src/execution/job-executor.d.ts +145 -0
  196. package/dist/src/execution/job-executor.d.ts.map +1 -0
  197. package/dist/src/execution/job-executor.js +475 -0
  198. package/dist/src/execution/job-executor.js.map +1 -0
  199. package/dist/src/execution/job-explorer.d.ts +15 -0
  200. package/dist/src/execution/job-explorer.d.ts.map +1 -0
  201. package/dist/src/execution/job-explorer.js +84 -0
  202. package/dist/src/execution/job-explorer.js.map +1 -0
  203. package/dist/src/execution/job-key.d.ts +3 -0
  204. package/dist/src/execution/job-key.d.ts.map +1 -0
  205. package/dist/src/execution/job-key.js +43 -0
  206. package/dist/src/execution/job-key.js.map +1 -0
  207. package/dist/src/execution/job-launcher.d.ts +75 -0
  208. package/dist/src/execution/job-launcher.d.ts.map +1 -0
  209. package/dist/src/execution/job-launcher.js +112 -0
  210. package/dist/src/execution/job-launcher.js.map +1 -0
  211. package/dist/src/execution/job-operator.d.ts +22 -0
  212. package/dist/src/execution/job-operator.d.ts.map +1 -0
  213. package/dist/src/execution/job-operator.js +125 -0
  214. package/dist/src/execution/job-operator.js.map +1 -0
  215. package/dist/src/execution/listener-invoker.d.ts +164 -0
  216. package/dist/src/execution/listener-invoker.d.ts.map +1 -0
  217. package/dist/src/execution/listener-invoker.js +246 -0
  218. package/dist/src/execution/listener-invoker.js.map +1 -0
  219. package/dist/src/execution/ref-resolver.d.ts +40 -0
  220. package/dist/src/execution/ref-resolver.d.ts.map +1 -0
  221. package/dist/src/execution/ref-resolver.js +41 -0
  222. package/dist/src/execution/ref-resolver.js.map +1 -0
  223. package/dist/src/execution/tasklet-step-executor.d.ts +79 -0
  224. package/dist/src/execution/tasklet-step-executor.d.ts.map +1 -0
  225. package/dist/src/execution/tasklet-step-executor.js +138 -0
  226. package/dist/src/execution/tasklet-step-executor.js.map +1 -0
  227. package/dist/src/explorer/batch-explorer.d.ts +138 -0
  228. package/dist/src/explorer/batch-explorer.d.ts.map +1 -0
  229. package/dist/src/explorer/batch-explorer.js +167 -0
  230. package/dist/src/explorer/batch-explorer.js.map +1 -0
  231. package/dist/src/explorer/index.d.ts +2 -0
  232. package/dist/src/explorer/index.d.ts.map +1 -0
  233. package/dist/src/explorer/index.js +20 -0
  234. package/dist/src/explorer/index.js.map +1 -0
  235. package/dist/src/flow/flow-evaluator.d.ts +30 -0
  236. package/dist/src/flow/flow-evaluator.d.ts.map +1 -0
  237. package/dist/src/flow/flow-evaluator.js +80 -0
  238. package/dist/src/flow/flow-evaluator.js.map +1 -0
  239. package/dist/src/flow/index.d.ts +2 -0
  240. package/dist/src/flow/index.d.ts.map +1 -0
  241. package/dist/src/flow/index.js +20 -0
  242. package/dist/src/flow/index.js.map +1 -0
  243. package/dist/src/index.d.ts +18 -0
  244. package/dist/src/index.d.ts.map +1 -0
  245. package/dist/src/index.js +90 -0
  246. package/dist/src/index.js.map +1 -0
  247. package/dist/src/io/checkpoint.d.ts +7 -0
  248. package/dist/src/io/checkpoint.d.ts.map +1 -0
  249. package/dist/src/io/checkpoint.js +56 -0
  250. package/dist/src/io/checkpoint.js.map +1 -0
  251. package/dist/src/io/database.d.ts +50 -0
  252. package/dist/src/io/database.d.ts.map +1 -0
  253. package/dist/src/io/database.js +108 -0
  254. package/dist/src/io/database.js.map +1 -0
  255. package/dist/src/io/file-readers.d.ts +54 -0
  256. package/dist/src/io/file-readers.d.ts.map +1 -0
  257. package/dist/src/io/file-readers.js +167 -0
  258. package/dist/src/io/file-readers.js.map +1 -0
  259. package/dist/src/io/file-writers.d.ts +31 -0
  260. package/dist/src/io/file-writers.d.ts.map +1 -0
  261. package/dist/src/io/file-writers.js +80 -0
  262. package/dist/src/io/file-writers.js.map +1 -0
  263. package/dist/src/io/index.d.ts +6 -0
  264. package/dist/src/io/index.d.ts.map +1 -0
  265. package/dist/src/io/index.js +24 -0
  266. package/dist/src/io/index.js.map +1 -0
  267. package/dist/src/io/s3.d.ts +50 -0
  268. package/dist/src/io/s3.d.ts.map +1 -0
  269. package/dist/src/io/s3.js +96 -0
  270. package/dist/src/io/s3.js.map +1 -0
  271. package/dist/src/listeners/builtin-listeners.d.ts +77 -0
  272. package/dist/src/listeners/builtin-listeners.d.ts.map +1 -0
  273. package/dist/src/listeners/builtin-listeners.js +108 -0
  274. package/dist/src/listeners/builtin-listeners.js.map +1 -0
  275. package/dist/src/listeners/index.d.ts +8 -0
  276. package/dist/src/listeners/index.d.ts.map +1 -0
  277. package/dist/src/listeners/index.js +25 -0
  278. package/dist/src/listeners/index.js.map +1 -0
  279. package/dist/src/module/adapter-options.d.ts +39 -0
  280. package/dist/src/module/adapter-options.d.ts.map +1 -0
  281. package/dist/src/module/adapter-options.js +34 -0
  282. package/dist/src/module/adapter-options.js.map +1 -0
  283. package/dist/src/module/adapter.d.ts +157 -0
  284. package/dist/src/module/adapter.d.ts.map +1 -0
  285. package/dist/src/module/adapter.js +80 -0
  286. package/dist/src/module/adapter.js.map +1 -0
  287. package/dist/src/module/batch-schedule-registry.d.ts +110 -0
  288. package/dist/src/module/batch-schedule-registry.d.ts.map +1 -0
  289. package/dist/src/module/batch-schedule-registry.js +0 -0
  290. package/dist/src/module/batch-schedule-registry.js.map +1 -0
  291. package/dist/src/module/index.d.ts +14 -0
  292. package/dist/src/module/index.d.ts.map +1 -0
  293. package/dist/src/module/index.js +31 -0
  294. package/dist/src/module/index.js.map +1 -0
  295. package/dist/src/module/nest-batch.module.d.ts +236 -0
  296. package/dist/src/module/nest-batch.module.d.ts.map +1 -0
  297. package/dist/src/module/nest-batch.module.js +475 -0
  298. package/dist/src/module/nest-batch.module.js.map +1 -0
  299. package/dist/src/module/tokens.d.ts +83 -0
  300. package/dist/src/module/tokens.d.ts.map +1 -0
  301. package/dist/src/module/tokens.js +58 -0
  302. package/dist/src/module/tokens.js.map +1 -0
  303. package/dist/src/observability/event-types.d.ts +55 -0
  304. package/dist/src/observability/event-types.d.ts.map +1 -0
  305. package/dist/src/observability/event-types.js +36 -0
  306. package/dist/src/observability/event-types.js.map +1 -0
  307. package/dist/src/observability/exporters.d.ts +35 -0
  308. package/dist/src/observability/exporters.d.ts.map +1 -0
  309. package/dist/src/observability/exporters.js +93 -0
  310. package/dist/src/observability/exporters.js.map +1 -0
  311. package/dist/src/observability/index.d.ts +3 -0
  312. package/dist/src/observability/index.d.ts.map +1 -0
  313. package/dist/src/observability/index.js +21 -0
  314. package/dist/src/observability/index.js.map +1 -0
  315. package/dist/src/partition-helpers.d.ts +127 -0
  316. package/dist/src/partition-helpers.d.ts.map +1 -0
  317. package/dist/src/partition-helpers.js +136 -0
  318. package/dist/src/partition-helpers.js.map +1 -0
  319. package/dist/src/policies/backoff.d.ts +3 -0
  320. package/dist/src/policies/backoff.d.ts.map +1 -0
  321. package/dist/src/policies/backoff.js +34 -0
  322. package/dist/src/policies/backoff.js.map +1 -0
  323. package/dist/src/policies/index.d.ts +4 -0
  324. package/dist/src/policies/index.d.ts.map +1 -0
  325. package/dist/src/policies/index.js +22 -0
  326. package/dist/src/policies/index.js.map +1 -0
  327. package/dist/src/policies/retry-policy.d.ts +13 -0
  328. package/dist/src/policies/retry-policy.d.ts.map +1 -0
  329. package/dist/src/policies/retry-policy.js +55 -0
  330. package/dist/src/policies/retry-policy.js.map +1 -0
  331. package/dist/src/policies/skip-policy.d.ts +12 -0
  332. package/dist/src/policies/skip-policy.d.ts.map +1 -0
  333. package/dist/src/policies/skip-policy.js +44 -0
  334. package/dist/src/policies/skip-policy.js.map +1 -0
  335. package/dist/src/registry/index.d.ts +2 -0
  336. package/dist/src/registry/index.d.ts.map +1 -0
  337. package/dist/src/registry/index.js +20 -0
  338. package/dist/src/registry/index.js.map +1 -0
  339. package/dist/src/registry/job-registry.d.ts +16 -0
  340. package/dist/src/registry/job-registry.d.ts.map +1 -0
  341. package/dist/src/registry/job-registry.js +50 -0
  342. package/dist/src/registry/job-registry.js.map +1 -0
  343. package/dist/src/repository/id-generator.d.ts +18 -0
  344. package/dist/src/repository/id-generator.d.ts.map +1 -0
  345. package/dist/src/repository/id-generator.js +37 -0
  346. package/dist/src/repository/id-generator.js.map +1 -0
  347. package/dist/src/repository/in-memory/in-memory-job-repository.d.ts +49 -0
  348. package/dist/src/repository/in-memory/in-memory-job-repository.d.ts.map +1 -0
  349. package/dist/src/repository/in-memory/in-memory-job-repository.js +291 -0
  350. package/dist/src/repository/in-memory/in-memory-job-repository.js.map +1 -0
  351. package/dist/src/repository/in-memory/index.d.ts +2 -0
  352. package/dist/src/repository/in-memory/index.d.ts.map +1 -0
  353. package/dist/src/repository/in-memory/index.js +20 -0
  354. package/dist/src/repository/in-memory/index.js.map +1 -0
  355. package/dist/src/repository/index.d.ts +4 -0
  356. package/dist/src/repository/index.d.ts.map +1 -0
  357. package/dist/src/repository/index.js +22 -0
  358. package/dist/src/repository/index.js.map +1 -0
  359. package/dist/src/repository/uuid-v7.d.ts +20 -0
  360. package/dist/src/repository/uuid-v7.d.ts.map +1 -0
  361. package/dist/src/repository/uuid-v7.js +31 -0
  362. package/dist/src/repository/uuid-v7.js.map +1 -0
  363. package/dist/src/scheduling/batch-scheduled.d.ts +87 -0
  364. package/dist/src/scheduling/batch-scheduled.d.ts.map +1 -0
  365. package/dist/src/scheduling/batch-scheduled.js +170 -0
  366. package/dist/src/scheduling/batch-scheduled.js.map +1 -0
  367. package/dist/src/transaction/in-memory-transaction-manager.d.ts +16 -0
  368. package/dist/src/transaction/in-memory-transaction-manager.d.ts.map +1 -0
  369. package/dist/src/transaction/in-memory-transaction-manager.js +33 -0
  370. package/dist/src/transaction/in-memory-transaction-manager.js.map +1 -0
  371. package/dist/src/transaction/index.d.ts +2 -0
  372. package/dist/src/transaction/index.d.ts.map +1 -0
  373. package/dist/src/transaction/index.js +20 -0
  374. package/dist/src/transaction/index.js.map +1 -0
  375. package/dist/tests/contracts/index.d.ts +26 -0
  376. package/dist/tests/contracts/index.d.ts.map +1 -0
  377. package/dist/tests/contracts/index.js +37 -0
  378. package/dist/tests/contracts/index.js.map +1 -0
  379. package/dist/tests/contracts/job-repository.contract.d.ts +46 -0
  380. package/dist/tests/contracts/job-repository.contract.d.ts.map +1 -0
  381. package/dist/tests/contracts/job-repository.contract.js +644 -0
  382. package/dist/tests/contracts/job-repository.contract.js.map +1 -0
  383. package/package.json +80 -0
  384. package/src/adapters/in-process.adapter.ts +182 -0
  385. package/src/adapters/index.ts +17 -0
  386. package/src/builder/batch-builder.ts +32 -0
  387. package/src/builder/flow-builder.ts +141 -0
  388. package/src/builder/index.ts +4 -0
  389. package/src/builder/job-builder.ts +206 -0
  390. package/src/builder/step-builder.ts +190 -0
  391. package/src/compiler/builder-types.ts +27 -0
  392. package/src/compiler/definition-compiler.ts +325 -0
  393. package/src/compiler/index.ts +2 -0
  394. package/src/core/errors.ts +125 -0
  395. package/src/core/execution-context/index.ts +3 -0
  396. package/src/core/execution-context/json-value.ts +3 -0
  397. package/src/core/execution-context/serializer.ts +21 -0
  398. package/src/core/execution-context/validator.ts +103 -0
  399. package/src/core/index.ts +7 -0
  400. package/src/core/ir/decider-definition.ts +25 -0
  401. package/src/core/ir/index.ts +7 -0
  402. package/src/core/ir/job-definition.ts +15 -0
  403. package/src/core/ir/listener-definition.ts +19 -0
  404. package/src/core/ir/policy-config.ts +19 -0
  405. package/src/core/ir/refs.ts +42 -0
  406. package/src/core/ir/step-definition.ts +62 -0
  407. package/src/core/ir/transition-definition.ts +9 -0
  408. package/src/core/item/index.ts +1 -0
  409. package/src/core/item/interfaces.ts +70 -0
  410. package/src/core/repository/index.ts +2 -0
  411. package/src/core/repository/job-repository.ts +100 -0
  412. package/src/core/repository/types.ts +91 -0
  413. package/src/core/status.ts +31 -0
  414. package/src/core/transaction/index.ts +1 -0
  415. package/src/core/transaction/transaction-manager.ts +8 -0
  416. package/src/core/validation/definition-validator.ts +215 -0
  417. package/src/core/validation/index.ts +1 -0
  418. package/src/decorators/constants.ts +9 -0
  419. package/src/decorators/flow.decorator.ts +31 -0
  420. package/src/decorators/index.ts +7 -0
  421. package/src/decorators/item.decorators.ts +51 -0
  422. package/src/decorators/job.decorator.ts +16 -0
  423. package/src/decorators/listener.decorators.ts +142 -0
  424. package/src/decorators/step.decorator.ts +33 -0
  425. package/src/decorators/tasklet.decorator.ts +14 -0
  426. package/src/execution/batch-worker-runner.ts +142 -0
  427. package/src/execution/chunk-step-executor.ts +594 -0
  428. package/src/execution/execution-strategy.ts +115 -0
  429. package/src/execution/external-task-execution-strategy.ts +104 -0
  430. package/src/execution/in-process-execution-strategy.ts +207 -0
  431. package/src/execution/index.ts +13 -0
  432. package/src/execution/job-executor.ts +553 -0
  433. package/src/execution/job-explorer.ts +73 -0
  434. package/src/execution/job-key.ts +35 -0
  435. package/src/execution/job-launcher.ts +132 -0
  436. package/src/execution/job-operator.ts +127 -0
  437. package/src/execution/listener-invoker.ts +389 -0
  438. package/src/execution/ref-resolver.ts +64 -0
  439. package/src/execution/tasklet-step-executor.ts +182 -0
  440. package/src/explorer/batch-explorer.ts +251 -0
  441. package/src/explorer/index.ts +1 -0
  442. package/src/flow/flow-evaluator.ts +89 -0
  443. package/src/flow/index.ts +1 -0
  444. package/src/index.ts +24 -0
  445. package/src/io/checkpoint.ts +47 -0
  446. package/src/io/database.ts +114 -0
  447. package/src/io/file-readers.ts +191 -0
  448. package/src/io/file-writers.ts +99 -0
  449. package/src/io/index.ts +5 -0
  450. package/src/io/s3.ts +117 -0
  451. package/src/listeners/builtin-listeners.ts +151 -0
  452. package/src/listeners/index.ts +7 -0
  453. package/src/module/adapter-options.ts +38 -0
  454. package/src/module/adapter.ts +160 -0
  455. package/src/module/batch-schedule-registry.ts +0 -0
  456. package/src/module/index.ts +13 -0
  457. package/src/module/nest-batch.module.ts +674 -0
  458. package/src/module/tokens.ts +95 -0
  459. package/src/observability/event-types.ts +61 -0
  460. package/src/observability/exporters.ts +96 -0
  461. package/src/observability/index.ts +2 -0
  462. package/src/partition-helpers.ts +204 -0
  463. package/src/policies/backoff.ts +22 -0
  464. package/src/policies/index.ts +3 -0
  465. package/src/policies/retry-policy.ts +57 -0
  466. package/src/policies/skip-policy.ts +51 -0
  467. package/src/registry/index.ts +1 -0
  468. package/src/registry/job-registry.ts +42 -0
  469. package/src/repository/id-generator.ts +25 -0
  470. package/src/repository/in-memory/in-memory-job-repository.ts +334 -0
  471. package/src/repository/in-memory/index.ts +1 -0
  472. package/src/repository/index.ts +3 -0
  473. package/src/repository/uuid-v7.ts +40 -0
  474. package/src/scheduling/batch-scheduled.ts +257 -0
  475. package/src/transaction/in-memory-transaction-manager.ts +23 -0
  476. package/src/transaction/index.ts +1 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Provider-token ref resolver — shared helper used by both the chunk and
3
+ * tasklet step executors to resolve a `RefKind.ProviderToken` ref against
4
+ * a `Map<string, unknown>` of pre-resolved provider instances.
5
+ *
6
+ * The caller (typically the JobExecutor) builds the map by walking the
7
+ * `JobDefinition` and looking each ref's `token` up in the Nest DI
8
+ * container (`ModuleRef.get(token, { strict: false })`). The executors
9
+ * themselves never touch the container — they only consult this map.
10
+ *
11
+ * The error message format is centralized here so every role
12
+ * (`reader` / `processor` / `writer` / `tasklet` / `listener`) reports
13
+ * missing tokens identically. The tests assert on
14
+ * `exitMessage.includes(missingTokenId)`.
15
+ */
16
+
17
+ /** Role label used to disambiguate error messages from the chunk/tasklet
18
+ * resolvers. Lowercase to match the surrounding executor code style. */
19
+ export type ProviderTokenRole = 'reader' | 'processor' | 'writer' | 'tasklet' | 'listener';
20
+
21
+ /** A provider instance bound to a string token. The runtime shape is
22
+ * determined by the role (e.g. `ItemReader` for `reader`), but the map
23
+ * itself is intentionally `unknown` so the resolver can serve every
24
+ * role from a single helper. */
25
+ export type ProviderResolvers = Map<string, unknown>;
26
+
27
+ /**
28
+ * Resolve a `RefKind.ProviderToken` ref to the bound provider instance.
29
+ *
30
+ * Throws a deterministic `Error` whose message contains BOTH the
31
+ * missing token id and the role label when the token is not bound.
32
+ * The chunk/tasklet executors' outer `try/catch` propagates this
33
+ * message into the `exitMessage` of the FAILED result.
34
+ *
35
+ * @param role The semantic role of the ref (used only in error messages).
36
+ * @param ref The `RefKind.ProviderToken` ref (must have a `token` field).
37
+ * @param map The provider-resolver map built by the caller.
38
+ * @returns The bound instance, narrowed to `T` at the call site.
39
+ */
40
+ export function resolveProviderToken<T>(
41
+ role: ProviderTokenRole,
42
+ ref: { token?: string },
43
+ map: ProviderResolvers | undefined,
44
+ ): T {
45
+ const token = ref.token;
46
+ if (!token) {
47
+ throw new Error(
48
+ `Missing token on ${role} ref: RefKind.ProviderToken requires a non-empty \`token\` field`,
49
+ );
50
+ }
51
+ if (!map) {
52
+ throw new Error(
53
+ `No provider resolvers available for ${role} ref (token=${token}); ` +
54
+ `the executor context did not receive a \`providerResolvers\` map`,
55
+ );
56
+ }
57
+ const instance = map.get(token);
58
+ if (instance === undefined) {
59
+ throw new Error(
60
+ `Provider for ${role} token "${token}" was not found in the provider resolvers map`,
61
+ );
62
+ }
63
+ return instance as T;
64
+ }
@@ -0,0 +1,182 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import type { TaskletStepDefinition, ListenerDefinition } from '../core/ir';
3
+ import { RefKind } from '../core/ir';
4
+ import type { Tasklet, TaskletContext } from '../core/item';
5
+ import type {
6
+ JobRepository,
7
+ ExecutionContext,
8
+ StepExecution,
9
+ ExecutionScope,
10
+ } from '../core/repository';
11
+ import type { TransactionManager } from '../core/transaction';
12
+ import { StepStatus, JobStatus } from '../core/status';
13
+ import { ListenerInvoker, type ListenerResolver } from './listener-invoker';
14
+ import { resolveProviderToken, type ProviderResolvers } from './ref-resolver';
15
+
16
+ /**
17
+ * Bundled dependencies + state for a single `TaskletStepExecutor.execute()` call.
18
+ * The caller (JobExecutor, Task 20) owns lifecycle and persistence.
19
+ */
20
+ export interface TaskletExecutionContext {
21
+ jobExecutionId: string;
22
+ jobRepository: JobRepository;
23
+ transactionManager: TransactionManager;
24
+ listenerInvoker: ListenerInvoker;
25
+ /** Map from ListenerRef key (`phase:name`) to actual function. */
26
+ listenerResolvers: Map<string, ListenerResolver>;
27
+ /** Optional map of provider-token id → already-resolved provider instance
28
+ * for `RefKind.ProviderToken` tasklet refs. */
29
+ providerResolvers?: ProviderResolvers;
30
+ }
31
+
32
+ /**
33
+ * Result of a single tasklet step. Mirrors the subset of `StepExecutionPatch`
34
+ * that the executor can fill in BEFORE the JobExecutor persists it.
35
+ *
36
+ * - `status` — `COMPLETED` if the tasklet returned, `FAILED` if it threw
37
+ * - `exitCode` — short string label (`COMPLETED` / `FAILED`)
38
+ * - `exitMessage` — tasklet's return value (on success) or error message (on failure)
39
+ * - `readCount`/`writeCount`/`skipCount` — always 0 for tasklets (no chunk loop)
40
+ */
41
+ export interface StepExecutionResult {
42
+ status: StepStatus;
43
+ exitCode: string;
44
+ exitMessage: string;
45
+ readCount: number;
46
+ writeCount: number;
47
+ skipCount: number;
48
+ }
49
+
50
+ /**
51
+ * TaskletStepExecutor — runs a single tasklet step.
52
+ *
53
+ * Orchestration contract (in order):
54
+ * 1. `before-step:*` listeners (always run; failures bubble up)
55
+ * 2. `transactionManager.withTransaction(tasklet.execute, ctx)`
56
+ * 3a. On success → result `{ status: COMPLETED, exitCode: 'COMPLETED', exitMessage: <return> }`
57
+ * 3b. On error → `on-step-error:*` listeners → result `{ status: FAILED, exitCode: 'FAILED', exitMessage: <err> }`
58
+ * 4. `after-step:*` listeners (always run, receives the result)
59
+ *
60
+ * Persistence of the StepExecution is the caller's responsibility —
61
+ * this executor returns a `StepExecutionResult` and the JobExecutor (Task 20)
62
+ * applies it via `jobRepository.updateStepExecution()`.
63
+ *
64
+ * Read/write counts are always 0 for tasklets; the chunk executor (Task 18)
65
+ * produces non-zero counts.
66
+ */
67
+ @Injectable()
68
+ export class TaskletStepExecutor {
69
+ /**
70
+ * Execute a tasklet step. Returns the step execution result.
71
+ * The caller (JobExecutor, Task 20) handles persistence of the StepExecution.
72
+ */
73
+ async execute(
74
+ step: TaskletStepDefinition,
75
+ context: TaskletExecutionContext,
76
+ ): Promise<StepExecutionResult> {
77
+ // Build the TaskletContext the tasklet will see.
78
+ //
79
+ // `stepExecutionId` is a placeholder here — the JobExecutor knows the real
80
+ // ID (it created the StepExecution) and will patch this object before the
81
+ // tasklet uses it. The placeholder keeps the contract explicit.
82
+ //
83
+ // `getExecutionContext` / `saveExecutionContext` are also stubbed here;
84
+ // they become real once the JobExecutor wires the stepExecutionId in.
85
+ // (For Wave 3 tests we do not exercise these methods.)
86
+ const taskletCtx: TaskletContext = {
87
+ jobExecutionId: context.jobExecutionId,
88
+ stepExecutionId: '<pending>',
89
+ getExecutionContext: async () => ({ data: null, version: 0 }),
90
+ saveExecutionContext: async (_ctx: ExecutionContext) => {
91
+ // wired by JobExecutor (Task 20) once stepExecutionId is known
92
+ },
93
+ };
94
+
95
+ // 1. before-step listeners
96
+ await context.listenerInvoker.invokeBeforeStep(context.listenerResolvers, {
97
+ jobExecutionId: context.jobExecutionId,
98
+ stepExecutionId: taskletCtx.stepExecutionId,
99
+ });
100
+
101
+ let result: StepExecutionResult;
102
+ try {
103
+ // 2. withTransaction wrap
104
+ const taskletInstance = this.resolveTasklet(step.tasklet, context);
105
+ const txResult = await context.transactionManager.withTransaction(async (_txCtx) => {
106
+ return taskletInstance.execute(taskletCtx);
107
+ });
108
+ result = {
109
+ status: StepStatus.COMPLETED,
110
+ exitCode: 'COMPLETED',
111
+ exitMessage: txResult === undefined ? '' : String(txResult),
112
+ readCount: 0,
113
+ writeCount: 0,
114
+ skipCount: 0,
115
+ };
116
+ } catch (err) {
117
+ // 3. on-step-error listeners (best-effort: rethrow their failures too)
118
+ await context.listenerInvoker.invokeOnErrorStep(
119
+ context.listenerResolvers,
120
+ { jobExecutionId: context.jobExecutionId, stepExecutionId: taskletCtx.stepExecutionId },
121
+ err,
122
+ );
123
+ result = {
124
+ status: StepStatus.FAILED,
125
+ exitCode: 'FAILED',
126
+ exitMessage: err instanceof Error ? err.message : String(err),
127
+ readCount: 0,
128
+ writeCount: 0,
129
+ skipCount: 0,
130
+ };
131
+ }
132
+
133
+ // 4. after-step listeners (always run, even on failure).
134
+ // Pass the LIVE `result` (not a snapshot) so an `after-step`
135
+ // listener can mutate `result.status` and steer the flow into a
136
+ // different branch — transition evaluation runs AFTER this call.
137
+ await context.listenerInvoker.invokeAfterStep(
138
+ context.listenerResolvers,
139
+ { jobExecutionId: context.jobExecutionId, stepExecutionId: taskletCtx.stepExecutionId },
140
+ result,
141
+ );
142
+
143
+ return result;
144
+ }
145
+
146
+ /**
147
+ * Resolve a `TaskletRef` to a `Tasklet` instance.
148
+ *
149
+ * Supported kinds:
150
+ * - `builder-lambda` — `taskletRef.fn` is the bound tasklet function.
151
+ * - `provider-token` — looked up in `context.providerResolvers` against
152
+ * `taskletRef.token`. The bound instance must
153
+ * expose an `execute(ctx)` method.
154
+ *
155
+ * Method refs are pre-resolved by the caller and wrapped in a
156
+ * `builder-lambda` ref before reaching this executor.
157
+ */
158
+ private resolveTasklet(
159
+ taskletRef: { kind: string; token?: string; fn?: ListenerResolver; classToken?: string; methodName?: string },
160
+ context: TaskletExecutionContext,
161
+ ): Tasklet {
162
+ if (taskletRef.kind === RefKind.BuilderLambda && taskletRef.fn) {
163
+ const result = taskletRef.fn();
164
+ if (typeof result === 'function') {
165
+ return { execute: result as Tasklet['execute'] };
166
+ }
167
+ if (result !== null && typeof result === 'object' && typeof (result as Tasklet).execute === 'function') {
168
+ return result as Tasklet;
169
+ }
170
+ return { execute: taskletRef.fn as Tasklet['execute'] };
171
+ }
172
+ if (taskletRef.kind === RefKind.ProviderToken) {
173
+ return resolveProviderToken<Tasklet>('tasklet', taskletRef, context.providerResolvers);
174
+ }
175
+ throw new Error(`Tasklet resolution not supported for ref kind: ${taskletRef.kind}`);
176
+ }
177
+ }
178
+
179
+ // Re-exports for convenience — callers may import types from the executor module.
180
+ export type { Tasklet, TaskletContext } from '../core/item';
181
+ export type { StepExecution, ExecutionScope };
182
+ export { StepStatus, JobStatus };
@@ -0,0 +1,251 @@
1
+ import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
2
+ import { DiscoveryService } from '@nestjs/core';
3
+ import type { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
4
+ import 'reflect-metadata';
5
+ import {
6
+ BATCH_JOB_METADATA,
7
+ BATCH_STEP_METADATA,
8
+ BATCH_TASKLET_METADATA,
9
+ BATCH_LISTENER_METADATA,
10
+ BATCH_TRANSITION_METADATA,
11
+ } from '../decorators/constants';
12
+ import type { JobableOptions, StepableOptions } from '../decorators';
13
+ import type { ListenerKind, ListenerPhase } from '../core/ir/listener-definition';
14
+
15
+ /**
16
+ * Raw shape of a discovered batch job, as it appears immediately after the
17
+ * explorer walks the Nest provider tree. The {@link DiscoveredJob} contains
18
+ * only metadata + class reference + (optionally) the resolved DI instance.
19
+ *
20
+ * It is intentionally NOT a `JobDefinition` yet — the {@link DefinitionCompiler}
21
+ * (Task 8) is responsible for resolving the prototype methods into concrete
22
+ * `ListenerRef` / `TaskletRef` / `ReaderRef` / `ProcessorRef` / `WriterRef` /
23
+ * `TransitionRef` records and for choosing a start step.
24
+ */
25
+ export interface DiscoveredJob {
26
+ /** The @Jobable-decorated class reference. */
27
+ classRef: Function;
28
+ /** The Nest-resolved DI instance, when available. May be `undefined` for
29
+ * factories or providers that have not been instantiated yet. */
30
+ instance?: unknown;
31
+ /** Raw options passed to `@Jobable(...)`. */
32
+ jobOptions: JobableOptions;
33
+ /** Every `@Stepable` method on the class prototype, in declaration order. */
34
+ stepMethods: DiscoveredStep[];
35
+ /** Every listener-decorated method on the class prototype, in declaration order. */
36
+ listenerMethods: DiscoveredListener[];
37
+ /** Every `@OnTransition` method on the class prototype, in declaration order. */
38
+ transitionMethods: DiscoveredTransition[];
39
+ }
40
+
41
+ /** A `@Stepable` method. `isTasklet` is true if `@Tasklet` was also applied. */
42
+ export interface DiscoveredStep {
43
+ methodName: string;
44
+ options: StepableOptions;
45
+ isTasklet: boolean;
46
+ }
47
+
48
+ /** A listener-decorated method (any of the 7 kinds). */
49
+ export interface DiscoveredListener {
50
+ methodName: string;
51
+ kind: ListenerKind;
52
+ phase: ListenerPhase;
53
+ nonCritical?: boolean;
54
+ }
55
+
56
+ /**
57
+ * A `@OnTransition` method. `onStatus` is the string name of a
58
+ * `FlowExecutionStatus` (e.g. `'COMPLETED'`, `'FAILED'`, `'STOPPED'`).
59
+ * `toStep === null` means the transition ends the flow.
60
+ */
61
+ export interface DiscoveredTransition {
62
+ methodName: string;
63
+ fromStep: string;
64
+ onStatus: string;
65
+ toStep: string | null;
66
+ }
67
+
68
+ /**
69
+ * Minimal shape required from an `InstanceWrapper`-like object. We accept
70
+ * this loose shape (rather than requiring the full Nest `InstanceWrapper`
71
+ * class) so that:
72
+ * 1. tests can pass plain `{ metatype, instance }` objects without booting
73
+ * a Nest application, and
74
+ * 2. future Nest versions that change the wrapper's internal shape will
75
+ * still work as long as `metatype` + `instance` are preserved.
76
+ */
77
+ export interface ProviderLike {
78
+ metatype?: Function;
79
+ instance?: unknown;
80
+ }
81
+
82
+ /**
83
+ * `BatchExplorer` is a Nest `OnModuleInit` provider that walks every
84
+ * provider registered in the application, looks for classes carrying
85
+ * `@Jobable(...)` metadata, and records every `@Stepable` / `@Tasklet` /
86
+ * listener / `@OnTransition` method on each discovered class.
87
+ *
88
+ * The actual `JobDefinition` IR is produced downstream by the
89
+ * `DefinitionCompiler` (Task 8). The explorer only collects the raw
90
+ * metadata; it does not validate it, compile references, or register jobs.
91
+ *
92
+ * Mirrors the pattern used by `@nestjs/schedule` (`SchedulerExplorer`) and
93
+ * `@nestjs/cqrs` (`Explorer`).
94
+ */
95
+ @Injectable()
96
+ export class BatchExplorer implements OnModuleInit {
97
+ private readonly logger = new Logger(BatchExplorer.name);
98
+ private discovered: DiscoveredJob[] = [];
99
+
100
+ constructor(private readonly discovery: DiscoveryService) {}
101
+
102
+ /** Hook called by Nest once the DI container is ready. */
103
+ onModuleInit(): void {
104
+ const providers = this.discovery.getProviders();
105
+ this.discovered = this.discoverFromProviders(providers as ProviderLike[]);
106
+ }
107
+
108
+ /**
109
+ * Returns the snapshot of jobs collected at `onModuleInit` time. The
110
+ * returned array is `readonly` — callers MUST NOT mutate it.
111
+ */
112
+ getDiscovered(): readonly DiscoveredJob[] {
113
+ return this.discovered;
114
+ }
115
+
116
+ /**
117
+ * Pure provider-walk: given an array of `InstanceWrapper`-like objects,
118
+ * returns the list of `DiscoveredJob`s. Does not require a Nest container.
119
+ *
120
+ * The `onModuleInit` hook delegates here. Tests call this directly.
121
+ */
122
+ discoverFromProviders(providers: ProviderLike[]): DiscoveredJob[] {
123
+ const out: DiscoveredJob[] = [];
124
+ for (const wrapper of providers) {
125
+ const metatype = wrapper.metatype;
126
+ if (!metatype) continue;
127
+
128
+ const jobOptions = Reflect.getMetadata(BATCH_JOB_METADATA, metatype) as
129
+ | JobableOptions
130
+ | undefined;
131
+ if (!jobOptions) continue;
132
+
133
+ out.push({
134
+ classRef: metatype,
135
+ instance: wrapper.instance,
136
+ jobOptions,
137
+ stepMethods: this.collectStepMethods(metatype.prototype),
138
+ listenerMethods: this.collectListenerMethods(metatype.prototype),
139
+ transitionMethods: this.collectTransitionMethods(metatype.prototype),
140
+ });
141
+
142
+ this.logger.log(`Discovered job: ${jobOptions.id}`);
143
+ }
144
+ return out;
145
+ }
146
+
147
+ // -------------------------------------------------------------------------
148
+ // Step methods
149
+ // -------------------------------------------------------------------------
150
+
151
+ /**
152
+ * Walks the class prototype chain and returns every method that carries
153
+ * `BATCH_STEP_METADATA`. Each entry's `isTasklet` is true when the same
154
+ * method also carries `BATCH_TASKLET_METADATA`.
155
+ *
156
+ * Walks the full prototype chain (not just `Object.getOwnPropertyNames`
157
+ * on the top-level prototype) so that inherited `@Stepable` methods are
158
+ * also picked up.
159
+ */
160
+ private collectStepMethods(prototype: object): DiscoveredStep[] {
161
+ const result: DiscoveredStep[] = [];
162
+ for (const name of this.allMethodNames(prototype)) {
163
+ const opts = Reflect.getMetadata(BATCH_STEP_METADATA, prototype, name) as
164
+ | StepableOptions
165
+ | undefined;
166
+ if (!opts) continue;
167
+ const isTasklet =
168
+ Reflect.getMetadata(BATCH_TASKLET_METADATA, prototype, name) === true;
169
+ result.push({ methodName: name, options: opts, isTasklet });
170
+ }
171
+ return result;
172
+ }
173
+
174
+ // -------------------------------------------------------------------------
175
+ // Listener methods
176
+ // -------------------------------------------------------------------------
177
+
178
+ /**
179
+ * Walks the prototype chain and returns every method decorated with one
180
+ * of the 7 listener kinds (job / step / chunk / item-read / item-process /
181
+ * item-write / skip). The metadata shape is uniform — `{ kind, phase,
182
+ * nonCritical? }` — because every listener decorator funnels through
183
+ * the same internal `defineListener` helper.
184
+ */
185
+ private collectListenerMethods(prototype: object): DiscoveredListener[] {
186
+ const result: DiscoveredListener[] = [];
187
+ for (const name of this.allMethodNames(prototype)) {
188
+ const opts = Reflect.getMetadata(BATCH_LISTENER_METADATA, prototype, name) as
189
+ | { kind: ListenerKind; phase: ListenerPhase; nonCritical?: boolean }
190
+ | undefined;
191
+ if (!opts) continue;
192
+ result.push({
193
+ methodName: name,
194
+ kind: opts.kind,
195
+ phase: opts.phase,
196
+ nonCritical: opts.nonCritical,
197
+ });
198
+ }
199
+ return result;
200
+ }
201
+
202
+ // -------------------------------------------------------------------------
203
+ // Transition methods
204
+ // -------------------------------------------------------------------------
205
+
206
+ /**
207
+ * Walks the prototype chain and returns every method carrying
208
+ * `BATCH_TRANSITION_METADATA` (written by the `@OnTransition` decorator
209
+ * added in Task 31). Until Task 31 lands, this method simply returns
210
+ * an empty array.
211
+ *
212
+ * `onStatus` is the *string name* of a `FlowExecutionStatus` value
213
+ * (e.g. `'COMPLETED'`, `'FAILED'`, `'STOPPED'`). It is stored as a string
214
+ * to avoid a circular import from `core/ir` → `core/status` and to keep
215
+ * the metadata JSON-serializable.
216
+ */
217
+ private collectTransitionMethods(prototype: object): DiscoveredTransition[] {
218
+ const result: DiscoveredTransition[] = [];
219
+ for (const name of this.allMethodNames(prototype)) {
220
+ const opts = Reflect.getMetadata(BATCH_TRANSITION_METADATA, prototype, name) as
221
+ | { fromStep: string; onStatus: string; toStep: string | null }
222
+ | undefined;
223
+ if (!opts) continue;
224
+ result.push({ methodName: name, ...opts });
225
+ }
226
+ return result;
227
+ }
228
+
229
+ // -------------------------------------------------------------------------
230
+ // Prototype walker
231
+ // -------------------------------------------------------------------------
232
+
233
+ /**
234
+ * Returns every own method name (excluding `constructor`) on the given
235
+ * prototype and all of its ancestors up to (but not including)
236
+ * `Object.prototype`. Order is undefined, so callers that need a stable
237
+ * order should sort afterwards.
238
+ */
239
+ private allMethodNames(prototype: object): Set<string> {
240
+ const names = new Set<string>();
241
+ let proto: object | null = prototype;
242
+ while (proto && proto !== Object.prototype) {
243
+ for (const name of Object.getOwnPropertyNames(proto)) {
244
+ if (name === 'constructor') continue;
245
+ names.add(name);
246
+ }
247
+ proto = Object.getPrototypeOf(proto);
248
+ }
249
+ return names;
250
+ }
251
+ }
@@ -0,0 +1 @@
1
+ export * from './batch-explorer';
@@ -0,0 +1,89 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import type { TransitionDefinition } from '../core/ir';
3
+ import { InvalidFlowGraphError } from '../core/errors';
4
+
5
+ function escapeRegex(value: string): string {
6
+ return value.replace(/[|\\{}()[\]^$+.:]/g, '\\$&');
7
+ }
8
+
9
+ function matchesPattern(pattern: string, status: string): boolean {
10
+ if (!pattern.includes('*') && !pattern.includes('?')) {
11
+ return pattern === status;
12
+ }
13
+ const source = pattern
14
+ .split('')
15
+ .map((ch) => {
16
+ if (ch === '*') return '.*';
17
+ if (ch === '?') return '.';
18
+ return escapeRegex(ch);
19
+ })
20
+ .join('');
21
+ return new RegExp(`^${source}$`).test(status);
22
+ }
23
+
24
+ function patternSpecificity(pattern: string): number {
25
+ let score = 0;
26
+ for (const ch of pattern) {
27
+ if (ch !== '*' && ch !== '?') score += 1;
28
+ }
29
+ return pattern.includes('*') || pattern.includes('?') ? score : score + 1000;
30
+ }
31
+
32
+ /**
33
+ * FlowEvaluator resolves the next step in a flow graph given the current step
34
+ * and its exit status. It is a pure, side-effect-free decision function:
35
+ * given the same inputs it always returns the same next step (or END).
36
+ *
37
+ * Per ORACLE verdict 3c, the API is uniformly async — even though the current
38
+ * implementation is synchronous internally, returning a Promise keeps the
39
+ * caller contract identical to future evaluators that may need to consult
40
+ * remote state (e.g. conditional / data-driven transitions).
41
+ */
42
+ @Injectable()
43
+ export class FlowEvaluator {
44
+ /**
45
+ * Evaluate the next step ID given the current step and exit status.
46
+ *
47
+ * - Returns `null` if the job should END — either no transition matches
48
+ * the (fromStepId, onStatus) pair, or the matching transition's
49
+ * `toStepId` is `null` (explicit END).
50
+ * - Supports `*` and `?` wildcards in `onStatus`. Exact matches win
51
+ * over wildcard matches. If multiple matches have the same
52
+ * specificity, the graph is ambiguous and the caller must fix it.
53
+ *
54
+ * @param transitions All transitions in the job's flow graph.
55
+ * @param fromStepId The current step's ID.
56
+ * @param status The current step's exit status.
57
+ */
58
+ async evaluate(
59
+ transitions: TransitionDefinition[],
60
+ fromStepId: string,
61
+ status: string,
62
+ ): Promise<string | null> {
63
+ const matches = transitions.filter((t) => this.matches(t, fromStepId, status));
64
+ if (matches.length === 0) return null;
65
+
66
+ const ranked = matches.map((transition) => ({
67
+ transition,
68
+ specificity: patternSpecificity(transition.onStatus),
69
+ }));
70
+ const maxSpecificity = Math.max(...ranked.map((candidate) => candidate.specificity));
71
+ const best = ranked.filter((candidate) => candidate.specificity === maxSpecificity);
72
+
73
+ if (best.length > 1) {
74
+ throw new InvalidFlowGraphError(
75
+ 'AMBIGUOUS_TRANSITION',
76
+ `Ambiguous transition from "${fromStepId}" on status "${status}": ${best.length} matches`,
77
+ { fromStepId, status, count: best.length },
78
+ );
79
+ }
80
+ return best[0]!.transition.toStepId;
81
+ }
82
+
83
+ matches(transition: TransitionDefinition, fromStepId: string, status: string): boolean {
84
+ return (
85
+ transition.fromStepId === fromStepId &&
86
+ matchesPattern(transition.onStatus, status)
87
+ );
88
+ }
89
+ }
@@ -0,0 +1 @@
1
+ export * from './flow-evaluator';
package/src/index.ts ADDED
@@ -0,0 +1,24 @@
1
+ // Public API barrel for @nest-batch/core.
2
+ //
3
+ // Decorator functions (ItemReader, ItemProcessor, ItemWriter, Tasklet) live in
4
+ // ./decorators and share names with interfaces in ./core/item. To avoid name
5
+ // collisions in the public surface, decorators are re-exported under the
6
+ // `BatchDecorators` namespace; interfaces remain reachable as bare names from
7
+ // ./core/item (or via core/index).
8
+ export * from './core';
9
+ export * from './compiler';
10
+ export * from './partition-helpers';
11
+ export * from './registry';
12
+ export * from './execution';
13
+ export * from './transaction';
14
+ export * from './repository';
15
+ export * as BatchDecorators from './decorators';
16
+ export * from './module';
17
+ export * from './builder';
18
+ export * from './explorer';
19
+ export * from './listeners';
20
+ export * from './policies';
21
+ export * from './flow';
22
+ export * from './observability';
23
+ export * from './adapters';
24
+ export * from './io';
@@ -0,0 +1,47 @@
1
+ import type { ExecutionContext, JsonValue } from '../core';
2
+
3
+ export function readCheckpoint(
4
+ context: ExecutionContext,
5
+ key: string,
6
+ ): Record<string, JsonValue> {
7
+ const root = asJsonRecord(context.data);
8
+ const value = root[key];
9
+ return asJsonRecord(value);
10
+ }
11
+
12
+ export function readCheckpointNumber(
13
+ context: ExecutionContext,
14
+ key: string,
15
+ field: string,
16
+ fallback: number,
17
+ ): number {
18
+ const value = readCheckpoint(context, key)[field];
19
+ return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
20
+ }
21
+
22
+ export function readCheckpointValue<T extends JsonValue>(
23
+ context: ExecutionContext,
24
+ key: string,
25
+ field: string,
26
+ fallback: T,
27
+ ): T {
28
+ const value = readCheckpoint(context, key)[field];
29
+ return value === undefined ? fallback : (value as T);
30
+ }
31
+
32
+ export function writeCheckpoint(
33
+ context: ExecutionContext,
34
+ key: string,
35
+ state: Record<string, JsonValue>,
36
+ ): ExecutionContext {
37
+ const root = { ...asJsonRecord(context.data), [key]: state };
38
+ context.data = root;
39
+ return context;
40
+ }
41
+
42
+ export function asJsonRecord(value: JsonValue | undefined): Record<string, JsonValue> {
43
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
44
+ return value;
45
+ }
46
+ return {};
47
+ }