@lizard-build/sdk 0.1.43 → 0.1.45

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 CHANGED
@@ -1,4 +1,4 @@
1
- # Lizard TypeScript SDK
1
+ # Lizard SDK for TypeScript
2
2
 
3
3
  Run commands, work with files and execute code in Linux sandboxes on Kubernetes. The SDK also manages Lizard apps, databases, storage and projects.
4
4
 
@@ -51,26 +51,26 @@ const result = await sandbox.process.exec('printf "hello\\n"', {
51
51
  if (result.exitCode !== 0) throw new Error(result.stderr)
52
52
  ```
53
53
 
54
- ## Run code
54
+ ## Run Python
55
55
 
56
- `CodeSandbox` uses the `code-interpreter-v1` template by default. Code errors appear in `result.error`; request failures throw.
56
+ Run Python with the `interpreter` template. Each process command starts a separate Python process, so Python variables do not survive between calls. Save intermediate results to files. The API returns stdout, stderr, and an exit code; it does not return typed notebook results or chart objects.
57
57
 
58
58
  ```ts
59
- import { CodeSandbox } from '@lizard-build/sdk'
59
+ import { Sandbox } from '@lizard-build/sdk';
60
60
 
61
- const sandbox = await CodeSandbox.create({ project: 'my-project' })
61
+ const sandbox = await Sandbox.create('interpreter', {
62
+ projectId: 'proj_123', timeoutMs: 300_000,
63
+ });
62
64
  try {
63
- const result = await sandbox.runCode('print(6 * 7)', {
64
- language: 'python',
65
- timeoutMs: 60_000,
66
- onStdout: chunk => process.stdout.write(chunk),
67
- })
68
- if (result.error) throw result.error
65
+ const result = await sandbox.process.exec("python -c 'print(2 ** 10)'");
66
+ console.log(result.stdout, result.stderr, result.exitCode);
69
67
  } finally {
70
- await sandbox.kill()
68
+ await sandbox.kill();
71
69
  }
72
70
  ```
73
71
 
72
+ `CodeSandbox`, `runCode` / `run_code`, and execution-context methods remain in the SDK, but the hosted template catalog does not provide their required execution server. The legacy default `code-interpreter-v1` is unavailable. Changing its name to `interpreter` does not enable this API. Use `Sandbox.create("interpreter")` and process commands as shown below.
73
+
74
74
  ## Configuration
75
75
 
76
76
  The SDK reads `LIZARD_API_KEY` and, optionally, `LIZARD_API_URL` (default: `https://lizard.build`). You can also pass `apiKey` and `apiUrl` to the constructor or static sandbox methods.
@@ -79,10 +79,16 @@ Pass `timeoutMs` to `create()` to set the sandbox lifetime. The default is five
79
79
 
80
80
  ## Runtime limits
81
81
 
82
- Sandboxes run on Kubernetes. Use volumes mounted at `/workspace` to keep files after a sandbox ends. Pause, resume, fork, snapshot creation and snapshot restore return HTTP 501 on the current backend.
82
+ Sandboxes run on Kubernetes. Use volumes mounted at `/workspace` to keep files after a sandbox ends. CRIU pause/resume and private snapshots preserve running memory and workspace files. Snapshot pools keep five copies warm by default and can be paused to release idle compute. Fork and file watching remain unsupported. See the [snapshot lifecycle guide](../../docs/sandboxes.md#snapshots-and-criu-pause-resume).
83
83
 
84
84
  `getHost()` returns a hostname without `https://`. File writes accept UTF-8 text or valid UTF-8 bytes; `readBytes()` supports binary downloads.
85
85
 
86
+ ## Current command and lifetime limits
87
+
88
+ Command results contain stdout, stderr, and the exit code. Command timeouts are limited to 1–600 seconds. The current runtime does not apply the SDK command options `envs`, `workdir`, or `user`; set the directory and environment in the shell command when needed. Create-time `envs` and `metadata` are also not applied.
89
+
90
+ The SDK and CLI default to a five-minute lifetime. The raw API and dashboard default to no expiration. Set an explicit lifetime: `timeoutMs: 0` at creation disables expiration; a positive value sets a deadline. `setTimeout` accepts 1000–2147483647 ms, not zero. Commands do not reset the deadline. This is not an idle timer.
91
+
86
92
  ## Learn more
87
93
 
88
94
  - [Sandbox reference](https://github.com/lizard-build/lizard-sdk/blob/main/docs/sandboxes.md)
package/dist/index.d.mts CHANGED
@@ -650,6 +650,9 @@ interface SandboxInfo {
650
650
  /** Region the sandbox runs in — the volume's region when one is attached. */
651
651
  region?: string;
652
652
  status?: string;
653
+ pauseError?: string | null;
654
+ size?: 'small' | 'medium' | 'large' | null;
655
+ pricePerHour?: number | null;
653
656
  cpus?: number;
654
657
  memoryMb?: number;
655
658
  metadata?: Record<string, string>;
@@ -665,6 +668,8 @@ interface SandboxOpts extends ConnectionOpts {
665
668
  /** Exact project ID — skips resolving {@link SandboxOpts.project}. */
666
669
  projectId?: string;
667
670
  template?: string;
671
+ snapshotId?: string;
672
+ size?: 'small' | 'medium' | 'large';
668
673
  metadata?: Record<string, string>;
669
674
  envs?: Record<string, string>;
670
675
  timeoutMs?: number;
@@ -731,6 +736,27 @@ declare class SandboxClient {
731
736
  }>;
732
737
  }
733
738
 
739
+ interface SandboxSnapshot {
740
+ id: string;
741
+ name: string;
742
+ projectId: string;
743
+ workspaceId: string;
744
+ region: string;
745
+ sourceSandboxId: string;
746
+ status: 'building' | 'warming' | 'ready' | 'paused' | 'suspended' | 'failed';
747
+ poolSize: number;
748
+ readyCount: number;
749
+ error: string | null;
750
+ cpus: number;
751
+ memoryMb: number;
752
+ createdAt: number;
753
+ }
754
+ interface SnapshotOpts {
755
+ poolSize?: number;
756
+ }
757
+ interface SnapshotWaitOpts extends ConnectionOpts {
758
+ waitTimeoutMs?: number;
759
+ }
734
760
  /**
735
761
  * A Linux sandbox running on Kubernetes.
736
762
  *
@@ -813,14 +839,15 @@ declare class Sandbox extends SandboxClient {
813
839
  * Create a new Lizard sandbox from the specified template.
814
840
  *
815
841
  * Template availability and installed tools depend on the platform and region.
816
- * Use `base` for shell commands or `CodeSandbox` for stateful code execution.
842
+ * Use `base` for shell commands or `interpreter` for Python process commands.
843
+ * Hosted templates do not support the legacy `CodeSandbox` execution API.
817
844
  *
818
845
  * @param template Name of the sandbox template to boot from.
819
846
  *
820
847
  * @example
821
848
  * ```ts
822
849
  * const sandbox = await Sandbox.create('base', { project: 'my-project' })
823
- * const pythonSandbox = await Sandbox.create('code-interpreter-v1', { project: 'my-project', timeoutMs: 10 * 60 * 1000 })
850
+ * const pythonSandbox = await Sandbox.create('interpreter', { project: 'my-project', timeoutMs: 10 * 60 * 1000 })
824
851
  * ```
825
852
  */
826
853
  static create(template: string, opts?: SandboxOpts): Promise<Sandbox>;
@@ -855,20 +882,12 @@ declare class Sandbox extends SandboxClient {
855
882
  * @returns `true` if the sandbox was terminated, `false` if it was already gone.
856
883
  */
857
884
  kill(opts?: ConnectionOpts): Promise<boolean>;
858
- /**
859
- * Request sandbox pause. The Kubernetes backend returns HTTP 501.
860
- *
861
- * @deprecated Unsupported on Kubernetes. Save files to a {@link Volume}
862
- * and attach it to a new sandbox instead.
863
- */
885
+ /** Queue a CRIU checkpoint and stop compute. Use waitForStatus('paused') before resuming. */
864
886
  pause(opts?: ConnectionOpts): Promise<boolean>;
865
- /**
866
- * Request sandbox resume. The Kubernetes backend returns HTTP 501.
867
- *
868
- * @deprecated Unsupported on Kubernetes. Use {@link Sandbox.connect} to
869
- * reconnect to a running sandbox.
870
- */
887
+ /** Queue restoration of saved memory and files. Use waitForStatus('running') before executing. */
871
888
  resume(opts?: ConnectionOpts): Promise<boolean>;
889
+ /** Wait for an asynchronous pause/resume operation to finish. */
890
+ waitForStatus(status: 'paused' | 'running', opts?: SnapshotWaitOpts): Promise<SandboxInfo>;
872
891
  /**
873
892
  * Get metadata and status information about this sandbox.
874
893
  */
@@ -898,18 +917,25 @@ declare class Sandbox extends SandboxClient {
898
917
  count?: number;
899
918
  timeoutMs?: number;
900
919
  }): Promise<unknown>;
901
- /** Snapshot creation is unsupported on Kubernetes; the backend returns HTTP 501. */
902
- snapshot(name?: string): Promise<unknown>;
920
+ /** Capture memory and workspace files. Disconnect active clients before capturing. */
921
+ snapshot(name?: string, opts?: SnapshotOpts): Promise<SandboxSnapshot>;
903
922
  unexpose(port: number): Promise<void>;
904
923
  logs(opts?: {
905
924
  tail?: number;
906
925
  signal?: AbortSignal;
907
926
  }): AsyncGenerator<StreamEvent, any, any>;
908
- static snapshots(projectId: string, opts?: ConnectionOpts): Promise<unknown[]>;
909
- /** Snapshot restore is unsupported on Kubernetes; the backend returns HTTP 501. */
927
+ static snapshots(projectId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot[]>;
928
+ static getSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
929
+ /** Start a sandbox from an available warm copy in the snapshot's project and region. */
910
930
  static restore(snapshotId: string, opts?: ConnectionOpts & {
911
931
  timeoutMs?: number;
912
932
  }): Promise<Sandbox>;
933
+ static setSnapshotWarmPool(snapshotId: string, poolSize: number, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
934
+ /** Release idle warm copies; retain saved state and existing claimed sandboxes. */
935
+ static pauseSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
936
+ /** Refill the configured warm pool without another capture. */
937
+ static resumeSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
938
+ static waitForSnapshot(snapshotId: string, opts?: SnapshotWaitOpts): Promise<SandboxSnapshot>;
913
939
  static deleteSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<void>;
914
940
  private resolveOpts;
915
941
  }
@@ -1682,31 +1708,14 @@ interface CreateContextOpts {
1682
1708
  }
1683
1709
 
1684
1710
  /**
1685
- * A Lizard sandbox with built-in stateful code execution.
1686
- *
1687
- * Extends the base Sandbox with `runCode()` — executes code in a persistent
1688
- * kernel so variables and imports survive between calls.
1689
- *
1690
- * Supports Python, JavaScript (Node.js), and Bash out of the box.
1691
- *
1692
- * @example
1693
- * ```ts
1694
- * import { CodeSandbox } from '@lizard-build/sdk'
1711
+ * Legacy client for the code-interpreter execution server.
1695
1712
  *
1696
- * const sandbox = await CodeSandbox.create({ project: 'my-project' })
1713
+ * Current hosted templates do not provide this server. The default
1714
+ * `code-interpreter-v1` template is unavailable; selecting `interpreter`
1715
+ * does not enable this API. Use `Sandbox.create('interpreter', options)`
1716
+ * and `sandbox.process.exec()` for Python commands instead.
1697
1717
  *
1698
- * await sandbox.runCode('x = 42')
1699
- * const result = await sandbox.runCode('print(x * 2)')
1700
- * console.log(result.stdout) // "84\n"
1701
- *
1702
- * await sandbox.kill()
1703
- * ```
1704
- *
1705
- * @example Run JavaScript:
1706
- * ```ts
1707
- * const result = await sandbox.runCode('1 + 1', { language: 'javascript' })
1708
- * console.log(result.results[0].data) // "2"
1709
- * ```
1718
+ * The methods remain for compatibility with a separately provided server.
1710
1719
  */
1711
1720
  declare class CodeSandbox extends Sandbox {
1712
1721
  protected static readonly defaultTemplate = "code-interpreter-v1";
@@ -1789,4 +1798,4 @@ declare class LizardCLI {
1789
1798
  }): Promise<CLIResult>;
1790
1799
  }
1791
1800
 
1792
- export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type FileInfo, type FsOpts, GitHubAPI, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, NotFoundError, PlatformClient, type ProcessOpts, type ProcessResult, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type RawMetrics, type Region, RegionsAPI, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type ScaleOpts, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, StorageAPI, type StreamEvent, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, WorkspacesAPI, resolveProjectId };
1801
+ export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type FileInfo, type FsOpts, GitHubAPI, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, NotFoundError, PlatformClient, type ProcessOpts, type ProcessResult, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type RawMetrics, type Region, RegionsAPI, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type SandboxSnapshot, type ScaleOpts, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, type SnapshotOpts, type SnapshotWaitOpts, StorageAPI, type StreamEvent, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, WorkspacesAPI, resolveProjectId };
package/dist/index.d.ts CHANGED
@@ -650,6 +650,9 @@ interface SandboxInfo {
650
650
  /** Region the sandbox runs in — the volume's region when one is attached. */
651
651
  region?: string;
652
652
  status?: string;
653
+ pauseError?: string | null;
654
+ size?: 'small' | 'medium' | 'large' | null;
655
+ pricePerHour?: number | null;
653
656
  cpus?: number;
654
657
  memoryMb?: number;
655
658
  metadata?: Record<string, string>;
@@ -665,6 +668,8 @@ interface SandboxOpts extends ConnectionOpts {
665
668
  /** Exact project ID — skips resolving {@link SandboxOpts.project}. */
666
669
  projectId?: string;
667
670
  template?: string;
671
+ snapshotId?: string;
672
+ size?: 'small' | 'medium' | 'large';
668
673
  metadata?: Record<string, string>;
669
674
  envs?: Record<string, string>;
670
675
  timeoutMs?: number;
@@ -731,6 +736,27 @@ declare class SandboxClient {
731
736
  }>;
732
737
  }
733
738
 
739
+ interface SandboxSnapshot {
740
+ id: string;
741
+ name: string;
742
+ projectId: string;
743
+ workspaceId: string;
744
+ region: string;
745
+ sourceSandboxId: string;
746
+ status: 'building' | 'warming' | 'ready' | 'paused' | 'suspended' | 'failed';
747
+ poolSize: number;
748
+ readyCount: number;
749
+ error: string | null;
750
+ cpus: number;
751
+ memoryMb: number;
752
+ createdAt: number;
753
+ }
754
+ interface SnapshotOpts {
755
+ poolSize?: number;
756
+ }
757
+ interface SnapshotWaitOpts extends ConnectionOpts {
758
+ waitTimeoutMs?: number;
759
+ }
734
760
  /**
735
761
  * A Linux sandbox running on Kubernetes.
736
762
  *
@@ -813,14 +839,15 @@ declare class Sandbox extends SandboxClient {
813
839
  * Create a new Lizard sandbox from the specified template.
814
840
  *
815
841
  * Template availability and installed tools depend on the platform and region.
816
- * Use `base` for shell commands or `CodeSandbox` for stateful code execution.
842
+ * Use `base` for shell commands or `interpreter` for Python process commands.
843
+ * Hosted templates do not support the legacy `CodeSandbox` execution API.
817
844
  *
818
845
  * @param template Name of the sandbox template to boot from.
819
846
  *
820
847
  * @example
821
848
  * ```ts
822
849
  * const sandbox = await Sandbox.create('base', { project: 'my-project' })
823
- * const pythonSandbox = await Sandbox.create('code-interpreter-v1', { project: 'my-project', timeoutMs: 10 * 60 * 1000 })
850
+ * const pythonSandbox = await Sandbox.create('interpreter', { project: 'my-project', timeoutMs: 10 * 60 * 1000 })
824
851
  * ```
825
852
  */
826
853
  static create(template: string, opts?: SandboxOpts): Promise<Sandbox>;
@@ -855,20 +882,12 @@ declare class Sandbox extends SandboxClient {
855
882
  * @returns `true` if the sandbox was terminated, `false` if it was already gone.
856
883
  */
857
884
  kill(opts?: ConnectionOpts): Promise<boolean>;
858
- /**
859
- * Request sandbox pause. The Kubernetes backend returns HTTP 501.
860
- *
861
- * @deprecated Unsupported on Kubernetes. Save files to a {@link Volume}
862
- * and attach it to a new sandbox instead.
863
- */
885
+ /** Queue a CRIU checkpoint and stop compute. Use waitForStatus('paused') before resuming. */
864
886
  pause(opts?: ConnectionOpts): Promise<boolean>;
865
- /**
866
- * Request sandbox resume. The Kubernetes backend returns HTTP 501.
867
- *
868
- * @deprecated Unsupported on Kubernetes. Use {@link Sandbox.connect} to
869
- * reconnect to a running sandbox.
870
- */
887
+ /** Queue restoration of saved memory and files. Use waitForStatus('running') before executing. */
871
888
  resume(opts?: ConnectionOpts): Promise<boolean>;
889
+ /** Wait for an asynchronous pause/resume operation to finish. */
890
+ waitForStatus(status: 'paused' | 'running', opts?: SnapshotWaitOpts): Promise<SandboxInfo>;
872
891
  /**
873
892
  * Get metadata and status information about this sandbox.
874
893
  */
@@ -898,18 +917,25 @@ declare class Sandbox extends SandboxClient {
898
917
  count?: number;
899
918
  timeoutMs?: number;
900
919
  }): Promise<unknown>;
901
- /** Snapshot creation is unsupported on Kubernetes; the backend returns HTTP 501. */
902
- snapshot(name?: string): Promise<unknown>;
920
+ /** Capture memory and workspace files. Disconnect active clients before capturing. */
921
+ snapshot(name?: string, opts?: SnapshotOpts): Promise<SandboxSnapshot>;
903
922
  unexpose(port: number): Promise<void>;
904
923
  logs(opts?: {
905
924
  tail?: number;
906
925
  signal?: AbortSignal;
907
926
  }): AsyncGenerator<StreamEvent, any, any>;
908
- static snapshots(projectId: string, opts?: ConnectionOpts): Promise<unknown[]>;
909
- /** Snapshot restore is unsupported on Kubernetes; the backend returns HTTP 501. */
927
+ static snapshots(projectId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot[]>;
928
+ static getSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
929
+ /** Start a sandbox from an available warm copy in the snapshot's project and region. */
910
930
  static restore(snapshotId: string, opts?: ConnectionOpts & {
911
931
  timeoutMs?: number;
912
932
  }): Promise<Sandbox>;
933
+ static setSnapshotWarmPool(snapshotId: string, poolSize: number, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
934
+ /** Release idle warm copies; retain saved state and existing claimed sandboxes. */
935
+ static pauseSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
936
+ /** Refill the configured warm pool without another capture. */
937
+ static resumeSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<SandboxSnapshot>;
938
+ static waitForSnapshot(snapshotId: string, opts?: SnapshotWaitOpts): Promise<SandboxSnapshot>;
913
939
  static deleteSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<void>;
914
940
  private resolveOpts;
915
941
  }
@@ -1682,31 +1708,14 @@ interface CreateContextOpts {
1682
1708
  }
1683
1709
 
1684
1710
  /**
1685
- * A Lizard sandbox with built-in stateful code execution.
1686
- *
1687
- * Extends the base Sandbox with `runCode()` — executes code in a persistent
1688
- * kernel so variables and imports survive between calls.
1689
- *
1690
- * Supports Python, JavaScript (Node.js), and Bash out of the box.
1691
- *
1692
- * @example
1693
- * ```ts
1694
- * import { CodeSandbox } from '@lizard-build/sdk'
1711
+ * Legacy client for the code-interpreter execution server.
1695
1712
  *
1696
- * const sandbox = await CodeSandbox.create({ project: 'my-project' })
1713
+ * Current hosted templates do not provide this server. The default
1714
+ * `code-interpreter-v1` template is unavailable; selecting `interpreter`
1715
+ * does not enable this API. Use `Sandbox.create('interpreter', options)`
1716
+ * and `sandbox.process.exec()` for Python commands instead.
1697
1717
  *
1698
- * await sandbox.runCode('x = 42')
1699
- * const result = await sandbox.runCode('print(x * 2)')
1700
- * console.log(result.stdout) // "84\n"
1701
- *
1702
- * await sandbox.kill()
1703
- * ```
1704
- *
1705
- * @example Run JavaScript:
1706
- * ```ts
1707
- * const result = await sandbox.runCode('1 + 1', { language: 'javascript' })
1708
- * console.log(result.results[0].data) // "2"
1709
- * ```
1718
+ * The methods remain for compatibility with a separately provided server.
1710
1719
  */
1711
1720
  declare class CodeSandbox extends Sandbox {
1712
1721
  protected static readonly defaultTemplate = "code-interpreter-v1";
@@ -1789,4 +1798,4 @@ declare class LizardCLI {
1789
1798
  }): Promise<CLIResult>;
1790
1799
  }
1791
1800
 
1792
- export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type FileInfo, type FsOpts, GitHubAPI, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, NotFoundError, PlatformClient, type ProcessOpts, type ProcessResult, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type RawMetrics, type Region, RegionsAPI, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type ScaleOpts, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, StorageAPI, type StreamEvent, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, WorkspacesAPI, resolveProjectId };
1801
+ export { type Account, type Addon, type AddonType, AddonsAPI, type ApiKey, type ApiKeyScope, ApiKeysAPI, AuthenticationError, type Balance, BillingAPI, type CLIOptions, type CLIResult, type CodeContext, CodeSandbox, ConfigApplyError, type ConfigResult, ConflictError, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateApiKeyOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type CreateWorkspaceOpts, type CreatedApiKey, type DeployEvent, DeployHandle, type DomainInfo, type DomainStatus, DomainsAPI, Execution, ExecutionError, type FileInfo, type FsOpts, GitHubAPI, type ListTransactionsOpts, Lizard, LizardCLI, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, MetricsAPI, NotFoundError, PlatformClient, type ProcessOpts, type ProcessResult, type Project, type ProjectConfig, type ProjectCost, ProjectsAPI, type RawMetrics, type Region, RegionsAPI, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type SandboxSnapshot, type ScaleOpts, type Secret, SecretsAPI, type Service, type ServiceMetrics, type ServiceUpdate, ServicesAPI, type SetSecretOpts, type SnapshotOpts, type SnapshotWaitOpts, StorageAPI, type StreamEvent, TimeoutError, type Transaction, type TransactionPage, Volume, type VolumeInfo, type Workspace, WorkspacesAPI, resolveProjectId };
package/dist/index.js CHANGED
@@ -849,6 +849,8 @@ var SandboxClient = class {
849
849
  headers: config.headers,
850
850
  body: JSON.stringify({
851
851
  template,
852
+ snapshotId: opts?.snapshotId,
853
+ size: opts?.size,
852
854
  timeoutMs,
853
855
  projectId,
854
856
  metadata: opts?.metadata,
@@ -981,24 +983,28 @@ var Sandbox = class extends SandboxClient {
981
983
  async kill(opts) {
982
984
  return SandboxClient.killSandbox(this.sandboxId, this.resolveOpts(opts));
983
985
  }
984
- /**
985
- * Request sandbox pause. The Kubernetes backend returns HTTP 501.
986
- *
987
- * @deprecated Unsupported on Kubernetes. Save files to a {@link Volume}
988
- * and attach it to a new sandbox instead.
989
- */
986
+ /** Queue a CRIU checkpoint and stop compute. Use waitForStatus('paused') before resuming. */
990
987
  async pause(opts) {
991
988
  return SandboxClient.pauseSandbox(this.sandboxId, this.resolveOpts(opts));
992
989
  }
993
- /**
994
- * Request sandbox resume. The Kubernetes backend returns HTTP 501.
995
- *
996
- * @deprecated Unsupported on Kubernetes. Use {@link Sandbox.connect} to
997
- * reconnect to a running sandbox.
998
- */
990
+ /** Queue restoration of saved memory and files. Use waitForStatus('running') before executing. */
999
991
  async resume(opts) {
1000
992
  return SandboxClient.resumeSandbox(this.sandboxId, this.resolveOpts(opts));
1001
993
  }
994
+ /** Wait for an asynchronous pause/resume operation to finish. */
995
+ async waitForStatus(status, opts) {
996
+ const deadline = Date.now() + (opts?.waitTimeoutMs ?? 6e5);
997
+ do {
998
+ const info = await this.getInfo(opts);
999
+ if (info.status === status) return info;
1000
+ if (["failed", "stopped", "deleted"].includes(info.status ?? "") || info.pauseError) {
1001
+ throw new ConflictError(info.pauseError ?? `Sandbox is ${info.status}`);
1002
+ }
1003
+ if (Date.now() >= deadline) break;
1004
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
1005
+ } while (Date.now() < deadline);
1006
+ throw new TimeoutError(`Sandbox did not become ${status} within the wait timeout`);
1007
+ }
1002
1008
  /**
1003
1009
  * Get metadata and status information about this sandbox.
1004
1010
  */
@@ -1034,9 +1040,9 @@ var Sandbox = class extends SandboxClient {
1034
1040
  fork(opts = {}) {
1035
1041
  return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/fork`, { count: opts.count ?? 1, timeoutMs: opts.timeoutMs ?? 0 });
1036
1042
  }
1037
- /** Snapshot creation is unsupported on Kubernetes; the backend returns HTTP 501. */
1038
- snapshot(name) {
1039
- return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/snapshot`, { name });
1043
+ /** Capture memory and workspace files. Disconnect active clients before capturing. */
1044
+ snapshot(name = `Snapshot ${this.sandboxId}`, opts = {}) {
1045
+ return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/snapshot`, { name, poolSize: opts.poolSize ?? 5 });
1040
1046
  }
1041
1047
  unexpose(port) {
1042
1048
  return new PlatformClient(this.resolveOpts()).delete(`/api/sandboxes/${this.sandboxId}/expose/${port}`);
@@ -1045,13 +1051,45 @@ var Sandbox = class extends SandboxClient {
1045
1051
  return new PlatformClient(this.resolveOpts()).events(query(`/api/sandboxes/${this.sandboxId}/logs`, { tail: opts.tail }), { signal: opts.signal });
1046
1052
  }
1047
1053
  static snapshots(projectId, opts) {
1048
- return new PlatformClient(opts ?? {}).get(`/api/projects/${projectId}/snapshots`);
1054
+ return new PlatformClient(opts ?? {}).get(`/api/projects/${encodeURIComponent(projectId)}/snapshots`);
1055
+ }
1056
+ static getSnapshot(snapshotId, opts) {
1057
+ return new PlatformClient(opts ?? {}).get(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`);
1049
1058
  }
1050
- /** Snapshot restore is unsupported on Kubernetes; the backend returns HTTP 501. */
1059
+ /** Start a sandbox from an available warm copy in the snapshot's project and region. */
1051
1060
  static async restore(snapshotId, opts) {
1052
- const result = await new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/fork`, { timeoutMs: opts?.timeoutMs ?? 0 });
1061
+ const client = new PlatformClient(opts ?? {});
1062
+ const snapshot = await this.getSnapshot(snapshotId, opts);
1063
+ const result = await client.post("/api/sandboxes", {
1064
+ snapshotId,
1065
+ projectId: snapshot.projectId,
1066
+ region: snapshot.region,
1067
+ timeoutMs: opts?.timeoutMs ?? DEFAULT_SANDBOX_TIMEOUT_MS
1068
+ });
1053
1069
  return new this({ ...opts, sandboxId: result.sandboxId ?? result.id });
1054
1070
  }
1071
+ static setSnapshotWarmPool(snapshotId, poolSize, opts) {
1072
+ return new PlatformClient(opts ?? {}).patch(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`, { poolSize });
1073
+ }
1074
+ /** Release idle warm copies; retain saved state and existing claimed sandboxes. */
1075
+ static pauseSnapshot(snapshotId, opts) {
1076
+ return new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/pause`, {});
1077
+ }
1078
+ /** Refill the configured warm pool without another capture. */
1079
+ static resumeSnapshot(snapshotId, opts) {
1080
+ return new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/resume`, {});
1081
+ }
1082
+ static async waitForSnapshot(snapshotId, opts) {
1083
+ const deadline = Date.now() + (opts?.waitTimeoutMs ?? 9e5);
1084
+ do {
1085
+ const snapshot = await this.getSnapshot(snapshotId, opts);
1086
+ if (snapshot.status === "ready") return snapshot;
1087
+ if (["failed", "paused", "suspended"].includes(snapshot.status)) throw new ConflictError(snapshot.error ?? `Snapshot is ${snapshot.status}`);
1088
+ if (Date.now() >= deadline) break;
1089
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
1090
+ } while (Date.now() < deadline);
1091
+ throw new TimeoutError("Snapshot did not become ready within the wait timeout");
1092
+ }
1055
1093
  static deleteSnapshot(snapshotId, opts) {
1056
1094
  return new PlatformClient(opts ?? {}).delete(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`);
1057
1095
  }
package/dist/index.mjs CHANGED
@@ -798,6 +798,8 @@ var SandboxClient = class {
798
798
  headers: config.headers,
799
799
  body: JSON.stringify({
800
800
  template,
801
+ snapshotId: opts?.snapshotId,
802
+ size: opts?.size,
801
803
  timeoutMs,
802
804
  projectId,
803
805
  metadata: opts?.metadata,
@@ -930,24 +932,28 @@ var Sandbox = class extends SandboxClient {
930
932
  async kill(opts) {
931
933
  return SandboxClient.killSandbox(this.sandboxId, this.resolveOpts(opts));
932
934
  }
933
- /**
934
- * Request sandbox pause. The Kubernetes backend returns HTTP 501.
935
- *
936
- * @deprecated Unsupported on Kubernetes. Save files to a {@link Volume}
937
- * and attach it to a new sandbox instead.
938
- */
935
+ /** Queue a CRIU checkpoint and stop compute. Use waitForStatus('paused') before resuming. */
939
936
  async pause(opts) {
940
937
  return SandboxClient.pauseSandbox(this.sandboxId, this.resolveOpts(opts));
941
938
  }
942
- /**
943
- * Request sandbox resume. The Kubernetes backend returns HTTP 501.
944
- *
945
- * @deprecated Unsupported on Kubernetes. Use {@link Sandbox.connect} to
946
- * reconnect to a running sandbox.
947
- */
939
+ /** Queue restoration of saved memory and files. Use waitForStatus('running') before executing. */
948
940
  async resume(opts) {
949
941
  return SandboxClient.resumeSandbox(this.sandboxId, this.resolveOpts(opts));
950
942
  }
943
+ /** Wait for an asynchronous pause/resume operation to finish. */
944
+ async waitForStatus(status, opts) {
945
+ const deadline = Date.now() + (opts?.waitTimeoutMs ?? 6e5);
946
+ do {
947
+ const info = await this.getInfo(opts);
948
+ if (info.status === status) return info;
949
+ if (["failed", "stopped", "deleted"].includes(info.status ?? "") || info.pauseError) {
950
+ throw new ConflictError(info.pauseError ?? `Sandbox is ${info.status}`);
951
+ }
952
+ if (Date.now() >= deadline) break;
953
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
954
+ } while (Date.now() < deadline);
955
+ throw new TimeoutError(`Sandbox did not become ${status} within the wait timeout`);
956
+ }
951
957
  /**
952
958
  * Get metadata and status information about this sandbox.
953
959
  */
@@ -983,9 +989,9 @@ var Sandbox = class extends SandboxClient {
983
989
  fork(opts = {}) {
984
990
  return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/fork`, { count: opts.count ?? 1, timeoutMs: opts.timeoutMs ?? 0 });
985
991
  }
986
- /** Snapshot creation is unsupported on Kubernetes; the backend returns HTTP 501. */
987
- snapshot(name) {
988
- return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/snapshot`, { name });
992
+ /** Capture memory and workspace files. Disconnect active clients before capturing. */
993
+ snapshot(name = `Snapshot ${this.sandboxId}`, opts = {}) {
994
+ return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/snapshot`, { name, poolSize: opts.poolSize ?? 5 });
989
995
  }
990
996
  unexpose(port) {
991
997
  return new PlatformClient(this.resolveOpts()).delete(`/api/sandboxes/${this.sandboxId}/expose/${port}`);
@@ -994,13 +1000,45 @@ var Sandbox = class extends SandboxClient {
994
1000
  return new PlatformClient(this.resolveOpts()).events(query(`/api/sandboxes/${this.sandboxId}/logs`, { tail: opts.tail }), { signal: opts.signal });
995
1001
  }
996
1002
  static snapshots(projectId, opts) {
997
- return new PlatformClient(opts ?? {}).get(`/api/projects/${projectId}/snapshots`);
1003
+ return new PlatformClient(opts ?? {}).get(`/api/projects/${encodeURIComponent(projectId)}/snapshots`);
1004
+ }
1005
+ static getSnapshot(snapshotId, opts) {
1006
+ return new PlatformClient(opts ?? {}).get(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`);
998
1007
  }
999
- /** Snapshot restore is unsupported on Kubernetes; the backend returns HTTP 501. */
1008
+ /** Start a sandbox from an available warm copy in the snapshot's project and region. */
1000
1009
  static async restore(snapshotId, opts) {
1001
- const result = await new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/fork`, { timeoutMs: opts?.timeoutMs ?? 0 });
1010
+ const client = new PlatformClient(opts ?? {});
1011
+ const snapshot = await this.getSnapshot(snapshotId, opts);
1012
+ const result = await client.post("/api/sandboxes", {
1013
+ snapshotId,
1014
+ projectId: snapshot.projectId,
1015
+ region: snapshot.region,
1016
+ timeoutMs: opts?.timeoutMs ?? DEFAULT_SANDBOX_TIMEOUT_MS
1017
+ });
1002
1018
  return new this({ ...opts, sandboxId: result.sandboxId ?? result.id });
1003
1019
  }
1020
+ static setSnapshotWarmPool(snapshotId, poolSize, opts) {
1021
+ return new PlatformClient(opts ?? {}).patch(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`, { poolSize });
1022
+ }
1023
+ /** Release idle warm copies; retain saved state and existing claimed sandboxes. */
1024
+ static pauseSnapshot(snapshotId, opts) {
1025
+ return new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/pause`, {});
1026
+ }
1027
+ /** Refill the configured warm pool without another capture. */
1028
+ static resumeSnapshot(snapshotId, opts) {
1029
+ return new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/resume`, {});
1030
+ }
1031
+ static async waitForSnapshot(snapshotId, opts) {
1032
+ const deadline = Date.now() + (opts?.waitTimeoutMs ?? 9e5);
1033
+ do {
1034
+ const snapshot = await this.getSnapshot(snapshotId, opts);
1035
+ if (snapshot.status === "ready") return snapshot;
1036
+ if (["failed", "paused", "suspended"].includes(snapshot.status)) throw new ConflictError(snapshot.error ?? `Snapshot is ${snapshot.status}`);
1037
+ if (Date.now() >= deadline) break;
1038
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
1039
+ } while (Date.now() < deadline);
1040
+ throw new TimeoutError("Snapshot did not become ready within the wait timeout");
1041
+ }
1004
1042
  static deleteSnapshot(snapshotId, opts) {
1005
1043
  return new PlatformClient(opts ?? {}).delete(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`);
1006
1044
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lizard-build/sdk",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
4
4
  "description": "TypeScript SDK for Lizard: Kubernetes sandboxes, code execution and cloud apps.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",