Repository navigation
feat(cli): show the project ID in sandbox, snapshot and template lists #2124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@e2b/cli': patch | ||
| --- | ||
|
|
||
| `e2b sandbox list`, `e2b sandbox snapshot list` and `e2b template list` show the `prj_` ID of the project they list, as a `Project ID` column and as `projectID` in `--format json`. With `E2B_API_KEY`, where the key decides the project, it is left out. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,7 @@ import { Sandbox, SandboxInfo, SandboxListOrder, SandboxState } from 'e2b' | |
|
|
||
| import { z } from 'zod' | ||
|
|
||
| import { ensureAuth } from 'src/api' | ||
| import { Auth, ensureAuth, projectIdOf } from 'src/api' | ||
| import { Format, parseFormat } from 'src/options' | ||
| import { renderTable } from 'src/utils/table' | ||
| import { integer, zodParser } from 'src/validation' | ||
|
|
@@ -69,7 +69,9 @@ export const listCommand = new commander.Command('list') | |
| const state = options.state || ['running'] | ||
| const limit = | ||
| options.limit === 0 ? undefined : (options.limit ?? DEFAULT_LIMIT) | ||
| const { sandboxes, hasMore } = await listSandboxes({ | ||
| const auth = await ensureAuth() | ||
| const projectId = projectIdOf(auth) | ||
| const { sandboxes, hasMore } = await listSandboxes(auth, { | ||
| limit, | ||
| state, | ||
| metadata: options.metadata, | ||
|
|
@@ -79,15 +81,21 @@ export const listCommand = new commander.Command('list') | |
| }) | ||
|
|
||
| if (options.format === Format.PRETTY) { | ||
| renderSandboxTable(sandboxes, options.order) | ||
| renderSandboxTable(sandboxes, options.order, projectId) | ||
| if (hasMore) { | ||
| console.log( | ||
| `Showing first ${limit} sandboxes. Use --limit to change.` | ||
| ) | ||
| } | ||
| } else { | ||
| console.log( | ||
| JSON.stringify(sortSandboxes(sandboxes, options.order), null, 2) | ||
| JSON.stringify( | ||
| sortSandboxes(sandboxes, options.order).map((sandbox) => | ||
| projectId ? { ...sandbox, projectID: projectId } : sandbox | ||
| ), | ||
| null, | ||
| 2 | ||
| ) | ||
| ) | ||
| } | ||
| } catch (err: any) { | ||
|
|
@@ -126,7 +134,8 @@ export function buildTableRows( | |
|
|
||
| function renderSandboxTable( | ||
| sandboxes: SandboxInfo[], | ||
| order?: SandboxListOrder | ||
| order?: SandboxListOrder, | ||
| projectId?: string | ||
| ) { | ||
| if (!sandboxes?.length) { | ||
| console.log('No sandboxes found') | ||
|
|
@@ -144,6 +153,8 @@ function renderSandboxTable( | |
| { header: 'RAM MiB', value: (row) => String(row.memoryMB) }, | ||
| { header: 'Envd version', value: (row) => row.envdVersion }, | ||
| { header: 'Metadata', value: (row) => row.metadata }, | ||
| // Omitted with E2B_API_KEY, where the CLI doesn't know the key's project. | ||
| ...(projectId ? [{ header: 'Project ID', value: () => projectId }] : []), | ||
|
Comment on lines
155
to
+157
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 nit (optional): With a login, every Why this was flaggedTrigger: a logged-in user (access-token auth, so projectIdOf returns a prj_ ID) runs Verification: In packages/cli/src/utils/table.ts, renderTable leaves only the last cell unpadded. In list.ts:155-157, the new Project ID column is added after |
||
| ]) | ||
| } | ||
|
|
||
|
|
@@ -161,16 +172,17 @@ type ListSandboxesResult = { | |
| hasMore: boolean | ||
| } | ||
|
|
||
| async function listSandboxes({ | ||
| limit, | ||
| state, | ||
| metadata, | ||
| template, | ||
| startedAfter, | ||
| order, | ||
| }: ListSandboxesOptions = {}): Promise<ListSandboxesResult> { | ||
| const auth = await ensureAuth() | ||
|
|
||
| async function listSandboxes( | ||
| auth: Auth, | ||
| { | ||
| limit, | ||
| state, | ||
| metadata, | ||
| template, | ||
| startedAfter, | ||
| order, | ||
| }: ListSandboxesOptions = {} | ||
| ): Promise<ListSandboxesResult> { | ||
| let pageLimit = limit | ||
| if (!limit || limit > PAGE_LIMIT) { | ||
| pageLimit = PAGE_LIMIT | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -306,3 +306,22 @@ export async function pickProject( | |
| default: current?.workspace.id === chosen.id ? current : undefined, | ||
| }) | ||
| } | ||
|
|
||
| const TYPEID_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz' | ||
|
|
||
| /** | ||
| * The `prj_` public ID of a project UUID: the TypeID encoding workspace-api | ||
| * uses for `public_id`, computed locally so lists don't need `/v1/me`. | ||
| * Anything that isn't a UUID is returned as is. | ||
| */ | ||
| export function publicProjectId(id: string): string { | ||
| const hex = id.replace(/-/g, '') | ||
| if (!/^[0-9a-f]{32}$/i.test(hex)) return id | ||
|
|
||
| const value = BigInt(`0x${hex}`) | ||
| let suffix = '' | ||
| for (let i = 25; i >= 0; i--) { | ||
| suffix += TYPEID_ALPHABET[Number((value >> BigInt(5 * i)) & 31n)] | ||
| } | ||
| return `prj_${suffix}` | ||
| } | ||
|
Comment on lines
+310
to
+327
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. T-52 — the backend is the source of truth; client code must never mirror backend business rules, because a duplicated rule drifts from the server's the moment the API changes.
A compliant version uses the
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
projectIdfor SDK-shaped JSON recordsWhen access-token users run
sandbox list --format json, these records otherwise preserve the SDK's camel-casedSandboxInfofields (sandboxId,templateId), so emittingprojectIDmakes the new public field inconsistent and causes consumers using the expected.projectIdpath to miss it. The snapshot JSON path has the same issue atpackages/cli/src/commands/sandbox/snapshot.ts:107, where the existing identifier issnapshotId; useprojectIdfor these two SDK-shaped outputs while retainingprojectIDfor template API records.Useful? React with 👍 / 👎.