Skip to content

Commit 80216a6

Browse files
authored
Merge branch 'main' into add-allow-deny-network-out-support
2 parents 20f27bf + bbeff74 commit 80216a6

File tree

23 files changed

+190
-160
lines changed

23 files changed

+190
-160
lines changed

.changeset/seven-cooks-tie.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"e2b": patch
3+
"@e2b/python-sdk": patch
4+
---
5+
6+
Support overriding sandbox API URL

.changeset/tasty-walls-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'e2b': patch
3+
---
4+
5+
fixes default context directory for windows paths

.github/workflows/cli_tests.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ permissions:
1414

1515
jobs:
1616
test:
17-
defaults:
18-
run:
19-
working-directory: ./packages/cli
2017
name: CLI - Build
2118
runs-on: ubuntu-22.04
2219
steps:
@@ -32,7 +29,6 @@ jobs:
3229

3330
- name: Install pnpm
3431
uses: pnpm/action-setup@v4
35-
id: pnpm-install
3632
with:
3733
version: '${{ env.TOOL_VERSION_PNPM }}'
3834

@@ -47,15 +43,20 @@ jobs:
4743
- name: Configure pnpm
4844
run: |
4945
pnpm config set auto-install-peers true
50-
pnpm config set exclude-links-from-lockfile true
5146
5247
- name: Install dependencies
5348
run: pnpm install --frozen-lockfile
5449

55-
- name: Test build
50+
- name: Build the SDK (pre-requisite for the tests)
5651
run: pnpm build
52+
working-directory: ./packages/js-sdk
53+
54+
- name: Build the CLI
55+
run: pnpm build
56+
working-directory: ./packages/cli
5757

5858
- name: Run tests
5959
run: pnpm test
60+
working-directory: ./packages/cli
6061
env:
6162
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}

.github/workflows/python_sdk_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ jobs:
5050
run: poetry build
5151

5252
- name: Run tests
53-
run: poetry run pytest --verbose -x
53+
run: make test
5454
env:
5555
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}

.tool-versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ deno 1.46.3
22
nodejs 20.19.5
33
pnpm 9.15.5
44
python 3.9
5-
poetry 1.8.3
5+
poetry 2.1.1

packages/js-sdk/src/connectionConfig.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ export interface ConnectionOpts {
3535
* @default E2B_API_URL // environment variable or `https://api.${domain}`
3636
*/
3737
apiUrl?: string
38+
/**
39+
* Sandbox Url to use for the API.
40+
* @internal
41+
* @default E2B_SANDBOX_URL // environment variable or `https://${port}-${sandboxID}.${domain}`
42+
*/
43+
sandboxUrl?: string
3844
/**
3945
* If true the SDK starts in the debug mode and connects to the local envd API server.
4046
* @internal
@@ -62,9 +68,12 @@ export interface ConnectionOpts {
6268
* Configuration for connecting to the API.
6369
*/
6470
export class ConnectionConfig {
71+
public static envdPort = 49983
72+
6573
readonly debug: boolean
6674
readonly domain: string
6775
readonly apiUrl: string
76+
readonly sandboxUrl?: string
6877
readonly logger?: Logger
6978

7079
readonly requestTimeoutMs: number
@@ -88,6 +97,8 @@ export class ConnectionConfig {
8897
opts?.apiUrl ||
8998
ConnectionConfig.apiUrl ||
9099
(this.debug ? 'http://localhost:3000' : `https://api.${this.domain}`)
100+
101+
this.sandboxUrl = opts?.sandboxUrl || ConnectionConfig.sandboxUrl
91102
}
92103

93104
private static get domain() {
@@ -98,6 +109,10 @@ export class ConnectionConfig {
98109
return getEnvVar('E2B_API_URL')
99110
}
100111

112+
private static get sandboxUrl() {
113+
return getEnvVar('E2B_SANDBOX_URL')
114+
}
115+
101116
private static get debug() {
102117
return (getEnvVar('E2B_DEBUG') || 'false').toLowerCase() === 'true'
103118
}
@@ -115,6 +130,25 @@ export class ConnectionConfig {
115130

116131
return timeout ? AbortSignal.timeout(timeout) : undefined
117132
}
133+
134+
getSandboxUrl(
135+
sandboxId: string,
136+
opts: { sandboxDomain: string; envdPort: number }
137+
) {
138+
if (this.sandboxUrl) {
139+
return this.sandboxUrl
140+
}
141+
142+
return `${this.debug ? 'http' : 'https'}://${this.getHost(sandboxId, opts.envdPort, opts.sandboxDomain)}`
143+
}
144+
145+
getHost(sandboxId: string, port: number, sandboxDomain: string) {
146+
if (this.debug) {
147+
return `localhost:${port}`
148+
}
149+
150+
return `${port}-${sandboxId}.${sandboxDomain ?? this.domain}`
151+
}
118152
}
119153

120154
/**

packages/js-sdk/src/sandbox/index.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,15 @@ export class Sandbox extends SandboxApi {
123123
this.sandboxDomain = opts.sandboxDomain ?? this.connectionConfig.domain
124124

125125
this.envdAccessToken = opts.envdAccessToken
126-
this.envdApiUrl = `${
127-
this.connectionConfig.debug ? 'http' : 'https'
128-
}://${this.getHost(this.envdPort)}`
126+
this.envdApiUrl = this.connectionConfig.getSandboxUrl(this.sandboxId, {
127+
sandboxDomain: this.sandboxDomain,
128+
envdPort: this.envdPort,
129+
})
130+
131+
const sandboxHeaders = {
132+
'E2b-Sandbox-Id': this.sandboxId,
133+
'E2b-Sandbox-Port': this.envdPort.toString(),
134+
}
129135

130136
const rpcTransport = createConnectTransport({
131137
baseUrl: this.envdApiUrl,
@@ -141,6 +147,9 @@ export class Sandbox extends SandboxApi {
141147
new Headers(options?.headers).forEach((value, key) =>
142148
headers.append(key, value)
143149
)
150+
new Headers(sandboxHeaders).forEach((value, key) =>
151+
headers.append(key, value)
152+
)
144153

145154
if (this.envdAccessToken) {
146155
headers.append('X-Access-Token', this.envdAccessToken)
@@ -459,11 +468,11 @@ export class Sandbox extends SandboxApi {
459468
* ```
460469
*/
461470
getHost(port: number) {
462-
if (this.connectionConfig.debug) {
463-
return `localhost:${port}`
464-
}
465-
466-
return `${port}-${this.sandboxId}.${this.sandboxDomain}`
471+
return this.connectionConfig.getHost(
472+
this.sandboxId,
473+
port,
474+
this.sandboxDomain
475+
)
467476
}
468477

469478
/**

packages/js-sdk/src/sandbox/sandboxApi.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ export interface SandboxOpts extends ConnectionOpts {
115115
* Sandbox network configuration
116116
*/
117117
network?: SandboxNetworkOpts
118+
119+
/**
120+
* Sandbox URL. Used for local development
121+
*/
122+
sandboxUrl?: string
118123
}
119124

120125
export type SandboxBetaCreateOpts = SandboxOpts & {

packages/js-sdk/src/template/utils.ts

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -176,35 +176,21 @@ export function getCallerFrame(depth: number): string | undefined {
176176
return lines.slice(depth).join('\n')
177177
}
178178

179-
/**
180-
* Extract the directory path from a stack trace line.
181-
*
182-
* Matches patterns like:
183-
* - "at <anonymous> (/path/to/file.js:1:1)"
184-
* - "at /path/to/file.js:1:1"
185-
* - "at <anonymous> (file:///C:/path/to/file.js:1:1)"
186-
* - "at (file:///C:/path/to/file.js:1:1)"
187-
* @param line A line from a stack trace
188-
* @returns The directory of the file, or undefined if not found
189-
*/
190-
export function matchFileDir(line: string): string | undefined {
191-
const match = line.match(
192-
/(?:file:\/\/\/)?([A-Za-z]:)?([/\\][^:]+)(?::\d+:\d+)?\)?/
193-
)
194-
if (match) {
195-
// Extract the full matched path
196-
let filePath = match[0]
197-
198-
// Remove file:/// protocol prefix if present
199-
filePath = filePath.replace(/^file:\/\/\//, '')
200-
201-
// Remove trailing closing parenthesis if present
202-
filePath = filePath.replace(/\)$/, '')
203-
204-
// Remove :line:column suffix if present
205-
filePath = filePath.replace(/:\d+:\d+$/, '')
179+
// adopted from https://github.com/sindresorhus/callsites
180+
export function callsites(depth: number): NodeJS.CallSite[] {
181+
const _originalPrepareStackTrace = Error.prepareStackTrace
182+
try {
183+
let result: NodeJS.CallSite[] = []
184+
Error.prepareStackTrace = (_, callSites) => {
185+
const callSitesWithoutCurrent = callSites.slice(depth)
186+
result = callSitesWithoutCurrent
187+
return callSitesWithoutCurrent
188+
}
206189

207-
return path.dirname(filePath)
190+
new Error().stack
191+
return result
192+
} finally {
193+
Error.prepareStackTrace = _originalPrepareStackTrace
208194
}
209195
}
210196

@@ -215,18 +201,18 @@ export function matchFileDir(line: string): string | undefined {
215201
* @returns The caller's directory path, or undefined if not available
216202
*/
217203
export function getCallerDirectory(depth: number): string | undefined {
218-
const caller = getCallerFrame(depth + 1) // +1 depth to skip this function (getCallerDirectory)
219-
if (!caller) {
220-
return
204+
// +1 depth to skip this function (getCallerDirectory)
205+
const callSites = callsites(depth + 1)
206+
if (callSites.length === 0) {
207+
return undefined
221208
}
222209

223-
const lines = caller.split('\n')
224-
if (lines.length === 0) {
225-
return
210+
const fileName = callSites[0].getFileName()
211+
if (!fileName) {
212+
return undefined
226213
}
227214

228-
const firstLine = lines[0]
229-
return matchFileDir(firstLine)
215+
return path.dirname(fileName)
230216
}
231217

232218
/**

packages/js-sdk/tests/template/utils/matchFileDir.test.ts

Lines changed: 0 additions & 78 deletions
This file was deleted.

0 commit comments

Comments
 (0)