@helmr/sdk 0.1.1-rc.3 → 0.1.1-rc.5
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 +20 -12
- package/dist/compile.d.ts +1 -1
- package/dist/compile.js +35 -4
- package/dist/config.d.ts +1 -1
- package/dist/idempotency.d.ts +30 -0
- package/dist/index.d.ts +26 -8
- package/dist/index.js +764 -204
- package/dist/internal.d.ts +162 -33
- package/dist/internal.js +265 -26
- package/dist/runtime/client.d.ts +114 -56
- package/dist/runtime/run.d.ts +32 -48
- package/dist/schedules.d.ts +30 -0
- package/dist/schema/payload.d.ts +40 -0
- package/dist/schema/task.d.ts +15 -0
- package/dist/task.d.ts +6 -3
- package/dist/trigger.d.ts +10 -20
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,9 +1,92 @@
|
|
|
1
|
+
// sdk/typescript/src/schema/payload.ts
|
|
2
|
+
var payloadSchemaValidationErrorBrand = Symbol.for("helmr.sdk.PayloadSchemaValidationError");
|
|
3
|
+
|
|
4
|
+
class PayloadSchemaValidationError extends Error {
|
|
5
|
+
issues;
|
|
6
|
+
constructor(label, issues) {
|
|
7
|
+
super(formatPayloadSchemaValidationMessage(label, issues));
|
|
8
|
+
this.name = "PayloadSchemaValidationError";
|
|
9
|
+
this.issues = issues;
|
|
10
|
+
Object.defineProperty(this, payloadSchemaValidationErrorBrand, { value: true });
|
|
11
|
+
}
|
|
12
|
+
static [Symbol.hasInstance](value) {
|
|
13
|
+
return this === PayloadSchemaValidationError && typeof value === "object" && value !== null && payloadSchemaValidationErrorBrand in value;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function assertPayloadSchema(value, label = "payload") {
|
|
17
|
+
if (value === undefined) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
assertStandardSchema(value, label);
|
|
21
|
+
}
|
|
22
|
+
function assertStandardSchema(value, label = "schema") {
|
|
23
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
24
|
+
throw new Error(`${label} must implement the Standard Schema v1 interface`);
|
|
25
|
+
}
|
|
26
|
+
const standard = value["~standard"];
|
|
27
|
+
if (standard === null || typeof standard !== "object") {
|
|
28
|
+
throw new Error(`${label} must implement the Standard Schema v1 interface`);
|
|
29
|
+
}
|
|
30
|
+
const record = standard;
|
|
31
|
+
if (record["version"] !== 1 || typeof record["validate"] !== "function") {
|
|
32
|
+
throw new Error(`${label} must implement the Standard Schema v1 interface`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function parsePayloadWithSchema(schema, payload, label) {
|
|
36
|
+
assertStandardSchema(schema, label);
|
|
37
|
+
const result = await schema["~standard"].validate(payload);
|
|
38
|
+
if ("issues" in result && result.issues !== undefined) {
|
|
39
|
+
throw new PayloadSchemaValidationError(label, result.issues);
|
|
40
|
+
}
|
|
41
|
+
return result.value;
|
|
42
|
+
}
|
|
43
|
+
function formatPayloadSchemaValidationMessage(label, issues) {
|
|
44
|
+
if (issues.length === 0) {
|
|
45
|
+
return `${label} failed validation`;
|
|
46
|
+
}
|
|
47
|
+
const formattedIssues = issues.slice(0, 5).map(formatPayloadSchemaIssue);
|
|
48
|
+
const suffix = issues.length > formattedIssues.length ? `; and ${issues.length - formattedIssues.length} more` : "";
|
|
49
|
+
return `${label} failed validation: ${formattedIssues.join("; ")}${suffix}`;
|
|
50
|
+
}
|
|
51
|
+
function formatPayloadSchemaIssue(issue) {
|
|
52
|
+
const path = formatPayloadSchemaIssuePath(issue.path);
|
|
53
|
+
return path === "" ? issue.message : `${path}: ${issue.message}`;
|
|
54
|
+
}
|
|
55
|
+
function formatPayloadSchemaIssuePath(path) {
|
|
56
|
+
if (path === undefined || path.length === 0) {
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
let formatted = "payload";
|
|
60
|
+
for (const segment of path) {
|
|
61
|
+
const key = typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment;
|
|
62
|
+
if (typeof key === "string" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
63
|
+
formatted += `.${key}`;
|
|
64
|
+
} else if (typeof key === "string" && isArrayIndexKey(key)) {
|
|
65
|
+
formatted += `[${key}]`;
|
|
66
|
+
} else if (typeof key === "number") {
|
|
67
|
+
formatted += `[${key}]`;
|
|
68
|
+
} else {
|
|
69
|
+
formatted += `[${JSON.stringify(String(key))}]`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return formatted;
|
|
73
|
+
}
|
|
74
|
+
function isArrayIndexKey(value) {
|
|
75
|
+
if (!/^(0|[1-9]\d*)$/.test(value)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const parsed = Number(value);
|
|
79
|
+
return Number.isSafeInteger(parsed);
|
|
80
|
+
}
|
|
81
|
+
|
|
1
82
|
// sdk/typescript/src/schema/task.ts
|
|
2
83
|
var TASK_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$";
|
|
3
84
|
var TASK_ID_MAX_LENGTH = 128;
|
|
4
85
|
var DEFAULT_MAX_DURATION_SECONDS = 900;
|
|
5
86
|
var MIN_MAX_DURATION_SECONDS = 5;
|
|
6
87
|
var MAX_DURATION_SECONDS = 86400;
|
|
88
|
+
var QUEUE_NAME_PATTERN = "^[A-Za-z0-9][A-Za-z0-9._/-]{0,255}$";
|
|
89
|
+
var QUEUE_NAME_MAX_LENGTH = 256;
|
|
7
90
|
|
|
8
91
|
class TaskIdError extends Error {
|
|
9
92
|
name = "TaskIdError";
|
|
@@ -57,37 +140,61 @@ function readOptionalMaxDurationSeconds(value, label = "task maxDuration") {
|
|
|
57
140
|
function validateOptionalMaxDurationSeconds(value, label = "task maxDuration") {
|
|
58
141
|
readOptionalMaxDurationSeconds(value, label);
|
|
59
142
|
}
|
|
60
|
-
function isAsciiAlnum(code) {
|
|
61
|
-
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
62
|
-
}
|
|
63
143
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
144
|
+
class TaskQueueNameError extends Error {
|
|
145
|
+
name = "TaskQueueNameError";
|
|
146
|
+
value;
|
|
147
|
+
constructor(value) {
|
|
148
|
+
super(`queue name must match ${QUEUE_NAME_PATTERN}: ${JSON.stringify(value)}`);
|
|
149
|
+
this.value = value;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
68
152
|
|
|
69
|
-
class
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
153
|
+
class TaskQueueConcurrencyLimitError extends Error {
|
|
154
|
+
name = "TaskQueueConcurrencyLimitError";
|
|
155
|
+
value;
|
|
156
|
+
constructor(value) {
|
|
157
|
+
super("queue concurrencyLimit must be a positive integer");
|
|
158
|
+
this.value = value;
|
|
74
159
|
}
|
|
75
|
-
|
|
76
|
-
|
|
160
|
+
}
|
|
161
|
+
function validateQueueName(value) {
|
|
162
|
+
if (!isValidQueueName(value)) {
|
|
163
|
+
throw new TaskQueueNameError(value);
|
|
77
164
|
}
|
|
78
165
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
super(message);
|
|
83
|
-
this.name = "MessageTimeoutError";
|
|
84
|
-
Object.defineProperty(this, messageTimeoutErrorBrand, { value: true });
|
|
166
|
+
function isValidQueueName(value) {
|
|
167
|
+
if (value.length === 0 || value.length > QUEUE_NAME_MAX_LENGTH) {
|
|
168
|
+
return false;
|
|
85
169
|
}
|
|
86
|
-
|
|
87
|
-
|
|
170
|
+
const first = value.charCodeAt(0);
|
|
171
|
+
if (!isAsciiAlnum(first)) {
|
|
172
|
+
return false;
|
|
88
173
|
}
|
|
174
|
+
for (let index = 1;index < value.length; index += 1) {
|
|
175
|
+
const code = value.charCodeAt(index);
|
|
176
|
+
if (!(isAsciiAlnum(code) || code === 46 || code === 95 || code === 45 || code === 47)) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
function validateOptionalQueueConcurrencyLimit(value) {
|
|
183
|
+
if (value === undefined || value === null) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (typeof value === "number" && Number.isInteger(value) && Number.isFinite(value) && value > 0) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
throw new TaskQueueConcurrencyLimitError(value);
|
|
190
|
+
}
|
|
191
|
+
function isAsciiAlnum(code) {
|
|
192
|
+
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
89
193
|
}
|
|
90
194
|
|
|
195
|
+
// sdk/typescript/src/internal.ts
|
|
196
|
+
var concurrentWaitErrorBrand = Symbol.for("helmr.sdk.ConcurrentWaitError");
|
|
197
|
+
|
|
91
198
|
class ConcurrentWaitError extends Error {
|
|
92
199
|
constructor(message) {
|
|
93
200
|
super(message);
|
|
@@ -162,12 +269,136 @@ var sandboxBuilderBrand = Symbol.for("helmr.sdk.SandboxBuilder");
|
|
|
162
269
|
var sourceFileRefBrand = Symbol.for("helmr.sdk.SourceFileRef");
|
|
163
270
|
var sourceDirRefBrand = Symbol.for("helmr.sdk.SourceDirRef");
|
|
164
271
|
function markTask(config) {
|
|
272
|
+
if ("schedule" in config) {
|
|
273
|
+
throw new Error(`task ${JSON.stringify(config.id)} must use schedules.task(...) for declarative schedules`);
|
|
274
|
+
}
|
|
275
|
+
return markTaskInternal(config, undefined);
|
|
276
|
+
}
|
|
277
|
+
function markScheduledTask(config, schedule) {
|
|
278
|
+
return markTaskInternal(config, schedule);
|
|
279
|
+
}
|
|
280
|
+
function markTaskInternal(config, schedule) {
|
|
165
281
|
validateTaskId(config.id);
|
|
166
282
|
validateOptionalMaxDurationSeconds(config.maxDuration);
|
|
283
|
+
validateTaskQueue(config.id, config.queue);
|
|
284
|
+
validateTaskSchedule(config.id, schedule);
|
|
285
|
+
validateOptionalTTL(config.ttl, `task ${JSON.stringify(config.id)} ttl`);
|
|
286
|
+
assertPayloadSchema(config.payload, `task ${JSON.stringify(config.id)} payload`);
|
|
287
|
+
if (schedule !== undefined) {
|
|
288
|
+
Object.defineProperty(config, "schedule", {
|
|
289
|
+
value: Object.freeze({ ...schedule }),
|
|
290
|
+
enumerable: true
|
|
291
|
+
});
|
|
292
|
+
}
|
|
167
293
|
Object.defineProperty(config, taskBrand, { value: true });
|
|
168
294
|
Object.defineProperty(config, taskOriginBrand, { value: captureTaskOrigin() });
|
|
169
295
|
return config;
|
|
170
296
|
}
|
|
297
|
+
function validateTaskSchedule(taskId, value) {
|
|
298
|
+
if (value === undefined) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (value.cron.trim() === "") {
|
|
302
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule cron is required`);
|
|
303
|
+
}
|
|
304
|
+
if (value.timezone !== undefined && value.timezone.trim() === "") {
|
|
305
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule timezone must not be empty`);
|
|
306
|
+
}
|
|
307
|
+
if (value.workspace.kind !== "github") {
|
|
308
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule workspace must be workspace.github(...)`);
|
|
309
|
+
}
|
|
310
|
+
if (value.secretBindings !== undefined) {
|
|
311
|
+
if (value.secretBindings === null || typeof value.secretBindings !== "object" || Array.isArray(value.secretBindings)) {
|
|
312
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule secretBindings must be an object`);
|
|
313
|
+
}
|
|
314
|
+
for (const [name, binding] of Object.entries(value.secretBindings)) {
|
|
315
|
+
validateSecretName(name, `task ${JSON.stringify(taskId)} schedule secretBindings.${name}`);
|
|
316
|
+
if (typeof binding !== "string" || binding.trim() === "") {
|
|
317
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule secretBindings.${name} must be a non-empty string`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function validateTaskQueue(taskId, value) {
|
|
323
|
+
if (value === undefined) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (value.name !== undefined) {
|
|
327
|
+
validateQueueName(value.name);
|
|
328
|
+
}
|
|
329
|
+
validateOptionalQueueConcurrencyLimit(value.concurrencyLimit);
|
|
330
|
+
if (value.name === undefined && value.concurrencyLimit === undefined) {
|
|
331
|
+
throw new Error(`task ${JSON.stringify(taskId)} queue must include name or concurrencyLimit`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function validateOptionalTTL(value, label = "ttl") {
|
|
335
|
+
if (value === undefined) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (typeof value === "string" && isPositiveDurationString(value)) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
throw new Error(`${label} must be a positive duration string`);
|
|
342
|
+
}
|
|
343
|
+
function isPositiveDurationString(value) {
|
|
344
|
+
const raw = value.trim();
|
|
345
|
+
if (raw === "") {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
if (/^[1-9][0-9]*d$/.test(raw)) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
const sign = raw.startsWith("+") || raw.startsWith("-") ? raw.slice(0, 1) : "";
|
|
352
|
+
if (sign === "-") {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
const body = sign === "" ? raw : raw.slice(1);
|
|
356
|
+
const tokenPattern = /([0-9]+(?:\.[0-9]*)?|\.[0-9]+)(ns|us|µs|μs|ms|s|m|h)/gy;
|
|
357
|
+
let totalNanoseconds = 0;
|
|
358
|
+
let offset = 0;
|
|
359
|
+
for (;; ) {
|
|
360
|
+
tokenPattern.lastIndex = offset;
|
|
361
|
+
const match = tokenPattern.exec(body);
|
|
362
|
+
if (match === null) {
|
|
363
|
+
return offset === body.length && totalNanoseconds >= 1;
|
|
364
|
+
}
|
|
365
|
+
if (match.index !== offset) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
const amount = Number(match[1]);
|
|
369
|
+
if (!Number.isFinite(amount) || amount < 0) {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
totalNanoseconds += amount * durationUnitNanoseconds(match[2] ?? "");
|
|
373
|
+
offset = tokenPattern.lastIndex;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function durationUnitNanoseconds(unit) {
|
|
377
|
+
switch (unit) {
|
|
378
|
+
case "ns":
|
|
379
|
+
return 1;
|
|
380
|
+
case "us":
|
|
381
|
+
case "µs":
|
|
382
|
+
case "μs":
|
|
383
|
+
return 1000;
|
|
384
|
+
case "ms":
|
|
385
|
+
return 1e6;
|
|
386
|
+
case "s":
|
|
387
|
+
return 1e9;
|
|
388
|
+
case "m":
|
|
389
|
+
return 60000000000;
|
|
390
|
+
case "h":
|
|
391
|
+
return 3600000000000;
|
|
392
|
+
default:
|
|
393
|
+
return 0;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async function parseTaskPayload(task, payload) {
|
|
397
|
+
if (task.payload === undefined) {
|
|
398
|
+
throw new Error(`task ${JSON.stringify(task.id)} does not accept payload`);
|
|
399
|
+
}
|
|
400
|
+
return await parsePayloadWithSchema(task.payload, payload, `task ${JSON.stringify(task.id)} payload`);
|
|
401
|
+
}
|
|
171
402
|
function markConfig(config) {
|
|
172
403
|
Object.defineProperty(config, configBrand, { value: true });
|
|
173
404
|
return config;
|
|
@@ -192,7 +423,7 @@ function stackFrameFile(line) {
|
|
|
192
423
|
return match[1].startsWith("file://") ? decodeURIComponent(new URL(match[1]).pathname) : match[1];
|
|
193
424
|
}
|
|
194
425
|
function isSdkInternalFrame(file) {
|
|
195
|
-
return file.includes("/sdk/typescript/src/internal
|
|
426
|
+
return file.includes("/sdk/typescript/src/internal") || file.includes("/sdk/typescript/src/task") || file.includes("/sdk/typescript/src/index") || file.includes("/runtime/typescript/src/");
|
|
196
427
|
}
|
|
197
428
|
|
|
198
429
|
class ImageBuilderImpl {
|
|
@@ -300,6 +531,55 @@ function hasBrand(value, brand) {
|
|
|
300
531
|
return value !== null && typeof value === "object" && value[brand] === true;
|
|
301
532
|
}
|
|
302
533
|
|
|
534
|
+
// sdk/typescript/src/idempotency.ts
|
|
535
|
+
import { createHash } from "node:crypto";
|
|
536
|
+
var idempotencyKeys = {
|
|
537
|
+
create(key, options = {}) {
|
|
538
|
+
const scope = options.scope ?? "run";
|
|
539
|
+
return {
|
|
540
|
+
value: createIdempotencyKey(key, scope, options),
|
|
541
|
+
key,
|
|
542
|
+
scope
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
function runIdempotencyRequestFields(input, ttl) {
|
|
547
|
+
if (input === undefined) {
|
|
548
|
+
return {};
|
|
549
|
+
}
|
|
550
|
+
const key = isIdempotencyKey(input) ? input : idempotencyKeys.create(input);
|
|
551
|
+
return {
|
|
552
|
+
idempotency_key: key.value,
|
|
553
|
+
...ttl === undefined ? {} : { idempotency_key_ttl: ttl },
|
|
554
|
+
idempotency_key_options: {
|
|
555
|
+
key: key.key,
|
|
556
|
+
scope: key.scope
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function createIdempotencyKey(key, scope, options) {
|
|
561
|
+
const material = {
|
|
562
|
+
scope,
|
|
563
|
+
key: Array.isArray(key) ? [...key] : [key]
|
|
564
|
+
};
|
|
565
|
+
const runId = "runId" in options ? options.runId : undefined;
|
|
566
|
+
const attemptNumber = "attemptNumber" in options ? options.attemptNumber : undefined;
|
|
567
|
+
if (scope === "run" && runId !== undefined) {
|
|
568
|
+
material["runId"] = runId;
|
|
569
|
+
}
|
|
570
|
+
if (scope === "attempt") {
|
|
571
|
+
if (runId === undefined || attemptNumber === undefined) {
|
|
572
|
+
throw new Error("attempt-scoped idempotency keys require runId and attemptNumber");
|
|
573
|
+
}
|
|
574
|
+
material["runId"] = runId;
|
|
575
|
+
material["attemptNumber"] = attemptNumber;
|
|
576
|
+
}
|
|
577
|
+
return createHash("sha256").update(JSON.stringify(material)).digest("hex");
|
|
578
|
+
}
|
|
579
|
+
function isIdempotencyKey(value) {
|
|
580
|
+
return typeof value === "object" && value !== null && "value" in value && "key" in value && "scope" in value;
|
|
581
|
+
}
|
|
582
|
+
|
|
303
583
|
// sdk/typescript/src/runtime/errors.ts
|
|
304
584
|
class RunNotFoundError extends Error {
|
|
305
585
|
runId;
|
|
@@ -352,27 +632,18 @@ function runSnapshot(snapshot) {
|
|
|
352
632
|
function pendingWaitpointFromResponse(runId, wait) {
|
|
353
633
|
if (wait === undefined || wait === null)
|
|
354
634
|
return null;
|
|
355
|
-
if (wait.kind === "approval") {
|
|
356
|
-
return {
|
|
357
|
-
kind: "approval",
|
|
358
|
-
runId,
|
|
359
|
-
waitpointId: wait.waitpoint_id,
|
|
360
|
-
message: wait.message ?? "",
|
|
361
|
-
timeout: wait.timeout ?? null,
|
|
362
|
-
requestedAt: wait.requested_at
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
635
|
return {
|
|
366
|
-
kind:
|
|
636
|
+
kind: wait.kind,
|
|
367
637
|
runId,
|
|
368
638
|
waitpointId: wait.waitpoint_id,
|
|
369
|
-
prompt: wait.prompt ?? null,
|
|
370
639
|
timeout: wait.timeout ?? null,
|
|
640
|
+
request: wait.request === undefined ? {} : wait.request,
|
|
641
|
+
displayText: wait.display_text ?? "",
|
|
371
642
|
requestedAt: wait.requested_at
|
|
372
643
|
};
|
|
373
644
|
}
|
|
374
645
|
function isTerminalRunStatus(status) {
|
|
375
|
-
return status === "succeeded" || status === "failed" || status === "cancelled";
|
|
646
|
+
return status === "succeeded" || status === "failed" || status === "cancelled" || status === "expired";
|
|
376
647
|
}
|
|
377
648
|
function runId(value) {
|
|
378
649
|
return typeof value === "string" ? value : value.id;
|
|
@@ -396,6 +667,7 @@ function runStatus(status) {
|
|
|
396
667
|
case "succeeded":
|
|
397
668
|
case "failed":
|
|
398
669
|
case "cancelled":
|
|
670
|
+
case "expired":
|
|
399
671
|
return status;
|
|
400
672
|
default:
|
|
401
673
|
throw new Error(`unsupported run status ${JSON.stringify(status)}`);
|
|
@@ -412,6 +684,9 @@ function runWorkspaceFromSpec(spec) {
|
|
|
412
684
|
}
|
|
413
685
|
|
|
414
686
|
// sdk/typescript/src/runtime/client.ts
|
|
687
|
+
var MAX_SSE_BUFFER_CHARS = 1024 * 1024;
|
|
688
|
+
var triggerTaskClientMethod = Symbol.for("helmr.sdk.client.triggerTask");
|
|
689
|
+
|
|
415
690
|
class HelmrClient {
|
|
416
691
|
#baseUrl;
|
|
417
692
|
#apiKey;
|
|
@@ -443,24 +718,57 @@ class HelmrClient {
|
|
|
443
718
|
}
|
|
444
719
|
}
|
|
445
720
|
tasks = {
|
|
446
|
-
trigger: async (
|
|
447
|
-
const
|
|
448
|
-
const
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
workspace: runWorkspace,
|
|
456
|
-
max_duration_seconds: maxDurationSeconds
|
|
457
|
-
}),
|
|
458
|
-
headers: { "content-type": "application/json" }
|
|
459
|
-
});
|
|
460
|
-
const run = await response.json();
|
|
461
|
-
return runHandle(run.id, run.task_id);
|
|
721
|
+
trigger: async (...args) => {
|
|
722
|
+
const taskId = args[0];
|
|
723
|
+
const hasPayload = args.length === 3;
|
|
724
|
+
const payload = hasPayload ? args[1] : undefined;
|
|
725
|
+
const opts = hasPayload ? args[2] : args[1];
|
|
726
|
+
if (hasPayload && payload === undefined) {
|
|
727
|
+
throw new Error(`task ${JSON.stringify(taskId)} requires payload`);
|
|
728
|
+
}
|
|
729
|
+
return await this.#triggerRun(taskId, payload, opts);
|
|
462
730
|
}
|
|
463
731
|
};
|
|
732
|
+
async[triggerTaskClientMethod](task, ...args) {
|
|
733
|
+
const hasPayload = task.payload !== undefined;
|
|
734
|
+
const payload = hasPayload ? args[0] : undefined;
|
|
735
|
+
const opts = hasPayload ? args[1] : args[0];
|
|
736
|
+
if (task.payload !== undefined) {
|
|
737
|
+
if (payload === undefined) {
|
|
738
|
+
throw new Error(`task ${JSON.stringify(task.id)} requires payload`);
|
|
739
|
+
}
|
|
740
|
+
await parseTaskPayload(task, payload);
|
|
741
|
+
} else if (args.length > 1) {
|
|
742
|
+
throw new Error(`task ${JSON.stringify(task.id)} does not accept payload`);
|
|
743
|
+
}
|
|
744
|
+
return await this.#triggerRun(task.id, payload, opts, readOptionalMaxDurationSeconds(task.maxDuration));
|
|
745
|
+
}
|
|
746
|
+
async#triggerRun(taskId, payload, opts, maxDurationSeconds) {
|
|
747
|
+
const runWorkspace = runWorkspaceFromSpec(opts.workspace);
|
|
748
|
+
const runOptions = {
|
|
749
|
+
...opts.deploymentId === undefined ? {} : { deployment_id: opts.deploymentId },
|
|
750
|
+
...opts.version === undefined ? {} : { version: opts.version },
|
|
751
|
+
...opts.queue === undefined ? {} : { queue: { name: opts.queue } },
|
|
752
|
+
...opts.concurrencyKey === undefined ? {} : { concurrency_key: opts.concurrencyKey },
|
|
753
|
+
...opts.priority === undefined ? {} : { priority: opts.priority },
|
|
754
|
+
...opts.ttl === undefined ? {} : { ttl: opts.ttl },
|
|
755
|
+
...maxDurationSeconds === undefined ? {} : { max_duration_seconds: maxDurationSeconds },
|
|
756
|
+
...runIdempotencyRequestFields(opts.idempotencyKey, opts.idempotencyKeyTTL)
|
|
757
|
+
};
|
|
758
|
+
const response = await this.#fetch("/api/runs", {
|
|
759
|
+
method: "POST",
|
|
760
|
+
body: JSON.stringify({
|
|
761
|
+
task_id: taskId,
|
|
762
|
+
secrets: opts.secrets ?? {},
|
|
763
|
+
...payload === undefined ? {} : { payload },
|
|
764
|
+
workspace: runWorkspace,
|
|
765
|
+
...Object.keys(runOptions).length === 0 ? {} : { options: runOptions }
|
|
766
|
+
}),
|
|
767
|
+
headers: { "content-type": "application/json" }
|
|
768
|
+
});
|
|
769
|
+
const run = await response.json();
|
|
770
|
+
return runHandle(run.id, run.task_id);
|
|
771
|
+
}
|
|
464
772
|
runs = {
|
|
465
773
|
retrieve: async (idOrHandle, opts = {}) => {
|
|
466
774
|
const response = await this.#json(`/api/runs/${encodeURIComponent(runId(idOrHandle))}`, requestSignal(opts.signal));
|
|
@@ -471,16 +779,21 @@ class HelmrClient {
|
|
|
471
779
|
const timeoutMs = opts.timeoutMs;
|
|
472
780
|
const intervalMs = opts.intervalMs ?? 1000;
|
|
473
781
|
const started = Date.now();
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
782
|
+
const wait = waitSignal(opts.signal, timeoutMs, () => new TimeoutError(`run ${id} did not finish within ${timeoutMs}ms`));
|
|
783
|
+
try {
|
|
784
|
+
for (;; ) {
|
|
785
|
+
throwIfAborted(wait.signal);
|
|
786
|
+
const run = await this.runs.retrieve(id, retrieveOptions(wait.signal));
|
|
787
|
+
if (isTerminalRunStatus(run.status)) {
|
|
788
|
+
return run;
|
|
789
|
+
}
|
|
790
|
+
if (timeoutMs !== undefined && Date.now() - started > timeoutMs) {
|
|
791
|
+
throw new TimeoutError(`run ${id} did not finish within ${timeoutMs}ms`);
|
|
792
|
+
}
|
|
793
|
+
await delay(intervalMs, wait.signal);
|
|
479
794
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
await delay(intervalMs, opts.signal);
|
|
795
|
+
} finally {
|
|
796
|
+
wait.cleanup();
|
|
484
797
|
}
|
|
485
798
|
},
|
|
486
799
|
list: async (opts = {}) => {
|
|
@@ -512,27 +825,19 @@ class HelmrClient {
|
|
|
512
825
|
}
|
|
513
826
|
};
|
|
514
827
|
waitpoints = {
|
|
515
|
-
|
|
516
|
-
const
|
|
517
|
-
await this.#fetch(`/api/runs/${encodeURIComponent(resolved.runId)}/waitpoints/${encodeURIComponent(resolved.waitpointId)}/approve`, {
|
|
518
|
-
method: "POST",
|
|
519
|
-
body: JSON.stringify(approvalBody(resolved.opts)),
|
|
520
|
-
headers: { "content-type": "application/json" }
|
|
521
|
-
});
|
|
522
|
-
},
|
|
523
|
-
deny: async (target, waitpointIdOrOpts, opts = {}) => {
|
|
524
|
-
const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
|
|
525
|
-
await this.#fetch(`/api/runs/${encodeURIComponent(resolved.runId)}/waitpoints/${encodeURIComponent(resolved.waitpointId)}/deny`, {
|
|
828
|
+
create: async (opts) => {
|
|
829
|
+
const response = await this.#json("/api/waitpoints", {
|
|
526
830
|
method: "POST",
|
|
527
|
-
body: JSON.stringify(
|
|
831
|
+
body: JSON.stringify(waitpointCreateBody(opts)),
|
|
528
832
|
headers: { "content-type": "application/json" }
|
|
529
833
|
});
|
|
834
|
+
return waitpointFromResponse(response);
|
|
530
835
|
},
|
|
531
|
-
|
|
836
|
+
respond: async (target, waitpointIdOrOpts, opts = {}) => {
|
|
532
837
|
const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
|
|
533
|
-
await this.#fetch(`/api/
|
|
838
|
+
await this.#fetch(`/api/waitpoints/${encodeURIComponent(resolved.waitpointId)}/respond`, {
|
|
534
839
|
method: "POST",
|
|
535
|
-
body: JSON.stringify(
|
|
840
|
+
body: JSON.stringify(waitpointRespondBody(resolved.opts)),
|
|
536
841
|
headers: { "content-type": "application/json" }
|
|
537
842
|
});
|
|
538
843
|
},
|
|
@@ -541,21 +846,77 @@ class HelmrClient {
|
|
|
541
846
|
const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
|
|
542
847
|
const response = await this.#json("/api/waitpoints/tokens", {
|
|
543
848
|
method: "POST",
|
|
544
|
-
body: JSON.stringify(waitpointTokenCreateBody(resolved.
|
|
849
|
+
body: JSON.stringify(waitpointTokenCreateBody(resolved.waitpointId, resolved.opts)),
|
|
545
850
|
headers: { "content-type": "application/json" }
|
|
546
851
|
});
|
|
547
852
|
return waitpointResponseTokenFromResponse(response);
|
|
548
853
|
},
|
|
549
|
-
|
|
550
|
-
const resolved = typeof target === "string" ?
|
|
551
|
-
await this.#fetch(`/api/waitpoints/tokens/${encodeURIComponent(resolved.id)}/
|
|
854
|
+
respond: async (target, tokenOrOpts, maybeOpts) => {
|
|
855
|
+
const resolved = typeof target === "string" ? resolveWaitpointTokenRespondArgs(target, tokenOrOpts, maybeOpts) : { id: target.id, token: target.token, opts: tokenOrOpts };
|
|
856
|
+
await this.#fetch(`/api/waitpoints/tokens/${encodeURIComponent(resolved.id)}/respond`, {
|
|
552
857
|
method: "POST",
|
|
553
|
-
body: JSON.stringify(
|
|
858
|
+
body: JSON.stringify(waitpointTokenRespondBody(resolved.token, resolved.opts)),
|
|
554
859
|
headers: { "content-type": "application/json" }
|
|
555
860
|
});
|
|
556
861
|
}
|
|
557
862
|
}
|
|
558
863
|
};
|
|
864
|
+
schedules = {
|
|
865
|
+
create: async (opts) => {
|
|
866
|
+
const response = await this.#json("/api/schedules", {
|
|
867
|
+
method: "POST",
|
|
868
|
+
body: JSON.stringify(scheduleCreateBody(opts)),
|
|
869
|
+
headers: { "content-type": "application/json" }
|
|
870
|
+
});
|
|
871
|
+
return scheduleFromResponse(response);
|
|
872
|
+
},
|
|
873
|
+
list: async (opts = {}) => {
|
|
874
|
+
const query = scheduleScopeQuery(opts);
|
|
875
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
876
|
+
const response = await this.#json(`/api/schedules${suffix}`, requestSignal(opts.signal));
|
|
877
|
+
return response.schedules.map(scheduleFromResponse);
|
|
878
|
+
},
|
|
879
|
+
update: async (id, opts) => {
|
|
880
|
+
const query = scheduleScopeQuery(opts);
|
|
881
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
882
|
+
const response = await this.#json(`/api/schedules/${encodeURIComponent(id)}${suffix}`, {
|
|
883
|
+
method: "PUT",
|
|
884
|
+
body: JSON.stringify(scheduleCreateBody(opts)),
|
|
885
|
+
headers: { "content-type": "application/json" },
|
|
886
|
+
...requestSignal(opts.signal)
|
|
887
|
+
});
|
|
888
|
+
return scheduleFromResponse(response);
|
|
889
|
+
},
|
|
890
|
+
retrieve: async (id, opts = {}) => {
|
|
891
|
+
const query = scheduleScopeQuery(opts);
|
|
892
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
893
|
+
return scheduleFromResponse(await this.#json(`/api/schedules/${encodeURIComponent(id)}${suffix}`, requestSignal(opts.signal)));
|
|
894
|
+
},
|
|
895
|
+
activate: async (id, opts = {}) => {
|
|
896
|
+
const query = scheduleScopeQuery(opts);
|
|
897
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
898
|
+
return scheduleFromResponse(await this.#json(`/api/schedules/${encodeURIComponent(id)}/activate${suffix}`, {
|
|
899
|
+
method: "POST",
|
|
900
|
+
...requestSignal(opts.signal)
|
|
901
|
+
}));
|
|
902
|
+
},
|
|
903
|
+
deactivate: async (id, opts = {}) => {
|
|
904
|
+
const query = scheduleScopeQuery(opts);
|
|
905
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
906
|
+
return scheduleFromResponse(await this.#json(`/api/schedules/${encodeURIComponent(id)}/deactivate${suffix}`, {
|
|
907
|
+
method: "POST",
|
|
908
|
+
...requestSignal(opts.signal)
|
|
909
|
+
}));
|
|
910
|
+
},
|
|
911
|
+
delete: async (id, opts = {}) => {
|
|
912
|
+
const query = scheduleScopeQuery(opts);
|
|
913
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
914
|
+
await this.#fetch(`/api/schedules/${encodeURIComponent(id)}${suffix}`, {
|
|
915
|
+
method: "DELETE",
|
|
916
|
+
...requestSignal(opts.signal)
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
};
|
|
559
920
|
async#retrieveLogs(id, signal) {
|
|
560
921
|
const response = await this.#json(`/api/runs/${encodeURIComponent(id)}/logs`, requestSignal(signal));
|
|
561
922
|
return {
|
|
@@ -657,43 +1018,122 @@ function runResponseToSnapshot(response) {
|
|
|
657
1018
|
exitCode: response.exit_code ?? null,
|
|
658
1019
|
...response.created_at === undefined ? {} : { createdAt: response.created_at },
|
|
659
1020
|
...response.updated_at === undefined ? {} : { updatedAt: response.updated_at },
|
|
660
|
-
pendingWaitpoint: pendingWaitpointFromResponse(response.id, response.
|
|
1021
|
+
pendingWaitpoint: pendingWaitpointFromResponse(response.id, response.pending_waitpoint),
|
|
661
1022
|
..."output" in response ? { output: response.output } : {}
|
|
662
1023
|
});
|
|
663
1024
|
}
|
|
664
|
-
function
|
|
665
|
-
return
|
|
1025
|
+
function scheduleCreateBody(opts) {
|
|
1026
|
+
return {
|
|
1027
|
+
..."deduplicationKey" in opts && opts.deduplicationKey !== undefined ? { deduplication_key: opts.deduplicationKey } : {},
|
|
1028
|
+
...opts.projectId === undefined ? {} : { project_id: opts.projectId },
|
|
1029
|
+
...opts.environmentId === undefined ? {} : { environment_id: opts.environmentId },
|
|
1030
|
+
...opts.externalId === undefined ? {} : { external_id: opts.externalId },
|
|
1031
|
+
task: opts.task,
|
|
1032
|
+
cron: opts.cron,
|
|
1033
|
+
...opts.timezone === undefined ? {} : { timezone: opts.timezone },
|
|
1034
|
+
...opts.active === undefined ? {} : { active: opts.active },
|
|
1035
|
+
workspace: runWorkspaceFromSpec(opts.workspace),
|
|
1036
|
+
...opts.secretBindings === undefined ? {} : { secret_bindings: opts.secretBindings },
|
|
1037
|
+
...opts.options === undefined ? {} : { options: runOptionsBody(opts.options) }
|
|
1038
|
+
};
|
|
666
1039
|
}
|
|
667
|
-
function
|
|
1040
|
+
function runOptionsBody(opts) {
|
|
1041
|
+
if (opts === undefined)
|
|
1042
|
+
return {};
|
|
1043
|
+
return {
|
|
1044
|
+
...opts.deploymentId === undefined ? {} : { deployment_id: opts.deploymentId },
|
|
1045
|
+
...opts.version === undefined ? {} : { version: opts.version },
|
|
1046
|
+
...opts.queue === undefined ? {} : { queue: { name: opts.queue } },
|
|
1047
|
+
...opts.concurrencyKey === undefined ? {} : { concurrency_key: opts.concurrencyKey },
|
|
1048
|
+
...opts.priority === undefined ? {} : { priority: opts.priority },
|
|
1049
|
+
...opts.ttl === undefined ? {} : { ttl: opts.ttl },
|
|
1050
|
+
...opts.maxDurationSeconds === undefined ? {} : { max_duration_seconds: opts.maxDurationSeconds }
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
function scheduleScopeQuery(opts) {
|
|
1054
|
+
const query = new URLSearchParams;
|
|
1055
|
+
if (opts.projectId !== undefined)
|
|
1056
|
+
query.set("project_id", opts.projectId);
|
|
1057
|
+
if (opts.environmentId !== undefined)
|
|
1058
|
+
query.set("environment_id", opts.environmentId);
|
|
1059
|
+
return query;
|
|
1060
|
+
}
|
|
1061
|
+
function scheduleFromResponse(response) {
|
|
1062
|
+
return {
|
|
1063
|
+
id: response.id,
|
|
1064
|
+
type: response.type,
|
|
1065
|
+
projectId: response.project_id,
|
|
1066
|
+
environmentId: response.environment_id,
|
|
1067
|
+
task: response.task,
|
|
1068
|
+
...response.deduplication_key === undefined || response.deduplication_key === "" ? {} : { deduplicationKey: response.deduplication_key },
|
|
1069
|
+
...response.external_id === undefined || response.external_id === "" ? {} : { externalId: response.external_id },
|
|
1070
|
+
cron: response.cron,
|
|
1071
|
+
timezone: response.timezone,
|
|
1072
|
+
active: response.active,
|
|
1073
|
+
status: response.status,
|
|
1074
|
+
...response.last_error === undefined || response.last_error === "" ? {} : { lastError: response.last_error },
|
|
1075
|
+
..."workspace" in response ? { workspace: response.workspace } : {},
|
|
1076
|
+
...response.next_scheduled_at === undefined ? {} : { nextScheduledAt: response.next_scheduled_at },
|
|
1077
|
+
...response.last_scheduled_at === undefined ? {} : { lastScheduledAt: response.last_scheduled_at },
|
|
1078
|
+
createdAt: response.created_at,
|
|
1079
|
+
updatedAt: response.updated_at
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
function waitpointTokenCreateBody(waitpointId, opts) {
|
|
668
1083
|
return {
|
|
669
|
-
run_id: runId2,
|
|
670
1084
|
waitpoint_id: waitpointId,
|
|
671
|
-
...opts.actions === undefined ? {} : { actions: opts.actions },
|
|
672
1085
|
...opts.expiresInSeconds === undefined ? {} : { expires_in_seconds: opts.expiresInSeconds },
|
|
673
1086
|
...opts.expiresAt === undefined ? {} : { expires_at: opts.expiresAt },
|
|
674
1087
|
...opts.metadata === undefined ? {} : { metadata: opts.metadata }
|
|
675
1088
|
};
|
|
676
1089
|
}
|
|
677
|
-
function
|
|
1090
|
+
function waitpointCreateBody(opts) {
|
|
678
1091
|
return {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
...
|
|
682
|
-
...
|
|
1092
|
+
...opts.projectId === undefined ? {} : { project_id: opts.projectId },
|
|
1093
|
+
...opts.environmentId === undefined ? {} : { environment_id: opts.environmentId },
|
|
1094
|
+
...opts.request === undefined ? {} : { request: opts.request },
|
|
1095
|
+
...opts.displayText === undefined ? {} : { display_text: opts.displayText },
|
|
1096
|
+
expires_at: opts.expiresAt,
|
|
1097
|
+
...opts.idempotencyKey === undefined ? {} : { idempotency_key: opts.idempotencyKey },
|
|
1098
|
+
...opts.idempotencyKeyExpiresAt === undefined ? {} : { idempotency_key_expires_at: opts.idempotencyKeyExpiresAt },
|
|
1099
|
+
...opts.idempotencyKeyTTLSeconds === undefined ? {} : { idempotency_key_ttl_seconds: opts.idempotencyKeyTTLSeconds }
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
function waitpointFromResponse(response) {
|
|
1103
|
+
return {
|
|
1104
|
+
id: response.id,
|
|
1105
|
+
projectId: response.project_id,
|
|
1106
|
+
environmentId: response.environment_id,
|
|
1107
|
+
kind: response.kind,
|
|
1108
|
+
status: response.status,
|
|
1109
|
+
request: response.request ?? {},
|
|
1110
|
+
displayText: response.display_text ?? "",
|
|
1111
|
+
expiresAt: response.expires_at ?? null,
|
|
1112
|
+
createdAt: response.created_at
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
function waitpointRespondBody(opts) {
|
|
1116
|
+
return {
|
|
1117
|
+
..."value" in opts ? { value: opts.value } : {},
|
|
683
1118
|
...opts.externalSubject === undefined ? {} : { external_subject: opts.externalSubject },
|
|
684
1119
|
...opts.metadata === undefined ? {} : { metadata: opts.metadata }
|
|
685
1120
|
};
|
|
686
1121
|
}
|
|
687
|
-
function
|
|
1122
|
+
function waitpointTokenRespondBody(token, opts) {
|
|
1123
|
+
return {
|
|
1124
|
+
token,
|
|
1125
|
+
...waitpointRespondBody(opts)
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
function resolveWaitpointTokenRespondArgs(id, token, opts) {
|
|
688
1129
|
if (typeof token !== "string" || opts === undefined) {
|
|
689
|
-
throw new Error("waitpoint token secret is required when
|
|
1130
|
+
throw new Error("waitpoint token secret is required when responding by token id");
|
|
690
1131
|
}
|
|
691
1132
|
return { id, token, opts };
|
|
692
1133
|
}
|
|
693
1134
|
function waitpointResponseTokenFromResponse(response) {
|
|
694
1135
|
return {
|
|
695
1136
|
id: response.id,
|
|
696
|
-
runId: response.run_id,
|
|
697
1137
|
waitpointId: response.waitpoint_id,
|
|
698
1138
|
url: response.url,
|
|
699
1139
|
token: response.token,
|
|
@@ -702,27 +1142,21 @@ function waitpointResponseTokenFromResponse(response) {
|
|
|
702
1142
|
}
|
|
703
1143
|
function resolveWaitpointArgs(target, waitpointIdOrOpts, opts) {
|
|
704
1144
|
if (isWaitpointRef(target)) {
|
|
705
|
-
const resolvedOpts = waitpointIdOrOpts !== undefined && typeof waitpointIdOrOpts !== "string" ? waitpointIdOrOpts : opts;
|
|
706
1145
|
return {
|
|
707
|
-
runId: target.runId,
|
|
708
1146
|
waitpointId: target.waitpointId,
|
|
709
|
-
opts:
|
|
1147
|
+
opts: waitpointIdOrOpts ?? opts ?? {}
|
|
710
1148
|
};
|
|
711
1149
|
}
|
|
712
|
-
if (typeof waitpointIdOrOpts !== "string") {
|
|
713
|
-
throw new Error("waitpoint id is required when resolving a waitpoint by run id");
|
|
714
|
-
}
|
|
715
1150
|
return {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
opts: opts ?? {}
|
|
1151
|
+
waitpointId: target,
|
|
1152
|
+
opts: waitpointIdOrOpts ?? opts ?? {}
|
|
719
1153
|
};
|
|
720
1154
|
}
|
|
721
1155
|
function isWaitpointRef(value) {
|
|
722
1156
|
if (value === null || typeof value !== "object")
|
|
723
1157
|
return false;
|
|
724
1158
|
const record = value;
|
|
725
|
-
return typeof record["
|
|
1159
|
+
return typeof record["waitpointId"] === "string";
|
|
726
1160
|
}
|
|
727
1161
|
function retrieveOptions(signal) {
|
|
728
1162
|
return signal === undefined ? {} : { signal };
|
|
@@ -730,6 +1164,28 @@ function retrieveOptions(signal) {
|
|
|
730
1164
|
function requestSignal(signal) {
|
|
731
1165
|
return signal === undefined ? {} : { signal };
|
|
732
1166
|
}
|
|
1167
|
+
function waitSignal(signal, timeoutMs, timeoutError) {
|
|
1168
|
+
if (timeoutMs === undefined) {
|
|
1169
|
+
return { signal, cleanup: () => {} };
|
|
1170
|
+
}
|
|
1171
|
+
const controller = new AbortController;
|
|
1172
|
+
const abortFromParent = () => {
|
|
1173
|
+
controller.abort(signal?.reason);
|
|
1174
|
+
};
|
|
1175
|
+
if (signal?.aborted === true) {
|
|
1176
|
+
abortFromParent();
|
|
1177
|
+
} else {
|
|
1178
|
+
signal?.addEventListener("abort", abortFromParent, { once: true });
|
|
1179
|
+
}
|
|
1180
|
+
const timeout = setTimeout(() => controller.abort(timeoutError()), timeoutMs);
|
|
1181
|
+
return {
|
|
1182
|
+
signal: controller.signal,
|
|
1183
|
+
cleanup: () => {
|
|
1184
|
+
clearTimeout(timeout);
|
|
1185
|
+
signal?.removeEventListener("abort", abortFromParent);
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
733
1189
|
function throwIfAborted(signal) {
|
|
734
1190
|
if (signal?.aborted !== true)
|
|
735
1191
|
return;
|
|
@@ -763,29 +1219,52 @@ async function* parseSse(response) {
|
|
|
763
1219
|
}
|
|
764
1220
|
const decoder = new TextDecoder;
|
|
765
1221
|
let buffer = "";
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
1222
|
+
try {
|
|
1223
|
+
for (;; ) {
|
|
1224
|
+
const { value, done } = await reader.read();
|
|
1225
|
+
if (done) {
|
|
1226
|
+
buffer += decoder.decode();
|
|
1227
|
+
const finalEvent = parseSseFrame(buffer);
|
|
1228
|
+
if (finalEvent !== undefined) {
|
|
1229
|
+
yield finalEvent;
|
|
1230
|
+
}
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1234
|
+
let boundary = findSseBoundary(buffer);
|
|
1235
|
+
while (boundary !== -1) {
|
|
1236
|
+
const delimiter = buffer.startsWith(`\r
|
|
775
1237
|
\r
|
|
776
1238
|
`, boundary) ? 4 : 2;
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
`);
|
|
781
|
-
if (data !== "") {
|
|
782
|
-
const event = runEventRecordToRunEvent(JSON.parse(data));
|
|
1239
|
+
const raw = buffer.slice(0, boundary);
|
|
1240
|
+
buffer = buffer.slice(boundary + delimiter);
|
|
1241
|
+
const event = parseSseFrame(raw);
|
|
783
1242
|
if (event !== undefined) {
|
|
784
1243
|
yield event;
|
|
785
1244
|
}
|
|
1245
|
+
boundary = findSseBoundary(buffer);
|
|
786
1246
|
}
|
|
787
|
-
|
|
1247
|
+
if (buffer.length > MAX_SSE_BUFFER_CHARS) {
|
|
1248
|
+
throw new Error("SSE event exceeded the maximum buffer size");
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
} finally {
|
|
1252
|
+
reader.releaseLock();
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
function parseSseFrame(raw) {
|
|
1256
|
+
const data = raw.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join(`
|
|
1257
|
+
`);
|
|
1258
|
+
if (data === "") {
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
try {
|
|
1262
|
+
return runEventRecordToRunEvent(JSON.parse(data));
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
if (error instanceof SyntaxError) {
|
|
1265
|
+
return;
|
|
788
1266
|
}
|
|
1267
|
+
throw error;
|
|
789
1268
|
}
|
|
790
1269
|
}
|
|
791
1270
|
function findSseBoundary(buffer) {
|
|
@@ -802,121 +1281,102 @@ function findSseBoundary(buffer) {
|
|
|
802
1281
|
return Math.min(lf, crlf);
|
|
803
1282
|
}
|
|
804
1283
|
function runEventRecordToRunEvent(event) {
|
|
805
|
-
const
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
1284
|
+
const record = objectRecord(event);
|
|
1285
|
+
const message = stringValue(record?.["message"]);
|
|
1286
|
+
const at = stringValue(record?.["at"]);
|
|
1287
|
+
if (record === undefined || message === undefined || at === undefined) {
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
const attributes = objectRecord(record["attributes"]);
|
|
1291
|
+
const runId2 = stringValue(record["run_id"]) ?? stringValue(attributes?.["run_id"]) ?? "";
|
|
1292
|
+
if (message === "log.stdout" || message === "log.stderr") {
|
|
1293
|
+
const stream = message === "log.stdout" ? "stdout" : "stderr";
|
|
809
1294
|
return {
|
|
810
1295
|
type: "log",
|
|
811
1296
|
run_id: runId2,
|
|
812
1297
|
stream,
|
|
813
1298
|
bytes: numberValue(attributes?.["bytes"]) ?? 0,
|
|
814
1299
|
observed_seq: numberValue(attributes?.["observed_seq"]) ?? 0,
|
|
815
|
-
at
|
|
1300
|
+
at
|
|
816
1301
|
};
|
|
817
1302
|
}
|
|
818
|
-
if (
|
|
819
|
-
const message = stringValue(attributes?.["display_text"]);
|
|
1303
|
+
if (message === "waitpoint.requested") {
|
|
820
1304
|
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
1305
|
+
const kind = stringValue(attributes?.["kind"]);
|
|
821
1306
|
if (waitpointId === undefined)
|
|
822
1307
|
return;
|
|
823
|
-
|
|
824
|
-
type: "approval_request",
|
|
825
|
-
run_id: runId2,
|
|
826
|
-
waitpoint_id: waitpointId,
|
|
827
|
-
message: message ?? "",
|
|
828
|
-
...optionalNumber("timeout", attributes?.["timeout"]),
|
|
829
|
-
at: event.at
|
|
830
|
-
};
|
|
831
|
-
}
|
|
832
|
-
if (event.message === "waitpoint.resolved" && stringValue(attributes?.["kind"]) === "approval") {
|
|
833
|
-
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
834
|
-
const resolution = stringValue(attributes?.["resolution_kind"]);
|
|
835
|
-
if (waitpointId === undefined)
|
|
836
|
-
return;
|
|
837
|
-
if (resolution !== "approved" && resolution !== "denied")
|
|
1308
|
+
if (kind === undefined)
|
|
838
1309
|
return;
|
|
839
1310
|
return {
|
|
840
|
-
type: "
|
|
1311
|
+
type: "waitpoint_request",
|
|
841
1312
|
run_id: runId2,
|
|
842
1313
|
waitpoint_id: waitpointId,
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
if (event.message === "waitpoint.requested" && stringValue(attributes?.["kind"]) === "message") {
|
|
849
|
-
const request = objectRecord(attributes?.["request"]);
|
|
850
|
-
const message = stringValue(attributes?.["display_text"]) ?? stringValue(request?.["prompt"]);
|
|
851
|
-
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
852
|
-
if (waitpointId === undefined)
|
|
853
|
-
return;
|
|
854
|
-
return {
|
|
855
|
-
type: "message_request",
|
|
856
|
-
run_id: runId2,
|
|
857
|
-
waitpoint_id: waitpointId,
|
|
858
|
-
...optionalString("prompt", message),
|
|
1314
|
+
kind,
|
|
1315
|
+
displayText: stringValue(attributes?.["display_text"]) ?? "",
|
|
1316
|
+
request: attributes?.["request"] ?? {},
|
|
859
1317
|
...optionalNumber("timeout", attributes?.["timeout"]),
|
|
860
|
-
at
|
|
1318
|
+
at
|
|
861
1319
|
};
|
|
862
1320
|
}
|
|
863
|
-
if (
|
|
864
|
-
const result = objectRecord(attributes?.["result"]);
|
|
865
|
-
const text = stringValue(result?.["text"]);
|
|
1321
|
+
if (message === "waitpoint.resolved") {
|
|
866
1322
|
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
1323
|
+
const kind = stringValue(attributes?.["kind"]);
|
|
1324
|
+
const resolution = stringValue(attributes?.["resolution_kind"]);
|
|
867
1325
|
if (waitpointId === undefined)
|
|
868
1326
|
return;
|
|
869
|
-
if (
|
|
1327
|
+
if (kind === undefined || resolution === undefined)
|
|
870
1328
|
return;
|
|
871
1329
|
return {
|
|
872
|
-
type: "
|
|
1330
|
+
type: "waitpoint_resolved",
|
|
873
1331
|
run_id: runId2,
|
|
874
1332
|
waitpoint_id: waitpointId,
|
|
875
|
-
|
|
876
|
-
|
|
1333
|
+
kind,
|
|
1334
|
+
resolutionKind: resolution,
|
|
1335
|
+
value: attributes?.["result"],
|
|
1336
|
+
at
|
|
877
1337
|
};
|
|
878
1338
|
}
|
|
879
|
-
if (
|
|
1339
|
+
if (message.startsWith("emit.")) {
|
|
880
1340
|
return {
|
|
881
1341
|
type: "emit",
|
|
882
1342
|
run_id: runId2,
|
|
883
|
-
event_type: stringValue(attributes?.["type"]) ??
|
|
1343
|
+
event_type: stringValue(attributes?.["type"]) ?? message.slice("emit.".length),
|
|
884
1344
|
content: attributes?.["content"],
|
|
885
|
-
at
|
|
1345
|
+
at
|
|
886
1346
|
};
|
|
887
1347
|
}
|
|
888
|
-
if (
|
|
1348
|
+
if (message === "run.completed") {
|
|
889
1349
|
return {
|
|
890
|
-
type: "
|
|
1350
|
+
type: "task_result",
|
|
891
1351
|
run_id: runId2,
|
|
892
1352
|
exit_code: numberValue(attributes?.["exit_code"]) ?? 0,
|
|
893
|
-
at
|
|
1353
|
+
at
|
|
894
1354
|
};
|
|
895
1355
|
}
|
|
896
|
-
if (
|
|
1356
|
+
if (message === "run.failed") {
|
|
897
1357
|
return {
|
|
898
1358
|
type: "run_failed",
|
|
899
1359
|
run_id: runId2,
|
|
900
1360
|
failure_kind: stringValue(attributes?.["failure_kind"]) ?? "task_failed",
|
|
901
1361
|
detail: attributes?.["detail"],
|
|
902
|
-
at
|
|
1362
|
+
at
|
|
903
1363
|
};
|
|
904
1364
|
}
|
|
905
|
-
if (
|
|
1365
|
+
if (message === "run.cancelled") {
|
|
906
1366
|
return {
|
|
907
|
-
type: "
|
|
1367
|
+
type: "run_cancelled",
|
|
908
1368
|
run_id: runId2,
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
at: event.at
|
|
1369
|
+
...optionalString("reason", attributes?.["reason"]),
|
|
1370
|
+
at
|
|
912
1371
|
};
|
|
913
1372
|
}
|
|
914
|
-
if (
|
|
1373
|
+
if (message === "run.expired") {
|
|
915
1374
|
return {
|
|
916
|
-
type: "
|
|
1375
|
+
type: "run_expired",
|
|
917
1376
|
run_id: runId2,
|
|
918
|
-
...optionalString("
|
|
919
|
-
|
|
1377
|
+
...optionalString("ttl", attributes?.["ttl"]),
|
|
1378
|
+
...optionalString("message", attributes?.["message"]),
|
|
1379
|
+
at
|
|
920
1380
|
};
|
|
921
1381
|
}
|
|
922
1382
|
return;
|
|
@@ -951,20 +1411,21 @@ function defineConfig(config) {
|
|
|
951
1411
|
if (config === null || typeof config !== "object") {
|
|
952
1412
|
throw new Error("defineConfig() requires an object");
|
|
953
1413
|
}
|
|
1414
|
+
if (!("project" in config)) {
|
|
1415
|
+
throw new Error("defineConfig({ project }) requires a non-empty string");
|
|
1416
|
+
}
|
|
1417
|
+
if (typeof config.project !== "string" || config.project.trim() === "") {
|
|
1418
|
+
throw new Error("defineConfig({ project }) must be a non-empty string");
|
|
1419
|
+
}
|
|
1420
|
+
if (config.project.includes("\x00")) {
|
|
1421
|
+
throw new Error("defineConfig({ project }) must not contain NUL");
|
|
1422
|
+
}
|
|
954
1423
|
if (!("dirs" in config)) {
|
|
955
1424
|
throw new Error("defineConfig({ dirs }) requires a non-empty dirs array");
|
|
956
1425
|
}
|
|
957
1426
|
if (!Array.isArray(config.dirs) || config.dirs.length === 0) {
|
|
958
1427
|
throw new Error("defineConfig({ dirs }) requires a non-empty dirs array");
|
|
959
1428
|
}
|
|
960
|
-
if (config.project !== undefined) {
|
|
961
|
-
if (typeof config.project !== "string" || config.project.trim() === "") {
|
|
962
|
-
throw new Error("defineConfig({ project }) must be a non-empty string");
|
|
963
|
-
}
|
|
964
|
-
if (config.project.includes("\x00")) {
|
|
965
|
-
throw new Error("defineConfig({ project }) must not contain NUL");
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
1429
|
for (const dir of config.dirs) {
|
|
969
1430
|
if (typeof dir !== "string" || dir.trim() === "") {
|
|
970
1431
|
throw new Error("defineConfig({ dirs }) entries must be non-empty strings");
|
|
@@ -987,17 +1448,12 @@ function defineConfig(config) {
|
|
|
987
1448
|
}
|
|
988
1449
|
}
|
|
989
1450
|
return markConfig({
|
|
990
|
-
|
|
1451
|
+
project: config.project,
|
|
991
1452
|
dirs: [...config.dirs],
|
|
992
1453
|
...config.ignorePatterns === undefined ? {} : { ignorePatterns: [...config.ignorePatterns] }
|
|
993
1454
|
});
|
|
994
1455
|
}
|
|
995
1456
|
|
|
996
|
-
// sdk/typescript/src/task.ts
|
|
997
|
-
function task(config) {
|
|
998
|
-
return markTask(config);
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
1457
|
// sdk/typescript/src/trigger.ts
|
|
1002
1458
|
var defaultClient;
|
|
1003
1459
|
function getDefaultClient() {
|
|
@@ -1005,10 +1461,102 @@ function getDefaultClient() {
|
|
|
1005
1461
|
return defaultClient;
|
|
1006
1462
|
}
|
|
1007
1463
|
var tasks = {
|
|
1008
|
-
trigger(
|
|
1009
|
-
return getDefaultClient().tasks.trigger(
|
|
1464
|
+
trigger(...args) {
|
|
1465
|
+
return getDefaultClient().tasks.trigger(...args);
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
function triggerTask(task, ...args) {
|
|
1469
|
+
return getDefaultClient()[triggerTaskClientMethod](task, ...args);
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
// sdk/typescript/src/task.ts
|
|
1473
|
+
function task(config) {
|
|
1474
|
+
const marked = markTask(config);
|
|
1475
|
+
Object.defineProperty(marked, "trigger", {
|
|
1476
|
+
value: (...args) => triggerTask(marked, ...args)
|
|
1477
|
+
});
|
|
1478
|
+
return marked;
|
|
1479
|
+
}
|
|
1480
|
+
function queue(config) {
|
|
1481
|
+
return Object.freeze({ ...config });
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
// sdk/typescript/src/schedules.ts
|
|
1485
|
+
function task2(config) {
|
|
1486
|
+
const { cron, workspace, secretBindings, ...taskConfig } = config;
|
|
1487
|
+
const taskId = config.id;
|
|
1488
|
+
if (cron !== undefined && workspace === undefined) {
|
|
1489
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule workspace is required`);
|
|
1490
|
+
}
|
|
1491
|
+
const schedule = cron === undefined ? undefined : {
|
|
1492
|
+
cron: typeof cron === "string" ? cron : cron.pattern,
|
|
1493
|
+
...typeof cron === "string" || cron.timezone === undefined ? {} : { timezone: cron.timezone },
|
|
1494
|
+
workspace,
|
|
1495
|
+
...secretBindings === undefined ? {} : { secretBindings }
|
|
1496
|
+
};
|
|
1497
|
+
const marked = markScheduledTask({ ...taskConfig, payload: scheduledTaskPayloadSchema }, schedule);
|
|
1498
|
+
Object.defineProperty(marked, "trigger", {
|
|
1499
|
+
value: (...args) => triggerTask(marked, ...args)
|
|
1500
|
+
});
|
|
1501
|
+
return marked;
|
|
1502
|
+
}
|
|
1503
|
+
var scheduledTaskPayloadSchema = {
|
|
1504
|
+
"~standard": {
|
|
1505
|
+
version: 1,
|
|
1506
|
+
vendor: "helmr",
|
|
1507
|
+
validate(value) {
|
|
1508
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
1509
|
+
return { issues: [{ message: "expected scheduled task payload object" }] };
|
|
1510
|
+
}
|
|
1511
|
+
const input = value;
|
|
1512
|
+
const timestamp = parseDateField(input["timestamp"], "timestamp");
|
|
1513
|
+
const lastTimestamp = parseOptionalDateField(input["lastTimestamp"], "lastTimestamp");
|
|
1514
|
+
const timezone = input["timezone"];
|
|
1515
|
+
const scheduleId = input["scheduleId"];
|
|
1516
|
+
const externalId = input["externalId"];
|
|
1517
|
+
const upcoming = input["upcoming"];
|
|
1518
|
+
const issues = [
|
|
1519
|
+
...timestamp.issues,
|
|
1520
|
+
...lastTimestamp.issues,
|
|
1521
|
+
...typeof timezone === "string" && timezone.trim() !== "" ? [] : [{ message: "expected string", path: ["timezone"] }],
|
|
1522
|
+
...typeof scheduleId === "string" && scheduleId.trim() !== "" ? [] : [{ message: "expected string", path: ["scheduleId"] }],
|
|
1523
|
+
...externalId === undefined || typeof externalId === "string" ? [] : [{ message: "expected string", path: ["externalId"] }],
|
|
1524
|
+
...Array.isArray(upcoming) ? [] : [{ message: "expected array", path: ["upcoming"] }]
|
|
1525
|
+
];
|
|
1526
|
+
const upcomingDates = Array.isArray(upcoming) ? upcoming.map((item, index) => parseDateField(item, `upcoming.${index}`)) : [];
|
|
1527
|
+
issues.push(...upcomingDates.flatMap((item) => item.issues));
|
|
1528
|
+
if (issues.length > 0) {
|
|
1529
|
+
return { issues };
|
|
1530
|
+
}
|
|
1531
|
+
return {
|
|
1532
|
+
value: {
|
|
1533
|
+
timestamp: timestamp.value,
|
|
1534
|
+
...lastTimestamp.value === undefined ? {} : { lastTimestamp: lastTimestamp.value },
|
|
1535
|
+
timezone,
|
|
1536
|
+
scheduleId,
|
|
1537
|
+
...externalId === undefined ? {} : { externalId },
|
|
1538
|
+
upcoming: upcomingDates.map((item) => item.value)
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1010
1542
|
}
|
|
1011
1543
|
};
|
|
1544
|
+
function parseDateField(value, path) {
|
|
1545
|
+
if (typeof value !== "string") {
|
|
1546
|
+
return { value: new Date(0), issues: [{ message: "expected ISO timestamp", path: path.split(".") }] };
|
|
1547
|
+
}
|
|
1548
|
+
const date = new Date(value);
|
|
1549
|
+
if (Number.isNaN(date.getTime())) {
|
|
1550
|
+
return { value: new Date(0), issues: [{ message: "expected ISO timestamp", path: path.split(".") }] };
|
|
1551
|
+
}
|
|
1552
|
+
return { value: date, issues: [] };
|
|
1553
|
+
}
|
|
1554
|
+
function parseOptionalDateField(value, path) {
|
|
1555
|
+
if (value === undefined || value === null) {
|
|
1556
|
+
return { issues: [] };
|
|
1557
|
+
}
|
|
1558
|
+
return parseDateField(value, path);
|
|
1559
|
+
}
|
|
1012
1560
|
// sdk/typescript/src/index.ts
|
|
1013
1561
|
var image = (id) => new ImageBuilderImpl(id);
|
|
1014
1562
|
var cache = (id) => ({ id });
|
|
@@ -1051,6 +1599,16 @@ var waitpoints = new Proxy({}, {
|
|
|
1051
1599
|
return Reflect.get(getDefaultClient().waitpoints, property, receiver);
|
|
1052
1600
|
}
|
|
1053
1601
|
});
|
|
1602
|
+
var schedules = Object.freeze({
|
|
1603
|
+
task: task2,
|
|
1604
|
+
create: (...args) => getDefaultClient().schedules.create(...args),
|
|
1605
|
+
update: (...args) => getDefaultClient().schedules.update(...args),
|
|
1606
|
+
list: (...args) => getDefaultClient().schedules.list(...args),
|
|
1607
|
+
retrieve: (...args) => getDefaultClient().schedules.retrieve(...args),
|
|
1608
|
+
activate: (...args) => getDefaultClient().schedules.activate(...args),
|
|
1609
|
+
deactivate: (...args) => getDefaultClient().schedules.deactivate(...args),
|
|
1610
|
+
delete: (...args) => getDefaultClient().schedules.delete(...args)
|
|
1611
|
+
});
|
|
1054
1612
|
export {
|
|
1055
1613
|
workspace,
|
|
1056
1614
|
waitpoints,
|
|
@@ -1058,17 +1616,19 @@ export {
|
|
|
1058
1616
|
tasks,
|
|
1059
1617
|
task,
|
|
1060
1618
|
source,
|
|
1619
|
+
schedules,
|
|
1061
1620
|
sandbox,
|
|
1062
1621
|
runs,
|
|
1622
|
+
queue,
|
|
1063
1623
|
image,
|
|
1624
|
+
idempotencyKeys,
|
|
1064
1625
|
defineConfig,
|
|
1065
1626
|
cache,
|
|
1066
1627
|
UnsupportedTransportError,
|
|
1067
1628
|
TimeoutError,
|
|
1068
1629
|
RunNotFoundError,
|
|
1069
|
-
|
|
1630
|
+
PayloadSchemaValidationError,
|
|
1070
1631
|
HelmrClient,
|
|
1071
1632
|
ConcurrentWaitError,
|
|
1072
|
-
AuthError
|
|
1073
|
-
ApprovalTimeoutError
|
|
1633
|
+
AuthError
|
|
1074
1634
|
};
|