alepha 0.19.3 → 0.19.5

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 (289) hide show
  1. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  2. package/dist/api/invitations/index.d.ts +790 -0
  3. package/dist/api/invitations/index.d.ts.map +1 -0
  4. package/dist/api/invitations/index.js +665 -0
  5. package/dist/api/invitations/index.js.map +1 -0
  6. package/dist/api/issues/index.d.ts +810 -0
  7. package/dist/api/issues/index.d.ts.map +1 -0
  8. package/dist/api/issues/index.js +447 -0
  9. package/dist/api/issues/index.js.map +1 -0
  10. package/dist/api/jobs/index.browser.js +8 -9
  11. package/dist/api/jobs/index.browser.js.map +1 -1
  12. package/dist/api/jobs/index.d.ts +99 -43
  13. package/dist/api/jobs/index.d.ts.map +1 -1
  14. package/dist/api/jobs/index.js +257 -40
  15. package/dist/api/jobs/index.js.map +1 -1
  16. package/dist/api/notifications/index.browser.js +0 -1
  17. package/dist/api/notifications/index.browser.js.map +1 -1
  18. package/dist/api/notifications/index.d.ts +3 -3
  19. package/dist/api/notifications/index.d.ts.map +1 -1
  20. package/dist/api/notifications/index.js +0 -1
  21. package/dist/api/notifications/index.js.map +1 -1
  22. package/dist/api/parameters/index.browser.js +112 -1
  23. package/dist/api/parameters/index.browser.js.map +1 -1
  24. package/dist/api/parameters/index.d.ts +90 -3
  25. package/dist/api/parameters/index.d.ts.map +1 -1
  26. package/dist/api/parameters/index.js +79 -12
  27. package/dist/api/parameters/index.js.map +1 -1
  28. package/dist/{billing → api/payments}/index.d.ts +67 -49
  29. package/dist/api/payments/index.d.ts.map +1 -0
  30. package/dist/{billing → api/payments}/index.js +108 -74
  31. package/dist/api/payments/index.js.map +1 -0
  32. package/dist/api/subscriptions/index.d.ts +1692 -0
  33. package/dist/api/subscriptions/index.d.ts.map +1 -0
  34. package/dist/api/subscriptions/index.js +1870 -0
  35. package/dist/api/subscriptions/index.js.map +1 -0
  36. package/dist/api/users/index.d.ts +24 -2
  37. package/dist/api/users/index.d.ts.map +1 -1
  38. package/dist/api/users/index.js +176 -36
  39. package/dist/api/users/index.js.map +1 -1
  40. package/dist/api/verifications/index.d.ts +13 -13
  41. package/dist/api/workflows/index.browser.js +246 -0
  42. package/dist/api/workflows/index.browser.js.map +1 -0
  43. package/dist/api/workflows/index.d.ts +1618 -0
  44. package/dist/api/workflows/index.d.ts.map +1 -0
  45. package/dist/api/workflows/index.js +1504 -0
  46. package/dist/api/workflows/index.js.map +1 -0
  47. package/dist/captcha/index.d.ts +142 -0
  48. package/dist/captcha/index.d.ts.map +1 -0
  49. package/dist/captcha/index.js +177 -0
  50. package/dist/captcha/index.js.map +1 -0
  51. package/dist/cli/core/index.d.ts +126 -30
  52. package/dist/cli/core/index.d.ts.map +1 -1
  53. package/dist/cli/core/index.js +106 -67
  54. package/dist/cli/core/index.js.map +1 -1
  55. package/dist/cli/platform/index.d.ts +84 -10
  56. package/dist/cli/platform/index.d.ts.map +1 -1
  57. package/dist/cli/platform/index.js +92 -4
  58. package/dist/cli/platform/index.js.map +1 -1
  59. package/dist/cli/vendor/index.d.ts +60 -10
  60. package/dist/cli/vendor/index.d.ts.map +1 -1
  61. package/dist/cli/vendor/index.js +177 -45
  62. package/dist/cli/vendor/index.js.map +1 -1
  63. package/dist/command/index.d.ts.map +1 -1
  64. package/dist/command/index.js +2 -3
  65. package/dist/command/index.js.map +1 -1
  66. package/dist/core/index.browser.js +21 -2
  67. package/dist/core/index.browser.js.map +1 -1
  68. package/dist/core/index.d.ts +33 -2
  69. package/dist/core/index.d.ts.map +1 -1
  70. package/dist/core/index.js +21 -2
  71. package/dist/core/index.js.map +1 -1
  72. package/dist/core/index.native.js +21 -2
  73. package/dist/core/index.native.js.map +1 -1
  74. package/dist/core/index.workerd.js +21 -2
  75. package/dist/core/index.workerd.js.map +1 -1
  76. package/dist/email/smtp/index.js +24 -8
  77. package/dist/email/smtp/index.js.map +1 -1
  78. package/dist/orm/core/index.browser.js +0 -18
  79. package/dist/orm/core/index.browser.js.map +1 -1
  80. package/dist/orm/core/index.bun.js +6 -23
  81. package/dist/orm/core/index.bun.js.map +1 -1
  82. package/dist/orm/core/index.d.ts +1 -13
  83. package/dist/orm/core/index.d.ts.map +1 -1
  84. package/dist/orm/core/index.js +6 -23
  85. package/dist/orm/core/index.js.map +1 -1
  86. package/dist/orm/postgres/index.bun.js +3 -3
  87. package/dist/orm/postgres/index.bun.js.map +1 -1
  88. package/dist/orm/postgres/index.d.ts.map +1 -1
  89. package/dist/orm/postgres/index.js +3 -3
  90. package/dist/orm/postgres/index.js.map +1 -1
  91. package/dist/react/i18n/index.d.ts +1 -0
  92. package/dist/react/i18n/index.d.ts.map +1 -1
  93. package/dist/react/i18n/index.js +8 -4
  94. package/dist/react/i18n/index.js.map +1 -1
  95. package/dist/react/router/index.browser.js +25 -3
  96. package/dist/react/router/index.browser.js.map +1 -1
  97. package/dist/react/router/index.d.ts +16 -1
  98. package/dist/react/router/index.d.ts.map +1 -1
  99. package/dist/react/router/index.js +25 -3
  100. package/dist/react/router/index.js.map +1 -1
  101. package/dist/security/index.d.ts +28 -0
  102. package/dist/security/index.d.ts.map +1 -1
  103. package/dist/security/index.js +28 -0
  104. package/dist/security/index.js.map +1 -1
  105. package/dist/server/auth/index.d.ts +145 -2
  106. package/dist/server/auth/index.d.ts.map +1 -1
  107. package/dist/server/auth/index.js +364 -63
  108. package/dist/server/auth/index.js.map +1 -1
  109. package/dist/server/cookies/index.d.ts.map +1 -1
  110. package/dist/server/cookies/index.js.map +1 -1
  111. package/dist/websocket/index.d.ts.map +1 -1
  112. package/dist/websocket/index.js.map +1 -1
  113. package/package.json +47 -20
  114. package/src/api/invitations/__tests__/InvitationService.spec.ts +439 -0
  115. package/src/api/invitations/controllers/AdminInvitationController.ts +86 -0
  116. package/src/api/invitations/controllers/InvitationController.ts +84 -0
  117. package/src/api/invitations/entities/invitations.ts +33 -0
  118. package/src/api/invitations/index.ts +65 -0
  119. package/src/api/invitations/jobs/InvitationJobs.ts +37 -0
  120. package/src/api/invitations/providers/InvitationProvider.ts +45 -0
  121. package/src/api/invitations/schemas/createInvitationSchema.ts +12 -0
  122. package/src/api/invitations/schemas/invitationConfigAtom.ts +20 -0
  123. package/src/api/invitations/schemas/invitationQuerySchema.ts +15 -0
  124. package/src/api/invitations/schemas/invitationResourceSchema.ts +6 -0
  125. package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +22 -0
  126. package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +10 -0
  127. package/src/api/invitations/services/InvitationService.ts +556 -0
  128. package/src/api/issues/__tests__/IssueService.spec.ts +263 -0
  129. package/src/api/issues/controllers/AdminIssueController.ts +149 -0
  130. package/src/api/issues/controllers/IssueController.ts +44 -0
  131. package/src/api/issues/entities/issues.ts +49 -0
  132. package/src/api/issues/index.ts +53 -0
  133. package/src/api/issues/schemas/createIssueSchema.ts +13 -0
  134. package/src/api/issues/schemas/issueConfigAtom.ts +13 -0
  135. package/src/api/issues/schemas/issueQuerySchema.ts +18 -0
  136. package/src/api/issues/schemas/issueResourceSchema.ts +6 -0
  137. package/src/api/issues/schemas/myIssueQuerySchema.ts +10 -0
  138. package/src/api/issues/schemas/updateIssueSchema.ts +13 -0
  139. package/src/api/issues/services/IssueService.ts +264 -0
  140. package/src/api/jobs/__tests__/$job.spec.ts +876 -0
  141. package/src/api/jobs/controllers/AdminJobController.ts +44 -0
  142. package/src/api/jobs/entities/jobExecutionEntity.ts +0 -2
  143. package/src/api/jobs/index.ts +0 -3
  144. package/src/api/jobs/primitives/$job.ts +22 -11
  145. package/src/api/jobs/providers/JobProvider.ts +229 -19
  146. package/src/api/jobs/schemas/jobConfigAtom.ts +4 -0
  147. package/src/api/jobs/schemas/jobCronInfoSchema.ts +1 -0
  148. package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +0 -1
  149. package/src/api/jobs/schemas/jobQueueDepthSchema.ts +1 -0
  150. package/src/api/jobs/schemas/jobRegistrationSchema.ts +1 -6
  151. package/src/api/jobs/services/JobService.ts +51 -12
  152. package/src/api/notifications/schemas/notificationQuerySchema.ts +0 -1
  153. package/src/api/parameters/__tests__/$parameter.spec.ts +327 -0
  154. package/src/api/parameters/controllers/AdminParameterController.ts +29 -3
  155. package/src/api/parameters/index.browser.ts +12 -0
  156. package/src/api/parameters/primitives/$parameter.ts +20 -3
  157. package/src/api/parameters/services/ParameterProvider.ts +48 -7
  158. package/src/{billing → api/payments}/__tests__/PaymentMethodService.spec.ts +32 -6
  159. package/src/api/payments/__tests__/PaymentService.spec.ts +279 -0
  160. package/src/{billing/controllers/AdminBillingController.ts → api/payments/controllers/AdminPaymentController.ts} +26 -21
  161. package/src/{billing/controllers/BillingController.ts → api/payments/controllers/PaymentController.ts} +23 -11
  162. package/src/{billing → api/payments}/entities/paymentIntents.ts +1 -0
  163. package/src/{billing/errors/BillingError.ts → api/payments/errors/PaymentError.ts} +1 -1
  164. package/src/{billing → api/payments}/index.ts +31 -25
  165. package/src/{billing/providers/MemoryBillingProvider.ts → api/payments/providers/MemoryPaymentProvider.ts} +4 -4
  166. package/src/{billing/providers/BillingProvider.ts → api/payments/providers/PaymentProvider.ts} +9 -2
  167. package/src/{billing → api/payments}/services/PaymentMethodService.ts +5 -5
  168. package/src/{billing/services/BillingService.ts → api/payments/services/PaymentService.ts} +94 -18
  169. package/src/api/subscriptions/__tests__/BillingService.spec.ts +218 -0
  170. package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +278 -0
  171. package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +212 -0
  172. package/src/api/subscriptions/controllers/SubscriptionController.ts +189 -0
  173. package/src/api/subscriptions/entities/subscriptionEvents.ts +54 -0
  174. package/src/api/subscriptions/entities/subscriptions.ts +68 -0
  175. package/src/api/subscriptions/index.ts +144 -0
  176. package/src/api/subscriptions/jobs/SubscriptionJobs.ts +382 -0
  177. package/src/api/subscriptions/middleware/$requireLimit.ts +50 -0
  178. package/src/api/subscriptions/middleware/$requirePlan.ts +49 -0
  179. package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +110 -0
  180. package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +8 -0
  181. package/src/api/subscriptions/schemas/changePlanSchema.ts +9 -0
  182. package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +11 -0
  183. package/src/api/subscriptions/schemas/entitlementsSchema.ts +21 -0
  184. package/src/api/subscriptions/schemas/mrrSchema.ts +13 -0
  185. package/src/api/subscriptions/schemas/planDefinitionSchema.ts +71 -0
  186. package/src/api/subscriptions/schemas/planResourceSchema.ts +25 -0
  187. package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +8 -0
  188. package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +19 -0
  189. package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +6 -0
  190. package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +32 -0
  191. package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +23 -0
  192. package/src/api/subscriptions/services/BillingService.ts +437 -0
  193. package/src/api/subscriptions/services/SubscriptionConfig.ts +56 -0
  194. package/src/api/subscriptions/services/SubscriptionService.ts +867 -0
  195. package/src/api/subscriptions/services/UsageService.ts +118 -0
  196. package/src/api/users/__tests__/AdminUserController.spec.ts +80 -1
  197. package/src/api/users/__tests__/CredentialService.spec.ts +177 -0
  198. package/src/api/users/__tests__/EmailVerification.spec.ts +29 -18
  199. package/src/api/users/__tests__/PasswordReset.spec.ts +3 -0
  200. package/src/api/users/__tests__/RegistrationService.spec.ts +148 -1
  201. package/src/api/users/__tests__/SessionService.spec.ts +142 -1
  202. package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -1
  203. package/src/api/users/controllers/UserController.ts +3 -8
  204. package/src/api/users/notifications/UserNotifications.ts +23 -0
  205. package/src/api/users/primitives/$realm.ts +24 -0
  206. package/src/api/users/schemas/loginSchema.ts +1 -1
  207. package/src/api/users/services/CredentialService.ts +57 -7
  208. package/src/api/users/services/RegistrationService.ts +50 -11
  209. package/src/api/users/services/SessionService.ts +64 -9
  210. package/src/api/users/services/UserService.ts +21 -12
  211. package/src/api/workflows/__tests__/$workflow.spec.ts +616 -0
  212. package/src/api/workflows/controllers/AdminWorkflowController.ts +191 -0
  213. package/src/api/workflows/entities/workflowExecutions.ts +74 -0
  214. package/src/api/workflows/entities/workflowStepExecutions.ts +74 -0
  215. package/src/api/workflows/entities/workflowStepLogs.ts +13 -0
  216. package/src/api/workflows/index.browser.ts +22 -0
  217. package/src/api/workflows/index.ts +124 -0
  218. package/src/api/workflows/jobs/WorkflowJobs.ts +77 -0
  219. package/src/api/workflows/primitives/$workflow.ts +202 -0
  220. package/src/api/workflows/providers/WorkflowProvider.ts +1284 -0
  221. package/src/api/workflows/schemas/workflowActivitySchema.ts +15 -0
  222. package/src/api/workflows/schemas/workflowConfigAtom.ts +51 -0
  223. package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +18 -0
  224. package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +26 -0
  225. package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +30 -0
  226. package/src/api/workflows/schemas/workflowRegistrationSchema.ts +26 -0
  227. package/src/api/workflows/schemas/workflowStatsSchema.ts +16 -0
  228. package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +15 -0
  229. package/src/api/workflows/services/WorkflowService.ts +382 -0
  230. package/src/captcha/__tests__/MemoryCaptchaProvider.spec.ts +74 -0
  231. package/src/captcha/index.ts +33 -0
  232. package/src/captcha/providers/CaptchaProvider.ts +17 -0
  233. package/src/captcha/providers/MemoryCaptchaProvider.ts +65 -0
  234. package/src/captcha/providers/TurnstileCaptchaProvider.ts +125 -0
  235. package/src/cli/core/atoms/buildOptions.ts +57 -0
  236. package/src/cli/core/commands/build.ts +2 -0
  237. package/src/cli/core/providers/ViteDevServerProvider.ts +1 -1
  238. package/src/cli/core/services/ViteUtils.ts +5 -2
  239. package/src/cli/core/tasks/BuildClientTask.ts +3 -1
  240. package/src/cli/core/tasks/BuildCloudflareTask.ts +4 -0
  241. package/src/cli/core/tasks/BuildPwaTask.ts +81 -0
  242. package/src/cli/core/templates/webAppRouterTs.ts +5 -58
  243. package/src/cli/platform/adapters/CloudflareAdapter.ts +24 -0
  244. package/src/cli/platform/atoms/platformOptions.ts +19 -3
  245. package/src/cli/platform/hooks/PlatformHook.ts +51 -0
  246. package/src/cli/platform/index.ts +1 -0
  247. package/src/cli/platform/services/CloudflareApi.ts +22 -1
  248. package/src/cli/platform/services/PlatformOrchestrator.ts +67 -2
  249. package/src/cli/vendor/__tests__/VendorService.spec.ts +322 -178
  250. package/src/cli/vendor/commands/VendorCommand.ts +41 -38
  251. package/src/cli/vendor/services/VendorService.ts +234 -31
  252. package/src/command/__tests__/CliProvider.spec.ts +45 -0
  253. package/src/command/providers/CliProvider.ts +3 -4
  254. package/src/core/__tests__/TypeProvider.spec.ts +4 -2
  255. package/src/core/providers/SchemaValidator.ts +1 -1
  256. package/src/core/providers/TypeProvider.ts +46 -3
  257. package/src/orm/__tests__/enums.spec.ts +22 -29
  258. package/src/orm/__tests__/orm-showcase-tests.ts +430 -0
  259. package/src/orm/__tests__/orm-showcase.spec.ts +167 -0
  260. package/src/orm/core/providers/DatabaseTypeProvider.ts +0 -29
  261. package/src/orm/core/services/Repository.ts +20 -6
  262. package/src/orm/postgres/services/PostgresModelBuilder.ts +3 -6
  263. package/src/react/i18n/__tests__/I18nProvider.spec.ts +83 -0
  264. package/src/react/i18n/providers/I18nProvider.ts +12 -10
  265. package/src/react/router/__tests__/$page.browser.spec.tsx +157 -0
  266. package/src/react/router/providers/ReactBrowserProvider.ts +39 -0
  267. package/src/react/router/providers/ReactBrowserRouterProvider.ts +22 -0
  268. package/src/security/__tests__/$secure-combinations.spec.ts +945 -0
  269. package/src/security/primitives/$issuer.ts +3 -1
  270. package/src/security/primitives/$secure.ts +28 -0
  271. package/src/server/auth/index.ts +7 -0
  272. package/src/server/auth/primitives/$auth.ts +37 -3
  273. package/src/server/auth/primitives/$authApple.ts +114 -4
  274. package/src/server/auth/primitives/$authFacebook.ts +98 -0
  275. package/src/server/auth/primitives/$authFranceConnect.ts +105 -0
  276. package/src/server/auth/primitives/$authGithub.ts +22 -16
  277. package/src/server/auth/primitives/$authMicrosoft.ts +88 -0
  278. package/src/server/auth/providers/ServerAuthProvider.ts +197 -72
  279. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -0
  280. package/src/server/core/__tests__/ServerRouterProvider-errorHandler.spec.ts +1 -1
  281. package/src/websocket/providers/NodeWebSocketServerProvider.ts +3 -1
  282. package/dist/billing/index.d.ts.map +0 -1
  283. package/dist/billing/index.js.map +0 -1
  284. package/src/billing/__tests__/BillingService.spec.ts +0 -136
  285. /package/src/{billing → api/payments}/entities/paymentMethods.ts +0 -0
  286. /package/src/{billing → api/payments}/entities/refunds.ts +0 -0
  287. /package/src/{billing → api/payments}/schemas/intentSchemas.ts +0 -0
  288. /package/src/{billing → api/payments}/schemas/paymentMethodSchemas.ts +0 -0
  289. /package/src/{billing → api/payments}/schemas/refundSchemas.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/api/jobs/schemas/jobActivitySchema.ts","../../../src/api/jobs/schemas/jobCronInfoSchema.ts","../../../src/api/jobs/entities/jobExecutionEntity.ts","../../../src/api/jobs/schemas/jobExecutionResourceSchema.ts","../../../src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts","../../../src/api/jobs/schemas/jobExecutionQuerySchema.ts","../../../src/api/jobs/schemas/jobFailureSchema.ts","../../../src/api/jobs/schemas/jobQueueDepthSchema.ts","../../../src/api/jobs/schemas/jobRegistrationSchema.ts","../../../src/api/jobs/schemas/jobStatsSchema.ts","../../../src/api/jobs/schemas/triggerJobSchema.ts","../../../src/api/jobs/entities/jobExecutionLogEntity.ts","../../../src/api/jobs/schemas/jobConfigAtom.ts","../../../src/api/jobs/providers/JobProvider.ts","../../../src/api/jobs/primitives/$job.ts","../../../src/api/jobs/services/JobService.ts","../../../src/api/jobs/controllers/AdminJobController.ts","../../../src/api/jobs/providers/JobQueueProvider.ts","../../../src/api/jobs/index.ts"],"sourcesContent":["import { type Static, t } from \"alepha\";\n\nexport const jobActivityPointSchema = t.object({\n date: t.text(),\n completed: t.integer(),\n failed: t.integer(),\n});\n\nexport type JobActivityPoint = Static<typeof jobActivityPointSchema>;\n\nexport const jobActivityQuerySchema = t.object({\n days: t.optional(t.integer({ minimum: 1, maximum: 90 })),\n});\n\nexport type JobActivityQuery = Static<typeof jobActivityQuerySchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobCronInfoSchema = t.object({\n name: t.text(),\n cron: t.text(),\n lock: t.boolean(),\n priority: t.enum([\"critical\", \"high\", \"normal\", \"low\"]),\n concurrency: t.integer(),\n hasSchema: t.boolean(),\n lastExecution: t.optional(\n t.object({\n id: t.uuid(),\n status: t.text(),\n startedAt: t.optional(t.datetime()),\n completedAt: t.optional(t.datetime()),\n error: t.optional(t.text()),\n }),\n ),\n});\n\nexport type JobCronInfo = Static<typeof jobCronInfoSchema>;\n","import { type Static, t } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const jobExecutionEntity = $entity({\n name: \"job_executions\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n\n jobName: t.text(),\n key: t.optional(t.nullable(t.text())),\n\n payload: t.optional(t.record(t.text(), t.any())),\n status: db.default(\n t.enum([\n \"pending\",\n \"scheduled\",\n \"retrying\",\n \"running\",\n \"completed\",\n \"failed\",\n \"dead\",\n \"cancelled\",\n ]),\n \"pending\",\n ),\n priority: db.default(t.integer({ minimum: 0, maximum: 3 }), 2),\n\n attempt: db.default(t.integer(), 0),\n maxAttempts: db.default(t.integer(), 1),\n\n scheduledAt: t.optional(t.datetime()),\n startedAt: t.optional(t.datetime()),\n completedAt: t.optional(t.datetime()),\n\n result: t.optional(t.record(t.text(), t.any())),\n error: t.optional(t.text()),\n workerId: t.optional(t.text()),\n\n triggeredBy: t.optional(t.text()),\n triggeredByName: t.optional(t.text()),\n cancelledBy: t.optional(t.text()),\n cancelledByName: t.optional(t.text()),\n }),\n indexes: [\n { columns: [\"jobName\", \"status\", \"priority\", \"scheduledAt\"] },\n { columns: [\"jobName\", \"status\", \"startedAt\"] },\n { columns: [\"jobName\", \"completedAt\"] },\n { columns: [\"jobName\", \"key\"], unique: true },\n ],\n});\n\nexport type JobExecutionEntity = Static<typeof jobExecutionEntity.schema>;\n\nexport type JobStatus =\n | \"pending\"\n | \"scheduled\"\n | \"retrying\"\n | \"running\"\n | \"completed\"\n | \"failed\"\n | \"dead\"\n | \"cancelled\";\n","import { type Static, t } from \"alepha\";\nimport { jobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\n\nexport const jobExecutionCanSchema = t.object({\n retry: t.boolean(),\n cancel: t.boolean(),\n});\n\nexport const jobExecutionResourceSchema = t.extend(\n jobExecutionEntity.schema,\n {\n can: jobExecutionCanSchema,\n },\n {\n title: \"JobExecutionResource\",\n description: \"A job execution resource.\",\n },\n);\n\nexport type JobExecutionResource = Static<typeof jobExecutionResourceSchema>;\n","import { type Static, t } from \"alepha\";\nimport { logEntrySchema } from \"alepha/logger\";\nimport { jobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionCanSchema } from \"./jobExecutionResourceSchema.ts\";\n\nexport const jobExecutionDetailResourceSchema = t.extend(\n jobExecutionEntity.schema,\n {\n can: jobExecutionCanSchema,\n logs: t.optional(t.array(logEntrySchema)),\n },\n {\n title: \"JobExecutionDetailResource\",\n description: \"A job execution resource with logs.\",\n },\n);\n\nexport type JobExecutionDetailResource = Static<\n typeof jobExecutionDetailResourceSchema\n>;\n","import { type Static, t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\n\nexport const jobExecutionQuerySchema = t.extend(pageQuerySchema, {\n job: t.optional(\n t.text({\n description: \"Filter by job name\",\n }),\n ),\n status: t.optional(\n t.enum([\n \"pending\",\n \"scheduled\",\n \"retrying\",\n \"running\",\n \"completed\",\n \"failed\",\n \"dead\",\n \"cancelled\",\n ]),\n ),\n priority: t.optional(t.enum([\"critical\", \"high\", \"normal\", \"low\"])),\n from: t.optional(\n t.datetime({\n description: \"From date (ISO)\",\n }),\n ),\n to: t.optional(\n t.datetime({\n description: \"To date (ISO)\",\n }),\n ),\n});\n\nexport type JobExecutionQuery = Static<typeof jobExecutionQuerySchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobFailureSchema = t.object({\n jobName: t.text(),\n failures: t.integer(),\n lastError: t.optional(t.text()),\n});\n\nexport type JobFailure = Static<typeof jobFailureSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobQueueDepthSchema = t.object({\n jobName: t.text(),\n pending: t.integer(),\n running: t.integer(),\n scheduled: t.integer(),\n retrying: t.integer(),\n dead: t.integer(),\n concurrency: t.integer(),\n});\n\nexport type JobQueueDepth = Static<typeof jobQueueDepthSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobRegistrationSchema = t.object({\n name: t.text(),\n type: t.enum([\"cron\", \"push\", \"both\"]),\n priority: t.enum([\"critical\", \"high\", \"normal\", \"low\"]),\n concurrency: t.integer(),\n hasSchema: t.boolean(),\n cron: t.optional(t.text()),\n timeout: t.optional(t.text()),\n retry: t.optional(\n t.object({\n retries: t.integer(),\n hasBackoff: t.boolean(),\n }),\n ),\n batch: t.optional(\n t.object({\n size: t.integer(),\n window: t.text(),\n }),\n ),\n});\n\nexport type JobRegistration = Static<typeof jobRegistrationSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobStatsSchema = t.object({\n registered: t.integer(),\n running: t.integer(),\n pending: t.integer(),\n scheduled: t.integer(),\n retrying: t.integer(),\n dead: t.integer(),\n completed: t.integer(),\n failed: t.integer(),\n});\n\nexport type JobStats = Static<typeof jobStatsSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const triggerJobSchema = t.object({\n name: t.text(),\n payload: t.optional(t.record(t.text(), t.any())),\n});\n\nexport type TriggerJob = Static<typeof triggerJobSchema>;\n","import { type Static, t } from \"alepha\";\nimport { logEntrySchema } from \"alepha/logger\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const jobExecutionLogEntity = $entity({\n name: \"job_execution_logs\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n logs: t.array(logEntrySchema),\n }),\n});\n\nexport type JobExecutionLogEntity = Static<typeof jobExecutionLogEntity.schema>;\n","import { $atom, type Static, t } from \"alepha\";\n\nexport const jobConfig = $atom({\n name: \"alepha.jobs\",\n description: \"Configuration for the $job v2 primitive.\",\n schema: t.object({\n recovery: t.object({\n interval: t.integer({ description: \"Sweep interval (ms).\" }),\n staleThreshold: t.integer({\n description: \"Pending age (ms) before re-dispatch.\",\n }),\n runTimeout: t.integer({\n description:\n \"Running age (ms) before assumed crash. Used as fallback when no per-job timeout is set.\",\n }),\n }),\n delayed: t.object({\n interval: t.integer({ description: \"Sweep interval (ms).\" }),\n }),\n logRetentionDays: t.integer({\n description: \"Days to keep completed/dead executions.\",\n }),\n logMaxEntries: t.integer({\n description: \"Max log entries captured per execution.\",\n }),\n }),\n default: {\n recovery: {\n interval: 300_000,\n staleThreshold: 300_000,\n runTimeout: 1_800_000,\n },\n delayed: {\n interval: 300_000,\n },\n logRetentionDays: 30,\n logMaxEntries: 100,\n },\n});\n\nexport type JobConfig = Static<typeof jobConfig.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [jobConfig.key]: JobConfig;\n }\n}\n","import {\n $hook,\n $inject,\n $state,\n Alepha,\n AlephaError,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport { DateTimeProvider, type DurationLike } from \"alepha/datetime\";\nimport type { LogEntry } from \"alepha/logger\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport { CronProvider } from \"alepha/scheduler\";\nimport {\n type JobStatus,\n jobExecutionEntity,\n} from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionLogEntity } from \"../entities/jobExecutionLogEntity.ts\";\nimport type {\n JobItem,\n JobPrimitiveOptions,\n JobPriority,\n JobRetryBackoff,\n JobRetryOptions,\n} from \"../primitives/$job.ts\";\nimport { jobConfig } from \"../schemas/jobConfigAtom.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\nconst PRIORITY_MAP: Record<string, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n};\n\nconst PRIORITY_REVERSE: Record<number, JobPriority> = {\n 0: \"critical\",\n 1: \"high\",\n 2: \"normal\",\n 3: \"low\",\n};\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport interface PushOptions {\n delay?: DurationLike;\n key?: string;\n priority?: JobPriority;\n scheduledAt?: Date;\n}\n\nexport interface PushManyItem<T extends TSchema = TSchema> {\n payload: Static<T>;\n key?: string;\n delay?: DurationLike;\n priority?: JobPriority;\n scheduledAt?: Date;\n}\n\nexport interface JobTriggerContext {\n payload?: Record<string, unknown>;\n triggeredBy?: string;\n triggeredByName?: string;\n}\n\nexport interface CancelContext {\n cancelledBy?: string;\n cancelledByName?: string;\n}\n\ninterface JobRegistration {\n name: string;\n options: JobPrimitiveOptions;\n}\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport class JobProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly dt = $inject(DateTimeProvider);\n protected readonly cronProvider = $inject(CronProvider);\n protected readonly config = $state(jobConfig);\n protected readonly log = $logger();\n protected readonly executions = $repository(jobExecutionEntity);\n protected readonly executionLogs = $repository(jobExecutionLogEntity);\n\n protected readonly jobs = new Map<string, JobRegistration>();\n\n /**\n * When set, job executions are dispatched through a queue (e.g. `JobQueueProvider`).\n * When null, jobs execute inline (fire-and-forget). Useful for serverless environments.\n */\n public queueDispatch:\n | ((jobName: string, executionId: string) => Promise<void>)\n | null = null;\n protected readonly logs = new Map<string, LogEntry[]>();\n protected readonly abortControllers = new Map<string, AbortController>();\n protected static readonly SWEEP_CRON = \"*/5 * * * *\";\n protected stopping = false;\n protected workerId = \"\";\n\n // --- Registration ---\n\n public registerJob(name: string, options: JobPrimitiveOptions): void {\n if (this.jobs.has(name)) {\n throw new AlephaError(`Job already registered: ${name}`);\n }\n\n this.jobs.set(name, { name, options });\n this.log.debug(`Registered job '${name}'`, {\n cron: options.cron,\n priority: options.priority ?? \"normal\",\n retries: options.retry?.retries ?? 0,\n });\n\n if (options.cron) {\n this.cronProvider.createCronJob(name, options.cron, async () => {\n try {\n await this.trigger(name, {\n triggeredBy: \"system\",\n triggeredByName: \"system (cron)\",\n });\n } catch (error) {\n this.log.error(`Cron trigger failed for job '${name}'`, error);\n }\n });\n }\n }\n\n /**\n * Get all registered job definitions.\n */\n public getRegisteredJobs(): Map<string, JobRegistration> {\n return this.jobs;\n }\n\n // --- Push ---\n\n public async push(\n name: string,\n payload: unknown,\n options?: PushOptions,\n ): Promise<string> {\n const registration = this.getRegistration(name);\n const opts = registration.options;\n\n if (!opts.schema) {\n throw new AlephaError(\n `Cannot push to job '${name}': no schema defined. Use trigger() for cron-only jobs.`,\n );\n }\n\n const validated = this.alepha.codec.validate(opts.schema, payload);\n\n const priority =\n PRIORITY_MAP[options?.priority ?? opts.priority ?? \"normal\"];\n const maxAttempts = (opts.retry?.retries ?? 0) + 1;\n\n const isDelayed = options?.delay || options?.scheduledAt;\n const status: JobStatus = isDelayed ? \"scheduled\" : \"pending\";\n\n let scheduledAt: string | undefined;\n if (options?.scheduledAt) {\n scheduledAt = options.scheduledAt.toISOString();\n } else if (options?.delay) {\n const now = this.dt.now();\n scheduledAt = now.add(this.dt.duration(options.delay)).toISOString();\n }\n\n // Keyed path: atomic upsert to avoid race between concurrent pushes\n if (options?.key) {\n const now = this.dt.nowISOString();\n const execution = await this.executions.upsert(\n {\n jobName: name,\n key: options.key,\n payload: validated as Record<string, unknown>,\n status,\n priority,\n maxAttempts,\n scheduledAt,\n createdAt: now,\n updatedAt: now,\n },\n { target: [\"jobName\", \"key\"], set: {}, now },\n );\n\n // Fresh insert: both timestamps equal the explicit `now` value.\n // Conflict: updatedAt was bumped by the ON CONFLICT SET clause, so they differ.\n if (\n execution.createdAt === execution.updatedAt &&\n status === \"pending\" &&\n !this.stopping\n ) {\n await this.scheduleProcessing(name, execution.id);\n }\n\n return execution.id;\n }\n\n const execution = await this.executions.create({\n jobName: name,\n payload: validated as Record<string, unknown>,\n status,\n priority,\n maxAttempts,\n scheduledAt,\n });\n\n this.log.debug(`Pushed job '${name}'`, {\n executionId: execution.id,\n status,\n priority: PRIORITY_REVERSE[priority],\n });\n\n // Dispatch to processing if immediate\n if (status === \"pending\" && !this.stopping) {\n await this.scheduleProcessing(name, execution.id);\n }\n\n return execution.id;\n }\n\n public async pushMany(\n name: string,\n items: Array<PushManyItem>,\n ): Promise<string[]> {\n const ids: string[] = [];\n for (const item of items) {\n const id = await this.push(name, item.payload, {\n key: item.key,\n delay: item.delay,\n priority: item.priority,\n scheduledAt: item.scheduledAt,\n });\n ids.push(id);\n }\n return ids;\n }\n\n // --- Trigger (manual / cron) ---\n\n public async trigger(\n name: string,\n context?: JobTriggerContext,\n ): Promise<void> {\n const registration = this.getRegistration(name);\n const opts = registration.options;\n\n if (context?.payload && opts.schema) {\n // Push-based trigger with payload\n const id = await this.push(name, context.payload, {});\n // Update trigger info\n await this.executions.updateById(id, {\n triggeredBy: context?.triggeredBy,\n triggeredByName: context?.triggeredByName,\n });\n return;\n }\n\n // Cron-style or manual trigger without payload\n const maxAttempts = (opts.retry?.retries ?? 0) + 1;\n const priority = PRIORITY_MAP[opts.priority ?? \"normal\"];\n\n const execution = await this.executions.create({\n jobName: name,\n status: \"pending\",\n priority,\n maxAttempts,\n triggeredBy: context?.triggeredBy,\n triggeredByName: context?.triggeredByName,\n });\n\n this.log.debug(`Triggered job '${name}'`, {\n executionId: execution.id,\n triggeredBy: context?.triggeredByName ?? context?.triggeredBy,\n });\n\n if (!this.stopping) {\n await this.scheduleProcessing(name, execution.id);\n }\n }\n\n // --- Cancel ---\n\n public async cancel(\n executionId: string,\n context?: CancelContext,\n ): Promise<void> {\n const execution = await this.executions.findById(executionId);\n if (!execution) {\n throw new AlephaError(`Execution not found: ${executionId}`);\n }\n\n if (\n execution.status === \"completed\" ||\n execution.status === \"dead\" ||\n execution.status === \"cancelled\"\n ) {\n throw new AlephaError(\n `Cannot cancel execution in '${execution.status}' status`,\n );\n }\n\n // If running, trigger the AbortSignal\n const controller = this.abortControllers.get(executionId);\n if (controller) {\n controller.abort();\n }\n\n await this.executions.updateById(executionId, {\n status: \"cancelled\",\n key: null,\n cancelledBy: context?.cancelledBy,\n cancelledByName: context?.cancelledByName,\n completedAt: this.dt.nowISOString(),\n });\n\n this.log.info(`Cancelled execution ${executionId}`, {\n jobName: execution.jobName,\n cancelledBy: context?.cancelledByName ?? context?.cancelledBy,\n });\n }\n\n // --- Execution ---\n\n protected async scheduleProcessing(\n jobName: string,\n executionId: string,\n ): Promise<void> {\n if (this.queueDispatch) {\n this.log.debug(`Dispatching job '${jobName}' via queue`, { executionId });\n await this.queueDispatch(jobName, executionId);\n } else {\n this.log.debug(`Executing job '${jobName}' inline`, { executionId });\n await this.processExecution(jobName, executionId);\n }\n }\n\n public async processExecution(\n jobName: string,\n executionId: string,\n ): Promise<void> {\n const registration = this.getRegistration(jobName);\n\n // Claim the execution atomically\n const claimed = await this.claim(executionId);\n if (!claimed) {\n this.log.debug(`Execution ${executionId} already claimed, skipping`);\n return;\n }\n\n const context = this.alepha.context.createContextId();\n this.logs.set(context, []);\n\n this.log.debug(`Started processing job '${jobName}'`, { executionId });\n\n try {\n await this.alepha.context.run(\n async () => {\n // Create AbortController for timeout + cancellation\n const abortController = new AbortController();\n this.abortControllers.set(executionId, abortController);\n\n // Set up timeout if configured\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const opts = registration.options;\n if (opts.timeout) {\n const ms = this.dt.duration(opts.timeout).as(\"milliseconds\");\n timeoutId = setTimeout(() => abortController.abort(), ms);\n }\n\n const now = this.dt.now();\n\n await this.alepha.events.emit(\"job:begin\", {\n name: jobName,\n now,\n executionId,\n });\n\n try {\n // Build items array\n const execution = await this.executions.findById(executionId);\n const items: Array<JobItem> = [];\n if (execution?.payload) {\n items.push({\n id: executionId,\n payload: execution.payload,\n attempt: execution.attempt,\n });\n }\n\n // Execute handler\n this.log.debug(`Running job '${jobName}'`, {\n executionId,\n attempt: execution?.attempt,\n items: items.length,\n });\n\n await opts.handler({\n items,\n now,\n signal: abortController.signal,\n });\n\n // Success\n await this.executions.updateById(executionId, {\n status: \"completed\",\n completedAt: this.dt.nowISOString(),\n key: null,\n });\n\n this.log.info(`Job '${jobName}' completed`, { executionId });\n\n // Write logs to cold table\n await this.writeLogs(executionId, context);\n\n await this.alepha.events.emit(\n \"job:success\",\n { name: jobName, executionId },\n { catch: true },\n );\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(String(error));\n\n // Check if this was a cancellation\n if (abortController.signal.aborted) {\n // Already marked as cancelled by cancel() or it's a timeout\n const currentExecution =\n await this.executions.findById(executionId);\n if (currentExecution?.status !== \"cancelled\") {\n // Timeout — treat as failure\n await this.handleFailure(executionId, jobName, err, context);\n } else {\n // Was cancelled explicitly — just write logs\n await this.writeLogs(executionId, context);\n await this.alepha.events.emit(\n \"job:cancel\",\n { name: jobName, executionId },\n { catch: true },\n );\n }\n } else {\n await this.handleFailure(executionId, jobName, err, context);\n }\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n this.abortControllers.delete(executionId);\n\n await this.alepha.events.emit(\n \"job:end\",\n { name: jobName, executionId },\n { catch: true },\n );\n }\n },\n { context },\n );\n } finally {\n this.logs.delete(context);\n }\n }\n\n protected async claim(executionId: string): Promise<boolean> {\n const execution = await this.executions.findById(executionId);\n if (!execution) return false;\n\n try {\n await this.executions.updateOne(\n { id: { eq: executionId }, status: { eq: \"pending\" } },\n {\n status: \"running\",\n attempt: execution.attempt + 1,\n startedAt: this.dt.nowISOString(),\n workerId: this.workerId,\n },\n );\n return true;\n } catch {\n return false;\n }\n }\n\n protected async handleFailure(\n executionId: string,\n jobName: string,\n error: Error,\n context: string,\n ): Promise<void> {\n const execution = await this.executions.findById(executionId);\n if (!execution) return;\n\n const registration = this.getRegistration(jobName);\n const opts = registration.options;\n const retryOpts = opts.retry;\n\n const canRetry =\n retryOpts &&\n execution.attempt < execution.maxAttempts &&\n (retryOpts.when ? retryOpts.when(error) : true);\n\n if (canRetry) {\n // Compute next scheduledAt from backoff\n const nextScheduledAt = this.computeBackoff(retryOpts, execution.attempt);\n\n this.log.info(\n `Job '${jobName}' failed, scheduling retry ${execution.attempt}/${execution.maxAttempts}`,\n { executionId, error: error.message, nextScheduledAt },\n );\n\n await this.executions.updateById(executionId, {\n status: \"retrying\",\n error: error.message,\n scheduledAt: nextScheduledAt,\n });\n\n await this.writeLogs(executionId, context);\n\n // Optimistic dispatch: schedule a timeout for the exact backoff delay.\n // The delayed dispatch sweep is the safety net in case of crash.\n const delayMs = Math.max(\n 0,\n new Date(nextScheduledAt).getTime() - this.dt.nowMillis(),\n );\n this.dt.createTimeout(\n () => void this.dispatchRetrying(jobName, executionId),\n delayMs,\n );\n } else {\n // Dead — all retries exhausted or predicate returned false\n this.log.info(\n `Job '${jobName}' is dead after ${execution.attempt} attempt(s)`,\n { executionId, error: error.message },\n );\n\n await this.executions.updateById(executionId, {\n status: \"dead\",\n error: error.message,\n completedAt: this.dt.nowISOString(),\n key: null,\n });\n\n await this.writeLogs(executionId, context);\n }\n\n await this.alepha.events.emit(\n \"job:error\",\n { name: jobName, error, executionId },\n { catch: true },\n );\n }\n\n protected computeBackoff(\n retryOpts: JobRetryOptions,\n attempt: number,\n ): string {\n const now = this.dt.now();\n\n if (!retryOpts.backoff) {\n // Default: 1 second fixed\n return now.add(1, \"second\").toISOString();\n }\n\n // Fixed backoff shorthand: [5, \"second\"]\n if (Array.isArray(retryOpts.backoff)) {\n const delay = this.dt.duration(retryOpts.backoff);\n return now.add(delay).toISOString();\n }\n\n // Exponential backoff\n const backoff = retryOpts.backoff as JobRetryBackoff;\n const initial = this.dt.duration(backoff.initial).as(\"milliseconds\");\n const factor = backoff.factor ?? 2;\n let delayMs = initial * factor ** (attempt - 1);\n\n if (backoff.max) {\n const maxMs = this.dt.duration(backoff.max).as(\"milliseconds\");\n delayMs = Math.min(delayMs, maxMs);\n }\n\n if (backoff.jitter) {\n // Add up to 25% random jitter\n delayMs = delayMs * (0.75 + Math.random() * 0.5);\n }\n\n return now.add(delayMs, \"millisecond\").toISOString();\n }\n\n protected async writeLogs(\n executionId: string,\n context: string,\n ): Promise<void> {\n const entries = this.logs.get(context);\n if (!entries || entries.length === 0) return;\n\n const maxEntries = this.config.logMaxEntries;\n if (maxEntries === 0) return;\n\n let logs = entries;\n if (logs.length > maxEntries) {\n logs = logs.slice(0, maxEntries);\n logs.push({\n level: \"WARN\",\n message: `Log entries truncated at ${maxEntries}`,\n timestamp: this.dt.nowMillis(),\n service: \"alepha.jobs\",\n module: \"JobProvider\",\n } as LogEntry);\n }\n\n try {\n await this.executionLogs.create({\n id: executionId,\n logs,\n });\n } catch {\n // Log write failure is not critical\n this.log.warn(`Failed to write logs for execution ${executionId}`);\n }\n }\n\n protected async dispatchRetrying(\n jobName: string,\n executionId: string,\n ): Promise<void> {\n if (this.stopping) return;\n try {\n await this.executions.updateOne(\n { id: { eq: executionId }, status: { eq: \"retrying\" } },\n { status: \"pending\" },\n );\n await this.scheduleProcessing(jobName, executionId);\n } catch {\n // Already transitioned by another worker or sweep\n }\n }\n\n // --- Internal system sweeps (Section 5 of spec) ---\n\n /**\n * Recovery Sweep (Section 5.1)\n *\n * Runs every `recovery.interval` (default: 1 minute).\n * - Stale `pending` jobs older than `staleThreshold` → re-dispatch.\n * - Crashed `running` jobs older than `max(job.timeout * 2, recovery.runTimeout)` → mark failed, apply retry policy.\n */\n protected async recoverySweep(): Promise<void> {\n this.log.trace(\"Starting recovery sweep\");\n if (this.stopping) return;\n try {\n const now = this.dt.now();\n\n // 1. Stale pending jobs\n const staleThreshold = now\n .subtract(this.config.recovery.staleThreshold, \"millisecond\")\n .toISOString();\n\n const pendingWhere = this.executions.createQueryWhere();\n pendingWhere.status = { eq: \"pending\" };\n pendingWhere.createdAt = { lte: staleThreshold };\n\n const stalePending = await this.executions.findMany({\n where: pendingWhere,\n });\n\n for (const exec of stalePending) {\n if (!this.jobs.has(exec.jobName)) continue;\n this.log.debug(\n `Recovery sweep: re-dispatching stale pending job ${exec.jobName} (${exec.id})`,\n );\n await this.scheduleProcessing(exec.jobName, exec.id);\n }\n\n // 2. Crashed running jobs\n const runningWhere = this.executions.createQueryWhere();\n runningWhere.status = { eq: \"running\" };\n\n const running = await this.executions.findMany({ where: runningWhere });\n const nowMs = now.valueOf();\n\n for (const exec of running) {\n const registration = this.jobs.get(exec.jobName);\n if (!registration) continue;\n\n // If this worker owns it and has an active AbortController, skip (still alive)\n if (this.abortControllers.has(exec.id)) continue;\n\n const opts = registration.options;\n let crashThresholdMs: number;\n if (opts.timeout) {\n crashThresholdMs =\n this.dt.duration(opts.timeout).as(\"milliseconds\") * 2;\n } else {\n crashThresholdMs = this.config.recovery.runTimeout;\n }\n\n const startedAt = exec.startedAt\n ? new Date(exec.startedAt).getTime()\n : 0;\n if (startedAt > 0 && nowMs - startedAt > crashThresholdMs) {\n this.log.warn(\n `Recovery sweep: marking crashed job ${exec.jobName} (${exec.id}) as failed`,\n );\n const error = new Error(\n \"Execution assumed crashed (recovered by sweep)\",\n );\n await this.handleFailure(exec.id, exec.jobName, error, \"\");\n }\n }\n } catch (e) {\n this.log.error(\"Recovery sweep failed\", { error: e });\n }\n }\n\n /**\n * Delayed Dispatch Sweep (Section 5.2)\n *\n * Runs every `delayed.interval` (default: 30 seconds).\n * Scans for `scheduled` and `retrying` jobs where `scheduledAt <= now`,\n * moves them to `pending`, and dispatches to the queue layer.\n */\n protected async delayedDispatchSweep(): Promise<void> {\n this.log.trace(\"Starting delayed dispatch sweep\");\n if (this.stopping) return;\n try {\n const now = this.dt.nowISOString();\n\n const where = this.executions.createQueryWhere();\n where.status = { inArray: [\"scheduled\", \"retrying\"] };\n where.scheduledAt = { lte: now };\n\n const ready = await this.executions.findMany({ where });\n\n for (const exec of ready) {\n if (!this.jobs.has(exec.jobName)) continue;\n await this.executions.updateById(exec.id, { status: \"pending\" });\n await this.scheduleProcessing(exec.jobName, exec.id);\n }\n } catch (e) {\n this.log.error(\"Delayed dispatch sweep failed\", { error: e });\n }\n }\n\n /**\n * Log Purge (Section 5.3)\n *\n * Runs daily at 03:00 via cron.\n * Deletes completed/dead/cancelled execution records older than `logRetentionDays`.\n */\n protected async logPurge(): Promise<void> {\n if (this.stopping) return;\n try {\n const cutoff = this.dt\n .now()\n .subtract(this.config.logRetentionDays, \"day\")\n .toISOString();\n\n const where = this.executions.createQueryWhere();\n where.status = { inArray: [\"completed\", \"dead\", \"cancelled\"] };\n where.completedAt = { lte: cutoff };\n\n const old = await this.executions.findMany({ where });\n\n for (const exec of old) {\n try {\n await this.executionLogs.deleteById(exec.id);\n } catch {\n // Log record may not exist\n }\n await this.executions.deleteById(exec.id);\n }\n\n if (old.length > 0) {\n this.log.info(`Log purge: deleted ${old.length} old execution records`);\n }\n } catch (e) {\n this.log.error(\"Log purge failed\", { error: e });\n }\n }\n\n // --- Lifecycle hooks ---\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n this.workerId = crypto.randomUUID().slice(0, 12);\n this.log.info(`Job system OK`, {\n workerId: this.workerId,\n dispatch: this.queueDispatch ? \"queue\" : \"inline\",\n });\n\n // Set up log capture listener (once)\n this.alepha.events.on(\"log\", ({ entry }) => {\n const ctx = entry.context;\n if (!ctx) return;\n const entries = this.logs.get(ctx);\n if (!entries) return;\n entries.push(entry);\n });\n\n // Run initial sweeps to recover from previous crashes.\n // Skipped on serverless — cron triggers handle periodic sweeps instead.\n if (!this.alepha.isServerless()) {\n await this.delayedDispatchSweep();\n await this.recoverySweep();\n }\n\n // Periodic sweeps via cron (works in serverless environments like Cloudflare Workers)\n this.cronProvider.createCronJob(\n \"_alepha:jobs:recovery\",\n JobProvider.SWEEP_CRON,\n async () => {\n await this.recoverySweep();\n },\n true,\n );\n this.cronProvider.createCronJob(\n \"_alepha:jobs:dispatch\",\n JobProvider.SWEEP_CRON,\n async () => {\n await this.delayedDispatchSweep();\n },\n true,\n );\n\n // Daily log purge\n this.cronProvider.createCronJob(\n \"_alepha:jobs:log-purge\",\n \"0 0 * * *\",\n async () => {\n await this.logPurge();\n },\n true,\n );\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: async () => {\n this.stopping = true;\n\n // Abort any running executions\n for (const controller of this.abortControllers.values()) {\n controller.abort();\n }\n },\n });\n\n // --- Helpers ---\n\n protected getRegistration(name: string): JobRegistration {\n const registration = this.jobs.get(name);\n if (!registration) {\n throw new AlephaError(`Job not registered: ${name}`);\n }\n return registration;\n }\n}\n","import {\n $inject,\n type Async,\n createPrimitive,\n KIND,\n PipelinePrimitive,\n type PipelinePrimitiveOptions,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport type { DateTime, DurationLike } from \"alepha/datetime\";\nimport {\n JobProvider,\n type JobTriggerContext,\n type PushManyItem,\n type PushOptions,\n} from \"../providers/JobProvider.ts\";\n\n/**\n * Job primitive for defining scheduled and on-demand tasks with payload validation, retry policies, and batching.\n */\nexport const $job = <T extends TSchema = TSchema>(\n options: JobPrimitiveOptions<T>,\n): JobPrimitive<T> => {\n return createPrimitive(JobPrimitive<T>, options);\n};\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport interface JobItem<T extends TSchema = TSchema> {\n id: string;\n payload: Static<T>;\n attempt: number;\n}\n\nexport interface JobHandlerArgs<T extends TSchema = TSchema> {\n items: Array<JobItem<T>>;\n now: DateTime;\n signal: AbortSignal;\n}\n\nexport interface JobRetryBackoff {\n initial: DurationLike;\n factor?: number;\n max?: DurationLike;\n jitter?: boolean;\n}\n\nexport interface JobRetryOptions {\n retries: number;\n backoff?: DurationLike | JobRetryBackoff;\n when?: (error: Error) => boolean;\n}\n\nexport interface JobBatchOptions {\n size: number;\n window: DurationLike;\n}\n\nexport type JobPriority = \"critical\" | \"high\" | \"normal\" | \"low\";\n\nexport interface JobPrimitiveOptions<T extends TSchema = TSchema>\n extends PipelinePrimitiveOptions {\n /**\n * Payload schema (TypeBox). Optional for cron-only jobs.\n */\n schema?: T;\n\n /**\n * Cron expression for automatic scheduling.\n */\n cron?: string;\n\n /**\n * Whether to use a distributed lock for cron execution.\n * @default true\n */\n lock?: boolean;\n\n /**\n * Retry policy for failed executions.\n */\n retry?: JobRetryOptions;\n\n /**\n * Max execution time per attempt.\n */\n timeout?: DurationLike;\n\n /**\n * Max parallel executions.\n * @default 1\n */\n concurrency?: number;\n\n /**\n * Consumer batching configuration.\n */\n batch?: JobBatchOptions;\n\n /**\n * Default priority for pushed jobs.\n * @default \"normal\"\n */\n priority?: JobPriority;\n\n /**\n * Handler function for job execution.\n */\n handler: (args: JobHandlerArgs<T>) => Async<void>;\n}\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport class JobPrimitive<\n T extends TSchema = TSchema,\n> extends PipelinePrimitive<JobPrimitiveOptions<T>> {\n protected readonly jobProvider = $inject(JobProvider);\n\n public get name(): string {\n return `${this.config.service.name}.${this.config.propertyKey}`;\n }\n\n protected onInit() {\n const handler = this.handler.run.bind(this.handler);\n this.jobProvider.registerJob(this.name, { ...this.options, handler });\n }\n\n /**\n * Push a single payload or an array of payloads.\n */\n public async push(\n payload: Static<T> | Array<Static<T>>,\n options?: PushOptions,\n ): Promise<string | string[]> {\n if (Array.isArray(payload)) {\n const ids = await Promise.all(\n payload.map((p) => this.jobProvider.push(this.name, p, options)),\n );\n return ids;\n }\n return this.jobProvider.push(this.name, payload, options);\n }\n\n /**\n * Push multiple payloads with per-item options.\n */\n public async pushMany(items: Array<PushManyItem<T>>): Promise<string[]> {\n return this.jobProvider.pushMany(this.name, items);\n }\n\n /**\n * Cancel a running or pending execution.\n */\n public async cancel(executionId: string): Promise<void> {\n return this.jobProvider.cancel(executionId);\n }\n\n /**\n * Manually trigger the job (admin / CLI).\n */\n public async trigger(context?: JobTriggerContext): Promise<void> {\n return this.jobProvider.trigger(this.name, context);\n }\n}\n\n$job[KIND] = JobPrimitive;\n","import { $inject, Alepha, AlephaError, t } from \"alepha\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository, DatabaseProvider, sql } from \"alepha/orm\";\nimport { NotFoundError } from \"alepha/server\";\nimport type { JobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionLogEntity } from \"../entities/jobExecutionLogEntity.ts\";\nimport { $job } from \"../primitives/$job.ts\";\nimport type { JobTriggerContext } from \"../providers/JobProvider.ts\";\nimport { JobProvider } from \"../providers/JobProvider.ts\";\nimport type { JobActivityPoint } from \"../schemas/jobActivitySchema.ts\";\nimport type { JobCronInfo } from \"../schemas/jobCronInfoSchema.ts\";\nimport type { JobExecutionQuery } from \"../schemas/jobExecutionQuerySchema.ts\";\nimport type { JobFailure } from \"../schemas/jobFailureSchema.ts\";\nimport type { JobQueueDepth } from \"../schemas/jobQueueDepthSchema.ts\";\nimport type { JobRegistration } from \"../schemas/jobRegistrationSchema.ts\";\nimport type { JobStats } from \"../schemas/jobStatsSchema.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport class JobService {\n protected readonly alepha = $inject(Alepha);\n protected readonly dt = $inject(DateTimeProvider);\n protected readonly log = $logger();\n protected readonly jobProvider = $inject(JobProvider);\n protected readonly database = $inject(DatabaseProvider);\n protected readonly executions = $repository(jobExecutionEntity);\n protected readonly executionLogs = $repository(jobExecutionLogEntity);\n\n protected computeCan(status: string) {\n return {\n retry: status === \"dead\" || status === \"cancelled\",\n cancel:\n status === \"pending\" ||\n status === \"running\" ||\n status === \"scheduled\" ||\n status === \"retrying\",\n };\n }\n\n /**\n * Convert an ISO date string to the raw SQL parameter format\n * expected by the current database dialect.\n *\n * - PostgreSQL: ISO string (timestamp comparison)\n * - SQLite: epoch milliseconds (integer comparison)\n */\n protected toRawDate(iso: string): string | number {\n return this.database.dialect === \"sqlite\" ? new Date(iso).getTime() : iso;\n }\n\n public async getStats(days?: number): Promise<JobStats> {\n const jobs = this.jobProvider.getRegisteredJobs();\n const periodAgo = this.toRawDate(\n this.dt\n .now()\n .subtract(days ?? 1, \"day\")\n .toISOString(),\n );\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT\n COUNT(*) FILTER (WHERE ${e.status} = 'running') AS running,\n COUNT(*) FILTER (WHERE ${e.status} = 'pending') AS pending,\n COUNT(*) FILTER (WHERE ${e.status} = 'scheduled') AS scheduled,\n COUNT(*) FILTER (WHERE ${e.status} = 'retrying') AS retrying,\n COUNT(*) FILTER (WHERE ${e.status} = 'dead') AS dead,\n COUNT(*) FILTER (WHERE ${e.status} = 'completed' AND ${e.completedAt} >= ${periodAgo}) AS completed_24h,\n COUNT(*) FILTER (WHERE ${e.status} IN ('dead', 'failed') AND ${e.completedAt} >= ${periodAgo}) AS failed_24h\n FROM ${e}\n `,\n t.object({\n running: t.string(),\n pending: t.string(),\n scheduled: t.string(),\n retrying: t.string(),\n dead: t.string(),\n completed_24h: t.string(),\n failed_24h: t.string(),\n }),\n );\n\n const row = rows[0];\n return {\n registered: jobs.size,\n running: Number(row.running),\n pending: Number(row.pending),\n scheduled: Number(row.scheduled),\n retrying: Number(row.retrying),\n dead: Number(row.dead),\n completed: Number(row.completed_24h),\n failed: Number(row.failed_24h),\n };\n }\n\n public getRegistry(): JobRegistration[] {\n const jobs = this.jobProvider.getRegisteredJobs();\n const result: JobRegistration[] = [];\n\n for (const [name, reg] of jobs) {\n const opts = reg.options;\n const hasCron = Boolean(opts.cron);\n const hasSchema = Boolean(opts.schema);\n\n let type: \"cron\" | \"push\" | \"both\";\n if (hasCron && hasSchema) {\n type = \"both\";\n } else if (hasCron) {\n type = \"cron\";\n } else {\n type = \"push\";\n }\n\n const registration: JobRegistration = {\n name,\n type,\n priority: (opts.priority ?? \"normal\") as JobRegistration[\"priority\"],\n concurrency: opts.concurrency ?? 1,\n hasSchema,\n cron: opts.cron,\n timeout: opts.timeout ? String(opts.timeout) : undefined,\n retry: opts.retry\n ? {\n retries: opts.retry.retries,\n hasBackoff: Boolean(opts.retry.backoff),\n }\n : undefined,\n batch: opts.batch\n ? {\n size: opts.batch.size,\n window: String(opts.batch.window),\n }\n : undefined,\n };\n\n result.push(registration);\n }\n\n return result;\n }\n\n public async findExecutions(query: JobExecutionQuery = {}) {\n query.sort ??= \"-createdAt\";\n\n const where = this.executions.createQueryWhere();\n\n if (query.job) {\n where.jobName = { eq: query.job };\n }\n\n if (query.status) {\n where.status = { eq: query.status };\n }\n\n if (query.priority) {\n const priorityMap: Record<string, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n };\n where.priority = { eq: priorityMap[query.priority] };\n }\n\n if (query.from) {\n where.createdAt = { gte: query.from };\n }\n\n if (query.to) {\n where.createdAt = {\n ...(where.createdAt as object),\n lte: query.to,\n };\n }\n\n const page = await this.executions.paginate(\n query,\n { where },\n { count: true },\n );\n return {\n ...page,\n content: page.content.map((exec: JobExecutionEntity) => ({\n ...exec,\n can: this.computeCan(exec.status),\n })),\n };\n }\n\n public async getExecution(id: string) {\n const execution = await this.executions.findById(id);\n if (!execution) {\n throw new NotFoundError(`Execution not found: ${id}`);\n }\n\n const logRecord = await this.executionLogs.findById(id);\n\n return {\n ...execution,\n can: this.computeCan(execution.status),\n logs: logRecord?.logs,\n };\n }\n\n public async triggerJob(\n name: string,\n context?: JobTriggerContext,\n ): Promise<{ ok: boolean }> {\n const jobPrimitives = this.alepha.primitives($job);\n const job = jobPrimitives.find((j) => j.name === name);\n\n if (!job) {\n throw new NotFoundError(`Job not found: ${name}`);\n }\n\n this.log.info(`Triggering job '${name}'`, {\n triggeredBy: context?.triggeredByName ?? context?.triggeredBy,\n });\n\n await job.trigger(context);\n return { ok: true };\n }\n\n public async retryExecution(\n id: string,\n context?: { triggeredBy?: string; triggeredByName?: string },\n ): Promise<{ ok: boolean }> {\n const execution = await this.executions.findById(id);\n if (!execution) {\n throw new NotFoundError(`Execution not found: ${id}`);\n }\n\n if (execution.status !== \"dead\" && execution.status !== \"cancelled\") {\n throw new AlephaError(\n `Cannot retry execution in '${execution.status}' status`,\n );\n }\n\n this.log.info(`Retrying execution ${id}`, {\n jobName: execution.jobName,\n previousStatus: execution.status,\n triggeredBy: context?.triggeredByName ?? context?.triggeredBy,\n });\n\n const jobPrimitives = this.alepha.primitives($job);\n const job = jobPrimitives.find((j) => j.name === execution.jobName);\n\n if (!job) {\n throw new NotFoundError(`Job not found: ${execution.jobName}`);\n }\n\n if (execution.payload) {\n await job.push(execution.payload, {});\n } else {\n await job.trigger({\n triggeredBy: context?.triggeredBy,\n triggeredByName: context?.triggeredByName,\n });\n }\n\n return { ok: true };\n }\n\n public async cancelExecution(\n id: string,\n context?: { cancelledBy?: string; cancelledByName?: string },\n ): Promise<{ ok: boolean }> {\n this.log.info(`Cancelling execution ${id}`, {\n cancelledBy: context?.cancelledByName ?? context?.cancelledBy,\n });\n\n await this.jobProvider.cancel(id, {\n cancelledBy: context?.cancelledBy,\n cancelledByName: context?.cancelledByName,\n });\n return { ok: true };\n }\n\n public async getCronJobs(): Promise<JobCronInfo[]> {\n const jobs = this.jobProvider.getRegisteredJobs();\n const cronJobNames: string[] = [];\n\n for (const [name, reg] of jobs) {\n if (reg.options.cron) cronJobNames.push(name);\n }\n\n const lastByJob = await this.getLastExecutionPerJob(cronJobNames);\n\n const result: JobCronInfo[] = [];\n for (const name of cronJobNames) {\n const reg = jobs.get(name)!;\n const opts = reg.options;\n const last = lastByJob.get(name);\n\n result.push({\n name,\n cron: opts.cron!,\n lock: opts.lock !== false,\n priority: (opts.priority ?? \"normal\") as JobCronInfo[\"priority\"],\n concurrency: opts.concurrency ?? 1,\n hasSchema: Boolean(opts.schema),\n lastExecution: last\n ? {\n id: last.id,\n status: last.status,\n startedAt: last.started_at ?? undefined,\n completedAt: last.completed_at ?? undefined,\n error: last.error ?? undefined,\n }\n : undefined,\n });\n }\n\n return result;\n }\n\n public async getQueueDepth(): Promise<JobQueueDepth[]> {\n const jobs = this.jobProvider.getRegisteredJobs();\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT\n ${e.jobName} AS job_name,\n COUNT(*) FILTER (WHERE ${e.status} = 'pending') AS pending,\n COUNT(*) FILTER (WHERE ${e.status} = 'running') AS running,\n COUNT(*) FILTER (WHERE ${e.status} = 'scheduled') AS scheduled,\n COUNT(*) FILTER (WHERE ${e.status} = 'retrying') AS retrying,\n COUNT(*) FILTER (WHERE ${e.status} = 'dead') AS dead\n FROM ${e}\n WHERE ${e.status} IN ('pending', 'running', 'scheduled', 'retrying', 'dead')\n GROUP BY ${e.jobName}\n `,\n t.object({\n job_name: t.string(),\n pending: t.string(),\n running: t.string(),\n scheduled: t.string(),\n retrying: t.string(),\n dead: t.string(),\n }),\n );\n\n const counts = new Map(rows.map((r) => [r.job_name, r]));\n\n const result: JobQueueDepth[] = [];\n for (const [name, reg] of jobs) {\n const row = counts.get(name);\n result.push({\n jobName: name,\n pending: Number(row?.pending ?? 0),\n running: Number(row?.running ?? 0),\n scheduled: Number(row?.scheduled ?? 0),\n retrying: Number(row?.retrying ?? 0),\n dead: Number(row?.dead ?? 0),\n concurrency: reg.options.concurrency ?? 1,\n });\n }\n\n return result;\n }\n\n public async getActivity(days = 14): Promise<JobActivityPoint[]> {\n if (this.database.dialect === \"sqlite\") {\n return this.getActivitySqlite(days);\n }\n\n const rows = await this.executions.query(\n (e) => sql`\n WITH date_series AS (\n SELECT generate_series(\n CURRENT_DATE - ${days - 1}::int,\n CURRENT_DATE,\n '1 day'::interval\n )::date AS date\n )\n SELECT\n ds.date::text AS date,\n COALESCE(COUNT(*) FILTER (WHERE ${e.status} = 'completed'), 0) AS completed,\n COALESCE(COUNT(*) FILTER (WHERE ${e.status} IN ('dead', 'failed')), 0) AS failed\n FROM date_series ds\n LEFT JOIN ${e} ON DATE(${e.completedAt}) = ds.date\n AND ${e.status} IN ('completed', 'dead', 'failed')\n GROUP BY ds.date\n ORDER BY ds.date ASC\n `,\n t.object({\n date: t.string(),\n completed: t.string(),\n failed: t.string(),\n }),\n );\n\n return rows.map((row) => ({\n date: row.date,\n completed: Number(row.completed),\n failed: Number(row.failed),\n }));\n }\n\n protected async getActivitySqlite(days = 14): Promise<JobActivityPoint[]> {\n const now = this.dt.now();\n const startDate = now.subtract(days - 1, \"day\");\n\n const where = this.executions.createQueryWhere();\n where.status = { inArray: [\"completed\", \"dead\", \"failed\"] };\n where.completedAt = { gte: startDate.startOf(\"day\").toISOString() };\n\n const executions = await this.executions.findMany({ where });\n\n // Build date → counts map\n const byDate = new Map<string, { completed: number; failed: number }>();\n for (let i = 0; i < days; i++) {\n const date = startDate.add(i, \"day\").format(\"YYYY-MM-DD\");\n byDate.set(date, { completed: 0, failed: 0 });\n }\n\n for (const exec of executions) {\n if (!exec.completedAt) continue;\n const date = this.dt.of(exec.completedAt).format(\"YYYY-MM-DD\");\n const entry = byDate.get(date);\n if (!entry) continue;\n if (exec.status === \"completed\") entry.completed++;\n else entry.failed++;\n }\n\n return [...byDate.entries()].map(([date, counts]) => ({\n date,\n ...counts,\n }));\n }\n\n public async getTopFailures(days?: number): Promise<JobFailure[]> {\n const periodAgoIso = this.dt\n .now()\n .subtract(days ?? 7, \"day\")\n .toISOString();\n\n if (this.database.dialect === \"sqlite\") {\n return this.getTopFailuresSqlite(periodAgoIso);\n }\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT\n ${e.jobName} AS job_name,\n COUNT(*) AS failures,\n (ARRAY_AGG(${e.error} ORDER BY ${e.completedAt} DESC))[1] AS last_error\n FROM ${e}\n WHERE ${e.status} IN ('dead', 'failed')\n AND ${e.completedAt} >= ${periodAgoIso}\n GROUP BY ${e.jobName}\n ORDER BY failures DESC\n `,\n t.object({\n job_name: t.string(),\n failures: t.string(),\n last_error: t.optional(t.nullable(t.string())),\n }),\n );\n\n return rows.map((row) => ({\n jobName: row.job_name,\n failures: Number(row.failures),\n lastError: row.last_error ?? undefined,\n }));\n }\n\n protected async getTopFailuresSqlite(\n periodAgoIso: string,\n ): Promise<JobFailure[]> {\n const where = this.executions.createQueryWhere();\n where.status = { inArray: [\"dead\", \"failed\"] };\n where.completedAt = { gte: periodAgoIso };\n\n const failures = await this.executions.findMany({\n where,\n orderBy: { column: \"completedAt\", direction: \"desc\" },\n });\n\n const byJob = new Map<string, { failures: number; lastError?: string }>();\n for (const exec of failures) {\n const entry = byJob.get(exec.jobName) ?? { failures: 0 };\n entry.failures++;\n if (!entry.lastError) entry.lastError = exec.error ?? undefined;\n byJob.set(exec.jobName, entry);\n }\n\n return [...byJob.entries()]\n .map(([jobName, data]) => ({\n jobName,\n failures: data.failures,\n lastError: data.lastError,\n }))\n .sort((a, b) => b.failures - a.failures);\n }\n\n /**\n * Fetch the most recent execution per job name.\n *\n * - PostgreSQL: uses `DISTINCT ON` for a single-pass query\n * - SQLite: uses ORM queries (one per job name) since `DISTINCT ON` is not supported\n */\n protected async getLastExecutionPerJob(jobNames: string[]): Promise<\n Map<\n string,\n {\n id: string;\n job_name: string;\n status: string;\n started_at?: string | null;\n completed_at?: string | null;\n error?: string | null;\n }\n >\n > {\n if (jobNames.length === 0) {\n return new Map();\n }\n\n if (this.database.dialect === \"sqlite\") {\n const result = new Map<string, any>();\n for (const name of jobNames) {\n const rows = await this.executions.findMany({\n where: { jobName: { eq: name } },\n orderBy: { column: \"createdAt\", direction: \"desc\" },\n limit: 1,\n });\n if (rows[0]) {\n result.set(name, {\n id: rows[0].id,\n job_name: rows[0].jobName,\n status: rows[0].status,\n started_at: rows[0].startedAt,\n completed_at: rows[0].completedAt,\n error: rows[0].error,\n });\n }\n }\n return result;\n }\n\n const schema = t.object({\n id: t.string(),\n job_name: t.string(),\n status: t.string(),\n started_at: t.optional(t.nullable(t.string())),\n completed_at: t.optional(t.nullable(t.string())),\n error: t.optional(t.nullable(t.string())),\n });\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT DISTINCT ON (${e.jobName})\n ${e.id}, ${e.jobName} AS job_name, ${e.status},\n ${e.startedAt} AS started_at, ${e.completedAt} AS completed_at, ${e.error}\n FROM ${e}\n WHERE ${e.jobName} IN (${sql.join(\n jobNames.map((n) => sql`${n}`),\n sql`, `,\n )})\n ORDER BY ${e.jobName}, ${e.createdAt} DESC\n `,\n schema,\n );\n\n return new Map(rows.map((r) => [r.job_name, r]));\n }\n}\n","import { $inject, t } from \"alepha\";\nimport { $secure } from \"alepha/security\";\nimport { $action, okSchema } from \"alepha/server\";\nimport {\n jobActivityPointSchema,\n jobActivityQuerySchema,\n} from \"../schemas/jobActivitySchema.ts\";\nimport { jobCronInfoSchema } from \"../schemas/jobCronInfoSchema.ts\";\nimport { jobExecutionDetailResourceSchema } from \"../schemas/jobExecutionDetailResourceSchema.ts\";\nimport { jobExecutionQuerySchema } from \"../schemas/jobExecutionQuerySchema.ts\";\nimport { jobExecutionResourceSchema } from \"../schemas/jobExecutionResourceSchema.ts\";\nimport { jobFailureSchema } from \"../schemas/jobFailureSchema.ts\";\nimport { jobQueueDepthSchema } from \"../schemas/jobQueueDepthSchema.ts\";\nimport { jobRegistrationSchema } from \"../schemas/jobRegistrationSchema.ts\";\nimport { jobStatsSchema } from \"../schemas/jobStatsSchema.ts\";\nimport { triggerJobSchema } from \"../schemas/triggerJobSchema.ts\";\nimport { JobService } from \"../services/JobService.ts\";\n\nexport class AdminJobController {\n protected readonly url: string = \"/jobs\";\n protected readonly group: string = \"admin:jobs\";\n protected readonly jobService = $inject(JobService);\n\n public readonly getJobStats = $action({\n path: `${this.url}/stats`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobActivityQuerySchema,\n response: jobStatsSchema,\n },\n handler: ({ query }) => this.jobService.getStats(query.days),\n });\n\n public readonly getJobRegistry = $action({\n path: this.url,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n response: t.array(jobRegistrationSchema),\n },\n handler: () => this.jobService.getRegistry(),\n });\n\n public readonly findJobExecutions = $action({\n path: `${this.url}/executions`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobExecutionQuerySchema,\n response: t.page(jobExecutionResourceSchema),\n },\n handler: ({ query }) => this.jobService.findExecutions(query),\n });\n\n public readonly getJobExecution = $action({\n path: `${this.url}/executions/:id`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n params: t.object({\n id: t.uuid(),\n }),\n response: jobExecutionDetailResourceSchema,\n },\n handler: ({ params }) => this.jobService.getExecution(params.id),\n });\n\n public readonly triggerJob = $action({\n method: \"POST\",\n path: `${this.url}/trigger`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:trigger\"] })],\n schema: {\n body: triggerJobSchema,\n response: okSchema,\n },\n handler: async ({ body, user }) => {\n return this.jobService.triggerJob(body.name, {\n payload: body.payload,\n triggeredBy: user?.id,\n triggeredByName: user?.name,\n });\n },\n });\n\n public readonly retryJobExecution = $action({\n method: \"POST\",\n path: `${this.url}/executions/:id/retry`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:trigger\"] })],\n schema: {\n params: t.object({\n id: t.uuid(),\n }),\n response: okSchema,\n },\n handler: async ({ params, user }) => {\n return this.jobService.retryExecution(params.id, {\n triggeredBy: user?.id,\n triggeredByName: user?.name,\n });\n },\n });\n\n public readonly cancelJobExecution = $action({\n method: \"POST\",\n path: `${this.url}/executions/:id/cancel`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:cancel\"] })],\n schema: {\n params: t.object({\n id: t.uuid(),\n }),\n response: okSchema,\n },\n handler: async ({ params, user }) => {\n return this.jobService.cancelExecution(params.id, {\n cancelledBy: user?.id,\n cancelledByName: user?.name,\n });\n },\n });\n\n public readonly getJobActivity = $action({\n path: `${this.url}/activity`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobActivityQuerySchema,\n response: t.array(jobActivityPointSchema),\n },\n handler: ({ query }) => this.jobService.getActivity(query.days),\n });\n\n public readonly getCronJobs = $action({\n path: `${this.url}/cron`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n response: t.array(jobCronInfoSchema),\n },\n handler: () => this.jobService.getCronJobs(),\n });\n\n public readonly getJobQueueDepth = $action({\n path: `${this.url}/queue`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n response: t.array(jobQueueDepthSchema),\n },\n handler: () => this.jobService.getQueueDepth(),\n });\n\n public readonly getJobTopFailures = $action({\n path: `${this.url}/failures`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobActivityQuerySchema,\n response: t.array(jobFailureSchema),\n },\n handler: ({ query }) => this.jobService.getTopFailures(query.days),\n });\n}\n","import { $hook, $inject, t } from \"alepha\";\nimport { $queue } from \"alepha/queue\";\nimport { JobProvider } from \"./JobProvider.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\n/**\n * Optional queue-backed dispatch for the job system.\n *\n * When registered, `JobProvider` will push work through this queue instead of\n * executing inline. This is the default for long-running (non-serverless) environments.\n * In serverless environments (Cloudflare Workers, Vercel), this provider is typically\n * omitted so jobs execute inline without requiring an external queue resource.\n */\nexport class JobQueueProvider {\n protected readonly jobProvider = $inject(JobProvider);\n\n protected readonly queue = $queue({\n name: \"_alepha:jobs:dispatch\",\n schema: t.object({ jobName: t.text(), executionId: t.text() }),\n handler: async (msg) => {\n await this.jobProvider.processExecution(\n msg.payload.jobName,\n msg.payload.executionId,\n );\n },\n });\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n this.jobProvider.queueDispatch = (jobName, executionId) =>\n this.push(jobName, executionId);\n },\n });\n\n /**\n * Push a job execution onto the queue for async processing.\n */\n public async push(jobName: string, executionId: string): Promise<void> {\n await this.queue.push({ jobName, executionId });\n }\n}\n","import { $module, type Alepha, type Static, t } from \"alepha\";\nimport { AlephaBatch } from \"alepha/batch\";\nimport type { DateTime } from \"alepha/datetime\";\nimport { AlephaLock } from \"alepha/lock\";\nimport { AlephaQueue } from \"alepha/queue\";\nimport { AlephaScheduler } from \"alepha/scheduler\";\nimport { AdminJobController } from \"./controllers/AdminJobController.ts\";\nimport { JobProvider } from \"./providers/JobProvider.ts\";\nimport { JobQueueProvider } from \"./providers/JobQueueProvider.ts\";\nimport { JobService } from \"./services/JobService.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport * from \"./controllers/AdminJobController.ts\";\nexport * from \"./entities/jobExecutionEntity.ts\";\nexport * from \"./entities/jobExecutionLogEntity.ts\";\nexport * from \"./primitives/$job.ts\";\nexport * from \"./providers/JobProvider.ts\";\nexport * from \"./providers/JobQueueProvider.ts\";\nexport * from \"./schemas/jobActivitySchema.ts\";\nexport * from \"./schemas/jobConfigAtom.ts\";\nexport * from \"./schemas/jobCronInfoSchema.ts\";\nexport * from \"./schemas/jobExecutionDetailResourceSchema.ts\";\nexport * from \"./schemas/jobExecutionQuerySchema.ts\";\nexport * from \"./schemas/jobExecutionResourceSchema.ts\";\nexport * from \"./schemas/jobFailureSchema.ts\";\nexport * from \"./schemas/jobQueueDepthSchema.ts\";\nexport * from \"./schemas/jobRegistrationSchema.ts\";\nexport * from \"./schemas/jobStatsSchema.ts\";\nexport * from \"./schemas/triggerJobSchema.ts\";\nexport * from \"./services/JobService.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof jobEnvSchema>> {}\n\n interface Hooks {\n \"job:begin\": { name: string; now: DateTime; executionId: string };\n \"job:success\": { name: string; executionId: string };\n \"job:error\": { name: string; error: Error; executionId: string };\n \"job:cancel\": { name: string; executionId: string };\n \"job:end\": { name: string; executionId: string };\n }\n}\n\n// -----------------------------------------------------------------------------------------------------------------\n\nconst jobEnvSchema = t.object({\n /**\n * Controls whether the job system dispatches work through a queue or executes inline.\n *\n * - `1` — always use queue (force queue even in serverless)\n * - `0` — never use queue (force inline, useful for testing)\n * - not set — auto: use queue when NOT serverless (default)\n */\n ALEPHA_JOBS_QUEUE: t.optional(\n t.integer({\n description:\n \"Set to 1 to always use queue, 0 to disable queue (default: auto-detect based on environment)\",\n }),\n ),\n});\n\n// -----------------------------------------------------------------------------------------------------------------\n\n/**\n * Job execution framework — unified primitive for deferred, scheduled, and queued work.\n *\n * **Features:**\n * - Push-based jobs with typed payloads\n * - Cron scheduling with execution tracking\n * - Retry with exponential backoff\n * - Priority, delay, cancellation\n * - Deduplication via unique keys\n * - Per-execution log capture\n *\n * @module alepha.api.jobs\n */\nexport const AlephaApiJobs = $module({\n name: \"alepha.api.jobs\",\n services: [\n AlephaQueue,\n AlephaScheduler,\n AlephaLock,\n AlephaBatch,\n JobProvider,\n JobQueueProvider,\n JobService,\n AdminJobController,\n ],\n register: (alepha: Alepha) => {\n const env = alepha.parseEnv(jobEnvSchema);\n const useQueue =\n env.ALEPHA_JOBS_QUEUE === 1\n ? true\n : env.ALEPHA_JOBS_QUEUE === 0\n ? false\n : !alepha.isServerless();\n\n alepha.with(AlephaScheduler);\n alepha.with(AlephaLock);\n alepha.with(AlephaBatch);\n alepha.with(JobProvider);\n alepha.with(JobService);\n alepha.with(AdminJobController);\n\n if (useQueue) {\n alepha.with(AlephaQueue);\n alepha.with(JobQueueProvider);\n }\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/api/jobs/schemas/jobActivitySchema.ts","../../../src/api/jobs/schemas/jobCronInfoSchema.ts","../../../src/api/jobs/entities/jobExecutionEntity.ts","../../../src/api/jobs/schemas/jobExecutionResourceSchema.ts","../../../src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts","../../../src/api/jobs/schemas/jobExecutionQuerySchema.ts","../../../src/api/jobs/schemas/jobFailureSchema.ts","../../../src/api/jobs/schemas/jobQueueDepthSchema.ts","../../../src/api/jobs/schemas/jobRegistrationSchema.ts","../../../src/api/jobs/schemas/jobStatsSchema.ts","../../../src/api/jobs/schemas/triggerJobSchema.ts","../../../src/api/jobs/entities/jobExecutionLogEntity.ts","../../../src/api/jobs/schemas/jobConfigAtom.ts","../../../src/api/jobs/providers/JobProvider.ts","../../../src/api/jobs/primitives/$job.ts","../../../src/api/jobs/services/JobService.ts","../../../src/api/jobs/controllers/AdminJobController.ts","../../../src/api/jobs/providers/JobQueueProvider.ts","../../../src/api/jobs/index.ts"],"sourcesContent":["import { type Static, t } from \"alepha\";\n\nexport const jobActivityPointSchema = t.object({\n date: t.text(),\n completed: t.integer(),\n failed: t.integer(),\n});\n\nexport type JobActivityPoint = Static<typeof jobActivityPointSchema>;\n\nexport const jobActivityQuerySchema = t.object({\n days: t.optional(t.integer({ minimum: 1, maximum: 90 })),\n});\n\nexport type JobActivityQuery = Static<typeof jobActivityQuerySchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobCronInfoSchema = t.object({\n name: t.text(),\n cron: t.text(),\n lock: t.boolean(),\n priority: t.enum([\"critical\", \"high\", \"normal\", \"low\"]),\n concurrency: t.integer(),\n hasSchema: t.boolean(),\n paused: t.boolean(),\n lastExecution: t.optional(\n t.object({\n id: t.uuid(),\n status: t.text(),\n startedAt: t.optional(t.datetime()),\n completedAt: t.optional(t.datetime()),\n error: t.optional(t.text()),\n }),\n ),\n});\n\nexport type JobCronInfo = Static<typeof jobCronInfoSchema>;\n","import { type Static, t } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const jobExecutionEntity = $entity({\n name: \"job_executions\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n\n jobName: t.text(),\n key: t.optional(t.nullable(t.text())),\n\n payload: t.optional(t.record(t.text(), t.any())),\n status: db.default(\n t.enum([\n \"pending\",\n \"scheduled\",\n \"retrying\",\n \"running\",\n \"completed\",\n \"dead\",\n \"cancelled\",\n ]),\n \"pending\",\n ),\n priority: db.default(t.integer({ minimum: 0, maximum: 3 }), 2),\n\n attempt: db.default(t.integer(), 0),\n maxAttempts: db.default(t.integer(), 1),\n\n scheduledAt: t.optional(t.datetime()),\n startedAt: t.optional(t.datetime()),\n completedAt: t.optional(t.datetime()),\n\n result: t.optional(t.record(t.text(), t.any())),\n error: t.optional(t.text()),\n workerId: t.optional(t.text()),\n\n triggeredBy: t.optional(t.text()),\n triggeredByName: t.optional(t.text()),\n cancelledBy: t.optional(t.text()),\n cancelledByName: t.optional(t.text()),\n }),\n indexes: [\n { columns: [\"jobName\", \"status\", \"priority\", \"scheduledAt\"] },\n { columns: [\"jobName\", \"status\", \"startedAt\"] },\n { columns: [\"jobName\", \"completedAt\"] },\n { columns: [\"jobName\", \"key\"], unique: true },\n ],\n});\n\nexport type JobExecutionEntity = Static<typeof jobExecutionEntity.schema>;\n\nexport type JobStatus =\n | \"pending\"\n | \"scheduled\"\n | \"retrying\"\n | \"running\"\n | \"completed\"\n | \"dead\"\n | \"cancelled\";\n","import { type Static, t } from \"alepha\";\nimport { jobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\n\nexport const jobExecutionCanSchema = t.object({\n retry: t.boolean(),\n cancel: t.boolean(),\n});\n\nexport const jobExecutionResourceSchema = t.extend(\n jobExecutionEntity.schema,\n {\n can: jobExecutionCanSchema,\n },\n {\n title: \"JobExecutionResource\",\n description: \"A job execution resource.\",\n },\n);\n\nexport type JobExecutionResource = Static<typeof jobExecutionResourceSchema>;\n","import { type Static, t } from \"alepha\";\nimport { logEntrySchema } from \"alepha/logger\";\nimport { jobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionCanSchema } from \"./jobExecutionResourceSchema.ts\";\n\nexport const jobExecutionDetailResourceSchema = t.extend(\n jobExecutionEntity.schema,\n {\n can: jobExecutionCanSchema,\n logs: t.optional(t.array(logEntrySchema)),\n },\n {\n title: \"JobExecutionDetailResource\",\n description: \"A job execution resource with logs.\",\n },\n);\n\nexport type JobExecutionDetailResource = Static<\n typeof jobExecutionDetailResourceSchema\n>;\n","import { type Static, t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\n\nexport const jobExecutionQuerySchema = t.extend(pageQuerySchema, {\n job: t.optional(\n t.text({\n description: \"Filter by job name\",\n }),\n ),\n status: t.optional(\n t.enum([\n \"pending\",\n \"scheduled\",\n \"retrying\",\n \"running\",\n \"completed\",\n \"dead\",\n \"cancelled\",\n ]),\n ),\n priority: t.optional(t.enum([\"critical\", \"high\", \"normal\", \"low\"])),\n from: t.optional(\n t.datetime({\n description: \"From date (ISO)\",\n }),\n ),\n to: t.optional(\n t.datetime({\n description: \"To date (ISO)\",\n }),\n ),\n});\n\nexport type JobExecutionQuery = Static<typeof jobExecutionQuerySchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobFailureSchema = t.object({\n jobName: t.text(),\n failures: t.integer(),\n lastError: t.optional(t.text()),\n});\n\nexport type JobFailure = Static<typeof jobFailureSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobQueueDepthSchema = t.object({\n jobName: t.text(),\n pending: t.integer(),\n running: t.integer(),\n scheduled: t.integer(),\n retrying: t.integer(),\n dead: t.integer(),\n concurrency: t.integer(),\n paused: t.boolean(),\n});\n\nexport type JobQueueDepth = Static<typeof jobQueueDepthSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobRegistrationSchema = t.object({\n name: t.text(),\n type: t.enum([\"cron\", \"push\", \"both\"]),\n priority: t.enum([\"critical\", \"high\", \"normal\", \"low\"]),\n concurrency: t.integer(),\n hasSchema: t.boolean(),\n cron: t.optional(t.text()),\n timeout: t.optional(t.text()),\n retry: t.optional(\n t.object({\n retries: t.integer(),\n hasBackoff: t.boolean(),\n }),\n ),\n paused: t.boolean(),\n});\n\nexport type JobRegistration = Static<typeof jobRegistrationSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const jobStatsSchema = t.object({\n registered: t.integer(),\n running: t.integer(),\n pending: t.integer(),\n scheduled: t.integer(),\n retrying: t.integer(),\n dead: t.integer(),\n completed: t.integer(),\n failed: t.integer(),\n});\n\nexport type JobStats = Static<typeof jobStatsSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const triggerJobSchema = t.object({\n name: t.text(),\n payload: t.optional(t.record(t.text(), t.any())),\n});\n\nexport type TriggerJob = Static<typeof triggerJobSchema>;\n","import { type Static, t } from \"alepha\";\nimport { logEntrySchema } from \"alepha/logger\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const jobExecutionLogEntity = $entity({\n name: \"job_execution_logs\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n logs: t.array(logEntrySchema),\n }),\n});\n\nexport type JobExecutionLogEntity = Static<typeof jobExecutionLogEntity.schema>;\n","import { $atom, type Static, t } from \"alepha\";\n\nexport const jobConfig = $atom({\n name: \"alepha.jobs\",\n description: \"Configuration for the $job v2 primitive.\",\n schema: t.object({\n recovery: t.object({\n interval: t.integer({ description: \"Sweep interval (ms).\" }),\n staleThreshold: t.integer({\n description: \"Pending age (ms) before re-dispatch.\",\n }),\n runTimeout: t.integer({\n description:\n \"Running age (ms) before assumed crash. Used as fallback when no per-job timeout is set.\",\n }),\n }),\n delayed: t.object({\n interval: t.integer({ description: \"Sweep interval (ms).\" }),\n }),\n logRetentionDays: t.integer({\n description: \"Days to keep completed/dead executions.\",\n }),\n logMaxEntries: t.integer({\n description: \"Max log entries captured per execution.\",\n }),\n drainTimeout: t.integer({\n description: \"Max time (ms) to wait for in-flight jobs during shutdown.\",\n }),\n }),\n default: {\n recovery: {\n interval: 300_000,\n staleThreshold: 300_000,\n runTimeout: 1_800_000,\n },\n delayed: {\n interval: 300_000,\n },\n logRetentionDays: 30,\n logMaxEntries: 100,\n drainTimeout: 30_000,\n },\n});\n\nexport type JobConfig = Static<typeof jobConfig.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [jobConfig.key]: JobConfig;\n }\n}\n","import {\n $hook,\n $inject,\n $state,\n Alepha,\n AlephaError,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport { DateTimeProvider, type DurationLike } from \"alepha/datetime\";\nimport { LockProvider } from \"alepha/lock\";\nimport type { LogEntry } from \"alepha/logger\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport { CronProvider } from \"alepha/scheduler\";\nimport {\n type JobStatus,\n jobExecutionEntity,\n} from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionLogEntity } from \"../entities/jobExecutionLogEntity.ts\";\nimport type {\n JobItem,\n JobPrimitiveOptions,\n JobPriority,\n JobRetryBackoff,\n JobRetryOptions,\n} from \"../primitives/$job.ts\";\nimport { jobConfig } from \"../schemas/jobConfigAtom.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\nconst PRIORITY_MAP: Record<string, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n};\n\nconst PRIORITY_REVERSE: Record<number, JobPriority> = {\n 0: \"critical\",\n 1: \"high\",\n 2: \"normal\",\n 3: \"low\",\n};\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport interface PushOptions {\n delay?: DurationLike;\n key?: string;\n priority?: JobPriority;\n scheduledAt?: Date;\n}\n\nexport interface PushManyItem<T extends TSchema = TSchema> {\n payload: Static<T>;\n key?: string;\n delay?: DurationLike;\n priority?: JobPriority;\n scheduledAt?: Date;\n}\n\nexport interface JobTriggerContext {\n payload?: Record<string, unknown>;\n triggeredBy?: string;\n triggeredByName?: string;\n}\n\nexport interface CancelContext {\n cancelledBy?: string;\n cancelledByName?: string;\n}\n\ninterface JobRegistration {\n name: string;\n options: JobPrimitiveOptions;\n}\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport class JobProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly dt = $inject(DateTimeProvider);\n protected readonly cronProvider = $inject(CronProvider);\n protected readonly lockProvider = $inject(LockProvider);\n protected readonly config = $state(jobConfig);\n protected readonly log = $logger();\n protected readonly executions = $repository(jobExecutionEntity);\n protected readonly executionLogs = $repository(jobExecutionLogEntity);\n\n protected readonly jobs = new Map<string, JobRegistration>();\n protected readonly pausedJobs = new Set<string>();\n protected readonly inFlight = new Set<Promise<void>>();\n\n /**\n * When set, job executions are dispatched through a queue (e.g. `JobQueueProvider`).\n * When null, jobs execute inline (fire-and-forget). Useful for serverless environments.\n */\n public queueDispatch:\n | ((jobName: string, executionId: string) => Promise<void>)\n | null = null;\n protected readonly logs = new Map<string, LogEntry[]>();\n protected readonly abortControllers = new Map<string, AbortController>();\n protected static readonly SWEEP_CRON = \"*/5 * * * *\";\n protected stopping = false;\n protected workerId = \"\";\n\n // --- Registration ---\n\n public registerJob(name: string, options: JobPrimitiveOptions): void {\n if (this.jobs.has(name)) {\n throw new AlephaError(`Job already registered: ${name}`);\n }\n\n this.jobs.set(name, { name, options });\n this.log.debug(`Registered job '${name}'`, {\n cron: options.cron,\n priority: options.priority ?? \"normal\",\n retries: options.retry?.retries ?? 0,\n });\n\n if (options.cron) {\n this.cronProvider.createCronJob(name, options.cron, async () => {\n try {\n await this.trigger(name, {\n triggeredBy: \"system\",\n triggeredByName: \"system (cron)\",\n });\n } catch (error) {\n this.log.error(`Cron trigger failed for job '${name}'`, error);\n }\n });\n }\n }\n\n /**\n * Get all registered job definitions.\n */\n public getRegisteredJobs(): Map<string, JobRegistration> {\n return this.jobs;\n }\n\n // --- Push ---\n\n public async push(\n name: string,\n payload: unknown,\n options?: PushOptions,\n ): Promise<string> {\n const registration = this.getRegistration(name);\n const opts = registration.options;\n\n if (!opts.schema) {\n throw new AlephaError(\n `Cannot push to job '${name}': no schema defined. Use trigger() for cron-only jobs.`,\n );\n }\n\n const validated = this.alepha.codec.validate(opts.schema, payload);\n\n const priority =\n PRIORITY_MAP[options?.priority ?? opts.priority ?? \"normal\"];\n const maxAttempts = (opts.retry?.retries ?? 0) + 1;\n\n const isDelayed = options?.delay || options?.scheduledAt;\n const status: JobStatus = isDelayed ? \"scheduled\" : \"pending\";\n\n let scheduledAt: string | undefined;\n if (options?.scheduledAt) {\n scheduledAt = options.scheduledAt.toISOString();\n } else if (options?.delay) {\n const now = this.dt.now();\n scheduledAt = now.add(this.dt.duration(options.delay)).toISOString();\n }\n\n // Keyed path: atomic upsert to avoid race between concurrent pushes\n if (options?.key) {\n const now = this.dt.nowISOString();\n const execution = await this.executions.upsert(\n {\n jobName: name,\n key: options.key,\n payload: validated as Record<string, unknown>,\n status,\n priority,\n maxAttempts,\n scheduledAt,\n createdAt: now,\n updatedAt: now,\n },\n { target: [\"jobName\", \"key\"], set: {}, now },\n );\n\n // Fresh insert: both timestamps equal the explicit `now` value.\n // Conflict: updatedAt was bumped by the ON CONFLICT SET clause, so they differ.\n if (\n execution.createdAt === execution.updatedAt &&\n status === \"pending\" &&\n !this.stopping\n ) {\n await this.scheduleProcessing(name, execution.id);\n }\n\n return execution.id;\n }\n\n const execution = await this.executions.create({\n jobName: name,\n payload: validated as Record<string, unknown>,\n status,\n priority,\n maxAttempts,\n scheduledAt,\n });\n\n this.log.debug(`Pushed job '${name}'`, {\n executionId: execution.id,\n status,\n priority: PRIORITY_REVERSE[priority],\n });\n\n // Dispatch to processing if immediate\n if (status === \"pending\" && !this.stopping) {\n await this.scheduleProcessing(name, execution.id);\n }\n\n return execution.id;\n }\n\n public async pushMany(\n name: string,\n items: Array<PushManyItem>,\n ): Promise<string[]> {\n if (items.length === 0) return [];\n\n const registration = this.getRegistration(name);\n const opts = registration.options;\n\n if (!opts.schema) {\n throw new AlephaError(\n `Cannot push to job '${name}': no schema defined. Use trigger() for cron-only jobs.`,\n );\n }\n\n const maxAttempts = (opts.retry?.retries ?? 0) + 1;\n\n // Keyed items need upsert logic — fall back to individual push\n const keyed: PushManyItem[] = [];\n const bulkRows: Array<{\n jobName: string;\n payload: Record<string, unknown>;\n status: JobStatus;\n priority: number;\n maxAttempts: number;\n scheduledAt?: string;\n }> = [];\n\n for (const item of items) {\n const validated = this.alepha.codec.validate(opts.schema, item.payload);\n if (item.key) {\n keyed.push({ ...item, payload: validated as Static<TSchema> });\n } else {\n const isDelayed = item.delay || item.scheduledAt;\n const status: JobStatus = isDelayed ? \"scheduled\" : \"pending\";\n let scheduledAt: string | undefined;\n if (item.scheduledAt) {\n scheduledAt = item.scheduledAt.toISOString();\n } else if (item.delay) {\n scheduledAt = this.dt\n .now()\n .add(this.dt.duration(item.delay))\n .toISOString();\n }\n bulkRows.push({\n jobName: name,\n payload: validated as Record<string, unknown>,\n status,\n priority: PRIORITY_MAP[item.priority ?? opts.priority ?? \"normal\"],\n maxAttempts,\n scheduledAt,\n });\n }\n }\n\n const ids: string[] = [];\n\n // Keyed: sequential upserts\n for (const item of keyed) {\n const id = await this.push(name, item.payload, {\n key: item.key,\n delay: item.delay,\n priority: item.priority,\n scheduledAt: item.scheduledAt,\n });\n ids.push(id);\n }\n\n // Non-keyed: single bulk insert\n if (bulkRows.length > 0) {\n const created = await this.executions.createMany(bulkRows);\n for (const exec of created) {\n ids.push(exec.id);\n if (exec.status === \"pending\" && !this.stopping) {\n await this.scheduleProcessing(name, exec.id);\n }\n }\n }\n\n this.log.debug(`pushMany '${name}': ${ids.length} jobs created`, {\n bulk: bulkRows.length,\n keyed: keyed.length,\n });\n\n return ids;\n }\n\n // --- Trigger (manual / cron) ---\n\n public async trigger(\n name: string,\n context?: JobTriggerContext,\n ): Promise<void> {\n const registration = this.getRegistration(name);\n const opts = registration.options;\n\n if (context?.payload && opts.schema) {\n // Push-based trigger with payload\n const id = await this.push(name, context.payload, {});\n // Update trigger info\n await this.executions.updateById(id, {\n triggeredBy: context?.triggeredBy,\n triggeredByName: context?.triggeredByName,\n });\n return;\n }\n\n // Cron-style or manual trigger without payload\n const maxAttempts = (opts.retry?.retries ?? 0) + 1;\n const priority = PRIORITY_MAP[opts.priority ?? \"normal\"];\n\n const execution = await this.executions.create({\n jobName: name,\n status: \"pending\",\n priority,\n maxAttempts,\n triggeredBy: context?.triggeredBy,\n triggeredByName: context?.triggeredByName,\n });\n\n this.log.debug(`Triggered job '${name}'`, {\n executionId: execution.id,\n triggeredBy: context?.triggeredByName ?? context?.triggeredBy,\n });\n\n if (!this.stopping) {\n await this.scheduleProcessing(name, execution.id);\n }\n }\n\n // --- Cancel ---\n\n public async cancel(\n executionId: string,\n context?: CancelContext,\n ): Promise<void> {\n const execution = await this.executions.findById(executionId);\n if (!execution) {\n throw new AlephaError(`Execution not found: ${executionId}`);\n }\n\n if (\n execution.status === \"completed\" ||\n execution.status === \"dead\" ||\n execution.status === \"cancelled\"\n ) {\n throw new AlephaError(\n `Cannot cancel execution in '${execution.status}' status`,\n );\n }\n\n // If running, trigger the AbortSignal\n const controller = this.abortControllers.get(executionId);\n if (controller) {\n controller.abort();\n }\n\n await this.executions.updateById(executionId, {\n status: \"cancelled\",\n key: null,\n cancelledBy: context?.cancelledBy,\n cancelledByName: context?.cancelledByName,\n completedAt: this.dt.nowISOString(),\n });\n\n this.log.info(`Cancelled execution ${executionId}`, {\n jobName: execution.jobName,\n cancelledBy: context?.cancelledByName ?? context?.cancelledBy,\n });\n }\n\n // --- Execution ---\n\n protected async scheduleProcessing(\n jobName: string,\n executionId: string,\n ): Promise<void> {\n if (this.pausedJobs.has(jobName)) {\n this.log.debug(`Job '${jobName}' is paused, deferring`, { executionId });\n return;\n }\n\n const registration = this.getRegistration(jobName);\n const maxConcurrency = registration.options.concurrency ?? 1;\n const runningCount = await this.executions.count({\n jobName: { eq: jobName },\n status: { eq: \"running\" },\n });\n if (runningCount >= maxConcurrency) {\n this.log.debug(\n `Job '${jobName}' at concurrency limit (${runningCount}/${maxConcurrency}), deferring`,\n { executionId },\n );\n return;\n }\n\n if (this.queueDispatch) {\n this.log.debug(`Dispatching job '${jobName}' via queue`, { executionId });\n await this.queueDispatch(jobName, executionId);\n } else {\n this.log.debug(`Executing job '${jobName}' inline`, { executionId });\n await this.processExecution(jobName, executionId);\n }\n }\n\n public async processExecution(\n jobName: string,\n executionId: string,\n ): Promise<void> {\n const promise = this.processExecutionInner(jobName, executionId);\n this.inFlight.add(promise);\n try {\n await promise;\n } finally {\n this.inFlight.delete(promise);\n }\n }\n\n protected async processExecutionInner(\n jobName: string,\n executionId: string,\n ): Promise<void> {\n const registration = this.getRegistration(jobName);\n\n // Claim the execution atomically\n const claimed = await this.claim(executionId);\n if (!claimed) {\n this.log.debug(`Execution ${executionId} already claimed, skipping`);\n return;\n }\n\n const context = this.alepha.context.createContextId();\n this.logs.set(context, []);\n\n this.log.debug(`Started processing job '${jobName}'`, { executionId });\n\n try {\n await this.alepha.context.run(\n async () => {\n // Create AbortController for timeout + cancellation\n const abortController = new AbortController();\n this.abortControllers.set(executionId, abortController);\n\n // Set up timeout if configured\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const opts = registration.options;\n if (opts.timeout) {\n const ms = this.dt.duration(opts.timeout).as(\"milliseconds\");\n timeoutId = setTimeout(() => abortController.abort(), ms);\n }\n\n const now = this.dt.now();\n\n await this.alepha.events.emit(\"job:begin\", {\n name: jobName,\n now,\n executionId,\n });\n\n try {\n // Build items array\n const execution = await this.executions.findById(executionId);\n const items: Array<JobItem> = [];\n if (execution?.payload) {\n items.push({\n id: executionId,\n payload: execution.payload,\n attempt: execution.attempt,\n });\n }\n\n // Execute handler\n this.log.debug(`Running job '${jobName}'`, {\n executionId,\n attempt: execution?.attempt,\n items: items.length,\n });\n\n await opts.handler({\n items,\n now,\n signal: abortController.signal,\n });\n\n // Success\n await this.executions.updateById(executionId, {\n status: \"completed\",\n completedAt: this.dt.nowISOString(),\n key: null,\n });\n\n this.log.info(`Job '${jobName}' completed`, { executionId });\n\n // Write logs to cold table\n await this.writeLogs(executionId, context);\n\n await this.alepha.events.emit(\n \"job:success\",\n { name: jobName, executionId },\n { catch: true },\n );\n } catch (error) {\n const err =\n error instanceof Error ? error : new Error(String(error));\n\n // Check if this was a cancellation\n if (abortController.signal.aborted) {\n // Already marked as cancelled by cancel() or it's a timeout\n const currentExecution =\n await this.executions.findById(executionId);\n if (currentExecution?.status !== \"cancelled\") {\n // Timeout — treat as failure\n await this.handleFailure(executionId, jobName, err, context);\n } else {\n // Was cancelled explicitly — just write logs\n await this.writeLogs(executionId, context);\n await this.alepha.events.emit(\n \"job:cancel\",\n { name: jobName, executionId },\n { catch: true },\n );\n }\n } else {\n await this.handleFailure(executionId, jobName, err, context);\n }\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n this.abortControllers.delete(executionId);\n\n await this.alepha.events.emit(\n \"job:end\",\n { name: jobName, executionId },\n { catch: true },\n );\n\n // A slot just opened — dispatch next pending job if any\n await this.dispatchNextPending(jobName);\n }\n },\n { context },\n );\n } finally {\n this.logs.delete(context);\n }\n }\n\n /**\n * After a job finishes (success, failure, or cancel), dispatch any pending\n * jobs that were deferred due to the concurrency limit.\n */\n protected async dispatchNextPending(jobName: string): Promise<void> {\n if (this.stopping || this.pausedJobs.has(jobName)) return;\n\n const registration = this.jobs.get(jobName);\n if (!registration) return;\n\n const maxConcurrency = registration.options.concurrency ?? 1;\n const runningCount = await this.executions.count({\n jobName: { eq: jobName },\n status: { eq: \"running\" },\n });\n\n const available = maxConcurrency - runningCount;\n if (available <= 0) return;\n\n const pending = await this.executions.findMany({\n where: { jobName: { eq: jobName }, status: { eq: \"pending\" } },\n orderBy: { column: \"priority\", direction: \"asc\" },\n limit: available,\n });\n\n for (const exec of pending) {\n await this.scheduleProcessing(jobName, exec.id);\n }\n }\n\n protected async claim(executionId: string): Promise<boolean> {\n const execution = await this.executions.findById(executionId);\n if (!execution) return false;\n\n try {\n await this.executions.updateOne(\n { id: { eq: executionId }, status: { eq: \"pending\" } },\n {\n status: \"running\",\n attempt: execution.attempt + 1,\n startedAt: this.dt.nowISOString(),\n workerId: this.workerId,\n },\n );\n return true;\n } catch {\n return false;\n }\n }\n\n protected async handleFailure(\n executionId: string,\n jobName: string,\n error: Error,\n context: string,\n ): Promise<void> {\n const execution = await this.executions.findById(executionId);\n if (!execution) return;\n\n const registration = this.getRegistration(jobName);\n const opts = registration.options;\n const retryOpts = opts.retry;\n\n const canRetry =\n retryOpts &&\n execution.attempt < execution.maxAttempts &&\n (retryOpts.when ? retryOpts.when(error) : true);\n\n if (canRetry) {\n // Compute next scheduledAt from backoff\n const nextScheduledAt = this.computeBackoff(retryOpts, execution.attempt);\n\n this.log.info(\n `Job '${jobName}' failed, scheduling retry ${execution.attempt}/${execution.maxAttempts}`,\n { executionId, error: error.message, nextScheduledAt },\n );\n\n await this.executions.updateById(executionId, {\n status: \"retrying\",\n error: error.message,\n scheduledAt: nextScheduledAt,\n });\n\n await this.writeLogs(executionId, context);\n\n // Optimistic dispatch: schedule a timeout for the exact backoff delay.\n // The delayed dispatch sweep is the safety net in case of crash.\n const delayMs = Math.max(\n 0,\n new Date(nextScheduledAt).getTime() - this.dt.nowMillis(),\n );\n this.dt.createTimeout(\n () => void this.dispatchRetrying(jobName, executionId),\n delayMs,\n );\n } else {\n // Dead — all retries exhausted or predicate returned false\n this.log.info(\n `Job '${jobName}' is dead after ${execution.attempt} attempt(s)`,\n { executionId, error: error.message },\n );\n\n await this.executions.updateById(executionId, {\n status: \"dead\",\n error: error.message,\n completedAt: this.dt.nowISOString(),\n key: null,\n });\n\n await this.writeLogs(executionId, context);\n }\n\n await this.alepha.events.emit(\n \"job:error\",\n { name: jobName, error, executionId },\n { catch: true },\n );\n }\n\n protected computeBackoff(\n retryOpts: JobRetryOptions,\n attempt: number,\n ): string {\n const now = this.dt.now();\n\n if (!retryOpts.backoff) {\n // Default: 1 second fixed\n return now.add(1, \"second\").toISOString();\n }\n\n // Fixed backoff shorthand: [5, \"second\"]\n if (Array.isArray(retryOpts.backoff)) {\n const delay = this.dt.duration(retryOpts.backoff);\n return now.add(delay).toISOString();\n }\n\n // Exponential backoff\n const backoff = retryOpts.backoff as JobRetryBackoff;\n const initial = this.dt.duration(backoff.initial).as(\"milliseconds\");\n const factor = backoff.factor ?? 2;\n let delayMs = initial * factor ** (attempt - 1);\n\n if (backoff.max) {\n const maxMs = this.dt.duration(backoff.max).as(\"milliseconds\");\n delayMs = Math.min(delayMs, maxMs);\n }\n\n if (backoff.jitter) {\n // Add up to 25% random jitter\n delayMs = delayMs * (0.75 + Math.random() * 0.5);\n }\n\n return now.add(delayMs, \"millisecond\").toISOString();\n }\n\n protected async writeLogs(\n executionId: string,\n context: string,\n ): Promise<void> {\n const entries = this.logs.get(context);\n if (!entries || entries.length === 0) return;\n\n const maxEntries = this.config.logMaxEntries;\n if (maxEntries === 0) return;\n\n let logs = entries;\n if (logs.length > maxEntries) {\n logs = logs.slice(0, maxEntries);\n logs.push({\n level: \"WARN\",\n message: `Log entries truncated at ${maxEntries}`,\n timestamp: this.dt.nowMillis(),\n service: \"alepha.jobs\",\n module: \"JobProvider\",\n } as LogEntry);\n }\n\n try {\n await this.executionLogs.create({\n id: executionId,\n logs,\n });\n } catch {\n // Log write failure is not critical\n this.log.warn(`Failed to write logs for execution ${executionId}`);\n }\n }\n\n protected async dispatchRetrying(\n jobName: string,\n executionId: string,\n ): Promise<void> {\n if (this.stopping) return;\n try {\n await this.executions.updateOne(\n { id: { eq: executionId }, status: { eq: \"retrying\" } },\n { status: \"pending\" },\n );\n await this.scheduleProcessing(jobName, executionId);\n } catch {\n // Already transitioned by another worker or sweep\n }\n }\n\n // --- Internal system sweeps (Section 5 of spec) ---\n\n /**\n * Recovery Sweep (Section 5.1)\n *\n * Runs every `recovery.interval` (default: 1 minute).\n * - Stale `pending` jobs older than `staleThreshold` → re-dispatch.\n * - Crashed `running` jobs older than `max(job.timeout * 2, recovery.runTimeout)` → mark failed, apply retry policy.\n */\n protected async recoverySweep(): Promise<void> {\n this.log.trace(\"Starting recovery sweep\");\n if (this.stopping) return;\n\n const acquired = await this.tryLock(\"_alepha:jobs:recovery-lock\", 300_000);\n if (!acquired) return;\n\n try {\n const now = this.dt.now();\n\n // 1. Stale pending jobs (priority-ordered)\n const staleThreshold = now\n .subtract(this.config.recovery.staleThreshold, \"millisecond\")\n .toISOString();\n\n const pendingWhere = this.executions.createQueryWhere();\n pendingWhere.status = { eq: \"pending\" };\n pendingWhere.createdAt = { lte: staleThreshold };\n\n const stalePending = await this.executions.findMany({\n where: pendingWhere,\n orderBy: { column: \"priority\", direction: \"asc\" },\n });\n\n for (const exec of stalePending) {\n if (!this.jobs.has(exec.jobName)) continue;\n this.log.debug(\n `Recovery sweep: re-dispatching stale pending job ${exec.jobName} (${exec.id})`,\n );\n await this.scheduleProcessing(exec.jobName, exec.id);\n }\n\n // 2. Crashed running jobs\n const runningWhere = this.executions.createQueryWhere();\n runningWhere.status = { eq: \"running\" };\n\n const running = await this.executions.findMany({ where: runningWhere });\n const nowMs = now.valueOf();\n\n for (const exec of running) {\n const registration = this.jobs.get(exec.jobName);\n if (!registration) continue;\n\n // If this worker owns it and has an active AbortController, skip (still alive)\n if (this.abortControllers.has(exec.id)) continue;\n\n const opts = registration.options;\n let crashThresholdMs: number;\n if (opts.timeout) {\n crashThresholdMs =\n this.dt.duration(opts.timeout).as(\"milliseconds\") * 2;\n } else {\n crashThresholdMs = this.config.recovery.runTimeout;\n }\n\n const startedAt = exec.startedAt\n ? new Date(exec.startedAt).getTime()\n : 0;\n if (startedAt > 0 && nowMs - startedAt > crashThresholdMs) {\n this.log.warn(\n `Recovery sweep: marking crashed job ${exec.jobName} (${exec.id}) as failed`,\n );\n const error = new Error(\n \"Execution assumed crashed (recovered by sweep)\",\n );\n await this.handleFailure(exec.id, exec.jobName, error, \"\");\n }\n }\n } catch (e) {\n this.log.error(\"Recovery sweep failed\", { error: e });\n } finally {\n await this.releaseLock(\"_alepha:jobs:recovery-lock\");\n }\n }\n\n /**\n * Delayed Dispatch Sweep (Section 5.2)\n *\n * Runs every `delayed.interval` (default: 30 seconds).\n * Scans for `scheduled` and `retrying` jobs where `scheduledAt <= now`,\n * moves them to `pending`, and dispatches to the queue layer.\n */\n protected async delayedDispatchSweep(): Promise<void> {\n this.log.trace(\"Starting delayed dispatch sweep\");\n if (this.stopping) return;\n\n const acquired = await this.tryLock(\"_alepha:jobs:dispatch-lock\", 60_000);\n if (!acquired) return;\n\n try {\n const now = this.dt.nowISOString();\n\n const where = this.executions.createQueryWhere();\n where.status = { inArray: [\"scheduled\", \"retrying\"] };\n where.scheduledAt = { lte: now };\n\n const ready = await this.executions.findMany({\n where,\n orderBy: { column: \"priority\", direction: \"asc\" },\n });\n\n for (const exec of ready) {\n if (!this.jobs.has(exec.jobName)) continue;\n await this.executions.updateById(exec.id, { status: \"pending\" });\n await this.scheduleProcessing(exec.jobName, exec.id);\n }\n } catch (e) {\n this.log.error(\"Delayed dispatch sweep failed\", { error: e });\n } finally {\n await this.releaseLock(\"_alepha:jobs:dispatch-lock\");\n }\n }\n\n /**\n * Log Purge (Section 5.3)\n *\n * Runs daily at 03:00 via cron.\n * Deletes completed/dead/cancelled execution records older than `logRetentionDays`.\n */\n protected async logPurge(): Promise<void> {\n if (this.stopping) return;\n try {\n const cutoff = this.dt\n .now()\n .subtract(this.config.logRetentionDays, \"day\")\n .toISOString();\n\n const where = this.executions.createQueryWhere();\n where.status = { inArray: [\"completed\", \"dead\", \"cancelled\"] };\n where.completedAt = { lte: cutoff };\n\n // Bulk-delete logs first (FK-safe), then executions\n const expiredIds = await this.executions.findMany({\n where,\n columns: [\"id\"] as any,\n });\n if (expiredIds.length > 0) {\n const ids = expiredIds.map((e) => e.id);\n await this.executionLogs.deleteMany({ id: { inArray: ids } });\n await this.executions.deleteMany({ id: { inArray: ids } });\n this.log.info(`Log purge: deleted ${ids.length} old execution records`);\n }\n } catch (e) {\n this.log.error(\"Log purge failed\", { error: e });\n }\n }\n\n // --- Pause / Resume ---\n\n public pauseJob(name: string): void {\n this.getRegistration(name);\n this.pausedJobs.add(name);\n this.log.info(`Paused job '${name}'`);\n }\n\n public async resumeJob(name: string): Promise<void> {\n this.getRegistration(name);\n this.pausedJobs.delete(name);\n this.log.info(`Resumed job '${name}'`);\n\n // Dispatch any pending items for this job\n const pending = await this.executions.findMany({\n where: { jobName: { eq: name }, status: { eq: \"pending\" } },\n orderBy: { column: \"priority\", direction: \"asc\" },\n });\n for (const exec of pending) {\n await this.scheduleProcessing(name, exec.id);\n }\n }\n\n public isJobPaused(name: string): boolean {\n return this.pausedJobs.has(name);\n }\n\n public getPausedJobs(): string[] {\n return [...this.pausedJobs];\n }\n\n // --- Lock helpers ---\n\n protected async tryLock(key: string, ttlMs: number): Promise<boolean> {\n const lockValue = `${this.workerId},${this.dt.nowISOString()}`;\n const result = await this.lockProvider.set(key, lockValue, true, ttlMs);\n const [lockId] = result.split(\",\");\n return lockId === this.workerId;\n }\n\n protected async releaseLock(key: string): Promise<void> {\n await this.lockProvider.del(key);\n }\n\n // --- Lifecycle hooks ---\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n this.workerId = crypto.randomUUID().slice(0, 12);\n this.log.info(`Job system OK`, {\n workerId: this.workerId,\n dispatch: this.queueDispatch ? \"queue\" : \"inline\",\n });\n\n // Set up log capture listener (once)\n this.alepha.events.on(\"log\", ({ entry }) => {\n const ctx = entry.context;\n if (!ctx) return;\n const entries = this.logs.get(ctx);\n if (!entries) return;\n entries.push(entry);\n });\n\n // Run initial sweeps to recover from previous crashes.\n // Skipped on serverless — cron triggers handle periodic sweeps instead.\n if (!this.alepha.isServerless()) {\n await this.delayedDispatchSweep();\n await this.recoverySweep();\n }\n\n // Periodic sweeps via cron (works in serverless environments like Cloudflare Workers)\n this.cronProvider.createCronJob(\n \"_alepha:jobs:recovery\",\n JobProvider.SWEEP_CRON,\n async () => {\n await this.recoverySweep();\n },\n true,\n );\n this.cronProvider.createCronJob(\n \"_alepha:jobs:dispatch\",\n JobProvider.SWEEP_CRON,\n async () => {\n await this.delayedDispatchSweep();\n },\n true,\n );\n\n // Daily log purge\n this.cronProvider.createCronJob(\n \"_alepha:jobs:log-purge\",\n \"0 0 * * *\",\n async () => {\n await this.logPurge();\n },\n true,\n );\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: async () => {\n this.stopping = true;\n\n // Drain: wait for in-flight jobs to finish before aborting\n if (this.inFlight.size > 0) {\n this.log.info(`Draining ${this.inFlight.size} in-flight job(s)...`);\n await Promise.race([\n Promise.allSettled([...this.inFlight]),\n this.dt.wait([this.config.drainTimeout, \"millisecond\"]),\n ]);\n }\n\n // Abort any still-running executions after drain timeout\n if (this.abortControllers.size > 0) {\n this.log.warn(\n `Aborting ${this.abortControllers.size} remaining job(s) after drain timeout`,\n );\n for (const controller of this.abortControllers.values()) {\n controller.abort();\n }\n }\n },\n });\n\n // --- Helpers ---\n\n protected getRegistration(name: string): JobRegistration {\n const registration = this.jobs.get(name);\n if (!registration) {\n throw new AlephaError(`Job not registered: ${name}`);\n }\n return registration;\n }\n}\n","import {\n $inject,\n type Async,\n createPrimitive,\n KIND,\n PipelinePrimitive,\n type PipelinePrimitiveOptions,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport type { DateTime, DurationLike } from \"alepha/datetime\";\nimport {\n JobProvider,\n type JobTriggerContext,\n type PushManyItem,\n type PushOptions,\n} from \"../providers/JobProvider.ts\";\n\n/**\n * Job primitive for defining scheduled and on-demand tasks with payload validation and retry policies.\n */\nexport const $job = <T extends TSchema = TSchema>(\n options: JobPrimitiveOptions<T>,\n): JobPrimitive<T> => {\n return createPrimitive(JobPrimitive<T>, options);\n};\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport interface JobItem<T extends TSchema = TSchema> {\n id: string;\n payload: Static<T>;\n attempt: number;\n}\n\nexport interface JobHandlerArgs<T extends TSchema = TSchema> {\n items: Array<JobItem<T>>;\n now: DateTime;\n signal: AbortSignal;\n}\n\nexport interface JobRetryBackoff {\n initial: DurationLike;\n factor?: number;\n max?: DurationLike;\n jitter?: boolean;\n}\n\nexport interface JobRetryOptions {\n retries: number;\n backoff?: DurationLike | JobRetryBackoff;\n when?: (error: Error) => boolean;\n}\n\nexport type JobPriority = \"critical\" | \"high\" | \"normal\" | \"low\";\n\nexport interface JobPrimitiveOptions<T extends TSchema = TSchema>\n extends PipelinePrimitiveOptions {\n /**\n * Payload schema (TypeBox). Optional for cron-only jobs.\n */\n schema?: T;\n\n /**\n * Cron expression for automatic scheduling.\n */\n cron?: string;\n\n /**\n * Whether to use a distributed lock for cron execution.\n * @default true\n */\n lock?: boolean;\n\n /**\n * Retry policy for failed executions.\n */\n retry?: JobRetryOptions;\n\n /**\n * Max execution time per attempt.\n */\n timeout?: DurationLike;\n\n /**\n * Max parallel executions.\n * @default 1\n */\n concurrency?: number;\n\n /**\n * Default priority for pushed jobs.\n * @default \"normal\"\n */\n priority?: JobPriority;\n\n /**\n * Handler function for job execution.\n */\n handler: (args: JobHandlerArgs<T>) => Async<void>;\n}\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport class JobPrimitive<\n T extends TSchema = TSchema,\n> extends PipelinePrimitive<JobPrimitiveOptions<T>> {\n protected readonly jobProvider = $inject(JobProvider);\n\n public get name(): string {\n return `${this.config.service.name}.${this.config.propertyKey}`;\n }\n\n protected onInit() {\n const handler = this.handler.run.bind(this.handler);\n this.jobProvider.registerJob(this.name, { ...this.options, handler });\n }\n\n /**\n * Push a single payload or an array of payloads.\n */\n public async push(\n payload: Static<T> | Array<Static<T>>,\n options?: PushOptions,\n ): Promise<string | string[]> {\n if (Array.isArray(payload)) {\n const ids = await Promise.all(\n payload.map((p) => this.jobProvider.push(this.name, p, options)),\n );\n return ids;\n }\n return this.jobProvider.push(this.name, payload, options);\n }\n\n /**\n * Push multiple payloads with per-item options.\n */\n public async pushMany(items: Array<PushManyItem<T>>): Promise<string[]> {\n return this.jobProvider.pushMany(this.name, items);\n }\n\n /**\n * Cancel a running or pending execution.\n */\n public async cancel(executionId: string): Promise<void> {\n return this.jobProvider.cancel(executionId);\n }\n\n /**\n * Manually trigger the job (admin / CLI).\n */\n public async trigger(context?: JobTriggerContext): Promise<void> {\n return this.jobProvider.trigger(this.name, context);\n }\n\n /**\n * Pause this job. Pushed items are still accepted but processing is held.\n */\n public pause(): void {\n this.jobProvider.pauseJob(this.name);\n }\n\n /**\n * Resume a paused job and dispatch any pending items.\n */\n public async resume(): Promise<void> {\n return this.jobProvider.resumeJob(this.name);\n }\n\n /**\n * Whether this job is currently paused.\n */\n public get paused(): boolean {\n return this.jobProvider.isJobPaused(this.name);\n }\n}\n\n$job[KIND] = JobPrimitive;\n","import { $inject, Alepha, AlephaError, t } from \"alepha\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository, DatabaseProvider, sql } from \"alepha/orm\";\nimport { NotFoundError } from \"alepha/server\";\nimport type { JobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionEntity } from \"../entities/jobExecutionEntity.ts\";\nimport { jobExecutionLogEntity } from \"../entities/jobExecutionLogEntity.ts\";\nimport { $job } from \"../primitives/$job.ts\";\nimport type { JobTriggerContext } from \"../providers/JobProvider.ts\";\nimport { JobProvider } from \"../providers/JobProvider.ts\";\nimport type { JobActivityPoint } from \"../schemas/jobActivitySchema.ts\";\nimport type { JobCronInfo } from \"../schemas/jobCronInfoSchema.ts\";\nimport type { JobExecutionQuery } from \"../schemas/jobExecutionQuerySchema.ts\";\nimport type { JobFailure } from \"../schemas/jobFailureSchema.ts\";\nimport type { JobQueueDepth } from \"../schemas/jobQueueDepthSchema.ts\";\nimport type { JobRegistration } from \"../schemas/jobRegistrationSchema.ts\";\nimport type { JobStats } from \"../schemas/jobStatsSchema.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport class JobService {\n protected readonly alepha = $inject(Alepha);\n protected readonly dt = $inject(DateTimeProvider);\n protected readonly log = $logger();\n protected readonly jobProvider = $inject(JobProvider);\n protected readonly database = $inject(DatabaseProvider);\n protected readonly executions = $repository(jobExecutionEntity);\n protected readonly executionLogs = $repository(jobExecutionLogEntity);\n\n protected computeCan(status: string) {\n return {\n retry: status === \"dead\" || status === \"cancelled\",\n cancel:\n status === \"pending\" ||\n status === \"running\" ||\n status === \"scheduled\" ||\n status === \"retrying\",\n };\n }\n\n /**\n * Convert an ISO date string to the raw SQL parameter format\n * expected by the current database dialect.\n *\n * - PostgreSQL: ISO string (timestamp comparison)\n * - SQLite: epoch milliseconds (integer comparison)\n */\n protected toRawDate(iso: string): string | number {\n return this.database.dialect === \"sqlite\" ? new Date(iso).getTime() : iso;\n }\n\n public async getStats(days?: number): Promise<JobStats> {\n const jobs = this.jobProvider.getRegisteredJobs();\n const periodAgo = this.toRawDate(\n this.dt\n .now()\n .subtract(days ?? 1, \"day\")\n .toISOString(),\n );\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT\n COUNT(*) FILTER (WHERE ${e.status} = 'running') AS running,\n COUNT(*) FILTER (WHERE ${e.status} = 'pending') AS pending,\n COUNT(*) FILTER (WHERE ${e.status} = 'scheduled') AS scheduled,\n COUNT(*) FILTER (WHERE ${e.status} = 'retrying') AS retrying,\n COUNT(*) FILTER (WHERE ${e.status} = 'dead') AS dead,\n COUNT(*) FILTER (WHERE ${e.status} = 'completed' AND ${e.completedAt} >= ${periodAgo}) AS completed_24h,\n COUNT(*) FILTER (WHERE ${e.status} = 'dead' AND ${e.completedAt} >= ${periodAgo}) AS failed_24h\n FROM ${e}\n `,\n t.object({\n running: t.string(),\n pending: t.string(),\n scheduled: t.string(),\n retrying: t.string(),\n dead: t.string(),\n completed_24h: t.string(),\n failed_24h: t.string(),\n }),\n );\n\n const row = rows[0];\n return {\n registered: jobs.size,\n running: Number(row.running),\n pending: Number(row.pending),\n scheduled: Number(row.scheduled),\n retrying: Number(row.retrying),\n dead: Number(row.dead),\n completed: Number(row.completed_24h),\n failed: Number(row.failed_24h),\n };\n }\n\n public getRegistry(): JobRegistration[] {\n const jobs = this.jobProvider.getRegisteredJobs();\n const result: JobRegistration[] = [];\n\n for (const [name, reg] of jobs) {\n const opts = reg.options;\n const hasCron = Boolean(opts.cron);\n const hasSchema = Boolean(opts.schema);\n\n let type: \"cron\" | \"push\" | \"both\";\n if (hasCron && hasSchema) {\n type = \"both\";\n } else if (hasCron) {\n type = \"cron\";\n } else {\n type = \"push\";\n }\n\n const registration: JobRegistration = {\n name,\n type,\n priority: (opts.priority ?? \"normal\") as JobRegistration[\"priority\"],\n concurrency: opts.concurrency ?? 1,\n hasSchema,\n cron: opts.cron,\n timeout: opts.timeout ? String(opts.timeout) : undefined,\n retry: opts.retry\n ? {\n retries: opts.retry.retries,\n hasBackoff: Boolean(opts.retry.backoff),\n }\n : undefined,\n paused: this.jobProvider.isJobPaused(name),\n };\n\n result.push(registration);\n }\n\n return result;\n }\n\n public async findExecutions(query: JobExecutionQuery = {}) {\n query.sort ??= \"-createdAt\";\n\n const where = this.executions.createQueryWhere();\n\n if (query.job) {\n where.jobName = { eq: query.job };\n }\n\n if (query.status) {\n where.status = { eq: query.status };\n }\n\n if (query.priority) {\n const priorityMap: Record<string, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n };\n where.priority = { eq: priorityMap[query.priority] };\n }\n\n if (query.from) {\n where.createdAt = { gte: query.from };\n }\n\n if (query.to) {\n where.createdAt = {\n ...(where.createdAt as object),\n lte: query.to,\n };\n }\n\n const page = await this.executions.paginate(\n query,\n { where },\n { count: true },\n );\n return {\n ...page,\n content: page.content.map((exec: JobExecutionEntity) => ({\n ...exec,\n can: this.computeCan(exec.status),\n })),\n };\n }\n\n public async getExecution(id: string) {\n const execution = await this.executions.findById(id);\n if (!execution) {\n throw new NotFoundError(`Execution not found: ${id}`);\n }\n\n const logRecord = await this.executionLogs.findById(id);\n\n return {\n ...execution,\n can: this.computeCan(execution.status),\n logs: logRecord?.logs,\n };\n }\n\n public async triggerJob(\n name: string,\n context?: JobTriggerContext,\n ): Promise<{ ok: boolean }> {\n const jobPrimitives = this.alepha.primitives($job);\n const job = jobPrimitives.find((j) => j.name === name);\n\n if (!job) {\n throw new NotFoundError(`Job not found: ${name}`);\n }\n\n this.log.info(`Triggering job '${name}'`, {\n triggeredBy: context?.triggeredByName ?? context?.triggeredBy,\n });\n\n await job.trigger(context);\n return { ok: true };\n }\n\n public async retryExecution(\n id: string,\n context?: { triggeredBy?: string; triggeredByName?: string },\n ): Promise<{ ok: boolean }> {\n const execution = await this.executions.findById(id);\n if (!execution) {\n throw new NotFoundError(`Execution not found: ${id}`);\n }\n\n if (execution.status !== \"dead\" && execution.status !== \"cancelled\") {\n throw new AlephaError(\n `Cannot retry execution in '${execution.status}' status`,\n );\n }\n\n this.log.info(`Retrying execution ${id}`, {\n jobName: execution.jobName,\n previousStatus: execution.status,\n triggeredBy: context?.triggeredByName ?? context?.triggeredBy,\n });\n\n const jobPrimitives = this.alepha.primitives($job);\n const job = jobPrimitives.find((j) => j.name === execution.jobName);\n\n if (!job) {\n throw new NotFoundError(`Job not found: ${execution.jobName}`);\n }\n\n if (execution.payload) {\n await job.push(execution.payload, {});\n } else {\n await job.trigger({\n triggeredBy: context?.triggeredBy,\n triggeredByName: context?.triggeredByName,\n });\n }\n\n return { ok: true };\n }\n\n public async cancelExecution(\n id: string,\n context?: { cancelledBy?: string; cancelledByName?: string },\n ): Promise<{ ok: boolean }> {\n this.log.info(`Cancelling execution ${id}`, {\n cancelledBy: context?.cancelledByName ?? context?.cancelledBy,\n });\n\n await this.jobProvider.cancel(id, {\n cancelledBy: context?.cancelledBy,\n cancelledByName: context?.cancelledByName,\n });\n return { ok: true };\n }\n\n public pauseJob(\n name: string,\n context?: { pausedBy?: string; pausedByName?: string },\n ): { ok: boolean } {\n const jobPrimitives = this.alepha.primitives($job);\n const job = jobPrimitives.find((j) => j.name === name);\n\n if (!job) {\n throw new NotFoundError(`Job not found: ${name}`);\n }\n\n this.log.info(`Pausing job '${name}'`, {\n pausedBy: context?.pausedByName ?? context?.pausedBy,\n });\n\n job.pause();\n return { ok: true };\n }\n\n public async resumeJob(\n name: string,\n context?: { resumedBy?: string; resumedByName?: string },\n ): Promise<{ ok: boolean }> {\n const jobPrimitives = this.alepha.primitives($job);\n const job = jobPrimitives.find((j) => j.name === name);\n\n if (!job) {\n throw new NotFoundError(`Job not found: ${name}`);\n }\n\n this.log.info(`Resuming job '${name}'`, {\n resumedBy: context?.resumedByName ?? context?.resumedBy,\n });\n\n await job.resume();\n return { ok: true };\n }\n\n public getPausedJobs(): string[] {\n return this.jobProvider.getPausedJobs();\n }\n\n public async getCronJobs(): Promise<JobCronInfo[]> {\n const jobs = this.jobProvider.getRegisteredJobs();\n const cronJobNames: string[] = [];\n\n for (const [name, reg] of jobs) {\n if (reg.options.cron) cronJobNames.push(name);\n }\n\n const lastByJob = await this.getLastExecutionPerJob(cronJobNames);\n\n const result: JobCronInfo[] = [];\n for (const name of cronJobNames) {\n const reg = jobs.get(name)!;\n const opts = reg.options;\n const last = lastByJob.get(name);\n\n result.push({\n name,\n cron: opts.cron!,\n lock: opts.lock !== false,\n priority: (opts.priority ?? \"normal\") as JobCronInfo[\"priority\"],\n concurrency: opts.concurrency ?? 1,\n hasSchema: Boolean(opts.schema),\n paused: this.jobProvider.isJobPaused(name),\n lastExecution: last\n ? {\n id: last.id,\n status: last.status,\n startedAt: last.started_at ?? undefined,\n completedAt: last.completed_at ?? undefined,\n error: last.error ?? undefined,\n }\n : undefined,\n });\n }\n\n return result;\n }\n\n public async getQueueDepth(): Promise<JobQueueDepth[]> {\n const jobs = this.jobProvider.getRegisteredJobs();\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT\n ${e.jobName} AS job_name,\n COUNT(*) FILTER (WHERE ${e.status} = 'pending') AS pending,\n COUNT(*) FILTER (WHERE ${e.status} = 'running') AS running,\n COUNT(*) FILTER (WHERE ${e.status} = 'scheduled') AS scheduled,\n COUNT(*) FILTER (WHERE ${e.status} = 'retrying') AS retrying,\n COUNT(*) FILTER (WHERE ${e.status} = 'dead') AS dead\n FROM ${e}\n WHERE ${e.status} IN ('pending', 'running', 'scheduled', 'retrying', 'dead')\n GROUP BY ${e.jobName}\n `,\n t.object({\n job_name: t.string(),\n pending: t.string(),\n running: t.string(),\n scheduled: t.string(),\n retrying: t.string(),\n dead: t.string(),\n }),\n );\n\n const counts = new Map(rows.map((r) => [r.job_name, r]));\n\n const result: JobQueueDepth[] = [];\n for (const [name, reg] of jobs) {\n const row = counts.get(name);\n result.push({\n jobName: name,\n pending: Number(row?.pending ?? 0),\n running: Number(row?.running ?? 0),\n scheduled: Number(row?.scheduled ?? 0),\n retrying: Number(row?.retrying ?? 0),\n dead: Number(row?.dead ?? 0),\n concurrency: reg.options.concurrency ?? 1,\n paused: this.jobProvider.isJobPaused(name),\n });\n }\n\n return result;\n }\n\n public async getActivity(days = 14): Promise<JobActivityPoint[]> {\n if (this.database.dialect === \"sqlite\") {\n return this.getActivitySqlite(days);\n }\n\n const rows = await this.executions.query(\n (e) => sql`\n WITH date_series AS (\n SELECT generate_series(\n CURRENT_DATE - ${days - 1}::int,\n CURRENT_DATE,\n '1 day'::interval\n )::date AS date\n )\n SELECT\n ds.date::text AS date,\n COALESCE(COUNT(*) FILTER (WHERE ${e.status} = 'completed'), 0) AS completed,\n COALESCE(COUNT(*) FILTER (WHERE ${e.status} = 'dead'), 0) AS failed\n FROM date_series ds\n LEFT JOIN ${e} ON DATE(${e.completedAt}) = ds.date\n AND ${e.status} IN ('completed', 'dead')\n GROUP BY ds.date\n ORDER BY ds.date ASC\n `,\n t.object({\n date: t.string(),\n completed: t.string(),\n failed: t.string(),\n }),\n );\n\n return rows.map((row) => ({\n date: row.date,\n completed: Number(row.completed),\n failed: Number(row.failed),\n }));\n }\n\n protected async getActivitySqlite(days = 14): Promise<JobActivityPoint[]> {\n const now = this.dt.now();\n const startDate = now.subtract(days - 1, \"day\");\n\n const where = this.executions.createQueryWhere();\n where.status = { inArray: [\"completed\", \"dead\"] };\n where.completedAt = { gte: startDate.startOf(\"day\").toISOString() };\n\n const executions = await this.executions.findMany({ where });\n\n // Build date → counts map\n const byDate = new Map<string, { completed: number; failed: number }>();\n for (let i = 0; i < days; i++) {\n const date = startDate.add(i, \"day\").format(\"YYYY-MM-DD\");\n byDate.set(date, { completed: 0, failed: 0 });\n }\n\n for (const exec of executions) {\n if (!exec.completedAt) continue;\n const date = this.dt.of(exec.completedAt).format(\"YYYY-MM-DD\");\n const entry = byDate.get(date);\n if (!entry) continue;\n if (exec.status === \"completed\") entry.completed++;\n else entry.failed++;\n }\n\n return [...byDate.entries()].map(([date, counts]) => ({\n date,\n ...counts,\n }));\n }\n\n public async getTopFailures(days?: number): Promise<JobFailure[]> {\n const periodAgoIso = this.dt\n .now()\n .subtract(days ?? 7, \"day\")\n .toISOString();\n\n if (this.database.dialect === \"sqlite\") {\n return this.getTopFailuresSqlite(periodAgoIso);\n }\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT\n ${e.jobName} AS job_name,\n COUNT(*) AS failures,\n (ARRAY_AGG(${e.error} ORDER BY ${e.completedAt} DESC))[1] AS last_error\n FROM ${e}\n WHERE ${e.status} = 'dead'\n AND ${e.completedAt} >= ${periodAgoIso}\n GROUP BY ${e.jobName}\n ORDER BY failures DESC\n `,\n t.object({\n job_name: t.string(),\n failures: t.string(),\n last_error: t.optional(t.nullable(t.string())),\n }),\n );\n\n return rows.map((row) => ({\n jobName: row.job_name,\n failures: Number(row.failures),\n lastError: row.last_error ?? undefined,\n }));\n }\n\n protected async getTopFailuresSqlite(\n periodAgoIso: string,\n ): Promise<JobFailure[]> {\n const where = this.executions.createQueryWhere();\n where.status = { eq: \"dead\" };\n where.completedAt = { gte: periodAgoIso };\n\n const failures = await this.executions.findMany({\n where,\n orderBy: { column: \"completedAt\", direction: \"desc\" },\n });\n\n const byJob = new Map<string, { failures: number; lastError?: string }>();\n for (const exec of failures) {\n const entry = byJob.get(exec.jobName) ?? { failures: 0 };\n entry.failures++;\n if (!entry.lastError) entry.lastError = exec.error ?? undefined;\n byJob.set(exec.jobName, entry);\n }\n\n return [...byJob.entries()]\n .map(([jobName, data]) => ({\n jobName,\n failures: data.failures,\n lastError: data.lastError,\n }))\n .sort((a, b) => b.failures - a.failures);\n }\n\n /**\n * Fetch the most recent execution per job name.\n *\n * - PostgreSQL: uses `DISTINCT ON` for a single-pass query\n * - SQLite: uses ORM queries (one per job name) since `DISTINCT ON` is not supported\n */\n protected async getLastExecutionPerJob(jobNames: string[]): Promise<\n Map<\n string,\n {\n id: string;\n job_name: string;\n status: string;\n started_at?: string | null;\n completed_at?: string | null;\n error?: string | null;\n }\n >\n > {\n if (jobNames.length === 0) {\n return new Map();\n }\n\n if (this.database.dialect === \"sqlite\") {\n const result = new Map<string, any>();\n for (const name of jobNames) {\n const rows = await this.executions.findMany({\n where: { jobName: { eq: name } },\n orderBy: { column: \"createdAt\", direction: \"desc\" },\n limit: 1,\n });\n if (rows[0]) {\n result.set(name, {\n id: rows[0].id,\n job_name: rows[0].jobName,\n status: rows[0].status,\n started_at: rows[0].startedAt,\n completed_at: rows[0].completedAt,\n error: rows[0].error,\n });\n }\n }\n return result;\n }\n\n const schema = t.object({\n id: t.string(),\n job_name: t.string(),\n status: t.string(),\n started_at: t.optional(t.nullable(t.string())),\n completed_at: t.optional(t.nullable(t.string())),\n error: t.optional(t.nullable(t.string())),\n });\n\n const rows = await this.executions.query(\n (e) => sql`\n SELECT DISTINCT ON (${e.jobName})\n ${e.id}, ${e.jobName} AS job_name, ${e.status},\n ${e.startedAt} AS started_at, ${e.completedAt} AS completed_at, ${e.error}\n FROM ${e}\n WHERE ${e.jobName} IN (${sql.join(\n jobNames.map((n) => sql`${n}`),\n sql`, `,\n )})\n ORDER BY ${e.jobName}, ${e.createdAt} DESC\n `,\n schema,\n );\n\n return new Map(rows.map((r) => [r.job_name, r]));\n }\n}\n","import { $inject, t } from \"alepha\";\nimport { $secure } from \"alepha/security\";\nimport { $action, okSchema } from \"alepha/server\";\nimport {\n jobActivityPointSchema,\n jobActivityQuerySchema,\n} from \"../schemas/jobActivitySchema.ts\";\nimport { jobCronInfoSchema } from \"../schemas/jobCronInfoSchema.ts\";\nimport { jobExecutionDetailResourceSchema } from \"../schemas/jobExecutionDetailResourceSchema.ts\";\nimport { jobExecutionQuerySchema } from \"../schemas/jobExecutionQuerySchema.ts\";\nimport { jobExecutionResourceSchema } from \"../schemas/jobExecutionResourceSchema.ts\";\nimport { jobFailureSchema } from \"../schemas/jobFailureSchema.ts\";\nimport { jobQueueDepthSchema } from \"../schemas/jobQueueDepthSchema.ts\";\nimport { jobRegistrationSchema } from \"../schemas/jobRegistrationSchema.ts\";\nimport { jobStatsSchema } from \"../schemas/jobStatsSchema.ts\";\nimport { triggerJobSchema } from \"../schemas/triggerJobSchema.ts\";\nimport { JobService } from \"../services/JobService.ts\";\n\nexport class AdminJobController {\n protected readonly url: string = \"/jobs\";\n protected readonly group: string = \"admin:jobs\";\n protected readonly jobService = $inject(JobService);\n\n public readonly getJobStats = $action({\n path: `${this.url}/stats`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobActivityQuerySchema,\n response: jobStatsSchema,\n },\n handler: ({ query }) => this.jobService.getStats(query.days),\n });\n\n public readonly getJobRegistry = $action({\n path: this.url,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n response: t.array(jobRegistrationSchema),\n },\n handler: () => this.jobService.getRegistry(),\n });\n\n public readonly findJobExecutions = $action({\n path: `${this.url}/executions`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobExecutionQuerySchema,\n response: t.page(jobExecutionResourceSchema),\n },\n handler: ({ query }) => this.jobService.findExecutions(query),\n });\n\n public readonly getJobExecution = $action({\n path: `${this.url}/executions/:id`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n params: t.object({\n id: t.uuid(),\n }),\n response: jobExecutionDetailResourceSchema,\n },\n handler: ({ params }) => this.jobService.getExecution(params.id),\n });\n\n public readonly triggerJob = $action({\n method: \"POST\",\n path: `${this.url}/trigger`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:trigger\"] })],\n schema: {\n body: triggerJobSchema,\n response: okSchema,\n },\n handler: async ({ body, user }) => {\n return this.jobService.triggerJob(body.name, {\n payload: body.payload,\n triggeredBy: user?.id,\n triggeredByName: user?.name,\n });\n },\n });\n\n public readonly retryJobExecution = $action({\n method: \"POST\",\n path: `${this.url}/executions/:id/retry`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:trigger\"] })],\n schema: {\n params: t.object({\n id: t.uuid(),\n }),\n response: okSchema,\n },\n handler: async ({ params, user }) => {\n return this.jobService.retryExecution(params.id, {\n triggeredBy: user?.id,\n triggeredByName: user?.name,\n });\n },\n });\n\n public readonly cancelJobExecution = $action({\n method: \"POST\",\n path: `${this.url}/executions/:id/cancel`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:cancel\"] })],\n schema: {\n params: t.object({\n id: t.uuid(),\n }),\n response: okSchema,\n },\n handler: async ({ params, user }) => {\n return this.jobService.cancelExecution(params.id, {\n cancelledBy: user?.id,\n cancelledByName: user?.name,\n });\n },\n });\n\n public readonly getJobActivity = $action({\n path: `${this.url}/activity`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobActivityQuerySchema,\n response: t.array(jobActivityPointSchema),\n },\n handler: ({ query }) => this.jobService.getActivity(query.days),\n });\n\n public readonly getCronJobs = $action({\n path: `${this.url}/cron`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n response: t.array(jobCronInfoSchema),\n },\n handler: () => this.jobService.getCronJobs(),\n });\n\n public readonly getJobQueueDepth = $action({\n path: `${this.url}/queue`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n response: t.array(jobQueueDepthSchema),\n },\n handler: () => this.jobService.getQueueDepth(),\n });\n\n public readonly getJobTopFailures = $action({\n path: `${this.url}/failures`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n query: jobActivityQuerySchema,\n response: t.array(jobFailureSchema),\n },\n handler: ({ query }) => this.jobService.getTopFailures(query.days),\n });\n\n public readonly pauseJob = $action({\n method: \"POST\",\n path: `${this.url}/pause`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:trigger\"] })],\n schema: {\n body: t.object({ name: t.text() }),\n response: okSchema,\n },\n handler: ({ body, user }) => {\n return this.jobService.pauseJob(body.name, {\n pausedBy: user?.id,\n pausedByName: user?.name,\n });\n },\n });\n\n public readonly resumeJob = $action({\n method: \"POST\",\n path: `${this.url}/resume`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:trigger\"] })],\n schema: {\n body: t.object({ name: t.text() }),\n response: okSchema,\n },\n handler: async ({ body, user }) => {\n return this.jobService.resumeJob(body.name, {\n resumedBy: user?.id,\n resumedByName: user?.name,\n });\n },\n });\n\n public readonly getPausedJobs = $action({\n path: `${this.url}/paused`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:job:read\"] })],\n schema: {\n response: t.array(t.text()),\n },\n handler: () => this.jobService.getPausedJobs(),\n });\n}\n","import { $hook, $inject, t } from \"alepha\";\nimport { $queue } from \"alepha/queue\";\nimport { JobProvider } from \"./JobProvider.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\n/**\n * Optional queue-backed dispatch for the job system.\n *\n * When registered, `JobProvider` will push work through this queue instead of\n * executing inline. This is the default for long-running (non-serverless) environments.\n * In serverless environments (Cloudflare Workers, Vercel), this provider is typically\n * omitted so jobs execute inline without requiring an external queue resource.\n */\nexport class JobQueueProvider {\n protected readonly jobProvider = $inject(JobProvider);\n\n protected readonly queue = $queue({\n name: \"_alepha:jobs:dispatch\",\n schema: t.object({ jobName: t.text(), executionId: t.text() }),\n handler: async (msg) => {\n await this.jobProvider.processExecution(\n msg.payload.jobName,\n msg.payload.executionId,\n );\n },\n });\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n this.jobProvider.queueDispatch = (jobName, executionId) =>\n this.push(jobName, executionId);\n },\n });\n\n /**\n * Push a job execution onto the queue for async processing.\n */\n public async push(jobName: string, executionId: string): Promise<void> {\n await this.queue.push({ jobName, executionId });\n }\n}\n","import { $module, type Alepha, type Static, t } from \"alepha\";\nimport type { DateTime } from \"alepha/datetime\";\nimport { AlephaLock } from \"alepha/lock\";\nimport { AlephaQueue } from \"alepha/queue\";\nimport { AlephaScheduler } from \"alepha/scheduler\";\nimport { AdminJobController } from \"./controllers/AdminJobController.ts\";\nimport { JobProvider } from \"./providers/JobProvider.ts\";\nimport { JobQueueProvider } from \"./providers/JobQueueProvider.ts\";\nimport { JobService } from \"./services/JobService.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\nexport * from \"./controllers/AdminJobController.ts\";\nexport * from \"./entities/jobExecutionEntity.ts\";\nexport * from \"./entities/jobExecutionLogEntity.ts\";\nexport * from \"./primitives/$job.ts\";\nexport * from \"./providers/JobProvider.ts\";\nexport * from \"./providers/JobQueueProvider.ts\";\nexport * from \"./schemas/jobActivitySchema.ts\";\nexport * from \"./schemas/jobConfigAtom.ts\";\nexport * from \"./schemas/jobCronInfoSchema.ts\";\nexport * from \"./schemas/jobExecutionDetailResourceSchema.ts\";\nexport * from \"./schemas/jobExecutionQuerySchema.ts\";\nexport * from \"./schemas/jobExecutionResourceSchema.ts\";\nexport * from \"./schemas/jobFailureSchema.ts\";\nexport * from \"./schemas/jobQueueDepthSchema.ts\";\nexport * from \"./schemas/jobRegistrationSchema.ts\";\nexport * from \"./schemas/jobStatsSchema.ts\";\nexport * from \"./schemas/triggerJobSchema.ts\";\nexport * from \"./services/JobService.ts\";\n\n// -----------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof jobEnvSchema>> {}\n\n interface Hooks {\n \"job:begin\": { name: string; now: DateTime; executionId: string };\n \"job:success\": { name: string; executionId: string };\n \"job:error\": { name: string; error: Error; executionId: string };\n \"job:cancel\": { name: string; executionId: string };\n \"job:end\": { name: string; executionId: string };\n }\n}\n\n// -----------------------------------------------------------------------------------------------------------------\n\nconst jobEnvSchema = t.object({\n /**\n * Controls whether the job system dispatches work through a queue or executes inline.\n *\n * - `1` — always use queue (force queue even in serverless)\n * - `0` — never use queue (force inline, useful for testing)\n * - not set — auto: use queue when NOT serverless (default)\n */\n ALEPHA_JOBS_QUEUE: t.optional(\n t.integer({\n description:\n \"Set to 1 to always use queue, 0 to disable queue (default: auto-detect based on environment)\",\n }),\n ),\n});\n\n// -----------------------------------------------------------------------------------------------------------------\n\n/**\n * Job execution framework — unified primitive for deferred, scheduled, and queued work.\n *\n * **Features:**\n * - Push-based jobs with typed payloads\n * - Cron scheduling with execution tracking\n * - Retry with exponential backoff\n * - Priority, delay, cancellation\n * - Deduplication via unique keys\n * - Per-execution log capture\n *\n * @module alepha.api.jobs\n */\nexport const AlephaApiJobs = $module({\n name: \"alepha.api.jobs\",\n services: [\n AlephaQueue,\n AlephaScheduler,\n AlephaLock,\n JobProvider,\n JobQueueProvider,\n JobService,\n AdminJobController,\n ],\n register: (alepha: Alepha) => {\n const env = alepha.parseEnv(jobEnvSchema);\n const useQueue =\n env.ALEPHA_JOBS_QUEUE === 1\n ? true\n : env.ALEPHA_JOBS_QUEUE === 0\n ? false\n : !alepha.isServerless();\n\n alepha.with(AlephaScheduler);\n alepha.with(AlephaLock);\n alepha.with(JobProvider);\n alepha.with(JobService);\n alepha.with(AdminJobController);\n\n if (useQueue) {\n alepha.with(AlephaQueue);\n alepha.with(JobQueueProvider);\n }\n },\n});\n"],"mappings":"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"}
@@ -60,7 +60,6 @@ const notificationQuerySchema = t.extend(pageQuerySchema, { status: t.optional(t
60
60
  "retrying",
61
61
  "running",
62
62
  "completed",
63
- "failed",
64
63
  "dead",
65
64
  "cancelled"
66
65
  ])) });
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","names":[],"sources":["../../../src/api/notifications/schemas/notificationContactPreferencesSchema.ts","../../../src/api/notifications/schemas/notificationContactSchema.ts","../../../src/api/notifications/schemas/notificationResourceSchema.ts","../../../src/api/notifications/schemas/notificationDetailResourceSchema.ts","../../../src/api/notifications/schemas/notificationPayloadSchema.ts","../../../src/api/notifications/schemas/notificationQuerySchema.ts","../../../src/api/notifications/index.browser.ts"],"sourcesContent":["import { type Static, t } from \"alepha\";\n\nexport const notificationContactPreferencesSchema = t.object({\n language: t.optional(t.text()),\n exclude: t.array(t.text()),\n});\n\nexport type NotificationContactPreferences = Static<\n typeof notificationContactPreferencesSchema\n>;\n","import { type Static, t } from \"alepha\";\n\nexport const notificationContactSchema = t.object({\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n firstName: t.optional(t.shortText()),\n lastName: t.optional(t.text({ size: \"short\" })),\n language: t.optional(t.bcp47()),\n});\n\nexport type NotificationContact = Static<typeof notificationContactSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const notificationResourceSchema = t.object({\n id: t.uuid(),\n createdAt: t.datetime(),\n status: t.text(),\n template: t.optional(t.text()),\n type: t.optional(t.text()),\n contact: t.optional(t.text()),\n category: t.optional(t.text()),\n critical: t.optional(t.boolean()),\n sensitive: t.optional(t.boolean()),\n startedAt: t.optional(t.datetime()),\n completedAt: t.optional(t.datetime()),\n error: t.optional(t.text()),\n});\n\nexport type NotificationResource = Static<typeof notificationResourceSchema>;\n","import { type Static, t } from \"alepha\";\nimport { logEntrySchema } from \"alepha/logger\";\nimport { notificationResourceSchema } from \"./notificationResourceSchema.ts\";\n\nexport const notificationDetailResourceSchema = t.extend(\n notificationResourceSchema,\n {\n variables: t.optional(t.record(t.text(), t.any())),\n rendered: t.optional(t.record(t.text(), t.any())),\n logs: t.optional(t.array(logEntrySchema)),\n },\n {\n title: \"NotificationDetailResource\",\n description: \"A notification resource with rendered content and logs.\",\n },\n);\n\nexport type NotificationDetailResource = Static<\n typeof notificationDetailResourceSchema\n>;\n","import { type Static, t } from \"alepha\";\n\nexport const notificationPayloadSchema = t.object({\n type: t.enum([\"email\", \"sms\"]),\n template: t.text(),\n contact: t.text(),\n variables: t.optional(t.record(t.text(), t.any())),\n category: t.optional(t.text()),\n critical: t.optional(t.boolean()),\n sensitive: t.optional(t.boolean()),\n});\n\nexport type NotificationPayload = Static<typeof notificationPayloadSchema>;\n","import { type Static, t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\n\nexport const notificationQuerySchema = t.extend(pageQuerySchema, {\n status: t.optional(\n t.enum([\n \"pending\",\n \"scheduled\",\n \"retrying\",\n \"running\",\n \"completed\",\n \"failed\",\n \"dead\",\n \"cancelled\",\n ]),\n ),\n});\n\nexport type NotificationQuery = Static<typeof notificationQuerySchema>;\n","import { $module } from \"alepha\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./schemas/notificationContactPreferencesSchema.ts\";\nexport * from \"./schemas/notificationContactSchema.ts\";\nexport * from \"./schemas/notificationDetailResourceSchema.ts\";\nexport * from \"./schemas/notificationPayloadSchema.ts\";\nexport * from \"./schemas/notificationQuerySchema.ts\";\nexport * from \"./schemas/notificationResourceSchema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaApiNotifications = $module({\n name: \"alepha.api.notifications\",\n services: [],\n});\n"],"mappings":";;;;AAEA,MAAa,uCAAuC,EAAE,OAAO;CAC3D,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;CAC3B,CAAC;;;ACHF,MAAa,4BAA4B,EAAE,OAAO;CAChD,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC;CAC5B,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC;CACjC,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC;CACpC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC,CAAC;CAC/C,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC;CAChC,CAAC;;;ACNF,MAAa,6BAA6B,EAAE,OAAO;CACjD,IAAI,EAAE,MAAM;CACZ,WAAW,EAAE,UAAU;CACvB,QAAQ,EAAE,MAAM;CAChB,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC;CAC1B,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC;CAC7B,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC;CACjC,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC;CAClC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC;CACnC,aAAa,EAAE,SAAS,EAAE,UAAU,CAAC;CACrC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;;;ACXF,MAAa,mCAAmC,EAAE,OAChD,4BACA;CACE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;CAClD,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;CACjD,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;CAC1C,EACD;CACE,OAAO;CACP,aAAa;CACd,CACF;;;ACbD,MAAa,4BAA4B,EAAE,OAAO;CAChD,MAAM,EAAE,KAAK,CAAC,SAAS,MAAM,CAAC;CAC9B,UAAU,EAAE,MAAM;CAClB,SAAS,EAAE,MAAM;CACjB,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;CAClD,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC;CACjC,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC;CACnC,CAAC;;;ACPF,MAAa,0BAA0B,EAAE,OAAO,iBAAiB,EAC/D,QAAQ,EAAE,SACR,EAAE,KAAK;CACL;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,CACH,EACF,CAAC;;;ACHF,MAAa,yBAAyB,QAAQ;CAC5C,MAAM;CACN,UAAU,EAAE;CACb,CAAC"}
1
+ {"version":3,"file":"index.browser.js","names":[],"sources":["../../../src/api/notifications/schemas/notificationContactPreferencesSchema.ts","../../../src/api/notifications/schemas/notificationContactSchema.ts","../../../src/api/notifications/schemas/notificationResourceSchema.ts","../../../src/api/notifications/schemas/notificationDetailResourceSchema.ts","../../../src/api/notifications/schemas/notificationPayloadSchema.ts","../../../src/api/notifications/schemas/notificationQuerySchema.ts","../../../src/api/notifications/index.browser.ts"],"sourcesContent":["import { type Static, t } from \"alepha\";\n\nexport const notificationContactPreferencesSchema = t.object({\n language: t.optional(t.text()),\n exclude: t.array(t.text()),\n});\n\nexport type NotificationContactPreferences = Static<\n typeof notificationContactPreferencesSchema\n>;\n","import { type Static, t } from \"alepha\";\n\nexport const notificationContactSchema = t.object({\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n firstName: t.optional(t.shortText()),\n lastName: t.optional(t.text({ size: \"short\" })),\n language: t.optional(t.bcp47()),\n});\n\nexport type NotificationContact = Static<typeof notificationContactSchema>;\n","import { type Static, t } from \"alepha\";\n\nexport const notificationResourceSchema = t.object({\n id: t.uuid(),\n createdAt: t.datetime(),\n status: t.text(),\n template: t.optional(t.text()),\n type: t.optional(t.text()),\n contact: t.optional(t.text()),\n category: t.optional(t.text()),\n critical: t.optional(t.boolean()),\n sensitive: t.optional(t.boolean()),\n startedAt: t.optional(t.datetime()),\n completedAt: t.optional(t.datetime()),\n error: t.optional(t.text()),\n});\n\nexport type NotificationResource = Static<typeof notificationResourceSchema>;\n","import { type Static, t } from \"alepha\";\nimport { logEntrySchema } from \"alepha/logger\";\nimport { notificationResourceSchema } from \"./notificationResourceSchema.ts\";\n\nexport const notificationDetailResourceSchema = t.extend(\n notificationResourceSchema,\n {\n variables: t.optional(t.record(t.text(), t.any())),\n rendered: t.optional(t.record(t.text(), t.any())),\n logs: t.optional(t.array(logEntrySchema)),\n },\n {\n title: \"NotificationDetailResource\",\n description: \"A notification resource with rendered content and logs.\",\n },\n);\n\nexport type NotificationDetailResource = Static<\n typeof notificationDetailResourceSchema\n>;\n","import { type Static, t } from \"alepha\";\n\nexport const notificationPayloadSchema = t.object({\n type: t.enum([\"email\", \"sms\"]),\n template: t.text(),\n contact: t.text(),\n variables: t.optional(t.record(t.text(), t.any())),\n category: t.optional(t.text()),\n critical: t.optional(t.boolean()),\n sensitive: t.optional(t.boolean()),\n});\n\nexport type NotificationPayload = Static<typeof notificationPayloadSchema>;\n","import { type Static, t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\n\nexport const notificationQuerySchema = t.extend(pageQuerySchema, {\n status: t.optional(\n t.enum([\n \"pending\",\n \"scheduled\",\n \"retrying\",\n \"running\",\n \"completed\",\n \"dead\",\n \"cancelled\",\n ]),\n ),\n});\n\nexport type NotificationQuery = Static<typeof notificationQuerySchema>;\n","import { $module } from \"alepha\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./schemas/notificationContactPreferencesSchema.ts\";\nexport * from \"./schemas/notificationContactSchema.ts\";\nexport * from \"./schemas/notificationDetailResourceSchema.ts\";\nexport * from \"./schemas/notificationPayloadSchema.ts\";\nexport * from \"./schemas/notificationQuerySchema.ts\";\nexport * from \"./schemas/notificationResourceSchema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaApiNotifications = $module({\n name: \"alepha.api.notifications\",\n services: [],\n});\n"],"mappings":";;;;AAEA,MAAa,uCAAuC,EAAE,OAAO;CAC3D,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;CAC3B,CAAC;;;ACHF,MAAa,4BAA4B,EAAE,OAAO;CAChD,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC;CAC5B,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC;CACjC,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC;CACpC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC,CAAC;CAC/C,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC;CAChC,CAAC;;;ACNF,MAAa,6BAA6B,EAAE,OAAO;CACjD,IAAI,EAAE,MAAM;CACZ,WAAW,EAAE,UAAU;CACvB,QAAQ,EAAE,MAAM;CAChB,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC;CAC1B,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC;CAC7B,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC;CACjC,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC;CAClC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC;CACnC,aAAa,EAAE,SAAS,EAAE,UAAU,CAAC;CACrC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;;;ACXF,MAAa,mCAAmC,EAAE,OAChD,4BACA;CACE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;CAClD,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;CACjD,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;CAC1C,EACD;CACE,OAAO;CACP,aAAa;CACd,CACF;;;ACbD,MAAa,4BAA4B,EAAE,OAAO;CAChD,MAAM,EAAE,KAAK,CAAC,SAAS,MAAM,CAAC;CAC9B,UAAU,EAAE,MAAM;CAClB,SAAS,EAAE,MAAM;CACjB,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;CAClD,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC;CAC9B,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC;CACjC,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC;CACnC,CAAC;;;ACPF,MAAa,0BAA0B,EAAE,OAAO,iBAAiB,EAC/D,QAAQ,EAAE,SACR,EAAE,KAAK;CACL;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,CACH,EACF,CAAC;;;ACFF,MAAa,yBAAyB,QAAQ;CAC5C,MAAM;CACN,UAAU,EAAE;CACb,CAAC"}
@@ -138,7 +138,7 @@ declare class NotificationJobs {
138
138
  jobName: _$alepha.TString;
139
139
  key: _$alepha.TOptional<_$alepha.TUnion<[_$alepha.TNull, _$alepha.TString]>>;
140
140
  payload: _$alepha.TOptional<_$alepha.TRecord<"^.*$", _$alepha.TAny>>;
141
- status: _$alepha_orm0.PgAttr<_$alepha.TUnsafe<"pending" | "scheduled" | "retrying" | "running" | "completed" | "failed" | "dead" | "cancelled">, typeof _$alepha_orm0.PG_DEFAULT>;
141
+ status: _$alepha_orm0.PgAttr<_$alepha.TUnsafe<"pending" | "scheduled" | "retrying" | "running" | "completed" | "dead" | "cancelled">, typeof _$alepha_orm0.PG_DEFAULT>;
142
142
  priority: _$alepha_orm0.PgAttr<_$alepha.TInteger, typeof _$alepha_orm0.PG_DEFAULT>;
143
143
  attempt: _$alepha_orm0.PgAttr<_$alepha.TInteger, typeof _$alepha_orm0.PG_DEFAULT>;
144
144
  maxAttempts: _$alepha_orm0.PgAttr<_$alepha.TInteger, typeof _$alepha_orm0.PG_DEFAULT>;
@@ -176,7 +176,7 @@ declare class AdminNotificationController {
176
176
  page: _$alepha.TOptional<_$alepha.TInteger>;
177
177
  size: _$alepha.TOptional<_$alepha.TInteger>;
178
178
  sort: _$alepha.TOptional<_$alepha.TString>;
179
- status: _$alepha.TOptional<_$alepha.TUnsafe<"pending" | "scheduled" | "retrying" | "running" | "completed" | "failed" | "dead" | "cancelled">>;
179
+ status: _$alepha.TOptional<_$alepha.TUnsafe<"pending" | "scheduled" | "retrying" | "running" | "completed" | "dead" | "cancelled">>;
180
180
  }>;
181
181
  response: _$alepha.TPage<_$alepha.TObject<{
182
182
  id: _$alepha.TString;
@@ -308,7 +308,7 @@ declare const notificationQuerySchema: _$alepha.TObject<{
308
308
  page: _$alepha.TOptional<_$alepha.TInteger>;
309
309
  size: _$alepha.TOptional<_$alepha.TInteger>;
310
310
  sort: _$alepha.TOptional<_$alepha.TString>;
311
- status: _$alepha.TOptional<_$alepha.TUnsafe<"pending" | "scheduled" | "retrying" | "running" | "completed" | "failed" | "dead" | "cancelled">>;
311
+ status: _$alepha.TOptional<_$alepha.TUnsafe<"pending" | "scheduled" | "retrying" | "running" | "completed" | "dead" | "cancelled">>;
312
312
  }>;
313
313
  type NotificationQuery = Static<typeof notificationQuerySchema>;
314
314
  //#endregion