Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-pause-jsdoc-test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"e2b": patch
---

fix: update pause() JSDoc and add regression tests for apiKey propagation
4 changes: 2 additions & 2 deletions packages/js-sdk/src/connectionConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ export class ConnectionConfig {
readonly headers?: Record<string, string>

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 || {}
Expand Down
14 changes: 10 additions & 4 deletions packages/js-sdk/src/sandbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,11 +572,11 @@ export class Sandbox extends SandboxApi {
}

/**
* Pause a sandbox by its ID.
* Pause this sandbox.
*
* @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
Expand All @@ -585,14 +585,20 @@ export class Sandbox extends SandboxApi {
* ```
*/
async pause(opts?: ConnectionOpts): Promise<boolean> {
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<boolean> {
return await SandboxApi.betaPause(this.sandboxId, opts)
return await SandboxApi.betaPause(this.sandboxId, {
...this.connectionConfig,
...opts,
})
}

/**
Expand Down
103 changes: 103 additions & 0 deletions packages/js-sdk/tests/sandbox/pause.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { assert } from 'vitest'

import { Sandbox } from '../../src'
import { isDebug, sandboxTest } 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 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,
})

// 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()
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, including empty strings
process.env.E2B_API_KEY = savedApiKey ?? undefined
}
}
)

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')

// 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(
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
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, {
apiKey: finalApiKey,
})

// 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())
}
)