@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
@@ -0,0 +1,127 @@
1
+ import { readSource } from "./ast.js";
2
+ import { resolveConfig } from "./config.js";
3
+ import { jsonSchemaOf, opIdsOf } from "./define.js";
4
+ import { DRIFT_WORKFLOW } from "./drift.js";
5
+ import { lintWorkflow } from "./lint.js";
6
+ import { VENDOR } from "./op.js";
7
+ import { outlineWithSource } from "./outline.js";
8
+ import { allowAll, policyOpOf } from "./policy.js";
9
+ import { resourceTypesOf } from "./resource.js";
10
+ import { readDataFiles } from "./resources.js";
11
+ // `@sanoma-ai/workflows/describe`: what a UI renders from, apart from the main entry.
12
+ export { outlineWorkflow } from "./outline.js";
13
+ export { readDataFiles, readResources, } from "./resources.js";
14
+ /**
15
+ * Describes a config. Throws what `startWorker` would refuse (see `resolveConfig`), except missing
16
+ * credentials (`SanomaClient.credentials` gives their statuses) and what is wrong in a workflow's
17
+ * file, which the worker refuses when it reads the outline: that is data, on each workflow's
18
+ * entry, as the data files' problems are, `problems`, beside the resources read without any.
19
+ * Each workflow's file is read and parsed once, however many workflows it defines.
20
+ */
21
+ export function describeConfig(config) {
22
+ const resolved = resolveConfig(config);
23
+ const vendors = {};
24
+ // A vendor whose operations are split over several connectors is named by the first; its
25
+ // resource types are every connector's.
26
+ for (const connector of config.connectors) {
27
+ const { id, info } = connector[VENDOR];
28
+ vendors[id] ??= vendorEntry(id, info, resolved.fakes.has(id));
29
+ }
30
+ const resources = resourceTypesOf(config.connectors);
31
+ // Each resource type's state is described once, on its entry, and referenced from its operations.
32
+ const refs = new Map([...resources].map(([id, r]) => [r.schema, resourceTypeUri(id)]));
33
+ const resourceTypes = [...resources]
34
+ .map(([id, { vendor, type, title, identity, fields, schema }]) => ({
35
+ id,
36
+ vendor,
37
+ type,
38
+ title,
39
+ identity,
40
+ fields,
41
+ schema: { $id: resourceTypeUri(id), ...toJsonSchema(schema, `${id} state`, "output") },
42
+ ops: [`${id}.import`, `${id}.read`],
43
+ }))
44
+ .toSorted((a, b) => a.id.localeCompare(b.id));
45
+ const ops = [...resolved.ops.values()].map((op) => ({
46
+ ...policyOpOf(op),
47
+ idempotent: op.idempotent,
48
+ description: op.description,
49
+ ...(op.phrases && { phrases: op.phrases }),
50
+ input: toJsonSchema(op.input, `${op.id} input`, "input", refs),
51
+ output: toJsonSchema(op.output, `${op.id} output`, "output", refs),
52
+ }));
53
+ ops.sort((a, b) => a.id.localeCompare(b.id));
54
+ const read = memoised(readSource);
55
+ const lint = memoised((file) => lintWorkflow(file));
56
+ const workflows = [...resolved.workflows.values()].map((wf) => {
57
+ const file = read(wf.file);
58
+ const { outline, source, found } = outlineWithSource(wf, file);
59
+ // What the lint does not report: the file unread, or no workflow of this name in it.
60
+ const own = "error" in outline && !found && (typeof file === "string" || !file.problems.length);
61
+ const problems = wf.name === DRIFT_WORKFLOW
62
+ ? []
63
+ : [
64
+ ...(typeof file === "string" ? [] : lint(file)),
65
+ ...(own ? [{ line: 1, column: 1, message: outline.error }] : []),
66
+ ];
67
+ return {
68
+ name: wf.name,
69
+ title: wf.title,
70
+ trigger: wf.trigger,
71
+ ...(wf.name === DRIFT_WORKFLOW && { builtin: true }),
72
+ input: toJsonSchema(wf.input, `${wf.name} input`, "input"),
73
+ ops: opIdsOf(wf),
74
+ builtins: wf.uses.filter((u) => typeof u === "string"),
75
+ file: wf.file,
76
+ outline,
77
+ problems,
78
+ ...(source === undefined ? {} : { source }),
79
+ };
80
+ });
81
+ workflows.sort((a, b) => a.name.localeCompare(b.name));
82
+ const dataFiles = readDataFiles(resolved.root, config.connectors, resources);
83
+ return {
84
+ appName: resolved.appName,
85
+ version: resolved.version,
86
+ workflows,
87
+ ops,
88
+ vendors,
89
+ resourceTypes,
90
+ resources: dataFiles.resources,
91
+ problems: dataFiles.problems,
92
+ policy: {
93
+ defined: resolved.policy !== allowAll,
94
+ ...(resolved.policy.version === undefined ? {} : { version: resolved.policy.version }),
95
+ },
96
+ };
97
+ }
98
+ /** `fn`, called once per argument for as long as the returned function lives. */
99
+ function memoised(fn) {
100
+ const seen = new Map();
101
+ return (arg) => {
102
+ if (!seen.has(arg))
103
+ seen.set(arg, fn(arg));
104
+ return seen.get(arg);
105
+ };
106
+ }
107
+ const svgDataUrl = (svg) => `data:image/svg+xml,${encodeURIComponent(svg.trim())}`;
108
+ const vendorEntry = (id, info, fake) => ({
109
+ title: info?.title ?? id,
110
+ ...(info?.logo && {
111
+ logo: { src: svgDataUrl(info.logo.svg), ...(info.logo.dark && { dark: svgDataUrl(info.logo.dark) }) },
112
+ }),
113
+ ...(info?.package && { package: info.package }),
114
+ ...(info?.homepage && { homepage: info.homepage }),
115
+ fake,
116
+ });
117
+ /** Where a resource type's state schema is, for a `$ref`. */
118
+ const resourceTypeUri = (id) => `sanoma:resource-type/${id}`;
119
+ function toJsonSchema(schema, what, io, refs) {
120
+ try {
121
+ return jsonSchemaOf(schema, io, refs);
122
+ }
123
+ catch (e) {
124
+ throw new Error(`Cannot describe ${what} as JSON Schema: ${e.message}`, { cause: e });
125
+ }
126
+ }
127
+ //# sourceMappingURL=describe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe.js","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,UAAU,EAAmB,MAAM,UAAU,CAAC;AACzE,OAAO,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAgB,YAAY,EAAE,OAAO,EAAY,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAe,MAAM,EAAmB,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAgB,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAuB,eAAe,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAyB,aAAa,EAAwB,MAAM,gBAAgB,CAAC;AAE5F,sFAAsF;AACtF,OAAO,EAAE,eAAe,EAA6C,MAAM,cAAc,CAAC;AAG1F,OAAO,EACL,aAAa,EACb,aAAa,GAId,MAAM,gBAAgB,CAAC;AAmHxB;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,OAAO,GAAgC,EAAE,CAAC;IAChD,yFAAyF;IACzF,wCAAwC;IACxC,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAC1C,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,OAAO,CAAC,EAAE,CAAC,KAAK,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACrD,kGAAkG;IAClG,MAAM,IAAI,GAAG,IAAI,GAAG,CAAoB,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1G,MAAM,aAAa,GAAwB,CAAC,GAAG,SAAS,CAAC;SACtD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACjE,EAAE;QACF,MAAM;QACN,IAAI;QACJ,KAAK;QACL,QAAQ;QACR,MAAM;QACN,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,CAAC,EAAE,CAAC,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE;QACtF,GAAG,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC;KACpC,CAAC,CAAC;SACF,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAc,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7D,GAAG,UAAU,CAAC,EAAE,CAAC;QACjB,UAAU,EAAE,EAAE,CAAC,UAAU;QACzB,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,GAAG,CAAC,EAAE,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC;QAC1C,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;QAC9D,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC;KACnE,CAAC,CAAC,CAAC;IACJ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,IAAgB,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,MAAM,SAAS,GAAoB,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;QAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/D,qFAAqF;QACrF,MAAM,GAAG,GAAG,OAAO,IAAI,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChG,MAAM,QAAQ,GACZ,EAAE,CAAC,IAAI,KAAK,cAAc;YACxB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC;gBACE,GAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/C,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aACjE,CAAC;QACR,OAAO;YACL,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,OAAO,EAAE,EAAE,CAAC,OAAO;YACnB,GAAG,CAAC,EAAE,CAAC,IAAI,KAAK,cAAc,IAAI,EAAE,OAAO,EAAE,IAAa,EAAE,CAAC;YAC7D,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,QAAQ,EAAE,OAAO,CAAC;YAC1D,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;YAChB,QAAQ,EAAG,EAAE,CAAC,IAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAgB,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YAC/E,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,OAAO;YACP,QAAQ;YACR,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;SAC5C,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAE7E,OAAO;QACL,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,SAAS;QACT,GAAG;QACH,OAAO;QACP,aAAa;QACb,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,MAAM,EAAE;YACN,OAAO,EAAE,QAAQ,CAAC,MAAM,KAAK,QAAQ;YACrC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;SACvF;KACF,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,SAAS,QAAQ,CAAO,EAAiB;IACvC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAQ,CAAC;IAC7B,OAAO,CAAC,GAAG,EAAE,EAAE;QACb,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;IACxB,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,sBAAsB,kBAAkB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;AAE3F,MAAM,WAAW,GAAG,CAAC,EAAU,EAAE,IAA4B,EAAE,IAAa,EAAe,EAAE,CAAC,CAAC;IAC7F,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;IACxB,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI;QAChB,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;KACtG,CAAC;IACF,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IAC/C,GAAG,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClD,IAAI;CACL,CAAC,CAAC;AAEH,6DAA6D;AAC7D,MAAM,eAAe,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,wBAAwB,EAAE,EAAE,CAAC;AAErE,SAAS,YAAY,CACnB,MAAiB,EACjB,IAAY,EACZ,EAAsB,EACtB,IAAmC;IAEnC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,oBAAqB,CAAW,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACnG,CAAC;AACH,CAAC"}
@@ -0,0 +1,75 @@
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
+ export type { DriftField } from "./resource.ts";
7
+ export { DRIFT_WORKFLOW } from "./shared.ts";
8
+ /**
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).
12
+ */
13
+ export type DriftStatus = "clean" | "drifted" | "gone" | "error";
14
+ /** One declared resource in a drift report. */
15
+ export interface DriftResult {
16
+ /** The resource's id, `<file>#<export>`: `resources/identity/github.ts#website`. */
17
+ id: string;
18
+ /** Its type within the vendor, such as `repository`. */
19
+ type: string;
20
+ vendor: string;
21
+ /** Its import id. */
22
+ name: string;
23
+ status: DriftStatus;
24
+ /** The declared fields that differ; empty unless `drifted`. */
25
+ fields: DriftField[];
26
+ /** Why it could not be read, for `error`. */
27
+ error?: string;
28
+ }
29
+ /** The drift workflow's output. */
30
+ export interface DriftReport {
31
+ /** Epoch milliseconds, by `ctx.now()`. */
32
+ startedAt: number;
33
+ /** Epoch milliseconds, by `ctx.now()`. */
34
+ finishedAt: number;
35
+ /** What was wrong in the data files when the run read them: their resources are not in `resources`. */
36
+ problems: ResourceProblem[];
37
+ /** Each resource the data files declared when the run read them, in their order. */
38
+ resources: DriftResult[];
39
+ }
40
+ /**
41
+ * The drift workflow's input: nothing. The run reads the data files itself, so a run says what
42
+ * they declared when it ran, and no caller can hand it other resources to check.
43
+ */
44
+ export declare const DriftInput: z.ZodObject<{}, z.core.$strict>;
45
+ /**
46
+ * What a drift run records of the data files, as its first step: each resource without its
47
+ * write-only values, and the problems.
48
+ */
49
+ export interface DriftDeclared {
50
+ resources: Pick<DeclaredResource, "id" | "vendor" | "type" | "name" | "desired" | "refs">[];
51
+ problems: ResourceProblem[];
52
+ }
53
+ type State = Record<string, unknown>;
54
+ type ImportOp = Op<string, string, "import", {
55
+ id: string;
56
+ }, {
57
+ id: string;
58
+ gone: boolean;
59
+ state?: State;
60
+ }>;
61
+ /**
62
+ * The drift workflow for a config: it `uses` the `import` of every resource type the connectors
63
+ * declare (`types`) that has a driver, so its version changes with them, not with the data
64
+ * files. `resolveConfig` adds it to a config whose connectors declare resource types, with
65
+ * `declared`, the step that reads the data files.
66
+ *
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
72
+ * `error`, and the run goes on to the next; a failure that ends the run (`isRunControlError`)
73
+ * ends it.
74
+ */
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>;
package/dist/drift.js ADDED
@@ -0,0 +1,90 @@
1
+ import { z } from "zod";
2
+ import { defineWorkflow } from "./define.js";
3
+ import { isRunControlError } from "./errors.js";
4
+ import { diffDeclared } from "./resource.js";
5
+ import { errorMessage } from "./shared.js";
6
+ export { DRIFT_WORKFLOW } from "./shared.js";
7
+ /**
8
+ * The drift workflow's input: nothing. The run reads the data files itself, so a run says what
9
+ * they declared when it ran, and no caller can hand it other resources to check.
10
+ */
11
+ export const DriftInput = z.object({}).strict();
12
+ /**
13
+ * The drift workflow for a config: it `uses` the `import` of every resource type the connectors
14
+ * declare (`types`) that has a driver, so its version changes with them, not with the data
15
+ * files. `resolveConfig` adds it to a config whose connectors declare resource types, with
16
+ * `declared`, the step that reads the data files.
17
+ *
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
23
+ * `error`, and the run goes on to the next; a failure that ends the run (`isRunControlError`)
24
+ * ends it.
25
+ */
26
+ 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
+ }
37
+ return defineWorkflow({
38
+ // The literal, held to the one name: the outline finds a workflow by a string, or a const of its own file.
39
+ name: "drift",
40
+ title: "Check resources for drift",
41
+ trigger: "manual",
42
+ input: DriftInput,
43
+ uses,
44
+ run: async (ctx) => {
45
+ const startedAt = await ctx.now();
46
+ const { resources, problems } = await declared();
47
+ // Every import first, so a reference compares against what its resource holds now.
48
+ 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}`;
52
+ // 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 });
55
+ else {
56
+ try {
57
+ const out = await ctx[vendor][type].import({ id: name });
58
+ found.set(id, out.gone || !out.state ? { gone: true } : { state: out.state });
59
+ }
60
+ catch (err) {
61
+ if (isRunControlError(err))
62
+ throw err;
63
+ found.set(id, { error: errorMessage(err) });
64
+ }
65
+ }
66
+ }
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: [] };
74
+ 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);
82
+ }
83
+ const fields = diffDeclared(resource, now.state, desired, accept);
84
+ return { ...row, status: fields.length ? "drifted" : "clean", fields };
85
+ });
86
+ return { startedAt, finishedAt: await ctx.now(), problems, resources: results };
87
+ },
88
+ });
89
+ }
90
+ //# sourceMappingURL=drift.js.map
@@ -0,0 +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"}
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 {};