@shware/workflow 0.0.0-stage → 0.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 (442) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -2
  3. package/dist/_virtual/_rolldown/runtime.cjs +23 -0
  4. package/dist/apns-relay.cjs +105 -0
  5. package/dist/apns-relay.cjs.map +1 -0
  6. package/dist/apns-relay.d.cts +28 -0
  7. package/dist/apns-relay.d.cts.map +1 -0
  8. package/dist/apns-relay.d.mts +28 -0
  9. package/dist/apns-relay.d.mts.map +1 -0
  10. package/dist/apns-relay.mjs +104 -0
  11. package/dist/apns-relay.mjs.map +1 -0
  12. package/dist/apns.cjs +121 -0
  13. package/dist/apns.cjs.map +1 -0
  14. package/dist/apns.d.cts +63 -0
  15. package/dist/apns.d.cts.map +1 -0
  16. package/dist/apns.d.mts +63 -0
  17. package/dist/apns.d.mts.map +1 -0
  18. package/dist/apns.mjs +116 -0
  19. package/dist/apns.mjs.map +1 -0
  20. package/dist/client.cjs +125 -0
  21. package/dist/client.cjs.map +1 -0
  22. package/dist/client.d.cts +108 -0
  23. package/dist/client.d.cts.map +1 -0
  24. package/dist/client.d.mts +108 -0
  25. package/dist/client.d.mts.map +1 -0
  26. package/dist/client.mjs +122 -0
  27. package/dist/client.mjs.map +1 -0
  28. package/dist/cloudflare/bindings.cjs +28 -0
  29. package/dist/cloudflare/bindings.cjs.map +1 -0
  30. package/dist/cloudflare/bindings.d.cts +144 -0
  31. package/dist/cloudflare/bindings.d.cts.map +1 -0
  32. package/dist/cloudflare/bindings.d.mts +144 -0
  33. package/dist/cloudflare/bindings.d.mts.map +1 -0
  34. package/dist/cloudflare/bindings.mjs +25 -0
  35. package/dist/cloudflare/bindings.mjs.map +1 -0
  36. package/dist/cloudflare/channels.cjs +164 -0
  37. package/dist/cloudflare/channels.cjs.map +1 -0
  38. package/dist/cloudflare/channels.d.cts +29 -0
  39. package/dist/cloudflare/channels.d.cts.map +1 -0
  40. package/dist/cloudflare/channels.d.mts +29 -0
  41. package/dist/cloudflare/channels.d.mts.map +1 -0
  42. package/dist/cloudflare/channels.mjs +161 -0
  43. package/dist/cloudflare/channels.mjs.map +1 -0
  44. package/dist/cloudflare/d1-env.cjs +17 -0
  45. package/dist/cloudflare/d1-env.cjs.map +1 -0
  46. package/dist/cloudflare/d1-env.d.cts +12 -0
  47. package/dist/cloudflare/d1-env.d.cts.map +1 -0
  48. package/dist/cloudflare/d1-env.d.mts +12 -0
  49. package/dist/cloudflare/d1-env.d.mts.map +1 -0
  50. package/dist/cloudflare/d1-env.mjs +16 -0
  51. package/dist/cloudflare/d1-env.mjs.map +1 -0
  52. package/dist/cloudflare/index.cjs +54 -0
  53. package/dist/cloudflare/index.d.cts +19 -0
  54. package/dist/cloudflare/index.d.mts +19 -0
  55. package/dist/cloudflare/index.mjs +16 -0
  56. package/dist/cloudflare/router.cjs +516 -0
  57. package/dist/cloudflare/router.cjs.map +1 -0
  58. package/dist/cloudflare/router.d.cts +157 -0
  59. package/dist/cloudflare/router.d.cts.map +1 -0
  60. package/dist/cloudflare/router.d.mts +157 -0
  61. package/dist/cloudflare/router.d.mts.map +1 -0
  62. package/dist/cloudflare/router.mjs +503 -0
  63. package/dist/cloudflare/router.mjs.map +1 -0
  64. package/dist/cloudflare/runner.cjs +225 -0
  65. package/dist/cloudflare/runner.cjs.map +1 -0
  66. package/dist/cloudflare/runner.d.cts +73 -0
  67. package/dist/cloudflare/runner.d.cts.map +1 -0
  68. package/dist/cloudflare/runner.d.mts +73 -0
  69. package/dist/cloudflare/runner.d.mts.map +1 -0
  70. package/dist/cloudflare/runner.mjs +224 -0
  71. package/dist/cloudflare/runner.mjs.map +1 -0
  72. package/dist/cloudflare/schema.sql +127 -0
  73. package/dist/cloudflare/senders.cjs +114 -0
  74. package/dist/cloudflare/senders.cjs.map +1 -0
  75. package/dist/cloudflare/senders.d.cts +68 -0
  76. package/dist/cloudflare/senders.d.cts.map +1 -0
  77. package/dist/cloudflare/senders.d.mts +68 -0
  78. package/dist/cloudflare/senders.d.mts.map +1 -0
  79. package/dist/cloudflare/senders.mjs +108 -0
  80. package/dist/cloudflare/senders.mjs.map +1 -0
  81. package/dist/cloudflare/worker.cjs +228 -0
  82. package/dist/cloudflare/worker.cjs.map +1 -0
  83. package/dist/cloudflare/worker.d.cts +92 -0
  84. package/dist/cloudflare/worker.d.cts.map +1 -0
  85. package/dist/cloudflare/worker.d.mts +92 -0
  86. package/dist/cloudflare/worker.d.mts.map +1 -0
  87. package/dist/cloudflare/worker.mjs +224 -0
  88. package/dist/cloudflare/worker.mjs.map +1 -0
  89. package/dist/cloudflare/workers.d.cjs +0 -0
  90. package/dist/cloudflare/workers.d.cts +44 -0
  91. package/dist/cloudflare/workers.d.cts.map +1 -0
  92. package/dist/cloudflare/workers.d.mts +44 -0
  93. package/dist/cloudflare/workers.d.mts.map +1 -0
  94. package/dist/config.cjs +151 -0
  95. package/dist/config.cjs.map +1 -0
  96. package/dist/config.d.cts +149 -0
  97. package/dist/config.d.cts.map +1 -0
  98. package/dist/config.d.mts +149 -0
  99. package/dist/config.d.mts.map +1 -0
  100. package/dist/config.mjs +143 -0
  101. package/dist/config.mjs.map +1 -0
  102. package/dist/contract.cjs +212 -0
  103. package/dist/contract.cjs.map +1 -0
  104. package/dist/contract.d.cts +90 -0
  105. package/dist/contract.d.cts.map +1 -0
  106. package/dist/contract.d.mts +90 -0
  107. package/dist/contract.d.mts.map +1 -0
  108. package/dist/contract.mjs +206 -0
  109. package/dist/contract.mjs.map +1 -0
  110. package/dist/dsl/action.cjs +29 -0
  111. package/dist/dsl/action.cjs.map +1 -0
  112. package/dist/dsl/action.d.cts +64 -0
  113. package/dist/dsl/action.d.cts.map +1 -0
  114. package/dist/dsl/action.d.mts +64 -0
  115. package/dist/dsl/action.d.mts.map +1 -0
  116. package/dist/dsl/action.mjs +28 -0
  117. package/dist/dsl/action.mjs.map +1 -0
  118. package/dist/dsl/base.cjs +34 -0
  119. package/dist/dsl/base.cjs.map +1 -0
  120. package/dist/dsl/base.d.cts +45 -0
  121. package/dist/dsl/base.d.cts.map +1 -0
  122. package/dist/dsl/base.d.mts +45 -0
  123. package/dist/dsl/base.d.mts.map +1 -0
  124. package/dist/dsl/base.mjs +30 -0
  125. package/dist/dsl/base.mjs.map +1 -0
  126. package/dist/dsl/bundle.cjs +207 -0
  127. package/dist/dsl/bundle.cjs.map +1 -0
  128. package/dist/dsl/bundle.d.cts +19 -0
  129. package/dist/dsl/bundle.d.cts.map +1 -0
  130. package/dist/dsl/bundle.d.mts +19 -0
  131. package/dist/dsl/bundle.d.mts.map +1 -0
  132. package/dist/dsl/bundle.mjs +206 -0
  133. package/dist/dsl/bundle.mjs.map +1 -0
  134. package/dist/dsl/condition.cjs +177 -0
  135. package/dist/dsl/condition.cjs.map +1 -0
  136. package/dist/dsl/condition.d.cts +140 -0
  137. package/dist/dsl/condition.d.cts.map +1 -0
  138. package/dist/dsl/condition.d.mts +140 -0
  139. package/dist/dsl/condition.d.mts.map +1 -0
  140. package/dist/dsl/condition.mjs +156 -0
  141. package/dist/dsl/condition.mjs.map +1 -0
  142. package/dist/dsl/flow.cjs +228 -0
  143. package/dist/dsl/flow.cjs.map +1 -0
  144. package/dist/dsl/flow.d.cts +223 -0
  145. package/dist/dsl/flow.d.cts.map +1 -0
  146. package/dist/dsl/flow.d.mts +223 -0
  147. package/dist/dsl/flow.d.mts.map +1 -0
  148. package/dist/dsl/flow.mjs +226 -0
  149. package/dist/dsl/flow.mjs.map +1 -0
  150. package/dist/dsl/index.cjs +38 -0
  151. package/dist/dsl/index.d.cts +10 -0
  152. package/dist/dsl/index.d.mts +10 -0
  153. package/dist/dsl/index.mjs +9 -0
  154. package/dist/dsl/refs.cjs +59 -0
  155. package/dist/dsl/refs.cjs.map +1 -0
  156. package/dist/dsl/refs.d.cts +88 -0
  157. package/dist/dsl/refs.d.cts.map +1 -0
  158. package/dist/dsl/refs.d.mts +88 -0
  159. package/dist/dsl/refs.d.mts.map +1 -0
  160. package/dist/dsl/refs.mjs +55 -0
  161. package/dist/dsl/refs.mjs.map +1 -0
  162. package/dist/dsl/template.cjs +65 -0
  163. package/dist/dsl/template.cjs.map +1 -0
  164. package/dist/dsl/template.d.cts +75 -0
  165. package/dist/dsl/template.d.cts.map +1 -0
  166. package/dist/dsl/template.d.mts +75 -0
  167. package/dist/dsl/template.d.mts.map +1 -0
  168. package/dist/dsl/template.mjs +63 -0
  169. package/dist/dsl/template.mjs.map +1 -0
  170. package/dist/dsl/trigger.cjs +40 -0
  171. package/dist/dsl/trigger.cjs.map +1 -0
  172. package/dist/dsl/trigger.d.cts +65 -0
  173. package/dist/dsl/trigger.d.cts.map +1 -0
  174. package/dist/dsl/trigger.d.mts +65 -0
  175. package/dist/dsl/trigger.d.mts.map +1 -0
  176. package/dist/dsl/trigger.mjs +39 -0
  177. package/dist/dsl/trigger.mjs.map +1 -0
  178. package/dist/dsl/workflow.cjs +121 -0
  179. package/dist/dsl/workflow.cjs.map +1 -0
  180. package/dist/dsl/workflow.d.cts +59 -0
  181. package/dist/dsl/workflow.d.cts.map +1 -0
  182. package/dist/dsl/workflow.d.mts +59 -0
  183. package/dist/dsl/workflow.d.mts.map +1 -0
  184. package/dist/dsl/workflow.mjs +120 -0
  185. package/dist/dsl/workflow.mjs.map +1 -0
  186. package/dist/engine/actions.cjs +27 -0
  187. package/dist/engine/actions.cjs.map +1 -0
  188. package/dist/engine/actions.d.cts +40 -0
  189. package/dist/engine/actions.d.cts.map +1 -0
  190. package/dist/engine/actions.d.mts +40 -0
  191. package/dist/engine/actions.d.mts.map +1 -0
  192. package/dist/engine/actions.mjs +26 -0
  193. package/dist/engine/actions.mjs.map +1 -0
  194. package/dist/engine/bucket.cjs +72 -0
  195. package/dist/engine/bucket.cjs.map +1 -0
  196. package/dist/engine/bucket.d.cts +32 -0
  197. package/dist/engine/bucket.d.cts.map +1 -0
  198. package/dist/engine/bucket.d.mts +32 -0
  199. package/dist/engine/bucket.d.mts.map +1 -0
  200. package/dist/engine/bucket.mjs +69 -0
  201. package/dist/engine/bucket.mjs.map +1 -0
  202. package/dist/engine/condition.cjs +166 -0
  203. package/dist/engine/condition.cjs.map +1 -0
  204. package/dist/engine/condition.d.cts +52 -0
  205. package/dist/engine/condition.d.cts.map +1 -0
  206. package/dist/engine/condition.d.mts +52 -0
  207. package/dist/engine/condition.d.mts.map +1 -0
  208. package/dist/engine/condition.mjs +161 -0
  209. package/dist/engine/condition.mjs.map +1 -0
  210. package/dist/engine/index.cjs +20 -0
  211. package/dist/engine/index.d.cts +8 -0
  212. package/dist/engine/index.d.mts +8 -0
  213. package/dist/engine/index.mjs +7 -0
  214. package/dist/engine/interpreter.cjs +428 -0
  215. package/dist/engine/interpreter.cjs.map +1 -0
  216. package/dist/engine/interpreter.d.cts +6 -0
  217. package/dist/engine/interpreter.d.cts.map +1 -0
  218. package/dist/engine/interpreter.d.mts +6 -0
  219. package/dist/engine/interpreter.d.mts.map +1 -0
  220. package/dist/engine/interpreter.mjs +427 -0
  221. package/dist/engine/interpreter.mjs.map +1 -0
  222. package/dist/engine/ports.cjs +0 -0
  223. package/dist/engine/ports.d.cts +252 -0
  224. package/dist/engine/ports.d.cts.map +1 -0
  225. package/dist/engine/ports.d.mts +252 -0
  226. package/dist/engine/ports.d.mts.map +1 -0
  227. package/dist/engine/ports.mjs +1 -0
  228. package/dist/engine/recipient.cjs +23 -0
  229. package/dist/engine/recipient.cjs.map +1 -0
  230. package/dist/engine/recipient.d.cts +13 -0
  231. package/dist/engine/recipient.d.cts.map +1 -0
  232. package/dist/engine/recipient.d.mts +13 -0
  233. package/dist/engine/recipient.d.mts.map +1 -0
  234. package/dist/engine/recipient.mjs +22 -0
  235. package/dist/engine/recipient.mjs.map +1 -0
  236. package/dist/engine/time-scale.cjs +54 -0
  237. package/dist/engine/time-scale.cjs.map +1 -0
  238. package/dist/engine/time-scale.d.cts +31 -0
  239. package/dist/engine/time-scale.d.cts.map +1 -0
  240. package/dist/engine/time-scale.d.mts +31 -0
  241. package/dist/engine/time-scale.d.mts.map +1 -0
  242. package/dist/engine/time-scale.mjs +52 -0
  243. package/dist/engine/time-scale.mjs.map +1 -0
  244. package/dist/engine/time-window.cjs +149 -0
  245. package/dist/engine/time-window.cjs.map +1 -0
  246. package/dist/engine/time-window.d.cts +22 -0
  247. package/dist/engine/time-window.d.cts.map +1 -0
  248. package/dist/engine/time-window.d.mts +22 -0
  249. package/dist/engine/time-window.d.mts.map +1 -0
  250. package/dist/engine/time-window.mjs +147 -0
  251. package/dist/engine/time-window.mjs.map +1 -0
  252. package/dist/fcm.cjs +125 -0
  253. package/dist/fcm.cjs.map +1 -0
  254. package/dist/fcm.d.cts +48 -0
  255. package/dist/fcm.d.cts.map +1 -0
  256. package/dist/fcm.d.mts +48 -0
  257. package/dist/fcm.d.mts.map +1 -0
  258. package/dist/fcm.mjs +121 -0
  259. package/dist/fcm.mjs.map +1 -0
  260. package/dist/hash.cjs +245 -0
  261. package/dist/hash.cjs.map +1 -0
  262. package/dist/hash.d.cts +30 -0
  263. package/dist/hash.d.cts.map +1 -0
  264. package/dist/hash.d.mts +30 -0
  265. package/dist/hash.d.mts.map +1 -0
  266. package/dist/hash.mjs +239 -0
  267. package/dist/hash.mjs.map +1 -0
  268. package/dist/index.cjs +100 -0
  269. package/dist/index.d.cts +18 -0
  270. package/dist/index.d.mts +18 -0
  271. package/dist/index.mjs +17 -0
  272. package/dist/ir.cjs +366 -0
  273. package/dist/ir.cjs.map +1 -0
  274. package/dist/ir.d.cts +486 -0
  275. package/dist/ir.d.cts.map +1 -0
  276. package/dist/ir.d.mts +486 -0
  277. package/dist/ir.d.mts.map +1 -0
  278. package/dist/ir.mjs +344 -0
  279. package/dist/ir.mjs.map +1 -0
  280. package/dist/jwt.cjs +22 -0
  281. package/dist/jwt.cjs.map +1 -0
  282. package/dist/jwt.d.cts +9 -0
  283. package/dist/jwt.d.cts.map +1 -0
  284. package/dist/jwt.d.mts +9 -0
  285. package/dist/jwt.d.mts.map +1 -0
  286. package/dist/jwt.mjs +20 -0
  287. package/dist/jwt.mjs.map +1 -0
  288. package/dist/plan.cjs +223 -0
  289. package/dist/plan.cjs.map +1 -0
  290. package/dist/plan.d.cts +68 -0
  291. package/dist/plan.d.cts.map +1 -0
  292. package/dist/plan.d.mts +68 -0
  293. package/dist/plan.d.mts.map +1 -0
  294. package/dist/plan.mjs +221 -0
  295. package/dist/plan.mjs.map +1 -0
  296. package/dist/postgres-js.cjs +42 -0
  297. package/dist/postgres-js.cjs.map +1 -0
  298. package/dist/postgres-js.d.cts +28 -0
  299. package/dist/postgres-js.d.cts.map +1 -0
  300. package/dist/postgres-js.d.mts +28 -0
  301. package/dist/postgres-js.d.mts.map +1 -0
  302. package/dist/postgres-js.mjs +38 -0
  303. package/dist/postgres-js.mjs.map +1 -0
  304. package/dist/provenance.cjs +67 -0
  305. package/dist/provenance.cjs.map +1 -0
  306. package/dist/provenance.d.cts +41 -0
  307. package/dist/provenance.d.cts.map +1 -0
  308. package/dist/provenance.d.mts +41 -0
  309. package/dist/provenance.d.mts.map +1 -0
  310. package/dist/provenance.mjs +65 -0
  311. package/dist/provenance.mjs.map +1 -0
  312. package/dist/push.cjs +14 -0
  313. package/dist/push.cjs.map +1 -0
  314. package/dist/push.d.cts +16 -0
  315. package/dist/push.d.cts.map +1 -0
  316. package/dist/push.d.mts +16 -0
  317. package/dist/push.d.mts.map +1 -0
  318. package/dist/push.mjs +13 -0
  319. package/dist/push.mjs.map +1 -0
  320. package/dist/react-email.cjs +48 -0
  321. package/dist/react-email.cjs.map +1 -0
  322. package/dist/react-email.d.cts +7 -0
  323. package/dist/react-email.d.cts.map +1 -0
  324. package/dist/react-email.d.mts +7 -0
  325. package/dist/react-email.d.mts.map +1 -0
  326. package/dist/react-email.mjs +47 -0
  327. package/dist/react-email.mjs.map +1 -0
  328. package/dist/reporting/classify.cjs +42 -0
  329. package/dist/reporting/classify.cjs.map +1 -0
  330. package/dist/reporting/classify.d.cts +60 -0
  331. package/dist/reporting/classify.d.cts.map +1 -0
  332. package/dist/reporting/classify.d.mts +60 -0
  333. package/dist/reporting/classify.d.mts.map +1 -0
  334. package/dist/reporting/classify.mjs +38 -0
  335. package/dist/reporting/classify.mjs.map +1 -0
  336. package/dist/reporting/observer.cjs +63 -0
  337. package/dist/reporting/observer.cjs.map +1 -0
  338. package/dist/reporting/observer.d.cts +18 -0
  339. package/dist/reporting/observer.d.cts.map +1 -0
  340. package/dist/reporting/observer.d.mts +18 -0
  341. package/dist/reporting/observer.d.mts.map +1 -0
  342. package/dist/reporting/observer.mjs +62 -0
  343. package/dist/reporting/observer.mjs.map +1 -0
  344. package/dist/reporting/tracking.cjs +153 -0
  345. package/dist/reporting/tracking.cjs.map +1 -0
  346. package/dist/reporting/tracking.d.cts +43 -0
  347. package/dist/reporting/tracking.d.cts.map +1 -0
  348. package/dist/reporting/tracking.d.mts +43 -0
  349. package/dist/reporting/tracking.d.mts.map +1 -0
  350. package/dist/reporting/tracking.mjs +151 -0
  351. package/dist/reporting/tracking.mjs.map +1 -0
  352. package/dist/runtime.cjs +19 -0
  353. package/dist/runtime.cjs.map +1 -0
  354. package/dist/runtime.d.cts +30 -0
  355. package/dist/runtime.d.cts.map +1 -0
  356. package/dist/runtime.d.mts +30 -0
  357. package/dist/runtime.d.mts.map +1 -0
  358. package/dist/runtime.mjs +18 -0
  359. package/dist/runtime.mjs.map +1 -0
  360. package/dist/store/d1.cjs +185 -0
  361. package/dist/store/d1.cjs.map +1 -0
  362. package/dist/store/d1.d.cts +55 -0
  363. package/dist/store/d1.d.cts.map +1 -0
  364. package/dist/store/d1.d.mts +55 -0
  365. package/dist/store/d1.d.mts.map +1 -0
  366. package/dist/store/d1.mjs +184 -0
  367. package/dist/store/d1.mjs.map +1 -0
  368. package/dist/store/facts.cjs +60 -0
  369. package/dist/store/facts.cjs.map +1 -0
  370. package/dist/store/facts.d.cts +38 -0
  371. package/dist/store/facts.d.cts.map +1 -0
  372. package/dist/store/facts.d.mts +38 -0
  373. package/dist/store/facts.d.mts.map +1 -0
  374. package/dist/store/facts.mjs +58 -0
  375. package/dist/store/facts.mjs.map +1 -0
  376. package/dist/store/index.cjs +31 -0
  377. package/dist/store/index.cjs.map +1 -0
  378. package/dist/store/index.d.cts +291 -0
  379. package/dist/store/index.d.cts.map +1 -0
  380. package/dist/store/index.d.mts +291 -0
  381. package/dist/store/index.d.mts.map +1 -0
  382. package/dist/store/index.mjs +22 -0
  383. package/dist/store/index.mjs.map +1 -0
  384. package/dist/store/postgres-reporting.cjs +213 -0
  385. package/dist/store/postgres-reporting.cjs.map +1 -0
  386. package/dist/store/postgres-reporting.d.cts +63 -0
  387. package/dist/store/postgres-reporting.d.cts.map +1 -0
  388. package/dist/store/postgres-reporting.d.mts +63 -0
  389. package/dist/store/postgres-reporting.d.mts.map +1 -0
  390. package/dist/store/postgres-reporting.mjs +212 -0
  391. package/dist/store/postgres-reporting.mjs.map +1 -0
  392. package/dist/store/postgres.cjs +309 -0
  393. package/dist/store/postgres.cjs.map +1 -0
  394. package/dist/store/postgres.d.cts +77 -0
  395. package/dist/store/postgres.d.cts.map +1 -0
  396. package/dist/store/postgres.d.mts +77 -0
  397. package/dist/store/postgres.d.mts.map +1 -0
  398. package/dist/store/postgres.mjs +306 -0
  399. package/dist/store/postgres.mjs.map +1 -0
  400. package/dist/store/sql.cjs +24 -0
  401. package/dist/store/sql.cjs.map +1 -0
  402. package/dist/store/sql.d.cts +25 -0
  403. package/dist/store/sql.d.cts.map +1 -0
  404. package/dist/store/sql.d.mts +25 -0
  405. package/dist/store/sql.d.mts.map +1 -0
  406. package/dist/store/sql.mjs +23 -0
  407. package/dist/store/sql.mjs.map +1 -0
  408. package/dist/store/tables.cjs +404 -0
  409. package/dist/store/tables.cjs.map +1 -0
  410. package/dist/store/tables.d.cts +81 -0
  411. package/dist/store/tables.d.cts.map +1 -0
  412. package/dist/store/tables.d.mts +81 -0
  413. package/dist/store/tables.d.mts.map +1 -0
  414. package/dist/store/tables.mjs +399 -0
  415. package/dist/store/tables.mjs.map +1 -0
  416. package/dist/templates.cjs +247 -0
  417. package/dist/templates.cjs.map +1 -0
  418. package/dist/templates.d.cts +187 -0
  419. package/dist/templates.d.cts.map +1 -0
  420. package/dist/templates.d.mts +187 -0
  421. package/dist/templates.d.mts.map +1 -0
  422. package/dist/templates.mjs +230 -0
  423. package/dist/templates.mjs.map +1 -0
  424. package/dist/webhooks.cjs +96 -0
  425. package/dist/webhooks.cjs.map +1 -0
  426. package/dist/webhooks.d.cts +25 -0
  427. package/dist/webhooks.d.cts.map +1 -0
  428. package/dist/webhooks.d.mts +25 -0
  429. package/dist/webhooks.d.mts.map +1 -0
  430. package/dist/webhooks.mjs +94 -0
  431. package/dist/webhooks.mjs.map +1 -0
  432. package/dist/webpush.cjs +180 -0
  433. package/dist/webpush.cjs.map +1 -0
  434. package/dist/webpush.d.cts +53 -0
  435. package/dist/webpush.d.cts.map +1 -0
  436. package/dist/webpush.d.mts +53 -0
  437. package/dist/webpush.d.mts.map +1 -0
  438. package/dist/webpush.mjs +175 -0
  439. package/dist/webpush.mjs.map +1 -0
  440. package/package.json +189 -3
  441. package/src/cloudflare/schema.sql +127 -0
  442. package/src/cloudflare/workers.d.ts +44 -0
@@ -0,0 +1,63 @@
1
+ import { SqlClientLike } from "./sql.cjs";
2
+ import { TableKey } from "./tables.cjs";
3
+ import { ClickContext, Engagement, JourneyReporting, MessageRecord } from "./index.cjs";
4
+ //#region src/store/postgres-reporting.d.ts
5
+ /**
6
+ * Journey reporting on the engine's Postgres schema (tables.ts: instance, message,
7
+ * message_link, message_open, message_click, segment_member, segment_snapshot). Every timestamp
8
+ * is written here, never defaulted, and every write is idempotent: the engine reports again when
9
+ * a step is retried.
10
+ */
11
+ export declare class PostgresReporting implements JourneyReporting {
12
+ private readonly sql;
13
+ private readonly t;
14
+ constructor(sql: SqlClientLike, t: Record<TableKey, string>);
15
+ instanceStarted(input: {
16
+ workflow: string;
17
+ instanceId: string;
18
+ userId: string;
19
+ at: number;
20
+ }): Promise<void>;
21
+ nodeReached(input: {
22
+ workflow: string;
23
+ instanceId: string;
24
+ userId: string;
25
+ nodeId: string;
26
+ at: number;
27
+ }): Promise<void>;
28
+ instanceFinished(input: {
29
+ workflow: string;
30
+ instanceId: string;
31
+ userId: string;
32
+ status: string;
33
+ at: number;
34
+ convertedAt?: number;
35
+ }): Promise<void>;
36
+ recordMessage(message: MessageRecord): Promise<string>;
37
+ settleMessage(idempotencyKey: string, result: {
38
+ delivered: true;
39
+ } | {
40
+ delivered: false;
41
+ reason: string;
42
+ }, at: number): Promise<void>;
43
+ recordLinks(messageId: string, urls: readonly string[]): Promise<void>;
44
+ recordOpen(messageId: string, judge: (message: {
45
+ userId: string;
46
+ deliveredAt: number;
47
+ }) => Engagement | undefined): Promise<boolean>;
48
+ recordClick(messageId: string, position: number, at: number, windowMs: number, judge: (link: ClickContext) => {
49
+ engagement: Engagement;
50
+ backdate: boolean;
51
+ }): Promise<{
52
+ url: string;
53
+ engagement: Engagement;
54
+ } | undefined>;
55
+ recordDeviceDelivered(messageId: string, at: number): Promise<boolean>;
56
+ recordUnsubscribe(messageId: string, at: number): Promise<boolean>;
57
+ snapshotSegments(at: number): Promise<{
58
+ segment: string;
59
+ size: number;
60
+ }[]>;
61
+ }
62
+ //#endregion
63
+ //# sourceMappingURL=postgres-reporting.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-reporting.d.cts","names":[],"sources":["../../src/store/postgres-reporting.ts"],"mappings":";;;;;;;;;;qBAiBa,6BAA6B;mBAErB;mBACA;EAFnB,YACmB,KAAK,eACL,GAAG,OAAO;EAGvB,gBAAgB;IACpB;IACA;IACA;IACA;MACE;EASE,YAAY;IAChB;IACA;IACA;IACA;IACA;MACE;EASE,iBAAiB;IACrB;IACA;IACA;IACA;IACA;IACA;MACE;EAmBE,cAAc,SAAS,gBAAgB;EAyBvC,cACJ,wBACA;IAAU;;IAAsB;IAAkB;KAClD,aACC;EAcG,YAAY,mBAAmB,0BAA0B;EASzD,WACJ,mBACA,QAAQ;IAAW;IAAgB;QAA0B,yBAC5D;EAwCG,YACJ,mBACA,kBACA,YACA,kBACA,QAAQ,MAAM;IAAmB,YAAY;IAAY;MACxD;IAAU;IAAa,YAAY;;EA4EhC,sBAAsB,mBAAmB,aAAa;EAStD,kBAAkB,mBAAmB,aAAa;EAmBlD,iBAAiB,aAAa;IAAU;IAAiB"}
@@ -0,0 +1,63 @@
1
+ import { SqlClientLike } from "./sql.mjs";
2
+ import { TableKey } from "./tables.mjs";
3
+ import { ClickContext, Engagement, JourneyReporting, MessageRecord } from "./index.mjs";
4
+ //#region src/store/postgres-reporting.d.ts
5
+ /**
6
+ * Journey reporting on the engine's Postgres schema (tables.ts: instance, message,
7
+ * message_link, message_open, message_click, segment_member, segment_snapshot). Every timestamp
8
+ * is written here, never defaulted, and every write is idempotent: the engine reports again when
9
+ * a step is retried.
10
+ */
11
+ export declare class PostgresReporting implements JourneyReporting {
12
+ private readonly sql;
13
+ private readonly t;
14
+ constructor(sql: SqlClientLike, t: Record<TableKey, string>);
15
+ instanceStarted(input: {
16
+ workflow: string;
17
+ instanceId: string;
18
+ userId: string;
19
+ at: number;
20
+ }): Promise<void>;
21
+ nodeReached(input: {
22
+ workflow: string;
23
+ instanceId: string;
24
+ userId: string;
25
+ nodeId: string;
26
+ at: number;
27
+ }): Promise<void>;
28
+ instanceFinished(input: {
29
+ workflow: string;
30
+ instanceId: string;
31
+ userId: string;
32
+ status: string;
33
+ at: number;
34
+ convertedAt?: number;
35
+ }): Promise<void>;
36
+ recordMessage(message: MessageRecord): Promise<string>;
37
+ settleMessage(idempotencyKey: string, result: {
38
+ delivered: true;
39
+ } | {
40
+ delivered: false;
41
+ reason: string;
42
+ }, at: number): Promise<void>;
43
+ recordLinks(messageId: string, urls: readonly string[]): Promise<void>;
44
+ recordOpen(messageId: string, judge: (message: {
45
+ userId: string;
46
+ deliveredAt: number;
47
+ }) => Engagement | undefined): Promise<boolean>;
48
+ recordClick(messageId: string, position: number, at: number, windowMs: number, judge: (link: ClickContext) => {
49
+ engagement: Engagement;
50
+ backdate: boolean;
51
+ }): Promise<{
52
+ url: string;
53
+ engagement: Engagement;
54
+ } | undefined>;
55
+ recordDeviceDelivered(messageId: string, at: number): Promise<boolean>;
56
+ recordUnsubscribe(messageId: string, at: number): Promise<boolean>;
57
+ snapshotSegments(at: number): Promise<{
58
+ segment: string;
59
+ size: number;
60
+ }[]>;
61
+ }
62
+ //#endregion
63
+ //# sourceMappingURL=postgres-reporting.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-reporting.d.mts","names":[],"sources":["../../src/store/postgres-reporting.ts"],"mappings":";;;;;;;;;;qBAiBa,6BAA6B;mBAErB;mBACA;EAFnB,YACmB,KAAK,eACL,GAAG,OAAO;EAGvB,gBAAgB;IACpB;IACA;IACA;IACA;MACE;EASE,YAAY;IAChB;IACA;IACA;IACA;IACA;MACE;EASE,iBAAiB;IACrB;IACA;IACA;IACA;IACA;IACA;MACE;EAmBE,cAAc,SAAS,gBAAgB;EAyBvC,cACJ,wBACA;IAAU;;IAAsB;IAAkB;KAClD,aACC;EAcG,YAAY,mBAAmB,0BAA0B;EASzD,WACJ,mBACA,QAAQ;IAAW;IAAgB;QAA0B,yBAC5D;EAwCG,YACJ,mBACA,kBACA,YACA,kBACA,QAAQ,MAAM;IAAmB,YAAY;IAAY;MACxD;IAAU;IAAa,YAAY;;EA4EhC,sBAAsB,mBAAmB,aAAa;EAStD,kBAAkB,mBAAmB,aAAa;EAmBlD,iBAAiB,aAAa;IAAU;IAAiB"}
@@ -0,0 +1,212 @@
1
+ import { uuidv7 } from "./sql.mjs";
2
+ //#region src/store/postgres-reporting.ts
3
+ /**
4
+ * Epoch milliseconds → timestamptz, and back: numbers in and out, whatever the driver maps (a
5
+ * driver may hand a double or a bigint count back as a string).
6
+ */
7
+ const TS = (param) => `to_timestamp(${param}::double precision / 1000)`;
8
+ const MS = (column) => `(extract(epoch from ${column}) * 1000)::double precision`;
9
+ /**
10
+ * Journey reporting on the engine's Postgres schema (tables.ts: instance, message,
11
+ * message_link, message_open, message_click, segment_member, segment_snapshot). Every timestamp
12
+ * is written here, never defaulted, and every write is idempotent: the engine reports again when
13
+ * a step is retried.
14
+ */
15
+ var PostgresReporting = class {
16
+ sql;
17
+ t;
18
+ constructor(sql, t) {
19
+ this.sql = sql;
20
+ this.t = t;
21
+ }
22
+ async instanceStarted(input) {
23
+ await this.sql.query(`INSERT INTO ${this.t.instance} (instance_id, workflow, user_id, entered_at, status)
24
+ VALUES ($1, $2, $3, ${TS("$4")}, 'running')
25
+ ON CONFLICT (instance_id) DO NOTHING`, [
26
+ input.instanceId,
27
+ input.workflow,
28
+ input.userId,
29
+ input.at
30
+ ]);
31
+ }
32
+ async nodeReached(input) {
33
+ await this.sql.query(`INSERT INTO ${this.t.instance} (instance_id, workflow, user_id, entered_at, node_id, node_at, status)
34
+ VALUES ($1, $2, $3, ${TS("$4")}, $5, ${TS("$4")}, 'running')
35
+ ON CONFLICT (instance_id) DO UPDATE SET node_id = EXCLUDED.node_id, node_at = EXCLUDED.node_at`, [
36
+ input.instanceId,
37
+ input.workflow,
38
+ input.userId,
39
+ input.at,
40
+ input.nodeId
41
+ ]);
42
+ }
43
+ async instanceFinished(input) {
44
+ await this.sql.query(`INSERT INTO ${this.t.instance}
45
+ (instance_id, workflow, user_id, entered_at, status, finished_at, converted_at)
46
+ VALUES ($1, $2, $3, ${TS("$5")}, $4, ${TS("$5")}, ${TS("$6")})
47
+ ON CONFLICT (instance_id) DO UPDATE SET status = EXCLUDED.status,
48
+ finished_at = EXCLUDED.finished_at, converted_at = EXCLUDED.converted_at`, [
49
+ input.instanceId,
50
+ input.workflow,
51
+ input.userId,
52
+ input.status,
53
+ input.at,
54
+ input.convertedAt ?? null
55
+ ]);
56
+ }
57
+ async recordMessage(message) {
58
+ const id = (await this.sql.query(`INSERT INTO ${this.t.message}
59
+ (id, idempotency_key, workflow, instance_id, node_id, template, channel, user_id, sent_at)
60
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, ${TS("$9")})
61
+ ON CONFLICT (idempotency_key) DO UPDATE SET idempotency_key = EXCLUDED.idempotency_key
62
+ RETURNING id`, [
63
+ uuidv7(message.sentAt),
64
+ message.idempotencyKey,
65
+ message.workflow,
66
+ message.instanceId,
67
+ message.nodeId,
68
+ message.template,
69
+ message.channel,
70
+ message.userId,
71
+ message.sentAt
72
+ ]))[0]?.id;
73
+ if (id === void 0) throw new Error(`message ${message.idempotencyKey} was not recorded`);
74
+ return id;
75
+ }
76
+ async settleMessage(idempotencyKey, result, at) {
77
+ if (result.delivered) await this.sql.query(`UPDATE ${this.t.message} SET delivered_at = coalesce(delivered_at, ${TS("$2")}) WHERE idempotency_key = $1`, [idempotencyKey, at]);
78
+ else await this.sql.query(`UPDATE ${this.t.message} SET undelivered_reason = $2 WHERE idempotency_key = $1`, [idempotencyKey, result.reason]);
79
+ }
80
+ async recordLinks(messageId, urls) {
81
+ if (urls.length === 0) return;
82
+ const values = urls.map((_, i) => `($1, ${i}, $${i + 2})`).join(", ");
83
+ await this.sql.query(`INSERT INTO ${this.t.messageLink} (message_id, position, url) VALUES ${values} ON CONFLICT DO NOTHING`, [messageId, ...urls]);
84
+ }
85
+ async recordOpen(messageId, judge) {
86
+ return this.sql.transaction(async (tx) => {
87
+ const row = (await tx.query(`SELECT user_id, ${MS("coalesce(delivered_at, sent_at)")} AS delivered_at
88
+ FROM ${this.t.message} WHERE id = $1`, [messageId]))[0];
89
+ if (row === void 0) return false;
90
+ const open = judge({
91
+ userId: row.user_id,
92
+ deliveredAt: Number(row.delivered_at)
93
+ });
94
+ if (open === void 0) return true;
95
+ await tx.query(`INSERT INTO ${this.t.messageOpen}
96
+ (id, message_id, opened_at, machine, reason, user_agent, asn, as_organization, country)
97
+ VALUES ($1, $2, ${TS("$3")}, $4, $5, $6, $7, $8, $9)`, [
98
+ uuidv7(open.at),
99
+ messageId,
100
+ open.at,
101
+ open.machine,
102
+ open.reason,
103
+ open.userAgent,
104
+ open.asn,
105
+ open.organization,
106
+ open.country
107
+ ]);
108
+ await tx.query(`UPDATE ${this.t.message} SET
109
+ opened_at = coalesce(opened_at, ${TS("$2")}),
110
+ human_opened_at = CASE WHEN $3 THEN human_opened_at ELSE coalesce(human_opened_at, ${TS("$2")}) END
111
+ WHERE id = $1`, [
112
+ messageId,
113
+ open.at,
114
+ open.machine
115
+ ]);
116
+ return true;
117
+ });
118
+ }
119
+ async recordClick(messageId, position, at, windowMs, judge) {
120
+ return this.sql.transaction(async (tx) => {
121
+ const message = (await tx.query(`SELECT ${MS("coalesce(delivered_at, sent_at)")} AS delivered_at
122
+ FROM ${this.t.message} WHERE id = $1 FOR UPDATE`, [messageId]))[0];
123
+ if (message === void 0) return void 0;
124
+ const link = (await tx.query(`SELECT l.url,
125
+ (SELECT count(*) FROM ${this.t.messageLink} a WHERE a.message_id = l.message_id) AS link_count
126
+ FROM ${this.t.messageLink} l WHERE l.message_id = $1 AND l.position = $2`, [messageId, position]))[0];
127
+ if (link === void 0) return void 0;
128
+ const since = at - windowMs;
129
+ const recent = await tx.query(`SELECT position, ${MS("clicked_at")} AS at FROM ${this.t.messageClick}
130
+ WHERE message_id = $1 AND clicked_at >= ${TS("$2")} ORDER BY clicked_at`, [messageId, since]);
131
+ const { engagement: click, backdate } = judge({
132
+ url: link.url,
133
+ deliveredAt: Number(message.delivered_at),
134
+ linkCount: Number(link.link_count),
135
+ recent: recent.map((row) => ({
136
+ position: row.position,
137
+ at: Number(row.at)
138
+ }))
139
+ });
140
+ await tx.query(`INSERT INTO ${this.t.messageClick}
141
+ (id, message_id, position, url, clicked_at, machine, reason, user_agent, asn, as_organization, country)
142
+ VALUES ($1, $2, $3, $4, ${TS("$5")}, $6, $7, $8, $9, $10, $11)`, [
143
+ uuidv7(click.at),
144
+ messageId,
145
+ position,
146
+ link.url,
147
+ click.at,
148
+ click.machine,
149
+ click.reason,
150
+ click.userAgent,
151
+ click.asn,
152
+ click.organization,
153
+ click.country
154
+ ]);
155
+ if (backdate) await tx.query(`UPDATE ${this.t.messageClick} SET machine = true, reason = $4
156
+ WHERE message_id = $1 AND NOT machine
157
+ AND clicked_at BETWEEN ${TS("$2")} AND ${TS("$3")}`, [
158
+ messageId,
159
+ since,
160
+ at,
161
+ click.reason
162
+ ]);
163
+ await tx.query(`UPDATE ${this.t.message} m SET
164
+ clicked_at = coalesce(m.clicked_at, ${TS("$2")}),
165
+ opened_at = coalesce(m.opened_at, ${TS("$2")}),
166
+ human_clicked_at = (SELECT min(c.clicked_at) FROM ${this.t.messageClick} c
167
+ WHERE c.message_id = m.id AND NOT c.machine),
168
+ human_opened_at = (SELECT min(t) FROM (
169
+ SELECT o.opened_at AS t FROM ${this.t.messageOpen} o WHERE o.message_id = m.id AND NOT o.machine
170
+ UNION ALL
171
+ SELECT c.clicked_at FROM ${this.t.messageClick} c WHERE c.message_id = m.id AND NOT c.machine
172
+ ) human)
173
+ WHERE m.id = $1`, [messageId, at]);
174
+ return {
175
+ url: link.url,
176
+ engagement: click
177
+ };
178
+ });
179
+ }
180
+ async recordDeviceDelivered(messageId, at) {
181
+ return (await this.sql.query(`UPDATE ${this.t.message} SET device_delivered_at = coalesce(device_delivered_at, ${TS("$2")})
182
+ WHERE id = $1 RETURNING id`, [messageId, at])).length > 0;
183
+ }
184
+ async recordUnsubscribe(messageId, at) {
185
+ return this.sql.transaction(async (tx) => {
186
+ const userId = (await tx.query(`UPDATE ${this.t.message} SET unsubscribed_at = coalesce(unsubscribed_at, ${TS("$2")})
187
+ WHERE id = $1 AND channel = 'email' RETURNING user_id`, [messageId, at]))[0]?.user_id;
188
+ if (userId === void 0) return false;
189
+ await tx.query(`INSERT INTO ${this.t.suppression} (user_id, channel, ts) VALUES ($1, 'email', ${TS("$2")})
190
+ ON CONFLICT DO NOTHING`, [userId, at]);
191
+ return true;
192
+ });
193
+ }
194
+ async snapshotSegments(at) {
195
+ return this.sql.transaction(async (tx) => {
196
+ await tx.query(`DELETE FROM ${this.t.segmentMember} m
197
+ WHERE NOT EXISTS (SELECT 1 FROM ${this.t.segment} s WHERE s.id = m.segment)`);
198
+ return (await tx.query(`INSERT INTO ${this.t.segmentSnapshot} (segment, taken_at, size)
199
+ SELECT s.id, ${TS("$1")}, (SELECT count(*) FROM ${this.t.segmentMember} m WHERE m.segment = s.id)
200
+ FROM ${this.t.segment} s
201
+ ON CONFLICT DO NOTHING
202
+ RETURNING segment, size`, [at])).map((row) => ({
203
+ segment: row.segment,
204
+ size: Number(row.size)
205
+ })).sort((a, b) => a.segment.localeCompare(b.segment));
206
+ });
207
+ }
208
+ };
209
+ //#endregion
210
+ export { PostgresReporting };
211
+
212
+ //# sourceMappingURL=postgres-reporting.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-reporting.mjs","names":[],"sources":["../../src/store/postgres-reporting.ts"],"sourcesContent":["import type { ClickContext, Engagement, JourneyReporting, MessageRecord } from './index';\nimport { type SqlClientLike, uuidv7 } from './sql';\nimport type { TableKey } from './tables';\n\n/**\n * Epoch milliseconds → timestamptz, and back: numbers in and out, whatever the driver maps (a\n * driver may hand a double or a bigint count back as a string).\n */\nconst TS = (param: string) => `to_timestamp(${param}::double precision / 1000)`;\nconst MS = (column: string) => `(extract(epoch from ${column}) * 1000)::double precision`;\n\n/**\n * Journey reporting on the engine's Postgres schema (tables.ts: instance, message,\n * message_link, message_open, message_click, segment_member, segment_snapshot). Every timestamp\n * is written here, never defaulted, and every write is idempotent: the engine reports again when\n * a step is retried.\n */\nexport class PostgresReporting implements JourneyReporting {\n constructor(\n private readonly sql: SqlClientLike,\n private readonly t: Record<TableKey, string>\n ) {}\n\n async instanceStarted(input: {\n workflow: string;\n instanceId: string;\n userId: string;\n at: number;\n }): Promise<void> {\n await this.sql.query(\n `INSERT INTO ${this.t.instance} (instance_id, workflow, user_id, entered_at, status)\n VALUES ($1, $2, $3, ${TS('$4')}, 'running')\n ON CONFLICT (instance_id) DO NOTHING`,\n [input.instanceId, input.workflow, input.userId, input.at]\n );\n }\n\n async nodeReached(input: {\n workflow: string;\n instanceId: string;\n userId: string;\n nodeId: string;\n at: number;\n }): Promise<void> {\n await this.sql.query(\n `INSERT INTO ${this.t.instance} (instance_id, workflow, user_id, entered_at, node_id, node_at, status)\n VALUES ($1, $2, $3, ${TS('$4')}, $5, ${TS('$4')}, 'running')\n ON CONFLICT (instance_id) DO UPDATE SET node_id = EXCLUDED.node_id, node_at = EXCLUDED.node_at`,\n [input.instanceId, input.workflow, input.userId, input.at, input.nodeId]\n );\n }\n\n async instanceFinished(input: {\n workflow: string;\n instanceId: string;\n userId: string;\n status: string;\n at: number;\n convertedAt?: number;\n }): Promise<void> {\n // An upsert: an instance that started before its start was reported still gets its row\n await this.sql.query(\n `INSERT INTO ${this.t.instance}\n (instance_id, workflow, user_id, entered_at, status, finished_at, converted_at)\n VALUES ($1, $2, $3, ${TS('$5')}, $4, ${TS('$5')}, ${TS('$6')})\n ON CONFLICT (instance_id) DO UPDATE SET status = EXCLUDED.status,\n finished_at = EXCLUDED.finished_at, converted_at = EXCLUDED.converted_at`,\n [\n input.instanceId,\n input.workflow,\n input.userId,\n input.status,\n input.at,\n input.convertedAt ?? null,\n ]\n );\n }\n\n async recordMessage(message: MessageRecord): Promise<string> {\n // A retried step records the same copy again: the row it already wrote is the one\n const rows = await this.sql.query<{ id: string }>(\n `INSERT INTO ${this.t.message}\n (id, idempotency_key, workflow, instance_id, node_id, template, channel, user_id, sent_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, ${TS('$9')})\n ON CONFLICT (idempotency_key) DO UPDATE SET idempotency_key = EXCLUDED.idempotency_key\n RETURNING id`,\n [\n uuidv7(message.sentAt),\n message.idempotencyKey,\n message.workflow,\n message.instanceId,\n message.nodeId,\n message.template,\n message.channel,\n message.userId,\n message.sentAt,\n ]\n );\n const id = rows[0]?.id;\n if (id === undefined) throw new Error(`message ${message.idempotencyKey} was not recorded`);\n return id;\n }\n\n async settleMessage(\n idempotencyKey: string,\n result: { delivered: true } | { delivered: false; reason: string },\n at: number\n ): Promise<void> {\n if (result.delivered) {\n await this.sql.query(\n `UPDATE ${this.t.message} SET delivered_at = coalesce(delivered_at, ${TS('$2')}) WHERE idempotency_key = $1`,\n [idempotencyKey, at]\n );\n } else {\n await this.sql.query(\n `UPDATE ${this.t.message} SET undelivered_reason = $2 WHERE idempotency_key = $1`,\n [idempotencyKey, result.reason]\n );\n }\n }\n\n async recordLinks(messageId: string, urls: readonly string[]): Promise<void> {\n if (urls.length === 0) return;\n const values = urls.map((_, i) => `($1, ${i}, $${i + 2})`).join(', ');\n await this.sql.query(\n `INSERT INTO ${this.t.messageLink} (message_id, position, url) VALUES ${values} ON CONFLICT DO NOTHING`,\n [messageId, ...urls]\n );\n }\n\n async recordOpen(\n messageId: string,\n judge: (message: { userId: string; deliveredAt: number }) => Engagement | undefined\n ): Promise<boolean> {\n // In a transaction: read through Hyperdrive, a bare read may come from its cache, from before\n // the copy existed\n return this.sql.transaction(async (tx) => {\n const rows = await tx.query<{ user_id: string; delivered_at: number | string }>(\n `SELECT user_id, ${MS('coalesce(delivered_at, sent_at)')} AS delivered_at\n FROM ${this.t.message} WHERE id = $1`,\n [messageId]\n );\n const row = rows[0];\n if (row === undefined) return false;\n const open = judge({ userId: row.user_id, deliveredAt: Number(row.delivered_at) });\n if (open === undefined) return true;\n await tx.query(\n `INSERT INTO ${this.t.messageOpen}\n (id, message_id, opened_at, machine, reason, user_agent, asn, as_organization, country)\n VALUES ($1, $2, ${TS('$3')}, $4, $5, $6, $7, $8, $9)`,\n [\n uuidv7(open.at),\n messageId,\n open.at,\n open.machine,\n open.reason,\n open.userAgent,\n open.asn,\n open.organization,\n open.country,\n ]\n );\n await tx.query(\n `UPDATE ${this.t.message} SET\n opened_at = coalesce(opened_at, ${TS('$2')}),\n human_opened_at = CASE WHEN $3 THEN human_opened_at ELSE coalesce(human_opened_at, ${TS('$2')}) END\n WHERE id = $1`,\n [messageId, open.at, open.machine]\n );\n return true;\n });\n }\n\n async recordClick(\n messageId: string,\n position: number,\n at: number,\n windowMs: number,\n judge: (link: ClickContext) => { engagement: Engagement; backdate: boolean }\n ): Promise<{ url: string; engagement: Engagement } | undefined> {\n return this.sql.transaction(async (tx) => {\n // The copy's row is the lock: concurrent clicks on it are judged one at a time\n const messages = await tx.query<{ delivered_at: number | string }>(\n `SELECT ${MS('coalesce(delivered_at, sent_at)')} AS delivered_at\n FROM ${this.t.message} WHERE id = $1 FOR UPDATE`,\n [messageId]\n );\n const message = messages[0];\n if (message === undefined) return undefined;\n const links = await tx.query<{ url: string; link_count: number | string }>(\n `SELECT l.url,\n (SELECT count(*) FROM ${this.t.messageLink} a WHERE a.message_id = l.message_id) AS link_count\n FROM ${this.t.messageLink} l WHERE l.message_id = $1 AND l.position = $2`,\n [messageId, position]\n );\n const link = links[0];\n if (link === undefined) return undefined;\n const since = at - windowMs;\n const recent = await tx.query<{ position: number; at: number | string }>(\n `SELECT position, ${MS('clicked_at')} AS at FROM ${this.t.messageClick}\n WHERE message_id = $1 AND clicked_at >= ${TS('$2')} ORDER BY clicked_at`,\n [messageId, since]\n );\n const { engagement: click, backdate } = judge({\n url: link.url,\n deliveredAt: Number(message.delivered_at),\n linkCount: Number(link.link_count),\n recent: recent.map((row) => ({ position: row.position, at: Number(row.at) })),\n });\n await tx.query(\n `INSERT INTO ${this.t.messageClick}\n (id, message_id, position, url, clicked_at, machine, reason, user_agent, asn, as_organization, country)\n VALUES ($1, $2, $3, $4, ${TS('$5')}, $6, $7, $8, $9, $10, $11)`,\n [\n uuidv7(click.at),\n messageId,\n position,\n link.url,\n click.at,\n click.machine,\n click.reason,\n click.userAgent,\n click.asn,\n click.organization,\n click.country,\n ]\n );\n if (backdate) {\n // A walk across the copy is found on its later clicks: the earlier ones were part of it\n await tx.query(\n `UPDATE ${this.t.messageClick} SET machine = true, reason = $4\n WHERE message_id = $1 AND NOT machine\n AND clicked_at BETWEEN ${TS('$2')} AND ${TS('$3')}`,\n [messageId, since, at, click.reason]\n );\n }\n // First opens and clicks, from the classified rows (a click implies an open)\n await tx.query(\n `UPDATE ${this.t.message} m SET\n clicked_at = coalesce(m.clicked_at, ${TS('$2')}),\n opened_at = coalesce(m.opened_at, ${TS('$2')}),\n human_clicked_at = (SELECT min(c.clicked_at) FROM ${this.t.messageClick} c\n WHERE c.message_id = m.id AND NOT c.machine),\n human_opened_at = (SELECT min(t) FROM (\n SELECT o.opened_at AS t FROM ${this.t.messageOpen} o WHERE o.message_id = m.id AND NOT o.machine\n UNION ALL\n SELECT c.clicked_at FROM ${this.t.messageClick} c WHERE c.message_id = m.id AND NOT c.machine\n ) human)\n WHERE m.id = $1`,\n [messageId, at]\n );\n return { url: link.url, engagement: click };\n });\n }\n\n async recordDeviceDelivered(messageId: string, at: number): Promise<boolean> {\n const rows = await this.sql.query<{ id: string }>(\n `UPDATE ${this.t.message} SET device_delivered_at = coalesce(device_delivered_at, ${TS('$2')})\n WHERE id = $1 RETURNING id`,\n [messageId, at]\n );\n return rows.length > 0;\n }\n\n async recordUnsubscribe(messageId: string, at: number): Promise<boolean> {\n return this.sql.transaction(async (tx) => {\n const rows = await tx.query<{ user_id: string }>(\n `UPDATE ${this.t.message} SET unsubscribed_at = coalesce(unsubscribed_at, ${TS('$2')})\n WHERE id = $1 AND channel = 'email' RETURNING user_id`,\n [messageId, at]\n );\n const userId = rows[0]?.user_id;\n if (userId === undefined) return false;\n // The opt-out itself: the engine sends this user no more email\n await tx.query(\n `INSERT INTO ${this.t.suppression} (user_id, channel, ts) VALUES ($1, 'email', ${TS('$2')})\n ON CONFLICT DO NOTHING`,\n [userId, at]\n );\n return true;\n });\n }\n\n async snapshotSegments(at: number): Promise<{ segment: string; size: number }[]> {\n return this.sql.transaction(async (tx) => {\n // Segments no longer deployed take their members with them\n await tx.query(\n `DELETE FROM ${this.t.segmentMember} m\n WHERE NOT EXISTS (SELECT 1 FROM ${this.t.segment} s WHERE s.id = m.segment)`\n );\n const rows = await tx.query<{ segment: string; size: number | string }>(\n `INSERT INTO ${this.t.segmentSnapshot} (segment, taken_at, size)\n SELECT s.id, ${TS('$1')}, (SELECT count(*) FROM ${this.t.segmentMember} m WHERE m.segment = s.id)\n FROM ${this.t.segment} s\n ON CONFLICT DO NOTHING\n RETURNING segment, size`,\n [at]\n );\n return rows\n .map((row) => ({ segment: row.segment, size: Number(row.size) }))\n .sort((a, b) => a.segment.localeCompare(b.segment));\n });\n }\n}\n"],"mappings":"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"}