@shware/workflow 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -2
- package/dist/apns-relay.cjs +4 -17
- package/dist/apns-relay.cjs.map +1 -1
- package/dist/apns-relay.mjs +4 -17
- package/dist/apns-relay.mjs.map +1 -1
- package/dist/aws/engine-step.cjs +104 -0
- package/dist/aws/engine-step.cjs.map +1 -0
- package/dist/aws/engine-step.d.cts +28 -0
- package/dist/aws/engine-step.d.cts.map +1 -0
- package/dist/aws/engine-step.d.mts +28 -0
- package/dist/aws/engine-step.d.mts.map +1 -0
- package/dist/aws/engine-step.mjs +102 -0
- package/dist/aws/engine-step.mjs.map +1 -0
- package/dist/aws/function-url.cjs +62 -0
- package/dist/aws/function-url.cjs.map +1 -0
- package/dist/aws/function-url.d.cts +38 -0
- package/dist/aws/function-url.d.cts.map +1 -0
- package/dist/aws/function-url.d.mts +38 -0
- package/dist/aws/function-url.d.mts.map +1 -0
- package/dist/aws/function-url.mjs +59 -0
- package/dist/aws/function-url.mjs.map +1 -0
- package/dist/aws/index.cjs +160 -0
- package/dist/aws/index.cjs.map +1 -0
- package/dist/aws/index.d.cts +62 -0
- package/dist/aws/index.d.cts.map +1 -0
- package/dist/aws/index.d.mts +62 -0
- package/dist/aws/index.d.mts.map +1 -0
- package/dist/aws/index.mjs +148 -0
- package/dist/aws/index.mjs.map +1 -0
- package/dist/aws/instances.cjs +176 -0
- package/dist/aws/instances.cjs.map +1 -0
- package/dist/aws/instances.d.cts +75 -0
- package/dist/aws/instances.d.cts.map +1 -0
- package/dist/aws/instances.d.mts +75 -0
- package/dist/aws/instances.d.mts.map +1 -0
- package/dist/aws/instances.mjs +172 -0
- package/dist/aws/instances.mjs.map +1 -0
- package/dist/aws/lambda-api.cjs +89 -0
- package/dist/aws/lambda-api.cjs.map +1 -0
- package/dist/aws/lambda-api.d.cts +43 -0
- package/dist/aws/lambda-api.d.cts.map +1 -0
- package/dist/aws/lambda-api.d.mts +43 -0
- package/dist/aws/lambda-api.d.mts.map +1 -0
- package/dist/aws/lambda-api.mjs +88 -0
- package/dist/aws/lambda-api.mjs.map +1 -0
- package/dist/client.d.cts +1 -1
- package/dist/client.d.mts +1 -1
- package/dist/cloudflare/bindings.cjs +19 -0
- package/dist/cloudflare/bindings.cjs.map +1 -1
- package/dist/cloudflare/bindings.d.cts +37 -0
- package/dist/cloudflare/bindings.d.cts.map +1 -1
- package/dist/cloudflare/bindings.d.mts +37 -0
- package/dist/cloudflare/bindings.d.mts.map +1 -1
- package/dist/cloudflare/bindings.mjs +18 -1
- package/dist/cloudflare/bindings.mjs.map +1 -1
- package/dist/cloudflare/index.cjs +32 -28
- package/dist/cloudflare/index.d.cts +8 -6
- package/dist/cloudflare/index.d.mts +8 -6
- package/dist/cloudflare/index.mjs +12 -10
- package/dist/cloudflare/runner.cjs +27 -76
- package/dist/cloudflare/runner.cjs.map +1 -1
- package/dist/cloudflare/runner.d.cts +7 -2
- package/dist/cloudflare/runner.d.cts.map +1 -1
- package/dist/cloudflare/runner.d.mts +7 -2
- package/dist/cloudflare/runner.d.mts.map +1 -1
- package/dist/cloudflare/runner.mjs +26 -75
- package/dist/cloudflare/runner.mjs.map +1 -1
- package/dist/cloudflare/worker.cjs +22 -203
- package/dist/cloudflare/worker.cjs.map +1 -1
- package/dist/cloudflare/worker.d.cts +10 -56
- package/dist/cloudflare/worker.d.cts.map +1 -1
- package/dist/cloudflare/worker.d.mts +10 -56
- package/dist/cloudflare/worker.d.mts.map +1 -1
- package/dist/cloudflare/worker.mjs +20 -199
- package/dist/cloudflare/worker.mjs.map +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +2 -2
- package/dist/config.mjs.map +1 -1
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +1 -1
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +1 -1
- package/dist/contract.d.mts.map +1 -1
- package/dist/contract.mjs.map +1 -1
- package/dist/dsl/action.cjs.map +1 -1
- package/dist/dsl/action.d.cts +2 -2
- package/dist/dsl/action.d.cts.map +1 -1
- package/dist/dsl/action.d.mts +2 -2
- package/dist/dsl/action.d.mts.map +1 -1
- package/dist/dsl/action.mjs.map +1 -1
- package/dist/dsl/bundle.cjs.map +1 -1
- package/dist/dsl/bundle.d.cts +1 -1
- package/dist/dsl/bundle.d.mts +1 -1
- package/dist/dsl/bundle.mjs.map +1 -1
- package/dist/dsl/flow.cjs.map +1 -1
- package/dist/dsl/flow.d.cts +1 -1
- package/dist/dsl/flow.d.cts.map +1 -1
- package/dist/dsl/flow.d.mts +1 -1
- package/dist/dsl/flow.d.mts.map +1 -1
- package/dist/dsl/flow.mjs.map +1 -1
- package/dist/dsl/refs.cjs.map +1 -1
- package/dist/dsl/refs.d.cts +5 -4
- package/dist/dsl/refs.d.cts.map +1 -1
- package/dist/dsl/refs.d.mts +5 -4
- package/dist/dsl/refs.d.mts.map +1 -1
- package/dist/dsl/refs.mjs.map +1 -1
- package/dist/dsl/template.cjs.map +1 -1
- package/dist/dsl/template.d.cts +2 -2
- package/dist/dsl/template.d.cts.map +1 -1
- package/dist/dsl/template.d.mts +2 -2
- package/dist/dsl/template.d.mts.map +1 -1
- package/dist/dsl/template.mjs.map +1 -1
- package/dist/email-sender.cjs +62 -0
- package/dist/email-sender.cjs.map +1 -0
- package/dist/email-sender.d.cts +70 -0
- package/dist/email-sender.d.cts.map +1 -0
- package/dist/email-sender.d.mts +70 -0
- package/dist/email-sender.d.mts.map +1 -0
- package/dist/email-sender.mjs +60 -0
- package/dist/email-sender.mjs.map +1 -0
- package/dist/email.cjs +21 -0
- package/dist/email.cjs.map +1 -1
- package/dist/email.d.cts +6 -0
- package/dist/email.d.cts.map +1 -1
- package/dist/email.d.mts +6 -0
- package/dist/email.d.mts.map +1 -1
- package/dist/email.mjs +21 -1
- package/dist/email.mjs.map +1 -1
- package/dist/engine/index.cjs +1 -1
- package/dist/engine/index.mjs +1 -1
- package/dist/engine/interpreter.cjs +1 -1
- package/dist/engine/interpreter.cjs.map +1 -1
- package/dist/engine/interpreter.d.cts.map +1 -1
- package/dist/engine/interpreter.d.mts.map +1 -1
- package/dist/engine/interpreter.mjs +1 -1
- package/dist/engine/interpreter.mjs.map +1 -1
- package/dist/engine/ports.d.cts +6 -1
- package/dist/engine/ports.d.cts.map +1 -1
- package/dist/engine/ports.d.mts +6 -1
- package/dist/engine/ports.d.mts.map +1 -1
- package/dist/{cloudflare → host}/channels.cjs +13 -11
- package/dist/host/channels.cjs.map +1 -0
- package/dist/{cloudflare → host}/channels.d.cts +8 -3
- package/dist/host/channels.d.cts.map +1 -0
- package/dist/{cloudflare → host}/channels.d.mts +8 -3
- package/dist/host/channels.d.mts.map +1 -0
- package/dist/{cloudflare → host}/channels.mjs +9 -7
- package/dist/host/channels.mjs.map +1 -0
- package/dist/host/execute.cjs +82 -0
- package/dist/host/execute.cjs.map +1 -0
- package/dist/host/execute.d.cts +41 -0
- package/dist/host/execute.d.cts.map +1 -0
- package/dist/host/execute.d.mts +41 -0
- package/dist/host/execute.d.mts.map +1 -0
- package/dist/host/execute.mjs +81 -0
- package/dist/host/execute.mjs.map +1 -0
- package/dist/host/journey-host.cjs +214 -0
- package/dist/host/journey-host.cjs.map +1 -0
- package/dist/host/journey-host.d.cts +105 -0
- package/dist/host/journey-host.d.cts.map +1 -0
- package/dist/host/journey-host.d.mts +105 -0
- package/dist/host/journey-host.d.mts.map +1 -0
- package/dist/host/journey-host.mjs +210 -0
- package/dist/host/journey-host.mjs.map +1 -0
- package/dist/{cloudflare → host}/router.cjs +28 -9
- package/dist/host/router.cjs.map +1 -0
- package/dist/{cloudflare → host}/router.d.cts +2 -2
- package/dist/host/router.d.cts.map +1 -0
- package/dist/{cloudflare → host}/router.d.mts +2 -2
- package/dist/host/router.d.mts.map +1 -0
- package/dist/{cloudflare → host}/router.mjs +28 -9
- package/dist/host/router.mjs.map +1 -0
- package/dist/host/senders.cjs +63 -0
- package/dist/host/senders.cjs.map +1 -0
- package/dist/host/senders.d.cts +31 -0
- package/dist/host/senders.d.cts.map +1 -0
- package/dist/host/senders.d.mts +31 -0
- package/dist/host/senders.d.mts.map +1 -0
- package/dist/host/senders.mjs +59 -0
- package/dist/host/senders.mjs.map +1 -0
- package/dist/http2-client.cjs +88 -0
- package/dist/http2-client.cjs.map +1 -0
- package/dist/http2-client.d.cts +44 -0
- package/dist/http2-client.d.cts.map +1 -0
- package/dist/http2-client.d.mts +44 -0
- package/dist/http2-client.d.mts.map +1 -0
- package/dist/http2-client.mjs +86 -0
- package/dist/http2-client.mjs.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/react-email.cjs.map +1 -1
- package/dist/react-email.d.cts +1 -2
- package/dist/react-email.d.cts.map +1 -1
- package/dist/react-email.d.mts +1 -2
- package/dist/react-email.d.mts.map +1 -1
- package/dist/react-email.mjs.map +1 -1
- package/dist/reporting/tracking.cjs +5 -1
- package/dist/reporting/tracking.cjs.map +1 -1
- package/dist/reporting/tracking.d.cts.map +1 -1
- package/dist/reporting/tracking.d.mts.map +1 -1
- package/dist/reporting/tracking.mjs +5 -1
- package/dist/reporting/tracking.mjs.map +1 -1
- package/dist/store/d1.cjs +1 -0
- package/dist/store/d1.cjs.map +1 -1
- package/dist/store/d1.d.cts.map +1 -1
- package/dist/store/d1.d.mts.map +1 -1
- package/dist/store/d1.mjs +1 -0
- package/dist/store/d1.mjs.map +1 -1
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +63 -0
- package/dist/store/index.d.cts.map +1 -1
- package/dist/store/index.d.mts +63 -0
- package/dist/store/index.d.mts.map +1 -1
- package/dist/store/index.mjs.map +1 -1
- package/dist/store/postgres-reporting.cjs +5 -5
- package/dist/store/postgres-reporting.cjs.map +1 -1
- package/dist/store/postgres-reporting.mjs +5 -5
- package/dist/store/postgres-reporting.mjs.map +1 -1
- package/dist/store/postgres.cjs +143 -2
- package/dist/store/postgres.cjs.map +1 -1
- package/dist/store/postgres.d.cts +4 -1
- package/dist/store/postgres.d.cts.map +1 -1
- package/dist/store/postgres.d.mts +4 -1
- package/dist/store/postgres.d.mts.map +1 -1
- package/dist/store/postgres.mjs +143 -2
- package/dist/store/postgres.mjs.map +1 -1
- package/dist/store/tables.cjs +26 -0
- package/dist/store/tables.cjs.map +1 -1
- package/dist/store/tables.d.cts +1 -0
- package/dist/store/tables.d.cts.map +1 -1
- package/dist/store/tables.d.mts +1 -0
- package/dist/store/tables.d.mts.map +1 -1
- package/dist/store/tables.mjs +26 -0
- package/dist/store/tables.mjs.map +1 -1
- package/dist/templates.cjs.map +1 -1
- package/dist/templates.mjs.map +1 -1
- package/dist/transports/cloudflare-email.cjs +59 -0
- package/dist/transports/cloudflare-email.cjs.map +1 -0
- package/dist/transports/cloudflare-email.d.cts +38 -0
- package/dist/transports/cloudflare-email.d.cts.map +1 -0
- package/dist/transports/cloudflare-email.d.mts +38 -0
- package/dist/transports/cloudflare-email.d.mts.map +1 -0
- package/dist/transports/cloudflare-email.mjs +57 -0
- package/dist/transports/cloudflare-email.mjs.map +1 -0
- package/dist/transports/ses.cjs +91 -0
- package/dist/transports/ses.cjs.map +1 -0
- package/dist/transports/ses.d.cts +39 -0
- package/dist/transports/ses.d.cts.map +1 -0
- package/dist/transports/ses.d.mts +39 -0
- package/dist/transports/ses.d.mts.map +1 -0
- package/dist/transports/ses.mjs +89 -0
- package/dist/transports/ses.mjs.map +1 -0
- package/dist/transports/sigv4.cjs +83 -0
- package/dist/transports/sigv4.cjs.map +1 -0
- package/dist/transports/sigv4.d.cts +27 -0
- package/dist/transports/sigv4.d.cts.map +1 -0
- package/dist/transports/sigv4.d.mts +27 -0
- package/dist/transports/sigv4.d.mts.map +1 -0
- package/dist/transports/sigv4.mjs +82 -0
- package/dist/transports/sigv4.mjs.map +1 -0
- package/package.json +53 -1
- package/dist/cloudflare/channels.cjs.map +0 -1
- package/dist/cloudflare/channels.d.cts.map +0 -1
- package/dist/cloudflare/channels.d.mts.map +0 -1
- package/dist/cloudflare/channels.mjs.map +0 -1
- package/dist/cloudflare/router.cjs.map +0 -1
- package/dist/cloudflare/router.d.cts.map +0 -1
- package/dist/cloudflare/router.d.mts.map +0 -1
- package/dist/cloudflare/router.mjs.map +0 -1
- package/dist/cloudflare/senders.cjs +0 -121
- package/dist/cloudflare/senders.cjs.map +0 -1
- package/dist/cloudflare/senders.d.cts +0 -72
- package/dist/cloudflare/senders.d.cts.map +0 -1
- package/dist/cloudflare/senders.d.mts +0 -72
- package/dist/cloudflare/senders.d.mts.map +0 -1
- package/dist/cloudflare/senders.mjs +0 -115
- package/dist/cloudflare/senders.mjs.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EmailAddress } from "../email.cjs";
|
|
2
|
+
import { ExecutionStart } from "../store/index.cjs";
|
|
2
3
|
//#region src/cloudflare/bindings.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* A minimal structural interface over the Cloudflare bindings.
|
|
@@ -44,12 +45,37 @@ export interface WorkflowInstanceLike {
|
|
|
44
45
|
status: string;
|
|
45
46
|
}>;
|
|
46
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* How the router starts, wakes and stops instances: Cloudflare's workflow binding, or the AWS
|
|
50
|
+
* adapter's equivalent over durable executions.
|
|
51
|
+
*/
|
|
47
52
|
export interface WorkflowBindingLike {
|
|
48
53
|
create(options: {
|
|
49
54
|
id: string;
|
|
50
55
|
params: unknown;
|
|
51
56
|
}): Promise<WorkflowInstanceLike>;
|
|
52
57
|
get(id: string): Promise<WorkflowInstanceLike>;
|
|
58
|
+
/**
|
|
59
|
+
* For a runtime whose start is a submit that can be lost in flight (AWS): the start to record
|
|
60
|
+
* with the entry, in one transaction. A failed `create` then keeps the entry — its recorded
|
|
61
|
+
* start is retried by the next ingest for the pair (`resume`) or by maintenance, never rolled
|
|
62
|
+
* back and re-entered as a second execution.
|
|
63
|
+
*/
|
|
64
|
+
plan?(options: {
|
|
65
|
+
id: string;
|
|
66
|
+
params: JourneyParams;
|
|
67
|
+
ts: number;
|
|
68
|
+
}): Promise<ExecutionStart>;
|
|
69
|
+
/** Retry the recorded, unconfirmed start of the (workflow, user) entry still running, if any. */
|
|
70
|
+
resume?(entry: {
|
|
71
|
+
workflow: string;
|
|
72
|
+
userId: string;
|
|
73
|
+
}): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Maintenance the sweep runs first: old unconfirmed starts retried (or given up on), and
|
|
76
|
+
* executions the platform ended on its own (timeout, stop, crash) reconciled into the ledger.
|
|
77
|
+
*/
|
|
78
|
+
maintain?(): Promise<void>;
|
|
53
79
|
}
|
|
54
80
|
/**
|
|
55
81
|
* Cloudflare Email Service's send_email binding (structural subset).
|
|
@@ -121,6 +147,17 @@ export interface JourneyEnv {
|
|
|
121
147
|
/** Development only: the HTTP/2 relay `wrangler dev` sends APNs requests through (see `@shware/workflow/apns-relay`). */
|
|
122
148
|
APNS_RELAY_ORIGIN?: string;
|
|
123
149
|
}
|
|
150
|
+
/** The runtime does not know the instance: the only failure that lets the router drop its wakes. */
|
|
151
|
+
export declare class InstanceNotFoundError extends Error {
|
|
152
|
+
readonly instanceId: string;
|
|
153
|
+
readonly name = "InstanceNotFoundError";
|
|
154
|
+
constructor(instanceId: string);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Does this lookup failure say the instance is gone, rather than that the lookup failed?
|
|
158
|
+
* Cloudflare reports an unknown id as `instance.not_found`.
|
|
159
|
+
*/
|
|
160
|
+
export declare function isInstanceNotFound(error: unknown): boolean;
|
|
124
161
|
/** The event type the router uses to wake waiting instances (sendEvent's `type`). */
|
|
125
162
|
export declare const WAKE_EVENT_TYPE = "wake";
|
|
126
163
|
/** Journey instance parameters, passed by the ingest router when it creates one. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bindings.d.cts","names":[],"sources":["../../src/cloudflare/bindings.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"bindings.d.cts","names":[],"sources":["../../src/cloudflare/bindings.ts"],"mappings":";;;;;;;;;;;iBAYiB;EACf,IAAI,cAAc;EAClB,IAAI,aAAa,gBAAgB;;;iBAIlB;EACf;IAAS;;;iBAGM;EACf,QAAQ,oBAAoB;EAC5B,MAAM,IAAI,4BAA4B,QAAQ;EAC9C,IAAI,IAAI,4BAA4B;IAAU,SAAS;;EACvD,OAAO,QAAQ;;iBAGA;EACf,QAAQ,cAAc;;EAEtB,MAAM,YAAY,4BAA4B;;iBAG/B;EACf;EACA,UAAU;IAAS;IAAc;MAAsB;;EAEvD,cAAc;;EAEd,WAAW;IAAU;;;;;;;iBAON;EACf,OAAO;IAAW;IAAY;MAAoB,QAAQ;EAC1D,IAAI,aAAa,QAAQ;;;;;;;EAOzB,MAAM;IAAW;IAAY,QAAQ;IAAe;MAAe,QAAQ;;EAE3E,QAAQ;IAAS;IAAkB;MAAmB;;;;;EAKtD,aAAa;;;;;;;;;;;;iBAaE;EACf,KAAK;IACH,MAAM;IACN,IAAI;IACJ,UAAU;IACV;IACA;;IAEA;MACE;;;iBAIW;;;;;EAKf,cAAc;;EAEd,KAAK;;EAEL,SAAS;;EAET;;;;;;EAMA;;;;;EAKA;;EAEA;;EAEA,QAAQ;;EAER;;EAEA;;EAEA;EACA;;;;;;;EAOA;IAAwB;IAAY;IAAc;;;EAElD;;;qBAIW,8BAA8B;WAEpB;WADH;EAClB,YAAqB;;;;;;wBASP,mBAAmB;;qBAMtB;;iBAGI;EACf;;EAEA;EACA;EACA;IAAW;IAAe,SAAS;;GAClC;;;;;;;qBAQU;;;;;;;;;;wBAWG,YAAY,mBAAmB,mBAAmB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EmailAddress } from "../email.mjs";
|
|
2
|
+
import { ExecutionStart } from "../store/index.mjs";
|
|
2
3
|
//#region src/cloudflare/bindings.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* A minimal structural interface over the Cloudflare bindings.
|
|
@@ -44,12 +45,37 @@ export interface WorkflowInstanceLike {
|
|
|
44
45
|
status: string;
|
|
45
46
|
}>;
|
|
46
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* How the router starts, wakes and stops instances: Cloudflare's workflow binding, or the AWS
|
|
50
|
+
* adapter's equivalent over durable executions.
|
|
51
|
+
*/
|
|
47
52
|
export interface WorkflowBindingLike {
|
|
48
53
|
create(options: {
|
|
49
54
|
id: string;
|
|
50
55
|
params: unknown;
|
|
51
56
|
}): Promise<WorkflowInstanceLike>;
|
|
52
57
|
get(id: string): Promise<WorkflowInstanceLike>;
|
|
58
|
+
/**
|
|
59
|
+
* For a runtime whose start is a submit that can be lost in flight (AWS): the start to record
|
|
60
|
+
* with the entry, in one transaction. A failed `create` then keeps the entry — its recorded
|
|
61
|
+
* start is retried by the next ingest for the pair (`resume`) or by maintenance, never rolled
|
|
62
|
+
* back and re-entered as a second execution.
|
|
63
|
+
*/
|
|
64
|
+
plan?(options: {
|
|
65
|
+
id: string;
|
|
66
|
+
params: JourneyParams;
|
|
67
|
+
ts: number;
|
|
68
|
+
}): Promise<ExecutionStart>;
|
|
69
|
+
/** Retry the recorded, unconfirmed start of the (workflow, user) entry still running, if any. */
|
|
70
|
+
resume?(entry: {
|
|
71
|
+
workflow: string;
|
|
72
|
+
userId: string;
|
|
73
|
+
}): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Maintenance the sweep runs first: old unconfirmed starts retried (or given up on), and
|
|
76
|
+
* executions the platform ended on its own (timeout, stop, crash) reconciled into the ledger.
|
|
77
|
+
*/
|
|
78
|
+
maintain?(): Promise<void>;
|
|
53
79
|
}
|
|
54
80
|
/**
|
|
55
81
|
* Cloudflare Email Service's send_email binding (structural subset).
|
|
@@ -121,6 +147,17 @@ export interface JourneyEnv {
|
|
|
121
147
|
/** Development only: the HTTP/2 relay `wrangler dev` sends APNs requests through (see `@shware/workflow/apns-relay`). */
|
|
122
148
|
APNS_RELAY_ORIGIN?: string;
|
|
123
149
|
}
|
|
150
|
+
/** The runtime does not know the instance: the only failure that lets the router drop its wakes. */
|
|
151
|
+
export declare class InstanceNotFoundError extends Error {
|
|
152
|
+
readonly instanceId: string;
|
|
153
|
+
readonly name = "InstanceNotFoundError";
|
|
154
|
+
constructor(instanceId: string);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Does this lookup failure say the instance is gone, rather than that the lookup failed?
|
|
158
|
+
* Cloudflare reports an unknown id as `instance.not_found`.
|
|
159
|
+
*/
|
|
160
|
+
export declare function isInstanceNotFound(error: unknown): boolean;
|
|
124
161
|
/** The event type the router uses to wake waiting instances (sendEvent's `type`). */
|
|
125
162
|
export declare const WAKE_EVENT_TYPE = "wake";
|
|
126
163
|
/** Journey instance parameters, passed by the ingest router when it creates one. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bindings.d.mts","names":[],"sources":["../../src/cloudflare/bindings.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"bindings.d.mts","names":[],"sources":["../../src/cloudflare/bindings.ts"],"mappings":";;;;;;;;;;;iBAYiB;EACf,IAAI,cAAc;EAClB,IAAI,aAAa,gBAAgB;;;iBAIlB;EACf;IAAS;;;iBAGM;EACf,QAAQ,oBAAoB;EAC5B,MAAM,IAAI,4BAA4B,QAAQ;EAC9C,IAAI,IAAI,4BAA4B;IAAU,SAAS;;EACvD,OAAO,QAAQ;;iBAGA;EACf,QAAQ,cAAc;;EAEtB,MAAM,YAAY,4BAA4B;;iBAG/B;EACf;EACA,UAAU;IAAS;IAAc;MAAsB;;EAEvD,cAAc;;EAEd,WAAW;IAAU;;;;;;;iBAON;EACf,OAAO;IAAW;IAAY;MAAoB,QAAQ;EAC1D,IAAI,aAAa,QAAQ;;;;;;;EAOzB,MAAM;IAAW;IAAY,QAAQ;IAAe;MAAe,QAAQ;;EAE3E,QAAQ;IAAS;IAAkB;MAAmB;;;;;EAKtD,aAAa;;;;;;;;;;;;iBAaE;EACf,KAAK;IACH,MAAM;IACN,IAAI;IACJ,UAAU;IACV;IACA;;IAEA;MACE;;;iBAIW;;;;;EAKf,cAAc;;EAEd,KAAK;;EAEL,SAAS;;EAET;;;;;;EAMA;;;;;EAKA;;EAEA;;EAEA,QAAQ;;EAER;;EAEA;;EAEA;EACA;;;;;;;EAOA;IAAwB;IAAY;IAAc;;;EAElD;;;qBAIW,8BAA8B;WAEpB;WADH;EAClB,YAAqB;;;;;;wBASP,mBAAmB;;qBAMtB;;iBAGI;EACf;;EAEA;EACA;EACA;IAAW;IAAe,SAAS;;GAClC;;;;;;;qBAQU;;;;;;;;;;wBAWG,YAAY,mBAAmB,mBAAmB"}
|
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
//#region src/cloudflare/bindings.ts
|
|
2
|
+
/** The runtime does not know the instance: the only failure that lets the router drop its wakes. */
|
|
3
|
+
var InstanceNotFoundError = class extends Error {
|
|
4
|
+
instanceId;
|
|
5
|
+
name = "InstanceNotFoundError";
|
|
6
|
+
constructor(instanceId) {
|
|
7
|
+
super(`no such instance: ${instanceId}`);
|
|
8
|
+
this.instanceId = instanceId;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Does this lookup failure say the instance is gone, rather than that the lookup failed?
|
|
13
|
+
* Cloudflare reports an unknown id as `instance.not_found`.
|
|
14
|
+
*/
|
|
15
|
+
function isInstanceNotFound(error) {
|
|
16
|
+
if (error instanceof InstanceNotFoundError) return true;
|
|
17
|
+
return /not[_ ]found|no such instance/i.test(String(error));
|
|
18
|
+
}
|
|
2
19
|
/** The event type the router uses to wake waiting instances (sendEvent's `type`). */
|
|
3
20
|
const WAKE_EVENT_TYPE = "wake";
|
|
4
21
|
/**
|
|
@@ -20,6 +37,6 @@ function wakeExpired(startedAt, timeoutMs, now) {
|
|
|
20
37
|
return now - startedAt >= Math.max(0, timeoutMs - WAKE_TIMEOUT_TOLERANCE_MS);
|
|
21
38
|
}
|
|
22
39
|
//#endregion
|
|
23
|
-
export { WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, wakeExpired };
|
|
40
|
+
export { InstanceNotFoundError, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, isInstanceNotFound, wakeExpired };
|
|
24
41
|
|
|
25
42
|
//# sourceMappingURL=bindings.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bindings.mjs","names":[],"sources":["../../src/cloudflare/bindings.ts"],"sourcesContent":["import type { EmailAddress } from '../email';\n\n/**\n * A minimal structural interface over the Cloudflare bindings.\n *\n * @cloudflare/workers-types is deliberately not used: the global types it\n * injects clash with the DOM lib this package's react side needs. A structural\n * subset plus the ambient cloudflare:workers declaration is enough to compile,\n * and the real bindings satisfy it structurally at runtime.\n */\n\nexport interface KVNamespaceLike {\n get(key: string): Promise<string | null>;\n put(key: string, value: string): Promise<void>;\n}\n\n/** Structural subset of D1Result: `meta.changes` is how INSERT OR IGNORE reports whether it inserted. */\nexport interface D1RunResultLike {\n meta?: { changes?: number };\n}\n\nexport interface D1PreparedStatementLike {\n bind(...values: unknown[]): D1PreparedStatementLike;\n first<T = Record<string, unknown>>(): Promise<T | null>;\n all<T = Record<string, unknown>>(): Promise<{ results: T[] }>;\n run(): Promise<D1RunResultLike>;\n}\n\nexport interface D1DatabaseLike {\n prepare(sql: string): D1PreparedStatementLike;\n /** Statements run in order inside one transaction (real D1 semantics) — deploy relies on the atomicity. */\n batch(statements: D1PreparedStatementLike[]): Promise<unknown>;\n}\n\nexport interface WorkflowInstanceLike {\n id: string;\n sendEvent(event: { type: string; payload?: unknown }): Promise<void>;\n /** Stop the instance for good (Cloudflare Workflows' `terminate`). */\n terminate?(): Promise<void>;\n /** Where it stands (`complete`, `errored`, `terminated`, `running`, …). */\n status?(): Promise<{ status: string }>;\n}\n\nexport interface WorkflowBindingLike {\n create(options: { id: string; params: unknown }): Promise<WorkflowInstanceLike>;\n get(id: string): Promise<WorkflowInstanceLike>;\n}\n\n/**\n * Cloudflare Email Service's send_email binding (structural subset).\n *\n * `idempotencyKey` is part of the call because the send happens inside a\n * `step.do`: a step body re-runs after its fn resolved but before the\n * checkpoint committed, so a binding that drops the key mails the user twice.\n * The binding is app-supplied glue (nothing here can de-duplicate — there is\n * no state between two runs of the same step), which is why the port makes the\n * key impossible to miss rather than merely available.\n */\nexport interface EmailBindingLike {\n send(message: {\n from: EmailAddress;\n to: EmailAddress;\n replyTo?: EmailAddress;\n subject: string;\n html: string;\n /** `${instanceId}:${nodeId}`: stable across replays and retries — drop a send whose key was already delivered. */\n idempotencyKey: string;\n }): Promise<unknown>;\n}\n\n/** Every binding the journey engine needs (names match the wrangler config). */\nexport interface JourneyEnv {\n /**\n * BundleIR storage for the default D1 store (`wf:${contentHash}` → WorkflowIR JSON). Optional:\n * a Worker on another JourneyStore (Postgres, say) does not declare it.\n */\n WORKFLOW_KV?: KVNamespaceLike;\n /** Tables of the default D1 store (events / profiles / segments / triggers / entries / subscriptions). Optional, as above. */\n DB?: D1DatabaseLike;\n /** JourneyRunner's workflow binding (creating instances and waking them). */\n JOURNEY: WorkflowBindingLike;\n /** Optional message-delivery webhook (defaults to the console logging sender). */\n MESSAGE_WEBHOOK_URL?: string;\n /**\n * Bearer token required on every mutating HTTP endpoint (`Authorization:\n * Bearer <token>`). Unset = open — acceptable only for local dev; /deploy in\n * particular rewrites the whole routing table, so production must set this.\n */\n API_TOKEN?: string;\n /**\n * This Worker's public origin. With a store that keeps reporting (Postgres), journey emails'\n * links and open pixel point at its `/t/...` routes; without it emails go out untracked.\n */\n WORKFLOW_ORIGIN?: string;\n /** Which `workflow.config.ts` entry applies (`development`, `production`, …); production when unset. */\n ENVIRONMENT?: string;\n /** Cloudflare Email Sending, when the config has `emails`. */\n EMAIL?: EmailBindingLike;\n /** The APNs auth key (`.p8`, base64) named by the config's `apns.keyId`. */\n APNS_PRIVATE_KEY_BASE64?: string;\n /** The Firebase service account (base64 JSON) the config's `fcm` sends with. */\n GOOGLE_APPLICATION_CREDENTIALS_BASE64?: string;\n /** The VAPID key pair web pushes are signed with (`generateVapidKeys`); the config's `webPush` turns the channel on. */\n VAPID_PUBLIC_KEY?: string;\n VAPID_PRIVATE_KEY?: string;\n /**\n * Cloudflare's version metadata binding (wrangler `\"version_metadata\": { \"binding\":\n * \"CF_VERSION_METADATA\" }`). With it, and a store that records the live version (Postgres),\n * journeyWorker makes the bundle compiled into each new version live by itself: `wrangler\n * deploy` is the whole deploy.\n */\n CF_VERSION_METADATA?: { id: string; tag?: string; timestamp: string };\n /** Development only: the HTTP/2 relay `wrangler dev` sends APNs requests through (see `@shware/workflow/apns-relay`). */\n APNS_RELAY_ORIGIN?: string;\n}\n\n/** The event type the router uses to wake waiting instances (sendEvent's `type`). */\nexport const WAKE_EVENT_TYPE = 'wake';\n\n/** Journey instance parameters, passed by the ingest router when it creates one. */\nexport interface JourneyParams {\n workflowId: string;\n /** The IR version pinned at entry. */\n contentHash: string;\n userId: string;\n trigger: { event: string; payload: Record<string, unknown> };\n [key: string]: unknown;\n}\n\n/**\n * Slack on the deadline when deciding whether a thrown wait was a timeout: the\n * platform may surface the expiry a moment early, and a wait shorter than this\n * has no room to tell the two apart anyway.\n */\nexport const WAKE_TIMEOUT_TOLERANCE_MS = 5_000;\n\n/**\n * Did a wait that threw actually reach its deadline?\n *\n * CF signals a wait timeout by throwing, and so does every other failure in\n * there — a broken binding, an evicted instance, a malformed timeout. The\n * adapter used to read them all as timeouts, which made an infrastructure\n * fault indistinguishable from \"the user never did it\": the journey took its\n * onTimeout branch, early and silently. Only the clock can tell them apart.\n */\nexport function wakeExpired(startedAt: number, timeoutMs: number, now: number): boolean {\n return now - startedAt >= Math.max(0, timeoutMs - WAKE_TIMEOUT_TOLERANCE_MS);\n}\n"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"bindings.mjs","names":[],"sources":["../../src/cloudflare/bindings.ts"],"sourcesContent":["import type { EmailAddress } from '../email';\nimport type { ExecutionStart } from '../store/index';\n\n/**\n * A minimal structural interface over the Cloudflare bindings.\n *\n * @cloudflare/workers-types is deliberately not used: the global types it\n * injects clash with the DOM lib this package's react side needs. A structural\n * subset plus the ambient cloudflare:workers declaration is enough to compile,\n * and the real bindings satisfy it structurally at runtime.\n */\n\nexport interface KVNamespaceLike {\n get(key: string): Promise<string | null>;\n put(key: string, value: string): Promise<void>;\n}\n\n/** Structural subset of D1Result: `meta.changes` is how INSERT OR IGNORE reports whether it inserted. */\nexport interface D1RunResultLike {\n meta?: { changes?: number };\n}\n\nexport interface D1PreparedStatementLike {\n bind(...values: unknown[]): D1PreparedStatementLike;\n first<T = Record<string, unknown>>(): Promise<T | null>;\n all<T = Record<string, unknown>>(): Promise<{ results: T[] }>;\n run(): Promise<D1RunResultLike>;\n}\n\nexport interface D1DatabaseLike {\n prepare(sql: string): D1PreparedStatementLike;\n /** Statements run in order inside one transaction (real D1 semantics) — deploy relies on the atomicity. */\n batch(statements: D1PreparedStatementLike[]): Promise<unknown>;\n}\n\nexport interface WorkflowInstanceLike {\n id: string;\n sendEvent(event: { type: string; payload?: unknown }): Promise<void>;\n /** Stop the instance for good (Cloudflare Workflows' `terminate`). */\n terminate?(): Promise<void>;\n /** Where it stands (`complete`, `errored`, `terminated`, `running`, …). */\n status?(): Promise<{ status: string }>;\n}\n\n/**\n * How the router starts, wakes and stops instances: Cloudflare's workflow binding, or the AWS\n * adapter's equivalent over durable executions.\n */\nexport interface WorkflowBindingLike {\n create(options: { id: string; params: unknown }): Promise<WorkflowInstanceLike>;\n get(id: string): Promise<WorkflowInstanceLike>;\n /**\n * For a runtime whose start is a submit that can be lost in flight (AWS): the start to record\n * with the entry, in one transaction. A failed `create` then keeps the entry — its recorded\n * start is retried by the next ingest for the pair (`resume`) or by maintenance, never rolled\n * back and re-entered as a second execution.\n */\n plan?(options: { id: string; params: JourneyParams; ts: number }): Promise<ExecutionStart>;\n /** Retry the recorded, unconfirmed start of the (workflow, user) entry still running, if any. */\n resume?(entry: { workflow: string; userId: string }): Promise<void>;\n /**\n * Maintenance the sweep runs first: old unconfirmed starts retried (or given up on), and\n * executions the platform ended on its own (timeout, stop, crash) reconciled into the ledger.\n */\n maintain?(): Promise<void>;\n}\n\n/**\n * Cloudflare Email Service's send_email binding (structural subset).\n *\n * `idempotencyKey` is part of the call because the send happens inside a\n * `step.do`: a step body re-runs after its fn resolved but before the\n * checkpoint committed, so a binding that drops the key mails the user twice.\n * The binding is app-supplied glue (nothing here can de-duplicate — there is\n * no state between two runs of the same step), which is why the port makes the\n * key impossible to miss rather than merely available.\n */\nexport interface EmailBindingLike {\n send(message: {\n from: EmailAddress;\n to: EmailAddress;\n replyTo?: EmailAddress;\n subject: string;\n html: string;\n /** `${instanceId}:${nodeId}`: stable across replays and retries — drop a send whose key was already delivered. */\n idempotencyKey: string;\n }): Promise<unknown>;\n}\n\n/** Every binding the journey engine needs (names match the wrangler config). */\nexport interface JourneyEnv {\n /**\n * BundleIR storage for the default D1 store (`wf:${contentHash}` → WorkflowIR JSON). Optional:\n * a Worker on another JourneyStore (Postgres, say) does not declare it.\n */\n WORKFLOW_KV?: KVNamespaceLike;\n /** Tables of the default D1 store (events / profiles / segments / triggers / entries / subscriptions). Optional, as above. */\n DB?: D1DatabaseLike;\n /** JourneyRunner's workflow binding (creating instances and waking them). */\n JOURNEY: WorkflowBindingLike;\n /** Optional message-delivery webhook (defaults to the console logging sender). */\n MESSAGE_WEBHOOK_URL?: string;\n /**\n * Bearer token required on every mutating HTTP endpoint (`Authorization:\n * Bearer <token>`). Unset = open — acceptable only for local dev; /deploy in\n * particular rewrites the whole routing table, so production must set this.\n */\n API_TOKEN?: string;\n /**\n * This Worker's public origin. With a store that keeps reporting (Postgres), journey emails'\n * links and open pixel point at its `/t/...` routes; without it emails go out untracked.\n */\n WORKFLOW_ORIGIN?: string;\n /** Which `workflow.config.ts` entry applies (`development`, `production`, …); production when unset. */\n ENVIRONMENT?: string;\n /** Cloudflare Email Sending, when the config has `emails`. */\n EMAIL?: EmailBindingLike;\n /** The APNs auth key (`.p8`, base64) named by the config's `apns.keyId`. */\n APNS_PRIVATE_KEY_BASE64?: string;\n /** The Firebase service account (base64 JSON) the config's `fcm` sends with. */\n GOOGLE_APPLICATION_CREDENTIALS_BASE64?: string;\n /** The VAPID key pair web pushes are signed with (`generateVapidKeys`); the config's `webPush` turns the channel on. */\n VAPID_PUBLIC_KEY?: string;\n VAPID_PRIVATE_KEY?: string;\n /**\n * Cloudflare's version metadata binding (wrangler `\"version_metadata\": { \"binding\":\n * \"CF_VERSION_METADATA\" }`). With it, and a store that records the live version (Postgres),\n * journeyWorker makes the bundle compiled into each new version live by itself: `wrangler\n * deploy` is the whole deploy.\n */\n CF_VERSION_METADATA?: { id: string; tag?: string; timestamp: string };\n /** Development only: the HTTP/2 relay `wrangler dev` sends APNs requests through (see `@shware/workflow/apns-relay`). */\n APNS_RELAY_ORIGIN?: string;\n}\n\n/** The runtime does not know the instance: the only failure that lets the router drop its wakes. */\nexport class InstanceNotFoundError extends Error {\n override readonly name = 'InstanceNotFoundError';\n constructor(readonly instanceId: string) {\n super(`no such instance: ${instanceId}`);\n }\n}\n\n/**\n * Does this lookup failure say the instance is gone, rather than that the lookup failed?\n * Cloudflare reports an unknown id as `instance.not_found`.\n */\nexport function isInstanceNotFound(error: unknown): boolean {\n if (error instanceof InstanceNotFoundError) return true;\n return /not[_ ]found|no such instance/i.test(String(error));\n}\n\n/** The event type the router uses to wake waiting instances (sendEvent's `type`). */\nexport const WAKE_EVENT_TYPE = 'wake';\n\n/** Journey instance parameters, passed by the ingest router when it creates one. */\nexport interface JourneyParams {\n workflowId: string;\n /** The IR version pinned at entry. */\n contentHash: string;\n userId: string;\n trigger: { event: string; payload: Record<string, unknown> };\n [key: string]: unknown;\n}\n\n/**\n * Slack on the deadline when deciding whether a thrown wait was a timeout: the\n * platform may surface the expiry a moment early, and a wait shorter than this\n * has no room to tell the two apart anyway.\n */\nexport const WAKE_TIMEOUT_TOLERANCE_MS = 5_000;\n\n/**\n * Did a wait that threw actually reach its deadline?\n *\n * CF signals a wait timeout by throwing, and so does every other failure in\n * there — a broken binding, an evicted instance, a malformed timeout. The\n * adapter used to read them all as timeouts, which made an infrastructure\n * fault indistinguishable from \"the user never did it\": the journey took its\n * onTimeout branch, early and silently. Only the clock can tell them apart.\n */\nexport function wakeExpired(startedAt: number, timeoutMs: number, now: number): boolean {\n return now - startedAt >= Math.max(0, timeoutMs - WAKE_TIMEOUT_TOLERANCE_MS);\n}\n"],"mappings":";;AAwIA,IAAa,wBAAb,cAA2C,MAAM;CAE1B;CADrB,OAAyB;CACzB,YAAY,YAA6B;EACvC,MAAM,qBAAqB,YAAY;EADpB,KAAA,aAAA;CAErB;AACF;;;;;AAMA,SAAgB,mBAAmB,OAAyB;CAC1D,IAAI,iBAAiB,uBAAuB,OAAO;CACnD,OAAO,iCAAiC,KAAK,OAAO,KAAK,CAAC;AAC5D;;AAGA,MAAa,kBAAkB;;;;;;AAiB/B,MAAa,4BAA4B;;;;;;;;;;AAWzC,SAAgB,YAAY,WAAmB,WAAmB,KAAsB;CACtF,OAAO,MAAM,aAAa,KAAK,IAAI,GAAG,YAAY,yBAAyB;AAC7E"}
|
|
@@ -1,55 +1,59 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_email_sender = require("../email-sender.cjs");
|
|
2
3
|
const require_store_postgres_reporting = require("../store/postgres-reporting.cjs");
|
|
3
4
|
const require_store_postgres = require("../store/postgres.cjs");
|
|
5
|
+
const require_store_facts = require("../store/facts.cjs");
|
|
4
6
|
const require_cloudflare_bindings = require("./bindings.cjs");
|
|
7
|
+
const require_store_d1 = require("../store/d1.cjs");
|
|
8
|
+
const require_cloudflare_d1_env = require("./d1-env.cjs");
|
|
5
9
|
const require_reporting_classify = require("../reporting/classify.cjs");
|
|
6
10
|
const require_reporting_tracking = require("../reporting/tracking.cjs");
|
|
7
|
-
const require_store_facts = require("../store/facts.cjs");
|
|
8
|
-
const require_store_d1 = require("../store/d1.cjs");
|
|
9
11
|
const require_store_index = require("../store/index.cjs");
|
|
10
|
-
const
|
|
11
|
-
const require_cloudflare_router = require("./router.cjs");
|
|
12
|
-
const require_cloudflare_senders = require("./senders.cjs");
|
|
13
|
-
const require_cloudflare_channels = require("./channels.cjs");
|
|
14
|
-
const require_cloudflare_runner = require("./runner.cjs");
|
|
12
|
+
const require_host_router = require("../host/router.cjs");
|
|
15
13
|
const require_reporting_observer = require("../reporting/observer.cjs");
|
|
14
|
+
const require_host_senders = require("../host/senders.cjs");
|
|
15
|
+
const require_host_channels = require("../host/channels.cjs");
|
|
16
|
+
const require_host_journey_host = require("../host/journey-host.cjs");
|
|
17
|
+
const require_cloudflare_runner = require("./runner.cjs");
|
|
16
18
|
const require_cloudflare_worker = require("./worker.cjs");
|
|
17
19
|
exports.BURST_WINDOW_MS = require_reporting_classify.BURST_WINDOW_MS;
|
|
18
|
-
exports.BundleIntegrityError =
|
|
19
|
-
exports.CfEmailSender = require_cloudflare_senders.CfEmailSender;
|
|
20
|
+
exports.BundleIntegrityError = require_host_router.BundleIntegrityError;
|
|
20
21
|
exports.D1JourneyStore = require_store_d1.D1JourneyStore;
|
|
21
22
|
exports.DEFAULT_QUICK_MS = require_reporting_classify.DEFAULT_QUICK_MS;
|
|
22
|
-
exports.
|
|
23
|
+
exports.EmailSender = require_email_sender.EmailSender;
|
|
24
|
+
exports.EnvValidationError = require_host_journey_host.EnvValidationError;
|
|
25
|
+
exports.InstanceNotFoundError = require_cloudflare_bindings.InstanceNotFoundError;
|
|
23
26
|
exports.JourneyFactSource = require_store_facts.JourneyFactSource;
|
|
24
27
|
exports.JourneyRunner = require_cloudflare_runner.JourneyRunner;
|
|
25
|
-
exports.LogMessageSender =
|
|
28
|
+
exports.LogMessageSender = require_host_senders.LogMessageSender;
|
|
26
29
|
exports.PostgresJourneyStore = require_store_postgres.PostgresJourneyStore;
|
|
27
30
|
exports.PostgresReporting = require_store_postgres_reporting.PostgresReporting;
|
|
28
31
|
exports.SchemaMismatchError = require_store_index.SchemaMismatchError;
|
|
29
|
-
exports.UnversionedStoreError =
|
|
32
|
+
exports.UnversionedStoreError = require_host_router.UnversionedStoreError;
|
|
30
33
|
exports.WAKE_EVENT_TYPE = require_cloudflare_bindings.WAKE_EVENT_TYPE;
|
|
31
34
|
exports.WAKE_TIMEOUT_TOLERANCE_MS = require_cloudflare_bindings.WAKE_TIMEOUT_TOLERANCE_MS;
|
|
32
|
-
exports.WebhookMessageSender =
|
|
33
|
-
exports.channelsFromConfig =
|
|
35
|
+
exports.WebhookMessageSender = require_host_senders.WebhookMessageSender;
|
|
36
|
+
exports.channelsFromConfig = require_host_channels.channelsFromConfig;
|
|
34
37
|
exports.classifyClick = require_reporting_classify.classifyClick;
|
|
35
38
|
exports.classifyOpen = require_reporting_classify.classifyOpen;
|
|
36
39
|
exports.d1Store = require_cloudflare_d1_env.d1Store;
|
|
37
|
-
exports.deployBundle =
|
|
38
|
-
exports.forgetUser =
|
|
39
|
-
exports.handleRequest =
|
|
40
|
+
exports.deployBundle = require_host_router.deployBundle;
|
|
41
|
+
exports.forgetUser = require_host_router.forgetUser;
|
|
42
|
+
exports.handleRequest = require_host_router.handleRequest;
|
|
40
43
|
exports.handleTracking = require_reporting_tracking.handleTracking;
|
|
41
|
-
exports.identifyUser =
|
|
42
|
-
exports.ingestEvent =
|
|
43
|
-
exports.
|
|
44
|
+
exports.identifyUser = require_host_router.identifyUser;
|
|
45
|
+
exports.ingestEvent = require_host_router.ingestEvent;
|
|
46
|
+
exports.isInstanceNotFound = require_cloudflare_bindings.isInstanceNotFound;
|
|
47
|
+
exports.journeyMode = require_host_channels.journeyMode;
|
|
44
48
|
exports.journeyWorker = require_cloudflare_worker.journeyWorker;
|
|
45
49
|
exports.recordPushOpen = require_reporting_tracking.recordPushOpen;
|
|
46
|
-
exports.registerDevice =
|
|
47
|
-
exports.removeDevice =
|
|
50
|
+
exports.registerDevice = require_host_router.registerDevice;
|
|
51
|
+
exports.removeDevice = require_host_router.removeDevice;
|
|
48
52
|
exports.reportingObserver = require_reporting_observer.reportingObserver;
|
|
49
|
-
exports.routeByChannel =
|
|
50
|
-
exports.routeByPlatform =
|
|
51
|
-
exports.runtimeFromConfig =
|
|
52
|
-
exports.sweepSegments =
|
|
53
|
-
exports.trackEmail =
|
|
54
|
-
exports.unbindDevice =
|
|
53
|
+
exports.routeByChannel = require_host_senders.routeByChannel;
|
|
54
|
+
exports.routeByPlatform = require_host_senders.routeByPlatform;
|
|
55
|
+
exports.runtimeFromConfig = require_host_channels.runtimeFromConfig;
|
|
56
|
+
exports.sweepSegments = require_host_router.sweepSegments;
|
|
57
|
+
exports.trackEmail = require_email_sender.trackEmail;
|
|
58
|
+
exports.unbindDevice = require_host_router.unbindDevice;
|
|
55
59
|
exports.wakeExpired = require_cloudflare_bindings.wakeExpired;
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { JourneyObserver, LinkPurpose, MessageTracking, OutboundMessage, PushDevice, SendResult } from "../engine/ports.cjs";
|
|
2
2
|
import { EmailAddress } from "../email.cjs";
|
|
3
|
-
import { D1DatabaseLike, EmailBindingLike, JourneyEnv, JourneyParams, KVNamespaceLike, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, WorkflowBindingLike, WorkflowInstanceLike, wakeExpired } from "./bindings.cjs";
|
|
3
|
+
import { D1DatabaseLike, EmailBindingLike, InstanceNotFoundError, JourneyEnv, JourneyParams, KVNamespaceLike, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, WorkflowBindingLike, WorkflowInstanceLike, isInstanceNotFound, wakeExpired } from "./bindings.cjs";
|
|
4
4
|
import { D1JourneyStore } from "../store/d1.cjs";
|
|
5
5
|
import { JourneyFactSource } from "../store/facts.cjs";
|
|
6
6
|
import { SqlClientLike } from "../store/sql.cjs";
|
|
7
7
|
import { PostgresJourneyStore, PostgresJourneyStoreOptions } from "../store/postgres.cjs";
|
|
8
8
|
import { PostgresReporting } from "../store/postgres-reporting.cjs";
|
|
9
9
|
import { BundleVersion, Engagement, EntryInput, EntryOutcome, EventInput, JourneyReporting, JourneyStore, MessageRecord, ProfileProps, SchemaMismatchError, SegmentTriggerRoute, StoreLease, TriggerRoute } from "../store/index.cjs";
|
|
10
|
+
import { EmailMessage, EmailRenderer, EmailSender, EmailSenderOptions, EmailTransport, RenderedEmail, trackEmail } from "../email-sender.cjs";
|
|
11
|
+
import { BundleIntegrityError, DeployResult, DeviceRegistration, IdentifyResult, IngestInput, IngestResult, SweepResult, UnversionedStoreError, deployBundle, forgetUser, handleRequest, identifyUser, ingestEvent, registerDevice, removeDevice, sweepSegments, unbindDevice } from "../host/router.cjs";
|
|
12
|
+
import { EnvValidationError } from "../host/journey-host.cjs";
|
|
10
13
|
import { d1Store } from "./d1-env.cjs";
|
|
11
|
-
import { BundleIntegrityError, DeployResult, DeviceRegistration, IdentifyResult, IngestInput, IngestResult, SweepResult, UnversionedStoreError, deployBundle, forgetUser, handleRequest, identifyUser, ingestEvent, registerDevice, removeDevice, sweepSegments, unbindDevice } from "./router.cjs";
|
|
12
14
|
import { JourneyRunner } from "./runner.cjs";
|
|
13
|
-
import {
|
|
14
|
-
import { ChannelsConfig, channelsFromConfig, journeyMode, runtimeFromConfig } from "
|
|
15
|
+
import { LogMessageSender, WebhookMessageSender, routeByChannel, routeByPlatform } from "../host/senders.cjs";
|
|
16
|
+
import { ChannelsConfig, channelsFromConfig, journeyMode, runtimeFromConfig } from "../host/channels.cjs";
|
|
15
17
|
import { reportingObserver } from "../reporting/observer.cjs";
|
|
16
18
|
import { TrackingOptions, handleTracking, recordPushOpen } from "../reporting/tracking.cjs";
|
|
17
19
|
import { BURST_WINDOW_MS, ClassifyOptions, ClickFacts, DEFAULT_QUICK_MS, RequestFacts, Verdict, classifyClick, classifyOpen } from "../reporting/classify.cjs";
|
|
18
|
-
import {
|
|
19
|
-
export { BURST_WINDOW_MS, BundleIntegrityError, type BundleVersion, type
|
|
20
|
+
import { ExecutionContextLike, JourneyWorker, JourneyWorkerOptions, journeyWorker } from "./worker.cjs";
|
|
21
|
+
export { BURST_WINDOW_MS, BundleIntegrityError, type BundleVersion, type ChannelsConfig, type ClassifyOptions, type ClickFacts, type D1DatabaseLike, D1JourneyStore, DEFAULT_QUICK_MS, type DeployResult, type DeviceRegistration, type EmailAddress, type EmailBindingLike, type EmailMessage, type EmailRenderer, EmailSender, type EmailSenderOptions, type EmailTransport, type Engagement, type EntryInput, type EntryOutcome, EnvValidationError, type EventInput, type ExecutionContextLike, type IdentifyResult, type IngestInput, type IngestResult, InstanceNotFoundError, type JourneyEnv, JourneyFactSource, type JourneyObserver, type JourneyParams, type JourneyReporting, JourneyRunner, type JourneyStore, type JourneyWorker, type JourneyWorkerOptions, type KVNamespaceLike, type LinkPurpose, LogMessageSender, type MessageRecord, type MessageTracking, type OutboundMessage, PostgresJourneyStore, type PostgresJourneyStoreOptions, PostgresReporting, type ProfileProps, type PushDevice, type RenderedEmail, type RequestFacts, SchemaMismatchError, type SegmentTriggerRoute, type SendResult, type SqlClientLike, type StoreLease, type SweepResult, type TrackingOptions, type TriggerRoute, UnversionedStoreError, type Verdict, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, WebhookMessageSender, type WorkflowBindingLike, type WorkflowInstanceLike, channelsFromConfig, classifyClick, classifyOpen, d1Store, deployBundle, forgetUser, handleRequest, handleTracking, identifyUser, ingestEvent, isInstanceNotFound, journeyMode, journeyWorker, recordPushOpen, registerDevice, removeDevice, reportingObserver, routeByChannel, routeByPlatform, runtimeFromConfig, sweepSegments, trackEmail, unbindDevice, wakeExpired };
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { JourneyObserver, LinkPurpose, MessageTracking, OutboundMessage, PushDevice, SendResult } from "../engine/ports.mjs";
|
|
2
2
|
import { EmailAddress } from "../email.mjs";
|
|
3
|
-
import { D1DatabaseLike, EmailBindingLike, JourneyEnv, JourneyParams, KVNamespaceLike, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, WorkflowBindingLike, WorkflowInstanceLike, wakeExpired } from "./bindings.mjs";
|
|
3
|
+
import { D1DatabaseLike, EmailBindingLike, InstanceNotFoundError, JourneyEnv, JourneyParams, KVNamespaceLike, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, WorkflowBindingLike, WorkflowInstanceLike, isInstanceNotFound, wakeExpired } from "./bindings.mjs";
|
|
4
4
|
import { D1JourneyStore } from "../store/d1.mjs";
|
|
5
5
|
import { JourneyFactSource } from "../store/facts.mjs";
|
|
6
6
|
import { SqlClientLike } from "../store/sql.mjs";
|
|
7
7
|
import { PostgresJourneyStore, PostgresJourneyStoreOptions } from "../store/postgres.mjs";
|
|
8
8
|
import { PostgresReporting } from "../store/postgres-reporting.mjs";
|
|
9
9
|
import { BundleVersion, Engagement, EntryInput, EntryOutcome, EventInput, JourneyReporting, JourneyStore, MessageRecord, ProfileProps, SchemaMismatchError, SegmentTriggerRoute, StoreLease, TriggerRoute } from "../store/index.mjs";
|
|
10
|
+
import { EmailMessage, EmailRenderer, EmailSender, EmailSenderOptions, EmailTransport, RenderedEmail, trackEmail } from "../email-sender.mjs";
|
|
11
|
+
import { BundleIntegrityError, DeployResult, DeviceRegistration, IdentifyResult, IngestInput, IngestResult, SweepResult, UnversionedStoreError, deployBundle, forgetUser, handleRequest, identifyUser, ingestEvent, registerDevice, removeDevice, sweepSegments, unbindDevice } from "../host/router.mjs";
|
|
12
|
+
import { EnvValidationError } from "../host/journey-host.mjs";
|
|
10
13
|
import { d1Store } from "./d1-env.mjs";
|
|
11
|
-
import { BundleIntegrityError, DeployResult, DeviceRegistration, IdentifyResult, IngestInput, IngestResult, SweepResult, UnversionedStoreError, deployBundle, forgetUser, handleRequest, identifyUser, ingestEvent, registerDevice, removeDevice, sweepSegments, unbindDevice } from "./router.mjs";
|
|
12
14
|
import { JourneyRunner } from "./runner.mjs";
|
|
13
|
-
import {
|
|
14
|
-
import { ChannelsConfig, channelsFromConfig, journeyMode, runtimeFromConfig } from "
|
|
15
|
+
import { LogMessageSender, WebhookMessageSender, routeByChannel, routeByPlatform } from "../host/senders.mjs";
|
|
16
|
+
import { ChannelsConfig, channelsFromConfig, journeyMode, runtimeFromConfig } from "../host/channels.mjs";
|
|
15
17
|
import { reportingObserver } from "../reporting/observer.mjs";
|
|
16
18
|
import { TrackingOptions, handleTracking, recordPushOpen } from "../reporting/tracking.mjs";
|
|
17
19
|
import { BURST_WINDOW_MS, ClassifyOptions, ClickFacts, DEFAULT_QUICK_MS, RequestFacts, Verdict, classifyClick, classifyOpen } from "../reporting/classify.mjs";
|
|
18
|
-
import {
|
|
19
|
-
export { BURST_WINDOW_MS, BundleIntegrityError, type BundleVersion, type
|
|
20
|
+
import { ExecutionContextLike, JourneyWorker, JourneyWorkerOptions, journeyWorker } from "./worker.mjs";
|
|
21
|
+
export { BURST_WINDOW_MS, BundleIntegrityError, type BundleVersion, type ChannelsConfig, type ClassifyOptions, type ClickFacts, type D1DatabaseLike, D1JourneyStore, DEFAULT_QUICK_MS, type DeployResult, type DeviceRegistration, type EmailAddress, type EmailBindingLike, type EmailMessage, type EmailRenderer, EmailSender, type EmailSenderOptions, type EmailTransport, type Engagement, type EntryInput, type EntryOutcome, EnvValidationError, type EventInput, type ExecutionContextLike, type IdentifyResult, type IngestInput, type IngestResult, InstanceNotFoundError, type JourneyEnv, JourneyFactSource, type JourneyObserver, type JourneyParams, type JourneyReporting, JourneyRunner, type JourneyStore, type JourneyWorker, type JourneyWorkerOptions, type KVNamespaceLike, type LinkPurpose, LogMessageSender, type MessageRecord, type MessageTracking, type OutboundMessage, PostgresJourneyStore, type PostgresJourneyStoreOptions, PostgresReporting, type ProfileProps, type PushDevice, type RenderedEmail, type RequestFacts, SchemaMismatchError, type SegmentTriggerRoute, type SendResult, type SqlClientLike, type StoreLease, type SweepResult, type TrackingOptions, type TriggerRoute, UnversionedStoreError, type Verdict, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, WebhookMessageSender, type WorkflowBindingLike, type WorkflowInstanceLike, channelsFromConfig, classifyClick, classifyOpen, d1Store, deployBundle, forgetUser, handleRequest, handleTracking, identifyUser, ingestEvent, isInstanceNotFound, journeyMode, journeyWorker, recordPushOpen, registerDevice, removeDevice, reportingObserver, routeByChannel, routeByPlatform, runtimeFromConfig, sweepSegments, trackEmail, unbindDevice, wakeExpired };
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
import { EmailSender, trackEmail } from "../email-sender.mjs";
|
|
1
2
|
import { PostgresReporting } from "../store/postgres-reporting.mjs";
|
|
2
3
|
import { PostgresJourneyStore } from "../store/postgres.mjs";
|
|
3
|
-
import { WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, wakeExpired } from "./bindings.mjs";
|
|
4
|
-
import { BURST_WINDOW_MS, DEFAULT_QUICK_MS, classifyClick, classifyOpen } from "../reporting/classify.mjs";
|
|
5
|
-
import { handleTracking, recordPushOpen } from "../reporting/tracking.mjs";
|
|
6
4
|
import { JourneyFactSource } from "../store/facts.mjs";
|
|
5
|
+
import { InstanceNotFoundError, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, isInstanceNotFound, wakeExpired } from "./bindings.mjs";
|
|
7
6
|
import { D1JourneyStore } from "../store/d1.mjs";
|
|
8
|
-
import { SchemaMismatchError } from "../store/index.mjs";
|
|
9
7
|
import { d1Store } from "./d1-env.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
8
|
+
import { BURST_WINDOW_MS, DEFAULT_QUICK_MS, classifyClick, classifyOpen } from "../reporting/classify.mjs";
|
|
9
|
+
import { handleTracking, recordPushOpen } from "../reporting/tracking.mjs";
|
|
10
|
+
import { SchemaMismatchError } from "../store/index.mjs";
|
|
11
|
+
import { BundleIntegrityError, UnversionedStoreError, deployBundle, forgetUser, handleRequest, identifyUser, ingestEvent, registerDevice, removeDevice, sweepSegments, unbindDevice } from "../host/router.mjs";
|
|
14
12
|
import { reportingObserver } from "../reporting/observer.mjs";
|
|
15
|
-
import {
|
|
16
|
-
|
|
13
|
+
import { LogMessageSender, WebhookMessageSender, routeByChannel, routeByPlatform } from "../host/senders.mjs";
|
|
14
|
+
import { channelsFromConfig, journeyMode, runtimeFromConfig } from "../host/channels.mjs";
|
|
15
|
+
import { EnvValidationError } from "../host/journey-host.mjs";
|
|
16
|
+
import { JourneyRunner } from "./runner.mjs";
|
|
17
|
+
import { journeyWorker } from "./worker.mjs";
|
|
18
|
+
export { BURST_WINDOW_MS, BundleIntegrityError, D1JourneyStore, DEFAULT_QUICK_MS, EmailSender, EnvValidationError, InstanceNotFoundError, JourneyFactSource, JourneyRunner, LogMessageSender, PostgresJourneyStore, PostgresReporting, SchemaMismatchError, UnversionedStoreError, WAKE_EVENT_TYPE, WAKE_TIMEOUT_TOLERANCE_MS, WebhookMessageSender, channelsFromConfig, classifyClick, classifyOpen, d1Store, deployBundle, forgetUser, handleRequest, handleTracking, identifyUser, ingestEvent, isInstanceNotFound, journeyMode, journeyWorker, recordPushOpen, registerDevice, removeDevice, reportingObserver, routeByChannel, routeByPlatform, runtimeFromConfig, sweepSegments, trackEmail, unbindDevice, wakeExpired };
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_contract = require("../contract.cjs");
|
|
3
2
|
const require_runtime = require("../runtime.cjs");
|
|
4
3
|
const require_cloudflare_bindings = require("./bindings.cjs");
|
|
5
|
-
const require_store_facts = require("../store/facts.cjs");
|
|
6
4
|
const require_cloudflare_d1_env = require("./d1-env.cjs");
|
|
7
|
-
const
|
|
8
|
-
const require_cloudflare_senders = require("./senders.cjs");
|
|
5
|
+
const require_host_execute = require("../host/execute.cjs");
|
|
9
6
|
const require_engine_actions = require("../engine/actions.cjs");
|
|
10
|
-
const
|
|
11
|
-
const require_engine_time_scale = require("../engine/time-scale.cjs");
|
|
7
|
+
const require_host_senders = require("../host/senders.cjs");
|
|
12
8
|
let cloudflare_workers = require("cloudflare:workers");
|
|
13
9
|
let cloudflare_workflows = require("cloudflare:workflows");
|
|
14
10
|
//#region src/cloudflare/runner.ts
|
|
@@ -73,13 +69,6 @@ var CfEngineStep = class {
|
|
|
73
69
|
}
|
|
74
70
|
}
|
|
75
71
|
};
|
|
76
|
-
/** Development aid: echo each outbound message before handing it to the real sender. */
|
|
77
|
-
function logging(sender) {
|
|
78
|
-
return { async send(message) {
|
|
79
|
-
console.log(`[journey] ${message.channel} ${message.template} → ${message.recipient ?? message.userId} ${JSON.stringify(message.props)}`);
|
|
80
|
-
return sender.send(message);
|
|
81
|
-
} };
|
|
82
|
-
}
|
|
83
72
|
/**
|
|
84
73
|
* The generic journey executor: one class runs every workflow, because IR is
|
|
85
74
|
* data. It is loaded from the store by the contentHash pinned at entry —
|
|
@@ -114,11 +103,11 @@ var JourneyRunner = class extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
114
103
|
}
|
|
115
104
|
/**
|
|
116
105
|
* Message outlet; an app overrides this to plug in real channels (say
|
|
117
|
-
*
|
|
106
|
+
* an EmailSender over a transport with a react-email renderer). By default it picks the webhook
|
|
118
107
|
* or logging sender based on the environment.
|
|
119
108
|
*/
|
|
120
109
|
createMessageSender() {
|
|
121
|
-
return this.env.MESSAGE_WEBHOOK_URL ? new
|
|
110
|
+
return this.env.MESSAGE_WEBHOOK_URL ? new require_host_senders.WebhookMessageSender(this.env.MESSAGE_WEBHOOK_URL) : new require_host_senders.LogMessageSender();
|
|
122
111
|
}
|
|
123
112
|
/**
|
|
124
113
|
* Custom-action registry; an app overrides this returning the same
|
|
@@ -150,73 +139,35 @@ var JourneyRunner = class extends cloudflare_workers.WorkflowEntrypoint {
|
|
|
150
139
|
createActionInvoker() {
|
|
151
140
|
return new require_engine_actions.RegistryActionInvoker(this.actions());
|
|
152
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Everything one run is wired to. By default it is composed from the methods above; a host
|
|
144
|
+
* that assembles the whole set itself (journeyWorker) overrides this one instead.
|
|
145
|
+
*/
|
|
146
|
+
createRunParts(store, params) {
|
|
147
|
+
return {
|
|
148
|
+
store,
|
|
149
|
+
env: this.env,
|
|
150
|
+
runtime: this.runtime(params),
|
|
151
|
+
messages: this.createMessageSender(),
|
|
152
|
+
actions: this.createActionInvoker(),
|
|
153
|
+
contract: this.contract(),
|
|
154
|
+
validator: this.createMessageValidator(),
|
|
155
|
+
observer: this.createObserver(store)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
153
158
|
async run(event, step) {
|
|
154
159
|
const store = this.createStore();
|
|
155
160
|
try {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
await this.closeStore(store);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
async execute(event, step, store) {
|
|
162
|
-
const { workflowId, contentHash, userId } = event.payload;
|
|
163
|
-
const env = this.env;
|
|
164
|
-
const stored = await store.getWorkflowIR(contentHash);
|
|
165
|
-
if (stored === void 0) throw new Error(`WorkflowIR not found: ${workflowId}@${contentHash}`);
|
|
166
|
-
const runtime = require_runtime.resolveRuntime({ current: this.runtime(event.payload) }, "current");
|
|
167
|
-
const ir = require_engine_time_scale.scaleDurations(stored, runtime.timeScale);
|
|
168
|
-
const observer = this.createObserver(store);
|
|
169
|
-
const finished = (status, convertedAt) => observer?.finished?.({
|
|
170
|
-
workflow: workflowId,
|
|
171
|
-
instanceId: event.instanceId,
|
|
172
|
-
userId,
|
|
173
|
-
status,
|
|
174
|
-
at: Date.now(),
|
|
175
|
-
...convertedAt === void 0 ? {} : { convertedAt }
|
|
176
|
-
});
|
|
177
|
-
const messages = runtime.logMessages ? logging(this.createMessageSender()) : this.createMessageSender();
|
|
178
|
-
const contract = this.contract();
|
|
179
|
-
const events = { emit: async (name, payload, id) => {
|
|
180
|
-
let accepted = payload;
|
|
181
|
-
if (contract !== void 0) {
|
|
182
|
-
const verdict = require_contract.checkEvent(contract, name, payload);
|
|
183
|
-
if (!verdict.ok) throw new require_contract.ContractValidationError(name, verdict.issues);
|
|
184
|
-
accepted = verdict.data;
|
|
185
|
-
}
|
|
186
|
-
await require_cloudflare_router.ingestEvent(env, {
|
|
187
|
-
id,
|
|
188
|
-
userId,
|
|
189
|
-
event: name,
|
|
190
|
-
payload: accepted
|
|
191
|
-
}, store);
|
|
192
|
-
} };
|
|
193
|
-
let outcome;
|
|
194
|
-
try {
|
|
195
|
-
outcome = await require_engine_interpreter.runJourney(ir, {
|
|
196
|
-
userId,
|
|
161
|
+
const { userId } = event.payload;
|
|
162
|
+
return await require_host_execute.executeJourney({
|
|
197
163
|
instanceId: event.instanceId,
|
|
164
|
+
params: event.payload,
|
|
198
165
|
enteredAtMs: event.timestamp.getTime(),
|
|
199
|
-
step: new CfEngineStep(step, store, userId, event.instanceId)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
actions: this.createActionInvoker(),
|
|
204
|
-
validator: this.createMessageValidator(),
|
|
205
|
-
observer
|
|
206
|
-
});
|
|
207
|
-
} catch (error) {
|
|
208
|
-
await step.do("finalize:failed", async () => {
|
|
209
|
-
await store.setEntryStatus(event.instanceId, "failed");
|
|
210
|
-
await finished("failed");
|
|
211
|
-
});
|
|
212
|
-
throw error;
|
|
166
|
+
step: new CfEngineStep(step, store, userId, event.instanceId)
|
|
167
|
+
}, this.createRunParts(store, event.payload));
|
|
168
|
+
} finally {
|
|
169
|
+
await this.closeStore(store);
|
|
213
170
|
}
|
|
214
|
-
await step.do("finalize", async () => {
|
|
215
|
-
await store.setEntryStatus(event.instanceId, outcome.status);
|
|
216
|
-
await store.unsubscribe(event.instanceId);
|
|
217
|
-
await finished(outcome.status, outcome.convertedAt);
|
|
218
|
-
});
|
|
219
|
-
return outcome;
|
|
220
171
|
}
|
|
221
172
|
};
|
|
222
173
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.cjs","names":["NonRetryableError","WAKE_EVENT_TYPE","wakeExpired","WorkflowEntrypoint","d1Store","resolveRuntime","WebhookMessageSender","LogMessageSender","RegistryActionInvoker","scaleDurations","checkEvent","ContractValidationError","ingestEvent","runJourney","JourneyFactSource"],"sources":["../../src/cloudflare/runner.ts"],"sourcesContent":["import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from 'cloudflare:workers';\nimport { NonRetryableError } from 'cloudflare:workflows';\nimport { type Contract, ContractValidationError, checkEvent } from '../contract';\nimport { type RegisteredAction, RegistryActionInvoker } from '../engine/actions';\nimport { runJourney } from '../engine/interpreter';\nimport type {\n ActionInvoker,\n EngineStep,\n EventSink,\n JourneyObserver,\n JourneyOutcome,\n MessageSender,\n MessageValidator,\n} from '../engine/ports';\nimport { scaleDurations } from '../engine/time-scale';\nimport { type JourneyRuntimeOptions, resolveRuntime } from '../runtime';\nimport { JourneyFactSource } from '../store/facts';\nimport type { JourneyStore } from '../store/index';\nimport { type JourneyEnv, type JourneyParams, WAKE_EVENT_TYPE, wakeExpired } from './bindings';\nimport { d1Store } from './d1-env';\nimport { ingestEvent } from './router';\nimport { LogMessageSender, WebhookMessageSender } from './senders';\n\n/**\n * Adapts CF's WorkflowStep to EngineStep.\n * subscribe/unsubscribe write the subscription table inside durable steps (the\n * router wakes instances from that table); waitForWake parks on CF's\n * waitForEvent, which signals a timeout by throwing — and so does every other\n * failure in there, so only the clock can tell them apart (see wakeExpired).\n */\n/** Refusals a retry would only repeat: a template's props, an emitted event's payload. */\nconst NON_RETRYABLE = new Set(['TemplateValidationError', 'ContractValidationError']);\n\nclass CfEngineStep implements EngineStep {\n constructor(\n private readonly step: WorkflowStep,\n private readonly store: JourneyStore,\n private readonly userId: string,\n private readonly instanceId: string\n ) {}\n\n /**\n * A template refusing its props, or the contract refusing an emitted event,\n * is deterministic — a retry hits the same refusal — so it ends the step at\n * once instead of burning the retry budget.\n */\n do<T>(name: string, fn: () => Promise<T>): Promise<T> {\n return this.step.do(name, async () => {\n try {\n return await fn();\n } catch (error) {\n if (error instanceof Error && NON_RETRYABLE.has(error.name)) {\n throw new NonRetryableError(error.message, error.name);\n }\n throw error;\n }\n });\n }\n\n sleep(name: string, ms: number): Promise<void> {\n return this.step.sleep(name, ms);\n }\n\n sleepUntil(name: string, timestampMs: number): Promise<void> {\n return this.step.sleepUntil(name, timestampMs);\n }\n\n subscribe(name: string, events: readonly string[]): Promise<void> {\n // Idempotent in the store: the interpreter re-subscribes on every wait\n // attempt (one-shot-callback contract) and registrations persist here.\n return this.step.do(name, () =>\n this.store.subscribe(this.instanceId, this.userId, events, Date.now())\n );\n }\n\n unsubscribe(name: string): Promise<void> {\n return this.step.do(name, () => this.store.unsubscribe(this.instanceId));\n }\n\n async waitForWake(name: string, timeoutMs: number): Promise<'event' | 'timeout'> {\n const startedAt = Date.now();\n try {\n await this.step.waitForEvent(name, { type: WAKE_EVENT_TYPE, timeout: timeoutMs });\n return 'event';\n } catch (error) {\n /*\n * Only the deadline can tell a real timeout from a failure (see\n * wakeExpired). `startedAt` is not replay-stable, but it is read only\n * inside the step body below, and a step body runs on the live attempt\n * alone — a replay returns the persisted verdict without touching the\n * clock.\n */\n const timedOut = await this.step.do(`${name}:timed-out`, async () =>\n wakeExpired(startedAt, timeoutMs, Date.now())\n );\n if (timedOut) return 'timeout';\n throw error;\n }\n }\n}\n\n/** Development aid: echo each outbound message before handing it to the real sender. */\nfunction logging(sender: MessageSender): MessageSender {\n return {\n async send(message) {\n console.log(\n `[journey] ${message.channel} ${message.template} → ${message.recipient ?? message.userId} ${JSON.stringify(message.props)}`\n );\n return sender.send(message);\n },\n };\n}\n\n/**\n * The generic journey executor: one class runs every workflow, because IR is\n * data. It is loaded from the store by the contentHash pinned at entry —\n * content addressing makes it immutable, so reading it outside a step is\n * replay-safe.\n */\nexport class JourneyRunner extends WorkflowEntrypoint<JourneyEnv, JourneyParams> {\n /**\n * The data plane. D1 + KV from the env by default; an app on Postgres\n * overrides this (and `closeStore` if its client needs closing):\n *\n * protected override createStore() { return new PostgresJourneyStore(client(this.env)); }\n */\n protected createStore(): JourneyStore {\n return d1Store(this.env);\n }\n\n /** Called once `run` is over, success or not — release whatever `createStore` opened. */\n protected async closeStore(_store: JourneyStore): Promise<void> {}\n\n /**\n * Runtime options for this instance — typed configuration, resolved by the app (typically\n * `resolveRuntime(config.runtime, mode)` over its workflow.config.ts, with the mode coming from\n * an ENVIRONMENT var). The instance params are passed so the decision can also be per user:\n * a tester account in production can run in fast-forward while everyone else runs in real\n * time. Defaults: real time, quiet.\n *\n * protected override runtime({ userId }) {\n * return resolveRuntime(workflowConfig.runtime, isTester(userId) ? 'test' : this.env.ENVIRONMENT);\n * }\n */\n protected runtime(_params: JourneyParams): JourneyRuntimeOptions {\n return resolveRuntime(undefined, 'production');\n }\n\n /**\n * Message outlet; an app overrides this to plug in real channels (say\n * CfEmailSender with a react-email renderer). By default it picks the webhook\n * or logging sender based on the environment.\n */\n protected createMessageSender(): MessageSender {\n return this.env.MESSAGE_WEBHOOK_URL\n ? new WebhookMessageSender(this.env.MESSAGE_WEBHOOK_URL)\n : new LogMessageSender();\n }\n\n /**\n * Custom-action registry; an app overrides this returning the same\n * `action(...)` objects its workflows reference (an ActionRef is a\n * RegisteredAction structurally) — the code plane of the dual-plane model:\n *\n * protected override actions() { return [syncCrm, issueCoupon]; }\n */\n protected actions(): readonly RegisteredAction[] {\n return [];\n }\n\n /**\n * The contract events this journey emits (`.sendEvent()`) are checked\n * against, exactly like ingest; journeyWorker passes its config's.\n */\n protected contract(): Contract | undefined {\n return undefined;\n }\n\n /**\n * Template props check before every send; an app overrides this with\n * `registryValidator({ emails, pushes })` (journeyWorker does it from its\n * registries). By default props go out as resolved.\n */\n protected createMessageValidator(): MessageValidator | undefined {\n return undefined;\n }\n\n /**\n * Reporting hooks: node arrivals, every copy sent, how each instance ended. The host stores\n * what it needs for its dashboards; by default nothing is reported.\n */\n protected createObserver(_store: JourneyStore): JourneyObserver | undefined {\n return undefined;\n }\n\n /** Override for a different version policy ('warn' by default) or a fully custom invoker (e.g. webhook degradation for hosted tenants). */\n protected createActionInvoker(): ActionInvoker {\n return new RegistryActionInvoker(this.actions());\n }\n\n async run(event: WorkflowEvent<JourneyParams>, step: WorkflowStep): Promise<JourneyOutcome> {\n const store = this.createStore();\n try {\n return await this.execute(event, step, store);\n } finally {\n await this.closeStore(store);\n }\n }\n\n private async execute(\n event: WorkflowEvent<JourneyParams>,\n step: WorkflowStep,\n store: JourneyStore\n ): Promise<JourneyOutcome> {\n const { workflowId, contentHash, userId } = event.payload;\n const env = this.env;\n\n const stored = await store.getWorkflowIR(contentHash);\n if (stored === undefined) {\n throw new Error(`WorkflowIR not found: ${workflowId}@${contentHash}`);\n }\n const runtime = resolveRuntime({ current: this.runtime(event.payload) }, 'current');\n // Development runs the journey in fast-forward; the pinned hash still names the version.\n const ir = scaleDurations(stored, runtime.timeScale);\n\n const observer = this.createObserver(store);\n const finished = (status: JourneyOutcome['status'] | 'failed', convertedAt?: number) =>\n observer?.finished?.({\n workflow: workflowId,\n instanceId: event.instanceId,\n userId,\n status,\n at: Date.now(),\n ...(convertedAt === undefined ? {} : { convertedAt }),\n });\n\n const messages = runtime.logMessages\n ? logging(this.createMessageSender())\n : this.createMessageSender();\n\n // send_event feeds straight back into the router logic — an in-Worker call\n // forming the event edge between workflows. The step's identity travels as\n // the event id, so a retried emit records the occurrence once.\n // An emitted event passes the same contract check as one arriving over HTTP.\n const contract = this.contract();\n const events: EventSink = {\n emit: async (name, payload, id) => {\n let accepted: Record<string, unknown> = payload;\n if (contract !== undefined) {\n const verdict = checkEvent(contract, name, payload);\n if (!verdict.ok) throw new ContractValidationError(name, verdict.issues);\n accepted = verdict.data;\n }\n await ingestEvent(env, { id, userId, event: name, payload: accepted }, store);\n },\n };\n\n let outcome: JourneyOutcome;\n try {\n outcome = await runJourney(ir, {\n userId,\n instanceId: event.instanceId,\n // Trigger-event creation time: replay-stable, unlike Date.now() here\n enteredAtMs: event.timestamp.getTime(),\n step: new CfEngineStep(step, store, userId, event.instanceId),\n facts: new JourneyFactSource(store, userId),\n messages,\n events,\n actions: this.createActionInvoker(),\n validator: this.createMessageValidator(),\n observer,\n });\n } catch (error) {\n /*\n * An error escaping run() ends the instance, and the ledger is the only\n * place anyone looks afterwards: leaving it at 'running' meant a dead\n * journey stayed indistinguishable from a waiting one, in the dashboard\n * and in the once-policy, forever.\n *\n * Subscriptions are deliberately left in place. They are cleaned up on\n * every ordinary ending, but here the wake rows are the only evidence of\n * what the instance was waiting for, and dropping them would also break\n * the instance if the platform does re-run it.\n */\n await step.do('finalize:failed', async () => {\n await store.setEntryStatus(event.instanceId, 'failed');\n await finished('failed');\n });\n throw error;\n }\n\n await step.do('finalize', async () => {\n await store.setEntryStatus(event.instanceId, outcome.status);\n await store.unsubscribe(event.instanceId);\n await finished(outcome.status, outcome.convertedAt);\n });\n\n return outcome;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runner.cjs","names":["NonRetryableError","WAKE_EVENT_TYPE","wakeExpired","WorkflowEntrypoint","d1Store","resolveRuntime","WebhookMessageSender","LogMessageSender","RegistryActionInvoker","executeJourney"],"sources":["../../src/cloudflare/runner.ts"],"sourcesContent":["import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from 'cloudflare:workers';\nimport { NonRetryableError } from 'cloudflare:workflows';\nimport type { Contract } from '../contract';\nimport { type RegisteredAction, RegistryActionInvoker } from '../engine/actions';\nimport type {\n ActionInvoker,\n EngineStep,\n JourneyObserver,\n JourneyOutcome,\n MessageSender,\n MessageValidator,\n} from '../engine/ports';\nimport { type JourneyRunParts, executeJourney } from '../host/execute';\nimport { LogMessageSender, WebhookMessageSender } from '../host/senders';\nimport { type JourneyRuntimeOptions, resolveRuntime } from '../runtime';\nimport type { JourneyStore } from '../store/index';\nimport { type JourneyEnv, type JourneyParams, WAKE_EVENT_TYPE, wakeExpired } from './bindings';\nimport { d1Store } from './d1-env';\n\n/**\n * Adapts CF's WorkflowStep to EngineStep.\n * subscribe/unsubscribe write the subscription table inside durable steps (the\n * router wakes instances from that table); waitForWake parks on CF's\n * waitForEvent, which signals a timeout by throwing — and so does every other\n * failure in there, so only the clock can tell them apart (see wakeExpired).\n */\n/** Refusals a retry would only repeat: a template's props, an emitted event's payload. */\nconst NON_RETRYABLE = new Set(['TemplateValidationError', 'ContractValidationError']);\n\nclass CfEngineStep implements EngineStep {\n constructor(\n private readonly step: WorkflowStep,\n private readonly store: JourneyStore,\n private readonly userId: string,\n private readonly instanceId: string\n ) {}\n\n /**\n * A template refusing its props, or the contract refusing an emitted event,\n * is deterministic — a retry hits the same refusal — so it ends the step at\n * once instead of burning the retry budget.\n */\n do<T>(name: string, fn: () => Promise<T>): Promise<T> {\n return this.step.do(name, async () => {\n try {\n return await fn();\n } catch (error) {\n if (error instanceof Error && NON_RETRYABLE.has(error.name)) {\n throw new NonRetryableError(error.message, error.name);\n }\n throw error;\n }\n });\n }\n\n sleep(name: string, ms: number): Promise<void> {\n return this.step.sleep(name, ms);\n }\n\n sleepUntil(name: string, timestampMs: number): Promise<void> {\n return this.step.sleepUntil(name, timestampMs);\n }\n\n subscribe(name: string, events: readonly string[]): Promise<void> {\n // Idempotent in the store: the interpreter re-subscribes on every wait\n // attempt (one-shot-callback contract) and registrations persist here.\n return this.step.do(name, () =>\n this.store.subscribe(this.instanceId, this.userId, events, Date.now())\n );\n }\n\n unsubscribe(name: string): Promise<void> {\n return this.step.do(name, () => this.store.unsubscribe(this.instanceId));\n }\n\n async waitForWake(name: string, timeoutMs: number): Promise<'event' | 'timeout'> {\n const startedAt = Date.now();\n try {\n await this.step.waitForEvent(name, { type: WAKE_EVENT_TYPE, timeout: timeoutMs });\n return 'event';\n } catch (error) {\n /*\n * Only the deadline can tell a real timeout from a failure (see\n * wakeExpired). `startedAt` is not replay-stable, but it is read only\n * inside the step body below, and a step body runs on the live attempt\n * alone — a replay returns the persisted verdict without touching the\n * clock.\n */\n const timedOut = await this.step.do(`${name}:timed-out`, async () =>\n wakeExpired(startedAt, timeoutMs, Date.now())\n );\n if (timedOut) return 'timeout';\n throw error;\n }\n }\n}\n\n/**\n * The generic journey executor: one class runs every workflow, because IR is\n * data. It is loaded from the store by the contentHash pinned at entry —\n * content addressing makes it immutable, so reading it outside a step is\n * replay-safe.\n */\nexport class JourneyRunner extends WorkflowEntrypoint<JourneyEnv, JourneyParams> {\n /**\n * The data plane. D1 + KV from the env by default; an app on Postgres\n * overrides this (and `closeStore` if its client needs closing):\n *\n * protected override createStore() { return new PostgresJourneyStore(client(this.env)); }\n */\n protected createStore(): JourneyStore {\n return d1Store(this.env);\n }\n\n /** Called once `run` is over, success or not — release whatever `createStore` opened. */\n protected async closeStore(_store: JourneyStore): Promise<void> {}\n\n /**\n * Runtime options for this instance — typed configuration, resolved by the app (typically\n * `resolveRuntime(config.runtime, mode)` over its workflow.config.ts, with the mode coming from\n * an ENVIRONMENT var). The instance params are passed so the decision can also be per user:\n * a tester account in production can run in fast-forward while everyone else runs in real\n * time. Defaults: real time, quiet.\n *\n * protected override runtime({ userId }) {\n * return resolveRuntime(workflowConfig.runtime, isTester(userId) ? 'test' : this.env.ENVIRONMENT);\n * }\n */\n protected runtime(_params: JourneyParams): JourneyRuntimeOptions {\n return resolveRuntime(undefined, 'production');\n }\n\n /**\n * Message outlet; an app overrides this to plug in real channels (say\n * an EmailSender over a transport with a react-email renderer). By default it picks the webhook\n * or logging sender based on the environment.\n */\n protected createMessageSender(): MessageSender {\n return this.env.MESSAGE_WEBHOOK_URL\n ? new WebhookMessageSender(this.env.MESSAGE_WEBHOOK_URL)\n : new LogMessageSender();\n }\n\n /**\n * Custom-action registry; an app overrides this returning the same\n * `action(...)` objects its workflows reference (an ActionRef is a\n * RegisteredAction structurally) — the code plane of the dual-plane model:\n *\n * protected override actions() { return [syncCrm, issueCoupon]; }\n */\n protected actions(): readonly RegisteredAction[] {\n return [];\n }\n\n /**\n * The contract events this journey emits (`.sendEvent()`) are checked\n * against, exactly like ingest; journeyWorker passes its config's.\n */\n protected contract(): Contract | undefined {\n return undefined;\n }\n\n /**\n * Template props check before every send; an app overrides this with\n * `registryValidator({ emails, pushes })` (journeyWorker does it from its\n * registries). By default props go out as resolved.\n */\n protected createMessageValidator(): MessageValidator | undefined {\n return undefined;\n }\n\n /**\n * Reporting hooks: node arrivals, every copy sent, how each instance ended. The host stores\n * what it needs for its dashboards; by default nothing is reported.\n */\n protected createObserver(_store: JourneyStore): JourneyObserver | undefined {\n return undefined;\n }\n\n /** Override for a different version policy ('warn' by default) or a fully custom invoker (e.g. webhook degradation for hosted tenants). */\n protected createActionInvoker(): ActionInvoker {\n return new RegistryActionInvoker(this.actions());\n }\n\n /**\n * Everything one run is wired to. By default it is composed from the methods above; a host\n * that assembles the whole set itself (journeyWorker) overrides this one instead.\n */\n protected createRunParts(store: JourneyStore, params: JourneyParams): JourneyRunParts {\n return {\n store,\n env: this.env,\n runtime: this.runtime(params),\n messages: this.createMessageSender(),\n actions: this.createActionInvoker(),\n contract: this.contract(),\n validator: this.createMessageValidator(),\n observer: this.createObserver(store),\n };\n }\n\n async run(event: WorkflowEvent<JourneyParams>, step: WorkflowStep): Promise<JourneyOutcome> {\n const store = this.createStore();\n try {\n const { userId } = event.payload;\n return await executeJourney(\n {\n instanceId: event.instanceId,\n params: event.payload,\n // Trigger-event creation time: replay-stable, unlike Date.now() here\n enteredAtMs: event.timestamp.getTime(),\n step: new CfEngineStep(step, store, userId, event.instanceId),\n },\n this.createRunParts(store, event.payload)\n );\n } finally {\n await this.closeStore(store);\n }\n }\n}\n"],"mappings":"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"}
|