Commit Graph

938 Commits

Author SHA1 Message Date
Mish Ushakov e873ee94b6 feat(sdk): add allowNetworkMounts option to filesystem watch (#1420)
Client-side counterpart to
[e2b-dev/infra#2982](https://github.com/e2b-dev/infra/pull/2982): adds
an `allowNetworkMounts`/`allow_network_mounts` option to filesystem
directory watching across the JS and Python (sync + async) SDKs, so
clients can explicitly opt into watching paths on network filesystem
mounts (NFS, CIFS, SMB, FUSE), which envd rejects by default. Events on
network mounts may be unreliable or not delivered at all, hence the
explicit opt-in.

This regenerates the filesystem proto code from the updated spec and
threads the flag through `watchDir`/`watch_dir` (streaming `WatchDir`
and polling `CreateWatcher`). The option requires envd 0.6.4 (shipped by
the infra PR); using it against an older sandbox throws a
`TemplateError`/`TemplateException`. Default behavior is unchanged.

Includes new watch tests for all three SDKs and a minor-bump changeset
for `e2b` and `@e2b/python-sdk`.

> Note: the new tests exercise the flag on a regular directory (a
network mount can't be set up from SDK tests) and require envd 0.6.4, so
this should land with/after the infra deploy. All pre-existing watch
tests pass; the new ones currently fail with the expected
`TemplateError` against the deployed envd.

### Usage

**JavaScript**
```ts
const handle = await sandbox.files.watchDir(
  '/mnt/nfs-share/my-dir',
  (event) => console.log(event.type, event.name),
  { allowNetworkMounts: true }
)
```

**Python (async)**
```python
handle = await sandbox.files.watch_dir(
    "/mnt/nfs-share/my-dir",
    on_event=lambda e: print(e.type, e.name),
    allow_network_mounts=True,
)
```

**Python (sync)**
```python
handle = sandbox.files.watch_dir("/mnt/nfs-share/my-dir", allow_network_mounts=True)
for e in handle.get_new_events():
    print(e.type, e.name)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 15:34:02 +02:00
Mish Ushakov cab59caa0b fix(js-sdk): pass getMetrics start/end as query params (#1427)
## Description

`Sandbox.getMetrics()` in the JS SDK passed the `start` and `end`
options as path parameters instead of query parameters, so openapi-fetch
never serialized them and the requested time range was silently ignored.
They are now sent under `query`, matching the OpenAPI spec; the Python
SDKs already passed them correctly. The metrics tests across JS and
Python (sync/async) now assert that returned metrics fall within the
requested window (with slack for 5s metric-bucket alignment) and that a
window from before the sandbox existed returns no metrics, which would
have caught this regression.

## Usage

```ts
const start = new Date(Date.now() - 60_000)
const metrics = await sandbox.getMetrics({ start, end: new Date() })
// metrics are now actually limited to the requested time range
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-14 00:18:04 -07:00
Mish Ushakov 32880d6e96 fix(python-sdk): key async transport caches by loop object, not id(loop) (#1434)
## Description

The per-event-loop caches for `AsyncHTTPTransport`s and
`httpx.AsyncClient`s (Sandbox API, envd, and volume clients) were keyed
by `id(asyncio.get_running_loop())`, but CPython reuses object ids of
dead loops almost immediately — so sequential loops could inherit a
transport bound to a previous, closed loop and fail. The caches are now
`weakref.WeakKeyDictionary`s keyed by the loop object itself, which
makes stale id collisions impossible and releases entries when their
loop is garbage collected (fixing a leak where dead-loop entries
accumulated forever). Added regression tests covering the
sequential-loop scenario for all three caches.

This pattern no longer breaks:

```python
# e.g. a worker or test harness running repeated event loops
for job in jobs:
    asyncio.run(process_with_sandbox(job))  # each run previously risked
                                            # inheriting a closed loop's transport
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 22:18:20 +02:00
Mish Ushakov 0b0c728fe8 Fix volume SDK issues: transports, timeouts, empty files, eager stream errors (#1431)
Fixes a batch of review findings in the JS and Python volume SDKs,
aligning behavior between the two. Python now caches `AsyncVolume` HTTP
transports per event loop and proxy (sync per thread) instead of a
process-wide singleton, applies the 60s default `request_timeout` to
metadata operations that previously ran with httpx timeouts disabled, no
longer falls back to `E2B_ACCESS_TOKEN` for volume content auth, and no
longer mutates the caller's `headers` dict. JS `Volume.readFile` now
returns empty values instead of `undefined` for empty files, and volume
content requests get the documented 60s default request timeout. All
changes are covered by new mock-based unit tests (no live API needed)
plus changesets for both SDKs.

## Usage examples

```python
volume = await AsyncVolume.connect(volume_id)

# Times out after 60s by default (previously could hang indefinitely)
entries = await volume.list("/")
```

```ts
const volume = await Volume.connect(volumeId)

// Returns an empty Blob / ReadableStream for empty files (previously undefined)
const blob = await volume.readFile('empty.txt', { format: 'blob' })

// Times out after the documented 60s by default; pass 0 to disable
await volume.getInfo('file.txt', { requestTimeoutMs: 0 })
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 19:17:11 +00:00
Weilu JIa 1328d9fe44 fix(python): Retry connections on HTTP/2 API transports (#1425) 2026-06-12 11:17:27 +00:00
github-actions[bot] de47dfd6b1 [skip ci] Release new versions 2026-06-12 00:18:17 +00:00
Matt Brockman 82d6e323fc Use dedicated clients for Python template uploads (#1424) 2026-06-11 17:10:58 -07:00
Matt Brockman 554dc88bd1 Deduplicate sync thread-local client setup (#1423) 2026-06-11 16:05:38 -07:00
github-actions[bot] b9e131ad88 [skip ci] Release new versions 2026-06-11 20:00:01 +00:00
Matt Brockman 44c1e9f575 Fix/python sync thread local envd (#1422)
safer threading handling
2026-06-11 19:39:33 +00:00
Mish Ushakov 1d5259ca1d fix(sdks): transport proxy caching, request timeout, and option handling (#1421)
Fixes a batch of connection-handling bugs found in review, with unit
tests for each and a changeset for both SDKs.

- **Python**: cached HTTP transports are now keyed on the configured
proxy, so clients with different (or no) proxy settings no longer
silently reuse the transport built for the first proxy seen.
- **Python**: `request_timeout` now applies to control-plane API
requests — the underlying httpx client was previously built with no
timeout at all (`request_timeout=0` still disables it).
- **Python**: the server-stream parser no longer stalls or drops the
final envelope when the remaining payload is shorter than the 5-byte
envelope header; also removed the no-op `@_retry` decorators from the
streaming RPC methods to avoid confusion.
- **JS + Python**: an explicit `debug=False` / `debug: false` now
overrides `E2B_DEBUG=true` instead of being ignored.
- **JS**: the RPC logger no longer crashes requests with a `TypeError`
when a response contains protobuf int64 (`bigint`) fields (e.g.
`EntryInfo.size` returned by `files.list()`/`stat()` and `includeEntry`
watch events); they are logged as strings.

## Usage examples

```ts
// JS: logging RPCs whose responses carry int64 fields no longer throws
const sbx = await Sandbox.create({ logger: console })
await sbx.files.list('/')

// JS: force-disable debug mode even when E2B_DEBUG=true is set
const sbx2 = await Sandbox.create({ debug: false })
```

```python
# Python: per-call API timeout is now actually enforced
Sandbox.list(request_timeout=10)

# Python: clients with different proxies get their own transports
Sandbox.create(proxy="http://127.0.0.1:8080")
Sandbox.create()  # no longer routed through the proxy above
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 19:12:47 +00:00
github-actions[bot] d23ad659a4 [skip ci] Release new versions 2026-06-10 17:33:36 +00:00
Mish Ushakov da85b1e33c feat(sdk): add includeEntry option to filesystem watch (#1385)
Client-side counterpart to
[e2b-dev/infra#2930](https://github.com/e2b-dev/infra/pull/2930): adds
an `includeEntry`/`include_entry` option to filesystem directory
watching across the JS and Python (sync + async) SDKs, so each
`FilesystemEvent` can carry the affected entry's `EntryInfo`
(best-effort — unset for remove/rename-away events where the path no
longer exists). This regenerates the filesystem proto code from the
updated spec, threads the flag through `watchDir`/`watch_dir` (streaming
`WatchDir` and polling `CreateWatcher`), maps the new `entry` field onto
the event, and extracts a shared entry-mapping helper reused by
`list`/`getInfo`/`rename`. The option degrades gracefully: older
sandboxes (< envd 0.6.2) ignore it and leave `entry` unset, so there's
no hard version gate. Includes new watch tests for all three SDKs and a
minor-bump changeset for `e2b` and `@e2b/python-sdk`.

> Note: the entry-info tests require envd 0.6.2 (shipped by the infra
PR), so this should land with/after that deploy.

### Usage

**JavaScript**
```ts
const handle = await sandbox.files.watchDir(
  'my-dir',
  (event) => {
    console.log(event.type, event.name, event.entry?.path, event.entry?.type)
  },
  { includeEntry: true }
)
```

**Python (async)**
```python
def on_event(e):
    print(e.type, e.name, e.entry.path if e.entry else None)

handle = await sandbox.files.watch_dir("my-dir", on_event=on_event, include_entry=True)
```

**Python (sync)**
```python
handle = sandbox.files.watch_dir("my-dir", include_entry=True)
for e in handle.get_new_events():
    print(e.type, e.name, e.entry.path if e.entry else None)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 19:02:09 +02:00
Mish Ushakov 961ffbae84 feat(sdks): expose user-defined file metadata on sandbox.files (#1383)
Adds a `metadata` option to file uploads and surfaces persisted metadata
on every `EntryInfo` / `WriteInfo` returned by `getInfo`, `list`,
`rename`, and write responses, across the JS and Python (sync + async)
SDKs.

Metadata is sent as `X-Metadata-<key>: <value>` request headers and
persisted by envd as `user.e2b.*` extended attributes; the same map is
applied to every file in a multi-file upload. Keys and values must be
printable US-ASCII and keys are lowercased by the sandbox, so they may
differ in case when read back. Requires **envd 0.6.2 or later**.

This syncs the envd OpenAPI spec and filesystem proto with
[infra#2732](https://github.com/e2b-dev/infra/pull/2732) and regenerates
the JS/Python clients.

## Usage

**JavaScript / TypeScript**
```ts
// Single file
const info = await sandbox.files.write('report.txt', 'hello', {
  metadata: { author: 'mish', purpose: 'demo' },
})
console.log(info.metadata) // { author: 'mish', purpose: 'demo' }

// Multiple files (same metadata applied to each)
await sandbox.files.writeFiles(
  [
    { path: 'a.txt', data: 'A' },
    { path: 'b.txt', data: 'B' },
  ],
  { metadata: { source: 'import' } }
)

// Read it back
const stat = await sandbox.files.getInfo('report.txt')
console.log(stat.metadata) // { author: 'mish', purpose: 'demo' }
```

**Python**
```python
# Single file
info = sandbox.files.write("report.txt", "hello", metadata={"author": "mish"})
print(info.metadata)  # {"author": "mish"}

# Multiple files (same metadata applied to each)
sandbox.files.write_files(
    [
        WriteEntry(path="a.txt", data="A"),
        WriteEntry(path="b.txt", data="B"),
    ],
    metadata={"source": "import"},
)

# Read it back
stat = sandbox.files.get_info("report.txt")
print(stat.metadata)  # {"author": "mish"}
```

The async Python API is identical with `await`.

## Tests

Integration tests cover the round-trip across `write` / `getInfo` /
`list` / `rename`, octet-stream uploads, multi-file uploads,
overwrite-clears-stale-metadata, and metadata written directly as
`user.e2b.*` xattrs via `sandbox.commands.run` surfacing in `getInfo`.
They require a sandbox running envd 0.6.2+.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 16:05:34 +00:00
Mish Ushakov 7dc861f899 fix: align behavior and API surface between the JS and Python SDKs (#1411)
Aligns several behavioral and API-surface discrepancies between the JS
and Python SDKs found during a cross-SDK audit. **Python:**
`commands.send_stdin`/`CommandHandle.send_stdin` now accept `bytes`
(plus `request_timeout` on the handle), `git.reset` gets a typed
`GitResetMode` with JS-matching validation, `sandbox_url` is threaded
through `get_api_params` (and the dead `SandboxOpts` key removed), and
`from_image` requires both `username` and `password` when credentials
are given. **JS:** `getFullInfo` was removed in favor of a single
`getInfo` that now includes `sandboxDomain` (matching Python's
`get_info`), `fromImage` requires both credentials, `getBuildStatus`
defaults `logsOffset` to `0`, `getMetrics`/`kill` short-circuit
consistently in debug mode (instance + static), and `requestTimeoutMs:
0` explicitly disables the request timeout. Tests were added on both
sides (git-arg validation, stdin bytes, credential validation,
timeout-0, connection config) and the CLI's `sandbox info` now uses
`getInfo`. See the changeset for the full per-SDK list.

## Usage examples

```ts
// JS: registry credentials now require both fields
Template().fromImage('registry.example.com/img:latest', { username: 'u', password: 'p' })

// JS: getInfo now exposes sandboxDomain (getFullInfo removed)
const info = await Sandbox.getInfo(sandboxId)
console.log(info.sandboxDomain)

// JS: disable the request timeout
await Sandbox.create({ requestTimeoutMs: 0 })
```

```python
# Python: send raw bytes to stdin
sandbox.commands.send_stdin(cmd.pid, b"hello")

# Python: typed git reset mode (validated)
sandbox.git.reset(repo, mode="hard")

# Python: registry credentials require both fields
Template().from_image("registry.example.com/img:latest", username="u", password="p")
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 13:40:22 +00:00
Mish Ushakov f63efeb76d test(sdk): add pty.kill coverage for JS and Python sync/async (#1412)
Adds the previously-missing test coverage for `pty.kill()`, which was
untested across all three SDK implementations despite the rest of the
PTY API (create/connect/sendInput/resize) being well covered.

Each suite gets two tests covering both return paths of `kill()`:
- **Kill a live PTY** — asserts `kill()` returns `true`, then confirms
the process is gone via `kill -0 <pid>` (throws
`ProcessExitError`/`CommandExitException`).
- **Kill a non-existent PID** — asserts `kill()` returns `false`,
matching the documented not-found behavior.

The tests mirror the style of the existing `commands.kill` tests and
were verified to lint cleanly and be discovered by vitest/pytest (full
runs require a live sandbox).

## Files
- `packages/js-sdk/tests/sandbox/pty/kill.test.ts`
- `packages/python-sdk/tests/sync/sandbox_sync/pty/test_pty_kill.py`
- `packages/python-sdk/tests/async/sandbox_async/pty/test_pty_kill.py`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 12:03:27 +02:00
github-actions[bot] a6dca9a31e [skip ci] Release new versions 2026-06-09 17:26:37 +00:00
Mish Ushakov 4e16cffc2f feat(js-sdk): add proxy connection param (#1386)
Adds a `proxy` connection parameter to the JS SDK, mirroring the Python
SDK. When set, requests are routed through the given HTTP proxy via an
undici `ProxyAgent` dispatcher (fetchers are cached per-proxy so
non-proxy traffic is unaffected). It applies to control-plane API
requests, all requests made to the returned sandbox (REST plus
filesystem/commands/pty RPC), and volume requests. Behavior is unchanged
when no proxy is provided, and unit tests cover both the API and envd
fetch paths.

## Usage

```ts
import { Sandbox } from 'e2b'

// Routes API + all sandbox requests through the proxy
const sandbox = await Sandbox.create({
  proxy: 'http://user:pass@127.0.0.1:8080',
})
await sandbox.files.write('/hello.txt', 'world')

// Also works when connecting to an existing sandbox
const sbx = await Sandbox.connect(sandboxId, { proxy: 'http://127.0.0.1:8080' })
```

> Proxying relies on the optional `undici` package and the Node runtime;
in browser/edge runtimes requests use global `fetch`, which has no proxy
support (same as the existing HTTP/2 dispatcher).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:29:16 +02:00
github-actions[bot] 26ca87c3f1 [skip ci] Release new versions 2026-06-09 12:34:31 +00:00
Mish Ushakov d86368a11e fix(python-sdk): align sync and async implementations (#1403)
Reconciles divergences found while auditing the sync and async Python
SDK trees, keeping behavior equivalent across both.

- **Parameter ordering:** aligned `_create` and `Commands._start`
signatures to the public API and to each other, and reordered the
`Commands.connect` rpc args (`headers` before `timeout`) to match the
`_start` convention.
- **`pause` return:** the public `pause()` / `beta_pause()` are now
annotated `-> str` and actually return the sandbox ID (matching
`_cls_pause` and the class-method form, which already returned it)
instead of `-> None`; the `:return:` docstrings are restored.
- **Exceptions:** the internal "Body of the request is None" guard in
`sandbox_api` now consistently raises a bare `Exception` (matching the
volume client) instead of mixing `Exception`/`SandboxException` between
sync and async.
- **Misc:** async `Filesystem.write` now passes keyword args; the async
constructor reuses the cached `envd_api_url` property instead of
recomputing the sandbox URL; async pty `resize` gains a `-> None`
annotation.
- **Docstrings:** aligned the deprecation marker and
`get_metrics`/`write_files`/`kill` wording across sync/async, and fixed
a `**seconds**s` typo.

These are alignment/consistency fixes only; the deeper architectural
async-vs-sync splits (streaming-vs-polling `watch_dir`, pty `on_data`,
command output callbacks) are intentional and left untouched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 14:15:15 +02:00
Mish Ushakov 7296b2c55d fix(python-sdk): drop envd headers from control-plane connect request (#1402)
`Sandbox.connect` was attaching the data-plane envd headers
(`E2b-Sandbox-Id`, `E2b-Sandbox-Port`) to the control-plane `POST
/sandboxes/{id}/connect` call in both the sync and async SDKs. These
headers belong only on data-plane (filesystem/commands/pty) requests, so
this aligns the Python SDK with the JS SDK, which never sends them on
the connect call.

## Usage

No API change — `Sandbox.connect(sandbox_id)` (and the async equivalent)
behaves the same, just without the spurious headers on the control-plane
request.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 12:43:54 +02:00
Mish Ushakov f2550fa999 chore(python-sdk): mark packages as typed (PEP 561) (#1363)
## Summary

Add empty `py.typed` markers to the `e2b` and `e2b_connect` packages so
mypy/Pyright honor the inline annotations on `Sandbox`, `AsyncSandbox`,
and other public APIs instead of treating imports as `Any`. Includes a
patch changeset for `@e2b/python-sdk`.

## Test plan
- [ ] `pip install` the built wheel in a fresh env and confirm `mypy` no
longer reports `e2b` as untyped without `--follow-untyped-imports`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 12:36:06 +02:00
Matt Brockman 6c04e31f68 fix(python-sdk): use thread-local API transports (#1399)
makes the sync python python API http transport cache thread-local to
handle unsafe usage of the shared transport under pressure (e.g.
concurrent template builds). uses the same logic that we were using for
envd.

test
`test_sync_api_transport_cache_reuses_within_thread_and_isolates_across_threads`
fails on main, passes on branch.
2026-06-08 12:36:11 +02:00
Mish Ushakov 08012eeb4a feat: add sendStdin/closeStdin to CommandHandle (#1397)
Adds `sendStdin`/`send_stdin` and `closeStdin`/`close_stdin` directly on
the command handle (JS, Python sync, and Python async) so background
commands can be fed stdin and signalled EOF without reaching back to
`sandbox.commands` with the PID. The handle delegates to the existing
`Commands` methods via closures, mirroring how `kill` is wired, and also
adds the previously-missing `close_stdin`/`aclose_stdin` to the Python
`Commands` class (version-gated on `ENVD_ENVD_CLOSE`, matching JS).
PTY-created handles don't support these and raise a clear error, and the
existing PID-based `Commands.sendStdin` methods are untouched, so the
change is fully backward-compatible. Includes handle-based tests across
all three SDKs and a changeset bumping `e2b` and `@e2b/python-sdk` at
patch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 10:51:39 +02:00
github-actions[bot] c892017cb6 [skip ci] Release new versions 2026-06-06 06:44:16 +00:00
Tomas Valenta 073661a8b5 feat(sdk): add API-only header options (#1395)
## Summary
- Adds `apiHeaders` / `api_headers` for API-only custom headers.
- Deprecates the existing `headers` option in favor of the explicit API
header option.

## Usage
```ts
await Sandbox.create({ apiHeaders: { Authorization: 'Bearer ...' } })
```

```python
sandbox = Sandbox.create(api_headers={"Authorization": "Bearer ..."})
```

## Tests
- Python syntax checks passed for touched files.
- IDE lints and `git diff --check` passed.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-05 23:25:21 -07:00
Mish Ushakov e7a82ea9eb chore: remove unused dead code across SDK packages (#1388)
Removes internal symbols with zero references, found via knip
(js-sdk/cli) and vulture (python-sdk) and verified with repo-wide greps:
`wait` (js-sdk),
`asSandboxTemplate`/`asHeadline`/`selectOption`/`basicDockerfile` (cli),
and `format_execution_timeout_error` (python-sdk). No public API changes
— only dead, unexported-from-index or unreferenced code is dropped.
`format`, `lint`, and `typecheck` pass for all touched packages, and a
patch changeset is included for the three published packages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:50:13 +02:00
Mish Ushakov 5b2bb941de fix(sdk): consistent rate limit error for envd 429 responses (#1387)
## Summary

The main API client already raised `RateLimitError` (JS) /
`RateLimitException` (Python) for HTTP 429, but the lower-level **envd**
HTTP and RPC layers fell through to a generic sandbox error, so the same
rate-limit condition surfaced as a different type depending on which
request path hit it. This maps envd 429 (and the equivalent gRPC
`ResourceExhausted` code) to the dedicated rate-limit error consistently
across the JS SDK and the Python sync/async SDKs. The JS RPC layer was
also missing the `ResourceExhausted` mapping entirely, which is now
added for parity with Python.

## Changes
- `js-sdk/src/envd/api.ts`, `python-sdk/e2b/envd/api.py` — envd HTTP 429
→ `RateLimitError`/`RateLimitException`
- `js-sdk/src/envd/rpc.ts` — added gRPC `Code.ResourceExhausted` →
`RateLimitError`
- Added unit tests for both the envd HTTP and RPC error mappers in JS
and Python
- Changeset (`e2b`: patch)

## Usage example
```ts
import { Sandbox, RateLimitError } from 'e2b'

try {
  await sandbox.files.write('/tmp/file.txt', 'data')
} catch (err) {
  if (err instanceof RateLimitError) {
    // now reliably caught regardless of which request path was rate limited
  }
}
```

```python
from e2b import RateLimitException

try:
    sandbox.files.write("/tmp/file.txt", "data")
except RateLimitException:
    ...
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:44:27 -07:00
dependabot[bot] 33009eb307 chore(deps): bump idna from 3.11 to 3.15 in /packages/python-sdk in the pip group across 1 directory (#1379)
Bumps the pip group with 1 update in the /packages/python-sdk directory:
[idna](https://github.com/kjd/idna).

Updates `idna` from 3.11 to 3.15
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/kjd/idna/blob/master/HISTORY.md">idna's
changelog</a>.</em></p>
<blockquote>
<h2>3.15 (2026-05-12)</h2>
<ul>
<li>Enforce DNS-length cap on individual labels early in
<code>check_label</code>,
short-circuiting contextual-rule processing for oversized input
while staying compatible with UTS 46 usage.</li>
<li>Tidy core helpers: hoist bidi category sets to module-level
frozensets (avoiding per-codepoint list construction), simplify
length checks, and reuse the shared <code>_unicode_dots_re</code> from
<code>idna.core</code> in the codec module.</li>
<li>Use <code>raise ... from err</code> for proper exception chaining
and
switch internal string formatting to f-strings.</li>
<li>Allow <code>flit_core</code> 4.x in the build backend.</li>
<li>Expand the ruff lint set (flake8-bugbear, flake8-simplify,
pyupgrade, perflint) and apply the surfaced fixes; pin lint CI
to Python 3.14.</li>
<li>Add Dependabot configuration for GitHub Actions.</li>
<li>Convert README and HISTORY from reStructuredText to Markdown.</li>
<li>Reference CVE-2026-45409 for the 3.14 advisory in place of the
initial GHSA identifier.</li>
</ul>
<p>Thanks to Felix Yan, Stan Ulbrych, and metsw24-max for
contributions to this release.</p>
<h2>3.14 (2026-05-10)</h2>
<ul>
<li>Removed opportunity to process long inputs into quadratic
time by rejecting oversize inputs up-front. Closes a bypass
of the CVE-2024-3651 mitigation. [CVE-2026-45409]</li>
</ul>
<p>Thanks to Stan Ulbrych for reporting the issue.</p>
<h2>3.13 (2026-04-22)</h2>
<ul>
<li>Correct classification error for codepoint U+A7F1</li>
</ul>
<h2>3.12 (2026-04-21)</h2>
<ul>
<li>Update to Unicode 17.0.0.</li>
<li>Issue a deprecation warning for the transitional argument.</li>
<li>Added lazy-loading to provide some performance improvements.</li>
<li>Removed vestiges of code related to Python 2 support, including
segmentation of data structures specific to Jython.</li>
</ul>
<p>Thanks to Rodrigo Nogueira for contributions to this release.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/kjd/idna/commit/af30a092e158181d0b35ac66dfa813788126bdd8"><code>af30a09</code></a>
Release 3.15</li>
<li><a
href="https://github.com/kjd/idna/commit/30314d4628744ca14cf2b5820564e5127a9f86f2"><code>30314d4</code></a>
Pre-release 3.15rc0</li>
<li><a
href="https://github.com/kjd/idna/commit/05d4b219aa9eddc47371fcbd2000f0301016f3e9"><code>05d4b21</code></a>
Merge pull request <a
href="https://redirect.github.com/kjd/idna/issues/237">#237</a> from
kjd/convert-docs-to-markdown</li>
<li><a
href="https://github.com/kjd/idna/commit/2987fdba1962bbb2358399e0084ba062b98a0bee"><code>2987fdb</code></a>
Convert README and HISTORY from reStructuredText to Markdown</li>
<li><a
href="https://github.com/kjd/idna/commit/59fa8002d514bf4a5ce7b58f67b9ec587d53fa9c"><code>59fa800</code></a>
Merge pull request <a
href="https://redirect.github.com/kjd/idna/issues/236">#236</a> from
kjd/dependabot/github_actions/actions-f3e34333ea</li>
<li><a
href="https://github.com/kjd/idna/commit/def69834ced5d4b3c50439d8b99c4c856ec19ca2"><code>def6983</code></a>
Merge branch 'master' into
dependabot/github_actions/actions-f3e34333ea</li>
<li><a
href="https://github.com/kjd/idna/commit/bbd8004a797185d8c56bb555cd5c88fde05e0631"><code>bbd8004</code></a>
Merge pull request <a
href="https://redirect.github.com/kjd/idna/issues/234">#234</a> from
StanFromIreland/patch-1</li>
<li><a
href="https://github.com/kjd/idna/commit/edd07c05024344a6ccb517414ccb36683aee99fc"><code>edd07c0</code></a>
Bump github/codeql-action from 3.35.2 to 4.35.2 in the actions
group</li>
<li><a
href="https://github.com/kjd/idna/commit/5557db030c11bdec50d62aa5f631d705d33ba123"><code>5557db0</code></a>
Merge branch 'master' into patch-1</li>
<li><a
href="https://github.com/kjd/idna/commit/f11746cf4981d25123ef7830d3ee60f07de8ae3d"><code>f11746c</code></a>
Merge pull request <a
href="https://redirect.github.com/kjd/idna/issues/235">#235</a> from
StanFromIreland/patch-2</li>
<li>Additional commits viewable in <a
href="https://github.com/kjd/idna/compare/v3.11...v3.15">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=idna&package-manager=pip&previous-version=3.11&new-version=3.15)](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>
2026-06-05 06:18:40 -07:00
dependabot[bot] 6e3a469a8c chore(deps-dev): bump urllib3 from 2.6.3 to 2.7.0 in /packages/python-sdk in the pip group across 1 directory (#1324)
Bumps the pip group with 1 update in the /packages/python-sdk directory:
[urllib3](https://github.com/urllib3/urllib3).

Updates `urllib3` from 2.6.3 to 2.7.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/urllib3/urllib3/releases">urllib3's
releases</a>.</em></p>
<blockquote>
<h2>2.7.0</h2>
<h2>🚀 urllib3 is fundraising for HTTP/2 support</h2>
<p><a
href="https://sethmlarson.dev/urllib3-is-fundraising-for-http2-support">urllib3
is raising ~$40,000 USD</a> to release HTTP/2 support and ensure
long-term sustainable maintenance of the project after a sharp decline
in financial support. If your company or organization uses Python and
would benefit from HTTP/2 support in Requests, pip, cloud SDKs, and
thousands of other projects <a
href="https://opencollective.com/urllib3">please consider contributing
financially</a> to ensure HTTP/2 support is developed sustainably and
maintained for the long-haul.</p>
<p>Thank you for your support.</p>
<h2>Security</h2>
<p>Addressed high-severity security issues. Impact was limited to
specific use cases detailed in the accompanying advisories; overall user
exposure was estimated to be marginal.</p>
<ul>
<li>
<p>Decompression-bomb safeguards of the streaming API were bypassed:</p>
<ol>
<li>When <code>HTTPResponse.drain_conn()</code> was called after the
response had been read and decompressed partially. (Reported by <a
href="https://github.com/Cycloctane"><code>@​Cycloctane</code></a>)</li>
<li>During the second <code>HTTPResponse.read(amt=N)</code> or
<code>HTTPResponse.stream(amt=N)</code> call when the response was
decompressed using the official <a
href="https://pypi.org/project/brotli/">Brotli</a> library. (Reported by
<a
href="https://github.com/kimkou2024"><code>@​kimkou2024</code></a>)</li>
</ol>
<p>See GHSA-mf9v-mfxr-j63j for details.</p>
</li>
<li>
<p>HTTP pools created using
<code>ProxyManager.connection_from_url</code> did not strip sensitive
headers specified in <code>Retry.remove_headers_on_redirect</code> when
redirecting to a different host. (GHSA-qccp-gfcp-xxvc reported by <a
href="https://github.com/christos-spearbit"><code>@​christos-spearbit</code></a>)</p>
</li>
</ul>
<h2>Deprecations and Removals</h2>
<ul>
<li>Used <code>FutureWarning</code> instead of
<code>DeprecationWarning</code> for better visibility of existing
deprecation notices. Rescheduled the removal of deprecated features to
version 3.0. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3763">urllib3/urllib3#3763</a>)</li>
<li>Removed support for end-of-life Python 3.9. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3720">urllib3/urllib3#3720</a>)</li>
<li>Removed support for end-of-life PyPy3.10. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4979">urllib3/urllib3#4979</a>)</li>
<li>Bumped the minimum supported pyOpenSSL version to 19.0.0. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3777">urllib3/urllib3#3777</a>)</li>
</ul>
<h2>Bugfixes</h2>
<ul>
<li>Fixed a bug where <code>HTTPResponse.read(amt=None)</code> was
ignoring decompressed data buffered from previous partial reads. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3636">urllib3/urllib3#3636</a>)</li>
<li>Fixed a bug where <code>HTTPResponse.read()</code> could cache only
part of the response after a partial read when
<code>cache_content=True</code>. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4967">urllib3/urllib3#4967</a>)</li>
<li>Fixed <code>HTTPResponse.stream()</code> and
<code>HTTPResponse.read_chunked()</code> to handle <code>amt=0</code>.
(<a
href="https://redirect.github.com/urllib3/urllib3/issues/3793">urllib3/urllib3#3793</a>)</li>
<li>Updated <code>_TYPE_BODY</code> type alias to include missing
<code>Iterable[str]</code>, matching the documented and runtime behavior
of chunked request bodies. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3798">urllib3/urllib3#3798</a>)</li>
<li>Fixed <code>LocationParseError</code> when paths resembling
schemeless URIs were passed to
<code>HTTPConnectionPool.urlopen()</code>. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3352">urllib3/urllib3#3352</a>)</li>
<li>Fixed <code>BaseHTTPResponse.readinto()</code> type annotation to
accept <code>memoryview</code> in addition to <code>bytearray</code>,
matching the <code>io.RawIOBase.readinto</code> contract and enabling
use with <code>io.BufferedReader</code> without type errors. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3764">urllib3/urllib3#3764</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/urllib3/urllib3/blob/main/CHANGES.rst">urllib3's
changelog</a>.</em></p>
<blockquote>
<h1>2.7.0 (2026-05-07)</h1>
<h2>Security</h2>
<p>Addressed high-severity security issues.
Impact was limited to specific use cases detailed in the accompanying
advisories; overall user exposure was estimated to be marginal.</p>
<ul>
<li>
<p>Decompression-bomb safeguards of the streaming API were bypassed:</p>
<ol>
<li>When <code>HTTPResponse.drain_conn()</code> was called after the
response had been
read and decompressed partially.</li>
<li>During the second <code>HTTPResponse.read(amt=N)</code> or
<code>HTTPResponse.stream(amt=N)</code> call when the response was
decompressed
using the official <code>Brotli
&lt;https://pypi.org/project/brotli/&gt;</code>__ library.</li>
</ol>
<p>See <code>GHSA-mf9v-mfxr-j63j
&lt;https://github.com/urllib3/urllib3/security/advisories/GHSA-mf9v-mfxr-j63j&gt;</code>__
for details.</p>
</li>
<li>
<p>HTTP pools created using
<code>ProxyManager.connection_from_url</code> did not strip
sensitive headers specified in
<code>Retry.remove_headers_on_redirect</code> when
redirecting to a different host.
(<code>GHSA-qccp-gfcp-xxvc
&lt;https://github.com/urllib3/urllib3/security/advisories/GHSA-qccp-gfcp-xxvc&gt;</code>__)</p>
</li>
</ul>
<h2>Deprecations and Removals</h2>
<ul>
<li>Used <code>FutureWarning</code> instead of
<code>DeprecationWarning</code> for better
visibility of existing deprecation notices. Rescheduled the removal of
deprecated features to version 3.0.
(<code>[#3763](https://github.com/urllib3/urllib3/issues/3763)
&lt;https://github.com/urllib3/urllib3/issues/3763&gt;</code>__)</li>
<li>Removed support for end-of-life Python 3.9.
(<code>[#3720](https://github.com/urllib3/urllib3/issues/3720)
&lt;https://github.com/urllib3/urllib3/issues/3720&gt;</code>__)</li>
<li>Removed support for end-of-life PyPy3.10.
(<code>[#4979](https://github.com/urllib3/urllib3/issues/4979)
&lt;https://github.com/urllib3/urllib3/issues/4979&gt;</code>__)</li>
<li>Bumped the minimum supported pyOpenSSL version to 19.0.0.
(<code>[#3777](https://github.com/urllib3/urllib3/issues/3777)
&lt;https://github.com/urllib3/urllib3/issues/3777&gt;</code>__)</li>
</ul>
<h2>Bugfixes</h2>
<ul>
<li>Fixed a bug where <code>HTTPResponse.read(amt=None)</code> was
ignoring decompressed
data buffered from previous partial reads.
(<code>[#3636](https://github.com/urllib3/urllib3/issues/3636)
&lt;https://github.com/urllib3/urllib3/issues/3636&gt;</code>__)</li>
<li>Fixed a bug where <code>HTTPResponse.read()</code> could cache only
part of the
response after a partial read when <code>cache_content=True</code>.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/urllib3/urllib3/commit/9a950b92d999f906b6020bb2d1076ee56cddd5d2"><code>9a950b9</code></a>
Release 2.7.0</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/5ec0de499b9166ca71c65ab04f2a7e4eb0d66fcc"><code>5ec0de4</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/2bdcc44d1e163fb5cc48a8662425e35e15adfe6a"><code>2bdcc44</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/f45b0df09d8620ac6ed0491eb9362c8c87b7bc2c"><code>f45b0df</code></a>
Fix a misleading example for <code>ProxyManager</code> (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4970">#4970</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/577193ca029872384f82c133449e0935f6d8a64b"><code>577193c</code></a>
Switch to nightly PyPy3.11 in CI for now (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4984">#4984</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/e90af45bb006c3a452a3a21644a2681523f5c7fc"><code>e90af45</code></a>
Avoid infinite loop in <code>HTTPResponse.read_chunked</code> when
<code>amt=0</code> (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4974">#4974</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/67ed74fdaec6659a6534621ec8e3aaaa6f976210"><code>67ed74f</code></a>
Bump dev dependencies (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4972">#4972</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/3abd481097b54d87b574ac7ea593c3f40938a84d"><code>3abd481</code></a>
Upgrade mypy to version 1.20.2 (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4978">#4978</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/2b8725dfcac4f21d4d93cc0cc3a64a33af08f890"><code>2b8725d</code></a>
Drop support for EOL PyPy3.10 (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4979">#4979</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/2944b2a0a6c573f5548a39cfd17196f98ee21b33"><code>2944b2a</code></a>
Upgrade <code>setup-chrome</code> and <code>setup-firefox</code> to fix
warnings (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4973">#4973</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/urllib3/urllib3/compare/2.6.3...2.7.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=urllib3&package-manager=pip&previous-version=2.6.3&new-version=2.7.0)](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: Jakub Novák <jakub@e2b.dev>
2026-06-01 18:57:09 +02:00
github-actions[bot] e113618db0 [skip ci] Release new versions 2026-05-29 23:46:06 +00:00
Matt Brockman 4b9cc043dc Fix/python envd stable transport (#1368) 2026-05-29 16:39:30 -07:00
github-actions[bot] 44f07b607a [skip ci] Release new versions 2026-05-27 21:33:52 +00:00
Mish Ushakov 4a4bb36839 feat(sdk): validate E2B API key format client-side (#1356)
## Summary

- Both JS and Python SDKs now validate that the configured E2B API key
matches `e2b_` followed by 40 hex characters (mirroring the server-side
check in
[`infra/.../keys/key.go`](https://github.com/e2b-dev/infra/blob/main/packages/shared/pkg/keys/key.go#L66))
and throw `AuthenticationError` / `AuthenticationException` with an
example token (`e2b_0000…`) and a link to the API Keys dashboard tab.
- Validation runs inside `ApiClient` / `ApiClient.__init__` whenever an
API key is present, so callers get immediate, actionable feedback
instead of a generic 401 from the server.
- Added unit tests (`validateApiKey.test.ts`,
`test_validate_api_key.py`) and updated existing fixtures that used
placeholder keys like `'test-key'` / `'base-api-key'` to use the valid
format.

## Test plan

- [x] `pnpm run format`, `pnpm run lint`, `pnpm run typecheck`
- [x] `pnpm exec vitest run tests/api/validateApiKey.test.ts
tests/api/handleApiError.test.ts tests/sandbox/abortSignal.test.ts
tests/template/abortSignal.test.ts
tests/sandbox/configPropagation.test.ts tests/connectionConfig.test.ts`
- [x] `poetry run pytest tests/test_validate_api_key.py
tests/test_api_client_transport.py
tests/sync/sandbox_sync/test_config_propagation.py
tests/async/sandbox_async/test_config_propagation.py
tests/test_connection_config.py`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 21:21:19 +00:00
Mish Ushakov 2691c73d1c chore(sdk): sync OpenAPI spec from infra, regenerate clients (#1357)
## Summary
- Sync `spec/openapi.yml` from
[e2b-dev/infra@main](https://github.com/e2b-dev/infra/blob/main/spec/openapi.yml)
and re-run `make codegen`.
- Schema changes surfaced in the generated clients:
`SandboxMetric.memCache` (new required int64 — also exposed on the
public `SandboxMetrics` wrapper in both SDKs), `NodeStatus` gains
`standby`, `TeamUser.email` becomes nullable + deprecated, and `POST
/v3/templates` gains a `403` response.
- Upstream-only spec changes (not generated because the client filters
by tag): new `AuthProviderBearerAuth`/`AuthProviderTeamAuth` security
schemes, new admin endpoints for team API keys, and a `clusterID` query
param on `GET /nodes`.

## Test plan
- [x] \`pnpm run format\`, \`pnpm run lint\`, \`pnpm run typecheck\`
- [x] JS \`tests/sandbox/metrics.test.ts\` against the live API
- [x] Python sync + async \`test_metrics.py\` against the live API

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 22:57:28 +02:00
Mish Ushakov a6bf71a083 fix(sdks): handle multi-source COPY/ADD in fromDockerfile (#1355)
## Summary

- Fixes #1349: `Template.fromDockerfile` (JS) and
`Template.from_dockerfile` (Python) silently dropped intermediate
sources from multi-source `COPY`/`ADD`, keeping only the first one and
producing broken images without warning.
- Both parsers now emit one `copy()` call per source to the same
destination (matching Docker semantics), preserving `--chown` across all
calls.
- Added tests in both SDKs (multi-source COPY, and multi-source COPY
with `--chown`), plus changesets for `e2b` and `@e2b/python-sdk`.

## Test plan

- [x] `pnpm run test tests/template/methods/fromDockerfile.test.ts` (JS)
- [x] `poetry run pytest
tests/{async,sync}/template_*/methods/test_from_dockerfile.py` (Python)
- [x] `pnpm run format` / `pnpm run lint`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 22:57:03 +02:00
github-actions[bot] d39f17e123 [skip ci] Release new versions 2026-05-27 00:24:30 +00:00
Mish Ushakov c485bf5476 feat(sdk): add Sandbox.updateNetwork / update_network (#1337) 2026-05-26 17:12:29 -07:00
Mish Ushakov 3786f34336 feat(sdk): support structured network rules with per-host transforms (#1286) 2026-05-26 16:35:21 -07:00
github-actions[bot] 43c4524293 [skip ci] Release new versions 2026-05-22 19:46:53 +00:00
Jakub Novák 8640378c17 feat(python-sdk): allow opting out of HTTP/2 in get_transport (#1347) 2026-05-22 12:40:00 -07:00
Mish Ushakov a9bb287fc1 fix(python-sdk): close gRPC streams on watcher/command teardown (#1346)
## Summary
- `AsyncWatchHandle.stop()` and `AsyncCommandHandle.disconnect()`
previously only cancelled the consumer task and left the underlying
server-streaming gRPC call open — the `await self._events.aclose()` was
commented out as a Python 3.8 `RuntimeError` workaround. On long-lived
sandboxes this leaks one stream per call and eventually produces
`Code.internal: error creating watcher: too many open files`.
- The SDK now pins `python = "^3.10"`, so the workaround is removed.
`stop()`/`disconnect()` cancel the consumer task, await it, then
`aclose()` the async generator. The JS SDK already aborts the underlying
request via `AbortController`, so no JS change is needed.

## Test plan
- [ ] CI: `pnpm run format`, `pnpm run lint`, `pnpm run typecheck`
(passed locally)
- [ ] CI: `tests/async/sandbox_async/files/test_watch.py` and async
command tests still pass
- [ ] Reproduce the leak: in a long-lived async sandbox, repeatedly
create+stop a watcher and confirm fd count no longer climbs

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-22 20:51:21 +02:00
github-actions[bot] 74c42b15ee [skip ci] Release new versions 2026-05-22 15:53:30 +00:00
Jakub Novák 2680c89c3e Remove Sandbox.betaCreate / beta_create (#1344)
It didn't have any extra functionality
2026-05-22 16:36:29 +02:00
github-actions[bot] 9b0c25f8ae [skip ci] Release new versions 2026-05-22 09:48:05 +00:00
Tomas Valenta d21b936bf7 fix(sdks): make lifecycle.on_timeout and auto_pause precedence consistent (#1343)
## Summary

When `lifecycle.on_timeout` is set it wins; otherwise we fall back to
the `auto_pause` argument.

Previously the Python SDKs subscripted `lifecycle["on_timeout"]`, which
raised `KeyError` if a caller passed a `lifecycle` dict missing that key
(TypedDict is not enforced at runtime). The JS SDK silently used the
whole `lifecycle` object even when `onTimeout` was undefined. In both
cases, mixing `lifecycle` and `auto_pause` had inconsistent and
surprising behavior across the public surfaces (`create` vs
`beta_create`).

Now both SDKs use `.get`/optional chaining on `on_timeout` and only
treat `lifecycle` as authoritative when that field is actually present.

Touched files:
- `packages/python-sdk/e2b/sandbox_async/sandbox_api.py`
- `packages/python-sdk/e2b/sandbox_sync/sandbox_api.py`
- `packages/js-sdk/src/sandbox/sandboxApi.ts`

---------

Co-authored-by: Jakub Novak <jakub@e2b.dev>
2026-05-22 02:28:18 -07:00
Mish Ushakov 2ac5de2edf feat(js-sdk): support AbortSignal for request cancellation (#1328) 2026-05-15 23:24:16 +02:00
github-actions[bot] 70f0d833f5 [skip ci] Release new versions 2026-05-14 17:36:14 +00:00
Mish Ushakov eaf452a82b feat: add optional name to createSnapshot and return snapshot names (#1327)
## Summary
- Add optional `name` parameter to `createSnapshot` / `create_snapshot`
in the JS and Python SDKs so callers can name the resulting snapshot
template.
- Return the `names` field from the snapshot API on `SnapshotInfo` (both
in `createSnapshot` responses and in `listSnapshots` paginator results)
so callers can discover the namespaced snapshot names.
- Includes a changeset (`patch` for `e2b` and `@e2b/python-sdk`).

## Test plan
- [ ] `pnpm run format`, `pnpm run lint`, `pnpm run typecheck` all pass
locally
- [ ] Integration tests on a sandbox with valid credentials:
`sandbox.createSnapshot({ name: 'my-snap' })` returns non-empty `names`

Resolves https://github.com/e2b-dev/E2B/issues/1249

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 17:22:31 +00:00
Mish Ushakov 575339b163 test(python-sdk): parallelize async sandbox teardown (#1309)
## Summary
- Replace the sequential `for sandbox in sandboxes: await
sandbox.kill()` teardown in `async_sandbox_factory` with
`asyncio.gather(..., return_exceptions=True)` so a failure on one kill
no longer blocks cleanup of the rest, and teardown runs concurrently.
- Hoist the `_test_failed` check above the loop so the failure log is
printed once per fixture rather than per sandbox.

## Test plan
- [ ] `pnpm run format`, `pnpm run lint`, `pnpm run typecheck`
(python-sdk) all pass
- [ ] `pnpm run test` against affected python async sandbox tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 13:26:47 +00:00