@lizard-build/sdk 0.1.6 → 0.1.15

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
@@ -21,8 +21,8 @@ pip install lizard-sdk
21
21
  ```ts
22
22
  import { Sandbox } from '@lizard-build/sdk'
23
23
 
24
- // Boot a Node.js microVM from the 'node22' template
25
- const sandbox = await Sandbox.create('node22')
24
+ // Boot a microVM from the 'base' template (Debian + Node.js 20)
25
+ const sandbox = await Sandbox.create('base')
26
26
 
27
27
  // Write a file directly into the microVM filesystem
28
28
  await sandbox.fs.write('/app/server.js', `
@@ -46,8 +46,8 @@ await sandbox.kill()
46
46
  ```python
47
47
  from lizard import Sandbox
48
48
 
49
- # Boot a Python microVM from the 'python312' template
50
- sandbox = Sandbox.create("python312")
49
+ # Boot a Python microVM from the 'code-interpreter-v1' template
50
+ sandbox = Sandbox.create("code-interpreter-v1")
51
51
 
52
52
  # Write a script into the microVM filesystem
53
53
  sandbox.fs.write("/app/main.py", """
@@ -77,7 +77,7 @@ Sandboxes can be snapshotted mid-execution and resumed exactly where they left o
77
77
 
78
78
  ```ts
79
79
  // Boot and set up the environment once
80
- const sandbox = await Sandbox.create('python312')
80
+ const sandbox = await Sandbox.create('code-interpreter-v1')
81
81
  await sandbox.process.exec('pip install numpy pandas scikit-learn')
82
82
  const id = sandbox.sandboxId
83
83
  await sandbox.pause()
@@ -92,7 +92,7 @@ await resumed.kill()
92
92
  ```python
93
93
  from lizard import Sandbox
94
94
 
95
- sandbox = Sandbox.create("python312")
95
+ sandbox = Sandbox.create("code-interpreter-v1")
96
96
  sandbox.process.exec_("pip install numpy pandas scikit-learn")
97
97
  sandbox_id = sandbox.sandbox_id
98
98
  sandbox.pause()
@@ -108,11 +108,11 @@ resumed.kill()
108
108
 
109
109
  ### `Sandbox.create(template?, opts?)`
110
110
 
111
- Boot a new Lizard microVM. Built-in templates: `base`, `node22`, `python312`. Custom templates can be pushed via `lizard push`.
111
+ Boot a new Lizard microVM. Built-in templates: `base` (Debian + Node.js 20) and `code-interpreter-v1` (Python 3.11 + Node.js 20). Custom templates can be pushed via `lizard push`.
112
112
 
113
113
  ```ts
114
- const sandbox = await Sandbox.create('node22')
115
- const sandbox = await Sandbox.create('python312', { timeoutMs: 10 * 60 * 1000 })
114
+ const sandbox = await Sandbox.create('base')
115
+ const sandbox = await Sandbox.create('code-interpreter-v1', { timeoutMs: 10 * 60 * 1000 })
116
116
  ```
117
117
 
118
118
  ### `Sandbox.connect(sandboxId, opts?)`
@@ -154,7 +154,7 @@ Returns a public HTTPS URL for a port listening inside the microVM — no tunnel
154
154
  ```ts
155
155
  await sandbox.process.exec('npx -y serve -p 3000 &')
156
156
  const url = sandbox.getHost(3000)
157
- // https://{sandboxId}-3000.sandbox.lizard.run
157
+ // https://{sandboxId}-3000.sandbox.{region}.onlizard.com
158
158
  ```
159
159
 
160
160
  ### `sandbox.pause()` / `sandbox.resume()`
@@ -175,8 +175,8 @@ Extend or reduce the sandbox timeout.
175
175
 
176
176
  | Variable | Description |
177
177
  |---|---|
178
- | `LIZARD_API_KEY` | API key (required — get one at [lizard.run](https://lizard.run)) |
179
- | `LIZARD_API_URL` | Override the API base URL (default: `https://api.lizard.run`) |
178
+ | `LIZARD_API_KEY` | API key (required — get one at [lizard.build](https://lizard.build)) |
179
+ | `LIZARD_API_URL` | Override the API base URL (default: `https://lizard.build`) |
180
180
 
181
181
  The `X-API-Key` header is used for all authenticated requests.
182
182
 
package/dist/index.d.mts CHANGED
@@ -141,6 +141,7 @@ interface SandboxOpts extends ConnectionOpts {
141
141
  metadata?: Record<string, string>;
142
142
  envs?: Record<string, string>;
143
143
  timeoutMs?: number;
144
+ volumeId?: string;
144
145
  }
145
146
  /**
146
147
  * Low-level HTTP client for the Lizard sandbox API.
@@ -156,6 +157,10 @@ declare class SandboxClient {
156
157
  protected static listSandboxes(opts?: ConnectionOpts): Promise<SandboxInfo[]>;
157
158
  protected static getSandboxInfo(sandboxId: string, opts?: ConnectionOpts): Promise<SandboxInfo>;
158
159
  protected static setTimeoutSandbox(sandboxId: string, timeoutMs: number, opts?: ConnectionOpts): Promise<void>;
160
+ protected static exposeSandboxPort(sandboxId: string, port: number, opts?: ConnectionOpts): Promise<{
161
+ hostname: string;
162
+ url: string;
163
+ }>;
159
164
  }
160
165
 
161
166
  /**
@@ -170,7 +175,7 @@ declare class SandboxClient {
170
175
  * ```ts
171
176
  * import { Sandbox } from 'lizard'
172
177
  *
173
- * const sandbox = await Sandbox.create('node22')
178
+ * const sandbox = await Sandbox.create('base')
174
179
  * await sandbox.fs.write('/app/index.js', 'console.log("hello world")')
175
180
  * const result = await sandbox.process.exec('node /app/index.js')
176
181
  * console.log(result.stdout) // "hello world"
@@ -179,7 +184,7 @@ declare class SandboxClient {
179
184
  *
180
185
  * @example Pause and resume a long-running session:
181
186
  * ```ts
182
- * const sandbox = await Sandbox.create('python312')
187
+ * const sandbox = await Sandbox.create('code-interpreter-v1')
183
188
  * await sandbox.process.exec('pip install numpy')
184
189
  * const id = sandbox.sandboxId
185
190
  * await sandbox.pause()
@@ -231,15 +236,16 @@ declare class Sandbox extends SandboxClient {
231
236
  /**
232
237
  * Create a new Lizard sandbox from the specified template.
233
238
  *
234
- * Available templates include `base`, `node22`, and `python312`. Custom
235
- * templates can be built and pushed via `lizard push`.
239
+ * Available templates: `base` (Debian + Node.js 20) and `code-interpreter-v1`
240
+ * (Python 3.11 + Node.js 20). Custom templates can be built and pushed via
241
+ * `lizard push`.
236
242
  *
237
243
  * @param template Name of the sandbox template to boot from.
238
244
  *
239
245
  * @example
240
246
  * ```ts
241
- * const sandbox = await Sandbox.create('node22')
242
- * const sandbox = await Sandbox.create('python312', { timeoutMs: 10 * 60 * 1000 })
247
+ * const sandbox = await Sandbox.create('base')
248
+ * const sandbox = await Sandbox.create('code-interpreter-v1', { timeoutMs: 10 * 60 * 1000 })
243
249
  * ```
244
250
  */
245
251
  static create(template: string, opts?: SandboxOpts): Promise<Sandbox>;
@@ -305,10 +311,10 @@ declare class Sandbox extends SandboxClient {
305
311
  * ```ts
306
312
  * await sandbox.process.exec('npx -y serve -p 3000 &')
307
313
  * const url = sandbox.getHost(3000)
308
- * // https://{sandboxId}-3000.sandbox.lizard.run
314
+ * // https://{sandboxId}-3000.sandbox.{region}.onlizard.com
309
315
  * ```
310
316
  */
311
- getHost(port: number): string;
317
+ getHost(port: number, opts?: ConnectionOpts): Promise<string>;
312
318
  private resolveOpts;
313
319
  }
314
320
 
@@ -476,4 +482,34 @@ declare class CodeSandbox extends Sandbox {
476
482
  static connect(sandboxId: string, opts?: ConnectionOpts): Promise<CodeSandbox>;
477
483
  }
478
484
 
479
- export { AuthenticationError, type CodeContext, CodeSandbox, type ConnectionOpts, type CreateContextOpts, Execution, ExecutionError, type FileInfo, type FsOpts, LizardError, NotFoundError, type ProcessOpts, type ProcessResult, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, TimeoutError };
485
+ interface VolumeInfo {
486
+ id: string;
487
+ projectId: string;
488
+ name: string;
489
+ sizeGb: number;
490
+ sizeMb?: number;
491
+ status: string;
492
+ attachedTo?: string | null;
493
+ createdAt: number;
494
+ }
495
+ interface CreateVolumeOpts extends ConnectionOpts {
496
+ sizeGb?: number;
497
+ }
498
+ /**
499
+ * A persistent volume that outlives sandboxes.
500
+ * Mount it to a sandbox via `Sandbox.create({ volumeId: volume.volumeId })`.
501
+ */
502
+ declare class Volume {
503
+ readonly volumeId: string;
504
+ private readonly config;
505
+ constructor(opts: {
506
+ volumeId: string;
507
+ } & ConnectionOpts);
508
+ static create(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
509
+ static get(projectId: string, volumeId: string, opts?: ConnectionOpts): Promise<Volume>;
510
+ static list(projectId: string, opts?: ConnectionOpts): Promise<VolumeInfo[]>;
511
+ getInfo(projectId: string): Promise<VolumeInfo>;
512
+ delete(projectId: string): Promise<void>;
513
+ }
514
+
515
+ export { AuthenticationError, type CodeContext, CodeSandbox, type ConnectionOpts, type CreateContextOpts, type CreateVolumeOpts, Execution, ExecutionError, type FileInfo, type FsOpts, LizardError, NotFoundError, type ProcessOpts, type ProcessResult, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, TimeoutError, Volume, type VolumeInfo };
package/dist/index.d.ts CHANGED
@@ -141,6 +141,7 @@ interface SandboxOpts extends ConnectionOpts {
141
141
  metadata?: Record<string, string>;
142
142
  envs?: Record<string, string>;
143
143
  timeoutMs?: number;
144
+ volumeId?: string;
144
145
  }
145
146
  /**
146
147
  * Low-level HTTP client for the Lizard sandbox API.
@@ -156,6 +157,10 @@ declare class SandboxClient {
156
157
  protected static listSandboxes(opts?: ConnectionOpts): Promise<SandboxInfo[]>;
157
158
  protected static getSandboxInfo(sandboxId: string, opts?: ConnectionOpts): Promise<SandboxInfo>;
158
159
  protected static setTimeoutSandbox(sandboxId: string, timeoutMs: number, opts?: ConnectionOpts): Promise<void>;
160
+ protected static exposeSandboxPort(sandboxId: string, port: number, opts?: ConnectionOpts): Promise<{
161
+ hostname: string;
162
+ url: string;
163
+ }>;
159
164
  }
160
165
 
161
166
  /**
@@ -170,7 +175,7 @@ declare class SandboxClient {
170
175
  * ```ts
171
176
  * import { Sandbox } from 'lizard'
172
177
  *
173
- * const sandbox = await Sandbox.create('node22')
178
+ * const sandbox = await Sandbox.create('base')
174
179
  * await sandbox.fs.write('/app/index.js', 'console.log("hello world")')
175
180
  * const result = await sandbox.process.exec('node /app/index.js')
176
181
  * console.log(result.stdout) // "hello world"
@@ -179,7 +184,7 @@ declare class SandboxClient {
179
184
  *
180
185
  * @example Pause and resume a long-running session:
181
186
  * ```ts
182
- * const sandbox = await Sandbox.create('python312')
187
+ * const sandbox = await Sandbox.create('code-interpreter-v1')
183
188
  * await sandbox.process.exec('pip install numpy')
184
189
  * const id = sandbox.sandboxId
185
190
  * await sandbox.pause()
@@ -231,15 +236,16 @@ declare class Sandbox extends SandboxClient {
231
236
  /**
232
237
  * Create a new Lizard sandbox from the specified template.
233
238
  *
234
- * Available templates include `base`, `node22`, and `python312`. Custom
235
- * templates can be built and pushed via `lizard push`.
239
+ * Available templates: `base` (Debian + Node.js 20) and `code-interpreter-v1`
240
+ * (Python 3.11 + Node.js 20). Custom templates can be built and pushed via
241
+ * `lizard push`.
236
242
  *
237
243
  * @param template Name of the sandbox template to boot from.
238
244
  *
239
245
  * @example
240
246
  * ```ts
241
- * const sandbox = await Sandbox.create('node22')
242
- * const sandbox = await Sandbox.create('python312', { timeoutMs: 10 * 60 * 1000 })
247
+ * const sandbox = await Sandbox.create('base')
248
+ * const sandbox = await Sandbox.create('code-interpreter-v1', { timeoutMs: 10 * 60 * 1000 })
243
249
  * ```
244
250
  */
245
251
  static create(template: string, opts?: SandboxOpts): Promise<Sandbox>;
@@ -305,10 +311,10 @@ declare class Sandbox extends SandboxClient {
305
311
  * ```ts
306
312
  * await sandbox.process.exec('npx -y serve -p 3000 &')
307
313
  * const url = sandbox.getHost(3000)
308
- * // https://{sandboxId}-3000.sandbox.lizard.run
314
+ * // https://{sandboxId}-3000.sandbox.{region}.onlizard.com
309
315
  * ```
310
316
  */
311
- getHost(port: number): string;
317
+ getHost(port: number, opts?: ConnectionOpts): Promise<string>;
312
318
  private resolveOpts;
313
319
  }
314
320
 
@@ -476,4 +482,34 @@ declare class CodeSandbox extends Sandbox {
476
482
  static connect(sandboxId: string, opts?: ConnectionOpts): Promise<CodeSandbox>;
477
483
  }
478
484
 
479
- export { AuthenticationError, type CodeContext, CodeSandbox, type ConnectionOpts, type CreateContextOpts, Execution, ExecutionError, type FileInfo, type FsOpts, LizardError, NotFoundError, type ProcessOpts, type ProcessResult, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, TimeoutError };
485
+ interface VolumeInfo {
486
+ id: string;
487
+ projectId: string;
488
+ name: string;
489
+ sizeGb: number;
490
+ sizeMb?: number;
491
+ status: string;
492
+ attachedTo?: string | null;
493
+ createdAt: number;
494
+ }
495
+ interface CreateVolumeOpts extends ConnectionOpts {
496
+ sizeGb?: number;
497
+ }
498
+ /**
499
+ * A persistent volume that outlives sandboxes.
500
+ * Mount it to a sandbox via `Sandbox.create({ volumeId: volume.volumeId })`.
501
+ */
502
+ declare class Volume {
503
+ readonly volumeId: string;
504
+ private readonly config;
505
+ constructor(opts: {
506
+ volumeId: string;
507
+ } & ConnectionOpts);
508
+ static create(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
509
+ static get(projectId: string, volumeId: string, opts?: ConnectionOpts): Promise<Volume>;
510
+ static list(projectId: string, opts?: ConnectionOpts): Promise<VolumeInfo[]>;
511
+ getInfo(projectId: string): Promise<VolumeInfo>;
512
+ delete(projectId: string): Promise<void>;
513
+ }
514
+
515
+ export { AuthenticationError, type CodeContext, CodeSandbox, type ConnectionOpts, type CreateContextOpts, type CreateVolumeOpts, Execution, ExecutionError, type FileInfo, type FsOpts, LizardError, NotFoundError, type ProcessOpts, type ProcessResult, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, TimeoutError, Volume, type VolumeInfo };
package/dist/index.js CHANGED
@@ -25,12 +25,13 @@ __export(index_exports, {
25
25
  LizardError: () => LizardError,
26
26
  NotFoundError: () => NotFoundError,
27
27
  Sandbox: () => Sandbox,
28
- TimeoutError: () => TimeoutError
28
+ TimeoutError: () => TimeoutError,
29
+ Volume: () => Volume
29
30
  });
30
31
  module.exports = __toCommonJS(index_exports);
31
32
 
32
33
  // src/config.ts
33
- var DEFAULT_API_URL = "https://api.lizard.run";
34
+ var DEFAULT_API_URL = "https://lizard.build";
34
35
  var DEFAULT_SANDBOX_TIMEOUT_MS = 5 * 60 * 1e3;
35
36
  var ConnectionConfig = class {
36
37
  constructor(opts) {
@@ -240,7 +241,8 @@ var SandboxClient = class {
240
241
  template,
241
242
  timeoutMs,
242
243
  metadata: opts?.metadata,
243
- envs: opts?.envs
244
+ envs: opts?.envs,
245
+ volumeId: opts?.volumeId
244
246
  })
245
247
  });
246
248
  if (!res.ok) await handleApiError(res);
@@ -301,6 +303,15 @@ var SandboxClient = class {
301
303
  });
302
304
  if (!res.ok) await handleApiError(res);
303
305
  }
306
+ static async exposeSandboxPort(sandboxId, port, opts) {
307
+ const config = new ConnectionConfig(opts);
308
+ const res = await fetch(`${config.apiUrl}/api/sandboxes/${sandboxId}/expose/${port}`, {
309
+ method: "POST",
310
+ headers: config.headers
311
+ });
312
+ if (!res.ok) await handleApiError(res);
313
+ return res.json();
314
+ }
304
315
  };
305
316
 
306
317
  // src/sandbox/index.ts
@@ -396,13 +407,12 @@ var Sandbox = class extends SandboxClient {
396
407
  * ```ts
397
408
  * await sandbox.process.exec('npx -y serve -p 3000 &')
398
409
  * const url = sandbox.getHost(3000)
399
- * // https://{sandboxId}-3000.sandbox.lizard.run
410
+ * // https://{sandboxId}-3000.sandbox.{region}.onlizard.com
400
411
  * ```
401
412
  */
402
- getHost(port) {
403
- const apiHost = new URL(this.connectionConfig.apiUrl).host;
404
- const baseHost = apiHost.replace(/^api\./, "");
405
- return `${this.sandboxId}-${port}.sandbox.${baseHost}`;
413
+ async getHost(port, opts) {
414
+ const { hostname } = await SandboxClient.exposeSandboxPort(this.sandboxId, port, this.resolveOpts(opts));
415
+ return hostname;
406
416
  }
407
417
  resolveOpts(opts) {
408
418
  return { ...this.connectionConfig, ...opts };
@@ -442,7 +452,7 @@ var Execution = class {
442
452
  var CODE_INTERPRETER_PORT = 8080;
443
453
  var CodeSandbox = class extends Sandbox {
444
454
  get serverUrl() {
445
- return `https://${this.getHost(CODE_INTERPRETER_PORT)}`;
455
+ return this.getHost(CODE_INTERPRETER_PORT).then((h) => `https://${h}`);
446
456
  }
447
457
  /**
448
458
  * Execute code in a persistent kernel.
@@ -477,7 +487,7 @@ var CodeSandbox = class extends Sandbox {
477
487
  const controller = new AbortController();
478
488
  const timer = opts?.timeoutMs ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
479
489
  try {
480
- const res = await fetch(`${this.serverUrl}/execute`, {
490
+ const res = await fetch(`${await this.serverUrl}/execute`, {
481
491
  method: "POST",
482
492
  headers: { "Content-Type": "application/json" },
483
493
  body: JSON.stringify(body),
@@ -537,7 +547,7 @@ var CodeSandbox = class extends Sandbox {
537
547
  * ```
538
548
  */
539
549
  async createContext(opts) {
540
- const res = await fetch(`${this.serverUrl}/contexts`, {
550
+ const res = await fetch(`${await this.serverUrl}/contexts`, {
541
551
  method: "POST",
542
552
  headers: { "Content-Type": "application/json" },
543
553
  body: JSON.stringify({
@@ -552,7 +562,7 @@ var CodeSandbox = class extends Sandbox {
552
562
  * List all active execution contexts in this sandbox.
553
563
  */
554
564
  async listContexts() {
555
- const res = await fetch(`${this.serverUrl}/contexts`);
565
+ const res = await fetch(`${await this.serverUrl}/contexts`);
556
566
  if (!res.ok) throw new Error(`Failed to list contexts: ${await res.text()}`);
557
567
  return res.json();
558
568
  }
@@ -561,7 +571,7 @@ var CodeSandbox = class extends Sandbox {
561
571
  */
562
572
  async deleteContext(context) {
563
573
  const id = typeof context === "string" ? context : context.id;
564
- const res = await fetch(`${this.serverUrl}/contexts/${id}`, { method: "DELETE" });
574
+ const res = await fetch(`${await this.serverUrl}/contexts/${id}`, { method: "DELETE" });
565
575
  if (!res.ok) throw new Error(`Failed to delete context: ${await res.text()}`);
566
576
  }
567
577
  /**
@@ -569,7 +579,7 @@ var CodeSandbox = class extends Sandbox {
569
579
  */
570
580
  async restartContext(context) {
571
581
  const id = typeof context === "string" ? context : context.id;
572
- const res = await fetch(`${this.serverUrl}/contexts/${id}/restart`, { method: "POST" });
582
+ const res = await fetch(`${await this.serverUrl}/contexts/${id}/restart`, { method: "POST" });
573
583
  if (!res.ok) throw new Error(`Failed to restart context: ${await res.text()}`);
574
584
  }
575
585
  static async create(templateOrOpts, opts) {
@@ -600,6 +610,55 @@ async function* readLines(body) {
600
610
  reader.releaseLock();
601
611
  }
602
612
  }
613
+
614
+ // src/volume/index.ts
615
+ var Volume = class _Volume {
616
+ constructor(opts) {
617
+ this.volumeId = opts.volumeId;
618
+ this.config = new ConnectionConfig(opts);
619
+ }
620
+ static async create(projectId, name, opts) {
621
+ const config = new ConnectionConfig(opts);
622
+ const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
623
+ method: "POST",
624
+ headers: config.headers,
625
+ body: JSON.stringify({ name, sizeGb: opts?.sizeGb ?? 5 })
626
+ });
627
+ if (!res.ok) await handleApiError(res);
628
+ const vol = await res.json();
629
+ return new _Volume({ volumeId: vol.id, ...opts });
630
+ }
631
+ static async get(projectId, volumeId, opts) {
632
+ const config = new ConnectionConfig(opts);
633
+ const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${volumeId}`, {
634
+ headers: config.headers
635
+ });
636
+ if (!res.ok) await handleApiError(res);
637
+ return new _Volume({ volumeId, ...opts });
638
+ }
639
+ static async list(projectId, opts) {
640
+ const config = new ConnectionConfig(opts);
641
+ const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
642
+ headers: config.headers
643
+ });
644
+ if (!res.ok) await handleApiError(res);
645
+ return res.json();
646
+ }
647
+ async getInfo(projectId) {
648
+ const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
649
+ headers: this.config.headers
650
+ });
651
+ if (!res.ok) await handleApiError(res);
652
+ return res.json();
653
+ }
654
+ async delete(projectId) {
655
+ const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
656
+ method: "DELETE",
657
+ headers: this.config.headers
658
+ });
659
+ if (!res.ok) await handleApiError(res);
660
+ }
661
+ };
603
662
  // Annotate the CommonJS export names for ESM import in node:
604
663
  0 && (module.exports = {
605
664
  AuthenticationError,
@@ -607,5 +666,6 @@ async function* readLines(body) {
607
666
  LizardError,
608
667
  NotFoundError,
609
668
  Sandbox,
610
- TimeoutError
669
+ TimeoutError,
670
+ Volume
611
671
  });
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/config.ts
2
- var DEFAULT_API_URL = "https://api.lizard.run";
2
+ var DEFAULT_API_URL = "https://lizard.build";
3
3
  var DEFAULT_SANDBOX_TIMEOUT_MS = 5 * 60 * 1e3;
4
4
  var ConnectionConfig = class {
5
5
  constructor(opts) {
@@ -209,7 +209,8 @@ var SandboxClient = class {
209
209
  template,
210
210
  timeoutMs,
211
211
  metadata: opts?.metadata,
212
- envs: opts?.envs
212
+ envs: opts?.envs,
213
+ volumeId: opts?.volumeId
213
214
  })
214
215
  });
215
216
  if (!res.ok) await handleApiError(res);
@@ -270,6 +271,15 @@ var SandboxClient = class {
270
271
  });
271
272
  if (!res.ok) await handleApiError(res);
272
273
  }
274
+ static async exposeSandboxPort(sandboxId, port, opts) {
275
+ const config = new ConnectionConfig(opts);
276
+ const res = await fetch(`${config.apiUrl}/api/sandboxes/${sandboxId}/expose/${port}`, {
277
+ method: "POST",
278
+ headers: config.headers
279
+ });
280
+ if (!res.ok) await handleApiError(res);
281
+ return res.json();
282
+ }
273
283
  };
274
284
 
275
285
  // src/sandbox/index.ts
@@ -365,13 +375,12 @@ var Sandbox = class extends SandboxClient {
365
375
  * ```ts
366
376
  * await sandbox.process.exec('npx -y serve -p 3000 &')
367
377
  * const url = sandbox.getHost(3000)
368
- * // https://{sandboxId}-3000.sandbox.lizard.run
378
+ * // https://{sandboxId}-3000.sandbox.{region}.onlizard.com
369
379
  * ```
370
380
  */
371
- getHost(port) {
372
- const apiHost = new URL(this.connectionConfig.apiUrl).host;
373
- const baseHost = apiHost.replace(/^api\./, "");
374
- return `${this.sandboxId}-${port}.sandbox.${baseHost}`;
381
+ async getHost(port, opts) {
382
+ const { hostname } = await SandboxClient.exposeSandboxPort(this.sandboxId, port, this.resolveOpts(opts));
383
+ return hostname;
375
384
  }
376
385
  resolveOpts(opts) {
377
386
  return { ...this.connectionConfig, ...opts };
@@ -411,7 +420,7 @@ var Execution = class {
411
420
  var CODE_INTERPRETER_PORT = 8080;
412
421
  var CodeSandbox = class extends Sandbox {
413
422
  get serverUrl() {
414
- return `https://${this.getHost(CODE_INTERPRETER_PORT)}`;
423
+ return this.getHost(CODE_INTERPRETER_PORT).then((h) => `https://${h}`);
415
424
  }
416
425
  /**
417
426
  * Execute code in a persistent kernel.
@@ -446,7 +455,7 @@ var CodeSandbox = class extends Sandbox {
446
455
  const controller = new AbortController();
447
456
  const timer = opts?.timeoutMs ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
448
457
  try {
449
- const res = await fetch(`${this.serverUrl}/execute`, {
458
+ const res = await fetch(`${await this.serverUrl}/execute`, {
450
459
  method: "POST",
451
460
  headers: { "Content-Type": "application/json" },
452
461
  body: JSON.stringify(body),
@@ -506,7 +515,7 @@ var CodeSandbox = class extends Sandbox {
506
515
  * ```
507
516
  */
508
517
  async createContext(opts) {
509
- const res = await fetch(`${this.serverUrl}/contexts`, {
518
+ const res = await fetch(`${await this.serverUrl}/contexts`, {
510
519
  method: "POST",
511
520
  headers: { "Content-Type": "application/json" },
512
521
  body: JSON.stringify({
@@ -521,7 +530,7 @@ var CodeSandbox = class extends Sandbox {
521
530
  * List all active execution contexts in this sandbox.
522
531
  */
523
532
  async listContexts() {
524
- const res = await fetch(`${this.serverUrl}/contexts`);
533
+ const res = await fetch(`${await this.serverUrl}/contexts`);
525
534
  if (!res.ok) throw new Error(`Failed to list contexts: ${await res.text()}`);
526
535
  return res.json();
527
536
  }
@@ -530,7 +539,7 @@ var CodeSandbox = class extends Sandbox {
530
539
  */
531
540
  async deleteContext(context) {
532
541
  const id = typeof context === "string" ? context : context.id;
533
- const res = await fetch(`${this.serverUrl}/contexts/${id}`, { method: "DELETE" });
542
+ const res = await fetch(`${await this.serverUrl}/contexts/${id}`, { method: "DELETE" });
534
543
  if (!res.ok) throw new Error(`Failed to delete context: ${await res.text()}`);
535
544
  }
536
545
  /**
@@ -538,7 +547,7 @@ var CodeSandbox = class extends Sandbox {
538
547
  */
539
548
  async restartContext(context) {
540
549
  const id = typeof context === "string" ? context : context.id;
541
- const res = await fetch(`${this.serverUrl}/contexts/${id}/restart`, { method: "POST" });
550
+ const res = await fetch(`${await this.serverUrl}/contexts/${id}/restart`, { method: "POST" });
542
551
  if (!res.ok) throw new Error(`Failed to restart context: ${await res.text()}`);
543
552
  }
544
553
  static async create(templateOrOpts, opts) {
@@ -569,11 +578,61 @@ async function* readLines(body) {
569
578
  reader.releaseLock();
570
579
  }
571
580
  }
581
+
582
+ // src/volume/index.ts
583
+ var Volume = class _Volume {
584
+ constructor(opts) {
585
+ this.volumeId = opts.volumeId;
586
+ this.config = new ConnectionConfig(opts);
587
+ }
588
+ static async create(projectId, name, opts) {
589
+ const config = new ConnectionConfig(opts);
590
+ const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
591
+ method: "POST",
592
+ headers: config.headers,
593
+ body: JSON.stringify({ name, sizeGb: opts?.sizeGb ?? 5 })
594
+ });
595
+ if (!res.ok) await handleApiError(res);
596
+ const vol = await res.json();
597
+ return new _Volume({ volumeId: vol.id, ...opts });
598
+ }
599
+ static async get(projectId, volumeId, opts) {
600
+ const config = new ConnectionConfig(opts);
601
+ const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${volumeId}`, {
602
+ headers: config.headers
603
+ });
604
+ if (!res.ok) await handleApiError(res);
605
+ return new _Volume({ volumeId, ...opts });
606
+ }
607
+ static async list(projectId, opts) {
608
+ const config = new ConnectionConfig(opts);
609
+ const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
610
+ headers: config.headers
611
+ });
612
+ if (!res.ok) await handleApiError(res);
613
+ return res.json();
614
+ }
615
+ async getInfo(projectId) {
616
+ const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
617
+ headers: this.config.headers
618
+ });
619
+ if (!res.ok) await handleApiError(res);
620
+ return res.json();
621
+ }
622
+ async delete(projectId) {
623
+ const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
624
+ method: "DELETE",
625
+ headers: this.config.headers
626
+ });
627
+ if (!res.ok) await handleApiError(res);
628
+ }
629
+ };
572
630
  export {
573
631
  AuthenticationError,
574
632
  CodeSandbox,
575
633
  LizardError,
576
634
  NotFoundError,
577
635
  Sandbox,
578
- TimeoutError
636
+ TimeoutError,
637
+ Volume
579
638
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lizard-build/sdk",
3
- "version": "0.1.6",
3
+ "version": "0.1.15",
4
4
  "description": "Lizard SDK — cloud sandboxes for AI agents",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -29,6 +29,12 @@
29
29
  "firecracker"
30
30
  ],
31
31
  "license": "Apache-2.0",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/lizard-build/lizard-sdk.git",
35
+ "directory": "packages/js"
36
+ },
37
+ "homepage": "https://lizard.build",
32
38
  "devDependencies": {
33
39
  "@types/node": "^20.0.0",
34
40
  "tsup": "^8.0.0",