diff --git a/packages/js-sdk/src/index.ts b/packages/js-sdk/src/index.ts index 1a52e70e62..ee29f0f57d 100644 --- a/packages/js-sdk/src/index.ts +++ b/packages/js-sdk/src/index.ts @@ -54,6 +54,7 @@ export type { SandboxNetworkOpts, SandboxLifecycle, SandboxInfoLifecycle, + SnapshotCreateOpts, SnapshotInfo, SnapshotListOpts, SnapshotPaginator, diff --git a/packages/js-sdk/src/sandbox/index.ts b/packages/js-sdk/src/sandbox/index.ts index 7384dc7af2..f1a6e411db 100644 --- a/packages/js-sdk/src/sandbox/index.ts +++ b/packages/js-sdk/src/sandbox/index.ts @@ -21,6 +21,7 @@ import { SandboxPaginator, SandboxBetaCreateOpts, SandboxApiOpts, + SnapshotCreateOpts, SnapshotListOpts, SnapshotInfo, SnapshotPaginator, @@ -621,11 +622,11 @@ export class Sandbox extends SandboxApi { * const newSandbox = await Sandbox.create(snapshot.snapshotId) * ``` */ - async createSnapshot(opts?: SandboxApiOpts): Promise { - return await SandboxApi.createSnapshot( - this.sandboxId, - this.resolveApiOpts(opts) - ) + async createSnapshot(opts?: SnapshotCreateOpts): Promise { + return await SandboxApi.createSnapshot(this.sandboxId, { + ...this.resolveApiOpts(opts), + ...(opts?.name ? { name: opts.name } : {}), + }) } /** diff --git a/packages/js-sdk/src/sandbox/sandboxApi.ts b/packages/js-sdk/src/sandbox/sandboxApi.ts index f1bcf86bf2..b076ddd6d1 100644 --- a/packages/js-sdk/src/sandbox/sandboxApi.ts +++ b/packages/js-sdk/src/sandbox/sandboxApi.ts @@ -270,12 +270,33 @@ export interface SnapshotListOpts extends SandboxApiOpts { /** * Information about a snapshot. */ +/** + * Options for creating a snapshot. + */ +export interface SnapshotCreateOpts extends SandboxApiOpts { + /** + * Optional name for the snapshot template. + * If a snapshot template with this name already exists, a new build will + * be assigned to the existing template instead of creating a new one. + * + * When a name is provided, the returned `snapshotId` will use the + * namespaced format (e.g. `team-slug/my-snapshot:default`) which can be + * passed directly to `Sandbox.create()`. + */ + name?: string +} + export interface SnapshotInfo { /** * Snapshot identifier — template ID with tag, or namespaced name with tag (e.g. my-snapshot:latest). * Can be used with Sandbox.create() to create a new sandbox from this snapshot. */ snapshotId: string + /** + * Full names of the snapshot template including team namespace and tag + * (e.g. `team-slug/my-snapshot:v2`). + */ + names: string[] } /** @@ -687,7 +708,7 @@ export class SandboxApi { */ static async createSnapshot( sandboxId: string, - opts?: SandboxApiOpts + opts?: SnapshotCreateOpts ): Promise { const config = new ConnectionConfig(opts) const client = new ApiClient(config) @@ -698,7 +719,9 @@ export class SandboxApi { sandboxID: sandboxId, }, }, - body: {}, + body: { + ...(opts?.name ? { name: opts.name } : {}), + }, signal: config.getSignal(opts?.requestTimeoutMs), }) @@ -713,6 +736,7 @@ export class SandboxApi { return { snapshotId: res.data!.snapshotID, + names: res.data!.names, } } @@ -1038,6 +1062,7 @@ export class SnapshotPaginator extends BasePaginator { return (res.data ?? []).map( (snapshot: components['schemas']['SnapshotInfo']) => ({ snapshotId: snapshot.snapshotID, + names: snapshot.names, }) ) }