@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,63 @@
1
+ import { MessageSender, OutboundMessage, SendResult } from "./engine/ports.cjs";
2
+ import "./engine/index.cjs";
3
+ import { PushRenderer } from "./push.cjs";
4
+ //#region src/apns.d.ts
5
+ /**
6
+ * `@shware/workflow/apns` — iOS push delivery straight to the Apple Push
7
+ * Notification service, token-based (an APNs auth key, the `.p8` file from the
8
+ * developer portal). No Firebase in between: the app registers the APNs device
9
+ * token in its own device table, and the host's DeviceDirectory hands it to the
10
+ * engine, which sends one message per device.
11
+ * No dependencies: the provider JWT is ES256-signed with WebCrypto.
12
+ *
13
+ * APNs speaks HTTP/2 only. A deployed Worker's `fetch` negotiates it, but
14
+ * workerd under `wrangler dev` does not (the connection is dropped), so a local
15
+ * host points `origin` at the Node relay in `@shware/workflow/apns-relay`.
16
+ */
17
+ export interface ApnsPushOptions {
18
+ /** The key's 10-character id, shown next to it in the developer portal. */
19
+ keyId: string;
20
+ /** The Apple Developer team id. */
21
+ teamId: string;
22
+ /** The `.p8` file's contents: PEM, `-----BEGIN PRIVATE KEY-----` (PKCS #8, P-256). */
23
+ privateKey: string;
24
+ /** The app's bundle id — APNs's `apns-topic`. */
25
+ topic: string;
26
+ /**
27
+ * Which APNs environment the device tokens come from: `sandbox` for builds
28
+ * signed with `aps-environment: development` (Xcode, the simulator),
29
+ * `production` for App Store and TestFlight builds. A token from one is
30
+ * `BadDeviceToken` on the other.
31
+ */
32
+ environment: 'sandbox' | 'production';
33
+ render: PushRenderer;
34
+ /**
35
+ * POST here instead of Apple's host — the dev relay, which forwards over
36
+ * HTTP/2. The real host still travels along (`apns-relay-upstream`), so the
37
+ * relay needs no configuration of its own.
38
+ */
39
+ origin?: string;
40
+ /** Fetch implementation (defaults to the global one). */
41
+ fetch?: typeof fetch;
42
+ /** Called for a token APNs reports as gone (`Unregistered`, `BadDeviceToken`); `channelsFromConfig` passes it on to the DeviceDirectory's `disable`. */
43
+ onUnregistered?: (message: OutboundMessage) => Promise<void> | void;
44
+ }
45
+ export declare const APNS_HOSTS: {
46
+ readonly sandbox: 'https://api.sandbox.push.apple.com';
47
+ readonly production: 'https://api.push.apple.com';
48
+ };
49
+ export declare class ApnsPushSender implements MessageSender {
50
+ private readonly options;
51
+ private token;
52
+ constructor(options: ApnsPushOptions);
53
+ send(message: OutboundMessage): Promise<void | SendResult>;
54
+ private providerToken;
55
+ }
56
+ /** APNs error bodies are `{ "reason": "…" }`. */
57
+ export declare function apnsReason(body: string): string;
58
+ /** ES256-sign the APNs provider token: header `kid`, claims `iss` (team) and `iat`. */
59
+ export declare function signApnsJwt(key: Pick<ApnsPushOptions, 'keyId' | 'teamId' | 'privateKey'>, nowMs?: number): Promise<string>;
60
+ /** The `.p8` as it is usually shipped in a secret: base64 of the file. */
61
+ export declare function apnsKeyFromBase64(value: string): string;
62
+ //#endregion
63
+ //# sourceMappingURL=apns.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apns.d.cts","names":[],"sources":["../src/apns.ts"],"mappings":";;;;;;;;;;;;;;;;iBAiBiB;;EAEf;;EAEA;;EAEA;;EAEA;;;;;;;EAOA;EACA,QAAQ;;;;;;EAMR;;EAEA,eAAe;;EAEf,kBAAkB,SAAS,oBAAoB;;qBAGpC;WACX;WACA;;qBAcW,0BAA0B;mBAGR;UAFrB;EAER,YAA6B,SAAS;EAEhC,KAAK,SAAS,kBAAkB,eAAe;UAsDvC;;;wBAYA,WAAW;;wBAUL,YACpB,KAAK,KAAK,qDACV,iBACC;;wBAoBa,kBAAkB"}
@@ -0,0 +1,63 @@
1
+ import { MessageSender, OutboundMessage, SendResult } from "./engine/ports.mjs";
2
+ import "./engine/index.mjs";
3
+ import { PushRenderer } from "./push.mjs";
4
+ //#region src/apns.d.ts
5
+ /**
6
+ * `@shware/workflow/apns` — iOS push delivery straight to the Apple Push
7
+ * Notification service, token-based (an APNs auth key, the `.p8` file from the
8
+ * developer portal). No Firebase in between: the app registers the APNs device
9
+ * token in its own device table, and the host's DeviceDirectory hands it to the
10
+ * engine, which sends one message per device.
11
+ * No dependencies: the provider JWT is ES256-signed with WebCrypto.
12
+ *
13
+ * APNs speaks HTTP/2 only. A deployed Worker's `fetch` negotiates it, but
14
+ * workerd under `wrangler dev` does not (the connection is dropped), so a local
15
+ * host points `origin` at the Node relay in `@shware/workflow/apns-relay`.
16
+ */
17
+ export interface ApnsPushOptions {
18
+ /** The key's 10-character id, shown next to it in the developer portal. */
19
+ keyId: string;
20
+ /** The Apple Developer team id. */
21
+ teamId: string;
22
+ /** The `.p8` file's contents: PEM, `-----BEGIN PRIVATE KEY-----` (PKCS #8, P-256). */
23
+ privateKey: string;
24
+ /** The app's bundle id — APNs's `apns-topic`. */
25
+ topic: string;
26
+ /**
27
+ * Which APNs environment the device tokens come from: `sandbox` for builds
28
+ * signed with `aps-environment: development` (Xcode, the simulator),
29
+ * `production` for App Store and TestFlight builds. A token from one is
30
+ * `BadDeviceToken` on the other.
31
+ */
32
+ environment: 'sandbox' | 'production';
33
+ render: PushRenderer;
34
+ /**
35
+ * POST here instead of Apple's host — the dev relay, which forwards over
36
+ * HTTP/2. The real host still travels along (`apns-relay-upstream`), so the
37
+ * relay needs no configuration of its own.
38
+ */
39
+ origin?: string;
40
+ /** Fetch implementation (defaults to the global one). */
41
+ fetch?: typeof fetch;
42
+ /** Called for a token APNs reports as gone (`Unregistered`, `BadDeviceToken`); `channelsFromConfig` passes it on to the DeviceDirectory's `disable`. */
43
+ onUnregistered?: (message: OutboundMessage) => Promise<void> | void;
44
+ }
45
+ export declare const APNS_HOSTS: {
46
+ readonly sandbox: 'https://api.sandbox.push.apple.com';
47
+ readonly production: 'https://api.push.apple.com';
48
+ };
49
+ export declare class ApnsPushSender implements MessageSender {
50
+ private readonly options;
51
+ private token;
52
+ constructor(options: ApnsPushOptions);
53
+ send(message: OutboundMessage): Promise<void | SendResult>;
54
+ private providerToken;
55
+ }
56
+ /** APNs error bodies are `{ "reason": "…" }`. */
57
+ export declare function apnsReason(body: string): string;
58
+ /** ES256-sign the APNs provider token: header `kid`, claims `iss` (team) and `iat`. */
59
+ export declare function signApnsJwt(key: Pick<ApnsPushOptions, 'keyId' | 'teamId' | 'privateKey'>, nowMs?: number): Promise<string>;
60
+ /** The `.p8` as it is usually shipped in a secret: base64 of the file. */
61
+ export declare function apnsKeyFromBase64(value: string): string;
62
+ //#endregion
63
+ //# sourceMappingURL=apns.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apns.d.mts","names":[],"sources":["../src/apns.ts"],"mappings":";;;;;;;;;;;;;;;;iBAiBiB;;EAEf;;EAEA;;EAEA;;EAEA;;;;;;;EAOA;EACA,QAAQ;;;;;;EAMR;;EAEA,eAAe;;EAEf,kBAAkB,SAAS,oBAAoB;;qBAGpC;WACX;WACA;;qBAcW,0BAA0B;mBAGR;UAFrB;EAER,YAA6B,SAAS;EAEhC,KAAK,SAAS,kBAAkB,eAAe;UAsDvC;;;wBAYA,WAAW;;wBAUL,YACpB,KAAK,KAAK,qDACV,iBACC;;wBAoBa,kBAAkB"}
package/dist/apns.mjs ADDED
@@ -0,0 +1,116 @@
1
+ import { base64url, pemToDer } from "./jwt.mjs";
2
+ //#region src/apns.ts
3
+ const APNS_HOSTS = {
4
+ sandbox: "https://api.sandbox.push.apple.com",
5
+ production: "https://api.push.apple.com"
6
+ };
7
+ /** Reasons APNs gives for a token that will never deliver again — not worth a retry. */
8
+ const DEAD_TOKEN_REASONS = /* @__PURE__ */ new Set([
9
+ "Unregistered",
10
+ "BadDeviceToken",
11
+ "DeviceTokenNotForTopic",
12
+ "ExpiredToken"
13
+ ]);
14
+ /** Apple: reuse a provider token for at least 20 minutes, never past 60. */
15
+ const TOKEN_TTL_MS = 3e6;
16
+ var ApnsPushSender = class {
17
+ options;
18
+ token;
19
+ constructor(options) {
20
+ this.options = options;
21
+ }
22
+ async send(message) {
23
+ if (message.channel !== "push") throw new Error(`ApnsPushSender: unsupported channel '${message.channel}'`);
24
+ if (message.recipient === void 0) throw new Error(`ApnsPushSender: no push token for user '${message.userId}'`);
25
+ const { title, body, image, url } = await this.options.render(message.template, message.props);
26
+ const mutable = image !== void 0 || message.tracking?.data?.delivered_url !== void 0;
27
+ const upstream = APNS_HOSTS[this.options.environment];
28
+ const origin = this.options.origin ?? upstream;
29
+ const response = await (this.options.fetch ?? fetch)(`${origin}/3/device/${message.recipient}`, {
30
+ method: "POST",
31
+ headers: {
32
+ authorization: `bearer ${await this.providerToken()}`,
33
+ "apns-topic": this.options.topic,
34
+ "apns-push-type": "alert",
35
+ "apns-priority": "10",
36
+ "content-type": "application/json",
37
+ ...this.options.origin === void 0 ? {} : { "apns-relay-upstream": upstream }
38
+ },
39
+ body: JSON.stringify({
40
+ aps: {
41
+ alert: {
42
+ title,
43
+ body
44
+ },
45
+ sound: "default",
46
+ ...mutable ? { "mutable-content": 1 } : {}
47
+ },
48
+ template: message.template,
49
+ idempotencyKey: message.idempotencyKey,
50
+ ...image === void 0 ? {} : { image },
51
+ ...url === void 0 ? {} : { url },
52
+ ...message.tracking?.data
53
+ })
54
+ });
55
+ if (response.ok) return;
56
+ const text = await response.text();
57
+ const reason = apnsReason(text);
58
+ if (response.status === 410 || DEAD_TOKEN_REASONS.has(reason)) {
59
+ console.warn(`[apns] token gone for user ${message.userId}: ${reason || response.status}`);
60
+ await this.options.onUnregistered?.(message);
61
+ return {
62
+ delivered: false,
63
+ reason: reason || `HTTP ${response.status}`
64
+ };
65
+ }
66
+ throw new Error(`APNs send failed: ${response.status} ${text}`);
67
+ }
68
+ async providerToken() {
69
+ const now = Date.now();
70
+ if (this.token !== void 0 && now - this.token.issuedAt < TOKEN_TTL_MS) return this.token.value;
71
+ const value = await signApnsJwt(this.options, now);
72
+ this.token = {
73
+ value,
74
+ issuedAt: now
75
+ };
76
+ return value;
77
+ }
78
+ };
79
+ /** APNs error bodies are `{ "reason": "…" }`. */
80
+ function apnsReason(body) {
81
+ try {
82
+ return JSON.parse(body).reason ?? "";
83
+ } catch {
84
+ return "";
85
+ }
86
+ }
87
+ /** ES256-sign the APNs provider token: header `kid`, claims `iss` (team) and `iat`. */
88
+ async function signApnsJwt(key, nowMs = Date.now()) {
89
+ const header = base64url(JSON.stringify({
90
+ alg: "ES256",
91
+ kid: key.keyId
92
+ }));
93
+ const claims = base64url(JSON.stringify({
94
+ iss: key.teamId,
95
+ iat: Math.floor(nowMs / 1e3)
96
+ }));
97
+ const cryptoKey = await crypto.subtle.importKey("pkcs8", pemToDer(key.privateKey), {
98
+ name: "ECDSA",
99
+ namedCurve: "P-256"
100
+ }, false, ["sign"]);
101
+ const signature = await crypto.subtle.sign({
102
+ name: "ECDSA",
103
+ hash: "SHA-256"
104
+ }, cryptoKey, new TextEncoder().encode(`${header}.${claims}`));
105
+ return `${header}.${claims}.${base64url(new Uint8Array(signature))}`;
106
+ }
107
+ /** The `.p8` as it is usually shipped in a secret: base64 of the file. */
108
+ function apnsKeyFromBase64(value) {
109
+ const pem = atob(value);
110
+ if (!pem.includes("-----BEGIN PRIVATE KEY-----")) throw new Error("APNs key is not a PKCS #8 PEM (.p8) file");
111
+ return pem;
112
+ }
113
+ //#endregion
114
+ export { APNS_HOSTS, ApnsPushSender, apnsKeyFromBase64, apnsReason, signApnsJwt };
115
+
116
+ //# sourceMappingURL=apns.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apns.mjs","names":[],"sources":["../src/apns.ts"],"sourcesContent":["import type { MessageSender, OutboundMessage, SendResult } from './engine';\nimport { base64url, pemToDer } from './jwt';\nimport type { PushRenderer } from './push';\n\n/**\n * `@shware/workflow/apns` — iOS push delivery straight to the Apple Push\n * Notification service, token-based (an APNs auth key, the `.p8` file from the\n * developer portal). No Firebase in between: the app registers the APNs device\n * token in its own device table, and the host's DeviceDirectory hands it to the\n * engine, which sends one message per device.\n * No dependencies: the provider JWT is ES256-signed with WebCrypto.\n *\n * APNs speaks HTTP/2 only. A deployed Worker's `fetch` negotiates it, but\n * workerd under `wrangler dev` does not (the connection is dropped), so a local\n * host points `origin` at the Node relay in `@shware/workflow/apns-relay`.\n */\n\nexport interface ApnsPushOptions {\n /** The key's 10-character id, shown next to it in the developer portal. */\n keyId: string;\n /** The Apple Developer team id. */\n teamId: string;\n /** The `.p8` file's contents: PEM, `-----BEGIN PRIVATE KEY-----` (PKCS #8, P-256). */\n privateKey: string;\n /** The app's bundle id — APNs's `apns-topic`. */\n topic: string;\n /**\n * Which APNs environment the device tokens come from: `sandbox` for builds\n * signed with `aps-environment: development` (Xcode, the simulator),\n * `production` for App Store and TestFlight builds. A token from one is\n * `BadDeviceToken` on the other.\n */\n environment: 'sandbox' | 'production';\n render: PushRenderer;\n /**\n * POST here instead of Apple's host — the dev relay, which forwards over\n * HTTP/2. The real host still travels along (`apns-relay-upstream`), so the\n * relay needs no configuration of its own.\n */\n origin?: string;\n /** Fetch implementation (defaults to the global one). */\n fetch?: typeof fetch;\n /** Called for a token APNs reports as gone (`Unregistered`, `BadDeviceToken`); `channelsFromConfig` passes it on to the DeviceDirectory's `disable`. */\n onUnregistered?: (message: OutboundMessage) => Promise<void> | void;\n}\n\nexport const APNS_HOSTS = {\n sandbox: 'https://api.sandbox.push.apple.com',\n production: 'https://api.push.apple.com',\n} as const;\n\n/** Reasons APNs gives for a token that will never deliver again — not worth a retry. */\nconst DEAD_TOKEN_REASONS = new Set([\n 'Unregistered',\n 'BadDeviceToken',\n 'DeviceTokenNotForTopic',\n 'ExpiredToken',\n]);\n\n/** Apple: reuse a provider token for at least 20 minutes, never past 60. */\nconst TOKEN_TTL_MS = 50 * 60_000;\n\nexport class ApnsPushSender implements MessageSender {\n private token: { value: string; issuedAt: number } | undefined;\n\n constructor(private readonly options: ApnsPushOptions) {}\n\n async send(message: OutboundMessage): Promise<void | SendResult> {\n if (message.channel !== 'push') {\n throw new Error(`ApnsPushSender: unsupported channel '${message.channel}'`);\n }\n if (message.recipient === undefined) {\n throw new Error(`ApnsPushSender: no push token for user '${message.userId}'`);\n }\n const { title, body, image, url } = await this.options.render(message.template, message.props);\n // A notification service extension runs only for a mutable push: it attaches the image and\n // reports the device delivery (`delivered_url`)\n const mutable = image !== undefined || message.tracking?.data?.delivered_url !== undefined;\n const upstream = APNS_HOSTS[this.options.environment];\n const origin = this.options.origin ?? upstream;\n const doFetch = this.options.fetch ?? fetch;\n\n const response = await doFetch(`${origin}/3/device/${message.recipient}`, {\n method: 'POST',\n headers: {\n authorization: `bearer ${await this.providerToken()}`,\n 'apns-topic': this.options.topic,\n 'apns-push-type': 'alert',\n 'apns-priority': '10',\n 'content-type': 'application/json',\n ...(this.options.origin === undefined ? {} : { 'apns-relay-upstream': upstream }),\n },\n body: JSON.stringify({\n aps: {\n alert: { title, body },\n sound: 'default',\n ...(mutable ? { 'mutable-content': 1 } : {}),\n },\n // The template key travels so the app can route a tap; the idempotency\n // key lets the app de-duplicate a redelivered push.\n template: message.template,\n idempotencyKey: message.idempotencyKey,\n ...(image === undefined ? {} : { image }),\n ...(url === undefined ? {} : { url }),\n ...message.tracking?.data,\n }),\n });\n if (response.ok) return;\n\n const text = await response.text();\n const reason = apnsReason(text);\n if (response.status === 410 || DEAD_TOKEN_REASONS.has(reason)) {\n // A dead token is a fact about the recipient, not a transient failure:\n // report it and move on, so the step does not retry into the same wall.\n console.warn(`[apns] token gone for user ${message.userId}: ${reason || response.status}`);\n await this.options.onUnregistered?.(message);\n return { delivered: false, reason: reason || `HTTP ${response.status}` };\n }\n throw new Error(`APNs send failed: ${response.status} ${text}`);\n }\n\n private async providerToken(): Promise<string> {\n const now = Date.now();\n if (this.token !== undefined && now - this.token.issuedAt < TOKEN_TTL_MS) {\n return this.token.value;\n }\n const value = await signApnsJwt(this.options, now);\n this.token = { value, issuedAt: now };\n return value;\n }\n}\n\n/** APNs error bodies are `{ \"reason\": \"…\" }`. */\nexport function apnsReason(body: string): string {\n try {\n const parsed = JSON.parse(body) as { reason?: string };\n return parsed.reason ?? '';\n } catch {\n return '';\n }\n}\n\n/** ES256-sign the APNs provider token: header `kid`, claims `iss` (team) and `iat`. */\nexport async function signApnsJwt(\n key: Pick<ApnsPushOptions, 'keyId' | 'teamId' | 'privateKey'>,\n nowMs = Date.now()\n): Promise<string> {\n const header = base64url(JSON.stringify({ alg: 'ES256', kid: key.keyId }));\n const claims = base64url(JSON.stringify({ iss: key.teamId, iat: Math.floor(nowMs / 1000) }));\n const cryptoKey = await crypto.subtle.importKey(\n 'pkcs8',\n pemToDer(key.privateKey),\n { name: 'ECDSA', namedCurve: 'P-256' },\n false,\n ['sign']\n );\n // WebCrypto's ECDSA signature is the raw r‖s pair, which is exactly JWS's ES256 encoding.\n const signature = await crypto.subtle.sign(\n { name: 'ECDSA', hash: 'SHA-256' },\n cryptoKey,\n new TextEncoder().encode(`${header}.${claims}`)\n );\n return `${header}.${claims}.${base64url(new Uint8Array(signature))}`;\n}\n\n/** The `.p8` as it is usually shipped in a secret: base64 of the file. */\nexport function apnsKeyFromBase64(value: string): string {\n const pem = atob(value);\n if (!pem.includes('-----BEGIN PRIVATE KEY-----')) {\n throw new Error('APNs key is not a PKCS #8 PEM (.p8) file');\n }\n return pem;\n}\n"],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/client.ts
3
+ var JourneyClientError = class extends Error {
4
+ path;
5
+ status;
6
+ body;
7
+ constructor(path, status, body) {
8
+ super(`journey ${path} failed: ${status} ${body}`);
9
+ this.path = path;
10
+ this.status = status;
11
+ this.body = body;
12
+ this.name = "JourneyClientError";
13
+ }
14
+ };
15
+ /** A payload or profile patch the contract refuses — raised before the request, with the field paths. */
16
+ var JourneyValidationError = class extends Error {
17
+ path;
18
+ event;
19
+ issues;
20
+ constructor(path, event, issues) {
21
+ super(`journey ${path}${event === void 0 ? "" : ` '${event}'`} refused by the contract: ${issues.map((i) => `${i.path || "(root)"} ${i.message}`).join("; ")}`);
22
+ this.path = path;
23
+ this.event = event;
24
+ this.issues = issues;
25
+ this.name = "JourneyValidationError";
26
+ }
27
+ };
28
+ var JourneyClient = class {
29
+ options;
30
+ constructor(options) {
31
+ this.options = options;
32
+ }
33
+ /** Merge profile properties (`null` clears one). Every property a journey reads must be identified before the event that starts it. */
34
+ identify(userId, props) {
35
+ const contract = this.options.contract;
36
+ if (contract !== void 0) {
37
+ const result = contract.parseProfilePatch(props);
38
+ if (!result.ok) return Promise.reject(new JourneyValidationError("/identify", void 0, result.issues));
39
+ }
40
+ return this.post("/identify", {
41
+ userId,
42
+ props
43
+ });
44
+ }
45
+ /**
46
+ * Record an event; the Worker starts every journey whose trigger matches it
47
+ * and wakes waits on it. A caller that retries should pass the same `id`
48
+ * each time: the Worker stores one occurrence per id, so a retry after a
49
+ * timeout cannot double-count the event. `ts` defaults to the Worker's clock.
50
+ */
51
+ track(userId, event, ...args) {
52
+ const [payload = {}, options = {}] = args;
53
+ const contract = this.options.contract;
54
+ if (contract !== void 0) {
55
+ const result = contract.parseEvent(event, payload);
56
+ if (!result.ok) return Promise.reject(new JourneyValidationError("/events", event, result.issues));
57
+ }
58
+ return this.post("/events", {
59
+ userId,
60
+ event,
61
+ payload,
62
+ ...options.id === void 0 ? {} : { id: options.id },
63
+ ...options.ts === void 0 ? {} : { ts: options.ts }
64
+ });
65
+ }
66
+ /**
67
+ * A push token the app registered for the user (call it on every registration: a token moves
68
+ * to the latest user). The engine keeps devices itself — pushes go to them, a token APNs / FCM
69
+ * reports as gone is dropped — and journeys waiting on `reachable('push')` wake.
70
+ */
71
+ registerDevice(userId, device) {
72
+ return this.post("/devices", {
73
+ userId,
74
+ ...device
75
+ });
76
+ }
77
+ /**
78
+ * A journey push tapped open: the `message_id` the push carried, reported for the user who
79
+ * tapped it. Recorded as a human open on the copy (an email's opens are tracked by the Worker).
80
+ */
81
+ messageOpened(userId, messageId) {
82
+ return this.post("/messages/opened", {
83
+ userId,
84
+ messageId
85
+ });
86
+ }
87
+ /**
88
+ * A deleted account: the engine records the erasure, stops the user's running journeys, then
89
+ * erases everything it keeps about them (profile, devices, events, reporting). Once this
90
+ * resolves the request is durable: `erased: false` means an instance would not stop yet, and
91
+ * the Worker's scheduled sweep finishes the job.
92
+ */
93
+ forgetUser(userId) {
94
+ return this.post("/users/forget", { userId });
95
+ }
96
+ /** The user signed out on that device: the token stays registered, bound to nobody. */
97
+ unbindDevice(token) {
98
+ return this.post("/devices/unbind", { token });
99
+ }
100
+ /** Forget a push token for good (an uninstall the app learned of, a token it replaced). */
101
+ removeDevice(token) {
102
+ return this.post("/devices/remove", { token });
103
+ }
104
+ /** Deploy a compiled bundle (BundleIR). */
105
+ deploy(bundle) {
106
+ return this.post("/deploy", bundle);
107
+ }
108
+ async post(path, body) {
109
+ const headers = { "content-type": "application/json" };
110
+ if (this.options.token !== void 0) headers.authorization = `Bearer ${this.options.token}`;
111
+ const response = await (this.options.fetch ?? fetch)(`${this.options.origin.replace(/\/$/, "")}${path}`, {
112
+ method: "POST",
113
+ headers,
114
+ body: JSON.stringify(body)
115
+ });
116
+ if (!response.ok) throw new JourneyClientError(path, response.status, await response.text());
117
+ return await response.json();
118
+ }
119
+ };
120
+ //#endregion
121
+ exports.JourneyClient = JourneyClient;
122
+ exports.JourneyClientError = JourneyClientError;
123
+ exports.JourneyValidationError = JourneyValidationError;
124
+
125
+ //# sourceMappingURL=client.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.cjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type * as core from 'zod/v4/core';\nimport type { DeployResult, IdentifyResult, IngestResult } from './cloudflare';\nimport type { Contract, ContractIssue, ProfilePatch } from './contract';\nimport type { ProfileProps } from './store';\n\n/**\n * `@shware/workflow/client` — the producer side of the ingest API, for the\n * service that knows what users do (an api server, a webhook handler). Plain\n * fetch, no dependencies; errors carry the status and body so a caller can\n * log them without failing the request that triggered the report.\n */\n\nexport interface JourneyClientOptions<C extends Contract | undefined = undefined> {\n /**\n * The shared `defineContract(...)`: types `track` (the event name picks the\n * payload type) and `identify`, and checks both before anything is sent.\n */\n contract?: C;\n /** The journey Worker's origin, e.g. `https://workflow.example.com`. */\n origin: string;\n /** Its API_TOKEN, sent as a bearer; omit against an open local instance. */\n token?: string;\n /** Fetch implementation (defaults to the global one). */\n fetch?: typeof fetch;\n}\n\nexport class JourneyClientError extends Error {\n constructor(\n readonly path: string,\n readonly status: number,\n readonly body: string\n ) {\n super(`journey ${path} failed: ${status} ${body}`);\n this.name = 'JourneyClientError';\n }\n}\n\n/** A payload or profile patch the contract refuses — raised before the request, with the field paths. */\nexport class JourneyValidationError extends Error {\n constructor(\n readonly path: string,\n readonly event: string | undefined,\n readonly issues: ContractIssue[]\n ) {\n super(\n `journey ${path}${event === undefined ? '' : ` '${event}'`} refused by the contract: ${issues\n .map((i) => `${i.path || '(root)'} ${i.message}`)\n .join('; ')}`\n );\n this.name = 'JourneyValidationError';\n }\n}\n\ntype EventsOf<C> = C extends Contract<infer E> ? E : never;\n/** Event names: the contract's, or any string without one. */\nexport type ClientEventName<C> = [C] extends [undefined] ? string : keyof EventsOf<C> & string;\ntype TrackArgs<C, K> = [C] extends [undefined]\n ? [payload?: Record<string, unknown>, options?: TrackOptions]\n : K extends keyof EventsOf<C>\n ? [payload: core.input<EventsOf<C>[K]>, options?: TrackOptions]\n : never;\ntype IdentifyProps<C> = [C] extends [undefined]\n ? ProfileProps\n : C extends Contract<Record<string, core.$ZodObject>, infer P>\n ? ProfilePatch<P>\n : never;\n\nexport interface TrackOptions {\n /** The occurrence's identity: a retry with the same id is recorded once. */\n id?: string;\n /** When it happened (epoch ms); the Worker's clock when omitted. */\n ts?: number;\n}\n\nexport class JourneyClient<C extends Contract | undefined = undefined> {\n constructor(private readonly options: JourneyClientOptions<C>) {}\n\n /** Merge profile properties (`null` clears one). Every property a journey reads must be identified before the event that starts it. */\n identify(userId: string, props: IdentifyProps<C>): Promise<IdentifyResult> {\n const contract = this.options.contract;\n if (contract !== undefined) {\n const result = contract.parseProfilePatch(props);\n if (!result.ok)\n return Promise.reject(new JourneyValidationError('/identify', undefined, result.issues));\n }\n return this.post<IdentifyResult>('/identify', { userId, props });\n }\n\n /**\n * Record an event; the Worker starts every journey whose trigger matches it\n * and wakes waits on it. A caller that retries should pass the same `id`\n * each time: the Worker stores one occurrence per id, so a retry after a\n * timeout cannot double-count the event. `ts` defaults to the Worker's clock.\n */\n track<K extends ClientEventName<C>>(\n userId: string,\n event: K,\n ...args: TrackArgs<C, K>\n ): Promise<IngestResult> {\n const [payload = {}, options = {}] = args as [Record<string, unknown>?, TrackOptions?];\n const contract = this.options.contract;\n if (contract !== undefined) {\n const result = contract.parseEvent(event, payload);\n if (!result.ok)\n return Promise.reject(new JourneyValidationError('/events', event, result.issues));\n }\n return this.post<IngestResult>('/events', {\n userId,\n event,\n payload,\n ...(options.id === undefined ? {} : { id: options.id }),\n ...(options.ts === undefined ? {} : { ts: options.ts }),\n });\n }\n\n /**\n * A push token the app registered for the user (call it on every registration: a token moves\n * to the latest user). The engine keeps devices itself — pushes go to them, a token APNs / FCM\n * reports as gone is dropped — and journeys waiting on `reachable('push')` wake.\n */\n registerDevice(\n userId: string,\n device: { token: string; platform: 'ios' | 'android' | 'web' }\n ): Promise<{ ok: true; woke: number }> {\n return this.post('/devices', { userId, ...device });\n }\n\n /**\n * A journey push tapped open: the `message_id` the push carried, reported for the user who\n * tapped it. Recorded as a human open on the copy (an email's opens are tracked by the Worker).\n */\n messageOpened(userId: string, messageId: string): Promise<{ ok: true; recorded: boolean }> {\n return this.post('/messages/opened', { userId, messageId });\n }\n\n /**\n * A deleted account: the engine records the erasure, stops the user's running journeys, then\n * erases everything it keeps about them (profile, devices, events, reporting). Once this\n * resolves the request is durable: `erased: false` means an instance would not stop yet, and\n * the Worker's scheduled sweep finishes the job.\n */\n forgetUser(userId: string): Promise<{ ok: true; erased: boolean; pending: string[] }> {\n return this.post('/users/forget', { userId });\n }\n\n /** The user signed out on that device: the token stays registered, bound to nobody. */\n unbindDevice(token: string): Promise<{ ok: true; woke: number }> {\n return this.post('/devices/unbind', { token });\n }\n\n /** Forget a push token for good (an uninstall the app learned of, a token it replaced). */\n removeDevice(token: string): Promise<{ ok: true; woke: number }> {\n return this.post('/devices/remove', { token });\n }\n\n /** Deploy a compiled bundle (BundleIR). */\n deploy(bundle: unknown): Promise<DeployResult> {\n return this.post<DeployResult>('/deploy', bundle);\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const headers: Record<string, string> = { 'content-type': 'application/json' };\n if (this.options.token !== undefined) headers.authorization = `Bearer ${this.options.token}`;\n const doFetch = this.options.fetch ?? fetch;\n const response = await doFetch(`${this.options.origin.replace(/\\/$/, '')}${path}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n if (!response.ok) throw new JourneyClientError(path, response.status, await response.text());\n return (await response.json()) as T;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import { Contract, ContractIssue, ProfilePatch } from "./contract.cjs";
2
+ import { ProfileProps } from "./store/index.cjs";
3
+ import { DeployResult, IdentifyResult, IngestResult } from "./cloudflare/router.cjs";
4
+ import "./cloudflare/index.cjs";
5
+ import * as core from "zod/v4/core";
6
+ //#region src/client.d.ts
7
+ /**
8
+ * `@shware/workflow/client` — the producer side of the ingest API, for the
9
+ * service that knows what users do (an api server, a webhook handler). Plain
10
+ * fetch, no dependencies; errors carry the status and body so a caller can
11
+ * log them without failing the request that triggered the report.
12
+ */
13
+ export interface JourneyClientOptions<C extends Contract | undefined = undefined> {
14
+ /**
15
+ * The shared `defineContract(...)`: types `track` (the event name picks the
16
+ * payload type) and `identify`, and checks both before anything is sent.
17
+ */
18
+ contract?: C;
19
+ /** The journey Worker's origin, e.g. `https://workflow.example.com`. */
20
+ origin: string;
21
+ /** Its API_TOKEN, sent as a bearer; omit against an open local instance. */
22
+ token?: string;
23
+ /** Fetch implementation (defaults to the global one). */
24
+ fetch?: typeof fetch;
25
+ }
26
+ export declare class JourneyClientError extends Error {
27
+ readonly path: string;
28
+ readonly status: number;
29
+ readonly body: string;
30
+ constructor(path: string, status: number, body: string);
31
+ }
32
+ /** A payload or profile patch the contract refuses — raised before the request, with the field paths. */
33
+ export declare class JourneyValidationError extends Error {
34
+ readonly path: string;
35
+ readonly event: string | undefined;
36
+ readonly issues: ContractIssue[];
37
+ constructor(path: string, event: string | undefined, issues: ContractIssue[]);
38
+ }
39
+ type EventsOf<C> = C extends Contract<infer E> ? E : never;
40
+ /** Event names: the contract's, or any string without one. */
41
+ export type ClientEventName<C> = [C] extends [undefined] ? string : keyof EventsOf<C> & string;
42
+ type TrackArgs<C, K> = [C] extends [undefined] ? [payload?: Record<string, unknown>, options?: TrackOptions] : K extends keyof EventsOf<C> ? [payload: core.input<EventsOf<C>[K]>, options?: TrackOptions] : never;
43
+ type IdentifyProps<C> = [C] extends [undefined] ? ProfileProps : C extends Contract<Record<string, core.$ZodObject>, infer P> ? ProfilePatch<P> : never;
44
+ export interface TrackOptions {
45
+ /** The occurrence's identity: a retry with the same id is recorded once. */
46
+ id?: string;
47
+ /** When it happened (epoch ms); the Worker's clock when omitted. */
48
+ ts?: number;
49
+ }
50
+ export declare class JourneyClient<C extends Contract | undefined = undefined> {
51
+ private readonly options;
52
+ constructor(options: JourneyClientOptions<C>);
53
+ /** Merge profile properties (`null` clears one). Every property a journey reads must be identified before the event that starts it. */
54
+ identify(userId: string, props: IdentifyProps<C>): Promise<IdentifyResult>;
55
+ /**
56
+ * Record an event; the Worker starts every journey whose trigger matches it
57
+ * and wakes waits on it. A caller that retries should pass the same `id`
58
+ * each time: the Worker stores one occurrence per id, so a retry after a
59
+ * timeout cannot double-count the event. `ts` defaults to the Worker's clock.
60
+ */
61
+ track<K extends ClientEventName<C>>(userId: string, event: K, ...args: TrackArgs<C, K>): Promise<IngestResult>;
62
+ /**
63
+ * A push token the app registered for the user (call it on every registration: a token moves
64
+ * to the latest user). The engine keeps devices itself — pushes go to them, a token APNs / FCM
65
+ * reports as gone is dropped — and journeys waiting on `reachable('push')` wake.
66
+ */
67
+ registerDevice(userId: string, device: {
68
+ token: string;
69
+ platform: 'ios' | 'android' | 'web';
70
+ }): Promise<{
71
+ ok: true;
72
+ woke: number;
73
+ }>;
74
+ /**
75
+ * A journey push tapped open: the `message_id` the push carried, reported for the user who
76
+ * tapped it. Recorded as a human open on the copy (an email's opens are tracked by the Worker).
77
+ */
78
+ messageOpened(userId: string, messageId: string): Promise<{
79
+ ok: true;
80
+ recorded: boolean;
81
+ }>;
82
+ /**
83
+ * A deleted account: the engine records the erasure, stops the user's running journeys, then
84
+ * erases everything it keeps about them (profile, devices, events, reporting). Once this
85
+ * resolves the request is durable: `erased: false` means an instance would not stop yet, and
86
+ * the Worker's scheduled sweep finishes the job.
87
+ */
88
+ forgetUser(userId: string): Promise<{
89
+ ok: true;
90
+ erased: boolean;
91
+ pending: string[];
92
+ }>;
93
+ /** The user signed out on that device: the token stays registered, bound to nobody. */
94
+ unbindDevice(token: string): Promise<{
95
+ ok: true;
96
+ woke: number;
97
+ }>;
98
+ /** Forget a push token for good (an uninstall the app learned of, a token it replaced). */
99
+ removeDevice(token: string): Promise<{
100
+ ok: true;
101
+ woke: number;
102
+ }>;
103
+ /** Deploy a compiled bundle (BundleIR). */
104
+ deploy(bundle: unknown): Promise<DeployResult>;
105
+ private post;
106
+ }
107
+ //#endregion
108
+ //# sourceMappingURL=client.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;;;;;;;;iBAYiB,qBAAqB,UAAU;;;;;EAK9C,WAAW;;EAEX;;EAEA;;EAEA,eAAe;;qBAGJ,2BAA2B;WAE3B;WACA;WACA;EAHX,YACW,cACA,gBACA;;;qBAQA,+BAA+B;WAE/B;WACA;WACA,QAAQ;EAHnB,YACW,cACA,2BACA,QAAQ;;KAWhB,SAAS,KAAK,UAAU,eAAe,KAAK;;YAErC,gBAAgB,MAAM,wCAAwC,SAAS;KAC9E,UAAU,GAAG,MAAM,0BACnB,UAAU,yBAAyB,UAAU,gBAC9C,gBAAgB,SAAS,MACtB,SAAS,KAAK,MAAM,SAAS,GAAG,KAAK,UAAU;KAEjD,cAAc,MAAM,yBACrB,eACA,UAAU,SAAS,eAAe,KAAK,mBAAmB,KACxD,aAAa;iBAGF;;EAEf;;EAEA;;qBAGW,cAAc,UAAU;mBACN;EAA7B,YAA6B,SAAS,qBAAqB;;EAG3D,SAAS,gBAAgB,OAAO,cAAc,KAAK,QAAQ;;;;;;;EAgB3D,MAAM,UAAU,gBAAgB,IAC9B,gBACA,OAAO,MACJ,MAAM,UAAU,GAAG,KACrB,QAAQ;;;;;;EAsBX,eACE,gBACA;IAAU;IAAe;MACxB;IAAU;IAAU;;;;;;EAQvB,cAAc,gBAAgB,oBAAoB;IAAU;IAAU;;;;;;;;EAUtE,WAAW,iBAAiB;IAAU;IAAU;IAAiB;;;EAKjE,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,OAAO,kBAAkB,QAAQ;UAInB"}
@@ -0,0 +1,108 @@
1
+ import { Contract, ContractIssue, ProfilePatch } from "./contract.mjs";
2
+ import { ProfileProps } from "./store/index.mjs";
3
+ import { DeployResult, IdentifyResult, IngestResult } from "./cloudflare/router.mjs";
4
+ import "./cloudflare/index.mjs";
5
+ import * as core from "zod/v4/core";
6
+ //#region src/client.d.ts
7
+ /**
8
+ * `@shware/workflow/client` — the producer side of the ingest API, for the
9
+ * service that knows what users do (an api server, a webhook handler). Plain
10
+ * fetch, no dependencies; errors carry the status and body so a caller can
11
+ * log them without failing the request that triggered the report.
12
+ */
13
+ export interface JourneyClientOptions<C extends Contract | undefined = undefined> {
14
+ /**
15
+ * The shared `defineContract(...)`: types `track` (the event name picks the
16
+ * payload type) and `identify`, and checks both before anything is sent.
17
+ */
18
+ contract?: C;
19
+ /** The journey Worker's origin, e.g. `https://workflow.example.com`. */
20
+ origin: string;
21
+ /** Its API_TOKEN, sent as a bearer; omit against an open local instance. */
22
+ token?: string;
23
+ /** Fetch implementation (defaults to the global one). */
24
+ fetch?: typeof fetch;
25
+ }
26
+ export declare class JourneyClientError extends Error {
27
+ readonly path: string;
28
+ readonly status: number;
29
+ readonly body: string;
30
+ constructor(path: string, status: number, body: string);
31
+ }
32
+ /** A payload or profile patch the contract refuses — raised before the request, with the field paths. */
33
+ export declare class JourneyValidationError extends Error {
34
+ readonly path: string;
35
+ readonly event: string | undefined;
36
+ readonly issues: ContractIssue[];
37
+ constructor(path: string, event: string | undefined, issues: ContractIssue[]);
38
+ }
39
+ type EventsOf<C> = C extends Contract<infer E> ? E : never;
40
+ /** Event names: the contract's, or any string without one. */
41
+ export type ClientEventName<C> = [C] extends [undefined] ? string : keyof EventsOf<C> & string;
42
+ type TrackArgs<C, K> = [C] extends [undefined] ? [payload?: Record<string, unknown>, options?: TrackOptions] : K extends keyof EventsOf<C> ? [payload: core.input<EventsOf<C>[K]>, options?: TrackOptions] : never;
43
+ type IdentifyProps<C> = [C] extends [undefined] ? ProfileProps : C extends Contract<Record<string, core.$ZodObject>, infer P> ? ProfilePatch<P> : never;
44
+ export interface TrackOptions {
45
+ /** The occurrence's identity: a retry with the same id is recorded once. */
46
+ id?: string;
47
+ /** When it happened (epoch ms); the Worker's clock when omitted. */
48
+ ts?: number;
49
+ }
50
+ export declare class JourneyClient<C extends Contract | undefined = undefined> {
51
+ private readonly options;
52
+ constructor(options: JourneyClientOptions<C>);
53
+ /** Merge profile properties (`null` clears one). Every property a journey reads must be identified before the event that starts it. */
54
+ identify(userId: string, props: IdentifyProps<C>): Promise<IdentifyResult>;
55
+ /**
56
+ * Record an event; the Worker starts every journey whose trigger matches it
57
+ * and wakes waits on it. A caller that retries should pass the same `id`
58
+ * each time: the Worker stores one occurrence per id, so a retry after a
59
+ * timeout cannot double-count the event. `ts` defaults to the Worker's clock.
60
+ */
61
+ track<K extends ClientEventName<C>>(userId: string, event: K, ...args: TrackArgs<C, K>): Promise<IngestResult>;
62
+ /**
63
+ * A push token the app registered for the user (call it on every registration: a token moves
64
+ * to the latest user). The engine keeps devices itself — pushes go to them, a token APNs / FCM
65
+ * reports as gone is dropped — and journeys waiting on `reachable('push')` wake.
66
+ */
67
+ registerDevice(userId: string, device: {
68
+ token: string;
69
+ platform: 'ios' | 'android' | 'web';
70
+ }): Promise<{
71
+ ok: true;
72
+ woke: number;
73
+ }>;
74
+ /**
75
+ * A journey push tapped open: the `message_id` the push carried, reported for the user who
76
+ * tapped it. Recorded as a human open on the copy (an email's opens are tracked by the Worker).
77
+ */
78
+ messageOpened(userId: string, messageId: string): Promise<{
79
+ ok: true;
80
+ recorded: boolean;
81
+ }>;
82
+ /**
83
+ * A deleted account: the engine records the erasure, stops the user's running journeys, then
84
+ * erases everything it keeps about them (profile, devices, events, reporting). Once this
85
+ * resolves the request is durable: `erased: false` means an instance would not stop yet, and
86
+ * the Worker's scheduled sweep finishes the job.
87
+ */
88
+ forgetUser(userId: string): Promise<{
89
+ ok: true;
90
+ erased: boolean;
91
+ pending: string[];
92
+ }>;
93
+ /** The user signed out on that device: the token stays registered, bound to nobody. */
94
+ unbindDevice(token: string): Promise<{
95
+ ok: true;
96
+ woke: number;
97
+ }>;
98
+ /** Forget a push token for good (an uninstall the app learned of, a token it replaced). */
99
+ removeDevice(token: string): Promise<{
100
+ ok: true;
101
+ woke: number;
102
+ }>;
103
+ /** Deploy a compiled bundle (BundleIR). */
104
+ deploy(bundle: unknown): Promise<DeployResult>;
105
+ private post;
106
+ }
107
+ //#endregion
108
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;;;;;;;;iBAYiB,qBAAqB,UAAU;;;;;EAK9C,WAAW;;EAEX;;EAEA;;EAEA,eAAe;;qBAGJ,2BAA2B;WAE3B;WACA;WACA;EAHX,YACW,cACA,gBACA;;;qBAQA,+BAA+B;WAE/B;WACA;WACA,QAAQ;EAHnB,YACW,cACA,2BACA,QAAQ;;KAWhB,SAAS,KAAK,UAAU,eAAe,KAAK;;YAErC,gBAAgB,MAAM,wCAAwC,SAAS;KAC9E,UAAU,GAAG,MAAM,0BACnB,UAAU,yBAAyB,UAAU,gBAC9C,gBAAgB,SAAS,MACtB,SAAS,KAAK,MAAM,SAAS,GAAG,KAAK,UAAU;KAEjD,cAAc,MAAM,yBACrB,eACA,UAAU,SAAS,eAAe,KAAK,mBAAmB,KACxD,aAAa;iBAGF;;EAEf;;EAEA;;qBAGW,cAAc,UAAU;mBACN;EAA7B,YAA6B,SAAS,qBAAqB;;EAG3D,SAAS,gBAAgB,OAAO,cAAc,KAAK,QAAQ;;;;;;;EAgB3D,MAAM,UAAU,gBAAgB,IAC9B,gBACA,OAAO,MACJ,MAAM,UAAU,GAAG,KACrB,QAAQ;;;;;;EAsBX,eACE,gBACA;IAAU;IAAe;MACxB;IAAU;IAAU;;;;;;EAQvB,cAAc,gBAAgB,oBAAoB;IAAU;IAAU;;;;;;;;EAUtE,WAAW,iBAAiB;IAAU;IAAU;IAAiB;;;EAKjE,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,aAAa,gBAAgB;IAAU;IAAU;;;EAKjD,OAAO,kBAAkB,QAAQ;UAInB"}