From dd26a1455e36369d532cacca60b59720e0e28523 Mon Sep 17 00:00:00 2001 From: passionworkeer Date: Fri, 20 Mar 2026 05:33:30 +0800 Subject: [PATCH 01/11] fix: pass apiKey from connectionConfig to pause() method When using Sandbox.connect() with an apiKey, the pause() method was not passing the apiKey to the API call, causing auth failures. This fix ensures pause() (and deprecated betaPause()) use the same pattern as kill() - merging connectionConfig with provided opts. Fixes: #1215 --- packages/js-sdk/src/sandbox/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/js-sdk/src/sandbox/index.ts b/packages/js-sdk/src/sandbox/index.ts index 3471dec6cd..63578aa283 100644 --- a/packages/js-sdk/src/sandbox/index.ts +++ b/packages/js-sdk/src/sandbox/index.ts @@ -585,14 +585,14 @@ export class Sandbox extends SandboxApi { * ``` */ async pause(opts?: ConnectionOpts): Promise { - return await SandboxApi.pause(this.sandboxId, opts) + return await SandboxApi.pause(this.sandboxId, { ...this.connectionConfig, ...opts }) } /** * @deprecated Use {@link Sandbox.pause} instead. */ async betaPause(opts?: ConnectionOpts): Promise { - return await SandboxApi.betaPause(this.sandboxId, opts) + return await SandboxApi.betaPause(this.sandboxId, { ...this.connectionConfig, ...opts }) } /** From 725d3627660bc0a92b12f7f83eff20b294839d2f Mon Sep 17 00:00:00 2001 From: passionworkeer Date: Sat, 21 Mar 2026 00:06:42 +0800 Subject: [PATCH 02/11] fix: update pause() JSDoc and add regression tests for apiKey propagation - Update @returns JSDoc: pause() returns boolean (true=paused, false=already paused) matching SandboxApi.pause semantics, not a sandbox ID - Add regression tests for apiKey propagation in Sandbox.connect(): - pause() succeeds when E2B_API_KEY is unset but apiKey is passed to connect() - pause() returns false when sandbox is already paused - pause() works on connected sandbox with apiKey in connectionConfig Refs: Copilot PR #1218 review comments --- packages/js-sdk/src/sandbox/index.ts | 2 +- packages/js-sdk/tests/sandbox/pause.test.ts | 75 +++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 packages/js-sdk/tests/sandbox/pause.test.ts diff --git a/packages/js-sdk/src/sandbox/index.ts b/packages/js-sdk/src/sandbox/index.ts index 63578aa283..3920b70c2d 100644 --- a/packages/js-sdk/src/sandbox/index.ts +++ b/packages/js-sdk/src/sandbox/index.ts @@ -576,7 +576,7 @@ export class Sandbox extends SandboxApi { * * @param opts connection options. * - * @returns sandbox ID that can be used to resume the sandbox. + * @returns true if the sandbox was paused successfully, false if it was already paused. * * @example * ```ts diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts new file mode 100644 index 0000000000..7d10d07fbd --- /dev/null +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -0,0 +1,75 @@ +import { assert, expect } from 'vitest' + +import { Sandbox } from '../../src' +import { isDebug, sandboxTest, template } from '../setup' + +/** + * Regression test: Sandbox.connect() with explicit apiKey should allow + * pause() to succeed even when E2B_API_KEY is not set in the environment. + * + * See: https://github.com/e2b-dev/E2B/pull/1218 + */ +sandboxTest.skipIf(isDebug)( + 'pause() uses apiKey from connectionConfig when E2B_API_KEY is not set', + async ({ sandbox }) => { + // Save and clear the environment API key + const savedApiKey = process.env.E2B_API_KEY + delete process.env.E2B_API_KEY + + try { + // Get the apiKey that was used to create this sandbox + const apiKey = process.env.E2B_API_KEY || savedApiKey + expect(apiKey).toBeDefined() + + // Connect to the sandbox with an explicit apiKey (E2B_API_KEY is now unset) + const connected = Sandbox.connect(sandbox.sandboxId, { apiKey }) + + // pause() should succeed using the apiKey from connectionConfig + // rather than requiring E2B_API_KEY to be set + const paused = await connected.pause() + assert.isTrue(paused, 'pause() should return true when successfully pausing a running sandbox') + + // Verify the sandbox is actually paused + assert.isFalse(await connected.isRunning(), 'sandbox should be paused after pause()') + } finally { + // Restore the environment API key + if (savedApiKey) { + process.env.E2B_API_KEY = savedApiKey + } + } + } +) + +sandboxTest.skipIf(isDebug)( + 'pause() returns false when sandbox is already paused', + async ({ sandbox }) => { + // Pause the sandbox first + const firstPause = await sandbox.pause() + assert.isTrue(firstPause, 'first pause() should return true') + + // Try to pause again - should return false since already paused + const secondPause = await sandbox.pause() + assert.isFalse(secondPause, 'pause() should return false when sandbox is already paused') + } +) + +sandboxTest.skipIf(isDebug)( + 'pause() works on connected sandbox with apiKey in connectionConfig', + async ({ sandbox }) => { + const apiKey = process.env.E2B_API_KEY + expect(apiKey).toBeDefined() + + // Connect to the sandbox using apiKey from connectionConfig + const connected = Sandbox.connect(sandbox.sandboxId, { apiKey }) + + // Ensure the sandbox is running before pausing + assert.isTrue(await sandbox.isRunning()) + + // Pause the connected sandbox + const paused = await connected.pause() + assert.isTrue(paused, 'pause() should succeed on connected sandbox') + + // Verify it's paused + assert.isFalse(await connected.isRunning()) + } +) From 1e9f602b0ae0e895b3a03ca86883f3d9b4e43f6b Mon Sep 17 00:00:00 2001 From: passionworkeer Date: Sat, 21 Mar 2026 00:33:31 +0800 Subject: [PATCH 03/11] fix: address Copilot review comments on pause() regression tests - Remove unused template import - Change savedApiKey truthy check to explicit undefined check - Add await before Sandbox.connect() calls (P1 - async Promise fix) - Add explicit non-null assertion after toBeDefined() for TypeScript --- packages/js-sdk/tests/sandbox/pause.test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index 7d10d07fbd..55f9f03f52 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -1,7 +1,7 @@ import { assert, expect } from 'vitest' import { Sandbox } from '../../src' -import { isDebug, sandboxTest, template } from '../setup' +import { isDebug, sandboxTest } from '../setup' /** * Regression test: Sandbox.connect() with explicit apiKey should allow @@ -20,9 +20,10 @@ sandboxTest.skipIf(isDebug)( // Get the apiKey that was used to create this sandbox const apiKey = process.env.E2B_API_KEY || savedApiKey expect(apiKey).toBeDefined() + const finalApiKey = apiKey! // Connect to the sandbox with an explicit apiKey (E2B_API_KEY is now unset) - const connected = Sandbox.connect(sandbox.sandboxId, { apiKey }) + const connected = await Sandbox.connect(sandbox.sandboxId, { apiKey: finalApiKey }) // pause() should succeed using the apiKey from connectionConfig // rather than requiring E2B_API_KEY to be set @@ -33,8 +34,10 @@ sandboxTest.skipIf(isDebug)( assert.isFalse(await connected.isRunning(), 'sandbox should be paused after pause()') } finally { // Restore the environment API key - if (savedApiKey) { + if (savedApiKey !== undefined) { process.env.E2B_API_KEY = savedApiKey + } else { + delete process.env.E2B_API_KEY } } } @@ -58,9 +61,10 @@ sandboxTest.skipIf(isDebug)( async ({ sandbox }) => { const apiKey = process.env.E2B_API_KEY expect(apiKey).toBeDefined() + const finalApiKey = apiKey! // Connect to the sandbox using apiKey from connectionConfig - const connected = Sandbox.connect(sandbox.sandboxId, { apiKey }) + const connected = await Sandbox.connect(sandbox.sandboxId, { apiKey: finalApiKey }) // Ensure the sandbox is running before pausing assert.isTrue(await sandbox.isRunning()) From 92680674aa2d86ddfd3f1d306512927c7fe58705 Mon Sep 17 00:00:00 2001 From: TRIX Date: Sat, 21 Mar 2026 12:05:03 +0800 Subject: [PATCH 04/11] fix: address Copilot review comments on pause() regression tests - Use savedApiKey directly instead of re-reading from process.env after deletion - Update pause() JSDoc to say 'Pause this sandbox' (instance method, not static) Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- packages/js-sdk/src/sandbox/index.ts | 2 +- packages/js-sdk/tests/sandbox/pause.test.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/js-sdk/src/sandbox/index.ts b/packages/js-sdk/src/sandbox/index.ts index 3920b70c2d..b3a18f6e25 100644 --- a/packages/js-sdk/src/sandbox/index.ts +++ b/packages/js-sdk/src/sandbox/index.ts @@ -572,7 +572,7 @@ export class Sandbox extends SandboxApi { } /** - * Pause a sandbox by its ID. + * Pause this sandbox. * * @param opts connection options. * diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index 55f9f03f52..aafd1876e5 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -18,9 +18,10 @@ sandboxTest.skipIf(isDebug)( try { // Get the apiKey that was used to create this sandbox - const apiKey = process.env.E2B_API_KEY || savedApiKey - expect(apiKey).toBeDefined() - const finalApiKey = apiKey! + const finalApiKey = savedApiKey + if (finalApiKey === undefined) { + throw new Error('apiKey must be defined at this point') + } // Connect to the sandbox with an explicit apiKey (E2B_API_KEY is now unset) const connected = await Sandbox.connect(sandbox.sandboxId, { apiKey: finalApiKey }) From 2f9021cdb15dbccfa951c3e0157a28646f0dd76e Mon Sep 17 00:00:00 2001 From: TRIX Date: Sun, 22 Mar 2026 02:41:43 +0800 Subject: [PATCH 05/11] chore: add changeset for pause() JSDoc fix --- .changeset/fix-pause-jsdoc-test.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-pause-jsdoc-test.md diff --git a/.changeset/fix-pause-jsdoc-test.md b/.changeset/fix-pause-jsdoc-test.md new file mode 100644 index 0000000000..24370e7499 --- /dev/null +++ b/.changeset/fix-pause-jsdoc-test.md @@ -0,0 +1,5 @@ +--- +"e2b": patch +--- + +fix: update pause() JSDoc and add regression tests for apiKey propagation From bf8afcbf0f9fbb14aa995dba323ee71c811c038a Mon Sep 17 00:00:00 2001 From: passionworkeer Date: Wed, 25 Mar 2026 20:12:19 +0800 Subject: [PATCH 06/11] chore(js-sdk): apply lint/format fixes to pause() JSDoc and regression tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-format the spread expressions in pause()/betaPause() to comply with the project’s prettier/eslint rules, and confirm all review feedback from Copilot and Codex is fully addressed: - Remove unused `template` import (Copilot #1) - Use `savedApiKey !== undefined` guard for env restoration (Copilot #2) - Add explicit throw guard for TypeScript narrowing on apiKey (Copilot #3) - `await Sandbox.connect()` for async correctness (Codex P1) No functional changes — only formatting adjustments and lint compliance. --- packages/js-sdk/src/sandbox/index.ts | 10 +++++++-- packages/js-sdk/tests/sandbox/pause.test.ts | 23 ++++++++++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/js-sdk/src/sandbox/index.ts b/packages/js-sdk/src/sandbox/index.ts index b3a18f6e25..043d8bc18b 100644 --- a/packages/js-sdk/src/sandbox/index.ts +++ b/packages/js-sdk/src/sandbox/index.ts @@ -585,14 +585,20 @@ export class Sandbox extends SandboxApi { * ``` */ async pause(opts?: ConnectionOpts): Promise { - return await SandboxApi.pause(this.sandboxId, { ...this.connectionConfig, ...opts }) + return await SandboxApi.pause(this.sandboxId, { + ...this.connectionConfig, + ...opts, + }) } /** * @deprecated Use {@link Sandbox.pause} instead. */ async betaPause(opts?: ConnectionOpts): Promise { - return await SandboxApi.betaPause(this.sandboxId, { ...this.connectionConfig, ...opts }) + return await SandboxApi.betaPause(this.sandboxId, { + ...this.connectionConfig, + ...opts, + }) } /** diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index aafd1876e5..a00d83d166 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -24,15 +24,23 @@ sandboxTest.skipIf(isDebug)( } // Connect to the sandbox with an explicit apiKey (E2B_API_KEY is now unset) - const connected = await Sandbox.connect(sandbox.sandboxId, { apiKey: finalApiKey }) + const connected = await Sandbox.connect(sandbox.sandboxId, { + apiKey: finalApiKey, + }) // pause() should succeed using the apiKey from connectionConfig // rather than requiring E2B_API_KEY to be set const paused = await connected.pause() - assert.isTrue(paused, 'pause() should return true when successfully pausing a running sandbox') + assert.isTrue( + paused, + 'pause() should return true when successfully pausing a running sandbox' + ) // Verify the sandbox is actually paused - assert.isFalse(await connected.isRunning(), 'sandbox should be paused after pause()') + assert.isFalse( + await connected.isRunning(), + 'sandbox should be paused after pause()' + ) } finally { // Restore the environment API key if (savedApiKey !== undefined) { @@ -53,7 +61,10 @@ sandboxTest.skipIf(isDebug)( // Try to pause again - should return false since already paused const secondPause = await sandbox.pause() - assert.isFalse(secondPause, 'pause() should return false when sandbox is already paused') + assert.isFalse( + secondPause, + 'pause() should return false when sandbox is already paused' + ) } ) @@ -65,7 +76,9 @@ sandboxTest.skipIf(isDebug)( const finalApiKey = apiKey! // Connect to the sandbox using apiKey from connectionConfig - const connected = await Sandbox.connect(sandbox.sandboxId, { apiKey: finalApiKey }) + const connected = await Sandbox.connect(sandbox.sandboxId, { + apiKey: finalApiKey, + }) // Ensure the sandbox is running before pausing assert.isTrue(await sandbox.isRunning()) From 7358071b45ae626c0a6b213ef6fd9471b52fb322 Mon Sep 17 00:00:00 2001 From: passionworkeer <2089966424@qq.com> Date: Fri, 27 Mar 2026 01:06:22 +0800 Subject: [PATCH 07/11] test(js-sdk): add isRunning() guard in already-paused test Add explicit isRunning() verification between the two pause() calls in the "returns false when already paused" test, consistent with the pattern used in the other two pause() tests. Co-Authored-By: Claude Sonnet 4.6 --- packages/js-sdk/tests/sandbox/pause.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index a00d83d166..89ead2f5bf 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -59,6 +59,12 @@ sandboxTest.skipIf(isDebug)( const firstPause = await sandbox.pause() assert.isTrue(firstPause, 'first pause() should return true') + // Verify the sandbox is actually paused before the second attempt + assert.isFalse( + await sandbox.isRunning(), + 'sandbox should be paused after first pause()' + ) + // Try to pause again - should return false since already paused const secondPause = await sandbox.pause() assert.isFalse( From 3af74470922490071fea9409a5c0a126b8806a79 Mon Sep 17 00:00:00 2001 From: passionworkeer <2089966424@qq.com> Date: Fri, 27 Mar 2026 02:09:42 +0800 Subject: [PATCH 08/11] fix(js-sdk): address remaining Copilot review feedback on pause() regression tests - Remove unused 'expect' import from vitest - Replace expect(apiKey).toBeDefined() + apiKey! with explicit if-check + throw in test 3, consistent with test 1 pattern Co-Authored-By: Claude Sonnet 4.6 --- packages/js-sdk/tests/sandbox/pause.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index 89ead2f5bf..81e56091b9 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -1,4 +1,4 @@ -import { assert, expect } from 'vitest' +import { assert } from 'vitest' import { Sandbox } from '../../src' import { isDebug, sandboxTest } from '../setup' @@ -78,8 +78,10 @@ sandboxTest.skipIf(isDebug)( 'pause() works on connected sandbox with apiKey in connectionConfig', async ({ sandbox }) => { const apiKey = process.env.E2B_API_KEY - expect(apiKey).toBeDefined() - const finalApiKey = apiKey! + if (apiKey === undefined) { + throw new Error('E2B_API_KEY must be set in environment') + } + const finalApiKey = apiKey // Connect to the sandbox using apiKey from connectionConfig const connected = await Sandbox.connect(sandbox.sandboxId, { From 6a14636b9f9ee18d218d067a097b919e9cf64f0c Mon Sep 17 00:00:00 2001 From: passionworkeer <2089966424@qq.com> Date: Sat, 28 Mar 2026 06:32:40 +0800 Subject: [PATCH 09/11] fix(js-sdk): use explicit type guard for apiKey in pause regression test Replace the runtime-only `expect(apiKey).toBeDefined()` + `apiKey!` pattern with an explicit if-guard that narrows the type to `string` at compile time. This matches the pattern already used in the first regression test and satisfies TypeScript's type checker when apiKey is typed as optional. Also removes the now-unused `expect` vitest import. Co-Authored-By: Claude Sonnet 4.6 --- packages/js-sdk/tests/sandbox/pause.test.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index 89ead2f5bf..b4e0a1b9d5 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -1,4 +1,4 @@ -import { assert, expect } from 'vitest' +import { assert } from 'vitest' import { Sandbox } from '../../src' import { isDebug, sandboxTest } from '../setup' @@ -78,12 +78,13 @@ sandboxTest.skipIf(isDebug)( 'pause() works on connected sandbox with apiKey in connectionConfig', async ({ sandbox }) => { const apiKey = process.env.E2B_API_KEY - expect(apiKey).toBeDefined() - const finalApiKey = apiKey! + if (apiKey === undefined) { + throw new Error('apiKey must be defined at this point') + } // Connect to the sandbox using apiKey from connectionConfig const connected = await Sandbox.connect(sandbox.sandboxId, { - apiKey: finalApiKey, + apiKey, }) // Ensure the sandbox is running before pausing From 2fbcda3cd7a98e695e21fe5b7565833c6294b0d1 Mon Sep 17 00:00:00 2001 From: passionworkeer <2089966424@qq.com> Date: Sat, 28 Mar 2026 08:06:22 +0800 Subject: [PATCH 10/11] fix(js-sdk): use ?? instead of || for apiKey/accessToken in ConnectionConfig Use nullish coalescing (??) instead of logical OR (||) when reading apiKey and accessToken from opts, so that empty-string values are preserved rather than incorrectly falling back to the environment variable. Also simplify E2B_API_KEY restoration in the pause regression test to use the same ?? pattern. Co-Authored-By: Claude Sonnet 4.6 --- packages/js-sdk/src/connectionConfig.ts | 4 ++-- packages/js-sdk/tests/sandbox/pause.test.ts | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/js-sdk/src/connectionConfig.ts b/packages/js-sdk/src/connectionConfig.ts index 298dff1dd9..68a631b443 100644 --- a/packages/js-sdk/src/connectionConfig.ts +++ b/packages/js-sdk/src/connectionConfig.ts @@ -84,10 +84,10 @@ export class ConnectionConfig { readonly headers?: Record constructor(opts?: ConnectionOpts) { - this.apiKey = opts?.apiKey || ConnectionConfig.apiKey + this.apiKey = opts?.apiKey ?? ConnectionConfig.apiKey this.debug = opts?.debug || ConnectionConfig.debug this.domain = opts?.domain || ConnectionConfig.domain - this.accessToken = opts?.accessToken || ConnectionConfig.accessToken + this.accessToken = opts?.accessToken ?? ConnectionConfig.accessToken this.requestTimeoutMs = opts?.requestTimeoutMs ?? REQUEST_TIMEOUT_MS this.logger = opts?.logger this.headers = opts?.headers || {} diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index 81e56091b9..ae62beb63c 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -42,12 +42,8 @@ sandboxTest.skipIf(isDebug)( 'sandbox should be paused after pause()' ) } finally { - // Restore the environment API key - if (savedApiKey !== undefined) { - process.env.E2B_API_KEY = savedApiKey - } else { - delete process.env.E2B_API_KEY - } + // Restore the environment API key, including empty strings + process.env.E2B_API_KEY = savedApiKey ?? undefined } } ) From 6221c8e6343d6bf16a63c0dc9246f91db0185ad1 Mon Sep 17 00:00:00 2001 From: passionworkeer <2089966424@qq.com> Date: Sat, 28 Mar 2026 08:26:02 +0800 Subject: [PATCH 11/11] fix(js-sdk): add isRunning() guard in apiKey-propagation pause regression test Add an explicit isRunning() assertion before calling pause() in the apiKey-propagation regression test, matching the defensive guard already present in the third pause regression test. Co-Authored-By: Claude Sonnet 4.6 --- packages/js-sdk/tests/sandbox/pause.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/js-sdk/tests/sandbox/pause.test.ts b/packages/js-sdk/tests/sandbox/pause.test.ts index ae62beb63c..e7e32d3df7 100644 --- a/packages/js-sdk/tests/sandbox/pause.test.ts +++ b/packages/js-sdk/tests/sandbox/pause.test.ts @@ -28,6 +28,12 @@ sandboxTest.skipIf(isDebug)( apiKey: finalApiKey, }) + // Guard: ensure the sandbox is running before we try to pause it + assert.isTrue( + await sandbox.isRunning(), + 'sandbox must be running before pause() is called' + ) + // pause() should succeed using the apiKey from connectionConfig // rather than requiring E2B_API_KEY to be set const paused = await connected.pause()