diff --git a/.github/workflows/cli_tests.yml b/.github/workflows/cli_tests.yml index e66d025ca6..d8229825ec 100644 --- a/.github/workflows/cli_tests.yml +++ b/.github/workflows/cli_tests.yml @@ -2,6 +2,9 @@ name: Test CLI on: workflow_call: + pull_request: + branches: + - main permissions: contents: read diff --git a/.github/workflows/js_sdk_tests.yml b/.github/workflows/js_sdk_tests.yml index da09a9cbcf..56b2d67353 100644 --- a/.github/workflows/js_sdk_tests.yml +++ b/.github/workflows/js_sdk_tests.yml @@ -5,6 +5,9 @@ on: secrets: E2B_API_KEY: required: true + pull_request: + branches: + - main permissions: contents: read diff --git a/.github/workflows/python_sdk_tests.yml b/.github/workflows/python_sdk_tests.yml index a50bdb5c68..2d7eb78b89 100644 --- a/.github/workflows/python_sdk_tests.yml +++ b/.github/workflows/python_sdk_tests.yml @@ -5,6 +5,9 @@ on: secrets: E2B_API_KEY: required: true + pull_request: + branches: + - main permissions: contents: read diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index a8369166b3..07947d00ef 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -82,6 +82,20 @@ const nextConfig = { ], } }, + async redirects() { + return [ + { + source: '/docs/sandbox-templates/overview', + destination: '/docs/sandbox-template', + permanent: true, + }, + { + source: '/docs/sandbox-templates', + destination: '/docs/sandbox-template', + permanent: true, + }, + ] + }, } export default withSearch( diff --git a/apps/web/src/app/(docs)/docs/code-interpreting/analyze-data-with-ai/page.mdx b/apps/web/src/app/(docs)/docs/code-interpreting/analyze-data-with-ai/page.mdx index 925e365c67..5e75c15eb3 100644 --- a/apps/web/src/app/(docs)/docs/code-interpreting/analyze-data-with-ai/page.mdx +++ b/apps/web/src/app/(docs)/docs/code-interpreting/analyze-data-with-ai/page.mdx @@ -6,7 +6,7 @@ import imgChart from '@/images/analyze-data-chart.png' You can use E2B Sandbox to run AI-generated code to analyze data. Here's how the AI data analysis workflow usually looks like: 1. Your user has a dataset in CSV format or other formats. 2. You prompt the LLM to generate code (usually Python) based on the user's data. -3. The sandbox runs the AU-generated code and returns the results. +3. The sandbox runs the AI-generated code and returns the results. 4. You display the results to the user. --- @@ -462,7 +462,7 @@ with open("../dataset.csv", "rb") as f: def run_ai_generated_code(ai_generated_code: str): print('Running the code in the sandbox....') - execution = sbx.notebook.exec_cell(ai_generated_code) + execution = sbx.run_code(ai_generated_code) print('Code execution finished!') # First let's check if the code ran successfully. diff --git a/apps/web/src/app/(docs)/docs/code-interpreting/create-charts-visualizations/static-charts/page.mdx b/apps/web/src/app/(docs)/docs/code-interpreting/create-charts-visualizations/static-charts/page.mdx index 527f9f7abe..28b5b2a397 100644 --- a/apps/web/src/app/(docs)/docs/code-interpreting/create-charts-visualizations/static-charts/page.mdx +++ b/apps/web/src/app/(docs)/docs/code-interpreting/create-charts-visualizations/static-charts/page.mdx @@ -39,8 +39,6 @@ if (firstResult.png) { import base64 from e2b_code_interpreter import Sandbox -sbx = Sandbox() - code_to_run = """ import matplotlib.pyplot as plt diff --git a/apps/web/src/app/(docs)/docs/filesystem/read-write/page.mdx b/apps/web/src/app/(docs)/docs/filesystem/read-write/page.mdx index c61c586c0d..b861cbe68f 100644 --- a/apps/web/src/app/(docs)/docs/filesystem/read-write/page.mdx +++ b/apps/web/src/app/(docs)/docs/filesystem/read-write/page.mdx @@ -2,7 +2,7 @@ ## Reading files -You can read files from the sandbox filesystem using the `files.reado()` method. +You can read files from the sandbox filesystem using the `files.read()` method. ```js @@ -18,20 +18,48 @@ file_content = sandbox.files.read('/path/to/file') ``` -## Writing files +## Writing single files -You can write files to the sandbox filesystem using the `files.write()` method. +You can write single files to the sandbox filesystem using the `files.write()` method. ```js import { Sandbox } from '@e2b/code-interpreter' const sandbox = await Sandbox.create() + await sandbox.files.write('/path/to/file', 'file content') ``` ```python from e2b_code_interpreter import Sandbox sandbox = Sandbox() + await sandbox.files.write('/path/to/file', 'file content') ``` + +## Writing multiple files + +You can also write multiple files to the sandbox filesystem using the `files.write()` method. + + +```js +import { Sandbox } from '@e2b/code-interpreter' +const sandbox = await Sandbox.create() + +await sandbox.files.write([ + { path: '/path/to/a', data: 'file content' }, + { path: '/another/path/to/b', data: 'file content' } +]) +``` +```python +from e2b_code_interpreter import Sandbox + +sandbox = Sandbox() + +await sandbox.files.write([ + { "path": "/path/to/a", "data": "file content" }, + { "path": "another/path/to/b", "data": "file content" } +]) +``` + \ No newline at end of file diff --git a/apps/web/src/app/(docs)/docs/filesystem/upload/page.mdx b/apps/web/src/app/(docs)/docs/filesystem/upload/page.mdx index 1b16f26687..b0d7877d7e 100644 --- a/apps/web/src/app/(docs)/docs/filesystem/upload/page.mdx +++ b/apps/web/src/app/(docs)/docs/filesystem/upload/page.mdx @@ -2,6 +2,8 @@ You can upload data to the sandbox using the `files.write()` method. +## Upload single file + ```js import fs from 'fs' @@ -22,6 +24,89 @@ sandbox = Sandbox() # Read file from local filesystem with open("path/to/local/file", "rb") as file: # Upload file to sandbox - sandbox.files.write("/path/in/sandbox", file) + sandbox.files.write("/path/in/sandbox", file) ``` + +## Upload directory / multiple files + + +```js +const fs = require('fs'); +const path = require('path'); + +import { Sandbox } from '@e2b/code-interpreter' + +const sandbox = await Sandbox.create() + +// Read all files in the directory and store their paths and contents in an array +const readDirectoryFiles = (directoryPath) => { + // Read all files in the local directory + const files = fs.readdirSync(directoryPath); + + // Map files to objects with path and data + const filesArray = files + .filter(file => { + const fullPath = path.join(directoryPath, file); + // Skip if it's a directory + return fs.statSync(fullPath).isFile(); + }) + .map(file => { + const filePath = path.join(directoryPath, file); + + // Read the content of each file + return { + path: filePath, + data: fs.readFileSync(filePath, 'utf8') + }; + }); + + return filesArray; +}; + +// Usage example +const files = readDirectoryContents('/local/dir'); +console.log(files); +// [ +// { path: '/local/dir/file1.txt', data: 'File 1 contents...' }, +// { path: '/local/dir/file2.txt', data: 'File 2 contents...' }, +// ... +// ] + +await sandbox.files.write(files) +``` +```python +import os +from e2b_code_interpreter import Sandbox + +sandbox = Sandbox() + +def read_directory_files(directory_path): + files = [] + + # Iterate through all files in the directory + for filename in os.listdir(directory_path): + file_path = os.path.join(directory_path, filename) + + # Skip if it's a directory + if os.path.isfile(file_path): + # Read file contents in binary mode + with open(file_path, "rb") as file: + files.append({ + 'path': file_path, + 'data': file.read() + }) + + return files + +files = read_directory_files("/local/dir") +print(files) +# [ +# {"'path": "/local/dir/file1.txt", "data": "File 1 contents..." }, +# { "path": "/local/dir/file2.txt", "data": "File 2 contents..." }, +# ... +# ] + +sandbox.files.write(files) +``` + \ No newline at end of file diff --git a/apps/web/src/app/(docs)/docs/sandbox/internet-access/page.mdx b/apps/web/src/app/(docs)/docs/sandbox/internet-access/page.mdx index 40393dd82d..12939b6a28 100644 --- a/apps/web/src/app/(docs)/docs/sandbox/internet-access/page.mdx +++ b/apps/web/src/app/(docs)/docs/sandbox/internet-access/page.mdx @@ -8,7 +8,7 @@ Every sandbox has a public URL that can be used to access running services insid ```js -import { Sandbox } from '@e2b/code-interpeter' +import { Sandbox } from '@e2b/code-interpreter' const sandbox = await Sandbox.create() @@ -31,10 +31,10 @@ The code above will print something like this: ```bash {{ language: 'js' }} -http://3000-i62mff4ahtrdfdkyn2esc-b0b684e9.e2b.dev +https://3000-i62mff4ahtrdfdkyn2esc-b0b684e9.e2b.dev ``` ```bash {{ language: 'python' }} -http://3000-i62mff4ahtrdfdkyn2esc-b0b684e9.e2b.dev +https://3000-i62mff4ahtrdfdkyn2esc-b0b684e9.e2b.dev ``` @@ -47,7 +47,7 @@ In this example we will start a simple HTTP server that listens on port 3000 and ```js -import { Sandbox } from '@e2b/code-interpeter' +import { Sandbox } from '@e2b/code-interpreter' const sandbox = await Sandbox.create() diff --git a/apps/web/src/app/(docs)/docs/sandbox/list/page.mdx b/apps/web/src/app/(docs)/docs/sandbox/list/page.mdx index 7aa2366952..b75205530d 100644 --- a/apps/web/src/app/(docs)/docs/sandbox/list/page.mdx +++ b/apps/web/src/app/(docs)/docs/sandbox/list/page.mdx @@ -63,9 +63,6 @@ Running sandbox template id: 3e4rngfa34txe0gxc1zf ## Filtering sandboxes - -This feature is in a private beta. - You can filter sandboxes by specifying Metadata key value pairs. Specifying multiple key value pairs will return sandboxes that match all of them. @@ -87,7 +84,9 @@ const sandbox = await Sandbox.create({ // List running sandboxes that has `userId` key with value `123` and `env` key with value `dev`. const runningSandboxes = await Sandbox.list({ - filters: { userId: '123', env: 'dev' } // $HighlightLine + query: { + metadata: { userId: '123', env: 'dev' }, // $HighlightLine + }, }) ``` ```python @@ -96,15 +95,20 @@ from e2b_code_interpreter import Sandbox # Create sandbox with metadata. sandbox = Sandbox( metadata={ - "env": "dev", # $HighlightLine - "app": "my-app", # $HighlightLine - "user_id": "123", # $HighlightLine + "env": "dev", # $HighlightLine + "app": "my-app", # $HighlightLine + "user_id": "123", # $HighlightLine }, ) # List running sandboxes that has `userId` key with value `123` and `env` key with value `dev`. -running_sandboxes = Sandbox.list(filters={ - "userId": "123", "env": "dev" # $HighlightLine -}) +running_sandboxes = Sandbox.list( + query=SandboxQuery( + metadata={ + "userId": "123", # $HighlightLine + "env": "dev", # $HighlightLine + } + ), +) ``` diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/auth/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/auth/page.mdx new file mode 100644 index 0000000000..2c82afa69f --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/auth/page.mdx @@ -0,0 +1,58 @@ +## e2b auth + + +authentication commands + +### Usage + +```bash +e2b auth [options] [command] +``` +## e2b auth login + + +log in to CLI + +### Usage + +```bash +e2b auth login [options] +``` + + +## e2b auth logout + + +log out of CLI + +### Usage + +```bash +e2b auth logout [options] +``` + + +## e2b auth info + + +get information about the current user + +### Usage + +```bash +e2b auth info [options] +``` + + +## e2b auth configure + + +configure user + +### Usage + +```bash +e2b auth configure [options] +``` + + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/sandbox/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/sandbox/page.mdx new file mode 100644 index 0000000000..53c9a5b354 --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/sandbox/page.mdx @@ -0,0 +1,89 @@ +## e2b sandbox + + +work with sandboxes + +### Usage + +```bash +e2b sandbox [options] [command] +``` +## e2b sandbox connect + + +connect terminal to already running sandbox + +### Usage + +```bash +e2b sandbox connect [options] +``` + + +## e2b sandbox list + + +list all running sandboxes + +### Usage + +```bash +e2b sandbox list [options] +``` + + +## e2b sandbox kill + + +kill sandbox + +### Usage + +```bash +e2b sandbox kill [options] [sandboxID] +``` + +### Options + + + - `-a, --all: kill all running sandboxes ` + + +## e2b sandbox spawn + + +spawn sandbox and connect terminal to it + +### Usage + +```bash +e2b sandbox spawn [options] [template] +``` + +### Options + + + - `-p, --path : change root directory where command is executed to directory ` + - `--config : specify path to the E2B config toml. By default E2B tries to find ./e2b.toml in root directory. ` + + +## e2b sandbox logs + + +show logs for sandbox + +### Usage + +```bash +e2b sandbox logs [options] +``` + +### Options + + + - `--level : filter logs by level (DEBUG, INFO, WARN, ERROR). The logs with the higher levels will be also shown. [default: INFO]` + - `-f, --follow: keep streaming logs until the sandbox is closed ` + - `--format : specify format for printing logs (json, pretty) [default: pretty]` + - `--loggers [loggers]: filter logs by loggers. Specify multiple loggers by separating them with a comma. ` + + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/template/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/template/page.mdx new file mode 100644 index 0000000000..1211bb3b0d --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/cli/v1.2.3/template/page.mdx @@ -0,0 +1,132 @@ +## e2b template + + +manage sandbox templates + +### Usage + +```bash +e2b template [options] [command] +``` +## e2b template build + + +build sandbox template defined by ./e2b.Dockerfile or ./Dockerfile in root directory. By default the root directory is the current working directory. This command also creates e2b.toml config. + +### Usage + +```bash +e2b template build [options] [template] +``` + +### Options + + + - `-p, --path : change root directory where command is executed to directory ` + - `-d, --dockerfile : specify path to Dockerfile. By default E2B tries to find e2b.Dockerfile or Dockerfile in root directory. ` + - `-n, --name : specify sandbox template name. You can use the template name to start the sandbox with SDK. The template name must be lowercase and contain only letters, numbers, dashes and underscores. ` + - `-c, --cmd : specify command that will be executed when the sandbox is started. ` + - `-t, --team : specify the team ID that the operation will be associated with. You can find team ID in the team settings in the E2B dashboard (https://e2b.dev/dashboard?tab=team). ` + - `--config : specify path to the E2B config toml. By default E2B tries to find ./e2b.toml in root directory. ` + - `--cpu-count : specify the number of CPUs that will be used to run the sandbox. The default value is 2. ` + - `--memory-mb : specify the amount of memory in megabytes that will be used to run the sandbox. Must be an even number. The default value is 512. ` + - `--build-arg : specify additional build arguments for the build command. The format should be =. ` + + +## e2b template list + + +list sandbox templates + +### Usage + +```bash +e2b template list [options] +``` + +### Options + + + - `-t, --team : specify the team ID that the operation will be associated with. You can find team ID in the team settings in the E2B dashboard (https://e2b.dev/dashboard?tab=team). ` + + +## e2b template init + + +create basic E2B Dockerfile (./e2b.Dockerfile) in root directory. You can then run e2b template build to build sandbox template from this Dockerfile + +### Usage + +```bash +e2b template init [options] +``` + +### Options + + + - `-p, --path : change root directory where command is executed to directory ` + + +## e2b template delete + + +delete sandbox template and e2b.toml config + +### Usage + +```bash +e2b template delete [options] [template] +``` + +### Options + + + - `-p, --path : change root directory where command is executed to directory ` + - `--config : specify path to the E2B config toml. By default E2B tries to find ./e2b.toml in root directory. ` + - `-s, --select: select sandbox template from interactive list ` + - `-t, --team : specify the team ID that the operation will be associated with. You can find team ID in the team settings in the E2B dashboard (https://e2b.dev/dashboard?tab=team). ` + - `-y, --yes: skip manual delete confirmation ` + + +## e2b template publish + + +publish sandbox template + +### Usage + +```bash +e2b template publish [options] [template] +``` + +### Options + + + - `-p, --path : change root directory where command is executed to directory ` + - `--config : specify path to the E2B config toml. By default E2B tries to find ./e2b.toml in root directory. ` + - `-s, --select: select sandbox template from interactive list ` + - `-t, --team : specify the team ID that the operation will be associated with. You can find team ID in the team settings in the E2B dashboard (https://e2b.dev/dashboard?tab=team). ` + - `-y, --yes: skip manual publish confirmation ` + + +## e2b template unpublish + + +unpublish sandbox template + +### Usage + +```bash +e2b template unpublish [options] [template] +``` + +### Options + + + - `-p, --path : change root directory where command is executed to directory ` + - `--config : specify path to the E2B config toml. By default E2B tries to find ./e2b.toml in root directory. ` + - `-s, --select: select sandbox template from interactive list ` + - `-t, --team : specify the team ID that the operation will be associated with. You can find team ID in the team settings in the E2B dashboard (https://e2b.dev/dashboard?tab=team). ` + - `-y, --yes: skip manual unpublish confirmation ` + + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/commands/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/commands/page.mdx new file mode 100644 index 0000000000..41f75547a3 --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/commands/page.mdx @@ -0,0 +1,483 @@ +### Commands + +Module for starting and interacting with commands in the sandbox. + +#### Constructors + +```ts +new Commands(transport: Transport, connectionConfig: ConnectionConfig): Commands +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `transport` | `Transport` | +| `connectionConfig` | `ConnectionConfig` | + +###### Returns + +`Commands` + +#### Methods + +### connect() + +```ts +connect(pid: number, opts?: CommandConnectOpts): Promise +``` + +Connect to a running command. +You can use CommandHandle.wait to wait for the command to finish and get execution results. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the command to connect to. You can get the list of running commands using Commands.list. | +| `opts`? | `CommandConnectOpts` | connection options. | + +###### Returns + +`Promise`\<`CommandHandle`\> + +`CommandHandle` handle to interact with the running command. + +### kill() + +```ts +kill(pid: number, opts?: CommandRequestOpts): Promise +``` + +Kill a running command specified by its process ID. +It uses `SIGKILL` signal to kill the command. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the command. You can get the list of running commands using Commands.list. | +| `opts`? | `CommandRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the command was killed, `false` if the command was not found. + +### list() + +```ts +list(opts?: CommandRequestOpts): Promise +``` + +List all running commands and PTY sessions. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts`? | `CommandRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`ProcessInfo`[]\> + +list of running commands and PTY sessions. + +### run() + +###### run(cmd, opts) + +```ts +run(cmd: string, opts?: CommandStartOpts & object): Promise +``` + +Start a new command and wait until it finishes executing. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `cmd` | `string` | command to execute. | +| `opts`? | `CommandStartOpts` & `object` | options for starting the command. | + +###### Returns + +`Promise`\<`CommandResult`\> + +`CommandResult` result of the command execution. + +###### run(cmd, opts) + +```ts +run(cmd: string, opts?: CommandStartOpts & object): Promise +``` + +Start a new command in the background. +You can use CommandHandle.wait to wait for the command to finish and get its result. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `cmd` | `string` | command to execute. | +| `opts`? | `CommandStartOpts` & `object` | options for starting the command | + +###### Returns + +`Promise`\<`CommandHandle`\> + +`CommandHandle` handle to interact with the running command. + +### sendStdin() + +```ts +sendStdin( + pid: number, + data: string, +opts?: CommandRequestOpts): Promise +``` + +Send data to command stdin. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the command. You can get the list of running commands using Commands.list. | +| `data` | `string` | data to send to the command. | +| `opts`? | `CommandRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`void`\> + +*** + +### Pty + +Module for interacting with PTYs (pseudo-terminals) in the sandbox. + +#### Constructors + +```ts +new Pty(transport: Transport, connectionConfig: ConnectionConfig): Pty +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `transport` | `Transport` | +| `connectionConfig` | `ConnectionConfig` | + +###### Returns + +`Pty` + +#### Methods + +### create() + +```ts +create(opts: PtyCreateOpts): Promise +``` + +Create a new PTY (pseudo-terminal). + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts` | `PtyCreateOpts` | options for creating the PTY. | + +###### Returns + +`Promise`\<`CommandHandle`\> + +handle to interact with the PTY. + +### kill() + +```ts +kill(pid: number, opts?: Pick): Promise +``` + +Kill a running PTY specified by process ID. +It uses `SIGKILL` signal to kill the PTY. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the PTY. | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the PTY was killed, `false` if the PTY was not found. + +### resize() + +```ts +resize( + pid: number, + size: object, +opts?: Pick): Promise +``` + +Resize PTY. +Call this when the terminal window is resized and the number of columns and rows has changed. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the PTY. | +| `size` | `object` | new size of the PTY. | +| `size.cols` | `number` | - | +| `size.rows`? | `number` | - | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### sendInput() + +```ts +sendInput( + pid: number, + data: Uint8Array, +opts?: Pick): Promise +``` + +Send input to a PTY. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the PTY. | +| `data` | `Uint8Array` | input data to send to the PTY. | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +## Interfaces + +### CommandRequestOpts + +Options for sending a command request. + +#### Extended by + +- `CommandStartOpts` + +#### Properties + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +*** + +### CommandStartOpts + +Options for starting a new command. + +#### Properties + +### background? + +```ts +optional background: boolean; +``` + +If true, starts command in the background and the method returns immediately. +You can use CommandHandle.wait to wait for the command to finish. + +### cwd? + +```ts +optional cwd: string; +``` + +Working directory for the command. + +###### Default + +```ts +// home directory of the user used to start the command +``` + +### envs? + +```ts +optional envs: Record; +``` + +Environment variables used for the command. + +This overrides the default environment variables from `Sandbox` constructor. + +###### Default + +`{}` + +### onStderr()? + +```ts +optional onStderr: (data: string) => void | Promise; +``` + +Callback for command stderr output. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `data` | `string` | + +###### Returns + +`void` \| `Promise`\<`void`\> + +### onStdout()? + +```ts +optional onStdout: (data: string) => void | Promise; +``` + +Callback for command stdout output. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `data` | `string` | + +###### Returns + +`void` \| `Promise`\<`void`\> + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### timeoutMs? + +```ts +optional timeoutMs: number; +``` + +Timeout for the command in **milliseconds**. + +###### Default + +```ts +60_000 // 60 seconds +``` + +### user? + +```ts +optional user: Username; +``` + +User to run the command as. + +###### Default + +`user` + +*** + +### ProcessInfo + +Information about a command, PTY session or start command running in the sandbox as process. + +#### Properties + +### args + +```ts +args: string[]; +``` + +Command arguments. + +### cmd + +```ts +cmd: string; +``` + +Command that was executed. + +### cwd? + +```ts +optional cwd: string; +``` + +Executed command working directory. + +### envs + +```ts +envs: Record; +``` + +Environment variables used for the command. + +### pid + +```ts +pid: number; +``` + +Process ID. + +### tag? + +```ts +optional tag: string; +``` + +Custom tag used for identifying special commands like start command in the custom template. + +## Type Aliases + +### CommandConnectOpts + +```ts +type CommandConnectOpts: Pick & CommandRequestOpts; +``` + +Options for connecting to a command. diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/errors/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/errors/page.mdx new file mode 100644 index 0000000000..c5aa2cc143 --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/errors/page.mdx @@ -0,0 +1,211 @@ +### AuthenticationError + +Thrown when authentication fails. + +#### Constructors + +```ts +new AuthenticationError(message: any): AuthenticationError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `any` | + +###### Returns + +`AuthenticationError` + +*** + +### InvalidArgumentError + +Thrown when an invalid argument is provided. + +#### Constructors + +```ts +new InvalidArgumentError(message: string): InvalidArgumentError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`InvalidArgumentError` + +*** + +### NotEnoughSpaceError + +Thrown when there is not enough disk space. + +#### Constructors + +```ts +new NotEnoughSpaceError(message: string): NotEnoughSpaceError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`NotEnoughSpaceError` + +*** + +### NotFoundError + +Thrown when a resource is not found. + +#### Constructors + +```ts +new NotFoundError(message: string): NotFoundError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`NotFoundError` + +*** + +### RateLimitError + +Thrown when the API rate limit is exceeded. + +#### Constructors + +```ts +new RateLimitError(message: any): RateLimitError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `any` | + +###### Returns + +`RateLimitError` + +*** + +### SandboxError + +Base class for all sandbox errors. + +Thrown when general sandbox errors occur. + +#### Extended by + +- `TimeoutError` +- `InvalidArgumentError` +- `NotEnoughSpaceError` +- `NotFoundError` +- `AuthenticationError` +- `TemplateError` +- `RateLimitError` + +#### Constructors + +```ts +new SandboxError(message: any): SandboxError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `any` | + +###### Returns + +`SandboxError` + +*** + +### TemplateError + +Thrown when the template uses old envd version. It isn't compatible with the new SDK. + +#### Constructors + +```ts +new TemplateError(message: string): TemplateError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`TemplateError` + +*** + +### TimeoutError + +Thrown when a timeout error occurs. + +The [unavailable] error type is caused by sandbox timeout. + +The [canceled] error type is caused by exceeding request timeout. + +The [deadline_exceeded] error type is caused by exceeding the timeout for command execution, watch, etc. + +The [unknown] error type is sometimes caused by the sandbox timeout when the request is not processed correctly. + +#### Constructors + +```ts +new TimeoutError(message: string): TimeoutError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`TimeoutError` + +## Functions + +### formatSandboxTimeoutError() + +```ts +function formatSandboxTimeoutError(message: string): TimeoutError +``` + +#### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +#### Returns + +`TimeoutError` diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/filesystem/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/filesystem/page.mdx new file mode 100644 index 0000000000..71b13f7881 --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/filesystem/page.mdx @@ -0,0 +1,469 @@ +### FileType + +Sandbox filesystem object type. + +#### Enumeration Members + +| Enumeration Member | Value | Description | +| ------ | ------ | ------ | +| `DIR` | `"dir"` | Filesystem object is a directory. | +| `FILE` | `"file"` | Filesystem object is a file. | + +## Classes + +### Filesystem + +Module for interacting with the sandbox filesystem. + +#### Constructors + +```ts +new Filesystem( + transport: Transport, + envdApi: EnvdApiClient, + connectionConfig: ConnectionConfig): Filesystem +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `transport` | `Transport` | +| `envdApi` | `EnvdApiClient` | +| `connectionConfig` | `ConnectionConfig` | + +###### Returns + +`Filesystem` + +#### Methods + +### exists() + +```ts +exists(path: string, opts?: FilesystemRequestOpts): Promise +``` + +Check if a file or a directory exists. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to a file or a directory | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the file or directory exists, `false` otherwise + +### list() + +```ts +list(path: string, opts?: FilesystemRequestOpts): Promise +``` + +List entries in a directory. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the directory. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`EntryInfo`[]\> + +list of entries in the sandbox filesystem directory. + +### makeDir() + +```ts +makeDir(path: string, opts?: FilesystemRequestOpts): Promise +``` + +Create a new directory and all directories along the way if needed on the specified path. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to a new directory. For example '/dirA/dirB' when creating 'dirB'. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the directory was created, `false` if it already exists. + +### read() + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise +``` + +Read file content as a `string`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`string`\> + +file content as string + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise +``` + +Read file content as a `Uint8Array`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`Uint8Array`\> + +file content as `Uint8Array` + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise +``` + +Read file content as a `Blob`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`Blob`\> + +file content as `Blob` + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise> +``` + +Read file content as a `ReadableStream`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`ReadableStream`\<`Uint8Array`\>\> + +file content as `ReadableStream` + +### remove() + +```ts +remove(path: string, opts?: FilesystemRequestOpts): Promise +``` + +Remove a file or directory. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to a file or directory. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### rename() + +```ts +rename( + oldPath: string, + newPath: string, +opts?: FilesystemRequestOpts): Promise +``` + +Rename a file or directory. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `oldPath` | `string` | path to the file or directory to rename. | +| `newPath` | `string` | new path for the file or directory. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`EntryInfo`\> + +information about renamed file or directory. + +### watchDir() + +```ts +watchDir( + path: string, + onEvent: (event: FilesystemEvent) => void | Promise, +opts?: WatchOpts & object): Promise +``` + +Start watching a directory for filesystem events. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to directory to watch. | +| `onEvent` | (`event`: `FilesystemEvent`) => `void` \| `Promise`\<`void`\> | callback to call when an event in the directory occurs. | +| `opts`? | `WatchOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`WatchHandle`\> + +`WatchHandle` object for stopping watching directory. + +### write() + +###### write(path, data, opts) + +```ts +write( + path: string, + data: string | ArrayBuffer | Blob | ReadableStream, +opts?: FilesystemRequestOpts): Promise +``` + +Write content to a file. + +Writing to a file that doesn't exist creates the file. + +Writing to a file that already exists overwrites the file. + +Writing to a file at path that doesn't exist creates the necessary directories. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to file. | +| `data` | `string` \| `ArrayBuffer` \| `Blob` \| `ReadableStream`\<`any`\> | data to write to the file. Data can be a string, `ArrayBuffer`, `Blob`, or `ReadableStream`. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`EntryInfo`\> + +information about the written file + +###### write(files, opts) + +```ts +write(files: WriteEntry[], opts?: FilesystemRequestOpts): Promise +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `files` | `WriteEntry`[] | +| `opts`? | `FilesystemRequestOpts` | + +###### Returns + +`Promise`\<`EntryInfo`[]\> + +## Interfaces + +### EntryInfo + +Sandbox filesystem object information. + +#### Properties + +### name + +```ts +name: string; +``` + +Name of the filesystem object. + +### path + +```ts +path: string; +``` + +Path to the filesystem object. + +### type? + +```ts +optional type: FileType; +``` + +Type of the filesystem object. + +*** + +### FilesystemRequestOpts + +Options for the sandbox filesystem operations. + +#### Extended by + +- `WatchOpts` + +#### Properties + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### user? + +```ts +optional user: Username; +``` + +User to use for the operation in the sandbox. +This affects the resolution of relative paths and ownership of the created filesystem objects. + +*** + +### WatchOpts + +Options for watching a directory. + +#### Properties + +### onExit()? + +```ts +optional onExit: (err?: Error) => void | Promise; +``` + +Callback to call when the watch operation stops. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `err`? | `Error` | + +###### Returns + +`void` \| `Promise`\<`void`\> + +### recursive? + +```ts +optional recursive: boolean; +``` + +Watch the directory recursively + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### timeoutMs? + +```ts +optional timeoutMs: number; +``` + +Timeout for the watch operation in **milliseconds**. +You can pass `0` to disable the timeout. + +###### Default + +```ts +60_000 // 60 seconds +``` + +### user? + +```ts +optional user: Username; +``` + +User to use for the operation in the sandbox. +This affects the resolution of relative paths and ownership of the created filesystem objects. + +## Type Aliases + +### WriteEntry + +```ts +type WriteEntry: object; +``` + +#### Type declaration + +| Name | Type | +| ------ | ------ | +| `data` | `string` \| `ArrayBuffer` \| `Blob` \| `ReadableStream` | +| `path` | `string` | diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/sandbox/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/sandbox/page.mdx new file mode 100644 index 0000000000..099b14853c --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.0/sandbox/page.mdx @@ -0,0 +1,498 @@ +### Sandbox + +E2B cloud sandbox is a secure and isolated cloud environment. + +The sandbox allows you to: +- Access Linux OS +- Create, list, and delete files and directories +- Run commands +- Run isolated code +- Access the internet + +Check docs here. + +Use Sandbox.create to create a new sandbox. + +#### Example + +```ts +import { Sandbox } from 'e2b' + +const sandbox = await Sandbox.create() +``` + +#### Properties + +| Property | Modifier | Type | Description | +| ------ | ------ | ------ | ------ | +| `commands` | `readonly` | `Commands` | Module for running commands in the sandbox | +| `files` | `readonly` | `Filesystem` | Module for interacting with the sandbox filesystem | +| `pty` | `readonly` | `Pty` | Module for interacting with the sandbox pseudo-terminals | +| `sandboxId` | `readonly` | `string` | Unique identifier of the sandbox. | + +#### Methods + +### downloadUrl() + +```ts +downloadUrl(path: string): string +``` + +Get the URL to download a file from the sandbox. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file to download. | + +###### Returns + +`string` + +URL for downloading file. + +### getHost() + +```ts +getHost(port: number): string +``` + +Get the host address for the specified sandbox port. +You can then use this address to connect to the sandbox port from outside the sandbox via HTTP or WebSocket. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `port` | `number` | number of the port in the sandbox. | + +###### Returns + +`string` + +host address of the sandbox port. + +###### Example + +```ts +const sandbox = await Sandbox.create() +// Start an HTTP server +await sandbox.commands.exec('python3 -m http.server 3000') +// Get the hostname of the HTTP server +const serverURL = sandbox.getHost(3000) +``` + +### isRunning() + +```ts +isRunning(opts?: Pick): Promise +``` + +Check if the sandbox is running. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the sandbox is running, `false` otherwise. + +###### Example + +```ts +const sandbox = await Sandbox.create() +await sandbox.isRunning() // Returns true + +await sandbox.kill() +await sandbox.isRunning() // Returns false +``` + +### kill() + +```ts +kill(opts?: Pick): Promise +``` + +Kill the sandbox. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts`? | `Pick`\<`SandboxOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### setTimeout() + +```ts +setTimeout(timeoutMs: number, opts?: Pick): Promise +``` + +Set the timeout of the sandbox. +After the timeout expires the sandbox will be automatically killed. + +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.setTimeout`. +Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `timeoutMs` | `number` | timeout in **milliseconds**. | +| `opts`? | `Pick`\<`SandboxOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### uploadUrl() + +```ts +uploadUrl(path?: string): string +``` + +Get the URL to upload a file to the sandbox. + +You have to send a POST request to this URL with the file as multipart/form-data. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path`? | `string` | the directory where to upload the file, defaults to user's home directory. | + +###### Returns + +`string` + +URL for uploading file. + +### connect() + +```ts +static connect( + this: S, + sandboxId: string, +opts?: Omit): Promise> +``` + +Connect to an existing sandbox. +With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc). + +###### Type Parameters + +| Type Parameter | +| ------ | +| `S` *extends* *typeof* `Sandbox` | + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `this` | `S` | - | +| `sandboxId` | `string` | sandbox ID. | +| `opts`? | `Omit`\<`SandboxOpts`, `"timeoutMs"` \| `"metadata"` \| `"envs"`\> | connection options. | + +###### Returns + +`Promise`\<`InstanceType`\<`S`\>\> + +sandbox instance for the existing sandbox. + +###### Example + +```ts +const sandbox = await Sandbox.create() +const sandboxId = sandbox.sandboxId + +// Connect to the same sandbox. +const sameSandbox = await Sandbox.connect(sandboxId) +``` + +### create() + +###### create(this, opts) + +```ts +static create(this: S, opts?: SandboxOpts): Promise> +``` + +Create a new sandbox from the default `base` sandbox template. + +###### Type Parameters + +| Type Parameter | +| ------ | +| `S` *extends* *typeof* `Sandbox` | + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `this` | `S` | - | +| `opts`? | `SandboxOpts` | connection options. | + +###### Returns + +`Promise`\<`InstanceType`\<`S`\>\> + +sandbox instance for the new sandbox. + +###### Example + +```ts +const sandbox = await Sandbox.create() +``` + +###### Constructs + +Sandbox + +###### create(this, template, opts) + +```ts +static create( + this: S, + template: string, +opts?: SandboxOpts): Promise> +``` + +Create a new sandbox from the specified sandbox template. + +###### Type Parameters + +| Type Parameter | +| ------ | +| `S` *extends* *typeof* `Sandbox` | + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `this` | `S` | - | +| `template` | `string` | sandbox template name or ID. | +| `opts`? | `SandboxOpts` | connection options. | + +###### Returns + +`Promise`\<`InstanceType`\<`S`\>\> + +sandbox instance for the new sandbox. + +###### Example + +```ts +const sandbox = await Sandbox.create('') +``` + +###### Constructs + +Sandbox + +### kill() + +```ts +static kill(sandboxId: string, opts?: SandboxApiOpts): Promise +``` + +Kill the sandbox specified by sandbox ID. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `sandboxId` | `string` | sandbox ID. | +| `opts`? | `SandboxApiOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the sandbox was found and killed, `false` otherwise. + +### list() + +```ts +static list(opts?: SandboxApiOpts): Promise +``` + +List all running sandboxes. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts`? | `SandboxApiOpts` | connection options. | + +###### Returns + +`Promise`\<`SandboxInfo`[]\> + +list of running sandboxes. + +### setTimeout() + +```ts +static setTimeout( + sandboxId: string, + timeoutMs: number, +opts?: SandboxApiOpts): Promise +``` + +Set the timeout of the specified sandbox. +After the timeout expires the sandbox will be automatically killed. + +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to Sandbox.setTimeout. + +Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `sandboxId` | `string` | sandbox ID. | +| `timeoutMs` | `number` | timeout in **milliseconds**. | +| `opts`? | `SandboxApiOpts` | connection options. | + +###### Returns + +`Promise`\<`void`\> + +## Interfaces + +### SandboxOpts + +Options for creating a new Sandbox. + +#### Properties + +### accessToken? + +```ts +optional accessToken: string; +``` + +E2B access token to use for authentication. + +###### Default + +```ts +E2B_ACCESS_TOKEN // environment variable +``` + +### apiKey? + +```ts +optional apiKey: string; +``` + +E2B API key to use for authentication. + +###### Default + +```ts +E2B_API_KEY // environment variable +``` + +### debug? + +```ts +optional debug: boolean; +``` + +**`Internal`** + +If true the SDK starts in the debug mode and connects to the local envd API server. + +###### Default + +E2B_DEBUG // environment variable or `false` + +### domain? + +```ts +optional domain: string; +``` + +Domain to use for the API. + +###### Default + +E2B_DOMAIN // environment variable or `e2b.dev` + +### envs? + +```ts +optional envs: Record; +``` + +Custom environment variables for the sandbox. + +Used when executing commands and code in the sandbox. +Can be overridden with the `envs` argument when executing commands or code. + +###### Default + +```ts +{} +``` + +### logger? + +```ts +optional logger: Logger; +``` + +Logger to use for logging messages. It can accept any object that implements `Logger` interface—for example, console. + +### metadata? + +```ts +optional metadata: Record; +``` + +Custom metadata for the sandbox. + +###### Default + +```ts +{} +``` + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### timeoutMs? + +```ts +optional timeoutMs: number; +``` + +Timeout for the sandbox in **milliseconds**. +Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users. + +###### Default + +```ts +300_000 // 5 minutes +``` diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/commands/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/commands/page.mdx new file mode 100644 index 0000000000..41f75547a3 --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/commands/page.mdx @@ -0,0 +1,483 @@ +### Commands + +Module for starting and interacting with commands in the sandbox. + +#### Constructors + +```ts +new Commands(transport: Transport, connectionConfig: ConnectionConfig): Commands +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `transport` | `Transport` | +| `connectionConfig` | `ConnectionConfig` | + +###### Returns + +`Commands` + +#### Methods + +### connect() + +```ts +connect(pid: number, opts?: CommandConnectOpts): Promise +``` + +Connect to a running command. +You can use CommandHandle.wait to wait for the command to finish and get execution results. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the command to connect to. You can get the list of running commands using Commands.list. | +| `opts`? | `CommandConnectOpts` | connection options. | + +###### Returns + +`Promise`\<`CommandHandle`\> + +`CommandHandle` handle to interact with the running command. + +### kill() + +```ts +kill(pid: number, opts?: CommandRequestOpts): Promise +``` + +Kill a running command specified by its process ID. +It uses `SIGKILL` signal to kill the command. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the command. You can get the list of running commands using Commands.list. | +| `opts`? | `CommandRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the command was killed, `false` if the command was not found. + +### list() + +```ts +list(opts?: CommandRequestOpts): Promise +``` + +List all running commands and PTY sessions. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts`? | `CommandRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`ProcessInfo`[]\> + +list of running commands and PTY sessions. + +### run() + +###### run(cmd, opts) + +```ts +run(cmd: string, opts?: CommandStartOpts & object): Promise +``` + +Start a new command and wait until it finishes executing. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `cmd` | `string` | command to execute. | +| `opts`? | `CommandStartOpts` & `object` | options for starting the command. | + +###### Returns + +`Promise`\<`CommandResult`\> + +`CommandResult` result of the command execution. + +###### run(cmd, opts) + +```ts +run(cmd: string, opts?: CommandStartOpts & object): Promise +``` + +Start a new command in the background. +You can use CommandHandle.wait to wait for the command to finish and get its result. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `cmd` | `string` | command to execute. | +| `opts`? | `CommandStartOpts` & `object` | options for starting the command | + +###### Returns + +`Promise`\<`CommandHandle`\> + +`CommandHandle` handle to interact with the running command. + +### sendStdin() + +```ts +sendStdin( + pid: number, + data: string, +opts?: CommandRequestOpts): Promise +``` + +Send data to command stdin. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the command. You can get the list of running commands using Commands.list. | +| `data` | `string` | data to send to the command. | +| `opts`? | `CommandRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`void`\> + +*** + +### Pty + +Module for interacting with PTYs (pseudo-terminals) in the sandbox. + +#### Constructors + +```ts +new Pty(transport: Transport, connectionConfig: ConnectionConfig): Pty +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `transport` | `Transport` | +| `connectionConfig` | `ConnectionConfig` | + +###### Returns + +`Pty` + +#### Methods + +### create() + +```ts +create(opts: PtyCreateOpts): Promise +``` + +Create a new PTY (pseudo-terminal). + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts` | `PtyCreateOpts` | options for creating the PTY. | + +###### Returns + +`Promise`\<`CommandHandle`\> + +handle to interact with the PTY. + +### kill() + +```ts +kill(pid: number, opts?: Pick): Promise +``` + +Kill a running PTY specified by process ID. +It uses `SIGKILL` signal to kill the PTY. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the PTY. | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the PTY was killed, `false` if the PTY was not found. + +### resize() + +```ts +resize( + pid: number, + size: object, +opts?: Pick): Promise +``` + +Resize PTY. +Call this when the terminal window is resized and the number of columns and rows has changed. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the PTY. | +| `size` | `object` | new size of the PTY. | +| `size.cols` | `number` | - | +| `size.rows`? | `number` | - | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### sendInput() + +```ts +sendInput( + pid: number, + data: Uint8Array, +opts?: Pick): Promise +``` + +Send input to a PTY. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `pid` | `number` | process ID of the PTY. | +| `data` | `Uint8Array` | input data to send to the PTY. | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +## Interfaces + +### CommandRequestOpts + +Options for sending a command request. + +#### Extended by + +- `CommandStartOpts` + +#### Properties + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +*** + +### CommandStartOpts + +Options for starting a new command. + +#### Properties + +### background? + +```ts +optional background: boolean; +``` + +If true, starts command in the background and the method returns immediately. +You can use CommandHandle.wait to wait for the command to finish. + +### cwd? + +```ts +optional cwd: string; +``` + +Working directory for the command. + +###### Default + +```ts +// home directory of the user used to start the command +``` + +### envs? + +```ts +optional envs: Record; +``` + +Environment variables used for the command. + +This overrides the default environment variables from `Sandbox` constructor. + +###### Default + +`{}` + +### onStderr()? + +```ts +optional onStderr: (data: string) => void | Promise; +``` + +Callback for command stderr output. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `data` | `string` | + +###### Returns + +`void` \| `Promise`\<`void`\> + +### onStdout()? + +```ts +optional onStdout: (data: string) => void | Promise; +``` + +Callback for command stdout output. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `data` | `string` | + +###### Returns + +`void` \| `Promise`\<`void`\> + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### timeoutMs? + +```ts +optional timeoutMs: number; +``` + +Timeout for the command in **milliseconds**. + +###### Default + +```ts +60_000 // 60 seconds +``` + +### user? + +```ts +optional user: Username; +``` + +User to run the command as. + +###### Default + +`user` + +*** + +### ProcessInfo + +Information about a command, PTY session or start command running in the sandbox as process. + +#### Properties + +### args + +```ts +args: string[]; +``` + +Command arguments. + +### cmd + +```ts +cmd: string; +``` + +Command that was executed. + +### cwd? + +```ts +optional cwd: string; +``` + +Executed command working directory. + +### envs + +```ts +envs: Record; +``` + +Environment variables used for the command. + +### pid + +```ts +pid: number; +``` + +Process ID. + +### tag? + +```ts +optional tag: string; +``` + +Custom tag used for identifying special commands like start command in the custom template. + +## Type Aliases + +### CommandConnectOpts + +```ts +type CommandConnectOpts: Pick & CommandRequestOpts; +``` + +Options for connecting to a command. diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/errors/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/errors/page.mdx new file mode 100644 index 0000000000..c5aa2cc143 --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/errors/page.mdx @@ -0,0 +1,211 @@ +### AuthenticationError + +Thrown when authentication fails. + +#### Constructors + +```ts +new AuthenticationError(message: any): AuthenticationError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `any` | + +###### Returns + +`AuthenticationError` + +*** + +### InvalidArgumentError + +Thrown when an invalid argument is provided. + +#### Constructors + +```ts +new InvalidArgumentError(message: string): InvalidArgumentError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`InvalidArgumentError` + +*** + +### NotEnoughSpaceError + +Thrown when there is not enough disk space. + +#### Constructors + +```ts +new NotEnoughSpaceError(message: string): NotEnoughSpaceError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`NotEnoughSpaceError` + +*** + +### NotFoundError + +Thrown when a resource is not found. + +#### Constructors + +```ts +new NotFoundError(message: string): NotFoundError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`NotFoundError` + +*** + +### RateLimitError + +Thrown when the API rate limit is exceeded. + +#### Constructors + +```ts +new RateLimitError(message: any): RateLimitError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `any` | + +###### Returns + +`RateLimitError` + +*** + +### SandboxError + +Base class for all sandbox errors. + +Thrown when general sandbox errors occur. + +#### Extended by + +- `TimeoutError` +- `InvalidArgumentError` +- `NotEnoughSpaceError` +- `NotFoundError` +- `AuthenticationError` +- `TemplateError` +- `RateLimitError` + +#### Constructors + +```ts +new SandboxError(message: any): SandboxError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `any` | + +###### Returns + +`SandboxError` + +*** + +### TemplateError + +Thrown when the template uses old envd version. It isn't compatible with the new SDK. + +#### Constructors + +```ts +new TemplateError(message: string): TemplateError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`TemplateError` + +*** + +### TimeoutError + +Thrown when a timeout error occurs. + +The [unavailable] error type is caused by sandbox timeout. + +The [canceled] error type is caused by exceeding request timeout. + +The [deadline_exceeded] error type is caused by exceeding the timeout for command execution, watch, etc. + +The [unknown] error type is sometimes caused by the sandbox timeout when the request is not processed correctly. + +#### Constructors + +```ts +new TimeoutError(message: string): TimeoutError +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +###### Returns + +`TimeoutError` + +## Functions + +### formatSandboxTimeoutError() + +```ts +function formatSandboxTimeoutError(message: string): TimeoutError +``` + +#### Parameters + +| Parameter | Type | +| ------ | ------ | +| `message` | `string` | + +#### Returns + +`TimeoutError` diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/filesystem/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/filesystem/page.mdx new file mode 100644 index 0000000000..71b13f7881 --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/filesystem/page.mdx @@ -0,0 +1,469 @@ +### FileType + +Sandbox filesystem object type. + +#### Enumeration Members + +| Enumeration Member | Value | Description | +| ------ | ------ | ------ | +| `DIR` | `"dir"` | Filesystem object is a directory. | +| `FILE` | `"file"` | Filesystem object is a file. | + +## Classes + +### Filesystem + +Module for interacting with the sandbox filesystem. + +#### Constructors + +```ts +new Filesystem( + transport: Transport, + envdApi: EnvdApiClient, + connectionConfig: ConnectionConfig): Filesystem +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `transport` | `Transport` | +| `envdApi` | `EnvdApiClient` | +| `connectionConfig` | `ConnectionConfig` | + +###### Returns + +`Filesystem` + +#### Methods + +### exists() + +```ts +exists(path: string, opts?: FilesystemRequestOpts): Promise +``` + +Check if a file or a directory exists. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to a file or a directory | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the file or directory exists, `false` otherwise + +### list() + +```ts +list(path: string, opts?: FilesystemRequestOpts): Promise +``` + +List entries in a directory. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the directory. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`EntryInfo`[]\> + +list of entries in the sandbox filesystem directory. + +### makeDir() + +```ts +makeDir(path: string, opts?: FilesystemRequestOpts): Promise +``` + +Create a new directory and all directories along the way if needed on the specified path. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to a new directory. For example '/dirA/dirB' when creating 'dirB'. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the directory was created, `false` if it already exists. + +### read() + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise +``` + +Read file content as a `string`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`string`\> + +file content as string + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise +``` + +Read file content as a `Uint8Array`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`Uint8Array`\> + +file content as `Uint8Array` + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise +``` + +Read file content as a `Blob`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`Blob`\> + +file content as `Blob` + +###### read(path, opts) + +```ts +read(path: string, opts?: FilesystemRequestOpts & object): Promise> +``` + +Read file content as a `ReadableStream`. + +You can pass `text`, `bytes`, `blob`, or `stream` to `opts.format` to change the return type. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file. | +| `opts`? | `FilesystemRequestOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`ReadableStream`\<`Uint8Array`\>\> + +file content as `ReadableStream` + +### remove() + +```ts +remove(path: string, opts?: FilesystemRequestOpts): Promise +``` + +Remove a file or directory. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to a file or directory. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### rename() + +```ts +rename( + oldPath: string, + newPath: string, +opts?: FilesystemRequestOpts): Promise +``` + +Rename a file or directory. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `oldPath` | `string` | path to the file or directory to rename. | +| `newPath` | `string` | new path for the file or directory. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`EntryInfo`\> + +information about renamed file or directory. + +### watchDir() + +```ts +watchDir( + path: string, + onEvent: (event: FilesystemEvent) => void | Promise, +opts?: WatchOpts & object): Promise +``` + +Start watching a directory for filesystem events. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to directory to watch. | +| `onEvent` | (`event`: `FilesystemEvent`) => `void` \| `Promise`\<`void`\> | callback to call when an event in the directory occurs. | +| `opts`? | `WatchOpts` & `object` | connection options. | + +###### Returns + +`Promise`\<`WatchHandle`\> + +`WatchHandle` object for stopping watching directory. + +### write() + +###### write(path, data, opts) + +```ts +write( + path: string, + data: string | ArrayBuffer | Blob | ReadableStream, +opts?: FilesystemRequestOpts): Promise +``` + +Write content to a file. + +Writing to a file that doesn't exist creates the file. + +Writing to a file that already exists overwrites the file. + +Writing to a file at path that doesn't exist creates the necessary directories. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to file. | +| `data` | `string` \| `ArrayBuffer` \| `Blob` \| `ReadableStream`\<`any`\> | data to write to the file. Data can be a string, `ArrayBuffer`, `Blob`, or `ReadableStream`. | +| `opts`? | `FilesystemRequestOpts` | connection options. | + +###### Returns + +`Promise`\<`EntryInfo`\> + +information about the written file + +###### write(files, opts) + +```ts +write(files: WriteEntry[], opts?: FilesystemRequestOpts): Promise +``` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `files` | `WriteEntry`[] | +| `opts`? | `FilesystemRequestOpts` | + +###### Returns + +`Promise`\<`EntryInfo`[]\> + +## Interfaces + +### EntryInfo + +Sandbox filesystem object information. + +#### Properties + +### name + +```ts +name: string; +``` + +Name of the filesystem object. + +### path + +```ts +path: string; +``` + +Path to the filesystem object. + +### type? + +```ts +optional type: FileType; +``` + +Type of the filesystem object. + +*** + +### FilesystemRequestOpts + +Options for the sandbox filesystem operations. + +#### Extended by + +- `WatchOpts` + +#### Properties + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### user? + +```ts +optional user: Username; +``` + +User to use for the operation in the sandbox. +This affects the resolution of relative paths and ownership of the created filesystem objects. + +*** + +### WatchOpts + +Options for watching a directory. + +#### Properties + +### onExit()? + +```ts +optional onExit: (err?: Error) => void | Promise; +``` + +Callback to call when the watch operation stops. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `err`? | `Error` | + +###### Returns + +`void` \| `Promise`\<`void`\> + +### recursive? + +```ts +optional recursive: boolean; +``` + +Watch the directory recursively + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### timeoutMs? + +```ts +optional timeoutMs: number; +``` + +Timeout for the watch operation in **milliseconds**. +You can pass `0` to disable the timeout. + +###### Default + +```ts +60_000 // 60 seconds +``` + +### user? + +```ts +optional user: Username; +``` + +User to use for the operation in the sandbox. +This affects the resolution of relative paths and ownership of the created filesystem objects. + +## Type Aliases + +### WriteEntry + +```ts +type WriteEntry: object; +``` + +#### Type declaration + +| Name | Type | +| ------ | ------ | +| `data` | `string` \| `ArrayBuffer` \| `Blob` \| `ReadableStream` | +| `path` | `string` | diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/sandbox/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/sandbox/page.mdx new file mode 100644 index 0000000000..8fd73ba37d --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/js-sdk/v1.1.1/sandbox/page.mdx @@ -0,0 +1,498 @@ +### Sandbox + +E2B cloud sandbox is a secure and isolated cloud environment. + +The sandbox allows you to: +- Access Linux OS +- Create, list, and delete files and directories +- Run commands +- Run isolated code +- Access the internet + +Check docs here. + +Use Sandbox.create to create a new sandbox. + +#### Example + +```ts +import { Sandbox } from 'e2b' + +const sandbox = await Sandbox.create() +``` + +#### Properties + +| Property | Modifier | Type | Description | +| ------ | ------ | ------ | ------ | +| `commands` | `readonly` | `Commands` | Module for running commands in the sandbox | +| `files` | `readonly` | `Filesystem` | Module for interacting with the sandbox filesystem | +| `pty` | `readonly` | `Pty` | Module for interacting with the sandbox pseudo-terminals | +| `sandboxId` | `readonly` | `string` | Unique identifier of the sandbox. | + +#### Methods + +### downloadUrl() + +```ts +downloadUrl(path: string): string +``` + +Get the URL to download a file from the sandbox. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path` | `string` | path to the file to download. | + +###### Returns + +`string` + +URL for downloading file. + +### getHost() + +```ts +getHost(port: number): string +``` + +Get the host address for the specified sandbox port. +You can then use this address to connect to the sandbox port from outside the sandbox via HTTP or WebSocket. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `port` | `number` | number of the port in the sandbox. | + +###### Returns + +`string` + +host address of the sandbox port. + +###### Example + +```ts +const sandbox = await Sandbox.create() +// Start an HTTP server +await sandbox.commands.exec('python3 -m http.server 3000') +// Get the hostname of the HTTP server +const serverURL = sandbox.getHost(3000) +``` + +### isRunning() + +```ts +isRunning(opts?: Pick): Promise +``` + +Check if the sandbox is running. + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `opts`? | `Pick`\<`ConnectionOpts`, `"requestTimeoutMs"`\> | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the sandbox is running, `false` otherwise. + +###### Example + +```ts +const sandbox = await Sandbox.create() +await sandbox.isRunning() // Returns true + +await sandbox.kill() +await sandbox.isRunning() // Returns false +``` + +### kill() + +```ts +kill(opts?: Pick): Promise +``` + +Kill the sandbox. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts`? | `Pick`\<`SandboxOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### setTimeout() + +```ts +setTimeout(timeoutMs: number, opts?: Pick): Promise +``` + +Set the timeout of the sandbox. +After the timeout expires the sandbox will be automatically killed. + +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.setTimeout`. +Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `timeoutMs` | `number` | timeout in **milliseconds**. | +| `opts`? | `Pick`\<`SandboxOpts`, `"requestTimeoutMs"`\> | connection options. | + +###### Returns + +`Promise`\<`void`\> + +### uploadUrl() + +```ts +uploadUrl(path?: string): string +``` + +Get the URL to upload a file to the sandbox. + +You have to send a POST request to this URL with the file as multipart/form-data. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `path`? | `string` | the directory where to upload the file, defaults to user's home directory. | + +###### Returns + +`string` + +URL for uploading file. + +### connect() + +```ts +static connect( + this: S, + sandboxId: string, +opts?: Omit): Promise> +``` + +Connect to an existing sandbox. +With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc). + +###### Type Parameters + +| Type Parameter | +| ------ | +| `S` *extends* *typeof* `Sandbox` | + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `this` | `S` | - | +| `sandboxId` | `string` | sandbox ID. | +| `opts`? | `Omit`\<`SandboxOpts`, `"timeoutMs"` \| `"metadata"` \| `"envs"`\> | connection options. | + +###### Returns + +`Promise`\<`InstanceType`\<`S`\>\> + +sandbox instance for the existing sandbox. + +###### Example + +```ts +const sandbox = await Sandbox.create() +const sandboxId = sandbox.sandboxId + +// Connect to the same sandbox. +const sameSandbox = await Sandbox.connect(sandboxId) +``` + +### create() + +###### create(this, opts) + +```ts +static create(this: S, opts?: SandboxOpts): Promise> +``` + +Create a new sandbox from the default `base` sandbox template. + +###### Type Parameters + +| Type Parameter | +| ------ | +| `S` *extends* *typeof* `Sandbox` | + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `this` | `S` | - | +| `opts`? | `SandboxOpts` | connection options. | + +###### Returns + +`Promise`\<`InstanceType`\<`S`\>\> + +sandbox instance for the new sandbox. + +###### Example + +```ts +const sandbox = await Sandbox.create() +``` + +###### Constructs + +Sandbox + +###### create(this, template, opts) + +```ts +static create( + this: S, + template: string, +opts?: SandboxOpts): Promise> +``` + +Create a new sandbox from the specified sandbox template. + +###### Type Parameters + +| Type Parameter | +| ------ | +| `S` *extends* *typeof* `Sandbox` | + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `this` | `S` | - | +| `template` | `string` | sandbox template name or ID. | +| `opts`? | `SandboxOpts` | connection options. | + +###### Returns + +`Promise`\<`InstanceType`\<`S`\>\> + +sandbox instance for the new sandbox. + +###### Example + +```ts +const sandbox = await Sandbox.create('') +``` + +###### Constructs + +Sandbox + +### kill() + +```ts +static kill(sandboxId: string, opts?: SandboxApiOpts): Promise +``` + +Kill the sandbox specified by sandbox ID. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `sandboxId` | `string` | sandbox ID. | +| `opts`? | `SandboxApiOpts` | connection options. | + +###### Returns + +`Promise`\<`boolean`\> + +`true` if the sandbox was found and killed, `false` otherwise. + +### list() + +```ts +static list(opts?: SandboxListOpts): Promise +``` + +List all running sandboxes. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `opts`? | `SandboxListOpts` | connection options. | + +###### Returns + +`Promise`\<`SandboxInfo`[]\> + +list of running sandboxes. + +### setTimeout() + +```ts +static setTimeout( + sandboxId: string, + timeoutMs: number, +opts?: SandboxApiOpts): Promise +``` + +Set the timeout of the specified sandbox. +After the timeout expires the sandbox will be automatically killed. + +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to Sandbox.setTimeout. + +Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `sandboxId` | `string` | sandbox ID. | +| `timeoutMs` | `number` | timeout in **milliseconds**. | +| `opts`? | `SandboxApiOpts` | connection options. | + +###### Returns + +`Promise`\<`void`\> + +## Interfaces + +### SandboxOpts + +Options for creating a new Sandbox. + +#### Properties + +### accessToken? + +```ts +optional accessToken: string; +``` + +E2B access token to use for authentication. + +###### Default + +```ts +E2B_ACCESS_TOKEN // environment variable +``` + +### apiKey? + +```ts +optional apiKey: string; +``` + +E2B API key to use for authentication. + +###### Default + +```ts +E2B_API_KEY // environment variable +``` + +### debug? + +```ts +optional debug: boolean; +``` + +**`Internal`** + +If true the SDK starts in the debug mode and connects to the local envd API server. + +###### Default + +E2B_DEBUG // environment variable or `false` + +### domain? + +```ts +optional domain: string; +``` + +Domain to use for the API. + +###### Default + +E2B_DOMAIN // environment variable or `e2b.dev` + +### envs? + +```ts +optional envs: Record; +``` + +Custom environment variables for the sandbox. + +Used when executing commands and code in the sandbox. +Can be overridden with the `envs` argument when executing commands or code. + +###### Default + +```ts +{} +``` + +### logger? + +```ts +optional logger: Logger; +``` + +Logger to use for logging messages. It can accept any object that implements `Logger` interface—for example, console. + +### metadata? + +```ts +optional metadata: Record; +``` + +Custom metadata for the sandbox. + +###### Default + +```ts +{} +``` + +### requestTimeoutMs? + +```ts +optional requestTimeoutMs: number; +``` + +Timeout for requests to the API in **milliseconds**. + +###### Default + +```ts +30_000 // 30 seconds +``` + +### timeoutMs? + +```ts +optional timeoutMs: number; +``` + +Timeout for the sandbox in **milliseconds**. +Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users. + +###### Default + +```ts +300_000 // 5 minutes +``` diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/exceptions/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/exceptions/page.mdx new file mode 100644 index 0000000000..17864645df --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/exceptions/page.mdx @@ -0,0 +1,84 @@ + + + +## SandboxException + +```python +class SandboxException(Exception) +``` + +Base class for all sandbox errors. + +Raised when a general sandbox exception occurs. + + +## TimeoutException + +```python +class TimeoutException(SandboxException) +``` + +Raised when a timeout occurs. + +The `unavailable` exception type is caused by sandbox timeout. + +The `canceled` exception type is caused by exceeding request timeout. + +The `deadline_exceeded` exception type is caused by exceeding the timeout for process, watch, etc. + +The `unknown` exception type is sometimes caused by the sandbox timeout when the request is not processed correctly. + + +## InvalidArgumentException + +```python +class InvalidArgumentException(SandboxException) +``` + +Raised when an invalid argument is provided. + + +## NotEnoughSpaceException + +```python +class NotEnoughSpaceException(SandboxException) +``` + +Raised when there is not enough disk space. + + +## NotFoundException + +```python +class NotFoundException(SandboxException) +``` + +Raised when a resource is not found. + + +## AuthenticationException + +```python +class AuthenticationException(SandboxException) +``` + +Raised when authentication fails. + + +## TemplateException + +```python +class TemplateException(SandboxException) +``` + +Exception raised when the template uses old envd version. It isn't compatible with the new SDK. + + +## RateLimitException + +```python +class RateLimitException(SandboxException) +``` + +Raised when the API rate limit is exceeded. + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/sandbox_async/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/sandbox_async/page.mdx new file mode 100644 index 0000000000..f687aa37fb --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/sandbox_async/page.mdx @@ -0,0 +1,966 @@ + + + + + +## AsyncCommandHandle + +```python +class AsyncCommandHandle() +``` + +Command execution handle. + +It provides methods for waiting for the command to finish, retrieving stdout/stderr, and killing the command. + + +### pid + +```python +@property +def pid() +``` + +Command process ID. + + +### stdout + +```python +@property +def stdout() +``` + +Command stdout output. + + +### stderr + +```python +@property +def stderr() +``` + +Command stderr output. + + +### error + +```python +@property +def error() +``` + +Command execution error message. + + +### exit\_code + +```python +@property +def exit_code() +``` + +Command execution exit code. + +`0` if the command finished successfully. + +It is `None` if the command is still running. + + +### disconnect + +```python +async def disconnect() -> None +``` + +Disconnects from the command. + +The command is not killed, but SDK stops receiving events from the command. +You can reconnect to the command using `sandbox.commands.connect` method. + + +### wait + +```python +async def wait() -> CommandResult +``` + +Wait for the command to finish and return the result. + +If the command exits with a non-zero exit code, it throws a `CommandExitException`. + +**Returns**: + +`CommandResult` result of command execution + + +### kill + +```python +async def kill() -> bool +``` + +Kills the command. + +It uses `SIGKILL` signal to kill the command + +**Returns**: + +`True` if the command was killed successfully, `False` if the command was not found + + + + +## Pty + +```python +class Pty() +``` + +Module for interacting with PTYs (pseudo-terminals) in the sandbox. + + +### kill + +```python +async def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kill PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`true` if the PTY was killed, `false` if the PTY was not found + + +### send\_stdin + +```python +async def send_stdin(pid: int, + data: bytes, + request_timeout: Optional[float] = None) -> None +``` + +Send input to a PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `data`: Input data to send +- `request_timeout`: Timeout for the request in **seconds** + + +### create + +```python +async def create( + size: PtySize, + on_data: OutputHandler[PtyOutput], + user: Username = "user", + cwd: Optional[str] = None, + envs: Optional[Dict[str, str]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> AsyncCommandHandle +``` + +Start a new PTY (pseudo-terminal). + +**Arguments**: + +- `size`: Size of the PTY +- `on_data`: Callback to handle PTY data +- `user`: User to use for the PTY +- `cwd`: Working directory for the PTY +- `envs`: Environment variables for the PTY +- `timeout`: Timeout for the PTY in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Handle to interact with the PTY + + +### resize + +```python +async def resize(pid: int, + size: PtySize, + request_timeout: Optional[float] = None) +``` + +Resize PTY. + +Call this when the terminal window is resized and the number of columns and rows has changed. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `size`: New size of the PTY +- `request_timeout`: Timeout for the request in **seconds** + + + + +## Commands + +```python +class Commands() +``` + +Module for executing commands in the sandbox. + + +### list + +```python +async def list(request_timeout: Optional[float] = None) -> List[ProcessInfo] +``` + +Lists all running commands and PTY sessions. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of running commands and PTY sessions + + +### kill + +```python +async def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kill a running command specified by its process ID. + +It uses `SIGKILL` signal to kill the command. + +**Arguments**: + +- `pid`: Process ID of the command. You can get the list of processes using `sandbox.commands.list()` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the command was killed, `False` if the command was not found + + +### send\_stdin + +```python +async def send_stdin(pid: int, + data: str, + request_timeout: Optional[float] = None) -> None +``` + +Send data to command stdin. + +:param pid Process ID of the command. You can get the list of processes using `sandbox.commands.list()`. +:param data: Data to send to the command +:param request_timeout: Timeout for the request in **seconds** + + + +### run + +```python +@overload +async def run(cmd: str, + background: Union[Literal[False], None] = None, + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: Optional[OutputHandler[Stdout]] = None, + on_stderr: Optional[OutputHandler[Stderr]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandResult +``` + +Start a new command and wait until it finishes executing. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: **`False` if the command should be executed in the foreground**, `True` if the command should be executed in the background +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandResult` result of the command execution + + +### run + +```python +@overload +async def run(cmd: str, + background: Literal[True], + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: Optional[OutputHandler[Stdout]] = None, + on_stderr: Optional[OutputHandler[Stderr]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> AsyncCommandHandle +``` + +Start a new command and return a handle to interact with it. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: `False` if the command should be executed in the foreground, **`True` if the command should be executed in the background** +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`AsyncCommandHandle` handle to interact with the running command + + +### connect + +```python +async def connect( + pid: int, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None, + on_stdout: Optional[OutputHandler[Stdout]] = None, + on_stderr: Optional[OutputHandler[Stderr]] = None +) -> AsyncCommandHandle +``` + +Connects to a running command. + +You can use `AsyncCommandHandle.wait()` to wait for the command to finish and get execution results. + +**Arguments**: + +- `pid`: Process ID of the command to connect to. You can get the list of processes using `sandbox.commands.list()` +- `request_timeout`: Request timeout in **seconds** +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output + +**Returns**: + +`AsyncCommandHandle` handle to interact with the running command + + + + +## SandboxApi + +```python +class SandboxApi(SandboxApiBase) +``` + + +### list + +```python +@classmethod +async def list(cls, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> List[SandboxInfo] +``` + +List all running sandboxes. + +**Arguments**: + +- `api_key`: API key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of running sandboxes + + + + +## AsyncSandbox + +```python +class AsyncSandbox(SandboxSetup, SandboxApi) +``` + +E2B cloud sandbox is a secure and isolated cloud environment. + +The sandbox allows you to: +- Access Linux OS +- Create, list, and delete files and directories +- Run commands +- Run isolated code +- Access the internet + +Check docs [here](https://e2b.dev/docs). + +Use the `AsyncSandbox.create()` to create a new sandbox. + +**Example**: + +```python +from e2b import AsyncSandbox + +sandbox = await AsyncSandbox.create() +``` + + +### files + +```python +@property +def files() -> Filesystem +``` + +Module for interacting with the sandbox filesystem. + + +### commands + +```python +@property +def commands() -> Commands +``` + +Module for running commands in the sandbox. + + +### pty + +```python +@property +def pty() -> Pty +``` + +Module for interacting with the sandbox pseudo-terminal. + + +### sandbox\_id + +```python +@property +def sandbox_id() -> str +``` + +Unique identifier of the sandbox. + + +### \_\_init\_\_ + +```python +def __init__(**opts: Unpack[AsyncSandboxOpts]) +``` + +Use `AsyncSandbox.create()` to create a new sandbox instead. + + +### is\_running + +```python +async def is_running(request_timeout: Optional[float] = None) -> bool +``` + +Check if the sandbox is running. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox is running, `False` otherwise +Example +```python +sandbox = await AsyncSandbox.create() +await sandbox.is_running() # Returns True + +await sandbox.kill() +await sandbox.is_running() # Returns False +``` + + +### create + +```python +@classmethod +async def create(cls, + template: Optional[str] = None, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + envs: Optional[Dict[str, str]] = None, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) +``` + +Create a new sandbox. + +By default, the sandbox is created from the default `base` sandbox template. + +**Arguments**: + +- `template`: Sandbox template name or ID +- `timeout`: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. +- `metadata`: Custom metadata for the sandbox +- `envs`: Custom environment variables for the sandbox +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +sandbox instance for the new sandbox +Use this method instead of using the constructor to create a new sandbox. + + +### connect + +```python +@classmethod +async def connect(cls, + sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None) +``` + +Connect to an existing sandbox. + +With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc). + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable + +**Returns**: + +sandbox instance for the existing sandbox +@example +```python +sandbox = await AsyncSandbox.create() +sandbox_id = sandbox.sandbox_id + +same_sandbox = await AsyncSandbox.connect(sandbox_id) + + +### kill + +```python +@overload +async def kill(request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### kill + +```python +@overload +@staticmethod +async def kill(sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox specified by sandbox ID. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### set\_timeout + +```python +@overload +async def set_timeout(timeout: int, + request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the sandbox. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `timeout`: Timeout for the sandbox in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + + +### set\_timeout + +```python +@overload +@staticmethod +async def set_timeout(sandbox_id: str, + timeout: int, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the specified sandbox. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `timeout`: Timeout for the sandbox in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + + + + +## AsyncWatchHandle + +```python +class AsyncWatchHandle() +``` + +Handle for watching a directory in the sandbox filesystem. + +Use `.stop()` to stop watching the directory. + + +### stop + +```python +async def stop() +``` + +Stop watching the directory. + + + + +## Filesystem + +```python +class Filesystem() +``` + +Module for interacting with the filesystem in the sandbox. + + +### read + +```python +@overload +async def read(path: str, + format: Literal["text"] = "text", + user: Username = "user", + request_timeout: Optional[float] = None) -> str +``` + +Read file content as a `str`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`text` by default +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `str` + + +### read + +```python +@overload +async def read(path: str, + format: Literal["bytes"], + user: Username = "user", + request_timeout: Optional[float] = None) -> bytearray +``` + +Read file content as a `bytearray`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`bytes` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `bytearray` + + +### read + +```python +@overload +async def read( + path: str, + format: Literal["stream"], + user: Username = "user", + request_timeout: Optional[float] = None) -> AsyncIterator[bytes] +``` + +Read file content as a `AsyncIterator[bytes]`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`stream` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as an `AsyncIterator[bytes]` + + +### write + +```python +@overload +async def write(path: str, + data: Union[str, bytes, IO], + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Write content to a file on the path. + +Writing to a file that doesn't exist creates the file. + +Writing to a file that already exists overwrites the file. + +Writing to a file at path that doesn't exist creates the necessary directories. + +**Arguments**: + +- `path`: Path to the file +- `data`: Data to write to the file, can be a `str`, `bytes`, or `IO`. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the written file + + +### write + +```python +@overload +async def write(files: List[WriteEntry], + user: Optional[Username] = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +Writes multiple files. + +**Arguments**: + +- `files`: list of files to write +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request + +**Returns**: + +Information about the written files + + +### write + +```python +async def write( + path_or_files: Union[str, List[WriteEntry]], + data_or_user: Union[str, bytes, IO, Username] = "user", + user_or_request_timeout: Optional[Union[float, Username]] = None, + request_timeout_or_none: Optional[float] = None +) -> Union[EntryInfo, List[EntryInfo]] +``` + +Writes content to a file on the path. +When writing to a file that doesn't exist, the file will get created. +When writing to a file that already exists, the file will get overwritten. +When writing to a file that's in a directory that doesn't exist, you'll get an error. + + +### list + +```python +async def list(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +List entries in a directory. + +**Arguments**: + +- `path`: Path to the directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of entries in the directory + + +### exists + +```python +async def exists(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Check if a file or a directory exists. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the file or directory exists, `False` otherwise + + +### remove + +```python +async def remove(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> None +``` + +Remove a file or a directory. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + + +### rename + +```python +async def rename(old_path: str, + new_path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Rename a file or directory. + +**Arguments**: + +- `old_path`: Path to the file or directory to rename +- `new_path`: New path to the file or directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the renamed file or directory + + +### make\_dir + +```python +async def make_dir(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Create a new directory and all directories along the way if needed on the specified path. + +**Arguments**: + +- `path`: Path to a new directory. For example '/dirA/dirB' when creating 'dirB'. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the directory was created, `False` if the directory already exists + + +### watch\_dir + +```python +async def watch_dir(path: str, + on_event: OutputHandler[FilesystemEvent], + on_exit: Optional[OutputHandler[Exception]] = None, + user: Username = "user", + request_timeout: Optional[float] = None, + timeout: Optional[float] = 60, + recursive: bool = False) -> AsyncWatchHandle +``` + +Watch directory for filesystem events. + +**Arguments**: + +- `path`: Path to a directory to watch +- `on_event`: Callback to call on each event in the directory +- `on_exit`: Callback to call when the watching ends +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** +- `timeout`: Timeout for the watch operation in **seconds**. Using `0` will not limit the watch time +- `recursive`: Watch directory recursively + +**Returns**: + +`AsyncWatchHandle` object for stopping watching directory + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/sandbox_sync/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/sandbox_sync/page.mdx new file mode 100644 index 0000000000..ea4fef907d --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.0/sandbox_sync/page.mdx @@ -0,0 +1,931 @@ + + + +## CommandHandle + +```python +class CommandHandle() +``` + +Command execution handle. + +It provides methods for waiting for the command to finish, retrieving stdout/stderr, and killing the command. + + +### pid + +```python +@property +def pid() +``` + +Command process ID. + + +### \_\_iter\_\_ + +```python +def __iter__() +``` + +Iterate over the command output. + +**Returns**: + +Generator of command outputs + + +### disconnect + +```python +def disconnect() -> None +``` + +Disconnect from the command. + +The command is not killed, but SDK stops receiving events from the command. +You can reconnect to the command using `sandbox.commands.connect` method. + + +### wait + +```python +def wait(on_pty: Optional[Callable[[PtyOutput], None]] = None, + on_stdout: Optional[Callable[[str], None]] = None, + on_stderr: Optional[Callable[[str], None]] = None) -> CommandResult +``` + +Wait for the command to finish and returns the result. + +If the command exits with a non-zero exit code, it throws a `CommandExitException`. + +**Arguments**: + +- `on_pty`: Callback for pty output +- `on_stdout`: Callback for stdout output +- `on_stderr`: Callback for stderr output + +**Returns**: + +`CommandResult` result of command execution + + +### kill + +```python +def kill() -> bool +``` + +Kills the command. + +It uses `SIGKILL` signal to kill the command. + +**Returns**: + +Whether the command was killed successfully + + + + +## Pty + +```python +class Pty() +``` + +Module for interacting with PTYs (pseudo-terminals) in the sandbox. + + +### kill + +```python +def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kill PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`true` if the PTY was killed, `false` if the PTY was not found + + +### send\_stdin + +```python +def send_stdin(pid: int, + data: bytes, + request_timeout: Optional[float] = None) -> None +``` + +Send input to a PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `data`: Input data to send +- `request_timeout`: Timeout for the request in **seconds** + + +### create + +```python +def create(size: PtySize, + user: Username = "user", + cwd: Optional[str] = None, + envs: Optional[Dict[str, str]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandHandle +``` + +Start a new PTY (pseudo-terminal). + +**Arguments**: + +- `size`: Size of the PTY +- `user`: User to use for the PTY +- `cwd`: Working directory for the PTY +- `envs`: Environment variables for the PTY +- `timeout`: Timeout for the PTY in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Handle to interact with the PTY + + +### resize + +```python +def resize(pid: int, + size: PtySize, + request_timeout: Optional[float] = None) -> None +``` + +Resize PTY. + +Call this when the terminal window is resized and the number of columns and rows has changed. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `size`: New size of the PTY +- `request_timeout`: Timeout for the request in **seconds**s + + + + +## Commands + +```python +class Commands() +``` + +Module for executing commands in the sandbox. + + +### list + +```python +def list(request_timeout: Optional[float] = None) -> List[ProcessInfo] +``` + +Lists all running commands and PTY sessions. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of running commands and PTY sessions + + +### kill + +```python +def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kills a running command specified by its process ID. + +It uses `SIGKILL` signal to kill the command. + +**Arguments**: + +- `pid`: Process ID of the command. You can get the list of processes using `sandbox.commands.list()` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the command was killed, `False` if the command was not found + + +### send\_stdin + +```python +def send_stdin(pid: int, data: str, request_timeout: Optional[float] = None) +``` + +Send data to command stdin. + +:param pid Process ID of the command. You can get the list of processes using `sandbox.commands.list()`. +:param data: Data to send to the command +:param request_timeout: Timeout for the request in **seconds** + + + +### run + +```python +@overload +def run(cmd: str, + background: Union[Literal[False], None] = None, + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: Optional[Callable[[str], None]] = None, + on_stderr: Optional[Callable[[str], None]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandResult +``` + +Start a new command and wait until it finishes executing. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: **`False` if the command should be executed in the foreground**, `True` if the command should be executed in the background +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandResult` result of the command execution + + +### run + +```python +@overload +def run(cmd: str, + background: Literal[True], + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: None = None, + on_stderr: None = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandHandle +``` + +Start a new command and return a handle to interact with it. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: `False` if the command should be executed in the foreground, **`True` if the command should be executed in the background** +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandHandle` handle to interact with the running command + + +### connect + +```python +def connect(pid: int, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) +``` + +Connects to a running command. + +You can use `CommandHandle.wait()` to wait for the command to finish and get execution results. + +**Arguments**: + +- `pid`: Process ID of the command to connect to. You can get the list of processes using `sandbox.commands.list()` +- `timeout`: Timeout for the connection in **seconds**. Using `0` will not limit the connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandHandle` handle to interact with the running command + + + + +## SandboxApi + +```python +class SandboxApi(SandboxApiBase) +``` + + +### list + +```python +@classmethod +def list(cls, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> List[SandboxInfo] +``` + +List all running sandboxes. + +**Arguments**: + +- `api_key`: API key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of sandbox info + + + + +## Sandbox + +```python +class Sandbox(SandboxSetup, SandboxApi) +``` + +E2B cloud sandbox is a secure and isolated cloud environment. + +The sandbox allows you to: +- Access Linux OS +- Create, list, and delete files and directories +- Run commands +- Run isolated code +- Access the internet + +Check docs [here](https://e2b.dev/docs). + +Use the `Sandbox()` to create a new sandbox. + +**Example**: + +```python +from e2b import Sandbox + +sandbox = Sandbox() +``` + + +### files + +```python +@property +def files() -> Filesystem +``` + +Module for interacting with the sandbox filesystem. + + +### commands + +```python +@property +def commands() -> Commands +``` + +Module for running commands in the sandbox. + + +### pty + +```python +@property +def pty() -> Pty +``` + +Module for interacting with the sandbox pseudo-terminal. + + +### sandbox\_id + +```python +@property +def sandbox_id() -> str +``` + +Unique identifier of the sandbox + + +### \_\_init\_\_ + +```python +def __init__(template: Optional[str] = None, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + envs: Optional[Dict[str, str]] = None, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + sandbox_id: Optional[str] = None, + request_timeout: Optional[float] = None) +``` + +Create a new sandbox. + +By default, the sandbox is created from the default `base` sandbox template. + +**Arguments**: + +- `template`: Sandbox template name or ID +- `timeout`: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users +- `metadata`: Custom metadata for the sandbox +- `envs`: Custom environment variables for the sandbox +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +sandbox instance for the new sandbox + + +### is\_running + +```python +def is_running(request_timeout: Optional[float] = None) -> bool +``` + +Check if the sandbox is running. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox is running, `False` otherwise +Example +```python +sandbox = Sandbox() +sandbox.is_running() # Returns True + +sandbox.kill() +sandbox.is_running() # Returns False +``` + + +### connect + +```python +@classmethod +def connect(cls, + sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None) +``` + +Connects to an existing Sandbox. + +With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc). + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable + +**Returns**: + +sandbox instance for the existing sandbox +@example +```python +sandbox = Sandbox() +sandbox_id = sandbox.sandbox_id + +same_sandbox = Sandbox.connect(sandbox_id) +``` + + +### kill + +```python +@overload +def kill(request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### kill + +```python +@overload +@staticmethod +def kill(sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox specified by sandbox ID. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### kill + +```python +@class_method_variant("_cls_kill") +def kill(request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox. + +**Arguments**: + +- `request_timeout`: Timeout for the request + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### set\_timeout + +```python +@overload +def set_timeout(timeout: int, request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the sandbox. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `timeout`: Timeout for the sandbox in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + + +### set\_timeout + +```python +@overload +@staticmethod +def set_timeout(sandbox_id: str, + timeout: int, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the sandbox specified by sandbox ID. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `timeout`: Timeout for the sandbox in **seconds** +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + + + + +## WatchHandle + +```python +class WatchHandle() +``` + +Handle for watching filesystem events. +It is used to get the latest events that have occurred in the watched directory. + +Use `.stop()` to stop watching the directory. + + +### stop + +```python +def stop() +``` + +Stop watching the directory. +After you stop the watcher you won't be able to get the events anymore. + + +### get\_new\_events + +```python +def get_new_events() -> List[FilesystemEvent] +``` + +Get the latest events that have occurred in the watched directory since the last call, or from the beginning of the watching, up until now. + +**Returns**: + +List of filesystem events + + + + +## Filesystem + +```python +class Filesystem() +``` + +Module for interacting with the filesystem in the sandbox. + + +### read + +```python +@overload +def read(path: str, + format: Literal["text"] = "text", + user: Username = "user", + request_timeout: Optional[float] = None) -> str +``` + +Read file content as a `str`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`text` by default +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `str` + + +### read + +```python +@overload +def read(path: str, + format: Literal["bytes"], + user: Username = "user", + request_timeout: Optional[float] = None) -> bytearray +``` + +Read file content as a `bytearray`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`bytes` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `bytearray` + + +### read + +```python +@overload +def read(path: str, + format: Literal["stream"], + user: Username = "user", + request_timeout: Optional[float] = None) -> Iterator[bytes] +``` + +Read file content as a `Iterator[bytes]`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`stream` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as an `Iterator[bytes]` + + +### write + +```python +@overload +def write(path: str, + data: Union[str, bytes, IO], + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Write content to a file on the path. + +Writing to a file that doesn't exist creates the file. + +Writing to a file that already exists overwrites the file. + +Writing to a file at path that doesn't exist creates the necessary directories. + +**Arguments**: + +- `path`: Path to the file +- `data`: Data to write to the file, can be a `str`, `bytes`, or `IO`. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the written file + + +### write + +```python +@overload +def write(files: List[WriteEntry], + user: Optional[Username] = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +Writes a list of files to the filesystem. + +When writing to a file that doesn't exist, the file will get created. +When writing to a file that already exists, the file will get overwritten. +When writing to a file that's in a directory that doesn't exist, you'll get an error. + +**Arguments**: + +- `files`: list of files to write +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request + +**Returns**: + +Information about the written files + + +### list + +```python +def list(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +List entries in a directory. + +**Arguments**: + +- `path`: Path to the directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of entries in the directory + + +### exists + +```python +def exists(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Check if a file or a directory exists. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the file or directory exists, `False` otherwise + + +### remove + +```python +def remove(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> None +``` + +Remove a file or a directory. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + + +### rename + +```python +def rename(old_path: str, + new_path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Rename a file or directory. + +**Arguments**: + +- `old_path`: Path to the file or directory to rename +- `new_path`: New path to the file or directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the renamed file or directory + + +### make\_dir + +```python +def make_dir(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Create a new directory and all directories along the way if needed on the specified path. + +**Arguments**: + +- `path`: Path to a new directory. For example '/dirA/dirB' when creating 'dirB'. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the directory was created, `False` if the directory already exists + + +### watch\_dir + +```python +def watch_dir(path: str, + user: Username = "user", + request_timeout: Optional[float] = None, + recursive: bool = False) -> WatchHandle +``` + +Watch directory for filesystem events. + +**Arguments**: + +- `path`: Path to a directory to watch +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** +- `recursive`: Watch directory recursively + +**Returns**: + +`WatchHandle` object for stopping watching directory + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/exceptions/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/exceptions/page.mdx new file mode 100644 index 0000000000..17864645df --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/exceptions/page.mdx @@ -0,0 +1,84 @@ + + + +## SandboxException + +```python +class SandboxException(Exception) +``` + +Base class for all sandbox errors. + +Raised when a general sandbox exception occurs. + + +## TimeoutException + +```python +class TimeoutException(SandboxException) +``` + +Raised when a timeout occurs. + +The `unavailable` exception type is caused by sandbox timeout. + +The `canceled` exception type is caused by exceeding request timeout. + +The `deadline_exceeded` exception type is caused by exceeding the timeout for process, watch, etc. + +The `unknown` exception type is sometimes caused by the sandbox timeout when the request is not processed correctly. + + +## InvalidArgumentException + +```python +class InvalidArgumentException(SandboxException) +``` + +Raised when an invalid argument is provided. + + +## NotEnoughSpaceException + +```python +class NotEnoughSpaceException(SandboxException) +``` + +Raised when there is not enough disk space. + + +## NotFoundException + +```python +class NotFoundException(SandboxException) +``` + +Raised when a resource is not found. + + +## AuthenticationException + +```python +class AuthenticationException(SandboxException) +``` + +Raised when authentication fails. + + +## TemplateException + +```python +class TemplateException(SandboxException) +``` + +Exception raised when the template uses old envd version. It isn't compatible with the new SDK. + + +## RateLimitException + +```python +class RateLimitException(SandboxException) +``` + +Raised when the API rate limit is exceeded. + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/sandbox_async/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/sandbox_async/page.mdx new file mode 100644 index 0000000000..9a9ae08a0b --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/sandbox_async/page.mdx @@ -0,0 +1,970 @@ + + + + + +## AsyncCommandHandle + +```python +class AsyncCommandHandle() +``` + +Command execution handle. + +It provides methods for waiting for the command to finish, retrieving stdout/stderr, and killing the command. + + +### pid + +```python +@property +def pid() +``` + +Command process ID. + + +### stdout + +```python +@property +def stdout() +``` + +Command stdout output. + + +### stderr + +```python +@property +def stderr() +``` + +Command stderr output. + + +### error + +```python +@property +def error() +``` + +Command execution error message. + + +### exit\_code + +```python +@property +def exit_code() +``` + +Command execution exit code. + +`0` if the command finished successfully. + +It is `None` if the command is still running. + + +### disconnect + +```python +async def disconnect() -> None +``` + +Disconnects from the command. + +The command is not killed, but SDK stops receiving events from the command. +You can reconnect to the command using `sandbox.commands.connect` method. + + +### wait + +```python +async def wait() -> CommandResult +``` + +Wait for the command to finish and return the result. + +If the command exits with a non-zero exit code, it throws a `CommandExitException`. + +**Returns**: + +`CommandResult` result of command execution + + +### kill + +```python +async def kill() -> bool +``` + +Kills the command. + +It uses `SIGKILL` signal to kill the command + +**Returns**: + +`True` if the command was killed successfully, `False` if the command was not found + + + + +## Pty + +```python +class Pty() +``` + +Module for interacting with PTYs (pseudo-terminals) in the sandbox. + + +### kill + +```python +async def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kill PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`true` if the PTY was killed, `false` if the PTY was not found + + +### send\_stdin + +```python +async def send_stdin(pid: int, + data: bytes, + request_timeout: Optional[float] = None) -> None +``` + +Send input to a PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `data`: Input data to send +- `request_timeout`: Timeout for the request in **seconds** + + +### create + +```python +async def create( + size: PtySize, + on_data: OutputHandler[PtyOutput], + user: Username = "user", + cwd: Optional[str] = None, + envs: Optional[Dict[str, str]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> AsyncCommandHandle +``` + +Start a new PTY (pseudo-terminal). + +**Arguments**: + +- `size`: Size of the PTY +- `on_data`: Callback to handle PTY data +- `user`: User to use for the PTY +- `cwd`: Working directory for the PTY +- `envs`: Environment variables for the PTY +- `timeout`: Timeout for the PTY in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Handle to interact with the PTY + + +### resize + +```python +async def resize(pid: int, + size: PtySize, + request_timeout: Optional[float] = None) +``` + +Resize PTY. + +Call this when the terminal window is resized and the number of columns and rows has changed. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `size`: New size of the PTY +- `request_timeout`: Timeout for the request in **seconds** + + + + +## Commands + +```python +class Commands() +``` + +Module for executing commands in the sandbox. + + +### list + +```python +async def list(request_timeout: Optional[float] = None) -> List[ProcessInfo] +``` + +Lists all running commands and PTY sessions. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of running commands and PTY sessions + + +### kill + +```python +async def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kill a running command specified by its process ID. + +It uses `SIGKILL` signal to kill the command. + +**Arguments**: + +- `pid`: Process ID of the command. You can get the list of processes using `sandbox.commands.list()` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the command was killed, `False` if the command was not found + + +### send\_stdin + +```python +async def send_stdin(pid: int, + data: str, + request_timeout: Optional[float] = None) -> None +``` + +Send data to command stdin. + +:param pid Process ID of the command. You can get the list of processes using `sandbox.commands.list()`. +:param data: Data to send to the command +:param request_timeout: Timeout for the request in **seconds** + + + +### run + +```python +@overload +async def run(cmd: str, + background: Union[Literal[False], None] = None, + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: Optional[OutputHandler[Stdout]] = None, + on_stderr: Optional[OutputHandler[Stderr]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandResult +``` + +Start a new command and wait until it finishes executing. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: **`False` if the command should be executed in the foreground**, `True` if the command should be executed in the background +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandResult` result of the command execution + + +### run + +```python +@overload +async def run(cmd: str, + background: Literal[True], + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: Optional[OutputHandler[Stdout]] = None, + on_stderr: Optional[OutputHandler[Stderr]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> AsyncCommandHandle +``` + +Start a new command and return a handle to interact with it. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: `False` if the command should be executed in the foreground, **`True` if the command should be executed in the background** +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`AsyncCommandHandle` handle to interact with the running command + + +### connect + +```python +async def connect( + pid: int, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None, + on_stdout: Optional[OutputHandler[Stdout]] = None, + on_stderr: Optional[OutputHandler[Stderr]] = None +) -> AsyncCommandHandle +``` + +Connects to a running command. + +You can use `AsyncCommandHandle.wait()` to wait for the command to finish and get execution results. + +**Arguments**: + +- `pid`: Process ID of the command to connect to. You can get the list of processes using `sandbox.commands.list()` +- `request_timeout`: Request timeout in **seconds** +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output + +**Returns**: + +`AsyncCommandHandle` handle to interact with the running command + + + + +## SandboxApi + +```python +class SandboxApi(SandboxApiBase) +``` + + +### list + +```python +@classmethod +async def list(cls, + api_key: Optional[str] = None, + query: Optional[SandboxQuery] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> List[SandboxInfo] +``` + +List all running sandboxes. + +**Arguments**: + +- `api_key`: API key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `query`: Filter the list of sandboxes, e.g. by metadata `SandboxQuery(metadata={"key": "value"})`, if there are multiple filters they are combined with AND. +- `domain`: Domain to use for the request, only relevant for self-hosted environments +- `debug`: Enable debug mode, all requested are then sent to localhost +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of running sandboxes + + + + +## AsyncSandbox + +```python +class AsyncSandbox(SandboxSetup, SandboxApi) +``` + +E2B cloud sandbox is a secure and isolated cloud environment. + +The sandbox allows you to: +- Access Linux OS +- Create, list, and delete files and directories +- Run commands +- Run isolated code +- Access the internet + +Check docs [here](https://e2b.dev/docs). + +Use the `AsyncSandbox.create()` to create a new sandbox. + +**Example**: + +```python +from e2b import AsyncSandbox + +sandbox = await AsyncSandbox.create() +``` + + +### files + +```python +@property +def files() -> Filesystem +``` + +Module for interacting with the sandbox filesystem. + + +### commands + +```python +@property +def commands() -> Commands +``` + +Module for running commands in the sandbox. + + +### pty + +```python +@property +def pty() -> Pty +``` + +Module for interacting with the sandbox pseudo-terminal. + + +### sandbox\_id + +```python +@property +def sandbox_id() -> str +``` + +Unique identifier of the sandbox. + + +### \_\_init\_\_ + +```python +def __init__(**opts: Unpack[AsyncSandboxOpts]) +``` + +Use `AsyncSandbox.create()` to create a new sandbox instead. + + +### is\_running + +```python +async def is_running(request_timeout: Optional[float] = None) -> bool +``` + +Check if the sandbox is running. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox is running, `False` otherwise +Example +```python +sandbox = await AsyncSandbox.create() +await sandbox.is_running() # Returns True + +await sandbox.kill() +await sandbox.is_running() # Returns False +``` + + +### create + +```python +@classmethod +async def create(cls, + template: Optional[str] = None, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + envs: Optional[Dict[str, str]] = None, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) +``` + +Create a new sandbox. + +By default, the sandbox is created from the default `base` sandbox template. + +**Arguments**: + +- `template`: Sandbox template name or ID +- `timeout`: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. +- `metadata`: Custom metadata for the sandbox +- `envs`: Custom environment variables for the sandbox +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +sandbox instance for the new sandbox +Use this method instead of using the constructor to create a new sandbox. + + +### connect + +```python +@classmethod +async def connect(cls, + sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None) +``` + +Connect to an existing sandbox. + +With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc). + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable + +**Returns**: + +sandbox instance for the existing sandbox +@example +```python +sandbox = await AsyncSandbox.create() +sandbox_id = sandbox.sandbox_id + +same_sandbox = await AsyncSandbox.connect(sandbox_id) + + +### kill + +```python +@overload +async def kill(request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### kill + +```python +@overload +@staticmethod +async def kill(sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox specified by sandbox ID. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### set\_timeout + +```python +@overload +async def set_timeout(timeout: int, + request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the sandbox. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `timeout`: Timeout for the sandbox in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + + +### set\_timeout + +```python +@overload +@staticmethod +async def set_timeout(sandbox_id: str, + timeout: int, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the specified sandbox. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `timeout`: Timeout for the sandbox in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + + + + +## AsyncWatchHandle + +```python +class AsyncWatchHandle() +``` + +Handle for watching a directory in the sandbox filesystem. + +Use `.stop()` to stop watching the directory. + + +### stop + +```python +async def stop() +``` + +Stop watching the directory. + + + + +## Filesystem + +```python +class Filesystem() +``` + +Module for interacting with the filesystem in the sandbox. + + +### read + +```python +@overload +async def read(path: str, + format: Literal["text"] = "text", + user: Username = "user", + request_timeout: Optional[float] = None) -> str +``` + +Read file content as a `str`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`text` by default +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `str` + + +### read + +```python +@overload +async def read(path: str, + format: Literal["bytes"], + user: Username = "user", + request_timeout: Optional[float] = None) -> bytearray +``` + +Read file content as a `bytearray`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`bytes` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `bytearray` + + +### read + +```python +@overload +async def read( + path: str, + format: Literal["stream"], + user: Username = "user", + request_timeout: Optional[float] = None) -> AsyncIterator[bytes] +``` + +Read file content as a `AsyncIterator[bytes]`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`stream` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as an `AsyncIterator[bytes]` + + +### write + +```python +@overload +async def write(path: str, + data: Union[str, bytes, IO], + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Write content to a file on the path. + +Writing to a file that doesn't exist creates the file. + +Writing to a file that already exists overwrites the file. + +Writing to a file at path that doesn't exist creates the necessary directories. + +**Arguments**: + +- `path`: Path to the file +- `data`: Data to write to the file, can be a `str`, `bytes`, or `IO`. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the written file + + +### write + +```python +@overload +async def write(files: List[WriteEntry], + user: Optional[Username] = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +Writes multiple files. + +**Arguments**: + +- `files`: list of files to write +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request + +**Returns**: + +Information about the written files + + +### write + +```python +async def write( + path_or_files: Union[str, List[WriteEntry]], + data_or_user: Union[str, bytes, IO, Username] = "user", + user_or_request_timeout: Optional[Union[float, Username]] = None, + request_timeout_or_none: Optional[float] = None +) -> Union[EntryInfo, List[EntryInfo]] +``` + +Writes content to a file on the path. +When writing to a file that doesn't exist, the file will get created. +When writing to a file that already exists, the file will get overwritten. +When writing to a file that's in a directory that doesn't exist, you'll get an error. + + +### list + +```python +async def list(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +List entries in a directory. + +**Arguments**: + +- `path`: Path to the directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of entries in the directory + + +### exists + +```python +async def exists(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Check if a file or a directory exists. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the file or directory exists, `False` otherwise + + +### remove + +```python +async def remove(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> None +``` + +Remove a file or a directory. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + + +### rename + +```python +async def rename(old_path: str, + new_path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Rename a file or directory. + +**Arguments**: + +- `old_path`: Path to the file or directory to rename +- `new_path`: New path to the file or directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the renamed file or directory + + +### make\_dir + +```python +async def make_dir(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Create a new directory and all directories along the way if needed on the specified path. + +**Arguments**: + +- `path`: Path to a new directory. For example '/dirA/dirB' when creating 'dirB'. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the directory was created, `False` if the directory already exists + + +### watch\_dir + +```python +async def watch_dir(path: str, + on_event: OutputHandler[FilesystemEvent], + on_exit: Optional[OutputHandler[Exception]] = None, + user: Username = "user", + request_timeout: Optional[float] = None, + timeout: Optional[float] = 60, + recursive: bool = False) -> AsyncWatchHandle +``` + +Watch directory for filesystem events. + +**Arguments**: + +- `path`: Path to a directory to watch +- `on_event`: Callback to call on each event in the directory +- `on_exit`: Callback to call when the watching ends +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** +- `timeout`: Timeout for the watch operation in **seconds**. Using `0` will not limit the watch time +- `recursive`: Watch directory recursively + +**Returns**: + +`AsyncWatchHandle` object for stopping watching directory + diff --git a/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/sandbox_sync/page.mdx b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/sandbox_sync/page.mdx new file mode 100644 index 0000000000..271bfe5cdb --- /dev/null +++ b/apps/web/src/app/(docs)/docs/sdk-reference/python-sdk/v1.2.1/sandbox_sync/page.mdx @@ -0,0 +1,935 @@ + + + +## CommandHandle + +```python +class CommandHandle() +``` + +Command execution handle. + +It provides methods for waiting for the command to finish, retrieving stdout/stderr, and killing the command. + + +### pid + +```python +@property +def pid() +``` + +Command process ID. + + +### \_\_iter\_\_ + +```python +def __iter__() +``` + +Iterate over the command output. + +**Returns**: + +Generator of command outputs + + +### disconnect + +```python +def disconnect() -> None +``` + +Disconnect from the command. + +The command is not killed, but SDK stops receiving events from the command. +You can reconnect to the command using `sandbox.commands.connect` method. + + +### wait + +```python +def wait(on_pty: Optional[Callable[[PtyOutput], None]] = None, + on_stdout: Optional[Callable[[str], None]] = None, + on_stderr: Optional[Callable[[str], None]] = None) -> CommandResult +``` + +Wait for the command to finish and returns the result. + +If the command exits with a non-zero exit code, it throws a `CommandExitException`. + +**Arguments**: + +- `on_pty`: Callback for pty output +- `on_stdout`: Callback for stdout output +- `on_stderr`: Callback for stderr output + +**Returns**: + +`CommandResult` result of command execution + + +### kill + +```python +def kill() -> bool +``` + +Kills the command. + +It uses `SIGKILL` signal to kill the command. + +**Returns**: + +Whether the command was killed successfully + + + + +## Pty + +```python +class Pty() +``` + +Module for interacting with PTYs (pseudo-terminals) in the sandbox. + + +### kill + +```python +def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kill PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`true` if the PTY was killed, `false` if the PTY was not found + + +### send\_stdin + +```python +def send_stdin(pid: int, + data: bytes, + request_timeout: Optional[float] = None) -> None +``` + +Send input to a PTY. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `data`: Input data to send +- `request_timeout`: Timeout for the request in **seconds** + + +### create + +```python +def create(size: PtySize, + user: Username = "user", + cwd: Optional[str] = None, + envs: Optional[Dict[str, str]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandHandle +``` + +Start a new PTY (pseudo-terminal). + +**Arguments**: + +- `size`: Size of the PTY +- `user`: User to use for the PTY +- `cwd`: Working directory for the PTY +- `envs`: Environment variables for the PTY +- `timeout`: Timeout for the PTY in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Handle to interact with the PTY + + +### resize + +```python +def resize(pid: int, + size: PtySize, + request_timeout: Optional[float] = None) -> None +``` + +Resize PTY. + +Call this when the terminal window is resized and the number of columns and rows has changed. + +**Arguments**: + +- `pid`: Process ID of the PTY +- `size`: New size of the PTY +- `request_timeout`: Timeout for the request in **seconds**s + + + + +## Commands + +```python +class Commands() +``` + +Module for executing commands in the sandbox. + + +### list + +```python +def list(request_timeout: Optional[float] = None) -> List[ProcessInfo] +``` + +Lists all running commands and PTY sessions. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of running commands and PTY sessions + + +### kill + +```python +def kill(pid: int, request_timeout: Optional[float] = None) -> bool +``` + +Kills a running command specified by its process ID. + +It uses `SIGKILL` signal to kill the command. + +**Arguments**: + +- `pid`: Process ID of the command. You can get the list of processes using `sandbox.commands.list()` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the command was killed, `False` if the command was not found + + +### send\_stdin + +```python +def send_stdin(pid: int, data: str, request_timeout: Optional[float] = None) +``` + +Send data to command stdin. + +:param pid Process ID of the command. You can get the list of processes using `sandbox.commands.list()`. +:param data: Data to send to the command +:param request_timeout: Timeout for the request in **seconds** + + + +### run + +```python +@overload +def run(cmd: str, + background: Union[Literal[False], None] = None, + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: Optional[Callable[[str], None]] = None, + on_stderr: Optional[Callable[[str], None]] = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandResult +``` + +Start a new command and wait until it finishes executing. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: **`False` if the command should be executed in the foreground**, `True` if the command should be executed in the background +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `on_stdout`: Callback for command stdout output +- `on_stderr`: Callback for command stderr output +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandResult` result of the command execution + + +### run + +```python +@overload +def run(cmd: str, + background: Literal[True], + envs: Optional[Dict[str, str]] = None, + user: Username = "user", + cwd: Optional[str] = None, + on_stdout: None = None, + on_stderr: None = None, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) -> CommandHandle +``` + +Start a new command and return a handle to interact with it. + +**Arguments**: + +- `cmd`: Command to execute +- `background`: `False` if the command should be executed in the foreground, **`True` if the command should be executed in the background** +- `envs`: Environment variables used for the command +- `user`: User to run the command as +- `cwd`: Working directory to run the command +- `timeout`: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandHandle` handle to interact with the running command + + +### connect + +```python +def connect(pid: int, + timeout: Optional[float] = 60, + request_timeout: Optional[float] = None) +``` + +Connects to a running command. + +You can use `CommandHandle.wait()` to wait for the command to finish and get execution results. + +**Arguments**: + +- `pid`: Process ID of the command to connect to. You can get the list of processes using `sandbox.commands.list()` +- `timeout`: Timeout for the connection in **seconds**. Using `0` will not limit the connection time +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`CommandHandle` handle to interact with the running command + + + + +## SandboxApi + +```python +class SandboxApi(SandboxApiBase) +``` + + +### list + +```python +@classmethod +def list(cls, + api_key: Optional[str] = None, + query: Optional[SandboxQuery] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> List[SandboxInfo] +``` + +List all running sandboxes. + +**Arguments**: + +- `api_key`: API key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `query`: Filter the list of sandboxes, e.g. by metadata `SandboxQuery(metadata={"key": "value"})`, if there are multiple filters they are combined with AND. +- `domain`: Domain to use for the request, only relevant for self-hosted environments +- `debug`: Enable debug mode, all requested are then sent to localhost +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of running sandboxes + + + + +## Sandbox + +```python +class Sandbox(SandboxSetup, SandboxApi) +``` + +E2B cloud sandbox is a secure and isolated cloud environment. + +The sandbox allows you to: +- Access Linux OS +- Create, list, and delete files and directories +- Run commands +- Run isolated code +- Access the internet + +Check docs [here](https://e2b.dev/docs). + +Use the `Sandbox()` to create a new sandbox. + +**Example**: + +```python +from e2b import Sandbox + +sandbox = Sandbox() +``` + + +### files + +```python +@property +def files() -> Filesystem +``` + +Module for interacting with the sandbox filesystem. + + +### commands + +```python +@property +def commands() -> Commands +``` + +Module for running commands in the sandbox. + + +### pty + +```python +@property +def pty() -> Pty +``` + +Module for interacting with the sandbox pseudo-terminal. + + +### sandbox\_id + +```python +@property +def sandbox_id() -> str +``` + +Unique identifier of the sandbox + + +### \_\_init\_\_ + +```python +def __init__(template: Optional[str] = None, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + envs: Optional[Dict[str, str]] = None, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + sandbox_id: Optional[str] = None, + request_timeout: Optional[float] = None) +``` + +Create a new sandbox. + +By default, the sandbox is created from the default `base` sandbox template. + +**Arguments**: + +- `template`: Sandbox template name or ID +- `timeout`: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users +- `metadata`: Custom metadata for the sandbox +- `envs`: Custom environment variables for the sandbox +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +sandbox instance for the new sandbox + + +### is\_running + +```python +def is_running(request_timeout: Optional[float] = None) -> bool +``` + +Check if the sandbox is running. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox is running, `False` otherwise +Example +```python +sandbox = Sandbox() +sandbox.is_running() # Returns True + +sandbox.kill() +sandbox.is_running() # Returns False +``` + + +### connect + +```python +@classmethod +def connect(cls, + sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None) +``` + +Connects to an existing Sandbox. + +With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc). + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable + +**Returns**: + +sandbox instance for the existing sandbox +@example +```python +sandbox = Sandbox() +sandbox_id = sandbox.sandbox_id + +same_sandbox = Sandbox.connect(sandbox_id) +``` + + +### kill + +```python +@overload +def kill(request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox. + +**Arguments**: + +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### kill + +```python +@overload +@staticmethod +def kill(sandbox_id: str, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox specified by sandbox ID. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### kill + +```python +@class_method_variant("_cls_kill") +def kill(request_timeout: Optional[float] = None) -> bool +``` + +Kill the sandbox. + +**Arguments**: + +- `request_timeout`: Timeout for the request + +**Returns**: + +`True` if the sandbox was killed, `False` if the sandbox was not found + + +### set\_timeout + +```python +@overload +def set_timeout(timeout: int, request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the sandbox. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `timeout`: Timeout for the sandbox in **seconds** +- `request_timeout`: Timeout for the request in **seconds** + + +### set\_timeout + +```python +@overload +@staticmethod +def set_timeout(sandbox_id: str, + timeout: int, + api_key: Optional[str] = None, + domain: Optional[str] = None, + debug: Optional[bool] = None, + request_timeout: Optional[float] = None) -> None +``` + +Set the timeout of the sandbox specified by sandbox ID. + +After the timeout expires the sandbox will be automatically killed. +This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`. + +Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users. + +**Arguments**: + +- `sandbox_id`: Sandbox ID +- `timeout`: Timeout for the sandbox in **seconds** +- `api_key`: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable +- `request_timeout`: Timeout for the request in **seconds** + + + + +## WatchHandle + +```python +class WatchHandle() +``` + +Handle for watching filesystem events. +It is used to get the latest events that have occurred in the watched directory. + +Use `.stop()` to stop watching the directory. + + +### stop + +```python +def stop() +``` + +Stop watching the directory. +After you stop the watcher you won't be able to get the events anymore. + + +### get\_new\_events + +```python +def get_new_events() -> List[FilesystemEvent] +``` + +Get the latest events that have occurred in the watched directory since the last call, or from the beginning of the watching, up until now. + +**Returns**: + +List of filesystem events + + + + +## Filesystem + +```python +class Filesystem() +``` + +Module for interacting with the filesystem in the sandbox. + + +### read + +```python +@overload +def read(path: str, + format: Literal["text"] = "text", + user: Username = "user", + request_timeout: Optional[float] = None) -> str +``` + +Read file content as a `str`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`text` by default +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `str` + + +### read + +```python +@overload +def read(path: str, + format: Literal["bytes"], + user: Username = "user", + request_timeout: Optional[float] = None) -> bytearray +``` + +Read file content as a `bytearray`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`bytes` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as a `bytearray` + + +### read + +```python +@overload +def read(path: str, + format: Literal["stream"], + user: Username = "user", + request_timeout: Optional[float] = None) -> Iterator[bytes] +``` + +Read file content as a `Iterator[bytes]`. + +**Arguments**: + +- `path`: Path to the file +- `user`: Run the operation as this user +- `format`: Format of the file content—`stream` +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +File content as an `Iterator[bytes]` + + +### write + +```python +@overload +def write(path: str, + data: Union[str, bytes, IO], + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Write content to a file on the path. + +Writing to a file that doesn't exist creates the file. + +Writing to a file that already exists overwrites the file. + +Writing to a file at path that doesn't exist creates the necessary directories. + +**Arguments**: + +- `path`: Path to the file +- `data`: Data to write to the file, can be a `str`, `bytes`, or `IO`. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the written file + + +### write + +```python +@overload +def write(files: List[WriteEntry], + user: Optional[Username] = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +Writes a list of files to the filesystem. + +When writing to a file that doesn't exist, the file will get created. +When writing to a file that already exists, the file will get overwritten. +When writing to a file that's in a directory that doesn't exist, you'll get an error. + +**Arguments**: + +- `files`: list of files to write +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request + +**Returns**: + +Information about the written files + + +### list + +```python +def list(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> List[EntryInfo] +``` + +List entries in a directory. + +**Arguments**: + +- `path`: Path to the directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +List of entries in the directory + + +### exists + +```python +def exists(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Check if a file or a directory exists. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the file or directory exists, `False` otherwise + + +### remove + +```python +def remove(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> None +``` + +Remove a file or a directory. + +**Arguments**: + +- `path`: Path to a file or a directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + + +### rename + +```python +def rename(old_path: str, + new_path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> EntryInfo +``` + +Rename a file or directory. + +**Arguments**: + +- `old_path`: Path to the file or directory to rename +- `new_path`: New path to the file or directory +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +Information about the renamed file or directory + + +### make\_dir + +```python +def make_dir(path: str, + user: Username = "user", + request_timeout: Optional[float] = None) -> bool +``` + +Create a new directory and all directories along the way if needed on the specified path. + +**Arguments**: + +- `path`: Path to a new directory. For example '/dirA/dirB' when creating 'dirB'. +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** + +**Returns**: + +`True` if the directory was created, `False` if the directory already exists + + +### watch\_dir + +```python +def watch_dir(path: str, + user: Username = "user", + request_timeout: Optional[float] = None, + recursive: bool = False) -> WatchHandle +``` + +Watch directory for filesystem events. + +**Arguments**: + +- `path`: Path to a directory to watch +- `user`: Run the operation as this user +- `request_timeout`: Timeout for the request in **seconds** +- `recursive`: Watch directory recursively + +**Returns**: + +`WatchHandle` object for stopping watching directory + diff --git a/packages/cli/src/commands/template/build.ts b/packages/cli/src/commands/template/build.ts index c36b872835..26d4c60923 100644 --- a/packages/cli/src/commands/template/build.ts +++ b/packages/cli/src/commands/template/build.ts @@ -397,7 +397,7 @@ export const buildCommand = new commander.Command('build') console.log( `> Triggered build for the sandbox template ${asFormattedSandboxTemplate( template - )} ` + )} with build ID: ${template.buildID}` ) console.log('Waiting for build to finish...') diff --git a/packages/js-sdk/src/api/schema.gen.ts b/packages/js-sdk/src/api/schema.gen.ts index 4af6c3c6fc..f4ea32fccf 100644 --- a/packages/js-sdk/src/api/schema.gen.ts +++ b/packages/js-sdk/src/api/schema.gen.ts @@ -15,8 +15,8 @@ export interface paths { get: { parameters: { query?: { - /** @description A query used to filter the sandboxes (e.g. "user=abc&app=prod"). Query and each key and values must be URL encoded. */ - query?: string; + /** @description Metadata query used to filter the sandboxes (e.g. "user=abc&app=prod"). Each key and values must be URL encoded. */ + metadata?: string; }; header?: never; path?: never; @@ -404,6 +404,48 @@ export interface paths { patch?: never; trace?: never; }; + "/sandboxes/metrics": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List all running sandboxes with metrics */ + get: { + parameters: { + query?: { + /** @description Metadata query used to filter the sandboxes (e.g. "user=abc&app=prod"). Each key and values must be URL encoded. */ + metadata?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned all running sandboxes with metrics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["RunningSandboxWithMetrics"][]; + }; + }; + 400: components["responses"]["400"]; + 401: components["responses"]["401"]; + 500: components["responses"]["500"]; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/templates": { parameters: { query?: never; @@ -656,6 +698,48 @@ export interface components { * @description CPU cores for the sandbox */ CPUCount: number; + CreatedAccessToken: { + /** + * Format: date-time + * @description Timestamp of access token creation + */ + createdAt: string; + /** + * Format: uuid + * @description Identifier of the access token + */ + id: string; + /** @description Name of the access token */ + name: string; + /** @description Raw value of the access token */ + token: string; + /** @description Mask of the access token */ + tokenMask: string; + }; + CreatedTeamAPIKey: { + /** + * Format: date-time + * @description Timestamp of API key creation + */ + createdAt: string; + createdBy: components["schemas"]["TeamUser"] | null; + /** + * Format: uuid + * @description Identifier of the API key + */ + id: string; + /** @description Raw value of the API key */ + key: string; + /** @description Mask of the API key */ + keyMask: string; + /** + * Format: date-time + * @description Last time this API key was used + */ + lastUsed: string | null; + /** @description Name of the API key */ + name: string; + }; EnvVars: { [key: string]: string; }; @@ -673,7 +757,16 @@ export interface components { * @description Memory for the sandbox in MB */ MemoryMB: number; + NewAccessToken: { + /** @description Name of the access token */ + name: string; + }; NewSandbox: { + /** + * @description Automatically pauses the sandbox after the timeout + * @default false + */ + autoPause: boolean; envVars?: components["schemas"]["EnvVars"]; metadata?: components["schemas"]["SandboxMetadata"]; /** @description Identifier of the required template */ @@ -685,6 +778,10 @@ export interface components { */ timeout: number; }; + NewTeamAPIKey: { + /** @description Name of the API key */ + name: string; + }; Node: { /** * Format: int32 @@ -696,6 +793,11 @@ export interface components { * @description Amount of allocated memory in MiB */ allocatedMemoryMiB: number; + /** + * Format: uint64 + * @description Number of sandbox create fails + */ + createFails: number; /** @description Identifier of the node */ nodeID: string; /** @@ -703,11 +805,21 @@ export interface components { * @description Number of sandboxes running on the node */ sandboxCount: number; + /** + * Format: int + * @description Number of starting Sandboxes + */ + sandboxStartingCount: number; status: components["schemas"]["NodeStatus"]; }; NodeDetail: { /** @description List of cached builds id on the node */ cachedBuilds: string[]; + /** + * Format: uint64 + * @description Number of sandbox create fails + */ + createFails: number; /** @description Identifier of the node */ nodeID: string; /** @description List of sandboxes running on the node */ @@ -718,11 +830,16 @@ export interface components { * @description Status of the node * @enum {string} */ - NodeStatus: "ready" | "draining"; + NodeStatus: "ready" | "draining" | "connecting" | "unhealthy"; NodeStatusChange: { status: components["schemas"]["NodeStatus"]; }; ResumedSandbox: { + /** + * @description Automatically pauses the sandbox after the timeout + * @default false + */ + autoPause: boolean; /** * Format: int32 * @description Time to live for the sandbox in seconds. @@ -753,6 +870,30 @@ export interface components { /** @description Identifier of the template from which is the sandbox created */ templateID: string; }; + RunningSandboxWithMetrics: { + /** @description Alias of the template */ + alias?: string; + /** @description Identifier of the client */ + clientID: string; + cpuCount: components["schemas"]["CPUCount"]; + /** + * Format: date-time + * @description Time when the sandbox will expire + */ + endAt: string; + memoryMB: components["schemas"]["MemoryMB"]; + metadata?: components["schemas"]["SandboxMetadata"]; + metrics?: components["schemas"]["SandboxMetric"][]; + /** @description Identifier of the sandbox */ + sandboxID: string; + /** + * Format: date-time + * @description Time when the sandbox was started + */ + startedAt: string; + /** @description Identifier of the template from which is the sandbox created */ + templateID: string; + }; Sandbox: { /** @description Alias of the template */ alias?: string; @@ -820,6 +961,28 @@ export interface components { /** @description Identifier of the team */ teamID: string; }; + TeamAPIKey: { + /** + * Format: date-time + * @description Timestamp of API key creation + */ + createdAt: string; + createdBy: components["schemas"]["TeamUser"] | null; + /** + * Format: uuid + * @description Identifier of the API key + */ + id: string; + /** @description Mask of the API key */ + keyMask: string; + /** + * Format: date-time + * @description Last time this API key was used + */ + lastUsed: string | null; + /** @description Name of the API key */ + name: string; + }; TeamUser: { /** @description Email of the user */ email: string; @@ -879,7 +1042,7 @@ export interface components { * @description Status of the template * @enum {string} */ - status: "building" | "ready" | "error"; + status: "building" | "waiting" | "ready" | "error"; /** @description Identifier of the template */ templateID: string; }; @@ -899,6 +1062,10 @@ export interface components { /** @description Whether the template is public or only accessible by the team */ public?: boolean; }; + UpdateTeamAPIKey: { + /** @description New name for the API key */ + name: string; + }; }; responses: { /** @description Bad request */ @@ -948,6 +1115,8 @@ export interface components { }; }; parameters: { + accessTokenID: string; + apiKeyID: string; buildID: string; nodeID: string; sandboxID: string; diff --git a/packages/js-sdk/src/index.ts b/packages/js-sdk/src/index.ts index 61541c1337..17e6e59d8b 100644 --- a/packages/js-sdk/src/index.ts +++ b/packages/js-sdk/src/index.ts @@ -1,26 +1,23 @@ export { ApiClient } from './api' export type { components, paths } from './api' +export { ConnectionConfig } from './connectionConfig' +export type { ConnectionOpts, Username } from './connectionConfig' export { AuthenticationError, - SandboxError, - TimeoutError, - NotFoundError, - NotEnoughSpaceError, InvalidArgumentError, + NotEnoughSpaceError, + NotFoundError, + SandboxError, TemplateError, + TimeoutError, } from './errors' -export { ConnectionConfig } from './connectionConfig' export type { Logger } from './logs' -export type { ConnectionOpts, Username } from './connectionConfig' -export { FilesystemEventType } from './sandbox/filesystem/watchHandle' -export type { - FilesystemEvent, - WatchHandle, -} from './sandbox/filesystem/watchHandle' -export type { EntryInfo, Filesystem, WatchOpts } from './sandbox/filesystem' export { FileType } from './sandbox/filesystem' +export type { EntryInfo, Filesystem } from './sandbox/filesystem' +export { FilesystemEventType } from './sandbox/filesystem/watchHandle' +export type { FilesystemEvent, WatchHandle } from './sandbox/filesystem/watchHandle' export { CommandExitError } from './sandbox/commands/commandHandle' export type { @@ -41,8 +38,8 @@ export type { Pty, } from './sandbox/commands' -export type { SandboxInfo } from './sandbox/sandboxApi' export type { SandboxOpts } from './sandbox' -import { Sandbox } from './sandbox' +export type { SandboxInfo } from './sandbox/sandboxApi' export { Sandbox } +import { Sandbox } from './sandbox' export default Sandbox diff --git a/packages/js-sdk/src/sandbox/filesystem/index.ts b/packages/js-sdk/src/sandbox/filesystem/index.ts index da61cdd18d..13f511458b 100644 --- a/packages/js-sdk/src/sandbox/filesystem/index.ts +++ b/packages/js-sdk/src/sandbox/filesystem/index.ts @@ -7,20 +7,23 @@ import { } from '@connectrpc/connect' import { ConnectionConfig, - defaultUsername, - Username, ConnectionOpts, - KEEPALIVE_PING_INTERVAL_SEC, + defaultUsername, KEEPALIVE_PING_HEADER, + KEEPALIVE_PING_INTERVAL_SEC, + Username, } from '../../connectionConfig' import { handleEnvdApiError, handleWatchDirStartEvent } from '../../envd/api' import { authenticationHeader, handleRpcError } from '../../envd/rpc' import { EnvdApiClient } from '../../envd/api' -import { FileType as FsFileType, Filesystem as FilesystemService } from '../../envd/filesystem/filesystem_pb' +import { + FileType as FsFileType, + Filesystem as FilesystemService, +} from '../../envd/filesystem/filesystem_pb' -import { WatchHandle, FilesystemEvent } from './watchHandle' +import { FilesystemEvent, WatchHandle } from './watchHandle' import { compareVersions } from 'compare-versions' import { TemplateError } from '../../errors' @@ -58,6 +61,11 @@ export const enum FileType { DIR = 'dir', } +export type WriteEntry = { + path: string + data: string | ArrayBuffer | Blob | ReadableStream +} + function mapFileType(fileType: FsFileType) { switch (fileType) { case FsFileType.DIRECTORY: @@ -233,22 +241,75 @@ export class Filesystem { path: string, data: string | ArrayBuffer | Blob | ReadableStream, opts?: FilesystemRequestOpts - ): Promise { - const blob = await new Response(data).blob() + ): Promise + async write( + files: WriteEntry[], + opts?: FilesystemRequestOpts + ): Promise + async write( + pathOrFiles: string | WriteEntry[], + dataOrOpts?: + | string + | ArrayBuffer + | Blob + | ReadableStream + | FilesystemRequestOpts, + opts?: FilesystemRequestOpts + ): Promise { + if (typeof pathOrFiles !== 'string' && !Array.isArray(pathOrFiles)) { + throw new Error('Path or files are required') + } + + if (typeof pathOrFiles === 'string' && Array.isArray(dataOrOpts)) { + throw new Error( + 'Cannot specify both path and array of files. You have to specify either path and data for a single file or an array for multiple files.' + ) + } + + const { path, writeOpts, writeFiles } = + typeof pathOrFiles === 'string' + ? { + path: pathOrFiles, + writeOpts: opts as FilesystemRequestOpts, + writeFiles: [ + { + data: dataOrOpts as + | string + | ArrayBuffer + | Blob + | ReadableStream, + }, + ], + } + : { + path: undefined, + writeOpts: dataOrOpts as FilesystemRequestOpts, + writeFiles: pathOrFiles as WriteEntry[], + } + + if (writeFiles.length === 0) return [] as EntryInfo[] + + const blobs = await Promise.all( + writeFiles.map((f) => new Response(f.data).blob()) + ) const res = await this.envdApi.api.POST('/files', { params: { query: { path, - username: opts?.user || defaultUsername, + username: writeOpts?.user || defaultUsername, }, }, bodySerializer() { - const fd = new FormData() - - fd.append('file', blob) - - return fd + return blobs.reduce((fd, blob, i) => { + // Important: RFC 7578, Section 4.2 requires that if a filename is provided, + // the directory path information must not be used. + // BUT in our case we need to use the directory path information with a custom + // muktipart part name getter in envd. + fd.append('file', blob, writeFiles[i].path) + + return fd + }, new FormData()) }, body: {}, headers: { @@ -262,12 +323,12 @@ export class Filesystem { throw err } - const files = res.data - if (!files || files.length === 0) { + const files = res.data as EntryInfo[] + if (!files) { throw new Error('Expected to receive information about written file') } - return files[0] as EntryInfo + return files.length === 1 && path ? files[0] : files } /** @@ -441,12 +502,19 @@ export class Filesystem { async watchDir( path: string, onEvent: (event: FilesystemEvent) => void | Promise, - opts?: WatchOpts + opts?: WatchOpts & { + timeout?: number + onExit?: (err?: Error) => void | Promise + } ): Promise { - if (opts?.recursive && this.envdApi.version && compareVersions(this.envdApi.version, ENVD_VERSION_RECURSIVE_WATCH) < 0) { + if ( + opts?.recursive && + this.envdApi.version && + compareVersions(this.envdApi.version, ENVD_VERSION_RECURSIVE_WATCH) < 0 + ) { throw new TemplateError( 'You need to update the template to use recursive watching. ' + - 'You can do this by running `e2b template build` in the directory with the template.' + 'You can do this by running `e2b template build` in the directory with the template.' ) } @@ -457,8 +525,8 @@ export class Filesystem { const reqTimeout = requestTimeoutMs ? setTimeout(() => { - controller.abort() - }, requestTimeoutMs) + controller.abort() + }, requestTimeoutMs) : undefined const events = this.rpc.watchDir( diff --git a/packages/js-sdk/src/sandbox/sandboxApi.ts b/packages/js-sdk/src/sandbox/sandboxApi.ts index 0a8aadf9c9..d1d66d2dc6 100644 --- a/packages/js-sdk/src/sandbox/sandboxApi.ts +++ b/packages/js-sdk/src/sandbox/sandboxApi.ts @@ -9,13 +9,13 @@ import { NotFoundError, TemplateError } from '../errors' export interface SandboxApiOpts extends Partial< Pick - > { } + > {} export interface SandboxListOpts extends SandboxApiOpts { /** - * Filter the list of sandboxes by metadata, e.g. `{"key": "value"}`, if there are multiple filters they are combined with AND. + * Filter the list of sandboxes, e.g. by metadata `metadata:{"key": "value"}`, if there are multiple filters they are combined with AND. */ - filters?: Record + query?: { metadata?: Record } } /** @@ -49,7 +49,7 @@ export interface SandboxInfo { } export class SandboxApi { - protected constructor() { } + protected constructor() {} /** * Kill the sandbox specified by sandbox ID. @@ -94,21 +94,27 @@ export class SandboxApi { * * @returns list of running sandboxes. */ - static async list( - opts?: SandboxListOpts): Promise { + static async list(opts?: SandboxListOpts): Promise { const config = new ConnectionConfig(opts) const client = new ApiClient(config) - let query = undefined - if (opts?.filters) { - const encodedPairs: Record = Object.fromEntries(Object.entries(opts.filters).map(([key, value]) => [encodeURIComponent(key),encodeURIComponent(value)])) - query = new URLSearchParams(encodedPairs).toString() + let metadata = undefined + if (opts?.query) { + if (opts.query.metadata) { + const encodedPairs: Record = Object.fromEntries( + Object.entries(opts.query.metadata).map(([key, value]) => [ + encodeURIComponent(key), + encodeURIComponent(value), + ]) + ) + metadata = new URLSearchParams(encodedPairs).toString() + } } const res = await client.api.GET('/sandboxes', { - params: { - query: {query}, - }, + params: { + query: { metadata }, + }, signal: config.getSignal(opts?.requestTimeoutMs), }) @@ -207,13 +213,13 @@ export class SandboxApi { } /** - * Pause the sandbox specified by sandbox ID. - * - * @param sandboxId sandbox ID. - * @param opts connection options. - * - * @returns `true` if the sandbox got paused, `false` if the sandbox was already paused. - */ + * Pause the sandbox specified by sandbox ID. + * + * @param sandboxId sandbox ID. + * @param opts connection options. + * + * @returns `true` if the sandbox got paused, `false` if the sandbox was already paused. + */ protected static async pauseSandbox( sandboxId: string, opts?: SandboxApiOpts @@ -247,7 +253,6 @@ export class SandboxApi { return true } - protected static async resumeSandbox( sandboxId: string, timeoutMs: number, @@ -263,6 +268,7 @@ export class SandboxApi { }, }, body: { + autoPause: false, timeout: this.timeoutToSeconds(timeoutMs), }, signal: config.getSignal(opts?.requestTimeoutMs), @@ -301,6 +307,7 @@ export class SandboxApi { const res = await client.api.POST('/sandboxes', { body: { + autoPause: false, templateID: template, metadata: opts?.metadata, envVars: opts?.envs, @@ -324,7 +331,7 @@ export class SandboxApi { ) throw new TemplateError( 'You need to update the template to use the new SDK. ' + - 'You can do this by running `e2b template build` in the directory with the template.' + 'You can do this by running `e2b template build` in the directory with the template.' ) } return { diff --git a/packages/js-sdk/tests/api/list.test.ts b/packages/js-sdk/tests/api/list.test.ts index e8e56d5bbb..3ca8371c9a 100644 --- a/packages/js-sdk/tests/api/list.test.ts +++ b/packages/js-sdk/tests/api/list.test.ts @@ -21,14 +21,16 @@ sandboxTest.skipIf(isDebug)('list sandboxes', async ({ sandbox }) => { } }) -sandboxTest.skipIf(isDebug)('list sandboxes with filter', async () => { +sandboxTest.skipIf(isDebug)('list sandboxes with metadata filter', async () => { const uniqueId = Date.now().toString() // Create an extra sandbox with a uniqueId - const extraSbx = await Sandbox.create({ }) + const extraSbx = await Sandbox.create({}) try { - const sbx = await Sandbox.create({metadata: {uniqueId: uniqueId}}) + const sbx = await Sandbox.create({ metadata: { uniqueId: uniqueId } }) try { - const sandboxes = await Sandbox.list({filters: {uniqueId}}) + const sandboxes = await Sandbox.list({ + query: { metadata: { uniqueId } }, + }) assert.equal(sandboxes.length, 1) assert.equal(sandboxes[0].sandboxId, sbx.sandboxId) } finally { @@ -38,3 +40,15 @@ sandboxTest.skipIf(isDebug)('list sandboxes with filter', async () => { await extraSbx.kill() } }) + +sandboxTest.skipIf(isDebug)( + 'list sandboxes empty filter', + async ({ sandbox }) => { + const sandboxes = await Sandbox.list() + assert.isAtLeast(sandboxes.length, 1) + assert.include( + sandboxes.map((s) => s.sandboxId), + sandbox.sandboxId + ) + } +) diff --git a/packages/js-sdk/tests/sandbox/files/write.test.ts b/packages/js-sdk/tests/sandbox/files/write.test.ts index 72d101d412..3ffe1be64b 100644 --- a/packages/js-sdk/tests/sandbox/files/write.test.ts +++ b/packages/js-sdk/tests/sandbox/files/write.test.ts @@ -1,12 +1,125 @@ -import { assert } from 'vitest' +import path from 'path' +import { assert, onTestFinished } from 'vitest' -import { sandboxTest } from '../../setup.js' +import { WriteEntry } from '../../../src/sandbox/filesystem' +import { isDebug, sandboxTest } from '../../setup.js' + +sandboxTest('write file', async ({ sandbox }) => { + const filename = 'test_write.txt' + const content = 'This is a test file.' + + // Attempt to write with undefined path and content + await sandbox.files + // @ts-ignore + .write(undefined, content) + .then((e) => { + assert.isUndefined(e) + }) + .catch((err) => { + assert.instanceOf(err, Error) + assert.include(err.message, 'Path or files are required') + }) + + const info = await sandbox.files.write(filename, content) + assert.isFalse(Array.isArray(info)) + assert.equal(info.name, filename) + assert.equal(info.type, 'file') + assert.equal(info.path, `/home/user/${filename}`) + + const exists = await sandbox.files.exists(filename) + assert.isTrue(exists) + const readContent = await sandbox.files.read(filename) + assert.equal(readContent, content) +}) + +sandboxTest('write multiple files', async ({ sandbox }) => { + // Attempt to write with empty files array + const emptyInfo = await sandbox.files.write([]) + assert.isTrue(Array.isArray(emptyInfo)) + assert.equal(emptyInfo.length, 0) + + // Attempt to write with undefined path and file array + await sandbox.files + // @ts-ignore + .write(undefined, [{ path: 'one_test_file.txt', data: 'This is a test file.' }]) + .then((e) => { + assert.isUndefined(e) + }) + .catch((err) => { + assert.instanceOf(err, Error) + assert.include(err.message, 'Path or files are required') + }) + + // Attempt to write with path and file array + await sandbox.files + // @ts-ignore + .write('/path/to/file', [{ path: 'one_test_file.txt', data: 'This is a test file.' }]) + .then((e) => { + assert.isUndefined(e) + }) + .catch((err) => { + assert.instanceOf(err, Error) + assert.include( + err.message, + 'Cannot specify both path and array of files. You have to specify either path and data for a single file or an array for multiple files.' + ) + }) + + // Attempt to write with one file in array + const info = await sandbox.files.write([{ path: 'one_test_file.txt', data: 'This is a test file.' }]) + assert.isTrue(Array.isArray(info)) + assert.equal(info[0].name, 'one_test_file.txt') + assert.equal(info[0].type, 'file') + assert.equal(info[0].path, '/home/user/one_test_file.txt') + + // Attempt to write with multiple files in array + const files: WriteEntry[] = [] + + for (let i = 0; i < 10; i++) { + let path = '' + if (i % 2 == 0) { + path = `/${i}/multi_test_file${i}.txt` + } else { + path = `/home/user/multi_test_file${i}.txt` + } + + if (isDebug) { + onTestFinished(async () => await sandbox.files.remove(path)) + } + + files.push({ + path: path, + data: `This is a test file ${i}.`, + }) + } + + const infos = await sandbox.files.write(files) + + assert.isTrue(Array.isArray(infos)) + assert.equal(infos.length, files.length) + + // Attempt to write with multiple files in array + for (let i = 0; i < files.length; i++) { + const file = files[i] + const info = infos[i] + + assert.equal(info.name, path.basename(file.path)) + assert.equal(info.path, file.path) + assert.equal(info.type, 'file') + + const exists = await sandbox.files.exists(file.path) + assert.isTrue(exists) + const readContent = await sandbox.files.read(file.path) + assert.equal(readContent, file.data) + } +}) sandboxTest('write file', async ({ sandbox }) => { const filename = 'test_write.txt' const content = 'This is a test file.' const info = await sandbox.files.write(filename, content) + assert.isFalse(Array.isArray(info)) assert.equal(info.name, filename) assert.equal(info.type, 'file') assert.equal(info.path, `/home/user/${filename}`) diff --git a/packages/js-sdk/tests/sandbox/metrics.test.ts b/packages/js-sdk/tests/sandbox/metrics.test.ts index c8643ad012..7d33b02454 100644 --- a/packages/js-sdk/tests/sandbox/metrics.test.ts +++ b/packages/js-sdk/tests/sandbox/metrics.test.ts @@ -1,23 +1,29 @@ import { assert } from 'vitest' -import Sandbox from '../../src/index.js' import { sandboxTest, wait } from '../setup.js' sandboxTest('get sandbox metrics', async ({ sandbox }) => { - console.log('Getting metrics for sandbox ID:', sandbox.sandboxId) + let testPassed = false - await wait(2_000) + const attempts = 10 + const intervalDuration = 10_000 - const metrics = await sandbox.getMetrics() - - assert.isAtLeast(metrics.length, 1) - assert.isAtLeast(metrics[0]?.cpuUsedPct, 0) - assert.isAtLeast(metrics[0]?.memTotalMiB, 0) - assert.isAtLeast(metrics[0]?.memUsedMiB, 0) - - const metrics2 = await Sandbox.getMetrics(sandbox.sandboxId) - assert.isAtLeast(metrics2.length, 1) - assert.isAtLeast(metrics2[0]?.cpuUsedPct, 0) - assert.isAtLeast(metrics2[0]?.memTotalMiB, 0) - assert.isAtLeast(metrics2[0]?.memUsedMiB, 0) + for (let i = 0; i < attempts; i++) { + const metrics = await sandbox.getMetrics() + if (metrics && metrics.length >= 1) { + assert.isAtLeast(metrics.length, 1) + assert.isAtLeast(metrics[0]?.cpuUsedPct, 0) + assert.isAtLeast(metrics[0]?.memTotalMiB, 0) + assert.isAtLeast(metrics[0]?.memUsedMiB, 0) + testPassed = true + break + } else { + await wait(intervalDuration) + continue + } + } + assert.isTrue( + testPassed, + `Metrics were not returned after ${(attempts * intervalDuration) / 1000}s` + ) }) diff --git a/packages/js-sdk/tests/sandbox/snapshot.test.ts b/packages/js-sdk/tests/sandbox/snapshot.test.ts index 03ecdfe5a9..3f7c67b202 100644 --- a/packages/js-sdk/tests/sandbox/snapshot.test.ts +++ b/packages/js-sdk/tests/sandbox/snapshot.test.ts @@ -27,29 +27,22 @@ sandboxTest.skipIf(isDebug)( envs: { TEST_VAR: 'sfisback' }, }) - try { - const cmd = await sandbox.commands.run('echo "$TEST_VAR"') + const cmd = await sandbox.commands.run('echo "$TEST_VAR"') - assert.equal(cmd.exitCode, 0) - assert.equal(cmd.stdout.trim(), 'sfisback') - } catch { - sandbox.kill() - } + assert.equal(cmd.exitCode, 0) + assert.equal(cmd.stdout.trim(), 'sfisback') await sandbox.pause() + assert.isFalse(await sandbox.isRunning()) await Sandbox.resume(sandbox.sandboxId) assert.isTrue(await sandbox.isRunning()) - try { - const cmd = await sandbox.commands.run('echo "$TEST_VAR"') + const cmd2 = await sandbox.commands.run('echo "$TEST_VAR"') - assert.equal(cmd.exitCode, 0) - assert.equal(cmd.stdout.trim(), 'sfisback') - } finally { - await sandbox.kill() - } + assert.equal(cmd2.exitCode, 0) + assert.equal(cmd2.stdout.trim(), 'sfisback') } ) @@ -103,10 +96,6 @@ sandboxTest.skipIf(isDebug)( assert.isObject(processInfo) assert.equal(processInfo.pid, expectedPid) - - onTestFinished(() => { - sandbox.commands.kill(expectedPid) - }) } ) @@ -139,10 +128,6 @@ sandboxTest.skipIf(isDebug)( assert.isTrue(exists2) const readContent2 = await sandbox.files.read(filename) assert.equal(readContent2.trim(), 'done') - - onTestFinished(() => { - sandbox.commands.kill(cmd.pid) - }) } ) @@ -169,9 +154,5 @@ sandboxTest.skipIf(isDebug)( url = await sandbox.getHost(8000) const response2 = await fetch(`https://${url}`) assert.equal(response2.status, 200) - - onTestFinished(() => { - sandbox.commands.kill(cmd.pid) - }) } ) diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py b/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py index 11b5a4cda9..b9e2cc4a85 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union +from typing import Any, Optional, Union import httpx @@ -10,8 +10,8 @@ def _get_kwargs( sandbox_id: str, -) -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { "method": "delete", "url": f"/sandboxes/{sandbox_id}", } @@ -19,16 +19,14 @@ def _get_kwargs( return _kwargs -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Any]: - if response.status_code == HTTPStatus.NO_CONTENT: +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: return None - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: return None - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: return None - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: return None if client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py index 0c2efe6121..ede6837446 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, List, Optional, Union, cast +from typing import Any, Optional, Union, cast import httpx @@ -11,15 +11,15 @@ def _get_kwargs( *, - query: Union[Unset, str] = UNSET, -) -> Dict[str, Any]: - params: Dict[str, Any] = {} + metadata: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} - params["query"] = query + params["metadata"] = metadata params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: Dict[str, Any] = { + _kwargs: dict[str, Any] = { "method": "get", "url": "/sandboxes", "params": params, @@ -30,8 +30,8 @@ def _get_kwargs( def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, List["RunningSandbox"]]]: - if response.status_code == HTTPStatus.OK: +) -> Optional[Union[Any, list["RunningSandbox"]]]: + if response.status_code == 200: response_200 = [] _response_200 = response.json() for response_200_item_data in _response_200: @@ -40,13 +40,13 @@ def _parse_response( response_200.append(response_200_item) return response_200 - if response.status_code == HTTPStatus.BAD_REQUEST: + if response.status_code == 400: response_400 = cast(Any, None) return response_400 - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: response_401 = cast(Any, None) return response_401 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: response_500 = cast(Any, None) return response_500 if client.raise_on_unexpected_status: @@ -57,7 +57,7 @@ def _parse_response( def _build_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, List["RunningSandbox"]]]: +) -> Response[Union[Any, list["RunningSandbox"]]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -69,23 +69,23 @@ def _build_response( def sync_detailed( *, client: AuthenticatedClient, - query: Union[Unset, str] = UNSET, -) -> Response[Union[Any, List["RunningSandbox"]]]: + metadata: Union[Unset, str] = UNSET, +) -> Response[Union[Any, list["RunningSandbox"]]]: """List all running sandboxes Args: - query (Union[Unset, str]): + metadata (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, List['RunningSandbox']]] + Response[Union[Any, list['RunningSandbox']]] """ kwargs = _get_kwargs( - query=query, + metadata=metadata, ) response = client.get_httpx_client().request( @@ -98,47 +98,47 @@ def sync_detailed( def sync( *, client: AuthenticatedClient, - query: Union[Unset, str] = UNSET, -) -> Optional[Union[Any, List["RunningSandbox"]]]: + metadata: Union[Unset, str] = UNSET, +) -> Optional[Union[Any, list["RunningSandbox"]]]: """List all running sandboxes Args: - query (Union[Unset, str]): + metadata (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, List['RunningSandbox']] + Union[Any, list['RunningSandbox']] """ return sync_detailed( client=client, - query=query, + metadata=metadata, ).parsed async def asyncio_detailed( *, client: AuthenticatedClient, - query: Union[Unset, str] = UNSET, -) -> Response[Union[Any, List["RunningSandbox"]]]: + metadata: Union[Unset, str] = UNSET, +) -> Response[Union[Any, list["RunningSandbox"]]]: """List all running sandboxes Args: - query (Union[Unset, str]): + metadata (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, List['RunningSandbox']]] + Response[Union[Any, list['RunningSandbox']]] """ kwargs = _get_kwargs( - query=query, + metadata=metadata, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -149,24 +149,24 @@ async def asyncio_detailed( async def asyncio( *, client: AuthenticatedClient, - query: Union[Unset, str] = UNSET, -) -> Optional[Union[Any, List["RunningSandbox"]]]: + metadata: Union[Unset, str] = UNSET, +) -> Optional[Union[Any, list["RunningSandbox"]]]: """List all running sandboxes Args: - query (Union[Unset, str]): + metadata (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, List['RunningSandbox']] + Union[Any, list['RunningSandbox']] """ return ( await asyncio_detailed( client=client, - query=query, + metadata=metadata, ) ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_metrics.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_metrics.py new file mode 100644 index 0000000000..689551f265 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_metrics.py @@ -0,0 +1,172 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.running_sandbox_with_metrics import RunningSandboxWithMetrics +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + metadata: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["metadata"] = metadata + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/sandboxes/metrics", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, list["RunningSandboxWithMetrics"]]]: + if response.status_code == 200: + response_200 = [] + _response_200 = response.json() + for response_200_item_data in _response_200: + response_200_item = RunningSandboxWithMetrics.from_dict(response_200_item_data) + + response_200.append(response_200_item) + + return response_200 + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, list["RunningSandboxWithMetrics"]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, + metadata: Union[Unset, str] = UNSET, +) -> Response[Union[Any, list["RunningSandboxWithMetrics"]]]: + """List all running sandboxes with metrics + + Args: + metadata (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['RunningSandboxWithMetrics']]] + """ + + kwargs = _get_kwargs( + metadata=metadata, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, + metadata: Union[Unset, str] = UNSET, +) -> Optional[Union[Any, list["RunningSandboxWithMetrics"]]]: + """List all running sandboxes with metrics + + Args: + metadata (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['RunningSandboxWithMetrics']] + """ + + return sync_detailed( + client=client, + metadata=metadata, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, + metadata: Union[Unset, str] = UNSET, +) -> Response[Union[Any, list["RunningSandboxWithMetrics"]]]: + """List all running sandboxes with metrics + + Args: + metadata (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, list['RunningSandboxWithMetrics']]] + """ + + kwargs = _get_kwargs( + metadata=metadata, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, + metadata: Union[Unset, str] = UNSET, +) -> Optional[Union[Any, list["RunningSandboxWithMetrics"]]]: + """List all running sandboxes with metrics + + Args: + metadata (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, list['RunningSandboxWithMetrics']] + """ + + return ( + await asyncio_detailed( + client=client, + metadata=metadata, + ) + ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py index 7ab59ee7e7..a03cae73e7 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union, cast +from typing import Any, Optional, Union, cast import httpx @@ -11,8 +11,8 @@ def _get_kwargs( sandbox_id: str, -) -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { "method": "get", "url": f"/sandboxes/{sandbox_id}", } @@ -23,17 +23,17 @@ def _get_kwargs( def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response ) -> Optional[Union[Any, RunningSandbox]]: - if response.status_code == HTTPStatus.OK: + if response.status_code == 200: response_200 = RunningSandbox.from_dict(response.json()) return response_200 - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: response_401 = cast(Any, None) return response_401 - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: response_404 = cast(Any, None) return response_404 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: response_500 = cast(Any, None) return response_500 if client.raise_on_unexpected_status: diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py index 7c70e28b73..11d6656123 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union, cast +from typing import Any, Optional, Union, cast import httpx @@ -14,8 +14,8 @@ def _get_kwargs( *, start: Union[Unset, int] = UNSET, limit: Union[Unset, int] = 1000, -) -> Dict[str, Any]: - params: Dict[str, Any] = {} +) -> dict[str, Any]: + params: dict[str, Any] = {} params["start"] = start @@ -23,7 +23,7 @@ def _get_kwargs( params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - _kwargs: Dict[str, Any] = { + _kwargs: dict[str, Any] = { "method": "get", "url": f"/sandboxes/{sandbox_id}/logs", "params": params, @@ -35,17 +35,17 @@ def _get_kwargs( def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response ) -> Optional[Union[Any, SandboxLogs]]: - if response.status_code == HTTPStatus.OK: + if response.status_code == 200: response_200 = SandboxLogs.from_dict(response.json()) return response_200 - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: response_401 = cast(Any, None) return response_401 - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: response_404 = cast(Any, None) return response_404 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: response_500 = cast(Any, None) return response_500 if client.raise_on_unexpected_status: diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py index 85851eda1c..76905092d8 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, List, Optional, Union, cast +from typing import Any, Optional, Union, cast import httpx @@ -11,8 +11,8 @@ def _get_kwargs( sandbox_id: str, -) -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { "method": "get", "url": f"/sandboxes/{sandbox_id}/metrics", } @@ -22,8 +22,8 @@ def _get_kwargs( def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, List["SandboxMetric"]]]: - if response.status_code == HTTPStatus.OK: +) -> Optional[Union[Any, list["SandboxMetric"]]]: + if response.status_code == 200: response_200 = [] _response_200 = response.json() for response_200_item_data in _response_200: @@ -32,13 +32,13 @@ def _parse_response( response_200.append(response_200_item) return response_200 - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: response_401 = cast(Any, None) return response_401 - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: response_404 = cast(Any, None) return response_404 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: response_500 = cast(Any, None) return response_500 if client.raise_on_unexpected_status: @@ -49,7 +49,7 @@ def _parse_response( def _build_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, List["SandboxMetric"]]]: +) -> Response[Union[Any, list["SandboxMetric"]]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -62,7 +62,7 @@ def sync_detailed( sandbox_id: str, *, client: AuthenticatedClient, -) -> Response[Union[Any, List["SandboxMetric"]]]: +) -> Response[Union[Any, list["SandboxMetric"]]]: """Get sandbox metrics Args: @@ -73,7 +73,7 @@ def sync_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, List['SandboxMetric']]] + Response[Union[Any, list['SandboxMetric']]] """ kwargs = _get_kwargs( @@ -91,7 +91,7 @@ def sync( sandbox_id: str, *, client: AuthenticatedClient, -) -> Optional[Union[Any, List["SandboxMetric"]]]: +) -> Optional[Union[Any, list["SandboxMetric"]]]: """Get sandbox metrics Args: @@ -102,7 +102,7 @@ def sync( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, List['SandboxMetric']] + Union[Any, list['SandboxMetric']] """ return sync_detailed( @@ -115,7 +115,7 @@ async def asyncio_detailed( sandbox_id: str, *, client: AuthenticatedClient, -) -> Response[Union[Any, List["SandboxMetric"]]]: +) -> Response[Union[Any, list["SandboxMetric"]]]: """Get sandbox metrics Args: @@ -126,7 +126,7 @@ async def asyncio_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Union[Any, List['SandboxMetric']]] + Response[Union[Any, list['SandboxMetric']]] """ kwargs = _get_kwargs( @@ -142,7 +142,7 @@ async def asyncio( sandbox_id: str, *, client: AuthenticatedClient, -) -> Optional[Union[Any, List["SandboxMetric"]]]: +) -> Optional[Union[Any, list["SandboxMetric"]]]: """Get sandbox metrics Args: @@ -153,7 +153,7 @@ async def asyncio( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Union[Any, List['SandboxMetric']] + Union[Any, list['SandboxMetric']] """ return ( diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py index 70fa540daa..0a4000b749 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union, cast +from typing import Any, Optional, Union, cast import httpx @@ -13,10 +13,10 @@ def _get_kwargs( *, body: NewSandbox, -) -> Dict[str, Any]: - headers: Dict[str, Any] = {} +) -> dict[str, Any]: + headers: dict[str, Any] = {} - _kwargs: Dict[str, Any] = { + _kwargs: dict[str, Any] = { "method": "post", "url": "/sandboxes", } @@ -33,17 +33,17 @@ def _get_kwargs( def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response ) -> Optional[Union[Any, Sandbox]]: - if response.status_code == HTTPStatus.CREATED: + if response.status_code == 201: response_201 = Sandbox.from_dict(response.json()) return response_201 - if response.status_code == HTTPStatus.BAD_REQUEST: + if response.status_code == 400: response_400 = cast(Any, None) return response_400 - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: response_401 = cast(Any, None) return response_401 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: response_500 = cast(Any, None) return response_500 if client.raise_on_unexpected_status: diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py index e47e052296..c802e4b11f 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union +from typing import Any, Optional, Union import httpx @@ -10,8 +10,8 @@ def _get_kwargs( sandbox_id: str, -) -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { "method": "post", "url": f"/sandboxes/{sandbox_id}/pause", } @@ -19,18 +19,16 @@ def _get_kwargs( return _kwargs -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Any]: - if response.status_code == HTTPStatus.NO_CONTENT: +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: return None - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: return None - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: return None - if response.status_code == HTTPStatus.CONFLICT: + if response.status_code == 409: return None - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: return None if client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py index 39dfc678a0..f843aeda77 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union +from typing import Any, Optional, Union import httpx @@ -15,10 +15,10 @@ def _get_kwargs( sandbox_id: str, *, body: PostSandboxesSandboxIDRefreshesBody, -) -> Dict[str, Any]: - headers: Dict[str, Any] = {} +) -> dict[str, Any]: + headers: dict[str, Any] = {} - _kwargs: Dict[str, Any] = { + _kwargs: dict[str, Any] = { "method": "post", "url": f"/sandboxes/{sandbox_id}/refreshes", } @@ -32,14 +32,12 @@ def _get_kwargs( return _kwargs -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Any]: - if response.status_code == HTTPStatus.NO_CONTENT: +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: return None - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: return None - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: return None if client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py index 1433aa5134..c50fc9c07d 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union, cast +from typing import Any, Optional, Union, cast import httpx @@ -14,10 +14,10 @@ def _get_kwargs( sandbox_id: str, *, body: ResumedSandbox, -) -> Dict[str, Any]: - headers: Dict[str, Any] = {} +) -> dict[str, Any]: + headers: dict[str, Any] = {} - _kwargs: Dict[str, Any] = { + _kwargs: dict[str, Any] = { "method": "post", "url": f"/sandboxes/{sandbox_id}/resume", } @@ -34,20 +34,20 @@ def _get_kwargs( def _parse_response( *, client: Union[AuthenticatedClient, Client], response: httpx.Response ) -> Optional[Union[Any, Sandbox]]: - if response.status_code == HTTPStatus.CREATED: + if response.status_code == 201: response_201 = Sandbox.from_dict(response.json()) return response_201 - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: response_401 = cast(Any, None) return response_401 - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: response_404 = cast(Any, None) return response_404 - if response.status_code == HTTPStatus.CONFLICT: + if response.status_code == 409: response_409 = cast(Any, None) return response_409 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: response_500 = cast(Any, None) return response_500 if client.raise_on_unexpected_status: diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py index 615963abf8..828e636b0e 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py @@ -1,5 +1,5 @@ from http import HTTPStatus -from typing import Any, Dict, Optional, Union +from typing import Any, Optional, Union import httpx @@ -15,10 +15,10 @@ def _get_kwargs( sandbox_id: str, *, body: PostSandboxesSandboxIDTimeoutBody, -) -> Dict[str, Any]: - headers: Dict[str, Any] = {} +) -> dict[str, Any]: + headers: dict[str, Any] = {} - _kwargs: Dict[str, Any] = { + _kwargs: dict[str, Any] = { "method": "post", "url": f"/sandboxes/{sandbox_id}/timeout", } @@ -32,16 +32,14 @@ def _get_kwargs( return _kwargs -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Any]: - if response.status_code == HTTPStatus.NO_CONTENT: +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == 204: return None - if response.status_code == HTTPStatus.UNAUTHORIZED: + if response.status_code == 401: return None - if response.status_code == HTTPStatus.NOT_FOUND: + if response.status_code == 404: return None - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + if response.status_code == 500: return None if client.raise_on_unexpected_status: raise errors.UnexpectedStatus(response.status_code, response.content) diff --git a/packages/python-sdk/e2b/api/client/client.py b/packages/python-sdk/e2b/api/client/client.py index 38b07d0575..d45ee0279d 100644 --- a/packages/python-sdk/e2b/api/client/client.py +++ b/packages/python-sdk/e2b/api/client/client.py @@ -1,5 +1,5 @@ import ssl -from typing import Any, Dict, Optional, Union +from typing import Any, Optional, Union import httpx from attrs import define, evolve, field @@ -36,22 +36,16 @@ class Client: raise_on_unexpected_status: bool = field(default=False, kw_only=True) _base_url: str = field(alias="base_url") - _cookies: Dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: Dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field( - default=None, kw_only=True, alias="timeout" - ) - _verify_ssl: Union[str, bool, ssl.SSLContext] = field( - default=True, kw_only=True, alias="verify_ssl" - ) - _follow_redirects: bool = field( - default=False, kw_only=True, alias="follow_redirects" - ) - _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") _client: Optional[httpx.Client] = field(default=None, init=False) _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - def with_headers(self, headers: Dict[str, str]) -> "Client": + def with_headers(self, headers: dict[str, str]) -> "Client": """Get a new client matching this one with additional headers""" if self._client is not None: self._client.headers.update(headers) @@ -59,7 +53,7 @@ def with_headers(self, headers: Dict[str, str]) -> "Client": self._async_client.headers.update(headers) return evolve(self, headers={**self._headers, **headers}) - def with_cookies(self, cookies: Dict[str, str]) -> "Client": + def with_cookies(self, cookies: dict[str, str]) -> "Client": """Get a new client matching this one with additional cookies""" if self._client is not None: self._client.cookies.update(cookies) @@ -76,7 +70,7 @@ def with_timeout(self, timeout: httpx.Timeout) -> "Client": return evolve(self, timeout=timeout) def set_httpx_client(self, client: httpx.Client) -> "Client": - """Manually the underlying httpx.Client + """Manually set the underlying httpx.Client **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. """ @@ -172,18 +166,12 @@ class AuthenticatedClient: raise_on_unexpected_status: bool = field(default=False, kw_only=True) _base_url: str = field(alias="base_url") - _cookies: Dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: Dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field( - default=None, kw_only=True, alias="timeout" - ) - _verify_ssl: Union[str, bool, ssl.SSLContext] = field( - default=True, kw_only=True, alias="verify_ssl" - ) - _follow_redirects: bool = field( - default=False, kw_only=True, alias="follow_redirects" - ) - _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") _client: Optional[httpx.Client] = field(default=None, init=False) _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) @@ -191,7 +179,7 @@ class AuthenticatedClient: prefix: str = "Bearer" auth_header_name: str = "Authorization" - def with_headers(self, headers: Dict[str, str]) -> "AuthenticatedClient": + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": """Get a new client matching this one with additional headers""" if self._client is not None: self._client.headers.update(headers) @@ -199,7 +187,7 @@ def with_headers(self, headers: Dict[str, str]) -> "AuthenticatedClient": self._async_client.headers.update(headers) return evolve(self, headers={**self._headers, **headers}) - def with_cookies(self, cookies: Dict[str, str]) -> "AuthenticatedClient": + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": """Get a new client matching this one with additional cookies""" if self._client is not None: self._client.cookies.update(cookies) @@ -216,7 +204,7 @@ def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": return evolve(self, timeout=timeout) def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually the underlying httpx.Client + """Manually set the underlying httpx.Client **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. """ diff --git a/packages/python-sdk/e2b/api/client/models/__init__.py b/packages/python-sdk/e2b/api/client/models/__init__.py index a5fe11187e..017a40937e 100644 --- a/packages/python-sdk/e2b/api/client/models/__init__.py +++ b/packages/python-sdk/e2b/api/client/models/__init__.py @@ -1,28 +1,41 @@ """Contains all the data models used in inputs/outputs""" +from .created_access_token import CreatedAccessToken +from .created_team_api_key import CreatedTeamAPIKey from .error import Error +from .new_access_token import NewAccessToken from .new_sandbox import NewSandbox -from .post_sandboxes_sandbox_id_refreshes_body import ( - PostSandboxesSandboxIDRefreshesBody, -) +from .new_team_api_key import NewTeamAPIKey +from .node import Node +from .node_detail import NodeDetail +from .node_status import NodeStatus +from .node_status_change import NodeStatusChange +from .post_sandboxes_sandbox_id_refreshes_body import PostSandboxesSandboxIDRefreshesBody from .post_sandboxes_sandbox_id_timeout_body import PostSandboxesSandboxIDTimeoutBody from .resumed_sandbox import ResumedSandbox from .running_sandbox import RunningSandbox +from .running_sandbox_with_metrics import RunningSandboxWithMetrics from .sandbox import Sandbox from .sandbox_log import SandboxLog from .sandbox_logs import SandboxLogs from .sandbox_metric import SandboxMetric from .team import Team +from .team_api_key import TeamAPIKey from .team_user import TeamUser from .template import Template from .template_build import TemplateBuild from .template_build_request import TemplateBuildRequest from .template_build_status import TemplateBuildStatus from .template_update_request import TemplateUpdateRequest +from .update_team_api_key import UpdateTeamAPIKey __all__ = ( + "CreatedAccessToken", + "CreatedTeamAPIKey", "Error", + "NewAccessToken", "NewSandbox", + "NewTeamAPIKey", "Node", "NodeDetail", "NodeStatus", @@ -31,15 +44,18 @@ "PostSandboxesSandboxIDTimeoutBody", "ResumedSandbox", "RunningSandbox", + "RunningSandboxWithMetrics", "Sandbox", "SandboxLog", "SandboxLogs", "SandboxMetric", "Team", + "TeamAPIKey", "TeamUser", "Template", "TemplateBuild", "TemplateBuildRequest", "TemplateBuildStatus", "TemplateUpdateRequest", + "UpdateTeamAPIKey", ) diff --git a/packages/python-sdk/e2b/api/client/models/created_access_token.py b/packages/python-sdk/e2b/api/client/models/created_access_token.py new file mode 100644 index 0000000000..31f22a3c02 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/created_access_token.py @@ -0,0 +1,93 @@ +import datetime +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +T = TypeVar("T", bound="CreatedAccessToken") + + +@_attrs_define +class CreatedAccessToken: + """ + Attributes: + created_at (datetime.datetime): Timestamp of access token creation + id (UUID): Identifier of the access token + name (str): Name of the access token + token (str): Raw value of the access token + token_mask (str): Mask of the access token + """ + + created_at: datetime.datetime + id: UUID + name: str + token: str + token_mask: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at = self.created_at.isoformat() + + id = str(self.id) + + name = self.name + + token = self.token + + token_mask = self.token_mask + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "createdAt": created_at, + "id": id, + "name": name, + "token": token, + "tokenMask": token_mask, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + created_at = isoparse(d.pop("createdAt")) + + id = UUID(d.pop("id")) + + name = d.pop("name") + + token = d.pop("token") + + token_mask = d.pop("tokenMask") + + created_access_token = cls( + created_at=created_at, + id=id, + name=name, + token=token, + token_mask=token_mask, + ) + + created_access_token.additional_properties = d + return created_access_token + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/created_team_api_key.py b/packages/python-sdk/e2b/api/client/models/created_team_api_key.py new file mode 100644 index 0000000000..3a6f2aa2b7 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/created_team_api_key.py @@ -0,0 +1,151 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +if TYPE_CHECKING: + from ..models.team_user import TeamUser + + +T = TypeVar("T", bound="CreatedTeamAPIKey") + + +@_attrs_define +class CreatedTeamAPIKey: + """ + Attributes: + created_at (datetime.datetime): Timestamp of API key creation + created_by (Union['TeamUser', None]): + id (UUID): Identifier of the API key + key (str): Raw value of the API key + key_mask (str): Mask of the API key + last_used (Union[None, datetime.datetime]): Last time this API key was used + name (str): Name of the API key + """ + + created_at: datetime.datetime + created_by: Union["TeamUser", None] + id: UUID + key: str + key_mask: str + last_used: Union[None, datetime.datetime] + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.team_user import TeamUser + + created_at = self.created_at.isoformat() + + created_by: Union[None, dict[str, Any]] + if isinstance(self.created_by, TeamUser): + created_by = self.created_by.to_dict() + else: + created_by = self.created_by + + id = str(self.id) + + key = self.key + + key_mask = self.key_mask + + last_used: Union[None, str] + if isinstance(self.last_used, datetime.datetime): + last_used = self.last_used.isoformat() + else: + last_used = self.last_used + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "createdAt": created_at, + "createdBy": created_by, + "id": id, + "key": key, + "keyMask": key_mask, + "lastUsed": last_used, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.team_user import TeamUser + + d = src_dict.copy() + created_at = isoparse(d.pop("createdAt")) + + def _parse_created_by(data: object) -> Union["TeamUser", None]: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + created_by_type_1 = TeamUser.from_dict(data) + + return created_by_type_1 + except: # noqa: E722 + pass + return cast(Union["TeamUser", None], data) + + created_by = _parse_created_by(d.pop("createdBy")) + + id = UUID(d.pop("id")) + + key = d.pop("key") + + key_mask = d.pop("keyMask") + + def _parse_last_used(data: object) -> Union[None, datetime.datetime]: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + last_used_type_0 = isoparse(data) + + return last_used_type_0 + except: # noqa: E722 + pass + return cast(Union[None, datetime.datetime], data) + + last_used = _parse_last_used(d.pop("lastUsed")) + + name = d.pop("name") + + created_team_api_key = cls( + created_at=created_at, + created_by=created_by, + id=id, + key=key, + key_mask=key_mask, + last_used=last_used, + name=name, + ) + + created_team_api_key.additional_properties = d + return created_team_api_key + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/error.py b/packages/python-sdk/e2b/api/client/models/error.py index b9680dc0c8..1dcf14741d 100644 --- a/packages/python-sdk/e2b/api/client/models/error.py +++ b/packages/python-sdk/e2b/api/client/models/error.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -16,14 +16,14 @@ class Error: code: int message: str - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: code = self.code message = self.message - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -35,7 +35,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() code = d.pop("code") @@ -50,7 +50,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return error @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/new_access_token.py b/packages/python-sdk/e2b/api/client/models/new_access_token.py new file mode 100644 index 0000000000..18cfb30b53 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/new_access_token.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="NewAccessToken") + + +@_attrs_define +class NewAccessToken: + """ + Attributes: + name (str): Name of the access token + """ + + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + name = d.pop("name") + + new_access_token = cls( + name=name, + ) + + new_access_token.additional_properties = d + return new_access_token + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/new_sandbox.py b/packages/python-sdk/e2b/api/client/models/new_sandbox.py index 10cf613103..aa79cac3f6 100644 --- a/packages/python-sdk/e2b/api/client/models/new_sandbox.py +++ b/packages/python-sdk/e2b/api/client/models/new_sandbox.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar, Union +from typing import Any, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -13,33 +13,39 @@ class NewSandbox: """ Attributes: template_id (str): Identifier of the required template + auto_pause (Union[Unset, bool]): Automatically pauses the sandbox after the timeout Default: False. env_vars (Union[Unset, Any]): metadata (Union[Unset, Any]): timeout (Union[Unset, int]): Time to live for the sandbox in seconds. Default: 15. """ template_id: str + auto_pause: Union[Unset, bool] = False env_vars: Union[Unset, Any] = UNSET metadata: Union[Unset, Any] = UNSET timeout: Union[Unset, int] = 15 - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: template_id = self.template_id + auto_pause = self.auto_pause + env_vars = self.env_vars metadata = self.metadata timeout = self.timeout - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { "templateID": template_id, } ) + if auto_pause is not UNSET: + field_dict["autoPause"] = auto_pause if env_vars is not UNSET: field_dict["envVars"] = env_vars if metadata is not UNSET: @@ -50,10 +56,12 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() template_id = d.pop("templateID") + auto_pause = d.pop("autoPause", UNSET) + env_vars = d.pop("envVars", UNSET) metadata = d.pop("metadata", UNSET) @@ -62,6 +70,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: new_sandbox = cls( template_id=template_id, + auto_pause=auto_pause, env_vars=env_vars, metadata=metadata, timeout=timeout, @@ -71,7 +80,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return new_sandbox @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/new_team_api_key.py b/packages/python-sdk/e2b/api/client/models/new_team_api_key.py new file mode 100644 index 0000000000..f6826f59c1 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/new_team_api_key.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="NewTeamAPIKey") + + +@_attrs_define +class NewTeamAPIKey: + """ + Attributes: + name (str): Name of the API key + """ + + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + name = d.pop("name") + + new_team_api_key = cls( + name=name, + ) + + new_team_api_key.additional_properties = d + return new_team_api_key + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/node.py b/packages/python-sdk/e2b/api/client/models/node.py index 8c207759f3..40b9510479 100644 --- a/packages/python-sdk/e2b/api/client/models/node.py +++ b/packages/python-sdk/e2b/api/client/models/node.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -14,37 +14,47 @@ class Node: Attributes: allocated_cpu (int): Number of allocated CPU cores allocated_memory_mi_b (int): Amount of allocated memory in MiB + create_fails (int): Number of sandbox create fails node_id (str): Identifier of the node sandbox_count (int): Number of sandboxes running on the node + sandbox_starting_count (int): Number of starting Sandboxes status (NodeStatus): Status of the node """ allocated_cpu: int allocated_memory_mi_b: int + create_fails: int node_id: str sandbox_count: int + sandbox_starting_count: int status: NodeStatus - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: allocated_cpu = self.allocated_cpu allocated_memory_mi_b = self.allocated_memory_mi_b + create_fails = self.create_fails + node_id = self.node_id sandbox_count = self.sandbox_count + sandbox_starting_count = self.sandbox_starting_count + status = self.status.value - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { "allocatedCPU": allocated_cpu, "allocatedMemoryMiB": allocated_memory_mi_b, + "createFails": create_fails, "nodeID": node_id, "sandboxCount": sandbox_count, + "sandboxStartingCount": sandbox_starting_count, "status": status, } ) @@ -52,23 +62,29 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() allocated_cpu = d.pop("allocatedCPU") allocated_memory_mi_b = d.pop("allocatedMemoryMiB") + create_fails = d.pop("createFails") + node_id = d.pop("nodeID") sandbox_count = d.pop("sandboxCount") + sandbox_starting_count = d.pop("sandboxStartingCount") + status = NodeStatus(d.pop("status")) node = cls( allocated_cpu=allocated_cpu, allocated_memory_mi_b=allocated_memory_mi_b, + create_fails=create_fails, node_id=node_id, sandbox_count=sandbox_count, + sandbox_starting_count=sandbox_starting_count, status=status, ) @@ -76,7 +92,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return node @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/node_detail.py b/packages/python-sdk/e2b/api/client/models/node_detail.py index a2326e0543..91a1c738f7 100644 --- a/packages/python-sdk/e2b/api/client/models/node_detail.py +++ b/packages/python-sdk/e2b/api/client/models/node_detail.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, cast +from typing import TYPE_CHECKING, Any, TypeVar, cast from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -16,21 +16,25 @@ class NodeDetail: """ Attributes: - cached_builds (List[str]): List of cached builds id on the node + cached_builds (list[str]): List of cached builds id on the node + create_fails (int): Number of sandbox create fails node_id (str): Identifier of the node - sandboxes (List['RunningSandbox']): List of sandboxes running on the node + sandboxes (list['RunningSandbox']): List of sandboxes running on the node status (NodeStatus): Status of the node """ - cached_builds: List[str] + cached_builds: list[str] + create_fails: int node_id: str - sandboxes: List["RunningSandbox"] + sandboxes: list["RunningSandbox"] status: NodeStatus - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: cached_builds = self.cached_builds + create_fails = self.create_fails + node_id = self.node_id sandboxes = [] @@ -40,11 +44,12 @@ def to_dict(self) -> Dict[str, Any]: status = self.status.value - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { "cachedBuilds": cached_builds, + "createFails": create_fails, "nodeID": node_id, "sandboxes": sandboxes, "status": status, @@ -54,11 +59,13 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: from ..models.running_sandbox import RunningSandbox d = src_dict.copy() - cached_builds = cast(List[str], d.pop("cachedBuilds")) + cached_builds = cast(list[str], d.pop("cachedBuilds")) + + create_fails = d.pop("createFails") node_id = d.pop("nodeID") @@ -73,6 +80,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: node_detail = cls( cached_builds=cached_builds, + create_fails=create_fails, node_id=node_id, sandboxes=sandboxes, status=status, @@ -82,7 +90,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return node_detail @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/node_status.py b/packages/python-sdk/e2b/api/client/models/node_status.py index 87a77905b9..4529e3b542 100644 --- a/packages/python-sdk/e2b/api/client/models/node_status.py +++ b/packages/python-sdk/e2b/api/client/models/node_status.py @@ -2,8 +2,10 @@ class NodeStatus(str, Enum): + CONNECTING = "connecting" DRAINING = "draining" READY = "ready" + UNHEALTHY = "unhealthy" def __str__(self) -> str: return str(self.value) diff --git a/packages/python-sdk/e2b/api/client/models/node_status_change.py b/packages/python-sdk/e2b/api/client/models/node_status_change.py index 43628b8093..c22453be21 100644 --- a/packages/python-sdk/e2b/api/client/models/node_status_change.py +++ b/packages/python-sdk/e2b/api/client/models/node_status_change.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -16,12 +16,12 @@ class NodeStatusChange: """ status: NodeStatus - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: status = self.status.value - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -32,7 +32,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() status = NodeStatus(d.pop("status")) @@ -44,7 +44,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return node_status_change @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py b/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py index 39536231ae..5cb0807cf9 100644 --- a/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +++ b/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar, Union +from typing import Any, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -16,12 +16,12 @@ class PostSandboxesSandboxIDRefreshesBody: """ duration: Union[Unset, int] = UNSET - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: duration = self.duration - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) if duration is not UNSET: @@ -30,7 +30,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() duration = d.pop("duration", UNSET) @@ -42,7 +42,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return post_sandboxes_sandbox_id_refreshes_body @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_timeout_body.py b/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_timeout_body.py index 5d0b876076..77907033b4 100644 --- a/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +++ b/packages/python-sdk/e2b/api/client/models/post_sandboxes_sandbox_id_timeout_body.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -14,12 +14,12 @@ class PostSandboxesSandboxIDTimeoutBody: """ timeout: int - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: timeout = self.timeout - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -30,7 +30,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() timeout = d.pop("timeout") @@ -42,7 +42,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return post_sandboxes_sandbox_id_timeout_body @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/resumed_sandbox.py b/packages/python-sdk/e2b/api/client/models/resumed_sandbox.py index ae872a6d12..c8481750b8 100644 --- a/packages/python-sdk/e2b/api/client/models/resumed_sandbox.py +++ b/packages/python-sdk/e2b/api/client/models/resumed_sandbox.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar, Union +from typing import Any, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -12,29 +12,38 @@ class ResumedSandbox: """ Attributes: + auto_pause (Union[Unset, bool]): Automatically pauses the sandbox after the timeout Default: False. timeout (Union[Unset, int]): Time to live for the sandbox in seconds. Default: 15. """ + auto_pause: Union[Unset, bool] = False timeout: Union[Unset, int] = 15 - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + auto_pause = self.auto_pause - def to_dict(self) -> Dict[str, Any]: timeout = self.timeout - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) + if auto_pause is not UNSET: + field_dict["autoPause"] = auto_pause if timeout is not UNSET: field_dict["timeout"] = timeout return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() + auto_pause = d.pop("autoPause", UNSET) + timeout = d.pop("timeout", UNSET) resumed_sandbox = cls( + auto_pause=auto_pause, timeout=timeout, ) @@ -42,7 +51,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return resumed_sandbox @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/running_sandbox.py b/packages/python-sdk/e2b/api/client/models/running_sandbox.py index c329511b5e..f4b2d772d1 100644 --- a/packages/python-sdk/e2b/api/client/models/running_sandbox.py +++ b/packages/python-sdk/e2b/api/client/models/running_sandbox.py @@ -1,5 +1,5 @@ import datetime -from typing import Any, Dict, List, Type, TypeVar, Union +from typing import Any, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -34,9 +34,9 @@ class RunningSandbox: template_id: str alias: Union[Unset, str] = UNSET metadata: Union[Unset, Any] = UNSET - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: client_id = self.client_id cpu_count = self.cpu_count @@ -55,7 +55,7 @@ def to_dict(self) -> Dict[str, Any]: metadata = self.metadata - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -76,7 +76,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() client_id = d.pop("clientID") @@ -112,7 +112,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return running_sandbox @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/running_sandbox_with_metrics.py b/packages/python-sdk/e2b/api/client/models/running_sandbox_with_metrics.py new file mode 100644 index 0000000000..95925acac5 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/running_sandbox_with_metrics.py @@ -0,0 +1,153 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.sandbox_metric import SandboxMetric + + +T = TypeVar("T", bound="RunningSandboxWithMetrics") + + +@_attrs_define +class RunningSandboxWithMetrics: + """ + Attributes: + client_id (str): Identifier of the client + cpu_count (int): CPU cores for the sandbox + end_at (datetime.datetime): Time when the sandbox will expire + memory_mb (int): Memory for the sandbox in MB + sandbox_id (str): Identifier of the sandbox + started_at (datetime.datetime): Time when the sandbox was started + template_id (str): Identifier of the template from which is the sandbox created + alias (Union[Unset, str]): Alias of the template + metadata (Union[Unset, Any]): + metrics (Union[Unset, list['SandboxMetric']]): + """ + + client_id: str + cpu_count: int + end_at: datetime.datetime + memory_mb: int + sandbox_id: str + started_at: datetime.datetime + template_id: str + alias: Union[Unset, str] = UNSET + metadata: Union[Unset, Any] = UNSET + metrics: Union[Unset, list["SandboxMetric"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + client_id = self.client_id + + cpu_count = self.cpu_count + + end_at = self.end_at.isoformat() + + memory_mb = self.memory_mb + + sandbox_id = self.sandbox_id + + started_at = self.started_at.isoformat() + + template_id = self.template_id + + alias = self.alias + + metadata = self.metadata + + metrics: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.metrics, Unset): + metrics = [] + for metrics_item_data in self.metrics: + metrics_item = metrics_item_data.to_dict() + metrics.append(metrics_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "clientID": client_id, + "cpuCount": cpu_count, + "endAt": end_at, + "memoryMB": memory_mb, + "sandboxID": sandbox_id, + "startedAt": started_at, + "templateID": template_id, + } + ) + if alias is not UNSET: + field_dict["alias"] = alias + if metadata is not UNSET: + field_dict["metadata"] = metadata + if metrics is not UNSET: + field_dict["metrics"] = metrics + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.sandbox_metric import SandboxMetric + + d = src_dict.copy() + client_id = d.pop("clientID") + + cpu_count = d.pop("cpuCount") + + end_at = isoparse(d.pop("endAt")) + + memory_mb = d.pop("memoryMB") + + sandbox_id = d.pop("sandboxID") + + started_at = isoparse(d.pop("startedAt")) + + template_id = d.pop("templateID") + + alias = d.pop("alias", UNSET) + + metadata = d.pop("metadata", UNSET) + + metrics = [] + _metrics = d.pop("metrics", UNSET) + for metrics_item_data in _metrics or []: + metrics_item = SandboxMetric.from_dict(metrics_item_data) + + metrics.append(metrics_item) + + running_sandbox_with_metrics = cls( + client_id=client_id, + cpu_count=cpu_count, + end_at=end_at, + memory_mb=memory_mb, + sandbox_id=sandbox_id, + started_at=started_at, + template_id=template_id, + alias=alias, + metadata=metadata, + metrics=metrics, + ) + + running_sandbox_with_metrics.additional_properties = d + return running_sandbox_with_metrics + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/sandbox.py b/packages/python-sdk/e2b/api/client/models/sandbox.py index baf5b4890e..3514d71b1e 100644 --- a/packages/python-sdk/e2b/api/client/models/sandbox.py +++ b/packages/python-sdk/e2b/api/client/models/sandbox.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar, Union +from typing import Any, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -24,9 +24,9 @@ class Sandbox: sandbox_id: str template_id: str alias: Union[Unset, str] = UNSET - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: client_id = self.client_id envd_version = self.envd_version @@ -37,7 +37,7 @@ def to_dict(self) -> Dict[str, Any]: alias = self.alias - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -53,7 +53,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() client_id = d.pop("clientID") @@ -77,7 +77,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return sandbox @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/sandbox_log.py b/packages/python-sdk/e2b/api/client/models/sandbox_log.py index 44c990e9a8..ea192436dd 100644 --- a/packages/python-sdk/e2b/api/client/models/sandbox_log.py +++ b/packages/python-sdk/e2b/api/client/models/sandbox_log.py @@ -1,5 +1,5 @@ import datetime -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -19,14 +19,14 @@ class SandboxLog: line: str timestamp: datetime.datetime - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: line = self.line timestamp = self.timestamp.isoformat() - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -38,7 +38,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() line = d.pop("line") @@ -53,7 +53,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return sandbox_log @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/sandbox_logs.py b/packages/python-sdk/e2b/api/client/models/sandbox_logs.py index 0594fdcc8a..0766a371b2 100644 --- a/packages/python-sdk/e2b/api/client/models/sandbox_logs.py +++ b/packages/python-sdk/e2b/api/client/models/sandbox_logs.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -14,19 +14,19 @@ class SandboxLogs: """ Attributes: - logs (List['SandboxLog']): Logs of the sandbox + logs (list['SandboxLog']): Logs of the sandbox """ - logs: List["SandboxLog"] - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + logs: list["SandboxLog"] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: logs = [] for logs_item_data in self.logs: logs_item = logs_item_data.to_dict() logs.append(logs_item) - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -37,7 +37,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: from ..models.sandbox_log import SandboxLog d = src_dict.copy() @@ -56,7 +56,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return sandbox_logs @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/sandbox_metric.py b/packages/python-sdk/e2b/api/client/models/sandbox_metric.py index 2f636976f3..54cea611c0 100644 --- a/packages/python-sdk/e2b/api/client/models/sandbox_metric.py +++ b/packages/python-sdk/e2b/api/client/models/sandbox_metric.py @@ -1,5 +1,5 @@ import datetime -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -25,9 +25,9 @@ class SandboxMetric: mem_total_mi_b: int mem_used_mi_b: int timestamp: datetime.datetime - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: cpu_count = self.cpu_count cpu_used_pct = self.cpu_used_pct @@ -38,7 +38,7 @@ def to_dict(self) -> Dict[str, Any]: timestamp = self.timestamp.isoformat() - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -53,7 +53,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() cpu_count = d.pop("cpuCount") @@ -77,7 +77,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return sandbox_metric @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/team.py b/packages/python-sdk/e2b/api/client/models/team.py index c957f9384e..f17cedd147 100644 --- a/packages/python-sdk/e2b/api/client/models/team.py +++ b/packages/python-sdk/e2b/api/client/models/team.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -20,9 +20,9 @@ class Team: is_default: bool name: str team_id: str - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: api_key = self.api_key is_default = self.is_default @@ -31,7 +31,7 @@ def to_dict(self) -> Dict[str, Any]: team_id = self.team_id - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -45,7 +45,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() api_key = d.pop("apiKey") @@ -66,7 +66,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return team @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/team_api_key.py b/packages/python-sdk/e2b/api/client/models/team_api_key.py new file mode 100644 index 0000000000..9726b62524 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/team_api_key.py @@ -0,0 +1,143 @@ +import datetime +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +if TYPE_CHECKING: + from ..models.team_user import TeamUser + + +T = TypeVar("T", bound="TeamAPIKey") + + +@_attrs_define +class TeamAPIKey: + """ + Attributes: + created_at (datetime.datetime): Timestamp of API key creation + created_by (Union['TeamUser', None]): + id (UUID): Identifier of the API key + key_mask (str): Mask of the API key + last_used (Union[None, datetime.datetime]): Last time this API key was used + name (str): Name of the API key + """ + + created_at: datetime.datetime + created_by: Union["TeamUser", None] + id: UUID + key_mask: str + last_used: Union[None, datetime.datetime] + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.team_user import TeamUser + + created_at = self.created_at.isoformat() + + created_by: Union[None, dict[str, Any]] + if isinstance(self.created_by, TeamUser): + created_by = self.created_by.to_dict() + else: + created_by = self.created_by + + id = str(self.id) + + key_mask = self.key_mask + + last_used: Union[None, str] + if isinstance(self.last_used, datetime.datetime): + last_used = self.last_used.isoformat() + else: + last_used = self.last_used + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "createdAt": created_at, + "createdBy": created_by, + "id": id, + "keyMask": key_mask, + "lastUsed": last_used, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + from ..models.team_user import TeamUser + + d = src_dict.copy() + created_at = isoparse(d.pop("createdAt")) + + def _parse_created_by(data: object) -> Union["TeamUser", None]: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + created_by_type_1 = TeamUser.from_dict(data) + + return created_by_type_1 + except: # noqa: E722 + pass + return cast(Union["TeamUser", None], data) + + created_by = _parse_created_by(d.pop("createdBy")) + + id = UUID(d.pop("id")) + + key_mask = d.pop("keyMask") + + def _parse_last_used(data: object) -> Union[None, datetime.datetime]: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + last_used_type_0 = isoparse(data) + + return last_used_type_0 + except: # noqa: E722 + pass + return cast(Union[None, datetime.datetime], data) + + last_used = _parse_last_used(d.pop("lastUsed")) + + name = d.pop("name") + + team_api_key = cls( + created_at=created_at, + created_by=created_by, + id=id, + key_mask=key_mask, + last_used=last_used, + name=name, + ) + + team_api_key.additional_properties = d + return team_api_key + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/team_user.py b/packages/python-sdk/e2b/api/client/models/team_user.py index 9aa62dfb59..b52b82ab46 100644 --- a/packages/python-sdk/e2b/api/client/models/team_user.py +++ b/packages/python-sdk/e2b/api/client/models/team_user.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, List, Type, TypeVar +from typing import Any, TypeVar +from uuid import UUID from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -11,19 +12,19 @@ class TeamUser: """ Attributes: email (str): Email of the user - id (str): Identifier of the user + id (UUID): Identifier of the user """ email: str - id: str - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: email = self.email - id = self.id + id = str(self.id) - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -35,11 +36,11 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() email = d.pop("email") - id = d.pop("id") + id = UUID(d.pop("id")) team_user = cls( email=email, @@ -50,7 +51,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return team_user @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/template.py b/packages/python-sdk/e2b/api/client/models/template.py index 7e76153e97..4c65a62def 100644 --- a/packages/python-sdk/e2b/api/client/models/template.py +++ b/packages/python-sdk/e2b/api/client/models/template.py @@ -1,5 +1,5 @@ import datetime -from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union, cast +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -29,7 +29,7 @@ class Template: spawn_count (int): Number of times the template was used template_id (str): Identifier of the template updated_at (datetime.datetime): Time when the template was last updated - aliases (Union[Unset, List[str]]): Aliases of the template + aliases (Union[Unset, list[str]]): Aliases of the template """ build_count: int @@ -43,10 +43,10 @@ class Template: spawn_count: int template_id: str updated_at: datetime.datetime - aliases: Union[Unset, List[str]] = UNSET - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + aliases: Union[Unset, list[str]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: from ..models.team_user import TeamUser build_count = self.build_count @@ -57,7 +57,7 @@ def to_dict(self) -> Dict[str, Any]: created_at = self.created_at.isoformat() - created_by: Union[Dict[str, Any], None] + created_by: Union[None, dict[str, Any]] if isinstance(self.created_by, TeamUser): created_by = self.created_by.to_dict() else: @@ -75,11 +75,11 @@ def to_dict(self) -> Dict[str, Any]: updated_at = self.updated_at.isoformat() - aliases: Union[Unset, List[str]] = UNSET + aliases: Union[Unset, list[str]] = UNSET if not isinstance(self.aliases, Unset): aliases = self.aliases - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -102,7 +102,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: from ..models.team_user import TeamUser d = src_dict.copy() @@ -141,7 +141,7 @@ def _parse_created_by(data: object) -> Union["TeamUser", None]: updated_at = isoparse(d.pop("updatedAt")) - aliases = cast(List[str], d.pop("aliases", UNSET)) + aliases = cast(list[str], d.pop("aliases", UNSET)) template = cls( build_count=build_count, @@ -162,7 +162,7 @@ def _parse_created_by(data: object) -> Union["TeamUser", None]: return template @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/template_build.py b/packages/python-sdk/e2b/api/client/models/template_build.py index ed05e1114d..34bb32aae5 100644 --- a/packages/python-sdk/e2b/api/client/models/template_build.py +++ b/packages/python-sdk/e2b/api/client/models/template_build.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar, cast +from typing import Any, TypeVar, cast from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -13,18 +13,18 @@ class TemplateBuild: """ Attributes: build_id (str): Identifier of the build - logs (List[str]): Build logs + logs (list[str]): Build logs status (TemplateBuildStatus): Status of the template template_id (str): Identifier of the template """ build_id: str - logs: List[str] + logs: list[str] status: TemplateBuildStatus template_id: str - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: build_id = self.build_id logs = self.logs @@ -33,7 +33,7 @@ def to_dict(self) -> Dict[str, Any]: template_id = self.template_id - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -47,11 +47,11 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() build_id = d.pop("buildID") - logs = cast(List[str], d.pop("logs")) + logs = cast(list[str], d.pop("logs")) status = TemplateBuildStatus(d.pop("status")) @@ -68,7 +68,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return template_build @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/template_build_request.py b/packages/python-sdk/e2b/api/client/models/template_build_request.py index 08ac58490f..18f1fb8f32 100644 --- a/packages/python-sdk/e2b/api/client/models/template_build_request.py +++ b/packages/python-sdk/e2b/api/client/models/template_build_request.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar, Union +from typing import Any, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -26,9 +26,9 @@ class TemplateBuildRequest: memory_mb: Union[Unset, int] = UNSET start_cmd: Union[Unset, str] = UNSET team_id: Union[Unset, str] = UNSET - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: dockerfile = self.dockerfile alias = self.alias @@ -41,7 +41,7 @@ def to_dict(self) -> Dict[str, Any]: team_id = self.team_id - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { @@ -62,7 +62,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() dockerfile = d.pop("dockerfile") @@ -89,7 +89,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return template_build_request @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/template_build_status.py b/packages/python-sdk/e2b/api/client/models/template_build_status.py index 9ecd819410..6cae835d59 100644 --- a/packages/python-sdk/e2b/api/client/models/template_build_status.py +++ b/packages/python-sdk/e2b/api/client/models/template_build_status.py @@ -5,6 +5,7 @@ class TemplateBuildStatus(str, Enum): BUILDING = "building" ERROR = "error" READY = "ready" + WAITING = "waiting" def __str__(self) -> str: return str(self.value) diff --git a/packages/python-sdk/e2b/api/client/models/template_update_request.py b/packages/python-sdk/e2b/api/client/models/template_update_request.py index 66e235c417..17df72644b 100644 --- a/packages/python-sdk/e2b/api/client/models/template_update_request.py +++ b/packages/python-sdk/e2b/api/client/models/template_update_request.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, TypeVar, Union +from typing import Any, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -16,12 +16,12 @@ class TemplateUpdateRequest: """ public: Union[Unset, bool] = UNSET - additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: public = self.public - field_dict: Dict[str, Any] = {} + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) if public is not UNSET: @@ -30,7 +30,7 @@ def to_dict(self) -> Dict[str, Any]: return field_dict @classmethod - def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: d = src_dict.copy() public = d.pop("public", UNSET) @@ -42,7 +42,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: return template_update_request @property - def additional_keys(self) -> List[str]: + def additional_keys(self) -> list[str]: return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/packages/python-sdk/e2b/api/client/models/update_team_api_key.py b/packages/python-sdk/e2b/api/client/models/update_team_api_key.py new file mode 100644 index 0000000000..03bae6c5a6 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/update_team_api_key.py @@ -0,0 +1,58 @@ +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UpdateTeamAPIKey") + + +@_attrs_define +class UpdateTeamAPIKey: + """ + Attributes: + name (str): New name for the API key + """ + + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T: + d = src_dict.copy() + name = d.pop("name") + + update_team_api_key = cls( + name=name, + ) + + update_team_api_key.additional_properties = d + return update_team_api_key + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/types.py b/packages/python-sdk/e2b/api/client/types.py index 21fac106f3..b9ed58b8aa 100644 --- a/packages/python-sdk/e2b/api/client/types.py +++ b/packages/python-sdk/e2b/api/client/types.py @@ -1,7 +1,8 @@ """Contains some shared types for properties""" +from collections.abc import MutableMapping from http import HTTPStatus -from typing import BinaryIO, Generic, Literal, MutableMapping, Optional, Tuple, TypeVar +from typing import BinaryIO, Generic, Literal, Optional, TypeVar from attrs import define @@ -13,7 +14,7 @@ def __bool__(self) -> Literal[False]: UNSET: Unset = Unset() -FileJsonType = Tuple[Optional[str], BinaryIO, Optional[str]] +FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]] @define @@ -42,4 +43,4 @@ class Response(Generic[T]): parsed: Optional[T] -__all__ = ["File", "Response", "FileJsonType", "Unset", "UNSET"] +__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"] diff --git a/packages/python-sdk/e2b/exceptions.py b/packages/python-sdk/e2b/exceptions.py index d0214936b5..d519972b49 100644 --- a/packages/python-sdk/e2b/exceptions.py +++ b/packages/python-sdk/e2b/exceptions.py @@ -30,10 +30,10 @@ class TimeoutException(SandboxException): """ Raised when a timeout occurs. - The [unavailable] exception type is caused by sandbox timeout.\n - The [canceled] exception type is caused by exceeding request timeout.\n - The [deadline_exceeded] exception type is caused by exceeding the timeout for process, watch, etc.\n - The [unknown] exception type is sometimes caused by the sandbox timeout when the request is not processed correctly.\n + The `unavailable` exception type is caused by sandbox timeout.\n + The `canceled` exception type is caused by exceeding request timeout.\n + The `deadline_exceeded` exception type is caused by exceeding the timeout for process, watch, etc.\n + The `unknown` exception type is sometimes caused by the sandbox timeout when the request is not processed correctly.\n """ pass diff --git a/packages/python-sdk/e2b/sandbox/filesystem/filesystem.py b/packages/python-sdk/e2b/sandbox/filesystem/filesystem.py index 9e04a39759..2f67170140 100644 --- a/packages/python-sdk/e2b/sandbox/filesystem/filesystem.py +++ b/packages/python-sdk/e2b/sandbox/filesystem/filesystem.py @@ -1,6 +1,6 @@ -from enum import Enum from dataclasses import dataclass -from typing import Optional +from enum import Enum +from typing import IO, Optional, Union from e2b.envd.filesystem import filesystem_pb2 @@ -45,3 +45,13 @@ class EntryInfo: """ Path to the filesystem object. """ + + +dataclass +class WriteEntry: + """ + Contains path and data of the file to be written to the filesystem. + """ + + path: str + data: Union[str, bytes, IO] diff --git a/packages/python-sdk/e2b/sandbox/sandbox_api.py b/packages/python-sdk/e2b/sandbox/sandbox_api.py index 5030e174cc..f7d603487f 100644 --- a/packages/python-sdk/e2b/sandbox/sandbox_api.py +++ b/packages/python-sdk/e2b/sandbox/sandbox_api.py @@ -38,6 +38,14 @@ class SandboxMetrics: """Total memory available""" +@dataclass +class SandboxQuery: + """Query parameters for listing sandboxes.""" + + metadata: Optional[dict[str, str]] = None + """Filter sandboxes by metadata.""" + + class SandboxApiBase(ABC): _limits = Limits( max_keepalive_connections=10, diff --git a/packages/python-sdk/e2b/sandbox_async/filesystem/filesystem.py b/packages/python-sdk/e2b/sandbox_async/filesystem/filesystem.py index f2d4f60766..998c1e9459 100644 --- a/packages/python-sdk/e2b/sandbox_async/filesystem/filesystem.py +++ b/packages/python-sdk/e2b/sandbox_async/filesystem/filesystem.py @@ -2,7 +2,8 @@ import httpx from io import TextIOBase from packaging.version import Version -from typing import IO, AsyncIterator, List, Literal, Optional, Union, overload +from typing import AsyncIterator, IO, List, Literal, Optional, overload, Union +from e2b.sandbox.filesystem.filesystem import WriteEntry import e2b_connect as connect from e2b.connection_config import ( @@ -133,6 +134,7 @@ async def read( elif format == "stream": return r.aiter_bytes() + @overload async def write( self, path: str, @@ -156,13 +158,69 @@ async def write( :return: Information about the written file """ - if isinstance(data, TextIOBase): - data = data.read().encode() + + @overload + async def write( + self, + files: List[WriteEntry], + user: Optional[Username] = "user", + request_timeout: Optional[float] = None, + ) -> List[EntryInfo]: + """ + Writes multiple files. + + :param files: list of files to write + :param user: Run the operation as this user + :param request_timeout: Timeout for the request + :return: Information about the written files + """ + + async def write( + self, + path_or_files: Union[str, List[WriteEntry]], + data_or_user: Union[str, bytes, IO, Username] = "user", + user_or_request_timeout: Optional[Union[float, Username]] = None, + request_timeout_or_none: Optional[float] = None + ) -> Union[EntryInfo, List[EntryInfo]]: + """ + Writes content to a file on the path. + When writing to a file that doesn't exist, the file will get created. + When writing to a file that already exists, the file will get overwritten. + When writing to a file that's in a directory that doesn't exist, you'll get an error. + """ + path, write_files, user, request_timeout = None, [], "user", None + if isinstance(path_or_files, str): + if isinstance(data_or_user, list): + raise Exception("Cannot specify both path and array of files. You have to specify either path and data for a single file or an array for multiple files.") + path, write_files, user, request_timeout = \ + path_or_files, [{"path": path_or_files, "data": data_or_user}], user_or_request_timeout or "user", request_timeout_or_none + else: + if path_or_files is None: + raise Exception("Path or files are required") + path, write_files, user, request_timeout = \ + None, path_or_files, data_or_user, user_or_request_timeout + + # Prepare the files for the multipart/form-data request + httpx_files = [] + for file in write_files: + file_path, file_data = file['path'], file['data'] + if isinstance(file_data, str) or isinstance(file_data, bytes): + httpx_files.append(('file', (file_path, file_data))) + elif isinstance(file_data, TextIOBase): + httpx_files.append(('file', (file_path, file_data.read()))) + else: + raise ValueError(f"Unsupported data type for file {file_path}") + + # Allow passing empty list of files + if len(httpx_files) == 0: return [] + + params = {"username": user} + if path is not None: params["path"] = path r = await self._envd_api.post( ENVD_API_FILES_ROUTE, - files={"file": data}, - params={"path": path, "username": user}, + files=httpx_files, + params=params, timeout=self._connection_config.get_request_timeout(request_timeout), ) @@ -170,13 +228,17 @@ async def write( if err: raise err - files = r.json() + write_files = r.json() - if not isinstance(files, list) or len(files) == 0: + if not isinstance(write_files, list) or len(write_files) == 0: raise Exception("Expected to receive information about written file") - file = files[0] - return EntryInfo(**file) + if len(write_files) == 1 and path: + file = write_files[0] + return EntryInfo(**file) + else: + return [EntryInfo(**file) for file in write_files] + async def list( self, diff --git a/packages/python-sdk/e2b/sandbox_async/sandbox_api.py b/packages/python-sdk/e2b/sandbox_async/sandbox_api.py index ee212f7db1..fe6a1b749e 100644 --- a/packages/python-sdk/e2b/sandbox_async/sandbox_api.py +++ b/packages/python-sdk/e2b/sandbox_async/sandbox_api.py @@ -1,7 +1,11 @@ import urllib.parse -from typing import Dict, List, Optional +from typing import Optional, Dict, List +from packaging.version import Version -from e2b.api import AsyncApiClient, SandboxCreateResponse, handle_api_exception +from e2b.sandbox.sandbox_api import SandboxInfo, SandboxApiBase, SandboxQuery +from e2b.exceptions import TemplateException +from e2b.api import AsyncApiClient, SandboxCreateResponse +from e2b.api.client.models import NewSandbox, PostSandboxesSandboxIDTimeoutBody from e2b.api.client.api.sandboxes import ( delete_sandboxes_sandbox_id, get_sandboxes, @@ -20,6 +24,7 @@ from e2b.exceptions import TemplateException, NotFoundException from e2b.sandbox.sandbox_api import SandboxApiBase, SandboxInfo, SandboxMetrics from packaging.version import Version +from e2b.api import handle_api_exception class SandboxApi(SandboxApiBase): @@ -27,7 +32,7 @@ class SandboxApi(SandboxApiBase): async def list( cls, api_key: Optional[str] = None, - filters: Optional[Dict[str, str]] = None, + query: Optional[SandboxQuery] = None, domain: Optional[str] = None, debug: Optional[bool] = None, request_timeout: Optional[float] = None, @@ -36,7 +41,7 @@ async def list( List all running sandboxes. :param api_key: API key to use for authentication, defaults to `E2B_API_KEY` environment variable - :param filters: Filter the list of sandboxes by metadata, e.g. `{"key": "value"}`, if there are multiple filters they are combined with AND. + :param query: Filter the list of sandboxes, e.g. by metadata `SandboxQuery(metadata={"key": "value"})`, if there are multiple filters they are combined with AND. :param domain: Domain to use for the request, only relevant for self-hosted environments :param debug: Enable debug mode, all requested are then sent to localhost :param request_timeout: Timeout for the request in **seconds** @@ -50,17 +55,20 @@ async def list( request_timeout=request_timeout, ) - query = None - if filters: - filters = { - urllib.parse.quote(k): urllib.parse.quote(v) for k, v in filters.items() - } - query = urllib.parse.urlencode(filters) + # Convert filters to the format expected by the API + metadata = None + if query: + if query.metadata: + quoted_metadata = { + urllib.parse.quote(k): urllib.parse.quote(v) + for k, v in query.metadata.items() + } + metadata = urllib.parse.urlencode(quoted_metadata) async with AsyncApiClient(config) as api_client: res = await get_sandboxes.asyncio_detailed( client=api_client, - query=query, + metadata=metadata, ) if res.status_code >= 300: diff --git a/packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py b/packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py index 7f979ec168..463353c7ab 100644 --- a/packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py +++ b/packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py @@ -1,5 +1,6 @@ from io import TextIOBase -from typing import IO, Iterator, List, Literal, Optional, Union, overload +from typing import IO, Iterator, List, Literal, Optional, overload, Union +from e2b.sandbox.filesystem.filesystem import WriteEntry import e2b_connect import httpcore @@ -132,6 +133,7 @@ def read( elif format == "stream": return r.iter_bytes() + @overload def write( self, path: str, @@ -155,13 +157,66 @@ def write( :return: Information about the written file """ - if isinstance(data, TextIOBase): - data = data.read().encode() + + @overload + def write( + self, + files: List[WriteEntry], + user: Optional[Username] = "user", + request_timeout: Optional[float] = None, + ) -> List[EntryInfo]: + """ + Writes a list of files to the filesystem. + When writing to a file that doesn't exist, the file will get created. + When writing to a file that already exists, the file will get overwritten. + When writing to a file that's in a directory that doesn't exist, you'll get an error. + + :param files: list of files to write + :param user: Run the operation as this user + :param request_timeout: Timeout for the request + :return: Information about the written files + """ + + def write( + self, + path_or_files: Union[str, List[WriteEntry]], + data_or_user: Union[str, bytes, IO, Username] = "user", + user_or_request_timeout: Optional[Union[float, Username]] = None, + request_timeout_or_none: Optional[float] = None + ) -> Union[EntryInfo, List[EntryInfo]]: + path, write_files, user, request_timeout = None, [], "user", None + if isinstance(path_or_files, str): + if isinstance(data_or_user, list): + raise Exception("Cannot specify both path and array of files. You have to specify either path and data for a single file or an array for multiple files.") + path, write_files, user, request_timeout = \ + path_or_files, [{"path": path_or_files, "data": data_or_user}], user_or_request_timeout or "user", request_timeout_or_none + else: + if path_or_files is None: + raise Exception("Path or files are required") + path, write_files, user, request_timeout = \ + None, path_or_files, data_or_user, user_or_request_timeout + + # Prepare the files for the multipart/form-data request + httpx_files = [] + for file in write_files: + file_path, file_data = file['path'], file['data'] + if isinstance(file_data, str) or isinstance(file_data, bytes): + httpx_files.append(('file', (file_path, file_data))) + elif isinstance(file_data, TextIOBase): + httpx_files.append(('file', (file_path, file_data.read()))) + else: + raise ValueError(f"Unsupported data type for file {file_path}") + + # Allow passing empty list of files + if len(httpx_files) == 0: return [] + + params = {"username": user} + if path is not None: params["path"] = path r = self._envd_api.post( ENVD_API_FILES_ROUTE, - files={"file": data}, - params={"path": path, "username": user}, + files=httpx_files, + params=params, timeout=self._connection_config.get_request_timeout(request_timeout), ) @@ -169,13 +224,16 @@ def write( if err: raise err - files = r.json() + write_files = r.json() - if not isinstance(files, list) or len(files) == 0: + if not isinstance(write_files, list) or len(write_files) == 0: raise Exception("Expected to receive information about written file") - file = files[0] - return EntryInfo(**file) + if len(write_files) == 1 and path: + file = write_files[0] + return EntryInfo(**file) + else: + return [EntryInfo(**file) for file in write_files] def list( self, diff --git a/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py b/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py index bc49b4efe5..4e0cde6cba 100644 --- a/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py +++ b/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py @@ -1,7 +1,13 @@ import urllib.parse -from typing import Dict, List, Optional -from e2b.api import ApiClient, SandboxCreateResponse, handle_api_exception +from httpx import HTTPTransport +from typing import Optional, Dict, List, Tuple +from packaging.version import Version + +from e2b.sandbox.sandbox_api import SandboxInfo, SandboxApiBase, SandboxQuery +from e2b.exceptions import TemplateException +from e2b.api import ApiClient, SandboxCreateResponse +from e2b.api.client.models import NewSandbox, PostSandboxesSandboxIDTimeoutBody from e2b.api.client.api.sandboxes import ( delete_sandboxes_sandbox_id, get_sandboxes, @@ -28,7 +34,7 @@ class SandboxApi(SandboxApiBase): def list( cls, api_key: Optional[str] = None, - filters: Optional[Dict[str, str]] = None, + query: Optional[SandboxQuery] = None, domain: Optional[str] = None, debug: Optional[bool] = None, request_timeout: Optional[float] = None, @@ -37,7 +43,7 @@ def list( List all running sandboxes. :param api_key: API key to use for authentication, defaults to `E2B_API_KEY` environment variable - :param filters: Filter the list of sandboxes by metadata, e.g. `{"key": "value"}`, if there are multiple filters they are combined with AND. + :param query: Filter the list of sandboxes, e.g. by metadata `SandboxQuery(metadata={"key": "value"})`, if there are multiple filters they are combined with AND. :param domain: Domain to use for the request, only relevant for self-hosted environments :param debug: Enable debug mode, all requested are then sent to localhost :param request_timeout: Timeout for the request in **seconds** @@ -52,17 +58,19 @@ def list( ) # Convert filters to the format expected by the API - query = None - if filters: - filters = { - urllib.parse.quote(k): urllib.parse.quote(v) for k, v in filters.items() - } - query = urllib.parse.urlencode(filters) + metadata = None + if query: + if query.metadata: + quoted_metadata = { + urllib.parse.quote(k): urllib.parse.quote(v) + for k, v in query.metadata.items() + } + metadata = urllib.parse.urlencode(quoted_metadata) with ApiClient( config, transport=HTTPTransport(limits=SandboxApiBase._limits) ) as api_client: - res = get_sandboxes.sync_detailed(client=api_client, query=query) + res = get_sandboxes.sync_detailed(client=api_client, metadata=metadata) if res.status_code >= 300: raise handle_api_exception(res) diff --git a/packages/python-sdk/tests/async/api_async/test_sbx_list.py b/packages/python-sdk/tests/async/api_async/test_sbx_list.py index 4e58e736bc..9274e3068b 100644 --- a/packages/python-sdk/tests/async/api_async/test_sbx_list.py +++ b/packages/python-sdk/tests/async/api_async/test_sbx_list.py @@ -4,6 +4,7 @@ import pytest from e2b import AsyncSandbox +from e2b.sandbox.sandbox_api import SandboxQuery @pytest.mark.skip_debug() @@ -19,8 +20,17 @@ async def test_list_sandboxes_with_filter(async_sandbox: AsyncSandbox): sbx = await AsyncSandbox.create(metadata={"unique_id": unique_id}) try: # There's an extra sandbox created by the test runner - sandboxes = await AsyncSandbox.list(filters={"unique_id": unique_id}) + sandboxes = await AsyncSandbox.list( + query=SandboxQuery(metadata={"unique_id": unique_id}) + ) assert len(sandboxes) == 1 assert sandboxes[0].metadata["unique_id"] == unique_id finally: await sbx.kill() + + +@pytest.mark.skip_debug() +async def test_list_sandboxes_with_empty_filter(async_sandbox: AsyncSandbox): + sandboxes = await AsyncSandbox.list(query=SandboxQuery()) + assert len(sandboxes) > 0 + assert async_sandbox.sandbox_id in [sbx.sandbox_id for sbx in sandboxes] diff --git a/packages/python-sdk/tests/async/sandbox_async/files/test_write.py b/packages/python-sdk/tests/async/sandbox_async/files/test_write.py index bdfbf514a7..b897f36732 100644 --- a/packages/python-sdk/tests/async/sandbox_async/files/test_write.py +++ b/packages/python-sdk/tests/async/sandbox_async/files/test_write.py @@ -1,10 +1,16 @@ from e2b import AsyncSandbox - +from e2b.sandbox_async.filesystem.filesystem import EntryInfo async def test_write_file(async_sandbox: AsyncSandbox): filename = "test_write.txt" content = "This is a test file." + # Attempt to write without path + try: + await async_sandbox.files.write(None, content) + except Exception as e: + assert "Path or files are required" in str(e) + info = await async_sandbox.files.write(filename, content) assert info.path == f"/home/user/{filename}" @@ -14,6 +20,55 @@ async def test_write_file(async_sandbox: AsyncSandbox): read_content = await async_sandbox.files.read(filename) assert read_content == content +async def test_write_multiple_files(async_sandbox: AsyncSandbox): + # Attempt to write with empty files array + empty_info = await async_sandbox.files.write([]) + assert isinstance(empty_info, list) + assert len(empty_info) == 0 + + # Attempt to write with None path and empty files array + try: + await async_sandbox.files.write(None, []) + except Exception as e: + assert "Path or files are required" in str(e) + + # Attempt to write with path and file array + try: + await async_sandbox.files.write("/path/to/file", [{ "path": "one_test_file.txt", "data": "This is a test file." }]) + except Exception as e: + assert "Cannot specify both path and array of files. You have to specify either path and data for a single file or an array for multiple files." in str(e) + + # Attempt to write with one file in array + info = await async_sandbox.files.write([{ "path": "one_test_file.txt", "data": "This is a test file." }]) + assert isinstance(info, list) + assert len(info) == 1 + info = info[0] + assert isinstance(info, EntryInfo) + assert info.path == "/home/user/one_test_file.txt" + exists = await async_sandbox.files.exists(info.path) + assert exists + + read_content = await async_sandbox.files.read(info.path) + assert read_content == "This is a test file." + + # Attempt to write with multiple files in array + files = [] + for i in range(10): + path = f"test_write_{i}.txt" + content = f"This is a test file {i}." + files.append({"path": path, "data": content}) + + infos = await async_sandbox.files.write(files) + assert isinstance(infos, list) + assert len(infos) == len(files) + for i, info in enumerate(infos): + assert isinstance(info, EntryInfo) + assert info.path == f"/home/user/test_write_{i}.txt" + exists = await async_sandbox.files.exists(path) + assert exists + + read_content = await async_sandbox.files.read(info.path) + assert read_content == files[i]["data"] async def test_overwrite_file(async_sandbox: AsyncSandbox): filename = "test_overwrite.txt" diff --git a/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py b/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py index cc2541a5fb..0b78a1ee55 100644 --- a/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py +++ b/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py @@ -4,6 +4,7 @@ import pytest from e2b import Sandbox +from e2b.sandbox.sandbox_api import SandboxQuery @pytest.mark.skip_debug() @@ -17,6 +18,13 @@ def test_list_sandboxes(sandbox: Sandbox): def test_list_sandboxes_with_filter(sandbox: Sandbox): unique_id = "".join(random.choices(string.ascii_letters, k=5)) Sandbox(metadata={"unique_id": unique_id}) - sandboxes = Sandbox.list(filters={"unique_id": unique_id}) + sandboxes = Sandbox.list(query=SandboxQuery(metadata={"unique_id": unique_id})) assert len(sandboxes) == 1 assert sandboxes[0].metadata["unique_id"] == unique_id + + +@pytest.mark.skip_debug() +def test_list_sandboxes_with_empty_filter(sandbox: Sandbox): + sandboxes = Sandbox.list(query=SandboxQuery()) + assert len(sandboxes) > 0 + assert sandbox.sandbox_id in [sbx.sandbox_id for sbx in sandboxes] diff --git a/packages/python-sdk/tests/sync/sandbox_sync/files/test_watch.py b/packages/python-sdk/tests/sync/sandbox_sync/files/test_watch.py index 859fc4ec12..ac5052af80 100644 --- a/packages/python-sdk/tests/sync/sandbox_sync/files/test_watch.py +++ b/packages/python-sdk/tests/sync/sandbox_sync/files/test_watch.py @@ -10,18 +10,15 @@ def test_watch_directory_changes(sandbox: Sandbox): sandbox.files.remove(dirname) sandbox.files.make_dir(dirname) + sandbox.files.write(f"{dirname}/{filename}", content) + handle = sandbox.files.watch_dir(dirname) sandbox.files.write(f"{dirname}/{filename}", content) events = handle.get_new_events() - assert len(events) == 3 - assert events[0].type == FilesystemEventType.CREATE + assert events[0].type == FilesystemEventType.WRITE assert events[0].name == filename - assert events[1].type == FilesystemEventType.CHMOD - assert events[1].name == filename - assert events[2].type == FilesystemEventType.WRITE - assert events[2].name == filename handle.stop() diff --git a/packages/python-sdk/tests/sync/sandbox_sync/files/test_write.py b/packages/python-sdk/tests/sync/sandbox_sync/files/test_write.py index ba0390ee1d..5a3638765c 100644 --- a/packages/python-sdk/tests/sync/sandbox_sync/files/test_write.py +++ b/packages/python-sdk/tests/sync/sandbox_sync/files/test_write.py @@ -1,7 +1,15 @@ +from e2b.sandbox.filesystem.filesystem import EntryInfo + def test_write_file(sandbox): filename = "test_write.txt" content = "This is a test file." + # Attempt to write without path + try: + sandbox.files.write(None, content) + except Exception as e: + assert "Path or files are required" in str(e) + info = sandbox.files.write(filename, content) assert info.path == f"/home/user/{filename}" @@ -11,6 +19,55 @@ def test_write_file(sandbox): read_content = sandbox.files.read(filename) assert read_content == content +def test_write_multiple_files(sandbox): + # Attempt to write with empty files array + empty_info = sandbox.files.write([]) + assert isinstance(empty_info, list) + assert len(empty_info) == 0 + + # Attempt to write with None path and empty files array + try: + sandbox.files.write(None, []) + except Exception as e: + assert "Path or files are required" in str(e) + + # Attempt to write with path and file array + try: + sandbox.files.write("/path/to/file", [{ "path": "one_test_file.txt", "data": "This is a test file." }]) + except Exception as e: + assert "Cannot specify both path and array of files. You have to specify either path and data for a single file or an array for multiple files." in str(e) + + # Attempt to write with one file in array + info = sandbox.files.write([{ "path": "one_test_file.txt", "data": "This is a test file." }]) + assert isinstance(info, list) + assert len(info) == 1 + info = info[0] + assert isinstance(info, EntryInfo) + assert info.path == "/home/user/one_test_file.txt" + exists = sandbox.files.exists(info.path) + assert exists + + read_content = sandbox.files.read(info.path) + assert read_content == "This is a test file." + + # Attempt to write with multiple files in array + files = [] + for i in range(10): + path = f"test_write_{i}.txt" + content = f"This is a test file {i}." + files.append({"path": path, "data": content}) + + infos = sandbox.files.write(files) + assert isinstance(infos, list) + assert len(infos) == len(files) + for i, info in enumerate(infos): + assert isinstance(info, EntryInfo) + assert info.path == f"/home/user/test_write_{i}.txt" + exists = sandbox.files.exists(path) + assert exists + + read_content = sandbox.files.read(info.path) + assert read_content == files[i]["data"] def test_overwrite_file(sandbox): filename = "test_overwrite.txt" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 643761efb2..9fd6ca6980 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -125,7 +125,7 @@ importers: version: 1.2.1 e2b: specifier: ^1.0.7 - version: 1.0.7 + version: 1.1.1 fast-glob: specifier: ^3.3.0 version: 3.3.1 @@ -276,7 +276,7 @@ importers: version: 2.11.2 e2b: specifier: ^1.0.7 - version: 1.0.7 + version: 1.1.1 inquirer: specifier: ^9.2.12 version: 9.2.12 @@ -3812,8 +3812,8 @@ packages: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} - e2b@1.0.7: - resolution: {integrity: sha512-7msagBbQ8tm51qaGp+hdaaaMjGG3zCzZtUS8bnz+LK7wdwtVTA1PmX+1Br9E3R7v6XIchnNWRpei+VjvGcfidA==} + e2b@1.1.1: + resolution: {integrity: sha512-XDFWJIyLbU4TkHswJg/gAeBib55+6R8ewa/U+LM3Q28K6uJ3LCyNl7G0fqJuaA0kvT5uMmqOw2LmmFhFV2ttrw==} engines: {node: '>=18'} eastasianwidth@0.2.0: @@ -11287,7 +11287,7 @@ snapshots: dotenv@16.4.5: {} - e2b@1.0.7: + e2b@1.1.1: dependencies: '@bufbuild/protobuf': 2.2.2 '@connectrpc/connect': 2.0.0-rc.3(@bufbuild/protobuf@2.2.2) diff --git a/spec/openapi.yml b/spec/openapi.yml index ca440f3637..f01c467790 100644 --- a/spec/openapi.yml +++ b/spec/openapi.yml @@ -16,6 +16,17 @@ components: type: http scheme: bearer bearerFormat: access_token + # Generated code uses security schemas in the alphabetical order. + # In order to check first the token, and then the team (so we can already use the user), + # there is a 1 and 2 present in the names of the security schemas. + Supabase1TokenAuth: + type: apiKey + in: header + name: X-Supabase-Token + Supabase2TeamAuth: + type: apiKey + in: header + name: X-Supabase-Team AdminTokenAuth: type: apiKey in: header @@ -46,6 +57,18 @@ components: required: true schema: type: string + apiKeyID: + name: apiKeyID + in: path + required: true + schema: + type: string + accessTokenID: + name: accessTokenID + in: path + required: true + schema: + type: string responses: "400": @@ -257,6 +280,47 @@ components: metadata: $ref: "#/components/schemas/SandboxMetadata" + RunningSandboxWithMetrics: + required: + - templateID + - sandboxID + - clientID + - startedAt + - cpuCount + - memoryMB + - endAt + properties: + templateID: + type: string + description: Identifier of the template from which is the sandbox created + alias: + type: string + description: Alias of the template + sandboxID: + type: string + description: Identifier of the sandbox + clientID: + type: string + description: Identifier of the client + startedAt: + type: string + format: date-time + description: Time when the sandbox was started + endAt: + type: string + format: date-time + description: Time when the sandbox will expire + cpuCount: + $ref: "#/components/schemas/CPUCount" + memoryMB: + $ref: "#/components/schemas/MemoryMB" + metadata: + $ref: "#/components/schemas/SandboxMetadata" + metrics: + type: array + items: + $ref: "#/components/schemas/SandboxMetric" + NewSandbox: required: - templateID @@ -270,6 +334,10 @@ components: minimum: 0 default: 15 description: Time to live for the sandbox in seconds. + autoPause: + type: boolean + default: false + description: Automatically pauses the sandbox after the timeout metadata: $ref: "#/components/schemas/SandboxMetadata" envVars: @@ -283,6 +351,10 @@ components: minimum: 0 default: 15 description: Time to live for the sandbox in seconds. + autoPause: + type: boolean + default: false + description: Automatically pauses the sandbox after the timeout Template: required: @@ -386,6 +458,7 @@ components: description: Status of the template enum: - building + - waiting - ready - error @@ -395,6 +468,8 @@ components: enum: - ready - draining + - connecting + - unhealthy NodeStatusChange: required: @@ -410,6 +485,8 @@ components: - sandboxCount - allocatedCPU - allocatedMemoryMiB + - createFails + - sandboxStartingCount properties: nodeID: type: string @@ -428,6 +505,14 @@ components: type: integer format: int32 description: Amount of allocated memory in MiB + createFails: + type: integer + format: uint64 + description: Number of sandbox create fails + sandboxStartingCount: + type: integer + format: int + description: Number of starting Sandboxes NodeDetail: required: @@ -435,6 +520,7 @@ components: - status - sandboxes - cachedBuilds + - createFails properties: nodeID: type: string @@ -451,7 +537,130 @@ components: description: List of cached builds id on the node items: type: string + createFails: + type: integer + format: uint64 + description: Number of sandbox create fails + + CreatedAccessToken: + required: + - id + - name + - token + - tokenMask + - createdAt + properties: + id: + type: string + format: uuid + description: Identifier of the access token + name: + type: string + description: Name of the access token + token: + type: string + description: Raw value of the access token + tokenMask: + type: string + description: Mask of the access token + createdAt: + type: string + format: date-time + description: Timestamp of access token creation + + NewAccessToken: + required: + - name + properties: + name: + type: string + description: Name of the access token + + TeamAPIKey: + required: + - id + - name + - keyMask + - createdAt + - createdBy + - lastUsed + properties: + id: + type: string + format: uuid + description: Identifier of the API key + name: + type: string + description: Name of the API key + keyMask: + type: string + description: Mask of the API key + createdAt: + type: string + format: date-time + description: Timestamp of API key creation + createdBy: + allOf: + - $ref: "#/components/schemas/TeamUser" + nullable: true + lastUsed: + type: string + format: date-time + description: Last time this API key was used + nullable: true + + CreatedTeamAPIKey: + required: + - id + - name + - key + - keyMask + - createdAt + - createdBy + - lastUsed + properties: + id: + type: string + format: uuid + description: Identifier of the API key + name: + type: string + description: Name of the API key + key: + type: string + description: Raw value of the API key + keyMask: + type: string + description: Mask of the API key + createdAt: + type: string + format: date-time + description: Timestamp of API key creation + createdBy: + allOf: + - $ref: "#/components/schemas/TeamUser" + nullable: true + lastUsed: + type: string + format: date-time + description: Last time this API key was used + nullable: true + + NewTeamAPIKey: + required: + - name + properties: + name: + type: string + description: Name of the API key + UpdateTeamAPIKey: + required: + - name + properties: + name: + type: string + description: New name for the API key Error: required: @@ -470,6 +679,8 @@ tags: - name: templates - name: sandboxes - name: auth + - name: access-tokens + - name: api-keys paths: /health: @@ -487,6 +698,7 @@ paths: tags: [auth] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] responses: "200": description: Successfully returned all teams @@ -508,10 +720,12 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] parameters: - - name: query + - name: metadata in: query - description: A query used to filter the sandboxes (e.g. "user=abc&app=prod"). Query and each key and values must be URL encoded. + description: Metadata query used to filter the sandboxes (e.g. "user=abc&app=prod"). Each key and values must be URL encoded. required: false schema: type: string @@ -536,6 +750,8 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] requestBody: required: true content: @@ -556,12 +772,44 @@ paths: "500": $ref: "#/components/responses/500" + /sandboxes/metrics: + get: + description: List all running sandboxes with metrics + tags: [sandboxes] + security: + - ApiKeyAuth: [] + parameters: + - name: metadata + in: query + description: Metadata query used to filter the sandboxes (e.g. "user=abc&app=prod"). Each key and values must be URL encoded. + required: false + schema: + type: string + responses: + "200": + description: Successfully returned all running sandboxes with metrics + content: + application/json: + schema: + type: array + items: + allOf: + - $ref: "#/components/schemas/RunningSandboxWithMetrics" + "401": + $ref: "#/components/responses/401" + "400": + $ref: "#/components/responses/400" + "500": + $ref: "#/components/responses/500" + /sandboxes/{sandboxID}/logs: get: description: Get sandbox logs tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] parameters: - $ref: "#/components/parameters/sandboxID" - in: query @@ -599,6 +847,8 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] parameters: - $ref: "#/components/parameters/sandboxID" responses: @@ -624,6 +874,8 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] parameters: - $ref: "#/components/parameters/sandboxID" responses: @@ -645,6 +897,8 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] parameters: - $ref: "#/components/parameters/sandboxID" responses: @@ -664,6 +918,8 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] parameters: - $ref: "#/components/parameters/sandboxID" responses: @@ -684,6 +940,8 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] parameters: - $ref: "#/components/parameters/sandboxID" requestBody: @@ -713,6 +971,8 @@ paths: description: Set the timeout for the sandbox. The sandbox will expire x seconds from the time of the request. Calling this method multiple times overwrites the TTL, each time using the current timestamp as the starting point to measure the timeout duration. security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] tags: [sandboxes] requestBody: content: @@ -744,6 +1004,8 @@ paths: description: Refresh the sandbox extending its time to live security: - ApiKeyAuth: [] + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] tags: [sandboxes] requestBody: content: @@ -772,6 +1034,7 @@ paths: tags: [templates] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] parameters: - in: query required: false @@ -798,6 +1061,7 @@ paths: tags: [templates] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] requestBody: required: true content: @@ -823,6 +1087,7 @@ paths: tags: [templates] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] parameters: - $ref: "#/components/parameters/templateID" requestBody: @@ -848,6 +1113,7 @@ paths: tags: [templates] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] parameters: - $ref: "#/components/parameters/templateID" responses: @@ -862,6 +1128,7 @@ paths: tags: [templates] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] parameters: - $ref: "#/components/parameters/templateID" requestBody: @@ -886,6 +1153,7 @@ paths: tags: [templates] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] parameters: - $ref: "#/components/parameters/templateID" - $ref: "#/components/parameters/buildID" @@ -903,6 +1171,7 @@ paths: tags: [templates] security: - AccessTokenAuth: [] + - Supabase1TokenAuth: [] parameters: - $ref: "#/components/parameters/templateID" - $ref: "#/components/parameters/buildID" @@ -989,5 +1258,133 @@ paths: $ref: "#/components/responses/401" "404": $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /access-tokens: + post: + description: Create a new access token + tags: [access-tokens] + security: + - Supabase1TokenAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/NewAccessToken" + responses: + "201": + description: Access token created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/CreatedAccessToken" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + /access-tokens/{accessTokenID}: + delete: + description: Delete an access token + tags: [access-tokens] + security: + - Supabase1TokenAuth: [] + parameters: + - $ref: "#/components/parameters/accessTokenID" + responses: + "204": + description: Access token deleted successfully + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + + /api-keys: + get: + description: List all team API keys + tags: [api-keys] + security: + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] + responses: + "200": + description: Successfully returned all team API keys + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TeamAPIKey" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + post: + description: Create a new team API key + tags: [api-keys] + security: + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/NewTeamAPIKey" + responses: + "201": + description: Team API key created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/CreatedTeamAPIKey" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + /api-keys/{apiKeyID}: + patch: + description: Update a team API key + tags: [api-keys] + security: + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] + parameters: + - $ref: "#/components/parameters/apiKeyID" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateTeamAPIKey" + responses: + "200": + description: Team API key updated successfully + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + delete: + description: Delete a team API key + tags: [api-keys] + security: + - Supabase1TokenAuth: [] + Supabase2TeamAuth: [] + parameters: + - $ref: "#/components/parameters/apiKeyID" + responses: + "204": + description: Team API key deleted successfully + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" "500": $ref: "#/components/responses/500" \ No newline at end of file