@sanoma-ai/workflows 0.9.1 → 0.10.1
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 +193 -50
- package/SECRET-SUPPORT.md +33 -0
- 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 +27 -13
- 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 +13 -24
- package/dist/apps.js +69 -68
- 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 +54 -0
- package/dist/authentication.js +138 -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 +36 -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 +62 -10
- package/dist/client.js +272 -47
- 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 +16 -4
- package/dist/config.js +89 -21
- package/dist/config.js.map +1 -1
- package/dist/connection.d.ts +389 -0
- package/dist/connection.js +657 -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/db.js +34 -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 +15 -175
- package/dist/describe.js +122 -35
- 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 +7 -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/fake.d.ts +13 -1
- package/dist/fake.js +70 -0
- package/dist/fake.js.map +1 -1
- package/dist/index.d.ts +11 -3
- 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 +2 -17
- package/dist/lint.js.map +1 -1
- package/dist/load.d.ts +85 -0
- package/dist/load.js +391 -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 +22 -5
- package/dist/op.js +20 -2
- package/dist/op.js.map +1 -1
- package/dist/outline.d.ts +5 -0
- package/dist/outline.js +46 -5
- package/dist/outline.js.map +1 -1
- package/dist/paths.d.ts +18 -2
- package/dist/paths.js +19 -7
- 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 +10 -4
- package/dist/resource.js +11 -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 +4 -0
- package/dist/run.js.map +1 -1
- package/dist/sandbox.d.ts +5 -2
- package/dist/sandbox.js +56 -7
- package/dist/sandbox.js.map +1 -1
- package/dist/scenario.d.ts +5 -0
- package/dist/scenario.js +3 -2
- 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/secret.d.ts +2 -0
- package/dist/secret.js +32 -0
- package/dist/secret.js.map +1 -1
- package/dist/shared.d.ts +21 -11
- package/dist/shared.js +41 -7
- package/dist/shared.js.map +1 -1
- package/dist/sites.d.ts +4 -93
- package/dist/sites.js +76 -84
- package/dist/sites.js.map +1 -1
- package/dist/steps.d.ts +3 -0
- 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 +1 -5
- package/package.json +6 -1
- package/src/apply-steps.ts +5 -2
- package/src/apply.ts +54 -21
- package/src/approvals.ts +7 -1
- package/src/apps.ts +71 -86
- package/src/ast.ts +6 -6
- package/src/authentication.ts +191 -0
- package/src/call-workflow.ts +5 -4
- package/src/call.ts +52 -9
- package/src/cedar.ts +14 -1
- package/src/change-steps.ts +7 -4
- package/src/change.ts +10 -0
- package/src/client.ts +346 -45
- package/src/collection.ts +10 -2
- package/src/config.ts +107 -19
- package/src/connection.ts +912 -0
- package/src/credentials.ts +94 -281
- package/src/db.ts +34 -2
- package/src/define.ts +7 -2
- package/src/definitions.ts +31 -0
- package/src/deployment-key.ts +23 -0
- package/src/describe.ts +150 -227
- package/src/description.ts +426 -0
- package/src/direct.ts +7 -0
- package/src/drift.ts +10 -2
- package/src/env.ts +4 -2
- package/src/fake.ts +71 -0
- package/src/index.ts +53 -1
- package/src/ledger.ts +3 -1
- package/src/lint.ts +2 -17
- package/src/load.ts +466 -0
- package/src/lockfile.ts +10 -3
- package/src/op.ts +41 -7
- package/src/outline.ts +53 -7
- package/src/paths.ts +21 -6
- package/src/plugin.ts +3 -24
- package/src/policy.ts +2 -0
- package/src/resource.ts +24 -6
- package/src/resources.ts +246 -301
- package/src/run.ts +4 -0
- package/src/sandbox.ts +61 -7
- package/src/scenario.ts +24 -6
- 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/secret.ts +29 -0
- package/src/shared.ts +44 -10
- package/src/sites.ts +85 -179
- package/src/steps.ts +3 -2
- 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
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
// `@sanoma-ai/workflows/description`: what `describeConfig` answers, as zod schemas, and its
|
|
2
|
+
// types inferred from them. zod only, no Node: a page can parse a description it is sent, and the
|
|
3
|
+
// app extends `ConfigDescriptionSchema` with what it adds (`AppConfigSchema`).
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import type { Outline } from "./outline.ts";
|
|
6
|
+
import type { ResourceFields } from "./resource.ts";
|
|
7
|
+
import { EFFECTS, FIELD_TYPES } from "./shared.ts";
|
|
8
|
+
|
|
9
|
+
/** A JSON Schema (draft 2020-12), as `jsonSchemaOf` writes one. */
|
|
10
|
+
const JsonSchema = z.record(z.string(), z.unknown());
|
|
11
|
+
|
|
12
|
+
/** Where a declaration is: its file, relative to the root with `/`, and the export that holds it (`default` for a default export). */
|
|
13
|
+
export const AtSchema = z.strictObject({ file: z.string(), export: z.string() });
|
|
14
|
+
export type At = z.infer<typeof AtSchema>;
|
|
15
|
+
|
|
16
|
+
/** Something wrong in a file, at a line and column from 1 (UTF-16 code units). */
|
|
17
|
+
export const LintProblemSchema = z.strictObject({ line: z.number(), column: z.number(), message: z.string() });
|
|
18
|
+
export type LintProblem = z.infer<typeof LintProblemSchema>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Something wrong in a company's files (a data file, an app's `app.ts`, a site's `site.ts`), or in
|
|
22
|
+
* finding them: at a place in the file when an error's stack gives one, else at an export.
|
|
23
|
+
*/
|
|
24
|
+
export const ResourceProblemSchema = z.strictObject({
|
|
25
|
+
/**
|
|
26
|
+
* The file, relative to the config's root, with `/`: `resources/identity/github.ts`. Absent
|
|
27
|
+
* when the problem is the config's: it has no root.
|
|
28
|
+
*/
|
|
29
|
+
file: z.string().optional(),
|
|
30
|
+
/** The export it is about: `website`, or `default`. */
|
|
31
|
+
export: z.string().optional(),
|
|
32
|
+
/** From 1. */
|
|
33
|
+
line: z.number().optional(),
|
|
34
|
+
/** From 1, in UTF-16 code units. */
|
|
35
|
+
column: z.number().optional(),
|
|
36
|
+
message: z.string(),
|
|
37
|
+
});
|
|
38
|
+
export type ResourceProblem = z.infer<typeof ResourceProblemSchema>;
|
|
39
|
+
|
|
40
|
+
/** A problem at a file, relative to the root: an app's, a site's. */
|
|
41
|
+
const FileProblemSchema = ResourceProblemSchema.extend({ file: z.string() });
|
|
42
|
+
|
|
43
|
+
/** A declaration's named connection: which grant of its vendor it is applied with. */
|
|
44
|
+
const ConnectionRefSchema = z.strictObject({
|
|
45
|
+
$connection: z.string(),
|
|
46
|
+
vendor: z.string(),
|
|
47
|
+
revision: z.string().optional(),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/** A resource a data file declares, as loading the file made it. */
|
|
51
|
+
export const DeclaredResourceSchema = z.strictObject({
|
|
52
|
+
/** `<file>#<export>`, the file relative to the config's root, with `/`: `resources/identity/github.ts#website`. */
|
|
53
|
+
id: z.string(),
|
|
54
|
+
/** The data file it is declared in, as `id` names it: `resources/identity/github.ts`. */
|
|
55
|
+
file: z.string(),
|
|
56
|
+
vendor: z.string(),
|
|
57
|
+
type: z.string(),
|
|
58
|
+
/** What people call it: its identity, else its export's name. */
|
|
59
|
+
name: z.string(),
|
|
60
|
+
/** The import id that finds it unbound: what its type's `find` makes of its fields; absent when the type has none. */
|
|
61
|
+
identity: z.string().optional(),
|
|
62
|
+
/** The vendor's id of the object the lockfile binds it to (`LOCKFILE`); absent when unbound. */
|
|
63
|
+
binding: z.string().optional(),
|
|
64
|
+
/** Its file and export. */
|
|
65
|
+
at: AtSchema,
|
|
66
|
+
/** Its fields, as its type checked them: each resource it names as that resource's `name`. */
|
|
67
|
+
desired: z.record(z.string(), z.unknown()),
|
|
68
|
+
connection: ConnectionRefSchema.optional(),
|
|
69
|
+
/**
|
|
70
|
+
* Where it names another declared resource: the field's dotted path (a list item's with its
|
|
71
|
+
* index, `teams.0`) to that resource's id.
|
|
72
|
+
*/
|
|
73
|
+
refs: z.record(z.string(), z.string()),
|
|
74
|
+
});
|
|
75
|
+
export type DeclaredResource = z.infer<typeof DeclaredResourceSchema>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A collection `resources/data.ts` declares: where it is, for its declaration on Hosting. Its fields are
|
|
79
|
+
* the collection's own (`describeConfig`'s `collections`), from the same file, which the runtime
|
|
80
|
+
* imports.
|
|
81
|
+
*/
|
|
82
|
+
export const DeclaredCollectionSchema = z.strictObject({
|
|
83
|
+
/** `<file>#<export>`, as a resource's: `resources/data.ts#outbound`. */
|
|
84
|
+
id: z.string(),
|
|
85
|
+
/** `resources/data.ts`, or an app's `apps/<app>/resources/data.ts`. */
|
|
86
|
+
file: z.string(),
|
|
87
|
+
/** The collection's name, its operations' middle segments (`data.<name>.get`): an app's with its app, `crm.contacts`. */
|
|
88
|
+
name: z.string(),
|
|
89
|
+
/** Its file and export. */
|
|
90
|
+
at: AtSchema,
|
|
91
|
+
});
|
|
92
|
+
export type DeclaredCollection = z.infer<typeof DeclaredCollectionSchema>;
|
|
93
|
+
|
|
94
|
+
/** A lockfile binding no data file declares, by its key (`<file>#<export>`). */
|
|
95
|
+
const OrphanSchema = z.strictObject({
|
|
96
|
+
key: z.string(),
|
|
97
|
+
type: z.string(),
|
|
98
|
+
id: z.string(),
|
|
99
|
+
connection: ConnectionRefSchema.optional(),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/** An app: a folder of `apps/`, and what its `app.ts` declares. */
|
|
103
|
+
export const AppEntrySchema = z.strictObject({
|
|
104
|
+
/** The folder's name, which prefixes what it declares (`crm.contacts`) and is the app's title. */
|
|
105
|
+
name: z.string(),
|
|
106
|
+
/** The folder, relative to the root, with `/`: `apps/crm`. */
|
|
107
|
+
dir: z.string(),
|
|
108
|
+
/** `defineApp({ source })` in its `app.ts`: the repository it was taken from; absent for the company's own app. */
|
|
109
|
+
source: z.string().optional(),
|
|
110
|
+
/** Its `app.ts`'s default export, when it has the file. */
|
|
111
|
+
at: AtSchema.optional(),
|
|
112
|
+
});
|
|
113
|
+
export type AppEntry = z.infer<typeof AppEntrySchema>;
|
|
114
|
+
|
|
115
|
+
/** A call a site's code makes: `<RunForm workflow="…" />`, or a use of `api`. */
|
|
116
|
+
export const SiteCallSchema = z.strictObject({
|
|
117
|
+
/** What it calls: a workflow, a collection (`api.data.<name>.<op>`) or an operation (`api.<vendor>.<resource>.<op>`). */
|
|
118
|
+
kind: z.enum(["workflow", "collection", "op"]),
|
|
119
|
+
/**
|
|
120
|
+
* The workflow's name (`RunForm`'s `workflow`, or the workflow whose `apiNameOf` is the name
|
|
121
|
+
* `api` gives; that name itself when none is), the collection's name, or the operation's id.
|
|
122
|
+
*/
|
|
123
|
+
target: z.string(),
|
|
124
|
+
/**
|
|
125
|
+
* What it calls of the workflow (`start`, or a read of its runs: `result`, `latest`, …) or the
|
|
126
|
+
* collection (`list`, `save`, …), as written; absent for a workflow called as itself or by
|
|
127
|
+
* `RunForm`, which starts it, and for an operation.
|
|
128
|
+
*/
|
|
129
|
+
method: z.string().optional(),
|
|
130
|
+
/** `<RunForm workflow="…" />` or a call on `api`, from `sanoma/site`. */
|
|
131
|
+
via: z.enum(["RunForm", "api"]),
|
|
132
|
+
/** The file, relative to the config's root, with `/`: `sites/sales/routes/index.tsx`. */
|
|
133
|
+
file: z.string(),
|
|
134
|
+
/** From 1. */
|
|
135
|
+
line: z.number(),
|
|
136
|
+
/** From 1, in UTF-16 code units. */
|
|
137
|
+
column: z.number(),
|
|
138
|
+
/**
|
|
139
|
+
* The path of the page the file is, from its `createFileRoute` (or `createLazyFileRoute`) id: groups and pathless
|
|
140
|
+
* segments left out, no trailing slash (`/sites/sales`). Absent for a file that is no page,
|
|
141
|
+
* such as a component's.
|
|
142
|
+
*/
|
|
143
|
+
page: z.string().optional(),
|
|
144
|
+
});
|
|
145
|
+
export type SiteCall = z.infer<typeof SiteCallSchema>;
|
|
146
|
+
|
|
147
|
+
/** A page of a site: a route file's path, and for a page per content entry the kind it reads. */
|
|
148
|
+
export const SitePageSchema = z.strictObject({
|
|
149
|
+
/** As `SiteCall.page` has it: `/sites/www`, `/sites/www/blog/$slug`. */
|
|
150
|
+
path: z.string(),
|
|
151
|
+
/**
|
|
152
|
+
* For a path with one parameter (`$slug`), the content kind whose entries are its pages: the one
|
|
153
|
+
* kind its file reads by that parameter, `content.<kind>.get(params.slug)` (or `slug`,
|
|
154
|
+
* destructured) with `content` from `sanoma/site`.
|
|
155
|
+
*/
|
|
156
|
+
content: z.string().optional(),
|
|
157
|
+
/**
|
|
158
|
+
* `false` when its route says `staticData: { sitemap: false }`, written out: the sitemap leaves it
|
|
159
|
+
* out. Its index route's `sitemap` (`true` or `false`) decides over a layout's at its path; a
|
|
160
|
+
* pathless or group layout's says nothing.
|
|
161
|
+
*/
|
|
162
|
+
sitemap: z.literal(false).optional(),
|
|
163
|
+
});
|
|
164
|
+
export type SitePage = z.infer<typeof SitePageSchema>;
|
|
165
|
+
|
|
166
|
+
/** A site, `sites/<name>/` or an app's `apps/<app>/sites/<name>/`, and what it calls. */
|
|
167
|
+
export const SiteEntrySchema = z.strictObject({
|
|
168
|
+
/** Its folder's name, `<app>/<name>` for an app's (`siteKey`): where it is mounted, `/sites/<name>`. */
|
|
169
|
+
name: z.string(),
|
|
170
|
+
/** The app whose folder holds it (`apps/<app>/sites/`); absent for one at the root. */
|
|
171
|
+
app: z.string().optional(),
|
|
172
|
+
/** Its `site.ts`'s default export, when it has the file. */
|
|
173
|
+
at: AtSchema.optional(),
|
|
174
|
+
/** `defineSite({ title })` in its `site.ts`. */
|
|
175
|
+
title: z.string().optional(),
|
|
176
|
+
/** `defineSite({ icon })` in its `site.ts`: a Lucide icon's name, as written. */
|
|
177
|
+
icon: z.string().optional(),
|
|
178
|
+
/** `defineSite({ public: true })`: served to visitors, not people. */
|
|
179
|
+
public: z.literal(true).optional(),
|
|
180
|
+
/** `defineSite({ login })`, the connector whose login half signs visitors in: one that names none is among `problems`. */
|
|
181
|
+
login: z.string().optional(),
|
|
182
|
+
/**
|
|
183
|
+
* `defineSite({ locales })`, a public site's languages, the first its default: kept only when
|
|
184
|
+
* every one is a `LOCALE`, written once, on a public site with no login; else a problem.
|
|
185
|
+
*/
|
|
186
|
+
locales: z.array(z.string()).optional(),
|
|
187
|
+
/** The host a public site answers on: set by `startApp` from its `domains`, never by `readSites`. */
|
|
188
|
+
domain: z.string().optional(),
|
|
189
|
+
/** Its pages, by path: one for each path its `routes/` files give (a layout and its index are one). */
|
|
190
|
+
pages: z.array(SitePageSchema),
|
|
191
|
+
/** Its calls, by file and then in the file's order. */
|
|
192
|
+
calls: z.array(SiteCallSchema),
|
|
193
|
+
/**
|
|
194
|
+
* Each call to a workflow, a collection or an operation the config does not have, or to an
|
|
195
|
+
* operation a page may not call directly, or, on a public site, that no policy lets a visitor
|
|
196
|
+
* make, at its file; then what is wrong in its `site.ts`.
|
|
197
|
+
*/
|
|
198
|
+
problems: z.array(FileProblemSchema),
|
|
199
|
+
/**
|
|
200
|
+
* On a public site, each page with one parameter whose file reads content the sitemap cannot
|
|
201
|
+
* tie to it (`SitePage.content`), so the sitemap lists none of its pages: at the first read.
|
|
202
|
+
*/
|
|
203
|
+
warnings: z.array(LintProblemSchema.extend({ file: z.string() })),
|
|
204
|
+
});
|
|
205
|
+
export type SiteEntry = z.infer<typeof SiteEntrySchema>;
|
|
206
|
+
|
|
207
|
+
/** `manual`, or the schedule a workflow starts on (`defineWorkflow`'s `trigger`). */
|
|
208
|
+
const TriggerSchema = z.union([
|
|
209
|
+
z.literal("manual"),
|
|
210
|
+
z.strictObject({ schedule: z.string(), timezone: z.string().optional() }),
|
|
211
|
+
]);
|
|
212
|
+
|
|
213
|
+
/** What a workflow is, read from its definition: enough to draw a start form and show what it may call. */
|
|
214
|
+
export const WorkflowEntrySchema = z.strictObject({
|
|
215
|
+
/** Its name: `<app>.<name>` for one an app's folder defines. */
|
|
216
|
+
name: z.string(),
|
|
217
|
+
/** The app whose folder defines it (`apps/<app>/workflows/`); absent for one at the root. */
|
|
218
|
+
app: z.string().optional(),
|
|
219
|
+
title: z.string().optional(),
|
|
220
|
+
/** `manual`, or the schedule it starts on (`defineWorkflow`'s `trigger`). */
|
|
221
|
+
trigger: TriggerSchema,
|
|
222
|
+
/**
|
|
223
|
+
* Set for a workflow the runtime adds itself, `drift`, `apply` or `call`, rather than the config: a label. It
|
|
224
|
+
* starts like any other.
|
|
225
|
+
*/
|
|
226
|
+
builtin: z.literal(true).optional(),
|
|
227
|
+
/** The input, as JSON Schema (draft 2020-12), from the zod schema. */
|
|
228
|
+
input: JsonSchema,
|
|
229
|
+
/** Operation ids the workflow may call, in the order declared. */
|
|
230
|
+
ops: z.array(z.string()),
|
|
231
|
+
/** Built-ins the workflow may call. */
|
|
232
|
+
builtins: z.array(z.enum(["approval", "sleep", "all"])),
|
|
233
|
+
/** The file that defined it, absolute. */
|
|
234
|
+
file: z.string(),
|
|
235
|
+
/** What its `run` calls, in order, read from its file (`outlineWorkflow`), which the worker holds its runs to. */
|
|
236
|
+
outline: z.custom<Outline>(),
|
|
237
|
+
/**
|
|
238
|
+
* What is wrong in its file, by position: what `lintWorkflow` finds (syntax, an import a
|
|
239
|
+
* workflow may not make, `instanceof` against the runtime's error classes, what the outline
|
|
240
|
+
* cannot draw in each `run`), read the one way the outline is, so a check sees what the
|
|
241
|
+
* worker refuses; and, at 1:1, an outline error that is the file's (it cannot be read, or holds
|
|
242
|
+
* no workflow of this name). A file defining several workflows gives each its problems. Empty
|
|
243
|
+
* for the built-in `drift`, which the package's tests hold to the lint.
|
|
244
|
+
*/
|
|
245
|
+
problems: z.array(LintProblemSchema),
|
|
246
|
+
/**
|
|
247
|
+
* The text the outline's spans index into: the workflow's file, with `\n` line endings.
|
|
248
|
+
* Absent only when the outline is `{ error }`. Whole files: a server may keep it from clients.
|
|
249
|
+
*/
|
|
250
|
+
source: z.string().optional(),
|
|
251
|
+
});
|
|
252
|
+
export type WorkflowEntry = z.infer<typeof WorkflowEntrySchema>;
|
|
253
|
+
|
|
254
|
+
/** What an operation is, read from its connector: enough to badge it and show its contract. */
|
|
255
|
+
export const OpEntrySchema = z.strictObject({
|
|
256
|
+
id: z.string(),
|
|
257
|
+
vendor: z.string(),
|
|
258
|
+
resource: z.string(),
|
|
259
|
+
name: z.string(),
|
|
260
|
+
effect: z.enum(EFFECTS),
|
|
261
|
+
idempotent: z.boolean(),
|
|
262
|
+
description: z.string().optional(),
|
|
263
|
+
/** How a scenario's steps name it: Cucumber expressions over its input's fields. */
|
|
264
|
+
phrases: z.strictObject({ given: z.string().optional(), expect: z.string().optional() }).optional(),
|
|
265
|
+
/** Whether it may be called directly, outside a run (`isDirect`): the one rule, read here, never derived again. */
|
|
266
|
+
direct: z.boolean(),
|
|
267
|
+
/** What a call sends, as JSON Schema (`io: "input"`: fields with defaults are optional). */
|
|
268
|
+
input: JsonSchema,
|
|
269
|
+
/** What a call returns once its schema has parsed the vendor's reply (`io: "output"`). */
|
|
270
|
+
output: JsonSchema,
|
|
271
|
+
});
|
|
272
|
+
export type OpEntry = z.infer<typeof OpEntrySchema>;
|
|
273
|
+
|
|
274
|
+
/** Who a vendor is, from its connector's `VendorInfo`: enough to name it, show its logo and link to its connector. */
|
|
275
|
+
export const VendorEntrySchema = z.strictObject({
|
|
276
|
+
/** The connector's `title`, else the vendor's id. */
|
|
277
|
+
title: z.string(),
|
|
278
|
+
/** The logo as `data:image/svg+xml` URLs, for an `<img>`: `dark` is for dark backgrounds. */
|
|
279
|
+
logo: z.strictObject({ src: z.string(), dark: z.string().optional() }).optional(),
|
|
280
|
+
/** The connector's npm package name. */
|
|
281
|
+
package: z.string().optional(),
|
|
282
|
+
/** The connector package's `homepage` from its package.json: where its code and README are, as an https URL. */
|
|
283
|
+
homepage: z.string().optional(),
|
|
284
|
+
/** Whether the vendor's connector attaches a fake (`withSetup`), for sandbox runs. */
|
|
285
|
+
fake: z.boolean(),
|
|
286
|
+
/**
|
|
287
|
+
* The environment variables its driver declares (`defineDriver`'s `env`), in declared order:
|
|
288
|
+
* each name, its one-line manual and whether it may be unset; never a value or a status
|
|
289
|
+
* (`SanomaClient.credentials` says those). Absent when its driver declares none.
|
|
290
|
+
*/
|
|
291
|
+
credentials: z
|
|
292
|
+
.array(
|
|
293
|
+
z.strictObject({ name: z.string(), description: z.string().optional(), optional: z.literal(true).optional() }),
|
|
294
|
+
)
|
|
295
|
+
.optional(),
|
|
296
|
+
});
|
|
297
|
+
export type VendorEntry = z.infer<typeof VendorEntrySchema>;
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* The contracts a resource type meets, from its spec: `host`, `database` and `wakeup` (`Host`,
|
|
301
|
+
* `Database`, `Wakeup`), and `source` for a type a host's `source` names (the repository it clones).
|
|
302
|
+
*/
|
|
303
|
+
export const CAPABILITIES = ["host", "database", "wakeup", "source"] as const;
|
|
304
|
+
|
|
305
|
+
/** A resource type a connector declares with `defineResource`. */
|
|
306
|
+
export const ResourceTypeEntrySchema = z.strictObject({
|
|
307
|
+
/** `<vendor>.<type>`, such as `github.repository`. */
|
|
308
|
+
id: z.string(),
|
|
309
|
+
vendor: z.string(),
|
|
310
|
+
type: z.string(),
|
|
311
|
+
title: z.string(),
|
|
312
|
+
/** How a declared resource's identity is made, such as `name` or `repository_id:pattern`; absent when it is found only by its binding. */
|
|
313
|
+
identity: z.string().optional(),
|
|
314
|
+
/** Its flagged fields, by dotted path. */
|
|
315
|
+
fields: z.custom<ResourceFields>(),
|
|
316
|
+
/**
|
|
317
|
+
* Its state, as a read returns it, as JSON Schema (`io: "output"`), with `$id`
|
|
318
|
+
* `sanoma:resource-type/<id>`: the operations' contracts `$ref` it instead of repeating it.
|
|
319
|
+
*/
|
|
320
|
+
schema: JsonSchema,
|
|
321
|
+
/** Its operations' ids, sorted: `<id>.import` and `<id>.read`, and for a writable type its change operations. */
|
|
322
|
+
ops: z.array(z.string()),
|
|
323
|
+
/** The contracts it meets (`CAPABILITIES`), in that order; absent when it meets none. */
|
|
324
|
+
capabilities: z.array(z.enum(CAPABILITIES)).optional(),
|
|
325
|
+
});
|
|
326
|
+
export type ResourceTypeEntry = z.infer<typeof ResourceTypeEntrySchema>;
|
|
327
|
+
|
|
328
|
+
/** A collection's field as declared: its type, or `{ type, optional }`, or `{ enum, optional }`. */
|
|
329
|
+
const FieldSchema = z.union([
|
|
330
|
+
z.enum(FIELD_TYPES),
|
|
331
|
+
z.strictObject({ type: z.enum(FIELD_TYPES), optional: z.literal(true).optional() }),
|
|
332
|
+
z.strictObject({ enum: z.tuple([z.string()], z.string()).readonly(), optional: z.literal(true).optional() }),
|
|
333
|
+
]);
|
|
334
|
+
|
|
335
|
+
/** A collection the config declares (`collection()`). */
|
|
336
|
+
export const CollectionEntrySchema = z.strictObject({
|
|
337
|
+
/** Its name: `<app>.<name>` for one an app's `resources/data.ts` declares. */
|
|
338
|
+
name: z.string(),
|
|
339
|
+
/** The app whose folder declares it (`apps/<app>/resources/data.ts`); absent for one at the root. */
|
|
340
|
+
app: z.string().optional(),
|
|
341
|
+
title: z.string().optional(),
|
|
342
|
+
/** The field each record is found by. */
|
|
343
|
+
key: z.string(),
|
|
344
|
+
/** Its fields as declared. */
|
|
345
|
+
fields: z.record(z.string(), FieldSchema),
|
|
346
|
+
/** What `save` accepts, as JSON Schema, with `$id` `sanoma:collection/<name>`. */
|
|
347
|
+
record: JsonSchema,
|
|
348
|
+
/** Its operations' ids: `data.<name>.get`, `.list`, `.save` and `.delete`. */
|
|
349
|
+
ops: z.array(z.string()),
|
|
350
|
+
/** Where `resources/data.ts` declares it, read as the data files are; absent for one declared elsewhere. */
|
|
351
|
+
declared: DeclaredCollectionSchema.optional(),
|
|
352
|
+
});
|
|
353
|
+
export type CollectionEntry = z.infer<typeof CollectionEntrySchema>;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* A plain-JSON description of what a config can do: its workflows, the operations they call,
|
|
357
|
+
* and whether a policy gates them. The app server builds it from the config and sends it to the
|
|
358
|
+
* browser, so the UI shows exactly what the worker enforces. Never written by hand.
|
|
359
|
+
*/
|
|
360
|
+
export const ConfigDescriptionSchema = z.strictObject({
|
|
361
|
+
secrets: z
|
|
362
|
+
.strictObject({
|
|
363
|
+
store: z.string(),
|
|
364
|
+
namespace: z.string(),
|
|
365
|
+
bindings: z.record(
|
|
366
|
+
z.string(),
|
|
367
|
+
z.strictObject({ path: z.string(), management: z.enum(["sanoma", "external"]), store: z.string() }),
|
|
368
|
+
),
|
|
369
|
+
})
|
|
370
|
+
.optional(),
|
|
371
|
+
connections: z
|
|
372
|
+
.array(
|
|
373
|
+
z.strictObject({
|
|
374
|
+
id: z.string(),
|
|
375
|
+
vendor: z.string(),
|
|
376
|
+
method: z.string(),
|
|
377
|
+
scopes: z.array(z.string()).readonly(),
|
|
378
|
+
account: z.string().optional(),
|
|
379
|
+
default: z.boolean(),
|
|
380
|
+
}),
|
|
381
|
+
)
|
|
382
|
+
.optional(),
|
|
383
|
+
appName: z.string(),
|
|
384
|
+
/** The application version runs started now are stamped with. */
|
|
385
|
+
version: z.string(),
|
|
386
|
+
workflows: z.array(WorkflowEntrySchema),
|
|
387
|
+
ops: z.array(OpEntrySchema),
|
|
388
|
+
/** Every vendor the operations are from, by its id (an `OpEntry`'s `vendor`). */
|
|
389
|
+
vendors: z.record(z.string(), VendorEntrySchema),
|
|
390
|
+
/** The resource types the connectors declare, by `id`. */
|
|
391
|
+
resourceTypes: z.array(ResourceTypeEntrySchema),
|
|
392
|
+
/** The config's collections, by name. */
|
|
393
|
+
collections: z.array(CollectionEntrySchema),
|
|
394
|
+
/**
|
|
395
|
+
* The resources the data files under `resources/` declare, by file and then in file order,
|
|
396
|
+
* less any with a problem and any that names one.
|
|
397
|
+
*/
|
|
398
|
+
resources: z.array(DeclaredResourceSchema),
|
|
399
|
+
/** Each binding in the lockfile (`LOCKFILE`) whose key no data file declares, as `loadDataFiles` reports it. */
|
|
400
|
+
orphans: z.array(OrphanSchema),
|
|
401
|
+
/**
|
|
402
|
+
* What is wrong in the data files (`loadDataFiles`) and the apps (a folder of `apps/` that is no
|
|
403
|
+
* app, an `app.ts` that cannot be read, a collection or site at the root named as an app is),
|
|
404
|
+
* each at its file, relative to the root, and its line and column or its export. A workflow's are on its entry.
|
|
405
|
+
*/
|
|
406
|
+
problems: z.array(ResourceProblemSchema),
|
|
407
|
+
/** The apps under `apps/` (`readApps`), by name. Each workflow, collection and site an app declares names it (`app`). */
|
|
408
|
+
apps: z.array(AppEntrySchema),
|
|
409
|
+
/**
|
|
410
|
+
* `defined` when the root has `policies/**\/*.cedar` (else the policy is `allowAll`), with their
|
|
411
|
+
* `version`, or while they have `problems` (`policyProblems`), none: then every call and start is
|
|
412
|
+
* refused. `files` are those files as read (`readPolicyFiles`): the root's, then each app's.
|
|
413
|
+
*/
|
|
414
|
+
policy: z.strictObject({
|
|
415
|
+
defined: z.boolean(),
|
|
416
|
+
version: z.string().optional(),
|
|
417
|
+
problems: z.array(z.string()).optional(),
|
|
418
|
+
files: z.array(z.strictObject({ file: z.string(), text: z.string() })),
|
|
419
|
+
}),
|
|
420
|
+
/**
|
|
421
|
+
* The sites under `sites/`, by name, with what each calls (`readSites`), and its calls to what
|
|
422
|
+
* the config does not have as its problems; none when the root has no `sites/`.
|
|
423
|
+
*/
|
|
424
|
+
sites: z.array(SiteEntrySchema),
|
|
425
|
+
});
|
|
426
|
+
export type ConfigDescription = z.infer<typeof ConfigDescriptionSchema>;
|
package/src/direct.ts
CHANGED
|
@@ -16,4 +16,11 @@ export const isDirect = (
|
|
|
16
16
|
): boolean =>
|
|
17
17
|
op.vendor === DATA_VENDOR ||
|
|
18
18
|
op.id === APPS_LIST ||
|
|
19
|
+
op.id === "sanoma.connection.disconnect" ||
|
|
20
|
+
op.id === "sanoma.connection.bind" ||
|
|
21
|
+
op.id === "sanoma.connection.create" ||
|
|
22
|
+
op.id === "sanoma.connection.prepare" ||
|
|
23
|
+
op.id === "sanoma.connection.configure" ||
|
|
24
|
+
op.id === "sanoma.connection.activate" ||
|
|
25
|
+
op.id === "sanoma.connection.test" ||
|
|
19
26
|
(op.effect === "read" && op.vendor !== "sanoma" && !isResourceOp(op, types));
|
package/src/drift.ts
CHANGED
|
@@ -65,7 +65,10 @@ export const DriftInput = z.object({}).strict();
|
|
|
65
65
|
* write-only values, and the problems.
|
|
66
66
|
*/
|
|
67
67
|
export interface DriftDeclared {
|
|
68
|
-
resources: Pick<
|
|
68
|
+
resources: Pick<
|
|
69
|
+
DeclaredResource,
|
|
70
|
+
"id" | "vendor" | "type" | "name" | "identity" | "binding" | "desired" | "refs" | "connection"
|
|
71
|
+
>[];
|
|
69
72
|
problems: ResourceProblem[];
|
|
70
73
|
}
|
|
71
74
|
|
|
@@ -210,7 +213,12 @@ export function driftWorkflow(
|
|
|
210
213
|
if (!("id" in by)) found.set(resource.id, by);
|
|
211
214
|
else {
|
|
212
215
|
try {
|
|
213
|
-
found.set(
|
|
216
|
+
found.set(
|
|
217
|
+
resource.id,
|
|
218
|
+
observed(
|
|
219
|
+
await ctx[resource.vendor]![resource.type]!.import({ id: by.id }, { connection: resource.connection }),
|
|
220
|
+
),
|
|
221
|
+
);
|
|
214
222
|
} catch (err) {
|
|
215
223
|
if (isRunControlError(err)) throw err;
|
|
216
224
|
found.set(resource.id, { error: errorMessage(err) });
|
package/src/env.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SecretLocation } from "./secret-store.ts";
|
|
1
2
|
import type { z } from "zod";
|
|
2
3
|
import type { Driver, DriverEnv } from "./op.ts";
|
|
3
4
|
import { credentialReady } from "./shared.ts";
|
|
@@ -7,6 +8,7 @@ import { credentialReady } from "./shared.ts";
|
|
|
7
8
|
|
|
8
9
|
/** One environment variable a driver declares in `env`, and whether its value lets the driver run: never the value. */
|
|
9
10
|
export interface CredentialStatus {
|
|
11
|
+
location?: SecretLocation;
|
|
10
12
|
/** The variable's name, such as `GHOST_ADMIN_API_KEY`. */
|
|
11
13
|
name: string;
|
|
12
14
|
/** Its one-line manual, from its schema's `.describe()`. */
|
|
@@ -108,9 +110,9 @@ function credentialStatus(
|
|
|
108
110
|
function check(schema: z.ZodType, value: string | undefined): { success: boolean; problem?: string } {
|
|
109
111
|
try {
|
|
110
112
|
const { success, error } = schema.safeParse(value);
|
|
111
|
-
return { success, ...(error && { problem:
|
|
113
|
+
return { success, ...(error && { problem: "does not match the required format" }) };
|
|
112
114
|
} catch {
|
|
113
|
-
return { success: false, problem: "
|
|
115
|
+
return { success: false, problem: "does not match the required format" };
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
|
package/src/fake.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { fail, type Instance, UNREGISTERED, type WakeupApi, wakeupCalls } from "./wakeup-driver.ts";
|
|
12
12
|
import { INSTANCE_TOKEN, instanceUrl } from "./wakeup-service.ts";
|
|
13
13
|
import { wakeupOps } from "./wakeup-type.ts";
|
|
14
|
+
import type { ConnectionRef } from "./connection.ts";
|
|
14
15
|
|
|
15
16
|
/*
|
|
16
17
|
* Fake vendors for tests, at `@sanoma-ai/workflows/fake`. Kept off the main entry so the
|
|
@@ -25,6 +26,76 @@ export interface FakeCall {
|
|
|
25
26
|
at: string;
|
|
26
27
|
idempotencyKey: string;
|
|
27
28
|
attempt: number;
|
|
29
|
+
connection?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A factory per named account: state, faults and idempotent replies never cross connections. */
|
|
33
|
+
export function connectionFakes<F extends Fake<unknown>>(make: () => F) {
|
|
34
|
+
const seen = new WeakSet<object>();
|
|
35
|
+
const fresh = () => {
|
|
36
|
+
const fake = make();
|
|
37
|
+
const parts = [
|
|
38
|
+
fake,
|
|
39
|
+
fake.driver,
|
|
40
|
+
fake.driver.ops,
|
|
41
|
+
...(fake.state && typeof fake.state === "object" ? [fake.state] : []),
|
|
42
|
+
];
|
|
43
|
+
if (parts.some((part) => seen.has(part)))
|
|
44
|
+
throw new Error("A named fake factory must create separate state for each connection");
|
|
45
|
+
for (const part of parts) seen.add(part);
|
|
46
|
+
return fake;
|
|
47
|
+
};
|
|
48
|
+
const first = fresh();
|
|
49
|
+
const { vendor } = first.driver;
|
|
50
|
+
let unused: F | undefined = first;
|
|
51
|
+
const accounts = new Map<string, { fake: F; identity?: string }>();
|
|
52
|
+
const calls: FakeCall[] = [];
|
|
53
|
+
const account = (ref: ConnectionRef): F => {
|
|
54
|
+
if (ref.vendor !== vendor || !ref.$connection.startsWith(`${vendor}/`))
|
|
55
|
+
throw new Error(`fake ${vendor}: select a connection of this connector`);
|
|
56
|
+
let entry = accounts.get(ref.$connection);
|
|
57
|
+
if (!entry) {
|
|
58
|
+
entry = { fake: unused ?? fresh() };
|
|
59
|
+
unused = undefined;
|
|
60
|
+
accounts.set(ref.$connection, entry);
|
|
61
|
+
}
|
|
62
|
+
return entry.fake;
|
|
63
|
+
};
|
|
64
|
+
const ops: Record<string, DriverFn> = {};
|
|
65
|
+
for (const key of Object.keys(first.driver.ops)) {
|
|
66
|
+
ops[key] = async (input, call) => {
|
|
67
|
+
const selected = call.connection;
|
|
68
|
+
if (!selected || selected.vendor !== vendor)
|
|
69
|
+
throw new DriverError(`fake ${vendor}: select a named connection`, { retryable: false });
|
|
70
|
+
const ref = { vendor, $connection: selected.id };
|
|
71
|
+
account(ref);
|
|
72
|
+
let entry = accounts.get(selected.id)!;
|
|
73
|
+
// Rebinding to another vendor account gets fresh state. Rotation within an account does not.
|
|
74
|
+
if (entry.identity !== undefined && entry.identity !== selected.account) {
|
|
75
|
+
entry = { fake: fresh() };
|
|
76
|
+
accounts.set(selected.id, entry);
|
|
77
|
+
}
|
|
78
|
+
entry.identity = selected.account;
|
|
79
|
+
calls.push({
|
|
80
|
+
op: `${vendor}.${key}`,
|
|
81
|
+
input: structuredClone(input),
|
|
82
|
+
at: new Date().toISOString(),
|
|
83
|
+
idempotencyKey: call.idempotencyKey,
|
|
84
|
+
attempt: call.attempt,
|
|
85
|
+
connection: selected.id,
|
|
86
|
+
});
|
|
87
|
+
return entry.fake.driver.ops[key]!(input, call);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
driver: { vendor, ops } satisfies Driver,
|
|
92
|
+
account,
|
|
93
|
+
calls,
|
|
94
|
+
reset() {
|
|
95
|
+
for (const entry of accounts.values()) entry.fake.reset();
|
|
96
|
+
calls.length = 0;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
28
99
|
}
|
|
29
100
|
|
|
30
101
|
export interface FakeOptions {
|
package/src/index.ts
CHANGED
|
@@ -62,7 +62,8 @@ export {
|
|
|
62
62
|
type SanomaConfig,
|
|
63
63
|
} from "./config.ts";
|
|
64
64
|
// An app's `app.ts` (`defineApp`), and where the launcher finds an app's workflows and data file.
|
|
65
|
-
export { type
|
|
65
|
+
export { type AppEntry, appSourceOf, readApps } from "./apps.ts";
|
|
66
|
+
export { type AppDefinition, defineApp } from "./definitions.ts";
|
|
66
67
|
export { appFolders, APPS_DIR, filesUnder, kindDirs } from "./paths.ts";
|
|
67
68
|
// `sanoma` itself (the people types' constructors) is at `@sanoma-ai/workflows/resources`, for data files.
|
|
68
69
|
// `collection()` itself is at `@sanoma-ai/workflows/data`, for `resources/data.ts`; this tells one apart, as the launcher does.
|
|
@@ -79,6 +80,7 @@ export {
|
|
|
79
80
|
} from "./apply.ts";
|
|
80
81
|
export { CALL_WORKFLOW, CallInput } from "./call-workflow.ts";
|
|
81
82
|
export {
|
|
83
|
+
ADMIN,
|
|
82
84
|
type ChangeDecision,
|
|
83
85
|
type ChangeDeploy,
|
|
84
86
|
type ChangeEvent,
|
|
@@ -88,6 +90,8 @@ export {
|
|
|
88
90
|
type ChangeReport,
|
|
89
91
|
type ChangeState,
|
|
90
92
|
type ChangeVerified,
|
|
93
|
+
isRules,
|
|
94
|
+
mayDeclarePeople,
|
|
91
95
|
runtimeHold,
|
|
92
96
|
touchesOf,
|
|
93
97
|
} from "./change.ts";
|
|
@@ -102,6 +106,7 @@ export {
|
|
|
102
106
|
} from "./drift.ts";
|
|
103
107
|
// readResources, which parses data files, is at `@sanoma-ai/workflows/describe`.
|
|
104
108
|
export type { DeclaredResource, ResourceProblem } from "./resources.ts";
|
|
109
|
+
export { peopleSources } from "./resources.ts";
|
|
105
110
|
export {
|
|
106
111
|
allow,
|
|
107
112
|
allowAll,
|
|
@@ -209,6 +214,7 @@ export {
|
|
|
209
214
|
type ChangesFilter,
|
|
210
215
|
type ChangeView,
|
|
211
216
|
type ClientOptions,
|
|
217
|
+
type ConnectionReview,
|
|
212
218
|
SanomaClient,
|
|
213
219
|
type RunsFilter,
|
|
214
220
|
type RunSummary,
|
|
@@ -261,3 +267,49 @@ export { defineDriver, type DriverImpl, type OpIdOf } from "./op.ts";
|
|
|
261
267
|
// Steps for Gherkin tests, as data; Cucumber runs them from `@sanoma-ai/workflows/scenario`.
|
|
262
268
|
export { defineSteps, type Expect, type RunView, type Seed, type Steps } from "./steps.ts";
|
|
263
269
|
// defineFake lives at `@sanoma-ai/workflows/fake`: test tooling, not runtime.
|
|
270
|
+
export {
|
|
271
|
+
SecretAccess,
|
|
272
|
+
SecretStoreError,
|
|
273
|
+
checkSecretConfiguration,
|
|
274
|
+
memorySecretStore,
|
|
275
|
+
type SecretAddress,
|
|
276
|
+
type SecretBinding,
|
|
277
|
+
type SecretConfiguration,
|
|
278
|
+
type SecretLocation,
|
|
279
|
+
type SecretStore,
|
|
280
|
+
type SecretStoreCapabilities,
|
|
281
|
+
type SecretStoreErrorCode,
|
|
282
|
+
type SecretValue,
|
|
283
|
+
} from "./secret-store.ts";
|
|
284
|
+
export {
|
|
285
|
+
defineAuthentication,
|
|
286
|
+
checkAuthenticationStore,
|
|
287
|
+
encodeCredentials,
|
|
288
|
+
decodeCredentials,
|
|
289
|
+
authenticationCredentials,
|
|
290
|
+
verifyAuthentication,
|
|
291
|
+
AuthenticationError,
|
|
292
|
+
type AuthenticationProblem,
|
|
293
|
+
type Authentication,
|
|
294
|
+
type AuthenticationIdentity,
|
|
295
|
+
type CallAuthentication,
|
|
296
|
+
} from "./authentication.ts";
|
|
297
|
+
export { checkSecretStore, type SecretStoreCheck } from "./secret-store-check.ts";
|
|
298
|
+
|
|
299
|
+
export { postgresSecretStore } from "./credentials.ts";
|
|
300
|
+
export { deploymentKey } from "./deployment-key.ts";
|
|
301
|
+
|
|
302
|
+
export {
|
|
303
|
+
defineConnection,
|
|
304
|
+
defineConnectionRule,
|
|
305
|
+
connectionRef,
|
|
306
|
+
connectionOps,
|
|
307
|
+
type ConnectionRef,
|
|
308
|
+
type ConnectionDefinition,
|
|
309
|
+
type ConnectionRule,
|
|
310
|
+
type ConnectionSnapshot,
|
|
311
|
+
type ConnectionCard,
|
|
312
|
+
type ConnectionHealth,
|
|
313
|
+
type ConnectionTarget,
|
|
314
|
+
type ConnectionSetup,
|
|
315
|
+
} from "./connection.ts";
|