Skip to content

New SDK release #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 46 additions & 17 deletions packages/projects-docs/pages/sdk/_meta.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,63 @@
{
"index": "Introduction",
"use-cases": "Use Cases",
"pricing": "Pricing",
"contact": {
"title": "Contact Us",
"href": "https://codesandbox.io/support#form",
"newWindow": true
"playground": {
"href": "https://wkyxcw-5173.csb.app/",
"title": "Example Playground"
},
"faq": "FAQ",
"pricing": "Pricing",

"-- api-reference": {
"-- sandboxes": {
"type": "separator",
"title": "API Reference"
"title": "Sandboxes"
},
"sandboxes": "Sandboxes",
"filesystem": "File System",
"shells": "Shells",
"ports": "Ports & Previews",
"tasks": "Tasks & Setup",
"create-resume": "Create & Resume",
"templates": "Templates",
"sessions": "Sessions",
"hibernate": "Hibernate",
"fork": "Fork",
"restart-shutdown": "Restart & Shutdown",
"specs": "VM Specs",
"persistence": "Persistence",
"update-sandbox": "Update Sandbox",
"-- previews": {
"type": "separator",
"title": "Previews"
},
"preview-tokens": "Preview Tokens",
"browser-previews": "Browser Previews",
"-- websocket-sessions": {
"type": "separator",
"title": "WebSocket Sessions"
},
"connect": "Connect",
"browser": "Connect Browser",
"filesystem": "File System",
"terminals": "Terminals",
"commands": "Commands",
"interpreters": "Interpreters",
"ports": "Ports",
"tasks": "Tasks",
"setup": "Setup",

"-- CLI": {
"type": "separator",
"title": "CLI"
},
"build-templates": "Build Templates",
"preview-hosts": "Preview Hosts",

"-- resources": {
"type": "separator",
"title": "Resources"
},
"snapshot-library": "Snapshot Library",
"snapshot-builder": "Snapshot Builder",
"snapshot-library": "Template Library",
"environment": "Environment",
"docker": "Docker & Docker Compose",
"persistence": "Persistence",
"fork": "Fork",
"faq": "FAQ"
"contact": {
"title": "Contact Us",
"href": "https://codesandbox.io/support#form",
"newWindow": true
}
}
92 changes: 92 additions & 0 deletions packages/projects-docs/pages/sdk/browser-previews.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
title: Browser Previews
description: Learn how you can interact with previews in your sandbox.
---

import { Callout } from 'nextra-theme-docs'

# Browser Previews

The browser previews API allows you to create and interact with previews in the browser. You can navigate, listen to messages and even inject custom code into the preview.

## API

```ts
import { createPreview } from '@codesandbox/sdk/browser'

const { url } = await fetch('/api/preview-tokens/' + sandboxId).then(res => res.json())
const preview = createPreview(url)

document.querySelector('#preview-container').appendChild(preview.iframe)
```

<Callout>
If you are running public previews you can also just use the port url directly without a preview token.
</Callout>

## Messages

You can listen to messages from the preview:

```ts
preview.onMessage((message) => {
switch (message.type) {
case 'SET_URL': {
// Url that was set
message.url
// If you can move backward
message.back
// If you can move forward
message.forward
break;
}
case 'RELOAD': {
// If preview reloaded
}
case 'PREVIEW_UNLOADING': {
// Preview will unload
}
}
})
```

<Callout>
By injecting your own code you can extend these messages to your own.
</Callout>

## Navigate

```ts
// Replace the current url
preview.setUrl("...")

// Navigate back
preview.back()

// Navigate forward
preview.forward()

// Reload the iframe
preview.reload()
```

## Inject and Invoke

You can inject any code into the preview. This is useful if you want to insert custom UI elements, background processes.etc The injected code can listen to messages, send messages and has access to any variables (scope) you send to the injected code.

```ts
preview.onMessage((message) => {
console.log(message)
})

preview.injectAndInvoke(function MyInjectedFunction({ previewProtocol, previewWindow, scope }) {
alert(scope.message)
previewProtocol.sendMessage({ type: 'ALERTED' })
}, {
message: 'Hello World'
})
```

<Callout>
Note that the function passed to `injectAndInvoke` will be stringified and sent to the preview. Be careful about your build tool transforming this function into invalid code.
</Callout>
85 changes: 85 additions & 0 deletions packages/projects-docs/pages/sdk/browser.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: Connect Browser
description: Learn how to connect to a sandbox in the browser with the CodeSandbox SDK.
---

import { Callout } from 'nextra-theme-docs'

# Connect Browser

Connecting to a Sandbox in the browser requires some collaboration with your server. Create an endpoint that will resume the sandbox and then create a browser session:

```ts
export const GET = async ({ params }) => {
const sandbox = await sdk.sandboxes.resume(params.sandboxId);
const session = await sandbox.createBrowserSession();

return session
}
```

Then in the browser:

```ts
import { connectToSandbox } from '@codesandbox/sdk/browser';

const session = await connectToSandbox({
id: '123',
getSession: (id) => fetch(`/api/sandboxes/${id}`).then(res => res.json())
});

await session.fs.writeTextFile('test.txt', 'Hello World');
```

The Browser session automatically manages the connection and will reconnect if the connection is lost. This is controlled by an option called `onFocusChange`.

```ts
const session = await connectToSandbox({
id: '123',
getSession: (id) => fetch(`/api/sandboxes/${id}`).then(res => res.json()),
onFocusChange: (notify) => {
const onVisibilityChange = () => {
notify(document.visibilityState === 'visible');
}

document.addEventListener('visibilitychange', onVisibilityChange);

return () => {
document.removeEventListener('visibilitychange', onVisibilityChange);
}
}
});
```

If you tell the browser session when it is in focus it will automatically reconnect when hibernated. Unless you explicitly disconnect the session.

While the `connectToSandbox` promise is resolving you can also listen to initialization events to show a loading state:

```ts
const session = await connectToSandbox({
id: '123',
getSession: (id) => fetch(`/api/sandboxes/${id}`).then(res => res.json()),
onInitCb: (event) => {}
});
```

## Disconnecting the Session

Disconnecting the session will end the session and automatically hibernate the sandbox after a timeout. You can also hibernate the sandbox explicitly from the server.

```ts
import { connectToSandbox } from '@codesandbox/sdk/browser'

const session = await connectToSandbox({
id: '123',
getSession: (id) => fetch(`/api/sandboxes/${id}`).then(res => res.json()),
})

// Disconnect returns a promise that resolves when the session is disconnected
session.disconnect();

// Optionally hibernate the sandbox explicitly
fetch('/api/sandboxes/' + sandbox.id + '/hibernate', {
method: 'POST'
})
```
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
---
title: Snapshot Builder
title: Build Templates
description: Learn how to create your own templates with the CodeSandbox SDK.
---

import Video from '../../../../shared-components/Video'

# Snapshot Builder
# Build Templates

If you’re using CodeSandbox SDK, there’s a big chance that you want to customize the base environment of your sandboxes. You might want to preload a custom Docker image, or prestart a server that should be available as soon as you create a sandbox.
If you’re using CodeSandbox SDK, you will likely want to customize the base environment of your sandboxes. Maybe you want to preload a custom Docker image, or prestart a server so it's available as soon as you create a sandbox.

You can use our CLI to create a memory snapshot that has all this data preloaded. This CLI will build a sandbox based on a folder, load the docker image, start the servers and finally create a memory snapshot that can be used when creating new sandboxes.
You can use our CLI to create a distributed memory snapshot that has all this data preloaded. This CLI will build a sandbox based on that folder, load the docker image, start any servers and finally create a memory snapshot that can be used when creating new sandboxes. It will do this for all our clusters improving latency and ensuring availability.

New sandboxes can be created from this memory snapshot, which means that new sandboxes will “hit the ground running” with the servers running during snapshot creation. Creating a sandbox from a memory snapshot takes 1-3 seconds.
New sandboxes can then be created from this memory snapshot, which means that those sandboxes will “hit the ground running”. Creating your new environment from the memory snapshot in only 1-3 seconds.

<Video controls={true} autoPlay={false} playsInline={false} src="../snapshot-builder.mp4" />

## Creating a snapshot
## Creating a template

Install the CodeSandbox SDK globally to enable the CLI:

Expand All @@ -29,15 +29,15 @@ Finally, run:

```jsx
$ CSB_API_KEY=KEY csb build <path>
abcde1
template-id
```

This will create a fresh sandbox, upload the files of your directory, start necessary servers and finally snapshot the sandbox to return the id you can use. You can then pass this id when creating new sandboxes:

```jsx
const sdk = new CodeSandbox(process.env.CSB_API_KEY);

const sandbox = await sdk.sandbox.create({ template: 'abcde1' });
const sandbox = await sdk.sandboxes.create({ source: 'template', id: 'template-id' });
```

### Custom Docker Image
Expand All @@ -50,9 +50,9 @@ CodeSandbox uses [Dev Containers](https://containers.dev/) for configuring Docke
}
```

When we boot the sandbox, we’ll make sure that the docker image is pulled (or built) and we’ll make sure that all shells will start within this container. The `/project/sandbox` folder is mounted inside the container.
When we boot the sandbox, we’ll make sure that the docker image is pulled (or built) and we’ll make sure that all shells will start within this container. Your `/project/sandbox` folder will also be mounted inside the container.

You can also decide to build the Docker image as part of the snapshot creation process. You can do this by defining this in your `.devcontainer/devcontainer.json`:
You can decide to build the Docker image as part of the snapshot creation process as well. You can do this by defining this in your `.devcontainer/devcontainer.json`:

```json
{
Expand All @@ -76,18 +76,20 @@ If you have a server, agent or dev server that you want to run as part of your s
"dev-server": {
"name": "Dev Server",
"command": "/bin/dev-server --port 3000",
"preview": {
"port": 3000
},
"runAtStart": true
}
}
}
```

During the snapshot creation process, we will start `/bin/dev-server` after the Docker container has been started, and we will wait until port 3000 resolves before creating a memory snapshot. Then, whenever a new sandbox is created from this snapshot, the dev server will already be running.
```jsx
$ CSB_API_KEY=KEY csb build <path> --ports 3000
template-id
```

You can also run more than one task, you can add as many as you’d like. All commands will be run from the project directory.
During the snapshot creation process, we will start `/bin/dev-server` after the Docker container has been started, then we will wait until port 3000 resolves before creating a memory snapshot. From that point on, whenever a new sandbox is created from this snapshot the dev server will already be running.

You can also run more than one task. You can add as many as you’d like! All commands will be run from the project directory.

You can learn more about tasks in our [tasks documentation](/sdk/tasks.mdx).

Expand All @@ -104,13 +106,15 @@ You can configure tasks to run after docker build has been done, but before we r
}
```

For any preparation you need to do inside the workspace directory (like building a binary from source files, or installing node_modules), a setup task would be better suited than putting it in the docker image. Also, if for some reason a sandbox starts without a memory snapshot, the setup tasks will also run before it starts any tasks.
For any preparation you need to do inside the workspace directory (like building a binary from source files, or installing node_modules), a setup task would be more suitable than putting it in the docker image. If a sandbox starts without a memory snapshot, the setup tasks will run before it starts any other tasks.

You can learn more about setup tasks in our [tasks documentation](/sdk/tasks.mdx).

### Setup Tasks vs Dockerfile

When would you configure something in the Dockerfile, and when would you configure something in setup tasks? As a rule of thumb, if something is configured in relation to the environment (like installing Node, or installing Postgres, or installing Bun), it should go into the Dockerfile. If something is related to the project setup (installing dependencies, building a binary), it should go inside setup tasks.
When would you configure something in the Dockerfile, and when would you configure something in setup tasks?

As a rule of thumb, if something is configured in relation to the environment (like installing Node, or installing Postgres, or installing Bun), it should go into the Dockerfile. If something is related to the project setup (installing dependencies, building a binary), it should go inside setup tasks.

## Examples

Expand All @@ -126,7 +130,6 @@ At CodeSandbox we’ve built many templates that follow this structure. You can
- You can create a snapshot that has a headless browser (like Playwright) already snapshotted and running inside a VM.
- This browser can open a websocket port, which you can use to control the browser.

## Future
## Tags (In Development)

- We're working on a way to create snapshots in multiple clusters, allowing you to run your sandboxes close to the user.
- We're working on a tagging system that allows you to use a tag (like `my-snapshot:latest`). This way you don't have to update ids whenever you create a new snapshot.
Loading