@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.
- package/README.md +169 -52
- package/dist/apply-steps.js +5 -2
- package/dist/apply-steps.js.map +1 -1
- package/dist/apply.d.ts +3 -0
- package/dist/apply.js +35 -21
- package/dist/apply.js.map +1 -1
- package/dist/approvals.d.ts +1 -0
- package/dist/approvals.js +6 -1
- package/dist/approvals.js.map +1 -1
- package/dist/apps.d.ts +7 -24
- package/dist/apps.js +51 -67
- package/dist/apps.js.map +1 -1
- package/dist/ast.d.ts +9 -7
- package/dist/ast.js +2 -0
- package/dist/ast.js.map +1 -1
- package/dist/authentication.d.ts +24 -0
- package/dist/authentication.js +68 -0
- package/dist/authentication.js.map +1 -0
- package/dist/call-workflow.d.ts +5 -0
- package/dist/call-workflow.js +4 -3
- package/dist/call-workflow.js.map +1 -1
- package/dist/call.d.ts +3 -2
- package/dist/call.js +34 -7
- package/dist/call.js.map +1 -1
- package/dist/cedar.js +14 -1
- package/dist/cedar.js.map +1 -1
- package/dist/change-steps.js +7 -5
- package/dist/change-steps.js.map +1 -1
- package/dist/change.d.ts +7 -0
- package/dist/change.js +7 -0
- package/dist/change.js.map +1 -1
- package/dist/client.d.ts +10 -6
- package/dist/client.js +96 -43
- package/dist/client.js.map +1 -1
- package/dist/collection.d.ts +7 -0
- package/dist/collection.js +5 -2
- package/dist/collection.js.map +1 -1
- package/dist/config.d.ts +14 -3
- package/dist/config.js +55 -14
- package/dist/config.js.map +1 -1
- package/dist/connection.d.ts +168 -0
- package/dist/connection.js +327 -0
- package/dist/connection.js.map +1 -0
- package/dist/credentials.d.ts +7 -53
- package/dist/credentials.js +84 -247
- package/dist/credentials.js.map +1 -1
- package/dist/cucumber.d.ts +4 -2
- package/dist/cucumber.js +8 -3
- package/dist/cucumber.js.map +1 -1
- package/dist/db.js +21 -2
- package/dist/db.js.map +1 -1
- package/dist/define.d.ts +9 -2
- package/dist/define.js.map +1 -1
- package/dist/definitions.d.ts +20 -0
- package/dist/definitions.js +16 -0
- package/dist/definitions.js.map +1 -0
- package/dist/deployment-key.d.ts +2 -0
- package/dist/deployment-key.js +22 -0
- package/dist/deployment-key.js.map +1 -0
- package/dist/describe.d.ts +9 -177
- package/dist/describe.js +71 -34
- package/dist/describe.js.map +1 -1
- package/dist/description.d.ts +532 -0
- package/dist/description.js +381 -0
- package/dist/description.js.map +1 -0
- package/dist/direct.js +3 -0
- package/dist/direct.js.map +1 -1
- package/dist/drift.d.ts +1 -1
- package/dist/drift.js +1 -1
- package/dist/drift.js.map +1 -1
- package/dist/env.d.ts +2 -0
- package/dist/env.js +2 -2
- package/dist/env.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +2 -0
- package/dist/ledger.js +1 -1
- package/dist/ledger.js.map +1 -1
- package/dist/lint.d.ts +0 -9
- package/dist/lint.js +1 -16
- package/dist/lint.js.map +1 -1
- package/dist/load.d.ts +74 -0
- package/dist/load.js +357 -0
- package/dist/load.js.map +1 -0
- package/dist/lockfile.d.ts +2 -0
- package/dist/lockfile.js +8 -3
- package/dist/lockfile.js.map +1 -1
- package/dist/op.d.ts +10 -1
- package/dist/op.js +1 -1
- package/dist/op.js.map +1 -1
- package/dist/outline.js +13 -4
- package/dist/outline.js.map +1 -1
- package/dist/paths.d.ts +18 -0
- package/dist/paths.js +21 -3
- package/dist/paths.js.map +1 -1
- package/dist/plugin.d.ts +0 -11
- package/dist/plugin.js +3 -18
- package/dist/plugin.js.map +1 -1
- package/dist/policy.d.ts +2 -0
- package/dist/policy.js.map +1 -1
- package/dist/resource.d.ts +27 -4
- package/dist/resource.js +49 -4
- package/dist/resource.js.map +1 -1
- package/dist/resources.d.ts +33 -76
- package/dist/resources.js +219 -227
- package/dist/resources.js.map +1 -1
- package/dist/run.d.ts +2 -0
- package/dist/run.js.map +1 -1
- package/dist/sandbox.d.ts +1 -1
- package/dist/sandbox.js +7 -3
- package/dist/sandbox.js.map +1 -1
- package/dist/scenario.d.ts +7 -0
- package/dist/scenario.js +33 -3
- package/dist/scenario.js.map +1 -1
- package/dist/scenarios.js +7 -1
- package/dist/scenarios.js.map +1 -1
- package/dist/schema.js +8 -0
- package/dist/schema.js.map +1 -1
- package/dist/secret-store-check.d.ts +11 -0
- package/dist/secret-store-check.js +76 -0
- package/dist/secret-store-check.js.map +1 -0
- package/dist/secret-store.d.ts +106 -0
- package/dist/secret-store.js +228 -0
- package/dist/secret-store.js.map +1 -0
- package/dist/shared.d.ts +17 -11
- package/dist/shared.js +34 -7
- package/dist/shared.js.map +1 -1
- package/dist/sites.d.ts +4 -93
- package/dist/sites.js +61 -84
- package/dist/sites.js.map +1 -1
- package/dist/source.d.ts +6 -0
- package/dist/source.js +13 -0
- package/dist/source.js.map +1 -1
- package/dist/steps.d.ts +3 -1
- package/dist/steps.js.map +1 -1
- package/dist/version.d.ts +2 -1
- package/dist/version.js +2 -1
- package/dist/version.js.map +1 -1
- package/dist/wakeup-driver.js +15 -6
- package/dist/wakeup-driver.js.map +1 -1
- package/dist/worker.js +12 -8
- package/dist/worker.js.map +1 -1
- package/dist/writer.d.ts +53 -14
- package/dist/writer.js +113 -43
- package/dist/writer.js.map +1 -1
- package/oxlint.json +0 -5
- package/package.json +6 -2
- package/src/apply-steps.ts +5 -2
- package/src/apply.ts +70 -29
- package/src/approvals.ts +7 -1
- package/src/apps.ts +54 -85
- package/src/ast.ts +6 -6
- package/src/authentication.ts +74 -0
- package/src/call-workflow.ts +5 -4
- package/src/call.ts +53 -9
- package/src/cedar.ts +14 -1
- package/src/change-steps.ts +7 -4
- package/src/change.ts +10 -0
- package/src/client.ts +108 -41
- package/src/collection.ts +10 -2
- package/src/config.ts +72 -13
- package/src/connection.ts +446 -0
- package/src/credentials.ts +94 -281
- package/src/cucumber.ts +16 -3
- package/src/db.ts +21 -2
- package/src/define.ts +7 -2
- package/src/definitions.ts +31 -0
- package/src/deployment-key.ts +23 -0
- package/src/describe.ts +102 -230
- package/src/description.ts +426 -0
- package/src/direct.ts +3 -0
- package/src/drift.ts +10 -2
- package/src/env.ts +4 -2
- package/src/index.ts +42 -1
- package/src/ledger.ts +3 -1
- package/src/lint.ts +1 -16
- package/src/load.ts +437 -0
- package/src/lockfile.ts +10 -3
- package/src/op.ts +10 -1
- package/src/outline.ts +18 -5
- package/src/paths.ts +24 -2
- package/src/plugin.ts +3 -24
- package/src/policy.ts +2 -0
- package/src/resource.ts +67 -6
- package/src/resources.ts +246 -301
- package/src/run.ts +2 -0
- package/src/sandbox.ts +11 -3
- package/src/scenario.ts +45 -3
- package/src/scenarios.ts +7 -1
- package/src/schema.ts +10 -0
- package/src/secret-store-check.ts +93 -0
- package/src/secret-store.ts +314 -0
- package/src/shared.ts +35 -10
- package/src/sites.ts +70 -180
- package/src/source.ts +14 -0
- package/src/steps.ts +3 -1
- package/src/version.ts +2 -1
- package/src/wakeup-driver.ts +22 -6
- package/src/worker.ts +12 -8
- package/src/writer.ts +145 -56
- package/dist/datafile.d.ts +0 -97
- package/dist/datafile.js +0 -479
- package/dist/datafile.js.map +0 -1
- 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
|
-
(
|
|
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
|
-
|
|
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 = (
|
|
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, {
|