@douglas-agent/sandbank-e2b 0.1.0
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/CubeSandboxAdapter.d.ts +19 -0
- package/dist/CubeSandboxAdapter.d.ts.map +1 -0
- package/dist/CubeSandboxAdapter.js +28 -0
- package/dist/E2BAdapter.d.ts +15 -0
- package/dist/E2BAdapter.d.ts.map +1 -0
- package/dist/E2BAdapter.js +25 -0
- package/dist/E2BProtocolAdapter.d.ts +50 -0
- package/dist/E2BProtocolAdapter.d.ts.map +1 -0
- package/dist/E2BProtocolAdapter.js +193 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/package.json +42 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { E2BProtocolAdapter } from './E2BProtocolAdapter.js';
|
|
2
|
+
import type { CubeSandboxAdapterConfig } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Tencent CubeSandbox adapter.
|
|
5
|
+
*
|
|
6
|
+
* CubeSandbox implements the E2B v2 HTTP protocol on top of self-hosted
|
|
7
|
+
* KVM+RustVMM microVMs. No default `apiUrl` — caller must supply their
|
|
8
|
+
* self-hosted cube-api URL (typically `http://<host>:3000`).
|
|
9
|
+
*
|
|
10
|
+
* `apiKey` is optional (CubeSandbox installs default to no auth).
|
|
11
|
+
*
|
|
12
|
+
* Provider tag: `'cube'` (distinct from `'e2b'` for monitoring / billing
|
|
13
|
+
* / log tagging separation).
|
|
14
|
+
*/
|
|
15
|
+
export declare class CubeSandboxAdapter extends E2BProtocolAdapter {
|
|
16
|
+
readonly name = "cube";
|
|
17
|
+
constructor(cfg: CubeSandboxAdapterConfig);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=CubeSandboxAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CubeSandboxAdapter.d.ts","sourceRoot":"","sources":["../src/CubeSandboxAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,qBAAa,kBAAmB,SAAQ,kBAAkB;IACxD,QAAQ,CAAC,IAAI,UAAU;gBAEX,GAAG,EAAE,wBAAwB;CAc1C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ProviderError } from '@douglas-agent/sandbank-core';
|
|
2
|
+
import { E2BProtocolAdapter } from './E2BProtocolAdapter.js';
|
|
3
|
+
/**
|
|
4
|
+
* Tencent CubeSandbox adapter.
|
|
5
|
+
*
|
|
6
|
+
* CubeSandbox implements the E2B v2 HTTP protocol on top of self-hosted
|
|
7
|
+
* KVM+RustVMM microVMs. No default `apiUrl` — caller must supply their
|
|
8
|
+
* self-hosted cube-api URL (typically `http://<host>:3000`).
|
|
9
|
+
*
|
|
10
|
+
* `apiKey` is optional (CubeSandbox installs default to no auth).
|
|
11
|
+
*
|
|
12
|
+
* Provider tag: `'cube'` (distinct from `'e2b'` for monitoring / billing
|
|
13
|
+
* / log tagging separation).
|
|
14
|
+
*/
|
|
15
|
+
export class CubeSandboxAdapter extends E2BProtocolAdapter {
|
|
16
|
+
name = 'cube';
|
|
17
|
+
constructor(cfg) {
|
|
18
|
+
if (!cfg.apiUrl) {
|
|
19
|
+
throw new ProviderError('cube', new Error('CubeSandboxAdapter requires apiUrl (self-hosted cube-api URL, e.g. http://10.116.83.96:3000)'));
|
|
20
|
+
}
|
|
21
|
+
super({
|
|
22
|
+
apiUrl: cfg.apiUrl,
|
|
23
|
+
apiKey: cfg.apiKey,
|
|
24
|
+
timeoutMs: cfg.timeoutMs,
|
|
25
|
+
fetch: cfg.fetch,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { E2BProtocolAdapter } from './E2BProtocolAdapter.js';
|
|
2
|
+
import { type E2BAdapterConfig } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* E2B Cloud / E2B Infra adapter.
|
|
5
|
+
*
|
|
6
|
+
* Defaults `apiUrl` to E2B Cloud public endpoint; requires `apiKey`.
|
|
7
|
+
* For E2B Infra self-hosted: pass your deployment URL via `apiUrl`.
|
|
8
|
+
*
|
|
9
|
+
* Provider tag: `'e2b'`.
|
|
10
|
+
*/
|
|
11
|
+
export declare class E2BAdapter extends E2BProtocolAdapter {
|
|
12
|
+
readonly name = "e2b";
|
|
13
|
+
constructor(cfg: E2BAdapterConfig);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=E2BAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2BAdapter.d.ts","sourceRoot":"","sources":["../src/E2BAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE;;;;;;;GAOG;AACH,qBAAa,UAAW,SAAQ,kBAAkB;IAChD,QAAQ,CAAC,IAAI,SAAS;gBAEV,GAAG,EAAE,gBAAgB;CAclC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ProviderError } from '@douglas-agent/sandbank-core';
|
|
2
|
+
import { E2BProtocolAdapter } from './E2BProtocolAdapter.js';
|
|
3
|
+
import { E2B_CLOUD_ENDPOINT } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* E2B Cloud / E2B Infra adapter.
|
|
6
|
+
*
|
|
7
|
+
* Defaults `apiUrl` to E2B Cloud public endpoint; requires `apiKey`.
|
|
8
|
+
* For E2B Infra self-hosted: pass your deployment URL via `apiUrl`.
|
|
9
|
+
*
|
|
10
|
+
* Provider tag: `'e2b'`.
|
|
11
|
+
*/
|
|
12
|
+
export class E2BAdapter extends E2BProtocolAdapter {
|
|
13
|
+
name = 'e2b';
|
|
14
|
+
constructor(cfg) {
|
|
15
|
+
if (!cfg.apiKey) {
|
|
16
|
+
throw new ProviderError('e2b', new Error('E2BAdapter requires apiKey (E2B Cloud / Infra both authenticate via X-API-Key)'));
|
|
17
|
+
}
|
|
18
|
+
super({
|
|
19
|
+
apiUrl: cfg.apiUrl ?? E2B_CLOUD_ENDPOINT,
|
|
20
|
+
apiKey: cfg.apiKey,
|
|
21
|
+
timeoutMs: cfg.timeoutMs,
|
|
22
|
+
fetch: cfg.fetch,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { AdapterSandbox, Capability, CreateConfig, ListFilter, SandboxAdapter, SandboxInfo } from '@douglas-agent/sandbank-core';
|
|
2
|
+
import { type E2BProtocolAdapterConfig } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Raw E2B API sandbox response shape (subset of E2B v2 OpenAPI).
|
|
5
|
+
* Field names follow E2B convention; CubeSandbox mirrors them.
|
|
6
|
+
*/
|
|
7
|
+
interface E2BSandbox {
|
|
8
|
+
sandboxID: string;
|
|
9
|
+
templateID?: string;
|
|
10
|
+
state?: string;
|
|
11
|
+
startedAt?: string;
|
|
12
|
+
endAt?: string;
|
|
13
|
+
metadata?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Shared base implementation of the E2B v2 HTTP protocol.
|
|
17
|
+
*
|
|
18
|
+
* NOT exported from the package — only used internally by
|
|
19
|
+
* `E2BAdapter` (E2B Cloud / Infra) and `CubeSandboxAdapter` (Tencent self-hosted).
|
|
20
|
+
*
|
|
21
|
+
* Endpoint paths follow the E2B v2 OpenAPI:
|
|
22
|
+
* POST /sandboxes
|
|
23
|
+
* GET /sandboxes
|
|
24
|
+
* GET /sandboxes/:id
|
|
25
|
+
* DELETE /sandboxes/:id
|
|
26
|
+
* POST /sandboxes/:id/exec
|
|
27
|
+
*
|
|
28
|
+
* Subclasses set their own `name` for `provider.name` tagging
|
|
29
|
+
* (`'e2b'` vs `'cube'`) and supply different defaults.
|
|
30
|
+
*/
|
|
31
|
+
export declare abstract class E2BProtocolAdapter implements SandboxAdapter {
|
|
32
|
+
abstract readonly name: string;
|
|
33
|
+
readonly capabilities: ReadonlySet<Capability>;
|
|
34
|
+
protected readonly apiUrl: string;
|
|
35
|
+
protected readonly apiKey?: string;
|
|
36
|
+
protected readonly timeoutMs: number;
|
|
37
|
+
protected readonly fetchImpl: typeof fetch;
|
|
38
|
+
constructor(cfg: E2BProtocolAdapterConfig);
|
|
39
|
+
createSandbox(config: CreateConfig): Promise<AdapterSandbox>;
|
|
40
|
+
getSandbox(id: string): Promise<AdapterSandbox>;
|
|
41
|
+
listSandboxes(filter?: ListFilter): Promise<SandboxInfo[]>;
|
|
42
|
+
destroySandbox(id: string): Promise<void>;
|
|
43
|
+
/** Issue an HTTP request against the E2B-compatible backend. */
|
|
44
|
+
protected request<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
45
|
+
private extractIdFromPath;
|
|
46
|
+
protected wrap(raw: E2BSandbox): AdapterSandbox;
|
|
47
|
+
private execImpl;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=E2BProtocolAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2BProtocolAdapter.d.ts","sourceRoot":"","sources":["../src/E2BProtocolAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,YAAY,EAGZ,UAAU,EACV,cAAc,EACd,WAAW,EAEZ,MAAM,8BAA8B,CAAC;AAMtC,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,UAAU,UAAU;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AA8BD;;;;;;;;;;;;;;;GAeG;AACH,8BAAsB,kBAAmB,YAAW,cAAc;IAChE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,UAAU,CAAC,CAA6B;IAE3E,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAClC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACnC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IACrC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,KAAK,CAAC;gBAE/B,GAAG,EAAE,wBAAwB;IAanC,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IAe5D,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAK/C,aAAa,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAmB1D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/C,gEAAgE;cAChD,OAAO,CAAC,CAAC,EACvB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,GACb,OAAO,CAAC,CAAC,CAAC;IA+Cb,OAAO,CAAC,iBAAiB;IAKzB,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,cAAc;YAUjC,QAAQ;CAoBvB"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { ProviderError, RateLimitError, SandboxNotFoundError, } from '@douglas-agent/sandbank-core';
|
|
2
|
+
import { E2B_PROTOCOL_CAPABILITIES, } from './types.js';
|
|
3
|
+
/** Map E2B state string → sandbank SandboxState. */
|
|
4
|
+
function mapState(s) {
|
|
5
|
+
switch (s) {
|
|
6
|
+
case 'running':
|
|
7
|
+
return 'running';
|
|
8
|
+
case 'paused':
|
|
9
|
+
case 'stopped':
|
|
10
|
+
return 'stopped';
|
|
11
|
+
case 'killed':
|
|
12
|
+
case 'terminated':
|
|
13
|
+
case 'end':
|
|
14
|
+
return 'terminated';
|
|
15
|
+
case 'pending':
|
|
16
|
+
case 'creating':
|
|
17
|
+
return 'creating';
|
|
18
|
+
case 'error':
|
|
19
|
+
return 'error';
|
|
20
|
+
default:
|
|
21
|
+
return 'running'; // E2B sometimes omits state on freshly created sandboxes
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Shared base implementation of the E2B v2 HTTP protocol.
|
|
26
|
+
*
|
|
27
|
+
* NOT exported from the package — only used internally by
|
|
28
|
+
* `E2BAdapter` (E2B Cloud / Infra) and `CubeSandboxAdapter` (Tencent self-hosted).
|
|
29
|
+
*
|
|
30
|
+
* Endpoint paths follow the E2B v2 OpenAPI:
|
|
31
|
+
* POST /sandboxes
|
|
32
|
+
* GET /sandboxes
|
|
33
|
+
* GET /sandboxes/:id
|
|
34
|
+
* DELETE /sandboxes/:id
|
|
35
|
+
* POST /sandboxes/:id/exec
|
|
36
|
+
*
|
|
37
|
+
* Subclasses set their own `name` for `provider.name` tagging
|
|
38
|
+
* (`'e2b'` vs `'cube'`) and supply different defaults.
|
|
39
|
+
*/
|
|
40
|
+
export class E2BProtocolAdapter {
|
|
41
|
+
capabilities = E2B_PROTOCOL_CAPABILITIES;
|
|
42
|
+
apiUrl;
|
|
43
|
+
apiKey;
|
|
44
|
+
timeoutMs;
|
|
45
|
+
fetchImpl;
|
|
46
|
+
constructor(cfg) {
|
|
47
|
+
if (!cfg.apiUrl) {
|
|
48
|
+
throw new ProviderError(this.constructor.name, new Error('apiUrl is required'));
|
|
49
|
+
}
|
|
50
|
+
this.apiUrl = cfg.apiUrl.replace(/\/+$/, '');
|
|
51
|
+
this.apiKey = cfg.apiKey;
|
|
52
|
+
this.timeoutMs = cfg.timeoutMs ?? 30_000;
|
|
53
|
+
this.fetchImpl = cfg.fetch ?? globalThis.fetch.bind(globalThis);
|
|
54
|
+
}
|
|
55
|
+
async createSandbox(config) {
|
|
56
|
+
const body = {
|
|
57
|
+
templateID: config.image ?? 'base',
|
|
58
|
+
metadata: config.env ?? {},
|
|
59
|
+
};
|
|
60
|
+
if (config.resources) {
|
|
61
|
+
body.resources = config.resources;
|
|
62
|
+
}
|
|
63
|
+
if (config.autoDestroyMinutes) {
|
|
64
|
+
body.timeoutMs = config.autoDestroyMinutes * 60_000;
|
|
65
|
+
}
|
|
66
|
+
const raw = await this.request('POST', '/sandboxes', body);
|
|
67
|
+
return this.wrap(raw);
|
|
68
|
+
}
|
|
69
|
+
async getSandbox(id) {
|
|
70
|
+
const raw = await this.request('GET', `/sandboxes/${id}`);
|
|
71
|
+
return this.wrap(raw);
|
|
72
|
+
}
|
|
73
|
+
async listSandboxes(filter) {
|
|
74
|
+
const raw = await this.request('GET', '/sandboxes');
|
|
75
|
+
const states = filter?.state
|
|
76
|
+
? Array.isArray(filter.state)
|
|
77
|
+
? filter.state
|
|
78
|
+
: [filter.state]
|
|
79
|
+
: null;
|
|
80
|
+
const limit = filter?.limit ?? Infinity;
|
|
81
|
+
return raw
|
|
82
|
+
.map((s) => ({
|
|
83
|
+
id: s.sandboxID,
|
|
84
|
+
state: mapState(s.state),
|
|
85
|
+
createdAt: s.startedAt ?? new Date().toISOString(),
|
|
86
|
+
image: s.templateID ?? 'base',
|
|
87
|
+
}))
|
|
88
|
+
.filter((info) => (states ? states.includes(info.state) : true))
|
|
89
|
+
.slice(0, limit);
|
|
90
|
+
}
|
|
91
|
+
async destroySandbox(id) {
|
|
92
|
+
try {
|
|
93
|
+
await this.request('DELETE', `/sandboxes/${id}`);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
if (e instanceof SandboxNotFoundError)
|
|
97
|
+
return; // idempotent
|
|
98
|
+
throw e;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ── internals ────────────────────────────────────────
|
|
102
|
+
/** Issue an HTTP request against the E2B-compatible backend. */
|
|
103
|
+
async request(method, path, body) {
|
|
104
|
+
const url = `${this.apiUrl}${path}`;
|
|
105
|
+
const headers = {
|
|
106
|
+
'Content-Type': 'application/json',
|
|
107
|
+
Accept: 'application/json',
|
|
108
|
+
};
|
|
109
|
+
if (this.apiKey)
|
|
110
|
+
headers['X-API-Key'] = this.apiKey;
|
|
111
|
+
const controller = new AbortController();
|
|
112
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
113
|
+
let res;
|
|
114
|
+
try {
|
|
115
|
+
res = await this.fetchImpl(url, {
|
|
116
|
+
method,
|
|
117
|
+
headers,
|
|
118
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
119
|
+
signal: controller.signal,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
throw new ProviderError(this.name, e);
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
}
|
|
128
|
+
if (res.status === 404) {
|
|
129
|
+
throw new SandboxNotFoundError(this.name, this.extractIdFromPath(path));
|
|
130
|
+
}
|
|
131
|
+
if (res.status === 429) {
|
|
132
|
+
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '0', 10);
|
|
133
|
+
throw new RateLimitError(this.name, retryAfter || undefined);
|
|
134
|
+
}
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
const text = await safeBody(res);
|
|
137
|
+
throw new ProviderError(this.name, new Error(`HTTP ${res.status}: ${text}`));
|
|
138
|
+
}
|
|
139
|
+
// 204 No Content
|
|
140
|
+
if (res.status === 204 || res.headers.get('Content-Length') === '0') {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
return (await res.json());
|
|
144
|
+
}
|
|
145
|
+
extractIdFromPath(path) {
|
|
146
|
+
const m = path.match(/\/sandboxes\/([^/?]+)/);
|
|
147
|
+
return m?.[1] ?? '';
|
|
148
|
+
}
|
|
149
|
+
wrap(raw) {
|
|
150
|
+
return new E2BAdapterSandbox(raw.sandboxID, mapState(raw.state), raw.startedAt ?? new Date().toISOString(), this.name, (cmd, opts) => this.execImpl(raw.sandboxID, cmd, opts));
|
|
151
|
+
}
|
|
152
|
+
async execImpl(sandboxId, command, options) {
|
|
153
|
+
const raw = await this.request('POST', `/sandboxes/${sandboxId}/exec`, {
|
|
154
|
+
command,
|
|
155
|
+
cwd: options?.cwd,
|
|
156
|
+
timeoutMs: options?.timeout,
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
stdout: raw.stdout ?? '',
|
|
160
|
+
stderr: raw.stderr ?? '',
|
|
161
|
+
exitCode: raw.exitCode ?? 0,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function safeBody(res) {
|
|
166
|
+
try {
|
|
167
|
+
return await res.text();
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return '';
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** Concrete AdapterSandbox wrapping an E2B sandbox. */
|
|
174
|
+
class E2BAdapterSandbox {
|
|
175
|
+
id;
|
|
176
|
+
state;
|
|
177
|
+
createdAt;
|
|
178
|
+
providerName;
|
|
179
|
+
execFn;
|
|
180
|
+
constructor(id, state, createdAt, providerName, execFn) {
|
|
181
|
+
this.id = id;
|
|
182
|
+
this.state = state;
|
|
183
|
+
this.createdAt = createdAt;
|
|
184
|
+
this.providerName = providerName;
|
|
185
|
+
this.execFn = execFn;
|
|
186
|
+
}
|
|
187
|
+
async exec(command, options) {
|
|
188
|
+
if (this.state === 'terminated' || this.state === 'error') {
|
|
189
|
+
throw new ProviderError(this.providerName, new Error(`exec on ${this.state} sandbox is not allowed`), this.id);
|
|
190
|
+
}
|
|
191
|
+
return this.execFn(command, options);
|
|
192
|
+
}
|
|
193
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { E2BAdapter } from './E2BAdapter.js';
|
|
2
|
+
export { CubeSandboxAdapter } from './CubeSandboxAdapter.js';
|
|
3
|
+
export { E2B_PROTOCOL_CAPABILITIES, E2B_CLOUD_ENDPOINT, type E2BAdapterConfig, type CubeSandboxAdapterConfig, } from './types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,GAC9B,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// E2BProtocolAdapter intentionally NOT exported — it is an internal base class.
|
|
2
|
+
// Consumers pick one of the concrete adapters based on the backend they target.
|
|
3
|
+
export { E2BAdapter } from './E2BAdapter.js';
|
|
4
|
+
export { CubeSandboxAdapter } from './CubeSandboxAdapter.js';
|
|
5
|
+
export { E2B_PROTOCOL_CAPABILITIES, E2B_CLOUD_ENDPOINT, } from './types.js';
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Capability } from '@douglas-agent/sandbank-core';
|
|
2
|
+
/** Base config shared by E2BAdapter / CubeSandboxAdapter. */
|
|
3
|
+
export interface E2BProtocolAdapterConfig {
|
|
4
|
+
/**
|
|
5
|
+
* Base URL of the E2B-compatible HTTP API.
|
|
6
|
+
*
|
|
7
|
+
* - E2B Cloud: https://api.e2b.dev
|
|
8
|
+
* - E2B Infra: https://<your-deployment>.<domain>
|
|
9
|
+
* - CubeSandbox: http://<host>:3000
|
|
10
|
+
*/
|
|
11
|
+
apiUrl: string;
|
|
12
|
+
/** Optional API key, sent as `X-API-Key` header. */
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
/** Per-request timeout in ms. */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Custom fetch impl (mainly for testing with undici MockAgent).
|
|
18
|
+
* @default globalThis.fetch
|
|
19
|
+
*/
|
|
20
|
+
fetch?: typeof fetch;
|
|
21
|
+
}
|
|
22
|
+
/** E2BAdapter-specific config (E2B Cloud / Infra). */
|
|
23
|
+
export interface E2BAdapterConfig extends Partial<Omit<E2BProtocolAdapterConfig, 'apiUrl' | 'apiKey'>> {
|
|
24
|
+
/** Defaults to E2B Cloud public endpoint. */
|
|
25
|
+
apiUrl?: string;
|
|
26
|
+
/** Required for E2B Cloud / E2B Infra. */
|
|
27
|
+
apiKey: string;
|
|
28
|
+
}
|
|
29
|
+
/** CubeSandboxAdapter-specific config. */
|
|
30
|
+
export interface CubeSandboxAdapterConfig extends Partial<Omit<E2BProtocolAdapterConfig, 'apiUrl'>> {
|
|
31
|
+
/** Self-hosted CubeSandbox cube-api URL (no default — caller-supplied). */
|
|
32
|
+
apiUrl: string;
|
|
33
|
+
}
|
|
34
|
+
/** Capabilities shared by all E2B-protocol adapters. */
|
|
35
|
+
export declare const E2B_PROTOCOL_CAPABILITIES: ReadonlySet<Capability>;
|
|
36
|
+
/** E2B Cloud default endpoint. */
|
|
37
|
+
export declare const E2B_CLOUD_ENDPOINT = "https://api.e2b.dev";
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,6DAA6D;AAC7D,MAAM,WAAW,wBAAwB;IACvC;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,sDAAsD;AACtD,MAAM,WAAW,gBAAiB,SAAQ,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACpG,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,0CAA0C;AAC1C,MAAM,WAAW,wBAAyB,SAAQ,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,QAAQ,CAAC,CAAC;IACjG,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wDAAwD;AACxD,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,UAAU,CAM5D,CAAC;AAEH,kCAAkC;AAClC,eAAO,MAAM,kBAAkB,wBAAwB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Capabilities shared by all E2B-protocol adapters. */
|
|
2
|
+
export const E2B_PROTOCOL_CAPABILITIES = new Set([
|
|
3
|
+
'exec.stream',
|
|
4
|
+
'terminal',
|
|
5
|
+
'sleep',
|
|
6
|
+
'snapshot',
|
|
7
|
+
'port.expose',
|
|
8
|
+
]);
|
|
9
|
+
/** E2B Cloud default endpoint. */
|
|
10
|
+
export const E2B_CLOUD_ENDPOINT = 'https://api.e2b.dev';
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@douglas-agent/sandbank-e2b",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "E2B-protocol sandbox adapters (E2B Cloud / E2B Infra / Tencent CubeSandbox) for Sandbank — shared HTTP base + flavor-specific subclasses",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"homepage": "https://github.com/Xeonice/sandbank-douglas-agent",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/Xeonice/sandbank-douglas-agent.git",
|
|
11
|
+
"directory": "packages/e2b"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"sandbox",
|
|
15
|
+
"ai-agent",
|
|
16
|
+
"e2b",
|
|
17
|
+
"cube-sandbox",
|
|
18
|
+
"tencent",
|
|
19
|
+
"firecracker"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"clean": "rm -rf dist"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@douglas-agent/sandbank-core": "^0.3.6",
|
|
37
|
+
"undici": "^7.5.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"typescript": "^5.7.3"
|
|
41
|
+
}
|
|
42
|
+
}
|