@lizard-build/sdk 0.1.22 → 0.1.24

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.d.ts CHANGED
@@ -177,12 +177,13 @@ declare class SandboxClient {
177
177
  *
178
178
  * Each sandbox is a full Linux environment with its own filesystem, network,
179
179
  * and process namespace. Sandboxes are spun up from templates and can be
180
- * paused to a snapshot, then resumed instantly — perfect for stateful AI
181
- * agent sessions or ephemeral code execution.
180
+ * paused — vCPUs frozen, memory and running processes kept — then resumed
181
+ * instantly, perfect for stateful AI agent sessions or ephemeral code
182
+ * execution.
182
183
  *
183
184
  * @example Basic usage:
184
185
  * ```ts
185
- * import { Sandbox } from 'lizard'
186
+ * import { Sandbox } from '@lizard-build/sdk'
186
187
  *
187
188
  * const sandbox = await Sandbox.create('base', { project: 'my-project' })
188
189
  * await sandbox.fs.write('/app/index.js', 'console.log("hello world")')
@@ -245,8 +246,8 @@ declare class Sandbox extends SandboxClient {
245
246
  /**
246
247
  * Create a new Lizard sandbox from the specified template.
247
248
  *
248
- * Available templates: `base` (Debian + Node.js 20) and `code-interpreter-v1`
249
- * (Python 3.11 + Node.js 20). Custom templates can be built and pushed via
249
+ * Available templates: `base` (Debian + Node.js 26) and `code-interpreter-v1`
250
+ * (Python 3.14 + Node.js 26). Custom templates can be built and pushed via
250
251
  * `lizard push`.
251
252
  *
252
253
  * @param template Name of the sandbox template to boot from.
@@ -262,7 +263,7 @@ declare class Sandbox extends SandboxClient {
262
263
  * Connect to an existing sandbox by its ID.
263
264
  *
264
265
  * If the sandbox is currently paused, it will be automatically resumed
265
- * from its last snapshot before this call returns.
266
+ * before this call returns.
266
267
  *
267
268
  * @example
268
269
  * ```ts
@@ -286,16 +287,21 @@ declare class Sandbox extends SandboxClient {
286
287
  */
287
288
  kill(opts?: ConnectionOpts): Promise<boolean>;
288
289
  /**
289
- * Snapshot and pause the sandbox microVM.
290
+ * Pause the sandbox microVM by freezing its vCPUs.
290
291
  *
291
- * The sandbox state — memory, filesystem, and running processes — is saved
292
- * to a snapshot. Resume with `sandbox.resume()` or `Sandbox.connect(id)`.
292
+ * Memory, filesystem, and running processes are held in the host's RAM —
293
+ * nothing is written to disk, so a paused sandbox does not survive a host
294
+ * failure. Resume with `sandbox.resume()` or `Sandbox.connect(id)`.
295
+ *
296
+ * Pausing does not stop the timeout: a paused sandbox is still deleted at
297
+ * its original expiry (default 5 minutes). Pass `timeoutMs: 0` at create
298
+ * time to opt out of expiry.
293
299
  *
294
300
  * @returns `true` if paused successfully.
295
301
  */
296
302
  pause(opts?: ConnectionOpts): Promise<boolean>;
297
303
  /**
298
- * Resume a paused sandbox from its last snapshot.
304
+ * Resume a paused sandbox by unfreezing its vCPUs.
299
305
  *
300
306
  * @returns `true` if resumed successfully.
301
307
  */
@@ -327,47 +333,428 @@ declare class Sandbox extends SandboxClient {
327
333
  private resolveOpts;
328
334
  }
329
335
 
336
+ /** Shared HTTP helper for platform (non-sandbox) API calls. */
337
+ declare class PlatformClient {
338
+ readonly config: ConnectionConfig;
339
+ constructor(opts: ConnectionOpts);
340
+ get<T>(path: string): Promise<T>;
341
+ post<T>(path: string, body?: unknown): Promise<T>;
342
+ patch<T>(path: string, body: unknown): Promise<T>;
343
+ delete<T = void>(path: string, body?: unknown): Promise<T>;
344
+ postForm<T>(path: string, form: FormData): Promise<T>;
345
+ /** Stream SSE events from a path, calling handler for each data line. */
346
+ streamSse(path: string): AsyncGenerator<string>;
347
+ }
348
+
349
+ interface Project {
350
+ id: string;
351
+ name: string;
352
+ slug: string;
353
+ workspaceId: string;
354
+ createdAt?: string;
355
+ }
356
+ interface CreateProjectOpts {
357
+ workspaceId: string;
358
+ name: string;
359
+ }
360
+ declare class ProjectsAPI {
361
+ private readonly client;
362
+ constructor(client: PlatformClient);
363
+ /** List all projects the API key can access. */
364
+ list(opts?: {
365
+ workspaceId?: string;
366
+ }): Promise<Project[]>;
367
+ /** Get a project by ID. */
368
+ get(id: string): Promise<Project>;
369
+ /** Create a new project. */
370
+ create(opts: CreateProjectOpts): Promise<Project>;
371
+ /** Update a project's name. */
372
+ update(id: string, opts: {
373
+ name?: string;
374
+ }): Promise<Project>;
375
+ /** Delete a project. */
376
+ delete(id: string): Promise<void>;
377
+ }
378
+
379
+ interface Service {
380
+ id: string;
381
+ name: string;
382
+ projectId: string;
383
+ status: 'none' | 'running' | 'crashed' | 'stopped';
384
+ deployStatus: 'idle' | 'building' | 'deploying' | 'restarting' | 'failed' | 'deleting';
385
+ domain?: string;
386
+ region?: string;
387
+ sourceType?: 'github' | 'upload';
388
+ repoUrl?: string;
389
+ branch?: string;
390
+ startCommand?: string;
391
+ buildCommand?: string;
392
+ containerPort?: number;
393
+ }
394
+ interface CreateServiceOpts {
395
+ projectId: string;
396
+ name: string;
397
+ sourceType?: 'github' | 'upload';
398
+ repoUrl?: string;
399
+ branch?: string;
400
+ startCommand?: string;
401
+ buildCommand?: string;
402
+ containerPort?: number;
403
+ region?: string;
404
+ /** Set to 0 for worker mode (no HTTP listener). */
405
+ port?: number;
406
+ }
407
+ interface ScaleOpts {
408
+ replicas?: number;
409
+ cpuMillis?: number;
410
+ memoryMi?: number;
411
+ storageMi?: number;
412
+ }
413
+ interface LogLine {
414
+ level: 'info' | 'error' | 'warn' | 'debug';
415
+ message: string;
416
+ ts: number;
417
+ service?: string;
418
+ replica?: string;
419
+ }
420
+ interface DeployEvent {
421
+ event: 'log' | 'done' | 'error' | 'deployed' | 'failed' | 'deploying';
422
+ line?: string;
423
+ message?: string;
424
+ status?: string;
425
+ url?: string | null;
426
+ }
427
+ /**
428
+ * Handle for a running deploy — stream its logs or await completion.
429
+ *
430
+ * @example
431
+ * ```ts
432
+ * const deploy = await lizard.services.upload({ projectId, source: fs.readFileSync('app.tar.gz') })
433
+ * for await (const line of deploy.logs()) console.log(line)
434
+ * const result = await deploy.wait()
435
+ * console.log('deployed to', result.url)
436
+ * ```
437
+ */
438
+ declare class DeployHandle {
439
+ private readonly _serviceId;
440
+ private readonly _buildId;
441
+ private readonly _client;
442
+ constructor(client: PlatformClient, serviceId: string, buildId?: string);
443
+ get serviceId(): string;
444
+ /** Stream build + runtime log lines until the deploy finishes. */
445
+ logs(): AsyncGenerator<string>;
446
+ /**
447
+ * Poll until the deploy reaches a terminal state.
448
+ * @returns `{ url, status }` on success; throws `LizardError` on failure.
449
+ */
450
+ wait(opts?: {
451
+ timeoutMs?: number;
452
+ pollMs?: number;
453
+ }): Promise<{
454
+ url: string | null;
455
+ status: string;
456
+ }>;
457
+ }
458
+ declare class ServicesAPI {
459
+ private readonly client;
460
+ constructor(client: PlatformClient);
461
+ /** List all services in a project. */
462
+ list(opts: {
463
+ projectId: string;
464
+ }): Promise<Service[]>;
465
+ /** Get a service by ID. */
466
+ get(id: string): Promise<Service>;
467
+ /**
468
+ * Create a service and start a deploy from a git repo.
469
+ * Returns a DeployHandle to track progress.
470
+ */
471
+ deploy(opts: CreateServiceOpts & {
472
+ waitForDeploy?: boolean;
473
+ }): Promise<DeployHandle>;
474
+ /**
475
+ * Upload a tarball and deploy it.
476
+ *
477
+ * @param opts.source - A `Buffer`, `Blob`, or `Uint8Array` of a `.tar.gz` file.
478
+ */
479
+ upload(opts: {
480
+ projectId: string;
481
+ name: string;
482
+ source: Blob | string;
483
+ startCommand?: string;
484
+ buildCommand?: string;
485
+ port?: number;
486
+ region?: string;
487
+ }): Promise<DeployHandle>;
488
+ /** Trigger a redeploy (rebuild from current source). */
489
+ redeploy(id: string): Promise<DeployHandle>;
490
+ /** Restart a service without rebuilding. */
491
+ restart(id: string): Promise<void>;
492
+ /** Scale a service. */
493
+ scale(id: string, opts: ScaleOpts): Promise<void>;
494
+ /**
495
+ * Get recent log lines. For a live tail, use the WebSocket API instead.
496
+ *
497
+ * @param opts.limit - Max lines to return (default 200, max 1000).
498
+ */
499
+ logs(id: string, opts?: {
500
+ limit?: number;
501
+ since?: string;
502
+ }): Promise<LogLine[]>;
503
+ /** Execute a command inside the running service VM. */
504
+ exec(id: string, cmd: string, opts?: {
505
+ timeoutMs?: number;
506
+ }): Promise<{
507
+ stdout: string;
508
+ stderr: string;
509
+ exitCode: number;
510
+ }>;
511
+ /** Update service configuration. */
512
+ update(id: string, opts: Partial<Pick<Service, 'name' | 'startCommand' | 'buildCommand' | 'containerPort' | 'repoUrl' | 'branch' | 'sourceType'>>): Promise<Service>;
513
+ /** Delete a service. */
514
+ delete(id: string): Promise<void>;
515
+ }
516
+
517
+ type AddonType = 'postgres' | 'mysql' | 'mongodb' | 'redis' | 's3';
518
+ interface Addon {
519
+ id: string;
520
+ name: string;
521
+ type: AddonType;
522
+ projectId: string;
523
+ status: 'none' | 'running' | 'crashed' | 'stopped';
524
+ deployStatus: string;
525
+ version?: string;
526
+ /** Exposed connection variables (e.g. DATABASE_URL, REDIS_URL). */
527
+ env?: Record<string, string>;
528
+ }
529
+ interface CreateAddonOpts {
530
+ projectId: string;
531
+ type: AddonType;
532
+ name?: string;
533
+ version?: string;
534
+ /** vCPU count */
535
+ vcpu?: number;
536
+ /** Memory in MB */
537
+ memoryMb?: number;
538
+ /** Storage in GB */
539
+ storageGb?: number;
540
+ }
541
+ declare class AddonsAPI {
542
+ private readonly client;
543
+ constructor(client: PlatformClient);
544
+ /** List all addons in a project. */
545
+ list(opts: {
546
+ projectId: string;
547
+ }): Promise<Addon[]>;
548
+ /** Get an addon by ID. */
549
+ get(projectId: string, addonId: string): Promise<Addon>;
550
+ /**
551
+ * Create a new managed addon (database, cache, or object store).
552
+ *
553
+ * @example
554
+ * ```ts
555
+ * const pg = await lizard.addons.create({ projectId, type: 'postgres' })
556
+ * // Inject into a service:
557
+ * await lizard.secrets.set({ serviceId: svcId, key: 'DATABASE_URL', value: `${{${pg.name}.DATABASE_URL}}` })
558
+ * ```
559
+ */
560
+ create(opts: CreateAddonOpts): Promise<Addon>;
561
+ /** Delete an addon. */
562
+ delete(projectId: string, addonId: string): Promise<void>;
563
+ /** Resize an addon (CPU / memory / storage). */
564
+ resize(projectId: string, addonId: string, opts: {
565
+ vcpu?: number;
566
+ memoryMb?: number;
567
+ storageGb?: number;
568
+ }): Promise<Addon>;
569
+ /** Restart an addon VM. */
570
+ redeploy(projectId: string, addonId: string): Promise<void>;
571
+ }
572
+
573
+ interface Secret {
574
+ key: string;
575
+ value: string;
576
+ }
577
+ interface SetSecretOpts {
578
+ key: string;
579
+ value: string;
580
+ /** Target a specific service. Omit for project-scope. */
581
+ serviceId?: string;
582
+ /** If true, set at project scope (shared across all services). */
583
+ global?: boolean;
584
+ }
585
+ interface ListSecretsOpts {
586
+ serviceId?: string;
587
+ }
588
+ declare class SecretsAPI {
589
+ private readonly client;
590
+ constructor(client: PlatformClient);
591
+ /**
592
+ * List secrets for a project or service.
593
+ *
594
+ * @param projectId - The project ID.
595
+ * @param opts.serviceId - If given, list service-scoped secrets instead of project secrets.
596
+ */
597
+ list(projectId: string, opts?: ListSecretsOpts): Promise<Secret[]>;
598
+ /**
599
+ * Set one or more secrets.
600
+ *
601
+ * ```ts
602
+ * // Service-scoped secret (default):
603
+ * await lizard.secrets.set(projectId, { key: 'DATABASE_URL', value: '${{postgres.DATABASE_URL}}', serviceId })
604
+ *
605
+ * // Project-scoped (shared across all services):
606
+ * await lizard.secrets.set(projectId, { key: 'LOG_LEVEL', value: 'info', global: true })
607
+ * ```
608
+ */
609
+ set(projectId: string, secrets: SetSecretOpts | SetSecretOpts[]): Promise<void>;
610
+ /** Delete a secret by key. */
611
+ delete(projectId: string, opts: {
612
+ key: string;
613
+ serviceId?: string;
614
+ }): Promise<void>;
615
+ }
616
+
617
+ interface DomainInfo {
618
+ domain: string;
619
+ /** 'pending' until DNS propagates and the platform verifies the CNAME/TXT record. */
620
+ verified: boolean;
621
+ txtRecord?: string;
622
+ cnameTarget?: string;
623
+ }
624
+ declare class DomainsAPI {
625
+ private readonly client;
626
+ constructor(client: PlatformClient);
627
+ /**
628
+ * Show the current domain(s) for a service.
629
+ * The platform-assigned `.onlizard.com` subdomain is always present.
630
+ */
631
+ list(serviceId: string): Promise<DomainInfo[]>;
632
+ /**
633
+ * Attach a custom domain to a service.
634
+ * Returns the DNS records to add before calling `verify()`.
635
+ *
636
+ * @example
637
+ * ```ts
638
+ * const info = await lizard.domains.add(serviceId, 'api.example.com')
639
+ * console.log('Add CNAME:', info.cnameTarget)
640
+ * ```
641
+ */
642
+ add(serviceId: string, domain: string): Promise<DomainInfo>;
643
+ /**
644
+ * Verify that DNS records have propagated and activate the domain.
645
+ * Call after adding the CNAME or TXT record returned by `add()`.
646
+ */
647
+ verify(serviceId: string, domain: string): Promise<DomainInfo>;
648
+ }
649
+
650
+ type MetricRange = '1h' | '6h' | '24h' | '7d' | '14d' | '30d';
651
+ interface MetricPoint {
652
+ t: number;
653
+ value: number;
654
+ }
655
+ interface ServiceMetrics {
656
+ cpu: MetricPoint[];
657
+ memory: MetricPoint[];
658
+ networkRx: MetricPoint[];
659
+ networkTx: MetricPoint[];
660
+ diskRead: MetricPoint[];
661
+ diskWrite: MetricPoint[];
662
+ }
663
+ interface CostMetrics {
664
+ compute: number;
665
+ egress: number;
666
+ storage: number;
667
+ total: number;
668
+ currency: string;
669
+ }
670
+ declare class MetricsAPI {
671
+ private readonly client;
672
+ constructor(client: PlatformClient);
673
+ /** Get CPU metrics for a service or addon. */
674
+ cpu(id: string, range?: MetricRange): Promise<MetricPoint[]>;
675
+ /** Get memory metrics for a service or addon. */
676
+ memory(id: string, range?: MetricRange): Promise<MetricPoint[]>;
677
+ /** Get network I/O metrics for a service. */
678
+ network(id: string, range?: MetricRange): Promise<{
679
+ rx: MetricPoint[];
680
+ tx: MetricPoint[];
681
+ }>;
682
+ /** Get disk I/O metrics for a service. */
683
+ disk(id: string, range?: MetricRange): Promise<{
684
+ read: MetricPoint[];
685
+ write: MetricPoint[];
686
+ }>;
687
+ /**
688
+ * Get cost breakdown for a project over the given range.
689
+ * Costs are in USD cents unless the `currency` field says otherwise.
690
+ */
691
+ cost(projectId: string, range?: MetricRange): Promise<CostMetrics>;
692
+ /**
693
+ * Convenience: fetch all metric types for a service in one call.
694
+ */
695
+ all(id: string, range?: MetricRange): Promise<ServiceMetrics>;
696
+ }
697
+
330
698
  interface LizardOpts extends ConnectionOpts {
331
699
  /**
332
700
  * The project every sandbox created through this client belongs to — its ID,
333
- * slug, or name. Required: sandboxes are billed per project, so a project-less
334
- * sandbox cannot be created.
701
+ * slug, or name. Required for sandbox operations; optional for platform
702
+ * management (projects, services, addons, etc.).
335
703
  */
336
- project: string;
704
+ project?: string;
337
705
  }
338
706
  /**
339
- * The Lizard client — the entry point for creating sandboxes.
707
+ * The Lizard client — entry point for sandboxes and platform management.
340
708
  *
341
- * A client is pinned to one project (billing is metered per project), so every
342
- * sandbox it creates is attributed correctly. The project reference — ID, slug,
343
- * or name — is resolved to a project ID on first use and cached.
344
- *
345
- * @example
709
+ * @example Sandbox usage (backward-compatible)
346
710
  * ```ts
347
- * import { Lizard } from '@lizard-build/sdk'
348
- *
349
- * const lizard = new Lizard({ project: 'my-project' }) // apiKey from LIZARD_API_KEY
350
- *
711
+ * const lizard = new Lizard({ project: 'my-project' })
351
712
  * const sandbox = await lizard.create('base')
352
713
  * await sandbox.process.exec('echo hello')
353
714
  * await sandbox.kill()
354
715
  * ```
716
+ *
717
+ * @example Platform management
718
+ * ```ts
719
+ * const lizard = new Lizard({ apiKey: process.env.LIZARD_API_KEY })
720
+ *
721
+ * // Deploy from git
722
+ * const deploy = await lizard.services.deploy({ projectId, name: 'api', repoUrl: '...', branch: 'main' })
723
+ * const result = await deploy.wait()
724
+ * console.log('Deployed to', result.url)
725
+ *
726
+ * // Add a Postgres addon and wire it to the service
727
+ * const pg = await lizard.addons.create({ projectId, type: 'postgres' })
728
+ * await lizard.secrets.set(projectId, {
729
+ * serviceId: result.serviceId,
730
+ * key: 'DATABASE_URL',
731
+ * value: `${{${pg.name}.DATABASE_URL}}`,
732
+ * })
733
+ * ```
355
734
  */
356
735
  declare class Lizard {
357
736
  private readonly config;
358
737
  private readonly projectRef;
738
+ private _platform;
739
+ /** Manage projects. */
740
+ readonly projects: ProjectsAPI;
741
+ /** Deploy and manage services. */
742
+ readonly services: ServicesAPI;
743
+ /** Manage addons (postgres, redis, s3, mysql, mongodb). */
744
+ readonly addons: AddonsAPI;
745
+ /** Manage secrets and environment variables. */
746
+ readonly secrets: SecretsAPI;
747
+ /** Manage custom domains. */
748
+ readonly domains: DomainsAPI;
749
+ /** Query CPU, memory, network, disk, and cost metrics. */
750
+ readonly metrics: MetricsAPI;
359
751
  constructor(opts: LizardOpts);
360
752
  /** Resolve the client's project reference to a stable project ID (cached). */
361
753
  projectId(): Promise<string>;
362
754
  private connectionOpts;
363
755
  /**
364
756
  * Create a new sandbox in this client's project.
365
- *
366
- * @example
367
- * ```ts
368
- * const sandbox = await lizard.create('base')
369
- * const sandbox = await lizard.create('code-interpreter-v1', { timeoutMs: 600_000 })
370
- * ```
757
+ * @requires `project` to be set in the constructor.
371
758
  */
372
759
  create(template?: string, opts?: Omit<SandboxOpts, 'project' | 'projectId'>): Promise<Sandbox>;
373
760
  /** Connect to an existing sandbox by ID (resumes it if paused). */
@@ -578,4 +965,4 @@ declare class Volume {
578
965
  delete(projectId: string): Promise<void>;
579
966
  }
580
967
 
581
- export { AuthenticationError, type CodeContext, CodeSandbox, type ConnectionOpts, type CreateContextOpts, type CreateVolumeOpts, Execution, ExecutionError, type FileInfo, type FsOpts, Lizard, LizardError, type LizardOpts, NotFoundError, type ProcessOpts, type ProcessResult, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, TimeoutError, Volume, type VolumeInfo, resolveProjectId };
968
+ export { type Addon, type AddonType, AuthenticationError, type CodeContext, CodeSandbox, type ConnectionOpts, type CostMetrics, type CreateAddonOpts, type CreateContextOpts, type CreateProjectOpts, type CreateServiceOpts, type CreateVolumeOpts, type DeployEvent, DeployHandle, type DomainInfo, Execution, ExecutionError, type FileInfo, type FsOpts, Lizard, LizardError, type LizardOpts, type LogLine, type MetricPoint, type MetricRange, NotFoundError, type ProcessOpts, type ProcessResult, type Project, type RunCodeLanguage, type RunCodeOpts, Sandbox, type SandboxInfo, type SandboxOpts, type ScaleOpts, type Secret, type Service, type ServiceMetrics, type SetSecretOpts, TimeoutError, Volume, type VolumeInfo, resolveProjectId };