@sanoma-ai/workflows 0.1.0 → 0.4.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 (184) hide show
  1. package/README.md +186 -76
  2. package/dist/apply-steps.d.ts +6 -0
  3. package/dist/apply-steps.js +93 -0
  4. package/dist/apply-steps.js.map +1 -0
  5. package/dist/apply.d.ts +197 -0
  6. package/dist/apply.js +470 -0
  7. package/dist/apply.js.map +1 -0
  8. package/dist/approvals.d.ts +11 -6
  9. package/dist/approvals.js +38 -10
  10. package/dist/approvals.js.map +1 -1
  11. package/dist/call-workflow.d.ts +16 -0
  12. package/dist/call-workflow.js +35 -0
  13. package/dist/call-workflow.js.map +1 -0
  14. package/dist/call.d.ts +35 -2
  15. package/dist/call.js +123 -43
  16. package/dist/call.js.map +1 -1
  17. package/dist/cedar.d.ts +87 -0
  18. package/dist/cedar.js +365 -0
  19. package/dist/cedar.js.map +1 -0
  20. package/dist/client.d.ts +123 -9
  21. package/dist/client.js +355 -34
  22. package/dist/client.js.map +1 -1
  23. package/dist/collection.d.ts +107 -0
  24. package/dist/collection.js +306 -0
  25. package/dist/collection.js.map +1 -0
  26. package/dist/config.d.ts +42 -14
  27. package/dist/config.js +109 -28
  28. package/dist/config.js.map +1 -1
  29. package/dist/constructors.d.ts +2 -0
  30. package/dist/constructors.js +5 -0
  31. package/dist/constructors.js.map +1 -0
  32. package/dist/credentials.d.ts +25 -0
  33. package/dist/credentials.js +73 -5
  34. package/dist/credentials.js.map +1 -1
  35. package/dist/data.d.ts +2 -0
  36. package/dist/data.js +3 -0
  37. package/dist/data.js.map +1 -0
  38. package/dist/datafile.d.ts +38 -3
  39. package/dist/datafile.js +166 -13
  40. package/dist/datafile.js.map +1 -1
  41. package/dist/db.d.ts +5 -3
  42. package/dist/db.js +88 -21
  43. package/dist/db.js.map +1 -1
  44. package/dist/define.d.ts +10 -4
  45. package/dist/define.js +1 -5
  46. package/dist/define.js.map +1 -1
  47. package/dist/describe.d.ts +54 -8
  48. package/dist/describe.js +84 -11
  49. package/dist/describe.js.map +1 -1
  50. package/dist/direct.d.ts +9 -0
  51. package/dist/direct.js +11 -0
  52. package/dist/direct.js.map +1 -0
  53. package/dist/drift.d.ts +64 -12
  54. package/dist/drift.js +118 -41
  55. package/dist/drift.js.map +1 -1
  56. package/dist/errors.d.ts +16 -1
  57. package/dist/errors.js +30 -1
  58. package/dist/errors.js.map +1 -1
  59. package/dist/expectations.d.ts +4 -4
  60. package/dist/expectations.js +43 -9
  61. package/dist/expectations.js.map +1 -1
  62. package/dist/host.d.ts +56 -0
  63. package/dist/host.js +45 -0
  64. package/dist/host.js.map +1 -0
  65. package/dist/index.d.ts +13 -5
  66. package/dist/index.js +15 -5
  67. package/dist/index.js.map +1 -1
  68. package/dist/ledger.d.ts +12 -1
  69. package/dist/ledger.js +18 -11
  70. package/dist/ledger.js.map +1 -1
  71. package/dist/lint.d.ts +5 -4
  72. package/dist/lint.js +24 -7
  73. package/dist/lint.js.map +1 -1
  74. package/dist/lockfile.d.ts +36 -0
  75. package/dist/lockfile.js +69 -0
  76. package/dist/lockfile.js.map +1 -0
  77. package/dist/op.d.ts +9 -0
  78. package/dist/op.js.map +1 -1
  79. package/dist/outline.d.ts +2 -0
  80. package/dist/outline.js +1 -1
  81. package/dist/outline.js.map +1 -1
  82. package/dist/paths.d.ts +4 -0
  83. package/dist/paths.js +17 -3
  84. package/dist/paths.js.map +1 -1
  85. package/dist/person.d.ts +61 -0
  86. package/dist/person.js +69 -0
  87. package/dist/person.js.map +1 -0
  88. package/dist/plugin.js +1 -1
  89. package/dist/plugin.js.map +1 -1
  90. package/dist/policy.d.ts +51 -55
  91. package/dist/policy.js +14 -36
  92. package/dist/policy.js.map +1 -1
  93. package/dist/resource.d.ts +207 -25
  94. package/dist/resource.js +184 -30
  95. package/dist/resource.js.map +1 -1
  96. package/dist/resources.d.ts +76 -9
  97. package/dist/resources.js +170 -30
  98. package/dist/resources.js.map +1 -1
  99. package/dist/run.d.ts +31 -1
  100. package/dist/run.js +6 -1
  101. package/dist/run.js.map +1 -1
  102. package/dist/sandbox.js +5 -1
  103. package/dist/sandbox.js.map +1 -1
  104. package/dist/scenario.d.ts +25 -9
  105. package/dist/scenario.js +125 -27
  106. package/dist/scenario.js.map +1 -1
  107. package/dist/scenarios.d.ts +10 -6
  108. package/dist/scenarios.js +8 -4
  109. package/dist/scenarios.js.map +1 -1
  110. package/dist/schema.d.ts +32 -0
  111. package/dist/schema.js +225 -0
  112. package/dist/schema.js.map +1 -0
  113. package/dist/sdk.d.ts +34 -0
  114. package/dist/sdk.js +168 -0
  115. package/dist/sdk.js.map +1 -0
  116. package/dist/secret.d.ts +42 -0
  117. package/dist/secret.js +58 -0
  118. package/dist/secret.js.map +1 -0
  119. package/dist/shared.d.ts +188 -4
  120. package/dist/shared.js +165 -5
  121. package/dist/shared.js.map +1 -1
  122. package/dist/sites.d.ts +52 -0
  123. package/dist/sites.js +174 -0
  124. package/dist/sites.js.map +1 -0
  125. package/dist/source.d.ts +58 -0
  126. package/dist/source.js +54 -0
  127. package/dist/source.js.map +1 -0
  128. package/dist/version.d.ts +3 -2
  129. package/dist/version.js +3 -2
  130. package/dist/version.js.map +1 -1
  131. package/dist/worker.d.ts +6 -2
  132. package/dist/worker.js +37 -8
  133. package/dist/worker.js.map +1 -1
  134. package/dist/writer.d.ts +35 -0
  135. package/dist/writer.js +201 -0
  136. package/dist/writer.js.map +1 -0
  137. package/oxlint.json +5 -16
  138. package/package.json +11 -1
  139. package/src/apply-steps.ts +110 -0
  140. package/src/apply.ts +626 -0
  141. package/src/approvals.ts +49 -13
  142. package/src/call-workflow.ts +44 -0
  143. package/src/call.ts +173 -46
  144. package/src/cedar.ts +493 -0
  145. package/src/client.ts +450 -49
  146. package/src/collection.ts +431 -0
  147. package/src/config.ts +168 -48
  148. package/src/constructors.ts +4 -0
  149. package/src/credentials.ts +90 -5
  150. package/src/data.ts +10 -0
  151. package/src/datafile.ts +207 -15
  152. package/src/db.ts +90 -22
  153. package/src/define.ts +11 -9
  154. package/src/describe.ts +146 -23
  155. package/src/direct.ts +15 -0
  156. package/src/drift.ts +155 -45
  157. package/src/errors.ts +36 -1
  158. package/src/expectations.ts +46 -11
  159. package/src/host.ts +96 -0
  160. package/src/index.ts +56 -2
  161. package/src/ledger.ts +35 -17
  162. package/src/lint.ts +29 -12
  163. package/src/lockfile.ts +95 -0
  164. package/src/op.ts +9 -0
  165. package/src/outline.ts +1 -1
  166. package/src/paths.ts +18 -3
  167. package/src/person.ts +75 -0
  168. package/src/plugin.ts +1 -1
  169. package/src/policy.ts +59 -63
  170. package/src/resource.ts +302 -52
  171. package/src/resources.ts +226 -30
  172. package/src/run.ts +33 -1
  173. package/src/sandbox.ts +5 -1
  174. package/src/scenario.ts +175 -43
  175. package/src/scenarios.ts +15 -8
  176. package/src/schema.ts +261 -0
  177. package/src/sdk.ts +211 -0
  178. package/src/secret.ts +92 -0
  179. package/src/shared.ts +279 -6
  180. package/src/sites.ts +220 -0
  181. package/src/source.ts +82 -0
  182. package/src/version.ts +3 -2
  183. package/src/worker.ts +45 -11
  184. package/src/writer.ts +225 -0
package/dist/direct.js ADDED
@@ -0,0 +1,11 @@
1
+ import { isResourceOp } from "./resource.js";
2
+ import { DATA_VENDOR } from "./shared.js";
3
+ /**
4
+ * Whether an operation may be called directly, outside a run (`SanomaClient.call`), as the
5
+ * person: a collection's (`data.<name>.<op>`), or a `read` that is neither the runtime's own
6
+ * (the vendor `sanoma`) nor a resource type's (`isResourceOp`), which only drift and apply call.
7
+ * Anything else (an effect at a vendor) is a workflow's. The one rule: the built-in `call`
8
+ * workflow, the SDK and the app read it, from here or from `OpEntry.direct`, and never derive it.
9
+ */
10
+ export const isDirect = (op, types) => op.vendor === DATA_VENDOR || (op.effect === "read" && op.vendor !== "sanoma" && !isResourceOp(op, types));
11
+ //# sourceMappingURL=direct.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct.js","sourceRoot":"","sources":["../src/direct.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,EAA8C,EAC9C,KAAmC,EAC1B,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,EAAE,CAAC,MAAM,KAAK,MAAM,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC"}
package/dist/drift.d.ts CHANGED
@@ -3,14 +3,16 @@ import { type WorkflowDefinition } from "./define.ts";
3
3
  import type { Op } from "./op.ts";
4
4
  import { type DriftField, type Resource } from "./resource.ts";
5
5
  import type { DeclaredResource, ResourceProblem } from "./resources.ts";
6
+ import { type sourceOps } from "./source.ts";
6
7
  export type { DriftField } from "./resource.ts";
7
8
  export { DRIFT_WORKFLOW } from "./shared.ts";
8
9
  /**
9
- * How a declared resource compares: `clean` when every declared field holds its declared value,
10
- * `drifted` when one does not, `gone` when the vendor has no such object, and `error` when it
11
- * could not be read (the vendor's error, a policy denial, or no driver for its type).
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).
12
14
  */
13
- export type DriftStatus = "clean" | "drifted" | "gone" | "error";
15
+ export type DriftStatus = "clean" | "drifted" | "gone" | "absent" | "error";
14
16
  /** One declared resource in a drift report. */
15
17
  export interface DriftResult {
16
18
  /** The resource's id, `<file>#<export>`: `resources/identity/github.ts#website`. */
@@ -18,9 +20,13 @@ export interface DriftResult {
18
20
  /** Its type within the vendor, such as `repository`. */
19
21
  type: string;
20
22
  vendor: string;
21
- /** Its import id. */
23
+ /** What people call it: its identity, else its export's name. */
22
24
  name: string;
23
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;
24
30
  /** The declared fields that differ; empty unless `drifted`. */
25
31
  fields: DriftField[];
26
32
  /** Why it could not be read, for `error`. */
@@ -47,7 +53,7 @@ export declare const DriftInput: z.ZodObject<{}, z.core.$strict>;
47
53
  * write-only values, and the problems.
48
54
  */
49
55
  export interface DriftDeclared {
50
- resources: Pick<DeclaredResource, "id" | "vendor" | "type" | "name" | "desired" | "refs">[];
56
+ resources: Pick<DeclaredResource, "id" | "vendor" | "type" | "name" | "identity" | "binding" | "desired" | "refs">[];
51
57
  problems: ResourceProblem[];
52
58
  }
53
59
  type State = Record<string, unknown>;
@@ -58,18 +64,64 @@ type ImportOp = Op<string, string, "import", {
58
64
  gone: boolean;
59
65
  state?: State;
60
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[];
61
105
  /**
62
106
  * The drift workflow for a config: it `uses` the `import` of every resource type the connectors
63
107
  * declare (`types`) that has a driver, so its version changes with them, not with the data
64
108
  * files. `resolveConfig` adds it to a config whose connectors declare resource types, with
65
109
  * `declared`, the step that reads the data files.
66
110
  *
67
- * A run reads the data files (`declared`, recorded as a step, so a replay checks the same list),
68
- * then imports each resource by its import id (its `name`), in the files' order: one vendor call
69
- * each. An import that says gone is `gone`. Else the state and the declared fields are compared
70
- * by `diffDeclared`, a reference against the state of the resource it names, read in the same run
71
- * (so GitHub's node id for a repository counts as its name). A failed call is that resource's
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
72
118
  * `error`, and the run goes on to the next; a failure that ends the run (`isRunControlError`)
73
119
  * ends it.
74
120
  */
75
- export declare function driftWorkflow(types: ReadonlyMap<string, Resource>, ops: ReadonlyMap<string, Op>, drivers: ReadonlyMap<string, unknown>, declared: () => Promise<DriftDeclared>): WorkflowDefinition<readonly ImportOp[], typeof DriftInput>;
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 CHANGED
@@ -1,39 +1,106 @@
1
1
  import { z } from "zod";
2
2
  import { defineWorkflow } from "./define.js";
3
3
  import { isRunControlError } from "./errors.js";
4
- import { diffDeclared } from "./resource.js";
4
+ import { diffDeclared, fieldPathOf, valueAt } from "./resource.js";
5
5
  import { errorMessage } from "./shared.js";
6
+ import { SOURCE_RESOLVE } from "./source.js";
6
7
  export { DRIFT_WORKFLOW } from "./shared.js";
7
8
  /**
8
9
  * The drift workflow's input: nothing. The run reads the data files itself, so a run says what
9
10
  * they declared when it ran, and no caller can hand it other resources to check.
10
11
  */
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
+ }
12
84
  /**
13
85
  * The drift workflow for a config: it `uses` the `import` of every resource type the connectors
14
86
  * declare (`types`) that has a driver, so its version changes with them, not with the data
15
87
  * files. `resolveConfig` adds it to a config whose connectors declare resource types, with
16
88
  * `declared`, the step that reads the data files.
17
89
  *
18
- * A run reads the data files (`declared`, recorded as a step, so a replay checks the same list),
19
- * then imports each resource by its import id (its `name`), in the files' order: one vendor call
20
- * each. An import that says gone is `gone`. Else the state and the declared fields are compared
21
- * by `diffDeclared`, a reference against the state of the resource it names, read in the same run
22
- * (so GitHub's node id for a repository counts as its name). A failed call is that resource's
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
23
97
  * `error`, and the run goes on to the next; a failure that ends the run (`isRunControlError`)
24
98
  * ends it.
25
99
  */
26
100
  export function driftWorkflow(types, ops, drivers, declared) {
27
- const uses = [...types.keys()].toSorted().flatMap((type) => {
28
- const op = ops.get(`${type}.import`);
29
- return op && drivers.has(op.id) ? [op] : [];
30
- });
31
- // Why a resource of each type cannot be read, if it cannot.
32
- const unreadable = new Map();
33
- for (const type of types.keys()) {
34
- if (!uses.some((op) => op.id === `${type}.import`))
35
- unreadable.set(type, `no driver for ${type}.import`);
36
- }
101
+ const imports = importsOf(types, ops, drivers);
102
+ const resolve = ops.get(SOURCE_RESOLVE);
103
+ const uses = [...imports, ...(resolve ? [resolve] : [])];
37
104
  return defineWorkflow({
38
105
  // The literal, held to the one name: the outline finds a workflow by a string, or a const of its own file.
39
106
  name: "drift",
@@ -46,45 +113,55 @@ export function driftWorkflow(types, ops, drivers, declared) {
46
113
  const { resources, problems } = await declared();
47
114
  // Every import first, so a reference compares against what its resource holds now.
48
115
  const found = new Map();
49
- for (const { id, vendor, type, name } of resources) {
50
- const key = `${vendor}.${type}`;
51
- const why = types.has(key) ? unreadable.get(key) : `the config's connectors declare no resource type ${key}`;
116
+ for (const resource of resources) {
117
+ const by = observeBy(resource, types, imports);
52
118
  // An if/else, not a `continue`: the outline draws the import as the way past the error.
53
- if (why !== undefined)
54
- found.set(id, { error: why });
119
+ if (!("id" in by))
120
+ found.set(resource.id, by);
55
121
  else {
56
122
  try {
57
- const out = await ctx[vendor][type].import({ id: name });
58
- found.set(id, out.gone || !out.state ? { gone: true } : { state: out.state });
123
+ found.set(resource.id, observed(await ctx[resource.vendor][resource.type].import({ id: by.id })));
59
124
  }
60
125
  catch (err) {
61
126
  if (isRunControlError(err))
62
127
  throw err;
63
- found.set(id, { error: errorMessage(err) });
128
+ found.set(resource.id, { error: errorMessage(err) });
64
129
  }
65
130
  }
66
131
  }
67
- const results = resources.map(({ id, vendor, type, name, desired, refs }) => {
68
- const row = { id, type, vendor, name };
69
- const now = found.get(id);
70
- if ("error" in now)
71
- return { ...row, status: "error", fields: [], error: now.error };
72
- if ("gone" in now)
73
- return { ...row, status: "gone", fields: [] };
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) {
74
135
  const resource = types.get(`${vendor}.${type}`);
75
- // Each reference, by where it is: the values the vendor may hold there for its resource.
76
- const accept = {};
77
- for (const [at, target] of Object.entries(refs)) {
78
- const by = resource.fields.references?.[at.replaceAll(/\.\d+(?=\.|$)/g, "")]?.by ?? [];
79
- const named = found.get(target);
80
- if (named && "state" in named)
81
- accept[at] = by.map((field) => named.state[field]).filter((v) => v != null);
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
+ }
82
148
  }
83
- const fields = diffDeclared(resource, now.state, desired, accept);
84
- return { ...row, status: fields.length ? "drifted" : "clean", fields };
85
- });
149
+ }
150
+ const results = compare(types, resources, found, revisions);
86
151
  return { startedAt, finishedAt: await ctx.now(), problems, resources: results };
87
152
  },
88
153
  });
89
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
+ }
90
167
  //# sourceMappingURL=drift.js.map
package/dist/drift.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"drift.js","sourceRoot":"","sources":["../src/drift.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAA2B,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAmB,YAAY,EAAiB,MAAM,eAAe,CAAC;AAE7E,OAAO,EAAuB,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAyC7C;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAmBhD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAoC,EACpC,GAA4B,EAC5B,OAAqC,EACrC,QAAsC;IAEtC,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACzD,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC;QACrC,OAAO,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;IACH,4DAA4D;IAC5D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,GAAG,IAAI,SAAS,CAAC;YAAE,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,iBAAiB,IAAI,SAAS,CAAC,CAAC;IAC3G,CAAC;IACD,OAAO,cAAc,CAAC;QACpB,2GAA2G;QAC3G,IAAI,EAAE,OAAuC;QAC7C,KAAK,EAAE,2BAA2B;QAClC,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,UAAU;QACjB,IAAI;QACJ,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACjB,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;YAClC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ,EAAE,CAAC;YACjD,mFAAmF;YACnF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiB,CAAC;YACvC,KAAK,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,SAAS,EAAE,CAAC;gBACnD,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,oDAAoD,GAAG,EAAE,CAAC;gBAC7G,wFAAwF;gBACxF,IAAI,GAAG,KAAK,SAAS;oBAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;qBAChD,CAAC;oBACJ,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAE,CAAC,IAAI,CAAE,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;wBAC3D,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;oBAChF,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,IAAI,iBAAiB,CAAC,GAAG,CAAC;4BAAE,MAAM,GAAG,CAAC;wBACtC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC9C,CAAC;gBACH,CAAC;YACH,CAAC;YACD,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAe,EAAE;gBACvF,MAAM,GAAG,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;gBACvC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;gBAC3B,IAAI,OAAO,IAAI,GAAG;oBAAE,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;gBACrF,IAAI,MAAM,IAAI,GAAG;oBAAE,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;gBACjE,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,IAAI,EAAE,CAAE,CAAC;gBACjD,yFAAyF;gBACzF,MAAM,MAAM,GAA8B,EAAE,CAAC;gBAC7C,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBAChD,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;oBACvF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBAChC,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK;wBAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;gBAC7G,CAAC;gBACD,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;gBAClE,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;YACzE,CAAC,CAAC,CAAC;YACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAwB,CAAC;QACxG,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../src/drift.ts"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { z } from "zod";
2
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"];
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", "approval_pending", "not_admitted"];
4
4
  /**
5
5
  * Why something failed, as a stable string a caller can branch on. Messages are for people
6
6
  * and may change; codes are the contract.
@@ -37,6 +37,21 @@ export declare const isRunControlError: (err: unknown) => boolean;
37
37
  export declare class PolicyDeniedError extends SanomaError {
38
38
  constructor(op: string, reason: string);
39
39
  }
40
+ /**
41
+ * Thrown by a direct call (`SanomaClient.call`) the policy holds for an approval: the call is now
42
+ * run `runId` of the built-in `call` workflow, which makes it once approved.
43
+ */
44
+ export declare class ApprovalPendingError extends SanomaError {
45
+ constructor(op: string, runId: string);
46
+ }
47
+ /**
48
+ * Thrown when the data files declare people (`sanoma.person`, in `resources/people.ts` by
49
+ * convention) and not this principal's id: nothing is started, called or decided.
50
+ */
51
+ export declare class NotAdmittedError extends SanomaError {
52
+ /** `problems`: what is wrong in the people's files, while nobody is admitted. */
53
+ constructor(id: string, problems?: readonly string[]);
54
+ }
40
55
  /** Thrown into the run when an approver rejects. The run fails with it. */
41
56
  export declare class RejectedError extends SanomaError {
42
57
  /**
package/dist/errors.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Error as DBOSErrors } from "@dbos-inc/dbos-sdk";
2
- import { errorMessage } from "./shared.js";
2
+ import { CALL_WORKFLOW, errorMessage } from "./shared.js";
3
3
  const CODES = [
4
4
  "policy_denied",
5
5
  "approval_rejected",
@@ -12,6 +12,8 @@ const CODES = [
12
12
  "run_ended",
13
13
  "run_running",
14
14
  "call_not_in_outline",
15
+ "approval_pending",
16
+ "not_admitted",
15
17
  ];
16
18
  const KNOWN = new Set(CODES);
17
19
  /**
@@ -61,6 +63,33 @@ export class PolicyDeniedError extends SanomaError {
61
63
  this.name = "PolicyDeniedError";
62
64
  }
63
65
  }
66
+ /**
67
+ * Thrown by a direct call (`SanomaClient.call`) the policy holds for an approval: the call is now
68
+ * run `runId` of the built-in `call` workflow, which makes it once approved.
69
+ */
70
+ export class ApprovalPendingError extends SanomaError {
71
+ constructor(op, runId) {
72
+ super("approval_pending", `${op} needs an approval: it waits in run ${runId}`, {
73
+ runId,
74
+ workflow: CALL_WORKFLOW,
75
+ op,
76
+ });
77
+ this.name = "ApprovalPendingError";
78
+ }
79
+ }
80
+ /**
81
+ * Thrown when the data files declare people (`sanoma.person`, in `resources/people.ts` by
82
+ * convention) and not this principal's id: nothing is started, called or decided.
83
+ */
84
+ export class NotAdmittedError extends SanomaError {
85
+ /** `problems`: what is wrong in the people's files, while nobody is admitted. */
86
+ constructor(id, problems = []) {
87
+ super("not_admitted", problems.length
88
+ ? `${id} cannot be admitted while the people's files have problems: ${problems.join("; ")}`
89
+ : `${id} is not declared in resources/people.ts`, { principal: id, ...(problems.length && { problems }) });
90
+ this.name = "NotAdmittedError";
91
+ }
92
+ }
64
93
  /** Thrown into the run when an approver rejects. The run fails with it. */
65
94
  export class RejectedError extends SanomaError {
66
95
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGzD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,KAAK,GAAG;IACZ,eAAe;IACf,mBAAmB;IACnB,cAAc;IACd,qBAAqB;IACrB,iBAAiB;IACjB,eAAe;IACf,eAAe;IACf,eAAe;IACf,WAAW;IACX,aAAa;IACb,qBAAqB;IACrB,kBAAkB;IAClB,cAAc;CACN,CAAC;AAQX,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,KAAK,CAAC,CAAC;AAErC;;;;GAIG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,IAAI,CAAY;IAChB,IAAI,CAA0B;IAEvC,YAAY,IAAe,EAAE,OAAe,EAAE,IAAI,GAA4B,EAAE,EAAE,OAAsB;QACtG,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,kGAAkG;AAClG,MAAM,UAAU,SAAS,CAAC,CAAU;IAClC,MAAM,IAAI,GAAG,GAAG,CAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9C,OAAO,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAkB,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAY,EAAW,EAAE,CAAE,GAAsC,EAAE,SAAS,KAAK,KAAK,CAAC;AAE/G,2DAA2D;AAC3D,MAAM,UAAU,MAAM,CAAC,GAAY;IACjC,MAAM,GAAG,GAAY,EAAE,CAAC;IACxB,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,YAAY,KAAK,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjF,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAY,EAAW,EAAE,CACzD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,UAAU,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC;AAE7F,2FAA2F;AAC3F,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAChD,YAAY,EAAU,EAAE,MAAc;QACpC,KAAK,CAAC,eAAe,EAAE,GAAG,EAAE,0BAA0B,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAChF,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,WAAW;IACnD,YAAY,EAAU,EAAE,KAAa;QACnC,KAAK,CAAC,kBAAkB,EAAE,GAAG,EAAE,uCAAuC,KAAK,EAAE,EAAE;YAC7E,KAAK;YACL,QAAQ,EAAE,aAAa;YACvB,EAAE;SACH,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,gBAAiB,SAAQ,WAAW;IAC/C,iFAAiF;IACjF,YAAY,EAAU,EAAE,QAAQ,GAAsB,EAAE;QACtD,KAAK,CACH,cAAc,EACd,QAAQ,CAAC,MAAM;YACb,CAAC,CAAC,GAAG,EAAE,+DAA+D,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC3F,CAAC,CAAC,GAAG,EAAE,yCAAyC,EAClD,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CACxD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,2EAA2E;AAC3E,MAAM,OAAO,aAAc,SAAQ,WAAW;IAC5C;;;;OAIG;IACH,YAAY,KAAa,EAAE,EAAa,EAAE,IAAwB,EAAE,UAAkB;QACpF,KAAK,CAAC,mBAAmB,EAAE,IAAI,KAAK,qBAAqB,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;YAC1F,KAAK;YACL,EAAE;YACF,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;YACvC,UAAU;SACX,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAkB,OAAU,EAAE,QAAiB;IACrE,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IACvC,MAAM,IAAI,GAAG,GAAG,CAA0B,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtE,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9E,CAAC;AASD,qGAAqG;AACrG,MAAM,UAAU,YAAY,CAC1B,MAAS,EACT,KAAc,EACd,IAAY,EACZ,IAA8B;IAE9B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC;IACvC,MAAM,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACtD,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,SAA4E,EAC5E,IAAI,GAA4B,EAAE;IAElC,MAAM,MAAM,GAAiB,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAwB,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACrE,OAAO;QACP,IAAI;KACL,CAAC,CAAC,CAAC;IACJ,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7G,OAAO,IAAI,WAAW,CAAC,eAAe,EAAE,GAAG,IAAI,KAAK,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AACnF,CAAC;AAqBD,oHAAoH;AACpH,SAAS,GAAG,CAAI,GAAY,EAAE,GAAW,EAAE,IAAgD;IACzF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1F,MAAM,KAAK,GAAI,GAA+B,CAAC,GAAG,CAAC,CAAC;IACpD,OAAO,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAE,KAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,KAAK,eAAe,CAAC;AAC7E,MAAM,WAAW,GAAG,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC;AACxE,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,IAAI,GAAG;IACX,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC;IAChC,CAAC,YAAY,EAAE,QAAQ,EAAE,UAAU,CAAC;IACpC,CAAC,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC;IACjC,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC;CACvB,CAAC;AAEX,MAAM,UAAU,SAAS,CAAC,GAAY;IACpC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAc;QACtB,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,IAAI,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;QAC/C,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC;KAC3B,CAAC;IACF,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5D,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IACvE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -16,10 +16,10 @@ type Unstepped<T> = T extends unknown ? Omit<T, "step"> : never;
16
16
  * Why an expectation of the generic steps does not hold against a run's ledger records, or
17
17
  * undefined when it does. A call is an `op.called` record without an `error`; one with an error
18
18
  * (a policy denial, a rejected approval, a vendor's final failure) was attempted, not made. An
19
- * operation `was denied` when the policy's decision on some call to it is `deny`, and `was held
20
- * for` an approver when an approval for that approver holds it: one the policy asked for on its
21
- * call, or one that `covers` it. A drift expectation reads the report a finished drift run
22
- * returned. A step named in the workflow's outline is read by the `name` its records carry
19
+ * operation `was denied` when the policy's decision on some call to it is `deny` (for the `reason`
20
+ * expected, when there is one), and `was held for` an approver (a group alone, as `{ group }`) when
21
+ * an approval for that approver holds it: one the policy asked for on its call, or one that `covers` it. A drift or apply expectation reads the report a finished run
22
+ * of it returned. A step named in the workflow's outline is read by the `name` its records carry
23
23
  * (its calls made, and `waitsOf`); a record written before steps had names has none.
24
24
  */
25
25
  export declare function detailOf(e: CoreExpectation, records: readonly LedgerRecord[]): string | undefined;
@@ -54,8 +54,12 @@ const inputs = (list) => list.map((r) => JSON.stringify(r.input)).join(", ");
54
54
  const words = (d) => d.kind === "allow" ? "allowed" : d.kind === "deny" ? "denied" : `held for ${approverLabel(d.approver)}`;
55
55
  /** What the policy decided for the calls, each decision once: `allowed and held for finance`. */
56
56
  const decisions = (calls) => [...new Set(calls.map((r) => words(r.decision)))].join(" and ");
57
- /** True when `who` names the approver: a person by id, or a group by its name. */
58
- const isApprover = (approver, who) => typeof approver === "string" ? approver === who : approver.group === who;
57
+ /** True when `who` names the approver: a person by id, or a group by its name; `{ group }` the group alone. */
58
+ const isApprover = (approver, who) => typeof who !== "string"
59
+ ? typeof approver !== "string" && approver.group === who.group
60
+ : typeof approver === "string"
61
+ ? approver === who
62
+ : approver.group === who;
59
63
  /** How a drift report found a resource, as words: `clean`, `gone`, `drifted in has_wiki, topics`. */
60
64
  const found = (r) => r.status === "drifted" ? `drifted in ${r.fields.map((f) => f.path).join(", ")}` : r.status;
61
65
  /**
@@ -77,14 +81,37 @@ function driftDetail(e, end) {
77
81
  return undefined;
78
82
  return `${e.declared} is ${found(resource)}, not ${e.status === "drifted" ? `drifted in ${e.field}` : e.status}`;
79
83
  }
84
+ /**
85
+ * Why an apply expectation fails against the report a finished apply run returned as its output:
86
+ * the resource `created` (a step that created it, done), or `bound` to an object in the lockfile it ended with.
87
+ */
88
+ function applyDetail(e, end) {
89
+ const report = end.output;
90
+ if (!Array.isArray(report?.results) || !report.lockfile)
91
+ return "the run's output is not an apply report";
92
+ if ("bound" in e) {
93
+ const binding = report.lockfile.bindings[e.declared];
94
+ if (binding?.id === e.bound)
95
+ return undefined;
96
+ return binding ? `${e.declared} is bound to ${binding.id}, not ${e.bound}` : `${e.declared} is not bound`;
97
+ }
98
+ const result = report.results.find((r) => r.id === e.declared);
99
+ // A gone object recreated is bound again; one forgotten is not.
100
+ const created = result?.status === "done" && (result.action === "create" || (result.action === "gone" && !!result.binding));
101
+ if (created)
102
+ return undefined;
103
+ if (!result)
104
+ return `apply did nothing with ${e.declared}`;
105
+ return `apply's ${result.action} of ${e.declared} ${result.status === "failed" ? `failed: ${result.error}` : `was ${result.status}`}`;
106
+ }
80
107
  /**
81
108
  * Why an expectation of the generic steps does not hold against a run's ledger records, or
82
109
  * undefined when it does. A call is an `op.called` record without an `error`; one with an error
83
110
  * (a policy denial, a rejected approval, a vendor's final failure) was attempted, not made. An
84
- * operation `was denied` when the policy's decision on some call to it is `deny`, and `was held
85
- * for` an approver when an approval for that approver holds it: one the policy asked for on its
86
- * call, or one that `covers` it. A drift expectation reads the report a finished drift run
87
- * returned. A step named in the workflow's outline is read by the `name` its records carry
111
+ * operation `was denied` when the policy's decision on some call to it is `deny` (for the `reason`
112
+ * expected, when there is one), and `was held for` an approver (a group alone, as `{ group }`) when
113
+ * an approval for that approver holds it: one the policy asked for on its call, or one that `covers` it. A drift or apply expectation reads the report a finished run
114
+ * of it returned. A step named in the workflow's outline is read by the `name` its records carry
88
115
  * (its calls made, and `waitsOf`); a record written before steps had names has none.
89
116
  */
90
117
  export function detailOf(e, records) {
@@ -96,15 +123,20 @@ export function detailOf(e, records) {
96
123
  if ("decision" in e) {
97
124
  const tries = callsTo(e.op);
98
125
  if (e.decision === "denied") {
99
- if (tries.some((r) => r.decision.kind === "deny"))
126
+ const denials = tries.flatMap(({ decision: d }) => (d.kind === "deny" ? [d.reason] : []));
127
+ if (denials.some((reason) => e.reason === undefined || reason === e.reason))
100
128
  return undefined;
129
+ if (denials.length) {
130
+ const said = [...new Set(denials)].map((reason) => JSON.stringify(reason)).join(" and ");
131
+ return `${e.op} was denied with ${said}, not ${JSON.stringify(e.reason)}`;
132
+ }
101
133
  return tries.length ? `${e.op} was ${decisions(tries)}, not denied` : `no call to ${e.op}`;
102
134
  }
103
135
  const holds = records.filter(isRequest).filter((r) => r.op === e.op || r.covers.includes(e.op));
104
136
  if (holds.some((r) => isApprover(r.approver, e.approver)))
105
137
  return undefined;
106
138
  return holds.length
107
- ? `${e.op} was held for ${[...new Set(holds.map((r) => approverLabel(r.approver)))].join(" and ")}, not ${e.approver}`
139
+ ? `${e.op} was held for ${[...new Set(holds.map((r) => approverLabel(r.approver)))].join(" and ")}, not ${approverLabel(e.approver)}`
108
140
  : tries.length
109
141
  ? `${e.op} was ${decisions(tries)}, not held`
110
142
  : `no call to ${e.op}`;
@@ -132,6 +164,8 @@ export function detailOf(e, records) {
132
164
  // A finished run: what `the run succeeds` expects, and what a drift expectation reads its report from.
133
165
  if (end.type === "run.failed")
134
166
  return `the run failed: ${end.error.message}`;
135
- return "declared" in e ? driftDetail(e, end) : undefined;
167
+ if (!("declared" in e))
168
+ return undefined;
169
+ return "status" in e ? driftDetail(e, end) : applyDetail(e, end);
136
170
  }
137
171
  //# sourceMappingURL=expectations.js.map