
Research
/Security News
Mini Shai-Hulud Campaign Hits Red Hat Cloud Services npm Packages
A mini Shai-Hulud campaign compromised Red Hat Cloud Services npm packages to steal developer and CI/CD secrets during installation.
@computesdk/provider
Advanced tools
Provider framework for ComputeSDK - define custom sandbox providers
The provider framework for building custom compute providers.
This package provides the tools and types to build custom sandbox providers for the ComputeSDK ecosystem. Use it to add support for new compute platforms, cloud providers, or sandbox environments.
npm install @computesdk/provider
import { defineProvider } from '@computesdk/provider';
import type { ProviderConfig } from '@computesdk/provider';
interface MyProviderConfig extends ProviderConfig {
apiKey: string;
region?: string;
}
export const myProvider = defineProvider<any, MyProviderConfig>({
name: 'my-provider',
defaultMode: 'direct',
methods: {
sandbox: {
create: async (config, options) => {
// Create sandbox via your provider's API
const response = await fetch(`https://api.example.com/sandboxes`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${config.apiKey}` },
body: JSON.stringify(options)
});
const data = await response.json();
return {
sandbox: data, // Your provider's sandbox object
sandboxId: data.id
};
},
getById: async (config, sandboxId) => {
const response = await fetch(
`https://api.example.com/sandboxes/${sandboxId}`,
{ headers: { 'Authorization': `Bearer ${config.apiKey}` } }
);
if (!response.ok) return null;
const data = await response.json();
return { sandbox: data, sandboxId: data.id };
},
list: async (config) => {
const response = await fetch(
`https://api.example.com/sandboxes`,
{ headers: { 'Authorization': `Bearer ${config.apiKey}` } }
);
const data = await response.json();
return data.map((s: any) => ({ sandbox: s, sandboxId: s.id }));
},
destroy: async (config, sandboxId) => {
await fetch(
`https://api.example.com/sandboxes/${sandboxId}`,
{
method: 'DELETE',
headers: { 'Authorization': `Bearer ${config.apiKey}` }
}
);
},
runCommand: async (sandbox, command, args) => {
// Run shell command
const response = await fetch(
`https://api.example.com/sandboxes/${sandbox.id}/command`,
{
method: 'POST',
body: JSON.stringify({ command, args })
}
);
const result = await response.json();
return {
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exitCode
};
},
getInfo: async (sandbox) => {
return {
id: sandbox.id,
status: sandbox.status,
createdAt: new Date(sandbox.created_at)
};
},
getUrl: async (sandbox, options) => {
return `https://${sandbox.id}.example.com:${options.port}`;
}
}
}
});
defineProvider(config)Define a new provider with sandbox lifecycle methods.
Parameters:
interface ProviderConfig<TSandbox, TConfig> {
name: string;
defaultMode?: 'direct' | 'gateway';
methods: {
sandbox: SandboxMethods<TSandbox, TConfig>;
template?: TemplateMethods<TTemplate, TConfig>;
snapshot?: SnapshotMethods<TSnapshot, TConfig>;
};
}
Returns: A factory function (config: TConfig) => Provider
These methods manage sandboxes at the collection level:
create(config, options?)Create a new sandbox.
create: async (config, options) => {
// Return: { sandbox: YourSandboxObject, sandboxId: string }
return {
sandbox: mySandboxInstance,
sandboxId: 'sandbox-123'
};
}
getById(config, sandboxId)Get an existing sandbox by ID.
getById: async (config, sandboxId) => {
// Return: { sandbox, sandboxId } or null if not found
return { sandbox: mySandboxInstance, sandboxId };
}
list(config)List all sandboxes.
list: async (config) => {
// Return: Array of { sandbox, sandboxId }
return [
{ sandbox: sandbox1, sandboxId: 'id1' },
{ sandbox: sandbox2, sandboxId: 'id2' }
];
}
destroy(config, sandboxId)Destroy a sandbox.
destroy: async (config, sandboxId) => {
await yourApi.deleteSandbox(sandboxId);
}
These methods operate on individual sandbox instances:
runCommand(sandbox, command, args?, options?)Run a shell command.
runCommand: async (sandbox, command, args) => {
const result = await yourApi.runCommand(sandbox.id, command, args);
return {
stdout: result.stdout,
stderr: result.errors,
exitCode: result.code
};
}
getInfo(sandbox)Get sandbox information.
getInfo: async (sandbox) => {
return {
id: sandbox.id,
status: 'running', // 'running' | 'stopped' | 'error'
createdAt: new Date(sandbox.created_at)
};
}
getUrl(sandbox, options)Get URL for accessing sandbox services.
getUrl: async (sandbox, options) => {
return `https://${sandbox.id}.example.com:${options.port}`;
}
Add filesystem support by implementing the filesystem methods. Import escapeShellArg from @computesdk/provider and always interpolate it inside double quotes — the helper escapes \, ", $, and backticks but not spaces or shell metacharacters like ; and |, so unquoted usage will break on paths with spaces and is unsafe for user-controlled input.
import { defineProvider, escapeShellArg } from '@computesdk/provider';
// ...
methods: {
sandbox: {
// ... required methods
filesystem: {
readFile: async (sandbox, path, runCommand) => {
const result = await runCommand(sandbox, `cat "${escapeShellArg(path)}"`);
return result.stdout;
},
writeFile: async (sandbox, path, content, runCommand) => {
await runCommand(sandbox, `cat > "${escapeShellArg(path)}" << 'EOF'\n${content}\nEOF`);
},
mkdir: async (sandbox, path, runCommand) => {
await runCommand(sandbox, `mkdir -p "${escapeShellArg(path)}"`);
},
readdir: async (sandbox, path, runCommand) => {
const result = await runCommand(sandbox, `ls -la "${escapeShellArg(path)}"`);
// Parse ls output and return FileEntry[]
return parseFileList(result.stdout);
},
exists: async (sandbox, path, runCommand) => {
const result = await runCommand(sandbox, `test -e "${escapeShellArg(path)}"`);
return result.exitCode === 0;
},
remove: async (sandbox, path, runCommand) => {
await runCommand(sandbox, `rm -rf "${escapeShellArg(path)}"`);
}
}
}
}
Note: If you don't implement filesystem, the sandbox will still work but filesystem operations will throw helpful "not supported" errors.
import type {
// Provider types
Provider,
ProviderConfig,
ProviderSandbox,
// Method definitions
SandboxMethods,
TemplateMethods,
SnapshotMethods,
// Result types
CodeResult,
CommandResult,
SandboxInfo,
// Options
CreateSandboxOptions,
RunCommandOptions,
// Filesystem
FileEntry,
SandboxFileSystem
} from '@computesdk/provider';
Providers can operate in different modes:
direct - Provider has native sandbox capabilities (e.g., E2B, Modal)gateway - Provider only has infrastructure - routes through gatewaySet the default mode in your provider config:
export const myProvider = defineProvider({
name: 'my-provider',
defaultMode: 'direct', // or 'gateway'
methods: { /* ... */ }
});
Here's a complete minimal provider implementation:
import { defineProvider } from '@computesdk/provider';
interface MinimalConfig {
apiKey: string;
}
export const minimal = defineProvider<any, MinimalConfig>({
name: 'minimal',
defaultMode: 'direct',
methods: {
sandbox: {
create: async (config, options) => {
const id = `sandbox-${Date.now()}`;
return {
sandbox: { id, status: 'running' },
sandboxId: id
};
},
getById: async (config, id) => {
return {
sandbox: { id, status: 'running' },
sandboxId: id
};
},
list: async (config) => {
return [];
},
destroy: async (config, id) => {
// Clean up sandbox
},
runCommand: async (sandbox, command, args) => {
return {
stdout: `Ran: ${command} ${args?.join(' ')}`,
stderr: '',
exitCode: 0
};
},
getInfo: async (sandbox) => {
return {
id: sandbox.id,
status: 'running',
createdAt: new Date()
};
},
getUrl: async (sandbox, options) => {
return `http://localhost:${options.port}`;
}
}
}
});
// Export factory function
export function createMinimal(config: MinimalConfig) {
return minimal(config);
}
Once you've defined your provider, export it from your package:
// In @computesdk/my-provider/src/index.ts
import { defineProvider } from '@computesdk/provider';
export const myProvider = defineProvider({ /* ... */ });
// Users can then use it directly
import { myProvider } from '@computesdk/my-provider';
const compute = myProvider({ apiKey: 'xxx' });
const sandbox = await compute.sandbox.create();
create: async (config, options) => {
if (!config.apiKey) {
throw new Error(
'Missing API key for my-provider.\n\n' +
'Setup instructions:\n' +
'1. Get your API key from https://example.com/keys\n' +
'2. Set environment variable: export MY_PROVIDER_API_KEY=your_key\n' +
'3. Or pass it directly: myProvider({ apiKey: "your_key" })'
);
}
if (!config.apiKey.startsWith('mp_')) {
throw new Error(
'Invalid API key format for my-provider.\n' +
'API keys should start with "mp_"'
);
}
// Continue with creation
}
runCommand: async (sandbox, command, args) => {
try {
return await yourApi.runCommand(sandbox.id, command, args);
} catch (error) {
if (error.code === 'QUOTA_EXCEEDED') {
throw new Error(
'API quota exceeded for my-provider.\n' +
'Upgrade your plan at https://example.com/pricing'
);
}
throw error;
}
}
If your provider doesn't support certain features:
// Don't implement filesystem methods - ComputeSDK will auto-generate
// helpful error messages for users
/**
* My Provider - Fast cloud sandboxes
*
* Features:
* - Python and Node.js runtimes
* - Full filesystem support
* - GPU acceleration (premium plans)
* - No terminal support
*/
export const myProvider = defineProvider({ /* ... */ });
Create tests to verify your provider implementation:
import { describe, it, expect } from 'vitest';
import { myProvider } from './index';
describe('MyProvider', () => {
it('creates and destroys sandboxes', async () => {
const compute = myProvider({ apiKey: process.env.MY_PROVIDER_API_KEY! });
const sandbox = await compute.sandbox.create();
expect(sandbox.sandboxId).toBeDefined();
const info = await sandbox.getInfo();
expect(info.status).toBe('running');
await sandbox.destroy();
});
it('executes code', async () => {
const compute = myProvider({ apiKey: process.env.MY_PROVIDER_API_KEY! });
const sandbox = await compute.sandbox.create();
const result = await sandbox.runCommand('python -c "print(\"Hello\")"');
expect(result.stdout).toContain('Hello');
expect(result.exitCode).toBe(0);
await sandbox.destroy();
});
});
See these provider implementations for reference:
MIT
FAQs
Provider framework for ComputeSDK - define custom sandbox providers
The npm package @computesdk/provider receives a total of 2,389 weekly downloads. As such, @computesdk/provider popularity was classified as popular.
We found that @computesdk/provider demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
A mini Shai-Hulud campaign compromised Red Hat Cloud Services npm packages to steal developer and CI/CD secrets during installation.

Research
/Security News
The North Korean malware loader hides in a Packagist-listed package and its GitHub branch to fetch and execute remote code in a likely Contagious Interview-style lure.

Security News
The Rust project is moving toward formal rules on LLM use in contributions after months of internal debate over maintainer burden, code quality, and contributor experience.