Using the TypeScript SDK

Volumes provide persistent storage that survives sandbox restarts. Let’s create a volume, verify it exists, and use it with a sandbox.

Step 1: Create a Volume

import SandboxSDK from '@avmcodes/sandbox-sdk';

const client = new SandboxSDK({
  apiKey: process.env['SANDBOX_SDK_API_KEY'],
});

// Create a volume with default size (10Gi)
const volume = await client.volumes.create({
  name: 'my-persistent-storage',
});

console.log('Volume created:', volume.id);
console.log('Volume name:', volume.name);
console.log('Volume size:', volume.size);
console.log('Volume status:', volume.status);

Step 2: Verify the Volume Exists

List all volumes to confirm your volume was created:

// List all volumes
const volumesResponse = await client.volumes.list();

// Find your volume
const myVolume = volumesResponse.data.find(
  v => v.name === 'my-persistent-storage'
);

if (myVolume) {
  console.log('Volume found:', myVolume.id);
  console.log('Status:', myVolume.status); // Should be "Bound" when ready
} else {
  console.log('Volume not found');
}

Step 3: Create a Sandbox with the Volume

Attach your volume to a sandbox at a custom mount point:

// Create a sandbox with the volume mounted at /data
const sandbox = await client.sandboxes.create({
  name: 'Sandbox with Persistent Storage',
  volumes: [
    {
      volume_id: volume.id,
      mount_path: '/data', // Custom mount point
    },
  ],
  resources: {
    cpus: 2,
    memory: 512,
  },
});

console.log('Sandbox created:', sandbox.id);
console.log('Volumes mounted:', sandbox.volumes);

Step 4: Download Something Heavy

Now let’s demonstrate persistence by downloading a large repository or dataset:

// Clone a large repository to the mounted volume
const result = await client.sandboxes.execute(sandbox.id, {
  command: 'cd /data && git clone --depth 1 https://github.com/torvalds/linux.git',
  timeout: 300, // 5 minutes for large downloads
});

if (result.status === 'completed' && result.exit_code === 0) {
  console.log('Repository cloned successfully!');
  console.log('Output:', result.stdout);
} else {
  console.error('Clone failed:', result.stderr);
}

Step 5: Verify Data Persistence

Check that the data is actually on the volume:

// List files in the mounted volume
const listResult = await client.sandboxes.execute(sandbox.id, {
  command: 'ls -lh /data',
  working_dir: '/data',
});

console.log('Files on volume:', listResult.stdout);

// Check the size of what we downloaded
const sizeResult = await client.sandboxes.execute(sandbox.id, {
  command: 'du -sh /data/linux 2>/dev/null || echo "Directory not found"',
});

console.log('Downloaded size:', sizeResult.stdout);

Complete Example

Here’s a complete example that ties everything together:

import SandboxSDK from '@avmcodes/sandbox-sdk';

const client = new SandboxSDK({
  apiKey: process.env['SANDBOX_SDK_API_KEY'],
});

async function createVolumeAndSandbox() {
  // 1. Create a volume
  console.log('Creating volume...');
  const volume = await client.volumes.create({
    name: 'my-dataset-storage',
    size: '20Gi', // Larger size for big datasets
  });
  console.log(`Volume created: ${volume.id}`);

  // 2. Wait a moment for volume to be ready
  await new Promise(resolve => setTimeout(resolve, 2000));

  // 3. Verify volume exists
  const volumesResponse = await client.volumes.list();
  const foundVolume = volumesResponse.data.find(v => v.id === volume.id);
  if (!foundVolume) {
    throw new Error('Volume not found after creation');
  }
  console.log(`Volume verified: ${foundVolume.status}`);

  // 4. Create sandbox with volume mounted
  console.log('Creating sandbox with volume...');
  const sandbox = await client.sandboxes.create({
    name: 'Data Processing Sandbox',
    volumes: [
      {
        volume_id: volume.id,
        mount_path: '/workspace', // Custom mount point
      },
    ],
    resources: {
      cpus: 4,
      memory: 2048,
    },
  });
  console.log(`Sandbox created: ${sandbox.id}`);

  // 5. Download a large dataset (example: TensorFlow models)
  console.log('Downloading large dataset...');
  const downloadResult = await client.sandboxes.execute(sandbox.id, {
    command: 'cd /workspace && wget -q --show-progress https://github.com/tensorflow/tensorflow/archive/refs/heads/master.zip -O tensorflow.zip',
    timeout: 600, // 10 minutes
  });

  if (downloadResult.status === 'completed') {
    console.log('Download completed!');
    console.log('Exit code:', downloadResult.exit_code);
  }

  // 6. Verify the download
  const verifyResult = await client.sandboxes.execute(sandbox.id, {
    command: 'ls -lh /workspace/tensorflow.zip',
  });
  console.log('File info:', verifyResult.stdout);

  return { volume, sandbox };
}

// Run the example
createVolumeAndSandbox()
  .then(({ volume, sandbox }) => {
    console.log('Success!');
    console.log(`Volume ID: ${volume.id}`);
    console.log(`Sandbox ID: ${sandbox.id}`);
  })
  .catch(console.error);

Customizing Volume Size

You can specify different volume sizes when creating:

// Small volume (100Mi)
const smallVolume = await client.volumes.create({
  name: 'small-storage',
  size: '100Mi',
});

// Medium volume (10Gi - default)
const mediumVolume = await client.volumes.create({
  name: 'medium-storage',
  size: '10Gi',
});

// Large volume (100Gi)
const largeVolume = await client.volumes.create({
  name: 'large-storage',
  size: '100Gi',
});

Using Multiple Volumes

You can mount multiple volumes to a single sandbox:

// Create multiple volumes
const dataVolume = await client.volumes.create({
  name: 'data-volume',
  size: '50Gi',
});

const cacheVolume = await client.volumes.create({
  name: 'cache-volume',
  size: '10Gi',
});

// Mount both volumes to a sandbox
const sandbox = await client.sandboxes.create({
  name: 'Multi-Volume Sandbox',
  volumes: [
    {
      volume_id: dataVolume.id,
      mount_path: '/data',
    },
    {
      volume_id: cacheVolume.id,
      mount_path: '/cache',
    },
  ],
});

Response Structure

The create() method returns a Volume object:

const volume = await client.volumes.create({
  name: 'my-volume',
});

// volume contains:
console.log(volume.id);        // "vol_x1y2z3a4b5c6d7e8"
console.log(volume.name);       // "my-volume"
console.log(volume.size);       // "10Gi"
console.log(volume.status);     // "Bound" or "Pending"
console.log(volume.created_at); // "2024-01-15T12:00:00Z"

Parameters

name
string
required

A descriptive name for your volume

size
string
default:
"10Gi"

Volume size in Kubernetes format (e.g., ‘10Gi’, ‘100Mi’, ‘1Ti’). Supported units: Mi, Gi, Ti

Volume Status

Volumes can have different statuses:

  • Pending - Volume is being created
  • Bound - Volume is ready to use
  • Lost - Volume is unavailable (rare)

Wait for the volume status to be Bound before mounting it to a sandbox for best results.

Best Practices

  1. Choose appropriate sizes: Estimate your storage needs to avoid running out of space
  2. Use descriptive names: Name volumes based on their purpose (e.g., ml-models, datasets, cache)
  3. Verify before use: Always check that a volume exists and is Bound before mounting
  4. Mount at logical paths: Use meaningful mount paths like /data, /workspace, /models
  5. Clean up: Delete volumes when no longer needed to free up resources

Next Steps