@sanoma-ai/workflows 0.2.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.
- package/README.md +121 -62
- package/dist/approvals.d.ts +11 -6
- package/dist/approvals.js +38 -10
- package/dist/approvals.js.map +1 -1
- package/dist/call-workflow.d.ts +16 -0
- package/dist/call-workflow.js +35 -0
- package/dist/call-workflow.js.map +1 -0
- package/dist/call.d.ts +33 -4
- package/dist/call.js +107 -42
- package/dist/call.js.map +1 -1
- package/dist/cedar.d.ts +87 -0
- package/dist/cedar.js +365 -0
- package/dist/cedar.js.map +1 -0
- package/dist/client.d.ts +85 -7
- package/dist/client.js +289 -25
- package/dist/client.js.map +1 -1
- package/dist/collection.d.ts +107 -0
- package/dist/collection.js +306 -0
- package/dist/collection.js.map +1 -0
- package/dist/config.d.ts +42 -14
- package/dist/config.js +82 -18
- package/dist/config.js.map +1 -1
- package/dist/constructors.d.ts +2 -0
- package/dist/constructors.js +5 -0
- package/dist/constructors.js.map +1 -0
- package/dist/data.d.ts +2 -0
- package/dist/data.js +3 -0
- package/dist/data.js.map +1 -0
- package/dist/datafile.d.ts +28 -2
- package/dist/datafile.js +118 -19
- package/dist/datafile.js.map +1 -1
- package/dist/db.d.ts +5 -3
- package/dist/db.js +88 -21
- package/dist/db.js.map +1 -1
- package/dist/define.d.ts +10 -4
- package/dist/define.js +1 -5
- package/dist/define.js.map +1 -1
- package/dist/describe.d.ts +45 -5
- package/dist/describe.js +72 -7
- package/dist/describe.js.map +1 -1
- package/dist/direct.d.ts +9 -0
- package/dist/direct.js +11 -0
- package/dist/direct.js.map +1 -0
- package/dist/errors.d.ts +16 -1
- package/dist/errors.js +30 -1
- package/dist/errors.js.map +1 -1
- package/dist/expectations.d.ts +3 -3
- package/dist/expectations.js +16 -7
- package/dist/expectations.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +12 -1
- package/dist/ledger.js +18 -11
- package/dist/ledger.js.map +1 -1
- package/dist/lint.d.ts +5 -4
- package/dist/lint.js +24 -7
- package/dist/lint.js.map +1 -1
- package/dist/op.d.ts +6 -0
- package/dist/op.js.map +1 -1
- package/dist/outline.d.ts +2 -0
- package/dist/outline.js +1 -1
- package/dist/outline.js.map +1 -1
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +17 -3
- package/dist/paths.js.map +1 -1
- package/dist/person.d.ts +61 -0
- package/dist/person.js +69 -0
- package/dist/person.js.map +1 -0
- package/dist/plugin.js +1 -1
- package/dist/plugin.js.map +1 -1
- package/dist/policy.d.ts +51 -55
- package/dist/policy.js +14 -36
- package/dist/policy.js.map +1 -1
- package/dist/resource.d.ts +21 -5
- package/dist/resource.js +12 -3
- package/dist/resource.js.map +1 -1
- package/dist/resources.d.ts +58 -6
- package/dist/resources.js +119 -26
- package/dist/resources.js.map +1 -1
- package/dist/run.d.ts +17 -1
- package/dist/run.js.map +1 -1
- package/dist/scenario.d.ts +16 -9
- package/dist/scenario.js +93 -20
- package/dist/scenario.js.map +1 -1
- package/dist/scenarios.d.ts +10 -6
- package/dist/scenarios.js +8 -4
- package/dist/scenarios.js.map +1 -1
- package/dist/schema.d.ts +32 -0
- package/dist/schema.js +225 -0
- package/dist/schema.js.map +1 -0
- package/dist/sdk.d.ts +34 -0
- package/dist/sdk.js +168 -0
- package/dist/sdk.js.map +1 -0
- package/dist/shared.d.ts +181 -5
- package/dist/shared.js +160 -7
- package/dist/shared.js.map +1 -1
- package/dist/sites.d.ts +52 -0
- package/dist/sites.js +174 -0
- package/dist/sites.js.map +1 -0
- package/dist/version.d.ts +3 -2
- package/dist/version.js +3 -2
- package/dist/version.js.map +1 -1
- package/dist/worker.d.ts +3 -2
- package/dist/worker.js +24 -4
- package/dist/worker.js.map +1 -1
- package/oxlint.json +5 -16
- package/package.json +8 -3
- package/src/approvals.ts +49 -13
- package/src/call-workflow.ts +44 -0
- package/src/call.ts +157 -45
- package/src/cedar.ts +493 -0
- package/src/client.ts +368 -37
- package/src/collection.ts +431 -0
- package/src/config.ts +131 -34
- package/src/constructors.ts +4 -0
- package/src/data.ts +10 -0
- package/src/datafile.ts +141 -21
- package/src/db.ts +90 -22
- package/src/define.ts +11 -9
- package/src/describe.ts +113 -10
- package/src/direct.ts +15 -0
- package/src/errors.ts +36 -1
- package/src/expectations.ts +17 -8
- package/src/index.ts +33 -2
- package/src/ledger.ts +35 -17
- package/src/lint.ts +29 -12
- package/src/op.ts +6 -0
- package/src/outline.ts +1 -1
- package/src/paths.ts +18 -3
- package/src/person.ts +75 -0
- package/src/plugin.ts +1 -1
- package/src/policy.ts +59 -63
- package/src/resource.ts +35 -8
- package/src/resources.ts +165 -24
- package/src/run.ts +18 -1
- package/src/scenario.ts +128 -33
- package/src/scenarios.ts +15 -8
- package/src/schema.ts +261 -0
- package/src/sdk.ts +211 -0
- package/src/shared.ts +271 -8
- package/src/sites.ts +220 -0
- package/src/version.ts +3 -2
- package/src/worker.ts +29 -6
package/dist/sdk.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { isObject } from "./resource.js";
|
|
4
|
+
import { SCHEMA_FILE, schemaText } from "./schema.js";
|
|
5
|
+
import { apiNameOf, DATA_VENDOR, problemLine } from "./shared.js";
|
|
6
|
+
// A company's generated SDK, `.sanoma/api.ts`: the types of a site's `api` from `sanoma/site`,
|
|
7
|
+
// written from `describeConfig` (types and JSDoc only: `api` itself is one generic client). It
|
|
8
|
+
// augments `sanoma/site`'s `Register`, so it is type-checked only through the sites' generated
|
|
9
|
+
// tsconfig, never the company's root one (Node, no DOM).
|
|
10
|
+
/** Where `writeApi` writes, under a company's root. */
|
|
11
|
+
export const API_FILE = join(".sanoma", "api.ts");
|
|
12
|
+
const API_NAME_PROBLEM = "A site calls this workflow api.";
|
|
13
|
+
/** `describeConfig`'s problem on a workflow whose api name is taken: `taken` says by what. */
|
|
14
|
+
export const apiNameProblem = (api, taken) => `${API_NAME_PROBLEM}${api}, ${taken}: rename it`;
|
|
15
|
+
/**
|
|
16
|
+
* `.sanoma/api.ts` for a description: one record type per collection, and `CompanyApi` (not `Api`,
|
|
17
|
+
* which inside `declare module "sanoma/site"` is the module's own), one member per
|
|
18
|
+
* workflow (`apiNameOf`), per vendor of the operations a person may call directly (`OpEntry.direct`,
|
|
19
|
+
* by resource) and `data` for the collections, each with its JSDoc; then `Register`'s
|
|
20
|
+
* augmentation. Pure: the same description gives the same text. A workflow whose api name another
|
|
21
|
+
* has, `describeConfig`'s problem on its entry, is left out, and its problem is in `problems`.
|
|
22
|
+
*/
|
|
23
|
+
export function generateApi(description) {
|
|
24
|
+
const problems = [];
|
|
25
|
+
const members = [];
|
|
26
|
+
for (const wf of description.workflows) {
|
|
27
|
+
const taken = wf.problems.filter((p) => p.message.startsWith(API_NAME_PROBLEM));
|
|
28
|
+
if (taken.length)
|
|
29
|
+
problems.push(...taken.map((p) => problemLine({ file: wf.file, ...p })));
|
|
30
|
+
else
|
|
31
|
+
members.push(workflowMember(wf));
|
|
32
|
+
}
|
|
33
|
+
// The ops are sorted by id, so by vendor and then resource.
|
|
34
|
+
const direct = description.ops.filter((op) => op.direct && op.vendor !== DATA_VENDOR);
|
|
35
|
+
for (const [vendor, ops] of Map.groupBy(direct, (op) => op.vendor)) {
|
|
36
|
+
const title = description.vendors[vendor]?.title ?? vendor;
|
|
37
|
+
const resources = [...Map.groupBy(ops, (op) => op.resource)].map(([resource, own]) => member(undefined, resource, block(own.map(opMember))));
|
|
38
|
+
members.push(member(`${title}: the operations a person may call directly.`, vendor, block(resources)));
|
|
39
|
+
}
|
|
40
|
+
if (description.collections.length) {
|
|
41
|
+
const data = description.collections.map((c) => member(collectionDoc(c), c.name, `CollectionApi<${recordName(c)}>`));
|
|
42
|
+
members.push(member("The company's collections.", DATA_VENDOR, block(data)));
|
|
43
|
+
}
|
|
44
|
+
const source = [
|
|
45
|
+
"// Generated by sanoma from sanoma.config.ts and the connectors it names; do not edit.",
|
|
46
|
+
"// The types of `api` from sanoma/site: what a site may call, as the person on the page.",
|
|
47
|
+
'import type { CollectionApi, OpFn, WorkflowFn } from "sanoma/site";',
|
|
48
|
+
...description.collections.map((c) => `\n${jsdoc(`A record of ${c.title ?? c.name}.`)}type ${recordName(c)} = ${typeOf(c.record)};`),
|
|
49
|
+
"",
|
|
50
|
+
`interface CompanyApi ${block(members)}`,
|
|
51
|
+
"",
|
|
52
|
+
'declare module "sanoma/site" {',
|
|
53
|
+
" interface Register {",
|
|
54
|
+
" api: CompanyApi;",
|
|
55
|
+
" }",
|
|
56
|
+
"}",
|
|
57
|
+
"",
|
|
58
|
+
"export {};",
|
|
59
|
+
"",
|
|
60
|
+
].join("\n");
|
|
61
|
+
return { source, problems };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Writes `<root>/.sanoma/api.ts` (`generateApi`) when its text differs from the file's, so an
|
|
65
|
+
* editor or a dev server sees no change when there is none; `wrote` says whether it did.
|
|
66
|
+
*/
|
|
67
|
+
export async function writeApi(root, description) {
|
|
68
|
+
const file = join(root, API_FILE);
|
|
69
|
+
return { wrote: await writeChanged(file, generateApi(description).source), file };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The generated files, each written when its text changed: `.sanoma/api.ts` (`writeApi`) and the
|
|
73
|
+
* Cedar schema's text, `.sanoma/schema.cedarschema` (`schemaText` of `schemaOf`). `wrote` lists
|
|
74
|
+
* those written, relative to the root.
|
|
75
|
+
*/
|
|
76
|
+
export async function writeGenerated(root, description, schema) {
|
|
77
|
+
const [api, cedar] = await Promise.all([
|
|
78
|
+
writeApi(root, description),
|
|
79
|
+
writeChanged(join(root, SCHEMA_FILE), schemaText(schema)),
|
|
80
|
+
]);
|
|
81
|
+
return { wrote: [...(api.wrote ? [API_FILE] : []), ...(cedar ? [SCHEMA_FILE] : [])] };
|
|
82
|
+
}
|
|
83
|
+
/** Writes `text` to `file` unless the file holds it already; true when it wrote. */
|
|
84
|
+
async function writeChanged(file, text) {
|
|
85
|
+
if ((await readFile(file, "utf8").catch(() => undefined)) === text)
|
|
86
|
+
return false;
|
|
87
|
+
await mkdir(dirname(file), { recursive: true });
|
|
88
|
+
await writeFile(file, text);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
const workflowMember = (wf) => member(`${wf.title ?? wf.name}: the workflow \`${wf.name}\`${wf.builtin ? ", built in" : ""}.`, apiNameOf(wf.name), `WorkflowFn<${typeOf(wf.input)}, unknown>`);
|
|
92
|
+
const opMember = (op) => member(`${op.description ? `${op.description}\n\n` : ""}\`${op.id}\`, a ${op.effect}.`, op.name, `OpFn<${typeOf(op.input)}, unknown>`);
|
|
93
|
+
const collectionDoc = (c) => `${c.title ?? c.name}: the collection \`${c.name}\`, keyed by \`${c.key}\`.`;
|
|
94
|
+
/** A collection's record type's name: `outbound` gives `OutboundRecord`, never `CompanyApi` nor an imported type's. */
|
|
95
|
+
const recordName = (c) => `${c.name[0].toUpperCase()}${c.name.slice(1)}Record`;
|
|
96
|
+
/**
|
|
97
|
+
* A JSON Schema as a TypeScript type, for the kinds a start form draws (`fieldsOf` in the app):
|
|
98
|
+
* strings (a date-time among them), numbers, integers, booleans, enums and constants, objects and
|
|
99
|
+
* arrays, each property with its description, and unions of those, `null` among them (a
|
|
100
|
+
* collection's date, a date or a date-time; a nullable field); anything else is `unknown`.
|
|
101
|
+
*/
|
|
102
|
+
const typeOf = (schema) => union(alternatives(schema));
|
|
103
|
+
/** One type of several: `unknown` when any is. */
|
|
104
|
+
function union(types) {
|
|
105
|
+
const distinct = new Set(types);
|
|
106
|
+
return distinct.has("unknown") ? "unknown" : [...distinct].join(" | ");
|
|
107
|
+
}
|
|
108
|
+
/** The types a schema allows, one per alternative. */
|
|
109
|
+
function alternatives(schema) {
|
|
110
|
+
if (!isObject(schema))
|
|
111
|
+
return ["unknown"];
|
|
112
|
+
if ("const" in schema && !isObject(schema.const) && !Array.isArray(schema.const)) {
|
|
113
|
+
return [JSON.stringify(schema.const)];
|
|
114
|
+
}
|
|
115
|
+
if (Array.isArray(schema.enum) && schema.enum.length && schema.enum.every((v) => v === null || !isObject(v))) {
|
|
116
|
+
return schema.enum.map((v) => JSON.stringify(v));
|
|
117
|
+
}
|
|
118
|
+
if (Array.isArray(schema.anyOf) && schema.anyOf.length)
|
|
119
|
+
return schema.anyOf.flatMap(alternatives);
|
|
120
|
+
if (Array.isArray(schema.type) && schema.type.length) {
|
|
121
|
+
return schema.type.flatMap((type) => alternatives({ ...schema, type }));
|
|
122
|
+
}
|
|
123
|
+
switch (schema.type) {
|
|
124
|
+
case "string":
|
|
125
|
+
return ["string"];
|
|
126
|
+
case "number":
|
|
127
|
+
case "integer":
|
|
128
|
+
return ["number"];
|
|
129
|
+
case "boolean":
|
|
130
|
+
return ["boolean"];
|
|
131
|
+
case "null":
|
|
132
|
+
return ["null"];
|
|
133
|
+
case "array": {
|
|
134
|
+
const item = typeOf(schema.items);
|
|
135
|
+
return [new Set(alternatives(schema.items)).size > 1 && item !== "unknown" ? `(${item})[]` : `${item}[]`];
|
|
136
|
+
}
|
|
137
|
+
case "object":
|
|
138
|
+
return [isObject(schema.properties) ? objectType(schema) : "Record<string, unknown>"];
|
|
139
|
+
default:
|
|
140
|
+
return ["unknown"];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function objectType(schema) {
|
|
144
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
145
|
+
const lines = Object.entries(schema.properties).map(([name, prop]) => {
|
|
146
|
+
const doc = isObject(prop) && typeof prop.description === "string" ? jsdoc(prop.description) : "";
|
|
147
|
+
return `${doc}${key(name)}${required.has(name) ? "" : "?"}: ${typeOf(prop)};`;
|
|
148
|
+
});
|
|
149
|
+
// An object that takes other keys too.
|
|
150
|
+
if (schema.additionalProperties !== undefined && schema.additionalProperties !== false) {
|
|
151
|
+
lines.push("[key: string]: unknown;");
|
|
152
|
+
}
|
|
153
|
+
return block(lines);
|
|
154
|
+
}
|
|
155
|
+
/** A property's name, quoted when it is not an identifier. */
|
|
156
|
+
const key = (name) => (/^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name));
|
|
157
|
+
/** A member, under its JSDoc when there is one. */
|
|
158
|
+
const member = (doc, name, type) => `${doc ? jsdoc(doc) : ""}${key(name)}: ${type};`;
|
|
159
|
+
/** `{ … }` around lines, each indented a level (a nested block's lines with it); `{}` for none. */
|
|
160
|
+
const block = (lines) => lines.length ? `{\n${lines.map((l) => l.replace(/^(?=.)/gm, " ")).join("\n")}\n}` : "{}";
|
|
161
|
+
/** A JSDoc comment and the line break after it; `*\/` in the text cannot end it. */
|
|
162
|
+
function jsdoc(text) {
|
|
163
|
+
const lines = text.replaceAll("*/", "*\\/").split("\n");
|
|
164
|
+
return lines.length === 1
|
|
165
|
+
? `/** ${lines[0]} */\n`
|
|
166
|
+
: `/**\n${lines.map((l) => ` *${l ? ` ${l}` : ""}`).join("\n")}\n */\n`;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=sdk.js.map
|
package/dist/sdk.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"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"}
|
package/dist/shared.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { RunSummary } from "./client.ts";
|
|
1
2
|
import type { CredentialStatus } from "./env.ts";
|
|
2
3
|
import type { ApprovalState, Approver, Principal } from "./define.ts";
|
|
3
|
-
import type {
|
|
4
|
+
import type { LedgerRecord } from "./ledger.ts";
|
|
5
|
+
import type { DeclaredResource, ResourceProblem } from "./resources.ts";
|
|
4
6
|
import type { OutlineNode } from "./outline.ts";
|
|
5
7
|
export type { Declared, Declaring, FieldReference, References, Resource, ResourceFields, ResourceSpec, } from "./resource.ts";
|
|
6
8
|
export type { DeclaredResource, ResourceProblem } from "./resources.ts";
|
|
@@ -19,7 +21,77 @@ export declare const DRIFT_WORKFLOW = "drift";
|
|
|
19
21
|
* change operations (`create`, `update`, `delete`).
|
|
20
22
|
*/
|
|
21
23
|
export declare const APPLY_WORKFLOW = "apply";
|
|
22
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The vendor of the collections' operations, `data.<collection>.<op>`: a collection's `get`,
|
|
26
|
+
* `list`, `save` and `delete`. No connector may take it.
|
|
27
|
+
*/
|
|
28
|
+
export declare const DATA_VENDOR = "data";
|
|
29
|
+
/** Every effect an operation may have, each an action group (`effect:<effect>`) of the Cedar schema. */
|
|
30
|
+
export declare const EFFECTS: readonly ["read", "write", "publish", "send", "money", "access"];
|
|
31
|
+
/** What a workflow start's action id starts with, as a policy names it: `workflow:<name>`. */
|
|
32
|
+
export declare const WORKFLOW_ACTION = "workflow:";
|
|
33
|
+
/** A site's folder name under `sites/`, its URL segment: what the app mounts and `readSites` reads. */
|
|
34
|
+
export declare const SITE_NAME: RegExp;
|
|
35
|
+
/**
|
|
36
|
+
* A record of a collection as `get`, `list` and `save` answer it: its key, the record, and when
|
|
37
|
+
* and by whom it was last saved (`updatedBy`: a person's id, or `run:<id>` for a run). A record
|
|
38
|
+
* saved under an older declaration comes back as it is stored, with `issues` saying where the
|
|
39
|
+
* fields no longer accept it.
|
|
40
|
+
*/
|
|
41
|
+
export type Saved<R = Record<string, unknown>> = {
|
|
42
|
+
key: string;
|
|
43
|
+
record: R;
|
|
44
|
+
/** ISO 8601. */
|
|
45
|
+
updatedAt: string;
|
|
46
|
+
updatedBy: string;
|
|
47
|
+
issues?: {
|
|
48
|
+
path: (string | number)[];
|
|
49
|
+
message: string;
|
|
50
|
+
}[];
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* What a collection's `list` takes: fields equal to a value or within a range (`where`), the
|
|
54
|
+
* field to sort by (`-field` for descending; by key otherwise), and how many at most (1 to
|
|
55
|
+
* 1000, default 100).
|
|
56
|
+
*/
|
|
57
|
+
export type ListQuery<R> = {
|
|
58
|
+
where?: {
|
|
59
|
+
[F in keyof R]?: Exclude<R[F], undefined> | Range<Exclude<R[F], undefined>>;
|
|
60
|
+
};
|
|
61
|
+
order?: (keyof R & string) | `-${keyof R & string}`;
|
|
62
|
+
limit?: number;
|
|
63
|
+
};
|
|
64
|
+
type Range<V> = {
|
|
65
|
+
gt?: V;
|
|
66
|
+
gte?: V;
|
|
67
|
+
lt?: V;
|
|
68
|
+
lte?: V;
|
|
69
|
+
};
|
|
70
|
+
/** How many records a collection's `list` answers: `default` when the query names no `limit`, `max` at most. */
|
|
71
|
+
export declare const LIST_LIMIT: {
|
|
72
|
+
readonly default: 100;
|
|
73
|
+
readonly max: 1000;
|
|
74
|
+
};
|
|
75
|
+
/** The kinds of value a field holds: text, a number, true or false, a date (ISO 8601) or a person's id. */
|
|
76
|
+
export declare const FIELD_TYPES: readonly ["text", "number", "boolean", "date", "person"];
|
|
77
|
+
/**
|
|
78
|
+
* Throws unless `collection()` takes this declaration: the name a lowercase letter then letters
|
|
79
|
+
* and digits, at least one field, each a type, the type marked optional or an enum of distinct
|
|
80
|
+
* strings, the key a required text field, the title a string. `collection()` and the reader of
|
|
81
|
+
* `resources/data.ts` both ask it, so `sanoma check` refuses what the runtime would.
|
|
82
|
+
*/
|
|
83
|
+
export declare function checkCollection(declaration: {
|
|
84
|
+
name?: unknown;
|
|
85
|
+
key?: unknown;
|
|
86
|
+
fields?: unknown;
|
|
87
|
+
title?: unknown;
|
|
88
|
+
}): void;
|
|
89
|
+
/**
|
|
90
|
+
* The built-in call workflow's name: one operation that may be called directly (`isDirect`),
|
|
91
|
+
* made a run when the policy holds a direct call for an approval.
|
|
92
|
+
*/
|
|
93
|
+
export declare const CALL_WORKFLOW = "call";
|
|
94
|
+
/** The workflows the runtime adds itself, which a config's own may not be named: drift, apply and call. */
|
|
23
95
|
export declare const BUILT_IN_WORKFLOWS: ReadonlySet<string>;
|
|
24
96
|
/**
|
|
25
97
|
* Every run status, in the order a run may pass through them: waiting on the queue, running,
|
|
@@ -33,10 +105,63 @@ export declare const ENDED_STATUSES: readonly ["finished", "failed", "cancelled"
|
|
|
33
105
|
/** True when the run has finished, failed or been cancelled. */
|
|
34
106
|
export declare const isEnded: (status: RunStatus) => boolean;
|
|
35
107
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
108
|
+
* Why the run's own actor may not decide an approval on it: separation of duties (`mayDecide`),
|
|
109
|
+
* while someone else could decide it.
|
|
110
|
+
*/
|
|
111
|
+
export declare const OWN_CHANGE = "own change";
|
|
112
|
+
/** A run as `mayDecide` reads it: who started it, its own actor. */
|
|
113
|
+
type DecidedRun = {
|
|
114
|
+
actor?: Pick<Principal, "id"> | undefined;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* True when `by` may decide the approval on `run`: `by.id` is the approver, or `by.groups` holds
|
|
118
|
+
* the approver group. The run's own actor is refused only while someone else could decide (separation
|
|
119
|
+
* of duties): the approver is a group with another declared person in `people` (an agent does not
|
|
120
|
+
* count). Pure: everything it reads is passed in.
|
|
121
|
+
*/
|
|
122
|
+
export declare const mayDecide: (approval: Pick<ApprovalState, "approver">, by: Principal, run: DecidedRun, people: readonly PeopleResource[]) => boolean;
|
|
123
|
+
/** Why `by` may not decide the approval on `run` (`mayDecide`), naming who may, or `OWN_CHANGE`; undefined when they may. */
|
|
124
|
+
export declare function refusalOf({ approver }: Pick<ApprovalState, "approver">, by: Principal, run: DecidedRun, people: readonly PeopleResource[]): string | undefined;
|
|
125
|
+
/** A declared resource as the people functions read it: only the runtime's people types count. */
|
|
126
|
+
export type PeopleResource = Pick<DeclaredResource, "vendor" | "type" | "desired">;
|
|
127
|
+
/** The group every agent is in, the runtime's own among them: no data file declares it. */
|
|
128
|
+
export declare const AGENTS = "agents";
|
|
129
|
+
/** The runtime's own agents (scenarios, the host check, scheduled runs), declared whether a data file names them or not. */
|
|
130
|
+
export declare const RUNTIME_AGENTS: readonly string[];
|
|
131
|
+
type PersonFields = {
|
|
132
|
+
id: string;
|
|
133
|
+
name?: string;
|
|
134
|
+
email?: string;
|
|
135
|
+
github?: string;
|
|
136
|
+
};
|
|
137
|
+
/** The groups a policy may name and a principal may be in: the declared ones and `agents`, sorted. */
|
|
138
|
+
export declare const groupNamesOf: (resources: readonly PeopleResource[]) => string[];
|
|
139
|
+
/** The declared people (`sanoma.person`), in the order declared: not agents, who never sign in. */
|
|
140
|
+
export declare const personsOf: (resources: readonly PeopleResource[]) => PersonFields[];
|
|
141
|
+
/** The ids of the declared people and agents (not the runtime's own). */
|
|
142
|
+
export declare const principalIdsOf: (resources: readonly PeopleResource[]) => string[];
|
|
143
|
+
/** True when the data files declare a person, agent or group: then only a declared principal is admitted. */
|
|
144
|
+
export declare const declaresPeople: (resources: readonly PeopleResource[]) => boolean;
|
|
145
|
+
/**
|
|
146
|
+
* The principal a declared person or agent (or one of the runtime's own agents) acts as, read
|
|
147
|
+
* from the data files' resources: its id, every group that lists it (and `agents` for an agent),
|
|
148
|
+
* sorted, and an agent's `onBehalfOf`. Undefined for an id nobody declares.
|
|
38
149
|
*/
|
|
39
|
-
export declare function
|
|
150
|
+
export declare function principalOf(id: string, resources: readonly PeopleResource[]): Principal | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* Who `name` is as an approver: a declared group's name (or `agents`) as `{ group }`, else a
|
|
153
|
+
* declared person's or agent's id; undefined when it is neither.
|
|
154
|
+
*/
|
|
155
|
+
export declare function approverOf(name: string, resources: readonly PeopleResource[]): Approver | undefined;
|
|
156
|
+
/**
|
|
157
|
+
* The id of the declared person a sign-in vouches for, or undefined: by email first, then by
|
|
158
|
+
* GitHub login (each ignoring case), then by id. Never an agent's: agents do not sign in.
|
|
159
|
+
*/
|
|
160
|
+
export declare function personOf(login: {
|
|
161
|
+
email?: string;
|
|
162
|
+
github?: string;
|
|
163
|
+
id?: string;
|
|
164
|
+
}, resources: readonly PeopleResource[]): string | undefined;
|
|
40
165
|
/** Who may decide, as text: the person's id, or "group <name>". */
|
|
41
166
|
export declare const approverLabel: (approver: Approver) => string;
|
|
42
167
|
/** An error's message, or the value as text when it is not an Error. */
|
|
@@ -67,3 +192,54 @@ export declare function problemLine(p: {
|
|
|
67
192
|
export declare const isLoopback: (host: string) => boolean;
|
|
68
193
|
/** Whether a driver's environment variable lets it run: set, or unset and optional. */
|
|
69
194
|
export declare const credentialReady: ({ status, optional }: CredentialStatus) => boolean;
|
|
195
|
+
/**
|
|
196
|
+
* A workflow's name in a site's `api`: kebab-case made camelCase, `outbound-next` as
|
|
197
|
+
* `api.outboundNext`. `describeConfig` reports two workflows that come out the same, or one that
|
|
198
|
+
* comes out as a vendor's id or `data`, as a problem on the workflow.
|
|
199
|
+
*/
|
|
200
|
+
export declare const apiNameOf: (name: string) => string;
|
|
201
|
+
/**
|
|
202
|
+
* A workflow as a site's `api` has it (`api.<apiNameOf(name)>`), started as the person on the
|
|
203
|
+
* page. Called, it starts a run and resolves with its output once the run ends, or rejects with
|
|
204
|
+
* its error; `start` gives the run's id at once, and the rest read runs of this workflow.
|
|
205
|
+
*/
|
|
206
|
+
export interface WorkflowFn<I, O> {
|
|
207
|
+
(input: I): Promise<O>;
|
|
208
|
+
/** Starts a run with this input, and answers with its id. */
|
|
209
|
+
start(input: I): Promise<{
|
|
210
|
+
runId: string;
|
|
211
|
+
}>;
|
|
212
|
+
/** The run's output once it ends, or its error; `run_running` when it has not ended within `waitMs` (at most 20 s). */
|
|
213
|
+
result(runId: string, waitMs?: number): Promise<O>;
|
|
214
|
+
/** The newest finished run's output, and when it finished (ms since the epoch); null when none has. */
|
|
215
|
+
latest(): Promise<{
|
|
216
|
+
runId: string;
|
|
217
|
+
output: O;
|
|
218
|
+
at: number;
|
|
219
|
+
} | null>;
|
|
220
|
+
/** Its latest runs, newest first. */
|
|
221
|
+
runs(query?: {
|
|
222
|
+
limit?: number;
|
|
223
|
+
}): Promise<RunSummary[]>;
|
|
224
|
+
/** The run's approvals, decided and waiting. */
|
|
225
|
+
approvals(runId: string): Promise<ApprovalState[]>;
|
|
226
|
+
/** The run's ledger records, in order. */
|
|
227
|
+
ledger(runId: string): Promise<LedgerRecord[]>;
|
|
228
|
+
}
|
|
229
|
+
/** An operation a site may call directly (a read, or a collection's write), as the person on the page. */
|
|
230
|
+
export type OpFn<I, O> = (input: I) => Promise<O>;
|
|
231
|
+
/** A collection as a site's `api.data.<name>` has it: its four operations (`Saved`, `ListQuery`). */
|
|
232
|
+
export interface CollectionApi<R> {
|
|
233
|
+
get: OpFn<{
|
|
234
|
+
key: string;
|
|
235
|
+
}, Saved<R> | null>;
|
|
236
|
+
list(query?: ListQuery<R>): Promise<Saved<R>[]>;
|
|
237
|
+
save: OpFn<{
|
|
238
|
+
record: R;
|
|
239
|
+
}, Saved<R>>;
|
|
240
|
+
delete: OpFn<{
|
|
241
|
+
key: string;
|
|
242
|
+
}, {
|
|
243
|
+
deleted: boolean;
|
|
244
|
+
}>;
|
|
245
|
+
}
|
package/dist/shared.js
CHANGED
|
@@ -13,8 +13,85 @@ export const DRIFT_WORKFLOW = "drift";
|
|
|
13
13
|
* change operations (`create`, `update`, `delete`).
|
|
14
14
|
*/
|
|
15
15
|
export const APPLY_WORKFLOW = "apply";
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The vendor of the collections' operations, `data.<collection>.<op>`: a collection's `get`,
|
|
18
|
+
* `list`, `save` and `delete`. No connector may take it.
|
|
19
|
+
*/
|
|
20
|
+
export const DATA_VENDOR = "data";
|
|
21
|
+
/** Every effect an operation may have, each an action group (`effect:<effect>`) of the Cedar schema. */
|
|
22
|
+
export const EFFECTS = ["read", "write", "publish", "send", "money", "access"];
|
|
23
|
+
/** What a workflow start's action id starts with, as a policy names it: `workflow:<name>`. */
|
|
24
|
+
export const WORKFLOW_ACTION = "workflow:";
|
|
25
|
+
/** A site's folder name under `sites/`, its URL segment: what the app mounts and `readSites` reads. */
|
|
26
|
+
export const SITE_NAME = /^[a-z][a-z0-9-]*$/;
|
|
27
|
+
/** How many records a collection's `list` answers: `default` when the query names no `limit`, `max` at most. */
|
|
28
|
+
export const LIST_LIMIT = { default: 100, max: 1000 };
|
|
29
|
+
/** The kinds of value a field holds: text, a number, true or false, a date (ISO 8601) or a person's id. */
|
|
30
|
+
export const FIELD_TYPES = ["text", "number", "boolean", "date", "person"];
|
|
31
|
+
const COLLECTION_NAME = /^[a-z][a-zA-Z0-9]*$/;
|
|
32
|
+
const FIELD_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
33
|
+
const KINDS = `${FIELD_TYPES.map((t) => `"${t}"`).join(", ")}, { type, optional: true } or { enum: [...] }`;
|
|
34
|
+
const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
35
|
+
/**
|
|
36
|
+
* Throws unless `collection()` takes this declaration: the name a lowercase letter then letters
|
|
37
|
+
* and digits, at least one field, each a type, the type marked optional or an enum of distinct
|
|
38
|
+
* strings, the key a required text field, the title a string. `collection()` and the reader of
|
|
39
|
+
* `resources/data.ts` both ask it, so `sanoma check` refuses what the runtime would.
|
|
40
|
+
*/
|
|
41
|
+
export function checkCollection(declaration) {
|
|
42
|
+
const { name, key, fields, title } = declaration;
|
|
43
|
+
const where = `collection("${String(name)}")`;
|
|
44
|
+
if (typeof name !== "string" || !COLLECTION_NAME.test(name)) {
|
|
45
|
+
throw new Error(`${where}: the name must be a lowercase letter, then letters and digits, such as "outbound"`);
|
|
46
|
+
}
|
|
47
|
+
if (!isRecord(fields) || !Object.keys(fields).length) {
|
|
48
|
+
throw new Error(`${where}: it needs fields, by name: each one of ${KINDS}`);
|
|
49
|
+
}
|
|
50
|
+
for (const [field, kind] of Object.entries(fields))
|
|
51
|
+
checkField(where, field, kind);
|
|
52
|
+
const keyKind = typeof key === "string" && Object.hasOwn(fields, key) ? fields[key] : undefined;
|
|
53
|
+
if (!(keyKind === "text" || (isRecord(keyKind) && keyKind.type === "text" && keyKind.optional === undefined))) {
|
|
54
|
+
throw new Error(`${where}: the key "${String(key)}" must be one of its fields, a required "text" one`);
|
|
55
|
+
}
|
|
56
|
+
if (title !== undefined && typeof title !== "string")
|
|
57
|
+
throw new Error(`${where}: the title must be a string`);
|
|
58
|
+
}
|
|
59
|
+
/** Throws unless `kind` is a field `collection()` takes: a type, the type marked optional, or an enum of distinct strings. */
|
|
60
|
+
function checkField(where, field, kind) {
|
|
61
|
+
const refused = (why) => new Error(`${where}: the field "${field}" ${why}`);
|
|
62
|
+
if (!FIELD_NAME.test(field))
|
|
63
|
+
throw refused("must be named with letters, digits and _, not a digit first");
|
|
64
|
+
const types = FIELD_TYPES;
|
|
65
|
+
const kinds = `is ${JSON.stringify(kind)}; a field is one of ${KINDS}`;
|
|
66
|
+
if (typeof kind === "string") {
|
|
67
|
+
if (!types.includes(kind))
|
|
68
|
+
throw refused(kinds);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!isRecord(kind))
|
|
72
|
+
throw refused(kinds);
|
|
73
|
+
const { type, enum: values, optional, ...rest } = kind;
|
|
74
|
+
if (Object.keys(rest).length || (type === undefined) === (values === undefined))
|
|
75
|
+
throw refused(kinds);
|
|
76
|
+
if (optional !== undefined && optional !== true)
|
|
77
|
+
throw refused("may only be marked `optional: true`");
|
|
78
|
+
if (type !== undefined && !types.includes(type))
|
|
79
|
+
throw refused(kinds);
|
|
80
|
+
if (values !== undefined &&
|
|
81
|
+
(!Array.isArray(values) ||
|
|
82
|
+
!values.length ||
|
|
83
|
+
values.some((v) => typeof v !== "string") ||
|
|
84
|
+
new Set(values).size < values.length)) {
|
|
85
|
+
throw refused("needs an enum of distinct strings, at least one");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The built-in call workflow's name: one operation that may be called directly (`isDirect`),
|
|
90
|
+
* made a run when the policy holds a direct call for an approval.
|
|
91
|
+
*/
|
|
92
|
+
export const CALL_WORKFLOW = "call";
|
|
93
|
+
/** The workflows the runtime adds itself, which a config's own may not be named: drift, apply and call. */
|
|
94
|
+
export const BUILT_IN_WORKFLOWS = new Set([DRIFT_WORKFLOW, APPLY_WORKFLOW, CALL_WORKFLOW]);
|
|
18
95
|
/**
|
|
19
96
|
* Every run status, in the order a run may pass through them: waiting on the queue, running,
|
|
20
97
|
* waiting for an approval, or ended. `waiting` is `running` with an approval pending.
|
|
@@ -25,12 +102,82 @@ export const ENDED_STATUSES = ["finished", "failed", "cancelled"];
|
|
|
25
102
|
/** True when the run has finished, failed or been cancelled. */
|
|
26
103
|
export const isEnded = (status) => ENDED_STATUSES.includes(status);
|
|
27
104
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
105
|
+
* Why the run's own actor may not decide an approval on it: separation of duties (`mayDecide`),
|
|
106
|
+
* while someone else could decide it.
|
|
30
107
|
*/
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
108
|
+
export const OWN_CHANGE = "own change";
|
|
109
|
+
/**
|
|
110
|
+
* True when `by` may decide the approval on `run`: `by.id` is the approver, or `by.groups` holds
|
|
111
|
+
* the approver group. The run's own actor is refused only while someone else could decide (separation
|
|
112
|
+
* of duties): the approver is a group with another declared person in `people` (an agent does not
|
|
113
|
+
* count). Pure: everything it reads is passed in.
|
|
114
|
+
*/
|
|
115
|
+
export const mayDecide = (approval, by, run, people) => refusalOf(approval, by, run, people) === undefined;
|
|
116
|
+
/** Why `by` may not decide the approval on `run` (`mayDecide`), naming who may, or `OWN_CHANGE`; undefined when they may. */
|
|
117
|
+
export function refusalOf({ approver }, by, run, people) {
|
|
118
|
+
if (typeof approver === "string") {
|
|
119
|
+
return approver === by.id ? undefined : `${by.id} is not the approver; ${approverLabel(approver)} is`;
|
|
120
|
+
}
|
|
121
|
+
if (!by.groups?.includes(approver.group))
|
|
122
|
+
return `${by.id} is not in ${approverLabel(approver)}`;
|
|
123
|
+
if (by.id !== run.actor?.id)
|
|
124
|
+
return undefined;
|
|
125
|
+
const someoneElse = personsOf(people).some(({ id }) => id !== by.id && principalOf(id, people)?.groups?.includes(approver.group));
|
|
126
|
+
return someoneElse ? OWN_CHANGE : undefined;
|
|
127
|
+
}
|
|
128
|
+
/** The group every agent is in, the runtime's own among them: no data file declares it. */
|
|
129
|
+
export const AGENTS = "agents";
|
|
130
|
+
/** The runtime's own agents (scenarios, the host check, scheduled runs), declared whether a data file names them or not. */
|
|
131
|
+
export const RUNTIME_AGENTS = ["scenarios", "host-check", "schedule"];
|
|
132
|
+
/** The declared resources of one of the runtime's people types, by `desired`. */
|
|
133
|
+
const peopleOfType = (resources, type) => resources.flatMap((r) => (r.vendor === "sanoma" && r.type === type ? [r.desired] : []));
|
|
134
|
+
/** The groups a policy may name and a principal may be in: the declared ones and `agents`, sorted. */
|
|
135
|
+
export const groupNamesOf = (resources) => [...new Set([...peopleOfType(resources, "group").map((g) => g.name), AGENTS])].toSorted();
|
|
136
|
+
/** The declared people (`sanoma.person`), in the order declared: not agents, who never sign in. */
|
|
137
|
+
export const personsOf = (resources) => peopleOfType(resources, "person");
|
|
138
|
+
/** The ids of the declared people and agents (not the runtime's own). */
|
|
139
|
+
export const principalIdsOf = (resources) => [...personsOf(resources), ...peopleOfType(resources, "agent")].map((p) => p.id);
|
|
140
|
+
/** True when the data files declare a person, agent or group: then only a declared principal is admitted. */
|
|
141
|
+
export const declaresPeople = (resources) => resources.some((r) => r.vendor === "sanoma");
|
|
142
|
+
/**
|
|
143
|
+
* The principal a declared person or agent (or one of the runtime's own agents) acts as, read
|
|
144
|
+
* from the data files' resources: its id, every group that lists it (and `agents` for an agent),
|
|
145
|
+
* sorted, and an agent's `onBehalfOf`. Undefined for an id nobody declares.
|
|
146
|
+
*/
|
|
147
|
+
export function principalOf(id, resources) {
|
|
148
|
+
const agent = peopleOfType(resources, "agent").find((a) => a.id === id);
|
|
149
|
+
const isAgent = agent !== undefined || RUNTIME_AGENTS.includes(id);
|
|
150
|
+
if (!isAgent && !peopleOfType(resources, "person").some((p) => p.id === id))
|
|
151
|
+
return undefined;
|
|
152
|
+
const groups = peopleOfType(resources, "group")
|
|
153
|
+
.filter((g) => g.members.includes(id))
|
|
154
|
+
.map((g) => g.name);
|
|
155
|
+
return {
|
|
156
|
+
id,
|
|
157
|
+
groups: [...new Set(isAgent ? [...groups, AGENTS] : groups)].toSorted(),
|
|
158
|
+
...(agent?.onBehalfOf !== undefined && { onBehalfOf: agent.onBehalfOf }),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Who `name` is as an approver: a declared group's name (or `agents`) as `{ group }`, else a
|
|
163
|
+
* declared person's or agent's id; undefined when it is neither.
|
|
164
|
+
*/
|
|
165
|
+
export function approverOf(name, resources) {
|
|
166
|
+
if (groupNamesOf(resources).includes(name))
|
|
167
|
+
return { group: name };
|
|
168
|
+
return principalOf(name, resources) && name;
|
|
169
|
+
}
|
|
170
|
+
/** True for two strings the same but for case: an email or a GitHub login. */
|
|
171
|
+
const same = (a, b) => a !== undefined && b !== undefined && a.toLowerCase() === b.toLowerCase();
|
|
172
|
+
/**
|
|
173
|
+
* The id of the declared person a sign-in vouches for, or undefined: by email first, then by
|
|
174
|
+
* GitHub login (each ignoring case), then by id. Never an agent's: agents do not sign in.
|
|
175
|
+
*/
|
|
176
|
+
export function personOf(login, resources) {
|
|
177
|
+
const people = personsOf(resources);
|
|
178
|
+
return (people.find((p) => same(p.email, login.email)) ??
|
|
179
|
+
people.find((p) => same(p.github, login.github)) ??
|
|
180
|
+
people.find((p) => login.id !== undefined && p.id === login.id))?.id;
|
|
34
181
|
}
|
|
35
182
|
/** Who may decide, as text: the person's id, or "group <name>". */
|
|
36
183
|
export const approverLabel = (approver) => typeof approver === "string" ? approver : `group ${approver.group}`;
|
|
@@ -81,4 +228,10 @@ export function problemLine(p) {
|
|
|
81
228
|
export const isLoopback = (host) => ["localhost", "::1", "[::1]"].includes(host) || /^127\.\d+\.\d+\.\d+$/.test(host);
|
|
82
229
|
/** Whether a driver's environment variable lets it run: set, or unset and optional. */
|
|
83
230
|
export const credentialReady = ({ status, optional }) => status === "set" || (status === "missing" && optional);
|
|
231
|
+
/**
|
|
232
|
+
* A workflow's name in a site's `api`: kebab-case made camelCase, `outbound-next` as
|
|
233
|
+
* `api.outboundNext`. `describeConfig` reports two workflows that come out the same, or one that
|
|
234
|
+
* comes out as a vendor's id or `data`, as a problem on the workflow.
|
|
235
|
+
*/
|
|
236
|
+
export const apiNameOf = (name) => name.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
84
237
|
//# sourceMappingURL=shared.js.map
|
package/dist/shared.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"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"}
|