@relayflows/surface 2.0.16 → 2.0.17
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/dist/context.d.ts +17 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/flow.d.ts.map +1 -1
- package/dist/flow.js +19 -4
- package/dist/flow.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/provider-trigger.d.ts +2 -2
- package/dist/provider-trigger.d.ts.map +1 -1
- package/dist/provider-trigger.js.map +1 -1
- package/dist/schedule.d.ts +76 -0
- package/dist/schedule.d.ts.map +1 -0
- package/dist/schedule.js +264 -0
- package/dist/schedule.js.map +1 -0
- package/dist/step.d.ts +20 -6
- package/dist/step.d.ts.map +1 -1
- package/dist/triggers/airtable.d.ts +13 -0
- package/dist/triggers/airtable.d.ts.map +1 -0
- package/dist/triggers/airtable.js +32 -0
- package/dist/triggers/airtable.js.map +1 -0
- package/dist/triggers/asana.d.ts +21 -0
- package/dist/triggers/asana.d.ts.map +1 -0
- package/dist/triggers/asana.js +56 -0
- package/dist/triggers/asana.js.map +1 -0
- package/dist/triggers/azure-blob.d.ts +7 -0
- package/dist/triggers/azure-blob.d.ts.map +1 -0
- package/dist/triggers/azure-blob.js +14 -0
- package/dist/triggers/azure-blob.js.map +1 -0
- package/dist/triggers/box.d.ts +7 -0
- package/dist/triggers/box.d.ts.map +1 -0
- package/dist/triggers/box.js +14 -0
- package/dist/triggers/box.js.map +1 -0
- package/dist/triggers/calendly.d.ts +16 -0
- package/dist/triggers/calendly.d.ts.map +1 -0
- package/dist/triggers/calendly.js +41 -0
- package/dist/triggers/calendly.js.map +1 -0
- package/dist/triggers/clickup.d.ts +16 -0
- package/dist/triggers/clickup.d.ts.map +1 -0
- package/dist/triggers/clickup.js +41 -0
- package/dist/triggers/clickup.js.map +1 -0
- package/dist/triggers/cloudflare.d.ts +12 -0
- package/dist/triggers/cloudflare.d.ts.map +1 -0
- package/dist/triggers/cloudflare.js +29 -0
- package/dist/triggers/cloudflare.js.map +1 -0
- package/dist/triggers/confluence.d.ts +10 -0
- package/dist/triggers/confluence.d.ts.map +1 -0
- package/dist/triggers/confluence.js +23 -0
- package/dist/triggers/confluence.js.map +1 -0
- package/dist/triggers/daytona.d.ts +11 -0
- package/dist/triggers/daytona.d.ts.map +1 -0
- package/dist/triggers/daytona.js +26 -0
- package/dist/triggers/daytona.js.map +1 -0
- package/dist/triggers/docker-hub.d.ts +5 -0
- package/dist/triggers/docker-hub.d.ts.map +1 -0
- package/dist/triggers/docker-hub.js +8 -0
- package/dist/triggers/docker-hub.js.map +1 -0
- package/dist/triggers/dropbox.d.ts +5 -0
- package/dist/triggers/dropbox.d.ts.map +1 -0
- package/dist/triggers/dropbox.js +8 -0
- package/dist/triggers/dropbox.js.map +1 -0
- package/dist/triggers/fathom.d.ts +5 -0
- package/dist/triggers/fathom.d.ts.map +1 -0
- package/dist/triggers/fathom.js +8 -0
- package/dist/triggers/fathom.js.map +1 -0
- package/dist/triggers/gcp.d.ts +13 -0
- package/dist/triggers/gcp.d.ts.map +1 -0
- package/dist/triggers/gcp.js +32 -0
- package/dist/triggers/gcp.js.map +1 -0
- package/dist/triggers/gcs.d.ts +7 -0
- package/dist/triggers/gcs.d.ts.map +1 -0
- package/dist/triggers/gcs.js +14 -0
- package/dist/triggers/gcs.js.map +1 -0
- package/dist/triggers/github.d.ts +22 -0
- package/dist/triggers/github.d.ts.map +1 -1
- package/dist/triggers/github.js +66 -0
- package/dist/triggers/github.js.map +1 -1
- package/dist/triggers/gitlab.d.ts +57 -0
- package/dist/triggers/gitlab.d.ts.map +1 -0
- package/dist/triggers/gitlab.js +164 -0
- package/dist/triggers/gitlab.js.map +1 -0
- package/dist/triggers/gmail.d.ts +7 -0
- package/dist/triggers/gmail.d.ts.map +1 -0
- package/dist/triggers/gmail.js +14 -0
- package/dist/triggers/gmail.js.map +1 -0
- package/dist/triggers/google-calendar.d.ts +7 -0
- package/dist/triggers/google-calendar.d.ts.map +1 -0
- package/dist/triggers/google-calendar.js +14 -0
- package/dist/triggers/google-calendar.js.map +1 -0
- package/dist/triggers/google-drive.d.ts +7 -0
- package/dist/triggers/google-drive.d.ts.map +1 -0
- package/dist/triggers/google-drive.js +14 -0
- package/dist/triggers/google-drive.js.map +1 -0
- package/dist/triggers/granola.d.ts +8 -0
- package/dist/triggers/granola.d.ts.map +1 -0
- package/dist/triggers/granola.js +17 -0
- package/dist/triggers/granola.js.map +1 -0
- package/dist/triggers/hubspot.d.ts +24 -0
- package/dist/triggers/hubspot.d.ts.map +1 -0
- package/dist/triggers/hubspot.js +65 -0
- package/dist/triggers/hubspot.js.map +1 -0
- package/dist/triggers/index.d.ts +92 -2
- package/dist/triggers/index.d.ts.map +1 -1
- package/dist/triggers/index.js +92 -2
- package/dist/triggers/index.js.map +1 -1
- package/dist/triggers/intercom.d.ts +22 -0
- package/dist/triggers/intercom.d.ts.map +1 -0
- package/dist/triggers/intercom.js +59 -0
- package/dist/triggers/intercom.js.map +1 -0
- package/dist/triggers/jira.d.ts +16 -0
- package/dist/triggers/jira.d.ts.map +1 -0
- package/dist/triggers/jira.js +41 -0
- package/dist/triggers/jira.js.map +1 -0
- package/dist/triggers/linear.d.ts +37 -0
- package/dist/triggers/linear.d.ts.map +1 -0
- package/dist/triggers/linear.js +104 -0
- package/dist/triggers/linear.js.map +1 -0
- package/dist/triggers/mailgun.d.ts +19 -0
- package/dist/triggers/mailgun.d.ts.map +1 -0
- package/dist/triggers/mailgun.js +50 -0
- package/dist/triggers/mailgun.js.map +1 -0
- package/dist/triggers/mixpanel.d.ts +16 -0
- package/dist/triggers/mixpanel.d.ts.map +1 -0
- package/dist/triggers/mixpanel.js +41 -0
- package/dist/triggers/mixpanel.js.map +1 -0
- package/dist/triggers/neon.d.ts +9 -0
- package/dist/triggers/neon.d.ts.map +1 -0
- package/dist/triggers/neon.js +20 -0
- package/dist/triggers/neon.js.map +1 -0
- package/dist/triggers/notion.d.ts +17 -0
- package/dist/triggers/notion.d.ts.map +1 -0
- package/dist/triggers/notion.js +44 -0
- package/dist/triggers/notion.js.map +1 -0
- package/dist/triggers/onedrive.d.ts +7 -0
- package/dist/triggers/onedrive.d.ts.map +1 -0
- package/dist/triggers/onedrive.js +14 -0
- package/dist/triggers/onedrive.js.map +1 -0
- package/dist/triggers/pipedrive.d.ts +18 -0
- package/dist/triggers/pipedrive.d.ts.map +1 -0
- package/dist/triggers/pipedrive.js +47 -0
- package/dist/triggers/pipedrive.js.map +1 -0
- package/dist/triggers/postgres.d.ts +7 -0
- package/dist/triggers/postgres.d.ts.map +1 -0
- package/dist/triggers/postgres.js +14 -0
- package/dist/triggers/postgres.js.map +1 -0
- package/dist/triggers/posthog.d.ts +6 -0
- package/dist/triggers/posthog.d.ts.map +1 -0
- package/dist/triggers/posthog.js +11 -0
- package/dist/triggers/posthog.js.map +1 -0
- package/dist/triggers/ramp.d.ts +51 -0
- package/dist/triggers/ramp.d.ts.map +1 -0
- package/dist/triggers/ramp.js +146 -0
- package/dist/triggers/ramp.js.map +1 -0
- package/dist/triggers/recall.d.ts +7 -0
- package/dist/triggers/recall.d.ts.map +1 -0
- package/dist/triggers/recall.js +14 -0
- package/dist/triggers/recall.js.map +1 -0
- package/dist/triggers/redis.d.ts +7 -0
- package/dist/triggers/redis.d.ts.map +1 -0
- package/dist/triggers/redis.js +14 -0
- package/dist/triggers/redis.js.map +1 -0
- package/dist/triggers/s3.d.ts +7 -0
- package/dist/triggers/s3.d.ts.map +1 -0
- package/dist/triggers/s3.js +14 -0
- package/dist/triggers/s3.js.map +1 -0
- package/dist/triggers/salesforce.d.ts +26 -0
- package/dist/triggers/salesforce.d.ts.map +1 -0
- package/dist/triggers/salesforce.js +71 -0
- package/dist/triggers/salesforce.js.map +1 -0
- package/dist/triggers/segment.d.ts +16 -0
- package/dist/triggers/segment.d.ts.map +1 -0
- package/dist/triggers/segment.js +41 -0
- package/dist/triggers/segment.js.map +1 -0
- package/dist/triggers/sendgrid.d.ts +21 -0
- package/dist/triggers/sendgrid.d.ts.map +1 -0
- package/dist/triggers/sendgrid.js +56 -0
- package/dist/triggers/sendgrid.js.map +1 -0
- package/dist/triggers/sharepoint.d.ts +7 -0
- package/dist/triggers/sharepoint.d.ts.map +1 -0
- package/dist/triggers/sharepoint.js +14 -0
- package/dist/triggers/sharepoint.js.map +1 -0
- package/dist/triggers/shopify.d.ts +28 -0
- package/dist/triggers/shopify.d.ts.map +1 -0
- package/dist/triggers/shopify.js +77 -0
- package/dist/triggers/shopify.js.map +1 -0
- package/dist/triggers/shortcut.d.ts +10 -0
- package/dist/triggers/shortcut.d.ts.map +1 -0
- package/dist/triggers/shortcut.js +23 -0
- package/dist/triggers/shortcut.js.map +1 -0
- package/dist/triggers/slack.d.ts +17 -0
- package/dist/triggers/slack.d.ts.map +1 -1
- package/dist/triggers/slack.js +51 -0
- package/dist/triggers/slack.js.map +1 -1
- package/dist/triggers/stripe.d.ts +25 -0
- package/dist/triggers/stripe.d.ts.map +1 -0
- package/dist/triggers/stripe.js +68 -0
- package/dist/triggers/stripe.js.map +1 -0
- package/dist/triggers/teams.d.ts +24 -0
- package/dist/triggers/teams.d.ts.map +1 -0
- package/dist/triggers/teams.js +65 -0
- package/dist/triggers/teams.js.map +1 -0
- package/dist/triggers/telegram.d.ts +29 -0
- package/dist/triggers/telegram.d.ts.map +1 -0
- package/dist/triggers/telegram.js +80 -0
- package/dist/triggers/telegram.js.map +1 -0
- package/dist/triggers/zendesk.d.ts +13 -0
- package/dist/triggers/zendesk.d.ts.map +1 -0
- package/dist/triggers/zendesk.js +32 -0
- package/dist/triggers/zendesk.js.map +1 -0
- package/dist/triggers.d.ts +5 -2
- package/dist/triggers.d.ts.map +1 -1
- package/dist/triggers.js.map +1 -1
- package/package.json +1 -1
- package/src/context.ts +18 -0
- package/src/flow.ts +17 -3
- package/src/index.ts +6 -2
- package/src/provider-trigger.ts +2 -2
- package/src/schedule.ts +282 -0
- package/src/step.ts +22 -6
- package/src/triggers/PROVIDERS.md +56 -0
- package/src/triggers/README.md +84 -8
- package/src/triggers/airtable.ts +34 -0
- package/src/triggers/asana.ts +58 -0
- package/src/triggers/azure-blob.ts +16 -0
- package/src/triggers/box.ts +16 -0
- package/src/triggers/calendly.ts +43 -0
- package/src/triggers/clickup.ts +43 -0
- package/src/triggers/cloudflare.ts +31 -0
- package/src/triggers/confluence.ts +25 -0
- package/src/triggers/daytona.ts +28 -0
- package/src/triggers/docker-hub.ts +10 -0
- package/src/triggers/dropbox.ts +10 -0
- package/src/triggers/fathom.ts +10 -0
- package/src/triggers/gcp.ts +34 -0
- package/src/triggers/gcs.ts +16 -0
- package/src/triggers/github.ts +66 -0
- package/src/triggers/gitlab.ts +166 -0
- package/src/triggers/gmail.ts +16 -0
- package/src/triggers/google-calendar.ts +16 -0
- package/src/triggers/google-drive.ts +16 -0
- package/src/triggers/granola.ts +19 -0
- package/src/triggers/hubspot.ts +67 -0
- package/src/triggers/index.ts +92 -2
- package/src/triggers/intercom.ts +61 -0
- package/src/triggers/jira.ts +43 -0
- package/src/triggers/linear.ts +106 -0
- package/src/triggers/mailgun.ts +52 -0
- package/src/triggers/mixpanel.ts +43 -0
- package/src/triggers/neon.ts +22 -0
- package/src/triggers/notion.ts +46 -0
- package/src/triggers/onedrive.ts +16 -0
- package/src/triggers/pipedrive.ts +49 -0
- package/src/triggers/postgres.ts +16 -0
- package/src/triggers/posthog.ts +13 -0
- package/src/triggers/ramp.ts +148 -0
- package/src/triggers/recall.ts +16 -0
- package/src/triggers/redis.ts +16 -0
- package/src/triggers/s3.ts +16 -0
- package/src/triggers/salesforce.ts +73 -0
- package/src/triggers/segment.ts +43 -0
- package/src/triggers/sendgrid.ts +58 -0
- package/src/triggers/sharepoint.ts +16 -0
- package/src/triggers/shopify.ts +79 -0
- package/src/triggers/shortcut.ts +25 -0
- package/src/triggers/slack.ts +51 -0
- package/src/triggers/stripe.ts +70 -0
- package/src/triggers/teams.ts +67 -0
- package/src/triggers/telegram.ts +82 -0
- package/src/triggers/zendesk.ts +34 -0
- package/src/triggers.ts +7 -2
package/dist/triggers.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScheduleTriggerSource } from "./schedule.js";
|
|
1
2
|
export type WebhookValue = null | boolean | number | string | readonly WebhookValue[] | {
|
|
2
3
|
readonly [key: string]: WebhookValue;
|
|
3
4
|
};
|
|
@@ -5,11 +6,13 @@ export type WebhookValue = null | boolean | number | string | readonly WebhookVa
|
|
|
5
6
|
export type WebhookFilter = {
|
|
6
7
|
readonly [key: string]: WebhookValue;
|
|
7
8
|
};
|
|
8
|
-
export interface
|
|
9
|
+
export interface WebhookTriggerSource {
|
|
9
10
|
readonly kind: "webhook";
|
|
10
11
|
readonly name: string;
|
|
11
12
|
readonly filter?: WebhookFilter;
|
|
12
13
|
}
|
|
14
|
+
/** A webhook inbox subscription, or a `schedule.*` tick subscription. */
|
|
15
|
+
export type TriggerSource = WebhookTriggerSource | ScheduleTriggerSource;
|
|
13
16
|
/** Plain, immutable data. Constructing a source opens no receiver. */
|
|
14
|
-
export declare function webhook(name: string, filter?: WebhookFilter):
|
|
17
|
+
export declare function webhook(name: string, filter?: WebhookFilter): WebhookTriggerSource;
|
|
15
18
|
//# sourceMappingURL=triggers.d.ts.map
|
package/dist/triggers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triggers.d.ts","sourceRoot":"","sources":["../src/triggers.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GACvD,SAAS,YAAY,EAAE,GAAG;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAEvE,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAErE,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"triggers.d.ts","sourceRoot":"","sources":["../src/triggers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE3D,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GACvD,SAAS,YAAY,EAAE,GAAG;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAEvE,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAErE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;CACjC;AAED,yEAAyE;AACzE,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,qBAAqB,CAAC;AAEzE,sEAAsE;AACtE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,oBAAoB,CASlF"}
|
package/dist/triggers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triggers.js","sourceRoot":"","sources":["../src/triggers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"triggers.js","sourceRoot":"","sources":["../src/triggers.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/context.ts
CHANGED
|
@@ -6,12 +6,30 @@ import type { Step } from "./step.js";
|
|
|
6
6
|
|
|
7
7
|
export interface AgentResult {
|
|
8
8
|
summary: string;
|
|
9
|
+
/**
|
|
10
|
+
* Files the agent created or changed under its working directory,
|
|
11
|
+
* cwd-relative POSIX paths, sorted — as journaled by the worker that spawned
|
|
12
|
+
* the CLI on the step's `step.completed`, never re-measured later. Empty
|
|
13
|
+
* for the relay transport (the agent ran elsewhere) and for an agent whose
|
|
14
|
+
* final message is a JSON object (that object is the output, unmodified).
|
|
15
|
+
*/
|
|
9
16
|
artifacts: string[];
|
|
10
17
|
}
|
|
11
18
|
|
|
19
|
+
/** Per-step declarations: validated and recorded, not currently enforced (gate 8 / #442).
|
|
20
|
+
* Separate from flow-wide FlowHeader.workspace / tools.fs scopes.
|
|
21
|
+
*/
|
|
22
|
+
export interface PermissionsSpec {
|
|
23
|
+
fileGlobs?: string[];
|
|
24
|
+
networkAllowlist?: string[];
|
|
25
|
+
accessPreset?: 'readonly' | 'readwrite';
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
export interface AgentOptions {
|
|
13
29
|
task: string;
|
|
14
30
|
workspace?: string;
|
|
31
|
+
/** Validated declaration only; not currently enforced (gate 8 / #442). */
|
|
32
|
+
permissions?: PermissionsSpec;
|
|
15
33
|
cli?: string;
|
|
16
34
|
model?: string;
|
|
17
35
|
/** Working directory for the CLI subprocess; defaults to the flow-runner's cwd. */
|
package/src/flow.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Helpers } from "./helpers/index.js";
|
|
|
3
3
|
type HelperTools = Partial<Record<keyof Helpers, boolean>>;
|
|
4
4
|
import type { Ctx } from "./context.js";
|
|
5
5
|
import { webhook, type TriggerSource } from "./triggers.js";
|
|
6
|
+
import { schedule } from "./schedule.js";
|
|
6
7
|
|
|
7
8
|
/** Optional escalation header; the empty header is the common case. */
|
|
8
9
|
export interface FlowHeader {
|
|
@@ -91,9 +92,22 @@ function makeHandle(definition: AuthoredFlowDefinition): FlowHandle {
|
|
|
91
92
|
value: <Event>(trigger: TriggerSource, body: FlowBody<Event>): TriggeredFlowHandle => {
|
|
92
93
|
if (typeof body !== "function") throw new TypeError("trigger handler requires a body");
|
|
93
94
|
assertHeaderObject(trigger, "trigger");
|
|
94
|
-
|
|
95
|
-
if (trigger.kind
|
|
96
|
-
|
|
95
|
+
let source: TriggerSource;
|
|
96
|
+
if (trigger.kind === "schedule") {
|
|
97
|
+
assertKnownKeys(trigger, ["kind", "name", "cron", "tz", "intervalMs", "epochMs"], "trigger");
|
|
98
|
+
// Re-derive from the declaration rather than trusting the object: the
|
|
99
|
+
// parsed form is what the SDK lowers, so it must be one this module made.
|
|
100
|
+
source = trigger.cron !== undefined
|
|
101
|
+
? schedule.cron(trigger.cron, trigger.tz === undefined ? {} : { tz: trigger.tz })
|
|
102
|
+
: schedule.every(`${Math.round((trigger.intervalMs ?? 0) / 1000)}s`);
|
|
103
|
+
if (source.intervalMs !== trigger.intervalMs || source.epochMs !== trigger.epochMs) {
|
|
104
|
+
throw new TypeError("schedule trigger grid does not match its declaration");
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
assertKnownKeys(trigger, ["kind", "name", "filter"], "trigger");
|
|
108
|
+
if (trigger.kind !== "webhook") throw new TypeError("unsupported trigger kind");
|
|
109
|
+
source = webhook(trigger.name, trigger.filter);
|
|
110
|
+
}
|
|
97
111
|
return makeHandle(Object.freeze({
|
|
98
112
|
...definition,
|
|
99
113
|
handlers: Object.freeze([...definition.handlers, Object.freeze({ trigger: source, body: body as FlowBody })]),
|
package/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type {
|
|
|
7
7
|
WorkerSummary,
|
|
8
8
|
CloudHelper,
|
|
9
9
|
} from "./cloud.js";
|
|
10
|
-
export type { AgentOptions, AgentResult, LlmOptions, Ctx } from "./context.js";
|
|
10
|
+
export type { AgentOptions, AgentResult, PermissionsSpec, LlmOptions, Ctx } from "./context.js";
|
|
11
11
|
export {
|
|
12
12
|
COMPLETION_REASONS,
|
|
13
13
|
RUN_COMPLETION_REASONS,
|
|
@@ -41,7 +41,11 @@ export {
|
|
|
41
41
|
} from "./slack.js";
|
|
42
42
|
export type { Helpers } from "./helpers/index.js";
|
|
43
43
|
export type { MemoryHelper, MemoryFinding, MemoryRecallOptions, HistoryEntry, TrajectoryEntry } from "./memory.js";
|
|
44
|
-
export { webhook, type TriggerSource, type WebhookFilter, type WebhookValue } from "./triggers.js";
|
|
44
|
+
export { webhook, type TriggerSource, type WebhookTriggerSource, type WebhookFilter, type WebhookValue } from "./triggers.js";
|
|
45
|
+
export {
|
|
46
|
+
schedule, scheduleIdFor, parseCron, cronGrid, cronFixedIntervalMs, cronMaxGapMs, everyToMs,
|
|
47
|
+
type ScheduleTriggerSource, type ScheduleCronOptions, type CronFields, type CronGrid,
|
|
48
|
+
} from "./schedule.js";
|
|
45
49
|
export * from "./triggers/index.js";
|
|
46
50
|
export type { ProviderTriggerSource } from "./provider-trigger.js";
|
|
47
51
|
export type { PluginMethod, PluginPrimitive } from './plugin-contract.js';
|
package/src/provider-trigger.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { webhook, type
|
|
1
|
+
import { webhook, type WebhookTriggerSource, type WebhookFilter } from "./triggers.js";
|
|
2
2
|
|
|
3
3
|
/** A provider inbox subscription over an envelope's type and payload. */
|
|
4
|
-
export interface ProviderTriggerSource<Provider extends string, Event extends string> extends
|
|
4
|
+
export interface ProviderTriggerSource<Provider extends string, Event extends string> extends WebhookTriggerSource {
|
|
5
5
|
readonly name: Provider;
|
|
6
6
|
readonly filter: WebhookFilter & { readonly provider: Provider; readonly type: Event };
|
|
7
7
|
}
|
package/src/schedule.ts
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schedule triggers. Hand-written, unlike the provider namespaces under
|
|
3
|
+
* `triggers/`, because a schedule is not a provider event: there is no inbox
|
|
4
|
+
* and no upstream mapping to generate from. A schedule is an event source —
|
|
5
|
+
* locally the `flows tick` runner, on Cloud a relaycron cron — that submits
|
|
6
|
+
* `flows.tick` events, and this namespace declares which ticks a flow wants.
|
|
7
|
+
*
|
|
8
|
+
* Constructing a source opens nothing. The SDK lowers it to the same
|
|
9
|
+
* `flows.tick` subscription `testdata/tick-heartbeat.flow.yaml` writes by
|
|
10
|
+
* hand (`scheduleTriggerSpec`), and `flows schedule` sends the cron to Cloud.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export interface ScheduleTriggerSource {
|
|
14
|
+
readonly kind: "schedule";
|
|
15
|
+
/** Fixed: every schedule is delivered as a `flows.tick` event. */
|
|
16
|
+
readonly name: "flows.tick";
|
|
17
|
+
/** A 5-field cron expression, when declared with `schedule.cron`. */
|
|
18
|
+
readonly cron?: string;
|
|
19
|
+
/** IANA zone for `cron`; defaults to UTC. */
|
|
20
|
+
readonly tz?: string;
|
|
21
|
+
/** Fixed interval in milliseconds, when declared with `schedule.every` or when `cron` is exactly a tick grid. */
|
|
22
|
+
readonly intervalMs?: number;
|
|
23
|
+
/** Phase of that grid: the first fire is `epochMs` past the Unix epoch; present exactly when `intervalMs` is. */
|
|
24
|
+
readonly epochMs?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ScheduleCronOptions {
|
|
28
|
+
readonly tz?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const EVERY = /^(\d+)(s|m|h|d)$/u;
|
|
32
|
+
const UNIT_MS = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 } as const;
|
|
33
|
+
|
|
34
|
+
/** `every("5m")` — a fixed interval. Units: s, m, h, d. Minimum one second. */
|
|
35
|
+
export function everyToMs(value: string): number {
|
|
36
|
+
const match = typeof value === "string" ? EVERY.exec(value.trim()) : null;
|
|
37
|
+
if (!match) throw new TypeError(`schedule.every expects <n><s|m|h|d>, got ${JSON.stringify(value)}`);
|
|
38
|
+
const ms = Number(match[1]) * UNIT_MS[match[2] as keyof typeof UNIT_MS];
|
|
39
|
+
if (!Number.isSafeInteger(ms) || ms < 1_000) throw new TypeError("schedule.every must be at least 1s");
|
|
40
|
+
return ms;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CronFields {
|
|
44
|
+
readonly minute: string;
|
|
45
|
+
readonly hour: string;
|
|
46
|
+
readonly dayOfMonth: string;
|
|
47
|
+
readonly month: string;
|
|
48
|
+
readonly dayOfWeek: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const FIELD_RANGES = [[0, 59], [0, 23], [1, 31], [1, 12], [0, 7]] as const;
|
|
52
|
+
const NAMES: Record<number, readonly string[]> = {
|
|
53
|
+
3: ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"],
|
|
54
|
+
4: ["sun", "mon", "tue", "wed", "thu", "fri", "sat"],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Standard five-field cron. Accepts `*`, values, ranges, lists and `/step`,
|
|
59
|
+
* plus month and weekday names; refuses anything outside each field's range.
|
|
60
|
+
* Validation, not evaluation — the schedule's clock is the runner's.
|
|
61
|
+
*/
|
|
62
|
+
export function parseCron(expression: string): CronFields {
|
|
63
|
+
const fields = typeof expression === "string" ? expression.trim().split(/\s+/u) : [];
|
|
64
|
+
if (fields.length !== 5) {
|
|
65
|
+
throw new TypeError(`cron expression must have five fields (minute hour day-of-month month day-of-week), got ${JSON.stringify(expression)}`);
|
|
66
|
+
}
|
|
67
|
+
fields.forEach((field, index) => {
|
|
68
|
+
const [low, high] = FIELD_RANGES[index]!;
|
|
69
|
+
for (const part of field.split(",")) {
|
|
70
|
+
const pieces = part.split("/");
|
|
71
|
+
if (pieces.length > 2 || part.length === 0) throw new TypeError(`cron field ${index + 1}: invalid ${JSON.stringify(part)}`);
|
|
72
|
+
const [range, step] = pieces;
|
|
73
|
+
if (step !== undefined && (!/^\d+$/u.test(step) || Number(step) < 1)) {
|
|
74
|
+
throw new TypeError(`cron field ${index + 1}: invalid step in ${JSON.stringify(part)}`);
|
|
75
|
+
}
|
|
76
|
+
if (range === "*") continue;
|
|
77
|
+
const bounds = range!.split("-");
|
|
78
|
+
if (bounds.length > 2) throw new TypeError(`cron field ${index + 1}: invalid range ${JSON.stringify(part)}`);
|
|
79
|
+
for (const bound of bounds) {
|
|
80
|
+
// Month names are 1-based (jan = 1); weekday names are 0-based (sun = 0).
|
|
81
|
+
const named = NAMES[index]?.indexOf(bound.toLowerCase());
|
|
82
|
+
const value = /^\d+$/u.test(bound) ? Number(bound)
|
|
83
|
+
: named === undefined || named === -1 ? undefined : named + (index === 3 ? 1 : 0);
|
|
84
|
+
if (value === undefined || value < low || value > high) {
|
|
85
|
+
throw new TypeError(`cron field ${index + 1}: ${JSON.stringify(bound)} is outside ${low}-${high}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return Object.freeze({
|
|
91
|
+
minute: fields[0]!, hour: fields[1]!, dayOfMonth: fields[2]!, month: fields[3]!, dayOfWeek: fields[4]!,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** A tick grid that reproduces a cron exactly: fire every `intervalMs`, phase-aligned at `epochMs` past the Unix epoch. */
|
|
96
|
+
export interface CronGrid {
|
|
97
|
+
readonly intervalMs: number;
|
|
98
|
+
readonly epochMs: number;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// The tick grid a cron expression amounts to, when one reproduces it exactly.
|
|
102
|
+
// The tick source fires at epochMs + k*intervalMs, so a cron is representable
|
|
103
|
+
// only when its period divides the next field's cycle (every N minutes with
|
|
104
|
+
// 60 % N == 0, every N hours with 24 % N == 0) and its phase is a single
|
|
105
|
+
// fixed value in the finer fields. `*/7 * * * *` is not (cron restarts the
|
|
106
|
+
// minute count each hour, a grid does not); `15 * * * *` is, with a 15-minute
|
|
107
|
+
// phase. Anything with day, month or weekday constraints, lists or ranges is
|
|
108
|
+
// not a grid — only a cron-aware runner (Cloud's relaycron) can drive it.
|
|
109
|
+
// Time zones: a grid is anchored in UTC, so only UTC schedules qualify; an
|
|
110
|
+
// offset zone would shift the phase and a DST zone would move it twice a year.
|
|
111
|
+
export function cronGrid(fields: CronFields, tz?: string): CronGrid | undefined {
|
|
112
|
+
const { minute, hour, dayOfMonth, month, dayOfWeek } = fields;
|
|
113
|
+
if (dayOfMonth !== "*" || month !== "*" || dayOfWeek !== "*") return undefined;
|
|
114
|
+
if (tz !== undefined && tz !== "UTC" && tz !== "Etc/UTC") return undefined;
|
|
115
|
+
const every = (field: string, cycle: number): number | undefined => {
|
|
116
|
+
if (field === "*") return 1;
|
|
117
|
+
const match = /^\*\/(\d+)$/u.exec(field);
|
|
118
|
+
if (!match) return undefined;
|
|
119
|
+
const step = Number(match[1]);
|
|
120
|
+
return step >= 1 && cycle % step === 0 ? step : undefined;
|
|
121
|
+
};
|
|
122
|
+
const fixed = (field: string): number | undefined => (/^\d+$/u.test(field) ? Number(field) : undefined);
|
|
123
|
+
const minuteStep = every(minute, 60);
|
|
124
|
+
if (minuteStep !== undefined && hour === "*") return { intervalMs: minuteStep * UNIT_MS.m, epochMs: 0 };
|
|
125
|
+
const minutePhase = fixed(minute);
|
|
126
|
+
const hourStep = every(hour, 24);
|
|
127
|
+
if (minutePhase !== undefined && hourStep !== undefined) {
|
|
128
|
+
return { intervalMs: hourStep * UNIT_MS.h, epochMs: minutePhase * UNIT_MS.m };
|
|
129
|
+
}
|
|
130
|
+
const hourPhase = fixed(hour);
|
|
131
|
+
if (minutePhase !== undefined && hourPhase !== undefined) {
|
|
132
|
+
return { intervalMs: UNIT_MS.d, epochMs: hourPhase * UNIT_MS.h + minutePhase * UNIT_MS.m };
|
|
133
|
+
}
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** The fixed interval of a cron, when `cronGrid` finds one. Kept for callers that only need the period. */
|
|
138
|
+
export function cronFixedIntervalMs(fields: CronFields, tz?: string): number | undefined {
|
|
139
|
+
return cronGrid(fields, tz)?.intervalMs;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function cronFieldMatches(field: string, value: number, index: number): boolean {
|
|
143
|
+
const [low, high] = FIELD_RANGES[index]!;
|
|
144
|
+
const named = (bound: string): number => {
|
|
145
|
+
if (/^\d+$/u.test(bound)) return Number(bound);
|
|
146
|
+
return NAMES[index]!.indexOf(bound.toLowerCase()) + (index === 3 ? 1 : 0);
|
|
147
|
+
};
|
|
148
|
+
return field.split(",").some((part) => {
|
|
149
|
+
const [range, step] = part.split("/");
|
|
150
|
+
const stride = step === undefined ? 1 : Number(step);
|
|
151
|
+
let from: number;
|
|
152
|
+
let to: number;
|
|
153
|
+
// `N/step` runs from N to the field's maximum — for weekdays that is 7,
|
|
154
|
+
// so `1/2` reaches Sunday-as-7 and the normalisation below applies.
|
|
155
|
+
if (range === "*") { from = low; to = index === 4 ? 6 : high; }
|
|
156
|
+
else {
|
|
157
|
+
const bounds = range!.split("-").map(named);
|
|
158
|
+
from = bounds[0]!;
|
|
159
|
+
to = bounds.length === 2 ? bounds[1]! : step === undefined ? bounds[0]! : high;
|
|
160
|
+
}
|
|
161
|
+
// Weekday 7 is Sunday, as 0 is. A lone `7` or a range ending in 7 is
|
|
162
|
+
// tested against Sunday-as-0 as well, so a stride counted from the
|
|
163
|
+
// range start still lands on it: `1-7/2` fires Mon, Wed, Fri, Sun.
|
|
164
|
+
if (index === 4 && to === 7) {
|
|
165
|
+
if (from === 7) return value === 0;
|
|
166
|
+
if (value === 0 && (7 - from) % stride === 0) return true;
|
|
167
|
+
to = 6;
|
|
168
|
+
}
|
|
169
|
+
return value >= from && value <= to && (value - from) % stride === 0;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* The longest gap between consecutive fires over two calendar years (one of
|
|
175
|
+
* them leap), in milliseconds — a cron's natural quiet period. Evaluated on
|
|
176
|
+
* the UTC calendar minute by minute; a zone offset does not change gap
|
|
177
|
+
* lengths, and a DST shift changes one gap by at most an hour, which the
|
|
178
|
+
* callers' multiple absorbs. An expression that fires at most once in the
|
|
179
|
+
* span reports the whole span. Returns undefined when it never fires.
|
|
180
|
+
*/
|
|
181
|
+
export function cronMaxGapMs(fields: CronFields): number | undefined {
|
|
182
|
+
const start = Date.UTC(2024, 0, 1);
|
|
183
|
+
const end = Date.UTC(2026, 0, 1);
|
|
184
|
+
let previous: number | undefined;
|
|
185
|
+
let first: number | undefined;
|
|
186
|
+
let maxGap = 0;
|
|
187
|
+
for (let t = start; t < end; t += UNIT_MS.m) {
|
|
188
|
+
const d = new Date(t);
|
|
189
|
+
const dom = fields.dayOfMonth === "*";
|
|
190
|
+
const dow = fields.dayOfWeek === "*";
|
|
191
|
+
const dayMatches = dom && dow
|
|
192
|
+
? true
|
|
193
|
+
// POSIX: when both day fields are restricted, either matching fires.
|
|
194
|
+
: dom !== dow
|
|
195
|
+
? (dom ? cronFieldMatches(fields.dayOfWeek, d.getUTCDay(), 4) : cronFieldMatches(fields.dayOfMonth, d.getUTCDate(), 2))
|
|
196
|
+
: cronFieldMatches(fields.dayOfMonth, d.getUTCDate(), 2) || cronFieldMatches(fields.dayOfWeek, d.getUTCDay(), 4);
|
|
197
|
+
if (!dayMatches || !cronFieldMatches(fields.month, d.getUTCMonth() + 1, 3)
|
|
198
|
+
|| !cronFieldMatches(fields.hour, d.getUTCHours(), 1) || !cronFieldMatches(fields.minute, d.getUTCMinutes(), 0)) continue;
|
|
199
|
+
if (previous !== undefined) maxGap = Math.max(maxGap, t - previous);
|
|
200
|
+
else first = t;
|
|
201
|
+
previous = t;
|
|
202
|
+
}
|
|
203
|
+
if (first === undefined || previous === undefined) return undefined;
|
|
204
|
+
return maxGap > 0 ? maxGap : end - start;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function assertTimeZone(tz: string): string {
|
|
208
|
+
if (typeof tz !== "string" || tz.trim().length === 0) throw new TypeError("schedule tz must be an IANA zone name");
|
|
209
|
+
try {
|
|
210
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
211
|
+
} catch {
|
|
212
|
+
throw new TypeError(`schedule tz ${JSON.stringify(tz)} is not a known IANA zone`);
|
|
213
|
+
}
|
|
214
|
+
return tz;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export const schedule = Object.freeze({
|
|
218
|
+
/** A five-field cron, evaluated in `tz` (default UTC). */
|
|
219
|
+
cron(expression: string, options: ScheduleCronOptions = {}): ScheduleTriggerSource {
|
|
220
|
+
const fields = parseCron(expression);
|
|
221
|
+
const tz = options.tz === undefined ? undefined : assertTimeZone(options.tz);
|
|
222
|
+
const grid = cronGrid(fields, tz);
|
|
223
|
+
return Object.freeze({
|
|
224
|
+
kind: "schedule", name: "flows.tick",
|
|
225
|
+
cron: expression.trim().split(/\s+/u).join(" "),
|
|
226
|
+
...(tz === undefined ? {} : { tz }),
|
|
227
|
+
...(grid === undefined ? {} : { intervalMs: grid.intervalMs, epochMs: grid.epochMs }),
|
|
228
|
+
});
|
|
229
|
+
},
|
|
230
|
+
/** A fixed interval: `every("5m")`, `every("2h")`. Units s, m, h, d. */
|
|
231
|
+
every(interval: string): ScheduleTriggerSource {
|
|
232
|
+
return Object.freeze({ kind: "schedule", name: "flows.tick", intervalMs: everyToMs(interval), epochMs: 0 });
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
/** UTF-8 code units of a string, without TextEncoder: this package compiles against no DOM or Node lib. */
|
|
237
|
+
function utf8Bytes(text: string): number[] {
|
|
238
|
+
const bytes: number[] = [];
|
|
239
|
+
for (const char of text) {
|
|
240
|
+
const cp = char.codePointAt(0)!;
|
|
241
|
+
if (cp < 0x80) bytes.push(cp);
|
|
242
|
+
else if (cp < 0x800) bytes.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));
|
|
243
|
+
else if (cp < 0x10000) bytes.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
|
|
244
|
+
else bytes.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
|
|
245
|
+
}
|
|
246
|
+
return bytes;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** 64-bit FNV-1a over UTF-8, as 16 hex characters. Dependency-free; not a security hash, an identity. */
|
|
250
|
+
function fnv1a64(text: string): string {
|
|
251
|
+
let hi = 0xcbf29ce4, lo = 0x84222325;
|
|
252
|
+
for (const byte of utf8Bytes(text)) {
|
|
253
|
+
lo ^= byte;
|
|
254
|
+
// (hi:lo) * 0x100000001b3 mod 2^64, in 16-bit limbs to stay exact in doubles.
|
|
255
|
+
const l0 = lo & 0xffff, l1 = lo >>> 16, h0 = hi & 0xffff, h1 = hi >>> 16;
|
|
256
|
+
let a = l0 * 0x01b3;
|
|
257
|
+
let b = l1 * 0x01b3 + (a >>> 16);
|
|
258
|
+
let c = h0 * 0x01b3 + (b >>> 16) + l0;
|
|
259
|
+
let d = h1 * 0x01b3 + (c >>> 16) + l1;
|
|
260
|
+
lo = ((b & 0xffff) << 16 | (a & 0xffff)) >>> 0;
|
|
261
|
+
hi = ((d & 0xffff) << 16 | (c & 0xffff)) >>> 0;
|
|
262
|
+
}
|
|
263
|
+
return hi.toString(16).padStart(8, "0") + lo.toString(16).padStart(8, "0");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* The `schedule_id` a flow's schedule subscribes to. Deterministic from the
|
|
268
|
+
* flow name and the declaration, so the local runner, `flows check` and the
|
|
269
|
+
* journal all name the same slot stream without a registry — and injective:
|
|
270
|
+
* a readable slug for humans, plus a hash of the exact declaration so
|
|
271
|
+
* `1-5` and `1,5`, or two zones, or two long names sharing a prefix, never
|
|
272
|
+
* share a stream (the kernel dispatches an event to its first matching
|
|
273
|
+
* subscription only).
|
|
274
|
+
*/
|
|
275
|
+
export function scheduleIdFor(flowName: string, source: ScheduleTriggerSource): string {
|
|
276
|
+
const canonical = JSON.stringify([flowName, source.cron ?? null, source.tz ?? null, source.intervalMs ?? null, source.epochMs ?? null]);
|
|
277
|
+
const spec = source.cron !== undefined
|
|
278
|
+
? `cron-${source.cron}${source.tz === undefined ? "" : `-${source.tz}`}`
|
|
279
|
+
: `every-${source.intervalMs}ms`;
|
|
280
|
+
const slug = `${flowName}-${spec}`.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-|-$/gu, "").slice(0, 96);
|
|
281
|
+
return `${slug}-${fnv1a64(canonical)}`;
|
|
282
|
+
}
|
package/src/step.ts
CHANGED
|
@@ -8,11 +8,14 @@ export interface Step<T> extends PromiseLike<T> {
|
|
|
8
8
|
*/
|
|
9
9
|
gate(config: NamedGate): Step<T>;
|
|
10
10
|
/**
|
|
11
|
-
* Predicate
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* Predicate gate: author code, run once by the runtime after the step
|
|
12
|
+
* completes, on the value the journal handed back. The closure itself is
|
|
13
|
+
* never serialized; its VERDICT is journaled as a lowered `<step>.gate`
|
|
14
|
+
* deterministic step that succeeds or fails, so resume and replay read the
|
|
15
|
+
* recorded verdict and never re-run the function. A false verdict fails the
|
|
16
|
+
* run as `gate_failed`, carrying `because`. `flows check` cannot prove a
|
|
17
|
+
* predicate (docs/SURFACE.md §6); use a `NamedGate` when the check must be
|
|
18
|
+
* inspectable before execution. One `.gate()` per step.
|
|
16
19
|
*/
|
|
17
20
|
gate(predicate: (value: T) => boolean, because?: string): Step<T>;
|
|
18
21
|
}
|
|
@@ -27,7 +30,20 @@ export type NamedGate =
|
|
|
27
30
|
| ReferencesInputNamedGate
|
|
28
31
|
| SubprocessNamedGate
|
|
29
32
|
| WordCountBoundsNamedGate
|
|
30
|
-
| RegexMatchNamedGate
|
|
33
|
+
| RegexMatchNamedGate
|
|
34
|
+
| ArtifactExistsNamedGate;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Passes when the step's journaled `artifacts` lists `path` — a file the
|
|
38
|
+
* agent's worker measured as created or changed under its working directory.
|
|
39
|
+
* The check reads the journal, so replay and resume see the verdict that was
|
|
40
|
+
* recorded, never a fresh look at the disk.
|
|
41
|
+
*/
|
|
42
|
+
export interface ArtifactExistsNamedGate {
|
|
43
|
+
type: 'artifact_exists';
|
|
44
|
+
/** Working-directory-relative POSIX path, e.g. `review/security.md`. */
|
|
45
|
+
path: string;
|
|
46
|
+
}
|
|
31
47
|
|
|
32
48
|
export interface ReferencesInputNamedGate {
|
|
33
49
|
type: 'references_input';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<!-- GENERATED by scripts/generate-triggers.mjs — do not edit. -->
|
|
2
|
+
# Provider trigger namespaces
|
|
3
|
+
|
|
4
|
+
47 providers, 570 events. `mapping` rows come from the adapter's `webhooks:` block (payload-aware signatures); `catalog` rows come from `KNOWN_TRIGGER_CATALOG` (`supportedEvents()`) only. Every provider also includes its catalog events, so the count is what ingress delivers.
|
|
5
|
+
|
|
6
|
+
| Provider | Namespace | Events | Source | Registry-only events |
|
|
7
|
+
|---|---|---:|---|---|
|
|
8
|
+
| `airtable` | `airtable` | 9 | catalog | |
|
|
9
|
+
| `asana` | `asana` | 17 | catalog | |
|
|
10
|
+
| `azure-blob` | `azure_blob` | 3 | mapping | |
|
|
11
|
+
| `box` | `box` | 3 | mapping | |
|
|
12
|
+
| `calendly` | `calendly` | 12 | catalog | |
|
|
13
|
+
| `clickup` | `clickup` | 12 | catalog | |
|
|
14
|
+
| `cloudflare` | `cloudflare` | 8 | mapping | |
|
|
15
|
+
| `confluence` | `confluence` | 6 | catalog | |
|
|
16
|
+
| `daytona` | `daytona` | 7 | mapping | |
|
|
17
|
+
| `docker-hub` | `docker_hub` | 1 | catalog | |
|
|
18
|
+
| `dropbox` | `dropbox` | 1 | mapping | |
|
|
19
|
+
| `fathom` | `fathom` | 1 | mapping | |
|
|
20
|
+
| `gcp` | `gcp` | 9 | mapping | |
|
|
21
|
+
| `gcs` | `gcs` | 3 | mapping | |
|
|
22
|
+
| `github` | `github` | 26 | mapping | |
|
|
23
|
+
| `gitlab` | `gitlab` | 53 | mapping | |
|
|
24
|
+
| `gmail` | `gmail` | 3 | mapping | |
|
|
25
|
+
| `google-calendar` | `google_calendar` | 3 | catalog | |
|
|
26
|
+
| `google-drive` | `google_drive` | 3 | mapping | |
|
|
27
|
+
| `granola` | `granola` | 4 | mapping | |
|
|
28
|
+
| `hubspot` | `hubspot` | 20 | catalog | |
|
|
29
|
+
| `intercom` | `intercom` | 18 | catalog | |
|
|
30
|
+
| `jira` | `jira` | 12 | catalog | |
|
|
31
|
+
| `linear` | `linear` | 33 | catalog | |
|
|
32
|
+
| `mailgun` | `mailgun` | 15 | catalog | |
|
|
33
|
+
| `mixpanel` | `mixpanel` | 12 | catalog | |
|
|
34
|
+
| `neon` | `neon` | 5 | mapping | |
|
|
35
|
+
| `notion` | `notion` | 13 | mapping | |
|
|
36
|
+
| `onedrive` | `onedrive` | 3 | mapping | |
|
|
37
|
+
| `pipedrive` | `pipedrive` | 14 | catalog | |
|
|
38
|
+
| `postgres` | `postgres` | 3 | mapping | |
|
|
39
|
+
| `posthog` | `posthog` | 2 | mapping | |
|
|
40
|
+
| `ramp` | `ramp` | 47 | mapping | |
|
|
41
|
+
| `recall` | `recall` | 3 | mapping | |
|
|
42
|
+
| `redis` | `redis` | 3 | mapping | |
|
|
43
|
+
| `s3` | `s3` | 3 | mapping | |
|
|
44
|
+
| `salesforce` | `salesforce` | 22 | catalog | |
|
|
45
|
+
| `segment` | `segment` | 12 | catalog | |
|
|
46
|
+
| `sendgrid` | `sendgrid` | 17 | catalog | |
|
|
47
|
+
| `sharepoint` | `sharepoint` | 3 | mapping | |
|
|
48
|
+
| `shopify` | `shopify` | 24 | catalog | |
|
|
49
|
+
| `shortcut` | `shortcut` | 6 | mapping | |
|
|
50
|
+
| `slack` | `slack` | 21 | mapping | `reaction.added` |
|
|
51
|
+
| `stripe` | `stripe` | 21 | catalog | |
|
|
52
|
+
| `teams` | `teams` | 20 | catalog | |
|
|
53
|
+
| `telegram` | `telegram` | 25 | catalog | |
|
|
54
|
+
| `zendesk` | `zendesk` | 9 | catalog | |
|
|
55
|
+
|
|
56
|
+
Registry-only events share an identifier with another event of the same provider; subscribe with `webhook(provider, { provider, type })`.
|
package/src/triggers/README.md
CHANGED
|
@@ -9,8 +9,25 @@ export default flow('triage')
|
|
|
9
9
|
.on(github.pull_request('opened'), async (f, event) => { f.done('success'); });
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
Every provider a relayfile adapter can deliver has a namespace — 47 today,
|
|
13
|
+
570 events; see [PROVIDERS.md](PROVIDERS.md) (generated) for the full table.
|
|
14
|
+
Hyphenated providers become identifiers: `azure-blob` → `azure_blob`,
|
|
15
|
+
`google-drive` → `google_drive`; the inbox name and event type keep the
|
|
16
|
+
upstream spelling, so `azure_blob.file_created()` lowers to
|
|
17
|
+
`{ provider: 'azure-blob', type: 'file.created' }`. Namespaces come from two
|
|
18
|
+
sources: an adapter's `webhooks:` mapping block, which carries payload shape
|
|
19
|
+
(`github.pull_request(action?)` takes an action because the mapping extracts
|
|
20
|
+
one), and the trigger catalog (`@relayfile/adapter-core/triggers`, every adapter's
|
|
21
|
+
`supportedEvents()`), which is the full set an adapter delivers and yields the
|
|
22
|
+
plain `(filter?)` signature. The two are unioned per provider: a mapping
|
|
23
|
+
covers payload shape for some events, never the whole set (gitlab maps 8 of
|
|
24
|
+
53). Where two upstream names share an identifier (`reaction.added` and
|
|
25
|
+
`reaction_added`), the mapping-declared one owns the method and the other
|
|
26
|
+
stays subscribable via `webhook(provider, { provider, type })`; PROVIDERS.md
|
|
27
|
+
lists them.
|
|
28
|
+
|
|
12
29
|
Provider namespaces also export from `@relayflows/surface/triggers` and
|
|
13
|
-
`@relayflows/surface/triggers/slack` (or `/github
|
|
30
|
+
`@relayflows/surface/triggers/slack` (or `/github`, `/notion`, …). Declarations are immutable
|
|
14
31
|
webhook sources: their executor/inbox name is the provider, and their filter
|
|
15
32
|
matches the provider, event type, and requested payload fields. Register those
|
|
16
33
|
provider names in `flows.json`'s `executors` array for preflight.
|
|
@@ -32,9 +49,21 @@ filter names that same provider, and the filter pins an event type.
|
|
|
32
49
|
`slack.reaction(emoji)` subscribes to `reaction_added`. Arguments match provider
|
|
33
50
|
values exactly: use the channel ID and reaction name from the incoming event.
|
|
34
51
|
`github.pull_request(action)` filters `payload.action`; omitting the action
|
|
35
|
-
accepts every pull request event.
|
|
36
|
-
|
|
37
|
-
|
|
52
|
+
accepts every pull request event. GitHub (and some other providers) appear in
|
|
53
|
+
two spellings because two ingresses deliver them: the aggregate event with the
|
|
54
|
+
action in the payload (`pull_request` + `payload.action`) is what a raw GitHub
|
|
55
|
+
delivery and this package's `POST /providers/github` receiver carry, while the
|
|
56
|
+
action-qualified name (`pull_request.opened`) is what relayfile's Cloud
|
|
57
|
+
ingress normalizes to and what the adapter catalog lists. Subscribe in the
|
|
58
|
+
spelling of the ingress that will deliver to you; action-qualified methods
|
|
59
|
+
take only a payload filter, never a second action. Upstream mappings do not declare action enums,
|
|
60
|
+
so the action parameter is a string. `github.check_run(action)` (a CI check
|
|
61
|
+
finished: `completed`, with `check_run.conclusion` in the payload) and
|
|
62
|
+
`github.issue_comment(action)` (a comment on an issue or pull-request
|
|
63
|
+
conversation: `created`, `edited`, `deleted`) take an action the same way — the
|
|
64
|
+
two events a PR reviewer needs for merge-on-green and comment-driven directives.
|
|
65
|
+
Other generated methods accept an optional recursive payload filter, for
|
|
66
|
+
example `github.push({ ref: 'refs/heads/main' })`.
|
|
38
67
|
|
|
39
68
|
The receiver accepts `POST /providers/slack` with this JSON:
|
|
40
69
|
|
|
@@ -72,9 +101,55 @@ Each provider inbox still binds one RunSpec. This extends E's declaration and
|
|
|
72
101
|
inbox contract; deploying TypeScript handler bodies remains the separate #301
|
|
73
102
|
binding step.
|
|
74
103
|
|
|
104
|
+
## Schedules
|
|
105
|
+
|
|
106
|
+
`schedule` is hand-written, not generated: a schedule is not a provider event.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { flow, schedule } from '@relayflows/surface';
|
|
110
|
+
|
|
111
|
+
export default flow('nightly')
|
|
112
|
+
.on(schedule.cron('0 9 * * 1-5', { tz: 'Europe/Oslo' }), async (f) => { f.done('success'); })
|
|
113
|
+
.on(schedule.every('5m'), async (f) => { f.done('success'); });
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`schedule.cron` validates a standard five-field expression (values, ranges,
|
|
117
|
+
lists, `/step`, month and weekday names) and an IANA `tz`; `schedule.every`
|
|
118
|
+
takes `<n><s|m|h|d>`, at least one second. Both are inert data. The SDK lowers
|
|
119
|
+
a declaration to the `flows.tick` subscription `testdata/tick-heartbeat.flow.yaml`
|
|
120
|
+
writes by hand — event type `flows.tick`, pattern `schedule_id`, the tick
|
|
121
|
+
dedupe key, and a three-slot silence budget — with a deterministic
|
|
122
|
+
`schedule_id` from the flow name and the declaration (`scheduleIdFor`).
|
|
123
|
+
`flows check` prints each one:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
SCHEDULE handler 0 every 300000ms -> flows.tick schedule_id nightly-every-300000ms-33a704f768702f7d [local: flows tick start --schedule-id nightly-every-300000ms-33a704f768702f7d --interval-ms 300000 --epoch-ms 0]
|
|
127
|
+
SCHEDULE handler 1 cron "0 9 * * 1-5" tz Europe/Oslo -> flows.tick schedule_id nightly-cron-0-9-1-5-europe-oslo-41f5a267fd758564 [Cloud only: ...]
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The id is a readable slug plus a hash of the exact declaration, so `1-5` and
|
|
131
|
+
`1,5`, two zones, or two long names never share a tick stream (the kernel
|
|
132
|
+
dispatches an event to its first matching subscription only).
|
|
133
|
+
|
|
134
|
+
Locally the tick runner fires at `epoch + k·interval`, so it drives a cron
|
|
135
|
+
only when that grid reproduces it **exactly**: `every(...)`; `*/N * * * *`
|
|
136
|
+
with `N` dividing 60; `M */N * * *` with `N` dividing 24 (phase `M`
|
|
137
|
+
minutes); `M H * * *` daily (phase `H:M`) — all in UTC. `*/7 * * * *` is not
|
|
138
|
+
a grid (cron restarts the count each hour, a grid drifts), nor is anything
|
|
139
|
+
with day, month or weekday constraints, lists, ranges, or a non-UTC zone.
|
|
140
|
+
Those are reported as Cloud-only rather than approximated; `flows schedule`
|
|
141
|
+
registers them on Cloud's cron-aware runner. Every schedule declares its own
|
|
142
|
+
silence budget — three intervals for a grid, three times the cron's longest
|
|
143
|
+
quiet period otherwise (`cronMaxGapMs`) — so a weekday-morning cron is not
|
|
144
|
+
journaled stale on Monday at 09:05 by the kernel's five-minute default.
|
|
145
|
+
Schedules need no `flows.json` executor entry: the tick source ships with
|
|
146
|
+
the CLI.
|
|
147
|
+
|
|
75
148
|
Generation requires the SDK's development dependencies. The default input is
|
|
76
|
-
the
|
|
77
|
-
|
|
149
|
+
the pinned `@relayfile/adapter-core` dependency: its `mappings/` fallbacks,
|
|
150
|
+
its `mappings/adapters/` bundle (every adapter's own mapping, adapter-core
|
|
151
|
+
≥ 0.5.26), and its trigger catalog. A checkout supplies the same three from
|
|
152
|
+
source:
|
|
78
153
|
|
|
79
154
|
```sh
|
|
80
155
|
node scripts/generate-triggers.mjs
|
|
@@ -83,6 +158,7 @@ node scripts/generate-triggers.mjs --adapters-dir /path/to/relayfile-adapters
|
|
|
83
158
|
```
|
|
84
159
|
|
|
85
160
|
The generator reads `packages/core/mappings/*.mapping.yaml`, then each adapter's
|
|
86
|
-
`packages/<adapter>/*.mapping.yaml
|
|
87
|
-
|
|
161
|
+
`packages/<adapter>/*.mapping.yaml` (adapter-local mappings take precedence),
|
|
162
|
+
then `packages/core/src/triggers/catalog.generated.json` for providers with no
|
|
163
|
+
`webhooks:` block. Only providers with at least one event produce modules. It never
|
|
88
164
|
imports or executes adapter code. Rebuild the surface and SDK after regeneration.
|