@shipfox/api-triggers 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +224 -0
  5. package/LICENSE +21 -0
  6. package/README.md +300 -0
  7. package/dist/config.d.ts +10 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +42 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/core/compute-next-fire-at.d.ts +9 -0
  12. package/dist/core/compute-next-fire-at.d.ts.map +1 -0
  13. package/dist/core/compute-next-fire-at.js +28 -0
  14. package/dist/core/compute-next-fire-at.js.map +1 -0
  15. package/dist/core/config.d.ts +26 -0
  16. package/dist/core/config.d.ts.map +1 -0
  17. package/dist/core/config.js +68 -0
  18. package/dist/core/config.js.map +1 -0
  19. package/dist/core/dispatch-integration-event.d.ts +14 -0
  20. package/dist/core/dispatch-integration-event.d.ts.map +1 -0
  21. package/dist/core/dispatch-integration-event.js +136 -0
  22. package/dist/core/dispatch-integration-event.js.map +1 -0
  23. package/dist/core/drain-cron-schedules.d.ts +30 -0
  24. package/dist/core/drain-cron-schedules.d.ts.map +1 -0
  25. package/dist/core/drain-cron-schedules.js +76 -0
  26. package/dist/core/drain-cron-schedules.js.map +1 -0
  27. package/dist/core/entities/cron-schedule.d.ts +11 -0
  28. package/dist/core/entities/cron-schedule.d.ts.map +1 -0
  29. package/dist/core/entities/cron-schedule.js +3 -0
  30. package/dist/core/entities/cron-schedule.js.map +1 -0
  31. package/dist/core/entities/decision.d.ts +23 -0
  32. package/dist/core/entities/decision.d.ts.map +1 -0
  33. package/dist/core/entities/decision.js +7 -0
  34. package/dist/core/entities/decision.js.map +1 -0
  35. package/dist/core/entities/index.d.ts +3 -0
  36. package/dist/core/entities/index.d.ts.map +1 -0
  37. package/dist/core/entities/index.js +3 -0
  38. package/dist/core/entities/index.js.map +1 -0
  39. package/dist/core/entities/job-listener-subscription.d.ts +14 -0
  40. package/dist/core/entities/job-listener-subscription.d.ts.map +1 -0
  41. package/dist/core/entities/job-listener-subscription.js +3 -0
  42. package/dist/core/entities/job-listener-subscription.js.map +1 -0
  43. package/dist/core/entities/received-event.d.ts +28 -0
  44. package/dist/core/entities/received-event.d.ts.map +1 -0
  45. package/dist/core/entities/received-event.js +14 -0
  46. package/dist/core/entities/received-event.js.map +1 -0
  47. package/dist/core/entities/subscription.d.ts +13 -0
  48. package/dist/core/entities/subscription.d.ts.map +1 -0
  49. package/dist/core/entities/subscription.js +3 -0
  50. package/dist/core/entities/subscription.js.map +1 -0
  51. package/dist/core/errors.d.ts +25 -0
  52. package/dist/core/errors.d.ts.map +1 -0
  53. package/dist/core/errors.js +41 -0
  54. package/dist/core/errors.js.map +1 -0
  55. package/dist/core/fire-cron.d.ts +28 -0
  56. package/dist/core/fire-cron.d.ts.map +1 -0
  57. package/dist/core/fire-cron.js +85 -0
  58. package/dist/core/fire-cron.js.map +1 -0
  59. package/dist/core/fire-manual.d.ts +9 -0
  60. package/dist/core/fire-manual.d.ts.map +1 -0
  61. package/dist/core/fire-manual.js +87 -0
  62. package/dist/core/fire-manual.js.map +1 -0
  63. package/dist/core/index.d.ts +11 -0
  64. package/dist/core/index.d.ts.map +1 -0
  65. package/dist/core/index.js +10 -0
  66. package/dist/core/index.js.map +1 -0
  67. package/dist/core/record-trigger-history.d.ts +35 -0
  68. package/dist/core/record-trigger-history.d.ts.map +1 -0
  69. package/dist/core/record-trigger-history.js +75 -0
  70. package/dist/core/record-trigger-history.js.map +1 -0
  71. package/dist/core/route-event-to-job-listeners.d.ts +31 -0
  72. package/dist/core/route-event-to-job-listeners.d.ts.map +1 -0
  73. package/dist/core/route-event-to-job-listeners.js +140 -0
  74. package/dist/core/route-event-to-job-listeners.js.map +1 -0
  75. package/dist/db/cron-schedules.d.ts +36 -0
  76. package/dist/db/cron-schedules.d.ts.map +1 -0
  77. package/dist/db/cron-schedules.js +104 -0
  78. package/dist/db/cron-schedules.js.map +1 -0
  79. package/dist/db/db.d.ts +2515 -0
  80. package/dist/db/db.d.ts.map +1 -0
  81. package/dist/db/db.js +28 -0
  82. package/dist/db/db.js.map +1 -0
  83. package/dist/db/event-history.d.ts +50 -0
  84. package/dist/db/event-history.d.ts.map +1 -0
  85. package/dist/db/event-history.js +207 -0
  86. package/dist/db/event-history.js.map +1 -0
  87. package/dist/db/event-queries.d.ts +38 -0
  88. package/dist/db/event-queries.d.ts.map +1 -0
  89. package/dist/db/event-queries.js +78 -0
  90. package/dist/db/event-queries.js.map +1 -0
  91. package/dist/db/index.d.ts +11 -0
  92. package/dist/db/index.d.ts.map +1 -0
  93. package/dist/db/index.js +14 -0
  94. package/dist/db/index.js.map +1 -0
  95. package/dist/db/job-listener-subscriptions.d.ts +24 -0
  96. package/dist/db/job-listener-subscriptions.d.ts.map +1 -0
  97. package/dist/db/job-listener-subscriptions.js +69 -0
  98. package/dist/db/job-listener-subscriptions.js.map +1 -0
  99. package/dist/db/received-events.d.ts +7 -0
  100. package/dist/db/received-events.d.ts.map +1 -0
  101. package/dist/db/received-events.js +11 -0
  102. package/dist/db/received-events.js.map +1 -0
  103. package/dist/db/schema/common.d.ts +2 -0
  104. package/dist/db/schema/common.d.ts.map +1 -0
  105. package/dist/db/schema/common.js +4 -0
  106. package/dist/db/schema/common.js.map +1 -0
  107. package/dist/db/schema/cron-schedules.d.ts +148 -0
  108. package/dist/db/schema/cron-schedules.d.ts.map +1 -0
  109. package/dist/db/schema/cron-schedules.js +39 -0
  110. package/dist/db/schema/cron-schedules.js.map +1 -0
  111. package/dist/db/schema/decisions.d.ts +284 -0
  112. package/dist/db/schema/decisions.d.ts.map +1 -0
  113. package/dist/db/schema/decisions.js +70 -0
  114. package/dist/db/schema/decisions.js.map +1 -0
  115. package/dist/db/schema/job-listener-subscriptions.d.ts +185 -0
  116. package/dist/db/schema/job-listener-subscriptions.d.ts.map +1 -0
  117. package/dist/db/schema/job-listener-subscriptions.js +41 -0
  118. package/dist/db/schema/job-listener-subscriptions.js.map +1 -0
  119. package/dist/db/schema/outbox.d.ts +195 -0
  120. package/dist/db/schema/outbox.d.ts.map +1 -0
  121. package/dist/db/schema/outbox.js +5 -0
  122. package/dist/db/schema/outbox.js.map +1 -0
  123. package/dist/db/schema/received-events.d.ts +544 -0
  124. package/dist/db/schema/received-events.d.ts.map +1 -0
  125. package/dist/db/schema/received-events.js +86 -0
  126. package/dist/db/schema/received-events.js.map +1 -0
  127. package/dist/db/schema/subscriptions.d.ts +182 -0
  128. package/dist/db/schema/subscriptions.d.ts.map +1 -0
  129. package/dist/db/schema/subscriptions.js +39 -0
  130. package/dist/db/schema/subscriptions.js.map +1 -0
  131. package/dist/db/subscriptions.d.ts +26 -0
  132. package/dist/db/subscriptions.d.ts.map +1 -0
  133. package/dist/db/subscriptions.js +103 -0
  134. package/dist/db/subscriptions.js.map +1 -0
  135. package/dist/index.d.ts +7 -0
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +68 -0
  138. package/dist/index.js.map +1 -0
  139. package/dist/metrics/index.d.ts +3 -0
  140. package/dist/metrics/index.d.ts.map +1 -0
  141. package/dist/metrics/index.js +4 -0
  142. package/dist/metrics/index.js.map +1 -0
  143. package/dist/metrics/instance.d.ts +15 -0
  144. package/dist/metrics/instance.d.ts.map +1 -0
  145. package/dist/metrics/instance.js +32 -0
  146. package/dist/metrics/instance.js.map +1 -0
  147. package/dist/metrics/service.d.ts +2 -0
  148. package/dist/metrics/service.d.ts.map +1 -0
  149. package/dist/metrics/service.js +15 -0
  150. package/dist/metrics/service.js.map +1 -0
  151. package/dist/presentation/dto/trigger-events.d.ts +7 -0
  152. package/dist/presentation/dto/trigger-events.d.ts.map +1 -0
  153. package/dist/presentation/dto/trigger-events.js +47 -0
  154. package/dist/presentation/dto/trigger-events.js.map +1 -0
  155. package/dist/presentation/index.d.ts +3 -0
  156. package/dist/presentation/index.d.ts.map +1 -0
  157. package/dist/presentation/index.js +4 -0
  158. package/dist/presentation/index.js.map +1 -0
  159. package/dist/presentation/routes/fire-manual.d.ts +2 -0
  160. package/dist/presentation/routes/fire-manual.d.ts.map +1 -0
  161. package/dist/presentation/routes/fire-manual.js +71 -0
  162. package/dist/presentation/routes/fire-manual.js.map +1 -0
  163. package/dist/presentation/routes/get-trigger-event.d.ts +2 -0
  164. package/dist/presentation/routes/get-trigger-event.d.ts.map +1 -0
  165. package/dist/presentation/routes/get-trigger-event.js +37 -0
  166. package/dist/presentation/routes/get-trigger-event.js.map +1 -0
  167. package/dist/presentation/routes/index.d.ts +3 -0
  168. package/dist/presentation/routes/index.d.ts.map +1 -0
  169. package/dist/presentation/routes/index.js +27 -0
  170. package/dist/presentation/routes/index.js.map +1 -0
  171. package/dist/presentation/routes/list-trigger-event-facets.d.ts +2 -0
  172. package/dist/presentation/routes/list-trigger-event-facets.d.ts.map +1 -0
  173. package/dist/presentation/routes/list-trigger-event-facets.js +29 -0
  174. package/dist/presentation/routes/list-trigger-event-facets.js.map +1 -0
  175. package/dist/presentation/routes/list-trigger-events.d.ts +2 -0
  176. package/dist/presentation/routes/list-trigger-events.d.ts.map +1 -0
  177. package/dist/presentation/routes/list-trigger-events.js +56 -0
  178. package/dist/presentation/routes/list-trigger-events.js.map +1 -0
  179. package/dist/presentation/subscribers/index.d.ts +6 -0
  180. package/dist/presentation/subscribers/index.d.ts.map +1 -0
  181. package/dist/presentation/subscribers/index.js +7 -0
  182. package/dist/presentation/subscribers/index.js.map +1 -0
  183. package/dist/presentation/subscribers/on-definition-deleted.d.ts +3 -0
  184. package/dist/presentation/subscribers/on-definition-deleted.d.ts.map +1 -0
  185. package/dist/presentation/subscribers/on-definition-deleted.js +8 -0
  186. package/dist/presentation/subscribers/on-definition-deleted.js.map +1 -0
  187. package/dist/presentation/subscribers/on-definition-resolved.d.ts +3 -0
  188. package/dist/presentation/subscribers/on-definition-resolved.d.ts.map +1 -0
  189. package/dist/presentation/subscribers/on-definition-resolved.js +11 -0
  190. package/dist/presentation/subscribers/on-definition-resolved.js.map +1 -0
  191. package/dist/presentation/subscribers/on-integration-event-received.d.ts +4 -0
  192. package/dist/presentation/subscribers/on-integration-event-received.d.ts.map +1 -0
  193. package/dist/presentation/subscribers/on-integration-event-received.js +17 -0
  194. package/dist/presentation/subscribers/on-integration-event-received.js.map +1 -0
  195. package/dist/presentation/subscribers/on-job-activated.d.ts +3 -0
  196. package/dist/presentation/subscribers/on-job-activated.d.ts.map +1 -0
  197. package/dist/presentation/subscribers/on-job-activated.js +13 -0
  198. package/dist/presentation/subscribers/on-job-activated.js.map +1 -0
  199. package/dist/presentation/subscribers/on-job-terminated.d.ts +3 -0
  200. package/dist/presentation/subscribers/on-job-terminated.d.ts.map +1 -0
  201. package/dist/presentation/subscribers/on-job-terminated.js +6 -0
  202. package/dist/presentation/subscribers/on-job-terminated.js.map +1 -0
  203. package/dist/temporal/activities/drain-cron-batch.d.ts +4 -0
  204. package/dist/temporal/activities/drain-cron-batch.d.ts.map +1 -0
  205. package/dist/temporal/activities/drain-cron-batch.js +20 -0
  206. package/dist/temporal/activities/drain-cron-batch.js.map +1 -0
  207. package/dist/temporal/activities/index.d.ts +10 -0
  208. package/dist/temporal/activities/index.d.ts.map +1 -0
  209. package/dist/temporal/activities/index.js +15 -0
  210. package/dist/temporal/activities/index.js.map +1 -0
  211. package/dist/temporal/activities/prune-trigger-events.d.ts +4 -0
  212. package/dist/temporal/activities/prune-trigger-events.d.ts.map +1 -0
  213. package/dist/temporal/activities/prune-trigger-events.js +11 -0
  214. package/dist/temporal/activities/prune-trigger-events.js.map +1 -0
  215. package/dist/temporal/constants.d.ts +7 -0
  216. package/dist/temporal/constants.d.ts.map +1 -0
  217. package/dist/temporal/constants.js +7 -0
  218. package/dist/temporal/constants.js.map +1 -0
  219. package/dist/temporal/workflows/cron-tick-cron.d.ts +9 -0
  220. package/dist/temporal/workflows/cron-tick-cron.d.ts.map +1 -0
  221. package/dist/temporal/workflows/cron-tick-cron.js +54 -0
  222. package/dist/temporal/workflows/cron-tick-cron.js.map +1 -0
  223. package/dist/temporal/workflows/index.d.ts +3 -0
  224. package/dist/temporal/workflows/index.d.ts.map +1 -0
  225. package/dist/temporal/workflows/index.js +4 -0
  226. package/dist/temporal/workflows/index.js.map +1 -0
  227. package/dist/temporal/workflows/prune-trigger-events-cron.d.ts +2 -0
  228. package/dist/temporal/workflows/prune-trigger-events-cron.d.ts.map +1 -0
  229. package/dist/temporal/workflows/prune-trigger-events-cron.js +18 -0
  230. package/dist/temporal/workflows/prune-trigger-events-cron.js.map +1 -0
  231. package/dist/tsconfig.test.tsbuildinfo +1 -0
  232. package/drizzle/0000_initial.sql +109 -0
  233. package/drizzle/meta/0000_snapshot.json +905 -0
  234. package/drizzle/meta/_journal.json +13 -0
  235. package/drizzle.config.ts +14 -0
  236. package/package.json +83 -0
  237. package/src/config.test.ts +33 -0
  238. package/src/config.ts +53 -0
  239. package/src/core/compute-next-fire-at.test.ts +69 -0
  240. package/src/core/compute-next-fire-at.ts +37 -0
  241. package/src/core/config.test.ts +213 -0
  242. package/src/core/config.ts +86 -0
  243. package/src/core/dispatch-integration-event.history-failure.test.ts +66 -0
  244. package/src/core/dispatch-integration-event.test.ts +1006 -0
  245. package/src/core/dispatch-integration-event.ts +150 -0
  246. package/src/core/drain-cron-schedules.test.ts +265 -0
  247. package/src/core/drain-cron-schedules.ts +90 -0
  248. package/src/core/entities/cron-schedule.ts +10 -0
  249. package/src/core/entities/decision.ts +24 -0
  250. package/src/core/entities/index.ts +5 -0
  251. package/src/core/entities/job-listener-subscription.ts +14 -0
  252. package/src/core/entities/received-event.ts +36 -0
  253. package/src/core/entities/subscription.ts +12 -0
  254. package/src/core/errors.ts +63 -0
  255. package/src/core/fire-cron.test.ts +146 -0
  256. package/src/core/fire-cron.ts +98 -0
  257. package/src/core/fire-manual.test.ts +157 -0
  258. package/src/core/fire-manual.ts +92 -0
  259. package/src/core/index.ts +34 -0
  260. package/src/core/record-trigger-history.test.ts +159 -0
  261. package/src/core/record-trigger-history.ts +145 -0
  262. package/src/core/route-event-to-job-listeners.test.ts +369 -0
  263. package/src/core/route-event-to-job-listeners.ts +184 -0
  264. package/src/db/cron-schedules.test.ts +358 -0
  265. package/src/db/cron-schedules.ts +163 -0
  266. package/src/db/db.ts +31 -0
  267. package/src/db/event-history.test.ts +421 -0
  268. package/src/db/event-history.ts +279 -0
  269. package/src/db/event-queries.ts +140 -0
  270. package/src/db/index.ts +51 -0
  271. package/src/db/job-listener-subscriptions.test.ts +270 -0
  272. package/src/db/job-listener-subscriptions.ts +133 -0
  273. package/src/db/received-events.ts +16 -0
  274. package/src/db/schema/common.ts +3 -0
  275. package/src/db/schema/cron-schedules.ts +37 -0
  276. package/src/db/schema/decisions.test.ts +279 -0
  277. package/src/db/schema/decisions.ts +77 -0
  278. package/src/db/schema/job-listener-subscriptions.ts +65 -0
  279. package/src/db/schema/outbox.ts +4 -0
  280. package/src/db/schema/received-events.test.ts +135 -0
  281. package/src/db/schema/received-events.ts +93 -0
  282. package/src/db/schema/subscriptions.ts +46 -0
  283. package/src/db/subscriptions.test.ts +340 -0
  284. package/src/db/subscriptions.ts +179 -0
  285. package/src/index.ts +108 -0
  286. package/src/metrics/index.ts +8 -0
  287. package/src/metrics/instance.ts +33 -0
  288. package/src/metrics/service.ts +18 -0
  289. package/src/presentation/dto/trigger-events.test.ts +144 -0
  290. package/src/presentation/dto/trigger-events.ts +60 -0
  291. package/src/presentation/index.ts +6 -0
  292. package/src/presentation/routes/fire-manual.test.ts +118 -0
  293. package/src/presentation/routes/fire-manual.ts +70 -0
  294. package/src/presentation/routes/get-trigger-event.test.ts +184 -0
  295. package/src/presentation/routes/get-trigger-event.ts +37 -0
  296. package/src/presentation/routes/index.ts +21 -0
  297. package/src/presentation/routes/list-trigger-event-facets.test.ts +116 -0
  298. package/src/presentation/routes/list-trigger-event-facets.ts +29 -0
  299. package/src/presentation/routes/list-trigger-events.test.ts +379 -0
  300. package/src/presentation/routes/list-trigger-events.ts +68 -0
  301. package/src/presentation/subscribers/index.ts +5 -0
  302. package/src/presentation/subscribers/on-definition-deleted.test.ts +42 -0
  303. package/src/presentation/subscribers/on-definition-deleted.ts +6 -0
  304. package/src/presentation/subscribers/on-definition-resolved.test.ts +67 -0
  305. package/src/presentation/subscribers/on-definition-resolved.ts +11 -0
  306. package/src/presentation/subscribers/on-integration-event-received.test.ts +53 -0
  307. package/src/presentation/subscribers/on-integration-event-received.ts +21 -0
  308. package/src/presentation/subscribers/on-job-activated.ts +14 -0
  309. package/src/presentation/subscribers/on-job-terminated.ts +6 -0
  310. package/src/temporal/activities/drain-cron-batch.ts +20 -0
  311. package/src/temporal/activities/index.ts +15 -0
  312. package/src/temporal/activities/prune-trigger-events.test.ts +78 -0
  313. package/src/temporal/activities/prune-trigger-events.ts +9 -0
  314. package/src/temporal/constants.ts +7 -0
  315. package/src/temporal/workflows/cron-tick-cron.ts +56 -0
  316. package/src/temporal/workflows/index.ts +2 -0
  317. package/src/temporal/workflows/prune-trigger-events-cron.ts +17 -0
  318. package/test/env.ts +8 -0
  319. package/test/factories/cron-schedule.ts +34 -0
  320. package/test/factories/decision.ts +49 -0
  321. package/test/factories/job-listener-subscription.ts +42 -0
  322. package/test/factories/received-event.ts +49 -0
  323. package/test/factories/subscription.ts +38 -0
  324. package/test/globalSetup.ts +20 -0
  325. package/test/index.ts +5 -0
  326. package/test/setup.ts +17 -0
  327. package/tsconfig.build.json +9 -0
  328. package/tsconfig.build.tsbuildinfo +1 -0
  329. package/tsconfig.json +3 -0
  330. package/tsconfig.test.json +8 -0
  331. package/vitest.config.ts +11 -0
@@ -0,0 +1,2 @@
1
+ $ shipfox-swc
2
+ Successfully compiled: 56 files with swc (93.82ms)
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-emit
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-check
package/CHANGELOG.md ADDED
@@ -0,0 +1,224 @@
1
+ # @shipfox/api-triggers
2
+
3
+ ## 2.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1b0d344: Publishes the complete API runtime closure with packed-consumer-safe internal imports and records its exact package set in application releases.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [0cd6dd4]
12
+ - Updated dependencies [a68458a]
13
+ - Updated dependencies [6eba800]
14
+ - Updated dependencies [1b0d344]
15
+ - Updated dependencies [521e006]
16
+ - @shipfox/node-module@0.2.0
17
+ - @shipfox/node-temporal@0.2.0
18
+ - @shipfox/api-auth-context@2.0.0
19
+ - @shipfox/api-definitions-dto@2.0.0
20
+ - @shipfox/api-integration-core-dto@2.0.0
21
+ - @shipfox/api-projects@2.0.0
22
+ - @shipfox/api-triggers-dto@2.0.0
23
+ - @shipfox/api-workflows@2.0.0
24
+ - @shipfox/api-workflows-dto@2.0.0
25
+ - @shipfox/config@1.2.1
26
+ - @shipfox/expression@1.1.1
27
+ - @shipfox/node-drizzle@0.2.1
28
+ - @shipfox/node-fastify@0.2.1
29
+ - @shipfox/node-opentelemetry@0.5.0
30
+ - @shipfox/node-outbox@0.2.1
31
+ - @shipfox/node-postgres@0.4.1
32
+ - @shipfox/workflow-document@2.0.1
33
+
34
+ ## 0.1.2
35
+
36
+ ### Patch Changes
37
+
38
+ - Updated dependencies [705dd43]
39
+ - @shipfox/node-outbox@0.2.0
40
+ - @shipfox/api-projects@0.1.2
41
+ - @shipfox/api-workflows@0.1.2
42
+ - @shipfox/node-module@0.1.2
43
+
44
+ ## 0.1.1
45
+
46
+ ### Patch Changes
47
+
48
+ - Updated dependencies [ec75cd5]
49
+ - Updated dependencies [6a1fb54]
50
+ - @shipfox/node-drizzle@0.2.0
51
+ - @shipfox/node-postgres@0.4.0
52
+ - @shipfox/api-projects@0.1.1
53
+ - @shipfox/api-workflows@0.1.1
54
+ - @shipfox/node-module@0.1.1
55
+ - @shipfox/node-outbox@0.1.1
56
+
57
+ ## 0.1.0
58
+
59
+ ### Minor Changes
60
+
61
+ - a460020: Add trigger event detail decisions with stored subscription names, run links, and payload inspection.
62
+ - 5ec8367: Adds trigger event inspection endpoints with matching DTO schemas for listing received events and reading event decisions.
63
+
64
+ ### Patch Changes
65
+
66
+ - ae7a63c: Adds daily dispatched outbox row retention with bounded cleanup batches and retention indexes on module outbox tables.
67
+ - 555299c: Add the append-only `triggers_received_events` and `triggers_decisions` tables that back the trigger event history. DB layer only: Drizzle schema, inferred types, and row→domain mappers, folded into the triggers module's baseline migration. No write or read path is wired yet.
68
+ - 9a4807d: Add the hourly Temporal prune cron and `TRIGGER_EVENT_RETENTION_DAYS` config var that bound trigger event history growth. The cron deletes `triggers_received_events` older than the retention window (default 30 days); `triggers_decisions` go with them via FK cascade.
69
+ - e5d2f13: Add the workspace **Events** page in Settings: a filterable, cursor-paginated table of
70
+ trigger events (status dot, source/event, routing summary, delivery id, received time)
71
+ mounted at `/workspaces/$wid/settings/events` and wired into the settings sub-nav. Filters
72
+ (date range, source, event, outcome) live in the URL via `validateSearch`, so a filtered
73
+ view is shareable. Source and event filters are populated by a new
74
+ `GET /trigger-events/facets` endpoint that returns each workspace's distinct source/event
75
+ values with counts (top 50, backed by `(workspace_id, source)` / `(workspace_id, event)`
76
+ indexes); the list still renders if facets fail to load.
77
+ - a982f20: Stop a permanently-broken trigger subscription from starving its siblings or wedging the outbox. Integration dispatch now attempts every matched subscription and classifies each `runWorkflow` failure: a permanent error (deleted definition or project mismatch) is recorded and skipped, while a transient one re-throws so the outbox replays the event and converges. The event reaches a terminal outcome once no transient error remains (`routed` when any run was created, otherwise the new `errored` outcome), with a guarded write that never records `errored` over an event that already produced a run. The manual-fire path records the same terminal outcome, and `@shipfox/api-workflows` exports an `isPermanentRunWorkflowError` classifier. The trigger-events read API (`triggerEventOutcomeSchema`) accepts the new `errored` outcome for serialization and filtering.
78
+ - 3dcd751: Adds listener filter snapshots to job activation events and persists them on listener subscriptions.
79
+ - 6077301: Adds shared timestamp/id keyset pagination helpers and migrates workflow run and trigger event lists onto them.
80
+ - 3bea87f: Adds a typed `subscriberFactory` that binds each outbox event name to its payload type at construction, so subscriber handlers receive a typed `(payload, event)` and the per-handler `event.payload as X` casts are gone; a private brand makes the factory the only way to build a module subscriber.
81
+ - b74f635: Adds workflow run interpolation context resolution while preserving authored step configuration for reruns and diagnostics.
82
+ - e192d86: Adds the cron firing engine: a once-per-minute tick fans out bounded drain activities that claim due schedules (FOR UPDATE SKIP LOCKED), advance their next fire time, and fire the workflow deduplicated and crash-safe, recorded in trigger history with a `cron` origin and surfaced through cron fire and backlog metrics.
83
+ - 638ac4d: Adds cron trigger schedule persistence and deterministic next-fire computation for resolved workflow definitions.
84
+ - Updated dependencies [eb40964]
85
+ - Updated dependencies [7bc7498]
86
+ - Updated dependencies [5c18360]
87
+ - Updated dependencies [2c156d2]
88
+ - Updated dependencies [26fea4b]
89
+ - Updated dependencies [0cf66c4]
90
+ - Updated dependencies [34ba284]
91
+ - Updated dependencies [a56748d]
92
+ - Updated dependencies [8f51daf]
93
+ - Updated dependencies [5707d6d]
94
+ - Updated dependencies [e689abf]
95
+ - Updated dependencies [59ba68b]
96
+ - Updated dependencies [7a9943d]
97
+ - Updated dependencies [ce3e5ca]
98
+ - Updated dependencies [f788565]
99
+ - Updated dependencies [b9c3f32]
100
+ - Updated dependencies [c17dd6e]
101
+ - Updated dependencies [a81b68c]
102
+ - Updated dependencies [115655e]
103
+ - Updated dependencies [c0a883c]
104
+ - Updated dependencies [72ce351]
105
+ - Updated dependencies [cdf8989]
106
+ - Updated dependencies [e47f8da]
107
+ - Updated dependencies [736249b]
108
+ - Updated dependencies [2bc5595]
109
+ - Updated dependencies [b1f57d1]
110
+ - Updated dependencies [1127ba2]
111
+ - Updated dependencies [36f871d]
112
+ - Updated dependencies [e7b01dd]
113
+ - Updated dependencies [d546b88]
114
+ - Updated dependencies [58c05ed]
115
+ - Updated dependencies [ce062a9]
116
+ - Updated dependencies [9086e65]
117
+ - Updated dependencies [7b175f5]
118
+ - Updated dependencies [7ca4c65]
119
+ - Updated dependencies [e9056c7]
120
+ - Updated dependencies [8e9c6cb]
121
+ - Updated dependencies [97162dd]
122
+ - Updated dependencies [b694b09]
123
+ - Updated dependencies [c47be09]
124
+ - Updated dependencies [f9f059e]
125
+ - Updated dependencies [940696a]
126
+ - Updated dependencies [f3614ae]
127
+ - Updated dependencies [f98c2be]
128
+ - Updated dependencies [e9396c9]
129
+ - Updated dependencies [ae7a63c]
130
+ - Updated dependencies [5729548]
131
+ - Updated dependencies [f92122b]
132
+ - Updated dependencies [e250c4c]
133
+ - Updated dependencies [b525dcd]
134
+ - Updated dependencies [f8f339a]
135
+ - Updated dependencies [857fd73]
136
+ - Updated dependencies [e5d2f13]
137
+ - Updated dependencies [a982f20]
138
+ - Updated dependencies [7fa8f0b]
139
+ - Updated dependencies [998eba3]
140
+ - Updated dependencies [5327934]
141
+ - Updated dependencies [314e84e]
142
+ - Updated dependencies [a460020]
143
+ - Updated dependencies [3afb7e3]
144
+ - Updated dependencies [139e3be]
145
+ - Updated dependencies [eb7d5e8]
146
+ - Updated dependencies [247cbd6]
147
+ - Updated dependencies [5d53ed4]
148
+ - Updated dependencies [c652a68]
149
+ - Updated dependencies [121b42e]
150
+ - Updated dependencies [75520ff]
151
+ - Updated dependencies [e87731a]
152
+ - Updated dependencies [795f440]
153
+ - Updated dependencies [3dcd751]
154
+ - Updated dependencies [c0a883c]
155
+ - Updated dependencies [362b3eb]
156
+ - Updated dependencies [b8e49ff]
157
+ - Updated dependencies [d6d4862]
158
+ - Updated dependencies [c0a883c]
159
+ - Updated dependencies [6077301]
160
+ - Updated dependencies [f85b223]
161
+ - Updated dependencies [9c1c947]
162
+ - Updated dependencies [f0afdf8]
163
+ - Updated dependencies [9d3b43a]
164
+ - Updated dependencies [d635979]
165
+ - Updated dependencies [3bea87f]
166
+ - Updated dependencies [82d22e4]
167
+ - Updated dependencies [d69b164]
168
+ - Updated dependencies [69d02e5]
169
+ - Updated dependencies [2fb3e87]
170
+ - Updated dependencies [01be723]
171
+ - Updated dependencies [f63c6b0]
172
+ - Updated dependencies [e0fee57]
173
+ - Updated dependencies [b74f635]
174
+ - Updated dependencies [fa67aa3]
175
+ - Updated dependencies [e192d86]
176
+ - Updated dependencies [9a5aac4]
177
+ - Updated dependencies [30d1c82]
178
+ - Updated dependencies [5ec8367]
179
+ - Updated dependencies [ef1e917]
180
+ - Updated dependencies [51eb38a]
181
+ - Updated dependencies [61de795]
182
+ - Updated dependencies [c6eb2ee]
183
+ - Updated dependencies [e2fbef8]
184
+ - Updated dependencies [8ecba0f]
185
+ - Updated dependencies [f9153e8]
186
+ - Updated dependencies [27770eb]
187
+ - Updated dependencies [2933c33]
188
+ - Updated dependencies [2ad300c]
189
+ - Updated dependencies [a314b05]
190
+ - Updated dependencies [43fd0c1]
191
+ - Updated dependencies [950ebef]
192
+ - Updated dependencies [6181819]
193
+ - Updated dependencies [a8905ed]
194
+ - Updated dependencies [1ea2f6a]
195
+ - Updated dependencies [e699508]
196
+ - Updated dependencies [ad6056b]
197
+ - Updated dependencies [282e66a]
198
+ - Updated dependencies [0dd23a7]
199
+ - Updated dependencies [9c149d1]
200
+ - Updated dependencies [f88aac9]
201
+ - Updated dependencies [e1d4972]
202
+ - Updated dependencies [f9bf446]
203
+ - Updated dependencies [a856155]
204
+ - Updated dependencies [78527ce]
205
+ - Updated dependencies [b8919da]
206
+ - Updated dependencies [8ecc121]
207
+ - Updated dependencies [d7b9596]
208
+ - @shipfox/workflow-document@2.0.0
209
+ - @shipfox/api-workflows@0.1.0
210
+ - @shipfox/api-workflows-dto@0.1.0
211
+ - @shipfox/expression@1.1.0
212
+ - @shipfox/node-fastify@0.2.0
213
+ - @shipfox/node-drizzle@0.1.0
214
+ - @shipfox/api-definitions-dto@0.0.1
215
+ - @shipfox/api-auth-context@0.1.0
216
+ - @shipfox/api-integration-core-dto@0.1.0
217
+ - @shipfox/api-projects@0.1.0
218
+ - @shipfox/node-opentelemetry@0.4.2
219
+ - @shipfox/node-postgres@0.3.2
220
+ - @shipfox/node-temporal@0.1.1
221
+ - @shipfox/node-module@0.1.0
222
+ - @shipfox/node-outbox@0.1.0
223
+ - @shipfox/api-triggers-dto@0.1.0
224
+ - @shipfox/config@1.2.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shipfox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # Shipfox API Triggers
2
+
3
+ Shipfox API Triggers decides when a workflow run starts. It projects the
4
+ `triggers` map from each workflow YAML into an indexed subscription table,
5
+ matches incoming integration events against those subscriptions, and starts
6
+ a workflow run for every match. It also exposes HTTP routes that fire manual
7
+ runs and inspect received trigger events.
8
+
9
+ ## Example
10
+
11
+ Register the module with the API module runner:
12
+
13
+ ```ts
14
+ import {triggersModule} from '@shipfox/api-triggers';
15
+ import {createApp, listen} from '@shipfox/node-fastify';
16
+ import {initializeModules, startModuleWorkers} from '@shipfox/node-module';
17
+
18
+ const {auth, routes, workers} = await initializeModules({
19
+ modules: [triggersModule /* and other modules */],
20
+ });
21
+
22
+ await createApp({auth, routes});
23
+ await startModuleWorkers({workers});
24
+ await listen();
25
+ ```
26
+
27
+ This adds:
28
+
29
+ - triggers database migrations from `libs/api/triggers/drizzle`
30
+ - the `POST /workflow-definitions/:definitionId/fire-manual` route
31
+ - the `GET /trigger-events`, `GET /trigger-events/facets`, and `GET /trigger-events/:id` inspection routes
32
+ - subscribers for `DEFINITION_RESOLVED`, `DEFINITION_DELETED`, and
33
+ `INTEGRATION_EVENT_RECEIVED`
34
+ - the `triggers` outbox publisher
35
+ - the hourly `triggers-prune-trigger-events` Temporal cron, which deletes old
36
+ rows from `triggers_received_events`
37
+
38
+ A workflow YAML opts into triggers like this:
39
+
40
+ ```yaml
41
+ triggers:
42
+ on_demand:
43
+ source: manual
44
+ on_push:
45
+ source: github_acme
46
+ event: push
47
+ on: main
48
+ ```
49
+
50
+ Each source is an integration connection slug. Each map key is the trigger's `name`. A workflow may declare any number of
51
+ integration triggers and at most one `source: manual` trigger; the manual
52
+ invariant is enforced at parse time so the fire route stays unambiguous.
53
+ The `event` field is optional when `source: manual` and defaults to
54
+ `fire`.
55
+
56
+ Integration triggers may include a CEL `filter` predicate. Dispatch evaluates
57
+ the predicate for every subscription that matches `(workspace_id, source,
58
+ event)` with the context `{event: payload, trigger: {source, event}}`. A
59
+ missing filter matches; `true` creates a run; `false` or a non-boolean result
60
+ skips the subscription and can leave the event `discarded`; an evaluation
61
+ failure records a `filter-error` decision and fails closed without creating a
62
+ run.
63
+
64
+ Webhook triggers use the webhook connection slug as `source` and the fixed
65
+ event name `received`. A delivery to `POST /webhook/:connectionId` publishes
66
+ an `INTEGRATION_EVENT_RECEIVED` envelope with `provider: webhook`,
67
+ `source: <connection.slug>`, `event: received`, and payload
68
+ `{method, headers, query, body}`. Trigger dispatch matches only on
69
+ `(workspace_id, source, event)`, so a workflow that listens to a webhook uses
70
+ the slug plus `event: received`:
71
+
72
+ ```yaml
73
+ triggers:
74
+ on_stripe:
75
+ source: stripe_prod
76
+ event: received
77
+ ```
78
+
79
+ Workflow interpolation exposes the webhook envelope as `event`, so steps can
80
+ read values such as `${{ event.body.payment_id }}` and
81
+ `${{ event.headers["x-stripe-signature"] }}`. Header/body-derived event
82
+ subtypes are not part of this contract.
83
+
84
+ GitHub triggers use the raw GitHub webhook resource name, plus the payload
85
+ `action` when one is present. For example, a pull request open event is
86
+ `pull_request.opened`, an issue close event is `issues.closed`, and a
87
+ release publish event is `release.published`. Events without an action use
88
+ the bare resource name, such as `push` or `fork`. Common GitHub events are:
89
+ `push`, `pull_request.opened`, `pull_request.closed`, `issues.opened`,
90
+ `issues.closed`, `issue_comment.created`, `release.published`,
91
+ `workflow_run.completed`, `installation.created`, and
92
+ `installation_repositories.added`. GitHub only sends events that the GitHub
93
+ App is subscribed to in its Permissions & events settings.
94
+
95
+ ## Setup
96
+
97
+ Install the package from the registry:
98
+
99
+ ```sh
100
+ pnpm add @shipfox/api-triggers
101
+ ```
102
+
103
+ The matching HTTP contract lives in
104
+ [`@shipfox/api-triggers-dto`](../triggers-dto). Import Zod schemas and DTO
105
+ types from there when you call the route from the client.
106
+
107
+ The package reads `TRIGGER_EVENT_RETENTION_DAYS` to decide how many days of
108
+ received trigger events to keep before the maintenance cron deletes them.
109
+ It also depends on the API database connection from `@shipfox/node-postgres`.
110
+
111
+ ## Routes
112
+
113
+ The routes are mounted by the host app under the `/workflow-definitions` and
114
+ `/trigger-events` prefixes.
115
+
116
+ | Method | Path | Auth | Result |
117
+ | --- | --- | --- | --- |
118
+ | `POST` | `/workflow-definitions/:definitionId/fire-manual` | bearer token | Fires the workflow's manual trigger and returns the new `workflow_run_id`. Optional `inputs` in the body are forwarded to the run. |
119
+ | `GET` | `/trigger-events?workspace_id=:workspaceId` | bearer token | Lists received trigger events for a workspace, newest first. Supports source, event, outcome, received-at window, limit, and cursor filters. |
120
+ | `GET` | `/trigger-events/facets?workspace_id=:workspaceId` | bearer token | Returns the workspace's distinct `source` and `event` filter values with counts (top 50 each, by count). Backs the Events page filter dropdowns. |
121
+ | `GET` | `/trigger-events/:id` | bearer token | Returns one received trigger event with its full payload and routing decisions. Cross-workspace ids return `404`. |
122
+
123
+ The manual route is keyed by workflow definition id, not subscription id. The
124
+ server resolves the manual subscription for the workflow internally; the
125
+ "at most one manual trigger per workflow" invariant from the parser keeps
126
+ that lookup unambiguous. Integration sources (github, etc.) fire through
127
+ the event bus and have no HTTP entry point.
128
+
129
+ ## Vocabulary
130
+
131
+ Three words, used the same way at every layer.
132
+
133
+ | Word | Meaning | Examples |
134
+ | --- | --- | --- |
135
+ | **source** | Where the trigger came from. | `github`, `gitlab`, `sentry`, `manual`, `cron` |
136
+ | **event** | The specific thing that happened, scoped to a source. | `push`, `issue_comment`, `alert_triggered`, `fire`, `tick` |
137
+ | **payload** | The data carried by the event, set by the producing integration. Triggers passes it through opaquely. | GitHub's raw webhook JSON for `(github, push)` |
138
+
139
+ The `name` field on a subscription is the YAML map key (for example
140
+ `on_push`). It identifies the trigger inside a workflow definition and is
141
+ unique per `(workflow_definition_id, name)`.
142
+
143
+ ### Words we do not use
144
+
145
+ - `provider` — reserved for the integration module's identity
146
+ (`integrations_connections.provider`). Trigger code says `source`.
147
+ - `eventType` / `type` — replaced by `event`. The bare word `type` would
148
+ collide with TypeScript discriminators and with the `IntegrationProvider`
149
+ capability `type` field.
150
+ - `triggerContext` — the runtime payload on a run is called
151
+ `triggerPayload`.
152
+ - `kind` — every trigger is identified by `(source, event)`. There is no
153
+ separate axis.
154
+
155
+ ## Architecture
156
+
157
+ Triggers flow through three layers. The YAML map is the source of truth,
158
+ the subscription table is the queryable projection, and the workflow run
159
+ table is the immutable history.
160
+
161
+ ```
162
+ ┌─────────────────────────────────────────────────────┐
163
+ │ workflow_definitions.definition (JSONB) │
164
+ │ triggers: {on_push: {source, event, ...}} │
165
+ └──────────────────────────┬──────────────────────────┘
166
+
167
+ │ DEFINITION_RESOLVED
168
+ │ / DEFINITION_DELETED
169
+
170
+ ┌─────────────────────────────────────────────────────┐
171
+ │ triggers_subscriptions │
172
+ │ (workspace_id, project_id, │
173
+ │ workflow_definition_id, name, │
174
+ │ source, event, config) │
175
+ └──────────────────────────┬──────────────────────────┘
176
+
177
+ INTEGRATION_EVENT_RECEIVED → match on (workspace, source, event)
178
+ or POST /workflow-definitions/:definitionId/fire-manual → look up manual subscription
179
+
180
+
181
+ ┌─────────────────────────────────────────────────────┐
182
+ │ workflow_runs │
183
+ │ trigger_source, trigger_event (indexed text) │
184
+ │ trigger_payload (jsonb) │
185
+ └─────────────────────────────────────────────────────┘
186
+ ```
187
+
188
+ ### Layer 1 — workflow definition (source of truth)
189
+
190
+ The YAML `triggers` map lives inside `workflow_definitions.definition`
191
+ (JSONB owned by the definitions module). That is the only place trigger
192
+ declarations live in raw form.
193
+
194
+ ### Layer 2 — projection (queryable)
195
+
196
+ `triggers_subscriptions` is rebuilt from `DEFINITION_RESOLVED` events,
197
+ which carry the parsed `triggers` map. The triggers module never reads the
198
+ definitions table — the event is the contract.
199
+
200
+ Cron triggers also project into `triggers_cron_schedules`, keyed by
201
+ `subscription_id`. That table stores the resolved cron expression, timezone,
202
+ next fire time, and last fire time used by the cron firing engine.
203
+
204
+ Indexes:
205
+
206
+ - `(workflow_definition_id, name)` — unique. One row per YAML trigger.
207
+ - `(workspace_id, source, event)` — the hot path for matching incoming
208
+ integration events at workspace scope.
209
+ - `(workflow_definition_id)` — used to clean up the projection on
210
+ `DEFINITION_DELETED`.
211
+ - `triggers_cron_schedules.next_fire_at` — used to drain due cron schedules
212
+ in next-fire order.
213
+
214
+ ### Layer 3 — run history (immutable)
215
+
216
+ `workflow_runs.trigger_source` and `trigger_event` are indexed text
217
+ columns. `trigger_payload` is a JSONB column typed by `TriggerPayload`:
218
+ `manual`/`cron` carry their own typed shapes, while integration events use
219
+ a generic `{source, event, deliveryId, data}` shape that forwards the raw
220
+ event payload as `data`. The `triggerSource` value on a row always equals
221
+ `triggerPayload.source`. The duplication is deliberate: the indexed column
222
+ is for filtering, the payload is for inspection.
223
+
224
+ ## Events
225
+
226
+ | Event | Published by | Consumed by | Purpose |
227
+ | --- | --- | --- | --- |
228
+ | `INTEGRATION_EVENT_RECEIVED` | `integration/*` | triggers, projects | An integration received a webhook and validated it. The payload is the integration's domain event. |
229
+ | `DEFINITION_RESOLVED` | definitions | triggers | A workflow definition was created or updated. The payload includes the parsed `triggers` map. |
230
+ | `DEFINITION_DELETED` | definitions | triggers | A workflow definition was soft-deleted. Subscription rows are removed. |
231
+
232
+ ## API
233
+
234
+ The package exports the module entry point:
235
+
236
+ ```ts
237
+ import {triggersModule} from '@shipfox/api-triggers';
238
+ ```
239
+
240
+ It also exports lower-level pieces for tests and advanced wiring:
241
+
242
+ - `fireManualSubscription()`: core function used by the route. Throws
243
+ `TriggerSubscriptionNotFoundError`,
244
+ `TriggerSubscriptionNotManualError`, or
245
+ `TriggerWorkspaceMismatchError`.
246
+ - `ManualTriggerNotFoundError`: thrown by the route handler when the
247
+ caller's workspace cannot reach the workflow, or the workflow declares
248
+ no manual trigger. Surfaced as `404 manual-trigger-not-found`.
249
+ - `findMatchingSubscriptions()`: hot-path lookup by
250
+ `(workspace_id, source, event)`.
251
+ - `getManualSubscriptionByDefinitionId()`: resolves the single manual
252
+ subscription for a workflow definition (or `undefined` if none).
253
+ - `getTriggerSubscriptionById()` and
254
+ `listSubscriptionsByWorkflowDefinitionIds()`: read helpers.
255
+ - `db`, `migrationsPath`, and `triggersOutbox`: the Drizzle handle,
256
+ migration path, and outbox table.
257
+ - Entity type: `TriggerSubscription`.
258
+
259
+ ## Adding a new source
260
+
261
+ To wire a new integration source (for example GitLab):
262
+
263
+ 1. Add a payload type for each supported event to
264
+ `@shipfox/api-integration-core-dto` (for example `GitlabPushPayload`).
265
+ 2. In the new `integration/<source>` package, receive webhooks and publish
266
+ `INTEGRATION_EVENT_RECEIVED` with `source: '<name>'`,
267
+ `event: '<type>'`, and the payload.
268
+
269
+ That is the whole list. The triggers subscriber is source-agnostic: it
270
+ matches subscriptions on `(workspace, source, event)` and forwards the raw
271
+ payload through the generic `TriggerPayload` shape, so no change to the
272
+ triggers module, the projection schema, the run table, or `TriggerPayload`
273
+ is needed for a new source. Author workflows that subscribe to the new
274
+ `(source, event)` and narrow `triggerPayload.data` themselves.
275
+
276
+ For Sentry's supported `(source, event)` values, see
277
+ [`@shipfox/api-integration-sentry`](../integration/sentry).
278
+
279
+ ## Development
280
+
281
+ Run checks for this package:
282
+
283
+ ```sh
284
+ turbo check --filter=@shipfox/api-triggers
285
+ turbo type --filter=@shipfox/api-triggers
286
+ turbo test --filter=@shipfox/api-triggers
287
+ ```
288
+
289
+ Tests use Vitest and a real PostgreSQL database. Start local services
290
+ before running the test suite:
291
+
292
+ ```sh
293
+ docker compose up -d
294
+ ```
295
+
296
+ The test environment uses the `api_test` database, set in `test/env.ts`.
297
+
298
+ ## License
299
+
300
+ MIT
@@ -0,0 +1,10 @@
1
+ export declare const config: Readonly<{
2
+ TRIGGER_EVENT_RETENTION_DAYS: number;
3
+ TRIGGER_CRON_JITTER_WINDOW_SECONDS: number;
4
+ TRIGGER_CRON_FANOUT: number;
5
+ TRIGGER_CRON_CLAIM_BATCH: number;
6
+ } & import("@shipfox/config").CleanedEnvAccessors>;
7
+ export declare function assertRetentionDaysWithinBounds(days: number): void;
8
+ export declare function assertCronConfigWithinBounds(jitterWindowSeconds: number): void;
9
+ export declare function assertCronThroughputWithinBounds(fanout: number, claimBatch: number): void;
10
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;;;;;kDAiBjB,CAAC;AAEH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMlE;AAID,wBAAgB,4BAA4B,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAM9E;AAID,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CASzF"}
package/dist/config.js ADDED
@@ -0,0 +1,42 @@
1
+ import { createConfig, num } from '@shipfox/config';
2
+ export const config = createConfig({
3
+ TRIGGER_EVENT_RETENTION_DAYS: num({
4
+ desc: 'How many days a recorded trigger event (and its decisions) is kept before the hourly prune cron deletes it. Must be at least 1; a smaller value moves the cutoff to now or the future and would delete freshly recorded events. Defaults to 30.',
5
+ default: 30
6
+ }),
7
+ TRIGGER_CRON_JITTER_WINDOW_SECONDS: num({
8
+ desc: 'Maximum number of seconds added as deterministic jitter to a cron trigger fire time. Use 0 to disable jitter. Values below about 60 seconds are usually no-ops when cron ticking runs at minute resolution; multi-minute windows spread large schedule herds.',
9
+ default: 0
10
+ }),
11
+ TRIGGER_CRON_FANOUT: num({
12
+ desc: 'How many drain activities the once-per-minute cron tick runs in parallel. Each activity claims and fires one bounded batch, so the per-minute ceiling is TRIGGER_CRON_FANOUT times TRIGGER_CRON_CLAIM_BATCH runs. Raise it (and pod count) to fire more schedules per minute. Must be at least 1. Defaults to 2.',
13
+ default: 2
14
+ }),
15
+ TRIGGER_CRON_CLAIM_BATCH: num({
16
+ desc: 'How many due cron schedules a single drain activity claims and fires per tick. Bounds the load a cron burst can put on the database and the run-creation path. Must be at least 1. Defaults to 100.',
17
+ default: 100
18
+ })
19
+ });
20
+ export function assertRetentionDaysWithinBounds(days) {
21
+ if (!Number.isFinite(days) || days < 1) {
22
+ throw new Error(`TRIGGER_EVENT_RETENTION_DAYS must be a finite number of at least 1, received ${days}.`);
23
+ }
24
+ }
25
+ assertRetentionDaysWithinBounds(config.TRIGGER_EVENT_RETENTION_DAYS);
26
+ export function assertCronConfigWithinBounds(jitterWindowSeconds) {
27
+ if (!Number.isFinite(jitterWindowSeconds) || jitterWindowSeconds < 0) {
28
+ throw new Error(`TRIGGER_CRON_JITTER_WINDOW_SECONDS must be a finite non-negative number, received ${jitterWindowSeconds}.`);
29
+ }
30
+ }
31
+ assertCronConfigWithinBounds(config.TRIGGER_CRON_JITTER_WINDOW_SECONDS);
32
+ export function assertCronThroughputWithinBounds(fanout, claimBatch) {
33
+ if (!Number.isInteger(fanout) || fanout < 1) {
34
+ throw new Error(`TRIGGER_CRON_FANOUT must be an integer of at least 1, received ${fanout}.`);
35
+ }
36
+ if (!Number.isInteger(claimBatch) || claimBatch < 1) {
37
+ throw new Error(`TRIGGER_CRON_CLAIM_BATCH must be an integer of at least 1, received ${claimBatch}.`);
38
+ }
39
+ }
40
+ assertCronThroughputWithinBounds(config.TRIGGER_CRON_FANOUT, config.TRIGGER_CRON_CLAIM_BATCH);
41
+
42
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {createConfig, num} from '@shipfox/config';\n\nexport const config = createConfig({\n TRIGGER_EVENT_RETENTION_DAYS: num({\n desc: 'How many days a recorded trigger event (and its decisions) is kept before the hourly prune cron deletes it. Must be at least 1; a smaller value moves the cutoff to now or the future and would delete freshly recorded events. Defaults to 30.',\n default: 30,\n }),\n TRIGGER_CRON_JITTER_WINDOW_SECONDS: num({\n desc: 'Maximum number of seconds added as deterministic jitter to a cron trigger fire time. Use 0 to disable jitter. Values below about 60 seconds are usually no-ops when cron ticking runs at minute resolution; multi-minute windows spread large schedule herds.',\n default: 0,\n }),\n TRIGGER_CRON_FANOUT: num({\n desc: 'How many drain activities the once-per-minute cron tick runs in parallel. Each activity claims and fires one bounded batch, so the per-minute ceiling is TRIGGER_CRON_FANOUT times TRIGGER_CRON_CLAIM_BATCH runs. Raise it (and pod count) to fire more schedules per minute. Must be at least 1. Defaults to 2.',\n default: 2,\n }),\n TRIGGER_CRON_CLAIM_BATCH: num({\n desc: 'How many due cron schedules a single drain activity claims and fires per tick. Bounds the load a cron burst can put on the database and the run-creation path. Must be at least 1. Defaults to 100.',\n default: 100,\n }),\n});\n\nexport function assertRetentionDaysWithinBounds(days: number): void {\n if (!Number.isFinite(days) || days < 1) {\n throw new Error(\n `TRIGGER_EVENT_RETENTION_DAYS must be a finite number of at least 1, received ${days}.`,\n );\n }\n}\n\nassertRetentionDaysWithinBounds(config.TRIGGER_EVENT_RETENTION_DAYS);\n\nexport function assertCronConfigWithinBounds(jitterWindowSeconds: number): void {\n if (!Number.isFinite(jitterWindowSeconds) || jitterWindowSeconds < 0) {\n throw new Error(\n `TRIGGER_CRON_JITTER_WINDOW_SECONDS must be a finite non-negative number, received ${jitterWindowSeconds}.`,\n );\n }\n}\n\nassertCronConfigWithinBounds(config.TRIGGER_CRON_JITTER_WINDOW_SECONDS);\n\nexport function assertCronThroughputWithinBounds(fanout: number, claimBatch: number): void {\n if (!Number.isInteger(fanout) || fanout < 1) {\n throw new Error(`TRIGGER_CRON_FANOUT must be an integer of at least 1, received ${fanout}.`);\n }\n if (!Number.isInteger(claimBatch) || claimBatch < 1) {\n throw new Error(\n `TRIGGER_CRON_CLAIM_BATCH must be an integer of at least 1, received ${claimBatch}.`,\n );\n }\n}\n\nassertCronThroughputWithinBounds(config.TRIGGER_CRON_FANOUT, config.TRIGGER_CRON_CLAIM_BATCH);\n"],"names":["createConfig","num","config","TRIGGER_EVENT_RETENTION_DAYS","desc","default","TRIGGER_CRON_JITTER_WINDOW_SECONDS","TRIGGER_CRON_FANOUT","TRIGGER_CRON_CLAIM_BATCH","assertRetentionDaysWithinBounds","days","Number","isFinite","Error","assertCronConfigWithinBounds","jitterWindowSeconds","assertCronThroughputWithinBounds","fanout","claimBatch","isInteger"],"mappings":"AAAA,SAAQA,YAAY,EAAEC,GAAG,QAAO,kBAAkB;AAElD,OAAO,MAAMC,SAASF,aAAa;IACjCG,8BAA8BF,IAAI;QAChCG,MAAM;QACNC,SAAS;IACX;IACAC,oCAAoCL,IAAI;QACtCG,MAAM;QACNC,SAAS;IACX;IACAE,qBAAqBN,IAAI;QACvBG,MAAM;QACNC,SAAS;IACX;IACAG,0BAA0BP,IAAI;QAC5BG,MAAM;QACNC,SAAS;IACX;AACF,GAAG;AAEH,OAAO,SAASI,gCAAgCC,IAAY;IAC1D,IAAI,CAACC,OAAOC,QAAQ,CAACF,SAASA,OAAO,GAAG;QACtC,MAAM,IAAIG,MACR,CAAC,6EAA6E,EAAEH,KAAK,CAAC,CAAC;IAE3F;AACF;AAEAD,gCAAgCP,OAAOC,4BAA4B;AAEnE,OAAO,SAASW,6BAA6BC,mBAA2B;IACtE,IAAI,CAACJ,OAAOC,QAAQ,CAACG,wBAAwBA,sBAAsB,GAAG;QACpE,MAAM,IAAIF,MACR,CAAC,kFAAkF,EAAEE,oBAAoB,CAAC,CAAC;IAE/G;AACF;AAEAD,6BAA6BZ,OAAOI,kCAAkC;AAEtE,OAAO,SAASU,iCAAiCC,MAAc,EAAEC,UAAkB;IACjF,IAAI,CAACP,OAAOQ,SAAS,CAACF,WAAWA,SAAS,GAAG;QAC3C,MAAM,IAAIJ,MAAM,CAAC,+DAA+D,EAAEI,OAAO,CAAC,CAAC;IAC7F;IACA,IAAI,CAACN,OAAOQ,SAAS,CAACD,eAAeA,aAAa,GAAG;QACnD,MAAM,IAAIL,MACR,CAAC,oEAAoE,EAAEK,WAAW,CAAC,CAAC;IAExF;AACF;AAEAF,iCAAiCd,OAAOK,mBAAmB,EAAEL,OAAOM,wBAAwB"}
@@ -0,0 +1,9 @@
1
+ export interface ComputeNextFireAtParams {
2
+ readonly cronExpression: string;
3
+ readonly timezone: string;
4
+ readonly from: Date;
5
+ readonly subscriptionId: string;
6
+ readonly jitterWindowSeconds: number;
7
+ }
8
+ export declare function computeNextFireAt(params: ComputeNextFireAtParams): Date;
9
+ //# sourceMappingURL=compute-next-fire-at.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-next-fire-at.d.ts","sourceRoot":"","sources":["../../src/core/compute-next-fire-at.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CAUvE"}
@@ -0,0 +1,28 @@
1
+ import { CronExpressionParser } from 'cron-parser';
2
+ export function computeNextFireAt(params) {
3
+ const iterator = CronExpressionParser.parse(params.cronExpression, {
4
+ currentDate: params.from,
5
+ tz: params.timezone
6
+ });
7
+ const occurrence = iterator.next().toDate();
8
+ const following = iterator.next().toDate();
9
+ const gapMs = following.getTime() - occurrence.getTime();
10
+ const offsetMs = jitterOffsetMs(params.subscriptionId, params.jitterWindowSeconds, gapMs);
11
+ return new Date(occurrence.getTime() + offsetMs);
12
+ }
13
+ function jitterOffsetMs(subscriptionId, windowSeconds, gapMs) {
14
+ const windowMs = Math.floor(windowSeconds * 1000);
15
+ const clampMs = Math.min(windowMs, gapMs);
16
+ if (clampMs <= 0) return 0;
17
+ return hashStringToUint32(subscriptionId) % clampMs;
18
+ }
19
+ function hashStringToUint32(value) {
20
+ let hash = 0x811c9dc5;
21
+ for(let index = 0; index < value.length; index += 1){
22
+ hash ^= value.charCodeAt(index);
23
+ hash = Math.imul(hash, 0x01000193);
24
+ }
25
+ return hash >>> 0;
26
+ }
27
+
28
+ //# sourceMappingURL=compute-next-fire-at.js.map