@fastgpt-sdk/sandbox-adapter 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -0
- package/dist/adapters/BaseSandboxAdapter.d.ts +59 -0
- package/dist/adapters/FastGPTSandboxAdapter/index.d.ts +85 -0
- package/dist/adapters/MinimalProviderAdapter.d.ts +52 -0
- package/dist/adapters/OpenSandboxAdapter.d.ts +229 -0
- package/dist/adapters/index.d.ts +26 -0
- package/dist/errors/CommandExecutionError.d.ts +16 -0
- package/dist/errors/ConnectionError.d.ts +8 -0
- package/dist/errors/FeatureNotSupportedError.d.ts +10 -0
- package/dist/errors/FileOperationError.d.ts +13 -0
- package/dist/errors/SandboxException.d.ts +17 -0
- package/dist/errors/SandboxStateError.d.ts +9 -0
- package/dist/errors/TimeoutError.d.ts +15 -0
- package/dist/errors/index.d.ts +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1225 -0
- package/dist/interfaces/ICommandExecution.d.ts +41 -0
- package/dist/interfaces/IFileSystem.d.ts +99 -0
- package/dist/interfaces/IHealthCheck.d.ts +23 -0
- package/dist/interfaces/ISandbox.d.ts +23 -0
- package/dist/interfaces/ISandboxLifecycle.d.ts +54 -0
- package/dist/interfaces/index.d.ts +5 -0
- package/dist/polyfill/CommandPolyfillService.d.ts +122 -0
- package/dist/types/execution.d.ts +61 -0
- package/dist/types/filesystem.d.ts +106 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/sandbox.d.ts +92 -0
- package/dist/utils/base64.d.ts +20 -0
- package/dist/utils/streams.d.ts +26 -0
- package/package.json +87 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @fastgpt/sandbox
|
|
2
|
+
|
|
3
|
+
A unified, high-level abstraction layer for cloud sandbox providers. It offers a consistent, vendor-agnostic interface for creating, managing, and interacting with sandboxed environments like OpenSandbox.
|
|
4
|
+
|
|
5
|
+
> This package is ESM-only (`"type": "module"`) and requires Node.js **>= 20**.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @fastgpt/sandbox
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
The following example demonstrates the complete lifecycle of a sandbox: creating, executing commands, managing files, and finally, deleting it.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createSandbox } from '@fastgpt/sandbox';
|
|
19
|
+
|
|
20
|
+
async function main() {
|
|
21
|
+
// 1. Create a sandbox with the OpenSandbox provider
|
|
22
|
+
const sandbox = createSandbox({
|
|
23
|
+
provider: 'opensandbox',
|
|
24
|
+
connection: {
|
|
25
|
+
apiKey: process.env.OPEN_SANDBOX_API_KEY,
|
|
26
|
+
baseUrl: 'http://127.0.0.1:8080', // Your OpenSandbox server
|
|
27
|
+
runtime: 'kubernetes',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log(`Provider: ${sandbox.provider}`);
|
|
32
|
+
try {
|
|
33
|
+
// 2. Create the sandbox instance with a specific image
|
|
34
|
+
await sandbox.create({
|
|
35
|
+
image: { repository: 'nginx', tag: 'latest' },
|
|
36
|
+
timeout: 3600, // Expiration in seconds
|
|
37
|
+
});
|
|
38
|
+
console.log(`Sandbox created: ${sandbox.id}`);
|
|
39
|
+
|
|
40
|
+
// 3. Wait until the sandbox is fully ready
|
|
41
|
+
await sandbox.waitUntilReady(60000); // 60-second timeout
|
|
42
|
+
console.log('Sandbox is ready.');
|
|
43
|
+
|
|
44
|
+
// 4. Execute a simple command
|
|
45
|
+
const version = await sandbox.execute('nginx -v');
|
|
46
|
+
console.log(`Nginx version: ${version.stdout || version.stderr}`);
|
|
47
|
+
|
|
48
|
+
// 5. Execute a command with streaming output
|
|
49
|
+
console.log('--- Streaming Execution ---');
|
|
50
|
+
await sandbox.executeStream('for i in 1 2 3; do echo "Line $i"; sleep 0.5; done', {
|
|
51
|
+
onStdout: (msg) => console.log(` [stdout] ${msg.text}`),
|
|
52
|
+
onStderr: (msg) => console.log(` [stderr] ${msg.text}`),
|
|
53
|
+
onComplete: (result) => console.log(` [done] Exit code: ${result.exitCode}`),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// 6. Work with the filesystem
|
|
57
|
+
console.log('\n--- Filesystem Operations ---');
|
|
58
|
+
// Write a file
|
|
59
|
+
await sandbox.writeFiles([
|
|
60
|
+
{
|
|
61
|
+
path: '/app/hello.js',
|
|
62
|
+
data: `console.log('Hello from sandbox!');`,
|
|
63
|
+
},
|
|
64
|
+
]);
|
|
65
|
+
console.log('Written /app/hello.js');
|
|
66
|
+
|
|
67
|
+
// Read the file back
|
|
68
|
+
const [file] = await sandbox.readFiles(['/app/hello.js']);
|
|
69
|
+
if (file && !file.error) {
|
|
70
|
+
const content = new TextDecoder().decode(file.content);
|
|
71
|
+
console.log(`Read content: "${content}"`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// List directory
|
|
75
|
+
const entries = await sandbox.listDirectory('/app');
|
|
76
|
+
console.log('Directory listing for /app:', entries.map(e => e.name));
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
// 7. Stop and delete the sandbox
|
|
80
|
+
console.log('\n--- Cleanup ---');
|
|
81
|
+
await sandbox.stop();
|
|
82
|
+
console.log('Sandbox stopped.');
|
|
83
|
+
|
|
84
|
+
if (sandbox.runtime !== 'kubernetes') {
|
|
85
|
+
await sandbox.delete();
|
|
86
|
+
console.log('Sandbox deleted.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('An error occurred:', error);
|
|
91
|
+
} finally {
|
|
92
|
+
// 8. Close the connection
|
|
93
|
+
await sandbox.close();
|
|
94
|
+
console.log('Connection closed.');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
main();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## API (`ISandbox`)
|
|
102
|
+
|
|
103
|
+
The `createSandbox(options)` function returns an instance that implements the `ISandbox` interface.
|
|
104
|
+
|
|
105
|
+
### Lifecycle Management
|
|
106
|
+
|
|
107
|
+
- **`create(options)`**: Creates a new sandbox instance.
|
|
108
|
+
- **`getInfo()`**: Retrieves detailed information about the sandbox.
|
|
109
|
+
- **`waitUntilReady(timeout)`**: Waits for the sandbox to become fully operational.
|
|
110
|
+
- **`renewExpiration(seconds)`**: Extends the sandbox's lifetime.
|
|
111
|
+
- **`pause()` / `resume()`**: Pauses and resumes a running sandbox (if supported).
|
|
112
|
+
- **`stop()`**: Stops the sandbox gracefully.
|
|
113
|
+
- **`delete()`**: Deletes the sandbox instance.
|
|
114
|
+
- **`close()`**: Closes the connection to the provider.
|
|
115
|
+
|
|
116
|
+
### Command Execution
|
|
117
|
+
|
|
118
|
+
- **`execute(command)`**: Executes a command and returns the result after completion.
|
|
119
|
+
- **`executeStream(command, handlers)`**: Executes a command and streams `stdout` and `stderr` in real-time.
|
|
120
|
+
- **`executeBackground(command)`**: Starts a command in the background and returns a session handle.
|
|
121
|
+
|
|
122
|
+
### Filesystem Operations
|
|
123
|
+
|
|
124
|
+
- **`writeFiles(files)`**: Writes one or more files to the sandbox.
|
|
125
|
+
- **`readFiles(paths)`**: Reads one or more files from the sandbox.
|
|
126
|
+
- **`listDirectory(path)`**: Lists the contents of a directory.
|
|
127
|
+
- **`createDirectories(paths)`**: Creates directories.
|
|
128
|
+
- **`deleteFiles(paths)`**: Deletes files.
|
|
129
|
+
- **`moveFiles(files)`**: Moves or renames files.
|
|
130
|
+
|
|
131
|
+
### Health and Metrics
|
|
132
|
+
|
|
133
|
+
- **`ping()`**: Performs a quick health check.
|
|
134
|
+
- **`getMetrics()`**: Retrieves CPU and memory usage statistics.
|
|
135
|
+
|
|
136
|
+
## Polyfill Behavior
|
|
137
|
+
|
|
138
|
+
The SDK uses `CommandPolyfillService` to provide filesystem, search, health, and metrics
|
|
139
|
+
operations by running shell commands inside the sandbox. Providers can override these
|
|
140
|
+
methods if they have native APIs, but the default behavior is consistent across adapters.
|
|
141
|
+
|
|
142
|
+
## Error Handling
|
|
143
|
+
|
|
144
|
+
The SDK exports specific error types to facilitate robust error handling:
|
|
145
|
+
|
|
146
|
+
- `SandboxException`
|
|
147
|
+
- `FeatureNotSupportedError`
|
|
148
|
+
- `FileOperationError`
|
|
149
|
+
- `CommandExecutionError`
|
|
150
|
+
- `TimeoutError`
|
|
151
|
+
|
|
152
|
+
Example:
|
|
153
|
+
```ts
|
|
154
|
+
import { FileOperationError } from '@fastgpt/sandbox';
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
await sandbox.readFiles(['/nonexistent-file']);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (error instanceof FileOperationError) {
|
|
160
|
+
console.error(`File operation failed: ${error.message}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ISandbox } from '../interfaces/ISandbox';
|
|
2
|
+
import { CommandPolyfillService } from '../polyfill/CommandPolyfillService';
|
|
3
|
+
import type { ContentReplaceEntry, DirectoryEntry, ExecuteOptions, ExecuteResult, FileDeleteResult, FileInfo, FileReadResult, FileWriteEntry, FileWriteResult, MoveEntry, PermissionEntry, ReadFileOptions, SandboxConfig, SandboxId, SandboxInfo, SandboxMetrics, SandboxStatus, SearchResult, StreamHandlers } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Abstract base class for all sandbox adapters.
|
|
6
|
+
*
|
|
7
|
+
* Provides default polyfilled implementations for common filesystem,
|
|
8
|
+
* search, health, and metrics operations via CommandPolyfillService.
|
|
9
|
+
* Subclasses can override the polyfill service in their constructor.
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class BaseSandboxAdapter implements ISandbox {
|
|
12
|
+
abstract readonly id: SandboxId;
|
|
13
|
+
abstract readonly provider: string;
|
|
14
|
+
protected _status: SandboxStatus;
|
|
15
|
+
protected polyfillService?: CommandPolyfillService;
|
|
16
|
+
constructor();
|
|
17
|
+
get status(): SandboxStatus;
|
|
18
|
+
abstract create(config: SandboxConfig): Promise<void>;
|
|
19
|
+
abstract start(): Promise<void>;
|
|
20
|
+
abstract stop(): Promise<void>;
|
|
21
|
+
abstract pause(): Promise<void>;
|
|
22
|
+
abstract resume(): Promise<void>;
|
|
23
|
+
abstract delete(): Promise<void>;
|
|
24
|
+
abstract getInfo(): Promise<SandboxInfo | null>;
|
|
25
|
+
abstract close(): Promise<void>;
|
|
26
|
+
waitUntilReady(timeoutMs?: number): Promise<void>;
|
|
27
|
+
renewExpiration(_additionalSeconds: number): Promise<void>;
|
|
28
|
+
abstract execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
29
|
+
executeStream(command: string, handlers: StreamHandlers, options?: ExecuteOptions): Promise<void>;
|
|
30
|
+
executeBackground(_command: string, _options?: ExecuteOptions): Promise<{
|
|
31
|
+
sessionId: string;
|
|
32
|
+
kill(): Promise<void>;
|
|
33
|
+
}>;
|
|
34
|
+
interrupt(_sessionId: string): Promise<void>;
|
|
35
|
+
readFiles(paths: string[], options?: ReadFileOptions): Promise<FileReadResult[]>;
|
|
36
|
+
writeFiles(entries: FileWriteEntry[]): Promise<FileWriteResult[]>;
|
|
37
|
+
deleteFiles(paths: string[]): Promise<FileDeleteResult[]>;
|
|
38
|
+
moveFiles(entries: MoveEntry[]): Promise<void>;
|
|
39
|
+
replaceContent(entries: ContentReplaceEntry[]): Promise<void>;
|
|
40
|
+
createDirectories(paths: string[], options?: {
|
|
41
|
+
mode?: number;
|
|
42
|
+
owner?: string;
|
|
43
|
+
group?: string;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
deleteDirectories(paths: string[], options?: {
|
|
46
|
+
recursive?: boolean;
|
|
47
|
+
force?: boolean;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
listDirectory(path: string): Promise<DirectoryEntry[]>;
|
|
50
|
+
readFileStream(path: string): AsyncIterable<Uint8Array>;
|
|
51
|
+
writeFileStream(path: string, stream: ReadableStream<Uint8Array>): Promise<void>;
|
|
52
|
+
getFileInfo(paths: string[]): Promise<Map<string, FileInfo>>;
|
|
53
|
+
setPermissions(entries: PermissionEntry[]): Promise<void>;
|
|
54
|
+
search(pattern: string, path?: string): Promise<SearchResult[]>;
|
|
55
|
+
ping(): Promise<boolean>;
|
|
56
|
+
getMetrics(): Promise<SandboxMetrics>;
|
|
57
|
+
protected sleep(ms: number): Promise<void>;
|
|
58
|
+
protected requirePolyfillService(feature: string, message: string): CommandPolyfillService;
|
|
59
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ExecuteOptions, ExecuteResult, SandboxConfig, SandboxId, SandboxInfo } from '../../types';
|
|
2
|
+
import { BaseSandboxAdapter } from '../BaseSandboxAdapter';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for FastGPT Sandbox Adapter.
|
|
5
|
+
*/
|
|
6
|
+
export interface FastGPTSandboxConfig {
|
|
7
|
+
/** Base URL for the FastGPT Sandbox Server API */
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
/** Authentication token */
|
|
10
|
+
token: string;
|
|
11
|
+
/** Container name (used as sandbox ID) */
|
|
12
|
+
containerName: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class FastGPTSandboxAdapter extends BaseSandboxAdapter {
|
|
15
|
+
private config;
|
|
16
|
+
/** Provider identifier */
|
|
17
|
+
readonly provider: "fastgpt";
|
|
18
|
+
/** SDK instance */
|
|
19
|
+
private sdk;
|
|
20
|
+
/** Container name (used as sandbox ID) */
|
|
21
|
+
private _id;
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new FastGPTSandboxAdapter instance.
|
|
24
|
+
*
|
|
25
|
+
* @param config - Connection configuration
|
|
26
|
+
*/
|
|
27
|
+
constructor(config: FastGPTSandboxConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Get the sandbox ID (container name).
|
|
30
|
+
*/
|
|
31
|
+
get id(): SandboxId;
|
|
32
|
+
/**
|
|
33
|
+
* Get detailed information about the sandbox.
|
|
34
|
+
*/
|
|
35
|
+
getInfo(): Promise<SandboxInfo | null>;
|
|
36
|
+
/**
|
|
37
|
+
* Create a new sandbox container.
|
|
38
|
+
*
|
|
39
|
+
* Note: The FastGPT SDK only accepts container name for creation.
|
|
40
|
+
* Image and resource configuration are handled server-side.
|
|
41
|
+
*
|
|
42
|
+
* @param _config - Sandbox configuration (not fully used by this SDK)
|
|
43
|
+
*/
|
|
44
|
+
create(_config: SandboxConfig): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Start a stopped or paused sandbox.
|
|
47
|
+
* Uses SDK's start method which resumes paused containers.
|
|
48
|
+
*/
|
|
49
|
+
start(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Stop the sandbox.
|
|
52
|
+
* Note: FastGPT SDK uses pause instead of stop.
|
|
53
|
+
*/
|
|
54
|
+
stop(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Pause a running sandbox.
|
|
57
|
+
*/
|
|
58
|
+
pause(): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Resume a paused sandbox.
|
|
61
|
+
*/
|
|
62
|
+
resume(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Delete the sandbox permanently.
|
|
65
|
+
*/
|
|
66
|
+
delete(): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Close the connection and release resources.
|
|
69
|
+
*/
|
|
70
|
+
close(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Execute a command and wait for completion.
|
|
73
|
+
*
|
|
74
|
+
* @param command - The command to execute
|
|
75
|
+
* @param options - Execution options
|
|
76
|
+
* @returns Execution result with stdout, stderr, and exit code
|
|
77
|
+
*/
|
|
78
|
+
execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Check if the sandbox is healthy.
|
|
81
|
+
*
|
|
82
|
+
* @returns true if healthy, false otherwise
|
|
83
|
+
*/
|
|
84
|
+
ping(): Promise<boolean>;
|
|
85
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ExecuteOptions, ExecuteResult, SandboxConfig, SandboxId, SandboxInfo, SandboxStatus } from '../types';
|
|
2
|
+
import { BaseSandboxAdapter } from './BaseSandboxAdapter';
|
|
3
|
+
/**
|
|
4
|
+
* Connection interface for minimal providers.
|
|
5
|
+
* Represents a provider that only supports basic command execution.
|
|
6
|
+
*/
|
|
7
|
+
export interface MinimalProviderConnection {
|
|
8
|
+
/** Unique identifier for the sandbox */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Execute a command and return result */
|
|
11
|
+
execute(command: string): Promise<{
|
|
12
|
+
stdout: string;
|
|
13
|
+
stderr: string;
|
|
14
|
+
exitCode: number;
|
|
15
|
+
}>;
|
|
16
|
+
/** Get current status */
|
|
17
|
+
getStatus(): Promise<SandboxStatus>;
|
|
18
|
+
/** Close the connection */
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export type MinimalProviderConfig = {
|
|
22
|
+
connectionFactory?: () => Promise<MinimalProviderConnection>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Minimal provider adapter.
|
|
26
|
+
*
|
|
27
|
+
* This demonstrates how to adapt a provider with minimal capabilities
|
|
28
|
+
* (only command execution) to the full ISandbox interface using
|
|
29
|
+
* the CommandPolyfillService.
|
|
30
|
+
*
|
|
31
|
+
* Use case: Legacy SSH-based sandboxes, custom container providers,
|
|
32
|
+
* or any provider that only exposes a shell interface.
|
|
33
|
+
*/
|
|
34
|
+
export declare class MinimalProviderAdapter extends BaseSandboxAdapter {
|
|
35
|
+
private config?;
|
|
36
|
+
readonly provider = "minimal";
|
|
37
|
+
private _id;
|
|
38
|
+
private connection?;
|
|
39
|
+
constructor(config?: MinimalProviderConfig | undefined);
|
|
40
|
+
get id(): SandboxId;
|
|
41
|
+
get status(): SandboxStatus;
|
|
42
|
+
create(config: SandboxConfig): Promise<void>;
|
|
43
|
+
connect(connection: MinimalProviderConnection): Promise<void>;
|
|
44
|
+
start(): Promise<void>;
|
|
45
|
+
stop(): Promise<void>;
|
|
46
|
+
pause(): Promise<void>;
|
|
47
|
+
resume(): Promise<void>;
|
|
48
|
+
delete(): Promise<void>;
|
|
49
|
+
getInfo(): Promise<SandboxInfo>;
|
|
50
|
+
close(): Promise<void>;
|
|
51
|
+
execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type { ExecuteOptions, ExecuteResult, SandboxConfig, SandboxId, SandboxInfo, SandboxMetrics, StreamHandlers } from '../types';
|
|
2
|
+
import { BaseSandboxAdapter } from './BaseSandboxAdapter';
|
|
3
|
+
/**
|
|
4
|
+
* Sandbox runtime type.
|
|
5
|
+
* - docker: Full-featured runtime with pause/resume support
|
|
6
|
+
* - kubernetes: Container orchestration runtime (no pause/resume, stop = delete)
|
|
7
|
+
*/
|
|
8
|
+
export type SandboxRuntimeType = 'docker' | 'kubernetes';
|
|
9
|
+
/**
|
|
10
|
+
* Connection configuration options for OpenSandboxAdapter.
|
|
11
|
+
*/
|
|
12
|
+
export interface OpenSandboxConnectionConfig {
|
|
13
|
+
/** Base URL for the OpenSandbox API (e.g., 'https://api.opensandbox.example.com') */
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
/** API key for authentication */
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Sandbox runtime type.
|
|
19
|
+
* - docker: Full-featured with pause/resume support
|
|
20
|
+
* - kubernetes: No pause/resume, stop operation deletes the sandbox
|
|
21
|
+
* @default 'docker'
|
|
22
|
+
*/
|
|
23
|
+
runtime?: SandboxRuntimeType;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* OpenSandbox provider adapter.
|
|
27
|
+
*
|
|
28
|
+
* This is the "Gold Standard" implementation with full native
|
|
29
|
+
* support for all features. Uses the OpenSandbox TypeScript SDK
|
|
30
|
+
* for all operations.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const adapter = new OpenSandboxAdapter({
|
|
35
|
+
* baseUrl: 'https://api.opensandbox.example.com',
|
|
36
|
+
* apiKey: 'your-api-key'
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* await adapter.create({
|
|
40
|
+
* image: { repository: 'node', tag: '18-alpine' }
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* const result = await adapter.execute('node --version');
|
|
44
|
+
* console.log(result.stdout); // v18.x.x
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
|
|
48
|
+
private connectionConfig;
|
|
49
|
+
/** Provider identifier */
|
|
50
|
+
readonly provider: "opensandbox";
|
|
51
|
+
/** Runtime type for this adapter instance */
|
|
52
|
+
readonly runtime: SandboxRuntimeType;
|
|
53
|
+
/** Internal SDK sandbox instance */
|
|
54
|
+
private _sandbox?;
|
|
55
|
+
/** SDK connection configuration */
|
|
56
|
+
private _connection;
|
|
57
|
+
/** Cached sandbox ID */
|
|
58
|
+
private _id;
|
|
59
|
+
/** Current adapter state */
|
|
60
|
+
private _connectionState;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new OpenSandboxAdapter instance.
|
|
63
|
+
*
|
|
64
|
+
* @param connectionConfig - Connection configuration options
|
|
65
|
+
*/
|
|
66
|
+
constructor(connectionConfig?: OpenSandboxConnectionConfig);
|
|
67
|
+
/**
|
|
68
|
+
* Get the sandbox ID. Returns empty string if not created/connected.
|
|
69
|
+
*/
|
|
70
|
+
get id(): SandboxId;
|
|
71
|
+
/**
|
|
72
|
+
* Get the current connection state.
|
|
73
|
+
*/
|
|
74
|
+
get connectionState(): typeof this._connectionState;
|
|
75
|
+
/**
|
|
76
|
+
* Get the underlying SDK sandbox instance.
|
|
77
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
78
|
+
*/
|
|
79
|
+
private get sandbox();
|
|
80
|
+
/**
|
|
81
|
+
* Create ConnectionConfig from adapter's connection options.
|
|
82
|
+
* Handles URL parsing with fallback to domain string.
|
|
83
|
+
*/
|
|
84
|
+
private createConnectionConfig;
|
|
85
|
+
/**
|
|
86
|
+
* Convert ImageSpec to SDK image format (string).
|
|
87
|
+
* Format: repository[:tag][@digest]
|
|
88
|
+
*/
|
|
89
|
+
private convertImageSpec;
|
|
90
|
+
/**
|
|
91
|
+
* Parse SDK image string into ImageSpec.
|
|
92
|
+
* Handles formats: repository, repository:tag, repository@digest
|
|
93
|
+
*/
|
|
94
|
+
private parseImageSpec;
|
|
95
|
+
/**
|
|
96
|
+
* Convert ResourceLimits to SDK resource format.
|
|
97
|
+
* Maps cpuCount -> cpu, memoryMiB -> memory, diskGiB -> disk
|
|
98
|
+
*/
|
|
99
|
+
private convertResourceLimits;
|
|
100
|
+
/**
|
|
101
|
+
* Parse SDK resource limits (Record<string, string>) to ResourceLimits.
|
|
102
|
+
* Handles memory format: 512Mi, 2Gi
|
|
103
|
+
*/
|
|
104
|
+
private parseResourceLimits;
|
|
105
|
+
/**
|
|
106
|
+
* Create a new sandbox with the given configuration.
|
|
107
|
+
*
|
|
108
|
+
* @param config - Sandbox configuration
|
|
109
|
+
* @throws {ConnectionError} If connection to the API fails
|
|
110
|
+
* @throws {CommandExecutionError} If sandbox creation fails
|
|
111
|
+
*/
|
|
112
|
+
create(config: SandboxConfig): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Connect to an existing OpenSandbox instance.
|
|
115
|
+
*
|
|
116
|
+
* @param sandboxId - The ID of the sandbox to connect to
|
|
117
|
+
* @throws {ConnectionError} If connection fails or sandbox not found
|
|
118
|
+
*/
|
|
119
|
+
connect(sandboxId: string): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Start a stopped or paused sandbox.
|
|
122
|
+
* For OpenSandbox, this resumes from paused state if applicable.
|
|
123
|
+
*
|
|
124
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
125
|
+
*/
|
|
126
|
+
start(): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Stop the sandbox (graceful shutdown).
|
|
129
|
+
*
|
|
130
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
131
|
+
*/
|
|
132
|
+
stop(): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Pause a running sandbox.
|
|
135
|
+
*
|
|
136
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
137
|
+
* @throws {FeatureNotSupportedError} If pause is not supported by the runtime
|
|
138
|
+
* @throws {CommandExecutionError} If pause fails
|
|
139
|
+
*/
|
|
140
|
+
pause(): Promise<void>;
|
|
141
|
+
/**
|
|
142
|
+
* Resume a paused sandbox.
|
|
143
|
+
*
|
|
144
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
145
|
+
* @throws {FeatureNotSupportedError} If resume is not supported by the runtime
|
|
146
|
+
* @throws {CommandExecutionError} If resume fails
|
|
147
|
+
*/
|
|
148
|
+
resume(): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Delete the sandbox permanently.
|
|
151
|
+
*
|
|
152
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
153
|
+
* @throws {CommandExecutionError} If deletion fails
|
|
154
|
+
*/
|
|
155
|
+
delete(): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Get detailed information about the sandbox.
|
|
158
|
+
*
|
|
159
|
+
* @returns Sandbox information
|
|
160
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
161
|
+
*/
|
|
162
|
+
getInfo(): Promise<SandboxInfo>;
|
|
163
|
+
/**
|
|
164
|
+
* Close the connection and release resources.
|
|
165
|
+
*/
|
|
166
|
+
close(): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* Renew the sandbox expiration.
|
|
169
|
+
*
|
|
170
|
+
* @param additionalSeconds - Seconds to extend the expiration by
|
|
171
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
172
|
+
* @throws {CommandExecutionError} If renewal fails
|
|
173
|
+
*/
|
|
174
|
+
renewExpiration(additionalSeconds: number): Promise<void>;
|
|
175
|
+
/**
|
|
176
|
+
* Execute a command and wait for completion.
|
|
177
|
+
*
|
|
178
|
+
* @param command - The command to execute
|
|
179
|
+
* @param options - Execution options
|
|
180
|
+
* @returns Execution result with stdout, stderr, and exit code
|
|
181
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
182
|
+
* @throws {CommandExecutionError} If execution fails
|
|
183
|
+
*/
|
|
184
|
+
execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
185
|
+
/**
|
|
186
|
+
* Execute a command with streaming output.
|
|
187
|
+
*
|
|
188
|
+
* @param command - The command to execute
|
|
189
|
+
* @param handlers - Stream handlers for output
|
|
190
|
+
* @param options - Execution options
|
|
191
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
192
|
+
* @throws {CommandExecutionError} If execution fails
|
|
193
|
+
*/
|
|
194
|
+
executeStream(command: string, handlers: StreamHandlers, options?: ExecuteOptions): Promise<void>;
|
|
195
|
+
/**
|
|
196
|
+
* Execute a command in the background.
|
|
197
|
+
*
|
|
198
|
+
* @param command - The command to execute
|
|
199
|
+
* @param options - Execution options
|
|
200
|
+
* @returns Handle with sessionId and kill function
|
|
201
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
202
|
+
* @throws {CommandExecutionError} If execution fails
|
|
203
|
+
*/
|
|
204
|
+
executeBackground(command: string, options?: ExecuteOptions): Promise<{
|
|
205
|
+
sessionId: string;
|
|
206
|
+
kill(): Promise<void>;
|
|
207
|
+
}>;
|
|
208
|
+
/**
|
|
209
|
+
* Interrupt/kill a running command session.
|
|
210
|
+
*
|
|
211
|
+
* @param sessionId - The session ID from executeBackground
|
|
212
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
213
|
+
* @throws {CommandExecutionError} If interruption fails
|
|
214
|
+
*/
|
|
215
|
+
interrupt(sessionId: string): Promise<void>;
|
|
216
|
+
/**
|
|
217
|
+
* Check if the sandbox is healthy.
|
|
218
|
+
*
|
|
219
|
+
* @returns true if healthy, false otherwise
|
|
220
|
+
*/
|
|
221
|
+
ping(): Promise<boolean>;
|
|
222
|
+
/**
|
|
223
|
+
* Get current resource metrics.
|
|
224
|
+
*
|
|
225
|
+
* @returns Current metrics
|
|
226
|
+
* @throws {SandboxStateError} If sandbox is not initialized
|
|
227
|
+
*/
|
|
228
|
+
getMetrics(): Promise<SandboxMetrics>;
|
|
229
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ISandbox } from '../interfaces';
|
|
2
|
+
import { type FastGPTSandboxConfig } from './FastGPTSandboxAdapter';
|
|
3
|
+
import { type MinimalProviderConfig } from './MinimalProviderAdapter';
|
|
4
|
+
import { type OpenSandboxConnectionConfig } from './OpenSandboxAdapter';
|
|
5
|
+
export { BaseSandboxAdapter } from './BaseSandboxAdapter';
|
|
6
|
+
export { FastGPTSandboxAdapter, type FastGPTSandboxConfig } from './FastGPTSandboxAdapter';
|
|
7
|
+
export { MinimalProviderAdapter, type MinimalProviderConfig, type MinimalProviderConnection } from './MinimalProviderAdapter';
|
|
8
|
+
export { OpenSandboxAdapter, type OpenSandboxConnectionConfig, type SandboxRuntimeType } from './OpenSandboxAdapter';
|
|
9
|
+
type CreateProviderType = {
|
|
10
|
+
provider: 'opensandbox';
|
|
11
|
+
config: OpenSandboxConnectionConfig;
|
|
12
|
+
} | {
|
|
13
|
+
provider: 'minimal';
|
|
14
|
+
config: MinimalProviderConfig;
|
|
15
|
+
} | {
|
|
16
|
+
provider: 'fastgpt';
|
|
17
|
+
config: FastGPTSandboxConfig;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Create a sandbox provider instance.
|
|
21
|
+
*
|
|
22
|
+
* @param config Provider configuration
|
|
23
|
+
* @returns Configured sandbox instance
|
|
24
|
+
* @throws Error if provider type is unknown
|
|
25
|
+
*/
|
|
26
|
+
export declare const createSandbox: ({ provider, config }: CreateProviderType) => ISandbox;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SandboxException } from './SandboxException';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when command execution fails.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CommandExecutionError extends SandboxException {
|
|
6
|
+
readonly command: string;
|
|
7
|
+
readonly exitCode?: number;
|
|
8
|
+
readonly stdout?: string;
|
|
9
|
+
readonly stderr?: string;
|
|
10
|
+
readonly commandError?: Error;
|
|
11
|
+
constructor(message: string, command: string, exitCodeOrCause?: number | Error, stdout?: string, stderr?: string);
|
|
12
|
+
/**
|
|
13
|
+
* Returns the combined output (stdout + stderr).
|
|
14
|
+
*/
|
|
15
|
+
getCombinedOutput(): string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SandboxException } from './SandboxException';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when connection to a sandbox fails.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ConnectionError extends SandboxException {
|
|
6
|
+
readonly endpoint?: string | undefined;
|
|
7
|
+
constructor(message: string, endpoint?: string | undefined, cause?: unknown);
|
|
8
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SandboxException } from './SandboxException';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a provider does not natively support a feature
|
|
4
|
+
* and no polyfill is available.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FeatureNotSupportedError extends SandboxException {
|
|
7
|
+
readonly feature: string;
|
|
8
|
+
readonly provider: string;
|
|
9
|
+
constructor(message: string, feature: string, provider: string);
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SandboxException } from './SandboxException';
|
|
2
|
+
/**
|
|
3
|
+
* Error codes specific to file operations.
|
|
4
|
+
*/
|
|
5
|
+
export type FileErrorCode = 'FILE_NOT_FOUND' | 'FILE_ALREADY_EXISTS' | 'PERMISSION_DENIED' | 'PATH_IS_DIRECTORY' | 'PATH_NOT_DIRECTORY' | 'INVALID_PATH' | 'QUOTA_EXCEEDED' | 'TRANSFER_ERROR';
|
|
6
|
+
/**
|
|
7
|
+
* Thrown when a file operation fails.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FileOperationError extends SandboxException {
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly fileErrorCode: FileErrorCode;
|
|
12
|
+
constructor(message: string, path: string, fileErrorCode: FileErrorCode, cause?: unknown);
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base exception class for all sandbox-related errors.
|
|
3
|
+
* Provides structured error information with codes and optional metadata.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SandboxException extends Error {
|
|
6
|
+
readonly code: SandboxErrorCode;
|
|
7
|
+
constructor(message: string, code?: SandboxErrorCode, cause?: unknown);
|
|
8
|
+
/**
|
|
9
|
+
* Returns a structured representation of the error for logging.
|
|
10
|
+
*/
|
|
11
|
+
toJSON(): Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Error codes for sandbox exceptions.
|
|
15
|
+
* Extensible via string intersection.
|
|
16
|
+
*/
|
|
17
|
+
export type SandboxErrorCode = 'INTERNAL_UNKNOWN_ERROR' | 'CONNECTION_ERROR' | 'TIMEOUT' | 'READY_TIMEOUT' | 'UNHEALTHY' | 'INVALID_ARGUMENT' | 'UNEXPECTED_RESPONSE' | 'FEATURE_NOT_SUPPORTED' | 'SANDBOX_NOT_FOUND' | 'PERMISSION_DENIED' | 'FILE_NOT_FOUND' | 'FILE_ALREADY_EXISTS' | 'COMMAND_FAILED' | (string & {});
|