@relayflows/surface 2.0.9 → 2.0.11

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 (343) hide show
  1. package/README.md +3 -2
  2. package/dist/completion.d.ts +2 -0
  3. package/dist/completion.d.ts.map +1 -1
  4. package/dist/context.d.ts +27 -6
  5. package/dist/context.d.ts.map +1 -1
  6. package/dist/effect-transport.d.ts +22 -0
  7. package/dist/effect-transport.d.ts.map +1 -0
  8. package/dist/effect-transport.js +42 -0
  9. package/dist/effect-transport.js.map +1 -0
  10. package/dist/flow.d.ts +30 -17
  11. package/dist/flow.d.ts.map +1 -1
  12. package/dist/flow.js +58 -73
  13. package/dist/flow.js.map +1 -1
  14. package/dist/helper-clients.d.ts +86 -0
  15. package/dist/helper-clients.d.ts.map +1 -0
  16. package/dist/helper-clients.js +30 -0
  17. package/dist/helper-clients.js.map +1 -0
  18. package/dist/helpers/airtable.d.ts +4 -0
  19. package/dist/helpers/airtable.d.ts.map +1 -0
  20. package/dist/helpers/airtable.js +5 -0
  21. package/dist/helpers/airtable.js.map +1 -0
  22. package/dist/helpers/asana.d.ts +5 -0
  23. package/dist/helpers/asana.d.ts.map +1 -0
  24. package/dist/helpers/asana.js +6 -0
  25. package/dist/helpers/asana.js.map +1 -0
  26. package/dist/helpers/azure-blob.d.ts +5 -0
  27. package/dist/helpers/azure-blob.d.ts.map +1 -0
  28. package/dist/helpers/azure-blob.js +6 -0
  29. package/dist/helpers/azure-blob.js.map +1 -0
  30. package/dist/helpers/box.d.ts +5 -0
  31. package/dist/helpers/box.d.ts.map +1 -0
  32. package/dist/helpers/box.js +6 -0
  33. package/dist/helpers/box.js.map +1 -0
  34. package/dist/helpers/calendly.d.ts +5 -0
  35. package/dist/helpers/calendly.d.ts.map +1 -0
  36. package/dist/helpers/calendly.js +6 -0
  37. package/dist/helpers/calendly.js.map +1 -0
  38. package/dist/helpers/clickup.d.ts +5 -0
  39. package/dist/helpers/clickup.d.ts.map +1 -0
  40. package/dist/helpers/clickup.js +6 -0
  41. package/dist/helpers/clickup.js.map +1 -0
  42. package/dist/helpers/clients.d.ts +3 -0
  43. package/dist/helpers/clients.d.ts.map +1 -0
  44. package/dist/helpers/clients.js +46 -0
  45. package/dist/helpers/clients.js.map +1 -0
  46. package/dist/helpers/cloudflare.d.ts +5 -0
  47. package/dist/helpers/cloudflare.d.ts.map +1 -0
  48. package/dist/helpers/cloudflare.js +6 -0
  49. package/dist/helpers/cloudflare.js.map +1 -0
  50. package/dist/helpers/confluence.d.ts +5 -0
  51. package/dist/helpers/confluence.d.ts.map +1 -0
  52. package/dist/helpers/confluence.js +6 -0
  53. package/dist/helpers/confluence.js.map +1 -0
  54. package/dist/helpers/daytona.d.ts +5 -0
  55. package/dist/helpers/daytona.d.ts.map +1 -0
  56. package/dist/helpers/daytona.js +6 -0
  57. package/dist/helpers/daytona.js.map +1 -0
  58. package/dist/helpers/docker-hub.d.ts +4 -0
  59. package/dist/helpers/docker-hub.d.ts.map +1 -0
  60. package/dist/helpers/docker-hub.js +5 -0
  61. package/dist/helpers/docker-hub.js.map +1 -0
  62. package/dist/helpers/dropbox.d.ts +5 -0
  63. package/dist/helpers/dropbox.d.ts.map +1 -0
  64. package/dist/helpers/dropbox.js +6 -0
  65. package/dist/helpers/dropbox.js.map +1 -0
  66. package/dist/helpers/fathom.d.ts +4 -0
  67. package/dist/helpers/fathom.d.ts.map +1 -0
  68. package/dist/helpers/fathom.js +5 -0
  69. package/dist/helpers/fathom.js.map +1 -0
  70. package/dist/helpers/gcp.d.ts +4 -0
  71. package/dist/helpers/gcp.d.ts.map +1 -0
  72. package/dist/helpers/gcp.js +5 -0
  73. package/dist/helpers/gcp.js.map +1 -0
  74. package/dist/helpers/gcs.d.ts +5 -0
  75. package/dist/helpers/gcs.d.ts.map +1 -0
  76. package/dist/helpers/gcs.js +6 -0
  77. package/dist/helpers/gcs.js.map +1 -0
  78. package/dist/helpers/github.d.ts +5 -0
  79. package/dist/helpers/github.d.ts.map +1 -0
  80. package/dist/helpers/github.js +6 -0
  81. package/dist/helpers/github.js.map +1 -0
  82. package/dist/helpers/gitlab.d.ts +5 -0
  83. package/dist/helpers/gitlab.d.ts.map +1 -0
  84. package/dist/helpers/gitlab.js +6 -0
  85. package/dist/helpers/gitlab.js.map +1 -0
  86. package/dist/helpers/gmail.d.ts +5 -0
  87. package/dist/helpers/gmail.d.ts.map +1 -0
  88. package/dist/helpers/gmail.js +6 -0
  89. package/dist/helpers/gmail.js.map +1 -0
  90. package/dist/helpers/google-calendar.d.ts +5 -0
  91. package/dist/helpers/google-calendar.d.ts.map +1 -0
  92. package/dist/helpers/google-calendar.js +6 -0
  93. package/dist/helpers/google-calendar.js.map +1 -0
  94. package/dist/helpers/google-drive.d.ts +5 -0
  95. package/dist/helpers/google-drive.d.ts.map +1 -0
  96. package/dist/helpers/google-drive.js +6 -0
  97. package/dist/helpers/google-drive.js.map +1 -0
  98. package/dist/helpers/granola.d.ts +5 -0
  99. package/dist/helpers/granola.d.ts.map +1 -0
  100. package/dist/helpers/granola.js +6 -0
  101. package/dist/helpers/granola.js.map +1 -0
  102. package/dist/helpers/hubspot.d.ts +5 -0
  103. package/dist/helpers/hubspot.d.ts.map +1 -0
  104. package/dist/helpers/hubspot.js +6 -0
  105. package/dist/helpers/hubspot.js.map +1 -0
  106. package/dist/helpers/index.d.ts +155 -0
  107. package/dist/helpers/index.d.ts.map +1 -0
  108. package/dist/helpers/index.js +105 -0
  109. package/dist/helpers/index.js.map +1 -0
  110. package/dist/helpers/intercom.d.ts +5 -0
  111. package/dist/helpers/intercom.d.ts.map +1 -0
  112. package/dist/helpers/intercom.js +6 -0
  113. package/dist/helpers/intercom.js.map +1 -0
  114. package/dist/helpers/jira.d.ts +5 -0
  115. package/dist/helpers/jira.d.ts.map +1 -0
  116. package/dist/helpers/jira.js +6 -0
  117. package/dist/helpers/jira.js.map +1 -0
  118. package/dist/helpers/linear.d.ts +5 -0
  119. package/dist/helpers/linear.d.ts.map +1 -0
  120. package/dist/helpers/linear.js +6 -0
  121. package/dist/helpers/linear.js.map +1 -0
  122. package/dist/helpers/mailgun.d.ts +5 -0
  123. package/dist/helpers/mailgun.d.ts.map +1 -0
  124. package/dist/helpers/mailgun.js +6 -0
  125. package/dist/helpers/mailgun.js.map +1 -0
  126. package/dist/helpers/mixpanel.d.ts +5 -0
  127. package/dist/helpers/mixpanel.d.ts.map +1 -0
  128. package/dist/helpers/mixpanel.js +6 -0
  129. package/dist/helpers/mixpanel.js.map +1 -0
  130. package/dist/helpers/neon.d.ts +4 -0
  131. package/dist/helpers/neon.d.ts.map +1 -0
  132. package/dist/helpers/neon.js +5 -0
  133. package/dist/helpers/neon.js.map +1 -0
  134. package/dist/helpers/notion.d.ts +5 -0
  135. package/dist/helpers/notion.d.ts.map +1 -0
  136. package/dist/helpers/notion.js +6 -0
  137. package/dist/helpers/notion.js.map +1 -0
  138. package/dist/helpers/onedrive.d.ts +5 -0
  139. package/dist/helpers/onedrive.d.ts.map +1 -0
  140. package/dist/helpers/onedrive.js +6 -0
  141. package/dist/helpers/onedrive.js.map +1 -0
  142. package/dist/helpers/pipedrive.d.ts +5 -0
  143. package/dist/helpers/pipedrive.d.ts.map +1 -0
  144. package/dist/helpers/pipedrive.js +6 -0
  145. package/dist/helpers/pipedrive.js.map +1 -0
  146. package/dist/helpers/postgres.d.ts +5 -0
  147. package/dist/helpers/postgres.d.ts.map +1 -0
  148. package/dist/helpers/postgres.js +6 -0
  149. package/dist/helpers/postgres.js.map +1 -0
  150. package/dist/helpers/posthog.d.ts +4 -0
  151. package/dist/helpers/posthog.d.ts.map +1 -0
  152. package/dist/helpers/posthog.js +5 -0
  153. package/dist/helpers/posthog.js.map +1 -0
  154. package/dist/helpers/providers.d.ts +252 -0
  155. package/dist/helpers/providers.d.ts.map +1 -0
  156. package/dist/helpers/providers.js +305 -0
  157. package/dist/helpers/providers.js.map +1 -0
  158. package/dist/helpers/ramp.d.ts +7 -0
  159. package/dist/helpers/ramp.d.ts.map +1 -0
  160. package/dist/helpers/ramp.js +7 -0
  161. package/dist/helpers/ramp.js.map +1 -0
  162. package/dist/helpers/recall.d.ts +5 -0
  163. package/dist/helpers/recall.d.ts.map +1 -0
  164. package/dist/helpers/recall.js +6 -0
  165. package/dist/helpers/recall.js.map +1 -0
  166. package/dist/helpers/reddit.d.ts +5 -0
  167. package/dist/helpers/reddit.d.ts.map +1 -0
  168. package/dist/helpers/reddit.js +6 -0
  169. package/dist/helpers/reddit.js.map +1 -0
  170. package/dist/helpers/redis.d.ts +5 -0
  171. package/dist/helpers/redis.d.ts.map +1 -0
  172. package/dist/helpers/redis.js +6 -0
  173. package/dist/helpers/redis.js.map +1 -0
  174. package/dist/helpers/s3.d.ts +5 -0
  175. package/dist/helpers/s3.d.ts.map +1 -0
  176. package/dist/helpers/s3.js +6 -0
  177. package/dist/helpers/s3.js.map +1 -0
  178. package/dist/helpers/salesforce.d.ts +5 -0
  179. package/dist/helpers/salesforce.d.ts.map +1 -0
  180. package/dist/helpers/salesforce.js +6 -0
  181. package/dist/helpers/salesforce.js.map +1 -0
  182. package/dist/helpers/segment.d.ts +4 -0
  183. package/dist/helpers/segment.d.ts.map +1 -0
  184. package/dist/helpers/segment.js +5 -0
  185. package/dist/helpers/segment.js.map +1 -0
  186. package/dist/helpers/sendgrid.d.ts +5 -0
  187. package/dist/helpers/sendgrid.d.ts.map +1 -0
  188. package/dist/helpers/sendgrid.js +6 -0
  189. package/dist/helpers/sendgrid.js.map +1 -0
  190. package/dist/helpers/sharepoint.d.ts +5 -0
  191. package/dist/helpers/sharepoint.d.ts.map +1 -0
  192. package/dist/helpers/sharepoint.js +6 -0
  193. package/dist/helpers/sharepoint.js.map +1 -0
  194. package/dist/helpers/shopify.d.ts +4 -0
  195. package/dist/helpers/shopify.d.ts.map +1 -0
  196. package/dist/helpers/shopify.js +5 -0
  197. package/dist/helpers/shopify.js.map +1 -0
  198. package/dist/helpers/shortcut.d.ts +5 -0
  199. package/dist/helpers/shortcut.d.ts.map +1 -0
  200. package/dist/helpers/shortcut.js +6 -0
  201. package/dist/helpers/shortcut.js.map +1 -0
  202. package/dist/helpers/slack.d.ts +17 -0
  203. package/dist/helpers/slack.d.ts.map +1 -0
  204. package/dist/helpers/slack.js +4 -0
  205. package/dist/helpers/slack.js.map +1 -0
  206. package/dist/helpers/stripe.d.ts +5 -0
  207. package/dist/helpers/stripe.d.ts.map +1 -0
  208. package/dist/helpers/stripe.js +6 -0
  209. package/dist/helpers/stripe.js.map +1 -0
  210. package/dist/helpers/teams.d.ts +5 -0
  211. package/dist/helpers/teams.d.ts.map +1 -0
  212. package/dist/helpers/teams.js +6 -0
  213. package/dist/helpers/teams.js.map +1 -0
  214. package/dist/helpers/telegram.d.ts +5 -0
  215. package/dist/helpers/telegram.d.ts.map +1 -0
  216. package/dist/helpers/telegram.js +6 -0
  217. package/dist/helpers/telegram.js.map +1 -0
  218. package/dist/helpers/webhook-server.d.ts +4 -0
  219. package/dist/helpers/webhook-server.d.ts.map +1 -0
  220. package/dist/helpers/webhook-server.js +5 -0
  221. package/dist/helpers/webhook-server.js.map +1 -0
  222. package/dist/helpers/x.d.ts +4 -0
  223. package/dist/helpers/x.d.ts.map +1 -0
  224. package/dist/helpers/x.js +5 -0
  225. package/dist/helpers/x.js.map +1 -0
  226. package/dist/helpers/zendesk.d.ts +5 -0
  227. package/dist/helpers/zendesk.d.ts.map +1 -0
  228. package/dist/helpers/zendesk.js +6 -0
  229. package/dist/helpers/zendesk.js.map +1 -0
  230. package/dist/index.d.ts +11 -4
  231. package/dist/index.d.ts.map +1 -1
  232. package/dist/index.js +3 -0
  233. package/dist/index.js.map +1 -1
  234. package/dist/memory.d.ts +19 -0
  235. package/dist/memory.d.ts.map +1 -0
  236. package/dist/memory.js +2 -0
  237. package/dist/memory.js.map +1 -0
  238. package/dist/plugin-contract.d.ts +5 -0
  239. package/dist/plugin-contract.d.ts.map +1 -0
  240. package/dist/plugin-contract.js +2 -0
  241. package/dist/plugin-contract.js.map +1 -0
  242. package/dist/provider-trigger.d.ts +13 -0
  243. package/dist/provider-trigger.d.ts.map +1 -0
  244. package/dist/provider-trigger.js +18 -0
  245. package/dist/provider-trigger.js.map +1 -0
  246. package/dist/runtime.d.ts +6 -1
  247. package/dist/runtime.d.ts.map +1 -1
  248. package/dist/runtime.js +5 -0
  249. package/dist/runtime.js.map +1 -1
  250. package/dist/slack.d.ts +34 -0
  251. package/dist/slack.d.ts.map +1 -0
  252. package/dist/slack.js +17 -0
  253. package/dist/slack.js.map +1 -0
  254. package/dist/step.d.ts +43 -1
  255. package/dist/step.d.ts.map +1 -1
  256. package/dist/triggers/github.d.ts +8 -0
  257. package/dist/triggers/github.d.ts.map +1 -0
  258. package/dist/triggers/github.js +17 -0
  259. package/dist/triggers/github.js.map +1 -0
  260. package/dist/triggers/index.d.ts +8 -0
  261. package/dist/triggers/index.d.ts.map +1 -0
  262. package/dist/triggers/index.js +9 -0
  263. package/dist/triggers/index.js.map +1 -0
  264. package/dist/triggers/slack.d.ts +8 -0
  265. package/dist/triggers/slack.d.ts.map +1 -0
  266. package/dist/triggers/slack.js +17 -0
  267. package/dist/triggers/slack.js.map +1 -0
  268. package/dist/triggers.d.ts +15 -0
  269. package/dist/triggers.d.ts.map +1 -0
  270. package/dist/triggers.js +43 -0
  271. package/dist/triggers.js.map +1 -0
  272. package/package.json +21 -2
  273. package/src/completion.ts +3 -0
  274. package/src/context.ts +26 -6
  275. package/src/effect-transport.ts +59 -0
  276. package/src/flow.ts +77 -106
  277. package/src/helper-clients.ts +30 -0
  278. package/src/helpers/README.md +42 -0
  279. package/src/helpers/airtable.ts +9 -0
  280. package/src/helpers/asana.ts +10 -0
  281. package/src/helpers/azure-blob.ts +10 -0
  282. package/src/helpers/box.ts +10 -0
  283. package/src/helpers/calendly.ts +10 -0
  284. package/src/helpers/clickup.ts +10 -0
  285. package/src/helpers/clients.ts +48 -0
  286. package/src/helpers/cloudflare.ts +10 -0
  287. package/src/helpers/confluence.ts +10 -0
  288. package/src/helpers/daytona.ts +10 -0
  289. package/src/helpers/docker-hub.ts +9 -0
  290. package/src/helpers/dropbox.ts +10 -0
  291. package/src/helpers/fathom.ts +9 -0
  292. package/src/helpers/gcp.ts +9 -0
  293. package/src/helpers/gcs.ts +10 -0
  294. package/src/helpers/github.ts +10 -0
  295. package/src/helpers/gitlab.ts +10 -0
  296. package/src/helpers/gmail.ts +10 -0
  297. package/src/helpers/google-calendar.ts +10 -0
  298. package/src/helpers/google-drive.ts +10 -0
  299. package/src/helpers/granola.ts +10 -0
  300. package/src/helpers/hubspot.ts +10 -0
  301. package/src/helpers/index.ts +212 -0
  302. package/src/helpers/intercom.ts +10 -0
  303. package/src/helpers/jira.ts +10 -0
  304. package/src/helpers/linear.ts +10 -0
  305. package/src/helpers/mailgun.ts +10 -0
  306. package/src/helpers/mixpanel.ts +10 -0
  307. package/src/helpers/neon.ts +9 -0
  308. package/src/helpers/notion.ts +10 -0
  309. package/src/helpers/onedrive.ts +10 -0
  310. package/src/helpers/pipedrive.ts +10 -0
  311. package/src/helpers/postgres.ts +10 -0
  312. package/src/helpers/posthog.ts +9 -0
  313. package/src/helpers/providers.ts +305 -0
  314. package/src/helpers/ramp.ts +12 -0
  315. package/src/helpers/recall.ts +10 -0
  316. package/src/helpers/reddit.ts +10 -0
  317. package/src/helpers/redis.ts +10 -0
  318. package/src/helpers/s3.ts +10 -0
  319. package/src/helpers/salesforce.ts +10 -0
  320. package/src/helpers/segment.ts +9 -0
  321. package/src/helpers/sendgrid.ts +10 -0
  322. package/src/helpers/sharepoint.ts +10 -0
  323. package/src/helpers/shopify.ts +9 -0
  324. package/src/helpers/shortcut.ts +10 -0
  325. package/src/helpers/slack.ts +16 -0
  326. package/src/helpers/stripe.ts +10 -0
  327. package/src/helpers/teams.ts +10 -0
  328. package/src/helpers/telegram.ts +10 -0
  329. package/src/helpers/webhook-server.ts +9 -0
  330. package/src/helpers/x.ts +9 -0
  331. package/src/helpers/zendesk.ts +10 -0
  332. package/src/index.ts +26 -3
  333. package/src/memory.ts +20 -0
  334. package/src/plugin-contract.ts +5 -0
  335. package/src/provider-trigger.ts +26 -0
  336. package/src/runtime.ts +8 -0
  337. package/src/slack.ts +47 -0
  338. package/src/step.ts +52 -1
  339. package/src/triggers/README.md +75 -0
  340. package/src/triggers/github.ts +19 -0
  341. package/src/triggers/index.ts +10 -0
  342. package/src/triggers/slack.ts +19 -0
  343. package/src/triggers.ts +49 -0
@@ -0,0 +1,12 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { providerClient } from "@relayfile/relay-helpers";
5
+ import type { RelayClientOptions } from "@relayfile/relay-helpers/transport";
6
+ const rampClient = (options: RelayClientOptions) => providerClient("ramp", options);
7
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
8
+
9
+ export type RampHelper = JournalHelper<ReturnType<typeof rampClient>>;
10
+
11
+ export const createRampHelper = (dispatch: EffectDispatcher): RampHelper =>
12
+ bindHelper("ramp", rampClient, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { recallClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type RecallHelper = JournalHelper<ReturnType<typeof recallClient>>;
8
+
9
+ export const createRecallHelper = (dispatch: EffectDispatcher): RecallHelper =>
10
+ bindHelper("recall", recallClient, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { redditClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type RedditHelper = JournalHelper<ReturnType<typeof redditClient>>;
8
+
9
+ export const createRedditHelper = (dispatch: EffectDispatcher): RedditHelper =>
10
+ bindHelper("reddit", redditClient, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { redisClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type RedisHelper = JournalHelper<ReturnType<typeof redisClient>>;
8
+
9
+ export const createRedisHelper = (dispatch: EffectDispatcher): RedisHelper =>
10
+ bindHelper("redis", redisClient, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { s3Client } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type S3Helper = JournalHelper<ReturnType<typeof s3Client>>;
8
+
9
+ export const createS3Helper = (dispatch: EffectDispatcher): S3Helper =>
10
+ bindHelper("s3", s3Client, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { salesforceClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type SalesforceHelper = JournalHelper<ReturnType<typeof salesforceClient>>;
8
+
9
+ export const createSalesforceHelper = (dispatch: EffectDispatcher): SalesforceHelper =>
10
+ bindHelper("salesforce", salesforceClient, dispatch);
@@ -0,0 +1,9 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { bindHelper, type EffectDispatcher, type JournalHelper, type UnavailableHelper } from "../effect-transport.js";
5
+
6
+ export type SegmentHelper = UnavailableHelper;
7
+
8
+ export const createSegmentHelper = (dispatch: EffectDispatcher): SegmentHelper =>
9
+ bindHelper("segment", undefined, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { sendgridClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type SendgridHelper = JournalHelper<ReturnType<typeof sendgridClient>>;
8
+
9
+ export const createSendgridHelper = (dispatch: EffectDispatcher): SendgridHelper =>
10
+ bindHelper("sendgrid", sendgridClient, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { sharepointClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type SharepointHelper = JournalHelper<ReturnType<typeof sharepointClient>>;
8
+
9
+ export const createSharepointHelper = (dispatch: EffectDispatcher): SharepointHelper =>
10
+ bindHelper("sharepoint", sharepointClient, dispatch);
@@ -0,0 +1,9 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { bindHelper, type EffectDispatcher, type JournalHelper, type UnavailableHelper } from "../effect-transport.js";
5
+
6
+ export type ShopifyHelper = UnavailableHelper;
7
+
8
+ export const createShopifyHelper = (dispatch: EffectDispatcher): ShopifyHelper =>
9
+ bindHelper("shopify", undefined, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { shortcutClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type ShortcutHelper = JournalHelper<ReturnType<typeof shortcutClient>>;
8
+
9
+ export const createShortcutHelper = (dispatch: EffectDispatcher): ShortcutHelper =>
10
+ bindHelper("shortcut", shortcutClient, dispatch);
@@ -0,0 +1,16 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import type { SlackHelper as RuntimeSlackHelper } from "../slack.js";
5
+
6
+ /** Generated from the pinned Slack OpenAPI fragments in scripts/slack-message-schema.json. */
7
+ export type SlackBlock = { type: string; [key: string]: unknown; };
8
+ export type SlackAttachment = { [key: string]: unknown; };
9
+
10
+ /** Adapter argument shapes over the journal-backed Slack dispatcher. */
11
+ export interface SlackHelper {
12
+ post(...args: Parameters<RuntimeSlackHelper["post"]>): ReturnType<RuntimeSlackHelper["post"]>;
13
+ dm(user: string, text: string): ReturnType<RuntimeSlackHelper["dm"]>;
14
+ reply(channel: string, threadTs: string, text: string): ReturnType<RuntimeSlackHelper["reply"]>;
15
+ react(channel: string, messageTs: string, emoji: string): ReturnType<RuntimeSlackHelper["react"]>;
16
+ }
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { stripeClient } from "../helper-clients.js";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type StripeHelper = JournalHelper<ReturnType<typeof stripeClient>>;
8
+
9
+ export const createStripeHelper = (dispatch: EffectDispatcher): StripeHelper =>
10
+ bindHelper("stripe", stripeClient, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { teamsClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type TeamsHelper = JournalHelper<ReturnType<typeof teamsClient>>;
8
+
9
+ export const createTeamsHelper = (dispatch: EffectDispatcher): TeamsHelper =>
10
+ bindHelper("teams", teamsClient, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { telegramClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type TelegramHelper = JournalHelper<ReturnType<typeof telegramClient>>;
8
+
9
+ export const createTelegramHelper = (dispatch: EffectDispatcher): TelegramHelper =>
10
+ bindHelper("telegram", telegramClient, dispatch);
@@ -0,0 +1,9 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { bindHelper, type EffectDispatcher, type JournalHelper, type UnavailableHelper } from "../effect-transport.js";
5
+
6
+ export type WebhookServerHelper = UnavailableHelper;
7
+
8
+ export const createWebhookServerHelper = (dispatch: EffectDispatcher): WebhookServerHelper =>
9
+ bindHelper("webhook-server", undefined, dispatch);
@@ -0,0 +1,9 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { bindHelper, type EffectDispatcher, type JournalHelper, type UnavailableHelper } from "../effect-transport.js";
5
+
6
+ export type XHelper = UnavailableHelper;
7
+
8
+ export const createXHelper = (dispatch: EffectDispatcher): XHelper =>
9
+ bindHelper("x", undefined, dispatch);
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-helpers.mjs — do not edit.
2
+ // Run `npm run gen --prefix packages/surface` from the repository root.
3
+
4
+ import { zendeskClient } from "@relayfile/relay-helpers";
5
+ import { bindHelper, type EffectDispatcher, type JournalHelper } from "../effect-transport.js";
6
+
7
+ export type ZendeskHelper = JournalHelper<ReturnType<typeof zendeskClient>>;
8
+
9
+ export const createZendeskHelper = (dispatch: EffectDispatcher): ZendeskHelper =>
10
+ bindHelper("zendesk", zendeskClient, dispatch);
package/src/index.ts CHANGED
@@ -7,17 +7,40 @@ export type {
7
7
  WorkerSummary,
8
8
  CloudHelper,
9
9
  } from "./cloud.js";
10
- export type { AgentOptions, AgentResult, Ctx } from "./context.js";
10
+ export type { AgentOptions, AgentResult, LlmOptions, Ctx } from "./context.js";
11
11
  export {
12
12
  COMPLETION_REASONS,
13
13
  RUN_COMPLETION_REASONS,
14
14
  type CompletionReason,
15
15
  type RunCompletionReason,
16
+ type FlowCompletionReason,
16
17
  } from "./completion.js";
17
- export type { Step } from "./step.js";
18
+ export type {
19
+ Step,
20
+ NamedGate,
21
+ ReferencesInputNamedGate,
22
+ SubprocessNamedGate,
23
+ WordCountBoundsNamedGate,
24
+ RegexMatchNamedGate,
25
+ } from "./step.js";
18
26
  export {
19
27
  flow,
20
28
  type FlowHandle,
29
+ type TriggeredFlowHandle,
21
30
  type FlowHeader,
22
- type NamedAgentDeclaration,
23
31
  } from "./flow.js";
32
+ export {
33
+ flowRunWritebackIdempotency,
34
+ type SlackHelper,
35
+ type SlackReceipt,
36
+ type SlackBlock,
37
+ type SlackAttachment,
38
+ type SlackPostMessage,
39
+ type SlackPostOptions,
40
+ } from "./slack.js";
41
+ export type { Helpers } from "./helpers/index.js";
42
+ export type { MemoryHelper, MemoryFinding, MemoryRecallOptions, HistoryEntry, TrajectoryEntry } from "./memory.js";
43
+ export { webhook, type TriggerSource, type WebhookFilter, type WebhookValue } from "./triggers.js";
44
+ export * from "./triggers/index.js";
45
+ export type { ProviderTriggerSource } from "./provider-trigger.js";
46
+ export type { PluginMethod, PluginPrimitive } from './plugin-contract.js';
package/src/memory.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { HistoryEntry, SearchOptions, TrajectoryEntry } from "ai-hist";
2
+
3
+ export type { HistoryEntry, TrajectoryEntry } from "ai-hist";
4
+ /** Reads cannot widen the current flow's script scope. */
5
+ export type MemoryRecallOptions = Omit<SearchOptions, "project">;
6
+ export interface MemoryFinding {
7
+ question: string;
8
+ chosen: string;
9
+ reasoning: string;
10
+ alternatives?: string[];
11
+ }
12
+
13
+ export interface MemoryHelper {
14
+ /** Local script memory read; does not journal a step. */
15
+ recall(query: string, options?: MemoryRecallOptions): Promise<HistoryEntry[]>;
16
+ /** Best matching decision trajectory, or an empty array. No journal step. */
17
+ why(task: string): Promise<TrajectoryEntry[]>;
18
+ /** Reserved for the journal-backed write slice; currently refuses. */
19
+ learn(finding: MemoryFinding): Promise<void>;
20
+ }
@@ -0,0 +1,5 @@
1
+ import type { Step } from './step.js';
2
+
3
+ /** Plugins augment Ctx in @relayflows/surface; no catch-all index signature. */
4
+ export type PluginMethod<Args, Output = unknown> = (args: Args) => Step<Output>;
5
+ export type PluginPrimitive = 'run' | 'llm' | 'agent' | 'effect' | 'wait';
@@ -0,0 +1,26 @@
1
+ import { webhook, type TriggerSource, type WebhookFilter } from "./triggers.js";
2
+
3
+ /** A provider inbox subscription over an envelope's type and payload. */
4
+ export interface ProviderTriggerSource<Provider extends string, Event extends string> extends TriggerSource {
5
+ readonly name: Provider;
6
+ readonly filter: WebhookFilter & { readonly provider: Provider; readonly type: Event };
7
+ }
8
+
9
+ /** Shared implementation for generated provider declarations. */
10
+ export function providerTrigger<P extends string, E extends string>(
11
+ provider: P, event: E, payload?: WebhookFilter,
12
+ ): ProviderTriggerSource<P, E> {
13
+ if (typeof event !== "string" || event.length === 0) throw new TypeError("provider event type must not be empty");
14
+ // Validate separately so an invalid payload cannot become a scalar filter leaf.
15
+ const filter = webhook(provider, payload).filter;
16
+ return webhook(provider, {
17
+ provider, type: event, ...(filter === undefined ? {} : { payload: filter }),
18
+ }) as ProviderTriggerSource<P, E>;
19
+ }
20
+
21
+ export function triggerArgument(value: string, name: string): string {
22
+ if (typeof value !== "string" || value.trim().length === 0) {
23
+ throw new TypeError(`${name} must be a nonempty string`);
24
+ }
25
+ return value;
26
+ }
package/src/runtime.ts CHANGED
@@ -3,5 +3,13 @@ export {
3
3
  type AuthoredFlowDefinition,
4
4
  type FlowBody,
5
5
  type FlowHandle,
6
+ type TriggerHandler,
7
+ type TriggeredFlowHandle,
6
8
  type ReadonlyFlowHeader,
7
9
  } from "./flow.js";
10
+ export { slackPostBody } from "./slack.js";
11
+
12
+ export { createHelpers } from "./helpers/index.js";
13
+ export { helperProviders } from "./helpers/providers.js";
14
+ export { helperClients } from "./helpers/clients.js";
15
+ export { invokeHelper, type HelperCall } from "./effect-transport.js";
package/src/slack.ts ADDED
@@ -0,0 +1,47 @@
1
+ import type { Step } from "./step.js";
2
+ import type { SlackAttachment, SlackBlock } from "./helpers/slack.js";
3
+
4
+ export type { SlackAttachment, SlackBlock } from "./helpers/slack.js";
5
+
6
+ /** Structured message content. Text supplies the notification/accessibility fallback. */
7
+ export interface SlackPostMessage {
8
+ text?: string;
9
+ blocks?: SlackBlock[];
10
+ attachments?: SlackAttachment[];
11
+ }
12
+
13
+ export interface SlackPostOptions extends Omit<SlackPostMessage, "text"> {
14
+ replyTo?: string;
15
+ }
16
+
17
+ export interface SlackReceipt {
18
+ channel: string;
19
+ ts: string;
20
+ ref: string;
21
+ }
22
+
23
+ /** Slack writeback helpers; every call is a journal-backed effect. */
24
+ export interface SlackHelper {
25
+ post(channel: string, text: string | SlackPostMessage, opts?: SlackPostOptions): Step<SlackReceipt>;
26
+ dm(user: string, text: string): Step<{ user: string; ts: string }>;
27
+ reply(channel: string, threadTs: string, text: string): Step<SlackReceipt>;
28
+ react(channel: string, messageTs: string, emoji: string): Step<void>;
29
+ }
30
+
31
+ /** Normalize both authoring forms to the adapter's JSON writeback body. */
32
+ export function slackPostBody(text: string | SlackPostMessage, opts?: SlackPostOptions): SlackPostMessage & { parentRef?: string } {
33
+ const message = typeof text === "string" ? { text } : text;
34
+ const blocks = opts?.blocks ?? message.blocks;
35
+ const attachments = opts?.attachments ?? message.attachments;
36
+ return {
37
+ ...(message.text === undefined ? {} : { text: message.text }),
38
+ ...(blocks === undefined ? {} : { blocks }),
39
+ ...(attachments === undefined ? {} : { attachments }),
40
+ ...(opts?.replyTo ? { parentRef: opts.replyTo } : {}),
41
+ };
42
+ }
43
+
44
+ /** Stable across attempts; deliberately independent of process-tick ordinals. */
45
+ export function flowRunWritebackIdempotency(runId: string, stepId: string): string {
46
+ return `${runId}:${stepId}`;
47
+ }
package/src/step.ts CHANGED
@@ -1,5 +1,56 @@
1
1
  /** A journal-backed step result with its postfix verification gate. */
2
2
  export interface Step<T> extends PromiseLike<T> {
3
- /** Fail the step with `verification_failed` when the predicate is false. */
3
+ /**
4
+ * Attach a named data gate to this step's `verification:` field. The gate is
5
+ * lowered by the SDK into a slice-P journal-honest check that survives
6
+ * replay — its shape is data, not code, so covenant 1 (journal-as-truth)
7
+ * holds. See `packages/sdk/src/named-gates.ts` for the enforcement.
8
+ */
9
+ gate(config: NamedGate): Step<T>;
10
+ /**
11
+ * Predicate gates cannot be journaled — the JavaScript closure would not
12
+ * survive replay — so the executor refuses this branch with
13
+ * `unsupported_gate`. Use a `NamedGate` config-object gate above, or the
14
+ * declarative `verification:` field on the compiled step spec, when you
15
+ * need journal-honest verification.
16
+ */
4
17
  gate(predicate: (value: T) => boolean, because?: string): Step<T>;
5
18
  }
19
+
20
+ /**
21
+ * Slice-P named data gates the authored surface can attach postfix via
22
+ * `.gate(config)`. The SDK's named-gate lowering enforces these exactly (see
23
+ * `packages/sdk/src/named-gates.ts`); the shapes here are the surface-visible
24
+ * subset kept in sync with `NamedDataGate` in the SDK spec.
25
+ */
26
+ export type NamedGate =
27
+ | ReferencesInputNamedGate
28
+ | SubprocessNamedGate
29
+ | WordCountBoundsNamedGate
30
+ | RegexMatchNamedGate;
31
+
32
+ export interface ReferencesInputNamedGate {
33
+ type: 'references_input';
34
+ input_key: string;
35
+ in_output_at?: Array<string | number>;
36
+ }
37
+
38
+ export interface SubprocessNamedGate {
39
+ type: 'subprocess_gate';
40
+ command: string;
41
+ from_output?: Array<string | number>;
42
+ }
43
+
44
+ export interface WordCountBoundsNamedGate {
45
+ type: 'word_count_bounds';
46
+ min?: number;
47
+ max?: number;
48
+ }
49
+
50
+ export interface RegexMatchNamedGate {
51
+ type: 'regex_match';
52
+ pattern: string;
53
+ /** Only i, m, and s; evaluated by a non-backtracking RE2 engine. */
54
+ flags?: string;
55
+ in_output_at?: Array<string | number>;
56
+ }
@@ -0,0 +1,75 @@
1
+ # Provider event triggers
2
+
3
+ ```ts
4
+ import { flow, slack, github } from '@relayflows/surface';
5
+
6
+ export default flow('triage')
7
+ .on(slack.mention('C123'), async (f, event) => { f.done('success'); })
8
+ .on(slack.reaction('eyes'), async (f, event) => { f.done('success'); })
9
+ .on(github.pull_request('opened'), async (f, event) => { f.done('success'); });
10
+ ```
11
+
12
+ Provider namespaces also export from `@relayflows/surface/triggers` and
13
+ `@relayflows/surface/triggers/slack` (or `/github`). Declarations are immutable
14
+ webhook sources: their executor/inbox name is the provider, and their filter
15
+ matches the provider, event type, and requested payload fields. Register those
16
+ provider names in `flows.json`'s `executors` array for preflight.
17
+
18
+ `slack.mention(channel)` subscribes to Slack's `app_mention` event;
19
+ `slack.reaction(emoji)` subscribes to `reaction_added`. Arguments match provider
20
+ values exactly: use the channel ID and reaction name from the incoming event.
21
+ `github.pull_request(action)` filters `payload.action`; omitting the action
22
+ accepts every pull request event. Upstream mappings do not declare action enums,
23
+ so the action parameter is a string. Other generated methods accept an optional
24
+ recursive payload filter, for example `github.push({ ref: 'refs/heads/main' })`.
25
+
26
+ The receiver accepts `POST /providers/slack` with this JSON:
27
+
28
+ ```json
29
+ {"type":"app_mention","payload":{"channel":"C123","text":"Please review"}}
30
+ ```
31
+
32
+ It writes `{ "provider": "slack", "type": "app_mention", "payload": {...} }`
33
+ atomically to `inbox/slack/<id>.json`. The path supplies the provider; a conflicting
34
+ provider in the body or unknown event type is rejected. `payload` is the provider
35
+ event body (Slack's inner `event` object). The event names are the exact mapping
36
+ keys; dots and hyphens become underscores only in TypeScript method names.
37
+ Ingress expects this envelope, not a raw vendor HTTP delivery. Signature
38
+ verification and public ingress remain part of the deployment work tracked in
39
+ #301. Generic `POST /<name>` retains its existing arbitrary-JSON contract.
40
+
41
+ The SDK's `webhookTriggerSpec(id, source)` lowers a declaration to `TriggerSpec`
42
+ for `compileSpec`/`toKernelSpec`. Provision the resulting RunSpec in
43
+ `triggers/<provider>.json`, with executable steps, as in the existing webhook
44
+ executor. The watcher applies the generated filters, journals matching events,
45
+ deduplicates by inbox file ID, and archives consumed events. For example:
46
+
47
+ ```ts
48
+ import { compileSpec, toKernelSpec, webhookTriggerSpec } from '@relayflows/sdk';
49
+ import { slack } from '@relayflows/surface';
50
+
51
+ const binding = toKernelSpec(compileSpec({
52
+ version: '0.1.0', name: 'mentions',
53
+ triggers: [webhookTriggerSpec('mention', slack.mention('C123'))],
54
+ steps: [{ id: 'ack', type: 'deterministic', command: 'printf accepted' }],
55
+ })); // Write binding as JSON to triggers/slack.json before ingress starts.
56
+ ```
57
+
58
+ Each provider inbox still binds one RunSpec. This extends E's declaration and
59
+ inbox contract; deploying TypeScript handler bodies remains the separate #301
60
+ binding step.
61
+
62
+ Generation requires the SDK's development dependencies. The default input is
63
+ the mapping YAML shipped in the pinned `@relayfile/adapter-core` dependency
64
+ (currently Slack and GitHub). A checkout supplies additional providers:
65
+
66
+ ```sh
67
+ node scripts/generate-triggers.mjs
68
+ node scripts/generate-triggers.mjs --check
69
+ node scripts/generate-triggers.mjs --adapters-dir /path/to/relayfile-adapters
70
+ ```
71
+
72
+ The generator reads `packages/core/mappings/*.mapping.yaml`, then each adapter's
73
+ `packages/<adapter>/*.mapping.yaml`; adapter-local mappings take precedence.
74
+ Only adapters with a nonempty `webhooks:` section produce modules. It never
75
+ imports or executes adapter code. Rebuild the surface and SDK after regeneration.
@@ -0,0 +1,19 @@
1
+ // GENERATED by scripts/generate-triggers.mjs — do not edit.
2
+
3
+ import { providerTrigger, triggerArgument } from "../provider-trigger.js";
4
+ import type { WebhookFilter } from "../triggers.js";
5
+
6
+ export const github = Object.freeze({
7
+ issues(filter?: WebhookFilter) {
8
+ return providerTrigger("github", "issues", filter);
9
+ },
10
+ pull_request(action?: string) {
11
+ return providerTrigger("github", "pull_request", action === undefined ? undefined : { action: triggerArgument(action, "action") });
12
+ },
13
+ pull_request_review(filter?: WebhookFilter) {
14
+ return providerTrigger("github", "pull_request_review", filter);
15
+ },
16
+ push(filter?: WebhookFilter) {
17
+ return providerTrigger("github", "push", filter);
18
+ },
19
+ });
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/generate-triggers.mjs — do not edit.
2
+
3
+ export { github } from "./github.js";
4
+ export { slack } from "./slack.js";
5
+
6
+ /** Exact upstream event names, plus the generated Slack mention shorthand. */
7
+ export const providerEventTypes = Object.freeze({
8
+ "github": Object.freeze(["issues","pull_request","pull_request_review","push"] as const),
9
+ "slack": Object.freeze(["app_mention","message","reaction_added"] as const),
10
+ });
@@ -0,0 +1,19 @@
1
+ // GENERATED by scripts/generate-triggers.mjs — do not edit.
2
+
3
+ import { providerTrigger, triggerArgument } from "../provider-trigger.js";
4
+ import type { WebhookFilter } from "../triggers.js";
5
+
6
+ export const slack = Object.freeze({
7
+ message(filter?: WebhookFilter) {
8
+ return providerTrigger("slack", "message", filter);
9
+ },
10
+ reaction_added(filter?: WebhookFilter) {
11
+ return providerTrigger("slack", "reaction_added", filter);
12
+ },
13
+ mention(channel: string) {
14
+ return providerTrigger("slack", "app_mention", { channel: triggerArgument(channel, "channel") });
15
+ },
16
+ reaction(emoji: string) {
17
+ return providerTrigger("slack", "reaction_added", { reaction: triggerArgument(emoji, "emoji") });
18
+ },
19
+ });
@@ -0,0 +1,49 @@
1
+ export type WebhookValue = null | boolean | number | string
2
+ | readonly WebhookValue[] | { readonly [key: string]: WebhookValue };
3
+
4
+ /** Recursive object subset; array and scalar leaves match exactly. */
5
+ export type WebhookFilter = { readonly [key: string]: WebhookValue };
6
+
7
+ export interface TriggerSource {
8
+ readonly kind: "webhook";
9
+ readonly name: string;
10
+ readonly filter?: WebhookFilter;
11
+ }
12
+
13
+ /** Plain, immutable data. Constructing a source opens no receiver. */
14
+ export function webhook(name: string, filter?: WebhookFilter): TriggerSource {
15
+ if (typeof name !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(name)) {
16
+ throw new TypeError("webhook name must be 1-128 letters, digits, underscores or hyphens, starting with a letter or digit");
17
+ }
18
+ if (filter === undefined) return Object.freeze({ kind: "webhook", name });
19
+ if (filter === null || typeof filter !== "object" || Array.isArray(filter)) {
20
+ throw new TypeError("webhook filter must be a JSON object");
21
+ }
22
+ return Object.freeze({ kind: "webhook", name, filter: snapshot(filter) as WebhookFilter });
23
+ }
24
+
25
+ function snapshot(value: unknown, ancestors = new Set<object>()): WebhookValue {
26
+ if (value === null || typeof value === "string" || typeof value === "boolean") return value;
27
+ if (typeof value === "number" && Number.isFinite(value)) return value;
28
+ if (typeof value !== "object" || value === null || ancestors.has(value)) {
29
+ throw new TypeError("webhook filter must contain finite, acyclic JSON data");
30
+ }
31
+ const array = Array.isArray(value);
32
+ if (!array && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
33
+ throw new TypeError("webhook filter must contain plain JSON objects");
34
+ }
35
+ ancestors.add(value);
36
+ const entries: [string, WebhookValue][] = [];
37
+ for (const key of Reflect.ownKeys(value)) {
38
+ if (array && key === "length") continue;
39
+ const descriptor = Object.getOwnPropertyDescriptor(value, key)!;
40
+ if (typeof key !== "string" || !descriptor.enumerable || !("value" in descriptor)) {
41
+ throw new TypeError("webhook filter must contain JSON data properties");
42
+ }
43
+ if (array && !/^(0|[1-9][0-9]*)$/.test(key)) throw new TypeError("invalid JSON array property");
44
+ entries.push([key, snapshot(descriptor.value, ancestors)]);
45
+ }
46
+ ancestors.delete(value);
47
+ if (array && entries.length !== value.length) throw new TypeError("webhook filter arrays must not be sparse");
48
+ return Object.freeze(array ? entries.map(([, item]) => item) : Object.fromEntries(entries));
49
+ }