Skip to content
27 changes: 27 additions & 0 deletions .changeset/snapshot-list-name-filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
"e2b": minor
"@e2b/python-sdk": minor
---

Add a `name` filter to `Sandbox.listSnapshots()` / `Sandbox.list_snapshots()`.

The filter accepts a snapshot name or ID, optionally tag-qualified (e.g.
`"my-snapshot"`, `"my-team/my-snapshot"` or `"my-snapshot:v1"`). Unknown names
return an empty list rather than an error. It can be combined with the existing
`sandboxId` / `sandbox_id` filter (results must match both).

```ts
// JS/TS
const paginator = Sandbox.listSnapshots({ name: 'my-snapshot' })
const snapshots = await paginator.nextItems()
```

```python
# Python (sync)
paginator = Sandbox.list_snapshots(name="my-snapshot")
snapshots = paginator.next_items()

# Python (async)
paginator = AsyncSandbox.list_snapshots(name="my-snapshot")
snapshots = await paginator.next_items()
```
1 change: 1 addition & 0 deletions packages/js-sdk/src/api/schema.gen.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions packages/js-sdk/src/sandbox/sandboxApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,12 @@ export interface SnapshotListOpts extends Omit<SandboxApiOpts, 'signal'> {
*/
sandboxId?: string

/**
* Filter snapshots by name or ID, optionally tag-qualified
* (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1").
*/
name?: string

/**
* Number of snapshots to return per page.
*
Expand Down Expand Up @@ -1335,11 +1341,13 @@ export class SandboxPaginator extends Paginator<SandboxInfo, SandboxApiOpts> {
*/
export class SnapshotPaginator extends Paginator<SnapshotInfo, SandboxApiOpts> {
private readonly sandboxId?: string
private readonly name?: string

constructor(opts?: SnapshotListOpts) {
super(opts, opts?.limit, opts?.nextToken)

this.sandboxId = opts?.sandboxId
this.name = opts?.name
}

async nextItems(opts?: SandboxApiOpts): Promise<SnapshotInfo[]> {
Expand All @@ -1354,6 +1362,7 @@ export class SnapshotPaginator extends Paginator<SnapshotInfo, SandboxApiOpts> {
params: {
query: {
sandboxID: this.sandboxId,
name: this.name,
limit: this.limit,
nextToken: this.nextToken,
},
Expand Down
28 changes: 28 additions & 0 deletions packages/js-sdk/tests/sandbox/snapshot-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,34 @@ sandboxTest.skipIf(isDebug)(
}
)

sandboxTest.skipIf(isDebug)(
'list snapshots filtered by name',
async ({ sandbox, sandboxTestId }) => {
const snapshotName = `snap-filter-${sandboxTestId}`

const snapshot = await sandbox.createSnapshot({ name: snapshotName })

try {
// Filtering by the snapshot name should return the snapshot
const paginator = Sandbox.listSnapshots({ name: snapshotName })
const snapshots = await paginator.nextItems()

const found = snapshots.find((s) => s.snapshotId === snapshot.snapshotId)
assert.isDefined(found)

// Filtering by an unknown name should return an empty list
const emptyPaginator = Sandbox.listSnapshots({
name: `${snapshotName}-does-not-exist`,
})
const emptySnapshots = await emptyPaginator.nextItems()
assert.isArray(emptySnapshots)
assert.equal(emptySnapshots.length, 0)
} finally {
await Sandbox.deleteSnapshot(snapshot.snapshotId)
}
}
)

sandboxTest.skipIf(isDebug)('delete snapshot', async ({ sandbox }) => {
const snapshot = await sandbox.createSnapshot()

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/python-sdk/e2b/sandbox/sandbox_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,10 +606,12 @@ def __init__(
sandbox_id: Optional[str] = None,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
):
super().__init__(limit=limit, next_token=next_token, **opts)
self.sandbox_id = sandbox_id
self.name = name


class SandboxPaginatorBase(PaginatorBase[SandboxInfo, ApiParams]):
Expand Down
9 changes: 9 additions & 0 deletions packages/python-sdk/e2b/sandbox_async/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,13 +771,15 @@ def list_snapshots(
self,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> AsyncSnapshotPaginator:
"""
List snapshots for this sandbox.

:param limit: Maximum number of snapshots to return per page
:param next_token: Token for pagination
:param name: Filter snapshots by name or ID, optionally tag-qualified (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1")

:return: Paginator for listing snapshots
"""
Expand All @@ -789,6 +791,7 @@ def list_snapshots(
sandbox_id: Optional[str] = None,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> AsyncSnapshotPaginator:
"""
Expand All @@ -797,6 +800,7 @@ def list_snapshots(
:param sandbox_id: Filter snapshots by source sandbox ID
:param limit: Maximum number of snapshots to return per page
:param next_token: Token for pagination
:param name: Filter snapshots by name or ID, optionally tag-qualified (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1")

:return: Paginator for listing snapshots
"""
Expand All @@ -807,18 +811,21 @@ def list_snapshots(
self,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> AsyncSnapshotPaginator:
"""
List snapshots for this sandbox.

:param limit: Maximum number of snapshots to return per page
:param next_token: Token for pagination
:param name: Filter snapshots by name or ID, optionally tag-qualified (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1")

:return: Paginator for listing snapshots
"""
return AsyncSnapshotPaginator(
sandbox_id=self.sandbox_id,
name=name,
limit=limit,
next_token=next_token,
**self.connection_config.get_api_params(**opts),
Expand All @@ -829,10 +836,12 @@ def _cls_list_snapshots(
sandbox_id: Optional[str] = None,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> AsyncSnapshotPaginator:
return AsyncSnapshotPaginator(
sandbox_id=sandbox_id,
name=name,
limit=limit,
next_token=next_token,
**opts,
Expand Down
1 change: 1 addition & 0 deletions packages/python-sdk/e2b/sandbox_async/paginator.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ async def next_items(self, **opts: Unpack[ApiParams]) -> List[SnapshotInfo]:
res = await get_snapshots.asyncio_detailed(
client=api_client,
sandbox_id=self.sandbox_id if self.sandbox_id else UNSET,
name=self.name if self.name else UNSET,
limit=self.limit if self.limit else UNSET,
next_token=self._next_token if self._next_token else UNSET,
)
Expand Down
9 changes: 9 additions & 0 deletions packages/python-sdk/e2b/sandbox_sync/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,13 +761,15 @@ def list_snapshots(
self,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> SnapshotPaginator:
"""
List snapshots for this sandbox.

:param limit: Maximum number of snapshots to return per page
:param next_token: Token for pagination
:param name: Filter snapshots by name or ID, optionally tag-qualified (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1")

:return: Paginator for listing snapshots
"""
Expand All @@ -779,6 +781,7 @@ def list_snapshots(
sandbox_id: Optional[str] = None,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> SnapshotPaginator:
"""
Expand All @@ -787,6 +790,7 @@ def list_snapshots(
:param sandbox_id: Filter snapshots by source sandbox ID
:param limit: Maximum number of snapshots to return per page
:param next_token: Token for pagination
:param name: Filter snapshots by name or ID, optionally tag-qualified (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1")

:return: Paginator for listing snapshots
"""
Expand All @@ -797,18 +801,21 @@ def list_snapshots(
self,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> SnapshotPaginator:
"""
List snapshots for this sandbox.

:param limit: Maximum number of snapshots to return per page
:param next_token: Token for pagination
:param name: Filter snapshots by name or ID, optionally tag-qualified (e.g. "my-snapshot", "my-team/my-snapshot" or "my-snapshot:v1")

:return: Paginator for listing snapshots
"""
return SnapshotPaginator(
sandbox_id=self.sandbox_id,
name=name,
limit=limit,
next_token=next_token,
**self.connection_config.get_api_params(**opts),
Expand All @@ -819,10 +826,12 @@ def _cls_list_snapshots(
sandbox_id: Optional[str] = None,
limit: Optional[int] = None,
next_token: Optional[str] = None,
name: Optional[str] = None,
**opts: Unpack[ApiParams],
) -> SnapshotPaginator:
return SnapshotPaginator(
sandbox_id=sandbox_id,
name=name,
limit=limit,
next_token=next_token,
**opts,
Expand Down
1 change: 1 addition & 0 deletions packages/python-sdk/e2b/sandbox_sync/paginator.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def next_items(self, **opts: Unpack[ApiParams]) -> List[SnapshotInfo]:
res = get_snapshots.sync_detailed(
client=api_client,
sandbox_id=self.sandbox_id if self.sandbox_id else UNSET,
name=self.name if self.name else UNSET,
limit=self.limit if self.limit else UNSET,
next_token=self._next_token if self._next_token else UNSET,
)
Expand Down
Loading
Loading