@e2b/cli@2.15.1
1782 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4fcf7cb150 |
feat: sync API specs from infra and belt with Copybara (#1564)
The specs in `spec/` were copied from their source repos by hand and had
drifted ~2,400 lines behind infra, so they are now imported with
Copybara (`copy.bara.sky`, run in a pinned Docker image by
`scripts/fetch-spec.sh`): `make codegen` re-fetches them at the commits
pinned in `spec/infra-ref` and `spec/belt-ref` before generating, and
the generated-files CI check fails if the tracked copies don't match the
pins. Regenerating from the current pins picks up the accumulated spec
changes in the generated JS/Python clients (renamed request schemas,
`SandboxNetworkConfig`, `SandboxIam` workload identity,
`FILE_TYPE_SYMLINK`, access-token auth deprecation, volume path-metadata
tweaks). The one handwritten SDK change follows from that: the public
`FileType` enums gain a `SYMLINK` member (JS and both Python surfaces)
so entries envd reports as symlinks show up in `files.list()` and
`getInfo()`/`get_info()` instead of being silently skipped as unknown
types. The custom `spec/remove_extra_tags.py` tag-filtering script is
replaced by Redocly CLI's `filter-in` decorator (`redocly.yaml`), which
produces identical generated JS output; a `filter-out` decorator
additionally drops any operation or component schema the upstream specs
mark `x-not-implemented: true` (currently the SOCKS5
`SandboxEgressProxyConfig`/`egressProxy` surface, which infra flagged as
spec-only); each SDK's bundle now goes to its own gitignored
`spec/openapi_generated.<api>.yml` instead of both pipelines overwriting
one shared file; Python client models now list fields in spec order
instead of alphabetical (mechanical reordering only — construct models
with keyword args). Spec fetches try whatever GitHub token is available
and fall back to the tracked copies with a warning (the public infra
specs also fetch anonymously); in CI a short-lived belt-scoped token is
minted from the org-wide Autofixer GitHub App (no new secrets), so fork
PRs simply fall back for the belt spec; the CI workflows also cache the
Copybara image alongside the codegen image, and the previously ignored
`CODEGEN_IMAGE` env is honored by the Makefile.
## Usage
```sh
# update the specs: bump a pin, then regenerate
echo <infra-commit-sha> > spec/infra-ref
make codegen
# fetch a single spec without regenerating
pnpm fetch:api-spec # spec/openapi.yml from infra
pnpm fetch:envd-spec # spec/envd/ from infra
pnpm fetch:volume-spec # spec/openapi-volumecontent.yml from belt
# try the latest spec without touching the pin
E2B_INFRA_REF=main pnpm fetch:api-spec
# change which endpoint tags an SDK exposes
$EDITOR redocly.yaml && make codegen
```
```ts
// symlinks are now visible in the filesystem API (JS; same shape in Python)
const entries = await sandbox.files.list('/home/user')
const link = entries.find((e) => e.type === FileType.SYMLINK)
console.log(link?.symlinkTarget)
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
ada1744cf1 |
test(js-sdk): run the template test suite on Bun (#1600)
## Description Adds `--project template` to `test:bun` so the Bun CI leg runs the template suite, matching the Deno leg (#1595). No code changes are needed: the template suite previously failed under Bun because Bun's JavaScriptCore elides tail-call frames and the fixed-depth stack walk attributed build errors one frame past the user's call site (the workaround attempt in #1596 was closed in favor of #1599). With #1599's boundary-based frame selection (now merged), the suite passes under Bun as-is. The CI workflow already passes `E2B_API_KEY`/`E2B_DOMAIN` to the Bun leg, and the matrix comment (updated in #1595) already covers Bun re-running API-backed suites, so `package.json` is the only change. ## Testing Full `test:bun` (unit + connectionConfig + template) green locally on Bun 1.3.14 against the real API: 530 passed, 35 skipped, 0 failed — including all 34 stack-trace/caller-directory tests that pin exact user call-site line/columns, the frames Bun used to elide. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1ae3f92090 |
feat(js-sdk): run the full unit test suite in Cloudflare workerd (#1593)
## What Promotes `test:cf` from a single dist smoke test to the **full unit + connectionConfig suite running inside Cloudflare's workerd** (`@cloudflare/vitest-pool-workers`) — the same coverage `test:bun` and `test:deno` get. Locally: **74 files / 393 tests green** against prod sandboxes. The real-deploy suite (`test:cf:deploy`) is unchanged and keeps covering the built bundle on actual Cloudflare infrastructure (the pool can't reproduce bundling bugs like #1579). ## SDK fixes the suite surfaced 1. **Dropped-connection mapping for Workers** (`src/envd/rpc.ts`): workerd surfaces a sandbox connection drop as `Network connection lost`, which fell through to a cryptic `SandboxError`. It's now matched like the Node/Bun/Deno variants, so killing a sandbox mid-request surfaces as the health-checked `TimeoutError`: ```ts const cmd = await sandbox.commands.run('sleep 60', { background: true }) await sandbox.kill() await cmd.wait() // now rejects with TimeoutError('…sandbox was killed or reached its end of life…') on Workers too ``` 2. **Double connection release on stream cancel** (`src/connectionConfig.ts`): `wrapStreamWithConnectionCleanup` claimed its `release` was idempotent but had no guard — cancelling a streamed download while a read was in flight ran `cleanup()` twice (both the `cancel` callback and the pending `pull` resolving `done` fire). workerd's stream scheduling hits this deterministically; the pooled connection was double-released. Both are runtime-behavior fixes specific to the JS fetch/streams stack — no Python SDK equivalent applies. ## Test adjustments - **boot_id reads** in the two "filesystem-only pause" tests now use `commands.run('cat …')` instead of `files.read`: envd's non-gzip download path serves procfs files as an empty 200 (filed as e2b-dev/infra#3363 — Go `ServeContent` sizes them by stat, which is 0). Only clients that don't negotiate gzip (workerd's fetch) observe it; the command path sidesteps the bug while keeping the reboot assertion on all runtimes. - **runtime.test.ts** Node-host detection scenarios skip under workerd via the existing host guard (same treatment as Bun/Deno). - **Pool config filters expected unhandled-rejection shapes** via vitest's `onUnhandledError` (not the blanket `dangerouslyIgnoreUnhandledErrors`): workerd reports a rejection as unhandled unless a handler attaches within the same microtask drain — even inline `await expect(op()).rejects` trips it — and vitest never processes the `rejectionhandled` retraction on any runtime, so the suite's deliberate rejections false-positive ~60× per run. A diagnostic pairing `unhandledrejection` with `rejectionhandled` confirmed all of them are handled-late false positives (zero genuine leaks). The filter drops only the shapes the tests provoke (SDK error classes, `ConnectError`, `AbortError`, workerd's `Network connection lost.`, one test stub); unknown rejection shapes and uncaught exceptions still fail the run — verified with a planted never-handled `TypeError` (exit 1). ## CI Rebased onto #1588's per-runtime matrix: the `cloudflare` leg (already ubuntu-only there) now runs the full suite; no extra jobs added. The stale `tests/integration` exclude was dropped after #1591 removed that suite. ## Notes - Suite config needs `nodejs_compat_populate_process_env` + `E2B_API_KEY`/`E2B_DOMAIN` miniflare bindings so the SDK and tests read env like on Node. - The deleted `tests/runtimes/cloudflare/run.test.ts` (dist smoke) is fully subsumed: lifecycle coverage by the suite, bundle coverage by `test:cf:deploy` + `tests/bundle/edgeCompat.test.ts`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
3f46d56026 |
fix(sdk): select stack-trace frames by SDK boundary instead of fixed depth (#1599)
## Description Template build stack traces were captured by walking a fixed number of frames (`STACK_TRACE_DEPTH` plus `±1` arithmetic at ~15 call sites), which broke whenever the frame count between `new Error()` and user code shifted — TS class-field initializer frames (#1539) and Bun's tail-call frame elision were both this bug. This PR makes two related changes: 1. **Boundary-based frame selection.** The caller's frame is now the first one whose file lies outside the SDK package, making extra transpiler frames and elided delegating frames irrelevant. In the JS SDK, frame parsing is delegated to `error-stack-parser-es` (ESM-only, so it's a devDependency inlined into both dist formats via tsdown `noExternal` — the engines range includes Node versions without `require(esm)`); the Python SDK equivalently walks `f_back` until `co_filename` leaves the `e2b` package root, in the shared builder used by both sync and async. If no user frame is identifiable (e.g. the SDK is bundled into the caller's own file), capture degrades to no trace rather than a wrong frame. 2. **Dead machinery removed.** Because boundary capture resolves through SDK-internal delegation (`remove()` → `runCmd()`, `fromDockerfile()` → parser) to the user's call site on its own, the suppress/override collection machinery (`runInNewStackTraceContext`, `runInStackTraceOverrideContext`, the enabled/override flags, and their Python equivalents) became redundant and is removed — superseding the approach in #1596. Error `.stack` synthesis (keeping the `Name: message` header and the throw site on `cause`) was prototyped here and backed out — it will come as a follow-up PR. ## Usage No API changes — build errors now point at the user's call site regardless of runtime or transpiler: ```ts const template = Template() .fromBaseImage() .runCmd('./does-not-exist') // ← build failures point exactly here await Template.build(template, 'my-template') ``` ## Testing - JS: `unit` + `template` vitest projects green against the real API (incl. 27 per-method stacktrace tests pinning exact call-site line/columns, `bunInstall` now covered); edge-compat bundle test and CLI build verified; built CJS/ESM dists smoke-tested with `require()`/`import()`. - Python: all 184 template tests green (shared + sync + async, incl. both `test_stacktrace.py` suites, `bun_install` now covered); `ruff` and `ty` clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
00253c39cc |
feat(python-sdk): migrate envd RPC to the official connectrpc client (#1558)
Replaces the vendored `e2b_connect` client and the custom Go `protoc-gen-connect-python` plugin with the official Connect RPC client for Python ([`connectrpc`](https://github.com/connectrpc/connect-py), transport: `pyqwest`/Rust hyper), and switches the envd messages from Google's `protobuf` runtime to Buf's [`protobuf-py`](https://github.com/bufbuild/protobuf-py) (which `connectrpc` already requires) — the SDK no longer depends on the conflict-prone `protobuf` package at all, and the protoc binary drops out of the codegen image. The wire format (same protos, same JSON) is unchanged. Closing a command or watch stream early now sends `RST_STREAM`, fixing abandoned streams leaking on the shared HTTP/2 connection, and peer resets surface as typed `ConnectError`s. The plumbing mirrors the `e2b.api` layout: shared pieces (a JSON codec that ignores unknown response fields, proxy narrowing, pool tuning) live in `e2b/envd/client_shared.py`, the flavor-specific pyqwest transports (wrapped in pyqwest's retry middleware, see the retry note below) and `create_rpc_client` factories in `e2b/envd/client_sync/` and `e2b/envd/client_async/`, and the default-header/logging interceptors in `e2b/envd/interceptors.py`; `e2b/envd/rpc.py` maps `connectrpc` error codes onto the existing SDK exceptions, so the public API is unchanged (`sandbox.commands.run(...)`, `files.watch_dir(...)`, etc. work exactly as before). The REST API and file upload/download keep using `httpx`. The `proxy` connection option now applies to sandbox RPC calls too — [pyqwest 0.7.0](https://github.com/curioswitch/pyqwest/releases/tag/v0.7.0) added an httpx-style `proxy` parameter to its transports, so commands, PTY, and filesystem watch traffic follow the same proxy as the REST API and file transfers (an earlier revision of this PR could only fall back to `http_proxy`/`https_proxy` env vars for RPC): ```python sandbox = Sandbox.create(proxy="http://user:pass@localhost:8030") # REST *and* RPC (commands, PTY, watch) traffic goes through the proxy result = sandbox.commands.run("echo through-the-proxy") ``` Notes: - `e2b_connect` is no longer shipped in the wheel; code importing it directly should switch to `connectrpc` (`ConnectError`, `Code`) — SDK exception types are unchanged. - The generated `e2b.envd.*.*_pb2` modules are replaced by `protobuf-py` equivalents (`process_pb`, `filesystem_pb`) with a different message API (`Oneof` objects, `has_field`); these are internal modules — `e2b-code-interpreter` and `e2b-desktop` were verified not to import them. - RPC transports are cached per proxy URL. `httpx.URL` and `httpx.Proxy` proxies keep working for RPC calls when they reduce to a proxy URL (`httpx.Proxy` auth is folded back into the URL userinfo); `httpx.Proxy` extras that pyqwest can't express — custom headers, an `ssl_context` — raise `InvalidArgumentException` rather than being silently dropped. - Plain (non-Connect-encoded) HTTP error responses — an edge proxy or gateway answering for envd — keep the vendored client's status mapping even when they carry a JSON body that isn't a valid Connect error (e.g. a gateway's `{"code": 429}` raises `RateLimitException`, not a misleading sandbox-timeout); only JSON bodies with a valid Connect `code` string are left to connectrpc to parse. An envd response that fails to decode surfaces as a `SandboxException` with a clear message — the SDK's JSON codec raises a typed `ConnectError(INTERNAL)` at the source (connectrpc re-raises codec-raised `ConnectError`s unchanged), rather than the error being reconstructed from `__cause__` heuristics in the exception mapper. - pyqwest 0.7.0 explicit transports default to an **empty TLS root store** (0.6.2 used reqwest's defaults), so the envd transports pass `tls_include_system_certs=True`; the dependency floor is `pyqwest>=0.7.0` accordingly. - Connection retries (`E2B_CONNECTION_RETRIES`, default 3) use pyqwest's transport-level retry middleware (`pyqwest.middleware.retry`), narrowed to retry only the builtin `ConnectionError` — raised solely while establishing the connection, before the request could have reached envd — with exponential backoff. A retry can therefore never replay a delivered request, for unary and streaming RPCs alike; the previous stack's replay of unary calls whose connection dropped mid-request is dropped deliberately, since it could re-execute a delivered call (e.g. `SendInput`). Pinned by unit tests plus end-to-end tests driving the generated stubs through the middleware (`tests/test_envd_retry_transport.py`). - For async streaming calls (`commands.run`/`connect`, PTY, `watch_dir`), `request_timeout` bounds opening the stream — the wait until envd confirms with a start event, matching the JS SDK's `requestTimeoutMs` — raising `TimeoutException` and cancelling the HTTP/2 stream when exceeded (pinned frame-level in `tests/test_envd_stream_reset.py`). The running stream stays bounded by the command/watch `timeout`. The sync SDK cannot interrupt its blocking wait, so `request_timeout` is not applied to sync stream setup — both setup and the running stream are bounded by `timeout` (unlimited when `0`). - The RPC logging interceptor was upstreamed to pyqwest as a logging middleware ([curioswitch/pyqwest#192](https://github.com/curioswitch/pyqwest/pull/192)); the SDK keeps its own `LoggingInterceptor` until that merges and ships in a release the SDK can depend on. - `pyqwest` ships binary wheels for manylinux/musllinux (x86_64, aarch64), macOS arm64 + x86_64 (Intel wheels landed in 0.7.0), Windows x64, and PyPy. - The `RST_STREAM`-on-early-close behavior is pinned by frame-level regression tests (`tests/test_envd_stream_reset.py`): a plaintext HTTP/2 server records the frames the real generated clients (with the SDK's codec and interceptors) send — early close via `disconnect()`, close through the logging interceptor, and abandoning the stream must all send `RST_STREAM(CANCEL)`; normal completion must send none (sync + async). - `E2B_MAX_CONNECTIONS` no longer applies to sandbox RPC traffic: reqwest's pool bounds only idle connections per host (`E2B_KEEPALIVE_EXPIRY`, `E2B_MAX_KEEPALIVE_CONNECTIONS`), not the total number of open connections. It still applies to the REST API and file transfers. - The sync sandbox modules build one RPC client each and share it across threads — the connectrpc sync client is stateless per call over the process-global transport (verified with a 16-thread frame-level test); only the httpx envd API clients stay per-thread with their transports. - Also fixes numeric env-var parsing (`E2B_KEEPALIVE_EXPIRY`, `E2B_MAX_KEEPALIVE_CONNECTIONS`, `E2B_MAX_CONNECTIONS`, `E2B_CONNECTION_RETRIES`): an empty-string value now falls back to the default instead of raising `ValueError` at import time. |
||
|
|
5e141a765f |
fix(js-sdk): use commands.run in Sandbox.getHost() example (#1531) (#1550)
The JSDoc `@example` on the public `Sandbox.getHost()` method calls
`sandbox.commands.exec(...)`, but the `Commands` class has no `exec`
method. It
exposes `run`. Copy-pasting the documented snippet therefore throws:
```
TypeError: sandbox.commands.exec is not a function
```
### Where
`packages/js-sdk/src/sandbox/index.ts`, in the `getHost()` doc comment:
```ts
/**
* ...
* @example
* ```ts
* const sandbox = await Sandbox.create()
* // Start an HTTP server
* await sandbox.commands.exec('python3 -m http.server 3000') // <- no such method
* // Get the hostname of the HTTP server
* const serverURL = sandbox.getHost(3000)
* ```
*/
```
The `Commands` class (`packages/js-sdk/src/sandbox/commands/index.ts`)
exposes
`list`, `sendStdin`, `closeStdin`, `kill`, `connect`, and `run` (four
`run`
overloads), plus a private `start`. There is no `exec`. The correct
method here
is `run`, which is what every other example already uses, including the
sibling
`@example` in this same file (the `commands.run(...)` snippet a few
methods up)
and both Python SDK mirrors (`get_host` in `sandbox_sync/main.py` and
`sandbox_async/main.py` already use `commands.run`).
### Fix
One token, `exec` -> `run`:
```ts
- await sandbox.commands.exec('python3 -m http.server 3000')
+ await sandbox.commands.run('python3 -m http.server 3000')
```
Documentation only. No behavior or type change.
### Parity with the Python SDK
The repo guidelines ask that SDK changes be mirrored across the JS and
Python
SDKs. Here the Python `get_host` examples already use `commands.run`
correctly,
so this defect exists only in the JS SDK doc comment and no Python
change is
needed to reach parity.
### Tests
This is a JSDoc `@example` correction with no runtime code path to
exercise, so
it adds no test, matching the repo's existing precedent for
documentation-only
fixes (e.g. `.changeset/sandbox-list-docstring.md`, and merged doc-fix
PRs such
as #1511 / #1500 / #1260, none of which added a regression test).
Correctness is
that the example now names the real public API: after the change,
`commands.exec`
no longer appears anywhere in the SDK source, and `commands.run` matches
the
`Commands` class and the sibling examples.
Offline gates run locally (Node 20, pnpm 9.15.5):
```
pnpm --filter e2b run lint # oxlint, clean
pnpm --filter e2b run typecheck # tsc --noEmit, clean
pnpm --filter e2b run build # tsc + tsup, ESM/CJS/DTS built
prettier --check src/sandbox/index.ts # clean
```
A changeset (`e2b`, patch) is included.
---
## Linked issues
- None. There is no existing GitHub issue for this; it is a self-evident
public
doc-example defect (the documented snippet throws at runtime). Not
filing a
separate issue for a one-token doc fix.
## Pre-flight checklist (repo AGENTS.md / CLAUDE.md gates)
- [x] `pnpm run format` - `prettier --check` clean on the changed file
- [x] `pnpm run lint` - oxlint clean (exit 0)
- [x] `pnpm run typecheck` - tsc --noEmit clean (exit 0)
- [x] `pnpm run build` - tsc + tsup clean
- [x] Changeset generated - `.changeset/fix-gethost-example-command.md`
(`e2b`: patch)
- [x] Conventional Commit message (`fix(js-sdk): ...`, reuses `js-sdk`
scope)
- [ ] Test added - not applicable (doc-only `@example`; see Tests
section for precedent)
- [ ] DCO / CLA - no sign-off required by this repo; CLA is signed via
`@cla-bot`
on the PR after opening (as on prior PRs #1518 / #1519 / #1507)
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
Co-authored-by: Anas Khan <anxkhn28@gmail.com>
|
||
|
|
9ee4414e6d |
feat(js-sdk): run the template test suite on Deno (#1595)
## What Extends the Deno vitest run (#1585) with the `template` project and fixes the real runtime bug the suite surfaced. Split out of #1594 (Bun counterpart: #1596). ```jsonc // packages/js-sdk/package.json "test:deno": "deno run -A npm:vitest run --project unit --project connectionConfig --project template", ``` ## Bug — Deno: template uploads used chunked transfer encoding Deno's native `fetch` ignores an explicit `Content-Length` header on stream bodies and falls back to `Transfer-Encoding: chunked` — exactly the failure #1243 fixed for Node, since S3-compatible presigned PUT URLs reject chunked uploads with 501. `uploadFile` now streams the spooled archive through **undici's `fetch`** (via the existing `loadUndici()` helper — undici 8 where it imports, undici 7 on Bun, global `fetch` where undici isn't resolvable, e.g. bundled apps), which honors the `Content-Length` header on stream bodies on every runtime. One upload path, no runtime sniffing. Approaches rejected along the way, all verified empirically with 1GB uploads + RSS sampling: - **File-backed `Blob` body (`fs.openAsBlob`)** — lazy on Node/Bun, but Deno's shim reads the whole file into memory eagerly (denoland/deno#32316), and Bun infers an unstrippable MIME type from the extension whose `Content-Type` breaks presigned signatures (403 against production storage). - **`node:http(s)` on Deno** — works (and is memory-bounded), but can't be unified: Bun's `node:http` ignores abort signals, and it's a second code path. Known caveat: Deno's `Readable.toWeb` shim has no backpressure, so the archive is buffered in memory during upload on Deno (Node and Bun stream in lockstep with the socket). Filed upstream as denoland/deno#36275 — accepted as Deno's to fix rather than worked around here. As part of this, `tarFileStream` became `spoolTarArchive`, returning `{ path, size, cleanup }` with caller-owned cleanup instead of a self-deleting read stream. `tests/template/uploadFile.test.ts` also asserts no `Content-Type` header is sent. ## Python SDK parity Intentionally none: `upload_file` already sends a sized file body via httpx. ## Testing - Real template builds (`tests/template/build.test.ts`, against prod S3 presigned URLs) green under **Node, Deno, and Bun** - `uploadFile` + `spoolTarArchive` suites green under Node, Deno, and Bun - `tests/template/abortSignal.test.ts` green under Deno - `pnpm build`, `lint`, `typecheck`, `prettier --check` clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5417dd4f9f |
fix(deps): resolve all open Dependabot alerts (#1598)
## Summary Fixes all 8 open [Dependabot alerts](https://github.com/e2b-dev/E2B/security/dependabot), all in `pnpm-lock.yaml`: | Package | Severity | Alerts | Before | After | How | |---|---|---|---|---|---| | `@vitest/browser` | critical | #328 | 4.1.8 | 4.1.10 | updated the vitest family in js-sdk and cli devDeps (4.1.10 peer-requires `vitest@4.1.10` exactly) | | `tar` | critical/high/medium ×4 | #324–#327 | 7.5.16 | 7.5.21 | bumped the js-sdk runtime dep floor to `^7.5.19` + repo-wide override | | `sharp` | high | #329 | 0.34.5 | 0.35.3 | new override (pinned exactly by miniflare, dev-only) | | `shell-quote` | high | #323 | 1.8.4 | 1.10.0 | widened existing override (dev-only, via npm-run-all) | | `brace-expansion` | high | #322 | 2.1.0 | 2.1.2 | widened existing override | The only runtime-dependency change is `tar` in the js-sdk (used for template build contexts), so a patch changeset for `e2b` is included. The CLI bundles the SDK and its dependencies into `dist/index.js`, so the published CLI also ships the vulnerable `tar` — a patch changeset for `@e2b/cli` is included to rebundle it. Everything else is dev tooling or lockfile-only. ## Verification - `pnpm run lint` and `pnpm run typecheck` pass (the 7 python-sdk ty diagnostics pre-exist on main) - js-sdk: unit + connectionConfig (393 passed) and template projects (132 passed, exercises the new `tar` end-to-end against the real API) on vitest 4.1.10; `pnpm run build` clean - js-sdk `test:cf` passes — miniflare/workerd boots with sharp 0.35.3 - cli: full suite green (103 passed) on vitest 4.1.10 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
67bf112efc |
test(js-sdk): rename deprecated test.scoped() to test.override() (#1597)
vitest 4.1 deprecates `test.scoped()` in favor of `test.override()`, emitting 15 warnings during test collection in CI. This renames all `sandboxTest.scoped()` fixture overrides to `sandboxTest.override()` across the six affected test files (network, snapshot, internetAccess, secure, files/signing, commands/envVars). It's a pure rename — the vitest 4.1.8 types confirm an identical signature — and `vitest list` on all six files now collects with zero deprecation warnings. Test-only change, so no changeset. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e00503b090 |
fix(ci): recover release 30006966441 and retry lockfile update with backoff (#1589)
## What happened
Release run
[30006966441](https://github.com/e2b-dev/E2B/actions/runs/30006966441)
successfully published **e2b@2.35.3** and **@e2b/cli@2.15.0** to npm and
pushed both tags, but then failed on the **Update lock file** step:
`pnpm i` ran ~6 seconds after `npm publish` and the registry had not
propagated the new version yet (`ERR_PNPM_NO_MATCHING_VERSION: No
matching version found for e2b@^2.35.3 — the latest release of e2b is
"2.35.2"`). Because that step failed, the **Commit new versions** step
was skipped, leaving main with stale versions and unconsumed changesets.
Auditing the rest of the publish path for similar races also turned up a
long-dead step: the `@e2b/sdk` alias republish.
## Changes
**Commit 1 — replay the missing release commit.** Reproduces exactly
what the bot would have committed: `pnpm run version` (consumes the
three changesets, bumps js-sdk 2.35.2 → 2.35.3 and cli 2.14.0 → 2.15.0)
followed by `pnpm i --no-link --no-frozen-lockfile` (now succeeds — the
registry has long since propagated). The only commit that landed on main
after the release was dispatched
([
|
||
|
|
aa3c2593b9 |
test(js-sdk): remove unused integration test suite (#1591)
## Summary Removes `packages/js-sdk/tests/integration/` — the suite was never wired into CI: no workflow references `test:integration` or sets the `E2B_INTEGRATION_TEST` env var that gated every test. The tests were also stale, referencing hardcoded template IDs (`en716jw99aj63v1k8ugh`, `integration-test-v1`) that likely no longer exist and passing `timeoutMs: 120` (120 ms). Also removes the `test:integration` script, the `integration` vitest project, and the unused `isIntegrationTest` helper from `tests/setup.ts`. Test-only change, no changeset needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
2defe39bd7 |
feat(cli): rename team to project in ~/.e2b/config.json (#1570)
Bumps `~/.e2b/config.json` to `version: 2` and renames
`teamName`/`teamId`/`teamApiKey` to
`projectName`/`projectId`/`projectApiKey`. The rename is internal to the
config file format — all user-facing CLI output, flags (`--team`), and
env vars (`E2B_TEAM_ID`) still say "team", and API `teamID` parameters
are unchanged.
Existing v1 configs keep working: they are converted to the new format
in memory on read, and the file on disk is left untouched — the v2
format is only persisted through paths that write the config anyway
(login, `e2b auth configure`, token refresh), so older CLI versions can
still read the file in the meantime. Unrecognized configs are no longer
deleted either; the CLI treats them as signed out and `e2b auth login`
overwrites them. Tools that read the config file directly must handle
the new field names once the file is written in the v2 format.
## Usage
```jsonc
// ~/.e2b/config.json (fresh login, or any config write after upgrading)
{
"version": 2,
"projectName": "default",
"projectId": "team-id",
"projectApiKey": "e2b_...",
// identity, oauth, tokens, last_refresh unchanged
}
```
CLI output is unchanged:
```bash
$ e2b auth info
You are logged in as user@example.com,
Selected team: default (team-id)
```
## Testing
`user_config_migration.test.ts` covers in-memory v1→v2 migration, v2
pass-through, and unrecognized configs being treated as signed out
without deleting the file; existing config-permissions and backend
integration tests updated to the new fields. `format`, `lint`,
`typecheck`, `build`, and `pnpm run test` pass (backend integration
suites are environment-gated on credentials).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
e29d406887 |
feat(js-sdk): run the vitest unit suite on Deno (#1585)
## Description `pnpm test:deno` now runs the full vitest suite — the `unit` and `connectionConfig` projects, 421 sandbox/files/commands/pty/git/api/config tests — under the Deno runtime via `deno run -A npm:vitest run --project unit --project connectionConfig`, replacing the previous single dist-based smoke test (superseded — the suite covers the SDK under Deno far more thoroughly). The CI step runs on ubuntu only and covers the same projects as the Bun suite step from #1584, and the Deno pin is bumped from 1.46.3 to 2.8.1 (`setup-deno@v2`) since vitest needs Deno 2's Node compat. Also drops the `edge` vitest project: `tests/runtimes/edge/` no longer exists, so it matched zero files. Rebased on main after #1584: the off-Node fetch-caching fix originally in this PR was superseded by #1584's late-binding fix, which also makes the whole suite (including the per-proxy cache tests) pass under Deno with no test changes — so this PR is pure test/CI wiring. Verified locally on Deno 2.8.1: unit project green (349 passed, 0 failed, 29 skipped — same skips as Node), connectionConfig project green (43 passed), and Node suite green. ## Usage ```bash cd packages/js-sdk pnpm test:deno ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d417e9c4e6 |
test(js-sdk): Cloudflare Workers smoke tests (workerd pool + real deploy) (#1586)
Adds two Cloudflare Workers smoke suites for the JS SDK, both exercising the built `dist/index.mjs`: `pnpm test:cf` runs the sandbox lifecycle inside workerd via `@cloudflare/vitest-pool-workers`, and `pnpm test:cf:deploy` deploys a worker to an ephemeral Cloudflare preview account (`wrangler deploy --temporary` in the suite's global setup — no Cloudflare credentials needed) and asserts the same lifecycle against the live `workers.dev` URL, deleting the worker in teardown. The pool suite immediately caught a runtime-detection bug: Node-compat shims populate `process.release.name` inside Workers, so `getRuntime()` misdetected Workers as Node and loaded `undici`; explicit runtime markers now take precedence over the generic Node check (unit-tested, changeset included). Both suites run in CI after the build step, alongside the Bun and Deno suites (deploy suite on ubuntu only). > [!IMPORTANT] > Merge #1583 first: the deploy suite reproduces the exact #1579 startup crash (Cloudflare rejects the upload with validation error 10021, `createRequire` receiving undefined `import.meta.url`) and stays red until that fix lands. Verified green end-to-end with #1583 applied. Usage: ```bash cd packages/js-sdk && pnpm build # sandbox lifecycle inside local workerd (vitest-pool-workers) pnpm test:cf # deploy to a temporary Cloudflare preview account, test the live worker, delete it E2B_API_KEY=... pnpm test:cf:deploy ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a406f78658 |
feat(js-sdk): run the full test suite under Bun (#1584)
## What
Runs the JS SDK's full vitest suite (the `unit` and `connectionConfig`
projects — 419 tests) under the Bun runtime, replacing the previous
single `bun:test` smoke test (superseded — the suite covers the SDK
under Bun far more thoroughly).
- `pnpm test:bun` → `bunx --bun vitest run --project unit --project
connectionConfig`
- CI step in `js_sdk_tests.yml` (ubuntu only for now); the old smoke
test and its Windows Bun install are removed
## SDK fixes surfaced by running the suite under Bun
1. **Late-bind `globalThis.fetch` on non-Node runtimes**
(`src/api/http2.ts`, `src/envd/http2.ts`). The factories previously
returned the bare global `fetch` reference, so:
- every per-proxy cache entry was the identical function, and
- a `fetch` swapped in *after* client creation (msw, instrumentation,
test stubs) was either ignored or — worse — a temporary stub was
captured permanently in the module-level fetcher cache.
They now return a closure that reads `globalThis.fetch` at call time.
2. **Pin abort reasons to their `AbortController`**
(`src/connectionConfig.ts`). Bun (observed on 1.3.14) holds
`AbortSignal.reason` weakly: a timeout `DOMException` constructed inside
a `setTimeout` callback gets garbage-collected, so consumers saw
`signal.reason === undefined` instead of a `TimeoutError`. Reasons are
now also stored on the controller, keeping them alive, and a losing
(post-abort) call never overwrites the pin. No behavior change on other
runtimes.
```ts
// Before (on Bun): sandbox operations that timed out aborted with
reason undefined
// After: they abort with DOMException('Request handshake timed out
after 30000ms', 'TimeoutError')
const sbx = await Sandbox.create({ requestTimeoutMs: 30_000 })
```
## Test changes
- `tests/envd/http2.test.ts`: the "uses global fetch outside Node" test
now asserts late-binding behavior (a fetch stubbed after fetcher
creation is picked up) instead of reference identity.
- `tests/volume/volume.test.ts`: the msw-mocked `format: 'stream'` read
is split into its own test and skipped on Bun — reading `response.body`
of an msw-intercepted fetch via a reader yields an immediately-done
stream there (msw/Bun incompatibility; `.text()`/`.blob()` work). Real
network streams on Bun work and are covered by the sandbox `files.read`
tests that now run under Bun.
## Verification
Locally on Bun 1.3.14 (macOS arm64) and Node 22:
- `pnpm test:bun`: 73 files passed, 389 tests passed / 30 skipped, 0
failed
- `npx vitest run --project unit --project connectionConfig` (Node): 389
passed / 29 skipped, 0 failed
- browser project (chromium via playwright): passed
- `pnpm run format` / `lint` / `typecheck`: clean
Python SDK parity: not applicable — the changes are JS-runtime-specific
(Bun/global-fetch handling).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
ab5f7666c9 | [skip ci] Release new versions | ||
|
|
a16dcdfc0c |
feat(cli): rename --team flag to --project and add E2B_PROJECT_ID env var (#1580)
Renames the `--team` flag to `-t, --project` on `template list`, `template publish`, `template unpublish`, and `template delete`. `--team` keeps working as a hidden alias that prints a deprecation warning to stderr. The project ID can now also be set via the new `E2B_PROJECT_ID` environment variable, with `E2B_TEAM_ID` still supported as a fallback. Resolution precedence: `--project` > `--team` > `E2B_PROJECT_ID` > `E2B_TEAM_ID` > `~/.e2b/config.json`. ## Usage ```sh e2b template list --project <project-id> # new flag (also -t) e2b template list --team <project-id> # still works, warns: "The --team flag is deprecated, use --project instead." E2B_PROJECT_ID=<project-id> e2b template list # new env var E2B_TEAM_ID=<project-id> e2b template list # still supported ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f10989813c |
fix(js-sdk): drop bare require calls that crash edge runtimes at import (#1583)
Fixes #1579. Bare `require` references in the SDK's ESM source made tsdown emit an eager `createRequire(import.meta.url)` shim at module scope in `dist/index.mjs`, which throws in Cloudflare Workers (workerd) where `import.meta.url` is undefined in bundled code — so `import 'e2b'` crashed before any API call. `sha256` now uses WebCrypto directly (the `node:crypto` fallback was dead code, since package engines require Node ≥ 20.18.1 and `globalThis.crypto` exists on all supported runtimes), and `getCallerDirectory` loads `fileURLToPath` via a static top-level `import url from 'node:url'`, matching the existing sibling `node:fs`/`node:os`/`node:path` imports in the same file. `dynamicRequire` is removed entirely (no remaining callers), and a new bundle test (`tests/bundle/edgeCompat.test.ts`) fails the suite if a `require` shim ever reappears in `dist/index.mjs` — it skips locally when `dist/` hasn't been built and throws in CI, where the workflow always builds first. Verified against the issue's repro in real workerd via wrangler: `e2b@2.35.1` reproduces the crash, while this build imports cleanly and runs a full sandbox lifecycle from inside a Worker. Also verified: chromium browser test, Bun runtime test, signing/secure tests (WebCrypto signatures accepted end-to-end), and the full template suite (134 tests) against live infra. ### Usage No API changes — importing the SDK in a Cloudflare Worker (with `nodejs_compat`) now works again: ```ts import { Sandbox } from 'e2b' export default { async fetch(request: Request, env: Env) { const sandbox = await Sandbox.create({ apiKey: env.E2B_API_KEY }) const result = await sandbox.commands.run('echo hello from workerd') await sandbox.kill() return Response.json({ stdout: result.stdout }) }, } ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
43db96a0ef | [skip ci] Release new versions | ||
|
|
e5a4bd655d | Use undici8.8 when on node >= 22.19 (#1575) | ||
|
|
04827ab163 |
chore(cli): remove dead e2b.toml write path (#1569)
## Description The CLI no longer writes `e2b.toml` anywhere, so this removes the dead code around it: - `saveConfig` and its `getConfigHeader` helper in `packages/cli/src/config/index.ts` had zero callers — removed along with now-unused imports. - The `team_id` field is dropped from the config schema and the unused `localConfigTeamId` parameter from `resolveTeamId` — nothing consumed it since the legacy `template build` command was removed. Team resolution is now: `--team` flag → `E2B_TEAM_ID` env → `~/.e2b/config.json` (the last only when `E2B_API_KEY` isn't set). yup ignores unknown keys, so legacy tomls containing `team_id` still parse. Parsing (`loadConfig`, `deleteConfig`, `getConfigPath`) is intentionally kept as the backward-compatibility read path for legacy projects: `template migrate` (its whole purpose), `template publish`, `template delete`, and `sandbox create`. No user-facing behavior changes; includes a `@e2b/cli` patch changeset. ## Test Format, lint, and typecheck pass; CLI tests: 88 passed, 8 skipped (one pre-existing backend integration suite fails only due to missing `E2B_API_KEY` in the environment). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c0fe6081bd |
feat(cli): rename user-visible "team" wording to "project" in terminal output (#1577)
## Summary Copy-only rename of the remaining user-visible "team" strings to "project" in the CLI (EN-1891) — part of the Teams → Projects rename, following the dashboard copy pass. 12 string literals across `auth login`, `auth info`, `auth configure`, and `template publish`; no flag, env var, config key, API call, or exit-code behavior changes. Explicitly untouched (owned by other PRs): `--team` flag + help text (#1571), `~/.e2b/config.json` keys (#1570), `e2b.toml` `team_id` (#1569), internal identifiers and API `Team` types. Best merged after #1569–#1571 to keep their rebases trivial. ## Usage examples ``` $ e2b auth login Logged in as you@e2b.dev with selected project Your Project $ e2b auth info You are logged in as you@e2b.dev, Selected project: Your Project (a1b2c3d4) $ e2b auth configure ? Select project Your Project (a1b2c3d4) (currently selected project) Project Your Project (a1b2c3d4) selected. $ e2b template publish ⚠️ This will make the template public to everyone outside your project ``` ## Testing - No new tests — strings only, not functionality (per review). Existing suite passes except the pre-existing backend-integration suites that need live sandbox access (fail identically on main). - Patch changeset included. |
||
|
|
4990471484 |
fix(cli): sort sandbox list by timestamp instead of locale date string (#1573)
Fixes #1572 ## Problem `e2b sandbox list` sorted rows *after* converting `startedAt` to a locale string, so ordering was lexicographic over strings like `"9/1/2026, 10:00:00 AM"`. In en-US, `"9/..."` sorts after `"10/..."`, so September sandboxes appeared after October ones — chronological order broke at any single-digit/double-digit month or day boundary. ## Fix Sort by the raw `startedAt` timestamp (with the existing sandbox-ID tiebreak) before formatting for display. The row-building logic is extracted into an exported `buildTableRows` helper and covered by unit tests, including the September/October regression case. The input array is no longer mutated in place. ## Example ``` $ e2b sandbox list --state paused Paused sandboxes Sandbox ID ... Started at sbx-sep ... 9/1/2026, 12:00:00 PM ← previously listed after October sbx-oct ... 10/1/2026, 11:00:00 AM ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/e2b-dev/codesmith/E2B/pr/1573"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1787240223&installation_model_id=14389&pr_number=1573&repository=e2b-dev%2FE2B&return_to=https%3A%2F%2Fgithub.com%2Fe2b-dev%2FE2B%2Fpull%2F1573&signature=85af1311c0e7aa33bbe8ea331f8bb86f82e89ab6e8ec39b29ab776c3a1466cc1"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
36639f5321 |
feat(cli): remove per-command tag from integration attribution (#1557)
## Description Removes the `e2b-cli-command/<command>` token (added in #1544) from the CLI's User-Agent integration attribution, so CLI traffic is attributed only by tool and version. This also lets `connectionConfig` and `client` in `packages/cli/src/api.ts` go back to plain `const` exports, deleting the per-command config/client rebuild machinery and the `preAction` hook that drove it. The attribution test now only checks the SDK and CLI tags, and a patch changeset for `@e2b/cli` is included. User-Agent sent by `e2b sandbox list`, before and after: ``` before: e2b-js-sdk/2.9.0 (Node.js/22.11.0) e2b-cli/2.13.3 e2b-cli-command/sandbox.list after: e2b-js-sdk/2.9.0 (Node.js/22.11.0) e2b-cli/2.13.3 ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
50de0af442 | [skip ci] Release new versions | ||
|
|
95e4dc2832 |
feat(sdk): add sandbox fork to JS and Python SDKs (#1554)
## Summary
Adds SDK support for the new `POST /sandboxes/{sandboxID}/fork` endpoint
(e2b-dev/infra#3202): checkpoint a running sandbox in place (briefly
paused, snapshotted with full memory state, and resumed — its ID and
expiration stay untouched) and boot `count` new sandboxes from that
snapshot.
- **spec**: adds `SandboxForkRequest` / `SandboxForkResult` schemas and
the `/sandboxes/{sandboxID}/fork` path (mirroring the infra spec); JS
and Python API clients regenerated via `make codegen`.
- **js-sdk**: `sandbox.fork(opts)` instance method and
`Sandbox.fork(sandboxId, opts)` static method. Returns
`Promise<Array<Sandbox | Error>>` — one entry per requested fork, each
either a connected `Sandbox` instance or an `Error` describing why that
fork failed to start (`Promise.allSettled`-style, matching the per-fork
results of the API). Per-fork error codes go through the same code→class
mapping as other API errors (extracted from `handleApiError` into
`apiErrorFromCode`), so e.g. a per-fork 429 (sandbox limit) surfaces as
`RateLimitError`. `SandboxForkOpts` extends the full `ConnectionOpts`
(like `SandboxConnectOpts`), so `proxy`, `logger`, `apiUrl`, etc. work
with fork-by-ID. `timeoutMs` defaults to 5 minutes like
`create`/`connect`; `count` defaults to 1 and is validated client-side
(`InvalidArgumentError` for `count < 1`); a whole-request 404 maps to
`SandboxNotFoundError` (the source sandbox is the missing resource —
same semantics as `pause`/`connect`/`setTimeout`), carrying the API
error message when present; per-fork 404 error codes map to generic
`NotFoundError` (the missing resource is fork-internal, e.g. the
snapshot).
- **python-sdk**: `sandbox.fork(timeout=..., count=...)` /
`Sandbox.fork(sandbox_id, ...)` and the `AsyncSandbox` equivalents (same
`@class_method_variant` instance/static pattern as `connect`/`pause`),
returning `List[Union[Sandbox, Exception]]`. Per-fork errors map through
the shared `api_exception_from_code` (extracted from
`handle_api_exception`). `timeout` is in seconds per Python SDK
convention; an explicit `timeout=0` is preserved. Whole-request 404
raises `SandboxNotFoundException`; per-fork 404 codes map to generic
`NotFoundException`.
- **changesets**: minor bumps for `e2b` and `@e2b/python-sdk`.
## Usage
JS:
```ts
const sandbox = await Sandbox.create()
const [fork1, fork2] = await sandbox.fork({ count: 2, timeoutMs: 60_000 })
if (fork1 instanceof Sandbox) {
await fork1.commands.run('echo "hello from fork"')
}
// or by ID
const forks = await Sandbox.fork(sandbox.sandboxId, { count: 2 })
```
Python (sync / async):
```python
sandbox = Sandbox.create()
fork1, fork2 = sandbox.fork(count=2, timeout=60)
if isinstance(fork1, Sandbox):
fork1.commands.run('echo "hello from fork"')
# or by ID
forks = Sandbox.fork(sandbox.sandbox_id, count=2)
```
```python
sandbox = await AsyncSandbox.create()
fork1, fork2 = await sandbox.fork(count=2)
```
## Notes
- The JS option is named `timeoutMs` (milliseconds) to match
`SandboxOpts.timeoutMs` / `SandboxConnectOpts.timeoutMs`; the API
receives seconds via `timeoutToSeconds` as elsewhere.
- Failed forks are returned as error **values** in the array rather than
rejected promises, so a partial failure doesn't throw away the
successful forks and there are no unhandled-rejection hazards. A
per-fork error message includes the API error code only when the API
returned one.
## Test plan
- [x] `pnpm run format`, `pnpm run lint`, `pnpm run typecheck` pass at
the repo root (`ty` diagnostics identical to baseline)
- [x] Offline tests pass: `count < 1` → `InvalidArgumentError` /
`InvalidArgumentException` in JS, Python sync, and Python async;
`handleApiError` suite passes after the `apiErrorFromCode` extraction
(plus a behavior-parity check of the Python `handle_api_exception`
refactor)
- [ ] Integration tests (single fork with FS state inheritance +
independence, multi-fork with unique IDs, fork-by-ID, fork of killed
sandbox → `SandboxNotFoundError`) are written but currently fail against
prod with 404 because the fork endpoint (e2b-dev/infra#3202) is not
deployed yet — they should pass once it lands.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
8c87016a57 | [skip ci] Release new versions | ||
|
|
2c77fc00bb |
feat(sdk): add name filter to snapshot list (#1523)
Adds an optional `name` filter to `Sandbox.listSnapshots()` / `Sandbox.list_snapshots()`, mirroring the infra snapshots list endpoint ([e2b-dev/infra#3184](https://github.com/e2b-dev/infra/pull/3184)). 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. It's a flat top-level option alongside the existing `sandboxId` filter (non-breaking) and can be combined with it — the backend applies both with AND, matching the `metadata`+`state` behavior of `Sandbox.list()`. Applied equivalently across the OpenAPI spec, generated clients, and the JS + Python sync/async SDKs, with tests and a changeset. ## Usage ```ts // JS/TS const paginator = Sandbox.listSnapshots({ name: 'my-snapshot' }) const snapshots = await paginator.nextItems() // combine filters (snapshots from a sandbox matching a name) Sandbox.listSnapshots({ sandboxId: 'sandbox-id', name: 'my-snapshot' }) ``` ```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() ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
78a91ab72f | [skip ci] Release new versions | ||
|
|
7474d904a2 |
fix(python-sdk): correct inverted no_install_recommends docstring (#1533)
Promotes the merged #1532 (by @anxkhn) from the staging branch `fix/no-install-recommends-docstring` into `main`. `TemplateBuilder.apt_install()` documents its `no_install_recommends` parameter as "Whether to install recommended packages", but the generated command does the opposite. In `packages/python-sdk/e2b/template/main.py` the command adds apt-get's `--no-install-recommends` flag when the argument is `True`: ```python f"... apt-get install -y {'--no-install-recommends ' if no_install_recommends else ''}..." ``` `--no-install-recommends` tells apt to *skip* recommended packages, so `no_install_recommends=True` skips them rather than installing them. A user who follows the docstring gets the inverse of the documented behavior. The parameter name and apt-get's own semantics confirm the code is correct and the docstring was wrong; this rewords the docstring line to match the real behavior. The `--no-install-recommends` flag was introduced in #983; the docstring has been inverted since then. This is Python-only. The JS twin `aptInstall` applies the same flag but has no per-parameter JSDoc for `noInstallRecommends` (it appears only inside an `@example`), so there is nothing contradictory to fix on the JS side. There is a single Python definition (no sync/async mirror for the template builder). No behavior change; documentation-only, plus a `@e2b/python-sdk: patch` changeset. ### Usage ```python from e2b import Template template = Template().from_image("ubuntu:22.04") # Install recommended packages as well (apt-get default): template.apt_install("vim") # Skip recommended packages (adds apt-get's --no-install-recommends): template.apt_install("vim", no_install_recommends=True) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> Co-authored-by: Anas Khan <anxkhn28@gmail.com> |
||
|
|
99e536f6eb |
fix(python-sdk): stop leaking per-call proxy pools in volume content clients (#1534)
The Python volume content client factories passed both `proxy` and the shared cached `transport` to httpx, so with a proxy configured (e.g. `Volume.connect(volume_id, proxy="http://user:pass@127.0.0.1:8080")`), every volume operation mounted a fresh, never-closed proxy transport that bypassed the cached connection pool. The client-level `proxy` argument is now dropped — the proxy is already baked into the cached transport, so proxied requests keep working but reuse one pooled transport per thread/event loop. The volume transports also gained connect-level retries (`E2B_CONNECTION_RETRIES`, default 3), matching the core API and envd transports. Includes a changeset for a `@e2b/python-sdk` patch release. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a4e07a6ab2 |
feat(cli): attribute CLI traffic with e2b-cli and per-command tags (#1544)
Follow-up promised in #1524 (original attempt #1525, closed while blocked on the backend User-Agent parser, since fixed by e2b-dev/infra#3149, which now iterates User-Agent tokens and ignores unrecognized ones — so the extra tags are safe on template builds). Sets `ConnectionConfig.setIntegration('e2b-cli/<version>')` at the top of `src/api.ts` before the shared connection config is built at import time, and a commander `preAction` hook extends the tag with the canonical invoked command (alias `ls` reports as `list`), rebuilding the shared config and client since they capture the User-Agent at construction. Every CLI request then carries: ``` User-Agent: e2b-js-sdk/2.32.0 e2b-cli/2.13.1 e2b-cli-command/sandbox.list ``` Tests drive the built CLI (`sandbox list` and the `ls` alias) against a local stub API server and assert the received User-Agent, which also guards that the bundle keeps shipping the workspace SDK where `setIntegration` exists. Includes a patch changeset for `@e2b/cli`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
347ebe8ad8 |
fix(cli): correct memory-mb help default and use non-deprecated pause (#1510)
Fixes two small CLI issues. The `e2b template create --memory-mb` help text claimed a default of 512 MB, but the real default is 1024 MB — the help now reflects that. The `e2b sandbox pause` command was calling the deprecated `Sandbox.betaPause()` alias and now calls `Sandbox.pause()` directly. ## Usage ```sh e2b template create --help # --memory-mb now shows "The default value is 1024." e2b sandbox pause <sandboxID> # behaves the same, no longer uses the deprecated method ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
64e9bc02b6 |
fix(js-sdk): unpin useDefineForClassFields — make caller-directory resolution emit-invariant (#1539)
Follow-up to #1536, which pinned `useDefineForClassFields: false` in the js-sdk tsconfig because raising `target` to `es2022` flips the default to `true`, and that broke the template builder. This PR fixes the root cause and removes the pin, so the SDK now compiles with the standard es2022 `[[Define]]` class-field semantics. ## Root cause `TemplateBase` resolved its default `fileContextPath` in a **class field initializer**: ```ts private fileContextPath: PathLike = runtime === 'browser' ? '.' : (getCallerDirectory(STACK_TRACE_DEPTH) ?? '.') ``` With native class fields (define semantics), V8 evaluates field initializers in an extra `<instance_members_initializer>` stack frame: ``` at getCallerDirectory (utils.ts) at <instance_members_initializer> (index.ts) ← extra frame under define semantics at new TemplateBase (index.ts) at Template (index.ts) at user code ← fixed-depth walk lands one frame short ``` `getCallerDirectory` walks the stack at a fixed depth, so it landed on the SDK's own `src/template` directory instead of the caller's — `.copy('folder/*', …)` then globbed against the wrong base dir (`Error: No files found in .../src/template/...`), and the resulting client-side failure mis-attributed build-step stack traces (the two `stacktrace.test.ts` failures were cascades of this one bug). ## Fix Move the default resolution into the constructor body, where the stack shape is identical under both emits: ```ts constructor(options?: TemplateOptions) { this.fileContextPath = options?.fileContextPath ?? (runtime === 'browser' ? '.' : (getCallerDirectory(STACK_TRACE_DEPTH) ?? '.')) ``` The call is now emit-invariant (same `STACK_TRACE_DEPTH`), so the tsconfig pin is removed. The method-level `getCallerFrame` call sites were never affected — method bodies don't change shape with class-field semantics. Only the js-sdk is touched: the Python SDKs resolve the caller via `inspect` and don't have this failure mode, and the CLI bundle doesn't include `TemplateBase`. ## Usage example Fixes relative-path resolution for SDK consumers whose toolchain emits native class fields (e.g. esbuild/vitest with `target: es2022+`): ```ts // user-project/scripts/template.ts const template = Template() .fromBaseImage() .copy('assets/*', '/app/assets') // now resolves against user-project/scripts/, // not the SDK's own directory ``` ## Verification - `tests/template/stacktrace.test.ts` — 30/30 pass with the flag defaulted (`true`), and still 30/30 when explicitly set back to `false` (emit-invariance) - `tests/template/build.test.ts` — 4/4 pass against the real backend (real `.copy` glob + build) - Smoke-tested built `dist/index.mjs` and `dist/index.js` from an external directory: `fileContextPath` resolves to the importing script's directory in both - Unit project A/B: identical results with and without this change (remaining failures are pre-existing `E2B_API_KEY`-gated live tests) - `pnpm run typecheck`, `lint`, `format` ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
dbc6bfa161 | [skip ci] Release new versions | ||
|
|
09e12b3f65 |
feat(sdk): set-once integration attribution via ConnectionConfig.setIntegration (#1524)
Replaces the per-call `integration` connection option with a set-once, process-wide setter — `ConnectionConfig.setIntegration()` in JS and `ConnectionConfig.set_integration()` in Python — so integrations wrapping the SDK tag themselves once at startup and every request carries the identifier in the `User-Agent` header, with no threading through individual SDK calls. The setter is internal and hidden from generated docs; the `integration` option is removed from `ConnectionConfigOpts` (kept as a deprecated alias of `ConnectionOpts`) and from the Python constructor, and the round-trip machinery from #1459 is no longer needed since rebuilt configs read the process-wide value. User-Agent handling now follows a single rule in both SDKs via one shared helper per SDK: an explicitly provided `User-Agent` always wins, otherwise the SDK sends its own tagged with the current integration — and SDK-built values are recomputed whenever a config is rebuilt, so clearing or changing the integration propagates. Tests cover attribution, clearing, config rebuilds, and custom User-Agent precedence in both SDKs, with changesets for `e2b` and `@e2b/python-sdk` (minor). CLI attribution using this setter will follow in a separate PR. Usage (internal integrations only): ```ts import { ConnectionConfig } from 'e2b' ConnectionConfig.setIntegration('e2b-code-interpreter/0.1.0') // once at startup ``` ```python from e2b import ConnectionConfig ConnectionConfig.set_integration("e2b-code-interpreter/0.1.0") # once at startup ``` A caller-supplied `User-Agent` (via `headers`/`apiHeaders`) is preserved in both SDKs: ```ts const sbx = await Sandbox.create({ apiHeaders: { 'User-Agent': 'my-app/1.0' } }) // requests carry: my-app/1.0 ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
07041ccffc |
test: skip live volume tests unless ENABLE_VOLUME_TESTS is set (#1526)
Live volume tests create real volumes against the API; this gates them
behind an `ENABLE_VOLUME_TESTS` env var so they skip by default. In the
JS SDK, the `volumeTest` fixture is chained with
`.skipIf(process.env.ENABLE_VOLUME_TESTS === undefined)`, skipping all
of `tests/volume/file.test.ts`. In the Python SDK, the `volume` and
`async_volume` fixtures call `pytest.skip` when the env var is unset,
gating `tests/{sync/volume_sync,async/volume_async}/test_file.py`.
Mocked and unit volume tests (msw-based `volume.test.ts`,
`test_volume.py`, `test_volume_content.py`, `test_volume_client.py`,
`test_volume_connection_config.py`) still run unconditionally. To run
the live tests: `ENABLE_VOLUME_TESTS=1 pnpm run test` or
`ENABLE_VOLUME_TESTS=1 poetry run pytest`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
0bd06d86d2 |
chore(js-sdk,cli): modernize tsconfig and adopt TypeScript 7 (side-by-side) (#1536)
Supersedes #1516 (same modernization at TypeScript 6.0). Rebased onto `main` now that the build runs on **tsdown** (#1515). ## What & why Adopt **TypeScript 7** for both packages and modernize the compiler config. TypeScript 7.0's native compiler [ships no programmatic API yet](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0) (it lands in 7.1), so anything built on the TS compiler API breaks on it — here that's tsdown's `.d.ts` generation and the codegen scripts (`openapi-typescript`, `json-schema-to-typescript`). Per the official guidance, TS 7 is installed **side-by-side** with TS 6: ```json "@typescript/native": "npm:typescript@^7.0.2", // native tsc — used for type-checking "typescript": "npm:@typescript/typescript6@^6.0.2" // TS6 w/ compiler API — used by tooling ``` - `tsc --noEmit` (typecheck) → **native TypeScript 7.0.2** (verified: `tsc --version` → 7.0.2) - `import 'typescript'` → **TypeScript 6.0** *with* the compiler API → tsdown dts + codegen keep working - Bonus: tsdown's dts no longer prints the "TypeScript 7.0 does not yet have a stable API and is experimental" warning (it's on the 6.0 API now) **Internal build-config change only — no public API or runtime behavior changes.** ## Compiler options: before → after ### `packages/js-sdk/tsconfig.json` | option | before | after | |---|---|---| | `target` | `es6` | `es2022` | | `lib` | `["dom","ESNext"]` | `["dom","es2022"]` | | `module` | _(unset)_ | `esnext` | | `moduleResolution` | `node` | `bundler` | | `allowJs` | `true` | **removed** (no `.js` sources) | | `allowSyntheticDefaultImports` | `true` | **removed** (implied by `esModuleInterop`) | | `useDefineForClassFields` | _(false, implied by es6)_ | **`false` (now explicit)** — see note | ### `packages/cli/tsconfig.json` | option | before | after | |---|---|---| | `moduleResolution` | `node` | `bundler` | | `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply`, `strictPropertyInitialization`, `noImplicitThis`, `alwaysStrict` | `true` | **removed** (implied by `strict`) | | `downlevelIteration` | `true` | **removed** (removed in TS 7; no-op at `es2022`) | | `baseUrl` | `"."` | **removed** (removed in TS 7) | | `paths` | `{ e2b }` | `{ src, "src/*", e2b }` (replaces `baseUrl` for the existing `src/...` import style) | | `outDir` | `"dist"` | **removed** (unused under `tsc --noEmit`) | | `exclude` | _(none)_ | `["dist","node_modules"]` (so the built bundle is never type-checked) | `target`/`lib` for the CLI were already `es2022`. ## Notes / decisions - **Why side-by-side, not a plain `typescript@7` bump:** TS 7.0 is the native (Go) compiler rewrite — feature-identical to 6.0 for type-checking, no programmatic API until 7.1. A plain bump crashed both codegen tools (`Cannot read properties of undefined (reading 'createKeywordTypeNode')`). Side-by-side gives native-TS-7 checking while keeping the TS-6 API for tooling. Once 7.1 ships the API and the tools update, this collapses back to a single `typescript@7` dep. - **`useDefineForClassFields: false` is pinned explicitly.** Raising js-sdk's `target` to `es2022` flips this default to `true`, changing class-field emit and shifting stack frames. The template builder resolves the caller's directory and per-step traces via **fixed-depth** stack walking (`getCallerDirectory` in `src/template/index.ts`), so the extra frames threw it off by one — resolving `.copy('folder/*', …)` against the wrong base dir and mis-attributing build steps (`tests/template/build.test.ts` + `stacktrace.test.ts`). Pinning `false` keeps the exact pre-existing field semantics (es6 already implied `false`); adopting `define` semantics should be a separate, deliberately tested change. - **Target stays at `es2022`, not `es2023`.** `engines` still allow Node 20 (`>=20.18.1 <21 || >=22`). - **`moduleResolution: "bundler"`** typechecks + builds cleanly in both packages. The CLI's `baseUrl`-based bare imports (`from 'src/user'`, `from 'src'`) are preserved via `paths`; the bundled output still resolves them (build verified, binary smoke-tested). ## Not done (intentionally) - **`verbatimModuleSyntax`** — ~177 `import type` conversions; left as a follow-up. - **Shared `tsconfig.base.json`** — the two configs diverge too much to factor out cleanly. ## Verification - `pnpm run typecheck` ✅ both packages, on **native TS 7.0.2** - `pnpm run build` ✅ both packages (js-sdk ESM + CJS + **DTS**; cli CJS; binary smoke-tested) - codegen ✅ `openapi-typescript` + `json2ts` run and produce identical output (idempotent) - `pnpm run lint` ✅ both packages - `pnpm run test` — `template/build` + `template/stacktrace` now pass (`stacktrace` verified locally 30/30); remaining local failures are all `E2B_API_KEY`-gated live tests, unaffected by this change 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
49367c8491 |
build: switch from tsup to tsdown (#1515)
Switches the build tooling for `packages/js-sdk` and `packages/cli` from `tsup` (esbuild) to `tsdown` (rolldown), replacing each `tsup.config.js` with a `tsdown.config.ts` and updating the `build`/`dev` scripts and devDependencies. The published artifact layout is intentionally unchanged — the SDK still ships `dist/index.js` (CJS), `dist/index.mjs` (ESM) and `dist/index.d.ts`/`.d.mts`, and the CLI still ships an executable `dist/index.js` plus `dist/templates` — kept identical via `fixedExtension: false`. CLI dependency bundling is preserved by mapping the old `noExternal` to tsdown's `deps.alwaysBundle` (still excluding the ESM-only, dynamically-imported `inquirer`), and template copying moves from an `onSuccess` shell step to tsdown's `copy` option. Also aligns Node versions: `engines.node` for both packages is set to `20 || >=22`, the CLI build targets `node20`, and the pinned `nodejs` in `.tool-versions` is bumped to `22.11.0`. The large `pnpm-lock.yaml` diff is expected — it swaps the tsup/esbuild dependency tree for tsdown's rolldown tree (no lockfile format change). ## Verification - Both packages build cleanly with output filenames identical to the previous tsup builds. - `typecheck`, `lint` (oxlint) and `build` pass for both packages; the built CLI runs (`--version`). - Built js-sdk imports correctly in both CJS (`require`) and ESM (`import`), exposing the default `Sandbox` export and all named exports. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e6c4e7e9d5 |
chore(js): modernize Connect/Protobuf and React test deps (#1512)
## What Modernizes the JS SDK's dependencies while remaining fully compatible with the current supported Node range (`>=20.18.1`) — no engine changes and no breaking impact for consumers. - **`@connectrpc/connect` / `@connectrpc/connect-web`:** `2.0.0-rc.3` → `^2.1.2` (off the pre-release pin onto the stable line, and switched to a `^` range). - **`@bufbuild/protobuf`:** `^2.6.2` → `^2.12.1`. - **React test deps:** `react` / `@types/react` → `^19.2.0`, and `react-dom` / `@types/react-dom` added at `^19.2.0` (previously auto-installed as v18 peers). Dev/test-only — no runtime impact. - **CI:** standardized `actions/setup-node` (mixed v3/v4/v6) to `v6` across all workflows; the three `@v3` uses were on the deprecated Node16 action runtime. No public SDK API changes — the sandbox filesystem and command RPCs use the same Connect transport configuration. ## Why undici / Node floor were dropped from this PR An earlier revision also bumped `undici` 7 → 8 and raised the Node floor to `>=22.19.0`. Usage data shows **Node 20 is still the single largest SDK runtime (~39% of sandbox creations)**, so dropping it would break the largest consumer segment via `engine-strict` install failures. undici 8 was the *only* change forcing Node 22, and undici `7.28.0` (already the latest 7.x) supports Node 20 — so undici stays at `^7.28.0` and the engine floor is unchanged. undici 8 is a good candidate for a future major once Node 20 usage declines. ## Verification - typecheck, lint (oxlint), and build pass - 22 mocked Connect/undici transport unit tests pass - 106 live filesystem/command tests pass over connectrpc `2.1.2` + undici `7.28.0` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0feb926937 | [skip ci] Release new versions | ||
|
|
5d84a8e7d2 |
chore(deps-dev): bump black from 23.7.0 to 26.3.1 in /packages/python-sdk in the uv group across 1 directory (#1530)
Bumps the uv group with 1 update in the /packages/python-sdk directory: [black](https://github.com/psf/black). Updates `black` from 23.7.0 to 26.3.1 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/psf/black/releases">black's releases</a>.</em></p> <blockquote> <h2>26.3.1</h2> <h3>Stable style</h3> <ul> <li>Prevent Jupyter notebook magic masking collisions from corrupting cells by using exact-length placeholders for short magics and aborting if a placeholder can no longer be unmasked safely (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Always hash cache filename components derived from <code>--python-cell-magics</code> so custom magic names cannot affect cache paths (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3><em>Blackd</em></h3> <ul> <li>Disable browser-originated requests by default, add configurable origin allowlisting and request body limits, and bound executor submissions to improve backpressure (<a href="https://redirect.github.com/psf/black/issues/5039">#5039</a>)</li> </ul> <h2>26.3.0</h2> <h3>Stable style</h3> <ul> <li>Don't double-decode input, causing non-UTF-8 files to be corrupted (<a href="https://redirect.github.com/psf/black/issues/4964">#4964</a>)</li> <li>Fix crash on standalone comment in lambda default arguments (<a href="https://redirect.github.com/psf/black/issues/4993">#4993</a>)</li> <li>Preserve parentheses when <code># type: ignore</code> comments would be merged with other comments on the same line, preventing AST equivalence failures (<a href="https://redirect.github.com/psf/black/issues/4888">#4888</a>)</li> </ul> <h3>Preview style</h3> <ul> <li>Fix bug where <code>if</code> guards in <code>case</code> blocks were incorrectly split when the pattern had a trailing comma (<a href="https://redirect.github.com/psf/black/issues/4884">#4884</a>)</li> <li>Fix <code>string_processing</code> crashing on unassigned long string literals with trailing commas (one-item tuples) (<a href="https://redirect.github.com/psf/black/issues/4929">#4929</a>)</li> <li>Simplify implementation of the power operator "hugging" logic (<a href="https://redirect.github.com/psf/black/issues/4918">#4918</a>)</li> </ul> <h3>Packaging</h3> <ul> <li>Fix shutdown errors in PyInstaller builds on macOS by disabling multiprocessing in frozen environments (<a href="https://redirect.github.com/psf/black/issues/4930">#4930</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Introduce winloop for windows as an alternative to uvloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Remove deprecated function <code>uvloop.install()</code> in favor of <code>uvloop.new_event_loop()</code> (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Rename <code>maybe_install_uvloop</code> function to <code>maybe_use_uvloop</code> to simplify loop installation and creation of either a uvloop/winloop evenloop or default eventloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> </ul> <h3>Output</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/psf/black/blob/main/CHANGES.md">black's changelog</a>.</em></p> <blockquote> <h2>Version 26.3.1</h2> <h3>Stable style</h3> <ul> <li>Prevent Jupyter notebook magic masking collisions from corrupting cells by using exact-length placeholders for short magics and aborting if a placeholder can no longer be unmasked safely (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Always hash cache filename components derived from <code>--python-cell-magics</code> so custom magic names cannot affect cache paths (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3><em>Blackd</em></h3> <ul> <li>Disable browser-originated requests by default, add configurable origin allowlisting and request body limits, and bound executor submissions to improve backpressure (<a href="https://redirect.github.com/psf/black/issues/5039">#5039</a>)</li> </ul> <h2>Version 26.3.0</h2> <h3>Stable style</h3> <ul> <li>Don't double-decode input, causing non-UTF-8 files to be corrupted (<a href="https://redirect.github.com/psf/black/issues/4964">#4964</a>)</li> <li>Fix crash on standalone comment in lambda default arguments (<a href="https://redirect.github.com/psf/black/issues/4993">#4993</a>)</li> <li>Preserve parentheses when <code># type: ignore</code> comments would be merged with other comments on the same line, preventing AST equivalence failures (<a href="https://redirect.github.com/psf/black/issues/4888">#4888</a>)</li> </ul> <h3>Preview style</h3> <ul> <li>Fix bug where <code>if</code> guards in <code>case</code> blocks were incorrectly split when the pattern had a trailing comma (<a href="https://redirect.github.com/psf/black/issues/4884">#4884</a>)</li> <li>Fix <code>string_processing</code> crashing on unassigned long string literals with trailing commas (one-item tuples) (<a href="https://redirect.github.com/psf/black/issues/4929">#4929</a>)</li> <li>Simplify implementation of the power operator "hugging" logic (<a href="https://redirect.github.com/psf/black/issues/4918">#4918</a>)</li> </ul> <h3>Packaging</h3> <ul> <li>Fix shutdown errors in PyInstaller builds on macOS by disabling multiprocessing in frozen environments (<a href="https://redirect.github.com/psf/black/issues/4930">#4930</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Introduce winloop for windows as an alternative to uvloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Remove deprecated function <code>uvloop.install()</code> in favor of <code>uvloop.new_event_loop()</code> (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Rename <code>maybe_install_uvloop</code> function to <code>maybe_use_uvloop</code> to simplify loop installation and creation of either a uvloop/winloop eventloop or default eventloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/psf/black/commit/c6755bb741b6481d6b3d3bb563c83fa060db96c9"><code>c6755bb</code></a> Prepare release 26.3.1 (<a href="https://redirect.github.com/psf/black/issues/5046">#5046</a>)</li> <li><a href="https://github.com/psf/black/commit/69973fd6950985fbeb1090d96da717dc4d8380b0"><code>69973fd</code></a> Harden blackd browser-facing request handling (<a href="https://redirect.github.com/psf/black/issues/5039">#5039</a>)</li> <li><a href="https://github.com/psf/black/commit/4937fe6cf241139ddbfc16b0bdbb5b422798909d"><code>4937fe6</code></a> Fix some shenanigans with the cache file and IPython (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> <li><a href="https://github.com/psf/black/commit/2e641d174469c505d5ae905e75d4c769597e681f"><code>2e641d1</code></a> docs: remove outdated Black Playground references (<a href="https://redirect.github.com/psf/black/issues/5044">#5044</a>)</li> <li><a href="https://github.com/psf/black/commit/c014b22a2d5e0632587b47b81151658bddfa0b88"><code>c014b22</code></a> Remove unused internal code (<a href="https://redirect.github.com/psf/black/issues/5041">#5041</a>)</li> <li><a href="https://github.com/psf/black/commit/0dae20b2d009f2f03de8696d06b0c947d3abafc9"><code>0dae20b</code></a> Add new changelog (<a href="https://redirect.github.com/psf/black/issues/5036">#5036</a>)</li> <li><a href="https://github.com/psf/black/commit/c5c1cbddd92cecb554ac2a77a24139dd76831030"><code>c5c1cbd</code></a> Minor release patches (<a href="https://redirect.github.com/psf/black/issues/5035">#5035</a>)</li> <li><a href="https://github.com/psf/black/commit/7e5a828c37d71b6a6666e28eed444816def6a8f4"><code>7e5a828</code></a> docs: clarify relationship between Black style and PEP 8 (<a href="https://redirect.github.com/psf/black/issues/5025">#5025</a>)</li> <li><a href="https://github.com/psf/black/commit/69705deb8776e7c5e585668da106d1abe2cb8d77"><code>69705de</code></a> docs: add clearer pyproject configuration guidance (<a href="https://redirect.github.com/psf/black/issues/5026">#5026</a>)</li> <li><a href="https://github.com/psf/black/commit/35ea67920b7f6ac8e09be1c47278752b1e827f76"><code>35ea679</code></a> Prepare release 26.3.0 (<a href="https://redirect.github.com/psf/black/issues/5032">#5032</a>)</li> <li>Additional commits viewable in <a href="https://github.com/psf/black/compare/23.7.0...26.3.1">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/e2b-dev/E2B/network/alerts). </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
be4eb5fd96 |
chore(python-sdk): migrate from Poetry to uv (#1513)
Migrates the Python SDK's packaging and CI from Poetry to [uv](https://docs.astral.sh/uv/): `pyproject.toml` is converted to PEP 621 metadata using uv's native `uv_build` backend (verified to produce a byte-equivalent wheel containing both `e2b` and `e2b_connect`), `poetry.lock` is replaced with `uv.lock`, and the `Makefile`, `package.json` scripts, `.tool-versions`, `CLAUDE.md`, and all six GitHub workflows now use `uv` (`astral-sh/setup-uv` + `uv sync`/`build`/`version`/`publish`). It also drops the now-redundant explicit sync steps (since `uv run` auto-syncs) and removes the orphaned `pydoc-markdown` dev dependency, whose only consumer was deleted long ago — trimming 58 packages from the dev lockfile. ## Usage ```sh cd packages/python-sdk uv sync # install deps (replaces `poetry install`) uv run pytest # run tests uv build # build the wheel/sdist make lint # ruff (run via `uv run`) ``` No user-facing SDK change — packaging/tooling only — so no changeset is included; the published package contents are unchanged. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a6b1cf4bcf |
fix(python-sdk): strip colon-separated SGR escape codes in build logs (#1522)
### What Cherry-picks the fix from #1519. `strip_ansi_escape_codes` in the Python SDK only matched semicolon-separated CSI parameters, so colon-separated SGR sequences leaked literal escape garbage into template build-log messages. This widens the parameter class from `;` to `[;:]` so colon-separated sequences are stripped too, matching the JS SDK's `stripAnsi`. Modern terminals emit colon-separated SGR sequences: - 256-color: `\x1b[38:5:82m` - truecolor: `\x1b[38:2::255:0:0m` - curly underline: `\x1b[4:3m` The two SDKs share one source (chalk/ansi-regex) and the JS twin was already updated to support colons (`packages/js-sdk/src/utils.ts:95`, comment: "supports ; and :"); the Python port lagged behind. `strip_ansi_escape_codes` is consumed by `LogEntry.__post_init__` (`packages/python-sdk/e2b/template/logger.py`), so the leftover escape bytes showed up in Python build logs only. ### The one-line fix ```python # packages/python-sdk/e2b/template/utils.py:319 - r"(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))", + r"(?:(?:\d{1,4}(?:[;:]\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))", ``` ### Usage example (before / after) ```python from e2b.template.utils import strip_ansi_escape_codes # 256-color, colon-separated strip_ansi_escape_codes("\x1b[38:5:82mX\x1b[0m") # before: ":5:82mX" after: "X" # truecolor, colon-separated strip_ansi_escape_codes("\x1b[38:2::255:0:0mRED\x1b[0m") # before: ":2::255:0:0mRED" after: "RED" # semicolon variants already worked and still do strip_ansi_escape_codes("\x1b[38;5;82mX\x1b[0m") # "X" (unchanged) ``` ### Tests Unit tests at `packages/python-sdk/tests/shared/template/utils/test_strip_ansi_escape_codes.py` (no API key / sandbox): colon-256, colon-truecolor, curly-underline, plus basic/semicolon regressions. All 7 pass locally. ### Changeset `.changeset/python-strip-ansi-colon.md` (patch on `@e2b/python-sdk`). ### Notes Original PR: #1519 (by @anxkhn). Opened against a fresh branch off `main` per request, rather than merging #1519 directly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> |
||
|
|
2b7dd17f10 |
feat(sdk): add gzip option to template copy layer (#1482)
Adds a `gzip` option to the template `.copy()` / `copyItems` layer that
controls whether copied files are gzipped before upload, threaded from
the copy call through the build-time tar stream in both the JS SDK and
the sync/async Python SDKs. It is enabled by default to preserve
existing behavior, so passing `gzip: false` (`gzip=False`) uploads an
uncompressed tar — useful for already-compressed payloads where gzip
adds CPU cost without shrinking the upload. The option name matches
node-tar's own `gzip` option and the existing sandbox filesystem `gzip`
kwarg. Gzip is deliberately excluded from the file cache hash, so
toggling it does not bust the build cache. Tests in both SDKs were
updated for the new argument and extended with `gzip: false` cases
asserting the archive is not gzipped yet still extracts, and a changeset
(`minor` for both packages) is included.
> [!NOTE]
> The server that extracts these uploaded archives lives in another repo
and must auto-detect compression (peek the gzip `0x1f 0x8b` magic)
rather than assuming gzip; confirm it handles plain tars before release.
## Usage
```ts
// JS/TS
template.copy('model.bin', '/app/', { gzip: false })
template.copyItems([{ src: 'a.bin', dest: '/app/', gzip: false }])
```
```python
# Python (sync & async)
template.copy('model.bin', '/app/', gzip=False)
template.copy_items([{ 'src': 'a.bin', 'dest': '/app/', 'gzip': False }])
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
a39db3bb36 |
chore: switch from eslint to oxlint (#1514)
Replaces ESLint (and its `@typescript-eslint/*` and `unused-imports` plugins) with [oxlint](https://oxc.rs) across the `js-sdk` and `cli` packages. A root `.oxlintrc.json` replaces the three `.eslintrc.cjs` files, the package `lint` scripts now run `oxlint`, the related devDependencies are swapped for `oxlint`, and the lint CI path filter is updated accordingly. Formatting rules (`quotes`/`semi`/`linebreak-style`) are dropped because Prettier already enforces them, and `no-unused-vars` is set to error to preserve the previous unused-imports check. The one behavior change is that `@typescript-eslint/member-ordering` has no oxlint equivalent and is no longer enforced. `lint`, `typecheck`, and `prettier` all pass clean for both packages. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9b4a74388d |
chore(cli): remove unused dockerfile-ast dependency (#1509)
The CLI declared `dockerfile-ast` as a dependency but never imported it — all Dockerfile parsing in the CLI goes through the `e2b` SDK, which keeps its own (newer) `dockerfile-ast` dependency. This drops the redundant copy from `packages/cli/package.json`, removing `dockerfile-ast@0.6.1` and its sub-deps from the lockfile while `dockerfile-ast@0.7.1` (used by the js-sdk) stays. No behavior change; CLI typecheck and lint pass, and a `@e2b/cli` patch changeset is included. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c385566c29 |
fix(python-sdk): correct Sandbox.list() docstring (also lists paused) (#1511)
Integration branch PR for #1500. Merges the docstring fix into `main`. Once #1500 is merged into `python-sdk-list-docstring-base`, this PR will carry those changes into `main`. --------- Co-authored-by: Leinux <tristone13th@outlook.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d071bb78c8 |
fix(cli): use absolute import in generated Python build scripts (#1505)
Fixes the generated Python build scripts to use an absolute import (from template import template) instead of a relative one, which broke python build_dev.py with ImportError: attempted relative import with no known parent package since the files are emitted as flat siblings with no package. This reverts an unintended change from #954 that was flagged by Cursor Bugbot at the time but not addressed. Fixes #1477. |
||
|
|
2869febdee |
feat(cli): add config override flags to template migrate (#1494)
Adds override flags to `e2b template migrate` so the generated SDK files don't have to inherit everything from `e2b.toml`: `--name`/`-n` (template name), `--cmd`/`-c` (start command), `--ready-cmd` (ready command), `--cpu-count`, and `--memory-mb`. Each flag falls back to the corresponding config value when omitted, and `--memory-mb` is validated to be even. Includes tests covering the overrides and the odd-memory rejection, plus a changeset for `@e2b/cli`. ## Usage ```bash e2b template migrate \ --language typescript \ --name my-custom-name \ --cmd "node server.js" \ --ready-cmd "curl localhost:3000" \ --cpu-count 4 \ --memory-mb 2048 ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |