@sanoma-ai/workflows 0.0.0-stage → 0.2.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 (176) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +544 -2
  3. package/dist/apply-steps.d.ts +6 -0
  4. package/dist/apply-steps.js +93 -0
  5. package/dist/apply-steps.js.map +1 -0
  6. package/dist/apply.d.ts +197 -0
  7. package/dist/apply.js +470 -0
  8. package/dist/apply.js.map +1 -0
  9. package/dist/approvals.d.ts +46 -0
  10. package/dist/approvals.js +111 -0
  11. package/dist/approvals.js.map +1 -0
  12. package/dist/ast.d.ts +57 -0
  13. package/dist/ast.js +81 -0
  14. package/dist/ast.js.map +1 -0
  15. package/dist/call.d.ts +37 -0
  16. package/dist/call.js +417 -0
  17. package/dist/call.js.map +1 -0
  18. package/dist/client.d.ts +203 -0
  19. package/dist/client.js +457 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/config.d.ts +126 -0
  22. package/dist/config.js +264 -0
  23. package/dist/config.js.map +1 -0
  24. package/dist/credentials.d.ts +55 -0
  25. package/dist/credentials.js +261 -0
  26. package/dist/credentials.js.map +1 -0
  27. package/dist/cucumber.d.ts +64 -0
  28. package/dist/cucumber.js +158 -0
  29. package/dist/cucumber.js.map +1 -0
  30. package/dist/datafile.d.ts +71 -0
  31. package/dist/datafile.js +380 -0
  32. package/dist/datafile.js.map +1 -0
  33. package/dist/db.d.ts +58 -0
  34. package/dist/db.js +179 -0
  35. package/dist/db.js.map +1 -0
  36. package/dist/define.d.ts +205 -0
  37. package/dist/define.js +103 -0
  38. package/dist/define.js.map +1 -0
  39. package/dist/describe.d.ts +141 -0
  40. package/dist/describe.js +135 -0
  41. package/dist/describe.js.map +1 -0
  42. package/dist/drift.d.ts +127 -0
  43. package/dist/drift.js +167 -0
  44. package/dist/drift.js.map +1 -0
  45. package/dist/env.d.ts +49 -0
  46. package/dist/env.js +83 -0
  47. package/dist/env.js.map +1 -0
  48. package/dist/errors.d.ts +88 -0
  49. package/dist/errors.js +148 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/expectations.d.ts +26 -0
  52. package/dist/expectations.js +162 -0
  53. package/dist/expectations.js.map +1 -0
  54. package/dist/fake.d.ts +55 -0
  55. package/dist/fake.js +87 -0
  56. package/dist/fake.js.map +1 -0
  57. package/dist/fill.d.ts +9 -0
  58. package/dist/fill.js +17 -0
  59. package/dist/fill.js.map +1 -0
  60. package/dist/host.d.ts +56 -0
  61. package/dist/host.js +45 -0
  62. package/dist/host.js.map +1 -0
  63. package/dist/index.d.ts +23 -0
  64. package/dist/index.js +29 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/ledger.d.ts +217 -0
  67. package/dist/ledger.js +251 -0
  68. package/dist/ledger.js.map +1 -0
  69. package/dist/lint.d.ts +32 -0
  70. package/dist/lint.js +168 -0
  71. package/dist/lint.js.map +1 -0
  72. package/dist/lockfile.d.ts +36 -0
  73. package/dist/lockfile.js +69 -0
  74. package/dist/lockfile.js.map +1 -0
  75. package/dist/log.d.ts +24 -0
  76. package/dist/log.js +83 -0
  77. package/dist/log.js.map +1 -0
  78. package/dist/op.d.ts +260 -0
  79. package/dist/op.js +188 -0
  80. package/dist/op.js.map +1 -0
  81. package/dist/outline.d.ts +179 -0
  82. package/dist/outline.js +506 -0
  83. package/dist/outline.js.map +1 -0
  84. package/dist/paths.d.ts +11 -0
  85. package/dist/paths.js +30 -0
  86. package/dist/paths.js.map +1 -0
  87. package/dist/plugin.d.ts +28 -0
  88. package/dist/plugin.js +25 -0
  89. package/dist/plugin.js.map +1 -0
  90. package/dist/policy.d.ts +114 -0
  91. package/dist/policy.js +60 -0
  92. package/dist/policy.js.map +1 -0
  93. package/dist/resource.d.ts +378 -0
  94. package/dist/resource.js +430 -0
  95. package/dist/resource.js.map +1 -0
  96. package/dist/resources.d.ts +77 -0
  97. package/dist/resources.js +244 -0
  98. package/dist/resources.js.map +1 -0
  99. package/dist/run.d.ts +101 -0
  100. package/dist/run.js +7 -0
  101. package/dist/run.js.map +1 -0
  102. package/dist/sandbox.d.ts +33 -0
  103. package/dist/sandbox.js +127 -0
  104. package/dist/sandbox.js.map +1 -0
  105. package/dist/scenario.d.ts +221 -0
  106. package/dist/scenario.js +1104 -0
  107. package/dist/scenario.js.map +1 -0
  108. package/dist/scenarios.d.ts +55 -0
  109. package/dist/scenarios.js +71 -0
  110. package/dist/scenarios.js.map +1 -0
  111. package/dist/secret.d.ts +42 -0
  112. package/dist/secret.js +58 -0
  113. package/dist/secret.js.map +1 -0
  114. package/dist/shared.d.ts +69 -0
  115. package/dist/shared.js +84 -0
  116. package/dist/shared.js.map +1 -0
  117. package/dist/source.d.ts +58 -0
  118. package/dist/source.js +54 -0
  119. package/dist/source.js.map +1 -0
  120. package/dist/steps.d.ts +76 -0
  121. package/dist/steps.js +23 -0
  122. package/dist/steps.js.map +1 -0
  123. package/dist/version.d.ts +29 -0
  124. package/dist/version.js +76 -0
  125. package/dist/version.js.map +1 -0
  126. package/dist/worker.d.ts +37 -0
  127. package/dist/worker.js +228 -0
  128. package/dist/worker.js.map +1 -0
  129. package/dist/writer.d.ts +35 -0
  130. package/dist/writer.js +201 -0
  131. package/dist/writer.js.map +1 -0
  132. package/oxlint.json +128 -0
  133. package/package.json +96 -3
  134. package/src/apply-steps.ts +110 -0
  135. package/src/apply.ts +626 -0
  136. package/src/approvals.ts +157 -0
  137. package/src/ast.ts +115 -0
  138. package/src/call.ts +483 -0
  139. package/src/client.ts +604 -0
  140. package/src/config.ts +404 -0
  141. package/src/credentials.ts +296 -0
  142. package/src/cucumber.ts +230 -0
  143. package/src/datafile.ts +481 -0
  144. package/src/db.ts +197 -0
  145. package/src/define.ts +285 -0
  146. package/src/describe.ts +282 -0
  147. package/src/drift.ts +259 -0
  148. package/src/env.ts +122 -0
  149. package/src/errors.ts +202 -0
  150. package/src/expectations.ts +191 -0
  151. package/src/fake.ts +156 -0
  152. package/src/fill.ts +24 -0
  153. package/src/host.ts +96 -0
  154. package/src/index.ts +143 -0
  155. package/src/ledger.ts +419 -0
  156. package/src/lint.ts +208 -0
  157. package/src/lockfile.ts +95 -0
  158. package/src/log.ts +82 -0
  159. package/src/op.ts +402 -0
  160. package/src/outline.ts +620 -0
  161. package/src/paths.ts +32 -0
  162. package/src/plugin.ts +37 -0
  163. package/src/policy.ts +139 -0
  164. package/src/resource.ts +670 -0
  165. package/src/resources.ts +311 -0
  166. package/src/run.ts +106 -0
  167. package/src/sandbox.ts +161 -0
  168. package/src/scenario.ts +1365 -0
  169. package/src/scenarios.ts +111 -0
  170. package/src/secret.ts +92 -0
  171. package/src/shared.ts +126 -0
  172. package/src/source.ts +82 -0
  173. package/src/steps.ts +90 -0
  174. package/src/version.ts +86 -0
  175. package/src/worker.ts +264 -0
  176. package/src/writer.ts +225 -0
@@ -0,0 +1,127 @@
1
+ import { z } from "zod";
2
+ import { type WorkflowDefinition } from "./define.ts";
3
+ import type { Op } from "./op.ts";
4
+ import { type DriftField, type Resource } from "./resource.ts";
5
+ import type { DeclaredResource, ResourceProblem } from "./resources.ts";
6
+ import { type sourceOps } from "./source.ts";
7
+ export type { DriftField } from "./resource.ts";
8
+ export { DRIFT_WORKFLOW } from "./shared.ts";
9
+ /**
10
+ * How a declared resource compares: `clean` when every declared field of its bound object holds
11
+ * its declared value, `drifted` when one does not, `gone` when the vendor no longer has its bound
12
+ * object, `absent` when it is bound to none (whether or not its identity finds one: `found`), and
13
+ * `error` when it could not be read (the vendor's error, a policy denial, or no driver for its type).
14
+ */
15
+ export type DriftStatus = "clean" | "drifted" | "gone" | "absent" | "error";
16
+ /** One declared resource in a drift report. */
17
+ export interface DriftResult {
18
+ /** The resource's id, `<file>#<export>`: `resources/identity/github.ts#website`. */
19
+ id: string;
20
+ /** Its type within the vendor, such as `repository`. */
21
+ type: string;
22
+ vendor: string;
23
+ /** What people call it: its identity, else its export's name. */
24
+ name: string;
25
+ status: DriftStatus;
26
+ /** The vendor's id of the object the lockfile binds it to; absent when unbound. */
27
+ binding?: string;
28
+ /** For `absent`: the binding id of the object its identity found, which apply may bind it to. */
29
+ found?: string;
30
+ /** The declared fields that differ; empty unless `drifted`. */
31
+ fields: DriftField[];
32
+ /** Why it could not be read, for `error`. */
33
+ error?: string;
34
+ }
35
+ /** The drift workflow's output. */
36
+ export interface DriftReport {
37
+ /** Epoch milliseconds, by `ctx.now()`. */
38
+ startedAt: number;
39
+ /** Epoch milliseconds, by `ctx.now()`. */
40
+ finishedAt: number;
41
+ /** What was wrong in the data files when the run read them: their resources are not in `resources`. */
42
+ problems: ResourceProblem[];
43
+ /** Each resource the data files declared when the run read them, in their order. */
44
+ resources: DriftResult[];
45
+ }
46
+ /**
47
+ * The drift workflow's input: nothing. The run reads the data files itself, so a run says what
48
+ * they declared when it ran, and no caller can hand it other resources to check.
49
+ */
50
+ export declare const DriftInput: z.ZodObject<{}, z.core.$strict>;
51
+ /**
52
+ * What a drift run records of the data files, as its first step: each resource without its
53
+ * write-only values, and the problems.
54
+ */
55
+ export interface DriftDeclared {
56
+ resources: Pick<DeclaredResource, "id" | "vendor" | "type" | "name" | "identity" | "binding" | "desired" | "refs">[];
57
+ problems: ResourceProblem[];
58
+ }
59
+ type State = Record<string, unknown>;
60
+ type ImportOp = Op<string, string, "import", {
61
+ id: string;
62
+ }, {
63
+ id: string;
64
+ gone: boolean;
65
+ state?: State;
66
+ }>;
67
+ export type ResolveOp = typeof sourceOps.source.resolve;
68
+ /** What one import found: the object's state, that it is gone, or why it could not be read. */
69
+ export type Found = {
70
+ state: State;
71
+ } | {
72
+ gone: true;
73
+ } | {
74
+ error: string;
75
+ };
76
+ /** What a host's ref names now, or why it could not be resolved. */
77
+ export type Revision = {
78
+ revision: string;
79
+ } | {
80
+ error: string;
81
+ };
82
+ /** The `import` ops of the types among `ops` with a driver, by type, sorted: what observing them uses. */
83
+ export declare function importsOf(types: ReadonlyMap<string, Resource>, ops: ReadonlyMap<string, Op>, drivers: ReadonlyMap<string, unknown>): ImportOp[];
84
+ /**
85
+ * What a declared resource is observed by: the import id (`by`, default its binding, else its
86
+ * identity), or without one what it is found to be: `gone` for none, `error` when its type is
87
+ * not the connectors' or has no import among `imports`.
88
+ */
89
+ export declare function observeBy({ vendor, type, binding, identity }: Pick<DeclaredResource, "vendor" | "type" | "binding" | "identity">, types: ReadonlyMap<string, Resource>, imports: readonly Pick<Op, "id">[], by?: string | undefined): {
90
+ id: string;
91
+ } | Found;
92
+ /** What an import's answer found. */
93
+ export declare const observed: (out: {
94
+ gone: boolean;
95
+ state?: State;
96
+ }) => Found;
97
+ /**
98
+ * Each declared resource against what its import `found`: `error`, `absent` (unbound, with the
99
+ * binding id of what its identity found as `found`), `gone`, else the state and the declared
100
+ * fields compared by `diffDeclared`, a reference against the state of the resource it names
101
+ * (so GitHub's node id for a repository counts as its name). A host with a `revisions` entry
102
+ * also compares its revision against the commit its ref names now (or is that entry's `error`).
103
+ */
104
+ export declare function compare(types: ReadonlyMap<string, Resource>, resources: DriftDeclared["resources"], found: ReadonlyMap<string, Found>, revisions?: ReadonlyMap<string, Revision>): DriftResult[];
105
+ /**
106
+ * The drift workflow for a config: it `uses` the `import` of every resource type the connectors
107
+ * declare (`types`) that has a driver, so its version changes with them, not with the data
108
+ * files. `resolveConfig` adds it to a config whose connectors declare resource types, with
109
+ * `declared`, the step that reads the data files.
110
+ *
111
+ * A run reads the data files and the lockfile (`declared`, recorded as a step, so a replay checks
112
+ * the same list), then imports each resource by its binding, else by its identity, in the files'
113
+ * order: one vendor call each, none for a resource with neither. A bound resource whose import
114
+ * says gone is `gone`; an unbound one is `absent`, with the binding id of what its identity found
115
+ * as `found`. Else the state and the declared fields are compared by `diffDeclared`, a reference
116
+ * against the state of the resource it names, read in the same run (so GitHub's node id for a
117
+ * repository counts as its name). A failed call is that resource's
118
+ * `error`, and the run goes on to the next; a failure that ends the run (`isRunControlError`)
119
+ * ends it.
120
+ */
121
+ export declare function driftWorkflow(types: ReadonlyMap<string, Resource>, ops: ReadonlyMap<string, Op>, drivers: ReadonlyMap<string, unknown>, declared: () => Promise<DriftDeclared>): WorkflowDefinition<readonly (ImportOp | ResolveOp)[], typeof DriftInput>;
122
+ /**
123
+ * A host's source: the clone URL its data file gives, or, when it names a declared repository
124
+ * (`target`), the first of the reference's `by` fields that holds one in that repository's state,
125
+ * read in this run.
126
+ */
127
+ export declare function sourceUrl(desired: State, target: string | undefined, { host, fields }: Resource, found: ReadonlyMap<string, Found>): string | undefined;
package/dist/drift.js ADDED
@@ -0,0 +1,167 @@
1
+ import { z } from "zod";
2
+ import { defineWorkflow } from "./define.js";
3
+ import { isRunControlError } from "./errors.js";
4
+ import { diffDeclared, fieldPathOf, valueAt } from "./resource.js";
5
+ import { errorMessage } from "./shared.js";
6
+ import { SOURCE_RESOLVE } from "./source.js";
7
+ export { DRIFT_WORKFLOW } from "./shared.js";
8
+ /**
9
+ * The drift workflow's input: nothing. The run reads the data files itself, so a run says what
10
+ * they declared when it ran, and no caller can hand it other resources to check.
11
+ */
12
+ export const DriftInput = z.object({}).strict();
13
+ /** A clone URL (a scheme's, or scp-like `user@host:path`): what a `by` field of a host's source holds, told from an id. */
14
+ const CLONE_URL = /^((https?|ssh|git|file):\/\/|[\w.-]+@[\w.-]+:)/;
15
+ // What drift and apply share. Observing a resource is one `ctx` call, which a workflow makes in
16
+ // its own `run` (the outline draws only those): `observeBy` says what each import is called with,
17
+ // `observed` reads its answer, and `compare` turns what every import found into drift's results.
18
+ /** The `import` ops of the types among `ops` with a driver, by type, sorted: what observing them uses. */
19
+ export function importsOf(types, ops, drivers) {
20
+ return [...types.keys()].toSorted().flatMap((type) => {
21
+ const op = ops.get(`${type}.import`);
22
+ return op && drivers.has(op.id) ? [op] : [];
23
+ });
24
+ }
25
+ /**
26
+ * What a declared resource is observed by: the import id (`by`, default its binding, else its
27
+ * identity), or without one what it is found to be: `gone` for none, `error` when its type is
28
+ * not the connectors' or has no import among `imports`.
29
+ */
30
+ export function observeBy({ vendor, type, binding, identity }, types, imports, by = binding ?? identity) {
31
+ const key = `${vendor}.${type}`;
32
+ if (!types.has(key))
33
+ return { error: `the config's connectors declare no resource type ${key}` };
34
+ if (!imports.some((op) => op.id === `${key}.import`))
35
+ return { error: `no driver for ${key}.import` };
36
+ return by === undefined ? { gone: true } : { id: by };
37
+ }
38
+ /** What an import's answer found. */
39
+ export const observed = (out) => out.gone || !out.state ? { gone: true } : { state: out.state };
40
+ /**
41
+ * Each declared resource against what its import `found`: `error`, `absent` (unbound, with the
42
+ * binding id of what its identity found as `found`), `gone`, else the state and the declared
43
+ * fields compared by `diffDeclared`, a reference against the state of the resource it names
44
+ * (so GitHub's node id for a repository counts as its name). A host with a `revisions` entry
45
+ * also compares its revision against the commit its ref names now (or is that entry's `error`).
46
+ */
47
+ export function compare(types, resources, found, revisions = new Map()) {
48
+ return resources.map(({ id, vendor, type, name, binding, desired, refs }) => {
49
+ const row = { id, type, vendor, name, ...(binding !== undefined && { binding }) };
50
+ const now = found.get(id);
51
+ if ("error" in now)
52
+ return { ...row, status: "error", fields: [], error: now.error };
53
+ const resource = types.get(`${vendor}.${type}`);
54
+ if (binding === undefined) {
55
+ return {
56
+ ...row,
57
+ status: "absent",
58
+ fields: [],
59
+ ...("state" in now && { found: resource.bindingId(now.state) }),
60
+ };
61
+ }
62
+ if ("gone" in now)
63
+ return { ...row, status: "gone", fields: [] };
64
+ // Each reference, by where it is: the values the vendor may hold there for its resource.
65
+ const accept = {};
66
+ for (const [at, target] of Object.entries(refs)) {
67
+ const by = resource.fields.references?.[fieldPathOf(at)]?.by ?? [];
68
+ const named = found.get(target);
69
+ if (named && "state" in named)
70
+ accept[at] = by.map((field) => named.state[field]).filter((v) => v != null);
71
+ }
72
+ const fields = diffDeclared(resource, now.state, desired, accept);
73
+ const resolved = revisions.get(id);
74
+ if (resolved && "error" in resolved)
75
+ return { ...row, status: "error", fields: [], error: resolved.error };
76
+ // A host whose state does not say which commit it runs is not compared.
77
+ const actual = resource.host?.outputs(now.state).revision;
78
+ if (resolved && actual !== undefined && actual !== resolved.revision) {
79
+ fields.push({ path: resource.host.revision, desired: resolved.revision, actual });
80
+ }
81
+ return { ...row, status: fields.length ? "drifted" : "clean", fields };
82
+ });
83
+ }
84
+ /**
85
+ * The drift workflow for a config: it `uses` the `import` of every resource type the connectors
86
+ * declare (`types`) that has a driver, so its version changes with them, not with the data
87
+ * files. `resolveConfig` adds it to a config whose connectors declare resource types, with
88
+ * `declared`, the step that reads the data files.
89
+ *
90
+ * A run reads the data files and the lockfile (`declared`, recorded as a step, so a replay checks
91
+ * the same list), then imports each resource by its binding, else by its identity, in the files'
92
+ * order: one vendor call each, none for a resource with neither. A bound resource whose import
93
+ * says gone is `gone`; an unbound one is `absent`, with the binding id of what its identity found
94
+ * as `found`. Else the state and the declared fields are compared by `diffDeclared`, a reference
95
+ * against the state of the resource it names, read in the same run (so GitHub's node id for a
96
+ * repository counts as its name). A failed call is that resource's
97
+ * `error`, and the run goes on to the next; a failure that ends the run (`isRunControlError`)
98
+ * ends it.
99
+ */
100
+ export function driftWorkflow(types, ops, drivers, declared) {
101
+ const imports = importsOf(types, ops, drivers);
102
+ const resolve = ops.get(SOURCE_RESOLVE);
103
+ const uses = [...imports, ...(resolve ? [resolve] : [])];
104
+ return defineWorkflow({
105
+ // The literal, held to the one name: the outline finds a workflow by a string, or a const of its own file.
106
+ name: "drift",
107
+ title: "Check resources for drift",
108
+ trigger: "manual",
109
+ input: DriftInput,
110
+ uses,
111
+ run: async (ctx) => {
112
+ const startedAt = await ctx.now();
113
+ const { resources, problems } = await declared();
114
+ // Every import first, so a reference compares against what its resource holds now.
115
+ const found = new Map();
116
+ for (const resource of resources) {
117
+ const by = observeBy(resource, types, imports);
118
+ // An if/else, not a `continue`: the outline draws the import as the way past the error.
119
+ if (!("id" in by))
120
+ found.set(resource.id, by);
121
+ else {
122
+ try {
123
+ found.set(resource.id, observed(await ctx[resource.vendor][resource.type].import({ id: by.id })));
124
+ }
125
+ catch (err) {
126
+ if (isRunControlError(err))
127
+ throw err;
128
+ found.set(resource.id, { error: errorMessage(err) });
129
+ }
130
+ }
131
+ }
132
+ // A host's revision against the commit its ref names now: a merge is drift on the host.
133
+ const revisions = new Map();
134
+ for (const { id, vendor, type, desired, refs } of resources) {
135
+ const resource = types.get(`${vendor}.${type}`);
136
+ const host = resource?.host;
137
+ const source = host && sourceUrl(desired, refs[host.inputs.source], resource, found);
138
+ const ref = host && valueAt(desired, host.inputs.ref);
139
+ if (host && "state" in found.get(id) && source !== undefined && typeof ref === "string" && ref) {
140
+ try {
141
+ revisions.set(id, await ctx.sanoma.source.resolve({ url: source, ref }));
142
+ }
143
+ catch (err) {
144
+ if (isRunControlError(err))
145
+ throw err;
146
+ revisions.set(id, { error: errorMessage(err) });
147
+ }
148
+ }
149
+ }
150
+ const results = compare(types, resources, found, revisions);
151
+ return { startedAt, finishedAt: await ctx.now(), problems, resources: results };
152
+ },
153
+ });
154
+ }
155
+ /**
156
+ * A host's source: the clone URL its data file gives, or, when it names a declared repository
157
+ * (`target`), the first of the reference's `by` fields that holds one in that repository's state,
158
+ * read in this run.
159
+ */
160
+ export function sourceUrl(desired, target, { host, fields }, found) {
161
+ const path = host.inputs.source;
162
+ const named = target === undefined ? undefined : found.get(target);
163
+ const by = fields.references?.[path]?.by ?? [];
164
+ const values = target === undefined ? [valueAt(desired, path)] : named && "state" in named ? by.map((f) => named.state[f]) : [];
165
+ return values.find((v) => typeof v === "string" && CLONE_URL.test(v));
166
+ }
167
+ //# sourceMappingURL=drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../src/drift.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ import type { Driver, DriverEnv } from "./op.ts";
2
+ /** One environment variable a driver declares in `env`, and whether its value lets the driver run: never the value. */
3
+ export interface CredentialStatus {
4
+ /** The variable's name, such as `GHOST_ADMIN_API_KEY`. */
5
+ name: string;
6
+ /** Its one-line manual, from its schema's `.describe()`. */
7
+ description?: string;
8
+ /** It may be unset. */
9
+ optional: boolean;
10
+ /** `missing` when unset or empty; `invalid` when its schema refuses the value. */
11
+ status: "set" | "missing" | "invalid";
12
+ /** Why it is `invalid`: the schema's first issue, never the value. */
13
+ problem?: string;
14
+ /**
15
+ * Where the value is from, when there is one: the process environment, which wins, or the
16
+ * credentials stored with `SanomaClient.setCredential`. Only `SanomaClient.credentials` says.
17
+ */
18
+ source?: "environment" | "stored";
19
+ /** Who set the stored value (`setCredential`'s `by`). */
20
+ setBy?: string;
21
+ /** When the stored value was set, as an ISO 8601 time. */
22
+ setAt?: string;
23
+ }
24
+ /**
25
+ * Each vendor's driver's `env` (a resolved config's `driversByVendor`), by vendor in the map's
26
+ * order (a vendor whose driver declares none has no entry), each variable in declared order and
27
+ * checked against the value `lookup` gives for its name: only the declared names are looked up,
28
+ * an empty value counts as unset, and a value is never kept. The one walk of the declarations:
29
+ * the worker, the client and its checks all read them through it.
30
+ */
31
+ export declare function credentialsOf(drivers: ReadonlyMap<string, Driver>, lookup: (name: string) => string | undefined): Map<string, CredentialStatus[]>;
32
+ /** One driver's `env`, each variable checked against `lookup`'s value, as `credentialsOf` checks it. */
33
+ export declare function statusesOf(env: DriverEnv, lookup: (name: string) => string | undefined): CredentialStatus[];
34
+ /**
35
+ * Why the vendor's drivers cannot run on `statuses`, as a call to one fails (`startWorker` names
36
+ * the vendor alone, `unconfiguredSummary`): `<vendor> is not configured: <problems>; <hint>`, a
37
+ * missing variable (not optional) as `NAME (description)`, an invalid one as `NAME is invalid:
38
+ * <why>`, never a value. The hint says
39
+ * where to set them: in the environment when an invalid value is there (the environment wins
40
+ * over a stored value, so the connector page cannot replace it), else on the connector page.
41
+ * Undefined when the drivers can run.
42
+ */
43
+ export declare function unconfigured(vendor: string, statuses: readonly CredentialStatus[]): string | undefined;
44
+ /**
45
+ * The one line `startWorker` prints for the vendors whose drivers cannot run yet (`vendors`, those
46
+ * `unconfigured` has a message for) among the config's `total`: their names alone, since a call
47
+ * to one fails with its own message, and its connector page says the same. Undefined for none.
48
+ */
49
+ export declare function unconfiguredSummary(vendors: readonly string[], total: number): string | undefined;
package/dist/env.js ADDED
@@ -0,0 +1,83 @@
1
+ import { credentialReady } from "./shared.js";
2
+ /**
3
+ * Each vendor's driver's `env` (a resolved config's `driversByVendor`), by vendor in the map's
4
+ * order (a vendor whose driver declares none has no entry), each variable in declared order and
5
+ * checked against the value `lookup` gives for its name: only the declared names are looked up,
6
+ * an empty value counts as unset, and a value is never kept. The one walk of the declarations:
7
+ * the worker, the client and its checks all read them through it.
8
+ */
9
+ export function credentialsOf(drivers, lookup) {
10
+ const map = new Map();
11
+ for (const [vendor, { env }] of drivers)
12
+ if (env)
13
+ map.set(vendor, statusesOf(env, lookup));
14
+ return map;
15
+ }
16
+ /** One driver's `env`, each variable checked against `lookup`'s value, as `credentialsOf` checks it. */
17
+ export function statusesOf(env, lookup) {
18
+ return Object.entries(env.shape).map(([name, schema]) => credentialStatus(name, schema, lookup(name) || undefined));
19
+ }
20
+ /**
21
+ * Why the vendor's drivers cannot run on `statuses`, as a call to one fails (`startWorker` names
22
+ * the vendor alone, `unconfiguredSummary`): `<vendor> is not configured: <problems>; <hint>`, a
23
+ * missing variable (not optional) as `NAME (description)`, an invalid one as `NAME is invalid:
24
+ * <why>`, never a value. The hint says
25
+ * where to set them: in the environment when an invalid value is there (the environment wins
26
+ * over a stored value, so the connector page cannot replace it), else on the connector page.
27
+ * Undefined when the drivers can run.
28
+ */
29
+ export function unconfigured(vendor, statuses) {
30
+ const unready = statuses.filter((c) => !credentialReady(c));
31
+ if (!unready.length)
32
+ return undefined;
33
+ const problems = unready.map((c) => c.status === "invalid"
34
+ ? `${c.name} is invalid: ${c.problem}`
35
+ : `${c.name}${c.description ? ` (${c.description})` : ""}`);
36
+ const inEnvironment = unready.some((c) => c.status === "invalid" && process.env[c.name]);
37
+ const hint = inEnvironment ? "set in the environment" : "set it on the connector page";
38
+ return `${vendor} is not configured: ${problems.join(", ")}; ${hint}`;
39
+ }
40
+ /**
41
+ * The one line `startWorker` prints for the vendors whose drivers cannot run yet (`vendors`, those
42
+ * `unconfigured` has a message for) among the config's `total`: their names alone, since a call
43
+ * to one fails with its own message, and its connector page says the same. Undefined for none.
44
+ */
45
+ export function unconfiguredSummary(vendors, total) {
46
+ if (!vendors.length)
47
+ return undefined;
48
+ return (`${vendors.length} of ${total} connectors not configured yet: ${vendors.join(", ")}; ` +
49
+ "set their variables on the connector pages or in the environment");
50
+ }
51
+ function credentialStatus(name, schema, value) {
52
+ const description = descriptionOf(schema);
53
+ const parsed = value === undefined ? undefined : check(schema, value);
54
+ const problem = parsed?.problem;
55
+ return {
56
+ name,
57
+ ...(description !== undefined && { description }),
58
+ optional: check(schema, undefined).success,
59
+ status: !parsed ? "missing" : parsed.success ? "set" : "invalid",
60
+ ...(problem !== undefined && { problem }),
61
+ };
62
+ }
63
+ /**
64
+ * `schema.safeParse(value)`, with its first issue's message as the problem. A check that throws
65
+ * (zod lets a `.refine()` or `.transform()` throw) fails without its error, which may carry the value.
66
+ */
67
+ function check(schema, value) {
68
+ try {
69
+ const { success, error } = schema.safeParse(value);
70
+ return { success, ...(error && { problem: error.issues[0].message }) };
71
+ }
72
+ catch {
73
+ return { success: false, problem: "its check threw" };
74
+ }
75
+ }
76
+ /** A schema's `.describe()`, also through `.optional()`, `.default()` and `.prefault()` in any order. */
77
+ function descriptionOf(schema) {
78
+ let s = schema;
79
+ while (s && !s.description)
80
+ s = "unwrap" in s ? s.unwrap() : undefined;
81
+ return s?.description;
82
+ }
83
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ import type { z } from "zod";
2
+ import type { Principal } from "./define.ts";
3
+ declare const CODES: readonly ["policy_denied", "approval_rejected", "not_approver", "no_pending_approval", "already_decided", "run_not_found", "driver_failed", "invalid_input", "run_ended", "run_running", "call_not_in_outline"];
4
+ /**
5
+ * Why something failed, as a stable string a caller can branch on. Messages are for people
6
+ * and may change; codes are the contract.
7
+ */
8
+ export type ErrorCode = (typeof CODES)[number];
9
+ /**
10
+ * An error with a `code` and plain-JSON `data`, both own enumerable properties, so they survive
11
+ * the trip through DBOS: a run's error is stored serialized and comes back as a new object that
12
+ * is not an instance of this class. Read the code with `errorCode`, never `instanceof`.
13
+ */
14
+ export declare class SanomaError extends Error {
15
+ readonly code: ErrorCode;
16
+ readonly data: Record<string, unknown>;
17
+ constructor(code: ErrorCode, message: string, data?: Record<string, unknown>, options?: ErrorOptions);
18
+ }
19
+ /** The error's code, read from its own `code` property, or undefined when it has none of ours. */
20
+ export declare function errorCode(e: unknown): ErrorCode | undefined;
21
+ /**
22
+ * True when the error says trying again would only repeat it (`retryable: false`), as a
23
+ * `DriverError` for a vendor's final answer or a ledger store for a corrupt file does. Read as
24
+ * a property, never `instanceof`: the error may come from another copy of this package.
25
+ */
26
+ export declare const isFinal: (err: unknown) => boolean;
27
+ /** The error and the ones it was caused by, a few deep. */
28
+ export declare function causes(err: unknown): Error[];
29
+ /**
30
+ * True for a failure that ends the run rather than one call: anything DBOS throws (it cancelled
31
+ * the run, another process took it over, the worker is shutting down, the run is not
32
+ * deterministic) and `run_ended` (a call queued after the run's body ended). Looked for in the
33
+ * error and its causes. A workflow that goes on past a failed call, as `drift` does, rethrows these.
34
+ */
35
+ export declare const isRunControlError: (err: unknown) => boolean;
36
+ /** Thrown into the run when the policy denies an operation call. The run fails with it. */
37
+ export declare class PolicyDeniedError extends SanomaError {
38
+ constructor(op: string, reason: string);
39
+ }
40
+ /** Thrown into the run when an approver rejects. The run fails with it. */
41
+ export declare class RejectedError extends SanomaError {
42
+ /**
43
+ * @param title The approval's title.
44
+ * @param by Who rejected it.
45
+ * @param approvalId The approval's id in the run, such as "approval-2".
46
+ */
47
+ constructor(title: string, by: Principal, note: string | undefined, approvalId: string);
48
+ }
49
+ /**
50
+ * The wrapper, given the original's own `code` and `data` when it has one of our codes, so
51
+ * `errorCode` reads the same through it: a denied call whose ledger write failed too is still
52
+ * `policy_denied`.
53
+ */
54
+ export declare function keepCode<E extends Error>(wrapper: E, original: unknown): E;
55
+ /** A zod issue as the ledger and an API can carry it: no symbols in the path. */
56
+ export interface InputIssue {
57
+ path: (string | number)[];
58
+ message: string;
59
+ code: string;
60
+ }
61
+ /** The value, parsed by the schema, or an `invalid_input` error carrying zod's issues and `data`. */
62
+ export declare function parseOrThrow<T extends z.ZodType>(schema: T, value: unknown, what: string, data?: Record<string, unknown>): z.output<T>;
63
+ /** An `invalid_input` error from zod issues, with the issues in `data` and a one-line message. */
64
+ export declare function invalidInput(what: string, zodIssues: readonly {
65
+ path: PropertyKey[];
66
+ message: string;
67
+ code: string;
68
+ }[], data?: Record<string, unknown>): SanomaError;
69
+ /**
70
+ * What the ledger keeps of an error. `status`, `vendorCode` and `retryable` are a
71
+ * `DriverError`'s account of the vendor's answer; `data` is one of the runtime's errors'. Each is
72
+ * there only when the error has it, and `data`, `status` and `vendorCode` only from those errors.
73
+ */
74
+ export interface ErrorInfo {
75
+ code?: ErrorCode;
76
+ name: string;
77
+ message: string;
78
+ /** The vendor's HTTP status, from a `DriverError`. */
79
+ status?: number;
80
+ /** The vendor's own error code, from a `DriverError`. */
81
+ vendorCode?: string;
82
+ /** Whether trying again could succeed, from a `DriverError` or a ledger store. */
83
+ retryable?: boolean;
84
+ /** A `SanomaError`'s `data`: the operation, the approval, the issues. */
85
+ data?: Record<string, unknown>;
86
+ }
87
+ export declare function errorInfo(err: unknown): ErrorInfo;
88
+ export {};