@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamkeel/testing-runtime",
3
- "version": "0.463.1",
3
+ "version": "0.465.0",
4
4
  "description": "Internal package used by the generated @teamkeel/testing package",
5
5
  "exports": "./src/index.mjs",
6
6
  "typings": "src/index.d.ts",
@@ -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
- async signedLink(options = {}) {
82
- const body = {};
83
- if (options.inputs !== undefined) body.inputs = options.inputs;
84
- if (options.reusable !== undefined) body.reusable = options.reusable;
85
- if (options.expiresAt !== undefined && options.expiresAt !== null) {
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
- url: result.url,
100
- expiresAt: result.expiresAt ? new Date(result.expiresAt) : null,
101
- flow: {
102
- name: result.flow?.name ?? this._name,
103
- runId: result.flow?.runId ?? null,
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) => setTimeout(resolve, 50));
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) => setTimeout(resolve, 50));
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";