Skip to content

feat(templates): template list pagination via GET /v2/templates#1479

Open
huv1k wants to merge 3 commits into
mainfrom
templates-list-pagination-for-cli-en-603
Open

feat(templates): template list pagination via GET /v2/templates#1479
huv1k wants to merge 3 commits into
mainfrom
templates-list-pagination-for-cli-en-603

Conversation

@huv1k

@huv1k huv1k commented Jun 24, 2026

Copy link
Copy Markdown
Member

Summary

Adds support for listing templates with pagination via the new GET /v2/templates endpoint (added to spec/openapi.yml, clients regenerated). The JS and Python SDKs gain a Template.list() paginator (TemplatePaginator / AsyncTemplatePaginator, yielding TemplateInfo) mirroring Sandbox.list(), and e2b template list now pages through results behind a new -l, --limit option (default 1000, 0 for no limit) with a "Showing first N…" hint. Pagination uses the limit/nextToken query params and the X-Next-Token response header, consistent with sandbox list. Covered by new unit tests (msw-based SDK test + mocked CLI test); minor version bump for all three packages via changeset.

Usage

CLI:

e2b template list                 # all templates (paginated under the hood)
e2b template list --limit 20      # cap at 20, prints a "Showing first 20…" hint
e2b template list --limit 0 -f json

JS SDK:

import { Template } from 'e2b'

const paginator = Template.list({ limit: 100 })
while (paginator.hasNext) {
  const templates = await paginator.nextItems()
  console.log(templates)
}

Python SDK:

from e2b import Template  # or AsyncTemplate

paginator = Template.list(limit=100)
while paginator.has_next:
    for t in paginator.next_items():
        print(t.template_id)

Add a paginated `GET /v2/templates` endpoint to the spec and expose it
across all packages:

- JS SDK: `Template.list()` -> `TemplatePaginator` returning `TemplateInfo`,
  matching `Sandbox.list()`.
- Python SDK: `Template.list()` / `AsyncTemplate.list()` ->
  `TemplatePaginator` / `AsyncTemplatePaginator` (sync + async).
- CLI: `e2b template list` pages through templates via the SDK paginator
  and adds a `-l, --limit` option (default 1000, 0 for no limit).

Pagination uses `limit`/`nextToken` query params and the `X-Next-Token`
response header, consistent with `sandbox list`.
@linear-code

linear-code Bot commented Jun 24, 2026

Copy link
Copy Markdown

EN-603

@cla-bot cla-bot Bot added the cla-signed label Jun 24, 2026
@changeset-bot

changeset-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: df8f73c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@e2b/python-sdk Minor
e2b Minor
@e2b/cli Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Package Artifacts

Built from b2369d3. Download artifacts from this workflow run.

JS SDK (e2b@2.30.6-templates-list-pagination-for-cli-en-603.0):

npm install ./e2b-2.30.6-templates-list-pagination-for-cli-en-603.0.tgz

CLI (@e2b/cli@2.12.3-templates-list-pagination-for-cli-en-603.0):

npm install ./e2b-cli-2.12.3-templates-list-pagination-for-cli-en-603.0.tgz

Python SDK (e2b==2.29.5+templates-list-pagination-for-cli-en-603):

pip install ./e2b-2.29.5+templates.list.pagination.for.cli.en.603-py3-none-any.whl

@huv1k huv1k marked this pull request as ready for review June 24, 2026 13:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 760d988327

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/commands/template/list.ts Outdated
Template.list builds its own ConnectionConfig, so passing only teamId/limit
left config-file logins (e2b auth login) unauthenticated. Resolve the API key
via ensureAPIKey() and pass it to the paginator, mirroring sandbox list. This
also fixes the delete/publish --select flows.
Comment thread packages/cli/src/commands/template/list.ts

@mishushakov mishushakov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move template method to template and shared classes to utils

Comment on lines +96 to +100
/**
* Identifier of the team whose templates should be listed. Defaults to the
* team the API key belongs to.
*/
teamId?: string

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that makes no sense, API key is scoped per team, I cannot check templates for a different team with same API key

@@ -0,0 +1,185 @@
import { ApiClient, components, handleApiError } from '../api'
import { ConnectionConfig } from '../connectionConfig'
import { BasePaginator, SandboxApiOpts } from '../sandbox/sandboxApi'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

importing anything from Sandbox here is no-bueno, if it's shared it should go to shared utils.ts

* }
* ```
*/
export class TemplatePaginator extends BasePaginator<TemplateInfo> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BasePaginator might not be re-usable here - its constructor opts are SandboxApiOpts
maybe you can make BasePaginator constructor more generic?

Comment on lines +137 to +139
if (!this.hasNext) {
throw new Error('No more items to fetch')
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check in other places in SDK - but not having next items should not raise any error - instead remove empty []

if that's the case elsewhere - add some comment that we'll be changing this

Comment on lines +162 to +182
return (res.data ?? []).map(
(template: components['schemas']['Template']) => ({
templateId: template.templateID,
buildId: template.buildID,
cpuCount: template.cpuCount,
memoryMB: template.memoryMB,
diskSizeMB: template.diskSizeMB,
public: template.public,
aliases: template.aliases ?? [],
names: template.names ?? [],
createdAt: new Date(template.createdAt),
updatedAt: new Date(template.updatedAt),
lastSpawnedAt: template.lastSpawnedAt
? new Date(template.lastSpawnedAt)
: null,
spawnCount: template.spawnCount,
buildCount: template.buildCount,
envdVersion: template.envdVersion,
createdBy: template.createdBy ?? null,
buildStatus: template.buildStatus,
})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just spread most of these

Comment on lines +174 to +175
if not self.has_next:
raise Exception("No more items to fetch")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as in JS

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

everything I said above applies here

from e2b.template.main import TemplateBase, TemplateClass
from e2b.template.types import BuildInfo, InstructionType, TemplateTag, TemplateTagInfo
from e2b.template.utils import normalize_build_arguments, read_dockerignore
from e2b.sandbox_async.paginator import AsyncTemplatePaginator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

importing from sandbox here is no-bueno

from .sandbox_async.paginator import (
AsyncSandboxPaginator,
AsyncSnapshotPaginator,
AsyncTemplatePaginator,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no bueno

throw err
}

this.updatePagination(res.response)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a particular reason we have this method in the JS SDK but not in Python?

@mishushakov

Copy link
Copy Markdown
Member

also, no tests for the Python SDKs?

@mishushakov mishushakov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more CLI feedback

export const listCommand = new commander.Command('list')
.description('list sandbox templates')
.alias('ls')
.addOption(teamOption)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this option should be prob deprecated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make it integration test instead, not mock

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here - no mock pls

Comment on lines +42 to +44
console.log(
`Showing first ${limit} templates. Use --limit to change.`
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for this, our users can count

Comment on lines +171 to +173
// Adapt the SDK's TemplateInfo back to the raw API schema shape the rest of the
// CLI (table rendering, selection prompts, `--format json`) is built around.
function toTemplateSchema(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it actually an issue?

import { teamOption } from '../../options'
import { handleE2BRequestError } from '../../utils/errors'

const DEFAULT_LIMIT = 1000

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine for now to just return the whole list, auto-paginate should be cheap op.
the reason is that ppl pipe the CLI output into other tools and we don't have a good way to paginate in the CLI - perhaps next task to figure out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants