@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/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
- // sdk/typescript/src/internal.ts
65
- var approvalTimeoutErrorBrand = Symbol.for("helmr.sdk.ApprovalTimeoutError");
66
- var messageTimeoutErrorBrand = Symbol.for("helmr.sdk.MessageTimeoutError");
67
- var concurrentWaitErrorBrand = Symbol.for("helmr.sdk.ConcurrentWaitError");
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 ApprovalTimeoutError extends Error {
70
- constructor(message) {
71
- super(message);
72
- this.name = "ApprovalTimeoutError";
73
- Object.defineProperty(this, approvalTimeoutErrorBrand, { value: true });
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
- static [Symbol.hasInstance](value) {
76
- return this === ApprovalTimeoutError && typeof value === "object" && value !== null && approvalTimeoutErrorBrand in value;
160
+ }
161
+ function validateQueueName(value) {
162
+ if (!isValidQueueName(value)) {
163
+ throw new TaskQueueNameError(value);
77
164
  }
78
165
  }
79
-
80
- class MessageTimeoutError extends Error {
81
- constructor(message) {
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
- static [Symbol.hasInstance](value) {
87
- return this === MessageTimeoutError && typeof value === "object" && value !== null && messageTimeoutErrorBrand in value;
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: "message",
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 (task, opts) => {
449
- const runWorkspace = runWorkspaceFromSpec(opts.workspace);
450
- const maxDurationSeconds = readOptionalMaxDurationSeconds(task.maxDuration);
451
- const response = await this.#fetch("/api/runs", {
452
- method: "POST",
453
- body: JSON.stringify({
454
- task_id: task.id,
455
- secrets: opts.secrets ?? {},
456
- payload: opts.payload,
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
- approve: async (target, waitpointIdOrOpts, opts = {}) => {
523
- const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
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(approvalBody(resolved.opts)),
818
+ body: JSON.stringify(waitpointCreateBody(opts)),
527
819
  headers: { "content-type": "application/json" }
528
820
  });
821
+ return waitpointFromResponse(response);
529
822
  },
530
- deny: async (target, waitpointIdOrOpts, opts = {}) => {
823
+ respond: async (target, waitpointIdOrOpts, opts = {}) => {
531
824
  const resolved = resolveWaitpointArgs(target, waitpointIdOrOpts, opts);
532
- await this.#fetch(`/api/runs/${encodeURIComponent(resolved.runId)}/waitpoints/${encodeURIComponent(resolved.waitpointId)}/deny`, {
825
+ await this.#fetch(`/api/waitpoints/${encodeURIComponent(resolved.waitpointId)}/respond`, {
533
826
  method: "POST",
534
- body: JSON.stringify(approvalBody(resolved.opts)),
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.runId, resolved.waitpointId, resolved.opts)),
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
- complete: async (target, tokenOrOpts, maybeOpts) => {
557
- const resolved = typeof target === "string" ? resolveWaitpointTokenCompleteArgs(target, tokenOrOpts, maybeOpts) : { id: target.id, token: target.token, opts: tokenOrOpts };
558
- await this.#fetch(`/api/waitpoints/tokens/${encodeURIComponent(resolved.id)}/complete`, {
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(waitpointTokenCompleteBody(resolved.token, resolved.opts)),
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.pending_wait),
1008
+ pendingWaitpoint: pendingWaitpointFromResponse(response.id, response.pending_waitpoint),
668
1009
  ..."output" in response ? { output: response.output } : {}
669
1010
  });
670
1011
  }
671
- function approvalBody(opts) {
672
- return opts.reason === undefined ? {} : { reason: opts.reason };
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(runId2, waitpointId, opts) {
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 waitpointTokenCompleteBody(token, opts) {
1075
+ function waitpointCreateBody(opts) {
685
1076
  return {
686
- token,
687
- action: opts.action,
688
- ..."reason" in opts && opts.reason === undefined ? {} : ("reason" in opts) ? { reason: opts.reason } : {},
689
- ..."text" in opts ? { text: opts.text } : {},
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 resolveWaitpointTokenCompleteArgs(id, token, opts) {
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 completing by token id");
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: resolvedOpts ?? {}
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
- runId: target,
724
- waitpointId: waitpointIdOrOpts,
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["runId"] === "string" && typeof record["waitpointId"] === "string";
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
- return runEventRecordToRunEvent(JSON.parse(data));
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 attributes = objectRecord(event.attributes);
851
- const runId2 = event.run_id ?? stringValue(attributes?.["run_id"]) ?? "";
852
- if (event.message === "log.stdout" || event.message === "log.stderr") {
853
- const stream = event.message === "log.stdout" ? "stdout" : "stderr";
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: event.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 (event.message === "waitpoint.resolved" && stringValue(attributes?.["kind"]) === "approval") {
1288
+ if (message === "waitpoint.requested") {
878
1289
  const waitpointId = stringValue(attributes?.["waitpoint_id"]);
879
- const resolution = stringValue(attributes?.["resolution_kind"]);
1290
+ const kind = stringValue(attributes?.["kind"]);
880
1291
  if (waitpointId === undefined)
881
1292
  return;
882
- if (resolution !== "approved" && resolution !== "denied")
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: "message_request",
1296
+ type: "waitpoint_request",
901
1297
  run_id: runId2,
902
1298
  waitpoint_id: waitpointId,
903
- ...optionalString("prompt", message),
1299
+ kind,
1300
+ displayText: stringValue(attributes?.["display_text"]) ?? "",
1301
+ request: attributes?.["request"] ?? {},
904
1302
  ...optionalNumber("timeout", attributes?.["timeout"]),
905
- at: event.at
1303
+ at
906
1304
  };
907
1305
  }
908
- if (event.message === "waitpoint.resolved" && stringValue(attributes?.["kind"]) === "message") {
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 (stringValue(attributes?.["resolution_kind"]) !== "replied")
1312
+ if (kind === undefined || resolution === undefined)
915
1313
  return;
916
1314
  return {
917
- type: "message_received",
1315
+ type: "waitpoint_resolved",
918
1316
  run_id: runId2,
919
1317
  waitpoint_id: waitpointId,
920
- text: text ?? "",
921
- at: event.at
1318
+ kind,
1319
+ resolutionKind: resolution,
1320
+ value: attributes?.["result"],
1321
+ at
922
1322
  };
923
1323
  }
924
- if (event.message.startsWith("emit.")) {
1324
+ if (message.startsWith("emit.")) {
925
1325
  return {
926
1326
  type: "emit",
927
1327
  run_id: runId2,
928
- event_type: stringValue(attributes?.["type"]) ?? event.message.slice("emit.".length),
1328
+ event_type: stringValue(attributes?.["type"]) ?? message.slice("emit.".length),
929
1329
  content: attributes?.["content"],
930
- at: event.at
1330
+ at
931
1331
  };
932
1332
  }
933
- if (event.message === "run.completed") {
1333
+ if (message === "run.completed") {
934
1334
  return {
935
- type: "task_complete",
1335
+ type: "task_result",
936
1336
  run_id: runId2,
937
1337
  exit_code: numberValue(attributes?.["exit_code"]) ?? 0,
938
- at: event.at
1338
+ at
939
1339
  };
940
1340
  }
941
- if (event.message === "run.failed") {
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: event.at
1347
+ at
948
1348
  };
949
1349
  }
950
- if (event.message === "run.timeout") {
1350
+ if (message === "run.cancelled") {
951
1351
  return {
952
- type: "run_timeout",
1352
+ type: "run_cancelled",
953
1353
  run_id: runId2,
954
- elapsed_secs: numberValue(attributes?.["elapsed_active_secs"]) ?? 0,
955
- limit_secs: numberValue(attributes?.["limit_secs"]) ?? 0,
956
- at: event.at
1354
+ ...optionalString("reason", attributes?.["reason"]),
1355
+ at
957
1356
  };
958
1357
  }
959
- if (event.message === "run.cancelled") {
1358
+ if (message === "run.expired") {
960
1359
  return {
961
- type: "run_cancelled",
1360
+ type: "run_expired",
962
1361
  run_id: runId2,
963
- ...optionalString("reason", attributes?.["reason"]),
964
- at: event.at
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(task2, opts) {
1055
- return getDefaultClient().tasks.trigger(task2, opts);
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
- MessageTimeoutError,
1588
+ PayloadSchemaValidationError,
1116
1589
  HelmrClient,
1117
1590
  ConcurrentWaitError,
1118
- AuthError,
1119
- ApprovalTimeoutError
1591
+ AuthError
1120
1592
  };