@sanoma-ai/workflows 0.9.0 → 0.10.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 (205) hide show
  1. package/README.md +169 -52
  2. package/dist/apply-steps.js +5 -2
  3. package/dist/apply-steps.js.map +1 -1
  4. package/dist/apply.d.ts +3 -0
  5. package/dist/apply.js +35 -21
  6. package/dist/apply.js.map +1 -1
  7. package/dist/approvals.d.ts +1 -0
  8. package/dist/approvals.js +6 -1
  9. package/dist/approvals.js.map +1 -1
  10. package/dist/apps.d.ts +7 -24
  11. package/dist/apps.js +51 -67
  12. package/dist/apps.js.map +1 -1
  13. package/dist/ast.d.ts +9 -7
  14. package/dist/ast.js +2 -0
  15. package/dist/ast.js.map +1 -1
  16. package/dist/authentication.d.ts +24 -0
  17. package/dist/authentication.js +68 -0
  18. package/dist/authentication.js.map +1 -0
  19. package/dist/call-workflow.d.ts +5 -0
  20. package/dist/call-workflow.js +4 -3
  21. package/dist/call-workflow.js.map +1 -1
  22. package/dist/call.d.ts +3 -2
  23. package/dist/call.js +34 -7
  24. package/dist/call.js.map +1 -1
  25. package/dist/cedar.js +14 -1
  26. package/dist/cedar.js.map +1 -1
  27. package/dist/change-steps.js +7 -5
  28. package/dist/change-steps.js.map +1 -1
  29. package/dist/change.d.ts +7 -0
  30. package/dist/change.js +7 -0
  31. package/dist/change.js.map +1 -1
  32. package/dist/client.d.ts +10 -6
  33. package/dist/client.js +96 -43
  34. package/dist/client.js.map +1 -1
  35. package/dist/collection.d.ts +7 -0
  36. package/dist/collection.js +5 -2
  37. package/dist/collection.js.map +1 -1
  38. package/dist/config.d.ts +14 -3
  39. package/dist/config.js +55 -14
  40. package/dist/config.js.map +1 -1
  41. package/dist/connection.d.ts +168 -0
  42. package/dist/connection.js +327 -0
  43. package/dist/connection.js.map +1 -0
  44. package/dist/credentials.d.ts +7 -53
  45. package/dist/credentials.js +84 -247
  46. package/dist/credentials.js.map +1 -1
  47. package/dist/cucumber.d.ts +4 -2
  48. package/dist/cucumber.js +8 -3
  49. package/dist/cucumber.js.map +1 -1
  50. package/dist/db.js +21 -2
  51. package/dist/db.js.map +1 -1
  52. package/dist/define.d.ts +9 -2
  53. package/dist/define.js.map +1 -1
  54. package/dist/definitions.d.ts +20 -0
  55. package/dist/definitions.js +16 -0
  56. package/dist/definitions.js.map +1 -0
  57. package/dist/deployment-key.d.ts +2 -0
  58. package/dist/deployment-key.js +22 -0
  59. package/dist/deployment-key.js.map +1 -0
  60. package/dist/describe.d.ts +9 -177
  61. package/dist/describe.js +71 -34
  62. package/dist/describe.js.map +1 -1
  63. package/dist/description.d.ts +532 -0
  64. package/dist/description.js +381 -0
  65. package/dist/description.js.map +1 -0
  66. package/dist/direct.js +3 -0
  67. package/dist/direct.js.map +1 -1
  68. package/dist/drift.d.ts +1 -1
  69. package/dist/drift.js +1 -1
  70. package/dist/drift.js.map +1 -1
  71. package/dist/env.d.ts +2 -0
  72. package/dist/env.js +2 -2
  73. package/dist/env.js.map +1 -1
  74. package/dist/index.d.ts +10 -2
  75. package/dist/index.js +10 -2
  76. package/dist/index.js.map +1 -1
  77. package/dist/ledger.d.ts +2 -0
  78. package/dist/ledger.js +1 -1
  79. package/dist/ledger.js.map +1 -1
  80. package/dist/lint.d.ts +0 -9
  81. package/dist/lint.js +1 -16
  82. package/dist/lint.js.map +1 -1
  83. package/dist/load.d.ts +74 -0
  84. package/dist/load.js +357 -0
  85. package/dist/load.js.map +1 -0
  86. package/dist/lockfile.d.ts +2 -0
  87. package/dist/lockfile.js +8 -3
  88. package/dist/lockfile.js.map +1 -1
  89. package/dist/op.d.ts +10 -1
  90. package/dist/op.js +1 -1
  91. package/dist/op.js.map +1 -1
  92. package/dist/outline.js +13 -4
  93. package/dist/outline.js.map +1 -1
  94. package/dist/paths.d.ts +18 -0
  95. package/dist/paths.js +21 -3
  96. package/dist/paths.js.map +1 -1
  97. package/dist/plugin.d.ts +0 -11
  98. package/dist/plugin.js +3 -18
  99. package/dist/plugin.js.map +1 -1
  100. package/dist/policy.d.ts +2 -0
  101. package/dist/policy.js.map +1 -1
  102. package/dist/resource.d.ts +27 -4
  103. package/dist/resource.js +49 -4
  104. package/dist/resource.js.map +1 -1
  105. package/dist/resources.d.ts +33 -76
  106. package/dist/resources.js +219 -227
  107. package/dist/resources.js.map +1 -1
  108. package/dist/run.d.ts +2 -0
  109. package/dist/run.js.map +1 -1
  110. package/dist/sandbox.d.ts +1 -1
  111. package/dist/sandbox.js +7 -3
  112. package/dist/sandbox.js.map +1 -1
  113. package/dist/scenario.d.ts +7 -0
  114. package/dist/scenario.js +33 -3
  115. package/dist/scenario.js.map +1 -1
  116. package/dist/scenarios.js +7 -1
  117. package/dist/scenarios.js.map +1 -1
  118. package/dist/schema.js +8 -0
  119. package/dist/schema.js.map +1 -1
  120. package/dist/secret-store-check.d.ts +11 -0
  121. package/dist/secret-store-check.js +76 -0
  122. package/dist/secret-store-check.js.map +1 -0
  123. package/dist/secret-store.d.ts +106 -0
  124. package/dist/secret-store.js +228 -0
  125. package/dist/secret-store.js.map +1 -0
  126. package/dist/shared.d.ts +17 -11
  127. package/dist/shared.js +34 -7
  128. package/dist/shared.js.map +1 -1
  129. package/dist/sites.d.ts +4 -93
  130. package/dist/sites.js +61 -84
  131. package/dist/sites.js.map +1 -1
  132. package/dist/source.d.ts +6 -0
  133. package/dist/source.js +13 -0
  134. package/dist/source.js.map +1 -1
  135. package/dist/steps.d.ts +3 -1
  136. package/dist/steps.js.map +1 -1
  137. package/dist/version.d.ts +2 -1
  138. package/dist/version.js +2 -1
  139. package/dist/version.js.map +1 -1
  140. package/dist/wakeup-driver.js +15 -6
  141. package/dist/wakeup-driver.js.map +1 -1
  142. package/dist/worker.js +12 -8
  143. package/dist/worker.js.map +1 -1
  144. package/dist/writer.d.ts +53 -14
  145. package/dist/writer.js +113 -43
  146. package/dist/writer.js.map +1 -1
  147. package/oxlint.json +0 -5
  148. package/package.json +6 -2
  149. package/src/apply-steps.ts +5 -2
  150. package/src/apply.ts +70 -29
  151. package/src/approvals.ts +7 -1
  152. package/src/apps.ts +54 -85
  153. package/src/ast.ts +6 -6
  154. package/src/authentication.ts +74 -0
  155. package/src/call-workflow.ts +5 -4
  156. package/src/call.ts +53 -9
  157. package/src/cedar.ts +14 -1
  158. package/src/change-steps.ts +7 -4
  159. package/src/change.ts +10 -0
  160. package/src/client.ts +108 -41
  161. package/src/collection.ts +10 -2
  162. package/src/config.ts +72 -13
  163. package/src/connection.ts +446 -0
  164. package/src/credentials.ts +94 -281
  165. package/src/cucumber.ts +16 -3
  166. package/src/db.ts +21 -2
  167. package/src/define.ts +7 -2
  168. package/src/definitions.ts +31 -0
  169. package/src/deployment-key.ts +23 -0
  170. package/src/describe.ts +102 -230
  171. package/src/description.ts +426 -0
  172. package/src/direct.ts +3 -0
  173. package/src/drift.ts +10 -2
  174. package/src/env.ts +4 -2
  175. package/src/index.ts +42 -1
  176. package/src/ledger.ts +3 -1
  177. package/src/lint.ts +1 -16
  178. package/src/load.ts +437 -0
  179. package/src/lockfile.ts +10 -3
  180. package/src/op.ts +10 -1
  181. package/src/outline.ts +18 -5
  182. package/src/paths.ts +24 -2
  183. package/src/plugin.ts +3 -24
  184. package/src/policy.ts +2 -0
  185. package/src/resource.ts +67 -6
  186. package/src/resources.ts +246 -301
  187. package/src/run.ts +2 -0
  188. package/src/sandbox.ts +11 -3
  189. package/src/scenario.ts +45 -3
  190. package/src/scenarios.ts +7 -1
  191. package/src/schema.ts +10 -0
  192. package/src/secret-store-check.ts +93 -0
  193. package/src/secret-store.ts +314 -0
  194. package/src/shared.ts +35 -10
  195. package/src/sites.ts +70 -180
  196. package/src/source.ts +14 -0
  197. package/src/steps.ts +3 -1
  198. package/src/version.ts +2 -1
  199. package/src/wakeup-driver.ts +22 -6
  200. package/src/worker.ts +12 -8
  201. package/src/writer.ts +145 -56
  202. package/dist/datafile.d.ts +0 -97
  203. package/dist/datafile.js +0 -479
  204. package/dist/datafile.js.map +0 -1
  205. package/src/datafile.ts +0 -601
package/src/resource.ts CHANGED
@@ -1,8 +1,11 @@
1
+ import type { ConnectionRef } from "./connection.ts";
1
2
  import { z } from "zod";
2
3
  import { checkDatabase, type DatabaseSpec } from "./database.ts";
4
+ import { isRunControlError } from "./errors.ts";
3
5
  import { checkHost, type HostSpec } from "./host.ts";
4
6
  import { type Connector, type OpSpec, RESOURCE, VENDOR } from "./op.ts";
5
7
  import { isSanomaSecret, isSecret, type Secret } from "./secret.ts";
8
+ import { errorMessage } from "./shared.ts";
6
9
  import { checkWakeup, type WakeupSpec } from "./wakeup.ts";
7
10
 
8
11
  /** Which fields of a resource are flagged, by dotted path (`pages.html_url`; a list's items have no index). */
@@ -123,6 +126,47 @@ export interface AfterCreate {
123
126
  until?: (output: any) => boolean;
124
127
  }
125
128
 
129
+ /** How long apply waits between calls of an `afterCreate` operation with `until`, and how many calls it makes. */
130
+ export const AFTER_CREATE_SECONDS = 5;
131
+ export const AFTER_CREATE_CALLS = 120;
132
+ /** How long an `afterCreate` operation may be polled, in all, in milliseconds. */
133
+ export const AFTER_CREATE_MS = AFTER_CREATE_SECONDS * AFTER_CREATE_CALLS * 1000;
134
+
135
+ /** Why an `afterCreate` operation with `until` did not pass: the time it was given, and its last call's error if that failed. */
136
+ export const afterCreateStuck = (op: string, failed: unknown): string =>
137
+ `${op} did not pass in ${AFTER_CREATE_MS / 60_000} minutes` +
138
+ (failed === undefined ? "" : `; its last call failed: ${errorMessage(failed)}`);
139
+
140
+ /**
141
+ * Calls one `afterCreate` operation for a new object as apply does: with `until`, again every
142
+ * few seconds until its output passes, a call that fails meanwhile being one that did not pass;
143
+ * without, once, a failure thrown. Returns why it did not pass, if it did not. Apply inlines the
144
+ * same loop in its `run`, which may not close over its `ctx`; an operation's own test calls this.
145
+ */
146
+ export async function callAfterCreate(
147
+ hook: AfterCreate,
148
+ made: { id: string; export: string },
149
+ call: (op: string, input: unknown) => Promise<unknown>,
150
+ sleep: (seconds: number) => Promise<void>,
151
+ ): Promise<string | undefined> {
152
+ const given = hook.input(made);
153
+ let output: unknown;
154
+ let failed: unknown;
155
+ for (let n = 0; n < AFTER_CREATE_CALLS && (n === 0 || (hook.until && !hook.until(output))); n++) {
156
+ if (n > 0) await sleep(AFTER_CREATE_SECONDS);
157
+ try {
158
+ output = await call(hook.op, given);
159
+ failed = undefined;
160
+ } catch (err) {
161
+ if (isRunControlError(err) || !hook.until) throw err;
162
+ output = undefined;
163
+ failed = err;
164
+ }
165
+ }
166
+ if (hook.until && !hook.until(output)) return afterCreateStuck(hook.op, failed);
167
+ return undefined;
168
+ }
169
+
126
170
  /**
127
171
  * Where a declared resource keeps its brand, its type's `<vendor>.<type>`: a symbol, so a field
128
172
  * holding a resource is told from data; a registered one (`Symbol.for`), so a copy of this
@@ -130,7 +174,7 @@ export interface AfterCreate {
130
174
  */
131
175
  export const DECLARED: unique symbol = Symbol.for("sanoma.declared");
132
176
 
133
- /** A resource a data file declares: `github.repository({ name: "sanoma" })`. */
177
+ /** A resource a data file declares: `github.repository({ owner: "acme", name: "sanoma" })`. */
134
178
  export interface Declared<Id extends string = string, T = State> {
135
179
  readonly [DECLARED]: Id;
136
180
  readonly vendor: string;
@@ -142,6 +186,7 @@ export interface Declared<Id extends string = string, T = State> {
142
186
  * checked, and what a drift check compares.
143
187
  */
144
188
  readonly desired: T;
189
+ readonly connection?: ConnectionRef;
145
190
  /**
146
191
  * Where it names another resource: the field's dotted path (a list item's with its index,
147
192
  * `teams.0`) to that resource's `<vendor>.<type>:<name>`.
@@ -288,7 +333,10 @@ export interface Resource<
288
333
  >
289
334
  >,
290
335
  Readonly<Pick<ResourceSpec<S>, "identity" | "find" | "host" | "wakeup" | "database" | "afterCreate">> {
291
- (desired: Declaring<z.input<S>, R>): Declared<Id, z.input<S>>;
336
+ (
337
+ desired: Declaring<z.input<S>, R>,
338
+ options?: { connection?: ConnectionRef<Id extends `${infer V}.${string}` ? V : string> },
339
+ ): Declared<Id, z.input<S>>;
292
340
  /** `read` and `import`, each effect `read`, idempotent, with the id as `target`; for a writable type, the change operations too. */
293
341
  readonly ops: ResourceOps<S, W>;
294
342
  /** True when apply may change its objects: it has the change operations. */
@@ -306,7 +354,9 @@ export const isObject = (v: unknown): v is State => typeof v === "object" && v !
306
354
  /** `path.name`, or `name` at the top: a field's dotted path. */
307
355
  export const joinPath = (path: string, name: string) => (path ? `${path}.${name}` : name);
308
356
 
309
- const isDeclared = (v: unknown): v is Declared => isObject(v) && typeof (v as Partial<Declared>)[DECLARED] === "string";
357
+ /** A declared resource: what a constructor returns, made by any copy of this package. */
358
+ export const isDeclared = (v: unknown): v is Declared =>
359
+ isObject(v) && typeof (v as Partial<Declared>)[DECLARED] === "string";
310
360
 
311
361
  /** One order for a list compared as a multiset: by each item's JSON. */
312
362
  const canonical = (items: unknown[]) =>
@@ -534,8 +584,8 @@ function pathsIn(value: unknown, paths: ReadonlySet<string>, prefix = ""): strin
534
584
  *
535
585
  * The ledger records a `handle` as `"<handle>"`, never its bytes (the operations' `opaque`).
536
586
  *
537
- * Calling the result declares one resource, for a data file: `repository({ name: "sanoma" })`
538
- * is a `Declared`, `{ vendor, type, name: "sanoma", desired, refs: {} }`. It refuses fields the
587
+ * Calling the result declares one resource, for a data file: `repository({ owner: "acme", name: "sanoma" })`
588
+ * is a `Declared`, `{ vendor, type, name: "acme/sanoma", desired, refs: {} }`. It refuses fields the
539
589
  * schema does not have, fields the vendor owns (unless the identity names them), values the
540
590
  * schema rejects, and an empty identity. Where `fields.references` allows it, a field may name
541
591
  * another declared resource of that type (`repository_id: site`): `desired` holds, and the
@@ -620,7 +670,17 @@ export function defineResource<
620
670
  const owned = new Set(fields.vendorOwned.filter((path) => !named.has(path)));
621
671
  const references: References = fields.references ?? {};
622
672
  const writeOnly = new Set(fields.writeOnly);
623
- const declare = (given: Declaring<z.input<S>, R>): Declared<`${V}.${T}`, z.input<S>> => {
673
+ const declare = (
674
+ given: Declaring<z.input<S>, R>,
675
+ options?: { connection?: ConnectionRef },
676
+ ): Declared<`${V}.${T}`, z.input<S>> => {
677
+ const connection = options?.connection;
678
+ if (
679
+ connection &&
680
+ (connection.vendor !== vendor || !new RegExp(`^${vendor}/[a-z][a-z0-9-]{0,63}$`).test(connection.$connection))
681
+ ) {
682
+ throw new Error(`${what}: select a declared connection of this connector`);
683
+ }
624
684
  const refs: Record<string, string> = {};
625
685
  // Where a secret is given, with list items' indexes: the schema does not judge its marker.
626
686
  const secrets = new Set<string>();
@@ -680,6 +740,7 @@ export function defineResource<
680
740
  ...(name !== undefined && { name }),
681
741
  desired,
682
742
  refs: Object.freeze(refs),
743
+ ...(connection && { connection: Object.freeze({ ...connection }) }),
683
744
  });
684
745
  };
685
746
  const resource = Object.assign(declare, {