@anyany/sandbox_provider
v0.1.2
Published
Unified abstraction layer for cloud sandbox providers with adapter pattern and feature polyfilling
Maintainers
Readme
sandbox_provider
A unified, high-level abstraction layer for cloud sandbox providers with strict OOP/SOLID principles, Adapter Pattern, and comprehensive feature polyfilling.
Features
- Adapter Pattern: Clean abstraction over provider-specific implementations
- Feature Polyfilling: Automatic emulation of missing features via command execution
- SOLID Principles: Interface segregation, dependency inversion, open/closed
- Full TypeScript: Type-safe with strict configuration
- TDD: Comprehensive test suite with Bun test runner
- Provider Support:
- OpenSandbox (full native support)
- MinimalProvider (command-only with polyfills)
- Extensible for Daytona, Modal, Runloop, etc.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ CONSUMER API │
│ - SandboxProviderFactory, ISandbox interface │
├─────────────────────────────────────────────────────────────────┤
│ SERVICE INTERFACES (Abstract Contracts) │
│ - ISandboxLifecycle, ICommandExecution, IFileSystem, etc. │
├─────────────────────────────────────────────────────────────────┤
│ ADAPTER LAYER (Provider Implementations) │
│ - OpenSandboxAdapter, MinimalProviderAdapter │
├─────────────────────────────────────────────────────────────────┤
│ CAPABILITY BRIDGE (Polyfill Engine) │
│ - CommandPolyfillService implements FS via exec │
├─────────────────────────────────────────────────────────────────┤
│ TRANSPORT & ERRORS │
│ - Exception hierarchy, connection management │
└─────────────────────────────────────────────────────────────────┘Installation
bun installUsage
Basic Usage with OpenSandbox
import { createSandbox } from 'sandbox_provider';
// Create a sandbox
const sandbox = createSandbox({
provider: 'opensandbox',
connection: {
apiKey: process.env.OPEN_SANDBOX_API_KEY,
},
});
// Create and initialize
await sandbox.create({
image: { repository: 'node', tag: '18' },
entrypoint: ['node', '--version'],
});
// Execute commands
const result = await sandbox.execute('npm install');
console.log(result.stdout);
// File operations
await sandbox.writeFiles([
{ path: '/app/index.js', data: 'console.log("Hello")' },
]);
const files = await sandbox.readFiles(['/app/index.js']);
// Cleanup
await sandbox.delete();
await sandbox.close();Minimal Provider (SSH/Command-only)
import { MinimalProviderAdapter } from 'sandbox_provider';
// Connect to a minimal provider (e.g., SSH-based sandbox)
const adapter = new MinimalProviderAdapter();
await adapter.connect({
id: 'my-sandbox',
execute: async (cmd) => {
// Your SSH execution logic here
return { stdout: '', stderr: '', exitCode: 0 };
},
getStatus: async () => ({ state: 'Running' }),
close: async () => {},
});
// Filesystem operations work via polyfill!
await adapter.writeFiles([
{ path: '/tmp/test.txt', data: 'Hello' },
]);
const files = await adapter.readFiles(['/tmp/test.txt']);Feature Detection
const sandbox = createSandbox({ provider: 'opensandbox' });
// Check capabilities
if (sandbox.capabilities.nativeFileSystem) {
console.log('Native FS available');
}
if (sandbox.capabilities.supportsStreamingOutput) {
await sandbox.executeStream('long-running', {
onStdout: (msg) => console.log(msg.text),
});
}API Reference
Interfaces
ISandbox
The main interface combining all capabilities:
interface ISandbox
extends ISandboxLifecycle,
ICommandExecution,
IFileSystem,
IHealthCheck {
readonly provider: string;
readonly capabilities: ProviderCapabilities;
close(): Promise<void>;
}ICommandExecution
interface ICommandExecution {
execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
executeStream(command: string, handlers: StreamHandlers, options?: ExecuteOptions): Promise<void>;
executeBackground(command: string, options?: ExecuteOptions): Promise<{ sessionId: string; kill(): Promise<void> }>;
interrupt(sessionId: string): Promise<void>;
}IFileSystem
interface IFileSystem {
readFiles(paths: string[], options?: ReadFileOptions): Promise<FileReadResult[]>;
writeFiles(entries: FileWriteEntry[]): Promise<FileWriteResult[]>;
deleteFiles(paths: string[]): Promise<FileDeleteResult[]>;
createDirectories(paths: string[], options?: { mode?: number; owner?: string; group?: string }): Promise<void>;
listDirectory(path: string): Promise<DirectoryEntry[]>;
getFileInfo(paths: string[]): Promise<Map<string, FileInfo>>;
search(pattern: string, path?: string): Promise<SearchResult[]>;
// ... and more
}Error Handling
import {
SandboxException,
FeatureNotSupportedError,
FileOperationError,
CommandExecutionError,
TimeoutError,
} from 'sandbox_provider';
try {
await sandbox.readFiles(['/secret']);
} catch (error) {
if (error instanceof FileOperationError) {
console.log(`File error: ${error.fileErrorCode}`);
}
}Provider Capabilities
| Feature | OpenSandbox | MinimalProvider | |---------|-------------|-----------------| | Native Filesystem | ✅ | ❌ (polyfilled) | | Streaming Output | ✅ | ❌ (fallback) | | Background Exec | ✅ | ⚠️ (simulated) | | Pause/Resume | ✅ | ❌ | | Health Check | ✅ | ⚠️ (polyfilled) | | Metrics | ✅ | ⚠️ (polyfilled) | | File Search | ✅ | ⚠️ (polyfilled) |
Development
Run Tests
# Run all tests
bun test
# Watch mode
bun test --watch
# Coverage
bun test --coverageBuild
bun run buildLint
bun run lintAdding a New Provider
To add a new provider:
- Create
src/adapters/FooBarAdapter.ts - Extend
BaseSandboxAdapter - Implement native methods
- Set appropriate capability flags
- Register in
SandboxProviderFactory
export class FooBarAdapter extends BaseSandboxAdapter {
readonly provider = 'foobar';
readonly capabilities: ProviderCapabilities = {
nativeFileSystem: true,
supportsStreamingOutput: true,
// ... etc
};
// Implement abstract methods...
}License
MIT
