@sanoma-ai/workflows 0.0.0-stage → 0.1.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.
Files changed (148) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +493 -2
  3. package/dist/approvals.d.ts +46 -0
  4. package/dist/approvals.js +111 -0
  5. package/dist/approvals.js.map +1 -0
  6. package/dist/ast.d.ts +57 -0
  7. package/dist/ast.js +81 -0
  8. package/dist/ast.js.map +1 -0
  9. package/dist/call.d.ts +33 -0
  10. package/dist/call.js +402 -0
  11. package/dist/call.js.map +1 -0
  12. package/dist/client.d.ts +167 -0
  13. package/dist/client.js +400 -0
  14. package/dist/client.js.map +1 -0
  15. package/dist/config.d.ts +126 -0
  16. package/dist/config.js +247 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/credentials.d.ts +30 -0
  19. package/dist/credentials.js +193 -0
  20. package/dist/credentials.js.map +1 -0
  21. package/dist/cucumber.d.ts +64 -0
  22. package/dist/cucumber.js +158 -0
  23. package/dist/cucumber.js.map +1 -0
  24. package/dist/datafile.d.ts +62 -0
  25. package/dist/datafile.js +326 -0
  26. package/dist/datafile.js.map +1 -0
  27. package/dist/db.d.ts +58 -0
  28. package/dist/db.js +179 -0
  29. package/dist/db.js.map +1 -0
  30. package/dist/define.d.ts +205 -0
  31. package/dist/define.js +103 -0
  32. package/dist/define.js.map +1 -0
  33. package/dist/describe.d.ts +135 -0
  34. package/dist/describe.js +127 -0
  35. package/dist/describe.js.map +1 -0
  36. package/dist/drift.d.ts +75 -0
  37. package/dist/drift.js +90 -0
  38. package/dist/drift.js.map +1 -0
  39. package/dist/env.d.ts +49 -0
  40. package/dist/env.js +83 -0
  41. package/dist/env.js.map +1 -0
  42. package/dist/errors.d.ts +88 -0
  43. package/dist/errors.js +148 -0
  44. package/dist/errors.js.map +1 -0
  45. package/dist/expectations.d.ts +26 -0
  46. package/dist/expectations.js +137 -0
  47. package/dist/expectations.js.map +1 -0
  48. package/dist/fake.d.ts +55 -0
  49. package/dist/fake.js +87 -0
  50. package/dist/fake.js.map +1 -0
  51. package/dist/fill.d.ts +9 -0
  52. package/dist/fill.js +17 -0
  53. package/dist/fill.js.map +1 -0
  54. package/dist/index.d.ts +19 -0
  55. package/dist/index.js +25 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/ledger.d.ts +217 -0
  58. package/dist/ledger.js +251 -0
  59. package/dist/ledger.js.map +1 -0
  60. package/dist/lint.d.ts +32 -0
  61. package/dist/lint.js +168 -0
  62. package/dist/lint.js.map +1 -0
  63. package/dist/log.d.ts +24 -0
  64. package/dist/log.js +83 -0
  65. package/dist/log.js.map +1 -0
  66. package/dist/op.d.ts +257 -0
  67. package/dist/op.js +188 -0
  68. package/dist/op.js.map +1 -0
  69. package/dist/outline.d.ts +179 -0
  70. package/dist/outline.js +506 -0
  71. package/dist/outline.js.map +1 -0
  72. package/dist/paths.d.ts +11 -0
  73. package/dist/paths.js +30 -0
  74. package/dist/paths.js.map +1 -0
  75. package/dist/plugin.d.ts +28 -0
  76. package/dist/plugin.js +25 -0
  77. package/dist/plugin.js.map +1 -0
  78. package/dist/policy.d.ts +114 -0
  79. package/dist/policy.js +60 -0
  80. package/dist/policy.js.map +1 -0
  81. package/dist/resource.d.ts +212 -0
  82. package/dist/resource.js +285 -0
  83. package/dist/resource.js.map +1 -0
  84. package/dist/resources.d.ts +62 -0
  85. package/dist/resources.js +197 -0
  86. package/dist/resources.js.map +1 -0
  87. package/dist/run.d.ts +87 -0
  88. package/dist/run.js +2 -0
  89. package/dist/run.js.map +1 -0
  90. package/dist/sandbox.d.ts +33 -0
  91. package/dist/sandbox.js +123 -0
  92. package/dist/sandbox.js.map +1 -0
  93. package/dist/scenario.d.ts +212 -0
  94. package/dist/scenario.js +1079 -0
  95. package/dist/scenario.js.map +1 -0
  96. package/dist/scenarios.d.ts +55 -0
  97. package/dist/scenarios.js +71 -0
  98. package/dist/scenarios.js.map +1 -0
  99. package/dist/shared.d.ts +61 -0
  100. package/dist/shared.js +77 -0
  101. package/dist/shared.js.map +1 -0
  102. package/dist/steps.d.ts +76 -0
  103. package/dist/steps.js +23 -0
  104. package/dist/steps.js.map +1 -0
  105. package/dist/version.d.ts +29 -0
  106. package/dist/version.js +76 -0
  107. package/dist/version.js.map +1 -0
  108. package/dist/worker.d.ts +34 -0
  109. package/dist/worker.js +219 -0
  110. package/dist/worker.js.map +1 -0
  111. package/oxlint.json +128 -0
  112. package/package.json +91 -3
  113. package/src/approvals.ts +157 -0
  114. package/src/ast.ts +115 -0
  115. package/src/call.ts +468 -0
  116. package/src/client.ts +534 -0
  117. package/src/config.ts +381 -0
  118. package/src/credentials.ts +211 -0
  119. package/src/cucumber.ts +230 -0
  120. package/src/datafile.ts +409 -0
  121. package/src/db.ts +197 -0
  122. package/src/define.ts +285 -0
  123. package/src/describe.ts +262 -0
  124. package/src/drift.ts +149 -0
  125. package/src/env.ts +122 -0
  126. package/src/errors.ts +202 -0
  127. package/src/expectations.ts +165 -0
  128. package/src/fake.ts +156 -0
  129. package/src/fill.ts +24 -0
  130. package/src/index.ts +120 -0
  131. package/src/ledger.ts +419 -0
  132. package/src/lint.ts +208 -0
  133. package/src/log.ts +82 -0
  134. package/src/op.ts +399 -0
  135. package/src/outline.ts +620 -0
  136. package/src/paths.ts +32 -0
  137. package/src/plugin.ts +37 -0
  138. package/src/policy.ts +139 -0
  139. package/src/resource.ts +447 -0
  140. package/src/resources.ts +256 -0
  141. package/src/run.ts +91 -0
  142. package/src/sandbox.ts +157 -0
  143. package/src/scenario.ts +1328 -0
  144. package/src/scenarios.ts +111 -0
  145. package/src/shared.ts +116 -0
  146. package/src/steps.ts +90 -0
  147. package/src/version.ts +86 -0
  148. package/src/worker.ts +253 -0
package/dist/client.js ADDED
@@ -0,0 +1,400 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { isDeepStrictEqual } from "node:util";
3
+ import { Error as DBOSErrors } from "@dbos-inc/dbos-sdk";
4
+ import { z } from "zod";
5
+ import { APPROVALS_EVENT, ApprovalMessage, decisionEventOf, messageKeyOf, topicOf } from "./approvals.js";
6
+ import { resolveConfig } from "./config.js";
7
+ import { deleteCredential, storeCredential, storedCredentials } from "./credentials.js";
8
+ import { dbosClient, lazyPool } from "./db.js";
9
+ import { credentialsOf } from "./env.js";
10
+ import { notApprover, Principal } from "./define.js";
11
+ import { DRIFT_WORKFLOW } from "./drift.js";
12
+ import { parseOrThrow, SanomaError } from "./errors.js";
13
+ import { ownedLedger } from "./ledger.js";
14
+ import { isEnded, mayDecide } from "./shared.js";
15
+ /**
16
+ * The run status each DBOS status maps to. `waiting` is PENDING with an approval pending, so
17
+ * only the approvals tell it from `running`. Keyed by every DBOS status, so one a later DBOS
18
+ * adds fails to compile here until it is mapped.
19
+ */
20
+ const FROM_DBOS = {
21
+ ENQUEUED: "queued",
22
+ DELAYED: "queued",
23
+ PENDING: "running",
24
+ SUCCESS: "finished",
25
+ ERROR: "failed",
26
+ MAX_RECOVERY_ATTEMPTS_EXCEEDED: "failed",
27
+ CANCELLED: "cancelled",
28
+ };
29
+ /** A run's status from DBOS's, and whether it has an approval pending. */
30
+ export function runStatus(dbosStatus, approvals) {
31
+ // A status this DBOS did not have when the table was written: not ended as far as we know.
32
+ const status = Object.hasOwn(FROM_DBOS, dbosStatus) ? FROM_DBOS[dbosStatus] : "running";
33
+ return status === "running" && approvals.some((a) => a.status === "pending") ? "waiting" : status;
34
+ }
35
+ /** The DBOS statuses the run statuses come from; `running` and `waiting` both come from PENDING. */
36
+ export const dbosStatusesOf = (...statuses) => Object.keys(FROM_DBOS).filter((s) => statuses.some((status) => FROM_DBOS[s] === (status === "waiting" ? "running" : status)));
37
+ /**
38
+ * The first `limit` items `keep` accepts, read a page of `pageSize` at a time from `list`, in
39
+ * its order, until there are enough or a page comes back short (the last one).
40
+ */
41
+ export async function firstMatching(list, keep, limit, pageSize) {
42
+ const found = [];
43
+ for (let offset = 0;; offset += pageSize) {
44
+ const rows = await list({ limit: pageSize, offset });
45
+ found.push(...rows.filter(keep));
46
+ if (found.length >= limit || rows.length < pageSize)
47
+ return found.slice(0, limit);
48
+ }
49
+ }
50
+ /** Talks to the runtime from another process (the app, a script), through the shared Postgres. */
51
+ export class SanomaClient {
52
+ dbos;
53
+ config;
54
+ drivers;
55
+ /** The config's own ledger store, or a Postgres one made for this client, which `close` then closes. */
56
+ audit;
57
+ /** On the config's database, for the credentials table: opened on first use. */
58
+ credentialsPool;
59
+ constructor(dbos, config, drivers) {
60
+ this.dbos = dbos;
61
+ this.config = config;
62
+ this.drivers = drivers;
63
+ this.audit = ownedLedger(config);
64
+ this.credentialsPool = lazyPool(config.databaseUrl, "credentials");
65
+ }
66
+ /**
67
+ * Connects to the runtime's Postgres for the config's app. Checks the config first and throws
68
+ * what the worker would refuse. Reads ledgers from the config's ledger store, or from the
69
+ * Postgres store on its database when it has none.
70
+ */
71
+ static async connect(config) {
72
+ const resolved = resolveConfig(config);
73
+ const dbos = await dbosClient(resolved.databaseUrl, resolved.appName);
74
+ return new SanomaClient(dbos, resolved, resolved.driversByVendor);
75
+ }
76
+ /**
77
+ * Checks the input against the workflow's schema, then queues a run for the worker. The run
78
+ * gets the input as sent, not as the schema parsed it: the worker parses it once, so a schema
79
+ * with a `.transform` or a default sees the caller's value, and `run.started` records it.
80
+ * `workflow` is a definition, or the name of one in the config's `workflows`.
81
+ */
82
+ async start(workflow, input, options) {
83
+ if (typeof workflow === "string") {
84
+ const named = this.config.workflows.get(workflow);
85
+ if (!named) {
86
+ const known = [...this.config.workflows.keys()];
87
+ throw new SanomaError("invalid_input", `No workflow named "${workflow}"; the config has ${known.join(", ")}`, {
88
+ workflow,
89
+ workflows: known,
90
+ });
91
+ }
92
+ workflow = named;
93
+ }
94
+ parseOrThrow(workflow.input, input, `The input does not match ${workflow.name}'s schema`);
95
+ const startedBy = parseOrThrow(Principal, options?.startedBy, '`startedBy` must be a principal, such as { id: "alice" }');
96
+ const { runId } = options;
97
+ const sandbox = parseOrThrow(z.string().min(1).optional(), options.sandbox, "`sandbox` must be the name of a scenario in the config's `scenarios/`");
98
+ const args = { input, startedBy, ...(sandbox === undefined ? {} : { sandbox }) };
99
+ // An id DBOS has already returns that run, unless it is another workflow's, which DBOS refuses.
100
+ const handle = await this.dbos
101
+ .enqueue({
102
+ queueName: this.config.queueName,
103
+ workflowName: workflow.name,
104
+ workflowID: runId,
105
+ applicationName: this.config.appName,
106
+ authenticatedUser: startedBy.id,
107
+ authenticatedRoles: startedBy.groups ?? [],
108
+ // Kept on the run's status row too, so a listing tells sandbox runs apart without its input.
109
+ ...(sandbox === undefined ? {} : { attributes: { sandbox } }),
110
+ }, args)
111
+ .catch((err) => {
112
+ if (runId !== undefined && err instanceof DBOSErrors.DBOSConflictingWorkflowError) {
113
+ throw new SanomaError("invalid_input", `Run ${runId} already exists as another workflow than ${workflow.name}; use another run id`, { runId, differs: ["workflow"] }, { cause: err });
114
+ }
115
+ throw err;
116
+ });
117
+ // After the enqueue, not before: of two starts racing with one new id, the first's run stands.
118
+ if (runId !== undefined)
119
+ await this.mustMatch(runId, args);
120
+ return handle.workflowID;
121
+ }
122
+ /** The run's audit record, in order, from the ledger store. */
123
+ async ledger(runId) {
124
+ await this.mustExist(runId);
125
+ return this.audit.store.read(runId);
126
+ }
127
+ /**
128
+ * The app's runs, newest first: the latest `limit`, or the latest `limit` with a `status`.
129
+ * Only the approvals tell `running` from `waiting`, so those read PENDING runs a page at a
130
+ * time until `limit` have that status.
131
+ */
132
+ async runs({ limit = 20, status, workflow } = {}) {
133
+ const list = (more) => this.dbos.listWorkflows({
134
+ ...more,
135
+ status: status && dbosStatusesOf(status),
136
+ workflowName: workflow,
137
+ sortDesc: true,
138
+ applicationName: this.config.appName,
139
+ loadInput: false,
140
+ // The output holds the error a summary shows; only an ended run can have one.
141
+ loadOutput: status === undefined || status === "failed" || status === "cancelled",
142
+ });
143
+ if (status !== "running" && status !== "waiting") {
144
+ return Promise.all((await list({ limit })).map((r) => this.summarize(r)));
145
+ }
146
+ return firstMatching(async (page) => Promise.all((await list(page)).map((r) => this.summarize(r))), (run) => run.status === status, limit, Math.max(limit * 2, 50));
147
+ }
148
+ async run(runId) {
149
+ const row = await this.dbos.getWorkflow(runId);
150
+ return row && this.summarize(row);
151
+ }
152
+ async approvals(runId) {
153
+ return (await this.dbos.getEvent(runId, APPROVALS_EVENT, 0)) ?? [];
154
+ }
155
+ /**
156
+ * Sends a decision on the run's pending approval (or the one named), as `message.by`, and
157
+ * waits for the run to read it. Returns the approval as decided. Throws without sending when
158
+ * it is decided already (`already_decided`), when the run has finished, failed or been
159
+ * cancelled (`run_ended`), when there is nothing to decide (`no_pending_approval`,
160
+ * `run_not_found`), or when `by` may not decide it (`not_approver`); and throws
161
+ * `already_decided` too when another decision reached the run first, and `not_approver` when
162
+ * the run read this one and refused it.
163
+ *
164
+ * If the run does not read the decision within `timeoutSeconds` (30 by default; the worker
165
+ * may be down), returns the approval as it stands, still `pending`: the decision stays
166
+ * queued for the run, which reads it when it next runs.
167
+ */
168
+ async decide(runId, message, approvalId, options = {}) {
169
+ const msg = parseOrThrow(ApprovalMessage, message, "Not a decision");
170
+ // A run that does not exist has no approvals, so run_not_found never hides already_decided.
171
+ const [all, row] = await Promise.all([this.approvals(runId), this.mustExist(runId)]);
172
+ const target = approvalId ? all.find((a) => a.id === approvalId) : all.find((a) => a.status === "pending");
173
+ if (target && target.status !== "pending")
174
+ throw alreadyDecided(runId, target);
175
+ // A run that has ended reads no more messages: a decision sent to it would wait forever.
176
+ const status = runStatus(row.status, all);
177
+ if (isEnded(status)) {
178
+ throw new SanomaError("run_ended", `Run ${runId} has ${status}; it takes no more decisions`, {
179
+ runId,
180
+ status,
181
+ ...(target ? { approvalId: target.id } : {}),
182
+ });
183
+ }
184
+ if (!target) {
185
+ throw new SanomaError("no_pending_approval", `Run ${runId} has no pending approval${approvalId ? ` "${approvalId}"` : ""}`, { runId, ...(approvalId ? { approvalId } : {}) });
186
+ }
187
+ if (!mayDecide(target, msg.by)) {
188
+ throw new SanomaError("not_approver", `${notApprover(target, msg.by)} (${target.id})`, {
189
+ runId,
190
+ approvalId: target.id,
191
+ approver: target.approver,
192
+ });
193
+ }
194
+ // The id names this message, so the run's answer says whether it decided with it, and is
195
+ // in its idempotency key, so a retried send queues it once.
196
+ const id = msg.id ?? randomUUID();
197
+ await this.dbos.send(runId, { ...msg, id }, topicOf(target.id), messageKeyOf(target.id, id));
198
+ // DBOSClient does not LISTEN for events: it polls, every 10 s unless told otherwise. A
199
+ // running worker answers within moments, so poll often at first, then once a second.
200
+ const event = decisionEventOf(target.id);
201
+ const timeoutSeconds = options.timeoutSeconds ?? 30;
202
+ const soon = Math.min(2, timeoutSeconds);
203
+ const decided = (await this.dbos.getEvent(runId, event, { timeoutSeconds: soon, pollingIntervalMs: 100 })) ??
204
+ (timeoutSeconds > soon
205
+ ? await this.dbos.getEvent(runId, event, {
206
+ timeoutSeconds: timeoutSeconds - soon,
207
+ pollingIntervalMs: 1000,
208
+ })
209
+ : null);
210
+ const now = decided ?? (await this.approvals(runId)).find((a) => a.id === target.id) ?? target;
211
+ // Read, but refused: the run checks the sender again, and said no.
212
+ const refused = now.refused.find((r) => r.id === id);
213
+ if (refused) {
214
+ throw new SanomaError("not_approver", `${refused.reason} (${target.id})`, {
215
+ runId,
216
+ approvalId: target.id,
217
+ approver: target.approver,
218
+ });
219
+ }
220
+ if (now.status !== "pending" && now.decidedWith !== id)
221
+ throw alreadyDecided(runId, now);
222
+ return now;
223
+ }
224
+ /**
225
+ * The run's output once it ends, or its error. Throws `run_running` when it has not ended
226
+ * within `timeoutMs`; the run goes on.
227
+ */
228
+ async result(runId, timeoutMs = 30_000) {
229
+ await this.mustExist(runId);
230
+ return this.awaitResult(runId, timeoutMs);
231
+ }
232
+ /**
233
+ * Starts the built-in drift workflow, which reads the config's data files itself: `start`
234
+ * with its input, `{}`. Returns the run id; `driftReport` waits for its report. Throws
235
+ * `invalid_input` when the config's connectors declare no resource types, so it has none.
236
+ */
237
+ async drift(options) {
238
+ const drift = this.config.workflows.get(DRIFT_WORKFLOW);
239
+ if (!drift) {
240
+ throw new SanomaError("invalid_input", "The config's connectors declare no resource types, so there is nothing to check for drift");
241
+ }
242
+ return this.start(drift, {}, options);
243
+ }
244
+ /**
245
+ * The report of a drift run once it ends. Throws `run_not_found`, `invalid_input` for another
246
+ * workflow's run, the run's error when it failed, and `run_running` when it has not ended
247
+ * within 30 s.
248
+ */
249
+ async driftReport(runId) {
250
+ const row = await this.mustExist(runId, { loadOutput: true });
251
+ if (row.workflowName !== DRIFT_WORKFLOW) {
252
+ throw new SanomaError("invalid_input", `Run ${runId} is a run of ${row.workflowName}, not of ${DRIFT_WORKFLOW}`, {
253
+ runId,
254
+ workflow: row.workflowName,
255
+ });
256
+ }
257
+ // A finished run's report came with its row; else wait for the run.
258
+ return (row.status === "SUCCESS" ? row.output : await this.awaitResult(runId, 30_000));
259
+ }
260
+ /**
261
+ * Stores a value for a variable a driver's `env` declares, as `by`, and tells the workers: each
262
+ * loads it into its environment, unless its environment sets the variable itself. Refuses
263
+ * (`invalid_input`) a name no driver declares, and a value the variable's schema refuses, with
264
+ * the schema's reason and never the value; an empty value too (`clearCredential` unsets one).
265
+ * Nothing records the value but its row, which records `by` and when.
266
+ */
267
+ async setCredential(name, value, options) {
268
+ // Checked against every declaration of the name, as the worker checks it.
269
+ const statuses = this.declared(name, (n) => (n === name ? value : undefined));
270
+ const setBy = actorOf(options);
271
+ const refused = statuses.find((c) => c.status !== "set");
272
+ if (refused) {
273
+ const problem = refused.problem ?? "it is empty; clear it to unset it";
274
+ throw new SanomaError("invalid_input", `${name} cannot be set: ${problem}`, {
275
+ name,
276
+ issues: [{ path: ["value"], message: problem, code: "custom" }],
277
+ });
278
+ }
279
+ await storeCredential(await this.credentialsDb(), { name, value, setBy });
280
+ }
281
+ /**
282
+ * Deletes the stored value of a declared variable, and tells the workers, which unset it unless
283
+ * their environment sets it. `by` is who asks; nothing records it once the row is gone.
284
+ * Refuses (`invalid_input`) a name no driver declares.
285
+ */
286
+ async clearCredential(name, options) {
287
+ this.declared(name, () => undefined);
288
+ actorOf(options);
289
+ await deleteCredential(await this.credentialsDb(), name);
290
+ }
291
+ /**
292
+ * Each vendor's declared variables and their statuses now: from this process's environment,
293
+ * which wins, else from the stored credentials, with `source` saying which (a value equal to
294
+ * the stored one, as a worker in this process loads it, is `stored`), and who set a stored one
295
+ * and when. Never a value.
296
+ */
297
+ async credentials() {
298
+ const names = [...credentialsOf(this.drivers, () => undefined).values()].flat().map((c) => c.name);
299
+ if (!names.length)
300
+ return new Map();
301
+ const rows = await storedCredentials(await this.credentialsDb(), names);
302
+ const statuses = credentialsOf(this.drivers, (name) => process.env[name] || rows.get(name)?.value);
303
+ const sourced = (c) => {
304
+ const row = rows.get(c.name);
305
+ const env = process.env[c.name];
306
+ // A worker in this process loads the stored values into its environment: those are stored.
307
+ if (env && env !== row?.value)
308
+ return { ...c, source: "environment" };
309
+ return row ? { ...c, source: "stored", setBy: row.setBy, setAt: row.setAt } : c;
310
+ };
311
+ return new Map([...statuses].map(([vendor, list]) => [vendor, list.map(sourced)]));
312
+ }
313
+ async close() {
314
+ await Promise.all([this.dbos.destroy(), this.credentialsPool.close(), this.audit.close()]);
315
+ }
316
+ /**
317
+ * The name's statuses with `lookup`'s value, one per vendor whose drivers declare it, or
318
+ * `invalid_input` when none does.
319
+ */
320
+ declared(name, lookup) {
321
+ const all = [...credentialsOf(this.drivers, lookup).values()].flat();
322
+ const statuses = all.filter((c) => c.name === name);
323
+ if (statuses.length)
324
+ return statuses;
325
+ const known = [...new Set(all.map((c) => c.name))];
326
+ // A name that is no variable's may be a value sent in its place: it is not repeated.
327
+ const named = VARIABLE.test(name);
328
+ const message = `${named ? `No driver declares ${name}` : "That is not a variable name"}; ${known.length ? `the declared variables are ${known.join(", ")}` : "none declares any"}`;
329
+ throw new SanomaError("invalid_input", message, {
330
+ ...(named && { name }),
331
+ issues: [{ path: ["name"], message, code: "custom" }],
332
+ });
333
+ }
334
+ /** The pool the credentials are read and written with, on the database once it is prepared. */
335
+ credentialsDb() {
336
+ return this.credentialsPool.db();
337
+ }
338
+ /** Refuses a run id whose run, as stored, was started with another input, by someone else, or in another sandbox. */
339
+ async mustMatch(runId, args) {
340
+ const [stored] = ((await this.dbos.getWorkflow(runId))?.input ?? []);
341
+ const differs = ["input", "startedBy", "sandbox"].filter((key) => !stored || !sameJson(stored[key], args[key]));
342
+ if (differs.length) {
343
+ throw new SanomaError("invalid_input", `Run ${runId} already exists with a different ${differs.join(", ")}; use another run id`, { runId, differs });
344
+ }
345
+ }
346
+ /** The run's status row, read without its input (and its output, unless asked), or `run_not_found`. */
347
+ async mustExist(runId, { loadOutput = false } = {}) {
348
+ const [row] = await this.dbos.listWorkflows({ workflowIDs: [runId], loadInput: false, loadOutput });
349
+ if (!row)
350
+ throw new SanomaError("run_not_found", `No run ${runId}`, { runId });
351
+ return row;
352
+ }
353
+ /** The run's output once it ends, or its error, polled every 100 ms; `run_running` after `timeoutMs`. */
354
+ async awaitResult(runId, timeoutMs) {
355
+ const running = () => new SanomaError("run_running", `Run ${runId} is still running after ${timeoutMs} ms`, { runId, timeoutMs });
356
+ let timer;
357
+ try {
358
+ // DBOSClient's wait takes no timeout of its own.
359
+ return await Promise.race([
360
+ this.dbos.retrieveWorkflow(runId).getResult({ pollingIntervalMs: 100 }),
361
+ new Promise((_, reject) => {
362
+ timer = setTimeout(() => reject(running()), timeoutMs).unref();
363
+ }),
364
+ ]);
365
+ }
366
+ finally {
367
+ clearTimeout(timer);
368
+ }
369
+ }
370
+ async summarize(r) {
371
+ const approvals = await this.approvals(r.workflowID);
372
+ const groups = r.authenticatedRoles ?? [];
373
+ return {
374
+ runId: r.workflowID,
375
+ workflow: r.workflowName,
376
+ status: runStatus(r.status, approvals),
377
+ startedBy: r.authenticatedUser ? { id: r.authenticatedUser, ...(groups.length ? { groups } : {}) } : undefined,
378
+ createdAt: r.createdAt,
379
+ updatedAt: r.updatedAt,
380
+ approvals,
381
+ error: r.error ? String(r.error.message ?? r.error) : undefined,
382
+ ...(typeof r.attributes?.sandbox === "string" && { sandbox: r.attributes.sandbox }),
383
+ };
384
+ }
385
+ }
386
+ /** The value as JSON reads it back: a Date as its string, undefined members gone. */
387
+ const asJson = (v) => (v === undefined ? undefined : JSON.parse(JSON.stringify(v)));
388
+ /** True when the two are the same JSON, whatever the order of their keys. */
389
+ const sameJson = (a, b) => isDeepStrictEqual(asJson(a), asJson(b));
390
+ /** What an environment variable's name looks like. */
391
+ const VARIABLE = /^[A-Z_][A-Z0-9_]*$/;
392
+ /** `options.by`, who sets or clears a credential: a name, or `invalid_input`. */
393
+ const actorOf = (options) => parseOrThrow(z.string().min(1), options?.by, '`by` must name who is asking, such as "alice"');
394
+ const alreadyDecided = (runId, a) => new SanomaError("already_decided", `${a.id} on run ${runId} was already ${a.status} by ${a.decidedBy}`, {
395
+ runId,
396
+ approvalId: a.id,
397
+ status: a.status,
398
+ decidedBy: a.decidedBy,
399
+ });
400
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import { type WorkflowDefinition } from "./define.ts";
2
+ import type { Fake } from "./fake.ts";
3
+ import type { LedgerStore } from "./ledger.ts";
4
+ import { type Connector, type Driver, type DriverFn, type Op } from "./op.ts";
5
+ import type { Policy } from "./policy.ts";
6
+ import { type Resource } from "./resource.ts";
7
+ import type { Steps } from "./steps.ts";
8
+ /**
9
+ * What a worker runs, on which connectors, under which policy: the argument to `startWorker`.
10
+ * A project usually keeps it in `sanoma.config.ts` and passes it in; nothing loads that file
11
+ * automatically. The rest is convention: each connector carries its driver and its fake
12
+ * (`withSetup`), the app's name is its `package.json`'s, and the scenarios and data files are
13
+ * `scenarios/` and `resources/` in `root`.
14
+ */
15
+ export interface SanomaConfig {
16
+ workflows: WorkflowDefinition<any, any>[];
17
+ /**
18
+ * The connectors (from `defineConnector`, as their packages export them). The worker takes
19
+ * each operation's effect, schemas and retry setting from here, not from the workflow, and
20
+ * refuses a workflow that declares an operation differently. A live run calls the driver its
21
+ * connector's package attaches; a sandbox run calls a fake of its own, which the connector's
22
+ * package attaches the maker of.
23
+ */
24
+ connectors: Connector<any, any>[];
25
+ /** Checked before every operation call. Required: `allowAll` says that every call is allowed. */
26
+ policy: Policy;
27
+ /**
28
+ * Where the audit record goes. Default: `postgresLedger` on the config's database, which the
29
+ * worker, the app and other processes share; the worker and the client each make their own
30
+ * and close it with themselves. A store given here is never closed by the runtime.
31
+ * `jsonlLedger(dir)` keeps it in files instead; `memoryLedger()` keeps it in this process
32
+ * only, for tests.
33
+ */
34
+ ledger?: LedgerStore;
35
+ /** Postgres for the runtime. Defaults to `SANOMA_DATABASE_URL`, then the local docker compose database. */
36
+ databaseUrl?: string;
37
+ /** The file that defined the config, absolute, when known. Set by `defineConfig` from its call site. */
38
+ file?: string;
39
+ /**
40
+ * The directory the config's conventions are relative to: its `package.json` (the app's name),
41
+ * `scenarios/` and `resources/`. Defaults to `file`'s directory; set it where that is not the
42
+ * source's, as in a bundle.
43
+ */
44
+ root?: string;
45
+ /** @deprecated Gone: each connector carries its driver (`withSetup`, from its package). Leave it out. */
46
+ drivers?: never;
47
+ /** @deprecated Gone: each connector carries the maker of its fake (`withSetup`, from its package). Leave it out. */
48
+ fakes?: never;
49
+ /** @deprecated Gone: the app's name is the `name` in `<root>/package.json`, else "sanoma". Leave it out. */
50
+ appName?: never;
51
+ /** @deprecated Gone: the scenarios are `<root>/scenarios/`. Leave it out. */
52
+ scenarios?: never;
53
+ /** The company's own steps for its scenarios (`defineSteps`), besides those its connectors ship. */
54
+ steps?: Steps[];
55
+ }
56
+ /** A config, checked, with everything a worker, client or app derives from it. */
57
+ export interface ResolvedConfig {
58
+ /**
59
+ * Scopes workflows, queues and versions in the system database: the `name` of
60
+ * `<root>/package.json` when it names one, else "sanoma".
61
+ */
62
+ appName: string;
63
+ databaseUrl: string;
64
+ /** The DBOS application version: `<appName>@<DBOS__APPVERSION, or a hash of the workflows>`. */
65
+ version: string;
66
+ /** The DBOS queue runs are started on: `sanoma:<appName>`. */
67
+ queueName: string;
68
+ /** The operations the connectors declare, by id. */
69
+ ops: Map<string, Op>;
70
+ /** The drivers' functions, by operation id, each guarded by its driver's `env` (`indexDrivers`). */
71
+ drivers: Map<string, DriverFn>;
72
+ /**
73
+ * The driver each vendor's connector attaches, made once for this resolution, by vendor id in
74
+ * `connectors` order: what `drivers` indexes and the credentials are read from (`credentialsOf`).
75
+ */
76
+ driversByVendor: Map<string, Driver>;
77
+ /** The makers of the fakes the connectors attach, by vendor id in `connectors` order: each sandbox run makes its own. */
78
+ fakes: Map<string, () => Fake<any, any>>;
79
+ /** `scenarios/` in `root`, as a `file:` URL, when that directory exists. */
80
+ scenarios?: URL;
81
+ /** The resource types the connectors declare, by `<vendor>.<type>`: what the drift workflow checks and scenarios seed. */
82
+ types: ReadonlyMap<string, Resource>;
83
+ /** The steps scenarios can use besides the generic ones: each connector's (`withSetup`), once each, then the config's own. */
84
+ steps: readonly Steps[];
85
+ /**
86
+ * By name; each checked against `ops` and `drivers`. The config's, and the built-in `drift`
87
+ * (`DRIFT_WORKFLOW`) when its connectors declare resource types.
88
+ */
89
+ workflows: Map<string, WorkflowDefinition<any, any>>;
90
+ policy: Policy;
91
+ /** The config's `ledger`, when it gives one; the worker and the client otherwise make `postgresLedger` on `databaseUrl` (`ownedLedger`). */
92
+ ledger?: LedgerStore;
93
+ /**
94
+ * The config's directory, absolute: its `root`, else its `file`'s directory. Its data files
95
+ * are `resources/` in it. Absent when the config has neither, so it has no data files.
96
+ */
97
+ root?: string;
98
+ }
99
+ export declare const DEFAULT_DATABASE_URL = "postgresql://postgres:dbos@localhost:5433/sanoma";
100
+ /** Returns the config, with the file it is called from as its `file`: its directory is the config's `root`. */
101
+ export declare function defineConfig(config: SanomaConfig): SanomaConfig;
102
+ export declare function resolveDatabaseUrl(config: {
103
+ databaseUrl?: string;
104
+ }, env?: NodeJS.ProcessEnv): string;
105
+ /**
106
+ * The config's directory, absolute: its `root`, else its `file`'s directory; undefined when it
107
+ * has neither. No fallback to the working directory: a config found nowhere has no data files,
108
+ * and says so. What a read that needs only the root calls, rather than `resolveConfig`.
109
+ */
110
+ export declare function rootOf(config: Pick<SanomaConfig, "root" | "file">): string | undefined;
111
+ /**
112
+ * Checks a config and derives what the runtime needs from it: the drivers and fakes from the
113
+ * connectors' setups (`withSetup`), and from `root`, the app's name (`package.json`) and the
114
+ * scenarios (`scenarios/`). Throws what `startWorker` would refuse, with the same message, so
115
+ * `describeConfig`, `SanomaClient.connect` and the app fail the same way the worker does. It
116
+ * opens nothing and reads no file outside `root`. Each entry
117
+ * point resolves once: the worker and the client when they start, the app at `startApp`, the
118
+ * `sanoma` bin when it loads the config.
119
+ */
120
+ export declare function resolveConfig(config: SanomaConfig): ResolvedConfig;
121
+ /**
122
+ * The drivers' functions by operation id, refusing one no connector declares. A driver that
123
+ * declares an `env` has each function guarded by it (`guarded`); a fake declares none, so a
124
+ * sandbox run's calls are not.
125
+ */
126
+ export declare function indexDrivers(list: Driver[], ops: Map<string, Op>): Map<string, DriverFn>;