@relayflows/surface 2.0.8 → 2.0.10
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.
- package/README.md +3 -2
- package/dist/completion.d.ts +2 -0
- package/dist/completion.d.ts.map +1 -1
- package/dist/context.d.ts +29 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/effect-transport.d.ts +22 -0
- package/dist/effect-transport.d.ts.map +1 -0
- package/dist/effect-transport.js +42 -0
- package/dist/effect-transport.js.map +1 -0
- package/dist/flow.d.ts +30 -5
- package/dist/flow.d.ts.map +1 -1
- package/dist/flow.js +58 -9
- package/dist/flow.js.map +1 -1
- package/dist/helper-clients.d.ts +86 -0
- package/dist/helper-clients.d.ts.map +1 -0
- package/dist/helper-clients.js +30 -0
- package/dist/helper-clients.js.map +1 -0
- package/dist/helpers/airtable.d.ts +4 -0
- package/dist/helpers/airtable.d.ts.map +1 -0
- package/dist/helpers/airtable.js +5 -0
- package/dist/helpers/airtable.js.map +1 -0
- package/dist/helpers/asana.d.ts +5 -0
- package/dist/helpers/asana.d.ts.map +1 -0
- package/dist/helpers/asana.js +6 -0
- package/dist/helpers/asana.js.map +1 -0
- package/dist/helpers/azure-blob.d.ts +5 -0
- package/dist/helpers/azure-blob.d.ts.map +1 -0
- package/dist/helpers/azure-blob.js +6 -0
- package/dist/helpers/azure-blob.js.map +1 -0
- package/dist/helpers/box.d.ts +5 -0
- package/dist/helpers/box.d.ts.map +1 -0
- package/dist/helpers/box.js +6 -0
- package/dist/helpers/box.js.map +1 -0
- package/dist/helpers/calendly.d.ts +5 -0
- package/dist/helpers/calendly.d.ts.map +1 -0
- package/dist/helpers/calendly.js +6 -0
- package/dist/helpers/calendly.js.map +1 -0
- package/dist/helpers/clickup.d.ts +5 -0
- package/dist/helpers/clickup.d.ts.map +1 -0
- package/dist/helpers/clickup.js +6 -0
- package/dist/helpers/clickup.js.map +1 -0
- package/dist/helpers/clients.d.ts +3 -0
- package/dist/helpers/clients.d.ts.map +1 -0
- package/dist/helpers/clients.js +46 -0
- package/dist/helpers/clients.js.map +1 -0
- package/dist/helpers/cloudflare.d.ts +5 -0
- package/dist/helpers/cloudflare.d.ts.map +1 -0
- package/dist/helpers/cloudflare.js +6 -0
- package/dist/helpers/cloudflare.js.map +1 -0
- package/dist/helpers/confluence.d.ts +5 -0
- package/dist/helpers/confluence.d.ts.map +1 -0
- package/dist/helpers/confluence.js +6 -0
- package/dist/helpers/confluence.js.map +1 -0
- package/dist/helpers/daytona.d.ts +5 -0
- package/dist/helpers/daytona.d.ts.map +1 -0
- package/dist/helpers/daytona.js +6 -0
- package/dist/helpers/daytona.js.map +1 -0
- package/dist/helpers/docker-hub.d.ts +4 -0
- package/dist/helpers/docker-hub.d.ts.map +1 -0
- package/dist/helpers/docker-hub.js +5 -0
- package/dist/helpers/docker-hub.js.map +1 -0
- package/dist/helpers/dropbox.d.ts +5 -0
- package/dist/helpers/dropbox.d.ts.map +1 -0
- package/dist/helpers/dropbox.js +6 -0
- package/dist/helpers/dropbox.js.map +1 -0
- package/dist/helpers/fathom.d.ts +4 -0
- package/dist/helpers/fathom.d.ts.map +1 -0
- package/dist/helpers/fathom.js +5 -0
- package/dist/helpers/fathom.js.map +1 -0
- package/dist/helpers/gcp.d.ts +4 -0
- package/dist/helpers/gcp.d.ts.map +1 -0
- package/dist/helpers/gcp.js +5 -0
- package/dist/helpers/gcp.js.map +1 -0
- package/dist/helpers/gcs.d.ts +5 -0
- package/dist/helpers/gcs.d.ts.map +1 -0
- package/dist/helpers/gcs.js +6 -0
- package/dist/helpers/gcs.js.map +1 -0
- package/dist/helpers/github.d.ts +5 -0
- package/dist/helpers/github.d.ts.map +1 -0
- package/dist/helpers/github.js +6 -0
- package/dist/helpers/github.js.map +1 -0
- package/dist/helpers/gitlab.d.ts +5 -0
- package/dist/helpers/gitlab.d.ts.map +1 -0
- package/dist/helpers/gitlab.js +6 -0
- package/dist/helpers/gitlab.js.map +1 -0
- package/dist/helpers/gmail.d.ts +5 -0
- package/dist/helpers/gmail.d.ts.map +1 -0
- package/dist/helpers/gmail.js +6 -0
- package/dist/helpers/gmail.js.map +1 -0
- package/dist/helpers/google-calendar.d.ts +5 -0
- package/dist/helpers/google-calendar.d.ts.map +1 -0
- package/dist/helpers/google-calendar.js +6 -0
- package/dist/helpers/google-calendar.js.map +1 -0
- package/dist/helpers/google-drive.d.ts +5 -0
- package/dist/helpers/google-drive.d.ts.map +1 -0
- package/dist/helpers/google-drive.js +6 -0
- package/dist/helpers/google-drive.js.map +1 -0
- package/dist/helpers/granola.d.ts +5 -0
- package/dist/helpers/granola.d.ts.map +1 -0
- package/dist/helpers/granola.js +6 -0
- package/dist/helpers/granola.js.map +1 -0
- package/dist/helpers/hubspot.d.ts +5 -0
- package/dist/helpers/hubspot.d.ts.map +1 -0
- package/dist/helpers/hubspot.js +6 -0
- package/dist/helpers/hubspot.js.map +1 -0
- package/dist/helpers/index.d.ts +155 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +105 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/intercom.d.ts +5 -0
- package/dist/helpers/intercom.d.ts.map +1 -0
- package/dist/helpers/intercom.js +6 -0
- package/dist/helpers/intercom.js.map +1 -0
- package/dist/helpers/jira.d.ts +5 -0
- package/dist/helpers/jira.d.ts.map +1 -0
- package/dist/helpers/jira.js +6 -0
- package/dist/helpers/jira.js.map +1 -0
- package/dist/helpers/linear.d.ts +5 -0
- package/dist/helpers/linear.d.ts.map +1 -0
- package/dist/helpers/linear.js +6 -0
- package/dist/helpers/linear.js.map +1 -0
- package/dist/helpers/mailgun.d.ts +5 -0
- package/dist/helpers/mailgun.d.ts.map +1 -0
- package/dist/helpers/mailgun.js +6 -0
- package/dist/helpers/mailgun.js.map +1 -0
- package/dist/helpers/mixpanel.d.ts +5 -0
- package/dist/helpers/mixpanel.d.ts.map +1 -0
- package/dist/helpers/mixpanel.js +6 -0
- package/dist/helpers/mixpanel.js.map +1 -0
- package/dist/helpers/neon.d.ts +4 -0
- package/dist/helpers/neon.d.ts.map +1 -0
- package/dist/helpers/neon.js +5 -0
- package/dist/helpers/neon.js.map +1 -0
- package/dist/helpers/notion.d.ts +5 -0
- package/dist/helpers/notion.d.ts.map +1 -0
- package/dist/helpers/notion.js +6 -0
- package/dist/helpers/notion.js.map +1 -0
- package/dist/helpers/onedrive.d.ts +5 -0
- package/dist/helpers/onedrive.d.ts.map +1 -0
- package/dist/helpers/onedrive.js +6 -0
- package/dist/helpers/onedrive.js.map +1 -0
- package/dist/helpers/pipedrive.d.ts +5 -0
- package/dist/helpers/pipedrive.d.ts.map +1 -0
- package/dist/helpers/pipedrive.js +6 -0
- package/dist/helpers/pipedrive.js.map +1 -0
- package/dist/helpers/postgres.d.ts +5 -0
- package/dist/helpers/postgres.d.ts.map +1 -0
- package/dist/helpers/postgres.js +6 -0
- package/dist/helpers/postgres.js.map +1 -0
- package/dist/helpers/posthog.d.ts +4 -0
- package/dist/helpers/posthog.d.ts.map +1 -0
- package/dist/helpers/posthog.js +5 -0
- package/dist/helpers/posthog.js.map +1 -0
- package/dist/helpers/providers.d.ts +252 -0
- package/dist/helpers/providers.d.ts.map +1 -0
- package/dist/helpers/providers.js +305 -0
- package/dist/helpers/providers.js.map +1 -0
- package/dist/helpers/ramp.d.ts +7 -0
- package/dist/helpers/ramp.d.ts.map +1 -0
- package/dist/helpers/ramp.js +7 -0
- package/dist/helpers/ramp.js.map +1 -0
- package/dist/helpers/recall.d.ts +5 -0
- package/dist/helpers/recall.d.ts.map +1 -0
- package/dist/helpers/recall.js +6 -0
- package/dist/helpers/recall.js.map +1 -0
- package/dist/helpers/reddit.d.ts +5 -0
- package/dist/helpers/reddit.d.ts.map +1 -0
- package/dist/helpers/reddit.js +6 -0
- package/dist/helpers/reddit.js.map +1 -0
- package/dist/helpers/redis.d.ts +5 -0
- package/dist/helpers/redis.d.ts.map +1 -0
- package/dist/helpers/redis.js +6 -0
- package/dist/helpers/redis.js.map +1 -0
- package/dist/helpers/s3.d.ts +5 -0
- package/dist/helpers/s3.d.ts.map +1 -0
- package/dist/helpers/s3.js +6 -0
- package/dist/helpers/s3.js.map +1 -0
- package/dist/helpers/salesforce.d.ts +5 -0
- package/dist/helpers/salesforce.d.ts.map +1 -0
- package/dist/helpers/salesforce.js +6 -0
- package/dist/helpers/salesforce.js.map +1 -0
- package/dist/helpers/segment.d.ts +4 -0
- package/dist/helpers/segment.d.ts.map +1 -0
- package/dist/helpers/segment.js +5 -0
- package/dist/helpers/segment.js.map +1 -0
- package/dist/helpers/sendgrid.d.ts +5 -0
- package/dist/helpers/sendgrid.d.ts.map +1 -0
- package/dist/helpers/sendgrid.js +6 -0
- package/dist/helpers/sendgrid.js.map +1 -0
- package/dist/helpers/sharepoint.d.ts +5 -0
- package/dist/helpers/sharepoint.d.ts.map +1 -0
- package/dist/helpers/sharepoint.js +6 -0
- package/dist/helpers/sharepoint.js.map +1 -0
- package/dist/helpers/shopify.d.ts +4 -0
- package/dist/helpers/shopify.d.ts.map +1 -0
- package/dist/helpers/shopify.js +5 -0
- package/dist/helpers/shopify.js.map +1 -0
- package/dist/helpers/shortcut.d.ts +5 -0
- package/dist/helpers/shortcut.d.ts.map +1 -0
- package/dist/helpers/shortcut.js +6 -0
- package/dist/helpers/shortcut.js.map +1 -0
- package/dist/helpers/slack.d.ts +17 -0
- package/dist/helpers/slack.d.ts.map +1 -0
- package/dist/helpers/slack.js +4 -0
- package/dist/helpers/slack.js.map +1 -0
- package/dist/helpers/stripe.d.ts +5 -0
- package/dist/helpers/stripe.d.ts.map +1 -0
- package/dist/helpers/stripe.js +6 -0
- package/dist/helpers/stripe.js.map +1 -0
- package/dist/helpers/teams.d.ts +5 -0
- package/dist/helpers/teams.d.ts.map +1 -0
- package/dist/helpers/teams.js +6 -0
- package/dist/helpers/teams.js.map +1 -0
- package/dist/helpers/telegram.d.ts +5 -0
- package/dist/helpers/telegram.d.ts.map +1 -0
- package/dist/helpers/telegram.js +6 -0
- package/dist/helpers/telegram.js.map +1 -0
- package/dist/helpers/webhook-server.d.ts +4 -0
- package/dist/helpers/webhook-server.d.ts.map +1 -0
- package/dist/helpers/webhook-server.js +5 -0
- package/dist/helpers/webhook-server.js.map +1 -0
- package/dist/helpers/x.d.ts +4 -0
- package/dist/helpers/x.d.ts.map +1 -0
- package/dist/helpers/x.js +5 -0
- package/dist/helpers/x.js.map +1 -0
- package/dist/helpers/zendesk.d.ts +5 -0
- package/dist/helpers/zendesk.d.ts.map +1 -0
- package/dist/helpers/zendesk.js +6 -0
- package/dist/helpers/zendesk.js.map +1 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +19 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +2 -0
- package/dist/memory.js.map +1 -0
- package/dist/plugin-contract.d.ts +5 -0
- package/dist/plugin-contract.d.ts.map +1 -0
- package/dist/plugin-contract.js +2 -0
- package/dist/plugin-contract.js.map +1 -0
- package/dist/provider-trigger.d.ts +13 -0
- package/dist/provider-trigger.d.ts.map +1 -0
- package/dist/provider-trigger.js +18 -0
- package/dist/provider-trigger.js.map +1 -0
- package/dist/runtime.d.ts +6 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +5 -0
- package/dist/runtime.js.map +1 -1
- package/dist/slack.d.ts +34 -0
- package/dist/slack.d.ts.map +1 -0
- package/dist/slack.js +17 -0
- package/dist/slack.js.map +1 -0
- package/dist/step.d.ts +43 -1
- package/dist/step.d.ts.map +1 -1
- package/dist/triggers/github.d.ts +8 -0
- package/dist/triggers/github.d.ts.map +1 -0
- package/dist/triggers/github.js +17 -0
- package/dist/triggers/github.js.map +1 -0
- package/dist/triggers/index.d.ts +8 -0
- package/dist/triggers/index.d.ts.map +1 -0
- package/dist/triggers/index.js +9 -0
- package/dist/triggers/index.js.map +1 -0
- package/dist/triggers/slack.d.ts +8 -0
- package/dist/triggers/slack.d.ts.map +1 -0
- package/dist/triggers/slack.js +17 -0
- package/dist/triggers/slack.js.map +1 -0
- package/dist/triggers.d.ts +15 -0
- package/dist/triggers.d.ts.map +1 -0
- package/dist/triggers.js +43 -0
- package/dist/triggers.js.map +1 -0
- package/package.json +21 -2
- package/src/completion.ts +3 -0
- package/src/context.ts +28 -4
- package/src/effect-transport.ts +59 -0
- package/src/flow.ts +77 -15
- package/src/helper-clients.ts +30 -0
- package/src/helpers/README.md +42 -0
- package/src/helpers/airtable.ts +9 -0
- package/src/helpers/asana.ts +10 -0
- package/src/helpers/azure-blob.ts +10 -0
- package/src/helpers/box.ts +10 -0
- package/src/helpers/calendly.ts +10 -0
- package/src/helpers/clickup.ts +10 -0
- package/src/helpers/clients.ts +48 -0
- package/src/helpers/cloudflare.ts +10 -0
- package/src/helpers/confluence.ts +10 -0
- package/src/helpers/daytona.ts +10 -0
- package/src/helpers/docker-hub.ts +9 -0
- package/src/helpers/dropbox.ts +10 -0
- package/src/helpers/fathom.ts +9 -0
- package/src/helpers/gcp.ts +9 -0
- package/src/helpers/gcs.ts +10 -0
- package/src/helpers/github.ts +10 -0
- package/src/helpers/gitlab.ts +10 -0
- package/src/helpers/gmail.ts +10 -0
- package/src/helpers/google-calendar.ts +10 -0
- package/src/helpers/google-drive.ts +10 -0
- package/src/helpers/granola.ts +10 -0
- package/src/helpers/hubspot.ts +10 -0
- package/src/helpers/index.ts +212 -0
- package/src/helpers/intercom.ts +10 -0
- package/src/helpers/jira.ts +10 -0
- package/src/helpers/linear.ts +10 -0
- package/src/helpers/mailgun.ts +10 -0
- package/src/helpers/mixpanel.ts +10 -0
- package/src/helpers/neon.ts +9 -0
- package/src/helpers/notion.ts +10 -0
- package/src/helpers/onedrive.ts +10 -0
- package/src/helpers/pipedrive.ts +10 -0
- package/src/helpers/postgres.ts +10 -0
- package/src/helpers/posthog.ts +9 -0
- package/src/helpers/providers.ts +305 -0
- package/src/helpers/ramp.ts +12 -0
- package/src/helpers/recall.ts +10 -0
- package/src/helpers/reddit.ts +10 -0
- package/src/helpers/redis.ts +10 -0
- package/src/helpers/s3.ts +10 -0
- package/src/helpers/salesforce.ts +10 -0
- package/src/helpers/segment.ts +9 -0
- package/src/helpers/sendgrid.ts +10 -0
- package/src/helpers/sharepoint.ts +10 -0
- package/src/helpers/shopify.ts +9 -0
- package/src/helpers/shortcut.ts +10 -0
- package/src/helpers/slack.ts +16 -0
- package/src/helpers/stripe.ts +10 -0
- package/src/helpers/teams.ts +10 -0
- package/src/helpers/telegram.ts +10 -0
- package/src/helpers/webhook-server.ts +9 -0
- package/src/helpers/x.ts +9 -0
- package/src/helpers/zendesk.ts +10 -0
- package/src/index.ts +26 -2
- package/src/memory.ts +20 -0
- package/src/plugin-contract.ts +5 -0
- package/src/provider-trigger.ts +26 -0
- package/src/runtime.ts +8 -0
- package/src/slack.ts +47 -0
- package/src/step.ts +52 -1
- package/src/triggers/README.md +75 -0
- package/src/triggers/github.ts +19 -0
- package/src/triggers/index.ts +10 -0
- package/src/triggers/slack.ts +19 -0
- package/src/triggers.ts +49 -0
|
@@ -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
|
-
/**
|
|
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
|
+
});
|
package/src/triggers.ts
ADDED
|
@@ -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
|
+
}
|