@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 @@
1
+ {"version":3,"file":"refs.cjs","names":[],"sources":["../../src/dsl/refs.ts"],"sourcesContent":["import type { EventMap, UserPropertyBase } from './base';\n\n/**\n * Reference tables — the DSL's only two type-injection points (drizzle's\n * column-object pattern): `u = user<UserProperty>()` and `e = event<Event>()`.\n * Every other function in the DSL is generic-free and reads types off these\n * references.\n *\n * Type technique: phantom types. `UserPropertyRef<T>` carries the property's\n * type in an optional, never-assigned `__t` — purely so free functions like\n * `eq` can infer T from the reference. At runtime a ref is just\n * `{ type, path }`, produced by a Proxy on property access.\n */\n\n/**\n * User-property reference (drizzle's column equivalent), shared by predicates\n * (eq/gt/…) and message-prop personalization. The phantom type __t is how a\n * free function reads the property's type off the reference.\n */\nexport interface UserPropertyRef<T> {\n readonly type: 'user_property';\n readonly path: string;\n readonly __t?: T;\n}\n\n/** Event reference: the argument to `performed`; future payload where-clauses and value refs hang off it. */\nexport interface EventRef<P = unknown> {\n readonly type: 'event_ref';\n readonly name: string;\n readonly __p?: P;\n}\n\n/** Property reference table: `u.subscription_status` is a UserPropertyRef (drizzle's `users.email`). */\nexport type UserRefs<U> = { readonly [K in keyof U]-?: UserPropertyRef<U[K]> };\n\n/** Event reference table: `e.purchase` is an EventRef. */\nexport type EventRefs<E> = { readonly [K in keyof E]-?: EventRef<E[K]> };\n\n/**\n * Build the reference tables: the app calls each once in its schema module and\n * exports the result (implemented with a Proxy — property access *is* the reference).\n *\n * export const u = user<UserProperty>();\n * export const e = event<Event>();\n *\n * From then on predicates and personalization are all property access:\n * eq(u.subscription_status, 'active'), performed(e.purchase, { within: '30 days' }),\n * { plan: u.subscription_plan }.\n *\n * Properties are deliberately single-level: the data source is a database\n * table and is naturally flat, so nested paths are out of scope.\n */\nexport function user<U extends UserPropertyBase>(): UserRefs<U> {\n return new Proxy({} as UserRefs<U>, {\n get: (_target, prop) => ({ type: 'user_property', path: String(prop) }),\n });\n}\n\nexport function event<E extends EventMap>(): EventRefs<E> {\n return new Proxy({} as EventRefs<E>, {\n get: (_target, prop) => ({ type: 'event_ref', name: String(prop) }),\n });\n}\n\nexport type PropInput<T> = T | UserPropertyRef<T>;\nexport type PropsInput<P> = { [K in keyof P]: PropInput<P[K]> };\n\n/** Props may be omitted when a template declares none, and are required when it does. */\nexport type MessageArgs<P> =\n Record<never, never> extends P ? [props?: PropsInput<P>] : [props: PropsInput<P>];\n\n/* ------------------------------ payload references ----------------------------- */\n\n/**\n * Where a payload ref keeps its own state. A payload ref doubles as the table\n * of its sub-fields, so every *string* key it answered for itself shadowed an\n * author's field of that name: with a payload field called `path`,\n * `performed(e.page_view, (p) => eq(p.path, '/pricing'))` type-checked, handed\n * `prop()` the ref's own prefix instead of a sub-ref, and compiled to a\n * *profile* predicate on a property named 'path' — a mistake that only\n * surfaced later, as a zod error nowhere near the line that caused it. A symbol\n * key cannot be reached by `p.<field>`, so no field name can collide with it.\n */\nexport const PAYLOAD_PATH: unique symbol = Symbol('workflow.payloadPath');\n\n/**\n * Event-payload reference: what a `where` callback's parameter hands out. The\n * path it carries is dotted for nested fields ('tags.utm_source'). Predicates\n * accept it alongside UserPropertyRef and compile to a `payload` condition —\n * which is only valid inside `performed({ where })` / the event trigger's\n * `where` (compileBundle enforces the placement).\n */\nexport interface PayloadRef<T> {\n readonly [PAYLOAD_PATH]: string;\n readonly __t?: T;\n}\n\n/** A payload field ref that is itself an object also acts as a table of its sub-field refs. */\nexport type PayloadRefNode<T> = [NonNullable<T>] extends [object]\n ? PayloadRef<T> & {\n readonly [K in keyof NonNullable<T> & string]-?: PayloadRefNode<NonNullable<T>[K]>;\n }\n : PayloadRef<T>;\n\n/** Payload reference table for an event's payload P — the `p` in `where: (p) => eq(p.platform, 'web')`. */\nexport type PayloadRefs<P> = [P] extends [object]\n ? { readonly [K in keyof P & string]-?: PayloadRefNode<P[K]> }\n : Record<string, PayloadRef<unknown>>;\n\n/**\n * Nested Proxy: every string key extends the dotted path, so an author's field\n * may be named anything — including `path` or `type`. The ref's own path reads\n * off PAYLOAD_PATH, the one key a field name cannot spell.\n * @internal used by performed() and trigger.event() to hand `p` to a where callback\n */\nexport function payloadRefs<P>(prefix = ''): PayloadRefs<P> {\n return new Proxy({} as PayloadRefs<P>, {\n get: (_target, prop) => {\n if (prop === PAYLOAD_PATH) return prefix;\n // Other symbols are the runtime's own probes (inspection, iteration, thenable checks), never fields\n if (typeof prop === 'symbol') return undefined;\n return payloadRefs(prefix === '' ? prop : `${prefix}.${prop}`);\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoDA,SAAgB,OAAgD;CAC9D,OAAO,IAAI,MAAM,CAAC,GAAkB,EAClC,MAAM,SAAS,UAAU;EAAE,MAAM;EAAiB,MAAM,OAAO,IAAI;CAAE,GACvE,CAAC;AACH;AAEA,SAAgB,QAA0C;CACxD,OAAO,IAAI,MAAM,CAAC,GAAmB,EACnC,MAAM,SAAS,UAAU;EAAE,MAAM;EAAa,MAAM,OAAO,IAAI;CAAE,GACnE,CAAC;AACH;;;;;;;;;;;AAqBA,MAAa,eAA8B,OAAO,sBAAsB;;;;;;;AAgCxE,SAAgB,YAAe,SAAS,IAAoB;CAC1D,OAAO,IAAI,MAAM,CAAC,GAAqB,EACrC,MAAM,SAAS,SAAS;EACtB,IAAI,SAAS,cAAc,OAAO;EAElC,IAAI,OAAO,SAAS,UAAU,OAAO,KAAA;EACrC,OAAO,YAAY,WAAW,KAAK,OAAO,GAAG,OAAO,GAAG,MAAM;CAC/D,EACF,CAAC;AACH"}
@@ -0,0 +1,88 @@
1
+ import { EventMap, UserPropertyBase } from "./base.cjs";
2
+ //#region src/dsl/refs.d.ts
3
+ /**
4
+ * Reference tables — the DSL's only two type-injection points (drizzle's
5
+ * column-object pattern): `u = user<UserProperty>()` and `e = event<Event>()`.
6
+ * Every other function in the DSL is generic-free and reads types off these
7
+ * references.
8
+ *
9
+ * Type technique: phantom types. `UserPropertyRef<T>` carries the property's
10
+ * type in an optional, never-assigned `__t` — purely so free functions like
11
+ * `eq` can infer T from the reference. At runtime a ref is just
12
+ * `{ type, path }`, produced by a Proxy on property access.
13
+ */
14
+ /**
15
+ * User-property reference (drizzle's column equivalent), shared by predicates
16
+ * (eq/gt/…) and message-prop personalization. The phantom type __t is how a
17
+ * free function reads the property's type off the reference.
18
+ */
19
+ export interface UserPropertyRef<T> {
20
+ readonly type: 'user_property';
21
+ readonly path: string;
22
+ readonly __t?: T;
23
+ }
24
+ /** Event reference: the argument to `performed`; future payload where-clauses and value refs hang off it. */
25
+ export interface EventRef<P = unknown> {
26
+ readonly type: 'event_ref';
27
+ readonly name: string;
28
+ readonly __p?: P;
29
+ }
30
+ /** Property reference table: `u.subscription_status` is a UserPropertyRef (drizzle's `users.email`). */
31
+ export type UserRefs<U> = { readonly [K in keyof U]-?: UserPropertyRef<U[K]>; };
32
+ /** Event reference table: `e.purchase` is an EventRef. */
33
+ export type EventRefs<E> = { readonly [K in keyof E]-?: EventRef<E[K]>; };
34
+ /**
35
+ * Build the reference tables: the app calls each once in its schema module and
36
+ * exports the result (implemented with a Proxy — property access *is* the reference).
37
+ *
38
+ * export const u = user<UserProperty>();
39
+ * export const e = event<Event>();
40
+ *
41
+ * From then on predicates and personalization are all property access:
42
+ * eq(u.subscription_status, 'active'), performed(e.purchase, { within: '30 days' }),
43
+ * { plan: u.subscription_plan }.
44
+ *
45
+ * Properties are deliberately single-level: the data source is a database
46
+ * table and is naturally flat, so nested paths are out of scope.
47
+ */
48
+ export declare function user<U extends UserPropertyBase>(): UserRefs<U>;
49
+ export declare function event<E extends EventMap>(): EventRefs<E>;
50
+ export type PropInput<T> = T | UserPropertyRef<T>;
51
+ export type PropsInput<P> = { [K in keyof P]: PropInput<P[K]>; };
52
+ /** Props may be omitted when a template declares none, and are required when it does. */
53
+ export type MessageArgs<P> = Record<never, never> extends P ? [props?: PropsInput<P>] : [props: PropsInput<P>];
54
+ /**
55
+ * Where a payload ref keeps its own state. A payload ref doubles as the table
56
+ * of its sub-fields, so every *string* key it answered for itself shadowed an
57
+ * author's field of that name: with a payload field called `path`,
58
+ * `performed(e.page_view, (p) => eq(p.path, '/pricing'))` type-checked, handed
59
+ * `prop()` the ref's own prefix instead of a sub-ref, and compiled to a
60
+ * *profile* predicate on a property named 'path' — a mistake that only
61
+ * surfaced later, as a zod error nowhere near the line that caused it. A symbol
62
+ * key cannot be reached by `p.<field>`, so no field name can collide with it.
63
+ */
64
+ export declare const PAYLOAD_PATH: unique symbol;
65
+ /**
66
+ * Event-payload reference: what a `where` callback's parameter hands out. The
67
+ * path it carries is dotted for nested fields ('tags.utm_source'). Predicates
68
+ * accept it alongside UserPropertyRef and compile to a `payload` condition —
69
+ * which is only valid inside `performed({ where })` / the event trigger's
70
+ * `where` (compileBundle enforces the placement).
71
+ */
72
+ export interface PayloadRef<T> {
73
+ readonly [PAYLOAD_PATH]: string;
74
+ readonly __t?: T;
75
+ }
76
+ /** A payload field ref that is itself an object also acts as a table of its sub-field refs. */
77
+ export type PayloadRefNode<T> = [NonNullable<T>] extends [object] ? PayloadRef<T> & { readonly [K in keyof NonNullable<T> & string]-?: PayloadRefNode<NonNullable<T>[K]>; } : PayloadRef<T>;
78
+ /** Payload reference table for an event's payload P — the `p` in `where: (p) => eq(p.platform, 'web')`. */
79
+ export type PayloadRefs<P> = [P] extends [object] ? { readonly [K in keyof P & string]-?: PayloadRefNode<P[K]>; } : Record<string, PayloadRef<unknown>>;
80
+ /**
81
+ * Nested Proxy: every string key extends the dotted path, so an author's field
82
+ * may be named anything — including `path` or `type`. The ref's own path reads
83
+ * off PAYLOAD_PATH, the one key a field name cannot spell.
84
+ * @internal used by performed() and trigger.event() to hand `p` to a where callback
85
+ */
86
+ export declare function payloadRefs<P>(prefix?: string): PayloadRefs<P>;
87
+ //#endregion
88
+ //# sourceMappingURL=refs.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.d.cts","names":[],"sources":["../../src/dsl/refs.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBAmBiB,gBAAgB;WACtB;WACA;WACA,MAAM;;;iBAIA,SAAS;WACf;WACA;WACA,MAAM;;;YAIL,SAAS,iBAAiB,WAAW,MAAM,gBAAgB,EAAE;;YAG7D,UAAU,iBAAiB,WAAW,MAAM,SAAS,EAAE;;;;;;;;;;;;;;;wBAgBnD,KAAK,UAAU,qBAAqB,SAAS;wBAM7C,MAAM,UAAU,aAAa,UAAU;YAM3C,UAAU,KAAK,IAAI,gBAAgB;YACnC,WAAW,QAAQ,WAAW,IAAI,UAAU,EAAE;;YAG9C,YAAY,KACtB,6BAA6B,KAAK,QAAQ,WAAW,OAAO,OAAO,WAAW;;;;;;;;;;;qBAcnE;;;;;;;;iBASI,WAAW;YAChB;WACD,MAAM;;;YAIL,eAAe,MAAM,YAAY,uBACzC,WAAW,iBACC,WAAW,YAAY,gBAAgB,eAAe,YAAY,GAAG,SAEjF,WAAW;;YAGH,YAAY,MAAM,kCACd,WAAW,eAAe,eAAe,EAAE,SACvD,eAAe;;;;;;;wBAQH,YAAY,GAAG,kBAAc,YAAY"}
@@ -0,0 +1,88 @@
1
+ import { EventMap, UserPropertyBase } from "./base.mjs";
2
+ //#region src/dsl/refs.d.ts
3
+ /**
4
+ * Reference tables — the DSL's only two type-injection points (drizzle's
5
+ * column-object pattern): `u = user<UserProperty>()` and `e = event<Event>()`.
6
+ * Every other function in the DSL is generic-free and reads types off these
7
+ * references.
8
+ *
9
+ * Type technique: phantom types. `UserPropertyRef<T>` carries the property's
10
+ * type in an optional, never-assigned `__t` — purely so free functions like
11
+ * `eq` can infer T from the reference. At runtime a ref is just
12
+ * `{ type, path }`, produced by a Proxy on property access.
13
+ */
14
+ /**
15
+ * User-property reference (drizzle's column equivalent), shared by predicates
16
+ * (eq/gt/…) and message-prop personalization. The phantom type __t is how a
17
+ * free function reads the property's type off the reference.
18
+ */
19
+ export interface UserPropertyRef<T> {
20
+ readonly type: 'user_property';
21
+ readonly path: string;
22
+ readonly __t?: T;
23
+ }
24
+ /** Event reference: the argument to `performed`; future payload where-clauses and value refs hang off it. */
25
+ export interface EventRef<P = unknown> {
26
+ readonly type: 'event_ref';
27
+ readonly name: string;
28
+ readonly __p?: P;
29
+ }
30
+ /** Property reference table: `u.subscription_status` is a UserPropertyRef (drizzle's `users.email`). */
31
+ export type UserRefs<U> = { readonly [K in keyof U]-?: UserPropertyRef<U[K]>; };
32
+ /** Event reference table: `e.purchase` is an EventRef. */
33
+ export type EventRefs<E> = { readonly [K in keyof E]-?: EventRef<E[K]>; };
34
+ /**
35
+ * Build the reference tables: the app calls each once in its schema module and
36
+ * exports the result (implemented with a Proxy — property access *is* the reference).
37
+ *
38
+ * export const u = user<UserProperty>();
39
+ * export const e = event<Event>();
40
+ *
41
+ * From then on predicates and personalization are all property access:
42
+ * eq(u.subscription_status, 'active'), performed(e.purchase, { within: '30 days' }),
43
+ * { plan: u.subscription_plan }.
44
+ *
45
+ * Properties are deliberately single-level: the data source is a database
46
+ * table and is naturally flat, so nested paths are out of scope.
47
+ */
48
+ export declare function user<U extends UserPropertyBase>(): UserRefs<U>;
49
+ export declare function event<E extends EventMap>(): EventRefs<E>;
50
+ export type PropInput<T> = T | UserPropertyRef<T>;
51
+ export type PropsInput<P> = { [K in keyof P]: PropInput<P[K]>; };
52
+ /** Props may be omitted when a template declares none, and are required when it does. */
53
+ export type MessageArgs<P> = Record<never, never> extends P ? [props?: PropsInput<P>] : [props: PropsInput<P>];
54
+ /**
55
+ * Where a payload ref keeps its own state. A payload ref doubles as the table
56
+ * of its sub-fields, so every *string* key it answered for itself shadowed an
57
+ * author's field of that name: with a payload field called `path`,
58
+ * `performed(e.page_view, (p) => eq(p.path, '/pricing'))` type-checked, handed
59
+ * `prop()` the ref's own prefix instead of a sub-ref, and compiled to a
60
+ * *profile* predicate on a property named 'path' — a mistake that only
61
+ * surfaced later, as a zod error nowhere near the line that caused it. A symbol
62
+ * key cannot be reached by `p.<field>`, so no field name can collide with it.
63
+ */
64
+ export declare const PAYLOAD_PATH: unique symbol;
65
+ /**
66
+ * Event-payload reference: what a `where` callback's parameter hands out. The
67
+ * path it carries is dotted for nested fields ('tags.utm_source'). Predicates
68
+ * accept it alongside UserPropertyRef and compile to a `payload` condition —
69
+ * which is only valid inside `performed({ where })` / the event trigger's
70
+ * `where` (compileBundle enforces the placement).
71
+ */
72
+ export interface PayloadRef<T> {
73
+ readonly [PAYLOAD_PATH]: string;
74
+ readonly __t?: T;
75
+ }
76
+ /** A payload field ref that is itself an object also acts as a table of its sub-field refs. */
77
+ export type PayloadRefNode<T> = [NonNullable<T>] extends [object] ? PayloadRef<T> & { readonly [K in keyof NonNullable<T> & string]-?: PayloadRefNode<NonNullable<T>[K]>; } : PayloadRef<T>;
78
+ /** Payload reference table for an event's payload P — the `p` in `where: (p) => eq(p.platform, 'web')`. */
79
+ export type PayloadRefs<P> = [P] extends [object] ? { readonly [K in keyof P & string]-?: PayloadRefNode<P[K]>; } : Record<string, PayloadRef<unknown>>;
80
+ /**
81
+ * Nested Proxy: every string key extends the dotted path, so an author's field
82
+ * may be named anything — including `path` or `type`. The ref's own path reads
83
+ * off PAYLOAD_PATH, the one key a field name cannot spell.
84
+ * @internal used by performed() and trigger.event() to hand `p` to a where callback
85
+ */
86
+ export declare function payloadRefs<P>(prefix?: string): PayloadRefs<P>;
87
+ //#endregion
88
+ //# sourceMappingURL=refs.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.d.mts","names":[],"sources":["../../src/dsl/refs.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBAmBiB,gBAAgB;WACtB;WACA;WACA,MAAM;;;iBAIA,SAAS;WACf;WACA;WACA,MAAM;;;YAIL,SAAS,iBAAiB,WAAW,MAAM,gBAAgB,EAAE;;YAG7D,UAAU,iBAAiB,WAAW,MAAM,SAAS,EAAE;;;;;;;;;;;;;;;wBAgBnD,KAAK,UAAU,qBAAqB,SAAS;wBAM7C,MAAM,UAAU,aAAa,UAAU;YAM3C,UAAU,KAAK,IAAI,gBAAgB;YACnC,WAAW,QAAQ,WAAW,IAAI,UAAU,EAAE;;YAG9C,YAAY,KACtB,6BAA6B,KAAK,QAAQ,WAAW,OAAO,OAAO,WAAW;;;;;;;;;;;qBAcnE;;;;;;;;iBASI,WAAW;YAChB;WACD,MAAM;;;YAIL,eAAe,MAAM,YAAY,uBACzC,WAAW,iBACC,WAAW,YAAY,gBAAgB,eAAe,YAAY,GAAG,SAEjF,WAAW;;YAGH,YAAY,MAAM,kCACd,WAAW,eAAe,eAAe,EAAE,SACvD,eAAe;;;;;;;wBAQH,YAAY,GAAG,kBAAc,YAAY"}
@@ -0,0 +1,55 @@
1
+ //#region src/dsl/refs.ts
2
+ /**
3
+ * Build the reference tables: the app calls each once in its schema module and
4
+ * exports the result (implemented with a Proxy — property access *is* the reference).
5
+ *
6
+ * export const u = user<UserProperty>();
7
+ * export const e = event<Event>();
8
+ *
9
+ * From then on predicates and personalization are all property access:
10
+ * eq(u.subscription_status, 'active'), performed(e.purchase, { within: '30 days' }),
11
+ * { plan: u.subscription_plan }.
12
+ *
13
+ * Properties are deliberately single-level: the data source is a database
14
+ * table and is naturally flat, so nested paths are out of scope.
15
+ */
16
+ function user() {
17
+ return new Proxy({}, { get: (_target, prop) => ({
18
+ type: "user_property",
19
+ path: String(prop)
20
+ }) });
21
+ }
22
+ function event() {
23
+ return new Proxy({}, { get: (_target, prop) => ({
24
+ type: "event_ref",
25
+ name: String(prop)
26
+ }) });
27
+ }
28
+ /**
29
+ * Where a payload ref keeps its own state. A payload ref doubles as the table
30
+ * of its sub-fields, so every *string* key it answered for itself shadowed an
31
+ * author's field of that name: with a payload field called `path`,
32
+ * `performed(e.page_view, (p) => eq(p.path, '/pricing'))` type-checked, handed
33
+ * `prop()` the ref's own prefix instead of a sub-ref, and compiled to a
34
+ * *profile* predicate on a property named 'path' — a mistake that only
35
+ * surfaced later, as a zod error nowhere near the line that caused it. A symbol
36
+ * key cannot be reached by `p.<field>`, so no field name can collide with it.
37
+ */
38
+ const PAYLOAD_PATH = Symbol("workflow.payloadPath");
39
+ /**
40
+ * Nested Proxy: every string key extends the dotted path, so an author's field
41
+ * may be named anything — including `path` or `type`. The ref's own path reads
42
+ * off PAYLOAD_PATH, the one key a field name cannot spell.
43
+ * @internal used by performed() and trigger.event() to hand `p` to a where callback
44
+ */
45
+ function payloadRefs(prefix = "") {
46
+ return new Proxy({}, { get: (_target, prop) => {
47
+ if (prop === PAYLOAD_PATH) return prefix;
48
+ if (typeof prop === "symbol") return void 0;
49
+ return payloadRefs(prefix === "" ? prop : `${prefix}.${prop}`);
50
+ } });
51
+ }
52
+ //#endregion
53
+ export { PAYLOAD_PATH, event, payloadRefs, user };
54
+
55
+ //# sourceMappingURL=refs.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.mjs","names":[],"sources":["../../src/dsl/refs.ts"],"sourcesContent":["import type { EventMap, UserPropertyBase } from './base';\n\n/**\n * Reference tables — the DSL's only two type-injection points (drizzle's\n * column-object pattern): `u = user<UserProperty>()` and `e = event<Event>()`.\n * Every other function in the DSL is generic-free and reads types off these\n * references.\n *\n * Type technique: phantom types. `UserPropertyRef<T>` carries the property's\n * type in an optional, never-assigned `__t` — purely so free functions like\n * `eq` can infer T from the reference. At runtime a ref is just\n * `{ type, path }`, produced by a Proxy on property access.\n */\n\n/**\n * User-property reference (drizzle's column equivalent), shared by predicates\n * (eq/gt/…) and message-prop personalization. The phantom type __t is how a\n * free function reads the property's type off the reference.\n */\nexport interface UserPropertyRef<T> {\n readonly type: 'user_property';\n readonly path: string;\n readonly __t?: T;\n}\n\n/** Event reference: the argument to `performed`; future payload where-clauses and value refs hang off it. */\nexport interface EventRef<P = unknown> {\n readonly type: 'event_ref';\n readonly name: string;\n readonly __p?: P;\n}\n\n/** Property reference table: `u.subscription_status` is a UserPropertyRef (drizzle's `users.email`). */\nexport type UserRefs<U> = { readonly [K in keyof U]-?: UserPropertyRef<U[K]> };\n\n/** Event reference table: `e.purchase` is an EventRef. */\nexport type EventRefs<E> = { readonly [K in keyof E]-?: EventRef<E[K]> };\n\n/**\n * Build the reference tables: the app calls each once in its schema module and\n * exports the result (implemented with a Proxy — property access *is* the reference).\n *\n * export const u = user<UserProperty>();\n * export const e = event<Event>();\n *\n * From then on predicates and personalization are all property access:\n * eq(u.subscription_status, 'active'), performed(e.purchase, { within: '30 days' }),\n * { plan: u.subscription_plan }.\n *\n * Properties are deliberately single-level: the data source is a database\n * table and is naturally flat, so nested paths are out of scope.\n */\nexport function user<U extends UserPropertyBase>(): UserRefs<U> {\n return new Proxy({} as UserRefs<U>, {\n get: (_target, prop) => ({ type: 'user_property', path: String(prop) }),\n });\n}\n\nexport function event<E extends EventMap>(): EventRefs<E> {\n return new Proxy({} as EventRefs<E>, {\n get: (_target, prop) => ({ type: 'event_ref', name: String(prop) }),\n });\n}\n\nexport type PropInput<T> = T | UserPropertyRef<T>;\nexport type PropsInput<P> = { [K in keyof P]: PropInput<P[K]> };\n\n/** Props may be omitted when a template declares none, and are required when it does. */\nexport type MessageArgs<P> =\n Record<never, never> extends P ? [props?: PropsInput<P>] : [props: PropsInput<P>];\n\n/* ------------------------------ payload references ----------------------------- */\n\n/**\n * Where a payload ref keeps its own state. A payload ref doubles as the table\n * of its sub-fields, so every *string* key it answered for itself shadowed an\n * author's field of that name: with a payload field called `path`,\n * `performed(e.page_view, (p) => eq(p.path, '/pricing'))` type-checked, handed\n * `prop()` the ref's own prefix instead of a sub-ref, and compiled to a\n * *profile* predicate on a property named 'path' — a mistake that only\n * surfaced later, as a zod error nowhere near the line that caused it. A symbol\n * key cannot be reached by `p.<field>`, so no field name can collide with it.\n */\nexport const PAYLOAD_PATH: unique symbol = Symbol('workflow.payloadPath');\n\n/**\n * Event-payload reference: what a `where` callback's parameter hands out. The\n * path it carries is dotted for nested fields ('tags.utm_source'). Predicates\n * accept it alongside UserPropertyRef and compile to a `payload` condition —\n * which is only valid inside `performed({ where })` / the event trigger's\n * `where` (compileBundle enforces the placement).\n */\nexport interface PayloadRef<T> {\n readonly [PAYLOAD_PATH]: string;\n readonly __t?: T;\n}\n\n/** A payload field ref that is itself an object also acts as a table of its sub-field refs. */\nexport type PayloadRefNode<T> = [NonNullable<T>] extends [object]\n ? PayloadRef<T> & {\n readonly [K in keyof NonNullable<T> & string]-?: PayloadRefNode<NonNullable<T>[K]>;\n }\n : PayloadRef<T>;\n\n/** Payload reference table for an event's payload P — the `p` in `where: (p) => eq(p.platform, 'web')`. */\nexport type PayloadRefs<P> = [P] extends [object]\n ? { readonly [K in keyof P & string]-?: PayloadRefNode<P[K]> }\n : Record<string, PayloadRef<unknown>>;\n\n/**\n * Nested Proxy: every string key extends the dotted path, so an author's field\n * may be named anything — including `path` or `type`. The ref's own path reads\n * off PAYLOAD_PATH, the one key a field name cannot spell.\n * @internal used by performed() and trigger.event() to hand `p` to a where callback\n */\nexport function payloadRefs<P>(prefix = ''): PayloadRefs<P> {\n return new Proxy({} as PayloadRefs<P>, {\n get: (_target, prop) => {\n if (prop === PAYLOAD_PATH) return prefix;\n // Other symbols are the runtime's own probes (inspection, iteration, thenable checks), never fields\n if (typeof prop === 'symbol') return undefined;\n return payloadRefs(prefix === '' ? prop : `${prefix}.${prop}`);\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;AAoDA,SAAgB,OAAgD;CAC9D,OAAO,IAAI,MAAM,CAAC,GAAkB,EAClC,MAAM,SAAS,UAAU;EAAE,MAAM;EAAiB,MAAM,OAAO,IAAI;CAAE,GACvE,CAAC;AACH;AAEA,SAAgB,QAA0C;CACxD,OAAO,IAAI,MAAM,CAAC,GAAmB,EACnC,MAAM,SAAS,UAAU;EAAE,MAAM;EAAa,MAAM,OAAO,IAAI;CAAE,GACnE,CAAC;AACH;;;;;;;;;;;AAqBA,MAAa,eAA8B,OAAO,sBAAsB;;;;;;;AAgCxE,SAAgB,YAAe,SAAS,IAAoB;CAC1D,OAAO,IAAI,MAAM,CAAC,GAAqB,EACrC,MAAM,SAAS,SAAS;EACtB,IAAI,SAAS,cAAc,OAAO;EAElC,IAAI,OAAO,SAAS,UAAU,OAAO,KAAA;EACrC,OAAO,YAAY,WAAW,KAAK,OAAO,GAAG,OAAO,GAAG,MAAM;CAC/D,EACF,CAAC;AACH"}
@@ -0,0 +1,65 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_templates = require("../templates.cjs");
3
+ //#region src/dsl/template.ts
4
+ const makeTemplate = (channel) => (key) => ({
5
+ channel,
6
+ key
7
+ });
8
+ /**
9
+ * Unbound template references, props typed by hand. Email and push refs come
10
+ * from the registries (`templates<Emails, Pushes>()`), which type both key and
11
+ * props; this is the low-level form for channels without a registry (sms,
12
+ * slack, …) and for tests.
13
+ *
14
+ * const alert = template.slack<{ plan: string }>('cs_churn_alert');
15
+ */
16
+ const template = {
17
+ email: makeTemplate("email"),
18
+ sms: makeTemplate("sms"),
19
+ push: makeTemplate("push"),
20
+ inApp: makeTemplate("in_app"),
21
+ slack: makeTemplate("slack"),
22
+ discord: makeTemplate("discord"),
23
+ survey: makeTemplate("survey")
24
+ };
25
+ /**
26
+ * Template references derived from the registries themselves: **the
27
+ * registries type the keys** — an unregistered key fails to compile, and a
28
+ * push template is not accepted where an email is — and each template's
29
+ * `props` schema types its use sites. Templates are registered once; the
30
+ * config takes the registries, the workflows take the references:
31
+ *
32
+ * export const registry = { email, push };
33
+ * export const t = templates(registry);
34
+ * flow.email(t.email.welcome, { name: u.name });
35
+ *
36
+ * Each reference is a plain `{ channel, key }` built from the registry's own
37
+ * keys; no template is rendered, and the registries are left untouched.
38
+ */
39
+ function templates(registry) {
40
+ return {
41
+ email: refTable("email", registry.email, require_templates.isEmailTemplate),
42
+ push: refTable("push", registry.push, require_templates.isPushTemplate),
43
+ discord: refTable("discord", registry.discord, require_templates.isDiscordTemplate),
44
+ slack: refTable("slack", registry.slack, require_templates.isSlackTemplate)
45
+ };
46
+ }
47
+ const ARTICLE = {
48
+ email: "an email",
49
+ push: "a push",
50
+ discord: "a Discord",
51
+ slack: "a Slack"
52
+ };
53
+ function refTable(channel, entries, is) {
54
+ const table = Object.create(null);
55
+ for (const [key, entry] of Object.entries(entries ?? {})) {
56
+ if (!is(entry)) throw new TypeError(`templates(): '${key}' in the ${channel} registry is not ${ARTICLE[channel]} template`);
57
+ table[key] = template[channel](key);
58
+ }
59
+ return Object.freeze(table);
60
+ }
61
+ //#endregion
62
+ exports.template = template;
63
+ exports.templates = templates;
64
+
65
+ //# sourceMappingURL=template.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.cjs","names":["isEmailTemplate","isPushTemplate","isDiscordTemplate","isSlackTemplate"],"sources":["../../src/dsl/template.ts"],"sourcesContent":["/**\n * Templates — named message-content assets. The DSL only ever holds a\n * reference ({ channel, key, phantom props }); the content itself (react-email\n * components) lives in the app and meets the reference again in the studio and\n * at send time via the registry.\n *\n * Type technique: `templates(registry)` derives the references from the\n * registries so **the registries type the keys** — an unregistered key fails\n * to compile — while `PropsOf<M>` reads the props contract off each template's\n * Zod schema, so it is written exactly once.\n */\n\nimport type * as core from 'zod/v4/core';\nimport {\n type DiscordTemplate,\n type EmailTemplate,\n type PropsSchema,\n type PushTemplate,\n type SlackTemplate,\n isDiscordTemplate,\n isEmailTemplate,\n isPushTemplate,\n isSlackTemplate,\n} from '../templates';\n\nexport type Channel = 'email' | 'sms' | 'push' | 'in_app' | 'slack' | 'discord' | 'survey';\n\nexport type EmptyProps = Record<never, never>;\n\n/**\n * Template reference: a top-level named asset, reusable across workflows and\n * versioned on its own. The props shape is declared here and checked at use.\n */\nexport interface TemplateRef<C extends Channel = Channel, P extends object = EmptyProps> {\n readonly channel: C;\n readonly key: string;\n readonly __props?: P;\n}\n\nexport interface TemplateFactory {\n email<P extends object = EmptyProps>(key: string): TemplateRef<'email', P>;\n sms<P extends object = EmptyProps>(key: string): TemplateRef<'sms', P>;\n push<P extends object = EmptyProps>(key: string): TemplateRef<'push', P>;\n inApp<P extends object = EmptyProps>(key: string): TemplateRef<'in_app', P>;\n slack<P extends object = EmptyProps>(key: string): TemplateRef<'slack', P>;\n discord<P extends object = EmptyProps>(key: string): TemplateRef<'discord', P>;\n survey<P extends object = EmptyProps>(key: string): TemplateRef<'survey', P>;\n}\n\nconst makeTemplate =\n <C extends Channel>(channel: C) =>\n <P extends object = EmptyProps>(key: string): TemplateRef<C, P> => ({ channel, key });\n\n/**\n * Unbound template references, props typed by hand. Email and push refs come\n * from the registries (`templates<Emails, Pushes>()`), which type both key and\n * props; this is the low-level form for channels without a registry (sms,\n * slack, …) and for tests.\n *\n * const alert = template.slack<{ plan: string }>('cs_churn_alert');\n */\nexport const template: TemplateFactory = {\n email: makeTemplate('email'),\n sms: makeTemplate('sms'),\n push: makeTemplate('push'),\n inApp: makeTemplate('in_app'),\n slack: makeTemplate('slack'),\n discord: makeTemplate('discord'),\n survey: makeTemplate('survey'),\n};\n\n/* ----------------------------- Template registry ---------------------------- */\n\n/** Template props: the input type of the template's Zod `props` schema — what the DSL passes. */\nexport type PropsOf<M> = M extends\n | EmailTemplate<infer S>\n | PushTemplate<infer S>\n | DiscordTemplate<infer S, never>\n | SlackTemplate<infer S, never>\n ? core.input<S> extends object\n ? core.input<S>\n : EmptyProps\n : never;\n\n/**\n * The channel registries: what the config registers as `templates` and what\n * `templates()` derives the references from — one type for both. Leave it\n * inferred, or check it with `satisfies TemplateRegistry`: annotating a value\n * as the bare type widens the keys to `string`.\n */\nexport interface TemplateRegistry<\n E extends Readonly<Record<string, EmailTemplate>> = Readonly<Record<string, EmailTemplate>>,\n P extends Readonly<Record<string, PushTemplate>> = Readonly<Record<string, PushTemplate>>,\n> {\n readonly email?: E;\n readonly push?: P;\n /** Discord webhook templates, each typed by the host's Env its `webhook` reads. */\n readonly discord?: Readonly<Record<string, DiscordTemplate<PropsSchema, never>>>;\n readonly slack?: Readonly<Record<string, SlackTemplate<PropsSchema, never>>>;\n}\n\n/** One channel's registry in `R`, without the `undefined` of an optional field; `never` when absent. */\ntype ChannelRegistry<R, K extends 'email' | 'push' | 'discord' | 'slack'> = K extends keyof R\n ? Exclude<R[K], undefined>\n : never;\n\n/** One reference per registered key, each typed by its own template's `props`. */\nexport type TemplateRefTable<C extends Channel, R> = {\n readonly [K in keyof R & string]: TemplateRef<C, PropsOf<R[K]>>;\n};\n\n/** `t.email.<key>` / `t.push.<key>`; a channel the registry leaves out is an empty table. */\nexport interface TemplateRefs<R extends TemplateRegistry> {\n readonly email: [ChannelRegistry<R, 'email'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'email', ChannelRegistry<R, 'email'>>;\n readonly push: [ChannelRegistry<R, 'push'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'push', ChannelRegistry<R, 'push'>>;\n readonly discord: [ChannelRegistry<R, 'discord'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'discord', ChannelRegistry<R, 'discord'>>;\n readonly slack: [ChannelRegistry<R, 'slack'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'slack', ChannelRegistry<R, 'slack'>>;\n}\n\n/**\n * Template references derived from the registries themselves: **the\n * registries type the keys** — an unregistered key fails to compile, and a\n * push template is not accepted where an email is — and each template's\n * `props` schema types its use sites. Templates are registered once; the\n * config takes the registries, the workflows take the references:\n *\n * export const registry = { email, push };\n * export const t = templates(registry);\n * flow.email(t.email.welcome, { name: u.name });\n *\n * Each reference is a plain `{ channel, key }` built from the registry's own\n * keys; no template is rendered, and the registries are left untouched.\n */\nexport function templates<const R extends TemplateRegistry>(registry: R): TemplateRefs<R> {\n return {\n email: refTable('email', registry.email, isEmailTemplate),\n push: refTable('push', registry.push, isPushTemplate),\n discord: refTable('discord', registry.discord, isDiscordTemplate),\n slack: refTable('slack', registry.slack, isSlackTemplate),\n } as unknown as TemplateRefs<R>;\n}\n\nconst ARTICLE: Record<'email' | 'push' | 'discord' | 'slack', string> = {\n email: 'an email',\n push: 'a push',\n discord: 'a Discord',\n slack: 'a Slack',\n};\n\nfunction refTable(\n channel: 'email' | 'push' | 'discord' | 'slack',\n entries: Readonly<Record<string, unknown>> | undefined,\n is: (value: unknown) => boolean\n): Readonly<Record<string, TemplateRef>> {\n const table: Record<string, TemplateRef> = Object.create(null);\n for (const [key, entry] of Object.entries(entries ?? {})) {\n if (!is(entry)) {\n throw new TypeError(\n `templates(): '${key}' in the ${channel} registry is not ${ARTICLE[channel]} template`\n );\n }\n table[key] = template[channel](key);\n }\n return Object.freeze(table);\n}\n"],"mappings":";;;AAiDA,MAAM,gBACgB,aACY,SAAoC;CAAE;CAAS;AAAI;;;;;;;;;AAUrF,MAAa,WAA4B;CACvC,OAAO,aAAa,OAAO;CAC3B,KAAK,aAAa,KAAK;CACvB,MAAM,aAAa,MAAM;CACzB,OAAO,aAAa,QAAQ;CAC5B,OAAO,aAAa,OAAO;CAC3B,SAAS,aAAa,SAAS;CAC/B,QAAQ,aAAa,QAAQ;AAC/B;;;;;;;;;;;;;;;AAwEA,SAAgB,UAA4C,UAA8B;CACxF,OAAO;EACL,OAAO,SAAS,SAAS,SAAS,OAAOA,kBAAAA,eAAe;EACxD,MAAM,SAAS,QAAQ,SAAS,MAAMC,kBAAAA,cAAc;EACpD,SAAS,SAAS,WAAW,SAAS,SAASC,kBAAAA,iBAAiB;EAChE,OAAO,SAAS,SAAS,SAAS,OAAOC,kBAAAA,eAAe;CAC1D;AACF;AAEA,MAAM,UAAkE;CACtE,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;AACT;AAEA,SAAS,SACP,SACA,SACA,IACuC;CACvC,MAAM,QAAqC,OAAO,OAAO,IAAI;CAC7D,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,WAAW,CAAC,CAAC,GAAG;EACxD,IAAI,CAAC,GAAG,KAAK,GACX,MAAM,IAAI,UACR,iBAAiB,IAAI,WAAW,QAAQ,mBAAmB,QAAQ,SAAS,UAC9E;EAEF,MAAM,OAAO,SAAS,QAAQ,CAAC,GAAG;CACpC;CACA,OAAO,OAAO,OAAO,KAAK;AAC5B"}
@@ -0,0 +1,75 @@
1
+ import { DiscordTemplate, EmailTemplate, PropsSchema, PushTemplate, SlackTemplate } from "../templates.cjs";
2
+ import * as core from "zod/v4/core";
3
+ //#region src/dsl/template.d.ts
4
+ export type Channel = 'email' | 'sms' | 'push' | 'in_app' | 'slack' | 'discord' | 'survey';
5
+ export type EmptyProps = Record<never, never>;
6
+ /**
7
+ * Template reference: a top-level named asset, reusable across workflows and
8
+ * versioned on its own. The props shape is declared here and checked at use.
9
+ */
10
+ export interface TemplateRef<C extends Channel = Channel, P extends object = EmptyProps> {
11
+ readonly channel: C;
12
+ readonly key: string;
13
+ readonly __props?: P;
14
+ }
15
+ export interface TemplateFactory {
16
+ email<P extends object = EmptyProps>(key: string): TemplateRef<'email', P>;
17
+ sms<P extends object = EmptyProps>(key: string): TemplateRef<'sms', P>;
18
+ push<P extends object = EmptyProps>(key: string): TemplateRef<'push', P>;
19
+ inApp<P extends object = EmptyProps>(key: string): TemplateRef<'in_app', P>;
20
+ slack<P extends object = EmptyProps>(key: string): TemplateRef<'slack', P>;
21
+ discord<P extends object = EmptyProps>(key: string): TemplateRef<'discord', P>;
22
+ survey<P extends object = EmptyProps>(key: string): TemplateRef<'survey', P>;
23
+ }
24
+ /**
25
+ * Unbound template references, props typed by hand. Email and push refs come
26
+ * from the registries (`templates<Emails, Pushes>()`), which type both key and
27
+ * props; this is the low-level form for channels without a registry (sms,
28
+ * slack, …) and for tests.
29
+ *
30
+ * const alert = template.slack<{ plan: string }>('cs_churn_alert');
31
+ */
32
+ export declare const template: TemplateFactory;
33
+ /** Template props: the input type of the template's Zod `props` schema — what the DSL passes. */
34
+ export type PropsOf<M> = M extends EmailTemplate<infer S> | PushTemplate<infer S> | DiscordTemplate<infer S, never> | SlackTemplate<infer S, never> ? core.input<S> extends object ? core.input<S> : EmptyProps : never;
35
+ /**
36
+ * The channel registries: what the config registers as `templates` and what
37
+ * `templates()` derives the references from — one type for both. Leave it
38
+ * inferred, or check it with `satisfies TemplateRegistry`: annotating a value
39
+ * as the bare type widens the keys to `string`.
40
+ */
41
+ export interface TemplateRegistry<E extends Readonly<Record<string, EmailTemplate>> = Readonly<Record<string, EmailTemplate>>, P extends Readonly<Record<string, PushTemplate>> = Readonly<Record<string, PushTemplate>>> {
42
+ readonly email?: E;
43
+ readonly push?: P;
44
+ /** Discord webhook templates, each typed by the host's Env its `webhook` reads. */
45
+ readonly discord?: Readonly<Record<string, DiscordTemplate<PropsSchema, never>>>;
46
+ readonly slack?: Readonly<Record<string, SlackTemplate<PropsSchema, never>>>;
47
+ }
48
+ /** One channel's registry in `R`, without the `undefined` of an optional field; `never` when absent. */
49
+ type ChannelRegistry<R, K extends 'email' | 'push' | 'discord' | 'slack'> = K extends keyof R ? Exclude<R[K], undefined> : never;
50
+ /** One reference per registered key, each typed by its own template's `props`. */
51
+ export type TemplateRefTable<C extends Channel, R> = { readonly [K in keyof R & string]: TemplateRef<C, PropsOf<R[K]>>; };
52
+ /** `t.email.<key>` / `t.push.<key>`; a channel the registry leaves out is an empty table. */
53
+ export interface TemplateRefs<R extends TemplateRegistry> {
54
+ readonly email: [ChannelRegistry<R, 'email'>] extends [never] ? EmptyProps : TemplateRefTable<'email', ChannelRegistry<R, 'email'>>;
55
+ readonly push: [ChannelRegistry<R, 'push'>] extends [never] ? EmptyProps : TemplateRefTable<'push', ChannelRegistry<R, 'push'>>;
56
+ readonly discord: [ChannelRegistry<R, 'discord'>] extends [never] ? EmptyProps : TemplateRefTable<'discord', ChannelRegistry<R, 'discord'>>;
57
+ readonly slack: [ChannelRegistry<R, 'slack'>] extends [never] ? EmptyProps : TemplateRefTable<'slack', ChannelRegistry<R, 'slack'>>;
58
+ }
59
+ /**
60
+ * Template references derived from the registries themselves: **the
61
+ * registries type the keys** — an unregistered key fails to compile, and a
62
+ * push template is not accepted where an email is — and each template's
63
+ * `props` schema types its use sites. Templates are registered once; the
64
+ * config takes the registries, the workflows take the references:
65
+ *
66
+ * export const registry = { email, push };
67
+ * export const t = templates(registry);
68
+ * flow.email(t.email.welcome, { name: u.name });
69
+ *
70
+ * Each reference is a plain `{ channel, key }` built from the registry's own
71
+ * keys; no template is rendered, and the registries are left untouched.
72
+ */
73
+ export declare function templates<const R extends TemplateRegistry>(registry: R): TemplateRefs<R>;
74
+ //#endregion
75
+ //# sourceMappingURL=template.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.cts","names":[],"sources":["../../src/dsl/template.ts"],"mappings":";;;YAyBY;YAEA,aAAa;;;;;iBAMR,YAAY,UAAU,UAAU,SAAS,mBAAmB;WAClE,SAAS;WACT;WACA,UAAU;;iBAGJ;EACf,MAAM,mBAAmB,YAAY,cAAc,qBAAqB;EACxE,IAAI,mBAAmB,YAAY,cAAc,mBAAmB;EACpE,KAAK,mBAAmB,YAAY,cAAc,oBAAoB;EACtE,MAAM,mBAAmB,YAAY,cAAc,sBAAsB;EACzE,MAAM,mBAAmB,YAAY,cAAc,qBAAqB;EACxE,QAAQ,mBAAmB,YAAY,cAAc,uBAAuB;EAC5E,OAAO,mBAAmB,YAAY,cAAc,sBAAsB;;;;;;;;;;qBAe/D,UAAU;;YAaX,QAAQ,KAAK,UACrB,oBAAoB,KACpB,mBAAmB,KACnB,sBAAsB,YACtB,oBAAoB,YACpB,KAAK,MAAM,oBACT,KAAK,MAAM,KACX;;;;;;;iBASW,iBACf,UAAU,SAAS,eAAe,kBAAkB,SAAS,eAAe,iBAC5E,UAAU,SAAS,eAAe,iBAAiB,SAAS,eAAe;WAElE,QAAQ;WACR,OAAO;;WAEP,UAAU,SAAS,eAAe,gBAAgB;WAClD,QAAQ,SAAS,eAAe,cAAc;;;KAIpD,gBAAgB,GAAG,oDAAoD,gBAAgB,IACxF,QAAQ,EAAE;;YAIF,iBAAiB,UAAU,SAAS,iBACpC,WAAW,aAAa,YAAY,GAAG,QAAQ,EAAE;;iBAI5C,aAAa,UAAU;WAC7B,QAAQ,gBAAgB,+BAC7B,aACA,0BAA0B,gBAAgB;WACrC,OAAO,gBAAgB,8BAC5B,aACA,yBAAyB,gBAAgB;WACpC,UAAU,gBAAgB,iCAC/B,aACA,4BAA4B,gBAAgB;WACvC,QAAQ,gBAAgB,+BAC7B,aACA,0BAA0B,gBAAgB;;;;;;;;;;;;;;;;wBAiBhC,gBAAgB,UAAU,kBAAkB,UAAU,IAAI,aAAa"}
@@ -0,0 +1,75 @@
1
+ import { DiscordTemplate, EmailTemplate, PropsSchema, PushTemplate, SlackTemplate } from "../templates.mjs";
2
+ import * as core from "zod/v4/core";
3
+ //#region src/dsl/template.d.ts
4
+ export type Channel = 'email' | 'sms' | 'push' | 'in_app' | 'slack' | 'discord' | 'survey';
5
+ export type EmptyProps = Record<never, never>;
6
+ /**
7
+ * Template reference: a top-level named asset, reusable across workflows and
8
+ * versioned on its own. The props shape is declared here and checked at use.
9
+ */
10
+ export interface TemplateRef<C extends Channel = Channel, P extends object = EmptyProps> {
11
+ readonly channel: C;
12
+ readonly key: string;
13
+ readonly __props?: P;
14
+ }
15
+ export interface TemplateFactory {
16
+ email<P extends object = EmptyProps>(key: string): TemplateRef<'email', P>;
17
+ sms<P extends object = EmptyProps>(key: string): TemplateRef<'sms', P>;
18
+ push<P extends object = EmptyProps>(key: string): TemplateRef<'push', P>;
19
+ inApp<P extends object = EmptyProps>(key: string): TemplateRef<'in_app', P>;
20
+ slack<P extends object = EmptyProps>(key: string): TemplateRef<'slack', P>;
21
+ discord<P extends object = EmptyProps>(key: string): TemplateRef<'discord', P>;
22
+ survey<P extends object = EmptyProps>(key: string): TemplateRef<'survey', P>;
23
+ }
24
+ /**
25
+ * Unbound template references, props typed by hand. Email and push refs come
26
+ * from the registries (`templates<Emails, Pushes>()`), which type both key and
27
+ * props; this is the low-level form for channels without a registry (sms,
28
+ * slack, …) and for tests.
29
+ *
30
+ * const alert = template.slack<{ plan: string }>('cs_churn_alert');
31
+ */
32
+ export declare const template: TemplateFactory;
33
+ /** Template props: the input type of the template's Zod `props` schema — what the DSL passes. */
34
+ export type PropsOf<M> = M extends EmailTemplate<infer S> | PushTemplate<infer S> | DiscordTemplate<infer S, never> | SlackTemplate<infer S, never> ? core.input<S> extends object ? core.input<S> : EmptyProps : never;
35
+ /**
36
+ * The channel registries: what the config registers as `templates` and what
37
+ * `templates()` derives the references from — one type for both. Leave it
38
+ * inferred, or check it with `satisfies TemplateRegistry`: annotating a value
39
+ * as the bare type widens the keys to `string`.
40
+ */
41
+ export interface TemplateRegistry<E extends Readonly<Record<string, EmailTemplate>> = Readonly<Record<string, EmailTemplate>>, P extends Readonly<Record<string, PushTemplate>> = Readonly<Record<string, PushTemplate>>> {
42
+ readonly email?: E;
43
+ readonly push?: P;
44
+ /** Discord webhook templates, each typed by the host's Env its `webhook` reads. */
45
+ readonly discord?: Readonly<Record<string, DiscordTemplate<PropsSchema, never>>>;
46
+ readonly slack?: Readonly<Record<string, SlackTemplate<PropsSchema, never>>>;
47
+ }
48
+ /** One channel's registry in `R`, without the `undefined` of an optional field; `never` when absent. */
49
+ type ChannelRegistry<R, K extends 'email' | 'push' | 'discord' | 'slack'> = K extends keyof R ? Exclude<R[K], undefined> : never;
50
+ /** One reference per registered key, each typed by its own template's `props`. */
51
+ export type TemplateRefTable<C extends Channel, R> = { readonly [K in keyof R & string]: TemplateRef<C, PropsOf<R[K]>>; };
52
+ /** `t.email.<key>` / `t.push.<key>`; a channel the registry leaves out is an empty table. */
53
+ export interface TemplateRefs<R extends TemplateRegistry> {
54
+ readonly email: [ChannelRegistry<R, 'email'>] extends [never] ? EmptyProps : TemplateRefTable<'email', ChannelRegistry<R, 'email'>>;
55
+ readonly push: [ChannelRegistry<R, 'push'>] extends [never] ? EmptyProps : TemplateRefTable<'push', ChannelRegistry<R, 'push'>>;
56
+ readonly discord: [ChannelRegistry<R, 'discord'>] extends [never] ? EmptyProps : TemplateRefTable<'discord', ChannelRegistry<R, 'discord'>>;
57
+ readonly slack: [ChannelRegistry<R, 'slack'>] extends [never] ? EmptyProps : TemplateRefTable<'slack', ChannelRegistry<R, 'slack'>>;
58
+ }
59
+ /**
60
+ * Template references derived from the registries themselves: **the
61
+ * registries type the keys** — an unregistered key fails to compile, and a
62
+ * push template is not accepted where an email is — and each template's
63
+ * `props` schema types its use sites. Templates are registered once; the
64
+ * config takes the registries, the workflows take the references:
65
+ *
66
+ * export const registry = { email, push };
67
+ * export const t = templates(registry);
68
+ * flow.email(t.email.welcome, { name: u.name });
69
+ *
70
+ * Each reference is a plain `{ channel, key }` built from the registry's own
71
+ * keys; no template is rendered, and the registries are left untouched.
72
+ */
73
+ export declare function templates<const R extends TemplateRegistry>(registry: R): TemplateRefs<R>;
74
+ //#endregion
75
+ //# sourceMappingURL=template.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.mts","names":[],"sources":["../../src/dsl/template.ts"],"mappings":";;;YAyBY;YAEA,aAAa;;;;;iBAMR,YAAY,UAAU,UAAU,SAAS,mBAAmB;WAClE,SAAS;WACT;WACA,UAAU;;iBAGJ;EACf,MAAM,mBAAmB,YAAY,cAAc,qBAAqB;EACxE,IAAI,mBAAmB,YAAY,cAAc,mBAAmB;EACpE,KAAK,mBAAmB,YAAY,cAAc,oBAAoB;EACtE,MAAM,mBAAmB,YAAY,cAAc,sBAAsB;EACzE,MAAM,mBAAmB,YAAY,cAAc,qBAAqB;EACxE,QAAQ,mBAAmB,YAAY,cAAc,uBAAuB;EAC5E,OAAO,mBAAmB,YAAY,cAAc,sBAAsB;;;;;;;;;;qBAe/D,UAAU;;YAaX,QAAQ,KAAK,UACrB,oBAAoB,KACpB,mBAAmB,KACnB,sBAAsB,YACtB,oBAAoB,YACpB,KAAK,MAAM,oBACT,KAAK,MAAM,KACX;;;;;;;iBASW,iBACf,UAAU,SAAS,eAAe,kBAAkB,SAAS,eAAe,iBAC5E,UAAU,SAAS,eAAe,iBAAiB,SAAS,eAAe;WAElE,QAAQ;WACR,OAAO;;WAEP,UAAU,SAAS,eAAe,gBAAgB;WAClD,QAAQ,SAAS,eAAe,cAAc;;;KAIpD,gBAAgB,GAAG,oDAAoD,gBAAgB,IACxF,QAAQ,EAAE;;YAIF,iBAAiB,UAAU,SAAS,iBACpC,WAAW,aAAa,YAAY,GAAG,QAAQ,EAAE;;iBAI5C,aAAa,UAAU;WAC7B,QAAQ,gBAAgB,+BAC7B,aACA,0BAA0B,gBAAgB;WACrC,OAAO,gBAAgB,8BAC5B,aACA,yBAAyB,gBAAgB;WACpC,UAAU,gBAAgB,iCAC/B,aACA,4BAA4B,gBAAgB;WACvC,QAAQ,gBAAgB,+BAC7B,aACA,0BAA0B,gBAAgB;;;;;;;;;;;;;;;;wBAiBhC,gBAAgB,UAAU,kBAAkB,UAAU,IAAI,aAAa"}
@@ -0,0 +1,63 @@
1
+ import { isDiscordTemplate, isEmailTemplate, isPushTemplate, isSlackTemplate } from "../templates.mjs";
2
+ //#region src/dsl/template.ts
3
+ const makeTemplate = (channel) => (key) => ({
4
+ channel,
5
+ key
6
+ });
7
+ /**
8
+ * Unbound template references, props typed by hand. Email and push refs come
9
+ * from the registries (`templates<Emails, Pushes>()`), which type both key and
10
+ * props; this is the low-level form for channels without a registry (sms,
11
+ * slack, …) and for tests.
12
+ *
13
+ * const alert = template.slack<{ plan: string }>('cs_churn_alert');
14
+ */
15
+ const template = {
16
+ email: makeTemplate("email"),
17
+ sms: makeTemplate("sms"),
18
+ push: makeTemplate("push"),
19
+ inApp: makeTemplate("in_app"),
20
+ slack: makeTemplate("slack"),
21
+ discord: makeTemplate("discord"),
22
+ survey: makeTemplate("survey")
23
+ };
24
+ /**
25
+ * Template references derived from the registries themselves: **the
26
+ * registries type the keys** — an unregistered key fails to compile, and a
27
+ * push template is not accepted where an email is — and each template's
28
+ * `props` schema types its use sites. Templates are registered once; the
29
+ * config takes the registries, the workflows take the references:
30
+ *
31
+ * export const registry = { email, push };
32
+ * export const t = templates(registry);
33
+ * flow.email(t.email.welcome, { name: u.name });
34
+ *
35
+ * Each reference is a plain `{ channel, key }` built from the registry's own
36
+ * keys; no template is rendered, and the registries are left untouched.
37
+ */
38
+ function templates(registry) {
39
+ return {
40
+ email: refTable("email", registry.email, isEmailTemplate),
41
+ push: refTable("push", registry.push, isPushTemplate),
42
+ discord: refTable("discord", registry.discord, isDiscordTemplate),
43
+ slack: refTable("slack", registry.slack, isSlackTemplate)
44
+ };
45
+ }
46
+ const ARTICLE = {
47
+ email: "an email",
48
+ push: "a push",
49
+ discord: "a Discord",
50
+ slack: "a Slack"
51
+ };
52
+ function refTable(channel, entries, is) {
53
+ const table = Object.create(null);
54
+ for (const [key, entry] of Object.entries(entries ?? {})) {
55
+ if (!is(entry)) throw new TypeError(`templates(): '${key}' in the ${channel} registry is not ${ARTICLE[channel]} template`);
56
+ table[key] = template[channel](key);
57
+ }
58
+ return Object.freeze(table);
59
+ }
60
+ //#endregion
61
+ export { template, templates };
62
+
63
+ //# sourceMappingURL=template.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.mjs","names":[],"sources":["../../src/dsl/template.ts"],"sourcesContent":["/**\n * Templates — named message-content assets. The DSL only ever holds a\n * reference ({ channel, key, phantom props }); the content itself (react-email\n * components) lives in the app and meets the reference again in the studio and\n * at send time via the registry.\n *\n * Type technique: `templates(registry)` derives the references from the\n * registries so **the registries type the keys** — an unregistered key fails\n * to compile — while `PropsOf<M>` reads the props contract off each template's\n * Zod schema, so it is written exactly once.\n */\n\nimport type * as core from 'zod/v4/core';\nimport {\n type DiscordTemplate,\n type EmailTemplate,\n type PropsSchema,\n type PushTemplate,\n type SlackTemplate,\n isDiscordTemplate,\n isEmailTemplate,\n isPushTemplate,\n isSlackTemplate,\n} from '../templates';\n\nexport type Channel = 'email' | 'sms' | 'push' | 'in_app' | 'slack' | 'discord' | 'survey';\n\nexport type EmptyProps = Record<never, never>;\n\n/**\n * Template reference: a top-level named asset, reusable across workflows and\n * versioned on its own. The props shape is declared here and checked at use.\n */\nexport interface TemplateRef<C extends Channel = Channel, P extends object = EmptyProps> {\n readonly channel: C;\n readonly key: string;\n readonly __props?: P;\n}\n\nexport interface TemplateFactory {\n email<P extends object = EmptyProps>(key: string): TemplateRef<'email', P>;\n sms<P extends object = EmptyProps>(key: string): TemplateRef<'sms', P>;\n push<P extends object = EmptyProps>(key: string): TemplateRef<'push', P>;\n inApp<P extends object = EmptyProps>(key: string): TemplateRef<'in_app', P>;\n slack<P extends object = EmptyProps>(key: string): TemplateRef<'slack', P>;\n discord<P extends object = EmptyProps>(key: string): TemplateRef<'discord', P>;\n survey<P extends object = EmptyProps>(key: string): TemplateRef<'survey', P>;\n}\n\nconst makeTemplate =\n <C extends Channel>(channel: C) =>\n <P extends object = EmptyProps>(key: string): TemplateRef<C, P> => ({ channel, key });\n\n/**\n * Unbound template references, props typed by hand. Email and push refs come\n * from the registries (`templates<Emails, Pushes>()`), which type both key and\n * props; this is the low-level form for channels without a registry (sms,\n * slack, …) and for tests.\n *\n * const alert = template.slack<{ plan: string }>('cs_churn_alert');\n */\nexport const template: TemplateFactory = {\n email: makeTemplate('email'),\n sms: makeTemplate('sms'),\n push: makeTemplate('push'),\n inApp: makeTemplate('in_app'),\n slack: makeTemplate('slack'),\n discord: makeTemplate('discord'),\n survey: makeTemplate('survey'),\n};\n\n/* ----------------------------- Template registry ---------------------------- */\n\n/** Template props: the input type of the template's Zod `props` schema — what the DSL passes. */\nexport type PropsOf<M> = M extends\n | EmailTemplate<infer S>\n | PushTemplate<infer S>\n | DiscordTemplate<infer S, never>\n | SlackTemplate<infer S, never>\n ? core.input<S> extends object\n ? core.input<S>\n : EmptyProps\n : never;\n\n/**\n * The channel registries: what the config registers as `templates` and what\n * `templates()` derives the references from — one type for both. Leave it\n * inferred, or check it with `satisfies TemplateRegistry`: annotating a value\n * as the bare type widens the keys to `string`.\n */\nexport interface TemplateRegistry<\n E extends Readonly<Record<string, EmailTemplate>> = Readonly<Record<string, EmailTemplate>>,\n P extends Readonly<Record<string, PushTemplate>> = Readonly<Record<string, PushTemplate>>,\n> {\n readonly email?: E;\n readonly push?: P;\n /** Discord webhook templates, each typed by the host's Env its `webhook` reads. */\n readonly discord?: Readonly<Record<string, DiscordTemplate<PropsSchema, never>>>;\n readonly slack?: Readonly<Record<string, SlackTemplate<PropsSchema, never>>>;\n}\n\n/** One channel's registry in `R`, without the `undefined` of an optional field; `never` when absent. */\ntype ChannelRegistry<R, K extends 'email' | 'push' | 'discord' | 'slack'> = K extends keyof R\n ? Exclude<R[K], undefined>\n : never;\n\n/** One reference per registered key, each typed by its own template's `props`. */\nexport type TemplateRefTable<C extends Channel, R> = {\n readonly [K in keyof R & string]: TemplateRef<C, PropsOf<R[K]>>;\n};\n\n/** `t.email.<key>` / `t.push.<key>`; a channel the registry leaves out is an empty table. */\nexport interface TemplateRefs<R extends TemplateRegistry> {\n readonly email: [ChannelRegistry<R, 'email'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'email', ChannelRegistry<R, 'email'>>;\n readonly push: [ChannelRegistry<R, 'push'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'push', ChannelRegistry<R, 'push'>>;\n readonly discord: [ChannelRegistry<R, 'discord'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'discord', ChannelRegistry<R, 'discord'>>;\n readonly slack: [ChannelRegistry<R, 'slack'>] extends [never]\n ? EmptyProps\n : TemplateRefTable<'slack', ChannelRegistry<R, 'slack'>>;\n}\n\n/**\n * Template references derived from the registries themselves: **the\n * registries type the keys** — an unregistered key fails to compile, and a\n * push template is not accepted where an email is — and each template's\n * `props` schema types its use sites. Templates are registered once; the\n * config takes the registries, the workflows take the references:\n *\n * export const registry = { email, push };\n * export const t = templates(registry);\n * flow.email(t.email.welcome, { name: u.name });\n *\n * Each reference is a plain `{ channel, key }` built from the registry's own\n * keys; no template is rendered, and the registries are left untouched.\n */\nexport function templates<const R extends TemplateRegistry>(registry: R): TemplateRefs<R> {\n return {\n email: refTable('email', registry.email, isEmailTemplate),\n push: refTable('push', registry.push, isPushTemplate),\n discord: refTable('discord', registry.discord, isDiscordTemplate),\n slack: refTable('slack', registry.slack, isSlackTemplate),\n } as unknown as TemplateRefs<R>;\n}\n\nconst ARTICLE: Record<'email' | 'push' | 'discord' | 'slack', string> = {\n email: 'an email',\n push: 'a push',\n discord: 'a Discord',\n slack: 'a Slack',\n};\n\nfunction refTable(\n channel: 'email' | 'push' | 'discord' | 'slack',\n entries: Readonly<Record<string, unknown>> | undefined,\n is: (value: unknown) => boolean\n): Readonly<Record<string, TemplateRef>> {\n const table: Record<string, TemplateRef> = Object.create(null);\n for (const [key, entry] of Object.entries(entries ?? {})) {\n if (!is(entry)) {\n throw new TypeError(\n `templates(): '${key}' in the ${channel} registry is not ${ARTICLE[channel]} template`\n );\n }\n table[key] = template[channel](key);\n }\n return Object.freeze(table);\n}\n"],"mappings":";;AAiDA,MAAM,gBACgB,aACY,SAAoC;CAAE;CAAS;AAAI;;;;;;;;;AAUrF,MAAa,WAA4B;CACvC,OAAO,aAAa,OAAO;CAC3B,KAAK,aAAa,KAAK;CACvB,MAAM,aAAa,MAAM;CACzB,OAAO,aAAa,QAAQ;CAC5B,OAAO,aAAa,OAAO;CAC3B,SAAS,aAAa,SAAS;CAC/B,QAAQ,aAAa,QAAQ;AAC/B;;;;;;;;;;;;;;;AAwEA,SAAgB,UAA4C,UAA8B;CACxF,OAAO;EACL,OAAO,SAAS,SAAS,SAAS,OAAO,eAAe;EACxD,MAAM,SAAS,QAAQ,SAAS,MAAM,cAAc;EACpD,SAAS,SAAS,WAAW,SAAS,SAAS,iBAAiB;EAChE,OAAO,SAAS,SAAS,SAAS,OAAO,eAAe;CAC1D;AACF;AAEA,MAAM,UAAkE;CACtE,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;AACT;AAEA,SAAS,SACP,SACA,SACA,IACuC;CACvC,MAAM,QAAqC,OAAO,OAAO,IAAI;CAC7D,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,WAAW,CAAC,CAAC,GAAG;EACxD,IAAI,CAAC,GAAG,KAAK,GACX,MAAM,IAAI,UACR,iBAAiB,IAAI,WAAW,QAAQ,mBAAmB,QAAQ,SAAS,UAC9E;EAEF,MAAM,OAAO,SAAS,QAAQ,CAAC,GAAG;CACpC;CACA,OAAO,OAAO,OAAO,KAAK;AAC5B"}