@shware/workflow 3.2.0 → 4.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 +100 -29
- package/dist/apns.cjs +113 -26
- package/dist/apns.cjs.map +1 -1
- package/dist/apns.d.cts +52 -6
- package/dist/apns.d.cts.map +1 -1
- package/dist/apns.d.mts +52 -6
- package/dist/apns.d.mts.map +1 -1
- package/dist/apns.mjs +111 -27
- package/dist/apns.mjs.map +1 -1
- package/dist/aws/engine-step.cjs +5 -5
- package/dist/aws/engine-step.cjs.map +1 -1
- package/dist/aws/engine-step.d.cts +8 -2
- package/dist/aws/engine-step.d.cts.map +1 -1
- package/dist/aws/engine-step.d.mts +8 -2
- package/dist/aws/engine-step.d.mts.map +1 -1
- package/dist/aws/engine-step.mjs +5 -5
- package/dist/aws/engine-step.mjs.map +1 -1
- package/dist/aws/index.cjs +47 -6
- package/dist/aws/index.cjs.map +1 -1
- package/dist/aws/index.d.cts +2 -2
- package/dist/aws/index.d.cts.map +1 -1
- package/dist/aws/index.d.mts +2 -2
- package/dist/aws/index.d.mts.map +1 -1
- package/dist/aws/index.mjs +47 -6
- package/dist/aws/index.mjs.map +1 -1
- package/dist/aws/instances.cjs +29 -6
- package/dist/aws/instances.cjs.map +1 -1
- package/dist/aws/instances.d.cts +11 -1
- package/dist/aws/instances.d.cts.map +1 -1
- package/dist/aws/instances.d.mts +11 -1
- package/dist/aws/instances.d.mts.map +1 -1
- package/dist/aws/instances.mjs +27 -4
- package/dist/aws/instances.mjs.map +1 -1
- package/dist/client.cjs +4 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +2 -2
- package/dist/client.d.cts.map +1 -1
- package/dist/client.d.mts +2 -2
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +4 -1
- package/dist/client.mjs.map +1 -1
- package/dist/cloudflare/bindings.cjs +28 -25
- package/dist/cloudflare/bindings.cjs.map +1 -1
- package/dist/cloudflare/bindings.d.cts +17 -129
- package/dist/cloudflare/bindings.d.cts.map +1 -1
- package/dist/cloudflare/bindings.d.mts +17 -129
- package/dist/cloudflare/bindings.d.mts.map +1 -1
- package/dist/cloudflare/bindings.mjs +28 -23
- package/dist/cloudflare/bindings.mjs.map +1 -1
- package/dist/cloudflare/d1-env.cjs +6 -6
- package/dist/cloudflare/d1-env.cjs.map +1 -1
- package/dist/cloudflare/d1-env.d.cts +5 -5
- package/dist/cloudflare/d1-env.d.mts +5 -5
- package/dist/cloudflare/d1-env.mjs +6 -6
- package/dist/cloudflare/d1-env.mjs.map +1 -1
- package/dist/cloudflare/index.cjs +28 -18
- package/dist/cloudflare/index.d.cts +8 -4
- package/dist/cloudflare/index.d.mts +8 -4
- package/dist/cloudflare/index.mjs +9 -5
- package/dist/cloudflare/runner.cjs +29 -14
- package/dist/cloudflare/runner.cjs.map +1 -1
- package/dist/cloudflare/runner.d.cts +9 -2
- package/dist/cloudflare/runner.d.cts.map +1 -1
- package/dist/cloudflare/runner.d.mts +9 -2
- package/dist/cloudflare/runner.d.mts.map +1 -1
- package/dist/cloudflare/runner.mjs +28 -13
- package/dist/cloudflare/runner.mjs.map +1 -1
- package/dist/cloudflare/schema.sql +27 -6
- package/dist/cloudflare/worker.cjs +19 -9
- package/dist/cloudflare/worker.cjs.map +1 -1
- package/dist/cloudflare/worker.d.cts +2 -2
- package/dist/cloudflare/worker.d.cts.map +1 -1
- package/dist/cloudflare/worker.d.mts +2 -2
- package/dist/cloudflare/worker.d.mts.map +1 -1
- package/dist/cloudflare/worker.mjs +19 -9
- package/dist/cloudflare/worker.mjs.map +1 -1
- package/dist/config.cjs +21 -5
- package/dist/config.cjs.map +1 -1
- package/dist/config.mjs +21 -5
- package/dist/config.mjs.map +1 -1
- package/dist/dsl/action.cjs +3 -6
- package/dist/dsl/action.cjs.map +1 -1
- package/dist/dsl/action.d.cts +12 -11
- package/dist/dsl/action.d.cts.map +1 -1
- package/dist/dsl/action.d.mts +12 -11
- package/dist/dsl/action.d.mts.map +1 -1
- package/dist/dsl/action.mjs +3 -6
- package/dist/dsl/action.mjs.map +1 -1
- package/dist/dsl/bundle.cjs +35 -31
- package/dist/dsl/bundle.cjs.map +1 -1
- package/dist/dsl/bundle.d.cts.map +1 -1
- package/dist/dsl/bundle.d.mts.map +1 -1
- package/dist/dsl/bundle.mjs +35 -31
- package/dist/dsl/bundle.mjs.map +1 -1
- package/dist/dsl/condition.cjs +13 -1
- package/dist/dsl/condition.cjs.map +1 -1
- package/dist/dsl/condition.d.cts +9 -1
- package/dist/dsl/condition.d.cts.map +1 -1
- package/dist/dsl/condition.d.mts +9 -1
- package/dist/dsl/condition.d.mts.map +1 -1
- package/dist/dsl/condition.mjs +13 -2
- package/dist/dsl/condition.mjs.map +1 -1
- package/dist/dsl/flow.cjs +33 -11
- package/dist/dsl/flow.cjs.map +1 -1
- package/dist/dsl/flow.d.cts +9 -1
- package/dist/dsl/flow.d.cts.map +1 -1
- package/dist/dsl/flow.d.mts +9 -1
- package/dist/dsl/flow.d.mts.map +1 -1
- package/dist/dsl/flow.mjs +34 -13
- package/dist/dsl/flow.mjs.map +1 -1
- package/dist/dsl/workflow.cjs +2 -3
- package/dist/dsl/workflow.cjs.map +1 -1
- package/dist/dsl/workflow.d.cts.map +1 -1
- package/dist/dsl/workflow.d.mts.map +1 -1
- package/dist/dsl/workflow.mjs +3 -4
- package/dist/dsl/workflow.mjs.map +1 -1
- package/dist/email-sender.cjs +24 -0
- package/dist/email-sender.cjs.map +1 -1
- package/dist/email-sender.d.cts +18 -0
- package/dist/email-sender.d.cts.map +1 -1
- package/dist/email-sender.d.mts +18 -0
- package/dist/email-sender.d.mts.map +1 -1
- package/dist/email-sender.mjs +24 -1
- package/dist/email-sender.mjs.map +1 -1
- package/dist/engine/actions.cjs +1 -8
- package/dist/engine/actions.cjs.map +1 -1
- package/dist/engine/actions.d.cts +1 -12
- package/dist/engine/actions.d.cts.map +1 -1
- package/dist/engine/actions.d.mts +1 -12
- package/dist/engine/actions.d.mts.map +1 -1
- package/dist/engine/actions.mjs +1 -8
- package/dist/engine/actions.mjs.map +1 -1
- package/dist/engine/condition.cjs +25 -5
- package/dist/engine/condition.cjs.map +1 -1
- package/dist/engine/condition.d.cts +12 -3
- package/dist/engine/condition.d.cts.map +1 -1
- package/dist/engine/condition.d.mts +12 -3
- package/dist/engine/condition.d.mts.map +1 -1
- package/dist/engine/condition.mjs +25 -6
- package/dist/engine/condition.mjs.map +1 -1
- package/dist/engine/index.cjs +3 -0
- package/dist/engine/index.d.cts +5 -5
- package/dist/engine/index.d.mts +5 -5
- package/dist/engine/index.mjs +4 -4
- package/dist/engine/interpreter.cjs +27 -20
- 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 +27 -20
- package/dist/engine/interpreter.mjs.map +1 -1
- package/dist/engine/ports.d.cts +21 -6
- package/dist/engine/ports.d.cts.map +1 -1
- package/dist/engine/ports.d.mts +21 -6
- package/dist/engine/ports.d.mts.map +1 -1
- package/dist/engine/retry.cjs +13 -0
- package/dist/engine/retry.cjs.map +1 -1
- package/dist/engine/retry.d.cts +12 -0
- package/dist/engine/retry.d.cts.map +1 -1
- package/dist/engine/retry.d.mts +12 -0
- package/dist/engine/retry.d.mts.map +1 -1
- package/dist/engine/retry.mjs +13 -1
- package/dist/engine/retry.mjs.map +1 -1
- package/dist/engine/time-scale.cjs +90 -15
- package/dist/engine/time-scale.cjs.map +1 -1
- package/dist/engine/time-scale.d.cts +9 -6
- package/dist/engine/time-scale.d.cts.map +1 -1
- package/dist/engine/time-scale.d.mts +9 -6
- package/dist/engine/time-scale.d.mts.map +1 -1
- package/dist/engine/time-scale.mjs +90 -16
- package/dist/engine/time-scale.mjs.map +1 -1
- package/dist/fcm.cjs +111 -38
- package/dist/fcm.cjs.map +1 -1
- package/dist/fcm.d.cts +45 -5
- package/dist/fcm.d.cts.map +1 -1
- package/dist/fcm.d.mts +45 -5
- package/dist/fcm.d.mts.map +1 -1
- package/dist/fcm.mjs +110 -39
- package/dist/fcm.mjs.map +1 -1
- package/dist/hash.cjs +6 -6
- package/dist/hash.cjs.map +1 -1
- package/dist/hash.mjs +6 -6
- package/dist/hash.mjs.map +1 -1
- package/dist/host/auth.cjs +49 -0
- package/dist/host/auth.cjs.map +1 -0
- package/dist/host/auth.d.cts +21 -0
- package/dist/host/auth.d.cts.map +1 -0
- package/dist/host/auth.d.mts +21 -0
- package/dist/host/auth.d.mts.map +1 -0
- package/dist/host/auth.mjs +47 -0
- package/dist/host/auth.mjs.map +1 -0
- package/dist/host/channels.cjs +118 -40
- package/dist/host/channels.cjs.map +1 -1
- package/dist/host/channels.d.cts +27 -1
- package/dist/host/channels.d.cts.map +1 -1
- package/dist/host/channels.d.mts +27 -1
- package/dist/host/channels.d.mts.map +1 -1
- package/dist/host/channels.mjs +121 -44
- package/dist/host/channels.mjs.map +1 -1
- package/dist/host/execute.cjs +14 -2
- package/dist/host/execute.cjs.map +1 -1
- package/dist/host/execute.d.cts +4 -4
- package/dist/host/execute.d.cts.map +1 -1
- package/dist/host/execute.d.mts +4 -4
- package/dist/host/execute.d.mts.map +1 -1
- package/dist/host/execute.mjs +13 -1
- package/dist/host/execute.mjs.map +1 -1
- package/dist/host/fresh-read.cjs +30 -0
- package/dist/host/fresh-read.cjs.map +1 -0
- package/dist/host/fresh-read.d.cts +18 -0
- package/dist/host/fresh-read.d.cts.map +1 -0
- package/dist/host/fresh-read.d.mts +18 -0
- package/dist/host/fresh-read.d.mts.map +1 -0
- package/dist/host/fresh-read.mjs +29 -0
- package/dist/host/fresh-read.mjs.map +1 -0
- package/dist/host/http.cjs +321 -0
- package/dist/host/http.cjs.map +1 -0
- package/dist/host/http.d.cts +54 -0
- package/dist/host/http.d.cts.map +1 -0
- package/dist/host/http.d.mts +54 -0
- package/dist/host/http.d.mts.map +1 -0
- package/dist/host/http.mjs +317 -0
- package/dist/host/http.mjs.map +1 -0
- package/dist/host/{router.cjs → ingest.cjs} +147 -175
- package/dist/host/ingest.cjs.map +1 -0
- package/dist/host/{router.d.cts → ingest.d.cts} +48 -30
- package/dist/host/ingest.d.cts.map +1 -0
- package/dist/host/{router.d.mts → ingest.d.mts} +48 -30
- package/dist/host/ingest.d.mts.map +1 -0
- package/dist/host/{router.mjs → ingest.mjs} +144 -173
- package/dist/host/ingest.mjs.map +1 -0
- package/dist/host/journey-host.cjs +65 -93
- package/dist/host/journey-host.cjs.map +1 -1
- package/dist/host/journey-host.d.cts +19 -26
- package/dist/host/journey-host.d.cts.map +1 -1
- package/dist/host/journey-host.d.mts +19 -26
- package/dist/host/journey-host.d.mts.map +1 -1
- package/dist/host/journey-host.mjs +65 -93
- package/dist/host/journey-host.mjs.map +1 -1
- package/dist/host/platform.cjs +21 -0
- package/dist/host/platform.cjs.map +1 -0
- package/dist/host/platform.d.cts +126 -0
- package/dist/host/platform.d.cts.map +1 -0
- package/dist/host/platform.d.mts +126 -0
- package/dist/host/platform.d.mts.map +1 -0
- package/dist/host/platform.mjs +19 -0
- package/dist/host/platform.mjs.map +1 -0
- package/dist/host/senders.cjs +18 -9
- package/dist/host/senders.cjs.map +1 -1
- package/dist/host/senders.d.cts +9 -4
- package/dist/host/senders.d.cts.map +1 -1
- package/dist/host/senders.d.mts +9 -4
- package/dist/host/senders.d.mts.map +1 -1
- package/dist/host/senders.mjs +18 -9
- package/dist/host/senders.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/ir.cjs +5 -7
- package/dist/ir.cjs.map +1 -1
- package/dist/ir.d.cts +3 -12
- package/dist/ir.d.cts.map +1 -1
- package/dist/ir.d.mts +3 -12
- package/dist/ir.d.mts.map +1 -1
- package/dist/ir.mjs +5 -7
- package/dist/ir.mjs.map +1 -1
- package/dist/plan.cjs +27 -33
- package/dist/plan.cjs.map +1 -1
- package/dist/plan.d.cts +1 -1
- package/dist/plan.d.cts.map +1 -1
- package/dist/plan.d.mts +1 -1
- package/dist/plan.d.mts.map +1 -1
- package/dist/plan.mjs +27 -33
- package/dist/plan.mjs.map +1 -1
- package/dist/reporting/observer.cjs +1 -0
- package/dist/reporting/observer.cjs.map +1 -1
- package/dist/reporting/observer.mjs +1 -0
- package/dist/reporting/observer.mjs.map +1 -1
- package/dist/reporting/tracking.cjs +19 -4
- package/dist/reporting/tracking.cjs.map +1 -1
- package/dist/reporting/tracking.d.cts +13 -11
- package/dist/reporting/tracking.d.cts.map +1 -1
- package/dist/reporting/tracking.d.mts +13 -11
- package/dist/reporting/tracking.d.mts.map +1 -1
- package/dist/reporting/tracking.mjs +19 -4
- package/dist/reporting/tracking.mjs.map +1 -1
- package/dist/store/d1.cjs +88 -29
- package/dist/store/d1.cjs.map +1 -1
- package/dist/store/d1.d.cts +29 -11
- package/dist/store/d1.d.cts.map +1 -1
- package/dist/store/d1.d.mts +29 -11
- package/dist/store/d1.d.mts.map +1 -1
- package/dist/store/d1.mjs +88 -29
- package/dist/store/d1.mjs.map +1 -1
- package/dist/store/erasure.cjs +22 -0
- package/dist/store/erasure.cjs.map +1 -0
- package/dist/store/erasure.d.cts +18 -0
- package/dist/store/erasure.d.cts.map +1 -0
- package/dist/store/erasure.d.mts +18 -0
- package/dist/store/erasure.d.mts.map +1 -0
- package/dist/store/erasure.mjs +21 -0
- package/dist/store/erasure.mjs.map +1 -0
- package/dist/store/index.cjs +2 -0
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +67 -13
- package/dist/store/index.d.cts.map +1 -1
- package/dist/store/index.d.mts +67 -13
- package/dist/store/index.d.mts.map +1 -1
- package/dist/store/index.mjs +2 -1
- package/dist/store/index.mjs.map +1 -1
- package/dist/store/postgres-reporting.cjs +125 -62
- package/dist/store/postgres-reporting.cjs.map +1 -1
- package/dist/store/postgres-reporting.d.cts +30 -2
- package/dist/store/postgres-reporting.d.cts.map +1 -1
- package/dist/store/postgres-reporting.d.mts +30 -2
- package/dist/store/postgres-reporting.d.mts.map +1 -1
- package/dist/store/postgres-reporting.mjs +125 -62
- package/dist/store/postgres-reporting.mjs.map +1 -1
- package/dist/store/postgres.cjs +179 -60
- package/dist/store/postgres.cjs.map +1 -1
- package/dist/store/postgres.d.cts +44 -7
- package/dist/store/postgres.d.cts.map +1 -1
- package/dist/store/postgres.d.mts +44 -7
- package/dist/store/postgres.d.mts.map +1 -1
- package/dist/store/postgres.mjs +179 -60
- package/dist/store/postgres.mjs.map +1 -1
- package/dist/store/tables.cjs +7 -5
- package/dist/store/tables.cjs.map +1 -1
- package/dist/store/tables.d.cts.map +1 -1
- package/dist/store/tables.d.mts.map +1 -1
- package/dist/store/tables.mjs +7 -5
- package/dist/store/tables.mjs.map +1 -1
- package/dist/store/user-lock.cjs +43 -0
- package/dist/store/user-lock.cjs.map +1 -0
- package/dist/store/user-lock.d.cts +32 -0
- package/dist/store/user-lock.d.cts.map +1 -0
- package/dist/store/user-lock.d.mts +32 -0
- package/dist/store/user-lock.d.mts.map +1 -0
- package/dist/store/user-lock.mjs +40 -0
- package/dist/store/user-lock.mjs.map +1 -0
- package/dist/transports/cloudflare-email.cjs +3 -2
- package/dist/transports/cloudflare-email.cjs.map +1 -1
- package/dist/transports/cloudflare-email.mjs +3 -2
- package/dist/transports/cloudflare-email.mjs.map +1 -1
- package/dist/transports/ses.cjs +52 -7
- package/dist/transports/ses.cjs.map +1 -1
- package/dist/transports/ses.d.cts +9 -1
- package/dist/transports/ses.d.cts.map +1 -1
- package/dist/transports/ses.d.mts +9 -1
- package/dist/transports/ses.d.mts.map +1 -1
- package/dist/transports/ses.mjs +52 -8
- package/dist/transports/ses.mjs.map +1 -1
- package/dist/webpush.cjs +133 -47
- package/dist/webpush.cjs.map +1 -1
- package/dist/webpush.d.cts +49 -8
- package/dist/webpush.d.cts.map +1 -1
- package/dist/webpush.d.mts +49 -8
- package/dist/webpush.d.mts.map +1 -1
- package/dist/webpush.mjs +130 -47
- package/dist/webpush.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cloudflare/schema.sql +27 -6
- package/dist/host/router.cjs.map +0 -1
- package/dist/host/router.d.cts.map +0 -1
- package/dist/host/router.d.mts.map +0 -1
- package/dist/host/router.mjs.map +0 -1
package/dist/engine/ports.d.mts
CHANGED
|
@@ -17,10 +17,11 @@ import { ChannelIR, ConditionIR, ScalarIR } from "../ir.mjs";
|
|
|
17
17
|
export interface EngineStep {
|
|
18
18
|
/** Durable step: fn's return value is checkpointed; on replay the result is reused without re-running. */
|
|
19
19
|
do<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Durable sleep: suspended time is not billed. The only sleep primitive — a wait until an
|
|
22
|
+
* absolute instant is the interpreter checkpointing the remaining time, then sleeping it.
|
|
23
|
+
*/
|
|
21
24
|
sleep(name: string, ms: number): Promise<void>;
|
|
22
|
-
/** Sleep until an absolute instant (used by time_window). */
|
|
23
|
-
sleepUntil(name: string, timestampMs: number): Promise<void>;
|
|
24
25
|
/**
|
|
25
26
|
* Durable: register interest in the named events (Cloudflare: write the
|
|
26
27
|
* subscription table; AWS: create a callback and store its id). Must
|
|
@@ -43,8 +44,18 @@ export interface EngineStep {
|
|
|
43
44
|
/**
|
|
44
45
|
* Wait for a wake-up or a timeout. A registration from `subscribe` must
|
|
45
46
|
* already exist — this call only parks the instance.
|
|
47
|
+
*
|
|
48
|
+
* Both numbers are checkpointed by the interpreter, so they are replay-stable: `timeoutMs`
|
|
49
|
+
* is how long this attempt may park (the remaining time when it was computed), `deadlineMs`
|
|
50
|
+
* the absolute instant the whole wait gives up. An adapter that learns of a timeout only by
|
|
51
|
+
* a thrown error (Cloudflare) decides against `deadlineMs` — the clock at the replay that
|
|
52
|
+
* first runs that decision is what matters, not when the park began; one whose wake handle
|
|
53
|
+
* carries its own timeout (AWS) set it from `deadlineMs` at subscribe and ignores both here.
|
|
46
54
|
*/
|
|
47
|
-
waitForWake(name: string,
|
|
55
|
+
waitForWake(name: string, wait: {
|
|
56
|
+
timeoutMs: number;
|
|
57
|
+
deadlineMs: number;
|
|
58
|
+
}): Promise<'event' | 'timeout'>;
|
|
48
59
|
}
|
|
49
60
|
/** One device a push can go to: the provider token (APNs device token, FCM registration token) and the platform that picks the provider. */
|
|
50
61
|
export interface PushDevice {
|
|
@@ -113,6 +124,12 @@ export interface MessageTracking {
|
|
|
113
124
|
link?: (url: string, purpose: LinkPurpose) => string;
|
|
114
125
|
/** Loaded when the email is opened. */
|
|
115
126
|
pixel?: string;
|
|
127
|
+
/**
|
|
128
|
+
* This copy's one-click unsubscribe endpoint (RFC 8058): a POST there, with no confirmation
|
|
129
|
+
* and no session, unsubscribes the recipient. The email sender puts it in the
|
|
130
|
+
* `List-Unsubscribe` header, so a mail client's own unsubscribe button works.
|
|
131
|
+
*/
|
|
132
|
+
unsubscribe?: string;
|
|
116
133
|
/** Extra string keys in the push payload. */
|
|
117
134
|
data?: Record<string, string>;
|
|
118
135
|
/**
|
|
@@ -203,8 +220,6 @@ export interface EventSink {
|
|
|
203
220
|
export interface ActionInvocation {
|
|
204
221
|
/** Registry name; the code itself lives in the deployed bundle (dual-plane model, see dsl/action.ts). */
|
|
205
222
|
action: string;
|
|
206
|
-
/** Code-identity pin from the IR the journey is running; adapters compare it against the registered implementation. */
|
|
207
|
-
codeHash?: string | undefined;
|
|
208
223
|
/** Already resolved: user_property references have been replaced by actual values (same contract as message props). */
|
|
209
224
|
args: Record<string, ScalarIR | undefined>;
|
|
210
225
|
userId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ports.d.mts","names":[],"sources":["../../src/engine/ports.ts"],"mappings":";;;;;;;;;;;;;;;;iBAiBiB;;EAEf,GAAG,GAAG,cAAc,UAAU,QAAQ,KAAK,QAAQ
|
|
1
|
+
{"version":3,"file":"ports.d.mts","names":[],"sources":["../../src/engine/ports.ts"],"mappings":";;;;;;;;;;;;;;;;iBAiBiB;;EAEf,GAAG,GAAG,cAAc,UAAU,QAAQ,KAAK,QAAQ;;;;;EAMnD,MAAM,cAAc,aAAa;;;;;;;;;;;;;;;EAgBjC,UACE,cACA,2BACA;IAAY;MACX;;EAGH,YAAY,eAAe;;;;;;;;;;;;EAa3B,YACE,cACA;IAAQ;IAAmB;MAC1B;;;iBAIY;EACf;EACA;;;iBAIe;;;;;;EAMf,YACE,eACA;IAAS;IAAkB;IAAkB,QAAQ;MACpD;EACH,YAAY,eAAe,QAAQ;;EAEnC,oBAAoB,eAAe,QAAQ;;EAE3C,eAAe,QAAQ;;EAEvB,cAAc,SAAS,YAAY;;iBAGpB;;EAEf;EACA;EACA;EACA,SAAS;EACT;;EAEA,OAAO,eAAe;EACtB;;;;;;EAMA;;EAEA,SAAS;;;;;;EAMT;;EAEA,WAAW;;;YAID;;;;;;iBAOK;;;;;EAKf,QAAQ,aAAa,SAAS;;EAE9B;;;;;;EAMA;;EAEA,OAAO;;;;;;EAMP,eAAe;;;;;;;iBAQA;EACf;EACA;;iBAGe;EACf,KAAK,SAAS,kBAAkB,eAAe;;;;;;;;;iBAUhC;;EAEf,SAAS;IACP;IACA;IACA;IACA;MACE;;EAEJ,aAAa;IACX;IACA;IACA;IACA;IACA;MACE;;EAEJ,iBAAiB,SAAS,kBAAkB,QAAQ;;EAEpD,aAAa,SAAS,iBAAiB;IAAU;MAAoB,aAAa;;EAElF,UAAU;IACR;IACA;IACA;IACA,QAAQ;IACR;;IAEA;MACE;;;;;;;;;iBAUW;EACf,SAAS;IACP,SAAS;IACT;IACA,OAAO,eAAe;MACpB,eAAe;;;iBAIJ;;;;;;;;EAQf,KAAK,eAAe,SAAS,eAAe,uBAAuB,aAAa;;;iBAIjE;;EAEf;;EAEA,MAAM,eAAe;EACrB;;EAEA;;;;;;;iBAQe;EACf,OAAO,YAAY,mBAAmB;;iBAGvB;EACf;;EAEA;;;;;;;EAOA;EACA,MAAM;EACN,OAAO;EACP,UAAU;EACV,QAAQ;;EAER,UAAU;;EAEV,YAAY;;EAEZ,WAAW;;;;;;;YAQD;EACN;;EACA;EAAkB;;EAClB;;EACA;;EACA"}
|
package/dist/engine/retry.cjs
CHANGED
|
@@ -7,6 +7,18 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
7
7
|
* instead of burning the retry budget and delaying the journey. Every runtime adapter asks this
|
|
8
8
|
* one rule.
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* A failure a retry would only repeat: a missing or malformed configuration, a provider refusing
|
|
12
|
+
* the request itself, an input the runtime cannot act on. Thrown inside a durable step, it ends
|
|
13
|
+
* the step at once (`isRetryable` is false) instead of burning the retry budget.
|
|
14
|
+
*/
|
|
15
|
+
var PermanentError = class extends Error {
|
|
16
|
+
name = "PermanentError";
|
|
17
|
+
retryable = false;
|
|
18
|
+
constructor(message, options) {
|
|
19
|
+
super(message, options);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
10
22
|
/** Errors the engine raises that are deterministic by construction. */
|
|
11
23
|
const DETERMINISTIC = /* @__PURE__ */ new Set(["TemplateValidationError", "ContractValidationError"]);
|
|
12
24
|
/**
|
|
@@ -23,6 +35,7 @@ function isRetryableStatus(status) {
|
|
|
23
35
|
return status === 408 || status === 429 || status >= 500;
|
|
24
36
|
}
|
|
25
37
|
//#endregion
|
|
38
|
+
exports.PermanentError = PermanentError;
|
|
26
39
|
exports.isRetryable = isRetryable;
|
|
27
40
|
exports.isRetryableStatus = isRetryableStatus;
|
|
28
41
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.cjs","names":[],"sources":["../../src/engine/retry.ts"],"sourcesContent":["/**\n * Which step failures a retry would only repeat. A durable step retries what it throws; an\n * error that is the same on every attempt — a template refusing its props, the contract\n * refusing an emitted event, a provider rejecting the request itself — ends the step at once\n * instead of burning the retry budget and delaying the journey. Every runtime adapter asks this\n * one rule.\n */\n\n/** Errors the engine raises that are deterministic by construction. */\nconst DETERMINISTIC = new Set(['TemplateValidationError', 'ContractValidationError']);\n\n/**\n * False for an error a retry cannot fix: one of the engine's deterministic refusals, or any\n * error that says so with `retryable: false` (the transports' 4xx answers).\n */\nexport function isRetryable(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n if (DETERMINISTIC.has(error.name)) return false;\n return (error as { retryable?: unknown }).retryable !== false;\n}\n\n/** An HTTP answer a retry can change: a timeout, throttling, or the provider's own fault. */\nexport function isRetryableStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"retry.cjs","names":[],"sources":["../../src/engine/retry.ts"],"sourcesContent":["/**\n * Which step failures a retry would only repeat. A durable step retries what it throws; an\n * error that is the same on every attempt — a template refusing its props, the contract\n * refusing an emitted event, a provider rejecting the request itself — ends the step at once\n * instead of burning the retry budget and delaying the journey. Every runtime adapter asks this\n * one rule.\n */\n\n/**\n * A failure a retry would only repeat: a missing or malformed configuration, a provider refusing\n * the request itself, an input the runtime cannot act on. Thrown inside a durable step, it ends\n * the step at once (`isRetryable` is false) instead of burning the retry budget.\n */\nexport class PermanentError extends Error {\n override readonly name: string = 'PermanentError';\n readonly retryable = false;\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n }\n}\n\n/** Errors the engine raises that are deterministic by construction. */\nconst DETERMINISTIC = new Set(['TemplateValidationError', 'ContractValidationError']);\n\n/**\n * False for an error a retry cannot fix: one of the engine's deterministic refusals, or any\n * error that says so with `retryable: false` (the transports' 4xx answers).\n */\nexport function isRetryable(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n if (DETERMINISTIC.has(error.name)) return false;\n return (error as { retryable?: unknown }).retryable !== false;\n}\n\n/** An HTTP answer a retry can change: a timeout, throttling, or the provider's own fault. */\nexport function isRetryableStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,IAAa,iBAAb,cAAoC,MAAM;CACxC,OAAiC;CACjC,YAAqB;CACrB,YAAY,SAAiB,SAA+B;EAC1D,MAAM,SAAS,OAAO;CACxB;AACF;;AAGA,MAAM,gCAAgB,IAAI,IAAI,CAAC,2BAA2B,yBAAyB,CAAC;;;;;AAMpF,SAAgB,YAAY,OAAyB;CACnD,IAAI,EAAE,iBAAiB,QAAQ,OAAO;CACtC,IAAI,cAAc,IAAI,MAAM,IAAI,GAAG,OAAO;CAC1C,OAAQ,MAAkC,cAAc;AAC1D;;AAGA,SAAgB,kBAAkB,QAAyB;CACzD,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU;AACvD"}
|
package/dist/engine/retry.d.cts
CHANGED
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
* instead of burning the retry budget and delaying the journey. Every runtime adapter asks this
|
|
7
7
|
* one rule.
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* A failure a retry would only repeat: a missing or malformed configuration, a provider refusing
|
|
11
|
+
* the request itself, an input the runtime cannot act on. Thrown inside a durable step, it ends
|
|
12
|
+
* the step at once (`isRetryable` is false) instead of burning the retry budget.
|
|
13
|
+
*/
|
|
14
|
+
export declare class PermanentError extends Error {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly retryable = false;
|
|
17
|
+
constructor(message: string, options?: {
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
9
21
|
/**
|
|
10
22
|
* False for an error a retry cannot fix: one of the engine's deterministic refusals, or any
|
|
11
23
|
* error that says so with `retryable: false` (the transports' 4xx answers).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.cts","names":[],"sources":["../../src/engine/retry.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"retry.d.cts","names":[],"sources":["../../src/engine/retry.ts"],"mappings":";;;;;;;;;;;;;qBAaa,uBAAuB;WAChB;WACT;EACT,YAAY,iBAAiB;IAAY;;;;;;;wBAY3B,YAAY;;wBAOZ,kBAAkB"}
|
package/dist/engine/retry.d.mts
CHANGED
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
* instead of burning the retry budget and delaying the journey. Every runtime adapter asks this
|
|
7
7
|
* one rule.
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* A failure a retry would only repeat: a missing or malformed configuration, a provider refusing
|
|
11
|
+
* the request itself, an input the runtime cannot act on. Thrown inside a durable step, it ends
|
|
12
|
+
* the step at once (`isRetryable` is false) instead of burning the retry budget.
|
|
13
|
+
*/
|
|
14
|
+
export declare class PermanentError extends Error {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly retryable = false;
|
|
17
|
+
constructor(message: string, options?: {
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
9
21
|
/**
|
|
10
22
|
* False for an error a retry cannot fix: one of the engine's deterministic refusals, or any
|
|
11
23
|
* error that says so with `retryable: false` (the transports' 4xx answers).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.mts","names":[],"sources":["../../src/engine/retry.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"retry.d.mts","names":[],"sources":["../../src/engine/retry.ts"],"mappings":";;;;;;;;;;;;;qBAaa,uBAAuB;WAChB;WACT;EACT,YAAY,iBAAiB;IAAY;;;;;;;wBAY3B,YAAY;;wBAOZ,kBAAkB"}
|
package/dist/engine/retry.mjs
CHANGED
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
* instead of burning the retry budget and delaying the journey. Every runtime adapter asks this
|
|
7
7
|
* one rule.
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* A failure a retry would only repeat: a missing or malformed configuration, a provider refusing
|
|
11
|
+
* the request itself, an input the runtime cannot act on. Thrown inside a durable step, it ends
|
|
12
|
+
* the step at once (`isRetryable` is false) instead of burning the retry budget.
|
|
13
|
+
*/
|
|
14
|
+
var PermanentError = class extends Error {
|
|
15
|
+
name = "PermanentError";
|
|
16
|
+
retryable = false;
|
|
17
|
+
constructor(message, options) {
|
|
18
|
+
super(message, options);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
9
21
|
/** Errors the engine raises that are deterministic by construction. */
|
|
10
22
|
const DETERMINISTIC = /* @__PURE__ */ new Set(["TemplateValidationError", "ContractValidationError"]);
|
|
11
23
|
/**
|
|
@@ -22,6 +34,6 @@ function isRetryableStatus(status) {
|
|
|
22
34
|
return status === 408 || status === 429 || status >= 500;
|
|
23
35
|
}
|
|
24
36
|
//#endregion
|
|
25
|
-
export { isRetryable, isRetryableStatus };
|
|
37
|
+
export { PermanentError, isRetryable, isRetryableStatus };
|
|
26
38
|
|
|
27
39
|
//# sourceMappingURL=retry.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.mjs","names":[],"sources":["../../src/engine/retry.ts"],"sourcesContent":["/**\n * Which step failures a retry would only repeat. A durable step retries what it throws; an\n * error that is the same on every attempt — a template refusing its props, the contract\n * refusing an emitted event, a provider rejecting the request itself — ends the step at once\n * instead of burning the retry budget and delaying the journey. Every runtime adapter asks this\n * one rule.\n */\n\n/** Errors the engine raises that are deterministic by construction. */\nconst DETERMINISTIC = new Set(['TemplateValidationError', 'ContractValidationError']);\n\n/**\n * False for an error a retry cannot fix: one of the engine's deterministic refusals, or any\n * error that says so with `retryable: false` (the transports' 4xx answers).\n */\nexport function isRetryable(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n if (DETERMINISTIC.has(error.name)) return false;\n return (error as { retryable?: unknown }).retryable !== false;\n}\n\n/** An HTTP answer a retry can change: a timeout, throttling, or the provider's own fault. */\nexport function isRetryableStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"retry.mjs","names":[],"sources":["../../src/engine/retry.ts"],"sourcesContent":["/**\n * Which step failures a retry would only repeat. A durable step retries what it throws; an\n * error that is the same on every attempt — a template refusing its props, the contract\n * refusing an emitted event, a provider rejecting the request itself — ends the step at once\n * instead of burning the retry budget and delaying the journey. Every runtime adapter asks this\n * one rule.\n */\n\n/**\n * A failure a retry would only repeat: a missing or malformed configuration, a provider refusing\n * the request itself, an input the runtime cannot act on. Thrown inside a durable step, it ends\n * the step at once (`isRetryable` is false) instead of burning the retry budget.\n */\nexport class PermanentError extends Error {\n override readonly name: string = 'PermanentError';\n readonly retryable = false;\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n }\n}\n\n/** Errors the engine raises that are deterministic by construction. */\nconst DETERMINISTIC = new Set(['TemplateValidationError', 'ContractValidationError']);\n\n/**\n * False for an error a retry cannot fix: one of the engine's deterministic refusals, or any\n * error that says so with `retryable: false` (the transports' 4xx answers).\n */\nexport function isRetryable(error: unknown): boolean {\n if (!(error instanceof Error)) return true;\n if (DETERMINISTIC.has(error.name)) return false;\n return (error as { retryable?: unknown }).retryable !== false;\n}\n\n/** An HTTP answer a retry can change: a timeout, throttling, or the provider's own fault. */\nexport function isRetryableStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,iBAAb,cAAoC,MAAM;CACxC,OAAiC;CACjC,YAAqB;CACrB,YAAY,SAAiB,SAA+B;EAC1D,MAAM,SAAS,OAAO;CACxB;AACF;;AAGA,MAAM,gCAAgB,IAAI,IAAI,CAAC,2BAA2B,yBAAyB,CAAC;;;;;AAMpF,SAAgB,YAAY,OAAyB;CACnD,IAAI,EAAE,iBAAiB,QAAQ,OAAO;CACtC,IAAI,cAAc,IAAI,MAAM,IAAI,GAAG,OAAO;CAC1C,OAAQ,MAAkC,cAAc;AAC1D;;AAGA,SAAgB,kBAAkB,QAAyB;CACzD,OAAO,WAAW,OAAO,WAAW,OAAO,UAAU;AACvD"}
|
|
@@ -13,25 +13,96 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
13
13
|
* live in the store rather than the workflow body; `scaleSegmentWindows`
|
|
14
14
|
* scales them as they are read, so a segment's `within` keeps pace too.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* written.
|
|
16
|
+
* The walk follows the IR's own structure — the fields that hold a Duration
|
|
17
|
+
* are known — so a message prop or an event payload that happens to look like
|
|
18
|
+
* one (`{ value, ms }`) is left alone. The source text is kept so the studio
|
|
19
|
+
* still shows what was written.
|
|
20
20
|
*/
|
|
21
21
|
function scaleDurations(ir, factor) {
|
|
22
22
|
if (!(factor > 0) || factor === 1) return ir;
|
|
23
|
-
return
|
|
23
|
+
return {
|
|
24
|
+
...ir,
|
|
25
|
+
trigger: ir.trigger.type === "event" ? {
|
|
26
|
+
...ir.trigger,
|
|
27
|
+
...ir.trigger.filter === void 0 ? {} : { filter: scaleCondition(ir.trigger.filter, factor) }
|
|
28
|
+
} : ir.trigger,
|
|
29
|
+
...ir.goal === void 0 ? {} : { goal: {
|
|
30
|
+
...ir.goal,
|
|
31
|
+
condition: scaleCondition(ir.goal.condition, factor),
|
|
32
|
+
...ir.goal.within === void 0 ? {} : { within: scale(ir.goal.within, factor) }
|
|
33
|
+
} },
|
|
34
|
+
...ir.exitWhen === void 0 ? {} : { exitWhen: scaleCondition(ir.exitWhen, factor) },
|
|
35
|
+
flow: scaleFlow(ir.flow, factor)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** A condition with its `performed(... within)` windows divided by `factor`. */
|
|
39
|
+
function scaleCondition(condition, factor) {
|
|
40
|
+
if (!(factor > 0) || factor === 1) return condition;
|
|
41
|
+
switch (condition.type) {
|
|
42
|
+
case "and":
|
|
43
|
+
case "or": return {
|
|
44
|
+
...condition,
|
|
45
|
+
conditions: condition.conditions.map((child) => scaleCondition(child, factor))
|
|
46
|
+
};
|
|
47
|
+
case "not": return {
|
|
48
|
+
...condition,
|
|
49
|
+
condition: scaleCondition(condition.condition, factor)
|
|
50
|
+
};
|
|
51
|
+
case "performed": return condition.within === void 0 ? condition : {
|
|
52
|
+
...condition,
|
|
53
|
+
within: scale(condition.within, factor)
|
|
54
|
+
};
|
|
55
|
+
default: return condition;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function scaleFlow(nodes, factor) {
|
|
59
|
+
return nodes.map((node) => scaleNode(node, factor));
|
|
60
|
+
}
|
|
61
|
+
function scaleNode(node, factor) {
|
|
62
|
+
switch (node.type) {
|
|
63
|
+
case "delay": return {
|
|
64
|
+
...node,
|
|
65
|
+
duration: scale(node.duration, factor)
|
|
66
|
+
};
|
|
67
|
+
case "random_delay": return {
|
|
68
|
+
...node,
|
|
69
|
+
min: scale(node.min, factor),
|
|
70
|
+
max: scale(node.max, factor)
|
|
71
|
+
};
|
|
72
|
+
case "wait_until": return {
|
|
73
|
+
...node,
|
|
74
|
+
condition: scaleCondition(node.condition, factor),
|
|
75
|
+
timeout: scale(node.timeout, factor),
|
|
76
|
+
onTimeout: Array.isArray(node.onTimeout) ? scaleFlow(node.onTimeout, factor) : node.onTimeout
|
|
77
|
+
};
|
|
78
|
+
case "branch": return {
|
|
79
|
+
...node,
|
|
80
|
+
cases: node.cases.map((branch) => ({
|
|
81
|
+
...branch,
|
|
82
|
+
condition: scaleCondition(branch.condition, factor),
|
|
83
|
+
flow: scaleFlow(branch.flow, factor)
|
|
84
|
+
})),
|
|
85
|
+
...node.otherwise === void 0 ? {} : { otherwise: scaleFlow(node.otherwise, factor) }
|
|
86
|
+
};
|
|
87
|
+
case "filter": return {
|
|
88
|
+
...node,
|
|
89
|
+
condition: scaleCondition(node.condition, factor)
|
|
90
|
+
};
|
|
91
|
+
case "cohort": return {
|
|
92
|
+
...node,
|
|
93
|
+
arms: node.arms.map((arm) => ({
|
|
94
|
+
...arm,
|
|
95
|
+
flow: scaleFlow(arm.flow, factor)
|
|
96
|
+
}))
|
|
97
|
+
};
|
|
98
|
+
default: return node;
|
|
99
|
+
}
|
|
24
100
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const keys = Object.keys(record);
|
|
30
|
-
if (keys.length === 2 && typeof record.value === "string" && typeof record.ms === "number") return {
|
|
31
|
-
value: record.value,
|
|
32
|
-
ms: Math.max(0, Math.round(record.ms / factor))
|
|
101
|
+
function scale(duration, factor) {
|
|
102
|
+
return {
|
|
103
|
+
value: duration.value,
|
|
104
|
+
ms: Math.max(0, Math.round(duration.ms / factor))
|
|
33
105
|
};
|
|
34
|
-
return Object.fromEntries(keys.map((key) => [key, walk(record[key], factor)]));
|
|
35
106
|
}
|
|
36
107
|
/**
|
|
37
108
|
* A store whose segment definitions come back scaled by `factor` — what journeyWorker reads
|
|
@@ -42,12 +113,16 @@ function walk(value, factor) {
|
|
|
42
113
|
function scaleSegmentWindows(store, factor) {
|
|
43
114
|
if (!(factor > 0) || factor === 1) return store;
|
|
44
115
|
return new Proxy(store, { get(target, property) {
|
|
45
|
-
if (property === "getSegmentCondition") return async (name) =>
|
|
116
|
+
if (property === "getSegmentCondition") return async (name) => {
|
|
117
|
+
const condition = await target.getSegmentCondition(name);
|
|
118
|
+
return condition === void 0 ? void 0 : scaleCondition(condition, factor);
|
|
119
|
+
};
|
|
46
120
|
const value = Reflect.get(target, property, target);
|
|
47
121
|
return typeof value === "function" ? value.bind(target) : value;
|
|
48
122
|
} });
|
|
49
123
|
}
|
|
50
124
|
//#endregion
|
|
125
|
+
exports.scaleCondition = scaleCondition;
|
|
51
126
|
exports.scaleDurations = scaleDurations;
|
|
52
127
|
exports.scaleSegmentWindows = scaleSegmentWindows;
|
|
53
128
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-scale.cjs","names":[],"sources":["../../src/engine/time-scale.ts"],"sourcesContent":["/**\n * Debug time scale: divide every duration in a workflow's IR by a factor so a\n * journey written in days plays out in seconds — with a factor of 3600, a\n * `delay('2 days')` sleeps 48 s, a `waitUntil(..., { timeout: '3 days' })`\n * gives up after 72 s, and a goal `within: '30 days'` closes after 12 min.\n *\n * Everything that is a Duration scales together (delays, random delays, wait\n * timeouts, goal and `performed(... within)` windows inside the workflow), so\n * the journey keeps its shape, just faster. What does not scale: wall-clock\n * `timeWindow`s (they are times of day, not durations). Segment definitions\n * live in the store rather than the workflow body; `scaleSegmentWindows`\n * scales them as they are read, so a segment's `within` keeps pace too.\n *\n *
|
|
1
|
+
{"version":3,"file":"time-scale.cjs","names":[],"sources":["../../src/engine/time-scale.ts"],"sourcesContent":["import type { ConditionIR, DurationIR, NodeIR, WorkflowIR } from '../ir';\n\n/**\n * Debug time scale: divide every duration in a workflow's IR by a factor so a\n * journey written in days plays out in seconds — with a factor of 3600, a\n * `delay('2 days')` sleeps 48 s, a `waitUntil(..., { timeout: '3 days' })`\n * gives up after 72 s, and a goal `within: '30 days'` closes after 12 min.\n *\n * Everything that is a Duration scales together (delays, random delays, wait\n * timeouts, goal and `performed(... within)` windows inside the workflow), so\n * the journey keeps its shape, just faster. What does not scale: wall-clock\n * `timeWindow`s (they are times of day, not durations). Segment definitions\n * live in the store rather than the workflow body; `scaleSegmentWindows`\n * scales them as they are read, so a segment's `within` keeps pace too.\n *\n * The walk follows the IR's own structure — the fields that hold a Duration\n * are known — so a message prop or an event payload that happens to look like\n * one (`{ value, ms }`) is left alone. The source text is kept so the studio\n * still shows what was written.\n */\nexport function scaleDurations(ir: WorkflowIR, factor: number): WorkflowIR {\n if (!(factor > 0) || factor === 1) return ir;\n return {\n ...ir,\n trigger:\n ir.trigger.type === 'event'\n ? {\n ...ir.trigger,\n ...(ir.trigger.filter === undefined\n ? {}\n : { filter: scaleCondition(ir.trigger.filter, factor) }),\n }\n : ir.trigger,\n ...(ir.goal === undefined\n ? {}\n : {\n goal: {\n ...ir.goal,\n condition: scaleCondition(ir.goal.condition, factor),\n ...(ir.goal.within === undefined ? {} : { within: scale(ir.goal.within, factor) }),\n },\n }),\n ...(ir.exitWhen === undefined ? {} : { exitWhen: scaleCondition(ir.exitWhen, factor) }),\n flow: scaleFlow(ir.flow, factor),\n };\n}\n\n/** A condition with its `performed(... within)` windows divided by `factor`. */\nexport function scaleCondition(condition: ConditionIR, factor: number): ConditionIR {\n if (!(factor > 0) || factor === 1) return condition;\n switch (condition.type) {\n case 'and':\n case 'or':\n return {\n ...condition,\n conditions: condition.conditions.map((child) => scaleCondition(child, factor)),\n };\n case 'not':\n return { ...condition, condition: scaleCondition(condition.condition, factor) };\n case 'performed':\n return condition.within === undefined\n ? condition\n : { ...condition, within: scale(condition.within, factor) };\n default:\n return condition;\n }\n}\n\nfunction scaleFlow(nodes: readonly NodeIR[], factor: number): NodeIR[] {\n return nodes.map((node) => scaleNode(node, factor));\n}\n\nfunction scaleNode(node: NodeIR, factor: number): NodeIR {\n switch (node.type) {\n case 'delay':\n return { ...node, duration: scale(node.duration, factor) };\n case 'random_delay':\n return { ...node, min: scale(node.min, factor), max: scale(node.max, factor) };\n case 'wait_until':\n return {\n ...node,\n condition: scaleCondition(node.condition, factor),\n timeout: scale(node.timeout, factor),\n onTimeout: Array.isArray(node.onTimeout)\n ? scaleFlow(node.onTimeout, factor)\n : node.onTimeout,\n };\n case 'branch':\n return {\n ...node,\n cases: node.cases.map((branch) => ({\n ...branch,\n condition: scaleCondition(branch.condition, factor),\n flow: scaleFlow(branch.flow, factor),\n })),\n ...(node.otherwise === undefined ? {} : { otherwise: scaleFlow(node.otherwise, factor) }),\n };\n case 'filter':\n return { ...node, condition: scaleCondition(node.condition, factor) };\n case 'cohort':\n return {\n ...node,\n arms: node.arms.map((arm) => ({ ...arm, flow: scaleFlow(arm.flow, factor) })),\n };\n default:\n return node;\n }\n}\n\nfunction scale(duration: DurationIR, factor: number): DurationIR {\n return { value: duration.value, ms: Math.max(0, Math.round(duration.ms / factor)) };\n}\n\n/**\n * A store whose segment definitions come back scaled by `factor` — what journeyWorker reads\n * through in fast-forward, so a segment's windows (`performed(e.login, { within: '7 days' })`)\n * shrink with the journeys that reference it, and with the segment triggers it routes. Every\n * other method is the store's own.\n */\nexport function scaleSegmentWindows<\n S extends { getSegmentCondition(name: string): Promise<ConditionIR | undefined> },\n>(store: S, factor: number): S {\n if (!(factor > 0) || factor === 1) return store;\n return new Proxy(store, {\n get(target, property) {\n if (property === 'getSegmentCondition') {\n return async (name: string) => {\n const condition = await target.getSegmentCondition(name);\n return condition === undefined ? undefined : scaleCondition(condition, factor);\n };\n }\n const value: unknown = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ConditionIR, WorkflowIR } from "../ir.cjs";
|
|
1
2
|
//#region src/engine/time-scale.d.ts
|
|
2
3
|
/**
|
|
3
4
|
* Debug time scale: divide every duration in a workflow's IR by a factor so a
|
|
@@ -12,12 +13,14 @@
|
|
|
12
13
|
* live in the store rather than the workflow body; `scaleSegmentWindows`
|
|
13
14
|
* scales them as they are read, so a segment's `within` keeps pace too.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* written.
|
|
16
|
+
* The walk follows the IR's own structure — the fields that hold a Duration
|
|
17
|
+
* are known — so a message prop or an event payload that happens to look like
|
|
18
|
+
* one (`{ value, ms }`) is left alone. The source text is kept so the studio
|
|
19
|
+
* still shows what was written.
|
|
19
20
|
*/
|
|
20
|
-
export declare function scaleDurations
|
|
21
|
+
export declare function scaleDurations(ir: WorkflowIR, factor: number): WorkflowIR;
|
|
22
|
+
/** A condition with its `performed(... within)` windows divided by `factor`. */
|
|
23
|
+
export declare function scaleCondition(condition: ConditionIR, factor: number): ConditionIR;
|
|
21
24
|
/**
|
|
22
25
|
* A store whose segment definitions come back scaled by `factor` — what journeyWorker reads
|
|
23
26
|
* through in fast-forward, so a segment's windows (`performed(e.login, { within: '7 days' })`)
|
|
@@ -25,7 +28,7 @@ export declare function scaleDurations<T>(ir: T, factor: number): T;
|
|
|
25
28
|
* other method is the store's own.
|
|
26
29
|
*/
|
|
27
30
|
export declare function scaleSegmentWindows<S extends {
|
|
28
|
-
getSegmentCondition(name: string): Promise<
|
|
31
|
+
getSegmentCondition(name: string): Promise<ConditionIR | undefined>;
|
|
29
32
|
}>(store: S, factor: number): S;
|
|
30
33
|
//#endregion
|
|
31
34
|
//# sourceMappingURL=time-scale.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-scale.d.cts","names":[],"sources":["../../src/engine/time-scale.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"time-scale.d.cts","names":[],"sources":["../../src/engine/time-scale.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;wBAoBgB,eAAe,IAAI,YAAY,iBAAiB;;wBA4BhD,eAAe,WAAW,aAAa,iBAAiB;;;;;;;wBAuExD,oBACd;EAAY,oBAAoB,eAAe,QAAQ;GACvD,OAAO,GAAG,iBAAiB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ConditionIR, WorkflowIR } from "../ir.mjs";
|
|
1
2
|
//#region src/engine/time-scale.d.ts
|
|
2
3
|
/**
|
|
3
4
|
* Debug time scale: divide every duration in a workflow's IR by a factor so a
|
|
@@ -12,12 +13,14 @@
|
|
|
12
13
|
* live in the store rather than the workflow body; `scaleSegmentWindows`
|
|
13
14
|
* scales them as they are read, so a segment's `within` keeps pace too.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* written.
|
|
16
|
+
* The walk follows the IR's own structure — the fields that hold a Duration
|
|
17
|
+
* are known — so a message prop or an event payload that happens to look like
|
|
18
|
+
* one (`{ value, ms }`) is left alone. The source text is kept so the studio
|
|
19
|
+
* still shows what was written.
|
|
19
20
|
*/
|
|
20
|
-
export declare function scaleDurations
|
|
21
|
+
export declare function scaleDurations(ir: WorkflowIR, factor: number): WorkflowIR;
|
|
22
|
+
/** A condition with its `performed(... within)` windows divided by `factor`. */
|
|
23
|
+
export declare function scaleCondition(condition: ConditionIR, factor: number): ConditionIR;
|
|
21
24
|
/**
|
|
22
25
|
* A store whose segment definitions come back scaled by `factor` — what journeyWorker reads
|
|
23
26
|
* through in fast-forward, so a segment's windows (`performed(e.login, { within: '7 days' })`)
|
|
@@ -25,7 +28,7 @@ export declare function scaleDurations<T>(ir: T, factor: number): T;
|
|
|
25
28
|
* other method is the store's own.
|
|
26
29
|
*/
|
|
27
30
|
export declare function scaleSegmentWindows<S extends {
|
|
28
|
-
getSegmentCondition(name: string): Promise<
|
|
31
|
+
getSegmentCondition(name: string): Promise<ConditionIR | undefined>;
|
|
29
32
|
}>(store: S, factor: number): S;
|
|
30
33
|
//#endregion
|
|
31
34
|
//# sourceMappingURL=time-scale.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-scale.d.mts","names":[],"sources":["../../src/engine/time-scale.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"time-scale.d.mts","names":[],"sources":["../../src/engine/time-scale.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;wBAoBgB,eAAe,IAAI,YAAY,iBAAiB;;wBA4BhD,eAAe,WAAW,aAAa,iBAAiB;;;;;;;wBAuExD,oBACd;EAAY,oBAAoB,eAAe,QAAQ;GACvD,OAAO,GAAG,iBAAiB"}
|
|
@@ -12,25 +12,96 @@
|
|
|
12
12
|
* live in the store rather than the workflow body; `scaleSegmentWindows`
|
|
13
13
|
* scales them as they are read, so a segment's `within` keeps pace too.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* written.
|
|
15
|
+
* The walk follows the IR's own structure — the fields that hold a Duration
|
|
16
|
+
* are known — so a message prop or an event payload that happens to look like
|
|
17
|
+
* one (`{ value, ms }`) is left alone. The source text is kept so the studio
|
|
18
|
+
* still shows what was written.
|
|
19
19
|
*/
|
|
20
20
|
function scaleDurations(ir, factor) {
|
|
21
21
|
if (!(factor > 0) || factor === 1) return ir;
|
|
22
|
-
return
|
|
22
|
+
return {
|
|
23
|
+
...ir,
|
|
24
|
+
trigger: ir.trigger.type === "event" ? {
|
|
25
|
+
...ir.trigger,
|
|
26
|
+
...ir.trigger.filter === void 0 ? {} : { filter: scaleCondition(ir.trigger.filter, factor) }
|
|
27
|
+
} : ir.trigger,
|
|
28
|
+
...ir.goal === void 0 ? {} : { goal: {
|
|
29
|
+
...ir.goal,
|
|
30
|
+
condition: scaleCondition(ir.goal.condition, factor),
|
|
31
|
+
...ir.goal.within === void 0 ? {} : { within: scale(ir.goal.within, factor) }
|
|
32
|
+
} },
|
|
33
|
+
...ir.exitWhen === void 0 ? {} : { exitWhen: scaleCondition(ir.exitWhen, factor) },
|
|
34
|
+
flow: scaleFlow(ir.flow, factor)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** A condition with its `performed(... within)` windows divided by `factor`. */
|
|
38
|
+
function scaleCondition(condition, factor) {
|
|
39
|
+
if (!(factor > 0) || factor === 1) return condition;
|
|
40
|
+
switch (condition.type) {
|
|
41
|
+
case "and":
|
|
42
|
+
case "or": return {
|
|
43
|
+
...condition,
|
|
44
|
+
conditions: condition.conditions.map((child) => scaleCondition(child, factor))
|
|
45
|
+
};
|
|
46
|
+
case "not": return {
|
|
47
|
+
...condition,
|
|
48
|
+
condition: scaleCondition(condition.condition, factor)
|
|
49
|
+
};
|
|
50
|
+
case "performed": return condition.within === void 0 ? condition : {
|
|
51
|
+
...condition,
|
|
52
|
+
within: scale(condition.within, factor)
|
|
53
|
+
};
|
|
54
|
+
default: return condition;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function scaleFlow(nodes, factor) {
|
|
58
|
+
return nodes.map((node) => scaleNode(node, factor));
|
|
59
|
+
}
|
|
60
|
+
function scaleNode(node, factor) {
|
|
61
|
+
switch (node.type) {
|
|
62
|
+
case "delay": return {
|
|
63
|
+
...node,
|
|
64
|
+
duration: scale(node.duration, factor)
|
|
65
|
+
};
|
|
66
|
+
case "random_delay": return {
|
|
67
|
+
...node,
|
|
68
|
+
min: scale(node.min, factor),
|
|
69
|
+
max: scale(node.max, factor)
|
|
70
|
+
};
|
|
71
|
+
case "wait_until": return {
|
|
72
|
+
...node,
|
|
73
|
+
condition: scaleCondition(node.condition, factor),
|
|
74
|
+
timeout: scale(node.timeout, factor),
|
|
75
|
+
onTimeout: Array.isArray(node.onTimeout) ? scaleFlow(node.onTimeout, factor) : node.onTimeout
|
|
76
|
+
};
|
|
77
|
+
case "branch": return {
|
|
78
|
+
...node,
|
|
79
|
+
cases: node.cases.map((branch) => ({
|
|
80
|
+
...branch,
|
|
81
|
+
condition: scaleCondition(branch.condition, factor),
|
|
82
|
+
flow: scaleFlow(branch.flow, factor)
|
|
83
|
+
})),
|
|
84
|
+
...node.otherwise === void 0 ? {} : { otherwise: scaleFlow(node.otherwise, factor) }
|
|
85
|
+
};
|
|
86
|
+
case "filter": return {
|
|
87
|
+
...node,
|
|
88
|
+
condition: scaleCondition(node.condition, factor)
|
|
89
|
+
};
|
|
90
|
+
case "cohort": return {
|
|
91
|
+
...node,
|
|
92
|
+
arms: node.arms.map((arm) => ({
|
|
93
|
+
...arm,
|
|
94
|
+
flow: scaleFlow(arm.flow, factor)
|
|
95
|
+
}))
|
|
96
|
+
};
|
|
97
|
+
default: return node;
|
|
98
|
+
}
|
|
23
99
|
}
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const keys = Object.keys(record);
|
|
29
|
-
if (keys.length === 2 && typeof record.value === "string" && typeof record.ms === "number") return {
|
|
30
|
-
value: record.value,
|
|
31
|
-
ms: Math.max(0, Math.round(record.ms / factor))
|
|
100
|
+
function scale(duration, factor) {
|
|
101
|
+
return {
|
|
102
|
+
value: duration.value,
|
|
103
|
+
ms: Math.max(0, Math.round(duration.ms / factor))
|
|
32
104
|
};
|
|
33
|
-
return Object.fromEntries(keys.map((key) => [key, walk(record[key], factor)]));
|
|
34
105
|
}
|
|
35
106
|
/**
|
|
36
107
|
* A store whose segment definitions come back scaled by `factor` — what journeyWorker reads
|
|
@@ -41,12 +112,15 @@ function walk(value, factor) {
|
|
|
41
112
|
function scaleSegmentWindows(store, factor) {
|
|
42
113
|
if (!(factor > 0) || factor === 1) return store;
|
|
43
114
|
return new Proxy(store, { get(target, property) {
|
|
44
|
-
if (property === "getSegmentCondition") return async (name) =>
|
|
115
|
+
if (property === "getSegmentCondition") return async (name) => {
|
|
116
|
+
const condition = await target.getSegmentCondition(name);
|
|
117
|
+
return condition === void 0 ? void 0 : scaleCondition(condition, factor);
|
|
118
|
+
};
|
|
45
119
|
const value = Reflect.get(target, property, target);
|
|
46
120
|
return typeof value === "function" ? value.bind(target) : value;
|
|
47
121
|
} });
|
|
48
122
|
}
|
|
49
123
|
//#endregion
|
|
50
|
-
export { scaleDurations, scaleSegmentWindows };
|
|
124
|
+
export { scaleCondition, scaleDurations, scaleSegmentWindows };
|
|
51
125
|
|
|
52
126
|
//# sourceMappingURL=time-scale.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-scale.mjs","names":[],"sources":["../../src/engine/time-scale.ts"],"sourcesContent":["/**\n * Debug time scale: divide every duration in a workflow's IR by a factor so a\n * journey written in days plays out in seconds — with a factor of 3600, a\n * `delay('2 days')` sleeps 48 s, a `waitUntil(..., { timeout: '3 days' })`\n * gives up after 72 s, and a goal `within: '30 days'` closes after 12 min.\n *\n * Everything that is a Duration scales together (delays, random delays, wait\n * timeouts, goal and `performed(... within)` windows inside the workflow), so\n * the journey keeps its shape, just faster. What does not scale: wall-clock\n * `timeWindow`s (they are times of day, not durations). Segment definitions\n * live in the store rather than the workflow body; `scaleSegmentWindows`\n * scales them as they are read, so a segment's `within` keeps pace too.\n *\n *
|
|
1
|
+
{"version":3,"file":"time-scale.mjs","names":[],"sources":["../../src/engine/time-scale.ts"],"sourcesContent":["import type { ConditionIR, DurationIR, NodeIR, WorkflowIR } from '../ir';\n\n/**\n * Debug time scale: divide every duration in a workflow's IR by a factor so a\n * journey written in days plays out in seconds — with a factor of 3600, a\n * `delay('2 days')` sleeps 48 s, a `waitUntil(..., { timeout: '3 days' })`\n * gives up after 72 s, and a goal `within: '30 days'` closes after 12 min.\n *\n * Everything that is a Duration scales together (delays, random delays, wait\n * timeouts, goal and `performed(... within)` windows inside the workflow), so\n * the journey keeps its shape, just faster. What does not scale: wall-clock\n * `timeWindow`s (they are times of day, not durations). Segment definitions\n * live in the store rather than the workflow body; `scaleSegmentWindows`\n * scales them as they are read, so a segment's `within` keeps pace too.\n *\n * The walk follows the IR's own structure — the fields that hold a Duration\n * are known — so a message prop or an event payload that happens to look like\n * one (`{ value, ms }`) is left alone. The source text is kept so the studio\n * still shows what was written.\n */\nexport function scaleDurations(ir: WorkflowIR, factor: number): WorkflowIR {\n if (!(factor > 0) || factor === 1) return ir;\n return {\n ...ir,\n trigger:\n ir.trigger.type === 'event'\n ? {\n ...ir.trigger,\n ...(ir.trigger.filter === undefined\n ? {}\n : { filter: scaleCondition(ir.trigger.filter, factor) }),\n }\n : ir.trigger,\n ...(ir.goal === undefined\n ? {}\n : {\n goal: {\n ...ir.goal,\n condition: scaleCondition(ir.goal.condition, factor),\n ...(ir.goal.within === undefined ? {} : { within: scale(ir.goal.within, factor) }),\n },\n }),\n ...(ir.exitWhen === undefined ? {} : { exitWhen: scaleCondition(ir.exitWhen, factor) }),\n flow: scaleFlow(ir.flow, factor),\n };\n}\n\n/** A condition with its `performed(... within)` windows divided by `factor`. */\nexport function scaleCondition(condition: ConditionIR, factor: number): ConditionIR {\n if (!(factor > 0) || factor === 1) return condition;\n switch (condition.type) {\n case 'and':\n case 'or':\n return {\n ...condition,\n conditions: condition.conditions.map((child) => scaleCondition(child, factor)),\n };\n case 'not':\n return { ...condition, condition: scaleCondition(condition.condition, factor) };\n case 'performed':\n return condition.within === undefined\n ? condition\n : { ...condition, within: scale(condition.within, factor) };\n default:\n return condition;\n }\n}\n\nfunction scaleFlow(nodes: readonly NodeIR[], factor: number): NodeIR[] {\n return nodes.map((node) => scaleNode(node, factor));\n}\n\nfunction scaleNode(node: NodeIR, factor: number): NodeIR {\n switch (node.type) {\n case 'delay':\n return { ...node, duration: scale(node.duration, factor) };\n case 'random_delay':\n return { ...node, min: scale(node.min, factor), max: scale(node.max, factor) };\n case 'wait_until':\n return {\n ...node,\n condition: scaleCondition(node.condition, factor),\n timeout: scale(node.timeout, factor),\n onTimeout: Array.isArray(node.onTimeout)\n ? scaleFlow(node.onTimeout, factor)\n : node.onTimeout,\n };\n case 'branch':\n return {\n ...node,\n cases: node.cases.map((branch) => ({\n ...branch,\n condition: scaleCondition(branch.condition, factor),\n flow: scaleFlow(branch.flow, factor),\n })),\n ...(node.otherwise === undefined ? {} : { otherwise: scaleFlow(node.otherwise, factor) }),\n };\n case 'filter':\n return { ...node, condition: scaleCondition(node.condition, factor) };\n case 'cohort':\n return {\n ...node,\n arms: node.arms.map((arm) => ({ ...arm, flow: scaleFlow(arm.flow, factor) })),\n };\n default:\n return node;\n }\n}\n\nfunction scale(duration: DurationIR, factor: number): DurationIR {\n return { value: duration.value, ms: Math.max(0, Math.round(duration.ms / factor)) };\n}\n\n/**\n * A store whose segment definitions come back scaled by `factor` — what journeyWorker reads\n * through in fast-forward, so a segment's windows (`performed(e.login, { within: '7 days' })`)\n * shrink with the journeys that reference it, and with the segment triggers it routes. Every\n * other method is the store's own.\n */\nexport function scaleSegmentWindows<\n S extends { getSegmentCondition(name: string): Promise<ConditionIR | undefined> },\n>(store: S, factor: number): S {\n if (!(factor > 0) || factor === 1) return store;\n return new Proxy(store, {\n get(target, property) {\n if (property === 'getSegmentCondition') {\n return async (name: string) => {\n const condition = await target.getSegmentCondition(name);\n return condition === undefined ? undefined : scaleCondition(condition, factor);\n };\n }\n const value: unknown = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n },\n });\n}\n"],"mappings":"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"}
|