@drej/opensandbox 0.1.2 → 0.1.4
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/dist/index.d.mts +249 -0
- package/dist/index.mjs +346 -0
- package/package.json +18 -8
- package/dist/control.d.ts +0 -28
- package/dist/exec.d.ts +0 -41
- package/dist/index.d.ts +0 -4
- package/dist/types.d.ts +0 -162
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface Resources {
|
|
3
|
+
cpu?: string;
|
|
4
|
+
memory?: string;
|
|
5
|
+
gpu?: string;
|
|
6
|
+
}
|
|
7
|
+
interface ImageAuth {
|
|
8
|
+
username: string;
|
|
9
|
+
password: string;
|
|
10
|
+
}
|
|
11
|
+
interface ImageSpec {
|
|
12
|
+
uri: string;
|
|
13
|
+
auth?: ImageAuth;
|
|
14
|
+
}
|
|
15
|
+
declare enum SandboxState {
|
|
16
|
+
Pending = "Pending",
|
|
17
|
+
Running = "Running",
|
|
18
|
+
Pausing = "Pausing",
|
|
19
|
+
Paused = "Paused",
|
|
20
|
+
Resuming = "Resuming",
|
|
21
|
+
Stopping = "Stopping",
|
|
22
|
+
Terminated = "Terminated",
|
|
23
|
+
Failed = "Failed",
|
|
24
|
+
Unknown = "Unknown"
|
|
25
|
+
}
|
|
26
|
+
interface SandboxStatus {
|
|
27
|
+
state: SandboxState;
|
|
28
|
+
reason?: string;
|
|
29
|
+
message?: string;
|
|
30
|
+
lastTransitionAt?: string;
|
|
31
|
+
}
|
|
32
|
+
interface Sandbox {
|
|
33
|
+
id: string;
|
|
34
|
+
status: SandboxStatus;
|
|
35
|
+
createdAt: string;
|
|
36
|
+
expiresAt?: string | null;
|
|
37
|
+
image?: ImageSpec;
|
|
38
|
+
snapshotId?: string;
|
|
39
|
+
entrypoint?: string[];
|
|
40
|
+
metadata?: Record<string, string>;
|
|
41
|
+
platform?: unknown;
|
|
42
|
+
}
|
|
43
|
+
interface CreateSandboxOptions {
|
|
44
|
+
image?: ImageSpec;
|
|
45
|
+
snapshotId?: string;
|
|
46
|
+
timeout?: number;
|
|
47
|
+
resourceLimits?: Resources;
|
|
48
|
+
entrypoint?: string[];
|
|
49
|
+
env?: Record<string, string>;
|
|
50
|
+
metadata?: Record<string, string>;
|
|
51
|
+
secureAccess?: boolean;
|
|
52
|
+
}
|
|
53
|
+
interface ListSandboxesOptions {
|
|
54
|
+
state?: SandboxState;
|
|
55
|
+
limit?: number;
|
|
56
|
+
offset?: number;
|
|
57
|
+
}
|
|
58
|
+
declare enum SnapshotState {
|
|
59
|
+
Pending = "Pending",
|
|
60
|
+
Committing = "Committing",
|
|
61
|
+
Pushing = "Pushing",
|
|
62
|
+
Ready = "Ready",
|
|
63
|
+
Failed = "Failed"
|
|
64
|
+
}
|
|
65
|
+
interface Snapshot {
|
|
66
|
+
id: string;
|
|
67
|
+
sandboxId: string;
|
|
68
|
+
state: SnapshotState;
|
|
69
|
+
createdAt: string;
|
|
70
|
+
}
|
|
71
|
+
interface ListSnapshotsOptions {
|
|
72
|
+
sandboxId?: string;
|
|
73
|
+
limit?: number;
|
|
74
|
+
offset?: number;
|
|
75
|
+
}
|
|
76
|
+
interface SandboxEndpoint {
|
|
77
|
+
endpoint: string;
|
|
78
|
+
headers?: Record<string, string>;
|
|
79
|
+
}
|
|
80
|
+
interface DiagnosticLog {
|
|
81
|
+
name: string;
|
|
82
|
+
size: number;
|
|
83
|
+
url?: string;
|
|
84
|
+
inline?: string;
|
|
85
|
+
}
|
|
86
|
+
interface DiagnosticEvent {
|
|
87
|
+
timestamp: string;
|
|
88
|
+
type: string;
|
|
89
|
+
message: string;
|
|
90
|
+
}
|
|
91
|
+
declare enum SSEEventType {
|
|
92
|
+
Init = "init",
|
|
93
|
+
Status = "status",
|
|
94
|
+
Stdout = "stdout",
|
|
95
|
+
Stderr = "stderr",
|
|
96
|
+
Result = "result",
|
|
97
|
+
ExecutionComplete = "execution_complete",
|
|
98
|
+
ExecutionCount = "execution_count",
|
|
99
|
+
Error = "error",
|
|
100
|
+
Ping = "ping",
|
|
101
|
+
Message = "message"
|
|
102
|
+
}
|
|
103
|
+
interface SSEEvent {
|
|
104
|
+
type: SSEEventType;
|
|
105
|
+
text?: string;
|
|
106
|
+
results?: Record<string, string>;
|
|
107
|
+
error?: {
|
|
108
|
+
name?: string;
|
|
109
|
+
message: string;
|
|
110
|
+
evalue?: string;
|
|
111
|
+
};
|
|
112
|
+
execution_count?: number;
|
|
113
|
+
execution_time?: number;
|
|
114
|
+
timestamp: number;
|
|
115
|
+
}
|
|
116
|
+
declare enum CodeLanguage {
|
|
117
|
+
Python = "python",
|
|
118
|
+
JavaScript = "javascript",
|
|
119
|
+
TypeScript = "typescript",
|
|
120
|
+
Go = "go",
|
|
121
|
+
Java = "java",
|
|
122
|
+
Bash = "bash"
|
|
123
|
+
}
|
|
124
|
+
interface CodeContext {
|
|
125
|
+
id: string;
|
|
126
|
+
language: CodeLanguage;
|
|
127
|
+
}
|
|
128
|
+
interface ExecuteCodeOptions {
|
|
129
|
+
code: string;
|
|
130
|
+
context?: {
|
|
131
|
+
id: string;
|
|
132
|
+
language: CodeLanguage;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
interface ExecuteCommandOptions {
|
|
136
|
+
command: string;
|
|
137
|
+
cwd?: string;
|
|
138
|
+
background?: boolean;
|
|
139
|
+
timeout?: number;
|
|
140
|
+
uid?: number;
|
|
141
|
+
gid?: number;
|
|
142
|
+
envs?: Record<string, string>;
|
|
143
|
+
}
|
|
144
|
+
interface CommandStatus {
|
|
145
|
+
session: string;
|
|
146
|
+
status: "running" | "completed" | "failed";
|
|
147
|
+
exitCode?: number;
|
|
148
|
+
}
|
|
149
|
+
interface FileInfo {
|
|
150
|
+
path: string;
|
|
151
|
+
type: "file" | "directory" | "symlink";
|
|
152
|
+
size: number;
|
|
153
|
+
mode: number;
|
|
154
|
+
modified_at: string;
|
|
155
|
+
created_at: string;
|
|
156
|
+
owner: string;
|
|
157
|
+
group: string;
|
|
158
|
+
}
|
|
159
|
+
interface FileReplacement {
|
|
160
|
+
path: string;
|
|
161
|
+
old: string;
|
|
162
|
+
new: string;
|
|
163
|
+
}
|
|
164
|
+
interface Metrics {
|
|
165
|
+
cpu: number;
|
|
166
|
+
memory: number;
|
|
167
|
+
timestamp: string;
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/control.d.ts
|
|
171
|
+
declare class OpenSandboxError extends Error {
|
|
172
|
+
readonly status: number;
|
|
173
|
+
constructor(message: string, status: number);
|
|
174
|
+
}
|
|
175
|
+
declare class ControlClient {
|
|
176
|
+
private baseUrl;
|
|
177
|
+
private apiKey;
|
|
178
|
+
private signal?;
|
|
179
|
+
constructor(options: {
|
|
180
|
+
baseUrl: string;
|
|
181
|
+
apiKey: string;
|
|
182
|
+
signal?: AbortSignal;
|
|
183
|
+
});
|
|
184
|
+
/** Return a new `ControlClient` instance that passes `signal` to every fetch call. */
|
|
185
|
+
withSignal(signal: AbortSignal): ControlClient;
|
|
186
|
+
private request;
|
|
187
|
+
createSandbox(options: CreateSandboxOptions): Promise<Sandbox>;
|
|
188
|
+
listSandboxes(options?: ListSandboxesOptions): Promise<Sandbox[]>;
|
|
189
|
+
getSandbox(id: string): Promise<Sandbox>;
|
|
190
|
+
deleteSandbox(id: string): Promise<void>;
|
|
191
|
+
pauseSandbox(id: string): Promise<void>;
|
|
192
|
+
resumeSandbox(id: string): Promise<void>;
|
|
193
|
+
renewExpiration(id: string): Promise<void>;
|
|
194
|
+
getEndpoint(sandboxId: string, port: number, useServerProxy?: boolean): Promise<SandboxEndpoint>;
|
|
195
|
+
getDiagnosticLogs(sandboxId: string): Promise<DiagnosticLog[]>;
|
|
196
|
+
getDiagnosticEvents(sandboxId: string): Promise<DiagnosticEvent[]>;
|
|
197
|
+
createSnapshot(sandboxId: string): Promise<Snapshot>;
|
|
198
|
+
listSnapshots(options?: ListSnapshotsOptions): Promise<Snapshot[]>;
|
|
199
|
+
getSnapshot(id: string): Promise<Snapshot>;
|
|
200
|
+
deleteSnapshot(id: string): Promise<void>;
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/exec.d.ts
|
|
204
|
+
declare class ExecClient {
|
|
205
|
+
private baseUrl;
|
|
206
|
+
private accessToken;
|
|
207
|
+
private signal?;
|
|
208
|
+
constructor(options: {
|
|
209
|
+
baseUrl?: string;
|
|
210
|
+
accessToken: string;
|
|
211
|
+
signal?: AbortSignal;
|
|
212
|
+
});
|
|
213
|
+
/** Return a new `ExecClient` instance that passes `signal` to every fetch call. */
|
|
214
|
+
withSignal(signal: AbortSignal): ExecClient;
|
|
215
|
+
private get authHeader();
|
|
216
|
+
private request;
|
|
217
|
+
private streamRequest;
|
|
218
|
+
ping(): Promise<{
|
|
219
|
+
status: string;
|
|
220
|
+
}>;
|
|
221
|
+
listContexts(language?: string): Promise<CodeContext[]>;
|
|
222
|
+
clearContexts(language?: string): Promise<void>;
|
|
223
|
+
deleteContext(contextId: string): Promise<void>;
|
|
224
|
+
createContext(language: string): Promise<CodeContext>;
|
|
225
|
+
executeCode(options: ExecuteCodeOptions): AsyncGenerator<SSEEvent>;
|
|
226
|
+
interruptCode(): Promise<void>;
|
|
227
|
+
executeCommand(options: ExecuteCommandOptions): AsyncGenerator<SSEEvent>;
|
|
228
|
+
interruptCommand(): Promise<void>;
|
|
229
|
+
getCommandStatus(session: string): Promise<CommandStatus>;
|
|
230
|
+
getCommandOutput(session: string): Promise<{
|
|
231
|
+
stdout: string;
|
|
232
|
+
stderr: string;
|
|
233
|
+
}>;
|
|
234
|
+
getFileInfo(path: string): Promise<FileInfo>;
|
|
235
|
+
deleteFile(path: string): Promise<void>;
|
|
236
|
+
setPermissions(path: string, mode: string): Promise<void>;
|
|
237
|
+
moveFile(from: string, to: string): Promise<void>;
|
|
238
|
+
searchFiles(pattern: string, path?: string): Promise<string[]>;
|
|
239
|
+
replaceInFiles(replacements: FileReplacement[]): Promise<void>;
|
|
240
|
+
uploadFile(path: string, content: Blob | BufferSource | string): Promise<void>;
|
|
241
|
+
downloadFile(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
242
|
+
listDirectory(path: string, depth?: number): Promise<FileInfo[]>;
|
|
243
|
+
createDirectory(path: string): Promise<void>;
|
|
244
|
+
deleteDirectory(path: string): Promise<void>;
|
|
245
|
+
getMetrics(): Promise<Metrics>;
|
|
246
|
+
watchMetrics(): AsyncGenerator<SSEEvent>;
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
249
|
+
export { type CodeContext, CodeLanguage, type CommandStatus, ControlClient, type CreateSandboxOptions, type DiagnosticEvent, type DiagnosticLog, ExecClient, type ExecuteCodeOptions, type ExecuteCommandOptions, type FileInfo, type FileReplacement, type ImageAuth, type ImageSpec, type ListSandboxesOptions, type ListSnapshotsOptions, type Metrics, OpenSandboxError, type Resources, type SSEEvent, SSEEventType, type Sandbox, type SandboxEndpoint, SandboxState, type SandboxStatus, type Snapshot, SnapshotState };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
//#region src/control.ts
|
|
2
|
+
function flattenSnapshot(raw) {
|
|
3
|
+
return {
|
|
4
|
+
id: raw.id,
|
|
5
|
+
sandboxId: raw.sandboxId,
|
|
6
|
+
state: raw.status.state,
|
|
7
|
+
createdAt: raw.createdAt
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
var OpenSandboxError = class extends Error {
|
|
11
|
+
status;
|
|
12
|
+
constructor(message, status) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.name = "OpenSandboxError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var ControlClient = class ControlClient {
|
|
19
|
+
baseUrl;
|
|
20
|
+
apiKey;
|
|
21
|
+
signal;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
24
|
+
this.apiKey = options.apiKey;
|
|
25
|
+
this.signal = options.signal;
|
|
26
|
+
}
|
|
27
|
+
/** Return a new `ControlClient` instance that passes `signal` to every fetch call. */
|
|
28
|
+
withSignal(signal) {
|
|
29
|
+
return new ControlClient({
|
|
30
|
+
baseUrl: this.baseUrl,
|
|
31
|
+
apiKey: this.apiKey,
|
|
32
|
+
signal
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async request(method, path, body) {
|
|
36
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
37
|
+
method,
|
|
38
|
+
headers: {
|
|
39
|
+
"OPEN-SANDBOX-API-KEY": this.apiKey,
|
|
40
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
41
|
+
},
|
|
42
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
43
|
+
signal: this.signal
|
|
44
|
+
});
|
|
45
|
+
if (!res.ok) throw new OpenSandboxError(await res.text().catch(() => "") || "OpenSandbox API error", res.status);
|
|
46
|
+
if (res.status === 204) return void 0;
|
|
47
|
+
return res.json();
|
|
48
|
+
}
|
|
49
|
+
createSandbox(options) {
|
|
50
|
+
return this.request("POST", "/v1/sandboxes", options);
|
|
51
|
+
}
|
|
52
|
+
listSandboxes(options = {}) {
|
|
53
|
+
const params = new URLSearchParams();
|
|
54
|
+
if (options.state) params.set("state", options.state);
|
|
55
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
56
|
+
if (options.offset !== void 0) params.set("offset", String(options.offset));
|
|
57
|
+
const qs = params.toString();
|
|
58
|
+
return this.request("GET", `/v1/sandboxes${qs ? `?${qs}` : ""}`);
|
|
59
|
+
}
|
|
60
|
+
getSandbox(id) {
|
|
61
|
+
return this.request("GET", `/v1/sandboxes/${id}`);
|
|
62
|
+
}
|
|
63
|
+
deleteSandbox(id) {
|
|
64
|
+
return this.request("DELETE", `/v1/sandboxes/${id}`);
|
|
65
|
+
}
|
|
66
|
+
pauseSandbox(id) {
|
|
67
|
+
return this.request("POST", `/v1/sandboxes/${id}/pause`);
|
|
68
|
+
}
|
|
69
|
+
resumeSandbox(id) {
|
|
70
|
+
return this.request("POST", `/v1/sandboxes/${id}/resume`);
|
|
71
|
+
}
|
|
72
|
+
renewExpiration(id) {
|
|
73
|
+
return this.request("POST", `/v1/sandboxes/${id}/renew-expiration`);
|
|
74
|
+
}
|
|
75
|
+
getEndpoint(sandboxId, port, useServerProxy) {
|
|
76
|
+
const qs = useServerProxy ? "?use_server_proxy=true" : "";
|
|
77
|
+
return this.request("GET", `/v1/sandboxes/${sandboxId}/endpoints/${port}${qs}`);
|
|
78
|
+
}
|
|
79
|
+
getDiagnosticLogs(sandboxId) {
|
|
80
|
+
return this.request("GET", `/v1/sandboxes/${sandboxId}/diagnostics/logs`);
|
|
81
|
+
}
|
|
82
|
+
getDiagnosticEvents(sandboxId) {
|
|
83
|
+
return this.request("GET", `/v1/sandboxes/${sandboxId}/diagnostics/events`);
|
|
84
|
+
}
|
|
85
|
+
async createSnapshot(sandboxId) {
|
|
86
|
+
return flattenSnapshot(await this.request("POST", `/v1/sandboxes/${sandboxId}/snapshots`));
|
|
87
|
+
}
|
|
88
|
+
listSnapshots(options = {}) {
|
|
89
|
+
const params = new URLSearchParams();
|
|
90
|
+
if (options.sandboxId) params.set("sandboxId", options.sandboxId);
|
|
91
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
92
|
+
if (options.offset !== void 0) params.set("offset", String(options.offset));
|
|
93
|
+
const qs = params.toString();
|
|
94
|
+
return this.request("GET", `/v1/snapshots${qs ? `?${qs}` : ""}`);
|
|
95
|
+
}
|
|
96
|
+
async getSnapshot(id) {
|
|
97
|
+
return flattenSnapshot(await this.request("GET", `/v1/snapshots/${id}`));
|
|
98
|
+
}
|
|
99
|
+
deleteSnapshot(id) {
|
|
100
|
+
return this.request("DELETE", `/v1/snapshots/${id}`);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/types.ts
|
|
105
|
+
let SandboxState = /* @__PURE__ */ function(SandboxState) {
|
|
106
|
+
SandboxState["Pending"] = "Pending";
|
|
107
|
+
SandboxState["Running"] = "Running";
|
|
108
|
+
SandboxState["Pausing"] = "Pausing";
|
|
109
|
+
SandboxState["Paused"] = "Paused";
|
|
110
|
+
SandboxState["Resuming"] = "Resuming";
|
|
111
|
+
SandboxState["Stopping"] = "Stopping";
|
|
112
|
+
SandboxState["Terminated"] = "Terminated";
|
|
113
|
+
SandboxState["Failed"] = "Failed";
|
|
114
|
+
SandboxState["Unknown"] = "Unknown";
|
|
115
|
+
return SandboxState;
|
|
116
|
+
}({});
|
|
117
|
+
let SnapshotState = /* @__PURE__ */ function(SnapshotState) {
|
|
118
|
+
SnapshotState["Pending"] = "Pending";
|
|
119
|
+
SnapshotState["Committing"] = "Committing";
|
|
120
|
+
SnapshotState["Pushing"] = "Pushing";
|
|
121
|
+
SnapshotState["Ready"] = "Ready";
|
|
122
|
+
SnapshotState["Failed"] = "Failed";
|
|
123
|
+
return SnapshotState;
|
|
124
|
+
}({});
|
|
125
|
+
let SSEEventType = /* @__PURE__ */ function(SSEEventType) {
|
|
126
|
+
SSEEventType["Init"] = "init";
|
|
127
|
+
SSEEventType["Status"] = "status";
|
|
128
|
+
SSEEventType["Stdout"] = "stdout";
|
|
129
|
+
SSEEventType["Stderr"] = "stderr";
|
|
130
|
+
SSEEventType["Result"] = "result";
|
|
131
|
+
SSEEventType["ExecutionComplete"] = "execution_complete";
|
|
132
|
+
SSEEventType["ExecutionCount"] = "execution_count";
|
|
133
|
+
SSEEventType["Error"] = "error";
|
|
134
|
+
SSEEventType["Ping"] = "ping";
|
|
135
|
+
SSEEventType["Message"] = "message";
|
|
136
|
+
return SSEEventType;
|
|
137
|
+
}({});
|
|
138
|
+
let CodeLanguage = /* @__PURE__ */ function(CodeLanguage) {
|
|
139
|
+
CodeLanguage["Python"] = "python";
|
|
140
|
+
CodeLanguage["JavaScript"] = "javascript";
|
|
141
|
+
CodeLanguage["TypeScript"] = "typescript";
|
|
142
|
+
CodeLanguage["Go"] = "go";
|
|
143
|
+
CodeLanguage["Java"] = "java";
|
|
144
|
+
CodeLanguage["Bash"] = "bash";
|
|
145
|
+
return CodeLanguage;
|
|
146
|
+
}({});
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region src/exec.ts
|
|
149
|
+
async function* parseSSE(stream) {
|
|
150
|
+
const reader = stream.getReader();
|
|
151
|
+
const decoder = new TextDecoder();
|
|
152
|
+
let buffer = "";
|
|
153
|
+
try {
|
|
154
|
+
while (true) {
|
|
155
|
+
const { done, value } = await reader.read();
|
|
156
|
+
if (done) break;
|
|
157
|
+
buffer += decoder.decode(value, { stream: true });
|
|
158
|
+
const blocks = buffer.split("\n\n");
|
|
159
|
+
buffer = blocks.pop() ?? "";
|
|
160
|
+
for (const block of blocks) {
|
|
161
|
+
const trimmed = block.trim();
|
|
162
|
+
if (!trimmed) continue;
|
|
163
|
+
if (trimmed.startsWith("{")) try {
|
|
164
|
+
yield JSON.parse(trimmed);
|
|
165
|
+
} catch {}
|
|
166
|
+
else {
|
|
167
|
+
let type;
|
|
168
|
+
let data;
|
|
169
|
+
for (const line of block.split("\n")) if (line.startsWith("event:")) type = line.slice(6).trim();
|
|
170
|
+
else if (line.startsWith("data:")) data = line.slice(5).trim();
|
|
171
|
+
if (data !== void 0) yield {
|
|
172
|
+
type: type ?? "message",
|
|
173
|
+
...JSON.parse(data)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} finally {
|
|
179
|
+
reader.releaseLock();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
var ExecClient = class ExecClient {
|
|
183
|
+
baseUrl;
|
|
184
|
+
accessToken;
|
|
185
|
+
signal;
|
|
186
|
+
constructor(options) {
|
|
187
|
+
this.baseUrl = (options.baseUrl ?? "http://localhost:44772").replace(/\/$/, "");
|
|
188
|
+
this.accessToken = options.accessToken;
|
|
189
|
+
this.signal = options.signal;
|
|
190
|
+
}
|
|
191
|
+
/** Return a new `ExecClient` instance that passes `signal` to every fetch call. */
|
|
192
|
+
withSignal(signal) {
|
|
193
|
+
return new ExecClient({
|
|
194
|
+
baseUrl: this.baseUrl,
|
|
195
|
+
accessToken: this.accessToken,
|
|
196
|
+
signal
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
get authHeader() {
|
|
200
|
+
return { "X-EXECD-ACCESS-TOKEN": this.accessToken };
|
|
201
|
+
}
|
|
202
|
+
async request(method, path, body) {
|
|
203
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
204
|
+
method,
|
|
205
|
+
headers: {
|
|
206
|
+
...this.authHeader,
|
|
207
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
208
|
+
},
|
|
209
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
210
|
+
signal: this.signal
|
|
211
|
+
});
|
|
212
|
+
if (!res.ok) {
|
|
213
|
+
const text = await res.text().catch(() => "");
|
|
214
|
+
throw new Error(text || `execd error ${res.status}`);
|
|
215
|
+
}
|
|
216
|
+
if (res.status === 204) return void 0;
|
|
217
|
+
return res.json();
|
|
218
|
+
}
|
|
219
|
+
async *streamRequest(method, path, body) {
|
|
220
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
221
|
+
method,
|
|
222
|
+
headers: {
|
|
223
|
+
...this.authHeader,
|
|
224
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
225
|
+
},
|
|
226
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
227
|
+
signal: this.signal
|
|
228
|
+
});
|
|
229
|
+
if (!res.ok) {
|
|
230
|
+
const text = await res.text().catch(() => "");
|
|
231
|
+
throw new Error(text || `execd error ${res.status}`);
|
|
232
|
+
}
|
|
233
|
+
if (!res.body) return;
|
|
234
|
+
yield* parseSSE(res.body);
|
|
235
|
+
}
|
|
236
|
+
ping() {
|
|
237
|
+
return this.request("GET", "/ping");
|
|
238
|
+
}
|
|
239
|
+
listContexts(language) {
|
|
240
|
+
const qs = language ? `?language=${encodeURIComponent(language)}` : "";
|
|
241
|
+
return this.request("GET", `/code/contexts${qs}`);
|
|
242
|
+
}
|
|
243
|
+
clearContexts(language) {
|
|
244
|
+
const qs = language ? `?language=${encodeURIComponent(language)}` : "";
|
|
245
|
+
return this.request("DELETE", `/code/contexts${qs}`);
|
|
246
|
+
}
|
|
247
|
+
deleteContext(contextId) {
|
|
248
|
+
return this.request("DELETE", `/code/contexts/${contextId}`);
|
|
249
|
+
}
|
|
250
|
+
createContext(language) {
|
|
251
|
+
return this.request("POST", "/code/context", { language });
|
|
252
|
+
}
|
|
253
|
+
async *executeCode(options) {
|
|
254
|
+
yield* this.streamRequest("POST", "/code", options);
|
|
255
|
+
}
|
|
256
|
+
interruptCode() {
|
|
257
|
+
return this.request("DELETE", "/code");
|
|
258
|
+
}
|
|
259
|
+
async *executeCommand(options) {
|
|
260
|
+
yield* this.streamRequest("POST", "/command", options);
|
|
261
|
+
}
|
|
262
|
+
interruptCommand() {
|
|
263
|
+
return this.request("DELETE", "/command");
|
|
264
|
+
}
|
|
265
|
+
getCommandStatus(session) {
|
|
266
|
+
return this.request("GET", `/command/status/${session}`);
|
|
267
|
+
}
|
|
268
|
+
getCommandOutput(session) {
|
|
269
|
+
return this.request("GET", `/command/output/${session}`);
|
|
270
|
+
}
|
|
271
|
+
async getFileInfo(path) {
|
|
272
|
+
const entry = (await this.request("GET", `/files/info?path=${encodeURIComponent(path)}`))[path];
|
|
273
|
+
if (!entry) throw new Error(`getFileInfo: no entry for path ${path}`);
|
|
274
|
+
return entry;
|
|
275
|
+
}
|
|
276
|
+
deleteFile(path) {
|
|
277
|
+
return this.request("DELETE", `/files?path=${encodeURIComponent(path)}`);
|
|
278
|
+
}
|
|
279
|
+
setPermissions(path, mode) {
|
|
280
|
+
return this.request("POST", "/files/permissions", { [path]: { mode: parseInt(mode, 10) } });
|
|
281
|
+
}
|
|
282
|
+
moveFile(from, to) {
|
|
283
|
+
return this.request("POST", "/files/mv", [{
|
|
284
|
+
src: from,
|
|
285
|
+
dest: to
|
|
286
|
+
}]);
|
|
287
|
+
}
|
|
288
|
+
async searchFiles(pattern, path = "/") {
|
|
289
|
+
const params = new URLSearchParams({
|
|
290
|
+
path,
|
|
291
|
+
pattern
|
|
292
|
+
});
|
|
293
|
+
return (await this.request("GET", `/files/search?${params}`)).map((e) => e.path);
|
|
294
|
+
}
|
|
295
|
+
replaceInFiles(replacements) {
|
|
296
|
+
const body = {};
|
|
297
|
+
for (const r of replacements) body[r.path] = {
|
|
298
|
+
old: r.old,
|
|
299
|
+
new: r.new
|
|
300
|
+
};
|
|
301
|
+
return this.request("POST", "/files/replace", body);
|
|
302
|
+
}
|
|
303
|
+
async uploadFile(path, content) {
|
|
304
|
+
const formData = new FormData();
|
|
305
|
+
formData.append("metadata", new File([JSON.stringify({ path })], "metadata.json", { type: "application/json" }));
|
|
306
|
+
formData.append("file", new File([content], path.split("/").pop() ?? "file", { type: "application/octet-stream" }));
|
|
307
|
+
const res = await fetch(`${this.baseUrl}/files/upload`, {
|
|
308
|
+
method: "POST",
|
|
309
|
+
headers: this.authHeader,
|
|
310
|
+
body: formData,
|
|
311
|
+
signal: this.signal
|
|
312
|
+
});
|
|
313
|
+
if (!res.ok) {
|
|
314
|
+
const text = await res.text().catch(() => "");
|
|
315
|
+
throw new Error(text || `execd error ${res.status}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
async downloadFile(path) {
|
|
319
|
+
const res = await fetch(`${this.baseUrl}/files/download?path=${encodeURIComponent(path)}`, {
|
|
320
|
+
headers: this.authHeader,
|
|
321
|
+
signal: this.signal
|
|
322
|
+
});
|
|
323
|
+
if (!res.ok) throw new Error(`execd error ${res.status}`);
|
|
324
|
+
if (!res.body) throw new Error("empty response body");
|
|
325
|
+
return res.body;
|
|
326
|
+
}
|
|
327
|
+
listDirectory(path, depth) {
|
|
328
|
+
const params = new URLSearchParams({ path });
|
|
329
|
+
if (depth !== void 0) params.set("depth", String(depth));
|
|
330
|
+
return this.request("GET", `/directories/list?${params}`);
|
|
331
|
+
}
|
|
332
|
+
createDirectory(path) {
|
|
333
|
+
return this.request("POST", "/directories", { [path]: { mode: 755 } });
|
|
334
|
+
}
|
|
335
|
+
deleteDirectory(path) {
|
|
336
|
+
return this.request("DELETE", `/directories?path=${encodeURIComponent(path)}`);
|
|
337
|
+
}
|
|
338
|
+
getMetrics() {
|
|
339
|
+
return this.request("GET", "/metrics");
|
|
340
|
+
}
|
|
341
|
+
async *watchMetrics() {
|
|
342
|
+
yield* this.streamRequest("GET", "/metrics/watch");
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
//#endregion
|
|
346
|
+
export { CodeLanguage, ControlClient, ExecClient, OpenSandboxError, SSEEventType, SandboxState, SnapshotState };
|
package/package.json
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drej/opensandbox",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"main": "./src/index.ts",
|
|
5
|
-
"types": "./dist/index.d.ts",
|
|
3
|
+
"version": "0.1.4",
|
|
6
4
|
"files": [
|
|
7
5
|
"dist"
|
|
8
6
|
],
|
|
9
|
-
"
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.mjs",
|
|
9
|
+
"types": "./dist/index.d.mts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/index.d.mts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
10
19
|
"scripts": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
20
|
+
"build": "tsdown",
|
|
21
|
+
"typecheck": "bunx tsc --noEmit"
|
|
13
22
|
},
|
|
14
23
|
"devDependencies": {
|
|
15
|
-
"bun-types": "
|
|
16
|
-
"
|
|
24
|
+
"bun-types": "1.3.14",
|
|
25
|
+
"tsdown": "0.22.3",
|
|
26
|
+
"typescript": "6.0.3"
|
|
17
27
|
}
|
|
18
28
|
}
|
package/dist/control.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { Sandbox, CreateSandboxOptions, ListSandboxesOptions, Snapshot, ListSnapshotsOptions, SandboxEndpoint, DiagnosticLog, DiagnosticEvent } from "./types";
|
|
2
|
-
export declare class OpenSandboxError extends Error {
|
|
3
|
-
readonly status: number;
|
|
4
|
-
constructor(message: string, status: number);
|
|
5
|
-
}
|
|
6
|
-
export declare class ControlClient {
|
|
7
|
-
private baseUrl;
|
|
8
|
-
private apiKey;
|
|
9
|
-
constructor(options: {
|
|
10
|
-
baseUrl: string;
|
|
11
|
-
apiKey: string;
|
|
12
|
-
});
|
|
13
|
-
private request;
|
|
14
|
-
createSandbox(options: CreateSandboxOptions): Promise<Sandbox>;
|
|
15
|
-
listSandboxes(options?: ListSandboxesOptions): Promise<Sandbox[]>;
|
|
16
|
-
getSandbox(id: string): Promise<Sandbox>;
|
|
17
|
-
deleteSandbox(id: string): Promise<void>;
|
|
18
|
-
pauseSandbox(id: string): Promise<void>;
|
|
19
|
-
resumeSandbox(id: string): Promise<void>;
|
|
20
|
-
renewExpiration(id: string): Promise<void>;
|
|
21
|
-
getEndpoint(sandboxId: string, port: number): Promise<SandboxEndpoint>;
|
|
22
|
-
getDiagnosticLogs(sandboxId: string): Promise<DiagnosticLog[]>;
|
|
23
|
-
getDiagnosticEvents(sandboxId: string): Promise<DiagnosticEvent[]>;
|
|
24
|
-
createSnapshot(sandboxId: string): Promise<Snapshot>;
|
|
25
|
-
listSnapshots(options?: ListSnapshotsOptions): Promise<Snapshot[]>;
|
|
26
|
-
getSnapshot(id: string): Promise<Snapshot>;
|
|
27
|
-
deleteSnapshot(id: string): Promise<void>;
|
|
28
|
-
}
|
package/dist/exec.d.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { SSEEvent, CodeContext, ExecuteCodeOptions, ExecuteCommandOptions, CommandStatus, FileInfo, FileReplacement, DirectoryEntry, Metrics } from "./types";
|
|
2
|
-
export declare class ExecClient {
|
|
3
|
-
private baseUrl;
|
|
4
|
-
private accessToken;
|
|
5
|
-
constructor(options: {
|
|
6
|
-
baseUrl?: string;
|
|
7
|
-
accessToken: string;
|
|
8
|
-
});
|
|
9
|
-
private get authHeader();
|
|
10
|
-
private request;
|
|
11
|
-
private streamRequest;
|
|
12
|
-
ping(): Promise<{
|
|
13
|
-
status: string;
|
|
14
|
-
}>;
|
|
15
|
-
listContexts(language?: string): Promise<CodeContext[]>;
|
|
16
|
-
clearContexts(language?: string): Promise<void>;
|
|
17
|
-
deleteContext(contextId: string): Promise<void>;
|
|
18
|
-
createContext(language: string): Promise<CodeContext>;
|
|
19
|
-
executeCode(options: ExecuteCodeOptions): AsyncGenerator<SSEEvent>;
|
|
20
|
-
interruptCode(): Promise<void>;
|
|
21
|
-
executeCommand(options: ExecuteCommandOptions): AsyncGenerator<SSEEvent>;
|
|
22
|
-
interruptCommand(): Promise<void>;
|
|
23
|
-
getCommandStatus(session: string): Promise<CommandStatus>;
|
|
24
|
-
getCommandOutput(session: string): Promise<{
|
|
25
|
-
stdout: string;
|
|
26
|
-
stderr: string;
|
|
27
|
-
}>;
|
|
28
|
-
getFileInfo(path: string): Promise<FileInfo>;
|
|
29
|
-
deleteFile(path: string): Promise<void>;
|
|
30
|
-
setPermissions(path: string, mode: string): Promise<void>;
|
|
31
|
-
moveFile(from: string, to: string): Promise<void>;
|
|
32
|
-
searchFiles(pattern: string, dir?: string): Promise<string[]>;
|
|
33
|
-
replaceInFiles(replacements: FileReplacement[]): Promise<void>;
|
|
34
|
-
uploadFile(path: string, content: Blob | BufferSource | string): Promise<void>;
|
|
35
|
-
downloadFile(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
36
|
-
listDirectory(path: string, depth?: number): Promise<DirectoryEntry[]>;
|
|
37
|
-
createDirectory(path: string): Promise<void>;
|
|
38
|
-
deleteDirectory(path: string): Promise<void>;
|
|
39
|
-
getMetrics(): Promise<Metrics>;
|
|
40
|
-
watchMetrics(): AsyncGenerator<SSEEvent>;
|
|
41
|
-
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { ControlClient, OpenSandboxError } from "./control";
|
|
2
|
-
export { ExecClient } from "./exec";
|
|
3
|
-
export { SandboxState, SnapshotState, SSEEventType } from "./types";
|
|
4
|
-
export type { Resources, ImageAuth, ImageSpec, Sandbox, SandboxStatus, CreateSandboxOptions, ListSandboxesOptions, Snapshot, ListSnapshotsOptions, SandboxEndpoint, DiagnosticLog, DiagnosticEvent, SSEEvent, CodeContext, ExecuteCodeOptions, ExecuteCommandOptions, CommandStatus, FileInfo, FileReplacement, DirectoryEntry, Metrics, } from "./types";
|
package/dist/types.d.ts
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
export interface Resources {
|
|
2
|
-
cpu?: string;
|
|
3
|
-
memory?: string;
|
|
4
|
-
gpu?: string;
|
|
5
|
-
}
|
|
6
|
-
export interface ImageAuth {
|
|
7
|
-
username: string;
|
|
8
|
-
password: string;
|
|
9
|
-
}
|
|
10
|
-
export interface ImageSpec {
|
|
11
|
-
uri: string;
|
|
12
|
-
auth?: ImageAuth;
|
|
13
|
-
}
|
|
14
|
-
export declare enum SandboxState {
|
|
15
|
-
Pending = "Pending",
|
|
16
|
-
Running = "Running",
|
|
17
|
-
Pausing = "Pausing",
|
|
18
|
-
Paused = "Paused",
|
|
19
|
-
Resuming = "Resuming",
|
|
20
|
-
Stopping = "Stopping",
|
|
21
|
-
Terminated = "Terminated",
|
|
22
|
-
Failed = "Failed",
|
|
23
|
-
Unknown = "Unknown"
|
|
24
|
-
}
|
|
25
|
-
export interface SandboxStatus {
|
|
26
|
-
state: SandboxState;
|
|
27
|
-
reason?: string;
|
|
28
|
-
message?: string;
|
|
29
|
-
lastTransitionAt?: string;
|
|
30
|
-
}
|
|
31
|
-
export interface Sandbox {
|
|
32
|
-
id: string;
|
|
33
|
-
status: SandboxStatus;
|
|
34
|
-
createdAt: string;
|
|
35
|
-
expiresAt?: string | null;
|
|
36
|
-
image?: ImageSpec;
|
|
37
|
-
snapshotId?: string;
|
|
38
|
-
entrypoint?: string[];
|
|
39
|
-
metadata?: Record<string, string>;
|
|
40
|
-
platform?: unknown;
|
|
41
|
-
}
|
|
42
|
-
export interface CreateSandboxOptions {
|
|
43
|
-
image?: ImageSpec;
|
|
44
|
-
snapshotId?: string;
|
|
45
|
-
timeout?: number;
|
|
46
|
-
resourceLimits?: Resources;
|
|
47
|
-
entrypoint?: string[];
|
|
48
|
-
env?: Record<string, string>;
|
|
49
|
-
metadata?: Record<string, string>;
|
|
50
|
-
secureAccess?: boolean;
|
|
51
|
-
}
|
|
52
|
-
export interface ListSandboxesOptions {
|
|
53
|
-
state?: SandboxState;
|
|
54
|
-
limit?: number;
|
|
55
|
-
offset?: number;
|
|
56
|
-
}
|
|
57
|
-
export declare enum SnapshotState {
|
|
58
|
-
Pending = "Pending",
|
|
59
|
-
Committing = "Committing",
|
|
60
|
-
Pushing = "Pushing",
|
|
61
|
-
Ready = "Ready",
|
|
62
|
-
Failed = "Failed"
|
|
63
|
-
}
|
|
64
|
-
export interface Snapshot {
|
|
65
|
-
id: string;
|
|
66
|
-
sandboxId: string;
|
|
67
|
-
state: SnapshotState;
|
|
68
|
-
createdAt: string;
|
|
69
|
-
}
|
|
70
|
-
export interface ListSnapshotsOptions {
|
|
71
|
-
sandboxId?: string;
|
|
72
|
-
limit?: number;
|
|
73
|
-
offset?: number;
|
|
74
|
-
}
|
|
75
|
-
export interface SandboxEndpoint {
|
|
76
|
-
endpoint: string;
|
|
77
|
-
headers?: Record<string, string>;
|
|
78
|
-
}
|
|
79
|
-
export interface DiagnosticLog {
|
|
80
|
-
name: string;
|
|
81
|
-
size: number;
|
|
82
|
-
url?: string;
|
|
83
|
-
inline?: string;
|
|
84
|
-
}
|
|
85
|
-
export interface DiagnosticEvent {
|
|
86
|
-
timestamp: string;
|
|
87
|
-
type: string;
|
|
88
|
-
message: string;
|
|
89
|
-
}
|
|
90
|
-
export declare enum SSEEventType {
|
|
91
|
-
Init = "init",
|
|
92
|
-
Status = "status",
|
|
93
|
-
Stdout = "stdout",
|
|
94
|
-
Stderr = "stderr",
|
|
95
|
-
Result = "result",
|
|
96
|
-
ExecutionComplete = "execution_complete",
|
|
97
|
-
ExecutionCount = "execution_count",
|
|
98
|
-
Error = "error",
|
|
99
|
-
Ping = "ping",
|
|
100
|
-
Message = "message"
|
|
101
|
-
}
|
|
102
|
-
export interface SSEEvent {
|
|
103
|
-
type: SSEEventType;
|
|
104
|
-
text?: string;
|
|
105
|
-
results?: Record<string, string>;
|
|
106
|
-
error?: {
|
|
107
|
-
name?: string;
|
|
108
|
-
message: string;
|
|
109
|
-
evalue?: string;
|
|
110
|
-
};
|
|
111
|
-
execution_count?: number;
|
|
112
|
-
execution_time?: number;
|
|
113
|
-
timestamp: number;
|
|
114
|
-
}
|
|
115
|
-
export interface CodeContext {
|
|
116
|
-
id: string;
|
|
117
|
-
language: string;
|
|
118
|
-
}
|
|
119
|
-
export interface ExecuteCodeOptions {
|
|
120
|
-
code: string;
|
|
121
|
-
context?: {
|
|
122
|
-
id: string;
|
|
123
|
-
language: string;
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
export interface ExecuteCommandOptions {
|
|
127
|
-
command: string;
|
|
128
|
-
cwd?: string;
|
|
129
|
-
background?: boolean;
|
|
130
|
-
timeout?: number;
|
|
131
|
-
uid?: number;
|
|
132
|
-
gid?: number;
|
|
133
|
-
envs?: Record<string, string>;
|
|
134
|
-
}
|
|
135
|
-
export interface CommandStatus {
|
|
136
|
-
session: string;
|
|
137
|
-
status: "running" | "completed" | "failed";
|
|
138
|
-
exitCode?: number;
|
|
139
|
-
}
|
|
140
|
-
export interface FileInfo {
|
|
141
|
-
path: string;
|
|
142
|
-
size: number;
|
|
143
|
-
mode: string;
|
|
144
|
-
modifiedAt: string;
|
|
145
|
-
isDirectory: boolean;
|
|
146
|
-
}
|
|
147
|
-
export interface DirectoryEntry {
|
|
148
|
-
name: string;
|
|
149
|
-
path: string;
|
|
150
|
-
isDirectory: boolean;
|
|
151
|
-
size?: number;
|
|
152
|
-
}
|
|
153
|
-
export interface FileReplacement {
|
|
154
|
-
path: string;
|
|
155
|
-
old: string;
|
|
156
|
-
new: string;
|
|
157
|
-
}
|
|
158
|
-
export interface Metrics {
|
|
159
|
-
cpu: number;
|
|
160
|
-
memory: number;
|
|
161
|
-
timestamp: string;
|
|
162
|
-
}
|