@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
package/dist/plan.cjs ADDED
@@ -0,0 +1,223 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_hash = require("./hash.cjs");
3
+ //#region src/plan.ts
4
+ /** Whether a status warrants human attention (metadata-only edits do not). */
5
+ function isSemanticChange(status) {
6
+ return status === "added" || status === "removed" || status === "changed";
7
+ }
8
+ /** Walk the node tree into a flat id → node map (branch arms, cohort arms and timeout flows included). */
9
+ function flatten(nodes, into) {
10
+ for (const node of nodes) {
11
+ into.set(node.id, node);
12
+ switch (node.type) {
13
+ case "branch":
14
+ for (const branchCase of node.cases) flatten(branchCase.flow, into);
15
+ if (node.otherwise) flatten(node.otherwise, into);
16
+ break;
17
+ case "cohort":
18
+ for (const arm of node.arms) flatten(arm.flow, into);
19
+ break;
20
+ case "wait_until": if (Array.isArray(node.onTimeout)) flatten(node.onTimeout, into);
21
+ }
22
+ }
23
+ return into;
24
+ }
25
+ /**
26
+ * A node's semantic fingerprint: metadata stripped, child flows excluded (they
27
+ * diff on their own ids). Everything else a compound node owns — branch case
28
+ * conditions, cohort arm names and weights, *having* a default arm or a
29
+ * timeout flow — is this node's semantics and stays in the fingerprint, so
30
+ * editing a branch condition or reweighting an A/B shows up on the node itself.
31
+ */
32
+ function nodeFingerprint(node) {
33
+ const bare = { ...node };
34
+ if (node.type === "branch") {
35
+ bare.cases = node.cases.map((branchCase) => ({ condition: branchCase.condition }));
36
+ delete bare.otherwise;
37
+ if (node.otherwise !== void 0) bare.otherwise = "<flow>";
38
+ }
39
+ if (node.type === "cohort") bare.arms = node.arms.map((arm) => ({
40
+ name: arm.name,
41
+ weight: arm.weight
42
+ }));
43
+ if (node.type === "wait_until" && Array.isArray(node.onTimeout)) bare.onTimeout = "<flow>";
44
+ return require_hash.fullHash(require_hash.stripMeta(bare));
45
+ }
46
+ function diffNodes(local, deployed) {
47
+ const localNodes = flatten(local.flow, /* @__PURE__ */ new Map());
48
+ const deployedNodes = flatten(deployed.flow, /* @__PURE__ */ new Map());
49
+ const changes = [];
50
+ for (const [id, node] of localNodes) {
51
+ const before = deployedNodes.get(id);
52
+ if (!before) changes.push({
53
+ id,
54
+ status: "added",
55
+ type: node.type
56
+ });
57
+ else if (nodeFingerprint(node) !== nodeFingerprint(before)) changes.push({
58
+ id,
59
+ status: "changed",
60
+ type: node.type
61
+ });
62
+ }
63
+ for (const [id, node] of deployedNodes) if (!localNodes.has(id)) changes.push({
64
+ id,
65
+ status: "removed",
66
+ type: node.type
67
+ });
68
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
69
+ }
70
+ function diffFields(local, deployed) {
71
+ const fields = [];
72
+ for (const field of [
73
+ "trigger",
74
+ "goal",
75
+ "exitWhen"
76
+ ]) if (require_hash.fullHash(require_hash.stripMeta(local[field])) !== require_hash.fullHash(require_hash.stripMeta(deployed[field]))) fields.push(field);
77
+ return fields;
78
+ }
79
+ function statusOf(local, deployed) {
80
+ if (local.contentHash !== deployed.contentHash) return "changed";
81
+ return require_hash.fullHash(require_hash.stripProvenance(local)) === require_hash.fullHash(require_hash.stripProvenance(deployed)) ? "unchanged" : "metadata_only";
82
+ }
83
+ function diffWorkflows(local, deployed) {
84
+ const deployedByName = new Map(deployed.map((item) => [item.id, item]));
85
+ const changes = [];
86
+ for (const item of local) {
87
+ const before = deployedByName.get(item.id);
88
+ if (!before) {
89
+ changes.push({
90
+ id: item.id,
91
+ status: "added",
92
+ after: item.contentHash,
93
+ fields: [],
94
+ nodes: []
95
+ });
96
+ continue;
97
+ }
98
+ const status = statusOf(item, before);
99
+ changes.push({
100
+ id: item.id,
101
+ status,
102
+ before: before.contentHash,
103
+ after: item.contentHash,
104
+ fields: status === "changed" ? diffFields(item, before) : [],
105
+ nodes: status === "changed" ? diffNodes(item, before) : []
106
+ });
107
+ }
108
+ const localNames = new Set(local.map((item) => item.id));
109
+ for (const item of deployed) if (!localNames.has(item.id)) changes.push({
110
+ id: item.id,
111
+ status: "removed",
112
+ before: item.contentHash,
113
+ fields: [],
114
+ nodes: []
115
+ });
116
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
117
+ }
118
+ function diffSegments(local, deployed) {
119
+ const deployedByName = new Map(deployed.map((item) => [item.id, item]));
120
+ const changes = local.map((item) => {
121
+ const before = deployedByName.get(item.id);
122
+ if (!before) return {
123
+ id: item.id,
124
+ status: "added",
125
+ after: item.contentHash
126
+ };
127
+ return {
128
+ id: item.id,
129
+ status: statusOf(item, before),
130
+ before: before.contentHash,
131
+ after: item.contentHash
132
+ };
133
+ });
134
+ const localNames = new Set(local.map((item) => item.id));
135
+ for (const item of deployed) if (!localNames.has(item.id)) changes.push({
136
+ id: item.id,
137
+ status: "removed",
138
+ before: item.contentHash
139
+ });
140
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
141
+ }
142
+ function diffTemplates(local, deployed) {
143
+ const deployedByKey = new Map(deployed.map((item) => [item.key, item]));
144
+ const changes = local.map((item) => {
145
+ const before = deployedByKey.get(item.key);
146
+ if (!before) return {
147
+ id: item.key,
148
+ status: "added"
149
+ };
150
+ return {
151
+ id: item.key,
152
+ status: before.channel === item.channel ? "unchanged" : "changed"
153
+ };
154
+ });
155
+ const localKeys = new Set(local.map((item) => item.key));
156
+ for (const item of deployed) if (!localKeys.has(item.key)) changes.push({
157
+ id: item.key,
158
+ status: "removed"
159
+ });
160
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
161
+ }
162
+ /** Actions diff on codeHash — the manifest's only semantic content (the code itself lives in the Worker bundle). */
163
+ function diffActions(local, deployed) {
164
+ const deployedByName = new Map(deployed.map((item) => [item.name, item]));
165
+ const changes = local.map((item) => {
166
+ const before = deployedByName.get(item.name);
167
+ if (!before) return {
168
+ id: item.name,
169
+ status: "added",
170
+ after: item.codeHash
171
+ };
172
+ return {
173
+ id: item.name,
174
+ status: before.codeHash === item.codeHash ? "unchanged" : "changed",
175
+ before: before.codeHash,
176
+ after: item.codeHash
177
+ };
178
+ });
179
+ const localNames = new Set(local.map((item) => item.name));
180
+ for (const item of deployed) if (!localNames.has(item.name)) changes.push({
181
+ id: item.name,
182
+ status: "removed",
183
+ before: item.codeHash
184
+ });
185
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
186
+ }
187
+ /** Empty bundle: the default `deployed` on a first deploy, so everything reports as added. */
188
+ const EMPTY = {
189
+ workflows: [],
190
+ segments: [],
191
+ templates: [],
192
+ actions: []
193
+ };
194
+ /**
195
+ * Compute a deployment plan. Omitting `deployed` means a first deploy.
196
+ *
197
+ * const changes = plan(compileBundle({ workflows }), await fetchDeployed());
198
+ * if (changes.hasChanges) { ... }
199
+ */
200
+ function plan(local, deployed) {
201
+ const base = deployed ?? EMPTY;
202
+ const workflows = diffWorkflows(local.workflows, base.workflows);
203
+ const segments = diffSegments(local.segments, base.segments);
204
+ const templates = diffTemplates(local.templates, base.templates);
205
+ const actions = diffActions(local.actions, base.actions);
206
+ return {
207
+ workflows,
208
+ segments,
209
+ templates,
210
+ actions,
211
+ hasChanges: [
212
+ ...workflows,
213
+ ...segments,
214
+ ...templates,
215
+ ...actions
216
+ ].some((change) => isSemanticChange(change.status))
217
+ };
218
+ }
219
+ //#endregion
220
+ exports.isSemanticChange = isSemanticChange;
221
+ exports.plan = plan;
222
+
223
+ //# sourceMappingURL=plan.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.cjs","names":["fullHash","stripMeta","stripProvenance"],"sources":["../src/plan.ts"],"sourcesContent":["import { fullHash, stripMeta, stripProvenance } from './hash';\nimport type { BundleIR, NodeIR, SegmentIR, WorkflowIR } from './ir';\n\n/**\n * Plan — the diff between local definitions and what is deployed (terraform\n * plan, same mental model).\n *\n * This is the core advantage of code-first over a UI canvas: before deploying,\n * a machine can answer \"what changed, and how many in-flight users does it\n * affect\". Pure function, zero IO — CLI, UI and CI share one verdict.\n *\n * Status comes from two levels of comparison:\n * - contentHash differs → `changed` (semantics moved; in-flight users may need\n * migration)\n * - contentHash equal but full content differs → `metadata_only` (description\n * or labels only, nothing about execution) — exactly what keeping metadata\n * out of the hash buys us.\n */\n\nexport type ChangeStatus = 'added' | 'removed' | 'changed' | 'metadata_only' | 'unchanged';\n\n/** Whether a status warrants human attention (metadata-only edits do not). */\nexport function isSemanticChange(status: ChangeStatus): boolean {\n return status === 'added' || status === 'removed' || status === 'changed';\n}\n\nexport interface NodeChange {\n id: string;\n status: 'added' | 'removed' | 'changed';\n /** Node type: taken from the deployed side when removed, local otherwise. */\n type: NodeIR['type'];\n}\n\nexport interface WorkflowChange {\n /** The workflow's id. */\n id: string;\n status: ChangeStatus;\n /** Deployed contentHash (absent when added). */\n before?: string;\n /** Local contentHash (absent when removed). */\n after?: string;\n /** Workflow-level semantic fields that moved (trigger / goal / exitWhen). */\n fields: ('trigger' | 'goal' | 'exitWhen')[];\n /**\n * Node-level detail, matched by structural-path id — so **inserting a node\n * shifts the ids of its later siblings**, and one insert can report as a run\n * of `changed` entries. That is the known trade-off of structural ids (see\n * ir.ts): the verdict stays correct, it is just noisier than ideal.\n */\n nodes: NodeChange[];\n}\n\nexport interface ResourceChange {\n /** The resource's identity: a segment's id, a template's key, an action's name. */\n id: string;\n status: ChangeStatus;\n before?: string;\n after?: string;\n}\n\nexport interface BundlePlan {\n workflows: WorkflowChange[];\n segments: ResourceChange[];\n templates: ResourceChange[];\n actions: ResourceChange[];\n /** Whether any semantic change exists (metadata-only edits do not count). */\n hasChanges: boolean;\n}\n\n/** Walk the node tree into a flat id → node map (branch arms, cohort arms and timeout flows included). */\nfunction flatten(nodes: readonly NodeIR[], into: Map<string, NodeIR>): Map<string, NodeIR> {\n for (const node of nodes) {\n into.set(node.id, node);\n switch (node.type) {\n case 'branch':\n for (const branchCase of node.cases) flatten(branchCase.flow, into);\n if (node.otherwise) flatten(node.otherwise, into);\n break;\n case 'cohort':\n for (const arm of node.arms) flatten(arm.flow, into);\n break;\n case 'wait_until':\n if (Array.isArray(node.onTimeout)) flatten(node.onTimeout, into);\n break;\n default:\n break;\n }\n }\n return into;\n}\n\n/**\n * A node's semantic fingerprint: metadata stripped, child flows excluded (they\n * diff on their own ids). Everything else a compound node owns — branch case\n * conditions, cohort arm names and weights, *having* a default arm or a\n * timeout flow — is this node's semantics and stays in the fingerprint, so\n * editing a branch condition or reweighting an A/B shows up on the node itself.\n */\nfunction nodeFingerprint(node: NodeIR): string {\n const bare: Record<string, unknown> = { ...node };\n if (node.type === 'branch') {\n bare.cases = node.cases.map((branchCase) => ({ condition: branchCase.condition }));\n delete bare.otherwise;\n if (node.otherwise !== undefined) bare.otherwise = '<flow>';\n }\n if (node.type === 'cohort') {\n bare.arms = node.arms.map((arm) => ({ name: arm.name, weight: arm.weight }));\n }\n if (node.type === 'wait_until' && Array.isArray(node.onTimeout)) {\n bare.onTimeout = '<flow>';\n }\n return fullHash(stripMeta(bare));\n}\n\nfunction diffNodes(local: WorkflowIR, deployed: WorkflowIR): NodeChange[] {\n const localNodes = flatten(local.flow, new Map());\n const deployedNodes = flatten(deployed.flow, new Map());\n const changes: NodeChange[] = [];\n\n for (const [id, node] of localNodes) {\n const before = deployedNodes.get(id);\n if (!before) {\n changes.push({ id, status: 'added', type: node.type });\n } else if (nodeFingerprint(node) !== nodeFingerprint(before)) {\n changes.push({ id, status: 'changed', type: node.type });\n }\n }\n for (const [id, node] of deployedNodes) {\n if (!localNodes.has(id)) changes.push({ id, status: 'removed', type: node.type });\n }\n\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction diffFields(local: WorkflowIR, deployed: WorkflowIR): WorkflowChange['fields'] {\n const fields: WorkflowChange['fields'] = [];\n for (const field of ['trigger', 'goal', 'exitWhen'] as const) {\n if (fullHash(stripMeta(local[field])) !== fullHash(stripMeta(deployed[field]))) {\n fields.push(field);\n }\n }\n return fields;\n}\n\nfunction statusOf(local: { contentHash: string }, deployed: { contentHash: string }): ChangeStatus {\n if (local.contentHash !== deployed.contentHash) return 'changed';\n /*\n * Provenance is deliberately not part of the comparison: a recorded loc is a\n * source map, and its path depends on the machine and the directory the\n * compile ran from ('packages/workflow/src/wf.ts' from the workspace root,\n * 'src/wf.ts' from the package). Comparing it turned every CI run into a\n * wall of metadata_only against a locally compiled deploy. Descriptions,\n * labels and reasons still count — those are edits somebody made.\n */\n return fullHash(stripProvenance(local)) === fullHash(stripProvenance(deployed))\n ? 'unchanged'\n : 'metadata_only';\n}\n\nfunction diffWorkflows(\n local: readonly WorkflowIR[],\n deployed: readonly WorkflowIR[]\n): WorkflowChange[] {\n const deployedByName = new Map(deployed.map((item) => [item.id, item]));\n const changes: WorkflowChange[] = [];\n\n for (const item of local) {\n const before = deployedByName.get(item.id);\n if (!before) {\n changes.push({\n id: item.id,\n status: 'added',\n after: item.contentHash,\n fields: [],\n nodes: [],\n });\n continue;\n }\n const status = statusOf(item, before);\n changes.push({\n id: item.id,\n status,\n before: before.contentHash,\n after: item.contentHash,\n fields: status === 'changed' ? diffFields(item, before) : [],\n nodes: status === 'changed' ? diffNodes(item, before) : [],\n });\n }\n\n const localNames = new Set(local.map((item) => item.id));\n for (const item of deployed) {\n if (!localNames.has(item.id)) {\n changes.push({\n id: item.id,\n status: 'removed',\n before: item.contentHash,\n fields: [],\n nodes: [],\n });\n }\n }\n\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction diffSegments(\n local: readonly SegmentIR[],\n deployed: readonly SegmentIR[]\n): ResourceChange[] {\n const deployedByName = new Map(deployed.map((item) => [item.id, item]));\n const changes: ResourceChange[] = local.map((item) => {\n const before = deployedByName.get(item.id);\n if (!before) return { id: item.id, status: 'added' as const, after: item.contentHash };\n return {\n id: item.id,\n status: statusOf(item, before),\n before: before.contentHash,\n after: item.contentHash,\n };\n });\n\n const localNames = new Set(local.map((item) => item.id));\n for (const item of deployed) {\n if (!localNames.has(item.id)) {\n changes.push({ id: item.id, status: 'removed', before: item.contentHash });\n }\n }\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction diffTemplates(local: BundleIR['templates'], deployed: BundleIR['templates']) {\n const deployedByKey = new Map(deployed.map((item) => [item.key, item]));\n const changes: ResourceChange[] = local.map((item) => {\n const before = deployedByKey.get(item.key);\n if (!before) return { id: item.key, status: 'added' as const };\n return { id: item.key, status: before.channel === item.channel ? 'unchanged' : 'changed' };\n });\n\n const localKeys = new Set(local.map((item) => item.key));\n for (const item of deployed) {\n if (!localKeys.has(item.key)) changes.push({ id: item.key, status: 'removed' });\n }\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\n/** Actions diff on codeHash — the manifest's only semantic content (the code itself lives in the Worker bundle). */\nfunction diffActions(local: BundleIR['actions'], deployed: BundleIR['actions']) {\n const deployedByName = new Map(deployed.map((item) => [item.name, item]));\n const changes: ResourceChange[] = local.map((item) => {\n const before = deployedByName.get(item.name);\n if (!before) return { id: item.name, status: 'added' as const, after: item.codeHash };\n return {\n id: item.name,\n status: before.codeHash === item.codeHash ? ('unchanged' as const) : ('changed' as const),\n before: before.codeHash,\n after: item.codeHash,\n };\n });\n\n const localNames = new Set(local.map((item) => item.name));\n for (const item of deployed) {\n if (!localNames.has(item.name)) {\n changes.push({ id: item.name, status: 'removed', before: item.codeHash });\n }\n }\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\n/** Empty bundle: the default `deployed` on a first deploy, so everything reports as added. */\nconst EMPTY: Pick<BundleIR, 'workflows' | 'segments' | 'templates' | 'actions'> = {\n workflows: [],\n segments: [],\n templates: [],\n actions: [],\n};\n\n/**\n * Compute a deployment plan. Omitting `deployed` means a first deploy.\n *\n * const changes = plan(compileBundle({ workflows }), await fetchDeployed());\n * if (changes.hasChanges) { ... }\n */\nexport function plan(local: BundleIR, deployed?: BundleIR): BundlePlan {\n const base = deployed ?? EMPTY;\n const workflows = diffWorkflows(local.workflows, base.workflows);\n const segments = diffSegments(local.segments, base.segments);\n const templates = diffTemplates(local.templates, base.templates);\n const actions = diffActions(local.actions, base.actions);\n\n const hasChanges = [...workflows, ...segments, ...templates, ...actions].some((change) =>\n isSemanticChange(change.status)\n );\n\n return { workflows, segments, templates, actions, hasChanges };\n}\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { BundleIR, NodeIR } from "./ir.cjs";
2
+ //#region src/plan.d.ts
3
+ /**
4
+ * Plan — the diff between local definitions and what is deployed (terraform
5
+ * plan, same mental model).
6
+ *
7
+ * This is the core advantage of code-first over a UI canvas: before deploying,
8
+ * a machine can answer "what changed, and how many in-flight users does it
9
+ * affect". Pure function, zero IO — CLI, UI and CI share one verdict.
10
+ *
11
+ * Status comes from two levels of comparison:
12
+ * - contentHash differs → `changed` (semantics moved; in-flight users may need
13
+ * migration)
14
+ * - contentHash equal but full content differs → `metadata_only` (description
15
+ * or labels only, nothing about execution) — exactly what keeping metadata
16
+ * out of the hash buys us.
17
+ */
18
+ export type ChangeStatus = 'added' | 'removed' | 'changed' | 'metadata_only' | 'unchanged';
19
+ /** Whether a status warrants human attention (metadata-only edits do not). */
20
+ export declare function isSemanticChange(status: ChangeStatus): boolean;
21
+ export interface NodeChange {
22
+ id: string;
23
+ status: 'added' | 'removed' | 'changed';
24
+ /** Node type: taken from the deployed side when removed, local otherwise. */
25
+ type: NodeIR['type'];
26
+ }
27
+ export interface WorkflowChange {
28
+ /** The workflow's id. */
29
+ id: string;
30
+ status: ChangeStatus;
31
+ /** Deployed contentHash (absent when added). */
32
+ before?: string;
33
+ /** Local contentHash (absent when removed). */
34
+ after?: string;
35
+ /** Workflow-level semantic fields that moved (trigger / goal / exitWhen). */
36
+ fields: ('trigger' | 'goal' | 'exitWhen')[];
37
+ /**
38
+ * Node-level detail, matched by structural-path id — so **inserting a node
39
+ * shifts the ids of its later siblings**, and one insert can report as a run
40
+ * of `changed` entries. That is the known trade-off of structural ids (see
41
+ * ir.ts): the verdict stays correct, it is just noisier than ideal.
42
+ */
43
+ nodes: NodeChange[];
44
+ }
45
+ export interface ResourceChange {
46
+ /** The resource's identity: a segment's id, a template's key, an action's name. */
47
+ id: string;
48
+ status: ChangeStatus;
49
+ before?: string;
50
+ after?: string;
51
+ }
52
+ export interface BundlePlan {
53
+ workflows: WorkflowChange[];
54
+ segments: ResourceChange[];
55
+ templates: ResourceChange[];
56
+ actions: ResourceChange[];
57
+ /** Whether any semantic change exists (metadata-only edits do not count). */
58
+ hasChanges: boolean;
59
+ }
60
+ /**
61
+ * Compute a deployment plan. Omitting `deployed` means a first deploy.
62
+ *
63
+ * const changes = plan(compileBundle({ workflows }), await fetchDeployed());
64
+ * if (changes.hasChanges) { ... }
65
+ */
66
+ export declare function plan(local: BundleIR, deployed?: BundleIR): BundlePlan;
67
+ //#endregion
68
+ //# sourceMappingURL=plan.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.cts","names":[],"sources":["../src/plan.ts"],"mappings":";;;;;;;;;;;;;;;;;YAmBY;;wBAGI,iBAAiB,QAAQ;iBAIxB;EACf;EACA;;EAEA,MAAM;;iBAGS;;EAEf;EACA,QAAQ;;EAER;;EAEA;;EAEA;;;;;;;EAOA,OAAO;;iBAGQ;;EAEf;EACA,QAAQ;EACR;EACA;;iBAGe;EACf,WAAW;EACX,UAAU;EACV,WAAW;EACX,SAAS;;EAET;;;;;;;;wBAwNc,KAAK,OAAO,UAAU,WAAW,WAAW"}
@@ -0,0 +1,68 @@
1
+ import { BundleIR, NodeIR } from "./ir.mjs";
2
+ //#region src/plan.d.ts
3
+ /**
4
+ * Plan — the diff between local definitions and what is deployed (terraform
5
+ * plan, same mental model).
6
+ *
7
+ * This is the core advantage of code-first over a UI canvas: before deploying,
8
+ * a machine can answer "what changed, and how many in-flight users does it
9
+ * affect". Pure function, zero IO — CLI, UI and CI share one verdict.
10
+ *
11
+ * Status comes from two levels of comparison:
12
+ * - contentHash differs → `changed` (semantics moved; in-flight users may need
13
+ * migration)
14
+ * - contentHash equal but full content differs → `metadata_only` (description
15
+ * or labels only, nothing about execution) — exactly what keeping metadata
16
+ * out of the hash buys us.
17
+ */
18
+ export type ChangeStatus = 'added' | 'removed' | 'changed' | 'metadata_only' | 'unchanged';
19
+ /** Whether a status warrants human attention (metadata-only edits do not). */
20
+ export declare function isSemanticChange(status: ChangeStatus): boolean;
21
+ export interface NodeChange {
22
+ id: string;
23
+ status: 'added' | 'removed' | 'changed';
24
+ /** Node type: taken from the deployed side when removed, local otherwise. */
25
+ type: NodeIR['type'];
26
+ }
27
+ export interface WorkflowChange {
28
+ /** The workflow's id. */
29
+ id: string;
30
+ status: ChangeStatus;
31
+ /** Deployed contentHash (absent when added). */
32
+ before?: string;
33
+ /** Local contentHash (absent when removed). */
34
+ after?: string;
35
+ /** Workflow-level semantic fields that moved (trigger / goal / exitWhen). */
36
+ fields: ('trigger' | 'goal' | 'exitWhen')[];
37
+ /**
38
+ * Node-level detail, matched by structural-path id — so **inserting a node
39
+ * shifts the ids of its later siblings**, and one insert can report as a run
40
+ * of `changed` entries. That is the known trade-off of structural ids (see
41
+ * ir.ts): the verdict stays correct, it is just noisier than ideal.
42
+ */
43
+ nodes: NodeChange[];
44
+ }
45
+ export interface ResourceChange {
46
+ /** The resource's identity: a segment's id, a template's key, an action's name. */
47
+ id: string;
48
+ status: ChangeStatus;
49
+ before?: string;
50
+ after?: string;
51
+ }
52
+ export interface BundlePlan {
53
+ workflows: WorkflowChange[];
54
+ segments: ResourceChange[];
55
+ templates: ResourceChange[];
56
+ actions: ResourceChange[];
57
+ /** Whether any semantic change exists (metadata-only edits do not count). */
58
+ hasChanges: boolean;
59
+ }
60
+ /**
61
+ * Compute a deployment plan. Omitting `deployed` means a first deploy.
62
+ *
63
+ * const changes = plan(compileBundle({ workflows }), await fetchDeployed());
64
+ * if (changes.hasChanges) { ... }
65
+ */
66
+ export declare function plan(local: BundleIR, deployed?: BundleIR): BundlePlan;
67
+ //#endregion
68
+ //# sourceMappingURL=plan.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.mts","names":[],"sources":["../src/plan.ts"],"mappings":";;;;;;;;;;;;;;;;;YAmBY;;wBAGI,iBAAiB,QAAQ;iBAIxB;EACf;EACA;;EAEA,MAAM;;iBAGS;;EAEf;EACA,QAAQ;;EAER;;EAEA;;EAEA;;;;;;;EAOA,OAAO;;iBAGQ;;EAEf;EACA,QAAQ;EACR;EACA;;iBAGe;EACf,WAAW;EACX,UAAU;EACV,WAAW;EACX,SAAS;;EAET;;;;;;;;wBAwNc,KAAK,OAAO,UAAU,WAAW,WAAW"}
package/dist/plan.mjs ADDED
@@ -0,0 +1,221 @@
1
+ import { fullHash, stripMeta, stripProvenance } from "./hash.mjs";
2
+ //#region src/plan.ts
3
+ /** Whether a status warrants human attention (metadata-only edits do not). */
4
+ function isSemanticChange(status) {
5
+ return status === "added" || status === "removed" || status === "changed";
6
+ }
7
+ /** Walk the node tree into a flat id → node map (branch arms, cohort arms and timeout flows included). */
8
+ function flatten(nodes, into) {
9
+ for (const node of nodes) {
10
+ into.set(node.id, node);
11
+ switch (node.type) {
12
+ case "branch":
13
+ for (const branchCase of node.cases) flatten(branchCase.flow, into);
14
+ if (node.otherwise) flatten(node.otherwise, into);
15
+ break;
16
+ case "cohort":
17
+ for (const arm of node.arms) flatten(arm.flow, into);
18
+ break;
19
+ case "wait_until": if (Array.isArray(node.onTimeout)) flatten(node.onTimeout, into);
20
+ }
21
+ }
22
+ return into;
23
+ }
24
+ /**
25
+ * A node's semantic fingerprint: metadata stripped, child flows excluded (they
26
+ * diff on their own ids). Everything else a compound node owns — branch case
27
+ * conditions, cohort arm names and weights, *having* a default arm or a
28
+ * timeout flow — is this node's semantics and stays in the fingerprint, so
29
+ * editing a branch condition or reweighting an A/B shows up on the node itself.
30
+ */
31
+ function nodeFingerprint(node) {
32
+ const bare = { ...node };
33
+ if (node.type === "branch") {
34
+ bare.cases = node.cases.map((branchCase) => ({ condition: branchCase.condition }));
35
+ delete bare.otherwise;
36
+ if (node.otherwise !== void 0) bare.otherwise = "<flow>";
37
+ }
38
+ if (node.type === "cohort") bare.arms = node.arms.map((arm) => ({
39
+ name: arm.name,
40
+ weight: arm.weight
41
+ }));
42
+ if (node.type === "wait_until" && Array.isArray(node.onTimeout)) bare.onTimeout = "<flow>";
43
+ return fullHash(stripMeta(bare));
44
+ }
45
+ function diffNodes(local, deployed) {
46
+ const localNodes = flatten(local.flow, /* @__PURE__ */ new Map());
47
+ const deployedNodes = flatten(deployed.flow, /* @__PURE__ */ new Map());
48
+ const changes = [];
49
+ for (const [id, node] of localNodes) {
50
+ const before = deployedNodes.get(id);
51
+ if (!before) changes.push({
52
+ id,
53
+ status: "added",
54
+ type: node.type
55
+ });
56
+ else if (nodeFingerprint(node) !== nodeFingerprint(before)) changes.push({
57
+ id,
58
+ status: "changed",
59
+ type: node.type
60
+ });
61
+ }
62
+ for (const [id, node] of deployedNodes) if (!localNodes.has(id)) changes.push({
63
+ id,
64
+ status: "removed",
65
+ type: node.type
66
+ });
67
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
68
+ }
69
+ function diffFields(local, deployed) {
70
+ const fields = [];
71
+ for (const field of [
72
+ "trigger",
73
+ "goal",
74
+ "exitWhen"
75
+ ]) if (fullHash(stripMeta(local[field])) !== fullHash(stripMeta(deployed[field]))) fields.push(field);
76
+ return fields;
77
+ }
78
+ function statusOf(local, deployed) {
79
+ if (local.contentHash !== deployed.contentHash) return "changed";
80
+ return fullHash(stripProvenance(local)) === fullHash(stripProvenance(deployed)) ? "unchanged" : "metadata_only";
81
+ }
82
+ function diffWorkflows(local, deployed) {
83
+ const deployedByName = new Map(deployed.map((item) => [item.id, item]));
84
+ const changes = [];
85
+ for (const item of local) {
86
+ const before = deployedByName.get(item.id);
87
+ if (!before) {
88
+ changes.push({
89
+ id: item.id,
90
+ status: "added",
91
+ after: item.contentHash,
92
+ fields: [],
93
+ nodes: []
94
+ });
95
+ continue;
96
+ }
97
+ const status = statusOf(item, before);
98
+ changes.push({
99
+ id: item.id,
100
+ status,
101
+ before: before.contentHash,
102
+ after: item.contentHash,
103
+ fields: status === "changed" ? diffFields(item, before) : [],
104
+ nodes: status === "changed" ? diffNodes(item, before) : []
105
+ });
106
+ }
107
+ const localNames = new Set(local.map((item) => item.id));
108
+ for (const item of deployed) if (!localNames.has(item.id)) changes.push({
109
+ id: item.id,
110
+ status: "removed",
111
+ before: item.contentHash,
112
+ fields: [],
113
+ nodes: []
114
+ });
115
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
116
+ }
117
+ function diffSegments(local, deployed) {
118
+ const deployedByName = new Map(deployed.map((item) => [item.id, item]));
119
+ const changes = local.map((item) => {
120
+ const before = deployedByName.get(item.id);
121
+ if (!before) return {
122
+ id: item.id,
123
+ status: "added",
124
+ after: item.contentHash
125
+ };
126
+ return {
127
+ id: item.id,
128
+ status: statusOf(item, before),
129
+ before: before.contentHash,
130
+ after: item.contentHash
131
+ };
132
+ });
133
+ const localNames = new Set(local.map((item) => item.id));
134
+ for (const item of deployed) if (!localNames.has(item.id)) changes.push({
135
+ id: item.id,
136
+ status: "removed",
137
+ before: item.contentHash
138
+ });
139
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
140
+ }
141
+ function diffTemplates(local, deployed) {
142
+ const deployedByKey = new Map(deployed.map((item) => [item.key, item]));
143
+ const changes = local.map((item) => {
144
+ const before = deployedByKey.get(item.key);
145
+ if (!before) return {
146
+ id: item.key,
147
+ status: "added"
148
+ };
149
+ return {
150
+ id: item.key,
151
+ status: before.channel === item.channel ? "unchanged" : "changed"
152
+ };
153
+ });
154
+ const localKeys = new Set(local.map((item) => item.key));
155
+ for (const item of deployed) if (!localKeys.has(item.key)) changes.push({
156
+ id: item.key,
157
+ status: "removed"
158
+ });
159
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
160
+ }
161
+ /** Actions diff on codeHash — the manifest's only semantic content (the code itself lives in the Worker bundle). */
162
+ function diffActions(local, deployed) {
163
+ const deployedByName = new Map(deployed.map((item) => [item.name, item]));
164
+ const changes = local.map((item) => {
165
+ const before = deployedByName.get(item.name);
166
+ if (!before) return {
167
+ id: item.name,
168
+ status: "added",
169
+ after: item.codeHash
170
+ };
171
+ return {
172
+ id: item.name,
173
+ status: before.codeHash === item.codeHash ? "unchanged" : "changed",
174
+ before: before.codeHash,
175
+ after: item.codeHash
176
+ };
177
+ });
178
+ const localNames = new Set(local.map((item) => item.name));
179
+ for (const item of deployed) if (!localNames.has(item.name)) changes.push({
180
+ id: item.name,
181
+ status: "removed",
182
+ before: item.codeHash
183
+ });
184
+ return changes.sort((a, b) => a.id.localeCompare(b.id));
185
+ }
186
+ /** Empty bundle: the default `deployed` on a first deploy, so everything reports as added. */
187
+ const EMPTY = {
188
+ workflows: [],
189
+ segments: [],
190
+ templates: [],
191
+ actions: []
192
+ };
193
+ /**
194
+ * Compute a deployment plan. Omitting `deployed` means a first deploy.
195
+ *
196
+ * const changes = plan(compileBundle({ workflows }), await fetchDeployed());
197
+ * if (changes.hasChanges) { ... }
198
+ */
199
+ function plan(local, deployed) {
200
+ const base = deployed ?? EMPTY;
201
+ const workflows = diffWorkflows(local.workflows, base.workflows);
202
+ const segments = diffSegments(local.segments, base.segments);
203
+ const templates = diffTemplates(local.templates, base.templates);
204
+ const actions = diffActions(local.actions, base.actions);
205
+ return {
206
+ workflows,
207
+ segments,
208
+ templates,
209
+ actions,
210
+ hasChanges: [
211
+ ...workflows,
212
+ ...segments,
213
+ ...templates,
214
+ ...actions
215
+ ].some((change) => isSemanticChange(change.status))
216
+ };
217
+ }
218
+ //#endregion
219
+ export { isSemanticChange, plan };
220
+
221
+ //# sourceMappingURL=plan.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.mjs","names":[],"sources":["../src/plan.ts"],"sourcesContent":["import { fullHash, stripMeta, stripProvenance } from './hash';\nimport type { BundleIR, NodeIR, SegmentIR, WorkflowIR } from './ir';\n\n/**\n * Plan — the diff between local definitions and what is deployed (terraform\n * plan, same mental model).\n *\n * This is the core advantage of code-first over a UI canvas: before deploying,\n * a machine can answer \"what changed, and how many in-flight users does it\n * affect\". Pure function, zero IO — CLI, UI and CI share one verdict.\n *\n * Status comes from two levels of comparison:\n * - contentHash differs → `changed` (semantics moved; in-flight users may need\n * migration)\n * - contentHash equal but full content differs → `metadata_only` (description\n * or labels only, nothing about execution) — exactly what keeping metadata\n * out of the hash buys us.\n */\n\nexport type ChangeStatus = 'added' | 'removed' | 'changed' | 'metadata_only' | 'unchanged';\n\n/** Whether a status warrants human attention (metadata-only edits do not). */\nexport function isSemanticChange(status: ChangeStatus): boolean {\n return status === 'added' || status === 'removed' || status === 'changed';\n}\n\nexport interface NodeChange {\n id: string;\n status: 'added' | 'removed' | 'changed';\n /** Node type: taken from the deployed side when removed, local otherwise. */\n type: NodeIR['type'];\n}\n\nexport interface WorkflowChange {\n /** The workflow's id. */\n id: string;\n status: ChangeStatus;\n /** Deployed contentHash (absent when added). */\n before?: string;\n /** Local contentHash (absent when removed). */\n after?: string;\n /** Workflow-level semantic fields that moved (trigger / goal / exitWhen). */\n fields: ('trigger' | 'goal' | 'exitWhen')[];\n /**\n * Node-level detail, matched by structural-path id — so **inserting a node\n * shifts the ids of its later siblings**, and one insert can report as a run\n * of `changed` entries. That is the known trade-off of structural ids (see\n * ir.ts): the verdict stays correct, it is just noisier than ideal.\n */\n nodes: NodeChange[];\n}\n\nexport interface ResourceChange {\n /** The resource's identity: a segment's id, a template's key, an action's name. */\n id: string;\n status: ChangeStatus;\n before?: string;\n after?: string;\n}\n\nexport interface BundlePlan {\n workflows: WorkflowChange[];\n segments: ResourceChange[];\n templates: ResourceChange[];\n actions: ResourceChange[];\n /** Whether any semantic change exists (metadata-only edits do not count). */\n hasChanges: boolean;\n}\n\n/** Walk the node tree into a flat id → node map (branch arms, cohort arms and timeout flows included). */\nfunction flatten(nodes: readonly NodeIR[], into: Map<string, NodeIR>): Map<string, NodeIR> {\n for (const node of nodes) {\n into.set(node.id, node);\n switch (node.type) {\n case 'branch':\n for (const branchCase of node.cases) flatten(branchCase.flow, into);\n if (node.otherwise) flatten(node.otherwise, into);\n break;\n case 'cohort':\n for (const arm of node.arms) flatten(arm.flow, into);\n break;\n case 'wait_until':\n if (Array.isArray(node.onTimeout)) flatten(node.onTimeout, into);\n break;\n default:\n break;\n }\n }\n return into;\n}\n\n/**\n * A node's semantic fingerprint: metadata stripped, child flows excluded (they\n * diff on their own ids). Everything else a compound node owns — branch case\n * conditions, cohort arm names and weights, *having* a default arm or a\n * timeout flow — is this node's semantics and stays in the fingerprint, so\n * editing a branch condition or reweighting an A/B shows up on the node itself.\n */\nfunction nodeFingerprint(node: NodeIR): string {\n const bare: Record<string, unknown> = { ...node };\n if (node.type === 'branch') {\n bare.cases = node.cases.map((branchCase) => ({ condition: branchCase.condition }));\n delete bare.otherwise;\n if (node.otherwise !== undefined) bare.otherwise = '<flow>';\n }\n if (node.type === 'cohort') {\n bare.arms = node.arms.map((arm) => ({ name: arm.name, weight: arm.weight }));\n }\n if (node.type === 'wait_until' && Array.isArray(node.onTimeout)) {\n bare.onTimeout = '<flow>';\n }\n return fullHash(stripMeta(bare));\n}\n\nfunction diffNodes(local: WorkflowIR, deployed: WorkflowIR): NodeChange[] {\n const localNodes = flatten(local.flow, new Map());\n const deployedNodes = flatten(deployed.flow, new Map());\n const changes: NodeChange[] = [];\n\n for (const [id, node] of localNodes) {\n const before = deployedNodes.get(id);\n if (!before) {\n changes.push({ id, status: 'added', type: node.type });\n } else if (nodeFingerprint(node) !== nodeFingerprint(before)) {\n changes.push({ id, status: 'changed', type: node.type });\n }\n }\n for (const [id, node] of deployedNodes) {\n if (!localNodes.has(id)) changes.push({ id, status: 'removed', type: node.type });\n }\n\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction diffFields(local: WorkflowIR, deployed: WorkflowIR): WorkflowChange['fields'] {\n const fields: WorkflowChange['fields'] = [];\n for (const field of ['trigger', 'goal', 'exitWhen'] as const) {\n if (fullHash(stripMeta(local[field])) !== fullHash(stripMeta(deployed[field]))) {\n fields.push(field);\n }\n }\n return fields;\n}\n\nfunction statusOf(local: { contentHash: string }, deployed: { contentHash: string }): ChangeStatus {\n if (local.contentHash !== deployed.contentHash) return 'changed';\n /*\n * Provenance is deliberately not part of the comparison: a recorded loc is a\n * source map, and its path depends on the machine and the directory the\n * compile ran from ('packages/workflow/src/wf.ts' from the workspace root,\n * 'src/wf.ts' from the package). Comparing it turned every CI run into a\n * wall of metadata_only against a locally compiled deploy. Descriptions,\n * labels and reasons still count — those are edits somebody made.\n */\n return fullHash(stripProvenance(local)) === fullHash(stripProvenance(deployed))\n ? 'unchanged'\n : 'metadata_only';\n}\n\nfunction diffWorkflows(\n local: readonly WorkflowIR[],\n deployed: readonly WorkflowIR[]\n): WorkflowChange[] {\n const deployedByName = new Map(deployed.map((item) => [item.id, item]));\n const changes: WorkflowChange[] = [];\n\n for (const item of local) {\n const before = deployedByName.get(item.id);\n if (!before) {\n changes.push({\n id: item.id,\n status: 'added',\n after: item.contentHash,\n fields: [],\n nodes: [],\n });\n continue;\n }\n const status = statusOf(item, before);\n changes.push({\n id: item.id,\n status,\n before: before.contentHash,\n after: item.contentHash,\n fields: status === 'changed' ? diffFields(item, before) : [],\n nodes: status === 'changed' ? diffNodes(item, before) : [],\n });\n }\n\n const localNames = new Set(local.map((item) => item.id));\n for (const item of deployed) {\n if (!localNames.has(item.id)) {\n changes.push({\n id: item.id,\n status: 'removed',\n before: item.contentHash,\n fields: [],\n nodes: [],\n });\n }\n }\n\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction diffSegments(\n local: readonly SegmentIR[],\n deployed: readonly SegmentIR[]\n): ResourceChange[] {\n const deployedByName = new Map(deployed.map((item) => [item.id, item]));\n const changes: ResourceChange[] = local.map((item) => {\n const before = deployedByName.get(item.id);\n if (!before) return { id: item.id, status: 'added' as const, after: item.contentHash };\n return {\n id: item.id,\n status: statusOf(item, before),\n before: before.contentHash,\n after: item.contentHash,\n };\n });\n\n const localNames = new Set(local.map((item) => item.id));\n for (const item of deployed) {\n if (!localNames.has(item.id)) {\n changes.push({ id: item.id, status: 'removed', before: item.contentHash });\n }\n }\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction diffTemplates(local: BundleIR['templates'], deployed: BundleIR['templates']) {\n const deployedByKey = new Map(deployed.map((item) => [item.key, item]));\n const changes: ResourceChange[] = local.map((item) => {\n const before = deployedByKey.get(item.key);\n if (!before) return { id: item.key, status: 'added' as const };\n return { id: item.key, status: before.channel === item.channel ? 'unchanged' : 'changed' };\n });\n\n const localKeys = new Set(local.map((item) => item.key));\n for (const item of deployed) {\n if (!localKeys.has(item.key)) changes.push({ id: item.key, status: 'removed' });\n }\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\n/** Actions diff on codeHash — the manifest's only semantic content (the code itself lives in the Worker bundle). */\nfunction diffActions(local: BundleIR['actions'], deployed: BundleIR['actions']) {\n const deployedByName = new Map(deployed.map((item) => [item.name, item]));\n const changes: ResourceChange[] = local.map((item) => {\n const before = deployedByName.get(item.name);\n if (!before) return { id: item.name, status: 'added' as const, after: item.codeHash };\n return {\n id: item.name,\n status: before.codeHash === item.codeHash ? ('unchanged' as const) : ('changed' as const),\n before: before.codeHash,\n after: item.codeHash,\n };\n });\n\n const localNames = new Set(local.map((item) => item.name));\n for (const item of deployed) {\n if (!localNames.has(item.name)) {\n changes.push({ id: item.name, status: 'removed', before: item.codeHash });\n }\n }\n return changes.sort((a, b) => a.id.localeCompare(b.id));\n}\n\n/** Empty bundle: the default `deployed` on a first deploy, so everything reports as added. */\nconst EMPTY: Pick<BundleIR, 'workflows' | 'segments' | 'templates' | 'actions'> = {\n workflows: [],\n segments: [],\n templates: [],\n actions: [],\n};\n\n/**\n * Compute a deployment plan. Omitting `deployed` means a first deploy.\n *\n * const changes = plan(compileBundle({ workflows }), await fetchDeployed());\n * if (changes.hasChanges) { ... }\n */\nexport function plan(local: BundleIR, deployed?: BundleIR): BundlePlan {\n const base = deployed ?? EMPTY;\n const workflows = diffWorkflows(local.workflows, base.workflows);\n const segments = diffSegments(local.segments, base.segments);\n const templates = diffTemplates(local.templates, base.templates);\n const actions = diffActions(local.actions, base.actions);\n\n const hasChanges = [...workflows, ...segments, ...templates, ...actions].some((change) =>\n isSemanticChange(change.status)\n );\n\n return { workflows, segments, templates, actions, hasChanges };\n}\n"],"mappings":"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"}