@sanoma-ai/workflows 0.5.0 → 0.7.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 +49 -15
- package/dist/apply.d.ts +2 -1
- package/dist/apply.js +29 -7
- package/dist/apply.js.map +1 -1
- package/dist/approvals.d.ts +27 -2
- package/dist/approvals.js +73 -9
- package/dist/approvals.js.map +1 -1
- package/dist/call.d.ts +3 -2
- package/dist/call.js +38 -30
- package/dist/call.js.map +1 -1
- package/dist/cedar.js +24 -9
- package/dist/cedar.js.map +1 -1
- package/dist/change.d.ts +219 -0
- package/dist/change.js +150 -0
- package/dist/change.js.map +1 -0
- package/dist/chats.d.ts +43 -0
- package/dist/chats.js +48 -0
- package/dist/chats.js.map +1 -0
- package/dist/client.d.ts +52 -6
- package/dist/client.js +88 -47
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +47 -5
- package/dist/config.js +71 -7
- package/dist/config.js.map +1 -1
- package/dist/database.d.ts +83 -0
- package/dist/database.js +92 -0
- package/dist/database.js.map +1 -0
- package/dist/db.d.ts +31 -1
- package/dist/db.js +89 -7
- package/dist/db.js.map +1 -1
- package/dist/deadlines.d.ts +88 -0
- package/dist/deadlines.js +171 -0
- package/dist/deadlines.js.map +1 -0
- package/dist/define.d.ts +25 -4
- package/dist/define.js +40 -0
- package/dist/define.js.map +1 -1
- package/dist/demo.d.ts +28 -0
- package/dist/demo.js +72 -0
- package/dist/demo.js.map +1 -0
- package/dist/describe.d.ts +6 -3
- package/dist/describe.js +11 -7
- package/dist/describe.js.map +1 -1
- package/dist/errors.d.ts +10 -1
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -1
- package/dist/fake.d.ts +8 -0
- package/dist/fake.js +11 -1
- package/dist/fake.js.map +1 -1
- package/dist/grid.d.ts +34 -0
- package/dist/grid.js +62 -0
- package/dist/grid.js.map +1 -0
- package/dist/host.d.ts +13 -2
- package/dist/host.js +2 -2
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +16 -8
- package/dist/index.js +12 -5
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +11 -2
- package/dist/ledger.js.map +1 -1
- package/dist/lint.js +1 -1
- package/dist/lint.js.map +1 -1
- package/dist/op.d.ts +14 -2
- package/dist/op.js.map +1 -1
- package/dist/policy.d.ts +7 -1
- package/dist/policy.js +2 -1
- package/dist/policy.js.map +1 -1
- package/dist/resource.d.ts +13 -1
- package/dist/resource.js +9 -1
- package/dist/resource.js.map +1 -1
- package/dist/resources.d.ts +2 -0
- package/dist/resources.js +10 -1
- package/dist/resources.js.map +1 -1
- package/dist/run.d.ts +5 -0
- package/dist/run.js.map +1 -1
- package/dist/sandbox.d.ts +38 -10
- package/dist/sandbox.js +66 -35
- package/dist/sandbox.js.map +1 -1
- package/dist/scenario.d.ts +18 -1
- package/dist/scenario.js +77 -27
- package/dist/scenario.js.map +1 -1
- package/dist/scenarios.d.ts +10 -1
- package/dist/scenarios.js +19 -4
- package/dist/scenarios.js.map +1 -1
- package/dist/schedules.d.ts +66 -0
- package/dist/schedules.js +158 -0
- package/dist/schedules.js.map +1 -0
- package/dist/schema.d.ts +6 -0
- package/dist/schema.js +13 -3
- package/dist/schema.js.map +1 -1
- package/dist/shared.d.ts +38 -2
- package/dist/shared.js +50 -4
- package/dist/shared.js.map +1 -1
- package/dist/sites.d.ts +38 -1
- package/dist/sites.js +153 -26
- package/dist/sites.js.map +1 -1
- package/dist/source.d.ts +61 -2
- package/dist/source.js.map +1 -1
- package/dist/supervisor.d.ts +38 -0
- package/dist/supervisor.js +77 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/version.d.ts +3 -1
- package/dist/version.js +3 -1
- package/dist/version.js.map +1 -1
- package/dist/wakeup-service.d.ts +83 -0
- package/dist/wakeup-service.js +421 -0
- package/dist/wakeup-service.js.map +1 -0
- package/dist/wakeup.d.ts +84 -0
- package/dist/wakeup.js +87 -0
- package/dist/wakeup.js.map +1 -0
- package/dist/worker.d.ts +39 -1
- package/dist/worker.js +130 -39
- package/dist/worker.js.map +1 -1
- package/oxlint.json +2 -1
- package/package.json +8 -2
- package/src/apply.ts +25 -6
- package/src/approvals.ts +89 -16
- package/src/call.ts +40 -29
- package/src/cedar.ts +24 -6
- package/src/change.ts +222 -0
- package/src/chats.ts +114 -0
- package/src/client.ts +145 -55
- package/src/config.ts +110 -13
- package/src/database.ts +152 -0
- package/src/db.ts +108 -9
- package/src/deadlines.ts +234 -0
- package/src/define.ts +71 -4
- package/src/demo.ts +87 -0
- package/src/describe.ts +19 -7
- package/src/errors.ts +14 -0
- package/src/fake.ts +12 -0
- package/src/grid.ts +100 -0
- package/src/host.ts +13 -4
- package/src/index.ts +62 -3
- package/src/ledger.ts +15 -3
- package/src/lint.ts +1 -1
- package/src/op.ts +15 -2
- package/src/policy.ts +7 -1
- package/src/resource.ts +22 -3
- package/src/resources.ts +12 -1
- package/src/run.ts +5 -0
- package/src/sandbox.ts +97 -37
- package/src/scenario.ts +97 -28
- package/src/scenarios.ts +21 -5
- package/src/schedules.ts +206 -0
- package/src/schema.ts +16 -3
- package/src/shared.ts +62 -4
- package/src/sites.ts +198 -33
- package/src/source.ts +58 -3
- package/src/supervisor.ts +107 -0
- package/src/version.ts +3 -1
- package/src/wakeup-service.ts +511 -0
- package/src/wakeup.ts +150 -0
- package/src/worker.ts +181 -44
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Db } from "./db.ts";
|
|
2
|
+
import type { ResolvedConfig } from "./config.ts";
|
|
3
|
+
import type { DriverFn, Op } from "./op.ts";
|
|
4
|
+
import type { Secrets } from "./secret.ts";
|
|
5
|
+
/** What a run blocked in a `ctx` wait waits for: a sleep, until its deadline, or an approval's decision, which has none. */
|
|
6
|
+
export type Wait = {
|
|
7
|
+
kind: "sleep";
|
|
8
|
+
until: number;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "approval";
|
|
11
|
+
};
|
|
12
|
+
/** A deadline besides the sleeping runs', such as a schedule's next fire; undefined for none. */
|
|
13
|
+
export type DeadlineSource = () => Date | undefined;
|
|
14
|
+
/** What a worker shows of its runs' deadlines (`Worker.deadlines`). */
|
|
15
|
+
export interface Deadlines {
|
|
16
|
+
/**
|
|
17
|
+
* Adds a deadline besides the sleeping runs', read each time `nextDeadline` is: a fixed time
|
|
18
|
+
* (a schedule's next fire), never one counted from now, which would never let the worker stop.
|
|
19
|
+
*/
|
|
20
|
+
addSource(source: DeadlineSource): void;
|
|
21
|
+
/** The earliest deadline: a sleeping run's `until`, or a source's. Undefined when there is none. */
|
|
22
|
+
nextDeadline(): Date | undefined;
|
|
23
|
+
/** How many runs are inside their body and in no wrapped wait: executing, or replaying. */
|
|
24
|
+
readonly busy: number;
|
|
25
|
+
/** What the run waits for while it is blocked in a wrapped wait; undefined otherwise. */
|
|
26
|
+
waitOf(runId: string): Wait | undefined;
|
|
27
|
+
}
|
|
28
|
+
/** The registry a worker's runs report to, through `running` and `waiting`. */
|
|
29
|
+
export interface DeadlineRegistry extends Deadlines {
|
|
30
|
+
/** Runs a run's body, counted busy but while it is in `waiting`. */
|
|
31
|
+
running<T>(runId: string, body: () => Promise<T>): Promise<T>;
|
|
32
|
+
/** Runs `fn`, the live wait itself (`DBOS.sleep`, `DBOS.recv`), with the run counted as waiting for `wait`. */
|
|
33
|
+
waiting<T>(runId: string, wait: Wait, fn: () => Promise<T>): Promise<T>;
|
|
34
|
+
}
|
|
35
|
+
/** A registry of its own for each worker: two copies of the package in one process never share one. */
|
|
36
|
+
export declare function deadlineRegistry(): DeadlineRegistry;
|
|
37
|
+
/** The worker `idle` asks about: the app, the version it runs, and its queue. */
|
|
38
|
+
export type IdleScope = Pick<ResolvedConfig, "appName" | "version" | "queueName">;
|
|
39
|
+
/**
|
|
40
|
+
* True when a run on `queue` (none for a run started outside a queue) is this worker's to run: on
|
|
41
|
+
* its own queue, or on one of DBOS's, where recovery puts runs.
|
|
42
|
+
*/
|
|
43
|
+
export declare const onOwnQueue: (queue: string | undefined, queueName: string) => boolean;
|
|
44
|
+
/**
|
|
45
|
+
* True when nothing this worker would run can run within `horizonMs`: no run of its is executing
|
|
46
|
+
* or replaying; none of its version is queued (or queued without one, while it is the latest) on
|
|
47
|
+
* its queue or DBOS's own (recovery queues there); each PENDING run of its version is blocked in
|
|
48
|
+
* a wrapped wait; and the next deadline is past the horizon. A run of another version or queue
|
|
49
|
+
* is not this worker's to run, so it never holds the worker up.
|
|
50
|
+
*/
|
|
51
|
+
export declare function idle(deadlines: Deadlines, scope: IdleScope, horizonMs: number): Promise<boolean>;
|
|
52
|
+
/** What `onStopped` hears when the worker stopped itself: the deadline it registered (null for none) and its generation. */
|
|
53
|
+
export interface SelfStop {
|
|
54
|
+
at: string | null;
|
|
55
|
+
generation: number;
|
|
56
|
+
}
|
|
57
|
+
/** What the stop rule acts on: the wakeup row, the wakeup's register operation, and the worker. */
|
|
58
|
+
export interface StopRule {
|
|
59
|
+
/** The wakeup row's database. */
|
|
60
|
+
db: () => Promise<Db>;
|
|
61
|
+
/** This worker's id on the row (`owner`), fresh for each worker. */
|
|
62
|
+
owner: string;
|
|
63
|
+
/** The declared wakeup's binding, else its declaration's id: what scopes a registration's idempotency key to this instance. */
|
|
64
|
+
wakeup: string;
|
|
65
|
+
/** The wakeup type's register operation, and its driver (none when the connector attaches none). */
|
|
66
|
+
register: {
|
|
67
|
+
op: Op;
|
|
68
|
+
fn: DriverFn | undefined;
|
|
69
|
+
};
|
|
70
|
+
secrets: Secrets;
|
|
71
|
+
deadlines: Deadlines;
|
|
72
|
+
idle: () => Promise<boolean>;
|
|
73
|
+
everyMs: number;
|
|
74
|
+
/** Stops the worker (`Worker.stop`). */
|
|
75
|
+
stop: () => Promise<void>;
|
|
76
|
+
onStopped?: ((stopped: SelfStop) => void) | undefined;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Checks every `everyMs` whether the worker is `idle`; when it is, counts the wakeup row's
|
|
80
|
+
* generation up, registers the next deadline with the wakeup (none when there is no deadline at
|
|
81
|
+
* all), and stops the worker, then tells `onStopped`. A failed registration is recorded on the
|
|
82
|
+
* row and logged once for each new message, and the worker keeps running: the next check tries
|
|
83
|
+
* again with a new generation. A run that arrives while it registers keeps the worker up, since
|
|
84
|
+
* the worker must be idle twice, with the same deadline, before it stops. `close` ends the checks.
|
|
85
|
+
*/
|
|
86
|
+
export declare function stopWhenIdle(rule: StopRule): {
|
|
87
|
+
close(): void;
|
|
88
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
2
|
+
import { dbosStatusesOf } from "./client.js";
|
|
3
|
+
import { nextWakeupGeneration, recordWakeupError, recordWakeupRegistration, recordWakeupStop } from "./db.js";
|
|
4
|
+
import { warn } from "./log.js";
|
|
5
|
+
import { errorMessage, WAKEUP_AGENT } from "./shared.js";
|
|
6
|
+
/** A registry of its own for each worker: two copies of the package in one process never share one. */
|
|
7
|
+
export function deadlineRegistry() {
|
|
8
|
+
// Each run inside its body, with what it waits for while it is blocked.
|
|
9
|
+
const runs = new Map();
|
|
10
|
+
const sources = [];
|
|
11
|
+
return {
|
|
12
|
+
addSource(source) {
|
|
13
|
+
sources.push(source);
|
|
14
|
+
},
|
|
15
|
+
nextDeadline() {
|
|
16
|
+
const times = [
|
|
17
|
+
...[...runs.values()].flatMap((wait) => (wait?.kind === "sleep" ? [wait.until] : [])),
|
|
18
|
+
...sources.flatMap((source) => source()?.getTime() ?? []),
|
|
19
|
+
];
|
|
20
|
+
return times.length ? new Date(Math.min(...times)) : undefined;
|
|
21
|
+
},
|
|
22
|
+
get busy() {
|
|
23
|
+
return [...runs.values()].filter((wait) => wait === undefined).length;
|
|
24
|
+
},
|
|
25
|
+
waitOf: (runId) => runs.get(runId),
|
|
26
|
+
async running(runId, body) {
|
|
27
|
+
runs.set(runId, undefined);
|
|
28
|
+
try {
|
|
29
|
+
return await body();
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
runs.delete(runId);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
async waiting(runId, wait, fn) {
|
|
36
|
+
// Every wait is inside a run's body; one outside is left uncounted rather than counted busy for good.
|
|
37
|
+
if (!runs.has(runId))
|
|
38
|
+
return fn();
|
|
39
|
+
runs.set(runId, wait);
|
|
40
|
+
try {
|
|
41
|
+
return await fn();
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
if (runs.has(runId))
|
|
45
|
+
runs.set(runId, undefined);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* True when a run on `queue` (none for a run started outside a queue) is this worker's to run: on
|
|
52
|
+
* its own queue, or on one of DBOS's, where recovery puts runs.
|
|
53
|
+
*/
|
|
54
|
+
export const onOwnQueue = (queue, queueName) => !queue || queue === queueName || queue.startsWith("_dbos_");
|
|
55
|
+
/**
|
|
56
|
+
* True when nothing this worker would run can run within `horizonMs`: no run of its is executing
|
|
57
|
+
* or replaying; none of its version is queued (or queued without one, while it is the latest) on
|
|
58
|
+
* its queue or DBOS's own (recovery queues there); each PENDING run of its version is blocked in
|
|
59
|
+
* a wrapped wait; and the next deadline is past the horizon. A run of another version or queue
|
|
60
|
+
* is not this worker's to run, so it never holds the worker up.
|
|
61
|
+
*/
|
|
62
|
+
export async function idle(deadlines, scope, horizonMs) {
|
|
63
|
+
if (deadlines.busy > 0)
|
|
64
|
+
return false;
|
|
65
|
+
const next = deadlines.nextDeadline();
|
|
66
|
+
if (next && next.getTime() <= Date.now() + horizonMs)
|
|
67
|
+
return false;
|
|
68
|
+
const runs = await DBOS.listWorkflows({
|
|
69
|
+
applicationName: scope.appName,
|
|
70
|
+
status: dbosStatusesOf("queued", "running"),
|
|
71
|
+
loadInput: false,
|
|
72
|
+
loadOutput: false,
|
|
73
|
+
});
|
|
74
|
+
const ours = runs.filter((r) => onOwnQueue(r.queueName, scope.queueName));
|
|
75
|
+
if (ours.some((r) => r.status === "PENDING" && r.applicationVersion === scope.version && !deadlines.waitOf(r.workflowID)))
|
|
76
|
+
return false;
|
|
77
|
+
const queued = ours.filter((r) => r.status !== "PENDING");
|
|
78
|
+
if (queued.some((r) => r.applicationVersion === scope.version))
|
|
79
|
+
return false;
|
|
80
|
+
// DBOS gives a run queued without a version to the app's latest version.
|
|
81
|
+
if (!queued.some((r) => !r.applicationVersion))
|
|
82
|
+
return true;
|
|
83
|
+
return (await DBOS.getLatestApplicationVersion()).versionName !== scope.version;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Checks every `everyMs` whether the worker is `idle`; when it is, counts the wakeup row's
|
|
87
|
+
* generation up, registers the next deadline with the wakeup (none when there is no deadline at
|
|
88
|
+
* all), and stops the worker, then tells `onStopped`. A failed registration is recorded on the
|
|
89
|
+
* row and logged once for each new message, and the worker keeps running: the next check tries
|
|
90
|
+
* again with a new generation. A run that arrives while it registers keeps the worker up, since
|
|
91
|
+
* the worker must be idle twice, with the same deadline, before it stops. `close` ends the checks.
|
|
92
|
+
*/
|
|
93
|
+
export function stopWhenIdle(rule) {
|
|
94
|
+
let closed = false;
|
|
95
|
+
let timer;
|
|
96
|
+
let lastProblem;
|
|
97
|
+
const problem = (message) => {
|
|
98
|
+
if (message !== lastProblem)
|
|
99
|
+
warn(message);
|
|
100
|
+
lastProblem = message;
|
|
101
|
+
};
|
|
102
|
+
const tryStop = async () => {
|
|
103
|
+
if (!(await rule.idle()))
|
|
104
|
+
return false;
|
|
105
|
+
const next = rule.deadlines.nextDeadline();
|
|
106
|
+
const at = next?.toISOString() ?? null;
|
|
107
|
+
const db = await rule.db();
|
|
108
|
+
const generation = await nextWakeupGeneration(db, rule.owner);
|
|
109
|
+
if (generation === undefined) {
|
|
110
|
+
// A worker claims the row only when it starts, so this one never gets it back.
|
|
111
|
+
warn("another worker registers this instance's wakeups now, so this one keeps running and stops checking");
|
|
112
|
+
closed = true;
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (at !== null) {
|
|
116
|
+
try {
|
|
117
|
+
await registerWakeup(rule, { at, generation });
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
const message = errorMessage(err);
|
|
121
|
+
await recordWakeupError(db, rule.owner, generation, message);
|
|
122
|
+
problem(`could not register the wakeup at ${at}, so the worker keeps running: ${message}`);
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
await recordWakeupRegistration(db, rule.owner, generation, at);
|
|
126
|
+
}
|
|
127
|
+
lastProblem = undefined;
|
|
128
|
+
if (closed || !(await rule.idle()) || rule.deadlines.nextDeadline()?.toISOString() !== next?.toISOString())
|
|
129
|
+
return false;
|
|
130
|
+
await recordWakeupStop(db, rule.owner, generation);
|
|
131
|
+
await rule.stop().catch((err) => warn(`the worker could not stop cleanly: ${errorMessage(err)}`));
|
|
132
|
+
rule.onStopped?.({ at, generation });
|
|
133
|
+
return true;
|
|
134
|
+
};
|
|
135
|
+
const check = async () => {
|
|
136
|
+
timer = undefined;
|
|
137
|
+
if (closed)
|
|
138
|
+
return;
|
|
139
|
+
const stopped = await tryStop().catch((err) => {
|
|
140
|
+
problem(`could not check whether the worker may stop: ${errorMessage(err)}`);
|
|
141
|
+
return false;
|
|
142
|
+
});
|
|
143
|
+
if (!stopped && !closed)
|
|
144
|
+
schedule();
|
|
145
|
+
};
|
|
146
|
+
const schedule = () => {
|
|
147
|
+
timer = setTimeout(() => void check(), rule.everyMs);
|
|
148
|
+
timer.unref();
|
|
149
|
+
};
|
|
150
|
+
schedule();
|
|
151
|
+
return {
|
|
152
|
+
close() {
|
|
153
|
+
closed = true;
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Calls the wakeup's register operation, as `SanomaClient.call` calls a driver: its input parsed,
|
|
160
|
+
* a `CallContext` of the runtime's, and no ledger record, which is a run's. The idempotency key
|
|
161
|
+
* is the generation's, so a retried registration is one registration.
|
|
162
|
+
*/
|
|
163
|
+
async function registerWakeup({ register: { op, fn }, secrets, wakeup }, registration) {
|
|
164
|
+
if (!fn)
|
|
165
|
+
throw new Error(`${op.id} has no driver: the connector package must attach one`);
|
|
166
|
+
// Every database counts generations from 0, so the key names the wakeup too.
|
|
167
|
+
const key = `wakeup:${wakeup}:${registration.generation}`;
|
|
168
|
+
const context = { idempotencyKey: key, runId: key, opId: op.id, attempt: 1, secrets, by: WAKEUP_AGENT };
|
|
169
|
+
await fn(op.input.parse(registration), context);
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=deadlines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deadlines.js","sourceRoot":"","sources":["../src/deadlines.ts"],"names":[],"mappings":"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"}
|
package/dist/define.d.ts
CHANGED
|
@@ -72,12 +72,23 @@ export interface ApprovalState extends Omit<ApprovalRequest, "covers"> {
|
|
|
72
72
|
input?: unknown;
|
|
73
73
|
/** For a policy request: the policies that held the call, by id, when the policy names them. */
|
|
74
74
|
reasons?: string[];
|
|
75
|
-
|
|
75
|
+
/**
|
|
76
|
+
* `withdrawn`: it no longer stands, as when its change got a new commit. A pending approval is
|
|
77
|
+
* withdrawn by a message (`SanomaClient.withdraw`), an approved one by its run
|
|
78
|
+
* (`withdrawApprovals`); either way it lets nothing through and takes no decision.
|
|
79
|
+
*/
|
|
80
|
+
status: "pending" | "approved" | "rejected" | "withdrawn";
|
|
81
|
+
/** Why it was withdrawn, once it is. */
|
|
82
|
+
withdrawnReason?: string;
|
|
83
|
+
/** When it was withdrawn, once it is. */
|
|
84
|
+
withdrawnAt?: number;
|
|
85
|
+
/** Who withdrew it, when someone did rather than its run (`withdrawApprovals`). */
|
|
86
|
+
withdrawnBy?: string;
|
|
76
87
|
requestedAt: number;
|
|
77
88
|
decidedBy?: string;
|
|
78
89
|
decidedAt?: number;
|
|
79
90
|
note?: string;
|
|
80
|
-
/** The `id` of the decision message the run decided with, when it had one. */
|
|
91
|
+
/** The `id` of the decision or withdrawal message the run decided with, when it had one. */
|
|
81
92
|
decidedWith?: string;
|
|
82
93
|
/** Set when the run's own actor decided it: nobody else could (`mayDecide`). */
|
|
83
94
|
alone?: true;
|
|
@@ -154,7 +165,7 @@ type CtxOps<O extends Op> = {
|
|
|
154
165
|
};
|
|
155
166
|
};
|
|
156
167
|
interface ApprovalCtx {
|
|
157
|
-
/** Waits, durably, until the approver (or someone in the approver group) approves. Throws `RejectedError` on a rejection. */
|
|
168
|
+
/** Waits, durably, until the approver (or someone in the approver group) approves. Throws `RejectedError` on a rejection, `WithdrawnError` on a withdrawal. */
|
|
158
169
|
approval(title: string, request: ApprovalRequest): Promise<ApprovalResult>;
|
|
159
170
|
}
|
|
160
171
|
interface SleepCtx {
|
|
@@ -186,11 +197,21 @@ export type Ctx<U extends readonly Use[]> = BaseCtx & CtxOps<OpsOf<U>> & ("appro
|
|
|
186
197
|
* What JSON Schema can't express is left open. Throws when zod can't convert the schema at all.
|
|
187
198
|
*/
|
|
188
199
|
export declare function jsonSchemaOf(schema: z.ZodType, io?: "input" | "output", refs?: ReadonlyMap<unknown, string>): Record<string, unknown>;
|
|
200
|
+
/**
|
|
201
|
+
* How a workflow starts: `manual` (by hand, or from code), or on a schedule, `schedule` a cron
|
|
202
|
+
* expression of five fields (minute, hour, day of month, month, day of week) read in `timezone`,
|
|
203
|
+
* an IANA time zone (`Europe/Amsterdam`), UTC without one. A scheduled run is started by the
|
|
204
|
+
* runtime's `schedule` agent with the input `{}`, as the policy allows; it can still be started by hand.
|
|
205
|
+
*/
|
|
206
|
+
export type Trigger = "manual" | {
|
|
207
|
+
readonly schedule: string;
|
|
208
|
+
readonly timezone?: string;
|
|
209
|
+
};
|
|
189
210
|
export interface WorkflowDefinition<U extends readonly Use[] = readonly Use[], S extends z.ZodType = z.ZodType> {
|
|
190
211
|
readonly kind: "workflow";
|
|
191
212
|
readonly name: string;
|
|
192
213
|
readonly title?: string;
|
|
193
|
-
readonly trigger:
|
|
214
|
+
readonly trigger: Trigger;
|
|
194
215
|
readonly input: S;
|
|
195
216
|
/** Every operation and built-in the workflow may call. `ctx` is built from this list and nothing else. */
|
|
196
217
|
readonly uses: U;
|
package/dist/define.js
CHANGED
|
@@ -70,6 +70,11 @@ export function defineWorkflow(def) {
|
|
|
70
70
|
if (!/^[a-z][a-z0-9-]*$/.test(def.name)) {
|
|
71
71
|
throw new Error(`Workflow name "${def.name}" must be lowercase letters, digits and dashes`);
|
|
72
72
|
}
|
|
73
|
+
checkTrigger(def.name, def.trigger);
|
|
74
|
+
// A scheduled run starts with no input of its own.
|
|
75
|
+
if (def.trigger !== "manual" && !acceptsEmpty(def.input)) {
|
|
76
|
+
throw new Error(`Workflow "${def.name}": a scheduled run starts with the input {}, which its input schema refuses: make each field optional or give it a default`);
|
|
77
|
+
}
|
|
73
78
|
const file = callerFile();
|
|
74
79
|
if (file === undefined) {
|
|
75
80
|
throw new Error(`Workflow "${def.name}" was defined from code with no file (an eval, or a bundle without one): ` +
|
|
@@ -77,6 +82,41 @@ export function defineWorkflow(def) {
|
|
|
77
82
|
}
|
|
78
83
|
return Object.freeze({ kind: "workflow", ...def, file });
|
|
79
84
|
}
|
|
85
|
+
/** True when `{}` parses: a schema zod can check only asynchronously is taken as accepting it, and the run parses it. */
|
|
86
|
+
function acceptsEmpty(schema) {
|
|
87
|
+
try {
|
|
88
|
+
return schema.safeParse({}).success;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Throws what is wrong with a workflow's `trigger`: not `manual` or a schedule, five fields, in a time zone there is. */
|
|
95
|
+
function checkTrigger(name, trigger) {
|
|
96
|
+
if (trigger === "manual")
|
|
97
|
+
return;
|
|
98
|
+
const { schedule, timezone } = (typeof trigger === "object" && trigger !== null ? trigger : {});
|
|
99
|
+
if (typeof schedule !== "string") {
|
|
100
|
+
throw new Error(`Workflow "${name}": its trigger is "manual" or { schedule, timezone? }`);
|
|
101
|
+
}
|
|
102
|
+
if (schedule.trim().split(/\s+/).length !== 5) {
|
|
103
|
+
throw new Error(`Workflow "${name}": its schedule "${schedule}" is a cron expression of five fields: minute, hour, day of month, month, day of week`);
|
|
104
|
+
}
|
|
105
|
+
if (timezone !== undefined && !isTimeZone(timezone)) {
|
|
106
|
+
throw new Error(`Workflow "${name}": its timezone "${String(timezone)}" is no IANA time zone, such as "Europe/Amsterdam"`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const isTimeZone = (zone) => {
|
|
110
|
+
// An offset (`+05:30`), which Intl takes too, is no IANA zone name.
|
|
111
|
+
if (typeof zone !== "string" || /^[+-]/.test(zone))
|
|
112
|
+
return false;
|
|
113
|
+
try {
|
|
114
|
+
return Boolean(new Intl.DateTimeFormat("en", { timeZone: zone }));
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
80
120
|
/**
|
|
81
121
|
* The file of the code that called the function calling this one (`defineWorkflow`'s caller),
|
|
82
122
|
* from V8's call sites, as a path; undefined where there is none.
|
package/dist/define.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAW,MAAM,SAAS,CAAC;AAexC,MAAM,CAAC,MAAM,SAAS,GAAyB,CAAC,CAAC,MAAM,CAAC;IACtD,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,sBAAsB,CAAC;IAClD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,8BAA8B,CAAC,CAAC,QAAQ,EAAE;CAC9E,CAAC,CAAC;AAQH,MAAM,CAAC,MAAM,QAAQ,GAAwB,CAAC,CAAC,KAAK,CAClD,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EACrE,EAAE,KAAK,EAAE,iDAAiD,EAAE,CAC7D,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAW,EAAE,CAAW,EAAW,EAAE,CAChE,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC;AAEjF,MAAM,MAAM,GAAG,qCAAqC,CAAC;AAErD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC;KACpB,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EACxE,EAAE,KAAK,EAAE,MAAM,EAAE,CAClB;KACA,QAAQ,EAAE,CAAC;AAcd;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAC3C;IACE,QAAQ,EAAE,QAAQ;IAClB,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC,CAAC,QAAQ,EAAE;IACnF,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC,QAAQ,EAAE;CACpE,EACD,EAAE,KAAK,EAAE,0DAA0D,EAAE,CACtE,CAAC;
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}
|
package/dist/demo.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SanomaClient } from "./client.ts";
|
|
2
|
+
import type { ResolvedConfig } from "./config.ts";
|
|
3
|
+
import { type Moment } from "./scenario.ts";
|
|
4
|
+
/** What the last `reseed` of an instance did: what the demo's banner shows. */
|
|
5
|
+
export interface DemoState {
|
|
6
|
+
/** When it was seeded, as an ISO timestamp. */
|
|
7
|
+
seededAt: string;
|
|
8
|
+
/** The worlds applied, by scenario name. */
|
|
9
|
+
worlds: string[];
|
|
10
|
+
/** Each moment started and left waiting: who it is for, where they land, its scenario and its run. */
|
|
11
|
+
moments: (Moment & {
|
|
12
|
+
scenario: string;
|
|
13
|
+
runId: string;
|
|
14
|
+
})[];
|
|
15
|
+
/** What could not be done, one line each: a feature file that did not load, a world or a moment that failed. */
|
|
16
|
+
problems: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Seeds the demo instance afresh: empties the collections' table, resets the instance's fakes,
|
|
20
|
+
* applies every world (a scenario with no `When`) to the instance (`applyGivens`: its records
|
|
21
|
+
* saved through the collections' driver, its vendor objects put in the fakes), then starts each
|
|
22
|
+
* moment as a sandbox run by its person, left undriven, so its first approval waits for them.
|
|
23
|
+
* `resolved` is the resolution the worker and `client` run on, made with `fakes: "instance"`.
|
|
24
|
+
* A world or a moment that fails is a problem in the state it returns, and the rest go on.
|
|
25
|
+
*/
|
|
26
|
+
export declare function reseed(client: SanomaClient, resolved: ResolvedConfig): Promise<DemoState>;
|
|
27
|
+
/** What the instance's last `reseed` did, or undefined before its first. */
|
|
28
|
+
export declare const demoState: (resolved: ResolvedConfig) => DemoState | undefined;
|
package/dist/demo.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DATA_TABLE } from "./db.js";
|
|
2
|
+
import { applyGivens } from "./sandbox.js";
|
|
3
|
+
import { loadScenarios } from "./scenario.js";
|
|
4
|
+
import { memorySecrets } from "./secret.js";
|
|
5
|
+
import { errorMessage } from "./shared.js";
|
|
6
|
+
/** Each instance's last reseed, by its resolution. */
|
|
7
|
+
const states = new WeakMap();
|
|
8
|
+
/**
|
|
9
|
+
* Seeds the demo instance afresh: empties the collections' table, resets the instance's fakes,
|
|
10
|
+
* applies every world (a scenario with no `When`) to the instance (`applyGivens`: its records
|
|
11
|
+
* saved through the collections' driver, its vendor objects put in the fakes), then starts each
|
|
12
|
+
* moment as a sandbox run by its person, left undriven, so its first approval waits for them.
|
|
13
|
+
* `resolved` is the resolution the worker and `client` run on, made with `fakes: "instance"`.
|
|
14
|
+
* A world or a moment that fails is a problem in the state it returns, and the rest go on.
|
|
15
|
+
*/
|
|
16
|
+
export async function reseed(client, resolved) {
|
|
17
|
+
const fakes = resolved.instanceFakes;
|
|
18
|
+
if (!fakes)
|
|
19
|
+
throw new Error('reseed seeds an instance on fakes: resolve its config with `fakes: "instance"`');
|
|
20
|
+
// Read first, so scenarios that cannot be read at all leave the instance as it was.
|
|
21
|
+
const { scenarios, errors } = await loadScenarios(resolved);
|
|
22
|
+
if (resolved.dataStore)
|
|
23
|
+
await (await resolved.dataStore.db()).query(`TRUNCATE ${DATA_TABLE}`);
|
|
24
|
+
for (const fake of fakes.values())
|
|
25
|
+
fake.reset();
|
|
26
|
+
const state = {
|
|
27
|
+
seededAt: new Date().toISOString(),
|
|
28
|
+
worlds: [],
|
|
29
|
+
moments: [],
|
|
30
|
+
problems: errors.map((e) => e.message),
|
|
31
|
+
};
|
|
32
|
+
const secrets = memorySecrets();
|
|
33
|
+
for (const world of scenarios.filter((s) => s.workflow === undefined)) {
|
|
34
|
+
try {
|
|
35
|
+
await applyGivens(world, {
|
|
36
|
+
kind: "instance",
|
|
37
|
+
drivers: resolved.drivers,
|
|
38
|
+
fakes,
|
|
39
|
+
ops: resolved.ops,
|
|
40
|
+
call: (i, opId) => ({
|
|
41
|
+
idempotencyKey: `world:${world.name}:${i}`,
|
|
42
|
+
runId: `world:${world.name}`,
|
|
43
|
+
opId,
|
|
44
|
+
attempt: 1,
|
|
45
|
+
secrets,
|
|
46
|
+
// Who its records are by: whoever it says is acting, else the runtime's own agent.
|
|
47
|
+
by: world.startedBy ?? "scenarios",
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
state.worlds.push(world.name);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
state.problems.push(`world "${world.name}": ${errorMessage(err)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const s of scenarios) {
|
|
57
|
+
if (!s.moment || s.workflow === undefined)
|
|
58
|
+
continue;
|
|
59
|
+
try {
|
|
60
|
+
const runId = await client.start(s.workflow, s.input, { sandbox: s.name, startedBy: s.moment.person });
|
|
61
|
+
state.moments.push({ ...s.moment, scenario: s.name, runId });
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
state.problems.push(`moment "${s.name}": ${errorMessage(err)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
states.set(resolved, state);
|
|
68
|
+
return state;
|
|
69
|
+
}
|
|
70
|
+
/** What the instance's last `reseed` did, or undefined before its first. */
|
|
71
|
+
export const demoState = (resolved) => states.get(resolved);
|
|
72
|
+
//# sourceMappingURL=demo.js.map
|
package/dist/demo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"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"}
|
package/dist/describe.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type LintProblem } from "./ast.ts";
|
|
2
2
|
import { type Field } from "./collection.ts";
|
|
3
3
|
import { type SanomaConfig } from "./config.ts";
|
|
4
|
-
import { type Builtin } from "./define.ts";
|
|
4
|
+
import { type Builtin, type Trigger } from "./define.ts";
|
|
5
5
|
import { type Effect } from "./op.ts";
|
|
6
6
|
import { type Outline } from "./outline.ts";
|
|
7
7
|
import { type ResourceFields } from "./resource.ts";
|
|
@@ -19,15 +19,18 @@ export { Reference, type DataValue } from "./datafile.ts";
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function readResources(config: SanomaConfig): DeclaredResource[];
|
|
21
21
|
export { LOCKFILE, readLockfile, serializeLockfile, writeLockfile, diffLockfiles, type Binding, type Bindings, type Rebind, } from "./lockfile.ts";
|
|
22
|
-
export { readSites, type SiteCall, type SiteEntry } from "./sites.ts";
|
|
22
|
+
export { readSites, type SiteCall, type SiteEntry, type SitePage, siteContentPages, siteLocales } from "./sites.ts";
|
|
23
23
|
export { API_FILE, generateApi, writeApi, writeGenerated } from "./sdk.ts";
|
|
24
24
|
export { SCHEMA_FILE, schemaOf, schemaText, type CedarSchemaJson } from "./schema.ts";
|
|
25
|
+
export { columnPrincipal, permissionsGrid, type PermissionsGrid, type PermissionsRow } from "./grid.ts";
|
|
26
|
+
export { previewRequests } from "./shared.ts";
|
|
25
27
|
export type { ApplyInput, ApplyPlan, ApplyReport, ApplyResult, PlanAnswer, PlanStep } from "./apply.ts";
|
|
26
28
|
/** What a workflow is, read from its definition: enough to draw a start form and show what it may call. */
|
|
27
29
|
export interface WorkflowEntry {
|
|
28
30
|
name: string;
|
|
29
31
|
title?: string;
|
|
30
|
-
trigger
|
|
32
|
+
/** `manual`, or the schedule it starts on (`defineWorkflow`'s `trigger`). */
|
|
33
|
+
trigger: Trigger;
|
|
31
34
|
/**
|
|
32
35
|
* Set for a workflow the runtime adds itself, `drift`, `apply` or `call`, rather than the config: a label. It
|
|
33
36
|
* starts like any other.
|
package/dist/describe.js
CHANGED
|
@@ -34,11 +34,14 @@ export function readResources(config) {
|
|
|
34
34
|
}
|
|
35
35
|
export { LOCKFILE, readLockfile, serializeLockfile, writeLockfile, diffLockfiles, } from "./lockfile.js";
|
|
36
36
|
// What the sites call, read from their source: a workflow's Used by.
|
|
37
|
-
export { readSites } from "./sites.js";
|
|
37
|
+
export { readSites, siteContentPages, siteLocales } from "./sites.js";
|
|
38
38
|
// The generated SDK, `.sanoma/api.ts`: a site's `api` typed from this description.
|
|
39
39
|
export { API_FILE, generateApi, writeApi, writeGenerated } from "./sdk.js";
|
|
40
40
|
// The Cedar schema, `.sanoma/schema.cedarschema`: what a company's policies are validated and decided against.
|
|
41
41
|
export { SCHEMA_FILE, schemaOf, schemaText } from "./schema.js";
|
|
42
|
+
// The Permissions grid: the app's page and `sanoma check`'s `checked` event compute it the one way.
|
|
43
|
+
export { columnPrincipal, permissionsGrid } from "./grid.js";
|
|
44
|
+
export { previewRequests } from "./shared.js";
|
|
42
45
|
/**
|
|
43
46
|
* Describes a config. Throws what `startWorker` would refuse (see `resolveConfig`), except missing
|
|
44
47
|
* credentials (`SanomaClient.credentials` gives their statuses) and what is wrong in a workflow's
|
|
@@ -169,15 +172,16 @@ function domainProblems(root, declared, types, sites, read) {
|
|
|
169
172
|
const others = `${names.length === 2 ? "both " : ""}${names.slice(0, -1).join(", ")}`;
|
|
170
173
|
messages.push(`${domain} is the domain of ${others} and ${names.at(-1)}`);
|
|
171
174
|
}
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
const file = read(join(root, resource.file));
|
|
175
|
-
const at = typeof file === "string" ? {} : file.at(resource.span[0]);
|
|
176
|
-
for (const message of messages)
|
|
177
|
-
problems.push({ file: resource.file, ...at, message });
|
|
175
|
+
if (root !== undefined)
|
|
176
|
+
problems.push(...messages.map((message) => problemAt(root, resource, read, message)));
|
|
178
177
|
}
|
|
179
178
|
return problems;
|
|
180
179
|
}
|
|
180
|
+
/** `message` at a declaration's `export const`. */
|
|
181
|
+
function problemAt(root, resource, read, message) {
|
|
182
|
+
const file = read(join(root, resource.file));
|
|
183
|
+
return { file: resource.file, ...(typeof file === "string" ? {} : file.at(resource.span[0])), message };
|
|
184
|
+
}
|
|
181
185
|
/**
|
|
182
186
|
* A site's `api` names each workflow `apiNameOf(name)` beside the vendors' operations and the
|
|
183
187
|
* collections (`api.data`), so a workflow whose name comes out as another's, a vendor's id or
|