@helmr/sdk 0.1.1-rc.4 → 0.1.1-rc.6
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 +18 -13
- package/dist/compile.js +29 -3
- package/dist/idempotency.d.ts +30 -0
- package/dist/index.d.ts +26 -9
- package/dist/index.js +674 -202
- package/dist/internal.d.ts +131 -65
- package/dist/internal.js +263 -26
- package/dist/runtime/client.d.ts +106 -56
- package/dist/runtime/run.d.ts +32 -48
- package/dist/schedules.d.ts +28 -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/runtime/source.d.ts +0 -7
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;
|
|
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
|
+
}
|
|
88
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,133 @@ 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.secretBindings !== undefined) {
|
|
308
|
+
if (value.secretBindings === null || typeof value.secretBindings !== "object" || Array.isArray(value.secretBindings)) {
|
|
309
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule secretBindings must be an object`);
|
|
310
|
+
}
|
|
311
|
+
for (const [name, binding] of Object.entries(value.secretBindings)) {
|
|
312
|
+
validateSecretName(name, `task ${JSON.stringify(taskId)} schedule secretBindings.${name}`);
|
|
313
|
+
if (typeof binding !== "string" || binding.trim() === "") {
|
|
314
|
+
throw new Error(`task ${JSON.stringify(taskId)} schedule secretBindings.${name} must be a non-empty string`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function validateTaskQueue(taskId, value) {
|
|
320
|
+
if (value === undefined) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (value.name !== undefined) {
|
|
324
|
+
validateQueueName(value.name);
|
|
325
|
+
}
|
|
326
|
+
validateOptionalQueueConcurrencyLimit(value.concurrencyLimit);
|
|
327
|
+
if (value.name === undefined && value.concurrencyLimit === undefined) {
|
|
328
|
+
throw new Error(`task ${JSON.stringify(taskId)} queue must include name or concurrencyLimit`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function validateOptionalTTL(value, label = "ttl") {
|
|
332
|
+
if (value === undefined) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (typeof value === "string" && isPositiveDurationString(value)) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
throw new Error(`${label} must be a positive duration string`);
|
|
339
|
+
}
|
|
340
|
+
function isPositiveDurationString(value) {
|
|
341
|
+
const raw = value.trim();
|
|
342
|
+
if (raw === "") {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
if (/^[1-9][0-9]*d$/.test(raw)) {
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
const sign = raw.startsWith("+") || raw.startsWith("-") ? raw.slice(0, 1) : "";
|
|
349
|
+
if (sign === "-") {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
const body = sign === "" ? raw : raw.slice(1);
|
|
353
|
+
const tokenPattern = /([0-9]+(?:\.[0-9]*)?|\.[0-9]+)(ns|us|µs|μs|ms|s|m|h)/gy;
|
|
354
|
+
let totalNanoseconds = 0;
|
|
355
|
+
let offset = 0;
|
|
356
|
+
for (;; ) {
|
|
357
|
+
tokenPattern.lastIndex = offset;
|
|
358
|
+
const match = tokenPattern.exec(body);
|
|
359
|
+
if (match === null) {
|
|
360
|
+
return offset === body.length && totalNanoseconds >= 1;
|
|
361
|
+
}
|
|
362
|
+
if (match.index !== offset) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
const amount = Number(match[1]);
|
|
366
|
+
if (!Number.isFinite(amount) || amount < 0) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
totalNanoseconds += amount * durationUnitNanoseconds(match[2] ?? "");
|
|
370
|
+
offset = tokenPattern.lastIndex;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function durationUnitNanoseconds(unit) {
|
|
374
|
+
switch (unit) {
|
|
375
|
+
case "ns":
|
|
376
|
+
return 1;
|
|
377
|
+
case "us":
|
|
378
|
+
case "µs":
|
|
379
|
+
case "μs":
|
|
380
|
+
return 1000;
|
|
381
|
+
case "ms":
|
|
382
|
+
return 1e6;
|
|
383
|
+
case "s":
|
|
384
|
+
return 1e9;
|
|
385
|
+
case "m":
|
|
386
|
+
return 60000000000;
|
|
387
|
+
case "h":
|
|
388
|
+
return 3600000000000;
|
|
389
|
+
default:
|
|
390
|
+
return 0;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async function parseTaskPayload(task, payload) {
|
|
394
|
+
if (task.payload === undefined) {
|
|
395
|
+
throw new Error(`task ${JSON.stringify(task.id)} does not accept payload`);
|
|
396
|
+
}
|
|
397
|
+
return await parsePayloadWithSchema(task.payload, payload, `task ${JSON.stringify(task.id)} payload`);
|
|
398
|
+
}
|
|
171
399
|
function markConfig(config) {
|
|
172
400
|
Object.defineProperty(config, configBrand, { value: true });
|
|
173
401
|
return config;
|
|
@@ -270,7 +498,8 @@ class SandboxBuilderImpl {
|
|
|
270
498
|
resources(opts) {
|
|
271
499
|
const resourceSpec = {
|
|
272
500
|
...opts.cpu === undefined ? {} : { cpu: opts.cpu },
|
|
273
|
-
...opts.memory === undefined ? {} : { memory: opts.memory }
|
|
501
|
+
...opts.memory === undefined ? {} : { memory: opts.memory },
|
|
502
|
+
...opts.disk === undefined ? {} : { disk: opts.disk }
|
|
274
503
|
};
|
|
275
504
|
return new SandboxBuilderImpl(this.id, this.imageBuilder, this.workspaceBinding, resourceSpec);
|
|
276
505
|
}
|
|
@@ -300,6 +529,55 @@ function hasBrand(value, brand) {
|
|
|
300
529
|
return value !== null && typeof value === "object" && value[brand] === true;
|
|
301
530
|
}
|
|
302
531
|
|
|
532
|
+
// sdk/typescript/src/idempotency.ts
|
|
533
|
+
import { createHash } from "node:crypto";
|
|
534
|
+
var idempotencyKeys = {
|
|
535
|
+
create(key, options = {}) {
|
|
536
|
+
const scope = options.scope ?? "run";
|
|
537
|
+
return {
|
|
538
|
+
value: createIdempotencyKey(key, scope, options),
|
|
539
|
+
key,
|
|
540
|
+
scope
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
function runIdempotencyRequestFields(input, ttl) {
|
|
545
|
+
if (input === undefined) {
|
|
546
|
+
return {};
|
|
547
|
+
}
|
|
548
|
+
const key = isIdempotencyKey(input) ? input : idempotencyKeys.create(input);
|
|
549
|
+
return {
|
|
550
|
+
idempotency_key: key.value,
|
|
551
|
+
...ttl === undefined ? {} : { idempotency_key_ttl: ttl },
|
|
552
|
+
idempotency_key_options: {
|
|
553
|
+
key: key.key,
|
|
554
|
+
scope: key.scope
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function createIdempotencyKey(key, scope, options) {
|
|
559
|
+
const material = {
|
|
560
|
+
scope,
|
|
561
|
+
key: Array.isArray(key) ? [...key] : [key]
|
|
562
|
+
};
|
|
563
|
+
const runId = "runId" in options ? options.runId : undefined;
|
|
564
|
+
const attemptNumber = "attemptNumber" in options ? options.attemptNumber : undefined;
|
|
565
|
+
if (scope === "run" && runId !== undefined) {
|
|
566
|
+
material["runId"] = runId;
|
|
567
|
+
}
|
|
568
|
+
if (scope === "attempt") {
|
|
569
|
+
if (runId === undefined || attemptNumber === undefined) {
|
|
570
|
+
throw new Error("attempt-scoped idempotency keys require runId and attemptNumber");
|
|
571
|
+
}
|
|
572
|
+
material["runId"] = runId;
|
|
573
|
+
material["attemptNumber"] = attemptNumber;
|
|
574
|
+
}
|
|
575
|
+
return createHash("sha256").update(JSON.stringify(material)).digest("hex");
|
|
576
|
+
}
|
|
577
|
+
function isIdempotencyKey(value) {
|
|
578
|
+
return typeof value === "object" && value !== null && "value" in value && "key" in value && "scope" in value;
|
|
579
|
+
}
|
|
580
|
+
|
|
303
581
|
// sdk/typescript/src/runtime/errors.ts
|
|
304
582
|
class RunNotFoundError extends Error {
|
|
305
583
|
runId;
|
|
@@ -352,27 +630,18 @@ function runSnapshot(snapshot) {
|
|
|
352
630
|
function pendingWaitpointFromResponse(runId, wait) {
|
|
353
631
|
if (wait === undefined || wait === null)
|
|
354
632
|
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
633
|
return {
|
|
366
|
-
kind:
|
|
634
|
+
kind: wait.kind,
|
|
367
635
|
runId,
|
|
368
636
|
waitpointId: wait.waitpoint_id,
|
|
369
|
-
prompt: wait.prompt ?? null,
|
|
370
637
|
timeout: wait.timeout ?? null,
|
|
638
|
+
request: wait.request === undefined ? {} : wait.request,
|
|
639
|
+
displayText: wait.display_text ?? "",
|
|
371
640
|
requestedAt: wait.requested_at
|
|
372
641
|
};
|
|
373
642
|
}
|
|
374
643
|
function isTerminalRunStatus(status) {
|
|
375
|
-
return status === "succeeded" || status === "failed" || status === "cancelled";
|
|
644
|
+
return status === "succeeded" || status === "failed" || status === "cancelled" || status === "expired";
|
|
376
645
|
}
|
|
377
646
|
function runId(value) {
|
|
378
647
|
return typeof value === "string" ? value : value.id;
|
|
@@ -396,23 +665,16 @@ function runStatus(status) {
|
|
|
396
665
|
case "succeeded":
|
|
397
666
|
case "failed":
|
|
398
667
|
case "cancelled":
|
|
668
|
+
case "expired":
|
|
399
669
|
return status;
|
|
400
670
|
default:
|
|
401
671
|
throw new Error(`unsupported run status ${JSON.stringify(status)}`);
|
|
402
672
|
}
|
|
403
673
|
}
|
|
404
674
|
|
|
405
|
-
// sdk/typescript/src/runtime/source.ts
|
|
406
|
-
function runWorkspaceFromSpec(spec) {
|
|
407
|
-
return {
|
|
408
|
-
repository: spec.repository,
|
|
409
|
-
ref: spec.ref,
|
|
410
|
-
...spec.subpath === undefined ? {} : { subpath: spec.subpath }
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
|
|
414
675
|
// sdk/typescript/src/runtime/client.ts
|
|
415
676
|
var MAX_SSE_BUFFER_CHARS = 1024 * 1024;
|
|
677
|
+
var triggerTaskClientMethod = Symbol.for("helmr.sdk.client.triggerTask");
|
|
416
678
|
|
|
417
679
|
class HelmrClient {
|
|
418
680
|
#baseUrl;
|
|
@@ -445,24 +707,55 @@ class HelmrClient {
|
|
|
445
707
|
}
|
|
446
708
|
}
|
|
447
709
|
tasks = {
|
|
448
|
-
trigger: async (
|
|
449
|
-
const
|
|
450
|
-
const
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
workspace: runWorkspace,
|
|
458
|
-
max_duration_seconds: maxDurationSeconds
|
|
459
|
-
}),
|
|
460
|
-
headers: { "content-type": "application/json" }
|
|
461
|
-
});
|
|
462
|
-
const run = await response.json();
|
|
463
|
-
return runHandle(run.id, run.task_id);
|
|
710
|
+
trigger: async (...args) => {
|
|
711
|
+
const taskId = args[0];
|
|
712
|
+
const hasPayload = args.length === 3;
|
|
713
|
+
const payload = hasPayload ? args[1] : undefined;
|
|
714
|
+
const opts = hasPayload ? args[2] : args[1];
|
|
715
|
+
if (hasPayload && payload === undefined) {
|
|
716
|
+
throw new Error(`task ${JSON.stringify(taskId)} requires payload`);
|
|
717
|
+
}
|
|
718
|
+
return await this.#triggerRun(taskId, payload, opts);
|
|
464
719
|
}
|
|
465
720
|
};
|
|
721
|
+
async[triggerTaskClientMethod](task, ...args) {
|
|
722
|
+
const hasPayload = task.payload !== undefined;
|
|
723
|
+
const payload = hasPayload ? args[0] : undefined;
|
|
724
|
+
const opts = hasPayload ? args[1] : args[0];
|
|
725
|
+
if (task.payload !== undefined) {
|
|
726
|
+
if (payload === undefined) {
|
|
727
|
+
throw new Error(`task ${JSON.stringify(task.id)} requires payload`);
|
|
728
|
+
}
|
|
729
|
+
await parseTaskPayload(task, payload);
|
|
730
|
+
} else if (args.length > 1) {
|
|
731
|
+
throw new Error(`task ${JSON.stringify(task.id)} does not accept payload`);
|
|
732
|
+
}
|
|
733
|
+
return await this.#triggerRun(task.id, payload, opts, readOptionalMaxDurationSeconds(task.maxDuration));
|
|
734
|
+
}
|
|
735
|
+
async#triggerRun(taskId, payload, opts, maxDurationSeconds) {
|
|
736
|
+
const runOptions = {
|
|
737
|
+
...opts.deploymentId === undefined ? {} : { deployment_id: opts.deploymentId },
|
|
738
|
+
...opts.version === undefined ? {} : { version: opts.version },
|
|
739
|
+
...opts.queue === undefined ? {} : { queue: { name: opts.queue } },
|
|
740
|
+
...opts.concurrencyKey === undefined ? {} : { concurrency_key: opts.concurrencyKey },
|
|
741
|
+
...opts.priority === undefined ? {} : { priority: opts.priority },
|
|
742
|
+
...opts.ttl === undefined ? {} : { ttl: opts.ttl },
|
|
743
|
+
...maxDurationSeconds === undefined ? {} : { max_duration_seconds: maxDurationSeconds },
|
|
744
|
+
...runIdempotencyRequestFields(opts.idempotencyKey, opts.idempotencyKeyTTL)
|
|
745
|
+
};
|
|
746
|
+
const response = await this.#fetch("/api/runs", {
|
|
747
|
+
method: "POST",
|
|
748
|
+
body: JSON.stringify({
|
|
749
|
+
task_id: taskId,
|
|
750
|
+
secrets: opts.secrets ?? {},
|
|
751
|
+
...payload === undefined ? {} : { payload },
|
|
752
|
+
...Object.keys(runOptions).length === 0 ? {} : { options: runOptions }
|
|
753
|
+
}),
|
|
754
|
+
headers: { "content-type": "application/json" }
|
|
755
|
+
});
|
|
756
|
+
const run = await response.json();
|
|
757
|
+
return runHandle(run.id, run.task_id);
|
|
758
|
+
}
|
|
466
759
|
runs = {
|
|
467
760
|
retrieve: async (idOrHandle, opts = {}) => {
|
|
468
761
|
const response = await this.#json(`/api/runs/${encodeURIComponent(runId(idOrHandle))}`, requestSignal(opts.signal));
|
|
@@ -519,27 +812,19 @@ class HelmrClient {
|
|
|
519
812
|
}
|
|
520
813
|
};
|
|
521
814
|
waitpoints = {
|
|
522
|
-
|
|
523
|
-
const
|
|
524
|
-
await this.#fetch(`/api/runs/${encodeURIComponent(resolved.runId)}/waitpoints/${encodeURIComponent(resolved.waitpointId)}/approve`, {
|
|
815
|
+
create: async (opts) => {
|
|
816
|
+
const response = await this.#json("/api/waitpoints", {
|
|
525
817
|
method: "POST",
|
|
526
|
-
body: JSON.stringify(
|
|
818
|
+
body: JSON.stringify(waitpointCreateBody(opts)),
|
|
527
819
|
headers: { "content-type": "application/json" }
|
|
528
820
|
});
|
|
821
|
+
return waitpointFromResponse(response);
|
|
529
822
|
},
|
|
530
|
-
|
|
823
|
+
respond: async (target, waitpointIdOrOpts, opts = {}) => {
|
|
531
824
|
const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
|
|
532
|
-
await this.#fetch(`/api/
|
|
825
|
+
await this.#fetch(`/api/waitpoints/${encodeURIComponent(resolved.waitpointId)}/respond`, {
|
|
533
826
|
method: "POST",
|
|
534
|
-
body: JSON.stringify(
|
|
535
|
-
headers: { "content-type": "application/json" }
|
|
536
|
-
});
|
|
537
|
-
},
|
|
538
|
-
reply: async (target, waitpointIdOrOpts, opts) => {
|
|
539
|
-
const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
|
|
540
|
-
await this.#fetch(`/api/runs/${encodeURIComponent(resolved.runId)}/waitpoints/${encodeURIComponent(resolved.waitpointId)}/message`, {
|
|
541
|
-
method: "POST",
|
|
542
|
-
body: JSON.stringify({ text: resolved.opts.text, attachments: [] }),
|
|
827
|
+
body: JSON.stringify(waitpointRespondBody(resolved.opts)),
|
|
543
828
|
headers: { "content-type": "application/json" }
|
|
544
829
|
});
|
|
545
830
|
},
|
|
@@ -548,21 +833,77 @@ class HelmrClient {
|
|
|
548
833
|
const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
|
|
549
834
|
const response = await this.#json("/api/waitpoints/tokens", {
|
|
550
835
|
method: "POST",
|
|
551
|
-
body: JSON.stringify(waitpointTokenCreateBody(resolved.
|
|
836
|
+
body: JSON.stringify(waitpointTokenCreateBody(resolved.waitpointId, resolved.opts)),
|
|
552
837
|
headers: { "content-type": "application/json" }
|
|
553
838
|
});
|
|
554
839
|
return waitpointResponseTokenFromResponse(response);
|
|
555
840
|
},
|
|
556
|
-
|
|
557
|
-
const resolved = typeof target === "string" ?
|
|
558
|
-
await this.#fetch(`/api/waitpoints/tokens/${encodeURIComponent(resolved.id)}/
|
|
841
|
+
respond: async (target, tokenOrOpts, maybeOpts) => {
|
|
842
|
+
const resolved = typeof target === "string" ? resolveWaitpointTokenRespondArgs(target, tokenOrOpts, maybeOpts) : { id: target.id, token: target.token, opts: tokenOrOpts };
|
|
843
|
+
await this.#fetch(`/api/waitpoints/tokens/${encodeURIComponent(resolved.id)}/respond`, {
|
|
559
844
|
method: "POST",
|
|
560
|
-
body: JSON.stringify(
|
|
845
|
+
body: JSON.stringify(waitpointTokenRespondBody(resolved.token, resolved.opts)),
|
|
561
846
|
headers: { "content-type": "application/json" }
|
|
562
847
|
});
|
|
563
848
|
}
|
|
564
849
|
}
|
|
565
850
|
};
|
|
851
|
+
schedules = {
|
|
852
|
+
create: async (opts) => {
|
|
853
|
+
const response = await this.#json("/api/schedules", {
|
|
854
|
+
method: "POST",
|
|
855
|
+
body: JSON.stringify(scheduleCreateBody(opts)),
|
|
856
|
+
headers: { "content-type": "application/json" }
|
|
857
|
+
});
|
|
858
|
+
return scheduleFromResponse(response);
|
|
859
|
+
},
|
|
860
|
+
list: async (opts = {}) => {
|
|
861
|
+
const query = scheduleScopeQuery(opts);
|
|
862
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
863
|
+
const response = await this.#json(`/api/schedules${suffix}`, requestSignal(opts.signal));
|
|
864
|
+
return response.schedules.map(scheduleFromResponse);
|
|
865
|
+
},
|
|
866
|
+
update: async (id, opts) => {
|
|
867
|
+
const query = scheduleScopeQuery(opts);
|
|
868
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
869
|
+
const response = await this.#json(`/api/schedules/${encodeURIComponent(id)}${suffix}`, {
|
|
870
|
+
method: "PUT",
|
|
871
|
+
body: JSON.stringify(scheduleCreateBody(opts)),
|
|
872
|
+
headers: { "content-type": "application/json" },
|
|
873
|
+
...requestSignal(opts.signal)
|
|
874
|
+
});
|
|
875
|
+
return scheduleFromResponse(response);
|
|
876
|
+
},
|
|
877
|
+
retrieve: async (id, opts = {}) => {
|
|
878
|
+
const query = scheduleScopeQuery(opts);
|
|
879
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
880
|
+
return scheduleFromResponse(await this.#json(`/api/schedules/${encodeURIComponent(id)}${suffix}`, requestSignal(opts.signal)));
|
|
881
|
+
},
|
|
882
|
+
activate: async (id, opts = {}) => {
|
|
883
|
+
const query = scheduleScopeQuery(opts);
|
|
884
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
885
|
+
return scheduleFromResponse(await this.#json(`/api/schedules/${encodeURIComponent(id)}/activate${suffix}`, {
|
|
886
|
+
method: "POST",
|
|
887
|
+
...requestSignal(opts.signal)
|
|
888
|
+
}));
|
|
889
|
+
},
|
|
890
|
+
deactivate: 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)}/deactivate${suffix}`, {
|
|
894
|
+
method: "POST",
|
|
895
|
+
...requestSignal(opts.signal)
|
|
896
|
+
}));
|
|
897
|
+
},
|
|
898
|
+
delete: async (id, opts = {}) => {
|
|
899
|
+
const query = scheduleScopeQuery(opts);
|
|
900
|
+
const suffix = query.size === 0 ? "" : `?${query}`;
|
|
901
|
+
await this.#fetch(`/api/schedules/${encodeURIComponent(id)}${suffix}`, {
|
|
902
|
+
method: "DELETE",
|
|
903
|
+
...requestSignal(opts.signal)
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
};
|
|
566
907
|
async#retrieveLogs(id, signal) {
|
|
567
908
|
const response = await this.#json(`/api/runs/${encodeURIComponent(id)}/logs`, requestSignal(signal));
|
|
568
909
|
return {
|
|
@@ -664,43 +1005,120 @@ function runResponseToSnapshot(response) {
|
|
|
664
1005
|
exitCode: response.exit_code ?? null,
|
|
665
1006
|
...response.created_at === undefined ? {} : { createdAt: response.created_at },
|
|
666
1007
|
...response.updated_at === undefined ? {} : { updatedAt: response.updated_at },
|
|
667
|
-
pendingWaitpoint: pendingWaitpointFromResponse(response.id, response.
|
|
1008
|
+
pendingWaitpoint: pendingWaitpointFromResponse(response.id, response.pending_waitpoint),
|
|
668
1009
|
..."output" in response ? { output: response.output } : {}
|
|
669
1010
|
});
|
|
670
1011
|
}
|
|
671
|
-
function
|
|
672
|
-
return
|
|
1012
|
+
function scheduleCreateBody(opts) {
|
|
1013
|
+
return {
|
|
1014
|
+
..."deduplicationKey" in opts && opts.deduplicationKey !== undefined ? { deduplication_key: opts.deduplicationKey } : {},
|
|
1015
|
+
...opts.projectId === undefined ? {} : { project_id: opts.projectId },
|
|
1016
|
+
...opts.environmentId === undefined ? {} : { environment_id: opts.environmentId },
|
|
1017
|
+
...opts.externalId === undefined ? {} : { external_id: opts.externalId },
|
|
1018
|
+
task: opts.task,
|
|
1019
|
+
cron: opts.cron,
|
|
1020
|
+
...opts.timezone === undefined ? {} : { timezone: opts.timezone },
|
|
1021
|
+
...opts.active === undefined ? {} : { active: opts.active },
|
|
1022
|
+
...opts.secretBindings === undefined ? {} : { secret_bindings: opts.secretBindings },
|
|
1023
|
+
...opts.options === undefined ? {} : { options: runOptionsBody(opts.options) }
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
function runOptionsBody(opts) {
|
|
1027
|
+
if (opts === undefined)
|
|
1028
|
+
return {};
|
|
1029
|
+
return {
|
|
1030
|
+
...opts.deploymentId === undefined ? {} : { deployment_id: opts.deploymentId },
|
|
1031
|
+
...opts.version === undefined ? {} : { version: opts.version },
|
|
1032
|
+
...opts.queue === undefined ? {} : { queue: { name: opts.queue } },
|
|
1033
|
+
...opts.concurrencyKey === undefined ? {} : { concurrency_key: opts.concurrencyKey },
|
|
1034
|
+
...opts.priority === undefined ? {} : { priority: opts.priority },
|
|
1035
|
+
...opts.ttl === undefined ? {} : { ttl: opts.ttl },
|
|
1036
|
+
...opts.maxDurationSeconds === undefined ? {} : { max_duration_seconds: opts.maxDurationSeconds }
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
function scheduleScopeQuery(opts) {
|
|
1040
|
+
const query = new URLSearchParams;
|
|
1041
|
+
if (opts.projectId !== undefined)
|
|
1042
|
+
query.set("project_id", opts.projectId);
|
|
1043
|
+
if (opts.environmentId !== undefined)
|
|
1044
|
+
query.set("environment_id", opts.environmentId);
|
|
1045
|
+
return query;
|
|
1046
|
+
}
|
|
1047
|
+
function scheduleFromResponse(response) {
|
|
1048
|
+
return {
|
|
1049
|
+
id: response.id,
|
|
1050
|
+
type: response.type,
|
|
1051
|
+
projectId: response.project_id,
|
|
1052
|
+
environmentId: response.environment_id,
|
|
1053
|
+
task: response.task,
|
|
1054
|
+
...response.deduplication_key === undefined || response.deduplication_key === "" ? {} : { deduplicationKey: response.deduplication_key },
|
|
1055
|
+
...response.external_id === undefined || response.external_id === "" ? {} : { externalId: response.external_id },
|
|
1056
|
+
cron: response.cron,
|
|
1057
|
+
timezone: response.timezone,
|
|
1058
|
+
active: response.active,
|
|
1059
|
+
status: response.status,
|
|
1060
|
+
...response.last_error === undefined || response.last_error === "" ? {} : { lastError: response.last_error },
|
|
1061
|
+
...response.next_scheduled_at === undefined ? {} : { nextScheduledAt: response.next_scheduled_at },
|
|
1062
|
+
...response.last_scheduled_at === undefined ? {} : { lastScheduledAt: response.last_scheduled_at },
|
|
1063
|
+
createdAt: response.created_at,
|
|
1064
|
+
updatedAt: response.updated_at
|
|
1065
|
+
};
|
|
673
1066
|
}
|
|
674
|
-
function waitpointTokenCreateBody(
|
|
1067
|
+
function waitpointTokenCreateBody(waitpointId, opts) {
|
|
675
1068
|
return {
|
|
676
|
-
run_id: runId2,
|
|
677
1069
|
waitpoint_id: waitpointId,
|
|
678
|
-
...opts.actions === undefined ? {} : { actions: opts.actions },
|
|
679
1070
|
...opts.expiresInSeconds === undefined ? {} : { expires_in_seconds: opts.expiresInSeconds },
|
|
680
1071
|
...opts.expiresAt === undefined ? {} : { expires_at: opts.expiresAt },
|
|
681
1072
|
...opts.metadata === undefined ? {} : { metadata: opts.metadata }
|
|
682
1073
|
};
|
|
683
1074
|
}
|
|
684
|
-
function
|
|
1075
|
+
function waitpointCreateBody(opts) {
|
|
685
1076
|
return {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
...
|
|
689
|
-
...
|
|
1077
|
+
...opts.projectId === undefined ? {} : { project_id: opts.projectId },
|
|
1078
|
+
...opts.environmentId === undefined ? {} : { environment_id: opts.environmentId },
|
|
1079
|
+
...opts.request === undefined ? {} : { request: opts.request },
|
|
1080
|
+
...opts.displayText === undefined ? {} : { display_text: opts.displayText },
|
|
1081
|
+
expires_at: opts.expiresAt,
|
|
1082
|
+
...opts.idempotencyKey === undefined ? {} : { idempotency_key: opts.idempotencyKey },
|
|
1083
|
+
...opts.idempotencyKeyExpiresAt === undefined ? {} : { idempotency_key_expires_at: opts.idempotencyKeyExpiresAt },
|
|
1084
|
+
...opts.idempotencyKeyTTLSeconds === undefined ? {} : { idempotency_key_ttl_seconds: opts.idempotencyKeyTTLSeconds }
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
function waitpointFromResponse(response) {
|
|
1088
|
+
return {
|
|
1089
|
+
id: response.id,
|
|
1090
|
+
projectId: response.project_id,
|
|
1091
|
+
environmentId: response.environment_id,
|
|
1092
|
+
kind: response.kind,
|
|
1093
|
+
status: response.status,
|
|
1094
|
+
request: response.request ?? {},
|
|
1095
|
+
displayText: response.display_text ?? "",
|
|
1096
|
+
expiresAt: response.expires_at ?? null,
|
|
1097
|
+
createdAt: response.created_at
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
function waitpointRespondBody(opts) {
|
|
1101
|
+
return {
|
|
1102
|
+
..."value" in opts ? { value: opts.value } : {},
|
|
690
1103
|
...opts.externalSubject === undefined ? {} : { external_subject: opts.externalSubject },
|
|
691
1104
|
...opts.metadata === undefined ? {} : { metadata: opts.metadata }
|
|
692
1105
|
};
|
|
693
1106
|
}
|
|
694
|
-
function
|
|
1107
|
+
function waitpointTokenRespondBody(token, opts) {
|
|
1108
|
+
return {
|
|
1109
|
+
token,
|
|
1110
|
+
...waitpointRespondBody(opts)
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
function resolveWaitpointTokenRespondArgs(id, token, opts) {
|
|
695
1114
|
if (typeof token !== "string" || opts === undefined) {
|
|
696
|
-
throw new Error("waitpoint token secret is required when
|
|
1115
|
+
throw new Error("waitpoint token secret is required when responding by token id");
|
|
697
1116
|
}
|
|
698
1117
|
return { id, token, opts };
|
|
699
1118
|
}
|
|
700
1119
|
function waitpointResponseTokenFromResponse(response) {
|
|
701
1120
|
return {
|
|
702
1121
|
id: response.id,
|
|
703
|
-
runId: response.run_id,
|
|
704
1122
|
waitpointId: response.waitpoint_id,
|
|
705
1123
|
url: response.url,
|
|
706
1124
|
token: response.token,
|
|
@@ -709,27 +1127,21 @@ function waitpointResponseTokenFromResponse(response) {
|
|
|
709
1127
|
}
|
|
710
1128
|
function resolveWaitpointArgs(target, waitpointIdOrOpts, opts) {
|
|
711
1129
|
if (isWaitpointRef(target)) {
|
|
712
|
-
const resolvedOpts = waitpointIdOrOpts !== undefined && typeof waitpointIdOrOpts !== "string" ? waitpointIdOrOpts : opts;
|
|
713
1130
|
return {
|
|
714
|
-
runId: target.runId,
|
|
715
1131
|
waitpointId: target.waitpointId,
|
|
716
|
-
opts:
|
|
1132
|
+
opts: waitpointIdOrOpts ?? opts ?? {}
|
|
717
1133
|
};
|
|
718
1134
|
}
|
|
719
|
-
if (typeof waitpointIdOrOpts !== "string") {
|
|
720
|
-
throw new Error("waitpoint id is required when resolving a waitpoint by run id");
|
|
721
|
-
}
|
|
722
1135
|
return {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
opts: opts ?? {}
|
|
1136
|
+
waitpointId: target,
|
|
1137
|
+
opts: waitpointIdOrOpts ?? opts ?? {}
|
|
726
1138
|
};
|
|
727
1139
|
}
|
|
728
1140
|
function isWaitpointRef(value) {
|
|
729
1141
|
if (value === null || typeof value !== "object")
|
|
730
1142
|
return false;
|
|
731
1143
|
const record = value;
|
|
732
|
-
return typeof record["
|
|
1144
|
+
return typeof record["waitpointId"] === "string";
|
|
733
1145
|
}
|
|
734
1146
|
function retrieveOptions(signal) {
|
|
735
1147
|
return signal === undefined ? {} : { signal };
|
|
@@ -831,7 +1243,14 @@ function parseSseFrame(raw) {
|
|
|
831
1243
|
if (data === "") {
|
|
832
1244
|
return;
|
|
833
1245
|
}
|
|
834
|
-
|
|
1246
|
+
try {
|
|
1247
|
+
return runEventRecordToRunEvent(JSON.parse(data));
|
|
1248
|
+
} catch (error) {
|
|
1249
|
+
if (error instanceof SyntaxError) {
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
throw error;
|
|
1253
|
+
}
|
|
835
1254
|
}
|
|
836
1255
|
function findSseBoundary(buffer) {
|
|
837
1256
|
const lf = buffer.indexOf(`
|
|
@@ -847,121 +1266,102 @@ function findSseBoundary(buffer) {
|
|
|
847
1266
|
return Math.min(lf, crlf);
|
|
848
1267
|
}
|
|
849
1268
|
function runEventRecordToRunEvent(event) {
|
|
850
|
-
const
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
1269
|
+
const record = objectRecord(event);
|
|
1270
|
+
const message = stringValue(record?.["message"]);
|
|
1271
|
+
const at = stringValue(record?.["at"]);
|
|
1272
|
+
if (record === undefined || message === undefined || at === undefined) {
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const attributes = objectRecord(record["attributes"]);
|
|
1276
|
+
const runId2 = stringValue(record["run_id"]) ?? stringValue(attributes?.["run_id"]) ?? "";
|
|
1277
|
+
if (message === "log.stdout" || message === "log.stderr") {
|
|
1278
|
+
const stream = message === "log.stdout" ? "stdout" : "stderr";
|
|
854
1279
|
return {
|
|
855
1280
|
type: "log",
|
|
856
1281
|
run_id: runId2,
|
|
857
1282
|
stream,
|
|
858
1283
|
bytes: numberValue(attributes?.["bytes"]) ?? 0,
|
|
859
1284
|
observed_seq: numberValue(attributes?.["observed_seq"]) ?? 0,
|
|
860
|
-
at
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
if (event.message === "waitpoint.requested" && stringValue(attributes?.["kind"]) === "approval") {
|
|
864
|
-
const message = stringValue(attributes?.["display_text"]);
|
|
865
|
-
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
866
|
-
if (waitpointId === undefined)
|
|
867
|
-
return;
|
|
868
|
-
return {
|
|
869
|
-
type: "approval_request",
|
|
870
|
-
run_id: runId2,
|
|
871
|
-
waitpoint_id: waitpointId,
|
|
872
|
-
message: message ?? "",
|
|
873
|
-
...optionalNumber("timeout", attributes?.["timeout"]),
|
|
874
|
-
at: event.at
|
|
1285
|
+
at
|
|
875
1286
|
};
|
|
876
1287
|
}
|
|
877
|
-
if (
|
|
1288
|
+
if (message === "waitpoint.requested") {
|
|
878
1289
|
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
879
|
-
const
|
|
1290
|
+
const kind = stringValue(attributes?.["kind"]);
|
|
880
1291
|
if (waitpointId === undefined)
|
|
881
1292
|
return;
|
|
882
|
-
if (
|
|
883
|
-
return;
|
|
884
|
-
return {
|
|
885
|
-
type: "approval_decided",
|
|
886
|
-
run_id: runId2,
|
|
887
|
-
waitpoint_id: waitpointId,
|
|
888
|
-
decision: resolution,
|
|
889
|
-
...optionalString("reason", attributes?.["reason"]),
|
|
890
|
-
at: event.at
|
|
891
|
-
};
|
|
892
|
-
}
|
|
893
|
-
if (event.message === "waitpoint.requested" && stringValue(attributes?.["kind"]) === "message") {
|
|
894
|
-
const request = objectRecord(attributes?.["request"]);
|
|
895
|
-
const message = stringValue(attributes?.["display_text"]) ?? stringValue(request?.["prompt"]);
|
|
896
|
-
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
897
|
-
if (waitpointId === undefined)
|
|
1293
|
+
if (kind === undefined)
|
|
898
1294
|
return;
|
|
899
1295
|
return {
|
|
900
|
-
type: "
|
|
1296
|
+
type: "waitpoint_request",
|
|
901
1297
|
run_id: runId2,
|
|
902
1298
|
waitpoint_id: waitpointId,
|
|
903
|
-
|
|
1299
|
+
kind,
|
|
1300
|
+
displayText: stringValue(attributes?.["display_text"]) ?? "",
|
|
1301
|
+
request: attributes?.["request"] ?? {},
|
|
904
1302
|
...optionalNumber("timeout", attributes?.["timeout"]),
|
|
905
|
-
at
|
|
1303
|
+
at
|
|
906
1304
|
};
|
|
907
1305
|
}
|
|
908
|
-
if (
|
|
909
|
-
const result = objectRecord(attributes?.["result"]);
|
|
910
|
-
const text = stringValue(result?.["text"]);
|
|
1306
|
+
if (message === "waitpoint.resolved") {
|
|
911
1307
|
const waitpointId = stringValue(attributes?.["waitpoint_id"]);
|
|
1308
|
+
const kind = stringValue(attributes?.["kind"]);
|
|
1309
|
+
const resolution = stringValue(attributes?.["resolution_kind"]);
|
|
912
1310
|
if (waitpointId === undefined)
|
|
913
1311
|
return;
|
|
914
|
-
if (
|
|
1312
|
+
if (kind === undefined || resolution === undefined)
|
|
915
1313
|
return;
|
|
916
1314
|
return {
|
|
917
|
-
type: "
|
|
1315
|
+
type: "waitpoint_resolved",
|
|
918
1316
|
run_id: runId2,
|
|
919
1317
|
waitpoint_id: waitpointId,
|
|
920
|
-
|
|
921
|
-
|
|
1318
|
+
kind,
|
|
1319
|
+
resolutionKind: resolution,
|
|
1320
|
+
value: attributes?.["result"],
|
|
1321
|
+
at
|
|
922
1322
|
};
|
|
923
1323
|
}
|
|
924
|
-
if (
|
|
1324
|
+
if (message.startsWith("emit.")) {
|
|
925
1325
|
return {
|
|
926
1326
|
type: "emit",
|
|
927
1327
|
run_id: runId2,
|
|
928
|
-
event_type: stringValue(attributes?.["type"]) ??
|
|
1328
|
+
event_type: stringValue(attributes?.["type"]) ?? message.slice("emit.".length),
|
|
929
1329
|
content: attributes?.["content"],
|
|
930
|
-
at
|
|
1330
|
+
at
|
|
931
1331
|
};
|
|
932
1332
|
}
|
|
933
|
-
if (
|
|
1333
|
+
if (message === "run.completed") {
|
|
934
1334
|
return {
|
|
935
|
-
type: "
|
|
1335
|
+
type: "task_result",
|
|
936
1336
|
run_id: runId2,
|
|
937
1337
|
exit_code: numberValue(attributes?.["exit_code"]) ?? 0,
|
|
938
|
-
at
|
|
1338
|
+
at
|
|
939
1339
|
};
|
|
940
1340
|
}
|
|
941
|
-
if (
|
|
1341
|
+
if (message === "run.failed") {
|
|
942
1342
|
return {
|
|
943
1343
|
type: "run_failed",
|
|
944
1344
|
run_id: runId2,
|
|
945
1345
|
failure_kind: stringValue(attributes?.["failure_kind"]) ?? "task_failed",
|
|
946
1346
|
detail: attributes?.["detail"],
|
|
947
|
-
at
|
|
1347
|
+
at
|
|
948
1348
|
};
|
|
949
1349
|
}
|
|
950
|
-
if (
|
|
1350
|
+
if (message === "run.cancelled") {
|
|
951
1351
|
return {
|
|
952
|
-
type: "
|
|
1352
|
+
type: "run_cancelled",
|
|
953
1353
|
run_id: runId2,
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
at: event.at
|
|
1354
|
+
...optionalString("reason", attributes?.["reason"]),
|
|
1355
|
+
at
|
|
957
1356
|
};
|
|
958
1357
|
}
|
|
959
|
-
if (
|
|
1358
|
+
if (message === "run.expired") {
|
|
960
1359
|
return {
|
|
961
|
-
type: "
|
|
1360
|
+
type: "run_expired",
|
|
962
1361
|
run_id: runId2,
|
|
963
|
-
...optionalString("
|
|
964
|
-
|
|
1362
|
+
...optionalString("ttl", attributes?.["ttl"]),
|
|
1363
|
+
...optionalString("message", attributes?.["message"]),
|
|
1364
|
+
at
|
|
965
1365
|
};
|
|
966
1366
|
}
|
|
967
1367
|
return;
|
|
@@ -1039,11 +1439,6 @@ function defineConfig(config) {
|
|
|
1039
1439
|
});
|
|
1040
1440
|
}
|
|
1041
1441
|
|
|
1042
|
-
// sdk/typescript/src/task.ts
|
|
1043
|
-
function task(config) {
|
|
1044
|
-
return markTask(config);
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
1442
|
// sdk/typescript/src/trigger.ts
|
|
1048
1443
|
var defaultClient;
|
|
1049
1444
|
function getDefaultClient() {
|
|
@@ -1051,10 +1446,97 @@ function getDefaultClient() {
|
|
|
1051
1446
|
return defaultClient;
|
|
1052
1447
|
}
|
|
1053
1448
|
var tasks = {
|
|
1054
|
-
trigger(
|
|
1055
|
-
return getDefaultClient().tasks.trigger(
|
|
1449
|
+
trigger(...args) {
|
|
1450
|
+
return getDefaultClient().tasks.trigger(...args);
|
|
1451
|
+
}
|
|
1452
|
+
};
|
|
1453
|
+
function triggerTask(task, ...args) {
|
|
1454
|
+
return getDefaultClient()[triggerTaskClientMethod](task, ...args);
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
// sdk/typescript/src/task.ts
|
|
1458
|
+
function task(config) {
|
|
1459
|
+
const marked = markTask(config);
|
|
1460
|
+
Object.defineProperty(marked, "trigger", {
|
|
1461
|
+
value: (...args) => triggerTask(marked, ...args)
|
|
1462
|
+
});
|
|
1463
|
+
return marked;
|
|
1464
|
+
}
|
|
1465
|
+
function queue(config) {
|
|
1466
|
+
return Object.freeze({ ...config });
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
// sdk/typescript/src/schedules.ts
|
|
1470
|
+
function task2(config) {
|
|
1471
|
+
const { cron, secretBindings, ...taskConfig } = config;
|
|
1472
|
+
const schedule = cron === undefined ? undefined : {
|
|
1473
|
+
cron: typeof cron === "string" ? cron : cron.pattern,
|
|
1474
|
+
...typeof cron === "string" || cron.timezone === undefined ? {} : { timezone: cron.timezone },
|
|
1475
|
+
...secretBindings === undefined ? {} : { secretBindings }
|
|
1476
|
+
};
|
|
1477
|
+
const marked = markScheduledTask({ ...taskConfig, payload: scheduledTaskPayloadSchema }, schedule);
|
|
1478
|
+
Object.defineProperty(marked, "trigger", {
|
|
1479
|
+
value: (...args) => triggerTask(marked, ...args)
|
|
1480
|
+
});
|
|
1481
|
+
return marked;
|
|
1482
|
+
}
|
|
1483
|
+
var scheduledTaskPayloadSchema = {
|
|
1484
|
+
"~standard": {
|
|
1485
|
+
version: 1,
|
|
1486
|
+
vendor: "helmr",
|
|
1487
|
+
validate(value) {
|
|
1488
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
1489
|
+
return { issues: [{ message: "expected scheduled task payload object" }] };
|
|
1490
|
+
}
|
|
1491
|
+
const input = value;
|
|
1492
|
+
const timestamp = parseDateField(input["timestamp"], "timestamp");
|
|
1493
|
+
const lastTimestamp = parseOptionalDateField(input["lastTimestamp"], "lastTimestamp");
|
|
1494
|
+
const timezone = input["timezone"];
|
|
1495
|
+
const scheduleId = input["scheduleId"];
|
|
1496
|
+
const externalId = input["externalId"];
|
|
1497
|
+
const upcoming = input["upcoming"];
|
|
1498
|
+
const issues = [
|
|
1499
|
+
...timestamp.issues,
|
|
1500
|
+
...lastTimestamp.issues,
|
|
1501
|
+
...typeof timezone === "string" && timezone.trim() !== "" ? [] : [{ message: "expected string", path: ["timezone"] }],
|
|
1502
|
+
...typeof scheduleId === "string" && scheduleId.trim() !== "" ? [] : [{ message: "expected string", path: ["scheduleId"] }],
|
|
1503
|
+
...externalId === undefined || typeof externalId === "string" ? [] : [{ message: "expected string", path: ["externalId"] }],
|
|
1504
|
+
...Array.isArray(upcoming) ? [] : [{ message: "expected array", path: ["upcoming"] }]
|
|
1505
|
+
];
|
|
1506
|
+
const upcomingDates = Array.isArray(upcoming) ? upcoming.map((item, index) => parseDateField(item, `upcoming.${index}`)) : [];
|
|
1507
|
+
issues.push(...upcomingDates.flatMap((item) => item.issues));
|
|
1508
|
+
if (issues.length > 0) {
|
|
1509
|
+
return { issues };
|
|
1510
|
+
}
|
|
1511
|
+
return {
|
|
1512
|
+
value: {
|
|
1513
|
+
timestamp: timestamp.value,
|
|
1514
|
+
...lastTimestamp.value === undefined ? {} : { lastTimestamp: lastTimestamp.value },
|
|
1515
|
+
timezone,
|
|
1516
|
+
scheduleId,
|
|
1517
|
+
...externalId === undefined ? {} : { externalId },
|
|
1518
|
+
upcoming: upcomingDates.map((item) => item.value)
|
|
1519
|
+
}
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1056
1522
|
}
|
|
1057
1523
|
};
|
|
1524
|
+
function parseDateField(value, path) {
|
|
1525
|
+
if (typeof value !== "string") {
|
|
1526
|
+
return { value: new Date(0), issues: [{ message: "expected ISO timestamp", path: path.split(".") }] };
|
|
1527
|
+
}
|
|
1528
|
+
const date = new Date(value);
|
|
1529
|
+
if (Number.isNaN(date.getTime())) {
|
|
1530
|
+
return { value: new Date(0), issues: [{ message: "expected ISO timestamp", path: path.split(".") }] };
|
|
1531
|
+
}
|
|
1532
|
+
return { value: date, issues: [] };
|
|
1533
|
+
}
|
|
1534
|
+
function parseOptionalDateField(value, path) {
|
|
1535
|
+
if (value === undefined || value === null) {
|
|
1536
|
+
return { issues: [] };
|
|
1537
|
+
}
|
|
1538
|
+
return parseDateField(value, path);
|
|
1539
|
+
}
|
|
1058
1540
|
// sdk/typescript/src/index.ts
|
|
1059
1541
|
var image = (id) => new ImageBuilderImpl(id);
|
|
1060
1542
|
var cache = (id) => ({ id });
|
|
@@ -1066,27 +1548,6 @@ var source = {
|
|
|
1066
1548
|
return new SourceDirRefImpl(path, opts?.ignore ? [...opts.ignore] : []);
|
|
1067
1549
|
}
|
|
1068
1550
|
};
|
|
1069
|
-
var workspace = {
|
|
1070
|
-
github(repo, opts) {
|
|
1071
|
-
const [org, name, extra] = repo.split("/");
|
|
1072
|
-
if (!org || !name || extra !== undefined) {
|
|
1073
|
-
throw new Error('workspace.github() repo must be "org/repo"');
|
|
1074
|
-
}
|
|
1075
|
-
const ref = opts.ref.trim();
|
|
1076
|
-
if (!ref) {
|
|
1077
|
-
throw new Error("workspace.github() ref is required");
|
|
1078
|
-
}
|
|
1079
|
-
if (ref.includes("\x00")) {
|
|
1080
|
-
throw new Error("workspace.github() ref must not contain NUL");
|
|
1081
|
-
}
|
|
1082
|
-
return {
|
|
1083
|
-
kind: "github",
|
|
1084
|
-
repository: repo,
|
|
1085
|
-
ref,
|
|
1086
|
-
...opts.subpath === undefined ? {} : { subpath: opts.subpath }
|
|
1087
|
-
};
|
|
1088
|
-
}
|
|
1089
|
-
};
|
|
1090
1551
|
var runs = new Proxy({}, {
|
|
1091
1552
|
get(_target, property, receiver) {
|
|
1092
1553
|
return Reflect.get(getDefaultClient().runs, property, receiver);
|
|
@@ -1097,24 +1558,35 @@ var waitpoints = new Proxy({}, {
|
|
|
1097
1558
|
return Reflect.get(getDefaultClient().waitpoints, property, receiver);
|
|
1098
1559
|
}
|
|
1099
1560
|
});
|
|
1561
|
+
var schedules = Object.freeze({
|
|
1562
|
+
task: task2,
|
|
1563
|
+
create: (...args) => getDefaultClient().schedules.create(...args),
|
|
1564
|
+
update: (...args) => getDefaultClient().schedules.update(...args),
|
|
1565
|
+
list: (...args) => getDefaultClient().schedules.list(...args),
|
|
1566
|
+
retrieve: (...args) => getDefaultClient().schedules.retrieve(...args),
|
|
1567
|
+
activate: (...args) => getDefaultClient().schedules.activate(...args),
|
|
1568
|
+
deactivate: (...args) => getDefaultClient().schedules.deactivate(...args),
|
|
1569
|
+
delete: (...args) => getDefaultClient().schedules.delete(...args)
|
|
1570
|
+
});
|
|
1100
1571
|
export {
|
|
1101
|
-
workspace,
|
|
1102
1572
|
waitpoints,
|
|
1103
1573
|
validateSecretName,
|
|
1104
1574
|
tasks,
|
|
1105
1575
|
task,
|
|
1106
1576
|
source,
|
|
1577
|
+
schedules,
|
|
1107
1578
|
sandbox,
|
|
1108
1579
|
runs,
|
|
1580
|
+
queue,
|
|
1109
1581
|
image,
|
|
1582
|
+
idempotencyKeys,
|
|
1110
1583
|
defineConfig,
|
|
1111
1584
|
cache,
|
|
1112
1585
|
UnsupportedTransportError,
|
|
1113
1586
|
TimeoutError,
|
|
1114
1587
|
RunNotFoundError,
|
|
1115
|
-
|
|
1588
|
+
PayloadSchemaValidationError,
|
|
1116
1589
|
HelmrClient,
|
|
1117
1590
|
ConcurrentWaitError,
|
|
1118
|
-
AuthError
|
|
1119
|
-
ApprovalTimeoutError
|
|
1591
|
+
AuthError
|
|
1120
1592
|
};
|