@tanstack/workflow-runtime 0.0.1
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 +22 -0
- package/dist/define-runtime.cjs +50 -0
- package/dist/define-runtime.cjs.map +1 -0
- package/dist/define-runtime.d.cts +16 -0
- package/dist/define-runtime.d.ts +16 -0
- package/dist/define-runtime.js +48 -0
- package/dist/define-runtime.js.map +1 -0
- package/dist/in-memory-store.cjs +457 -0
- package/dist/in-memory-store.cjs.map +1 -0
- package/dist/in-memory-store.d.cts +8 -0
- package/dist/in-memory-store.d.ts +8 -0
- package/dist/in-memory-store.js +457 -0
- package/dist/in-memory-store.js.map +1 -0
- package/dist/index.cjs +14 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/run-store-adapter.cjs +30 -0
- package/dist/run-store-adapter.cjs.map +1 -0
- package/dist/run-store-adapter.d.cts +7 -0
- package/dist/run-store-adapter.d.ts +7 -0
- package/dist/run-store-adapter.js +29 -0
- package/dist/run-store-adapter.js.map +1 -0
- package/dist/runtime-driver.cjs +334 -0
- package/dist/runtime-driver.cjs.map +1 -0
- package/dist/runtime-driver.d.cts +12 -0
- package/dist/runtime-driver.d.ts +12 -0
- package/dist/runtime-driver.js +334 -0
- package/dist/runtime-driver.js.map +1 -0
- package/dist/schedule-materializer.cjs +156 -0
- package/dist/schedule-materializer.cjs.map +1 -0
- package/dist/schedule-materializer.d.cts +28 -0
- package/dist/schedule-materializer.d.ts +28 -0
- package/dist/schedule-materializer.js +155 -0
- package/dist/schedule-materializer.js.map +1 -0
- package/dist/types.cjs +0 -0
- package/dist/types.d.cts +375 -0
- package/dist/types.d.ts +375 -0
- package/dist/types.js +1 -0
- package/package.json +60 -0
- package/src/define-runtime.ts +46 -0
- package/src/in-memory-store.ts +607 -0
- package/src/index.ts +74 -0
- package/src/run-store-adapter.ts +49 -0
- package/src/runtime-driver.ts +536 -0
- package/src/schedule-materializer.ts +272 -0
- package/src/types.ts +462 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @tanstack/workflow-runtime
|
|
2
|
+
|
|
3
|
+
Experimental runtime contracts for TanStack Workflow.
|
|
4
|
+
|
|
5
|
+
This package is the staging area for durable execution store, schedule, timer,
|
|
6
|
+
signal, lease, and host-adapter contracts. It is intentionally separate from
|
|
7
|
+
`@tanstack/workflow-core`, which remains the small replay engine.
|
|
8
|
+
|
|
9
|
+
See the main docs:
|
|
10
|
+
|
|
11
|
+
- [Guide](../../docs/guide/index.md)
|
|
12
|
+
- [Runtime model](../../docs/guide/runtime-model.md)
|
|
13
|
+
- [Runtime API](../../docs/api/runtime.md)
|
|
14
|
+
|
|
15
|
+
## Store adapter contract tests
|
|
16
|
+
|
|
17
|
+
Storage adapters should wire their implementation into
|
|
18
|
+
`tests/contracts/workflow-execution-store.contract.ts`. The contract suite covers
|
|
19
|
+
the behavior every durable store must preserve: idempotent run creation,
|
|
20
|
+
compare-and-swap event appends, run leases, stale run claiming, timers, signal
|
|
21
|
+
and approval delivery, schedules, timelines, and integration with the runtime
|
|
22
|
+
driver.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const require_runtime_driver = require('./runtime-driver.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/define-runtime.ts
|
|
4
|
+
function defineWorkflowRuntime(config) {
|
|
5
|
+
const driver = require_runtime_driver.createRuntimeDriver(config);
|
|
6
|
+
return {
|
|
7
|
+
__kind: "workflow-runtime",
|
|
8
|
+
...config,
|
|
9
|
+
...driver
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function cron(expression, options = {}) {
|
|
13
|
+
return {
|
|
14
|
+
kind: "cron",
|
|
15
|
+
expression,
|
|
16
|
+
timezone: options.timezone
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const every = {
|
|
20
|
+
milliseconds(everyMs) {
|
|
21
|
+
return {
|
|
22
|
+
kind: "interval",
|
|
23
|
+
everyMs
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
seconds(seconds) {
|
|
27
|
+
return {
|
|
28
|
+
kind: "interval",
|
|
29
|
+
everyMs: seconds * 1e3
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
minutes(minutes) {
|
|
33
|
+
return {
|
|
34
|
+
kind: "interval",
|
|
35
|
+
everyMs: minutes * 60 * 1e3
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
hours(hours) {
|
|
39
|
+
return {
|
|
40
|
+
kind: "interval",
|
|
41
|
+
everyMs: hours * 60 * 60 * 1e3
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
exports.cron = cron;
|
|
48
|
+
exports.defineWorkflowRuntime = defineWorkflowRuntime;
|
|
49
|
+
exports.every = every;
|
|
50
|
+
//# sourceMappingURL=define-runtime.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-runtime.cjs","names":["createRuntimeDriver"],"sources":["../src/define-runtime.ts"],"sourcesContent":["import { createRuntimeDriver } from './runtime-driver'\nimport type {\n WorkflowRegistrationMap,\n WorkflowRuntimeConfig,\n WorkflowRuntimeDefinition,\n WorkflowScheduleSpec,\n} from './types'\n\nexport function defineWorkflowRuntime<\n const TWorkflows extends WorkflowRegistrationMap,\n>(\n config: WorkflowRuntimeConfig<TWorkflows>,\n): WorkflowRuntimeDefinition<TWorkflows> {\n const driver = createRuntimeDriver(config)\n return {\n __kind: 'workflow-runtime',\n ...config,\n ...driver,\n }\n}\n\nexport function cron(\n expression: string,\n options: { timezone?: string } = {},\n): WorkflowScheduleSpec {\n return {\n kind: 'cron',\n expression,\n timezone: options.timezone,\n }\n}\n\nexport const every = {\n milliseconds(everyMs: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs }\n },\n seconds(seconds: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs: seconds * 1000 }\n },\n minutes(minutes: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs: minutes * 60 * 1000 }\n },\n hours(hours: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs: hours * 60 * 60 * 1000 }\n },\n}\n"],"mappings":";;;AAQA,SAAgB,sBAGd,QACuC;CACvC,MAAM,SAASA,2CAAoB,OAAO;AAC1C,QAAO;EACL,QAAQ;EACR,GAAG;EACH,GAAG;EACJ;;AAGH,SAAgB,KACd,YACA,UAAiC,EAAE,EACb;AACtB,QAAO;EACL,MAAM;EACN;EACA,UAAU,QAAQ;EACnB;;AAGH,MAAa,QAAQ;CACnB,aAAa,SAAuC;AAClD,SAAO;GAAE,MAAM;GAAY;GAAS;;CAEtC,QAAQ,SAAuC;AAC7C,SAAO;GAAE,MAAM;GAAY,SAAS,UAAU;GAAM;;CAEtD,QAAQ,SAAuC;AAC7C,SAAO;GAAE,MAAM;GAAY,SAAS,UAAU,KAAK;GAAM;;CAE3D,MAAM,OAAqC;AACzC,SAAO;GAAE,MAAM;GAAY,SAAS,QAAQ,KAAK,KAAK;GAAM;;CAE/D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { WorkflowRegistrationMap, WorkflowRuntimeConfig, WorkflowRuntimeDefinition, WorkflowScheduleSpec } from "./types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/define-runtime.d.ts
|
|
4
|
+
declare function defineWorkflowRuntime<const TWorkflows extends WorkflowRegistrationMap>(config: WorkflowRuntimeConfig<TWorkflows>): WorkflowRuntimeDefinition<TWorkflows>;
|
|
5
|
+
declare function cron(expression: string, options?: {
|
|
6
|
+
timezone?: string;
|
|
7
|
+
}): WorkflowScheduleSpec;
|
|
8
|
+
declare const every: {
|
|
9
|
+
milliseconds(everyMs: number): WorkflowScheduleSpec;
|
|
10
|
+
seconds(seconds: number): WorkflowScheduleSpec;
|
|
11
|
+
minutes(minutes: number): WorkflowScheduleSpec;
|
|
12
|
+
hours(hours: number): WorkflowScheduleSpec;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { cron, defineWorkflowRuntime, every };
|
|
16
|
+
//# sourceMappingURL=define-runtime.d.cts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { WorkflowRegistrationMap, WorkflowRuntimeConfig, WorkflowRuntimeDefinition, WorkflowScheduleSpec } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/define-runtime.d.ts
|
|
4
|
+
declare function defineWorkflowRuntime<const TWorkflows extends WorkflowRegistrationMap>(config: WorkflowRuntimeConfig<TWorkflows>): WorkflowRuntimeDefinition<TWorkflows>;
|
|
5
|
+
declare function cron(expression: string, options?: {
|
|
6
|
+
timezone?: string;
|
|
7
|
+
}): WorkflowScheduleSpec;
|
|
8
|
+
declare const every: {
|
|
9
|
+
milliseconds(everyMs: number): WorkflowScheduleSpec;
|
|
10
|
+
seconds(seconds: number): WorkflowScheduleSpec;
|
|
11
|
+
minutes(minutes: number): WorkflowScheduleSpec;
|
|
12
|
+
hours(hours: number): WorkflowScheduleSpec;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { cron, defineWorkflowRuntime, every };
|
|
16
|
+
//# sourceMappingURL=define-runtime.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createRuntimeDriver } from "./runtime-driver.js";
|
|
2
|
+
|
|
3
|
+
//#region src/define-runtime.ts
|
|
4
|
+
function defineWorkflowRuntime(config) {
|
|
5
|
+
const driver = createRuntimeDriver(config);
|
|
6
|
+
return {
|
|
7
|
+
__kind: "workflow-runtime",
|
|
8
|
+
...config,
|
|
9
|
+
...driver
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function cron(expression, options = {}) {
|
|
13
|
+
return {
|
|
14
|
+
kind: "cron",
|
|
15
|
+
expression,
|
|
16
|
+
timezone: options.timezone
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const every = {
|
|
20
|
+
milliseconds(everyMs) {
|
|
21
|
+
return {
|
|
22
|
+
kind: "interval",
|
|
23
|
+
everyMs
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
seconds(seconds) {
|
|
27
|
+
return {
|
|
28
|
+
kind: "interval",
|
|
29
|
+
everyMs: seconds * 1e3
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
minutes(minutes) {
|
|
33
|
+
return {
|
|
34
|
+
kind: "interval",
|
|
35
|
+
everyMs: minutes * 60 * 1e3
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
hours(hours) {
|
|
39
|
+
return {
|
|
40
|
+
kind: "interval",
|
|
41
|
+
everyMs: hours * 60 * 60 * 1e3
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { cron, defineWorkflowRuntime, every };
|
|
48
|
+
//# sourceMappingURL=define-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-runtime.js","names":[],"sources":["../src/define-runtime.ts"],"sourcesContent":["import { createRuntimeDriver } from './runtime-driver'\nimport type {\n WorkflowRegistrationMap,\n WorkflowRuntimeConfig,\n WorkflowRuntimeDefinition,\n WorkflowScheduleSpec,\n} from './types'\n\nexport function defineWorkflowRuntime<\n const TWorkflows extends WorkflowRegistrationMap,\n>(\n config: WorkflowRuntimeConfig<TWorkflows>,\n): WorkflowRuntimeDefinition<TWorkflows> {\n const driver = createRuntimeDriver(config)\n return {\n __kind: 'workflow-runtime',\n ...config,\n ...driver,\n }\n}\n\nexport function cron(\n expression: string,\n options: { timezone?: string } = {},\n): WorkflowScheduleSpec {\n return {\n kind: 'cron',\n expression,\n timezone: options.timezone,\n }\n}\n\nexport const every = {\n milliseconds(everyMs: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs }\n },\n seconds(seconds: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs: seconds * 1000 }\n },\n minutes(minutes: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs: minutes * 60 * 1000 }\n },\n hours(hours: number): WorkflowScheduleSpec {\n return { kind: 'interval', everyMs: hours * 60 * 60 * 1000 }\n },\n}\n"],"mappings":";;;AAQA,SAAgB,sBAGd,QACuC;CACvC,MAAM,SAAS,oBAAoB,OAAO;AAC1C,QAAO;EACL,QAAQ;EACR,GAAG;EACH,GAAG;EACJ;;AAGH,SAAgB,KACd,YACA,UAAiC,EAAE,EACb;AACtB,QAAO;EACL,MAAM;EACN;EACA,UAAU,QAAQ;EACnB;;AAGH,MAAa,QAAQ;CACnB,aAAa,SAAuC;AAClD,SAAO;GAAE,MAAM;GAAY;GAAS;;CAEtC,QAAQ,SAAuC;AAC7C,SAAO;GAAE,MAAM;GAAY,SAAS,UAAU;GAAM;;CAEtD,QAAQ,SAAuC;AAC7C,SAAO;GAAE,MAAM;GAAY,SAAS,UAAU,KAAK;GAAM;;CAE3D,MAAM,OAAqC;AACzC,SAAO;GAAE,MAAM;GAAY,SAAS,QAAQ,KAAK,KAAK;GAAM;;CAE/D"}
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
let _tanstack_workflow_core = require("@tanstack/workflow-core");
|
|
2
|
+
|
|
3
|
+
//#region src/in-memory-store.ts
|
|
4
|
+
function inMemoryWorkflowExecutionStore() {
|
|
5
|
+
const runs = /* @__PURE__ */ new Map();
|
|
6
|
+
const runStates = /* @__PURE__ */ new Map();
|
|
7
|
+
const logs = /* @__PURE__ */ new Map();
|
|
8
|
+
const timers = /* @__PURE__ */ new Map();
|
|
9
|
+
const signalDeliveries = /* @__PURE__ */ new Map();
|
|
10
|
+
const schedules = /* @__PURE__ */ new Map();
|
|
11
|
+
const scheduleBuckets = /* @__PURE__ */ new Map();
|
|
12
|
+
const subscribers = /* @__PURE__ */ new Map();
|
|
13
|
+
function setRun(run) {
|
|
14
|
+
runs.set(run.runId, cloneRun(run));
|
|
15
|
+
}
|
|
16
|
+
function getRun(runId) {
|
|
17
|
+
const run = runs.get(runId);
|
|
18
|
+
return run ? cloneRun(run) : void 0;
|
|
19
|
+
}
|
|
20
|
+
function updateRun(runId, updater) {
|
|
21
|
+
const existing = runs.get(runId);
|
|
22
|
+
if (!existing) return void 0;
|
|
23
|
+
const next = updater(cloneRun(existing));
|
|
24
|
+
setRun(next);
|
|
25
|
+
return cloneRun(next);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
async createRun(args) {
|
|
29
|
+
const existing = getRun(args.runId);
|
|
30
|
+
if (existing) return {
|
|
31
|
+
kind: "existing",
|
|
32
|
+
run: existing
|
|
33
|
+
};
|
|
34
|
+
const run = {
|
|
35
|
+
runId: args.runId,
|
|
36
|
+
workflowId: args.workflowId,
|
|
37
|
+
workflowVersion: args.workflowVersion,
|
|
38
|
+
status: "queued",
|
|
39
|
+
input: args.input,
|
|
40
|
+
createdAt: args.now,
|
|
41
|
+
updatedAt: args.now
|
|
42
|
+
};
|
|
43
|
+
setRun(run);
|
|
44
|
+
return {
|
|
45
|
+
kind: "created",
|
|
46
|
+
run: cloneRun(run)
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
async loadRun(runId) {
|
|
50
|
+
return getRun(runId);
|
|
51
|
+
},
|
|
52
|
+
async loadExecution(runId) {
|
|
53
|
+
const run = getRun(runId);
|
|
54
|
+
if (!run) return void 0;
|
|
55
|
+
return {
|
|
56
|
+
run,
|
|
57
|
+
events: cloneStoredEvents(logs.get(runId) ?? [])
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
async loadRunState(runId) {
|
|
61
|
+
const state = runStates.get(runId);
|
|
62
|
+
return state ? cloneRunState(state) : void 0;
|
|
63
|
+
},
|
|
64
|
+
async saveRunState(args) {
|
|
65
|
+
const state = cloneRunState(args.state);
|
|
66
|
+
runStates.set(state.runId, state);
|
|
67
|
+
setRun(executionFromRunState(state, runs.get(state.runId)?.lease));
|
|
68
|
+
},
|
|
69
|
+
async deleteRun(runId, _reason) {
|
|
70
|
+
runs.delete(runId);
|
|
71
|
+
runStates.delete(runId);
|
|
72
|
+
logs.delete(runId);
|
|
73
|
+
subscribers.delete(runId);
|
|
74
|
+
for (const [key, timer] of timers.entries()) if (timer.runId === runId) timers.delete(key);
|
|
75
|
+
for (const key of signalDeliveries.keys()) if (key.startsWith(`${runId}:`)) signalDeliveries.delete(key);
|
|
76
|
+
},
|
|
77
|
+
async appendEvents(args) {
|
|
78
|
+
const log = logs.get(args.runId) ?? [];
|
|
79
|
+
if (log.length !== args.expectedNextIndex) throw new _tanstack_workflow_core.LogConflictError(args.runId, args.expectedNextIndex, log[args.expectedNextIndex]?.event);
|
|
80
|
+
for (const event of args.events) {
|
|
81
|
+
const stored = storeEvent(args.runId, log.length, event);
|
|
82
|
+
log.push(stored);
|
|
83
|
+
publish(subscribers, args.runId, stored.event, stored.eventIndex);
|
|
84
|
+
}
|
|
85
|
+
logs.set(args.runId, log);
|
|
86
|
+
return { nextIndex: log.length };
|
|
87
|
+
},
|
|
88
|
+
async readEvents(args) {
|
|
89
|
+
const fromIndex = args.fromIndex ?? 0;
|
|
90
|
+
return cloneStoredEvents((logs.get(args.runId) ?? []).slice(fromIndex));
|
|
91
|
+
},
|
|
92
|
+
subscribeEvents(runId, fromIndex, onEvent) {
|
|
93
|
+
const log = logs.get(runId) ?? [];
|
|
94
|
+
for (let index = fromIndex; index < log.length; index++) {
|
|
95
|
+
const stored = log[index];
|
|
96
|
+
if (stored) onEvent(stored.event, stored.eventIndex);
|
|
97
|
+
}
|
|
98
|
+
let runSubscribers = subscribers.get(runId);
|
|
99
|
+
if (!runSubscribers) {
|
|
100
|
+
runSubscribers = /* @__PURE__ */ new Set();
|
|
101
|
+
subscribers.set(runId, runSubscribers);
|
|
102
|
+
}
|
|
103
|
+
runSubscribers.add(onEvent);
|
|
104
|
+
return () => {
|
|
105
|
+
runSubscribers.delete(onEvent);
|
|
106
|
+
if (runSubscribers.size === 0) subscribers.delete(runId);
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
async claimRun(args) {
|
|
110
|
+
const existing = getRun(args.runId);
|
|
111
|
+
if (!existing) return { kind: "not-found" };
|
|
112
|
+
if (isTerminal(existing.status)) return {
|
|
113
|
+
kind: "not-claimable",
|
|
114
|
+
run: existing
|
|
115
|
+
};
|
|
116
|
+
if (!canClaim(existing.lease, args.leaseOwner, args.now)) return {
|
|
117
|
+
kind: "not-claimable",
|
|
118
|
+
run: existing
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
kind: "claimed",
|
|
122
|
+
run: updateRun(args.runId, (run) => ({
|
|
123
|
+
...run,
|
|
124
|
+
status: "running",
|
|
125
|
+
lease: lease(args.leaseOwner, args.leaseMs, args.now),
|
|
126
|
+
updatedAt: args.now
|
|
127
|
+
}))
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
async heartbeatRunLease(args) {
|
|
131
|
+
updateRun(args.runId, (run) => {
|
|
132
|
+
if (run.lease?.owner !== args.leaseOwner) return run;
|
|
133
|
+
return {
|
|
134
|
+
...run,
|
|
135
|
+
lease: lease(args.leaseOwner, args.leaseMs, args.now),
|
|
136
|
+
updatedAt: args.now
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
async releaseRunLease(args) {
|
|
141
|
+
updateRun(args.runId, (run) => {
|
|
142
|
+
if (run.lease?.owner !== args.leaseOwner) return run;
|
|
143
|
+
return {
|
|
144
|
+
...run,
|
|
145
|
+
lease: void 0
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
async markRunPaused(args) {
|
|
150
|
+
updateRun(args.runId, (run) => ({
|
|
151
|
+
...run,
|
|
152
|
+
status: "paused",
|
|
153
|
+
waitingFor: args.waitingFor,
|
|
154
|
+
pendingApproval: args.pendingApproval,
|
|
155
|
+
wakeAt: args.wakeAt,
|
|
156
|
+
lease: void 0,
|
|
157
|
+
updatedAt: args.now
|
|
158
|
+
}));
|
|
159
|
+
},
|
|
160
|
+
async markRunFinished(args) {
|
|
161
|
+
updateRun(args.runId, (run) => ({
|
|
162
|
+
...run,
|
|
163
|
+
status: "finished",
|
|
164
|
+
output: args.output,
|
|
165
|
+
waitingFor: void 0,
|
|
166
|
+
pendingApproval: void 0,
|
|
167
|
+
wakeAt: void 0,
|
|
168
|
+
lease: void 0,
|
|
169
|
+
updatedAt: args.now
|
|
170
|
+
}));
|
|
171
|
+
},
|
|
172
|
+
async markRunErrored(args) {
|
|
173
|
+
args.code;
|
|
174
|
+
updateRun(args.runId, (run) => ({
|
|
175
|
+
...run,
|
|
176
|
+
status: "errored",
|
|
177
|
+
error: args.error,
|
|
178
|
+
waitingFor: void 0,
|
|
179
|
+
pendingApproval: void 0,
|
|
180
|
+
wakeAt: void 0,
|
|
181
|
+
lease: void 0,
|
|
182
|
+
updatedAt: args.now
|
|
183
|
+
}));
|
|
184
|
+
},
|
|
185
|
+
async scheduleTimer(args) {
|
|
186
|
+
timers.set(timerKey(args.runId, args.signalId), {
|
|
187
|
+
runId: args.runId,
|
|
188
|
+
workflowId: args.workflowId,
|
|
189
|
+
workflowVersion: args.workflowVersion,
|
|
190
|
+
wakeAt: args.wakeAt,
|
|
191
|
+
signalId: args.signalId
|
|
192
|
+
});
|
|
193
|
+
updateRun(args.runId, (run) => ({
|
|
194
|
+
...run,
|
|
195
|
+
wakeAt: args.wakeAt,
|
|
196
|
+
updatedAt: args.now
|
|
197
|
+
}));
|
|
198
|
+
},
|
|
199
|
+
async claimDueTimers(args) {
|
|
200
|
+
const due = [];
|
|
201
|
+
for (const [key, timer] of timers.entries()) {
|
|
202
|
+
if (due.length >= args.limit) break;
|
|
203
|
+
if (timer.wakeAt > args.now) continue;
|
|
204
|
+
if (!canClaim(timer.lease, args.leaseOwner, args.now)) continue;
|
|
205
|
+
timers.set(key, {
|
|
206
|
+
...timer,
|
|
207
|
+
lease: lease(args.leaseOwner, args.leaseMs, args.now)
|
|
208
|
+
});
|
|
209
|
+
due.push(cloneTimerWakeup(timer));
|
|
210
|
+
}
|
|
211
|
+
return due;
|
|
212
|
+
},
|
|
213
|
+
async deliverSignal(args) {
|
|
214
|
+
const run = getRun(args.runId);
|
|
215
|
+
if (!run) return { kind: "not-found" };
|
|
216
|
+
const key = signalKey(args.runId, args.delivery.signalId);
|
|
217
|
+
if (signalDeliveries.has(key)) return {
|
|
218
|
+
kind: "duplicate",
|
|
219
|
+
run
|
|
220
|
+
};
|
|
221
|
+
if (run.waitingFor?.signalName !== args.delivery.name) return {
|
|
222
|
+
kind: "not-waiting",
|
|
223
|
+
run
|
|
224
|
+
};
|
|
225
|
+
signalDeliveries.set(key, true);
|
|
226
|
+
timers.delete(timerKey(args.runId, args.delivery.signalId));
|
|
227
|
+
return {
|
|
228
|
+
kind: "delivered",
|
|
229
|
+
run: updateRun(args.runId, (current) => ({
|
|
230
|
+
...current,
|
|
231
|
+
status: "queued",
|
|
232
|
+
waitingFor: void 0,
|
|
233
|
+
pendingApproval: void 0,
|
|
234
|
+
wakeAt: void 0,
|
|
235
|
+
updatedAt: args.now
|
|
236
|
+
}))
|
|
237
|
+
};
|
|
238
|
+
},
|
|
239
|
+
async deliverApproval(args) {
|
|
240
|
+
const run = getRun(args.runId);
|
|
241
|
+
if (!run) return { kind: "not-found" };
|
|
242
|
+
const key = signalKey(args.runId, `approval:${args.approval.approvalId}`);
|
|
243
|
+
if (signalDeliveries.has(key)) return {
|
|
244
|
+
kind: "duplicate",
|
|
245
|
+
run
|
|
246
|
+
};
|
|
247
|
+
if (run.pendingApproval?.approvalId !== args.approval.approvalId) return {
|
|
248
|
+
kind: "not-waiting",
|
|
249
|
+
run
|
|
250
|
+
};
|
|
251
|
+
signalDeliveries.set(key, true);
|
|
252
|
+
return {
|
|
253
|
+
kind: "delivered",
|
|
254
|
+
run: updateRun(args.runId, (current) => ({
|
|
255
|
+
...current,
|
|
256
|
+
status: "queued",
|
|
257
|
+
waitingFor: void 0,
|
|
258
|
+
pendingApproval: void 0,
|
|
259
|
+
wakeAt: void 0,
|
|
260
|
+
updatedAt: args.now
|
|
261
|
+
}))
|
|
262
|
+
};
|
|
263
|
+
},
|
|
264
|
+
async upsertSchedule(args) {
|
|
265
|
+
schedules.set(args.scheduleId, {
|
|
266
|
+
scheduleId: args.scheduleId,
|
|
267
|
+
workflowId: args.workflowId,
|
|
268
|
+
workflowVersion: args.workflowVersion,
|
|
269
|
+
nextFireAt: args.nextFireAt,
|
|
270
|
+
input: args.input,
|
|
271
|
+
overlapPolicy: args.overlapPolicy,
|
|
272
|
+
enabled: args.enabled
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
async claimDueScheduleBuckets(args) {
|
|
276
|
+
const due = [];
|
|
277
|
+
for (const schedule of schedules.values()) {
|
|
278
|
+
if (due.length >= args.limit) break;
|
|
279
|
+
if (!schedule.enabled || schedule.nextFireAt === void 0) continue;
|
|
280
|
+
if (schedule.nextFireAt > args.now) continue;
|
|
281
|
+
const bucketId = `${schedule.nextFireAt}`;
|
|
282
|
+
const key = scheduleBucketKey(schedule.scheduleId, bucketId);
|
|
283
|
+
const existing = scheduleBuckets.get(key);
|
|
284
|
+
if (existing?.status === "started") continue;
|
|
285
|
+
if (existing && !canClaim(existing.lease, args.leaseOwner, args.now)) continue;
|
|
286
|
+
const bucket = {
|
|
287
|
+
scheduleId: schedule.scheduleId,
|
|
288
|
+
bucketId,
|
|
289
|
+
workflowId: schedule.workflowId,
|
|
290
|
+
workflowVersion: schedule.workflowVersion,
|
|
291
|
+
runId: `${schedule.workflowId}:${schedule.scheduleId}:${bucketId}`,
|
|
292
|
+
fireAt: schedule.nextFireAt,
|
|
293
|
+
input: schedule.input,
|
|
294
|
+
overlapPolicy: schedule.overlapPolicy,
|
|
295
|
+
status: "claimed",
|
|
296
|
+
lease: lease(args.leaseOwner, args.leaseMs, args.now)
|
|
297
|
+
};
|
|
298
|
+
scheduleBuckets.set(key, bucket);
|
|
299
|
+
due.push(cloneScheduleBucket(bucket));
|
|
300
|
+
}
|
|
301
|
+
return due;
|
|
302
|
+
},
|
|
303
|
+
async markScheduleBucketStarted(args) {
|
|
304
|
+
const key = scheduleBucketKey(args.scheduleId, args.bucketId);
|
|
305
|
+
const bucket = scheduleBuckets.get(key);
|
|
306
|
+
if (!bucket) return;
|
|
307
|
+
scheduleBuckets.set(key, {
|
|
308
|
+
...bucket,
|
|
309
|
+
runId: args.runId,
|
|
310
|
+
status: "started"
|
|
311
|
+
});
|
|
312
|
+
},
|
|
313
|
+
async claimStaleRuns(args) {
|
|
314
|
+
const claims = [];
|
|
315
|
+
for (const run of runs.values()) {
|
|
316
|
+
if (claims.length >= args.limit) break;
|
|
317
|
+
if (run.status !== "running") continue;
|
|
318
|
+
if (!run.lease || run.lease.expiresAt > args.now) continue;
|
|
319
|
+
const nextLease = lease(args.leaseOwner, args.leaseMs, args.now);
|
|
320
|
+
const claimed = updateRun(run.runId, (current) => ({
|
|
321
|
+
...current,
|
|
322
|
+
lease: nextLease,
|
|
323
|
+
updatedAt: args.now
|
|
324
|
+
}));
|
|
325
|
+
if (claimed) claims.push({
|
|
326
|
+
run: claimed,
|
|
327
|
+
lease: cloneLease(nextLease)
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return claims;
|
|
331
|
+
},
|
|
332
|
+
async listRuns(args) {
|
|
333
|
+
const offset = args.cursor ? Number(args.cursor) : 0;
|
|
334
|
+
const start = Number.isFinite(offset) && offset > 0 ? offset : 0;
|
|
335
|
+
return Array.from(runs.values()).filter((run) => !args.workflowId || run.workflowId === args.workflowId).filter((run) => !args.status || run.status === args.status).sort((a, b) => b.updatedAt - a.updatedAt).slice(start, start + args.limit).map(toRunSummary);
|
|
336
|
+
},
|
|
337
|
+
async getRunTimeline(runId) {
|
|
338
|
+
const run = getRun(runId);
|
|
339
|
+
if (!run) return void 0;
|
|
340
|
+
return {
|
|
341
|
+
run,
|
|
342
|
+
events: cloneStoredEvents(logs.get(runId) ?? [])
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function executionFromRunState(state, leaseValue) {
|
|
348
|
+
return {
|
|
349
|
+
runId: state.runId,
|
|
350
|
+
workflowId: state.workflowId,
|
|
351
|
+
workflowVersion: state.workflowVersion,
|
|
352
|
+
status: state.status,
|
|
353
|
+
input: state.input,
|
|
354
|
+
output: state.output,
|
|
355
|
+
error: state.error,
|
|
356
|
+
waitingFor: state.waitingFor,
|
|
357
|
+
pendingApproval: state.pendingApproval,
|
|
358
|
+
wakeAt: state.waitingFor?.signalName === "__timer" ? state.waitingFor.deadline : void 0,
|
|
359
|
+
lease: leaseValue ? cloneLease(leaseValue) : void 0,
|
|
360
|
+
createdAt: state.createdAt,
|
|
361
|
+
updatedAt: state.updatedAt
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function storeEvent(runId, eventIndex, event) {
|
|
365
|
+
return {
|
|
366
|
+
runId,
|
|
367
|
+
eventIndex,
|
|
368
|
+
eventType: event.type,
|
|
369
|
+
stepId: getStepId(event),
|
|
370
|
+
event,
|
|
371
|
+
createdAt: event.ts
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function getStepId(event) {
|
|
375
|
+
return "stepId" in event ? event.stepId : void 0;
|
|
376
|
+
}
|
|
377
|
+
function lease(owner, leaseMs, now) {
|
|
378
|
+
return {
|
|
379
|
+
owner,
|
|
380
|
+
expiresAt: now + leaseMs
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function canClaim(existing, owner, now) {
|
|
384
|
+
return !existing || existing.owner === owner || existing.expiresAt <= now;
|
|
385
|
+
}
|
|
386
|
+
function isTerminal(status) {
|
|
387
|
+
return status === "finished" || status === "errored" || status === "aborted";
|
|
388
|
+
}
|
|
389
|
+
function timerKey(runId, signalId) {
|
|
390
|
+
return `${runId}:${signalId}`;
|
|
391
|
+
}
|
|
392
|
+
function signalKey(runId, signalId) {
|
|
393
|
+
return `${runId}:${signalId}`;
|
|
394
|
+
}
|
|
395
|
+
function scheduleBucketKey(scheduleId, bucketId) {
|
|
396
|
+
return `${scheduleId}:${bucketId}`;
|
|
397
|
+
}
|
|
398
|
+
function publish(subscribers, runId, event, index) {
|
|
399
|
+
const runSubscribers = subscribers.get(runId);
|
|
400
|
+
if (!runSubscribers) return;
|
|
401
|
+
for (const subscriber of runSubscribers) try {
|
|
402
|
+
subscriber(event, index);
|
|
403
|
+
} catch {}
|
|
404
|
+
}
|
|
405
|
+
function toRunSummary(run) {
|
|
406
|
+
return {
|
|
407
|
+
runId: run.runId,
|
|
408
|
+
workflowId: run.workflowId,
|
|
409
|
+
workflowVersion: run.workflowVersion,
|
|
410
|
+
status: run.status,
|
|
411
|
+
waitingFor: run.waitingFor,
|
|
412
|
+
pendingApproval: run.pendingApproval,
|
|
413
|
+
wakeAt: run.wakeAt,
|
|
414
|
+
createdAt: run.createdAt,
|
|
415
|
+
updatedAt: run.updatedAt
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
function cloneRun(run) {
|
|
419
|
+
return {
|
|
420
|
+
...run,
|
|
421
|
+
waitingFor: run.waitingFor ? {
|
|
422
|
+
...run.waitingFor,
|
|
423
|
+
meta: cloneRecord(run.waitingFor.meta)
|
|
424
|
+
} : void 0,
|
|
425
|
+
pendingApproval: run.pendingApproval ? { ...run.pendingApproval } : void 0,
|
|
426
|
+
lease: run.lease ? cloneLease(run.lease) : void 0
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
function cloneRunState(state) {
|
|
430
|
+
return {
|
|
431
|
+
...state,
|
|
432
|
+
waitingFor: state.waitingFor ? {
|
|
433
|
+
...state.waitingFor,
|
|
434
|
+
meta: cloneRecord(state.waitingFor.meta)
|
|
435
|
+
} : void 0,
|
|
436
|
+
pendingApproval: state.pendingApproval ? { ...state.pendingApproval } : void 0
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function cloneStoredEvents(events) {
|
|
440
|
+
return events.map((event) => ({ ...event }));
|
|
441
|
+
}
|
|
442
|
+
function cloneTimerWakeup(timer) {
|
|
443
|
+
return { ...timer };
|
|
444
|
+
}
|
|
445
|
+
function cloneScheduleBucket(bucket) {
|
|
446
|
+
return { ...bucket };
|
|
447
|
+
}
|
|
448
|
+
function cloneLease(leaseValue) {
|
|
449
|
+
return { ...leaseValue };
|
|
450
|
+
}
|
|
451
|
+
function cloneRecord(value) {
|
|
452
|
+
return value ? { ...value } : value;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
//#endregion
|
|
456
|
+
exports.inMemoryWorkflowExecutionStore = inMemoryWorkflowExecutionStore;
|
|
457
|
+
//# sourceMappingURL=in-memory-store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-store.cjs","names":["LogConflictError"],"sources":["../src/in-memory-store.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/require-await -- In-memory implementation satisfies async storage contracts synchronously. */\nimport { LogConflictError } from '@tanstack/workflow-core'\nimport type {\n DeleteReason,\n RunState,\n WorkflowEvent,\n} from '@tanstack/workflow-core'\nimport type {\n AppendEventsArgs,\n AppendEventsResult,\n ClaimDueScheduleBucketsArgs,\n ClaimDueTimersArgs,\n ClaimRunArgs,\n ClaimRunResult,\n ClaimStaleRunsArgs,\n CreateRunArgs,\n CreateRunResult,\n DeliverApprovalArgs,\n DeliverApprovalResult,\n DeliverSignalArgs,\n DeliverSignalResult,\n HeartbeatRunLeaseArgs,\n LeaseOwner,\n ListRunsArgs,\n LoadedExecution,\n MarkRunErroredArgs,\n MarkRunFinishedArgs,\n MarkRunPausedArgs,\n MarkScheduleBucketStartedArgs,\n ReadEventsArgs,\n ReleaseRunLeaseArgs,\n RunClaim,\n RunId,\n RunSummary,\n RunTimeline,\n SaveRunStateArgs,\n ScheduleBucket,\n ScheduleBucketId,\n ScheduleId,\n ScheduleTimerArgs,\n StoredWorkflowEvent,\n TimerWakeup,\n UpsertScheduleArgs,\n WorkflowExecution,\n WorkflowExecutionStore,\n WorkflowLease,\n WorkflowRunStoreAdapterStore,\n} from './types'\n\ninterface TimerRecord extends TimerWakeup {\n lease?: WorkflowLease\n}\n\ninterface ScheduleRecord {\n scheduleId: ScheduleId\n workflowId: string\n workflowVersion?: string\n nextFireAt?: number\n input: unknown\n overlapPolicy: ScheduleBucket['overlapPolicy']\n enabled: boolean\n}\n\ninterface ScheduleBucketRecord extends ScheduleBucket {\n status: 'claimed' | 'started'\n lease?: WorkflowLease\n}\n\nexport type InMemoryWorkflowExecutionStore = WorkflowExecutionStore &\n WorkflowRunStoreAdapterStore\n\nexport function inMemoryWorkflowExecutionStore(): InMemoryWorkflowExecutionStore {\n const runs = new Map<RunId, WorkflowExecution>()\n const runStates = new Map<RunId, RunState>()\n const logs = new Map<RunId, Array<StoredWorkflowEvent>>()\n const timers = new Map<string, TimerRecord>()\n const signalDeliveries = new Map<string, true>()\n const schedules = new Map<ScheduleId, ScheduleRecord>()\n const scheduleBuckets = new Map<string, ScheduleBucketRecord>()\n const subscribers = new Map<\n RunId,\n Set<(event: WorkflowEvent, index: number) => void>\n >()\n\n function setRun(run: WorkflowExecution) {\n runs.set(run.runId, cloneRun(run))\n }\n\n function getRun(runId: RunId) {\n const run = runs.get(runId)\n return run ? cloneRun(run) : undefined\n }\n\n function updateRun(\n runId: RunId,\n updater: (run: WorkflowExecution) => WorkflowExecution,\n ) {\n const existing = runs.get(runId)\n if (!existing) return undefined\n const next = updater(cloneRun(existing))\n setRun(next)\n return cloneRun(next)\n }\n\n return {\n async createRun(args: CreateRunArgs): Promise<CreateRunResult> {\n const existing = getRun(args.runId)\n if (existing) return { kind: 'existing', run: existing }\n\n const run: WorkflowExecution = {\n runId: args.runId,\n workflowId: args.workflowId,\n workflowVersion: args.workflowVersion,\n status: 'queued',\n input: args.input,\n createdAt: args.now,\n updatedAt: args.now,\n }\n setRun(run)\n return { kind: 'created', run: cloneRun(run) }\n },\n\n async loadRun(runId: RunId) {\n return getRun(runId)\n },\n\n async loadExecution(runId: RunId): Promise<LoadedExecution | undefined> {\n const run = getRun(runId)\n if (!run) return undefined\n return {\n run,\n events: cloneStoredEvents(logs.get(runId) ?? []),\n }\n },\n\n async loadRunState(runId: RunId) {\n const state = runStates.get(runId)\n return state ? cloneRunState(state) : undefined\n },\n\n async saveRunState(args: SaveRunStateArgs) {\n const state = cloneRunState(args.state)\n runStates.set(state.runId, state)\n setRun(executionFromRunState(state, runs.get(state.runId)?.lease))\n },\n\n async deleteRun(runId: RunId, _reason: DeleteReason) {\n runs.delete(runId)\n runStates.delete(runId)\n logs.delete(runId)\n subscribers.delete(runId)\n for (const [key, timer] of timers.entries()) {\n if (timer.runId === runId) timers.delete(key)\n }\n for (const key of signalDeliveries.keys()) {\n if (key.startsWith(`${runId}:`)) signalDeliveries.delete(key)\n }\n },\n\n async appendEvents(args: AppendEventsArgs): Promise<AppendEventsResult> {\n const log = logs.get(args.runId) ?? []\n if (log.length !== args.expectedNextIndex) {\n throw new LogConflictError(\n args.runId,\n args.expectedNextIndex,\n log[args.expectedNextIndex]?.event,\n )\n }\n\n for (const event of args.events) {\n const stored = storeEvent(args.runId, log.length, event)\n log.push(stored)\n publish(subscribers, args.runId, stored.event, stored.eventIndex)\n }\n\n logs.set(args.runId, log)\n return { nextIndex: log.length }\n },\n\n async readEvents(args: ReadEventsArgs) {\n const fromIndex = args.fromIndex ?? 0\n return cloneStoredEvents((logs.get(args.runId) ?? []).slice(fromIndex))\n },\n\n subscribeEvents(runId, fromIndex, onEvent) {\n const log = logs.get(runId) ?? []\n for (let index = fromIndex; index < log.length; index++) {\n const stored = log[index]\n if (stored) onEvent(stored.event, stored.eventIndex)\n }\n\n let runSubscribers = subscribers.get(runId)\n if (!runSubscribers) {\n runSubscribers = new Set()\n subscribers.set(runId, runSubscribers)\n }\n runSubscribers.add(onEvent)\n\n return () => {\n runSubscribers.delete(onEvent)\n if (runSubscribers.size === 0) subscribers.delete(runId)\n }\n },\n\n async claimRun(args: ClaimRunArgs): Promise<ClaimRunResult> {\n const existing = getRun(args.runId)\n if (!existing) return { kind: 'not-found' }\n if (isTerminal(existing.status)) {\n return { kind: 'not-claimable', run: existing }\n }\n if (!canClaim(existing.lease, args.leaseOwner, args.now)) {\n return { kind: 'not-claimable', run: existing }\n }\n\n const claimed = updateRun(args.runId, (run) => ({\n ...run,\n status: 'running',\n lease: lease(args.leaseOwner, args.leaseMs, args.now),\n updatedAt: args.now,\n }))\n return { kind: 'claimed', run: claimed! }\n },\n\n async heartbeatRunLease(args: HeartbeatRunLeaseArgs) {\n updateRun(args.runId, (run) => {\n if (run.lease?.owner !== args.leaseOwner) return run\n return {\n ...run,\n lease: lease(args.leaseOwner, args.leaseMs, args.now),\n updatedAt: args.now,\n }\n })\n },\n\n async releaseRunLease(args: ReleaseRunLeaseArgs) {\n updateRun(args.runId, (run) => {\n if (run.lease?.owner !== args.leaseOwner) return run\n return {\n ...run,\n lease: undefined,\n }\n })\n },\n\n async markRunPaused(args: MarkRunPausedArgs) {\n updateRun(args.runId, (run) => ({\n ...run,\n status: 'paused',\n waitingFor: args.waitingFor,\n pendingApproval: args.pendingApproval,\n wakeAt: args.wakeAt,\n lease: undefined,\n updatedAt: args.now,\n }))\n },\n\n async markRunFinished(args: MarkRunFinishedArgs) {\n updateRun(args.runId, (run) => ({\n ...run,\n status: 'finished',\n output: args.output,\n waitingFor: undefined,\n pendingApproval: undefined,\n wakeAt: undefined,\n lease: undefined,\n updatedAt: args.now,\n }))\n },\n\n async markRunErrored(args: MarkRunErroredArgs) {\n void args.code\n updateRun(args.runId, (run) => ({\n ...run,\n status: 'errored',\n error: args.error,\n waitingFor: undefined,\n pendingApproval: undefined,\n wakeAt: undefined,\n lease: undefined,\n updatedAt: args.now,\n }))\n },\n\n async scheduleTimer(args: ScheduleTimerArgs) {\n timers.set(timerKey(args.runId, args.signalId), {\n runId: args.runId,\n workflowId: args.workflowId,\n workflowVersion: args.workflowVersion,\n wakeAt: args.wakeAt,\n signalId: args.signalId,\n })\n updateRun(args.runId, (run) => ({\n ...run,\n wakeAt: args.wakeAt,\n updatedAt: args.now,\n }))\n },\n\n async claimDueTimers(args: ClaimDueTimersArgs) {\n const due: Array<TimerWakeup> = []\n for (const [key, timer] of timers.entries()) {\n if (due.length >= args.limit) break\n if (timer.wakeAt > args.now) continue\n if (!canClaim(timer.lease, args.leaseOwner, args.now)) continue\n\n timers.set(key, {\n ...timer,\n lease: lease(args.leaseOwner, args.leaseMs, args.now),\n })\n due.push(cloneTimerWakeup(timer))\n }\n return due\n },\n\n async deliverSignal<TPayload>(\n args: DeliverSignalArgs<TPayload>,\n ): Promise<DeliverSignalResult> {\n const run = getRun(args.runId)\n if (!run) return { kind: 'not-found' }\n\n const key = signalKey(args.runId, args.delivery.signalId)\n if (signalDeliveries.has(key)) return { kind: 'duplicate', run }\n if (run.waitingFor?.signalName !== args.delivery.name) {\n return { kind: 'not-waiting', run }\n }\n\n signalDeliveries.set(key, true)\n timers.delete(timerKey(args.runId, args.delivery.signalId))\n const updated = updateRun(args.runId, (current) => ({\n ...current,\n status: 'queued',\n waitingFor: undefined,\n pendingApproval: undefined,\n wakeAt: undefined,\n updatedAt: args.now,\n }))\n return { kind: 'delivered', run: updated! }\n },\n\n async deliverApproval(\n args: DeliverApprovalArgs,\n ): Promise<DeliverApprovalResult> {\n const run = getRun(args.runId)\n if (!run) return { kind: 'not-found' }\n\n const key = signalKey(args.runId, `approval:${args.approval.approvalId}`)\n if (signalDeliveries.has(key)) return { kind: 'duplicate', run }\n if (run.pendingApproval?.approvalId !== args.approval.approvalId) {\n return { kind: 'not-waiting', run }\n }\n\n signalDeliveries.set(key, true)\n const updated = updateRun(args.runId, (current) => ({\n ...current,\n status: 'queued',\n waitingFor: undefined,\n pendingApproval: undefined,\n wakeAt: undefined,\n updatedAt: args.now,\n }))\n return { kind: 'delivered', run: updated! }\n },\n\n async upsertSchedule(args: UpsertScheduleArgs) {\n schedules.set(args.scheduleId, {\n scheduleId: args.scheduleId,\n workflowId: args.workflowId,\n workflowVersion: args.workflowVersion,\n nextFireAt: args.nextFireAt,\n input: args.input,\n overlapPolicy: args.overlapPolicy,\n enabled: args.enabled,\n })\n },\n\n async claimDueScheduleBuckets(args: ClaimDueScheduleBucketsArgs) {\n const due: Array<ScheduleBucket> = []\n for (const schedule of schedules.values()) {\n if (due.length >= args.limit) break\n if (!schedule.enabled || schedule.nextFireAt === undefined) continue\n if (schedule.nextFireAt > args.now) continue\n\n const bucketId = `${schedule.nextFireAt}` satisfies ScheduleBucketId\n const key = scheduleBucketKey(schedule.scheduleId, bucketId)\n const existing = scheduleBuckets.get(key)\n if (existing?.status === 'started') continue\n if (existing && !canClaim(existing.lease, args.leaseOwner, args.now)) {\n continue\n }\n\n const bucket: ScheduleBucketRecord = {\n scheduleId: schedule.scheduleId,\n bucketId,\n workflowId: schedule.workflowId,\n workflowVersion: schedule.workflowVersion,\n runId: `${schedule.workflowId}:${schedule.scheduleId}:${bucketId}`,\n fireAt: schedule.nextFireAt,\n input: schedule.input,\n overlapPolicy: schedule.overlapPolicy,\n status: 'claimed',\n lease: lease(args.leaseOwner, args.leaseMs, args.now),\n }\n scheduleBuckets.set(key, bucket)\n due.push(cloneScheduleBucket(bucket))\n }\n return due\n },\n\n async markScheduleBucketStarted(args: MarkScheduleBucketStartedArgs) {\n const key = scheduleBucketKey(args.scheduleId, args.bucketId)\n const bucket = scheduleBuckets.get(key)\n if (!bucket) return\n scheduleBuckets.set(key, {\n ...bucket,\n runId: args.runId,\n status: 'started',\n })\n },\n\n async claimStaleRuns(args: ClaimStaleRunsArgs) {\n const claims: Array<RunClaim> = []\n for (const run of runs.values()) {\n if (claims.length >= args.limit) break\n if (run.status !== 'running') continue\n if (!run.lease || run.lease.expiresAt > args.now) continue\n\n const nextLease = lease(args.leaseOwner, args.leaseMs, args.now)\n const claimed = updateRun(run.runId, (current) => ({\n ...current,\n lease: nextLease,\n updatedAt: args.now,\n }))\n if (claimed) claims.push({ run: claimed, lease: cloneLease(nextLease) })\n }\n return claims\n },\n\n async listRuns(args: ListRunsArgs) {\n const offset = args.cursor ? Number(args.cursor) : 0\n const start = Number.isFinite(offset) && offset > 0 ? offset : 0\n return Array.from(runs.values())\n .filter((run) => !args.workflowId || run.workflowId === args.workflowId)\n .filter((run) => !args.status || run.status === args.status)\n .sort((a, b) => b.updatedAt - a.updatedAt)\n .slice(start, start + args.limit)\n .map(toRunSummary)\n },\n\n async getRunTimeline(runId: RunId): Promise<RunTimeline | undefined> {\n const run = getRun(runId)\n if (!run) return undefined\n return {\n run,\n events: cloneStoredEvents(logs.get(runId) ?? []),\n }\n },\n }\n}\n\nfunction executionFromRunState(\n state: RunState,\n leaseValue?: WorkflowLease,\n): WorkflowExecution {\n return {\n runId: state.runId,\n workflowId: state.workflowId,\n workflowVersion: state.workflowVersion,\n status: state.status,\n input: state.input,\n output: state.output,\n error: state.error,\n waitingFor: state.waitingFor,\n pendingApproval: state.pendingApproval,\n wakeAt:\n state.waitingFor?.signalName === '__timer'\n ? state.waitingFor.deadline\n : undefined,\n lease: leaseValue ? cloneLease(leaseValue) : undefined,\n createdAt: state.createdAt,\n updatedAt: state.updatedAt,\n }\n}\n\nfunction storeEvent(\n runId: RunId,\n eventIndex: number,\n event: WorkflowEvent,\n): StoredWorkflowEvent {\n return {\n runId,\n eventIndex,\n eventType: event.type,\n stepId: getStepId(event),\n event,\n createdAt: event.ts,\n }\n}\n\nfunction getStepId(event: WorkflowEvent) {\n return 'stepId' in event ? event.stepId : undefined\n}\n\nfunction lease(owner: LeaseOwner, leaseMs: number, now: number): WorkflowLease {\n return { owner, expiresAt: now + leaseMs }\n}\n\nfunction canClaim(\n existing: WorkflowLease | undefined,\n owner: LeaseOwner,\n now: number,\n) {\n return !existing || existing.owner === owner || existing.expiresAt <= now\n}\n\nfunction isTerminal(status: WorkflowExecution['status']) {\n return status === 'finished' || status === 'errored' || status === 'aborted'\n}\n\nfunction timerKey(runId: RunId, signalId: string) {\n return `${runId}:${signalId}`\n}\n\nfunction signalKey(runId: RunId, signalId: string) {\n return `${runId}:${signalId}`\n}\n\nfunction scheduleBucketKey(scheduleId: ScheduleId, bucketId: ScheduleBucketId) {\n return `${scheduleId}:${bucketId}`\n}\n\nfunction publish(\n subscribers: Map<RunId, Set<(event: WorkflowEvent, index: number) => void>>,\n runId: RunId,\n event: WorkflowEvent,\n index: number,\n) {\n const runSubscribers = subscribers.get(runId)\n if (!runSubscribers) return\n for (const subscriber of runSubscribers) {\n try {\n subscriber(event, index)\n } catch {\n /* Subscriber errors must not break persistence. */\n }\n }\n}\n\nfunction toRunSummary(run: WorkflowExecution): RunSummary {\n return {\n runId: run.runId,\n workflowId: run.workflowId,\n workflowVersion: run.workflowVersion,\n status: run.status,\n waitingFor: run.waitingFor,\n pendingApproval: run.pendingApproval,\n wakeAt: run.wakeAt,\n createdAt: run.createdAt,\n updatedAt: run.updatedAt,\n }\n}\n\nfunction cloneRun(run: WorkflowExecution): WorkflowExecution {\n return {\n ...run,\n waitingFor: run.waitingFor\n ? { ...run.waitingFor, meta: cloneRecord(run.waitingFor.meta) }\n : undefined,\n pendingApproval: run.pendingApproval\n ? { ...run.pendingApproval }\n : undefined,\n lease: run.lease ? cloneLease(run.lease) : undefined,\n }\n}\n\nfunction cloneRunState(state: RunState): RunState {\n return {\n ...state,\n waitingFor: state.waitingFor\n ? { ...state.waitingFor, meta: cloneRecord(state.waitingFor.meta) }\n : undefined,\n pendingApproval: state.pendingApproval\n ? { ...state.pendingApproval }\n : undefined,\n }\n}\n\nfunction cloneStoredEvents(\n events: ReadonlyArray<StoredWorkflowEvent>,\n): Array<StoredWorkflowEvent> {\n return events.map((event) => ({ ...event }))\n}\n\nfunction cloneTimerWakeup(timer: TimerWakeup): TimerWakeup {\n return { ...timer }\n}\n\nfunction cloneScheduleBucket(bucket: ScheduleBucket): ScheduleBucket {\n return { ...bucket }\n}\n\nfunction cloneLease(leaseValue: WorkflowLease): WorkflowLease {\n return { ...leaseValue }\n}\n\nfunction cloneRecord(value: Record<string, unknown> | undefined) {\n return value ? { ...value } : value\n}\n"],"mappings":";;;AAuEA,SAAgB,iCAAiE;CAC/E,MAAM,uBAAO,IAAI,KAA+B;CAChD,MAAM,4BAAY,IAAI,KAAsB;CAC5C,MAAM,uBAAO,IAAI,KAAwC;CACzD,MAAM,yBAAS,IAAI,KAA0B;CAC7C,MAAM,mCAAmB,IAAI,KAAmB;CAChD,MAAM,4BAAY,IAAI,KAAiC;CACvD,MAAM,kCAAkB,IAAI,KAAmC;CAC/D,MAAM,8BAAc,IAAI,KAGrB;CAEH,SAAS,OAAO,KAAwB;AACtC,OAAK,IAAI,IAAI,OAAO,SAAS,IAAI,CAAC;;CAGpC,SAAS,OAAO,OAAc;EAC5B,MAAM,MAAM,KAAK,IAAI,MAAM;AAC3B,SAAO,MAAM,SAAS,IAAI,GAAG;;CAG/B,SAAS,UACP,OACA,SACA;EACA,MAAM,WAAW,KAAK,IAAI,MAAM;AAChC,MAAI,CAAC,SAAU,QAAO;EACtB,MAAM,OAAO,QAAQ,SAAS,SAAS,CAAC;AACxC,SAAO,KAAK;AACZ,SAAO,SAAS,KAAK;;AAGvB,QAAO;EACL,MAAM,UAAU,MAA+C;GAC7D,MAAM,WAAW,OAAO,KAAK,MAAM;AACnC,OAAI,SAAU,QAAO;IAAE,MAAM;IAAY,KAAK;IAAU;GAExD,MAAM,MAAyB;IAC7B,OAAO,KAAK;IACZ,YAAY,KAAK;IACjB,iBAAiB,KAAK;IACtB,QAAQ;IACR,OAAO,KAAK;IACZ,WAAW,KAAK;IAChB,WAAW,KAAK;IACjB;AACD,UAAO,IAAI;AACX,UAAO;IAAE,MAAM;IAAW,KAAK,SAAS,IAAI;IAAE;;EAGhD,MAAM,QAAQ,OAAc;AAC1B,UAAO,OAAO,MAAM;;EAGtB,MAAM,cAAc,OAAoD;GACtE,MAAM,MAAM,OAAO,MAAM;AACzB,OAAI,CAAC,IAAK,QAAO;AACjB,UAAO;IACL;IACA,QAAQ,kBAAkB,KAAK,IAAI,MAAM,IAAI,EAAE,CAAC;IACjD;;EAGH,MAAM,aAAa,OAAc;GAC/B,MAAM,QAAQ,UAAU,IAAI,MAAM;AAClC,UAAO,QAAQ,cAAc,MAAM,GAAG;;EAGxC,MAAM,aAAa,MAAwB;GACzC,MAAM,QAAQ,cAAc,KAAK,MAAM;AACvC,aAAU,IAAI,MAAM,OAAO,MAAM;AACjC,UAAO,sBAAsB,OAAO,KAAK,IAAI,MAAM,MAAM,EAAE,MAAM,CAAC;;EAGpE,MAAM,UAAU,OAAc,SAAuB;AACnD,QAAK,OAAO,MAAM;AAClB,aAAU,OAAO,MAAM;AACvB,QAAK,OAAO,MAAM;AAClB,eAAY,OAAO,MAAM;AACzB,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,SAAS,CACzC,KAAI,MAAM,UAAU,MAAO,QAAO,OAAO,IAAI;AAE/C,QAAK,MAAM,OAAO,iBAAiB,MAAM,CACvC,KAAI,IAAI,WAAW,GAAG,MAAM,GAAG,CAAE,kBAAiB,OAAO,IAAI;;EAIjE,MAAM,aAAa,MAAqD;GACtE,MAAM,MAAM,KAAK,IAAI,KAAK,MAAM,IAAI,EAAE;AACtC,OAAI,IAAI,WAAW,KAAK,kBACtB,OAAM,IAAIA,yCACR,KAAK,OACL,KAAK,mBACL,IAAI,KAAK,oBAAoB,MAC9B;AAGH,QAAK,MAAM,SAAS,KAAK,QAAQ;IAC/B,MAAM,SAAS,WAAW,KAAK,OAAO,IAAI,QAAQ,MAAM;AACxD,QAAI,KAAK,OAAO;AAChB,YAAQ,aAAa,KAAK,OAAO,OAAO,OAAO,OAAO,WAAW;;AAGnE,QAAK,IAAI,KAAK,OAAO,IAAI;AACzB,UAAO,EAAE,WAAW,IAAI,QAAQ;;EAGlC,MAAM,WAAW,MAAsB;GACrC,MAAM,YAAY,KAAK,aAAa;AACpC,UAAO,mBAAmB,KAAK,IAAI,KAAK,MAAM,IAAI,EAAE,EAAE,MAAM,UAAU,CAAC;;EAGzE,gBAAgB,OAAO,WAAW,SAAS;GACzC,MAAM,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE;AACjC,QAAK,IAAI,QAAQ,WAAW,QAAQ,IAAI,QAAQ,SAAS;IACvD,MAAM,SAAS,IAAI;AACnB,QAAI,OAAQ,SAAQ,OAAO,OAAO,OAAO,WAAW;;GAGtD,IAAI,iBAAiB,YAAY,IAAI,MAAM;AAC3C,OAAI,CAAC,gBAAgB;AACnB,qCAAiB,IAAI,KAAK;AAC1B,gBAAY,IAAI,OAAO,eAAe;;AAExC,kBAAe,IAAI,QAAQ;AAE3B,gBAAa;AACX,mBAAe,OAAO,QAAQ;AAC9B,QAAI,eAAe,SAAS,EAAG,aAAY,OAAO,MAAM;;;EAI5D,MAAM,SAAS,MAA6C;GAC1D,MAAM,WAAW,OAAO,KAAK,MAAM;AACnC,OAAI,CAAC,SAAU,QAAO,EAAE,MAAM,aAAa;AAC3C,OAAI,WAAW,SAAS,OAAO,CAC7B,QAAO;IAAE,MAAM;IAAiB,KAAK;IAAU;AAEjD,OAAI,CAAC,SAAS,SAAS,OAAO,KAAK,YAAY,KAAK,IAAI,CACtD,QAAO;IAAE,MAAM;IAAiB,KAAK;IAAU;AASjD,UAAO;IAAE,MAAM;IAAW,KANV,UAAU,KAAK,QAAQ,SAAS;KAC9C,GAAG;KACH,QAAQ;KACR,OAAO,MAAM,KAAK,YAAY,KAAK,SAAS,KAAK,IAAI;KACrD,WAAW,KAAK;KACjB,EACqC;IAAG;;EAG3C,MAAM,kBAAkB,MAA6B;AACnD,aAAU,KAAK,QAAQ,QAAQ;AAC7B,QAAI,IAAI,OAAO,UAAU,KAAK,WAAY,QAAO;AACjD,WAAO;KACL,GAAG;KACH,OAAO,MAAM,KAAK,YAAY,KAAK,SAAS,KAAK,IAAI;KACrD,WAAW,KAAK;KACjB;KACD;;EAGJ,MAAM,gBAAgB,MAA2B;AAC/C,aAAU,KAAK,QAAQ,QAAQ;AAC7B,QAAI,IAAI,OAAO,UAAU,KAAK,WAAY,QAAO;AACjD,WAAO;KACL,GAAG;KACH,OAAO;KACR;KACD;;EAGJ,MAAM,cAAc,MAAyB;AAC3C,aAAU,KAAK,QAAQ,SAAS;IAC9B,GAAG;IACH,QAAQ;IACR,YAAY,KAAK;IACjB,iBAAiB,KAAK;IACtB,QAAQ,KAAK;IACb,OAAO;IACP,WAAW,KAAK;IACjB,EAAE;;EAGL,MAAM,gBAAgB,MAA2B;AAC/C,aAAU,KAAK,QAAQ,SAAS;IAC9B,GAAG;IACH,QAAQ;IACR,QAAQ,KAAK;IACb,YAAY;IACZ,iBAAiB;IACjB,QAAQ;IACR,OAAO;IACP,WAAW,KAAK;IACjB,EAAE;;EAGL,MAAM,eAAe,MAA0B;AAC7C,GAAK,KAAK;AACV,aAAU,KAAK,QAAQ,SAAS;IAC9B,GAAG;IACH,QAAQ;IACR,OAAO,KAAK;IACZ,YAAY;IACZ,iBAAiB;IACjB,QAAQ;IACR,OAAO;IACP,WAAW,KAAK;IACjB,EAAE;;EAGL,MAAM,cAAc,MAAyB;AAC3C,UAAO,IAAI,SAAS,KAAK,OAAO,KAAK,SAAS,EAAE;IAC9C,OAAO,KAAK;IACZ,YAAY,KAAK;IACjB,iBAAiB,KAAK;IACtB,QAAQ,KAAK;IACb,UAAU,KAAK;IAChB,CAAC;AACF,aAAU,KAAK,QAAQ,SAAS;IAC9B,GAAG;IACH,QAAQ,KAAK;IACb,WAAW,KAAK;IACjB,EAAE;;EAGL,MAAM,eAAe,MAA0B;GAC7C,MAAM,MAA0B,EAAE;AAClC,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,SAAS,EAAE;AAC3C,QAAI,IAAI,UAAU,KAAK,MAAO;AAC9B,QAAI,MAAM,SAAS,KAAK,IAAK;AAC7B,QAAI,CAAC,SAAS,MAAM,OAAO,KAAK,YAAY,KAAK,IAAI,CAAE;AAEvD,WAAO,IAAI,KAAK;KACd,GAAG;KACH,OAAO,MAAM,KAAK,YAAY,KAAK,SAAS,KAAK,IAAI;KACtD,CAAC;AACF,QAAI,KAAK,iBAAiB,MAAM,CAAC;;AAEnC,UAAO;;EAGT,MAAM,cACJ,MAC8B;GAC9B,MAAM,MAAM,OAAO,KAAK,MAAM;AAC9B,OAAI,CAAC,IAAK,QAAO,EAAE,MAAM,aAAa;GAEtC,MAAM,MAAM,UAAU,KAAK,OAAO,KAAK,SAAS,SAAS;AACzD,OAAI,iBAAiB,IAAI,IAAI,CAAE,QAAO;IAAE,MAAM;IAAa;IAAK;AAChE,OAAI,IAAI,YAAY,eAAe,KAAK,SAAS,KAC/C,QAAO;IAAE,MAAM;IAAe;IAAK;AAGrC,oBAAiB,IAAI,KAAK,KAAK;AAC/B,UAAO,OAAO,SAAS,KAAK,OAAO,KAAK,SAAS,SAAS,CAAC;AAS3D,UAAO;IAAE,MAAM;IAAa,KARZ,UAAU,KAAK,QAAQ,aAAa;KAClD,GAAG;KACH,QAAQ;KACR,YAAY;KACZ,iBAAiB;KACjB,QAAQ;KACR,WAAW,KAAK;KACjB,EACuC;IAAG;;EAG7C,MAAM,gBACJ,MACgC;GAChC,MAAM,MAAM,OAAO,KAAK,MAAM;AAC9B,OAAI,CAAC,IAAK,QAAO,EAAE,MAAM,aAAa;GAEtC,MAAM,MAAM,UAAU,KAAK,OAAO,YAAY,KAAK,SAAS,aAAa;AACzE,OAAI,iBAAiB,IAAI,IAAI,CAAE,QAAO;IAAE,MAAM;IAAa;IAAK;AAChE,OAAI,IAAI,iBAAiB,eAAe,KAAK,SAAS,WACpD,QAAO;IAAE,MAAM;IAAe;IAAK;AAGrC,oBAAiB,IAAI,KAAK,KAAK;AAS/B,UAAO;IAAE,MAAM;IAAa,KARZ,UAAU,KAAK,QAAQ,aAAa;KAClD,GAAG;KACH,QAAQ;KACR,YAAY;KACZ,iBAAiB;KACjB,QAAQ;KACR,WAAW,KAAK;KACjB,EACuC;IAAG;;EAG7C,MAAM,eAAe,MAA0B;AAC7C,aAAU,IAAI,KAAK,YAAY;IAC7B,YAAY,KAAK;IACjB,YAAY,KAAK;IACjB,iBAAiB,KAAK;IACtB,YAAY,KAAK;IACjB,OAAO,KAAK;IACZ,eAAe,KAAK;IACpB,SAAS,KAAK;IACf,CAAC;;EAGJ,MAAM,wBAAwB,MAAmC;GAC/D,MAAM,MAA6B,EAAE;AACrC,QAAK,MAAM,YAAY,UAAU,QAAQ,EAAE;AACzC,QAAI,IAAI,UAAU,KAAK,MAAO;AAC9B,QAAI,CAAC,SAAS,WAAW,SAAS,eAAe,OAAW;AAC5D,QAAI,SAAS,aAAa,KAAK,IAAK;IAEpC,MAAM,WAAW,GAAG,SAAS;IAC7B,MAAM,MAAM,kBAAkB,SAAS,YAAY,SAAS;IAC5D,MAAM,WAAW,gBAAgB,IAAI,IAAI;AACzC,QAAI,UAAU,WAAW,UAAW;AACpC,QAAI,YAAY,CAAC,SAAS,SAAS,OAAO,KAAK,YAAY,KAAK,IAAI,CAClE;IAGF,MAAM,SAA+B;KACnC,YAAY,SAAS;KACrB;KACA,YAAY,SAAS;KACrB,iBAAiB,SAAS;KAC1B,OAAO,GAAG,SAAS,WAAW,GAAG,SAAS,WAAW,GAAG;KACxD,QAAQ,SAAS;KACjB,OAAO,SAAS;KAChB,eAAe,SAAS;KACxB,QAAQ;KACR,OAAO,MAAM,KAAK,YAAY,KAAK,SAAS,KAAK,IAAI;KACtD;AACD,oBAAgB,IAAI,KAAK,OAAO;AAChC,QAAI,KAAK,oBAAoB,OAAO,CAAC;;AAEvC,UAAO;;EAGT,MAAM,0BAA0B,MAAqC;GACnE,MAAM,MAAM,kBAAkB,KAAK,YAAY,KAAK,SAAS;GAC7D,MAAM,SAAS,gBAAgB,IAAI,IAAI;AACvC,OAAI,CAAC,OAAQ;AACb,mBAAgB,IAAI,KAAK;IACvB,GAAG;IACH,OAAO,KAAK;IACZ,QAAQ;IACT,CAAC;;EAGJ,MAAM,eAAe,MAA0B;GAC7C,MAAM,SAA0B,EAAE;AAClC,QAAK,MAAM,OAAO,KAAK,QAAQ,EAAE;AAC/B,QAAI,OAAO,UAAU,KAAK,MAAO;AACjC,QAAI,IAAI,WAAW,UAAW;AAC9B,QAAI,CAAC,IAAI,SAAS,IAAI,MAAM,YAAY,KAAK,IAAK;IAElD,MAAM,YAAY,MAAM,KAAK,YAAY,KAAK,SAAS,KAAK,IAAI;IAChE,MAAM,UAAU,UAAU,IAAI,QAAQ,aAAa;KACjD,GAAG;KACH,OAAO;KACP,WAAW,KAAK;KACjB,EAAE;AACH,QAAI,QAAS,QAAO,KAAK;KAAE,KAAK;KAAS,OAAO,WAAW,UAAU;KAAE,CAAC;;AAE1E,UAAO;;EAGT,MAAM,SAAS,MAAoB;GACjC,MAAM,SAAS,KAAK,SAAS,OAAO,KAAK,OAAO,GAAG;GACnD,MAAM,QAAQ,OAAO,SAAS,OAAO,IAAI,SAAS,IAAI,SAAS;AAC/D,UAAO,MAAM,KAAK,KAAK,QAAQ,CAAC,CAC7B,QAAQ,QAAQ,CAAC,KAAK,cAAc,IAAI,eAAe,KAAK,WAAW,CACvE,QAAQ,QAAQ,CAAC,KAAK,UAAU,IAAI,WAAW,KAAK,OAAO,CAC3D,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU,CACzC,MAAM,OAAO,QAAQ,KAAK,MAAM,CAChC,IAAI,aAAa;;EAGtB,MAAM,eAAe,OAAgD;GACnE,MAAM,MAAM,OAAO,MAAM;AACzB,OAAI,CAAC,IAAK,QAAO;AACjB,UAAO;IACL;IACA,QAAQ,kBAAkB,KAAK,IAAI,MAAM,IAAI,EAAE,CAAC;IACjD;;EAEJ;;AAGH,SAAS,sBACP,OACA,YACmB;AACnB,QAAO;EACL,OAAO,MAAM;EACb,YAAY,MAAM;EAClB,iBAAiB,MAAM;EACvB,QAAQ,MAAM;EACd,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,OAAO,MAAM;EACb,YAAY,MAAM;EAClB,iBAAiB,MAAM;EACvB,QACE,MAAM,YAAY,eAAe,YAC7B,MAAM,WAAW,WACjB;EACN,OAAO,aAAa,WAAW,WAAW,GAAG;EAC7C,WAAW,MAAM;EACjB,WAAW,MAAM;EAClB;;AAGH,SAAS,WACP,OACA,YACA,OACqB;AACrB,QAAO;EACL;EACA;EACA,WAAW,MAAM;EACjB,QAAQ,UAAU,MAAM;EACxB;EACA,WAAW,MAAM;EAClB;;AAGH,SAAS,UAAU,OAAsB;AACvC,QAAO,YAAY,QAAQ,MAAM,SAAS;;AAG5C,SAAS,MAAM,OAAmB,SAAiB,KAA4B;AAC7E,QAAO;EAAE;EAAO,WAAW,MAAM;EAAS;;AAG5C,SAAS,SACP,UACA,OACA,KACA;AACA,QAAO,CAAC,YAAY,SAAS,UAAU,SAAS,SAAS,aAAa;;AAGxE,SAAS,WAAW,QAAqC;AACvD,QAAO,WAAW,cAAc,WAAW,aAAa,WAAW;;AAGrE,SAAS,SAAS,OAAc,UAAkB;AAChD,QAAO,GAAG,MAAM,GAAG;;AAGrB,SAAS,UAAU,OAAc,UAAkB;AACjD,QAAO,GAAG,MAAM,GAAG;;AAGrB,SAAS,kBAAkB,YAAwB,UAA4B;AAC7E,QAAO,GAAG,WAAW,GAAG;;AAG1B,SAAS,QACP,aACA,OACA,OACA,OACA;CACA,MAAM,iBAAiB,YAAY,IAAI,MAAM;AAC7C,KAAI,CAAC,eAAgB;AACrB,MAAK,MAAM,cAAc,eACvB,KAAI;AACF,aAAW,OAAO,MAAM;SAClB;;AAMZ,SAAS,aAAa,KAAoC;AACxD,QAAO;EACL,OAAO,IAAI;EACX,YAAY,IAAI;EAChB,iBAAiB,IAAI;EACrB,QAAQ,IAAI;EACZ,YAAY,IAAI;EAChB,iBAAiB,IAAI;EACrB,QAAQ,IAAI;EACZ,WAAW,IAAI;EACf,WAAW,IAAI;EAChB;;AAGH,SAAS,SAAS,KAA2C;AAC3D,QAAO;EACL,GAAG;EACH,YAAY,IAAI,aACZ;GAAE,GAAG,IAAI;GAAY,MAAM,YAAY,IAAI,WAAW,KAAK;GAAE,GAC7D;EACJ,iBAAiB,IAAI,kBACjB,EAAE,GAAG,IAAI,iBAAiB,GAC1B;EACJ,OAAO,IAAI,QAAQ,WAAW,IAAI,MAAM,GAAG;EAC5C;;AAGH,SAAS,cAAc,OAA2B;AAChD,QAAO;EACL,GAAG;EACH,YAAY,MAAM,aACd;GAAE,GAAG,MAAM;GAAY,MAAM,YAAY,MAAM,WAAW,KAAK;GAAE,GACjE;EACJ,iBAAiB,MAAM,kBACnB,EAAE,GAAG,MAAM,iBAAiB,GAC5B;EACL;;AAGH,SAAS,kBACP,QAC4B;AAC5B,QAAO,OAAO,KAAK,WAAW,EAAE,GAAG,OAAO,EAAE;;AAG9C,SAAS,iBAAiB,OAAiC;AACzD,QAAO,EAAE,GAAG,OAAO;;AAGrB,SAAS,oBAAoB,QAAwC;AACnE,QAAO,EAAE,GAAG,QAAQ;;AAGtB,SAAS,WAAW,YAA0C;AAC5D,QAAO,EAAE,GAAG,YAAY;;AAG1B,SAAS,YAAY,OAA4C;AAC/D,QAAO,QAAQ,EAAE,GAAG,OAAO,GAAG"}
|