In many situations, you’ll need to operate a sandbox from a frontend client. When doing so, you cannot share the Blaxel credentials needed to access the sandbox. The solution is to use sessions. Sessions are created for a sandbox from a backend server (using Blaxel credentials) and then shared with the frontend client, allowing the browser to connect to the sandbox.

Basic example

Create a temporary backend session to access a sandbox instance from your client application. Main parameter for this is expiresAt, a Date() corresponding to the expiration date.
// From your backend
import { SandboxInstance } from "@blaxel/core";

const sandbox = await SandboxInstance.get("my-sandbox");

const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
const session = await sandbox.sessions.create({ expiresAt });
/// From your frontend:
import { SandboxInstance } from "@blaxel/core";

const sandboxWithSession = await SandboxInstance.fromSession(session)

Create if expired

This helper function either retrieves an existing session or creates a new one if it expired. You can optionally pass delta (default: 1 hour), the time window in milliseconds before actual expiration when a session should still be recreated.
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
const session = await sandbox.sessions.createIfExpired(
  { expiresAt },
  60000 // delta in milliseconds
);

Complete example (NextJS)

The following example (see full app on GitHub) demonstrates a full implementation of sessions in a backend server and frontend client using NextJS.

Server code (backend)

import { NextResponse } from 'next/server';
import { SandboxInstance } from "@blaxel/core";

const SANDBOX_NAME = 'my-sandbox';
const responseHeaders = {
  "Access-Control-Allow-Origin": "http://localhost:3000",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH",
  "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, X-Blaxel-Workspace, X-Blaxel-Preview-Token, X-Blaxel-Authorization",
  "Access-Control-Allow-Credentials": "true",
  "Access-Control-Expose-Headers": "Content-Length, X-Request-Id",
  "Access-Control-Max-Age": "86400",
  "Vary": "Origin"
}

export async function GET() {
  // Get or create sandbox
  const sandbox = await SandboxInstance.createIfNotExists({
    name: SANDBOX_NAME,
    image: "blaxel/prod-base:latest",
    memory: 4096,
    ports: [
      { name: "preview", target: 3000 }
    ]
  });

  // Create session (24 hours expiry)
  const session = await sandbox.sessions.create({
    expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
  });

  // Create preview for port 3000
  const preview = await sandbox.previews.create({
    metadata: { name: "app-preview" },
    spec: {
      port: 3000,
      public: true,
      responseHeaders: responseHeaders
    }
  });

  return NextResponse.json({
    session,
    preview_url: preview.spec?.url
  });
}

Client code (frontend)

'use client'

import { SandboxInstance } from "@blaxel/core";
import { useState, useEffect } from "react";

export default function SandboxClient() {
  const [sandbox, setSandbox] = useState(null);
  const [previewUrl, setPreviewUrl] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    initializeSandbox();
  }, []);

  async function initializeSandbox() {
    // Get session from backend
    const response = await fetch('/api/sandbox');
    const { session, preview_url } = await response.json();

    // Create sandbox from session
    const sandboxInstance = await SandboxInstance.fromSession(session);

    setSandbox(sandboxInstance);
    setPreviewUrl(preview_url);

    // Start development server
    await sandboxInstance.process.exec({
      name: "dev-server",
      command: "npm run dev",
      workingDir: "/app",
      waitForPorts: [3000]
    });
    setLoading(false);
  }

  if (loading) return <div>Loading sandbox...</div>;

  return (
    <div>
      <h1>Sandbox Demo</h1>
      {previewUrl && (
        <iframe
          src={previewUrl}
          width="100%"
          height="600px"
          title="App Preview"
        />
      )}
    </div>
  );
}