initiative-plugin-sdk 2.0.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/LICENSE +21 -0
- package/README.md +656 -0
- package/dist/build.d.ts +52 -0
- package/dist/build.js +229 -0
- package/dist/build.js.map +1 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +160 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +288 -0
- package/dist/client.js +539 -0
- package/dist/client.js.map +1 -0
- package/dist/contract.d.ts +1247 -0
- package/dist/contract.js +167 -0
- package/dist/contract.js.map +1 -0
- package/dist/define.d.ts +336 -0
- package/dist/define.js +120 -0
- package/dist/define.js.map +1 -0
- package/dist/dev.d.ts +28 -0
- package/dist/dev.js +147 -0
- package/dist/dev.js.map +1 -0
- package/dist/expression.d.ts +28 -0
- package/dist/expression.js +67 -0
- package/dist/expression.js.map +1 -0
- package/dist/init.d.ts +14 -0
- package/dist/init.js +52 -0
- package/dist/init.js.map +1 -0
- package/dist/keys.d.ts +85 -0
- package/dist/keys.js +109 -0
- package/dist/keys.js.map +1 -0
- package/dist/manifest.d.ts +8 -0
- package/dist/manifest.js +8 -0
- package/dist/manifest.js.map +1 -0
- package/dist/pack.d.ts +35 -0
- package/dist/pack.js +84 -0
- package/dist/pack.js.map +1 -0
- package/dist/plugin-api.generated.d.ts +4263 -0
- package/dist/plugin-api.generated.js +1019 -0
- package/dist/plugin-api.generated.js.map +1 -0
- package/dist/server.d.ts +75 -0
- package/dist/server.js +408 -0
- package/dist/server.js.map +1 -0
- package/dist/testing.d.ts +116 -0
- package/dist/testing.js +386 -0
- package/dist/testing.js.map +1 -0
- package/dist/tokens.d.ts +161 -0
- package/dist/tokens.js +215 -0
- package/dist/tokens.js.map +1 -0
- package/dist/validate.d.ts +86 -0
- package/dist/validate.js +997 -0
- package/dist/validate.js.map +1 -0
- package/dist/widget.d.ts +235 -0
- package/dist/widget.js +26 -0
- package/dist/widget.js.map +1 -0
- package/examples/minimal/README.md +48 -0
- package/examples/minimal/assets/avatar.png +0 -0
- package/examples/minimal/package.json +22 -0
- package/examples/minimal/src/plugin.ts +77 -0
- package/examples/minimal/src/widgets/open-issues.ts +11 -0
- package/examples/minimal/test/fixtures/issues-statistics.json +9 -0
- package/examples/minimal/test/issue-counts.test.ts +48 -0
- package/examples/minimal/tsconfig.json +14 -0
- package/manifest.contract.json +1886 -0
- package/package.json +92 -0
- package/schemas/plugin-manifest.json +1747 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `initiative-plugin-sdk/testing`: a declarative plug-in's requests and mappings,
|
|
3
|
+
* run against recorded vendor answers, with no server and no network.
|
|
4
|
+
*
|
|
5
|
+
* Each runner renders the requests the way Initiative makes them (method,
|
|
6
|
+
* address with its query, headers, body), answers them from `responses` in
|
|
7
|
+
* order, and maps the answers. It returns every request it rendered beside
|
|
8
|
+
* what the run answered:
|
|
9
|
+
*
|
|
10
|
+
* - `{ result }`: the mapped answer;
|
|
11
|
+
* - `{ unavailable, detail? }`: a code, from an `errors` rule, the defaults,
|
|
12
|
+
* the map itself, `range-too-large` from paging, or `mapping-failed` when an
|
|
13
|
+
* expression fails or a rendered address is not https on one of the plug-in's
|
|
14
|
+
* hosts (`detail` says which);
|
|
15
|
+
* - `{ transient: true }`: a passing failure, which Initiative answers as one
|
|
16
|
+
* to retry;
|
|
17
|
+
* - `{ refused }`: an `after_connect` that refused the connection.
|
|
18
|
+
*
|
|
19
|
+
* A rendered request carries no credential: Initiative adds the one its
|
|
20
|
+
* `connection` names, as the plug-in's `auth` says. A predicate (`when`, `more`,
|
|
21
|
+
* `refuse_when`) holds when JSONata's `$boolean` of its answer is true.
|
|
22
|
+
*
|
|
23
|
+
* A run fails, rather than answering, on a mistake in the test or the plug-in: a
|
|
24
|
+
* request with no recorded response left for it, a recorded response nothing
|
|
25
|
+
* asked for, or a mapped answer that does not fit the declared returns.
|
|
26
|
+
*/
|
|
27
|
+
import type { ConnectionState } from "./contract.js";
|
|
28
|
+
import type { AnyPlugin } from "./define.js";
|
|
29
|
+
export { evaluate, ExpressionError, parseExpression } from "./expression.js";
|
|
30
|
+
/** One answer the vendor gave, as a test records it. Status 200 and no headers when left out. */
|
|
31
|
+
export interface RecordedResponse {
|
|
32
|
+
status?: number;
|
|
33
|
+
headers?: Record<string, string>;
|
|
34
|
+
body?: unknown;
|
|
35
|
+
}
|
|
36
|
+
/** One request as Initiative sends it, less the credential. */
|
|
37
|
+
export interface RenderedRequest {
|
|
38
|
+
method: string;
|
|
39
|
+
url: string;
|
|
40
|
+
headers: Record<string, string>;
|
|
41
|
+
body?: unknown;
|
|
42
|
+
/** The connection whose credential Initiative would add. */
|
|
43
|
+
connection?: string;
|
|
44
|
+
}
|
|
45
|
+
/** What a run made and what it answered. */
|
|
46
|
+
export type Run<T> = {
|
|
47
|
+
requests: RenderedRequest[];
|
|
48
|
+
} & ({
|
|
49
|
+
result: T;
|
|
50
|
+
} | {
|
|
51
|
+
unavailable: string;
|
|
52
|
+
detail?: string;
|
|
53
|
+
} | {
|
|
54
|
+
transient: true;
|
|
55
|
+
} | {
|
|
56
|
+
refused: string;
|
|
57
|
+
});
|
|
58
|
+
export interface Recorded {
|
|
59
|
+
/** The vendor's answers, in the order the requests are made. */
|
|
60
|
+
responses: RecordedResponse[];
|
|
61
|
+
/** The time of the call: `now`, and what `$now()` and `$millis()` answer. Default: the present. */
|
|
62
|
+
now?: Date | string | number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* One declarative endpoint: its request or steps rendered from `params`, the
|
|
66
|
+
* `connections`' non-secret fields (keyed by connection id) and `now`, answered
|
|
67
|
+
* from `responses`, and its map held to the declared returns. An expression
|
|
68
|
+
* reads `connection`, the fields of the connection its request names, and
|
|
69
|
+
* `connections`, the fields of each connection the endpoint's `requires` names
|
|
70
|
+
* that `connections` holds, by id. The call has no actor: who may run it, and
|
|
71
|
+
* on whose credential, is Initiative's to decide.
|
|
72
|
+
*/
|
|
73
|
+
export declare function runEndpoint(plugin: AnyPlugin, name: string, call: Recorded & {
|
|
74
|
+
params?: Record<string, unknown>;
|
|
75
|
+
connections?: Record<string, Record<string, unknown>>;
|
|
76
|
+
}): Promise<Run<Record<string, unknown>>>;
|
|
77
|
+
/**
|
|
78
|
+
* A declarative `after_connect`: its request or steps made with the flow's
|
|
79
|
+
* `params`, mapped, and refused when it says. The map and `refuse_when` read
|
|
80
|
+
* the last answer as `response` and, with steps, each one's as `steps.<name>`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function runAfterConnect(plugin: AnyPlugin, connection: string, call: Recorded & {
|
|
83
|
+
params?: Record<string, string>;
|
|
84
|
+
}): Promise<Run<{
|
|
85
|
+
values?: Record<string, unknown>;
|
|
86
|
+
account_label?: string;
|
|
87
|
+
}>>;
|
|
88
|
+
/** A connection's health check: its request made with the connection's non-secret `fields`, and the state it reads. */
|
|
89
|
+
export declare function runHealth(plugin: AnyPlugin, connection: string, call: Recorded & {
|
|
90
|
+
fields?: Record<string, unknown>;
|
|
91
|
+
}): Promise<Run<ConnectionState>>;
|
|
92
|
+
/** What one delivery emits, and the connection state it sets. */
|
|
93
|
+
export interface WebhookRun {
|
|
94
|
+
event?: {
|
|
95
|
+
emit: string;
|
|
96
|
+
payload: Record<string, unknown>;
|
|
97
|
+
};
|
|
98
|
+
status?: {
|
|
99
|
+
connection: string;
|
|
100
|
+
state: ConnectionState;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* One webhook delivery, as a declarative plug-in maps it: the event the first
|
|
105
|
+
* matching `events` row emits (by the emit endpoint's key, its payload held to
|
|
106
|
+
* that endpoint's returns), and the state the first matching `status` row
|
|
107
|
+
* sets. A delivery nothing matches answers neither. An expression that fails
|
|
108
|
+
* throws {@link ExpressionError}.
|
|
109
|
+
*/
|
|
110
|
+
export declare function runWebhook(plugin: AnyPlugin, delivery: {
|
|
111
|
+
headers?: Record<string, string>;
|
|
112
|
+
payload: unknown;
|
|
113
|
+
/** The routed connection's non-secret fields. */
|
|
114
|
+
connection?: Record<string, unknown>;
|
|
115
|
+
now?: Date | string | number;
|
|
116
|
+
}): Promise<WebhookRun>;
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `initiative-plugin-sdk/testing`: a declarative plug-in's requests and mappings,
|
|
3
|
+
* run against recorded vendor answers, with no server and no network.
|
|
4
|
+
*
|
|
5
|
+
* Each runner renders the requests the way Initiative makes them (method,
|
|
6
|
+
* address with its query, headers, body), answers them from `responses` in
|
|
7
|
+
* order, and maps the answers. It returns every request it rendered beside
|
|
8
|
+
* what the run answered:
|
|
9
|
+
*
|
|
10
|
+
* - `{ result }`: the mapped answer;
|
|
11
|
+
* - `{ unavailable, detail? }`: a code, from an `errors` rule, the defaults,
|
|
12
|
+
* the map itself, `range-too-large` from paging, or `mapping-failed` when an
|
|
13
|
+
* expression fails or a rendered address is not https on one of the plug-in's
|
|
14
|
+
* hosts (`detail` says which);
|
|
15
|
+
* - `{ transient: true }`: a passing failure, which Initiative answers as one
|
|
16
|
+
* to retry;
|
|
17
|
+
* - `{ refused }`: an `after_connect` that refused the connection.
|
|
18
|
+
*
|
|
19
|
+
* A rendered request carries no credential: Initiative adds the one its
|
|
20
|
+
* `connection` names, as the plug-in's `auth` says. A predicate (`when`, `more`,
|
|
21
|
+
* `refuse_when`) holds when JSONata's `$boolean` of its answer is true.
|
|
22
|
+
*
|
|
23
|
+
* A run fails, rather than answering, on a mistake in the test or the plug-in: a
|
|
24
|
+
* request with no recorded response left for it, a recorded response nothing
|
|
25
|
+
* asked for, or a mapped answer that does not fit the declared returns.
|
|
26
|
+
*/
|
|
27
|
+
import { PLATFORM_CODES } from "./contract.js";
|
|
28
|
+
import { evaluate, ExpressionError } from "./expression.js";
|
|
29
|
+
export { evaluate, ExpressionError, parseExpression } from "./expression.js";
|
|
30
|
+
/** A run's answer, thrown from wherever it is decided. */
|
|
31
|
+
class Outcome {
|
|
32
|
+
answer;
|
|
33
|
+
constructor(answer) {
|
|
34
|
+
this.answer = answer;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class Context {
|
|
38
|
+
hosts;
|
|
39
|
+
rules;
|
|
40
|
+
requests = [];
|
|
41
|
+
now;
|
|
42
|
+
clock;
|
|
43
|
+
responses;
|
|
44
|
+
constructor(hosts, recorded,
|
|
45
|
+
/** The endpoint's own rules, and whether an answer outside 2xx fails the run. */
|
|
46
|
+
rules) {
|
|
47
|
+
this.hosts = hosts;
|
|
48
|
+
this.rules = rules;
|
|
49
|
+
this.clock = recorded.now ?? new Date();
|
|
50
|
+
this.now = new Date(this.clock).toISOString();
|
|
51
|
+
this.responses = [...recorded.responses];
|
|
52
|
+
}
|
|
53
|
+
async value(text, document, where) {
|
|
54
|
+
try {
|
|
55
|
+
return await evaluate(text, document, { now: this.clock });
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (!(error instanceof ExpressionError))
|
|
59
|
+
throw error;
|
|
60
|
+
throw new Outcome({ unavailable: "mapping-failed", detail: `${where}: ${error.message}` });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async holds(text, document, where) {
|
|
64
|
+
return (await evaluate("$boolean($)", await this.value(text, document, where))) === true;
|
|
65
|
+
}
|
|
66
|
+
answer(request) {
|
|
67
|
+
const recorded = this.responses.shift();
|
|
68
|
+
if (!recorded)
|
|
69
|
+
throw new Error(`no recorded response is left for ${request.method} ${request.url}`);
|
|
70
|
+
return {
|
|
71
|
+
status: recorded.status ?? 200,
|
|
72
|
+
headers: Object.fromEntries(Object.entries(recorded.headers ?? {}).map(([name, value]) => [name.toLowerCase(), value])),
|
|
73
|
+
body: recorded.body === undefined ? undefined : JSON.parse(JSON.stringify(recorded.body)),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async run(work) {
|
|
77
|
+
let answered;
|
|
78
|
+
try {
|
|
79
|
+
answered = await work();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (!(error instanceof Outcome))
|
|
83
|
+
throw error;
|
|
84
|
+
answered = error.answer;
|
|
85
|
+
}
|
|
86
|
+
if (this.responses.length) {
|
|
87
|
+
throw new Error(`${this.responses.length} recorded response(s) were not asked for`);
|
|
88
|
+
}
|
|
89
|
+
return { requests: this.requests, ...answered };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const matches = (status, actual) => typeof status === "number" ? status === actual : status[0] === String(actual)[0];
|
|
93
|
+
/** What an answer outside 2xx means when no rule says. */
|
|
94
|
+
function byDefault(status) {
|
|
95
|
+
if (status === 401 || status === 403)
|
|
96
|
+
return { unavailable: "not-authorized" };
|
|
97
|
+
if (status === 404)
|
|
98
|
+
return { unavailable: "not-found" };
|
|
99
|
+
if (status !== 429 && status >= 400 && status < 500)
|
|
100
|
+
return { unavailable: "invalid" };
|
|
101
|
+
return { transient: true };
|
|
102
|
+
}
|
|
103
|
+
function onHost(url, hosts) {
|
|
104
|
+
if (url.protocol !== "https:" || url.port !== "" || url.username || url.password)
|
|
105
|
+
return false;
|
|
106
|
+
return hosts.some((host) => {
|
|
107
|
+
if (!host.startsWith("*."))
|
|
108
|
+
return url.hostname === host;
|
|
109
|
+
const label = url.hostname.slice(0, -(host.length - 1));
|
|
110
|
+
return url.hostname.endsWith(host.slice(1)) && label.length > 0 && !label.includes(".");
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** The address a Link header gives as `rel="next"`, if any. */
|
|
114
|
+
function nextLink(header, base) {
|
|
115
|
+
for (const link of (header ?? "").split(",")) {
|
|
116
|
+
const [, target, rest] = /^\s*<([^>]*)>(.*)$/.exec(link) ?? [];
|
|
117
|
+
const rel = /;\s*rel="?([^";]*)"?/i.exec(rest ?? "")?.[1];
|
|
118
|
+
if (target !== undefined && rel?.split(/\s+/).includes("next"))
|
|
119
|
+
return new URL(target, base).toString();
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const text = (value) => (typeof value === "string" ? value : JSON.stringify(value));
|
|
124
|
+
async function render(request, document, context, where, page) {
|
|
125
|
+
const address = page.url ?? (await context.value(request.url, document, `${where}/url`));
|
|
126
|
+
let url;
|
|
127
|
+
try {
|
|
128
|
+
url = new URL(String(address));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
throw new Outcome({ unavailable: "mapping-failed", detail: `${where}/url: ${text(address)} is not an address` });
|
|
132
|
+
}
|
|
133
|
+
if (page.url === undefined) {
|
|
134
|
+
for (const [name, expression] of Object.entries(request.query ?? {})) {
|
|
135
|
+
const value = await context.value(expression, document, `${where}/query/${name}`);
|
|
136
|
+
for (const one of Array.isArray(value) ? value : [value]) {
|
|
137
|
+
if (one !== undefined && one !== null)
|
|
138
|
+
url.searchParams.append(name, text(one));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const paging = request.paging;
|
|
143
|
+
if (paging?.kind === "page_number") {
|
|
144
|
+
url.searchParams.set(paging.page_param, String(page.number));
|
|
145
|
+
if (paging.per_page_param)
|
|
146
|
+
url.searchParams.set(paging.per_page_param, String(paging.per_page));
|
|
147
|
+
}
|
|
148
|
+
if (paging?.kind === "cursor" && paging.param && page.number > 1)
|
|
149
|
+
url.searchParams.set(paging.param, text(page.cursor));
|
|
150
|
+
if (!onHost(url, context.hosts)) {
|
|
151
|
+
throw new Outcome({
|
|
152
|
+
unavailable: "mapping-failed",
|
|
153
|
+
detail: `${where}: ${url} is not https on one of the plug-in's hosts (${context.hosts.join(", ")})`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const headers = {};
|
|
157
|
+
for (const [name, expression] of Object.entries(request.headers ?? {})) {
|
|
158
|
+
const value = await context.value(expression, document, `${where}/headers/${name}`);
|
|
159
|
+
if (value !== undefined && value !== null)
|
|
160
|
+
headers[name] = text(value);
|
|
161
|
+
}
|
|
162
|
+
let body = request.body === undefined ? undefined : await context.value(request.body, document, `${where}/body`);
|
|
163
|
+
if (request.graphql) {
|
|
164
|
+
let variables = request.graphql.variables
|
|
165
|
+
? await context.value(request.graphql.variables, document, `${where}/graphql/variables`)
|
|
166
|
+
: undefined;
|
|
167
|
+
if (paging?.kind === "cursor" && paging.variable && page.number > 1) {
|
|
168
|
+
variables = { ...variables, [paging.variable]: page.cursor };
|
|
169
|
+
}
|
|
170
|
+
body = { query: request.graphql.query, ...(variables === undefined ? {} : { variables }) };
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
method: request.method,
|
|
174
|
+
url: url.toString(),
|
|
175
|
+
headers,
|
|
176
|
+
...(body === undefined ? {} : { body }),
|
|
177
|
+
...(request.connection ? { connection: request.connection } : {}),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* One request, every page of it, as `response` then reads it. Each answer is
|
|
182
|
+
* held to the endpoint's rules and then the defaults, unless the context
|
|
183
|
+
* judges none (a health check, whose states do).
|
|
184
|
+
*/
|
|
185
|
+
async function perform(request, document, context, where) {
|
|
186
|
+
const paging = request.paging;
|
|
187
|
+
const items = [];
|
|
188
|
+
const page = { number: 1 };
|
|
189
|
+
for (;;) {
|
|
190
|
+
const rendered = await render(request, document, context, where, page);
|
|
191
|
+
context.requests.push(rendered);
|
|
192
|
+
const answer = context.answer(rendered);
|
|
193
|
+
if (context.rules) {
|
|
194
|
+
const read = { ...document, response: answer };
|
|
195
|
+
for (const [index, rule] of context.rules.entries()) {
|
|
196
|
+
if (!matches(rule.status, answer.status))
|
|
197
|
+
continue;
|
|
198
|
+
if (rule.when !== undefined && !(await context.holds(rule.when, read, `errors/${index}/when`)))
|
|
199
|
+
continue;
|
|
200
|
+
throw new Outcome(rule.code === "transient" ? { transient: true } : { unavailable: rule.code });
|
|
201
|
+
}
|
|
202
|
+
if (answer.status < 200 || answer.status > 299)
|
|
203
|
+
throw new Outcome(byDefault(answer.status));
|
|
204
|
+
}
|
|
205
|
+
if (!paging)
|
|
206
|
+
return answer;
|
|
207
|
+
const read = { ...document, response: answer };
|
|
208
|
+
const got = paging.items === undefined ? answer.body : await context.value(paging.items, read, `${where}/paging/items`);
|
|
209
|
+
if (Array.isArray(got))
|
|
210
|
+
items.push(...got);
|
|
211
|
+
else if (got !== undefined)
|
|
212
|
+
items.push(got);
|
|
213
|
+
let more;
|
|
214
|
+
if (paging.kind === "page_number") {
|
|
215
|
+
more = (Array.isArray(got) ? got.length : got === undefined ? 0 : 1) >= paging.per_page;
|
|
216
|
+
}
|
|
217
|
+
else if (paging.kind === "link_header") {
|
|
218
|
+
page.url = nextLink(answer.headers.link, rendered.url);
|
|
219
|
+
more = page.url !== undefined;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
more = await context.holds(paging.more, read, `${where}/paging/more`);
|
|
223
|
+
page.cursor = await context.value(paging.next, read, `${where}/paging/next`);
|
|
224
|
+
}
|
|
225
|
+
if (more && page.number === paging.max_pages && paging.on_limit === "refuse") {
|
|
226
|
+
throw new Outcome({ unavailable: "range-too-large" });
|
|
227
|
+
}
|
|
228
|
+
if (!more || page.number === paging.max_pages)
|
|
229
|
+
return { ...answer, body: items };
|
|
230
|
+
page.number += 1;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/** Holds a mapped answer to the declared returns: declared names, of their declared types. */
|
|
234
|
+
function fits(answer, returns, where) {
|
|
235
|
+
if (!answer || typeof answer !== "object" || Array.isArray(answer)) {
|
|
236
|
+
throw new Error(`${where} answered ${text(answer)}, which is not an object of the declared returns`);
|
|
237
|
+
}
|
|
238
|
+
for (const [key, value] of Object.entries(answer)) {
|
|
239
|
+
const spec = returns?.[key];
|
|
240
|
+
if (spec === undefined)
|
|
241
|
+
throw new Error(`${where} answered '${key}', which is not a declared return`);
|
|
242
|
+
if (value === null)
|
|
243
|
+
continue;
|
|
244
|
+
const { type, list } = typeof spec === "string" ? { type: spec, list: false } : spec;
|
|
245
|
+
if (list && !Array.isArray(value)) {
|
|
246
|
+
throw new Error(`${where} answered '${key}' as ${text(value)}, and it is declared a list ` +
|
|
247
|
+
"(a JSONata path matching one item answers it alone: end the path with [] to keep a list)");
|
|
248
|
+
}
|
|
249
|
+
for (const one of list ? value : [value]) {
|
|
250
|
+
const ok = type === "int" ? Number.isInteger(one) : type === "bool" ? typeof one === "boolean" : typeof one === "string";
|
|
251
|
+
if (!ok)
|
|
252
|
+
throw new Error(`${where} answered '${key}' as ${text(one)}, which is not ${type}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return answer;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* One declarative endpoint: its request or steps rendered from `params`, the
|
|
259
|
+
* `connections`' non-secret fields (keyed by connection id) and `now`, answered
|
|
260
|
+
* from `responses`, and its map held to the declared returns. An expression
|
|
261
|
+
* reads `connection`, the fields of the connection its request names, and
|
|
262
|
+
* `connections`, the fields of each connection the endpoint's `requires` names
|
|
263
|
+
* that `connections` holds, by id. The call has no actor: who may run it, and
|
|
264
|
+
* on whose credential, is Initiative's to decide.
|
|
265
|
+
*/
|
|
266
|
+
export async function runEndpoint(plugin, name, call) {
|
|
267
|
+
const endpoint = plugin.endpoints?.[name];
|
|
268
|
+
if (!endpoint || !("map" in endpoint))
|
|
269
|
+
throw new TypeError(`'${name}' is not a declarative endpoint of this plug-in`);
|
|
270
|
+
const context = new Context(plugin.hosts ?? [], call, endpoint.errors ?? []);
|
|
271
|
+
return context.run(async () => {
|
|
272
|
+
const given = call.connections ?? {};
|
|
273
|
+
const required = [...(endpoint.requires?.all_of ?? []), ...(endpoint.requires?.any_of ?? [])];
|
|
274
|
+
const connections = Object.fromEntries(required.filter((id) => Object.hasOwn(given, id)).map((id) => [id, given[id]]));
|
|
275
|
+
const base = { params: call.params ?? {}, connections, now: context.now };
|
|
276
|
+
const steps = endpoint.steps ?? [{ name: "", request: endpoint.request }];
|
|
277
|
+
const answers = {};
|
|
278
|
+
let read = base;
|
|
279
|
+
for (const [index, step] of steps.entries()) {
|
|
280
|
+
read = {
|
|
281
|
+
...base,
|
|
282
|
+
connection: call.connections?.[step.request.connection ?? ""] ?? {},
|
|
283
|
+
...(endpoint.steps ? { steps: { ...answers } } : {}),
|
|
284
|
+
};
|
|
285
|
+
const where = endpoint.steps ? `steps/${index}/request` : "request";
|
|
286
|
+
const response = await perform(step.request, read, context, where);
|
|
287
|
+
if (endpoint.steps)
|
|
288
|
+
answers[step.name] = response;
|
|
289
|
+
read = { ...read, ...(endpoint.steps ? { steps: { ...answers } } : {}), response };
|
|
290
|
+
}
|
|
291
|
+
const answer = await context.value(endpoint.map, read, "map");
|
|
292
|
+
if (answer && typeof answer === "object" && "unavailable" in answer) {
|
|
293
|
+
const code = answer.unavailable;
|
|
294
|
+
if (typeof code !== "string" || ![...(endpoint.unavailable ?? []), ...PLATFORM_CODES].includes(code)) {
|
|
295
|
+
throw new Error(`map answered unavailable ${text(code)}, which is not one of this endpoint's codes`);
|
|
296
|
+
}
|
|
297
|
+
return { unavailable: code };
|
|
298
|
+
}
|
|
299
|
+
return { result: fits(answer, endpoint.returns, "map") };
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* A declarative `after_connect`: its request or steps made with the flow's
|
|
304
|
+
* `params`, mapped, and refused when it says. The map and `refuse_when` read
|
|
305
|
+
* the last answer as `response` and, with steps, each one's as `steps.<name>`.
|
|
306
|
+
*/
|
|
307
|
+
export async function runAfterConnect(plugin, connection, call) {
|
|
308
|
+
const after = plugin.connections?.[connection]?.flow?.after_connect;
|
|
309
|
+
if (typeof after !== "object")
|
|
310
|
+
throw new TypeError(`'${connection}' has no declarative after_connect`);
|
|
311
|
+
const context = new Context(plugin.hosts ?? [], call, []);
|
|
312
|
+
return context.run(async () => {
|
|
313
|
+
const base = { params: call.params ?? {}, now: context.now };
|
|
314
|
+
const steps = after.steps ?? [{ name: "", request: after.request }];
|
|
315
|
+
const answers = {};
|
|
316
|
+
let read = base;
|
|
317
|
+
for (const [index, step] of steps.entries()) {
|
|
318
|
+
read = { ...base, ...(after.steps ? { steps: { ...answers } } : {}) };
|
|
319
|
+
const where = after.steps ? `after_connect/steps/${index}/request` : "after_connect/request";
|
|
320
|
+
const response = await perform(step.request, read, context, where);
|
|
321
|
+
if (after.steps)
|
|
322
|
+
answers[step.name] = response;
|
|
323
|
+
read = { ...base, ...(after.steps ? { steps: { ...answers } } : {}), response };
|
|
324
|
+
}
|
|
325
|
+
const result = await context.value(after.map, read, "after_connect/map");
|
|
326
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) {
|
|
327
|
+
throw new Error(`after_connect/map answered ${text(result)}, which is not {values, account_label}`);
|
|
328
|
+
}
|
|
329
|
+
if (after.refuse_when && (await context.holds(after.refuse_when, { ...read, result }, "refuse_when"))) {
|
|
330
|
+
return { refused: after.code ?? "" };
|
|
331
|
+
}
|
|
332
|
+
return { result: result };
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
/** A connection's health check: its request made with the connection's non-secret `fields`, and the state it reads. */
|
|
336
|
+
export async function runHealth(plugin, connection, call) {
|
|
337
|
+
const health = plugin.connections?.[connection]?.health;
|
|
338
|
+
if (!health)
|
|
339
|
+
throw new TypeError(`'${connection}' declares no health check`);
|
|
340
|
+
const context = new Context(plugin.hosts ?? [], call, null);
|
|
341
|
+
return context.run(async () => {
|
|
342
|
+
const document = { params: {}, connection: call.fields ?? {}, now: context.now };
|
|
343
|
+
const response = await perform(health.request, document, context, "health/request");
|
|
344
|
+
for (const [index, row] of health.states.entries()) {
|
|
345
|
+
if (row.status !== undefined && !matches(row.status, response.status))
|
|
346
|
+
continue;
|
|
347
|
+
if (row.when !== undefined && !(await context.holds(row.when, { ...document, response }, `states/${index}/when`)))
|
|
348
|
+
continue;
|
|
349
|
+
return { result: row.state };
|
|
350
|
+
}
|
|
351
|
+
return { result: response.status >= 200 && response.status <= 299 ? "ok" : "unavailable" };
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* One webhook delivery, as a declarative plug-in maps it: the event the first
|
|
356
|
+
* matching `events` row emits (by the emit endpoint's key, its payload held to
|
|
357
|
+
* that endpoint's returns), and the state the first matching `status` row
|
|
358
|
+
* sets. A delivery nothing matches answers neither. An expression that fails
|
|
359
|
+
* throws {@link ExpressionError}.
|
|
360
|
+
*/
|
|
361
|
+
export async function runWebhook(plugin, delivery) {
|
|
362
|
+
const clock = delivery.now ?? new Date();
|
|
363
|
+
const document = {
|
|
364
|
+
headers: Object.fromEntries(Object.entries(delivery.headers ?? {}).map(([name, value]) => [name.toLowerCase(), value])),
|
|
365
|
+
payload: delivery.payload,
|
|
366
|
+
connection: delivery.connection ?? {},
|
|
367
|
+
now: new Date(clock).toISOString(),
|
|
368
|
+
};
|
|
369
|
+
const holds = async (expression) => (await evaluate("$boolean($)", await evaluate(expression, document, { now: clock }))) === true;
|
|
370
|
+
const out = {};
|
|
371
|
+
for (const row of plugin.webhooks?.events ?? []) {
|
|
372
|
+
if (!(await holds(row.when)))
|
|
373
|
+
continue;
|
|
374
|
+
const payload = await evaluate(row.map, document, { now: clock });
|
|
375
|
+
out.event = { emit: row.emit, payload: fits(payload, plugin.endpoints?.[row.emit]?.returns, `the ${row.emit} event`) };
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
for (const row of plugin.webhooks?.status ?? []) {
|
|
379
|
+
if (await holds(row.when)) {
|
|
380
|
+
out.status = { connection: row.connection, state: row.state };
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return out;
|
|
385
|
+
}
|
|
386
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|