inngest 4.19.0 → 4.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/components/realtime/types.d.cts +3 -3
  3. package/components/realtime/types.d.cts.map +1 -1
  4. package/components/realtime/types.d.ts +3 -3
  5. package/components/realtime/types.d.ts.map +1 -1
  6. package/components/sandbox/client.cjs +243 -29
  7. package/components/sandbox/client.cjs.map +1 -1
  8. package/components/sandbox/client.js +239 -31
  9. package/components/sandbox/client.js.map +1 -1
  10. package/components/sandbox/durable.cjs +158 -1
  11. package/components/sandbox/durable.cjs.map +1 -1
  12. package/components/sandbox/durable.js +160 -3
  13. package/components/sandbox/durable.js.map +1 -1
  14. package/components/sandbox/middleware.cjs +1 -0
  15. package/components/sandbox/middleware.cjs.map +1 -1
  16. package/components/sandbox/middleware.d.cts.map +1 -1
  17. package/components/sandbox/middleware.d.ts.map +1 -1
  18. package/components/sandbox/middleware.js +1 -0
  19. package/components/sandbox/middleware.js.map +1 -1
  20. package/components/sandbox/protocol.cjs +100 -4
  21. package/components/sandbox/protocol.cjs.map +1 -1
  22. package/components/sandbox/protocol.js +101 -5
  23. package/components/sandbox/protocol.js.map +1 -1
  24. package/components/sandbox/types.cjs +2 -0
  25. package/components/sandbox/types.cjs.map +1 -1
  26. package/components/sandbox/types.d.cts +100 -15
  27. package/components/sandbox/types.d.cts.map +1 -1
  28. package/components/sandbox/types.d.ts +100 -15
  29. package/components/sandbox/types.d.ts.map +1 -1
  30. package/components/sandbox/types.js +2 -0
  31. package/components/sandbox/types.js.map +1 -1
  32. package/components/sandbox/validation.cjs +75 -3
  33. package/components/sandbox/validation.cjs.map +1 -1
  34. package/components/sandbox/validation.js +71 -4
  35. package/components/sandbox/validation.js.map +1 -1
  36. package/experimental.d.cts +2 -2
  37. package/experimental.d.ts +2 -2
  38. package/package.json +1 -1
  39. package/react.d.cts +1 -1
  40. package/react.d.ts +1 -1
  41. package/types.d.cts +8 -8
  42. package/types.d.ts +8 -8
  43. package/version.cjs +1 -1
  44. package/version.cjs.map +1 -1
  45. package/version.d.cts +1 -1
  46. package/version.d.ts +1 -1
  47. package/version.js +1 -1
  48. package/version.js.map +1 -1
@@ -1,5 +1,5 @@
1
1
  import { SandboxError, SandboxValidationError } from "./types.js";
2
- import { canonicalUuidSchema, decodeBase64, decodeOutputChunk, decodeUtf8, normalizeFileDownloadOptions, normalizeFileUploadOptions, normalizeSandboxCommandOptions, normalizeSandboxCreateOptions, normalizeSandboxListOptions, normalizeSandboxProcessListOptions, normalizeSandboxProcessOutputOptions, normalizeSandboxProcessSignalOptions, normalizeSandboxProcessStartOptions, normalizeSandboxProcessWaitOptions, normalizeSandboxWaitUntilRunningOptions, parseWithSchema, restOutputChunkSchema, sandboxProcessRefFromResource, sandboxProcessRefSchema, sandboxRefFromResource, sandboxRefSchema } from "./validation.js";
2
+ import { canonicalUuidSchema, decodeBase64, decodeOutputChunk, decodeUtf8, normalizeFileDownloadOptions, normalizeFileUploadOptions, normalizeSandboxCommandOptions, normalizeSandboxCreateOptions, normalizeSandboxListOptions, normalizeSandboxProcessListOptions, normalizeSandboxProcessOutputOptions, normalizeSandboxProcessSignalOptions, normalizeSandboxProcessStartOptions, normalizeSandboxProcessWaitOptions, normalizeSandboxSnapshotCreateOptions, normalizeSandboxSnapshotListOptions, normalizeSandboxWaitUntilRunningOptions, parseWithSchema, restOutputChunkSchema, sandboxProcessRefFromResource, sandboxProcessRefSchema, sandboxRefFromResource, sandboxRefSchema, sandboxSnapshotRefFromResource, sandboxSnapshotRefSchema } from "./validation.js";
3
3
  import { z } from "zod/v3";
4
4
 
5
5
  //#region src/components/sandbox/client.ts
@@ -57,6 +57,8 @@ const waitProcessSchema = z.object({
57
57
  const safeRepeatActions = new Set([
58
58
  "create",
59
59
  "destroy",
60
+ "pause",
61
+ "resume",
60
62
  "file.upload",
61
63
  "list",
62
64
  "get",
@@ -67,7 +69,11 @@ const safeRepeatActions = new Set([
67
69
  "process.output",
68
70
  "process.stream",
69
71
  "logs.stream",
70
- "file.download"
72
+ "file.download",
73
+ "snapshot.list",
74
+ "snapshot.get",
75
+ "snapshot.waitUntilReady",
76
+ "snapshot.delete"
71
77
  ]);
72
78
  const sandboxTransportFailureMessage = (action) => {
73
79
  switch (action) {
@@ -77,6 +83,8 @@ const sandboxTransportFailureMessage = (action) => {
77
83
  case "exec": return "The sandbox command may have run. Inspect its external effects before running it again";
78
84
  case "process.start": return "A sandbox process may be running. List processes and reconcile before starting another";
79
85
  case "process.signal": return "The sandbox process signal may have been delivered. Get or wait for the process before sending another";
86
+ case "snapshot.create": return "Snapshot creation may have started and a retry may create a second snapshot. Check snapshots.list() before creating another";
87
+ case "snapshot.delete": return "Snapshot deletion may have started. Repeating Delete is safe";
80
88
  default: return "Compute is temporarily unavailable. Retry this operation";
81
89
  }
82
90
  };
@@ -93,11 +101,13 @@ var SandboxRestTransport = class {
93
101
  body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
94
102
  headers: options.body === void 0 ? void 0 : { "Content-Type": "application/json" },
95
103
  sandboxId: options.sandboxId,
96
- processId: options.processId
104
+ processId: options.processId,
105
+ snapshotId: options.snapshotId,
106
+ signal: options.signal
97
107
  });
98
- if (!options.statuses.includes(response.status)) await this.throwResponseError(action, response, options.sandboxId, options.processId);
108
+ if (!options.statuses.includes(response.status)) await this.throwResponseError(action, response, options.sandboxId, options.processId, options.snapshotId);
99
109
  if (response.status === 204) return { status: response.status };
100
- const raw = await this.readResponseJSON(action, response, options.sandboxId, options.processId);
110
+ const raw = await this.readResponseJSON(action, response, options.sandboxId, options.processId, options.snapshotId);
101
111
  return {
102
112
  status: response.status,
103
113
  envelope: parseWithSchema(responseEnvelopeSchema, raw, "sandbox API response")
@@ -105,11 +115,11 @@ var SandboxRestTransport = class {
105
115
  }
106
116
  async raw(action, method, path, options) {
107
117
  const response = await this.send(action, method, path, options);
108
- if (!response.ok) await this.throwResponseError(action, response, options.sandboxId, options.processId);
118
+ if (!response.ok) await this.throwResponseError(action, response, options.sandboxId, options.processId, options.snapshotId);
109
119
  return response;
110
120
  }
111
- async readResponseEnvelope(action, response, sandboxId, processId) {
112
- return parseWithSchema(responseEnvelopeSchema, await this.readResponseJSON(action, response, sandboxId, processId), "sandbox API response");
121
+ async readResponseEnvelope(action, response, sandboxId, processId, snapshotId) {
122
+ return parseWithSchema(responseEnvelopeSchema, await this.readResponseJSON(action, response, sandboxId, processId, snapshotId), "sandbox API response");
113
123
  }
114
124
  async stream(action, path, sandboxId, processId) {
115
125
  const abortController = new AbortController();
@@ -187,17 +197,17 @@ var SandboxRestTransport = class {
187
197
  try {
188
198
  return await this.config.fetch()(new URL(path, this.config.baseUrl()), requestInit);
189
199
  } catch (error) {
190
- throw this.transportFailure(action, error, options.sandboxId, options.processId);
200
+ throw this.transportFailure(action, error, options.sandboxId, options.processId, options.snapshotId);
191
201
  }
192
202
  }
193
- async readResponseJSON(action, response, sandboxId, processId) {
203
+ async readResponseJSON(action, response, sandboxId, processId, snapshotId) {
194
204
  try {
195
205
  return await response.json();
196
206
  } catch (error) {
197
- throw this.transportFailure(action, error, sandboxId, processId);
207
+ throw this.transportFailure(action, error, sandboxId, processId, snapshotId);
198
208
  }
199
209
  }
200
- transportFailure(action, cause, sandboxId, processId) {
210
+ transportFailure(action, cause, sandboxId, processId, snapshotId) {
201
211
  const safeToRepeat = safeRepeatActions.has(action);
202
212
  return new SandboxError({
203
213
  action,
@@ -205,22 +215,23 @@ var SandboxRestTransport = class {
205
215
  message: sandboxTransportFailureMessage(action),
206
216
  sandboxId,
207
217
  processId,
218
+ snapshotId,
208
219
  ambiguous: !safeToRepeat,
209
220
  retryable: safeToRepeat,
210
221
  details: [],
211
222
  cause
212
223
  });
213
224
  }
214
- async throwResponseError(action, response, sandboxId, processId) {
225
+ async throwResponseError(action, response, sandboxId, processId, snapshotId) {
215
226
  const raw = await response.json().catch(() => void 0);
216
227
  const parsed = errorEnvelopeSchema.safeParse(raw);
217
228
  const item = parsed.success ? parsed.data.errors[0] : {
218
229
  code: "internal_error",
219
230
  message: `Sandbox API returned HTTP ${response.status}`
220
231
  };
221
- throw this.errorFromItem(action, response.status, item, sandboxId, processId, response.headers.get("x-request-id") ?? void 0, parsed.success ? parsed.data.errors : []);
232
+ throw this.errorFromItem(action, response.status, item, sandboxId, processId, snapshotId, response.headers.get("x-request-id") ?? void 0, parsed.success ? parsed.data.errors : []);
222
233
  }
223
- errorFromItem(action, status, item, sandboxId, processId, requestId, details = []) {
234
+ errorFromItem(action, status, item, sandboxId, processId, snapshotId, requestId, details = []) {
224
235
  const ambiguous = item.code === "operation_ambiguous" || item.code === "sandbox_exec_output_too_large" || item.code === "sandbox_exec_timed_out";
225
236
  const availability = item.code === "compute_unavailable" || item.code === "rate_limited" || status === 429 || status === 503;
226
237
  return new SandboxError({
@@ -230,6 +241,7 @@ var SandboxRestTransport = class {
230
241
  status,
231
242
  sandboxId,
232
243
  processId,
244
+ snapshotId,
233
245
  ambiguous,
234
246
  retryable: !ambiguous && availability,
235
247
  requestId,
@@ -241,6 +253,18 @@ const processPath = (sandboxId, processId) => `/v2/sandboxes/${encodeURIComponen
241
253
  const sandboxStartingStatuses = new Set(["PENDING", "STARTING"]);
242
254
  const sandboxRunningPollIntervalMs = 1e3;
243
255
  const delay = async (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
256
+ const lifecycleTimeout = (options) => normalizeSandboxWaitUntilRunningOptions({ timeout: options?.timeout ?? 5 * 6e4 }).timeoutMs;
257
+ const abortableDelay = (milliseconds, signal) => new Promise((resolve, reject) => {
258
+ if (signal?.aborted) {
259
+ reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
260
+ return;
261
+ }
262
+ const timer = setTimeout(resolve, milliseconds);
263
+ signal?.addEventListener("abort", () => {
264
+ clearTimeout(timer);
265
+ reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
266
+ }, { once: true });
267
+ });
244
268
  const sandboxStartFailedError = (action, sandbox) => new SandboxError({
245
269
  action,
246
270
  code: "sandbox_start_failed",
@@ -319,6 +343,48 @@ const runSandboxCommandForOperation = (sandbox, command, options) => {
319
343
  if (!run) throw new SandboxValidationError("Sandbox commands can only run on an SDK sandbox resource");
320
344
  return run(command, options);
321
345
  };
346
+ const pollSandboxStatus = async (initial, target, action, transport, options) => {
347
+ const timeoutMs = lifecycleTimeout(options);
348
+ const deadline = Date.now() + timeoutMs;
349
+ let current = initial;
350
+ while (current.status !== target) {
351
+ if (["FAILED", "TERMINATED"].includes(current.status)) throw new SandboxError({
352
+ action,
353
+ code: "invalid_request",
354
+ message: `Sandbox entered ${current.status} before reaching ${target}`,
355
+ sandboxId: current.id
356
+ });
357
+ const remaining = deadline - Date.now();
358
+ if (remaining <= 0) throw new SandboxError({
359
+ action,
360
+ code: "sandbox_start_timed_out",
361
+ message: `Sandbox did not reach ${target} within ${timeoutMs} milliseconds`,
362
+ sandboxId: current.id
363
+ });
364
+ await abortableDelay(Math.min(1e3, remaining), options?.signal);
365
+ const { envelope } = await transport.json(action, "GET", `/v2/sandboxes/${encodeURIComponent(current.id)}`, {
366
+ statuses: [200],
367
+ sandboxId: current.id,
368
+ signal: options?.signal
369
+ });
370
+ current = sandboxRefFromResource(envelope?.data);
371
+ if (current.id !== initial.id || current.name !== initial.name) throw new SandboxValidationError("Sandbox lifecycle operation returned an unrelated sandbox");
372
+ }
373
+ return createDirectSandboxFacade(current, transport);
374
+ };
375
+ const createDirectSnapshotFacade = (rawRef, transport) => {
376
+ const ref = sandboxSnapshotRefFromResource(rawRef);
377
+ return Object.freeze({
378
+ ...ref,
379
+ resources: Object.freeze({ ...ref.resources }),
380
+ clone: async (options, waitOptions) => createSandbox(transport, {
381
+ name: options.name,
382
+ snapshotId: ref.id,
383
+ runningTimeout: options.runningTimeout ?? waitOptions?.timeout
384
+ }),
385
+ delete: async () => deleteSandboxSnapshot(transport, ref.id)
386
+ });
387
+ };
322
388
  const createDirectSandboxFacade = (rawRef, transport) => {
323
389
  const ref = parseWithSchema(sandboxRefSchema, rawRef, "sandbox reference");
324
390
  const basePath = `/v2/sandboxes/${encodeURIComponent(ref.id)}`;
@@ -424,6 +490,34 @@ const createDirectSandboxFacade = (rawRef, transport) => {
424
490
  }
425
491
  }),
426
492
  waitUntilRunning: async (options) => waitUntilSandboxRunning(ref, normalizeSandboxWaitUntilRunningOptions(options).timeoutMs, transport, "waitUntilRunning"),
493
+ pause: async (options) => {
494
+ const { envelope } = await transport.json("pause", "POST", `${basePath}/pause`, {
495
+ statuses: [
496
+ 200,
497
+ 201,
498
+ 202
499
+ ],
500
+ sandboxId: ref.id,
501
+ signal: options?.signal
502
+ });
503
+ return pollSandboxStatus(envelope?.data === void 0 ? ref : sandboxRefFromResource(envelope.data), "PAUSED", "pause", transport, options);
504
+ },
505
+ resume: async (options) => {
506
+ const { envelope } = await transport.json("resume", "POST", `${basePath}/resume`, {
507
+ statuses: [
508
+ 200,
509
+ 201,
510
+ 202
511
+ ],
512
+ sandboxId: ref.id,
513
+ signal: options?.signal
514
+ });
515
+ return pollSandboxStatus(envelope?.data === void 0 ? ref : sandboxRefFromResource(envelope.data), "RUNNING", "resume", transport, options);
516
+ },
517
+ snapshot: async (options = {}, waitOptions) => {
518
+ normalizeSandboxSnapshotCreateOptions(options);
519
+ return createDirectSnapshotFacade(await waitUntilSandboxSnapshotReady(transport, await createSandboxSnapshot(transport, ref.id, waitOptions?.signal), lifecycleTimeout(waitOptions), waitOptions?.signal), transport);
520
+ },
427
521
  destroy: async () => {
428
522
  const { status, envelope } = await transport.json("destroy", "DELETE", basePath, {
429
523
  statuses: [202, 204],
@@ -480,23 +574,123 @@ const transportForClient = (client) => {
480
574
  */
481
575
  const sandboxForOperation = (client, ref) => createDirectSandboxFacade(ref, transportForClient(client));
482
576
  const sandboxProcessForOperation = (client, ref) => createDirectProcessFacade(ref, transportForClient(client));
577
+ const getSnapshotForOperation = async (transport, snapshotId, action) => {
578
+ try {
579
+ const { envelope } = await transport.json(action, "GET", `/v2/snapshots/${encodeURIComponent(snapshotId)}`, {
580
+ statuses: [200],
581
+ snapshotId
582
+ });
583
+ return sandboxSnapshotRefFromResource(envelope?.data);
584
+ } catch (error) {
585
+ if (error instanceof SandboxError && error.code === "sandbox_snapshot_not_found") return null;
586
+ throw error;
587
+ }
588
+ };
589
+ const createSandboxSnapshot = async (transport, sandboxId, signal) => {
590
+ const { status, envelope } = await transport.json("snapshot.create", "POST", `/v2/sandboxes/${encodeURIComponent(sandboxId)}/snapshots`, {
591
+ body: {},
592
+ statuses: [201, 202],
593
+ sandboxId,
594
+ signal
595
+ });
596
+ const snapshot = sandboxSnapshotRefFromResource(envelope?.data);
597
+ if (status === 201 && snapshot.status !== "READY" || status === 202 && snapshot.status !== "CREATING") throw new SandboxValidationError(`Sandbox snapshot Create returned HTTP ${status} with status ${snapshot.status}`);
598
+ return snapshot;
599
+ };
600
+ const listSandboxSnapshots = async (transport, options) => {
601
+ const normalized = normalizeSandboxSnapshotListOptions(options);
602
+ const query = new URLSearchParams({ limit: `${normalized.limit}` });
603
+ if (normalized.cursor !== void 0) query.set("cursor", normalized.cursor);
604
+ const { envelope } = await transport.json("snapshot.list", "GET", `/v2/snapshots?${query}`, { statuses: [200] });
605
+ const resources = parseWithSchema(z.array(z.unknown()), envelope?.data, "sandbox snapshot list");
606
+ const page = parseWithSchema(sandboxPageSchema, envelope?.page, "sandbox snapshot list page");
607
+ const metadata = parseWithSchema(metadataSchema, envelope?.metadata, "sandbox snapshot list metadata");
608
+ return {
609
+ items: resources.map(sandboxSnapshotRefFromResource),
610
+ page: {
611
+ hasMore: page.hasMore,
612
+ limit: page.limit,
613
+ ...page.cursor != null && { cursor: page.cursor }
614
+ },
615
+ fetchedAt: metadata.fetchedAt
616
+ };
617
+ };
618
+ const createSandboxSnapshotForOperation = async (client, sandboxId) => createSandboxSnapshot(transportForClient(client), sandboxId);
619
+ const listSandboxSnapshotsForOperation = async (client, options) => listSandboxSnapshots(transportForClient(client), options);
620
+ const getSandboxSnapshotForOperation = async (client, snapshotId) => getSnapshotForOperation(transportForClient(client), snapshotId, "snapshot.get");
621
+ const snapshotNotReadyError = (snapshot) => new SandboxError({
622
+ action: "snapshot.waitUntilReady",
623
+ code: "sandbox_snapshot_not_ready",
624
+ message: `Snapshot entered ${snapshot.status} before reaching READY`,
625
+ snapshotId: snapshot.id,
626
+ retryable: false,
627
+ details: [{ status: snapshot.status }]
628
+ });
629
+ const snapshotWaitTimedOutError = (snapshot, timeoutMs) => new SandboxError({
630
+ action: "snapshot.waitUntilReady",
631
+ code: "sandbox_snapshot_wait_timed_out",
632
+ message: `Snapshot did not reach READY within ${timeoutMs} milliseconds`,
633
+ snapshotId: snapshot.id,
634
+ retryable: false,
635
+ details: [{
636
+ status: snapshot.status,
637
+ timeoutMs
638
+ }]
639
+ });
640
+ const waitUntilSandboxSnapshotReady = async (transport, initialSnapshot, timeoutMs, signal) => {
641
+ let snapshot = parseWithSchema(sandboxSnapshotRefSchema, initialSnapshot, "sandbox snapshot reference");
642
+ if (snapshot.status === "READY") return snapshot;
643
+ if (snapshot.status !== "CREATING") throw snapshotNotReadyError(snapshot);
644
+ const deadline = Date.now() + timeoutMs;
645
+ for (;;) {
646
+ if (deadline - Date.now() <= 0) throw snapshotWaitTimedOutError(snapshot, timeoutMs);
647
+ try {
648
+ const current = await getSnapshotForOperation(transport, snapshot.id, "snapshot.waitUntilReady");
649
+ if (!current) throw new SandboxError({
650
+ action: "snapshot.waitUntilReady",
651
+ code: "sandbox_snapshot_not_found",
652
+ message: "Snapshot not found",
653
+ snapshotId: snapshot.id,
654
+ retryable: false
655
+ });
656
+ snapshot = current;
657
+ } catch (error) {
658
+ if (!(error instanceof SandboxError && error.retryable)) throw error;
659
+ }
660
+ if (snapshot.status === "READY") return snapshot;
661
+ if (snapshot.status !== "CREATING") throw snapshotNotReadyError(snapshot);
662
+ const remainingMs = deadline - Date.now();
663
+ if (remainingMs <= 0) throw snapshotWaitTimedOutError(snapshot, timeoutMs);
664
+ await abortableDelay(Math.min(sandboxRunningPollIntervalMs, remainingMs), signal);
665
+ }
666
+ };
667
+ const waitUntilSandboxSnapshotReadyForOperation = async (client, initialSnapshot, timeoutMs) => waitUntilSandboxSnapshotReady(transportForClient(client), initialSnapshot, timeoutMs);
668
+ const deleteSandboxSnapshot = async (transport, snapshotId) => {
669
+ await transport.json("snapshot.delete", "DELETE", `/v2/snapshots/${encodeURIComponent(snapshotId)}`, {
670
+ statuses: [204],
671
+ snapshotId
672
+ });
673
+ };
674
+ const deleteSandboxSnapshotForOperation = async (client, snapshotId) => deleteSandboxSnapshot(transportForClient(client), snapshotId);
675
+ const createSandbox = async (transport, options) => {
676
+ const { runningTimeoutMs, ...body } = normalizeSandboxCreateOptions(options);
677
+ const { status, envelope } = await transport.json("create", "POST", "/v2/sandboxes", {
678
+ body,
679
+ statuses: [
680
+ 200,
681
+ 201,
682
+ 202
683
+ ]
684
+ });
685
+ const sandbox = sandboxRefFromResource(envelope?.data);
686
+ if (status === 201 && sandbox.status !== "RUNNING" || status === 202 && sandbox.status !== "STARTING") throw new SandboxValidationError(`Sandbox Create returned HTTP ${status} with status ${sandbox.status}`);
687
+ return runningTimeoutMs === false ? createDirectSandboxFacade(sandbox, transport) : waitUntilSandboxRunning(sandbox, runningTimeoutMs, transport, "create");
688
+ };
689
+ const createSandboxForOperation = async (client, options) => createSandbox(transportForClient(client), options);
483
690
  const createSandboxClient = (config) => {
484
691
  const transport = new SandboxRestTransport(config);
485
692
  const client = {
486
- create: async (options) => {
487
- const { runningTimeoutMs, ...body } = normalizeSandboxCreateOptions(options);
488
- const { status, envelope } = await transport.json("create", "POST", "/v2/sandboxes", {
489
- body,
490
- statuses: [
491
- 200,
492
- 201,
493
- 202
494
- ]
495
- });
496
- const sandbox = sandboxRefFromResource(envelope?.data);
497
- if (status === 201 && sandbox.status !== "RUNNING" || status === 202 && sandbox.status !== "STARTING") throw new SandboxValidationError(`Sandbox Create returned HTTP ${status} with status ${sandbox.status}`);
498
- return runningTimeoutMs === false ? createDirectSandboxFacade(sandbox, transport) : waitUntilSandboxRunning(sandbox, runningTimeoutMs, transport, "create");
499
- },
693
+ create: async (options) => createSandbox(transport, options),
500
694
  list: async (options) => {
501
695
  const normalized = normalizeSandboxListOptions(options);
502
696
  const query = new URLSearchParams({ limit: `${normalized.limit}` });
@@ -527,12 +721,26 @@ const createSandboxClient = (config) => {
527
721
  if (error instanceof SandboxError && error.code === "sandbox_not_found") return null;
528
722
  throw error;
529
723
  }
530
- }
724
+ },
725
+ snapshots: Object.freeze({
726
+ list: async (options) => {
727
+ const result = await listSandboxSnapshots(transport, options);
728
+ return {
729
+ items: result.items.map((snapshot) => createDirectSnapshotFacade(snapshot, transport)),
730
+ page: { ...result.page },
731
+ fetchedAt: result.fetchedAt
732
+ };
733
+ },
734
+ get: async (snapshotId) => {
735
+ const snapshot = await getSnapshotForOperation(transport, parseWithSchema(canonicalUuidSchema, snapshotId, "sandbox snapshot ID"), "snapshot.get");
736
+ return snapshot ? createDirectSnapshotFacade(snapshot, transport) : null;
737
+ }
738
+ })
531
739
  };
532
740
  sandboxClientTransports.set(client, transport);
533
741
  return client;
534
742
  };
535
743
 
536
744
  //#endregion
537
- export { createSandboxClient, runSandboxCommandForOperation, sandboxForOperation, sandboxProcessForOperation };
745
+ export { createSandboxClient, createSandboxForOperation, createSandboxSnapshotForOperation, deleteSandboxSnapshotForOperation, getSandboxSnapshotForOperation, listSandboxSnapshotsForOperation, runSandboxCommandForOperation, sandboxForOperation, sandboxProcessForOperation, waitUntilSandboxSnapshotReadyForOperation };
538
746
  //# sourceMappingURL=client.js.map