Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .changeset/thirty-sheep-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@e2b/desktop-python': major
'@e2b/desktop': major
---

SDK v2
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ npm install @e2b/desktop
from e2b_desktop import Sandbox

# Create a new desktop sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Launch an application
desktop.launch('google-chrome') # or vscode, firefox, etc.
Expand Down Expand Up @@ -122,7 +122,7 @@ console.log('Stream URL:', desktop.stream.getUrl({ authKey }))

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Start the stream
desktop.stream.start()
Expand Down Expand Up @@ -167,7 +167,7 @@ await desktop.stream.stop()

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Start the stream
desktop.stream.start(
Expand Down Expand Up @@ -220,7 +220,7 @@ await desktop.stream.stop()

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Get current (active) window ID
window_id = desktop.get_current_window_id()
Expand Down Expand Up @@ -261,7 +261,7 @@ await desktop.stream.stop()

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

desktop.double_click()
desktop.left_click()
Expand Down Expand Up @@ -304,7 +304,7 @@ await desktop.mouseRelease('left') // Release the mouse button

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Write text at the current cursor position with customizable typing speed
desktop.write("Hello, world!") # Default: chunk_size=25, delay_in_ms=75
Expand Down Expand Up @@ -341,7 +341,7 @@ await desktop.press(['ctrl', 'c']) // Key combination

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Get current (active) window ID
window_id = desktop.get_current_window_id()
Expand Down Expand Up @@ -376,7 +376,7 @@ const title = await desktop.getWindowTitle(windowId)

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Take a screenshot and save it as "screenshot.png" locally
image = desktop.screenshot()
Expand All @@ -402,7 +402,7 @@ fs.writeFileSync('screenshot.png', image)

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Open file with default application
desktop.files.write("/home/user/index.js", "console.log('hello')") # First create the file
Expand All @@ -427,7 +427,7 @@ await desktop.open('/home/user/index.js') // Then open it

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Launch the application
desktop.launch('google-chrome')
Expand All @@ -450,7 +450,7 @@ await desktop.launch('google-chrome')

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

# Run any bash command
out = desktop.commands.run("ls -la /home/user")
Expand All @@ -475,7 +475,7 @@ console.log(out)

```python
from e2b_desktop import Sandbox
desktop = Sandbox()
desktop = Sandbox.create()

desktop.wait(1000) # Wait for 1 second
```
Expand Down
2 changes: 1 addition & 1 deletion examples/basic-python/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def check_queue():

def main():
print("> Starting desktop sandbox...")
desktop = Sandbox()
desktop = Sandbox.create()
print(" - Desktop Sandbox started, ID:", desktop.sandbox_id)

width, height = desktop.get_screen_size()
Expand Down
2 changes: 1 addition & 1 deletion examples/streaming-apps-python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pip install e2b-desktop
from e2b_desktop import Sandbox

# Create a new desktop sandbox
desktop = Sandbox()
desktop = Sandbox.create()
print('Desktop sandbox created', desktop.sandbox_id)

# Launch an application
Expand Down
2 changes: 1 addition & 1 deletion packages/js-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,6 @@
"vitest": "^3.0.5"
},
"dependencies": {
"e2b": "^1.4.0"
"e2b": "^2.0.0"
}
}
147 changes: 109 additions & 38 deletions packages/js-sdk/src/sandbox.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
Sandbox as SandboxBase,
SandboxOpts as SandboxOptsBase,
SandboxBetaCreateOpts as SandboxBetaCreateOptsBase,
CommandHandle,
CommandResult,
CommandExitError,
ConnectionConfig,
TimeoutError,
} from 'e2b'

Expand Down Expand Up @@ -116,6 +116,31 @@ export interface SandboxOpts extends SandboxOptsBase {
display?: string
}

/**
* Configuration options for the Sandbox environment.
* @interface SandboxOpts
* @extends {SandboxOptsBase}
*/
export interface SandboxBetaCreateOpts extends SandboxBetaCreateOptsBase {
/**
* The screen resolution in pixels, specified as [width, height].
* @type {[number, number]}
*/
resolution?: [number, number]

/**
* Dots per inch (DPI) setting for the display.
* @type {number}
*/
dpi?: number

/**
* Display identifier.
* @type {string}
*/
display?: string
}

export class Sandbox extends SandboxBase {
protected static override readonly defaultTemplate: string = 'desktop'
private lastXfce4Pid: number | null = null
Expand All @@ -138,6 +163,7 @@ export class Sandbox extends SandboxBase {
) {
super(opts)
}

/**
* Create a new sandbox from the default `desktop` sandbox template.
*
Expand Down Expand Up @@ -184,8 +210,6 @@ export class Sandbox extends SandboxBase {
? { template: templateOrOpts, sandboxOpts: opts }
: { template: this.defaultTemplate, sandboxOpts: templateOrOpts }

const config = new ConnectionConfig(sandboxOpts)

// Add DISPLAY environment variable if not already set
const display = opts?.display || ':0'
const sandboxOptsWithDisplay = {
Expand All @@ -196,46 +220,70 @@ export class Sandbox extends SandboxBase {
},
}

let sbx
if (config.debug) {
sbx = new this({
sandboxId: 'desktop',
...sandboxOptsWithDisplay,
...config,
}) as InstanceType<S>
} else {
const sandbox = await this.createSandbox(
template,
sandboxOptsWithDisplay?.timeoutMs ?? this.defaultSandboxTimeoutMs,
sandboxOptsWithDisplay
)
sbx = new this({
...sandbox,
...sandboxOptsWithDisplay,
...config,
}) as InstanceType<S>
}
const sbx = await super.create(template, sandboxOptsWithDisplay) as InstanceType<S>
await sbx._start(display, sandboxOptsWithDisplay)

sbx.display = display
sbx.lastXfce4Pid = null
sbx.stream = new VNCServer(sbx)
return sbx
}

const [width, height] = sandboxOpts?.resolution ?? [1024, 768]
await sbx.commands.run(
`Xvfb ${sbx.display} -ac -screen 0 ${width}x${height}x24 ` +
`-retro -dpi ${sandboxOpts?.dpi ?? 96} -nolisten tcp -nolisten unix`,
{ background: true, timeoutMs: 0 }
)
/**
* Create a new sandbox from the default `desktop` sandbox template.
*
* @param opts connection options.
*
* @returns sandbox instance for the new sandbox.
*
* @example
* ```ts
* const sandbox = await Sandbox.create()
* ```
* @constructs Sandbox
*/
static async betaCreate<S extends typeof Sandbox>(
this: S,
opts?: SandboxBetaCreateOpts
): Promise<InstanceType<S>>
/**
* Create a new sandbox from the specified sandbox template.
*
* @param template sandbox template name or ID.
* @param opts connection options.
*
* @returns sandbox instance for the new sandbox.
*
* @example
* ```ts
* const sandbox = await Sandbox.create('<template-name-or-id>')
* ```
* @constructs Sandbox
*/
static async betaCreate<S extends typeof Sandbox>(
this: S,
template: string,
opts?: SandboxBetaCreateOpts
): Promise<InstanceType<S>>
static async betaCreate<S extends typeof Sandbox>(
this: S,
templateOrOpts?: SandboxBetaCreateOpts | string,
opts?: SandboxOpts
): Promise<InstanceType<S>> {
const { template, sandboxOpts } =
typeof templateOrOpts === 'string'
? { template: templateOrOpts, sandboxOpts: opts }
: { template: this.defaultTemplate, sandboxOpts: templateOrOpts }

let hasStarted = await sbx.waitAndVerify(
`xdpyinfo -display ${sbx.display}`,
(r: CommandResult) => r.exitCode === 0
)
if (!hasStarted) {
throw new TimeoutError('Could not start Xvfb')
// Add DISPLAY environment variable if not already set
const display = opts?.display || ':0'
const sandboxOptsWithDisplay = {
...sandboxOpts,
envs: {
...sandboxOpts?.envs,
DISPLAY: display,
},
}

await sbx.startXfce4()
const sbx = await super.betaCreate(template, sandboxOptsWithDisplay) as InstanceType<S>
await sbx._start(display, sandboxOptsWithDisplay)

return sbx
}
Expand Down Expand Up @@ -593,6 +641,29 @@ export class Sandbox extends SandboxBase {
timeoutMs: 0,
})
}

protected async _start(display:string, opts?: SandboxOpts): Promise<void> {
this.display = display
this.lastXfce4Pid = null
this.stream = new VNCServer(this)

const [width, height] = opts?.resolution ?? [1024, 768]
await this.commands.run(
`Xvfb ${display} -ac -screen 0 ${width}x${height}x24 ` +
`-retro -dpi ${opts?.dpi ?? 96} -nolisten tcp -nolisten unix`,
{ background: true, timeoutMs: 0 }
)

let hasStarted = await this.waitAndVerify(
`xdpyinfo -display ${display}`,
(r: CommandResult) => r.exitCode === 0
)
if (!hasStarted) {
throw new TimeoutError('Could not start Xvfb')
}

await this.startXfce4()
}
}

interface VNCServerOptions {
Expand Down
Loading