From aa54eb227e29a0fce5792ab35cd08b8310851a10 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Mon, 13 Apr 2026 22:02:55 +0300 Subject: [PATCH] Replace Mintlify starter kit with Pocketenv docs Add complete Pocketenv documentation: new README/index/quickstart, SDK pages, guides, and many API reference MDX files. Update api-reference/openapi.json and wire it into docs.json. Change theme, colors, navigation, favicon/logo, and add SDK examples. Remove starter AI-tool samples and starter favicon.svg. --- README.md | 105 +- ai-tools/claude-code.mdx | 43 - ai-tools/cursor.mdx | 39 - ai-tools/windsurf.mdx | 39 - api-reference/actor/get-actor-sandboxes.mdx | 4 + api-reference/actor/get-profile.mdx | 4 + api-reference/actor/get-terminal-token.mdx | 4 + api-reference/endpoint/create.mdx | 4 - api-reference/endpoint/delete.mdx | 4 - api-reference/endpoint/get.mdx | 4 - api-reference/endpoint/webhook.mdx | 4 - api-reference/file/add.mdx | 4 + api-reference/file/delete.mdx | 4 + api-reference/file/get.mdx | 4 + api-reference/file/list.mdx | 4 + api-reference/file/update.mdx | 4 + api-reference/introduction.mdx | 63 +- api-reference/openapi.json | 6258 ++++++++++++++++- api-reference/sandbox/claim.mdx | 4 + api-reference/sandbox/create-backup.mdx | 4 + api-reference/sandbox/create-integration.mdx | 4 + api-reference/sandbox/create.mdx | 4 + api-reference/sandbox/delete.mdx | 4 + api-reference/sandbox/exec.mdx | 4 + api-reference/sandbox/expose-port.mdx | 4 + api-reference/sandbox/expose-vscode.mdx | 4 + api-reference/sandbox/get-exposed-ports.mdx | 4 + api-reference/sandbox/get-preferences.mdx | 4 + api-reference/sandbox/get-ssh-keys.mdx | 4 + .../sandbox/get-tailscale-auth-key.mdx | 4 + api-reference/sandbox/get-tailscale-token.mdx | 4 + api-reference/sandbox/get.mdx | 4 + api-reference/sandbox/list-backups.mdx | 4 + api-reference/sandbox/list-integrations.mdx | 4 + api-reference/sandbox/list.mdx | 4 + api-reference/sandbox/pull-directory.mdx | 4 + api-reference/sandbox/push-directory.mdx | 4 + api-reference/sandbox/put-preferences.mdx | 4 + api-reference/sandbox/put-ssh-keys.mdx | 4 + .../sandbox/put-tailscale-auth-key.mdx | 4 + api-reference/sandbox/put-tailscale-token.mdx | 4 + api-reference/sandbox/restore-backup.mdx | 4 + api-reference/sandbox/start.mdx | 4 + api-reference/sandbox/stop.mdx | 4 + api-reference/sandbox/unexpose-port.mdx | 4 + api-reference/sandbox/update-settings.mdx | 4 + api-reference/secret/add.mdx | 4 + api-reference/secret/delete.mdx | 4 + api-reference/secret/get.mdx | 4 + api-reference/secret/list.mdx | 4 + api-reference/secret/update.mdx | 4 + api-reference/service/add.mdx | 4 + api-reference/service/delete.mdx | 4 + api-reference/service/list.mdx | 4 + api-reference/service/restart.mdx | 4 + api-reference/service/start.mdx | 4 + api-reference/service/stop.mdx | 4 + api-reference/service/update.mdx | 4 + api-reference/variable/add.mdx | 4 + api-reference/variable/delete.mdx | 4 + api-reference/variable/get.mdx | 4 + api-reference/variable/list.mdx | 4 + api-reference/variable/update.mdx | 4 + api-reference/volume/add.mdx | 4 + api-reference/volume/delete.mdx | 4 + api-reference/volume/get.mdx | 4 + api-reference/volume/list.mdx | 4 + api-reference/volume/update.mdx | 4 + development.mdx | 132 +- docs.json | 239 +- favicon.png | Bin 0 -> 2919 bytes favicon.svg | 5 - guides/backups.mdx | 97 + guides/exec-and-console.mdx | 105 + guides/ports-and-networking.mdx | 109 + guides/providers.mdx | 173 + guides/secrets-and-env.mdx | 95 + guides/services.mdx | 105 + index.mdx | 134 +- logo/logo.png | Bin 0 -> 2919 bytes quickstart.mdx | 162 +- sdks/clojure.mdx | 127 + sdks/elixir.mdx | 151 + sdks/gleam.mdx | 156 + sdks/javascript.mdx | 190 + 85 files changed, 8164 insertions(+), 611 deletions(-) delete mode 100644 ai-tools/claude-code.mdx delete mode 100644 ai-tools/cursor.mdx delete mode 100644 ai-tools/windsurf.mdx create mode 100644 api-reference/actor/get-actor-sandboxes.mdx create mode 100644 api-reference/actor/get-profile.mdx create mode 100644 api-reference/actor/get-terminal-token.mdx delete mode 100644 api-reference/endpoint/create.mdx delete mode 100644 api-reference/endpoint/delete.mdx delete mode 100644 api-reference/endpoint/get.mdx delete mode 100644 api-reference/endpoint/webhook.mdx create mode 100644 api-reference/file/add.mdx create mode 100644 api-reference/file/delete.mdx create mode 100644 api-reference/file/get.mdx create mode 100644 api-reference/file/list.mdx create mode 100644 api-reference/file/update.mdx create mode 100644 api-reference/sandbox/claim.mdx create mode 100644 api-reference/sandbox/create-backup.mdx create mode 100644 api-reference/sandbox/create-integration.mdx create mode 100644 api-reference/sandbox/create.mdx create mode 100644 api-reference/sandbox/delete.mdx create mode 100644 api-reference/sandbox/exec.mdx create mode 100644 api-reference/sandbox/expose-port.mdx create mode 100644 api-reference/sandbox/expose-vscode.mdx create mode 100644 api-reference/sandbox/get-exposed-ports.mdx create mode 100644 api-reference/sandbox/get-preferences.mdx create mode 100644 api-reference/sandbox/get-ssh-keys.mdx create mode 100644 api-reference/sandbox/get-tailscale-auth-key.mdx create mode 100644 api-reference/sandbox/get-tailscale-token.mdx create mode 100644 api-reference/sandbox/get.mdx create mode 100644 api-reference/sandbox/list-backups.mdx create mode 100644 api-reference/sandbox/list-integrations.mdx create mode 100644 api-reference/sandbox/list.mdx create mode 100644 api-reference/sandbox/pull-directory.mdx create mode 100644 api-reference/sandbox/push-directory.mdx create mode 100644 api-reference/sandbox/put-preferences.mdx create mode 100644 api-reference/sandbox/put-ssh-keys.mdx create mode 100644 api-reference/sandbox/put-tailscale-auth-key.mdx create mode 100644 api-reference/sandbox/put-tailscale-token.mdx create mode 100644 api-reference/sandbox/restore-backup.mdx create mode 100644 api-reference/sandbox/start.mdx create mode 100644 api-reference/sandbox/stop.mdx create mode 100644 api-reference/sandbox/unexpose-port.mdx create mode 100644 api-reference/sandbox/update-settings.mdx create mode 100644 api-reference/secret/add.mdx create mode 100644 api-reference/secret/delete.mdx create mode 100644 api-reference/secret/get.mdx create mode 100644 api-reference/secret/list.mdx create mode 100644 api-reference/secret/update.mdx create mode 100644 api-reference/service/add.mdx create mode 100644 api-reference/service/delete.mdx create mode 100644 api-reference/service/list.mdx create mode 100644 api-reference/service/restart.mdx create mode 100644 api-reference/service/start.mdx create mode 100644 api-reference/service/stop.mdx create mode 100644 api-reference/service/update.mdx create mode 100644 api-reference/variable/add.mdx create mode 100644 api-reference/variable/delete.mdx create mode 100644 api-reference/variable/get.mdx create mode 100644 api-reference/variable/list.mdx create mode 100644 api-reference/variable/update.mdx create mode 100644 api-reference/volume/add.mdx create mode 100644 api-reference/volume/delete.mdx create mode 100644 api-reference/volume/get.mdx create mode 100644 api-reference/volume/list.mdx create mode 100644 api-reference/volume/update.mdx create mode 100644 favicon.png delete mode 100644 favicon.svg create mode 100644 guides/backups.mdx create mode 100644 guides/exec-and-console.mdx create mode 100644 guides/ports-and-networking.mdx create mode 100644 guides/providers.mdx create mode 100644 guides/secrets-and-env.mdx create mode 100644 guides/services.mdx create mode 100644 logo/logo.png create mode 100644 sdks/clojure.mdx create mode 100644 sdks/elixir.mdx create mode 100644 sdks/gleam.mdx create mode 100644 sdks/javascript.mdx diff --git a/README.md b/README.md index 4552fbc..33f2562 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,92 @@ -# Mintlify Starter Kit +# Pocketenv Docs -Use the starter kit to get your docs deployed and ready to customize. +Official documentation for [Pocketenv](https://pocketenv.io) — open-source, multi-provider sandbox platform. -Click the green **Use this template** button at the top of this repo to copy the Mintlify starter kit. The starter kit contains examples with +Built with [Mintlify](https://mintlify.com) and published at **[docs.pocketenv.io](https://docs.pocketenv.io)**. -- Guide pages -- Navigation -- Customizations -- API reference pages -- Use of popular components +## What's inside -**[Follow the full quickstart guide](https://starter.mintlify.com/quickstart)** - -## AI-assisted writing - -Set up your AI coding tool to work with Mintlify: - -```bash -npx skills add https://mintlify.com/docs +``` +. +├── index.mdx # Landing page +├── quickstart.mdx # Install CLI & create first sandbox +├── development.mdx # SDK overview +├── guides/ +│ ├── providers.mdx # Supported backend providers +│ ├── exec-and-console.mdx # Running commands & interactive shell +│ ├── secrets-and-env.mdx # Secrets & environment variables +│ ├── ports-and-networking.mdx +│ ├── services.mdx +│ └── backups.mdx +├── sdks/ +│ ├── javascript.mdx # @pocketenv/sdk (JS/TS) +│ ├── gleam.mdx +│ ├── clojure.mdx +│ └── elixir.mdx +└── api-reference/ + ├── introduction.mdx + ├── openapi.json # XRPC OpenAPI spec + ├── actor/ + ├── sandbox/ + ├── file/ + ├── secret/ + ├── variable/ + ├── service/ + └── volume/ ``` -This command installs Mintlify's documentation skill for your configured AI tools like Claude Code, Cursor, Windsurf, and others. The skill includes component reference, writing standards, and workflow guidance. - -See the [AI tools guides](/ai-tools) for tool-specific setup. - -## Development +## Local development -Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview your documentation changes locally. To install, use the following command: +Install the Mintlify CLI: -``` +```sh npm i -g mint ``` -Run the following command at the root of your documentation, where your `docs.json` is located: +Run the local preview server from the root of this repo (where `docs.json` is): -``` +```sh mint dev ``` -View your local preview at `http://localhost:3000`. +Open [http://localhost:3000](http://localhost:3000). + +## Contributing -## Publishing changes +1. Fork & clone the repo +2. Run `mint dev` to preview changes locally +3. Edit or add `.mdx` files — pages map 1:1 to files +4. Update `docs.json` if you add or move pages +5. Open a pull request -Install our GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app) to propagate changes from your repo to your deployment. Changes are deployed to production automatically after pushing to the default branch. +### Adding a page -## Need help? +Create an `.mdx` file and add its path to the relevant `group` in `docs.json`: + +```json +{ + "group": "Guides", + "pages": ["guides/your-new-page"] +} +``` -### Troubleshooting +### API reference pages + +API pages are generated from `api-reference/openapi.json`. Each page is a single MDX file with an `openapi` frontmatter field: + +```mdx +--- +title: 'Create Sandbox' +openapi: 'POST /io.pocketenv.sandbox.createSandbox' +--- +``` -- If your dev environment isn't running: Run `mint update` to ensure you have the most recent version of the CLI. -- If a page loads as a 404: Make sure you are running in a folder with a valid `docs.json`. +## Related repos -### Resources -- [Mintlify documentation](https://mintlify.com/docs) +| Repo | Description | +|---|---| +| [pocketenv-io/pocketenv](https://github.com/pocketenv-io/pocketenv) | Core platform & CLI | +| [pocketenv-io/pocketenv-js](https://github.com/pocketenv-io/pocketenv-js) | JavaScript / TypeScript SDK | +| [pocketenv-io/pocketenv-gleam](https://github.com/pocketenv-io/pocketenv-gleam) | Gleam SDK | +| [pocketenv-io/pocketenv-clojure](https://github.com/pocketenv-io/pocketenv-clojure) | Clojure SDK | +| [pocketenv-io/pocketenv-elixir](https://github.com/pocketenv-io/pocketenv-elixir) | Elixir SDK | diff --git a/ai-tools/claude-code.mdx b/ai-tools/claude-code.mdx deleted file mode 100644 index a59ca25..0000000 --- a/ai-tools/claude-code.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Claude Code setup" -description: "Configure Claude Code for your documentation workflow" -icon: "asterisk" ---- - -Set up Claude Code to help you write and maintain your Mintlify documentation. - -## Prerequisites - -- Active Claude subscription (Pro, Max, or API access) - -## Setup - - - - ```bash - npm install -g @anthropic-ai/claude-code - ``` - - - - In your docs directory, run: - - ```bash - npx skills add https://mintlify.com/docs - ``` - - This gives Claude Code Mintlify's component reference, writing standards, - and workflow guidance. - - - - Edit `AGENTS.md` in your project root to add project-specific terminology, - style preferences, and content boundaries. - - - - ```bash - claude - ``` - - diff --git a/ai-tools/cursor.mdx b/ai-tools/cursor.mdx deleted file mode 100644 index 80bab56..0000000 --- a/ai-tools/cursor.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "Cursor setup" -description: "Configure Cursor for your documentation workflow" -icon: "arrow-pointer" ---- - -Set up Cursor to help you write and maintain your Mintlify documentation. - -## Prerequisites - -- Cursor editor installed - -## Setup - - - - Open the root of your documentation repository where `docs.json` is located. - - - - In the integrated terminal, run: - - ```bash - npx skills add https://mintlify.com/docs - ``` - - This gives Cursor Mintlify's component reference, writing standards, - and workflow guidance. - - - - Edit `AGENTS.md` in your project root to add project-specific terminology, - style preferences, and content boundaries. - - - - Open a file and use Cursor's AI features to draft and edit documentation. - - diff --git a/ai-tools/windsurf.mdx b/ai-tools/windsurf.mdx deleted file mode 100644 index 0776cca..0000000 --- a/ai-tools/windsurf.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: "Windsurf setup" -description: "Configure Windsurf for your documentation workflow" -icon: "water" ---- - -Set up Windsurf's Cascade AI assistant to help you write and maintain your Mintlify documentation. - -## Prerequisites - -- Windsurf editor installed - -## Setup - - - - Open the root of your documentation repository where `docs.json` is located. - - - - In the integrated terminal, run: - - ```bash - npx skills add https://mintlify.com/docs - ``` - - This gives Windsurf Mintlify's component reference, writing standards, - and workflow guidance. - - - - Edit `AGENTS.md` in your project root to add project-specific terminology, - style preferences, and content boundaries. - - - - Open a file and use Cascade to draft and edit documentation. - - diff --git a/api-reference/actor/get-actor-sandboxes.mdx b/api-reference/actor/get-actor-sandboxes.mdx new file mode 100644 index 0000000..ea3e51a --- /dev/null +++ b/api-reference/actor/get-actor-sandboxes.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Actor Sandboxes' +openapi: 'GET /io.pocketenv.actor.getActorSandboxes' +--- diff --git a/api-reference/actor/get-profile.mdx b/api-reference/actor/get-profile.mdx new file mode 100644 index 0000000..1d28eac --- /dev/null +++ b/api-reference/actor/get-profile.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Profile' +openapi: 'GET /io.pocketenv.actor.getProfile' +--- diff --git a/api-reference/actor/get-terminal-token.mdx b/api-reference/actor/get-terminal-token.mdx new file mode 100644 index 0000000..55a3a7c --- /dev/null +++ b/api-reference/actor/get-terminal-token.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Terminal Token' +openapi: 'GET /io.pocketenv.actor.getTerminalToken' +--- diff --git a/api-reference/endpoint/create.mdx b/api-reference/endpoint/create.mdx deleted file mode 100644 index 5689f1b..0000000 --- a/api-reference/endpoint/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Plant' -openapi: 'POST /plants' ---- diff --git a/api-reference/endpoint/delete.mdx b/api-reference/endpoint/delete.mdx deleted file mode 100644 index 657dfc8..0000000 --- a/api-reference/endpoint/delete.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Delete Plant' -openapi: 'DELETE /plants/{id}' ---- diff --git a/api-reference/endpoint/get.mdx b/api-reference/endpoint/get.mdx deleted file mode 100644 index 56aa09e..0000000 --- a/api-reference/endpoint/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Plants' -openapi: 'GET /plants' ---- diff --git a/api-reference/endpoint/webhook.mdx b/api-reference/endpoint/webhook.mdx deleted file mode 100644 index 3291340..0000000 --- a/api-reference/endpoint/webhook.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'New Plant' -openapi: 'WEBHOOK /plant/webhook' ---- diff --git a/api-reference/file/add.mdx b/api-reference/file/add.mdx new file mode 100644 index 0000000..4cdb8d5 --- /dev/null +++ b/api-reference/file/add.mdx @@ -0,0 +1,4 @@ +--- +title: 'Add File' +openapi: 'POST /io.pocketenv.file.addFile' +--- diff --git a/api-reference/file/delete.mdx b/api-reference/file/delete.mdx new file mode 100644 index 0000000..ca40875 --- /dev/null +++ b/api-reference/file/delete.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete File' +openapi: 'POST /io.pocketenv.file.deleteFile' +--- diff --git a/api-reference/file/get.mdx b/api-reference/file/get.mdx new file mode 100644 index 0000000..c6b5bc4 --- /dev/null +++ b/api-reference/file/get.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get File' +openapi: 'GET /io.pocketenv.file.getFile' +--- diff --git a/api-reference/file/list.mdx b/api-reference/file/list.mdx new file mode 100644 index 0000000..2612d2e --- /dev/null +++ b/api-reference/file/list.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Files' +openapi: 'GET /io.pocketenv.file.getFiles' +--- diff --git a/api-reference/file/update.mdx b/api-reference/file/update.mdx new file mode 100644 index 0000000..96e9b1c --- /dev/null +++ b/api-reference/file/update.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update File' +openapi: 'POST /io.pocketenv.file.updateFile' +--- diff --git a/api-reference/introduction.mdx b/api-reference/introduction.mdx index c835b78..e8e2716 100644 --- a/api-reference/introduction.mdx +++ b/api-reference/introduction.mdx @@ -1,33 +1,52 @@ --- -title: 'Introduction' -description: 'Example section for showcasing API endpoints' +title: 'API Reference' +description: 'Pocketenv XRPC API — manage sandboxes, files, secrets, services, and more.' --- - - If you're not looking to build API reference documentation, you can delete - this section by removing the api-reference folder. - +## Base URL -## Welcome +All API requests are made to: -There are two ways to build API documentation: [OpenAPI](https://mintlify.com/docs/api-playground/openapi/setup) and [MDX components](https://mintlify.com/docs/api-playground/mdx/configuration). For the starter kit, we are using the following OpenAPI specification. - - - View the OpenAPI specification file - +``` +https://api.pocketenv.io/xrpc/ +``` ## Authentication -All API endpoints are authenticated using Bearer tokens and picked up from the specification file. +Every endpoint requires a Bearer token in the `Authorization` header. + +```bash +Authorization: Bearer +``` + + + You can retrieve a token via the Pocketenv dashboard or by authenticating through the AT Protocol flow. + + +## Errors + +All errors return a JSON body with `error` and `message` fields. + +| Status | Meaning | +|--------|---------| +| `400` | Bad request — invalid parameters or missing fields | +| `401` | Unauthorized — missing or invalid Bearer token | ```json -"security": [ - { - "bearerAuth": [] - } -] +{ + "error": "InvalidRequest", + "message": "Missing required field: sandboxId" +} ``` + +## Resources + +| Resource | Description | +|----------|-------------| +| **Actor** | User profile and account-level sandbox access | +| **Sandboxes** | Full sandbox lifecycle — create, start, stop, exec, delete | +| **Files** | Read and write files inside a sandbox | +| **Secrets** | Encrypted key-value secrets scoped to a sandbox | +| **Variables** | Environment variables for sandbox configuration | +| **Services** | Long-running processes inside a sandbox | +| **Volumes** | Persistent storage volumes attached to sandboxes | diff --git a/api-reference/openapi.json b/api-reference/openapi.json index da5326e..70d72ec 100644 --- a/api-reference/openapi.json +++ b/api-reference/openapi.json @@ -1,94 +1,232 @@ { "openapi": "3.1.0", "info": { - "title": "OpenAPI Plant Store", - "description": "A sample API that uses a plant store as an example to demonstrate features in the OpenAPI specification", + "title": "AT Protocol XRPC API", + "summary": "An unofficial conversion of AT Protocol's lexicons to OpenAPI's schema format.", + "version": "0.0.0", "license": { - "name": "MIT" - }, - "version": "1.0.0" + "name": "MIT License", + "identifier": "MIT" + } }, "servers": [ { - "url": "http://sandbox.mintlify.com" - } - ], - "security": [ + "url": "https://api.pocketenv.io/xrpc/", + "description": "AT Protocol PDS XRPC server" + }, { - "bearerAuth": [] + "url": "https://api.pocketenv.io/xrpc/", + "description": "AT Protocol AppView XRPC server" } ], "paths": { - "/plants": { + "/io.pocketenv.actor.getActorSandboxes": { "get": { - "description": "Returns all plants from the system that the user has access to", + "tags": ["io.pocketenv.actor"], + "summary": "Get all sandboxes for a given actor", + "operationId": "io.pocketenv.actor.getActorSandboxes", + "security": [ + { + "Bearer": [] + } + ], "parameters": [ + { + "name": "did", + "in": "query", + "description": "The DID or handle of the actor", + "required": true, + "schema": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier" + } + }, { "name": "limit", "in": "query", - "description": "The maximum number of results to return", + "description": "The maximum number of sandboxes to return.", + "required": false, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "offset", + "in": "query", + "description": "The number of sandboxes to skip before starting to collect the result set.", + "required": false, "schema": { "type": "integer", - "format": "int32" + "minimum": 0 + } + }, + { + "name": "isRunning", + "in": "query", + "description": "Filter sandboxes by their running status.", + "required": false, + "schema": { + "type": "boolean", + "description": "Filter sandboxes by their running status." } } ], "responses": { "200": { - "description": "Plant response", + "description": "OK", "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Plant" + "type": "object", + "properties": { + "sandboxes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewDetailed" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } } } } } }, "400": { - "description": "Unexpected error", + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Error" + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } } } } } } - }, - "post": { - "description": "Creates a new plant in the store", - "requestBody": { - "description": "Plant to add to the store", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NewPlant" - } + } + }, + "/io.pocketenv.actor.getProfile": { + "get": { + "tags": ["io.pocketenv.actor"], + "summary": "Get the profile of an actor", + "operationId": "io.pocketenv.actor.getProfile", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "did", + "in": "query", + "description": "The DID or handle of the actor", + "required": false, + "schema": { + "type": "string", + "description": "The DID or handle of the actor", + "format": "at-identifier" } - }, - "required": true - }, + } + ], "responses": { "200": { - "description": "plant response", + "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Plant" + "$ref": "#/components/schemas/io.pocketenv.actor.defs.profileViewDetailed" } } } }, "400": { - "description": "unexpected error", + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Error" + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } } } } @@ -96,122 +234,6020 @@ } } }, - "/plants/{id}": { - "delete": { - "description": "Deletes a single plant based on the ID supplied", - "parameters": [ + "/io.pocketenv.actor.getTerminalToken": { + "get": { + "tags": ["io.pocketenv.actor"], + "summary": "Get a terminal token", + "operationId": "io.pocketenv.actor.getTerminalToken", + "security": [ { - "name": "id", - "in": "path", - "description": "ID of plant to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } + "Bearer": [] } ], "responses": { - "204": { - "description": "Plant deleted", - "content": {} + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "An access token that can be used to authenticate with the terminal service. This token is typically short-lived and should be used immediately to establish a connection with the terminal." + } + } + } + } + } }, "400": { - "description": "unexpected error", + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Error" + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } } } } } } } - } - }, - "webhooks": { - "/plant/webhook": { + }, + "/io.pocketenv.file.addFile": { "post": { - "description": "Information about a new plant added to the store", + "tags": ["io.pocketenv.file"], + "operationId": "io.pocketenv.file.addFile", + "security": [ + { + "Bearer": [] + } + ], "requestBody": { - "description": "Plant added to the store", + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/NewPlant" + "type": "object", + "required": ["file"], + "properties": { + "file": { + "$ref": "#/components/schemas/io.pocketenv.file.defs.file" + } + } } } } }, "responses": { "200": { - "description": "Return a 200 status to indicate that the data was received successfully" + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } } } } - } - }, - "components": { - "schemas": { - "Plant": { - "required": [ - "name" + }, + "/io.pocketenv.file.deleteFile": { + "post": { + "tags": ["io.pocketenv.file"], + "operationId": "io.pocketenv.file.deleteFile", + "security": [ + { + "Bearer": [] + } ], - "type": "object", - "properties": { - "name": { - "description": "The name of the plant", - "type": "string" + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } }, - "tag": { - "description": "Tag to specify the type", - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } } } - }, - "NewPlant": { - "allOf": [ + } + }, + "/io.pocketenv.file.getFile": { + "get": { + "tags": ["io.pocketenv.file"], + "operationId": "io.pocketenv.file.getFile", + "security": [ { - "$ref": "#/components/schemas/Plant" - }, + "Bearer": [] + } + ], + "parameters": [ { - "required": [ - "id" - ], - "type": "object", - "properties": { - "id": { - "description": "Identification number of the plant", - "type": "integer", - "format": "int64" - } + "name": "id", + "in": "query", + "description": "The ID of the file to retrieve.", + "required": true, + "schema": { + "type": "string", + "description": "The ID of the file to retrieve." } } - ] - }, - "Error": { - "required": [ - "error", - "message" ], - "type": "object", - "properties": { - "error": { - "type": "integer", - "format": "int32" + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "file": { + "$ref": "#/components/schemas/io.pocketenv.file.defs.fileView" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } }, - "message": { - "type": "string" + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } } } } }, - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer" + "/io.pocketenv.file.getFiles": { + "get": { + "tags": ["io.pocketenv.file"], + "operationId": "io.pocketenv.file.getFiles", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "sandboxId", + "in": "query", + "description": "The ID of the sandbox for which to retrieve files.", + "required": false, + "schema": { + "type": "string", + "description": "The ID of the sandbox for which to retrieve files." + } + }, + { + "name": "limit", + "in": "query", + "description": "The maximum number of files to return.", + "required": false, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "offset", + "in": "query", + "description": "The number of files to skip before starting to collect the result set.", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "files": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.file.defs.fileView" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } } + }, + "/io.pocketenv.file.updateFile": { + "post": { + "tags": ["io.pocketenv.file"], + "operationId": "io.pocketenv.file.updateFile", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "file"], + "properties": { + "id": { + "type": "string", + "description": "The ID of the file to delete" + }, + "file": { + "$ref": "#/components/schemas/io.pocketenv.file.defs.file" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.claimSandbox": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Claim a sandbox by id", + "operationId": "io.pocketenv.sandbox.claimSandbox", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewBasic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.createBackup": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Create a backup of a sandbox by id", + "operationId": "io.pocketenv.sandbox.createBackup", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["directory"], + "properties": { + "directory": { + "type": "string", + "description": "The directory to backup." + }, + "description": { + "type": "string", + "description": "An optional description for the backup." + }, + "ttl": { + "type": "integer" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.createIntegration": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Create a new integration for the sandbox.", + "operationId": "io.pocketenv.sandbox.createIntegration", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "name"], + "properties": { + "id": { + "type": "string", + "description": "The sandbox ID." + }, + "name": { + "type": "string", + "description": "The name of the integration." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.integrationView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.createSandbox": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Create a sandbox", + "operationId": "io.pocketenv.sandbox.createSandbox", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["base"], + "properties": { + "base": { + "type": "string", + "description": "The base sandbox URI to clone from, e.g. a template or an existing sandbox." + }, + "name": { + "type": "string", + "description": "The name of the sandbox", + "minLength": 1 + }, + "description": { + "type": "string", + "description": "A description for the sandbox" + }, + "provider": { + "type": "string", + "description": "The provider to create the sandbox on, e.g. 'daytona', 'vercel', 'cloudflare', etc." + }, + "topics": { + "type": "array", + "items": { + "type": "string", + "maxLength": 50 + } + }, + "repo": { + "type": "string", + "description": "A git repository URL to clone into the sandbox, e.g. a GitHub/Tangled repo." + }, + "vcpus": { + "type": "integer", + "minimum": 1 + }, + "memory": { + "type": "integer", + "minimum": 1 + }, + "disk": { + "type": "integer", + "minimum": 3 + }, + "readme": { + "type": "string", + "description": "A URI to a README for the sandbox.", + "format": "uri" + }, + "secrets": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.secrets" + }, + "envs": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.envs" + }, + "keepAlive": { + "type": "boolean", + "description": "Prevent the sandbox from being automatically stop after a period of inactivity. Use with caution, as this may lead to increased costs." + }, + "spriteToken": { + "type": "string", + "description": "A token (encrypted) for accessing sprite resources" + }, + "redactedSpriteToken": { + "type": "string", + "description": "A redacted token for accessing sprite resources" + }, + "denoDeployToken": { + "type": "string", + "description": "A token (encrypted) for accessing Deno Deploy resources" + }, + "redactedDenoDeployToken": { + "type": "string", + "description": "A redacted token for accessing Deno Deploy resources" + }, + "daytonaApiKey": { + "type": "string", + "description": "A token (encrypted) for accessing Daytona resources" + }, + "redactedDaytonaApiKey": { + "type": "string", + "description": "A redacted token for accessing Daytona resources" + }, + "daytonaOrganizationId": { + "type": "string", + "description": "The organization ID for Daytona resources" + }, + "vercelApiToken": { + "type": "string", + "description": "A token (encrypted) for accessing Vercel resources" + }, + "redactedVercelApiToken": { + "type": "string", + "description": "A redacted token for accessing Vercel resources" + }, + "vercelProjectId": { + "type": "string", + "description": "The project ID for Vercel resources" + }, + "vercelTeamId": { + "type": "string", + "description": "The team ID for Vercel resources" + }, + "modalTokenId": { + "type": "string", + "description": "A token (encrypted) for accessing Modal resources" + }, + "redactedModalTokenId": { + "type": "string", + "description": "A redacted token for accessing Modal resources" + }, + "modalTokenSecret": { + "type": "string", + "description": "A token (encrypted) for accessing Modal resources" + }, + "redactedModalTokenSecret": { + "type": "string", + "description": "A redacted token for accessing Modal resources" + }, + "e2bApiKey": { + "type": "string", + "description": "An API KEY (encrypted) for accessing E2B resources" + }, + "redactedE2bApiKey": { + "type": "string", + "description": "A redacted API KEY for accessing E2B resources" + }, + "hopxApiKey": { + "type": "string", + "description": "An API KEY (encrypted) for accessing hopx resources" + }, + "redactedHopxApiKey": { + "type": "string", + "description": "A redacted API KEY for accessing hopx resources" + }, + "runloopApiKey": { + "type": "string", + "description": "An API KEY (encrypted) for accessing Runloop resources" + }, + "redactedRunloopApiKey": { + "type": "string", + "description": "A redacted API KEY for accessing Runloop resources" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewBasic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.deleteSandbox": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Delete a sandbox by uri", + "operationId": "io.pocketenv.sandbox.deleteSandbox", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewBasic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.exec": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Execute a command in a sandbox.", + "operationId": "io.pocketenv.sandbox.exec", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["command"], + "properties": { + "command": { + "type": "string", + "description": "The command to execute in the sandbox." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "stdout": { + "type": "string", + "description": "The output of the executed command." + }, + "stderr": { + "type": "string", + "description": "The error output of the executed command, if any." + }, + "exitCode": { + "type": "integer" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.exposePort": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Expose a port for a sandbox.", + "operationId": "io.pocketenv.sandbox.exposePort", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["port"], + "properties": { + "port": { + "type": "integer", + "minimum": 1025, + "maximum": 65535 + }, + "description": { + "type": "string", + "description": "A description of the port." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "previewUrl": { + "type": "string", + "description": "The preview URL for the exposed port." + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.exposeVscode": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Expose an instance of VS Code for a sandbox. This allows users to access a web-based version of VS Code that is connected to their sandbox environment, enabling them to edit code, manage files, and perform other development tasks directly from their browser.", + "operationId": "io.pocketenv.sandbox.exposeVscode", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "previewUrl": { + "type": "string", + "description": "The preview URL for the exposed port." + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getBackups": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get the list of backups for a sandbox.", + "operationId": "io.pocketenv.sandbox.getBackups", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID.", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "backups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.port.defs.backupViewBasic" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getExposedPorts": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get the list of exposed ports for a sandbox.", + "operationId": "io.pocketenv.sandbox.getExposedPorts", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID.", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ports": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.port.defs.portView" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getIntegrations": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get the integrations for a sandbox.", + "operationId": "io.pocketenv.sandbox.getIntegrations", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID.", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.integrationsView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getPreferences": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get sandbox preferences", + "operationId": "io.pocketenv.sandbox.getPreferences", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID or URI to retrieve", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID or URI to retrieve" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.preferences" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getSandbox": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get a sandbox by ID or URI", + "operationId": "io.pocketenv.sandbox.getSandbox", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID or URI to retrieve", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID or URI to retrieve" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewBasic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getSandboxes": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get all sandboxes", + "operationId": "io.pocketenv.sandbox.getSandboxes", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "The maximum number of sandboxes to return.", + "required": false, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "offset", + "in": "query", + "description": "The number of sandboxes to skip before starting to collect the result set.", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sandboxes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewBasic" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getSshKeys": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get the SSH keys for a sandbox.", + "operationId": "io.pocketenv.sandbox.getSshKeys", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID.", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sshKeysView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getTailscaleAuthKey": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get the Tailscale token for a sandbox.", + "operationId": "io.pocketenv.sandbox.getTailscaleAuthKey", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID.", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.tailscaleAuthKeyView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.getTailscaleToken": { + "get": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Get the Tailscale token for a sandbox.", + "operationId": "io.pocketenv.sandbox.getTailscaleToken", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The sandbox ID.", + "required": true, + "schema": { + "type": "string", + "description": "The sandbox ID." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.tailscaleTokenView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.pullDirectory": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Pull a directory from the cp storage into a Sandbox.", + "operationId": "io.pocketenv.sandbox.pullDirectory", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["sandboxId", "directoryPath"], + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the Sandbox into which to pull the directory." + }, + "uuid": { + "type": "string", + "description": "ID of the directory in cp storage to pull into the Sandbox." + }, + "directoryPath": { + "type": "string", + "description": "Destination path within the Sandbox where the directory should be pulled. This should be an absolute path." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.pushDirectory": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Push a directory from a Sandbox to the cp Storage.", + "operationId": "io.pocketenv.sandbox.pushDirectory", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["sandboxId", "directoryPath"], + "properties": { + "sandboxId": { + "type": "string", + "description": "ID of the source Sandbox to read the directory from." + }, + "directoryPath": { + "type": "string", + "description": "Path of the directory within the Sandbox to push to cp storage. This should be an absolute path." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "description": "The UUID of the pushed directory in cp storage. This can be used to reference the directory in other API calls, such as creating a file from the directory or sharing the directory with another sandbox." + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.putPreferences": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Update sandbox preferences.", + "operationId": "io.pocketenv.sandbox.putPreferences", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["sandboxId", "preferences"], + "properties": { + "sandboxId": { + "type": "string", + "description": "The sandbox ID or URI" + }, + "preferences": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.preferences" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.putSshKeys": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Add or update SSH keys for a sandbox.", + "operationId": "io.pocketenv.sandbox.putSshKeys", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "privateKey", "publicKey"], + "properties": { + "id": { + "type": "string", + "description": "The sandbox ID." + }, + "privateKey": { + "type": "string", + "description": "The private SSH key (encrypted)" + }, + "publicKey": { + "type": "string", + "description": "The public SSH key." + }, + "redacted": { + "type": "string", + "description": "The redacted SSH key." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sshKeysView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.putTailscaleAuthKey": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Store a Tailscale Auth Key for the sandbox. This Auth Key will be used to authenticate with the Tailscale API and manage the sandbox's Tailscale node.", + "operationId": "io.pocketenv.sandbox.putTailscaleAuthKey", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "authKey"], + "properties": { + "id": { + "type": "string", + "description": "The sandbox ID." + }, + "authKey": { + "type": "string", + "description": "The Tailscale Auth Key (encrypted) to store for the sandbox." + }, + "redacted": { + "type": "string", + "description": "The redacted SSH key." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.tailscaleAuthKeyView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.putTailscaleToken": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Store a Tailscale token for the sandbox. This token will be used to authenticate with the Tailscale API and manage the sandbox's Tailscale node.", + "operationId": "io.pocketenv.sandbox.putTailscaleToken", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "token"], + "properties": { + "id": { + "type": "string", + "description": "The sandbox ID." + }, + "token": { + "type": "string", + "description": "The Tailscale token (encrypted) to store for the sandbox." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.tailscaleTokenView" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.restoreBackup": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Restore a backup of a sandbox", + "operationId": "io.pocketenv.sandbox.restoreBackup", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["backupId"], + "properties": { + "backupId": { + "type": "string", + "description": "The backup ID to restore." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.startSandbox": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Start a sandbox", + "operationId": "io.pocketenv.sandbox.startSandbox", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "repo": { + "type": "string", + "description": "The git repository URL to clone into the sandbox before starting it. Optional." + }, + "keepAlive": { + "type": "boolean", + "description": "Prevent the sandbox from being automatically stop after a period of inactivity. Use with caution, as this may lead to increased costs." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewBasic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.stopSandbox": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Stop a sandbox", + "operationId": "io.pocketenv.sandbox.stopSandbox", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxViewBasic" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.unexposePort": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Unexpose a port for a sandbox.", + "operationId": "io.pocketenv.sandbox.unexposePort", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["port"], + "properties": { + "port": { + "type": "integer", + "minimum": 1024, + "maximum": 65535 + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.sandbox.updateSandboxSettings": { + "post": { + "tags": ["io.pocketenv.sandbox"], + "summary": "Update sandbox settings", + "operationId": "io.pocketenv.sandbox.updateSandboxSettings", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the sandbox", + "minLength": 1 + }, + "description": { + "type": "string", + "description": "A description for the sandbox" + }, + "topics": { + "type": "array", + "items": { + "type": "string", + "maxLength": 50 + } + }, + "repo": { + "type": "string", + "description": "A git repository URL to clone into the sandbox, e.g. a GitHub/Tangled repo.", + "format": "uri" + }, + "vcpus": { + "type": "integer", + "minimum": 1 + }, + "memory": { + "type": "integer", + "minimum": 1 + }, + "disk": { + "type": "integer", + "minimum": 3 + }, + "readme": { + "type": "string", + "description": "A URI to a README for the sandbox.", + "format": "uri" + }, + "secrets": { + "$ref": "#/components/schemas/io.pocketenv.secret.defs.secrets" + }, + "variables": { + "$ref": "#/components/schemas/io.pocketenv.variable.defs.variables" + }, + "files": { + "$ref": "#/components/schemas/io.pocketenv.file.defs.file" + }, + "volumes": { + "$ref": "#/components/schemas/io.pocketenv.volume.defs.volumes" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.profileViewDetailed" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.secret.addSecret": { + "post": { + "tags": ["io.pocketenv.secret"], + "operationId": "io.pocketenv.secret.addSecret", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["secret"], + "properties": { + "secret": { + "$ref": "#/components/schemas/io.pocketenv.secret.defs.secret" + }, + "redacted": { + "type": "string", + "description": "The redacted secret value." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.secret.deleteSecret": { + "post": { + "tags": ["io.pocketenv.secret"], + "operationId": "io.pocketenv.secret.deleteSecret", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.secret.getSecret": { + "get": { + "tags": ["io.pocketenv.secret"], + "operationId": "io.pocketenv.secret.getSecret", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The ID of the secret for which to retrieve secrets.", + "required": true, + "schema": { + "type": "string", + "description": "The ID of the secret for which to retrieve secrets." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secret": { + "$ref": "#/components/schemas/io.pocketenv.secret.defs.secretView" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.secret.getSecrets": { + "get": { + "tags": ["io.pocketenv.secret"], + "operationId": "io.pocketenv.secret.getSecrets", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "sandboxId", + "in": "query", + "description": "The ID of the sandbox for which to retrieve secrets.", + "required": false, + "schema": { + "type": "string", + "description": "The ID of the sandbox for which to retrieve secrets." + } + }, + { + "name": "limit", + "in": "query", + "description": "The maximum number of secrets to return.", + "required": false, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "offset", + "in": "query", + "description": "The number of secrets to skip before starting to collect the result set.", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.secret.defs.secretView" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.secret.updateSecret": { + "post": { + "tags": ["io.pocketenv.secret"], + "operationId": "io.pocketenv.secret.updateSecret", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "secret"], + "properties": { + "id": { + "type": "string", + "description": "The ID of the secret to update." + }, + "secret": { + "$ref": "#/components/schemas/io.pocketenv.secret.defs.secret" + }, + "redacted": { + "type": "string", + "description": "The redacted secret value." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.service.addService": { + "post": { + "tags": ["io.pocketenv.service"], + "operationId": "io.pocketenv.service.addService", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["service"], + "properties": { + "service": { + "$ref": "#/components/schemas/io.pocketenv.service.defs.service" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.service.deleteService": { + "post": { + "tags": ["io.pocketenv.service"], + "operationId": "io.pocketenv.service.deleteService", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.service.getServices": { + "get": { + "tags": ["io.pocketenv.service"], + "operationId": "io.pocketenv.service.getServices", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "sandboxId", + "in": "query", + "description": "The ID of the sandbox for which to retrieve services.", + "required": true, + "schema": { + "type": "string", + "description": "The ID of the sandbox for which to retrieve services." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.service.defs.serviceView" + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.service.restartService": { + "post": { + "tags": ["io.pocketenv.service"], + "operationId": "io.pocketenv.service.restartService", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.service.startService": { + "post": { + "tags": ["io.pocketenv.service"], + "operationId": "io.pocketenv.service.startService", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.service.stopService": { + "post": { + "tags": ["io.pocketenv.service"], + "operationId": "io.pocketenv.service.stopService", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.service.updateService": { + "post": { + "tags": ["io.pocketenv.service"], + "operationId": "io.pocketenv.service.updateService", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["service"], + "properties": { + "service": { + "$ref": "#/components/schemas/io.pocketenv.service.defs.service" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.variable.addVariable": { + "post": { + "tags": ["io.pocketenv.variable"], + "operationId": "io.pocketenv.variable.addVariable", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["variable"], + "properties": { + "variable": { + "$ref": "#/components/schemas/io.pocketenv.variable.defs.variable" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.variable.deleteVariable": { + "post": { + "tags": ["io.pocketenv.variable"], + "operationId": "io.pocketenv.variable.deleteVariable", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.variable.getVariable": { + "get": { + "tags": ["io.pocketenv.variable"], + "operationId": "io.pocketenv.variable.getVariable", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The ID of the variable for which to retrieve variables.", + "required": true, + "schema": { + "type": "string", + "description": "The ID of the variable for which to retrieve variables." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "variable": { + "$ref": "#/components/schemas/io.pocketenv.variable.defs.variableView" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.variable.getVariables": { + "get": { + "tags": ["io.pocketenv.variable"], + "operationId": "io.pocketenv.variable.getVariables", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "sandboxId", + "in": "query", + "description": "The ID of the sandbox for which to retrieve variables.", + "required": false, + "schema": { + "type": "string", + "description": "The ID of the sandbox for which to retrieve variables." + } + }, + { + "name": "limit", + "in": "query", + "description": "The maximum number of variables to return.", + "required": false, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "offset", + "in": "query", + "description": "The number of variables to skip before starting to collect the result set.", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.variable.defs.variableView" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.variable.updateVariable": { + "post": { + "tags": ["io.pocketenv.variable"], + "operationId": "io.pocketenv.variable.updateVariable", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "variable"], + "properties": { + "id": { + "type": "string", + "description": "The ID of the variable to update." + }, + "variable": { + "$ref": "#/components/schemas/io.pocketenv.variable.defs.variable" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.volume.addVolume": { + "post": { + "tags": ["io.pocketenv.volume"], + "operationId": "io.pocketenv.volume.addVolume", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["volume"], + "properties": { + "volume": { + "$ref": "#/components/schemas/io.pocketenv.volume.defs.volume" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.volume.deleteVolume": { + "post": { + "tags": ["io.pocketenv.volume"], + "operationId": "io.pocketenv.volume.deleteVolume", + "security": [ + { + "Bearer": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.volume.getVolume": { + "get": { + "tags": ["io.pocketenv.volume"], + "operationId": "io.pocketenv.volume.getVolume", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "query", + "description": "The ID of the volume for which to retrieve volumes.", + "required": true, + "schema": { + "type": "string", + "description": "The ID of the volume for which to retrieve volumes." + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "volume": { + "$ref": "#/components/schemas/io.pocketenv.volume.defs.volumeView" + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.volume.getVolumes": { + "get": { + "tags": ["io.pocketenv.volume"], + "operationId": "io.pocketenv.volume.getVolumes", + "security": [ + { + "Bearer": [] + } + ], + "parameters": [ + { + "name": "sandboxId", + "in": "query", + "description": "The ID of the sandbox for which to retrieve volumes.", + "required": false, + "schema": { + "type": "string", + "description": "The ID of the sandbox for which to retrieve volumes." + } + }, + { + "name": "limit", + "in": "query", + "description": "The maximum number of volumes to return.", + "required": false, + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "name": "offset", + "in": "query", + "description": "The number of volumes to skip before starting to collect the result set.", + "required": false, + "schema": { + "type": "integer", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "volumes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.volume.defs.volumeView" + } + }, + "total": { + "type": "integer", + "minimum": 0 + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/io.pocketenv.volume.updateVolume": { + "post": { + "tags": ["io.pocketenv.volume"], + "operationId": "io.pocketenv.volume.updateVolume", + "security": [ + { + "Bearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["id", "volume"], + "properties": { + "id": { + "type": "string", + "description": "The ID of the volume to update." + }, + "volume": { + "$ref": "#/components/schemas/io.pocketenv.volume.defs.volume" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "InvalidRequest" + }, + { + "const": "ExpiredToken" + }, + { + "const": "InvalidToken" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "const": "AuthMissing" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "io.pocketenv.actor.defs.profileViewDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the actor." + }, + "did": { + "type": "string", + "description": "The DID of the actor." + }, + "handle": { + "type": "string", + "description": "The handle of the actor." + }, + "displayName": { + "type": "string", + "description": "The display name of the actor." + }, + "avatar": { + "type": "string", + "description": "The URL of the actor's avatar image.", + "format": "uri" + }, + "createdAt": { + "type": "string", + "description": "The date and time when the actor was created.", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "description": "The date and time when the actor was last updated.", + "format": "date-time" + } + } + }, + "app.bsky.actor.profile": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "maxLength": 640 + }, + "description": { + "type": "string", + "description": "Free-form profile description text.", + "maxLength": 2560 + }, + "avatar": { + "type": "string", + "format": "binary", + "maxLength": 1000000 + }, + "banner": { + "type": "string", + "format": "binary", + "maxLength": 10000000 + }, + "labels": { + "oneOf": [ + { + "$ref": "#/components/schemas/com.atproto.label.defs.selfLabels" + } + ] + }, + "joinedViaStarterPack": { + "$ref": "#/components/schemas/com.atproto.repo.strongRef" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + }, + "io.pocketenv.file.defs.file": { + "type": "object", + "required": ["path", "content"], + "properties": { + "sandboxId": { + "type": "string", + "description": "The ID of the sandbox to which the file belongs. This is used to associate the file with a specific sandbox environment." + }, + "path": { + "type": "string", + "description": "The file path within the sandbox, e.g. '/app/config.json', '/home/user/.ssh/id_rsa', etc." + }, + "content": { + "type": "string", + "description": "The content of the file. This will be written to the specified path within the sandbox. The content should be base64 encoded if it's binary data." + } + } + }, + "io.pocketenv.file.defs.fileView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the file." + }, + "path": { + "type": "string", + "description": "The file path within the sandbox, e.g. '/app/config.json', '/home/user/.ssh/id_rsa', etc." + }, + "createdAt": { + "type": "string", + "description": "The timestamp when the file was created.", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "description": "The timestamp when the file was last updated.", + "format": "date-time" + } + } + }, + "io.pocketenv.file.defs.files": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.file.defs.file" + } + }, + "io.pocketenv.port.defs.portView": { + "type": "object", + "description": "A view of a port exposed by a sandbox.", + "properties": { + "port": { + "type": "integer", + "minimum": 1025, + "maximum": 65535 + }, + "description": { + "type": "string", + "description": "A description of the port." + }, + "previewUrl": { + "type": "string", + "description": "A URL for previewing the service running on the port" + } + } + }, + "io.pocketenv.publicKey": { + "type": "object", + "required": ["name", "key", "createdAt"], + "properties": { + "name": { + "type": "string", + "description": "Name of the public key", + "maxLength": 255 + }, + "key": { + "type": "string", + "description": "The public key value, e.g. an SSH public key string." + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + }, + "io.pocketenv.sandbox.defs.sandboxViewBasic": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the sandbox", + "maxLength": 50 + }, + "provider": { + "type": "string", + "description": "The provider of the sandbox, e.g. 'daytona', 'vercel', 'cloudflare', etc.", + "maxLength": 50 + }, + "description": { + "type": "string", + "maxLength": 3000 + }, + "website": { + "type": "string", + "description": "Any URI related to the sandbox", + "format": "uri" + }, + "logo": { + "type": "string", + "description": "URI to an image logo for the sandbox", + "format": "uri" + }, + "topics": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "maxItems": 50 + }, + "repo": { + "type": "string", + "description": "A git repository URL to clone into the sandbox, e.g. a GitHub/Tangled repo." + }, + "readme": { + "type": "string", + "description": "A URI to a README for the sandbox.", + "format": "uri" + }, + "vcpus": { + "type": "integer" + }, + "memory": { + "type": "integer" + }, + "disk": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "integer", + "minimum": 1025, + "maximum": 65535 + }, + "maxItems": 100 + }, + "installs": { + "type": "integer" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + }, + "io.pocketenv.sandbox.defs.sandboxViewDetailed": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the sandbox", + "maxLength": 50 + }, + "provider": { + "type": "string", + "description": "The provider of the sandbox, e.g. 'daytona', 'vercel', 'cloudflare', etc.", + "maxLength": 50 + }, + "description": { + "type": "string", + "maxLength": 3000 + }, + "status": { + "type": "string", + "description": "The current status of the sandbox, e.g. 'RUNNING', 'STOPPED', etc." + }, + "startedAt": { + "type": "string", + "format": "date-time" + }, + "timeout": { + "type": "integer" + }, + "baseSandbox": { + "type": "string", + "description": "The base sandbox that this sandbox was created from, if any. This can be used to determine the template or configuration used to create the sandbox." + }, + "website": { + "type": "string", + "description": "Any URI related to the sandbox", + "format": "uri" + }, + "logo": { + "type": "string", + "description": "URI to an image logo for the sandbox", + "format": "uri" + }, + "topics": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "maxItems": 50 + }, + "repo": { + "type": "string", + "description": "A git repository URL to clone into the sandbox, e.g. a GitHub/Tangled repo." + }, + "readme": { + "type": "string", + "description": "A URI to a README for the sandbox.", + "format": "uri" + }, + "vcpus": { + "type": "integer" + }, + "memory": { + "type": "integer" + }, + "disk": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "integer", + "minimum": 1025, + "maximum": 65535 + }, + "maxItems": 100 + }, + "installs": { + "type": "integer" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "owner": { + "$ref": "#/components/schemas/io.pocketenv.user.defs.userViewBasic" + } + } + }, + "io.pocketenv.sandbox.defs.sandboxDetailsPref": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the sandbox", + "minLength": 1 + }, + "description": { + "type": "string", + "description": "A description for the sandbox" + }, + "topics": { + "type": "array", + "items": { + "type": "string", + "maxLength": 50 + } + }, + "repo": { + "type": "string", + "description": "A git repository URL to clone into the sandbox, e.g. a GitHub/Tangled repo." + }, + "vcpus": { + "type": "integer", + "minimum": 1 + }, + "memory": { + "type": "integer", + "minimum": 1 + }, + "disk": { + "type": "integer", + "minimum": 3 + }, + "readme": { + "type": "string", + "description": "A URI to a README for the sandbox.", + "format": "uri" + } + } + }, + "io.pocketenv.sandbox.defs.secretPref": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the secret", + "minLength": 1 + }, + "value": { + "type": "string", + "description": "The value of the secret. This will be encrypted at rest and redacted in any API responses." + } + } + }, + "io.pocketenv.sandbox.defs.variablePref": { + "type": "object", + "description": "A variable to add to the sandbox", + "properties": { + "name": { + "type": "string", + "description": "The name of the variable", + "minLength": 1 + }, + "value": { + "type": "string", + "description": "The value of the variable. This will be visible in API responses and should not contain sensitive information." + } + } + }, + "io.pocketenv.sandbox.defs.filePref": { + "type": "object", + "description": "A file to add to the sandbox", + "properties": { + "name": { + "type": "string", + "description": "The name of the file", + "minLength": 1 + }, + "content": { + "type": "string", + "description": "The content of the file." + }, + "encrypt": { + "type": "boolean", + "description": "Whether the file content should be encrypted at rest and redacted in API responses. This is useful for files that may contain sensitive information." + }, + "path": { + "type": "string", + "description": "The path within the sandbox where the file will be created, e.g. '/app/config.json'. If not provided, the file will be created in the root directory of the sandbox." + } + } + }, + "io.pocketenv.sandbox.defs.volumePref": { + "type": "object", + "description": "A volume to add to the sandbox", + "properties": { + "name": { + "type": "string", + "description": "The name of the volume", + "minLength": 1 + }, + "path": { + "type": "string", + "description": "The mount path within the sandbox where the volume will be attached, e.g. '/data', '/logs', etc." + }, + "readOnly": { + "type": "boolean", + "description": "Whether the volume should be mounted as read-only" + } + } + }, + "io.pocketenv.sandbox.defs.sandboxProviderPref": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "The name of the sandbox provider", + "minLength": 1 + }, + "apiKey": { + "type": "string", + "description": "The encrypted API key used to authenticate with the sandbox provider.", + "minLength": 1 + }, + "redactedApiKey": { + "type": "string", + "description": "The redacted API key for the sandbox provider, returned in API responses." + }, + "organizationId": { + "type": "string", + "description": "The ID of the organization in the sandbox provider, if applicable. This can be used to associate the sandbox with a specific organization or team within the provider's platform." + }, + "vercelProjectId": { + "type": "string", + "description": "The project ID for Vercel, if the sandbox provider is Vercel. This is used to determine which Vercel project the sandbox should be created in." + }, + "vercelTeamId": { + "type": "string", + "description": "The team ID for Vercel, if the sandbox provider is Vercel and the sandbox should be created within a specific team. This is used to determine which team within the Vercel project the sandbox should be associated with." + }, + "modalTokenId": { + "type": "string", + "description": "The token ID for Modal, if the sandbox provider is Modal. This is used to determine which Modal token to use when creating the sandbox." + }, + "modalTokenSecret": { + "type": "string", + "description": "The token secret for Modal, if the sandbox provider is Modal. This is used to determine which Modal token secret to use when creating the sandbox." + }, + "redactedModalTokenId": { + "type": "string", + "description": "The redacted token ID for Modal, returned in API responses when the sandbox provider is Modal. This can be used to identify which Modal token is being used without exposing the actual token ID." + }, + "redactedModalTokenSecret": { + "type": "string", + "description": "The redacted token secret for Modal, returned in API responses when the sandbox provider is Modal. This can be used to identify which Modal token secret is being used without exposing the actual token secret." + }, + "e2bApiKey": { + "type": "string", + "description": "The API KEY for E2B, if the sandbox provider is E2B. This is used to determine which E2B API KEY to use when creating the sandbox." + }, + "redactedE2bApiKey": { + "type": "string", + "description": "The redacted API KEY for E2B, returned in API responses when the sandbox provider is E2B. This can be used to identify which E2B API KEY is being used without exposing the actual API KEY." + }, + "hopxApiKey": { + "type": "string", + "description": "The API KEY for hopx, if the sandbox provider is hopx. This is used to determine which hopx API KEY to use when creating the sandbox." + }, + "redactedHopxApiKey": { + "type": "string", + "description": "The redacted API KEY for hopx, returned in API responses when the sandbox provider is hopx. This can be used to identify which hopx API KEY is being used without exposing the actual API KEY." + }, + "runloopApiKey": { + "type": "string", + "description": "The API KEY for Runloop, if the sandbox provider is Runloop. This is used to determine which Runloop API KEY to use when creating the sandbox." + }, + "redactedRunloopApiKey": { + "type": "string", + "description": "The redacted API KEY for Runloop, returned in API responses when the sandbox provider is Runloop. This can be used to identify which Runloop API KEY is being used without exposing the actual API KEY." + } + } + }, + "io.pocketenv.sandbox.defs.preferences": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxDetailsPref" + }, + { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.secretPref" + }, + { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.variablePref" + }, + { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.filePref" + }, + { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.volumePref" + }, + { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.sandboxProviderPref" + } + ] + } + }, + "io.pocketenv.sandbox.defs.sshKeysView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the SSH key." + }, + "publicKey": { + "type": "string", + "description": "The public SSH key." + }, + "privateKey": { + "type": "string", + "description": "The private SSH key (redacted in API responses)" + }, + "createdAt": { + "type": "string", + "description": "The timestamp when the SSH key was created.", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "description": "The timestamp when the SSH key was last updated.", + "format": "date-time" + } + } + }, + "io.pocketenv.sandbox.defs.tailscaleAuthKeyView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the Tailscale Auth Key." + }, + "authKey": { + "type": "string", + "description": "The Tailscale auth key (redacted in API responses)" + }, + "redacted": { + "type": "string", + "description": "The redacted Auth Key." + }, + "createdAt": { + "type": "string", + "description": "The timestamp when the Tailscale Auth Key was created.", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "description": "The timestamp when the Tailscale Auth Key was last updated.", + "format": "date-time" + } + } + }, + "io.pocketenv.sandbox.defs.integrationView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the integration." + }, + "name": { + "type": "string", + "description": "The name of the integration, e.g. 'GitHub', 'Slack', 'Trello', etc." + }, + "webhookUrl": { + "type": "string", + "description": "The webhook URL of the integration.", + "format": "uri" + }, + "createdAt": { + "type": "string", + "description": "The timestamp when the integration was created.", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "description": "The timestamp when the integration was last updated.", + "format": "date-time" + } + } + }, + "io.pocketenv.sandbox.defs.integrationsView": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.sandbox.defs.integrationView" + } + }, + "io.pocketenv.sandbox.defs.backupViewBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the backup." + }, + "directory": { + "type": "string", + "description": "The directory that was backed up." + }, + "description": { + "type": "string", + "description": "An optional description for the backup." + }, + "expiresAt": { + "type": "integer" + }, + "createdAt": { + "type": "string", + "description": "datetime when the backup was created.", + "format": "date-time" + } + } + }, + "io.pocketenv.sandbox": { + "type": "object", + "required": ["name", "createdAt"], + "properties": { + "name": { + "type": "string", + "description": "Name of the sandbox", + "maxLength": 255 + }, + "base": { + "$ref": "#/components/schemas/com.atproto.repo.strongRef" + }, + "provider": { + "type": "string", + "description": "The provider of the sandbox, e.g. 'daytona', 'vercel', 'cloudflare', etc.", + "maxLength": 50 + }, + "description": { + "type": "string", + "maxLength": 3000 + }, + "website": { + "type": "string", + "description": "Any URI related to the sandbox", + "format": "uri" + }, + "logo": { + "type": "string", + "description": "URI to an image logo for the sandbox", + "format": "uri" + }, + "topics": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 50 + }, + "maxItems": 50 + }, + "repo": { + "type": "string", + "description": "A git repository URL to clone into the sandbox, e.g. a GitHub/Tangled repo." + }, + "readme": { + "type": "string", + "description": "A URI to a README for the sandbox.", + "format": "uri" + }, + "vcpus": { + "type": "integer" + }, + "memory": { + "type": "integer" + }, + "disk": { + "type": "integer" + }, + "volumes": { + "type": "array", + "items": { + "type": "string", + "description": "A path to be mounted as a volume in the sandbox, e.g. '/data', '/logs', etc." + } + }, + "ports": { + "type": "array", + "items": { + "type": "integer" + } + }, + "secrets": { + "type": "array", + "items": { + "type": "string", + "description": "Name of a secret to be added to the sandbox environment. Secrets are typically encrypted and stored securely, and can be used to store sensitive information such as API keys, database credentials, etc." + } + }, + "envs": { + "type": "array", + "items": { + "type": "string", + "description": "Name of an environment variable to be added to the sandbox environment." + } + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + }, + "io.pocketenv.secret.defs.secretView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the secret." + }, + "name": { + "type": "string", + "description": "Name of the secret, e.g. 'DATABASE_URL', 'SSH_KEY', etc." + } + } + }, + "io.pocketenv.secret.defs.secret": { + "type": "object", + "required": ["name", "value"], + "properties": { + "sandboxId": { + "type": "string", + "description": "The ID of the sandbox to which the secret belongs. This is used to associate the secret with a specific sandbox environment." + }, + "name": { + "type": "string", + "description": "Name of the secret, e.g. 'DATABASE_URL', 'SSH_KEY', etc." + }, + "value": { + "type": "string", + "description": "Value of the secret. This will be encrypted at rest and redacted in any API responses." + } + } + }, + "io.pocketenv.secret.defs.secrets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.secret.defs.secret" + } + }, + "io.pocketenv.service.defs.serviceView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the service." + }, + "name": { + "type": "string", + "description": "Name of the service." + }, + "command": { + "type": "string", + "description": "Command to run the service." + }, + "description": { + "type": "string", + "description": "Description of the service." + }, + "ports": { + "type": "array", + "items": { + "type": "integer" + } + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "io.pocketenv.service.defs.service": { + "type": "object", + "required": ["name", "command"], + "properties": { + "name": { + "type": "string", + "description": "Name of the service." + }, + "command": { + "type": "string", + "description": "Command to run the service." + }, + "description": { + "type": "string", + "description": "Description of the service." + }, + "ports": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "com.atproto.repo.strongRef": { + "type": "object", + "required": ["uri", "cid"], + "properties": { + "uri": { + "type": "string", + "format": "at-uri" + }, + "cid": { + "type": "string", + "format": "cid" + } + } + }, + "io.pocketenv.variable.defs.variableView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the environment variable." + }, + "name": { + "type": "string", + "description": "Name of the environment variable, e.g. 'NODE_ENV', 'PORT', etc." + }, + "value": { + "type": "string", + "description": "Value of the environment variable. This will be visible in API responses and should not contain sensitive information." + } + } + }, + "io.pocketenv.variable.defs.variable": { + "type": "object", + "required": ["name", "value"], + "properties": { + "sandboxId": { + "type": "string", + "description": "The ID of the sandbox to which the environment variable belongs. This is used to associate the variable with a specific sandbox environment." + }, + "name": { + "type": "string", + "description": "Name of the environment variable, e.g. 'NODE_ENV', 'PORT', etc." + }, + "value": { + "type": "string", + "description": "Value of the environment variable. This will be visible in API responses and should not contain sensitive information." + } + } + }, + "io.pocketenv.variable.defs.variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.variable.defs.envVar" + } + }, + "io.pocketenv.volume.defs.volumeView": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the volume." + }, + "name": { + "type": "string", + "description": "Name of the volume, e.g. 'data-volume', 'logs', etc." + }, + "path": { + "type": "string", + "description": "The path within the sandbox where the volume will be mounted, e.g. '/data', '/logs', etc." + }, + "readOnly": { + "type": "boolean", + "description": "Whether the volume should be mounted as read-only within the sandbox. Defaults to false (read-write)." + }, + "createdAt": { + "type": "string", + "description": "The timestamp when the volume was created.", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "description": "The timestamp when the volume was last updated.", + "format": "date-time" + } + } + }, + "io.pocketenv.volume.defs.volumes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/io.pocketenv.volume.defs.volume" + } + }, + "io.pocketenv.volume.defs.volume": { + "type": "object", + "required": ["name"], + "properties": { + "sandboxId": { + "type": "string", + "description": "The ID of the sandbox to which the volume belongs. This is used to associate the volume with a specific sandbox environment." + }, + "name": { + "type": "string", + "description": "Name of the volume, e.g. 'data-volume', 'logs', etc." + }, + "path": { + "type": "string", + "description": "The path within the sandbox where the volume will be mounted, e.g. '/data', '/logs', etc." + }, + "readOnly": { + "type": "boolean", + "description": "Whether the volume should be mounted as read-only within the sandbox. Defaults to false (read-write)." + } + } + } + }, + "securitySchemes": { + "Bearer": { + "type": "http", + "scheme": "bearer" + } + } + }, + "tags": [ + { + "name": "io.pocketenv.actor" + }, + { + "name": "app.bsky.actor" + }, + { + "name": "io.pocketenv.file" + }, + { + "name": "io.pocketenv.port" + }, + { + "name": "io.pocketenv.publicKey" + }, + { + "name": "io.pocketenv.sandbox" + }, + { + "name": "io.pocketenv.secret" + }, + { + "name": "io.pocketenv.service" + }, + { + "name": "com.atproto.repo" + }, + { + "name": "io.pocketenv.variable" + }, + { + "name": "io.pocketenv.volume" } - } -} \ No newline at end of file + ] +} diff --git a/api-reference/sandbox/claim.mdx b/api-reference/sandbox/claim.mdx new file mode 100644 index 0000000..83bc9ae --- /dev/null +++ b/api-reference/sandbox/claim.mdx @@ -0,0 +1,4 @@ +--- +title: 'Claim Sandbox' +openapi: 'POST /io.pocketenv.sandbox.claimSandbox' +--- diff --git a/api-reference/sandbox/create-backup.mdx b/api-reference/sandbox/create-backup.mdx new file mode 100644 index 0000000..c39c940 --- /dev/null +++ b/api-reference/sandbox/create-backup.mdx @@ -0,0 +1,4 @@ +--- +title: 'Create Backup' +openapi: 'POST /io.pocketenv.sandbox.createBackup' +--- diff --git a/api-reference/sandbox/create-integration.mdx b/api-reference/sandbox/create-integration.mdx new file mode 100644 index 0000000..18aa5a1 --- /dev/null +++ b/api-reference/sandbox/create-integration.mdx @@ -0,0 +1,4 @@ +--- +title: 'Create Integration' +openapi: 'POST /io.pocketenv.sandbox.createIntegration' +--- diff --git a/api-reference/sandbox/create.mdx b/api-reference/sandbox/create.mdx new file mode 100644 index 0000000..694cf60 --- /dev/null +++ b/api-reference/sandbox/create.mdx @@ -0,0 +1,4 @@ +--- +title: 'Create Sandbox' +openapi: 'POST /io.pocketenv.sandbox.createSandbox' +--- diff --git a/api-reference/sandbox/delete.mdx b/api-reference/sandbox/delete.mdx new file mode 100644 index 0000000..bbb090b --- /dev/null +++ b/api-reference/sandbox/delete.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete Sandbox' +openapi: 'POST /io.pocketenv.sandbox.deleteSandbox' +--- diff --git a/api-reference/sandbox/exec.mdx b/api-reference/sandbox/exec.mdx new file mode 100644 index 0000000..cb487f0 --- /dev/null +++ b/api-reference/sandbox/exec.mdx @@ -0,0 +1,4 @@ +--- +title: 'Execute Command' +openapi: 'POST /io.pocketenv.sandbox.exec' +--- diff --git a/api-reference/sandbox/expose-port.mdx b/api-reference/sandbox/expose-port.mdx new file mode 100644 index 0000000..d9c7949 --- /dev/null +++ b/api-reference/sandbox/expose-port.mdx @@ -0,0 +1,4 @@ +--- +title: 'Expose Port' +openapi: 'POST /io.pocketenv.sandbox.exposePort' +--- diff --git a/api-reference/sandbox/expose-vscode.mdx b/api-reference/sandbox/expose-vscode.mdx new file mode 100644 index 0000000..2fe8d05 --- /dev/null +++ b/api-reference/sandbox/expose-vscode.mdx @@ -0,0 +1,4 @@ +--- +title: 'Expose VS Code' +openapi: 'POST /io.pocketenv.sandbox.exposeVscode' +--- diff --git a/api-reference/sandbox/get-exposed-ports.mdx b/api-reference/sandbox/get-exposed-ports.mdx new file mode 100644 index 0000000..abf7e5f --- /dev/null +++ b/api-reference/sandbox/get-exposed-ports.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Exposed Ports' +openapi: 'GET /io.pocketenv.sandbox.getExposedPorts' +--- diff --git a/api-reference/sandbox/get-preferences.mdx b/api-reference/sandbox/get-preferences.mdx new file mode 100644 index 0000000..660d81a --- /dev/null +++ b/api-reference/sandbox/get-preferences.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Preferences' +openapi: 'GET /io.pocketenv.sandbox.getPreferences' +--- diff --git a/api-reference/sandbox/get-ssh-keys.mdx b/api-reference/sandbox/get-ssh-keys.mdx new file mode 100644 index 0000000..b3ca372 --- /dev/null +++ b/api-reference/sandbox/get-ssh-keys.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get SSH Keys' +openapi: 'GET /io.pocketenv.sandbox.getSshKeys' +--- diff --git a/api-reference/sandbox/get-tailscale-auth-key.mdx b/api-reference/sandbox/get-tailscale-auth-key.mdx new file mode 100644 index 0000000..35c21f0 --- /dev/null +++ b/api-reference/sandbox/get-tailscale-auth-key.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Tailscale Auth Key' +openapi: 'GET /io.pocketenv.sandbox.getTailscaleAuthKey' +--- diff --git a/api-reference/sandbox/get-tailscale-token.mdx b/api-reference/sandbox/get-tailscale-token.mdx new file mode 100644 index 0000000..6d4f2e1 --- /dev/null +++ b/api-reference/sandbox/get-tailscale-token.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Tailscale Token' +openapi: 'GET /io.pocketenv.sandbox.getTailscaleToken' +--- diff --git a/api-reference/sandbox/get.mdx b/api-reference/sandbox/get.mdx new file mode 100644 index 0000000..9e5e994 --- /dev/null +++ b/api-reference/sandbox/get.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Sandbox' +openapi: 'GET /io.pocketenv.sandbox.getSandbox' +--- diff --git a/api-reference/sandbox/list-backups.mdx b/api-reference/sandbox/list-backups.mdx new file mode 100644 index 0000000..2f5d9fb --- /dev/null +++ b/api-reference/sandbox/list-backups.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Backups' +openapi: 'GET /io.pocketenv.sandbox.getBackups' +--- diff --git a/api-reference/sandbox/list-integrations.mdx b/api-reference/sandbox/list-integrations.mdx new file mode 100644 index 0000000..cadbfd1 --- /dev/null +++ b/api-reference/sandbox/list-integrations.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Integrations' +openapi: 'GET /io.pocketenv.sandbox.getIntegrations' +--- diff --git a/api-reference/sandbox/list.mdx b/api-reference/sandbox/list.mdx new file mode 100644 index 0000000..d5e7c76 --- /dev/null +++ b/api-reference/sandbox/list.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Sandboxes' +openapi: 'GET /io.pocketenv.sandbox.getSandboxes' +--- diff --git a/api-reference/sandbox/pull-directory.mdx b/api-reference/sandbox/pull-directory.mdx new file mode 100644 index 0000000..c238373 --- /dev/null +++ b/api-reference/sandbox/pull-directory.mdx @@ -0,0 +1,4 @@ +--- +title: 'Pull Directory' +openapi: 'POST /io.pocketenv.sandbox.pullDirectory' +--- diff --git a/api-reference/sandbox/push-directory.mdx b/api-reference/sandbox/push-directory.mdx new file mode 100644 index 0000000..1f25da6 --- /dev/null +++ b/api-reference/sandbox/push-directory.mdx @@ -0,0 +1,4 @@ +--- +title: 'Push Directory' +openapi: 'POST /io.pocketenv.sandbox.pushDirectory' +--- diff --git a/api-reference/sandbox/put-preferences.mdx b/api-reference/sandbox/put-preferences.mdx new file mode 100644 index 0000000..aa72134 --- /dev/null +++ b/api-reference/sandbox/put-preferences.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Preferences' +openapi: 'POST /io.pocketenv.sandbox.putPreferences' +--- diff --git a/api-reference/sandbox/put-ssh-keys.mdx b/api-reference/sandbox/put-ssh-keys.mdx new file mode 100644 index 0000000..fc4da1b --- /dev/null +++ b/api-reference/sandbox/put-ssh-keys.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update SSH Keys' +openapi: 'POST /io.pocketenv.sandbox.putSshKeys' +--- diff --git a/api-reference/sandbox/put-tailscale-auth-key.mdx b/api-reference/sandbox/put-tailscale-auth-key.mdx new file mode 100644 index 0000000..0052d74 --- /dev/null +++ b/api-reference/sandbox/put-tailscale-auth-key.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Tailscale Auth Key' +openapi: 'POST /io.pocketenv.sandbox.putTailscaleAuthKey' +--- diff --git a/api-reference/sandbox/put-tailscale-token.mdx b/api-reference/sandbox/put-tailscale-token.mdx new file mode 100644 index 0000000..590b12b --- /dev/null +++ b/api-reference/sandbox/put-tailscale-token.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Tailscale Token' +openapi: 'POST /io.pocketenv.sandbox.putTailscaleToken' +--- diff --git a/api-reference/sandbox/restore-backup.mdx b/api-reference/sandbox/restore-backup.mdx new file mode 100644 index 0000000..a92d9d7 --- /dev/null +++ b/api-reference/sandbox/restore-backup.mdx @@ -0,0 +1,4 @@ +--- +title: 'Restore Backup' +openapi: 'POST /io.pocketenv.sandbox.restoreBackup' +--- diff --git a/api-reference/sandbox/start.mdx b/api-reference/sandbox/start.mdx new file mode 100644 index 0000000..4ed8c55 --- /dev/null +++ b/api-reference/sandbox/start.mdx @@ -0,0 +1,4 @@ +--- +title: 'Start Sandbox' +openapi: 'POST /io.pocketenv.sandbox.startSandbox' +--- diff --git a/api-reference/sandbox/stop.mdx b/api-reference/sandbox/stop.mdx new file mode 100644 index 0000000..791ab8c --- /dev/null +++ b/api-reference/sandbox/stop.mdx @@ -0,0 +1,4 @@ +--- +title: 'Stop Sandbox' +openapi: 'POST /io.pocketenv.sandbox.stopSandbox' +--- diff --git a/api-reference/sandbox/unexpose-port.mdx b/api-reference/sandbox/unexpose-port.mdx new file mode 100644 index 0000000..2eb595b --- /dev/null +++ b/api-reference/sandbox/unexpose-port.mdx @@ -0,0 +1,4 @@ +--- +title: 'Unexpose Port' +openapi: 'POST /io.pocketenv.sandbox.unexposePort' +--- diff --git a/api-reference/sandbox/update-settings.mdx b/api-reference/sandbox/update-settings.mdx new file mode 100644 index 0000000..3df4081 --- /dev/null +++ b/api-reference/sandbox/update-settings.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Settings' +openapi: 'POST /io.pocketenv.sandbox.updateSandboxSettings' +--- diff --git a/api-reference/secret/add.mdx b/api-reference/secret/add.mdx new file mode 100644 index 0000000..7d5388a --- /dev/null +++ b/api-reference/secret/add.mdx @@ -0,0 +1,4 @@ +--- +title: 'Add Secret' +openapi: 'POST /io.pocketenv.secret.addSecret' +--- diff --git a/api-reference/secret/delete.mdx b/api-reference/secret/delete.mdx new file mode 100644 index 0000000..76fd182 --- /dev/null +++ b/api-reference/secret/delete.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete Secret' +openapi: 'POST /io.pocketenv.secret.deleteSecret' +--- diff --git a/api-reference/secret/get.mdx b/api-reference/secret/get.mdx new file mode 100644 index 0000000..79a64cb --- /dev/null +++ b/api-reference/secret/get.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Secret' +openapi: 'GET /io.pocketenv.secret.getSecret' +--- diff --git a/api-reference/secret/list.mdx b/api-reference/secret/list.mdx new file mode 100644 index 0000000..9884f8d --- /dev/null +++ b/api-reference/secret/list.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Secrets' +openapi: 'GET /io.pocketenv.secret.getSecrets' +--- diff --git a/api-reference/secret/update.mdx b/api-reference/secret/update.mdx new file mode 100644 index 0000000..1023161 --- /dev/null +++ b/api-reference/secret/update.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Secret' +openapi: 'POST /io.pocketenv.secret.updateSecret' +--- diff --git a/api-reference/service/add.mdx b/api-reference/service/add.mdx new file mode 100644 index 0000000..bd5977f --- /dev/null +++ b/api-reference/service/add.mdx @@ -0,0 +1,4 @@ +--- +title: 'Add Service' +openapi: 'POST /io.pocketenv.service.addService' +--- diff --git a/api-reference/service/delete.mdx b/api-reference/service/delete.mdx new file mode 100644 index 0000000..bd30179 --- /dev/null +++ b/api-reference/service/delete.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete Service' +openapi: 'POST /io.pocketenv.service.deleteService' +--- diff --git a/api-reference/service/list.mdx b/api-reference/service/list.mdx new file mode 100644 index 0000000..746edb5 --- /dev/null +++ b/api-reference/service/list.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Services' +openapi: 'GET /io.pocketenv.service.getServices' +--- diff --git a/api-reference/service/restart.mdx b/api-reference/service/restart.mdx new file mode 100644 index 0000000..57dd0cc --- /dev/null +++ b/api-reference/service/restart.mdx @@ -0,0 +1,4 @@ +--- +title: 'Restart Service' +openapi: 'POST /io.pocketenv.service.restartService' +--- diff --git a/api-reference/service/start.mdx b/api-reference/service/start.mdx new file mode 100644 index 0000000..dbb23f5 --- /dev/null +++ b/api-reference/service/start.mdx @@ -0,0 +1,4 @@ +--- +title: 'Start Service' +openapi: 'POST /io.pocketenv.service.startService' +--- diff --git a/api-reference/service/stop.mdx b/api-reference/service/stop.mdx new file mode 100644 index 0000000..43a082e --- /dev/null +++ b/api-reference/service/stop.mdx @@ -0,0 +1,4 @@ +--- +title: 'Stop Service' +openapi: 'POST /io.pocketenv.service.stopService' +--- diff --git a/api-reference/service/update.mdx b/api-reference/service/update.mdx new file mode 100644 index 0000000..d80bada --- /dev/null +++ b/api-reference/service/update.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Service' +openapi: 'POST /io.pocketenv.service.updateService' +--- diff --git a/api-reference/variable/add.mdx b/api-reference/variable/add.mdx new file mode 100644 index 0000000..a80e5c3 --- /dev/null +++ b/api-reference/variable/add.mdx @@ -0,0 +1,4 @@ +--- +title: 'Add Variable' +openapi: 'POST /io.pocketenv.variable.addVariable' +--- diff --git a/api-reference/variable/delete.mdx b/api-reference/variable/delete.mdx new file mode 100644 index 0000000..ede0aab --- /dev/null +++ b/api-reference/variable/delete.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete Variable' +openapi: 'POST /io.pocketenv.variable.deleteVariable' +--- diff --git a/api-reference/variable/get.mdx b/api-reference/variable/get.mdx new file mode 100644 index 0000000..429674c --- /dev/null +++ b/api-reference/variable/get.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Variable' +openapi: 'GET /io.pocketenv.variable.getVariable' +--- diff --git a/api-reference/variable/list.mdx b/api-reference/variable/list.mdx new file mode 100644 index 0000000..21d8e14 --- /dev/null +++ b/api-reference/variable/list.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Variables' +openapi: 'GET /io.pocketenv.variable.getVariables' +--- diff --git a/api-reference/variable/update.mdx b/api-reference/variable/update.mdx new file mode 100644 index 0000000..39743b0 --- /dev/null +++ b/api-reference/variable/update.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Variable' +openapi: 'POST /io.pocketenv.variable.updateVariable' +--- diff --git a/api-reference/volume/add.mdx b/api-reference/volume/add.mdx new file mode 100644 index 0000000..821d285 --- /dev/null +++ b/api-reference/volume/add.mdx @@ -0,0 +1,4 @@ +--- +title: 'Add Volume' +openapi: 'POST /io.pocketenv.volume.addVolume' +--- diff --git a/api-reference/volume/delete.mdx b/api-reference/volume/delete.mdx new file mode 100644 index 0000000..2676315 --- /dev/null +++ b/api-reference/volume/delete.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete Volume' +openapi: 'POST /io.pocketenv.volume.deleteVolume' +--- diff --git a/api-reference/volume/get.mdx b/api-reference/volume/get.mdx new file mode 100644 index 0000000..d4ed65d --- /dev/null +++ b/api-reference/volume/get.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Volume' +openapi: 'GET /io.pocketenv.volume.getVolume' +--- diff --git a/api-reference/volume/list.mdx b/api-reference/volume/list.mdx new file mode 100644 index 0000000..bfd6a41 --- /dev/null +++ b/api-reference/volume/list.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Volumes' +openapi: 'GET /io.pocketenv.volume.getVolumes' +--- diff --git a/api-reference/volume/update.mdx b/api-reference/volume/update.mdx new file mode 100644 index 0000000..e276789 --- /dev/null +++ b/api-reference/volume/update.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Volume' +openapi: 'POST /io.pocketenv.volume.updateVolume' +--- diff --git a/development.mdx b/development.mdx index ac633ba..19af039 100644 --- a/development.mdx +++ b/development.mdx @@ -1,94 +1,44 @@ --- -title: 'Development' -description: 'Preview changes locally to update your docs' +title: "SDKs" +description: "Official client libraries for the Pocketenv API." --- - - **Prerequisites**: - - Node.js version 19 or higher - - A docs repository with a `docs.json` file - - -Follow these steps to install and run Mintlify on your operating system. - - - - -```bash -npm i -g mint -``` - - - - -Navigate to your docs directory where your `docs.json` file is located, and run the following command: - -```bash -mint dev -``` - -A local preview of your documentation will be available at `http://localhost:3000`. - - - - -## Custom ports - -By default, Mintlify uses port 3000. You can customize the port Mintlify runs on by using the `--port` flag. For example, to run Mintlify on port 3333, use this command: - -```bash -mint dev --port 3333 -``` - -If you attempt to run Mintlify on a port that's already in use, it will use the next available port: - -```md -Port 3000 is already in use. Trying 3001 instead. -``` - -## Mintlify versions - -Please note that each CLI release is associated with a specific version of Mintlify. If your local preview does not align with the production version, please update the CLI: - -```bash -npm mint update -``` - -## Validating links - -The CLI can assist with validating links in your documentation. To identify any broken links, use the following command: - -```bash -mint broken-links -``` - -## Deployment - -If the deployment is successful, you should see the following: - - - Screenshot of a deployment confirmation message that says All checks have passed. - - -## Code formatting - -We suggest using extensions on your IDE to recognize and format MDX. If you're a VSCode user, consider the [MDX VSCode extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) for syntax highlighting, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting. - -## Troubleshooting - - - - - This may be due to an outdated version of node. Try the following: - 1. Remove the currently-installed version of the CLI: `npm remove -g mint` - 2. Upgrade to Node v19 or higher. - 3. Reinstall the CLI: `npm i -g mint` - - - - - Solution: Go to the root of your device and delete the `~/.mintlify` folder. Then run `mint dev` again. - - - -Curious about what changed in the latest CLI version? Check out the [CLI changelog](https://www.npmjs.com/package/mintlify?activeTab=versions). +Pocketenv provides official SDKs for multiple languages. All SDKs wrap the same [XRPC API](/api-reference/introduction) and follow similar conventions. + + + + `@pocketenv/sdk` — tagged template literals, builder pattern, full sub-resource support. + + + `pocketenv` on hex.pm — type-safe, functional, pipe-friendly API. + + + `io.pocketenv/pocketenv` on Clojars — idiomatic Clojure with `->` chaining. + + + `pocketenv_ex` on hex.pm — pipe-friendly, OTP-ready, config via `config.exs`. + + + +## Authentication + +All SDKs resolve your token from the same sources, in priority order: + +1. Passed explicitly at the call site +2. `POCKETENV_TOKEN` environment variable +3. `~/.pocketenv/token.json` — written by `pocketenv login` + +## Common concepts + +Every SDK covers the same core resources: + +| Resource | Description | +|---|---| +| **Sandbox** | Create, start, stop, delete, exec | +| **Environment variables** | Plaintext key-value config | +| **Secrets** | Encrypted credentials (redacted in responses) | +| **Files** | Read/write files inside a sandbox | +| **Ports** | Expose sandbox ports to the internet | +| **Services** | Long-running processes | +| **Volumes** | Persistent storage | +| **Backups** | Point-in-time directory snapshots | diff --git a/docs.json b/docs.json index 46b44cc..7c8e365 100644 --- a/docs.json +++ b/docs.json @@ -1,91 +1,205 @@ { "$schema": "https://mintlify.com/docs.json", - "theme": "mint", - "name": "Mint Starter Kit", + "theme": "almond", + "name": "Pocketenv Documentation", "colors": { - "primary": "#16A34A", - "light": "#07C983", - "dark": "#15803D" + "primary": "#7033ff", + "light": "#7033ff", + "dark": "#7033ff" + }, + "favicon": "/logo/logo.png", + "api": { + "openapi": [ + "api-reference/openapi.json" + ] }, - "favicon": "/favicon.svg", "navigation": { "tabs": [ { "tab": "Guides", "groups": [ { - "group": "Getting started", + "group": "Getting Started", "pages": [ "index", - "quickstart", - "development" - ] - }, - { - "group": "Customization", - "pages": [ - "essentials/settings", - "essentials/navigation" + "quickstart" ] }, { - "group": "Writing content", + "group": "SDKs", "pages": [ - "essentials/markdown", - "essentials/code", - "essentials/images", - "essentials/reusable-snippets" + "development", + "sdks/javascript", + "sdks/gleam", + "sdks/clojure", + "sdks/elixir" ] }, { - "group": "AI tools", + "group": "Guides", "pages": [ - "ai-tools/cursor", - "ai-tools/claude-code", - "ai-tools/windsurf" + "guides/providers", + "guides/exec-and-console", + "guides/secrets-and-env", + "guides/ports-and-networking", + "guides/services", + "guides/backups" ] } ] }, { - "tab": "API reference", + "tab": "API Reference", "groups": [ { - "group": "API documentation", + "group": "Overview", "pages": [ "api-reference/introduction" ] }, { - "group": "Endpoint examples", + "group": "Actor", + "expanded": true, "pages": [ - "api-reference/endpoint/get", - "api-reference/endpoint/create", - "api-reference/endpoint/delete", - "api-reference/endpoint/webhook" + "api-reference/actor/get-profile", + "api-reference/actor/get-actor-sandboxes", + "api-reference/actor/get-terminal-token" ] + }, + { + "group": "Sandboxes", + "pages": [ + "api-reference/sandbox/list", + "api-reference/sandbox/get", + "api-reference/sandbox/create", + "api-reference/sandbox/start", + "api-reference/sandbox/stop", + "api-reference/sandbox/delete", + "api-reference/sandbox/claim", + "api-reference/sandbox/exec", + "api-reference/sandbox/update-settings" + ], + "expanded": true + }, + { + "group": "Networking", + "pages": [ + "api-reference/sandbox/expose-port", + "api-reference/sandbox/unexpose-port", + "api-reference/sandbox/get-exposed-ports", + "api-reference/sandbox/expose-vscode" + ], + "expanded": true + }, + { + "group": "Directories", + "pages": [ + "api-reference/sandbox/push-directory", + "api-reference/sandbox/pull-directory" + ], + "expanded": true + }, + { + "group": "Preferences", + "pages": [ + "api-reference/sandbox/get-preferences", + "api-reference/sandbox/put-preferences" + ], + "expanded": true + }, + { + "group": "SSH & Tailscale", + "pages": [ + "api-reference/sandbox/get-ssh-keys", + "api-reference/sandbox/put-ssh-keys", + "api-reference/sandbox/get-tailscale-auth-key", + "api-reference/sandbox/put-tailscale-auth-key", + "api-reference/sandbox/get-tailscale-token", + "api-reference/sandbox/put-tailscale-token" + ], + "expanded": true + }, + { + "group": "Backups", + "pages": [ + "api-reference/sandbox/list-backups", + "api-reference/sandbox/create-backup", + "api-reference/sandbox/restore-backup" + ], + "expanded": true + }, + { + "group": "Integrations", + "pages": [ + "api-reference/sandbox/list-integrations", + "api-reference/sandbox/create-integration" + ], + "expanded": true + }, + { + "group": "Files", + "pages": [ + "api-reference/file/list", + "api-reference/file/get", + "api-reference/file/add", + "api-reference/file/update", + "api-reference/file/delete" + ], + "expanded": true + }, + { + "group": "Secrets", + "pages": [ + "api-reference/secret/list", + "api-reference/secret/get", + "api-reference/secret/add", + "api-reference/secret/update", + "api-reference/secret/delete" + ], + "expanded": true + }, + { + "group": "Variables", + "pages": [ + "api-reference/variable/list", + "api-reference/variable/get", + "api-reference/variable/add", + "api-reference/variable/update", + "api-reference/variable/delete" + ], + "expanded": true + }, + { + "group": "Services", + "pages": [ + "api-reference/service/list", + "api-reference/service/add", + "api-reference/service/start", + "api-reference/service/stop", + "api-reference/service/restart", + "api-reference/service/update", + "api-reference/service/delete" + ], + "expanded": true + }, + { + "group": "Volumes", + "pages": [ + "api-reference/volume/list", + "api-reference/volume/get", + "api-reference/volume/add", + "api-reference/volume/update", + "api-reference/volume/delete" + ], + "expanded": true } ] } - ], - "global": { - "anchors": [ - { - "anchor": "Documentation", - "href": "https://mintlify.com/docs", - "icon": "book-open-cover" - }, - { - "anchor": "Blog", - "href": "https://mintlify.com/blog", - "icon": "newspaper" - } - ] - } + ] }, "logo": { - "light": "/logo/light.svg", - "dark": "/logo/dark.svg" + "light": "/logo/logo.png", + "dark": "/logo/logo.png" }, "navbar": { "links": [ @@ -97,26 +211,25 @@ "primary": { "type": "button", "label": "Dashboard", - "href": "https://dashboard.mintlify.com" + "href": "https://pocketenv.io" } }, "contextual": { "options": [ - "copy", - "view", - "chatgpt", - "claude", - "perplexity", - "mcp", - "cursor", - "vscode" - ] + "copy", + "view", + "chatgpt", + "claude", + "perplexity", + "mcp", + "cursor", + "vscode" + ] }, "footer": { "socials": { - "x": "https://x.com/mintlify", - "github": "https://github.com/mintlify", - "linkedin": "https://linkedin.com/company/mintlify" + "github": "https://github.com/pocketenv-io", + "bluesky": "https://bsky.app/profile/pocketenv.io" } } -} +} \ No newline at end of file diff --git a/favicon.png b/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..bd1661a4521f3871c24c33400f7523c63e5d09f2 GIT binary patch literal 2919 zcmeAS@N?(olHy`uVBq!ia0y~yVEh8Y9Bd2>45zQ%?_ywJU@Q)DcVfJGQm3AQfq^C6 z(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF=T}3=JO>_%)p?h48n{ROYO@T7#P?~Jbhi+Uoi==aS6q6 z7N2Hd;9BkJ;uunK>+M}bKj}b$hKDyciSKmQe9<#y_mZbYuOWoSe7M<{tw?(Cl3-3<@t88Wu1!H1RQTSb-3N z4-ta!5lR$Z&`t};74)|i&2M^)G!KU9rp27MKJBW1^|dto?%Hm4fg4L^>-Xz5PvEw0 zSa8|lM60aB1x=BnMD~u8?T?PwoSo0wu%LVA3T6(gB)wM*8!Ox84xIj4yMBH28?%Q^ zujX1cEa0y6@4l;crA6lz!}RC&(>!H9WnBJwe1HE6<{1}S|FB$sYxQP-_!UOIiU7%!B&0`^%?I6+F=X_r=aO|1^VmGf~=GgU8 z2Bg46mch~e3M0$h{K7kWuNa#8R)7>JzhY?OTg0dEBIe%1XO34G1xj3G9WFS6)Fp=4 zmx-4`G|2|<0(qjts$s$Ntv7OgUV^lAfW>+ROBo#PXK(Dg8$IWetE|I?(?X>Tj>`{B z0bAl33o^=i~#Bf(|`vV$p*H$g^1bR(=nlSWwODhsxe5vp6f zG*G-0Y&n!-N0LSsN0kOS3hFi}B@0#zaTL^YC3S-^bao!1>vVZcBw16Kq~hO|H9oH!48kMS%S)wPJ@0 zij`N6$_SKr$dwwhv&e3`FVcJD&hKJ@5{}1Df5n|)WRW!#FLt=#cxH0Z9lj>MB)w-1 z3z}zu^V_p!#SRw)i$U6s#GGMtWCyDhEQV3+EV2VC?tbPd$XV`Zj>AmRKIYapg$LDZFXY1JO==i}YTAR9GI0Ym|=`E;e*Ov+*9+hvaP6 zqSGtslo9lg`6HfPn+#pS}gc!STZJ$rEGImZjRGnN$_eqX@Z?Eey+yp|OUl+0en z>2ZdUCHBnzU&lo4^Tdn!XBjLJ>$}SeNsJpayDUMeu=)ZE%iU#~&lotYlHNHA3zP^H zGdP;FDn4Uq>YKr=@S+2(ikZWz+2W2(hvk9#tcT@`xUG`TE%^7RrbG~wC>U7w8cO!v zJ$h#fUvl=t9kCY#iy0h`PtkieT^0>z76WDWZhFP)w4embEdu+IEf z$!@VCr*&s{KcAY<=A`$+?A*pfdQYw`-JtxWDetk&$>ZhA*Z)>mRFApRDyt}7BK@4x zu>D2ga - - - - diff --git a/guides/backups.mdx b/guides/backups.mdx new file mode 100644 index 0000000..a3980c0 --- /dev/null +++ b/guides/backups.mdx @@ -0,0 +1,97 @@ +--- +title: "Backups" +description: "Create point-in-time snapshots of sandbox directories and restore from them." +--- + +Backups capture the state of a directory inside your sandbox at a specific moment. Use them before risky operations, deployments, or as part of a CI pipeline. + +## Create a backup + +```bash +pocketenv backup create my-sandbox /app \ + --description "before-deploy" \ + --ttl 7d +``` + +Arguments: +- `` — target sandbox +- `` — absolute path to the directory to back up + +Options: +- `--description, -d` — optional label for the backup +- `--ttl, -t` — how long to keep the backup (e.g. `10m`, `2h`, `7d`). Default: `3d` + +### SDK + +```typescript +const backup = await sandbox.createBackup("/app", { + description: "before-deploy", + ttl: "7d", +}); +console.log(backup.id); // bkp_01jqwerty123456789 +``` + +## List backups + +```bash +pocketenv backup list my-sandbox +pocketenv backup ls my-sandbox # alias +``` + +Output includes backup ID, directory, description, and expiry time. + +### SDK + +```typescript +const backups = await sandbox.listBackups(); +// [{ id: "bkp_...", directory: "/app", description: "before-deploy", expiresAt: ..., createdAt: "..." }] +``` + +## Restore a backup + +```bash +pocketenv backup restore bkp_01jqwerty123456789 +``` + +This replaces the backed-up directory with the snapshot content. + + + Restoring overwrites the current state of the directory. Make sure to back up first if you want to preserve current changes. + + +### SDK + +```typescript +await Sandbox.restoreBackup("bkp_01jqwerty123456789"); +``` + +## TTL reference + +| Value | Duration | +|---|---| +| `10m` | 10 minutes | +| `2h` | 2 hours | +| `1d` | 1 day | +| `7d` | 7 days (max recommended) | + +Backups expire automatically after their TTL — they are not permanent storage. + +## Example: pre-deployment workflow + +```bash +# Back up before deploying +pocketenv backup create prod /app --description "pre-v2.0" --ttl 48h + +# Deploy +pocketenv exec prod "npm run deploy" + +# If something went wrong +pocketenv backup list prod +pocketenv backup restore bkp_01jqwerty123456789 +``` + +## API + +- [List Backups](/api-reference/sandbox/list-backups) +- [Create Backup](/api-reference/sandbox/create-backup) +- [Restore Backup](/api-reference/sandbox/restore-backup) diff --git a/guides/exec-and-console.mdx b/guides/exec-and-console.mdx new file mode 100644 index 0000000..90d6447 --- /dev/null +++ b/guides/exec-and-console.mdx @@ -0,0 +1,105 @@ +--- +title: "Running Commands" +description: "Execute commands inside a sandbox or drop into an interactive shell." +--- + +## Interactive console + +Open an SSH session directly inside a running sandbox: + +```bash +pocketenv console my-sandbox +``` + +Aliases: `shell`, `ssh`, `s` + +```bash +pocketenv shell my-sandbox +pocketenv s my-sandbox +``` + +The console auto-reconnects if the connection drops. Press `Ctrl+D` or type `exit` to close. + + + The sandbox must be running before you can open a console. Use `pocketenv start my-sandbox` first if it's stopped. + + +## Execute a single command + +Run a command non-interactively and get the output back: + +```bash +pocketenv exec my-sandbox "node --version" +# v22.4.0 + +pocketenv exec my-sandbox "ls /app" +``` + +Multi-word commands need quotes: + +```bash +pocketenv exec my-sandbox "npm install && npm run build" +``` + +## Copy files + +Transfer files between your local machine and a sandbox using `pocketenv copy` (alias: `cp`): + +```bash +# Local → sandbox +pocketenv cp ./local-file.txt my-sandbox:/remote/path/file.txt + +# Sandbox → local +pocketenv cp my-sandbox:/remote/path/file.txt ./local-file.txt + +# Directory (sandbox → local) +pocketenv cp my-sandbox:/app/dist ./dist-copy +``` + +## Clone a repository on start + +Pass `--repo` when starting a sandbox to automatically clone a git repository: + +```bash +pocketenv start my-sandbox --repo github:myorg/myapp +pocketenv start my-sandbox --repo tangled:myorg/myapp +pocketenv start my-sandbox --repo https://github.com/myorg/myapp.git +``` + +You can also do it at creation time: + +```bash +pocketenv create my-sandbox --repo github:myorg/myapp --ssh +``` + +The `--ssh` flag opens a console immediately after the sandbox starts. + +## Keep-alive + +By default, idle sandboxes stop automatically after a period of inactivity. Use `--keep-alive` to prevent that: + +```bash +pocketenv start my-sandbox --keep-alive +``` + + + Keep-alive sandboxes accrue compute costs continuously. Remember to stop them manually when done. + + +## SDK + +```typescript +import { Sandbox } from "@pocketenv/sdk"; + +const sandbox = await Sandbox.create({ name: "my-sandbox", base: "openclaw" }); + +// Tagged template literal (interpolation is safe) +const dir = "/app"; +const result = await sandbox.sh`ls -la ${dir}`; +console.log(result.stdout); +console.log(result.stderr); +console.log(result.exitCode); + +// Raw exec +await sandbox.exec("npm install"); +``` diff --git a/guides/ports-and-networking.mdx b/guides/ports-and-networking.mdx new file mode 100644 index 0000000..6957b86 --- /dev/null +++ b/guides/ports-and-networking.mdx @@ -0,0 +1,109 @@ +--- +title: "Ports & Networking" +description: "Make sandbox services publicly accessible and open VS Code in the browser." +--- + +## Expose a port + +When a process is listening on a port inside your sandbox, use `expose` to make it reachable from the internet: + +```bash +pocketenv expose my-sandbox 3000 "Web server" +# https://abc123.sbx.pocketenv.io +``` + +The command returns a **preview URL** you can open in a browser or share with others. + +```bash +# Expose without a description +pocketenv expose my-sandbox 8080 +``` + +Valid port range: `1025–65535`. + +### SDK + +```typescript +const exposed = await sandbox.expose(3000, "Web server"); +console.log(exposed.previewUrl); // https://abc123.sbx.pocketenv.io + +// Expose multiple ports +await sandbox.expose(8080, "Admin UI"); +await sandbox.expose(5432); // no description +``` + +## Unexpose a port + +Remove public access to a port: + +```bash +pocketenv unexpose my-sandbox 3000 +``` + +### SDK + +```typescript +await sandbox.unexpose(3000); +``` + +## List exposed ports + +```bash +pocketenv ports list my-sandbox +``` + +### SDK + +```typescript +const ports = await sandbox.ports.list(); +// [{ port: 3000, description: "Web server", previewUrl: "https://..." }] +``` + +## VS Code in the browser + +Expose a browser-based VS Code server running inside your sandbox: + +```bash +pocketenv vscode my-sandbox +# https://abc123-vscode.sbx.pocketenv.io +``` + +Aliases: `code`, `code-server` + +```bash +pocketenv code my-sandbox +pocketenv code-server my-sandbox +``` + +### SDK + +```typescript +const vscode = await sandbox.exposeVscode(); +console.log(vscode.previewUrl); +``` + +## Tailscale (mesh networking) + +For private networking between sandboxes, Pocketenv supports Tailscale: + +```bash +# Store a Tailscale auth key (prompted for the value) +pocketenv tailscale put my-sandbox + +# Retrieve the stored key (redacted) +pocketenv tailscale get my-sandbox +``` + +### SDK + +```typescript +await sandbox.putTailscaleAuthKey("tskey-auth-..."); +const key = await sandbox.getTailscaleAuthKey(); +``` + +## API + +- [Expose Port](/api-reference/sandbox/expose-port) +- [Unexpose Port](/api-reference/sandbox/unexpose-port) +- [Get Exposed Ports](/api-reference/sandbox/get-exposed-ports) +- [Expose VS Code](/api-reference/sandbox/expose-vscode) diff --git a/guides/providers.mdx b/guides/providers.mdx new file mode 100644 index 0000000..25e356c --- /dev/null +++ b/guides/providers.mdx @@ -0,0 +1,173 @@ +--- +title: "Providers" +description: "Pocketenv supports 10 backend providers. Switch between them without changing your code." +--- + +Pocketenv abstracts over different compute backends. A sandbox definition is a portable AT Protocol record — you choose which provider actually runs it. + +## Default provider + +The default is **Cloudflare**. No API key needed when using the managed Pocketenv platform. + +```bash +pocketenv create my-sandbox # uses cloudflare by default +pocketenv create my-sandbox --provider cloudflare +``` + +## Specifying a provider + +```bash +pocketenv create my-sandbox --provider +``` + +Via SDK: + +```typescript +const sandbox = await Sandbox.create({ provider: "daytona", base: "openclaw" }); +``` + +## Supported providers + + + + Lightweight sandboxes powered by Cloudflare Workers. No credentials needed on the managed platform. + + ```bash + pocketenv create my-sandbox --provider cloudflare + ``` + + + + Full-featured development environments via [Daytona](https://daytona.io). + + ```bash + pocketenv create my-sandbox --provider daytona + ``` + + Required credentials — store them as sandbox preferences: + + | Field | Description | + |---|---| + | `DAYTONA_API_KEY` | Your Daytona API key | + | `DAYTONA_ORGANIZATION_ID` | Optional organization ID | + + + + Serverless sandboxes on [Vercel](https://vercel.com/docs/functions/runtimes/sandbox). + + ```bash + pocketenv create my-sandbox --provider vercel + ``` + + | Field | Description | + |---|---| + | `VERCEL_API_TOKEN` | Your Vercel API token | + | `VERCEL_PROJECT_ID` | Target Vercel project | + | `VERCEL_TEAM_ID` | Optional team ID | + + + + Secure sandboxes optimized for AI agents via [E2B](https://e2b.dev). + + ```bash + pocketenv create my-sandbox --provider e2b + ``` + + | Field | Description | + |---|---| + | `E2B_API_KEY` | Your E2B API key | + + + + Serverless GPU/CPU compute via [Modal](https://modal.com). + + ```bash + pocketenv create my-sandbox --provider modal + ``` + + | Field | Description | + |---|---| + | `MODAL_TOKEN_ID` | Modal token ID | + | `MODAL_TOKEN_SECRET` | Modal token secret | + + + + Infrastructure-grade sandboxes via [Runloop](https://runloop.ai). + + ```bash + pocketenv create my-sandbox --provider runloop + ``` + + | Field | Description | + |---|---| + | `RUNLOOP_API_KEY` | Your Runloop API key | + + + + AI-native compute via [HopX](https://hopx.ai). + + ```bash + pocketenv create my-sandbox --provider hopx + ``` + + | Field | Description | + |---|---| + | `HOPX_API_KEY` | Your HopX API key | + + + + Deno-based sandboxes via [Deno Deploy](https://deno.com/deploy). + + ```bash + pocketenv create my-sandbox --provider deno + ``` + + | Field | Description | + |---|---| + | `DENO_DEPLOY_TOKEN` | Your Deno Deploy token | + + + + Fast micro-VMs via [Fly.io Sprites](https://fly.io/blog/fly-sprites). + + ```bash + pocketenv create my-sandbox --provider sprites + ``` + + | Field | Description | + |---|---| + | `SPRITE_TOKEN` | Your Sprites token | + + + + Pocketenv-native provider via [Blaxel](https://blaxel.ai). + + ```bash + pocketenv create my-sandbox --provider blaxel + ``` + + | Field | Description | + |---|---| + | `BLAXEL_WORKSPACE` | Your Blaxel workspace | + | `BLAXEL_API_KEY` | Your Blaxel API key | + + + +## Base images + +The `--base` flag sets the starting template for your sandbox. Bases are AT Protocol URIs but you can use short names: + +| Base | Description | +|---|---| +| `openclaw` | General-purpose Linux dev environment (default) | +| `zeroclaw` | Minimal base image | +| `picoclaw` | Ultra-lightweight | +| `nix` | Nix-based environment | +| `claude-code` | Optimized for Claude Code | +| `codex` | Optimized for Codex | +| `opencrust` | Rust development | + +```bash +pocketenv create my-sandbox --base openclaw +pocketenv create my-sandbox --base nix +``` diff --git a/guides/secrets-and-env.mdx b/guides/secrets-and-env.mdx new file mode 100644 index 0000000..3c0323d --- /dev/null +++ b/guides/secrets-and-env.mdx @@ -0,0 +1,95 @@ +--- +title: "Secrets & Environment Variables" +description: "Store configuration and credentials for your sandboxes." +--- + +Pocketenv has two ways to pass configuration into a sandbox: + +| | Environment Variables | Secrets | +|---|---|---| +| **Stored as** | Plaintext | Encrypted (libsodium) | +| **Visible in API** | Yes | Redacted | +| **Use for** | Non-sensitive config | Passwords, tokens, keys | + +## Environment variables + +### CLI + +```bash +# Set a variable +pocketenv env put my-sandbox DATABASE_URL "postgres://localhost/mydb" +pocketenv env put my-sandbox NODE_ENV "production" + +# List all variables +pocketenv env list my-sandbox +pocketenv env ls my-sandbox # alias + +# Delete a variable +pocketenv env delete +pocketenv env rm # alias +``` + +### SDK + +```typescript +await sandbox.env.put("DATABASE_URL", "postgres://localhost/mydb"); +await sandbox.env.put("NODE_ENV", "production"); + +const vars = await sandbox.env.list(); +// [{ id: "...", name: "DATABASE_URL", value: "postgres://..." }, ...] + +await sandbox.env.delete(varId); +``` + +## Secrets + +Secrets are encrypted at rest using libsodium. The value is never returned in API responses — only a redacted placeholder is shown. + +### CLI + +```bash +# Set a secret (you'll be prompted for the value) +pocketenv secret put my-sandbox API_KEY + +# List secret names (values are never shown) +pocketenv secret list my-sandbox +pocketenv secret ls my-sandbox # alias + +# Delete +pocketenv secret delete +pocketenv secret rm # alias +``` + +### SDK + +```typescript +await sandbox.secret.put("API_KEY", process.env.API_KEY!); +await sandbox.secret.put("STRIPE_SECRET", "sk_live_..."); + +const secrets = await sandbox.secret.list(); +// [{ id: "...", name: "API_KEY" }] ← value is never returned + +await sandbox.secret.delete(secretId); +``` + +## Setting variables at sandbox creation + +You can bake env vars and secrets into a sandbox at creation time via the SDK builder: + +```typescript +const sandbox = await Sandbox.builder("openclaw") + .name("my-app") + .env("NODE_ENV", "production") + .env("PORT", "3000") + .secret("DATABASE_URL", process.env.DATABASE_URL!) + .secret("API_KEY", process.env.API_KEY!) + .create(); +``` + +## API + +For direct API usage see: +- [Add Variable](/api-reference/variable/add) +- [List Variables](/api-reference/variable/list) +- [Add Secret](/api-reference/secret/add) +- [List Secrets](/api-reference/secret/list) diff --git a/guides/services.mdx b/guides/services.mdx new file mode 100644 index 0000000..5c092c7 --- /dev/null +++ b/guides/services.mdx @@ -0,0 +1,105 @@ +--- +title: "Services" +description: "Define and manage long-running processes inside your sandbox." +--- + +Services are named, persistent processes running inside a sandbox — think web servers, background workers, databases, or any daemon you want to manage independently. + +## Create a service + +```bash +pocketenv service create my-sandbox api "npm start" \ + --description "Node.js API server" \ + --ports 3000 8080 +``` + +Arguments: +- `` — target sandbox name or ID +- `` — service name +- `` — command to run + +Options: +- `--description, -d` — human-readable description +- `--ports, -p` — ports the service listens on (space-separated) + +### SDK + +```typescript +const service = await sandbox.service.add("api", { + command: "npm start", + description: "Node.js API server", + ports: [3000, 8080], +}); +console.log(service.id); +``` + +## List services + +```bash +pocketenv service list my-sandbox +pocketenv service ls my-sandbox # alias +``` + +### SDK + +```typescript +const services = await sandbox.service.list(); +// [{ id: "...", name: "api", command: "npm start", ... }] +``` + +## Lifecycle + +```bash +pocketenv service start # Start a stopped service +pocketenv service stop # Stop a running service +pocketenv service restart # Restart +pocketenv service delete # Remove permanently +``` + +### SDK + +```typescript +await sandbox.service.start(serviceId); +await sandbox.service.stop(serviceId); +await sandbox.service.restart(serviceId); +await sandbox.service.delete(serviceId); +``` + +## Update a service + +```bash +# Update via API (see API reference) +``` + +### SDK + +```typescript +await sandbox.service.update(serviceId, { + command: "node dist/index.js", + description: "Updated API server", + ports: [3000], +}); +``` + +## Example: full workflow + +```bash +# Create sandbox and a web service +pocketenv create web-app --base openclaw +pocketenv env put web-app PORT 3000 +pocketenv service create web-app server "node app.js" --ports 3000 + +# Start everything +pocketenv start web-app +pocketenv service start +pocketenv expose web-app 3000 "App" +``` + +## API + +- [List Services](/api-reference/service/list) +- [Add Service](/api-reference/service/add) +- [Start Service](/api-reference/service/start) +- [Stop Service](/api-reference/service/stop) +- [Restart Service](/api-reference/service/restart) +- [Delete Service](/api-reference/service/delete) diff --git a/index.mdx b/index.mdx index 15c23fb..af5f46b 100644 --- a/index.mdx +++ b/index.mdx @@ -1,97 +1,69 @@ --- -title: "Introduction" -description: "Welcome to the new home for your documentation" +title: "Pocketenv" +description: "Open-source, multi-provider sandbox platform for running code safely in isolated environments." --- -## Setting up +Pocketenv lets you create and manage sandboxes — isolated compute environments — across multiple backend providers, all from a single CLI or SDK. Run AI agents, untrusted code, and experiments without touching your local machine. -Get your documentation site up and running in minutes. - - - Follow our three step quickstart guide. - - -## Make it yours - -Design a docs site that looks great and empowers your users. - - - - Edit your docs locally and preview them in real time. + + + Install the CLI and spin up your first sandbox in minutes. - - Customize the design and colors of your site to match your brand. + + Integrate Pocketenv into your TypeScript or JavaScript app. - - Organize your docs to help users find what they need and succeed with your product. + + Choose from 10 supported backend providers. - - Auto-generate API documentation from OpenAPI specifications. + + Full XRPC API documentation with interactive playground. - - -## Create beautiful pages + -Everything you need to create world-class documentation. +## What you can do - - - Use MDX to style your docs pages. + + + Execute shell commands or drop into an interactive console. + + + Make services publicly accessible with a preview URL. - - Add sample code to demonstrate how to use your product. + + Store encrypted secrets and plaintext environment variables. - - Display images and other media. + + Define and manage long-running processes inside your sandbox. - - Write once and reuse across your docs. + + Create point-in-time snapshots and restore from them. - + + Attach volumes for data that survives sandbox restarts. + + + +## How it works + +Pocketenv uses the **AT Protocol** to define sandboxes as portable, versioned records — meaning a sandbox definition is not locked to any one provider. You can move between Cloudflare, Daytona, Vercel, E2B, Modal, and more without changing your code. + +```bash +# Create a sandbox on any provider +pocketenv create my-app --provider daytona --base openclaw + +# Run a command +pocketenv exec my-app "npm install && npm start" + +# Open an interactive shell +pocketenv console my-app +``` -## Need inspiration? +```typescript +// Or use the SDK +import { Sandbox } from "@pocketenv/sdk"; - - Browse our showcase of exceptional documentation sites. - +const sandbox = await Sandbox.create({ name: "my-app", base: "openclaw" }); +const result = await sandbox.sh`npm test`; +console.log(result.stdout); +await sandbox.stop(); +``` diff --git a/logo/logo.png b/logo/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bd1661a4521f3871c24c33400f7523c63e5d09f2 GIT binary patch literal 2919 zcmeAS@N?(olHy`uVBq!ia0y~yVEh8Y9Bd2>45zQ%?_ywJU@Q)DcVfJGQm3AQfq^C6 z(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF=T}3=JO>_%)p?h48n{ROYO@T7#P?~Jbhi+Uoi==aS6q6 z7N2Hd;9BkJ;uunK>+M}bKj}b$hKDyciSKmQe9<#y_mZbYuOWoSe7M<{tw?(Cl3-3<@t88Wu1!H1RQTSb-3N z4-ta!5lR$Z&`t};74)|i&2M^)G!KU9rp27MKJBW1^|dto?%Hm4fg4L^>-Xz5PvEw0 zSa8|lM60aB1x=BnMD~u8?T?PwoSo0wu%LVA3T6(gB)wM*8!Ox84xIj4yMBH28?%Q^ zujX1cEa0y6@4l;crA6lz!}RC&(>!H9WnBJwe1HE6<{1}S|FB$sYxQP-_!UOIiU7%!B&0`^%?I6+F=X_r=aO|1^VmGf~=GgU8 z2Bg46mch~e3M0$h{K7kWuNa#8R)7>JzhY?OTg0dEBIe%1XO34G1xj3G9WFS6)Fp=4 zmx-4`G|2|<0(qjts$s$Ntv7OgUV^lAfW>+ROBo#PXK(Dg8$IWetE|I?(?X>Tj>`{B z0bAl33o^=i~#Bf(|`vV$p*H$g^1bR(=nlSWwODhsxe5vp6f zG*G-0Y&n!-N0LSsN0kOS3hFi}B@0#zaTL^YC3S-^bao!1>vVZcBw16Kq~hO|H9oH!48kMS%S)wPJ@0 zij`N6$_SKr$dwwhv&e3`FVcJD&hKJ@5{}1Df5n|)WRW!#FLt=#cxH0Z9lj>MB)w-1 z3z}zu^V_p!#SRw)i$U6s#GGMtWCyDhEQV3+EV2VC?tbPd$XV`Zj>AmRKIYapg$LDZFXY1JO==i}YTAR9GI0Ym|=`E;e*Ov+*9+hvaP6 zqSGtslo9lg`6HfPn+#pS}gc!STZJ$rEGImZjRGnN$_eqX@Z?Eey+yp|OUl+0en z>2ZdUCHBnzU&lo4^Tdn!XBjLJ>$}SeNsJpayDUMeu=)ZE%iU#~&lotYlHNHA3zP^H zGdP;FDn4Uq>YKr=@S+2(ikZWz+2W2(hvk9#tcT@`xUG`TE%^7RrbG~wC>U7w8cO!v zJ$h#fUvl=t9kCY#iy0h`PtkieT^0>z76WDWZhFP)w4embEdu+IEf z$!@VCr*&s{KcAY<=A`$+?A*pfdQYw`-JtxWDetk&$>ZhA*Z)>mRFApRDyt}7BK@4x zu>D2ga - - During the onboarding process, you created a GitHub repository with your docs content if you didn't already have one. You can find a link to this repository in your [dashboard](https://dashboard.mintlify.com). - - To clone the repository locally so that you can make and preview changes to your docs, follow the [Cloning a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) guide in the GitHub docs. - - - 1. Install the Mintlify CLI: `npm i -g mint` - 2. Navigate to your docs directory and run: `mint dev` - 3. Open `http://localhost:3000` to see your docs live! - - Your preview updates automatically as you edit files. - - - -### Step 2: Deploy your changes - - - - Install the Mintlify GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app). - - Our GitHub app automatically deploys your changes to your docs site, so you don't need to manage deployments yourself. - - - For a first change, let's update the name and colors of your docs site. - - 1. Open `docs.json` in your editor. - 2. Change the `"name"` field to your project name. - 3. Update the `"colors"` to match your brand. - 4. Save and see your changes instantly at `http://localhost:3000`. - - Try changing the primary color to see an immediate difference! - - - -### Step 3: Go live - - - 1. Commit and push your changes. - 2. Your docs will update and be live in moments! - +## Install the CLI + + + + ```bash + npm install -g @pocketenv/cli + ``` + + + ```bash + brew install pocketenv-io/tap/pocketenv + ``` + + + ```bash + curl -fsSL https://cli.pocketenv.io | bash + ``` + + + ```bash + pnpm add -g @pocketenv/cli + ``` + + + ```bash + nix profile install github:pocketenv-io/pocketenv + ``` + + + +Verify the installation: + +```bash +pocketenv --version +``` + +## Log in + +Pocketenv uses your AT Protocol handle (e.g. a Bluesky account) for authentication. + +```bash +pocketenv login alice.bsky.social +``` + +This opens a browser window to complete the OAuth flow. Once done, your session token is saved to `~/.pocketenv/token.json`. -## Next steps + + For CI/CD environments, skip the browser flow by setting the `POCKETENV_TOKEN` environment variable instead. + -Now that you have your docs running, explore these key features: +## Create a sandbox - +```bash +pocketenv create my-first-sandbox +``` - - Learn MDX syntax and start writing your documentation. - +By default this uses the `cloudflare` provider and the `openclaw` base image — a minimal Linux environment with common dev tools pre-installed. - - Make your docs match your brand perfectly. - +Specify a different provider or base: - - Include syntax-highlighted code blocks. - +```bash +pocketenv create my-sandbox --provider daytona --base openclaw +``` - - Auto-generate API docs from OpenAPI specs. - +## Run a command - +```bash +pocketenv exec my-first-sandbox "echo hello from the sandbox" +# hello from the sandbox +``` - - **Need help?** See our [full documentation](https://mintlify.com/docs) or join our [community](https://mintlify.com/community). - +## Open an interactive shell + +```bash +pocketenv console my-first-sandbox +``` + +This drops you into a live SSH session inside the sandbox. Type `exit` to return to your local terminal. + +## Start, stop, and delete + +```bash +pocketenv stop my-first-sandbox # Stop the sandbox (keeps state) +pocketenv start my-first-sandbox # Resume it later +pocketenv rm my-first-sandbox # Delete permanently +``` + +## Next steps + + + + Configure Daytona, Vercel, E2B, Modal, and more. + + + Make your sandbox services accessible from the internet. + + + Store credentials and configuration securely. + + + Use Pocketenv programmatically from TypeScript/JavaScript. + + diff --git a/sdks/clojure.mdx b/sdks/clojure.mdx new file mode 100644 index 0000000..5dd5073 --- /dev/null +++ b/sdks/clojure.mdx @@ -0,0 +1,127 @@ +--- +title: "Clojure" +description: "Official Clojure SDK for Pocketenv — idiomatic, chainable with `->`." +--- + + + **GitHub:** [pocketenv-io/pocketenv-clojure](https://github.com/pocketenv-io/pocketenv-clojure) · **Clojars:** [io.pocketenv/pocketenv](https://clojars.org/io.pocketenv/pocketenv) + + +## Installation + +Add to `deps.edn`: + +```clojure +{:deps {io.pocketenv/pocketenv {:mvn/version "0.1.4"}}} +``` + +## Authentication + +| Method | Details | +|---|---| +| Env var | `POCKETENV_TOKEN=` | +| Token file | `~/.pocketenv/token.json` → `{"token": "..."}` | +| Per-call | Pass `:token "..."` in the opts map | + +All functions return `{:ok value}` on success or `{:error reason}` on failure. Sandbox operations also accept `{:ok sandbox}` tuples directly so you can chain with `->` without unwrapping. + +## Quick start + +```clojure +(require '[pocketenv-io.pocketenv :as pocketenv] + '[pocketenv-io.sandbox :as sandbox]) + +(-> (pocketenv/create-sandbox "my-box") + (sandbox/start) + (sandbox/wait-until-running) + (sandbox/exec "echo" ["hello from pocketenv"])) +;; => {:ok #ExecResult{:stdout "hello from pocketenv\n" :stderr "" :exit-code 0}} +``` + +## Sandbox lifecycle + +```clojure +;; Create (defaults: openclaw base, cloudflare provider) +(pocketenv/create-sandbox "my-box") + +;; With options +(pocketenv/create-sandbox "my-box" + {:provider "daytona" + :repo "https://github.com/acme/my-app" + :keep-alive true}) + +;; Fetch existing +(pocketenv/get-sandbox "my-box") + +;; List all sandboxes +(pocketenv/list-sandboxes) +(pocketenv/list-sandboxes {:limit 10 :offset 20}) + +;; List sandboxes for a specific user +(pocketenv/list-sandboxes-by-actor "alice.pocketenv.io") +(pocketenv/list-sandboxes-by-actor "did:plc:abc123") + +;; Lifecycle +(def sb (pocketenv/create-sandbox "my-box")) +(sandbox/start sb) +(sandbox/stop sb) +(sandbox/delete sb) + +;; Poll until running (with optional timeout) +(-> (pocketenv/create-sandbox "ci-runner") + (sandbox/start) + (sandbox/wait-until-running {:timeout-ms 120000 :interval-ms 3000})) +``` + +## Running commands + +```clojure +(-> (pocketenv/get-sandbox "my-box") + (sandbox/exec "ls" ["-la" "/"])) +;; => {:ok #ExecResult{:stdout "..." :stderr "" :exit-code 0}} + +;; ExecResult fields: :stdout :stderr :exit-code +(let [{:ok result} (sandbox/exec sb "node" ["--version"])] + (println (:stdout result))) +``` + +## Ports & networking + +```clojure +;; Expose a port +(-> (pocketenv/get-sandbox "my-box") + (sandbox/expose 3000 {:description "Web server"})) +;; => {:ok "https://preview.pocketenv.io/..."} + +;; List exposed ports +(-> (pocketenv/get-sandbox "my-box") + (sandbox/list-ports)) +;; => {:ok [#Port{:port 3000 :description "Web server" :preview-url "..."}]} + +;; Remove a port +(-> (pocketenv/get-sandbox "my-box") + (sandbox/unexpose 3000)) + +;; VS Code +(-> (pocketenv/get-sandbox "my-box") + (sandbox/vscode)) +;; => {:ok "https://preview.pocketenv.io/.../vscode/..."} +``` + +## Full pipeline example + +```clojure +(require '[pocketenv-io.pocketenv :as pocketenv] + '[pocketenv-io.sandbox :as sandbox]) + +(let [result + (-> (pocketenv/create-sandbox "ci-box" + {:provider "cloudflare" + :repo "https://github.com/myorg/myapp"}) + (sandbox/start) + (sandbox/wait-until-running {:timeout-ms 120000}) + (sandbox/exec "npm" ["install"]) + ;; exec returns {:ok result}, chain keeps working + )] + (println "Tests:" (get-in result [:ok :exit-code]))) +``` diff --git a/sdks/elixir.mdx b/sdks/elixir.mdx new file mode 100644 index 0000000..7452fc5 --- /dev/null +++ b/sdks/elixir.mdx @@ -0,0 +1,151 @@ +--- +title: "Elixir" +description: "Official Elixir SDK for Pocketenv — pipe-friendly, OTP-ready." +--- + + + **GitHub:** [pocketenv-io/pocketenv-elixir](https://github.com/pocketenv-io/pocketenv-elixir) · **hex.pm:** [pocketenv_ex](https://hex.pm/packages/pocketenv_ex) + + +## Installation + +Add to `mix.exs`: + +```elixir +def deps do + [ + {:pocketenv_ex, "~> 0.1"} + ] +end +``` + +```sh +mix deps.get +``` + +## Authentication + +**`config/config.exs`** (takes precedence over env vars): + +```elixir +import Config + +config :pocketenv_ex, + token: "your-pocketenv-token", + api_url: "https://api.pocketenv.io" # optional +``` + +**Environment variables:** + +```sh +export POCKETENV_TOKEN="your-pocketenv-token" +export POCKETENV_API_URL="https://api.pocketenv.io" # optional +``` + +All functions return `{:ok, result}` or `{:error, reason}`. Every `Sandbox` function accepts either a bare `%Sandbox{}` **or** an `{:ok, %Sandbox{}}` tuple as its first argument — so you can pipe across multiple steps without unwrapping. + +## Quick start + +```elixir +alias Pocketenv.Sandbox + +{:ok, sandbox} = + Pocketenv.create_sandbox("my-sandbox") + |> Sandbox.start() + |> Sandbox.wait_until_running() + +{:ok, result} = sandbox |> Sandbox.exec("echo", ["hello"]) +IO.puts(result.stdout) # => "hello" + +{:ok, url} = sandbox |> Sandbox.expose(3000) +IO.puts(url) # => "https://3000-my-sandbox.sbx.pocketenv.io" + +sandbox |> Sandbox.stop() |> Sandbox.delete() +``` + +## Sandbox lifecycle + +```elixir +# Create +{:ok, sandbox} = Pocketenv.create_sandbox("my-sandbox", + base: "openclaw", + provider: :cloudflare, + repo: "https://github.com/myorg/myapp", + keep_alive: true +) + +# Fetch existing +{:ok, sandbox} = Pocketenv.get_sandbox("my-sandbox") + +# List sandboxes +{:ok, {sandboxes, total}} = Pocketenv.list_sandboxes(limit: 20, offset: 0) + +# List by actor (DID or handle) +{:ok, {sandboxes, _}} = Pocketenv.list_sandboxes_by_actor("alice.bsky.social") + +# Lifecycle +{:ok, sandbox} = sandbox |> Sandbox.start() +{:ok, sandbox} = sandbox |> Sandbox.stop() +{:ok, sandbox} = sandbox |> Sandbox.delete() + +# Poll until running +{:ok, sandbox} = + Pocketenv.create_sandbox("ci-runner") + |> Sandbox.start() + |> Sandbox.wait_until_running(timeout_ms: 120_000, interval_ms: 3_000) +``` + +## Running commands + +```elixir +{:ok, result} = sandbox |> Sandbox.exec("ls", ["-la", "/"]) +IO.puts(result.stdout) +IO.puts(result.stderr) +IO.inspect(result.exit_code) +``` + +## Ports & networking + +```elixir +# Expose a port +{:ok, preview_url} = sandbox |> Sandbox.expose(3000) +{:ok, preview_url} = sandbox |> Sandbox.expose(3000, description: "API server") +IO.puts(preview_url) + +# Unexpose +:ok = sandbox |> Sandbox.unexpose(3000) + +# List exposed ports +{:ok, ports} = sandbox |> Sandbox.list_ports() + +# VS Code +{:ok, vscode_url} = sandbox |> Sandbox.vscode() +``` + +## Actor / profile + +```elixir +# Current user +{:ok, me} = Pocketenv.me() +IO.puts("Logged in as @#{me.handle}") + +# Any user by DID or handle +{:ok, profile} = Pocketenv.get_profile("alice.bsky.social") +``` + +## `create_sandbox/2` options + +| Option | Type | Default | Description | +|---|---|---|---| +| `:base` | `string` | `openclaw` | Base sandbox image | +| `:provider` | `atom` | `:cloudflare` | `:cloudflare`, `:daytona`, `:vercel`, `:deno`, `:e2b`, etc. | +| `:repo` | `string` | `nil` | Git repo URL to clone on start | +| `:keep_alive` | `boolean` | `false` | Prevent auto-stop on inactivity | +| `:token` | `string` | global config | Per-call token override | + +## `wait_until_running/2` options + +| Option | Default | Description | +|---|---|---| +| `:timeout_ms` | `60_000` | Max wait time in ms | +| `:interval_ms` | `2_000` | Poll interval in ms | diff --git a/sdks/gleam.mdx b/sdks/gleam.mdx new file mode 100644 index 0000000..22d3cdd --- /dev/null +++ b/sdks/gleam.mdx @@ -0,0 +1,156 @@ +--- +title: "Gleam" +description: "Official Gleam SDK for Pocketenv — type-safe, functional, pipe-friendly." +--- + + + **GitHub:** [pocketenv-io/pocketenv-gleam](https://github.com/pocketenv-io/pocketenv-gleam) · **hex.pm:** [pocketenv](https://hex.pm/packages/pocketenv) + + +## Installation + +```sh +gleam add pocketenv@1.3 +``` + +## Authentication + +Pass your token when creating a client: + +```gleam +import pocketenv + +pub fn main() { + let client = pocketenv.new_client("your-api-token") + // use client with any sub-module +} +``` + +## Sandboxes + +```gleam +import pocketenv +import pocketenv/sandbox +import gleam/option.{None, Some} +import gleam/io + +pub fn main() { + let client = pocketenv.new_client("your-token") + + // Create + let assert Ok(sb) = + client + |> sandbox.new("my-sandbox", "openclaw", "cloudflare") + |> sandbox.with_description("My app sandbox") + |> sandbox.create() + io.println("Created: " <> sb.data.id) + + // List + let assert Ok(#(sandboxes, _total)) = sandbox.list(client, None, None) + + // Start, exec, stop + let assert Ok(Nil) = sb |> sandbox.start(None, None) + let assert Ok(result) = sb |> sandbox.exec("echo hello") + io.println(result.stdout) + let assert Ok(Nil) = sb |> sandbox.stop() + + // Delete + let assert Ok(Nil) = sb |> sandbox.delete() +} +``` + +## Environment variables + +```gleam +import pocketenv/env +import gleam/option.{None} + +// Set a variable +let assert Ok(Nil) = sb |> env.put("DATABASE_URL", "postgres://localhost/mydb") + +// List variables +let assert Ok(vars) = sb |> env.list(None, None) + +// Delete by ID +case vars { + [first, ..] -> { let assert Ok(Nil) = sb |> env.delete(first.id) } + [] -> Nil +} +``` + +## Secrets + +```gleam +import pocketenv/secrets +import gleam/option.{None} + +// Store a secret (encrypted at rest) +let assert Ok(Nil) = sb |> secrets.put("API_KEY", "super-secret-value") + +// List secret names (values are never returned) +let assert Ok(all) = sb |> secrets.list(None, None) + +// Delete +case all { + [first, ..] -> { let assert Ok(Nil) = sb |> secrets.delete(first.id) } + [] -> Nil +} +``` + +## Files + +```gleam +import pocketenv/files + +// Write a file +let assert Ok(Nil) = sb |> files.write("/app/config.json", "{\"debug\": true}") + +// List files +let assert Ok(all) = sb |> files.list() + +// Delete +case all { + [first, ..] -> { let assert Ok(Nil) = sb |> files.delete(first.id) } + [] -> Nil +} +``` + +## Ports & networking + +```gleam +import pocketenv/ports + +// Expose a port +let assert Ok(preview_url) = sb |> ports.expose(3000, "Web server") +io.println(preview_url) + +// List exposed ports +let assert Ok(exposed) = sb |> ports.list() + +// Remove +let assert Ok(Nil) = sb |> ports.unexpose(3000) + +// VS Code +let assert Ok(vscode_url) = sb |> ports.vscode() +``` + +## Volumes + +```gleam +import pocketenv/volumes + +let assert Ok(Nil) = sb |> volumes.create("data", "/mnt/data", False) +let assert Ok(vols) = sb |> volumes.list() +``` + +## Services + +```gleam +import pocketenv/services + +let assert Ok(svc) = sb |> services.add("web", "npm start", "Node server", [3000]) +let assert Ok(Nil) = sb |> services.start(svc.id) +let assert Ok(Nil) = sb |> services.stop(svc.id) +let assert Ok(Nil) = sb |> services.restart(svc.id) +let assert Ok(Nil) = sb |> services.delete(svc.id) +``` diff --git a/sdks/javascript.mdx b/sdks/javascript.mdx new file mode 100644 index 0000000..7413ec2 --- /dev/null +++ b/sdks/javascript.mdx @@ -0,0 +1,190 @@ +--- +title: "JavaScript / TypeScript" +description: "Official JS/TS SDK for Pocketenv — `@pocketenv/sdk`." +--- + + + **GitHub:** [pocketenv-io/pocketenv-js](https://github.com/pocketenv-io/pocketenv-js) · **npm:** [@pocketenv/sdk](https://www.npmjs.com/package/@pocketenv/sdk) + + +## Installation + +```bash +npm install @pocketenv/sdk +# or +bun add @pocketenv/sdk +``` + +## Authentication + +Token resolution order: + +1. `Sandbox.configure({ token })` or inline `Sandbox.create({ token })` +2. `POCKETENV_TOKEN` environment variable +3. `~/.pocketenv/token.json` + +`Sandbox.configure()` is optional if you have a token file or env var set. + +## Quick start + +```typescript +import { Sandbox } from "@pocketenv/sdk"; + +const sandbox = await Sandbox.create({ base: "openclaw" }); + +const result = await sandbox.sh`echo hello`; +console.log(result.stdout); // "hello\n" + +await sandbox.stop(); +await sandbox.delete(); +``` + +## Sandbox lifecycle + +```typescript +// Create +const sandbox = await Sandbox.create({ + base: "openclaw", + name: "my-sandbox", + provider: "cloudflare", +}); + +// Fetch existing +const existing = await Sandbox.get("sandbox-id"); + +// List +const { sandboxes, total } = await Sandbox.list({ limit: 20, offset: 0 }); + +// Start / stop / delete +await sandbox.start({ repo: "github:myorg/myapp", keepAlive: true }); +await sandbox.stop(); +await sandbox.delete(); +``` + +## Builder pattern + +Useful when setting many options: + +```typescript +const sandbox = await Sandbox.builder("openclaw") + .name("api-sandbox") + .provider("daytona") + .vcpus(4) + .memory(8192) + .disk(20) + .env("NODE_ENV", "production") + .env("PORT", "3000") + .secret("DATABASE_URL", process.env.DATABASE_URL!) + .secret("API_KEY", process.env.API_KEY!) + .keepAlive() + .create(); +``` + +Available builder methods: `name`, `description`, `provider`, `topics`, `repo`, `vcpus`, `memory`, `disk`, `readme`, `env`, `secret`, `keepAlive`, `token`, `baseUrl`. + +## Running commands + +```typescript +// Tagged template literal (safe interpolation) +const dir = "/home/user/app"; +const result = await sandbox.sh`ls -la ${dir}`; +console.log(result.stdout); +console.log(result.stderr); +console.log(result.exitCode); + +// Raw exec +await sandbox.exec("npm install"); +``` + +## Environment variables & secrets + +```typescript +// Env vars (plaintext) +await sandbox.env.put("API_URL", "https://api.example.com"); +const vars = await sandbox.env.list(); +await sandbox.env.delete(varId); + +// Secrets (encrypted, redacted in responses) +await sandbox.secret.put("API_KEY", process.env.API_KEY!); +const secrets = await sandbox.secret.list(); +await sandbox.secret.delete(secretId); +``` + +## Ports & networking + +```typescript +const exposed = await sandbox.expose(3000, "Web server"); +console.log(exposed.previewUrl); + +await sandbox.unexpose(3000); + +const ports = await sandbox.ports.list(); + +// VS Code in the browser +const vscode = await sandbox.vscode(); +console.log(vscode.previewUrl); +``` + +## Files + +```typescript +await sandbox.file.write("/app/config.json", JSON.stringify({ debug: true })); + +const files = await sandbox.file.list(); +const file = await sandbox.file.get(fileId); +await sandbox.file.delete(fileId); +``` + +## Services + +```typescript +const service = await sandbox.service.add("web", { + command: "npm start", + description: "Node.js web server", + ports: [3000], +}); + +await sandbox.service.start(service.id); +await sandbox.service.restart(service.id); +await sandbox.service.stop(service.id); +await sandbox.service.delete(service.id); +``` + +## Volumes + +```typescript +await sandbox.volume.create("data", "/mnt/data"); +const volumes = await sandbox.volume.list(); +await sandbox.volume.delete(volumeId); +``` + +## Backups + +```typescript +const backup = await sandbox.createBackup("/workspace", "pre-deploy", "7d"); +const backups = await sandbox.listBackups(); +await Sandbox.restoreBackup(backupId); // static method +``` + +## SSH keys & Tailscale + +```typescript +const keys = await sandbox.getSshKeys(); +await sandbox.putSshKey(publicKey, privateKey); + +await sandbox.tailscale.setAuthKey("tskey-auth-..."); +const key = await sandbox.tailscale.getAuthKey(); +``` + +## Sub-resource reference + +| Sub-resource | Methods | +|---|---| +| `sandbox.file` | `write`, `list`, `get`, `update`, `delete` | +| `sandbox.env` | `put`, `list`, `get`, `update`, `delete` | +| `sandbox.secret` | `put`, `list`, `get`, `update`, `delete` | +| `sandbox.volume` | `create`, `list`, `get`, `update`, `delete` | +| `sandbox.ports` | `list` | +| `sandbox.service` | `add`, `list`, `start`, `stop`, `restart`, `update`, `delete` | +| `sandbox.tailscale` | `getAuthKey`, `setAuthKey` | +| `sandbox.backup` | `create`, `list`, `restore` | -- 2.51.2