@teamkeel/testing-runtime 0.463.1 → 0.465.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/package.json +1 -1
- package/src/FlowExecutor.mjs +58 -23
- package/src/index.d.ts +59 -10
- package/src/index.mjs +3 -0
package/package.json
CHANGED
package/src/FlowExecutor.mjs
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import jwt from "jsonwebtoken";
|
|
2
2
|
import { parseInputs, parseOutputs, reviver } from "./parsing.mjs";
|
|
3
3
|
|
|
4
|
+
// Interval (ms) between flow-run status polls in untilFinished/untilAwaitingInput.
|
|
5
|
+
// A lower interval means less dead wait per flow assertion (at the cost of a few
|
|
6
|
+
// more cheap status requests); overridable via env for tuning. In a test suite with
|
|
7
|
+
// many flow assertions the previous 50ms floor added up to meaningful wall-clock.
|
|
8
|
+
const FLOW_POLL_INTERVAL_MS =
|
|
9
|
+
Number(process.env.KEEL_FLOW_POLL_INTERVAL_MS) || 10;
|
|
10
|
+
|
|
4
11
|
export class FlowExecutor {
|
|
5
12
|
constructor(props) {
|
|
6
13
|
this._flowUrl =
|
|
@@ -78,29 +85,53 @@ export class FlowExecutor {
|
|
|
78
85
|
}).then(handleResponse);
|
|
79
86
|
}
|
|
80
87
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
body.expiresAt =
|
|
87
|
-
options.expiresAt instanceof Date
|
|
88
|
-
? options.expiresAt.toISOString()
|
|
89
|
-
: options.expiresAt;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const result = await fetch(this._flowUrl + "/share", {
|
|
93
|
-
method: "POST",
|
|
94
|
-
body: JSON.stringify(body),
|
|
95
|
-
headers: this.headers(),
|
|
96
|
-
}).then(handleResponse);
|
|
88
|
+
// The signed-link management namespace for this flow: create, list and revoke signed links. The
|
|
89
|
+
// generated testing types only expose `signedLinks` on flows declared with @externalAccess.
|
|
90
|
+
get signedLinks() {
|
|
91
|
+
const flowUrl = this._flowUrl;
|
|
92
|
+
const headers = () => this.headers();
|
|
97
93
|
|
|
98
94
|
return {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
async create(options = {}) {
|
|
96
|
+
const body = {};
|
|
97
|
+
if (options.inputs !== undefined) body.inputs = options.inputs;
|
|
98
|
+
if (options.reusable !== undefined) body.reusable = options.reusable;
|
|
99
|
+
if (options.expiresAt !== undefined && options.expiresAt !== null) {
|
|
100
|
+
body.expiresAt =
|
|
101
|
+
options.expiresAt instanceof Date
|
|
102
|
+
? options.expiresAt.toISOString()
|
|
103
|
+
: options.expiresAt;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return fetch(flowUrl + "/share", {
|
|
107
|
+
method: "POST",
|
|
108
|
+
body: JSON.stringify(body),
|
|
109
|
+
headers: headers(),
|
|
110
|
+
}).then(handleResponse);
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
async list(options = {}) {
|
|
114
|
+
let url = flowUrl + "/share";
|
|
115
|
+
if (options.status !== undefined && options.status !== null) {
|
|
116
|
+
const queryString = new URLSearchParams({
|
|
117
|
+
status: options.status,
|
|
118
|
+
}).toString();
|
|
119
|
+
url = `${url}?${queryString}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const result = await fetch(url, {
|
|
123
|
+
method: "GET",
|
|
124
|
+
headers: headers(),
|
|
125
|
+
}).then(handleResponse);
|
|
126
|
+
|
|
127
|
+
return { results: result.signedLinks || [] };
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
async revoke(linkId) {
|
|
131
|
+
return fetch(flowUrl + "/share/" + encodeURIComponent(linkId), {
|
|
132
|
+
method: "DELETE",
|
|
133
|
+
headers: headers(),
|
|
134
|
+
}).then(handleResponse);
|
|
104
135
|
},
|
|
105
136
|
};
|
|
106
137
|
}
|
|
@@ -172,7 +203,9 @@ export class FlowExecutor {
|
|
|
172
203
|
return flow;
|
|
173
204
|
}
|
|
174
205
|
|
|
175
|
-
await new Promise((resolve) =>
|
|
206
|
+
await new Promise((resolve) =>
|
|
207
|
+
setTimeout(resolve, FLOW_POLL_INTERVAL_MS)
|
|
208
|
+
);
|
|
176
209
|
}
|
|
177
210
|
}
|
|
178
211
|
|
|
@@ -204,7 +237,9 @@ export class FlowExecutor {
|
|
|
204
237
|
);
|
|
205
238
|
}
|
|
206
239
|
|
|
207
|
-
await new Promise((resolve) =>
|
|
240
|
+
await new Promise((resolve) =>
|
|
241
|
+
setTimeout(resolve, FLOW_POLL_INTERVAL_MS)
|
|
242
|
+
);
|
|
208
243
|
}
|
|
209
244
|
}
|
|
210
245
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -138,19 +138,10 @@ export type UIElement =
|
|
|
138
138
|
// Union type for UI configurations
|
|
139
139
|
export type UIConfig = UIPage | UIComplete;
|
|
140
140
|
|
|
141
|
-
declare class FlowExecutor<Input = {}> {
|
|
141
|
+
export declare class FlowExecutor<Input = {}> {
|
|
142
142
|
withIdentity(identity: sdk.Identity): FlowExecutor<Input>;
|
|
143
143
|
withAuthToken(token: string): FlowExecutor<Input>;
|
|
144
144
|
start(inputs: Input): Promise<FlowRun<Input>>;
|
|
145
|
-
signedLink(options?: {
|
|
146
|
-
inputs?: Input;
|
|
147
|
-
expiresAt?: Date;
|
|
148
|
-
reusable?: boolean;
|
|
149
|
-
}): Promise<{
|
|
150
|
-
url: string;
|
|
151
|
-
expiresAt: Date | null;
|
|
152
|
-
flow: { name: string; runId: string | null };
|
|
153
|
-
}>;
|
|
154
145
|
get(id: string): Promise<FlowRun<Input>>;
|
|
155
146
|
cancel(id: string): Promise<FlowRun<Input>>;
|
|
156
147
|
back(id: string): Promise<FlowRun<Input>>;
|
|
@@ -171,6 +162,63 @@ declare class FlowExecutor<Input = {}> {
|
|
|
171
162
|
untilFinished(id: string, timeout?: number): Promise<FlowRun<Input>>;
|
|
172
163
|
}
|
|
173
164
|
|
|
165
|
+
// The signed-link management namespace exposed on a shareable flow's executor as `signedLinks`.
|
|
166
|
+
export interface SignedLinksAPI<Input = {}> {
|
|
167
|
+
// Mint a signed link that lets an external, unauthenticated actor execute this flow.
|
|
168
|
+
create(options?: {
|
|
169
|
+
inputs?: Input;
|
|
170
|
+
expiresAt?: Date;
|
|
171
|
+
reusable?: boolean;
|
|
172
|
+
}): Promise<SignedLinkRecord>;
|
|
173
|
+
// List the signed links minted for this flow, optionally filtered by status.
|
|
174
|
+
list(options?: {
|
|
175
|
+
status?: "active" | "revoked" | "expired";
|
|
176
|
+
}): Promise<{ results: SignedLinkRecord[] }>;
|
|
177
|
+
// Revoke a signed link by id so it can no longer be opened. Idempotent.
|
|
178
|
+
revoke(linkId: string): Promise<SignedLinkRecord>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// A FlowExecutor for flows declared with @externalAccess: adds the signed-link management
|
|
182
|
+
// namespace. Runtime-wise there is a single FlowExecutor class; this declaration-only split lets
|
|
183
|
+
// generated testing types expose `signedLinks` only on shareable flows.
|
|
184
|
+
export declare class ShareableFlowExecutor<
|
|
185
|
+
Input = {},
|
|
186
|
+
> extends FlowExecutor<Input> {
|
|
187
|
+
withIdentity(identity: sdk.Identity): ShareableFlowExecutor<Input>;
|
|
188
|
+
withAuthToken(token: string): ShareableFlowExecutor<Input>;
|
|
189
|
+
readonly signedLinks: SignedLinksAPI<Input>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// A persisted shareable signed link for a flow. The shareable url is exposed so the link can be
|
|
193
|
+
// re-shared; the raw token/hash is never exposed. url is absent for links minted before the token
|
|
194
|
+
// was persisted.
|
|
195
|
+
export interface SignedLinkRecord {
|
|
196
|
+
id: string;
|
|
197
|
+
flowName: string;
|
|
198
|
+
inputs: Record<string, any> | null;
|
|
199
|
+
reusable: boolean;
|
|
200
|
+
createdBy: string | null;
|
|
201
|
+
expiresAt: Date | null;
|
|
202
|
+
usedCount: number;
|
|
203
|
+
revokedAt: Date | null;
|
|
204
|
+
createdAt: Date;
|
|
205
|
+
updatedAt: Date;
|
|
206
|
+
status: "active" | "revoked" | "expired";
|
|
207
|
+
url?: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Live progress snapshot reported by a step while it runs
|
|
211
|
+
export interface StepProgress {
|
|
212
|
+
message?: string;
|
|
213
|
+
current?: number;
|
|
214
|
+
total?: number;
|
|
215
|
+
unit?: string;
|
|
216
|
+
counter?: "count" | "percent" | "none";
|
|
217
|
+
logs?: string[];
|
|
218
|
+
data?: Record<string, unknown>;
|
|
219
|
+
updatedAt: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
174
222
|
// Step Definition
|
|
175
223
|
export interface FlowStep {
|
|
176
224
|
id: string;
|
|
@@ -186,6 +234,7 @@ export interface FlowStep {
|
|
|
186
234
|
createdAt: string;
|
|
187
235
|
updatedAt: string;
|
|
188
236
|
ui: UIConfig | null;
|
|
237
|
+
progress: StepProgress | null;
|
|
189
238
|
}
|
|
190
239
|
|
|
191
240
|
// Flow Run Definition
|
package/src/index.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { sql } from "kysely";
|
|
2
2
|
export { ActionExecutor } from "./ActionExecutor.mjs";
|
|
3
3
|
export { FlowExecutor } from "./FlowExecutor.mjs";
|
|
4
|
+
// ShareableFlowExecutor is a declaration-only refinement of FlowExecutor (see index.d.ts); at
|
|
5
|
+
// runtime they are the same class.
|
|
6
|
+
export { FlowExecutor as ShareableFlowExecutor } from "./FlowExecutor.mjs";
|
|
4
7
|
export { JobExecutor } from "./JobExecutor.mjs";
|
|
5
8
|
export { SubscriberExecutor } from "./SubscriberExecutor.mjs";
|
|
6
9
|
export { toHaveError } from "./toHaveError.mjs";
|