@shware/workflow 0.0.0-stage → 0.1.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,309 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_ir = require("../ir.cjs");
3
+ const require_store_sql = require("./sql.cjs");
4
+ const require_store_postgres_reporting = require("./postgres-reporting.cjs");
5
+ const require_store_tables = require("./tables.cjs");
6
+ //#region src/store/postgres.ts
7
+ /** information_schema's udt_name per column type. */
8
+ const UDT = {
9
+ uuid: "uuid",
10
+ text: "text",
11
+ jsonb: "jsonb",
12
+ timestamptz: "timestamptz",
13
+ integer: "int4",
14
+ boolean: "bool"
15
+ };
16
+ /** Epoch milliseconds → timestamptz, so the tables keep the database's native type. */
17
+ const TS = (param) => `to_timestamp(${param}::double precision / 1000)`;
18
+ function asJson(value) {
19
+ return typeof value === "string" ? JSON.parse(value) : value;
20
+ }
21
+ /**
22
+ * Journey data plane on Postgres. Same contract as D1JourneyStore, native
23
+ * types where Postgres has them (jsonb, timestamptz), and the concurrency
24
+ * guarantees come from the database: ON CONFLICT for the once policy and
25
+ * idempotent subscriptions, a transaction for the route swap, a jsonb merge
26
+ * for /identify. The tables are declared in tables.ts.
27
+ */
28
+ var PostgresJourneyStore = class {
29
+ sql;
30
+ t;
31
+ schema;
32
+ reporting;
33
+ constructor(sql, options = {}) {
34
+ this.sql = sql;
35
+ this.schema = options.schema ?? "workflow";
36
+ const qualify = (name) => `"${this.schema}"."${name}"`;
37
+ this.t = Object.fromEntries(Object.keys(require_store_tables.TABLES).map((key) => [key, qualify(require_store_tables.TABLES[key].name)]));
38
+ this.reporting = new require_store_postgres_reporting.PostgresReporting(sql, this.t);
39
+ }
40
+ /**
41
+ * What the live database lacks against tables.ts: missing tables, missing columns, a column
42
+ * of another type or nullability. Read-only — the engine never migrates the host's database; a
43
+ * deploy fails with these problems listed, and the fix is to regenerate the drizzle file and
44
+ * run the host's migrations.
45
+ */
46
+ async checkSchema() {
47
+ const rows = await this.sql.transaction((tx) => tx.query(`SELECT table_name, column_name, udt_name, is_nullable FROM information_schema.columns WHERE table_schema = $1`, [this.schema]));
48
+ const live = new Map(rows.map((row) => [`${row.table_name}.${row.column_name}`, row]));
49
+ const tables = new Set(rows.map((row) => row.table_name));
50
+ const problems = [];
51
+ for (const spec of Object.values(require_store_tables.TABLES)) {
52
+ const where = `"${this.schema}"."${spec.name}"`;
53
+ if (!tables.has(spec.name)) {
54
+ problems.push(`table ${where} is missing`);
55
+ continue;
56
+ }
57
+ for (const [key, column] of Object.entries(spec.columns)) {
58
+ const name = require_store_tables.columnName(key);
59
+ const row = live.get(`${spec.name}.${name}`);
60
+ if (row === void 0) problems.push(`column ${where}."${name}" is missing`);
61
+ else if (row.udt_name !== UDT[column.type]) problems.push(`column ${where}."${name}" is ${row.udt_name}, expected ${UDT[column.type]}`);
62
+ else if (row.is_nullable === "YES" !== (column.nullable === true)) problems.push(`column ${where}."${name}" should be ${column.nullable ? "nullable" : "NOT NULL"}`);
63
+ }
64
+ }
65
+ return problems;
66
+ }
67
+ async insertEvent(input) {
68
+ return (await this.sql.query(`INSERT INTO ${this.t.event} (id, event_id, user_id, name, ts, payload)
69
+ VALUES ($1, $2, $3, $4, ${TS("$5")}, $6::text::jsonb)
70
+ ON CONFLICT (event_id) DO NOTHING RETURNING id`, [
71
+ require_store_sql.uuidv7(input.ts),
72
+ input.id,
73
+ input.userId,
74
+ input.event,
75
+ input.ts,
76
+ JSON.stringify(input.payload)
77
+ ])).length > 0;
78
+ }
79
+ /** The event rows of one user and name, within the window's bounds (both inclusive). */
80
+ eventWindow(userId, event, window) {
81
+ const params = [userId, event];
82
+ let where = "user_id = $1 AND name = $2";
83
+ if (window?.sinceMs !== void 0) {
84
+ params.push(window.sinceMs);
85
+ where += ` AND ts >= ${TS(`$${params.length}`)}`;
86
+ }
87
+ if (window?.untilMs !== void 0) {
88
+ params.push(window.untilMs);
89
+ where += ` AND ts <= ${TS(`$${params.length}`)}`;
90
+ }
91
+ return {
92
+ where,
93
+ params
94
+ };
95
+ }
96
+ async countEvents(userId, event, window) {
97
+ const { where, params } = this.eventWindow(userId, event, window);
98
+ const rows = await this.sql.query(`SELECT count(*)::int AS c FROM ${this.t.event} WHERE ${where}`, params);
99
+ return Number(rows.at(0)?.c ?? 0);
100
+ }
101
+ async listEventPayloads(userId, event, window) {
102
+ const { where, params } = this.eventWindow(userId, event, window);
103
+ return (await this.sql.query(`SELECT payload FROM ${this.t.event} WHERE ${where}`, params)).map((row) => asJson(row.payload));
104
+ }
105
+ async getProfile(userId) {
106
+ const row = (await this.sql.query(`SELECT props FROM ${this.t.profile} WHERE user_id = $1`, [userId])).at(0);
107
+ return row === void 0 ? void 0 : asJson(row.props);
108
+ }
109
+ async mergeProfile(userId, props) {
110
+ return asJson((await this.sql.query(`INSERT INTO ${this.t.profile} (user_id, props) VALUES ($1, jsonb_strip_nulls($2::text::jsonb))
111
+ ON CONFLICT (user_id) DO UPDATE SET props = jsonb_strip_nulls(${this.t.profile}.props || $3::text::jsonb)
112
+ RETURNING props`, [
113
+ userId,
114
+ JSON.stringify(props),
115
+ JSON.stringify(props)
116
+ ])).at(0)?.props ?? {});
117
+ }
118
+ async listUserIds() {
119
+ return (await this.sql.query(`SELECT user_id FROM ${this.t.profile} UNION SELECT DISTINCT user_id FROM ${this.t.event}`)).map((row) => row.user_id);
120
+ }
121
+ listDevices(userId) {
122
+ return this.sql.query(`SELECT token, platform FROM ${this.t.device} WHERE user_id = $1 ORDER BY ts DESC`, [userId]);
123
+ }
124
+ async upsertDevice(device) {
125
+ await this.sql.query(`INSERT INTO ${this.t.device} (token, user_id, platform, ts) VALUES ($1, $2, $3, ${TS("$4")})
126
+ ON CONFLICT (token) DO UPDATE SET user_id = EXCLUDED.user_id, platform = EXCLUDED.platform, ts = EXCLUDED.ts`, [
127
+ device.token,
128
+ device.userId,
129
+ device.platform,
130
+ device.ts
131
+ ]);
132
+ }
133
+ async requestErasure(userId, at) {
134
+ await this.sql.query(`INSERT INTO ${this.t.erasure} (user_id, requested_at) VALUES ($1, ${TS("$2")})
135
+ ON CONFLICT DO NOTHING`, [userId, at]);
136
+ }
137
+ async pendingErasures() {
138
+ return (await this.sql.query(`SELECT user_id FROM ${this.t.erasure} ORDER BY requested_at`)).map((row) => row.user_id);
139
+ }
140
+ async runningInstances(userId) {
141
+ return (await this.sql.query(`SELECT instance_id FROM ${this.t.entry} WHERE user_id = $1 AND status = 'running'`, [userId])).map((row) => row.instance_id);
142
+ }
143
+ async forgetUser(userId) {
144
+ await this.sql.transaction(async (tx) => {
145
+ for (const child of [
146
+ this.t.messageOpen,
147
+ this.t.messageClick,
148
+ this.t.messageLink
149
+ ]) await tx.query(`DELETE FROM ${child} WHERE message_id IN (SELECT id FROM ${this.t.message} WHERE user_id = $1)`, [userId]);
150
+ for (const table of [
151
+ this.t.message,
152
+ this.t.instance,
153
+ this.t.entry,
154
+ this.t.subscription,
155
+ this.t.segmentStart,
156
+ this.t.segmentMember,
157
+ this.t.suppression,
158
+ this.t.device,
159
+ this.t.event,
160
+ this.t.profile,
161
+ this.t.erasure
162
+ ]) await tx.query(`DELETE FROM ${table} WHERE user_id = $1`, [userId]);
163
+ });
164
+ }
165
+ async isSuppressed(userId, channel) {
166
+ return (await this.sql.query(`SELECT 1 AS x FROM ${this.t.suppression} WHERE user_id = $1 AND channel = $2`, [userId, channel])).length > 0;
167
+ }
168
+ async removeDevice(token) {
169
+ return (await this.sql.query(`DELETE FROM ${this.t.device} WHERE token = $1 RETURNING user_id`, [token]))[0]?.user_id ?? void 0;
170
+ }
171
+ async unbindDevice(token) {
172
+ return (await this.sql.query(`WITH old AS (SELECT token, user_id FROM ${this.t.device} WHERE token = $1 FOR UPDATE)
173
+ UPDATE ${this.t.device} d SET user_id = NULL FROM old WHERE d.token = old.token
174
+ RETURNING old.user_id`, [token]))[0]?.user_id ?? void 0;
175
+ }
176
+ async listSegments() {
177
+ return (await this.sql.query(`SELECT id, condition FROM ${this.t.segment} ORDER BY id`)).map((row) => ({
178
+ id: row.id,
179
+ condition: require_ir.ConditionIR.parse(asJson(row.condition))
180
+ }));
181
+ }
182
+ async getSegmentCondition(id) {
183
+ const row = (await this.sql.query(`SELECT condition FROM ${this.t.segment} WHERE id = $1`, [id])).at(0);
184
+ return row === void 0 ? void 0 : require_ir.ConditionIR.parse(asJson(row.condition));
185
+ }
186
+ async findTriggers(event) {
187
+ return (await this.sql.query(`SELECT workflow, hash, "where" AS where_clause, filter FROM ${this.t.trigger} WHERE event = $1`, [event])).map((row) => ({
188
+ workflow: row.workflow,
189
+ hash: row.hash,
190
+ where: row.where_clause === null ? null : require_ir.ConditionIR.parse(asJson(row.where_clause)),
191
+ filter: row.filter === null ? null : require_ir.ConditionIR.parse(asJson(row.filter))
192
+ }));
193
+ }
194
+ listSegmentTriggers() {
195
+ return this.sql.query(`SELECT workflow, hash, segment FROM ${this.t.segmentTrigger}`);
196
+ }
197
+ async putWorkflowIR(workflow) {
198
+ await this.sql.query(`INSERT INTO ${this.t.ir} (content_hash, ir) VALUES ($1, $2::text::jsonb)
199
+ ON CONFLICT (content_hash) DO UPDATE SET ir = EXCLUDED.ir`, [workflow.contentHash, JSON.stringify(workflow)]);
200
+ }
201
+ async getWorkflowIR(contentHash) {
202
+ const row = (await this.sql.query(`SELECT ir FROM ${this.t.ir} WHERE content_hash = $1`, [contentHash])).at(0);
203
+ return row === void 0 ? void 0 : require_ir.WorkflowIR.parse(asJson(row.ir));
204
+ }
205
+ replaceRoutes(bundle) {
206
+ return this.sql.transaction(async (tx) => {
207
+ await tx.query(`DELETE FROM ${this.t.trigger}`);
208
+ await tx.query(`DELETE FROM ${this.t.segmentTrigger}`);
209
+ await tx.query(`DELETE FROM ${this.t.segment}`);
210
+ for (const segment of bundle.segments) await tx.query(`INSERT INTO ${this.t.segment} (id, condition, hash) VALUES ($1, $2::text::jsonb, $3)`, [
211
+ segment.id,
212
+ JSON.stringify(segment.condition),
213
+ segment.contentHash
214
+ ]);
215
+ for (const workflow of bundle.workflows) if (workflow.trigger.type === "event") await tx.query(`INSERT INTO ${this.t.trigger} (workflow, hash, event, "where", filter) VALUES ($1, $2, $3, $4::text::jsonb, $5::text::jsonb)`, [
216
+ workflow.id,
217
+ workflow.contentHash,
218
+ workflow.trigger.event,
219
+ workflow.trigger.where === void 0 ? null : JSON.stringify(workflow.trigger.where),
220
+ workflow.trigger.filter === void 0 ? null : JSON.stringify(workflow.trigger.filter)
221
+ ]);
222
+ else if (workflow.trigger.type === "segment") await tx.query(`INSERT INTO ${this.t.segmentTrigger} (workflow, hash, segment) VALUES ($1, $2, $3)`, [
223
+ workflow.id,
224
+ workflow.contentHash,
225
+ workflow.trigger.segment
226
+ ]);
227
+ });
228
+ }
229
+ async isSegmentMember(segment, userId) {
230
+ return (await this.sql.query(`SELECT 1 AS x FROM ${this.t.segmentMember} WHERE segment = $1 AND user_id = $2`, [segment, userId])).length > 0;
231
+ }
232
+ async addSegmentMember(segment, userId, ts, workflows) {
233
+ await this.sql.transaction(async (tx) => {
234
+ await tx.query(`INSERT INTO ${this.t.segmentMember} (segment, user_id, ts) VALUES ($1, $2, ${TS("$3")}) ON CONFLICT DO NOTHING`, [
235
+ segment,
236
+ userId,
237
+ ts
238
+ ]);
239
+ for (const workflow of workflows) await tx.query(`INSERT INTO ${this.t.segmentStart} (segment, workflow, user_id, ts)
240
+ VALUES ($1, $2, $3, ${TS("$4")}) ON CONFLICT DO NOTHING`, [
241
+ segment,
242
+ workflow,
243
+ userId,
244
+ ts
245
+ ]);
246
+ });
247
+ }
248
+ async pendingSegmentStarts(segment, userId) {
249
+ return (await this.sql.query(`SELECT workflow FROM ${this.t.segmentStart} WHERE segment = $1 AND user_id = $2`, [segment, userId])).map((row) => row.workflow);
250
+ }
251
+ async completeSegmentStart(segment, userId, workflow) {
252
+ await this.sql.query(`DELETE FROM ${this.t.segmentStart} WHERE segment = $1 AND user_id = $2 AND workflow = $3`, [
253
+ segment,
254
+ userId,
255
+ workflow
256
+ ]);
257
+ }
258
+ async removeSegmentMember(segment, userId) {
259
+ await this.sql.transaction(async (tx) => {
260
+ await tx.query(`DELETE FROM ${this.t.segmentStart} WHERE segment = $1 AND user_id = $2`, [segment, userId]);
261
+ await tx.query(`DELETE FROM ${this.t.segmentMember} WHERE segment = $1 AND user_id = $2`, [segment, userId]);
262
+ });
263
+ }
264
+ async enterJourney(entry) {
265
+ if ((await this.sql.query(`INSERT INTO ${this.t.entry} (workflow, user_id, instance_id, hash, status, ts)
266
+ VALUES ($1, $2, $3, $4, 'running', ${TS("$5")})
267
+ ON CONFLICT (workflow, user_id) DO NOTHING RETURNING instance_id`, [
268
+ entry.workflow,
269
+ entry.userId,
270
+ entry.instanceId,
271
+ entry.hash,
272
+ entry.ts
273
+ ])).length > 0) return "entered";
274
+ return (await this.sql.query(`UPDATE ${this.t.entry} SET instance_id = $1, hash = $2, status = 'running', ts = ${TS("$3")}
275
+ WHERE workflow = $4 AND user_id = $5 AND status = 'failed' RETURNING instance_id`, [
276
+ entry.instanceId,
277
+ entry.hash,
278
+ entry.ts,
279
+ entry.workflow,
280
+ entry.userId
281
+ ])).length > 0 ? "reclaimed" : null;
282
+ }
283
+ async removeEntry(instanceId) {
284
+ await this.sql.query(`DELETE FROM ${this.t.entry} WHERE instance_id = $1`, [instanceId]);
285
+ }
286
+ async setEntryStatus(instanceId, status) {
287
+ await this.sql.query(`UPDATE ${this.t.entry} SET status = $1 WHERE instance_id = $2`, [status, instanceId]);
288
+ }
289
+ async findWakeHandles(userId, event) {
290
+ return (await this.sql.query(`SELECT DISTINCT wake_handle AS handle FROM ${this.t.subscription} WHERE user_id = $1 AND event = $2`, [userId, event])).map((row) => row.handle);
291
+ }
292
+ async subscribe(handle, userId, events, ts) {
293
+ for (const event of events) await this.sql.query(`INSERT INTO ${this.t.subscription} (user_id, event, wake_handle, ts) VALUES ($1, $2, $3, ${TS("$4")}) ON CONFLICT DO NOTHING`, [
294
+ userId,
295
+ event,
296
+ handle,
297
+ ts
298
+ ]);
299
+ }
300
+ async unsubscribe(handle) {
301
+ await this.sql.query(`DELETE FROM ${this.t.subscription} WHERE wake_handle = $1`, [handle]);
302
+ }
303
+ };
304
+ //#endregion
305
+ exports.DEFAULT_SCHEMA = require_store_tables.DEFAULT_SCHEMA;
306
+ exports.PostgresJourneyStore = PostgresJourneyStore;
307
+ exports.uuidv7 = require_store_sql.uuidv7;
308
+
309
+ //# sourceMappingURL=postgres.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.cjs","names":["TABLES","PostgresReporting","columnName","uuidv7","ConditionIR","WorkflowIR"],"sources":["../../src/store/postgres.ts"],"sourcesContent":["import type { PushDevice } from '../engine/ports';\nimport { type BundleIR, ConditionIR, WorkflowIR } from '../ir';\nimport type {\n DeviceInput,\n EntryInput,\n EntryOutcome,\n EventInput,\n EventWindow,\n JourneyReporting,\n JourneyStore,\n ProfileProps,\n SegmentTriggerRoute,\n TriggerRoute,\n} from './index';\nimport { PostgresReporting } from './postgres-reporting';\nimport { type SqlClientLike, uuidv7 } from './sql';\nimport { type ColumnType, DEFAULT_SCHEMA, TABLES, type TableKey, columnName } from './tables';\n\nexport { DEFAULT_SCHEMA } from './tables';\nexport { type SqlClientLike, uuidv7 } from './sql';\n\nexport interface PostgresJourneyStoreOptions {\n /**\n * The Postgres schema the engine's tables live in — `workflow` by default, the config's\n * `database.schema` under journeyWorker. A schema of its own keeps the tables apart from the\n * app's. The host creates them with its own migrations, from the drizzle file\n * `renderDrizzleSchema` generates (or the plain `renderPostgresDdl`).\n */\n schema?: string;\n}\n\n/** information_schema's udt_name per column type. */\nconst UDT: Record<ColumnType, string> = {\n uuid: 'uuid',\n text: 'text',\n jsonb: 'jsonb',\n timestamptz: 'timestamptz',\n integer: 'int4',\n boolean: 'bool',\n};\n\n/** Epoch milliseconds → timestamptz, so the tables keep the database's native type. */\nconst TS = (param: string) => `to_timestamp(${param}::double precision / 1000)`;\n\nfunction asJson<T>(value: unknown): T {\n return (typeof value === 'string' ? JSON.parse(value) : value) as T;\n}\n\n/**\n * Journey data plane on Postgres. Same contract as D1JourneyStore, native\n * types where Postgres has them (jsonb, timestamptz), and the concurrency\n * guarantees come from the database: ON CONFLICT for the once policy and\n * idempotent subscriptions, a transaction for the route swap, a jsonb merge\n * for /identify. The tables are declared in tables.ts.\n */\nexport class PostgresJourneyStore implements JourneyStore {\n private readonly t: Record<TableKey, string>;\n private readonly schema: string;\n readonly reporting: JourneyReporting;\n\n constructor(\n private readonly sql: SqlClientLike,\n options: PostgresJourneyStoreOptions = {}\n ) {\n this.schema = options.schema ?? DEFAULT_SCHEMA;\n const qualify = (name: string) => `\"${this.schema}\".\"${name}\"`;\n this.t = Object.fromEntries(\n (Object.keys(TABLES) as TableKey[]).map((key) => [key, qualify(TABLES[key].name)])\n ) as Record<TableKey, string>;\n this.reporting = new PostgresReporting(sql, this.t);\n }\n\n /**\n * What the live database lacks against tables.ts: missing tables, missing columns, a column\n * of another type or nullability. Read-only — the engine never migrates the host's database; a\n * deploy fails with these problems listed, and the fix is to regenerate the drizzle file and\n * run the host's migrations.\n */\n async checkSchema(): Promise<string[]> {\n // In a transaction, so Hyperdrive answers from the database, not from its read cache — a\n // deploy right after the migration must see the new columns\n const rows = await this.sql.transaction((tx) =>\n tx.query<{\n table_name: string;\n column_name: string;\n udt_name: string;\n is_nullable: string;\n }>(\n `SELECT table_name, column_name, udt_name, is_nullable FROM information_schema.columns WHERE table_schema = $1`,\n [this.schema]\n )\n );\n const live = new Map(rows.map((row) => [`${row.table_name}.${row.column_name}`, row]));\n const tables = new Set(rows.map((row) => row.table_name));\n const problems: string[] = [];\n for (const spec of Object.values(TABLES)) {\n const where = `\"${this.schema}\".\"${spec.name}\"`;\n if (!tables.has(spec.name)) {\n problems.push(`table ${where} is missing`);\n continue;\n }\n for (const [key, column] of Object.entries(spec.columns)) {\n const name = columnName(key);\n const row = live.get(`${spec.name}.${name}`);\n if (row === undefined) problems.push(`column ${where}.\"${name}\" is missing`);\n else if (row.udt_name !== UDT[column.type])\n problems.push(\n `column ${where}.\"${name}\" is ${row.udt_name}, expected ${UDT[column.type]}`\n );\n else if ((row.is_nullable === 'YES') !== (column.nullable === true))\n problems.push(\n `column ${where}.\"${name}\" should be ${column.nullable ? 'nullable' : 'NOT NULL'}`\n );\n }\n }\n return problems;\n }\n\n async insertEvent(input: EventInput): Promise<boolean> {\n // The row key stays a UUID v7 (the house rule for every table); the\n // sender's occurrence id lives in event_id, whose unique index is what\n // makes a second delivery a no-op. ON CONFLICT DO NOTHING + RETURNING\n // reports which of the two happened without a second round trip.\n const rows = await this.sql.query(\n `INSERT INTO ${this.t.event} (id, event_id, user_id, name, ts, payload)\n VALUES ($1, $2, $3, $4, ${TS('$5')}, $6::text::jsonb)\n ON CONFLICT (event_id) DO NOTHING RETURNING id`,\n [\n uuidv7(input.ts),\n input.id,\n input.userId,\n input.event,\n input.ts,\n JSON.stringify(input.payload),\n ]\n );\n return rows.length > 0;\n }\n\n /** The event rows of one user and name, within the window's bounds (both inclusive). */\n private eventWindow(userId: string, event: string, window?: EventWindow) {\n const params: unknown[] = [userId, event];\n let where = 'user_id = $1 AND name = $2';\n if (window?.sinceMs !== undefined) {\n params.push(window.sinceMs);\n where += ` AND ts >= ${TS(`$${params.length}`)}`;\n }\n if (window?.untilMs !== undefined) {\n params.push(window.untilMs);\n where += ` AND ts <= ${TS(`$${params.length}`)}`;\n }\n return { where, params };\n }\n\n async countEvents(userId: string, event: string, window?: EventWindow): Promise<number> {\n const { where, params } = this.eventWindow(userId, event, window);\n const rows = await this.sql.query<{ c: number | string }>(\n `SELECT count(*)::int AS c FROM ${this.t.event} WHERE ${where}`,\n params\n );\n return Number(rows.at(0)?.c ?? 0);\n }\n\n async listEventPayloads(\n userId: string,\n event: string,\n window?: EventWindow\n ): Promise<Record<string, unknown>[]> {\n const { where, params } = this.eventWindow(userId, event, window);\n const rows = await this.sql.query<{ payload: unknown }>(\n `SELECT payload FROM ${this.t.event} WHERE ${where}`,\n params\n );\n return rows.map((row) => asJson<Record<string, unknown>>(row.payload));\n }\n\n async getProfile(userId: string): Promise<ProfileProps | undefined> {\n const rows = await this.sql.query<{ props: unknown }>(\n `SELECT props FROM ${this.t.profile} WHERE user_id = $1`,\n [userId]\n );\n const row = rows.at(0);\n return row === undefined ? undefined : asJson<ProfileProps>(row.props);\n }\n\n async mergeProfile(userId: string, props: ProfileProps): Promise<ProfileProps> {\n // RFC 7386 merge-patch in one statement: jsonb `||` overwrites key by key\n // and jsonb_strip_nulls then drops the keys the patch set to null (the\n // API's only way to unset a property). Atomic in the database, so two\n // concurrent identifies cannot lose each other's keys.\n const rows = await this.sql.query<{ props: unknown }>(\n `INSERT INTO ${this.t.profile} (user_id, props) VALUES ($1, jsonb_strip_nulls($2::text::jsonb))\n ON CONFLICT (user_id) DO UPDATE SET props = jsonb_strip_nulls(${this.t.profile}.props || $3::text::jsonb)\n RETURNING props`,\n // EXCLUDED.props would be the stripped insert value, so the update merges the raw patch again\n [userId, JSON.stringify(props), JSON.stringify(props)]\n );\n return asJson<ProfileProps>(rows.at(0)?.props ?? {});\n }\n\n async listUserIds(): Promise<string[]> {\n const rows = await this.sql.query<{ user_id: string }>(\n `SELECT user_id FROM ${this.t.profile} UNION SELECT DISTINCT user_id FROM ${this.t.event}`\n );\n return rows.map((row) => row.user_id);\n }\n\n listDevices(userId: string): Promise<PushDevice[]> {\n return this.sql.query<PushDevice>(\n `SELECT token, platform FROM ${this.t.device} WHERE user_id = $1 ORDER BY ts DESC`,\n [userId]\n );\n }\n\n async upsertDevice(device: DeviceInput): Promise<void> {\n await this.sql.query(\n `INSERT INTO ${this.t.device} (token, user_id, platform, ts) VALUES ($1, $2, $3, ${TS('$4')})\n ON CONFLICT (token) DO UPDATE SET user_id = EXCLUDED.user_id, platform = EXCLUDED.platform, ts = EXCLUDED.ts`,\n [device.token, device.userId, device.platform, device.ts]\n );\n }\n\n async requestErasure(userId: string, at: number): Promise<void> {\n await this.sql.query(\n `INSERT INTO ${this.t.erasure} (user_id, requested_at) VALUES ($1, ${TS('$2')})\n ON CONFLICT DO NOTHING`,\n [userId, at]\n );\n }\n\n async pendingErasures(): Promise<string[]> {\n const rows = await this.sql.query<{ user_id: string }>(\n `SELECT user_id FROM ${this.t.erasure} ORDER BY requested_at`\n );\n return rows.map((row) => row.user_id);\n }\n\n async runningInstances(userId: string): Promise<string[]> {\n const rows = await this.sql.query<{ instance_id: string }>(\n `SELECT instance_id FROM ${this.t.entry} WHERE user_id = $1 AND status = 'running'`,\n [userId]\n );\n return rows.map((row) => row.instance_id);\n }\n\n async forgetUser(userId: string): Promise<void> {\n await this.sql.transaction(async (tx) => {\n // Children before the copies they belong to\n for (const child of [this.t.messageOpen, this.t.messageClick, this.t.messageLink]) {\n await tx.query(\n `DELETE FROM ${child} WHERE message_id IN (SELECT id FROM ${this.t.message} WHERE user_id = $1)`,\n [userId]\n );\n }\n for (const table of [\n this.t.message,\n this.t.instance,\n this.t.entry,\n this.t.subscription,\n this.t.segmentStart,\n this.t.segmentMember,\n this.t.suppression,\n this.t.device,\n this.t.event,\n this.t.profile,\n // The request goes with the data it asked to erase\n this.t.erasure,\n ]) {\n await tx.query(`DELETE FROM ${table} WHERE user_id = $1`, [userId]);\n }\n });\n }\n\n async isSuppressed(userId: string, channel: string): Promise<boolean> {\n const rows = await this.sql.query(\n `SELECT 1 AS x FROM ${this.t.suppression} WHERE user_id = $1 AND channel = $2`,\n [userId, channel]\n );\n return rows.length > 0;\n }\n\n async removeDevice(token: string): Promise<string | undefined> {\n const rows = await this.sql.query<{ user_id: string | null }>(\n `DELETE FROM ${this.t.device} WHERE token = $1 RETURNING user_id`,\n [token]\n );\n return rows[0]?.user_id ?? undefined;\n }\n\n async unbindDevice(token: string): Promise<string | undefined> {\n // The owner as it was before the update: RETURNING alone would only show the null\n const rows = await this.sql.query<{ user_id: string | null }>(\n `WITH old AS (SELECT token, user_id FROM ${this.t.device} WHERE token = $1 FOR UPDATE)\n UPDATE ${this.t.device} d SET user_id = NULL FROM old WHERE d.token = old.token\n RETURNING old.user_id`,\n [token]\n );\n return rows[0]?.user_id ?? undefined;\n }\n\n async listSegments(): Promise<{ id: string; condition: ConditionIR }[]> {\n const rows = await this.sql.query<{ id: string; condition: unknown }>(\n `SELECT id, condition FROM ${this.t.segment} ORDER BY id`\n );\n return rows.map((row) => ({\n id: row.id,\n condition: ConditionIR.parse(asJson(row.condition)),\n }));\n }\n\n async getSegmentCondition(id: string): Promise<ConditionIR | undefined> {\n const rows = await this.sql.query<{ condition: unknown }>(\n `SELECT condition FROM ${this.t.segment} WHERE id = $1`,\n [id]\n );\n const row = rows.at(0);\n return row === undefined ? undefined : ConditionIR.parse(asJson(row.condition));\n }\n\n async findTriggers(event: string): Promise<TriggerRoute[]> {\n const rows = await this.sql.query<{\n workflow: string;\n hash: string;\n where_clause: unknown;\n filter: unknown;\n }>(\n `SELECT workflow, hash, \"where\" AS where_clause, filter FROM ${this.t.trigger} WHERE event = $1`,\n [event]\n );\n return rows.map((row) => ({\n workflow: row.workflow,\n hash: row.hash,\n where: row.where_clause === null ? null : ConditionIR.parse(asJson(row.where_clause)),\n filter: row.filter === null ? null : ConditionIR.parse(asJson(row.filter)),\n }));\n }\n\n listSegmentTriggers(): Promise<SegmentTriggerRoute[]> {\n return this.sql.query<SegmentTriggerRoute>(\n `SELECT workflow, hash, segment FROM ${this.t.segmentTrigger}`\n );\n }\n\n async putWorkflowIR(workflow: WorkflowIR): Promise<void> {\n await this.sql.query(\n `INSERT INTO ${this.t.ir} (content_hash, ir) VALUES ($1, $2::text::jsonb)\n ON CONFLICT (content_hash) DO UPDATE SET ir = EXCLUDED.ir`,\n [workflow.contentHash, JSON.stringify(workflow)]\n );\n }\n\n async getWorkflowIR(contentHash: string): Promise<WorkflowIR | undefined> {\n const rows = await this.sql.query<{ ir: unknown }>(\n `SELECT ir FROM ${this.t.ir} WHERE content_hash = $1`,\n [contentHash]\n );\n const row = rows.at(0);\n return row === undefined ? undefined : WorkflowIR.parse(asJson(row.ir));\n }\n\n replaceRoutes(bundle: BundleIR): Promise<void> {\n return this.sql.transaction(async (tx) => {\n await tx.query(`DELETE FROM ${this.t.trigger}`);\n await tx.query(`DELETE FROM ${this.t.segmentTrigger}`);\n await tx.query(`DELETE FROM ${this.t.segment}`);\n for (const segment of bundle.segments) {\n await tx.query(\n `INSERT INTO ${this.t.segment} (id, condition, hash) VALUES ($1, $2::text::jsonb, $3)`,\n [segment.id, JSON.stringify(segment.condition), segment.contentHash]\n );\n }\n for (const workflow of bundle.workflows) {\n if (workflow.trigger.type === 'event') {\n await tx.query(\n `INSERT INTO ${this.t.trigger} (workflow, hash, event, \"where\", filter) VALUES ($1, $2, $3, $4::text::jsonb, $5::text::jsonb)`,\n [\n workflow.id,\n workflow.contentHash,\n workflow.trigger.event,\n workflow.trigger.where === undefined ? null : JSON.stringify(workflow.trigger.where),\n workflow.trigger.filter === undefined\n ? null\n : JSON.stringify(workflow.trigger.filter),\n ]\n );\n } else if (workflow.trigger.type === 'segment') {\n await tx.query(\n `INSERT INTO ${this.t.segmentTrigger} (workflow, hash, segment) VALUES ($1, $2, $3)`,\n [workflow.id, workflow.contentHash, workflow.trigger.segment]\n );\n }\n }\n });\n }\n\n async isSegmentMember(segment: string, userId: string): Promise<boolean> {\n const rows = await this.sql.query(\n `SELECT 1 AS x FROM ${this.t.segmentMember} WHERE segment = $1 AND user_id = $2`,\n [segment, userId]\n );\n return rows.length > 0;\n }\n\n async addSegmentMember(\n segment: string,\n userId: string,\n ts: number,\n workflows: readonly string[]\n ): Promise<void> {\n await this.sql.transaction(async (tx) => {\n await tx.query(\n `INSERT INTO ${this.t.segmentMember} (segment, user_id, ts) VALUES ($1, $2, ${TS('$3')}) ON CONFLICT DO NOTHING`,\n [segment, userId, ts]\n );\n for (const workflow of workflows) {\n await tx.query(\n `INSERT INTO ${this.t.segmentStart} (segment, workflow, user_id, ts)\n VALUES ($1, $2, $3, ${TS('$4')}) ON CONFLICT DO NOTHING`,\n [segment, workflow, userId, ts]\n );\n }\n });\n }\n\n async pendingSegmentStarts(segment: string, userId: string): Promise<string[]> {\n const rows = await this.sql.query<{ workflow: string }>(\n `SELECT workflow FROM ${this.t.segmentStart} WHERE segment = $1 AND user_id = $2`,\n [segment, userId]\n );\n return rows.map((row) => row.workflow);\n }\n\n async completeSegmentStart(segment: string, userId: string, workflow: string): Promise<void> {\n await this.sql.query(\n `DELETE FROM ${this.t.segmentStart} WHERE segment = $1 AND user_id = $2 AND workflow = $3`,\n [segment, userId, workflow]\n );\n }\n\n async removeSegmentMember(segment: string, userId: string): Promise<void> {\n await this.sql.transaction(async (tx) => {\n await tx.query(`DELETE FROM ${this.t.segmentStart} WHERE segment = $1 AND user_id = $2`, [\n segment,\n userId,\n ]);\n await tx.query(`DELETE FROM ${this.t.segmentMember} WHERE segment = $1 AND user_id = $2`, [\n segment,\n userId,\n ]);\n });\n }\n\n async enterJourney(entry: EntryInput): Promise<EntryOutcome> {\n // The (workflow, user_id) primary key makes the once policy atomic:\n // concurrent ingests race on the insert and exactly one wins.\n const inserted = await this.sql.query(\n `INSERT INTO ${this.t.entry} (workflow, user_id, instance_id, hash, status, ts)\n VALUES ($1, $2, $3, $4, 'running', ${TS('$5')})\n ON CONFLICT (workflow, user_id) DO NOTHING RETURNING instance_id`,\n [entry.workflow, entry.userId, entry.instanceId, entry.hash, entry.ts]\n );\n if (inserted.length > 0) return 'entered';\n\n // An existing row blocks the entry unless it records an instance that died:\n // 'failed' is reclaimed rather than barring the user forever over one\n // outage. The status test is inside the UPDATE, so of two concurrent\n // retries exactly one gets a row back.\n const claimed = await this.sql.query(\n `UPDATE ${this.t.entry} SET instance_id = $1, hash = $2, status = 'running', ts = ${TS('$3')}\n WHERE workflow = $4 AND user_id = $5 AND status = 'failed' RETURNING instance_id`,\n [entry.instanceId, entry.hash, entry.ts, entry.workflow, entry.userId]\n );\n return claimed.length > 0 ? 'reclaimed' : null;\n }\n\n async removeEntry(instanceId: string): Promise<void> {\n await this.sql.query(`DELETE FROM ${this.t.entry} WHERE instance_id = $1`, [instanceId]);\n }\n\n async setEntryStatus(instanceId: string, status: string): Promise<void> {\n await this.sql.query(`UPDATE ${this.t.entry} SET status = $1 WHERE instance_id = $2`, [\n status,\n instanceId,\n ]);\n }\n\n async findWakeHandles(userId: string, event: string): Promise<string[]> {\n const rows = await this.sql.query<{ handle: string }>(\n `SELECT DISTINCT wake_handle AS handle FROM ${this.t.subscription} WHERE user_id = $1 AND event = $2`,\n [userId, event]\n );\n return rows.map((row) => row.handle);\n }\n\n async subscribe(\n handle: string,\n userId: string,\n events: readonly string[],\n ts: number\n ): Promise<void> {\n for (const event of events) {\n await this.sql.query(\n `INSERT INTO ${this.t.subscription} (user_id, event, wake_handle, ts) VALUES ($1, $2, $3, ${TS('$4')}) ON CONFLICT DO NOTHING`,\n [userId, event, handle, ts]\n );\n }\n }\n\n async unsubscribe(handle: string): Promise<void> {\n await this.sql.query(`DELETE FROM ${this.t.subscription} WHERE wake_handle = $1`, [handle]);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import { BundleIR, ConditionIR, WorkflowIR } from "../ir.cjs";
2
+ import { PushDevice } from "../engine/ports.cjs";
3
+ import { SqlClientLike, uuidv7 } from "./sql.cjs";
4
+ import { DEFAULT_SCHEMA } from "./tables.cjs";
5
+ import { DeviceInput, EntryInput, EntryOutcome, EventInput, EventWindow, JourneyReporting, JourneyStore, ProfileProps, SegmentTriggerRoute, TriggerRoute } from "./index.cjs";
6
+ //#region src/store/postgres.d.ts
7
+ export interface PostgresJourneyStoreOptions {
8
+ /**
9
+ * The Postgres schema the engine's tables live in — `workflow` by default, the config's
10
+ * `database.schema` under journeyWorker. A schema of its own keeps the tables apart from the
11
+ * app's. The host creates them with its own migrations, from the drizzle file
12
+ * `renderDrizzleSchema` generates (or the plain `renderPostgresDdl`).
13
+ */
14
+ schema?: string;
15
+ }
16
+ /**
17
+ * Journey data plane on Postgres. Same contract as D1JourneyStore, native
18
+ * types where Postgres has them (jsonb, timestamptz), and the concurrency
19
+ * guarantees come from the database: ON CONFLICT for the once policy and
20
+ * idempotent subscriptions, a transaction for the route swap, a jsonb merge
21
+ * for /identify. The tables are declared in tables.ts.
22
+ */
23
+ export declare class PostgresJourneyStore implements JourneyStore {
24
+ private readonly sql;
25
+ private readonly t;
26
+ private readonly schema;
27
+ readonly reporting: JourneyReporting;
28
+ constructor(sql: SqlClientLike, options?: PostgresJourneyStoreOptions);
29
+ /**
30
+ * What the live database lacks against tables.ts: missing tables, missing columns, a column
31
+ * of another type or nullability. Read-only — the engine never migrates the host's database; a
32
+ * deploy fails with these problems listed, and the fix is to regenerate the drizzle file and
33
+ * run the host's migrations.
34
+ */
35
+ checkSchema(): Promise<string[]>;
36
+ insertEvent(input: EventInput): Promise<boolean>;
37
+ /** The event rows of one user and name, within the window's bounds (both inclusive). */
38
+ private eventWindow;
39
+ countEvents(userId: string, event: string, window?: EventWindow): Promise<number>;
40
+ listEventPayloads(userId: string, event: string, window?: EventWindow): Promise<Record<string, unknown>[]>;
41
+ getProfile(userId: string): Promise<ProfileProps | undefined>;
42
+ mergeProfile(userId: string, props: ProfileProps): Promise<ProfileProps>;
43
+ listUserIds(): Promise<string[]>;
44
+ listDevices(userId: string): Promise<PushDevice[]>;
45
+ upsertDevice(device: DeviceInput): Promise<void>;
46
+ requestErasure(userId: string, at: number): Promise<void>;
47
+ pendingErasures(): Promise<string[]>;
48
+ runningInstances(userId: string): Promise<string[]>;
49
+ forgetUser(userId: string): Promise<void>;
50
+ isSuppressed(userId: string, channel: string): Promise<boolean>;
51
+ removeDevice(token: string): Promise<string | undefined>;
52
+ unbindDevice(token: string): Promise<string | undefined>;
53
+ listSegments(): Promise<{
54
+ id: string;
55
+ condition: ConditionIR;
56
+ }[]>;
57
+ getSegmentCondition(id: string): Promise<ConditionIR | undefined>;
58
+ findTriggers(event: string): Promise<TriggerRoute[]>;
59
+ listSegmentTriggers(): Promise<SegmentTriggerRoute[]>;
60
+ putWorkflowIR(workflow: WorkflowIR): Promise<void>;
61
+ getWorkflowIR(contentHash: string): Promise<WorkflowIR | undefined>;
62
+ replaceRoutes(bundle: BundleIR): Promise<void>;
63
+ isSegmentMember(segment: string, userId: string): Promise<boolean>;
64
+ addSegmentMember(segment: string, userId: string, ts: number, workflows: readonly string[]): Promise<void>;
65
+ pendingSegmentStarts(segment: string, userId: string): Promise<string[]>;
66
+ completeSegmentStart(segment: string, userId: string, workflow: string): Promise<void>;
67
+ removeSegmentMember(segment: string, userId: string): Promise<void>;
68
+ enterJourney(entry: EntryInput): Promise<EntryOutcome>;
69
+ removeEntry(instanceId: string): Promise<void>;
70
+ setEntryStatus(instanceId: string, status: string): Promise<void>;
71
+ findWakeHandles(userId: string, event: string): Promise<string[]>;
72
+ subscribe(handle: string, userId: string, events: readonly string[], ts: number): Promise<void>;
73
+ unsubscribe(handle: string): Promise<void>;
74
+ }
75
+ //#endregion
76
+ export { DEFAULT_SCHEMA, type SqlClientLike, uuidv7 };
77
+ //# sourceMappingURL=postgres.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.cts","names":[],"sources":["../../src/store/postgres.ts"],"mappings":";;;;;;iBAqBiB;;;;;;;EAOf;;;;;;;;;qBA2BW,gCAAgC;mBAMxB;mBALF;mBACA;WACR,WAAW;EAEpB,YACmB,KAAK,eACtB,UAAS;;;;;;;EAgBL,eAAe;EAwCf,YAAY,OAAO,aAAa;;UAsB9B;EAcF,YAAY,gBAAgB,eAAe,SAAS,cAAc;EASlE,kBACJ,gBACA,eACA,SAAS,cACR,QAAQ;EASL,WAAW,iBAAiB,QAAQ;EASpC,aAAa,gBAAgB,OAAO,eAAe,QAAQ;EAe3D,eAAe;EAOrB,YAAY,iBAAiB,QAAQ;EAO/B,aAAa,QAAQ,cAAc;EAQnC,eAAe,gBAAgB,aAAa;EAQ5C,mBAAmB;EAOnB,iBAAiB,iBAAiB;EAQlC,WAAW,iBAAiB;EA4B5B,aAAa,gBAAgB,kBAAkB;EAQ/C,aAAa,gBAAgB;EAQ7B,aAAa,gBAAgB;EAW7B,gBAAgB;IAAU;IAAY,WAAW;;EAUjD,oBAAoB,aAAa,QAAQ;EASzC,aAAa,gBAAgB,QAAQ;EAkB3C,uBAAuB,QAAQ;EAMzB,cAAc,UAAU,aAAa;EAQrC,cAAc,sBAAsB,QAAQ;EASlD,cAAc,QAAQ,WAAW;EAmC3B,gBAAgB,iBAAiB,iBAAiB;EAQlD,iBACJ,iBACA,gBACA,YACA,+BACC;EAgBG,qBAAqB,iBAAiB,iBAAiB;EAQvD,qBAAqB,iBAAiB,gBAAgB,mBAAmB;EAOzE,oBAAoB,iBAAiB,iBAAiB;EAatD,aAAa,OAAO,aAAa,QAAQ;EAuBzC,YAAY,qBAAqB;EAIjC,eAAe,oBAAoB,iBAAiB;EAOpD,gBAAgB,gBAAgB,gBAAgB;EAQhD,UACJ,gBACA,gBACA,2BACA,aACC;EASG,YAAY,iBAAiB"}
@@ -0,0 +1,77 @@
1
+ import { BundleIR, ConditionIR, WorkflowIR } from "../ir.mjs";
2
+ import { PushDevice } from "../engine/ports.mjs";
3
+ import { SqlClientLike, uuidv7 } from "./sql.mjs";
4
+ import { DEFAULT_SCHEMA } from "./tables.mjs";
5
+ import { DeviceInput, EntryInput, EntryOutcome, EventInput, EventWindow, JourneyReporting, JourneyStore, ProfileProps, SegmentTriggerRoute, TriggerRoute } from "./index.mjs";
6
+ //#region src/store/postgres.d.ts
7
+ export interface PostgresJourneyStoreOptions {
8
+ /**
9
+ * The Postgres schema the engine's tables live in — `workflow` by default, the config's
10
+ * `database.schema` under journeyWorker. A schema of its own keeps the tables apart from the
11
+ * app's. The host creates them with its own migrations, from the drizzle file
12
+ * `renderDrizzleSchema` generates (or the plain `renderPostgresDdl`).
13
+ */
14
+ schema?: string;
15
+ }
16
+ /**
17
+ * Journey data plane on Postgres. Same contract as D1JourneyStore, native
18
+ * types where Postgres has them (jsonb, timestamptz), and the concurrency
19
+ * guarantees come from the database: ON CONFLICT for the once policy and
20
+ * idempotent subscriptions, a transaction for the route swap, a jsonb merge
21
+ * for /identify. The tables are declared in tables.ts.
22
+ */
23
+ export declare class PostgresJourneyStore implements JourneyStore {
24
+ private readonly sql;
25
+ private readonly t;
26
+ private readonly schema;
27
+ readonly reporting: JourneyReporting;
28
+ constructor(sql: SqlClientLike, options?: PostgresJourneyStoreOptions);
29
+ /**
30
+ * What the live database lacks against tables.ts: missing tables, missing columns, a column
31
+ * of another type or nullability. Read-only — the engine never migrates the host's database; a
32
+ * deploy fails with these problems listed, and the fix is to regenerate the drizzle file and
33
+ * run the host's migrations.
34
+ */
35
+ checkSchema(): Promise<string[]>;
36
+ insertEvent(input: EventInput): Promise<boolean>;
37
+ /** The event rows of one user and name, within the window's bounds (both inclusive). */
38
+ private eventWindow;
39
+ countEvents(userId: string, event: string, window?: EventWindow): Promise<number>;
40
+ listEventPayloads(userId: string, event: string, window?: EventWindow): Promise<Record<string, unknown>[]>;
41
+ getProfile(userId: string): Promise<ProfileProps | undefined>;
42
+ mergeProfile(userId: string, props: ProfileProps): Promise<ProfileProps>;
43
+ listUserIds(): Promise<string[]>;
44
+ listDevices(userId: string): Promise<PushDevice[]>;
45
+ upsertDevice(device: DeviceInput): Promise<void>;
46
+ requestErasure(userId: string, at: number): Promise<void>;
47
+ pendingErasures(): Promise<string[]>;
48
+ runningInstances(userId: string): Promise<string[]>;
49
+ forgetUser(userId: string): Promise<void>;
50
+ isSuppressed(userId: string, channel: string): Promise<boolean>;
51
+ removeDevice(token: string): Promise<string | undefined>;
52
+ unbindDevice(token: string): Promise<string | undefined>;
53
+ listSegments(): Promise<{
54
+ id: string;
55
+ condition: ConditionIR;
56
+ }[]>;
57
+ getSegmentCondition(id: string): Promise<ConditionIR | undefined>;
58
+ findTriggers(event: string): Promise<TriggerRoute[]>;
59
+ listSegmentTriggers(): Promise<SegmentTriggerRoute[]>;
60
+ putWorkflowIR(workflow: WorkflowIR): Promise<void>;
61
+ getWorkflowIR(contentHash: string): Promise<WorkflowIR | undefined>;
62
+ replaceRoutes(bundle: BundleIR): Promise<void>;
63
+ isSegmentMember(segment: string, userId: string): Promise<boolean>;
64
+ addSegmentMember(segment: string, userId: string, ts: number, workflows: readonly string[]): Promise<void>;
65
+ pendingSegmentStarts(segment: string, userId: string): Promise<string[]>;
66
+ completeSegmentStart(segment: string, userId: string, workflow: string): Promise<void>;
67
+ removeSegmentMember(segment: string, userId: string): Promise<void>;
68
+ enterJourney(entry: EntryInput): Promise<EntryOutcome>;
69
+ removeEntry(instanceId: string): Promise<void>;
70
+ setEntryStatus(instanceId: string, status: string): Promise<void>;
71
+ findWakeHandles(userId: string, event: string): Promise<string[]>;
72
+ subscribe(handle: string, userId: string, events: readonly string[], ts: number): Promise<void>;
73
+ unsubscribe(handle: string): Promise<void>;
74
+ }
75
+ //#endregion
76
+ export { DEFAULT_SCHEMA, type SqlClientLike, uuidv7 };
77
+ //# sourceMappingURL=postgres.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.mts","names":[],"sources":["../../src/store/postgres.ts"],"mappings":";;;;;;iBAqBiB;;;;;;;EAOf;;;;;;;;;qBA2BW,gCAAgC;mBAMxB;mBALF;mBACA;WACR,WAAW;EAEpB,YACmB,KAAK,eACtB,UAAS;;;;;;;EAgBL,eAAe;EAwCf,YAAY,OAAO,aAAa;;UAsB9B;EAcF,YAAY,gBAAgB,eAAe,SAAS,cAAc;EASlE,kBACJ,gBACA,eACA,SAAS,cACR,QAAQ;EASL,WAAW,iBAAiB,QAAQ;EASpC,aAAa,gBAAgB,OAAO,eAAe,QAAQ;EAe3D,eAAe;EAOrB,YAAY,iBAAiB,QAAQ;EAO/B,aAAa,QAAQ,cAAc;EAQnC,eAAe,gBAAgB,aAAa;EAQ5C,mBAAmB;EAOnB,iBAAiB,iBAAiB;EAQlC,WAAW,iBAAiB;EA4B5B,aAAa,gBAAgB,kBAAkB;EAQ/C,aAAa,gBAAgB;EAQ7B,aAAa,gBAAgB;EAW7B,gBAAgB;IAAU;IAAY,WAAW;;EAUjD,oBAAoB,aAAa,QAAQ;EASzC,aAAa,gBAAgB,QAAQ;EAkB3C,uBAAuB,QAAQ;EAMzB,cAAc,UAAU,aAAa;EAQrC,cAAc,sBAAsB,QAAQ;EASlD,cAAc,QAAQ,WAAW;EAmC3B,gBAAgB,iBAAiB,iBAAiB;EAQlD,iBACJ,iBACA,gBACA,YACA,+BACC;EAgBG,qBAAqB,iBAAiB,iBAAiB;EAQvD,qBAAqB,iBAAiB,gBAAgB,mBAAmB;EAOzE,oBAAoB,iBAAiB,iBAAiB;EAatD,aAAa,OAAO,aAAa,QAAQ;EAuBzC,YAAY,qBAAqB;EAIjC,eAAe,oBAAoB,iBAAiB;EAOpD,gBAAgB,gBAAgB,gBAAgB;EAQhD,UACJ,gBACA,gBACA,2BACA,aACC;EASG,YAAY,iBAAiB"}