@brimble/sandbox 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/CODEX.md +188 -0
- package/PLAN.md +364 -0
- package/README.md +147 -0
- package/dist/package.json +23 -0
- package/dist/src/client.d.ts +23 -0
- package/dist/src/client.js +46 -0
- package/dist/src/constants.d.ts +14 -0
- package/dist/src/constants.js +21 -0
- package/dist/src/enums/code-language.d.ts +4 -0
- package/dist/src/enums/code-language.js +8 -0
- package/dist/src/enums/destroy-reason.d.ts +8 -0
- package/dist/src/enums/destroy-reason.js +12 -0
- package/dist/src/enums/destroy-timeout.d.ts +8 -0
- package/dist/src/enums/destroy-timeout.js +12 -0
- package/dist/src/enums/index.d.ts +7 -0
- package/dist/src/enums/index.js +17 -0
- package/dist/src/enums/sandbox-status.d.ts +9 -0
- package/dist/src/enums/sandbox-status.js +13 -0
- package/dist/src/enums/snapshot-mode.d.ts +4 -0
- package/dist/src/enums/snapshot-mode.js +8 -0
- package/dist/src/enums/snapshot-status.d.ts +5 -0
- package/dist/src/enums/snapshot-status.js +9 -0
- package/dist/src/enums/volume-type.d.ts +3 -0
- package/dist/src/enums/volume-type.js +7 -0
- package/dist/src/errors/index.d.ts +2 -0
- package/dist/src/errors/index.js +9 -0
- package/dist/src/errors/sandbox-api-error.d.ts +29 -0
- package/dist/src/errors/sandbox-api-error.js +48 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +40 -0
- package/dist/src/resources/exec.d.ts +19 -0
- package/dist/src/resources/exec.js +45 -0
- package/dist/src/resources/files.d.ts +16 -0
- package/dist/src/resources/files.js +41 -0
- package/dist/src/resources/index.d.ts +8 -0
- package/dist/src/resources/index.js +20 -0
- package/dist/src/resources/path.d.ts +7 -0
- package/dist/src/resources/path.js +19 -0
- package/dist/src/resources/sandbox-handle.d.ts +78 -0
- package/dist/src/resources/sandbox-handle.js +151 -0
- package/dist/src/resources/sandboxes.d.ts +64 -0
- package/dist/src/resources/sandboxes.js +224 -0
- package/dist/src/resources/scoped-sandbox.d.ts +39 -0
- package/dist/src/resources/scoped-sandbox.js +51 -0
- package/dist/src/resources/snapshots.d.ts +26 -0
- package/dist/src/resources/snapshots.js +88 -0
- package/dist/src/resources/stats.d.ts +11 -0
- package/dist/src/resources/stats.js +26 -0
- package/dist/src/resources/volumes.d.ts +21 -0
- package/dist/src/resources/volumes.js +80 -0
- package/dist/src/transport/auth.d.ts +2 -0
- package/dist/src/transport/auth.js +7 -0
- package/dist/src/transport/http.d.ts +73 -0
- package/dist/src/transport/http.js +354 -0
- package/dist/src/transport/pagination.d.ts +3 -0
- package/dist/src/transport/pagination.js +11 -0
- package/dist/src/types/exec.d.ts +34 -0
- package/dist/src/types/exec.js +2 -0
- package/dist/src/types/files.d.ts +1 -0
- package/dist/src/types/files.js +2 -0
- package/dist/src/types/index.d.ts +9 -0
- package/dist/src/types/index.js +2 -0
- package/dist/src/types/pagination.d.ts +14 -0
- package/dist/src/types/pagination.js +2 -0
- package/dist/src/types/region.d.ts +17 -0
- package/dist/src/types/region.js +2 -0
- package/dist/src/types/sandbox.d.ts +90 -0
- package/dist/src/types/sandbox.js +2 -0
- package/dist/src/types/snapshot.d.ts +15 -0
- package/dist/src/types/snapshot.js +2 -0
- package/dist/src/types/stats.d.ts +31 -0
- package/dist/src/types/stats.js +2 -0
- package/dist/src/types/template.d.ts +5 -0
- package/dist/src/types/template.js +2 -0
- package/dist/src/types/volume.d.ts +24 -0
- package/dist/src/types/volume.js +2 -0
- package/package.json +26 -0
- package/src/client.ts +61 -0
- package/src/constants.ts +17 -0
- package/src/enums/code-language.ts +4 -0
- package/src/enums/destroy-reason.ts +8 -0
- package/src/enums/destroy-timeout.ts +8 -0
- package/src/enums/index.ts +7 -0
- package/src/enums/sandbox-status.ts +9 -0
- package/src/enums/snapshot-mode.ts +4 -0
- package/src/enums/snapshot-status.ts +5 -0
- package/src/enums/volume-type.ts +3 -0
- package/src/errors/index.ts +2 -0
- package/src/errors/sandbox-api-error.ts +54 -0
- package/src/index.ts +71 -0
- package/src/resources/exec.ts +56 -0
- package/src/resources/files.ts +46 -0
- package/src/resources/index.ts +8 -0
- package/src/resources/path.ts +16 -0
- package/src/resources/sandbox-handle.ts +215 -0
- package/src/resources/sandboxes.ts +297 -0
- package/src/resources/scoped-sandbox.ts +65 -0
- package/src/resources/snapshots.ts +104 -0
- package/src/resources/stats.ts +30 -0
- package/src/resources/volumes.ts +95 -0
- package/src/transport/auth.ts +4 -0
- package/src/transport/http.ts +501 -0
- package/src/transport/pagination.ts +10 -0
- package/src/types/exec.ts +42 -0
- package/src/types/files.ts +1 -0
- package/src/types/index.ts +23 -0
- package/src/types/pagination.ts +16 -0
- package/src/types/region.ts +19 -0
- package/src/types/sandbox.ts +103 -0
- package/src/types/snapshot.ts +17 -0
- package/src/types/stats.ts +35 -0
- package/src/types/template.ts +5 -0
- package/src/types/volume.ts +26 -0
- package/test/integration/sandbox.integration.test.ts +269 -0
- package/test/unit/client.test.ts +87 -0
- package/test/unit/sandboxes.test.ts +69 -0
- package/test/unit/transport.test.ts +126 -0
- package/test/unit/volumes.test.ts +122 -0
- package/tsconfig.json +16 -0
- package/vitest.config.ts +12 -0
- package/vitest.integration.config.ts +15 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxesResource = void 0;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const enums_1 = require("../enums");
|
|
6
|
+
const pagination_1 = require("../transport/pagination");
|
|
7
|
+
const sandbox_handle_1 = require("./sandbox-handle");
|
|
8
|
+
const scoped_sandbox_1 = require("./scoped-sandbox");
|
|
9
|
+
const volumes_1 = require("./volumes");
|
|
10
|
+
class SandboxesResource {
|
|
11
|
+
transport;
|
|
12
|
+
volumes;
|
|
13
|
+
/** @internal Create the sandboxes resource wrapper. */
|
|
14
|
+
constructor(transport) {
|
|
15
|
+
this.transport = transport;
|
|
16
|
+
this.volumes = new volumes_1.VolumesResource(transport);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a new sandbox.
|
|
20
|
+
* Region is optional; when omitted this SDK picks the first available region.
|
|
21
|
+
* The sandbox starts asynchronously, so fetch it until `status` is `ready`
|
|
22
|
+
* before running commands or file operations.
|
|
23
|
+
*/
|
|
24
|
+
async create(input, options) {
|
|
25
|
+
const region = await this.resolveRegionId(input.region, options);
|
|
26
|
+
const body = {
|
|
27
|
+
...input,
|
|
28
|
+
region,
|
|
29
|
+
};
|
|
30
|
+
const result = (await this.transport.requestJson({
|
|
31
|
+
endpoint: '/sandboxes',
|
|
32
|
+
method: 'POST',
|
|
33
|
+
body,
|
|
34
|
+
...options,
|
|
35
|
+
}));
|
|
36
|
+
return new sandbox_handle_1.SandboxHandle(this, result);
|
|
37
|
+
}
|
|
38
|
+
/** Create a sandbox and wait until it is `ready` before returning it. */
|
|
39
|
+
async createReady(input, options = {}) {
|
|
40
|
+
const sandbox = await this.create(input, options.request);
|
|
41
|
+
await sandbox.waitUntilReady(options.wait);
|
|
42
|
+
return sandbox;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Create a volume and then create a sandbox attached to that volume.
|
|
46
|
+
* This is the one-call helper for persistent sandbox workflows.
|
|
47
|
+
*/
|
|
48
|
+
async withVolume(input, options) {
|
|
49
|
+
const region = await this.resolveRegionId(input.sandbox.region ?? input.volume.region, options);
|
|
50
|
+
const volume = await this.volumes.create({
|
|
51
|
+
...input.volume,
|
|
52
|
+
region,
|
|
53
|
+
type: enums_1.VolumeType.Sandbox,
|
|
54
|
+
}, options);
|
|
55
|
+
return this.create({
|
|
56
|
+
...input.sandbox,
|
|
57
|
+
region,
|
|
58
|
+
volumeId: volume.id,
|
|
59
|
+
}, options);
|
|
60
|
+
}
|
|
61
|
+
/** Create a sandbox-scoped volume with package-level defaults and validation. */
|
|
62
|
+
createVolume(input, options) {
|
|
63
|
+
return this.volumes.create(input, options);
|
|
64
|
+
}
|
|
65
|
+
/** List your sandboxes with pagination. */
|
|
66
|
+
async list(query = {}, options) {
|
|
67
|
+
const page = await this.listData(query, options);
|
|
68
|
+
return {
|
|
69
|
+
...page,
|
|
70
|
+
data: page.data.map((sandbox) => new sandbox_handle_1.SandboxHandle(this, sandbox)),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Iterate over all sandbox handles across paginated results. */
|
|
74
|
+
async *iterate(query = {}, options) {
|
|
75
|
+
const limit = query.limit ?? constants_1.DEFAULT_PAGE_LIMIT;
|
|
76
|
+
let page = query.page ?? constants_1.DEFAULT_PAGE;
|
|
77
|
+
while (true) {
|
|
78
|
+
const paginated = await this.list({ ...query, page, limit }, options);
|
|
79
|
+
for (const sandbox of paginated.data) {
|
|
80
|
+
yield sandbox;
|
|
81
|
+
}
|
|
82
|
+
if (page >= paginated.totalPages || paginated.data.length === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
page += 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Fetch one sandbox handle by id. */
|
|
89
|
+
async get(sandboxId, options) {
|
|
90
|
+
const sandbox = await this.getData(sandboxId, options);
|
|
91
|
+
return new sandbox_handle_1.SandboxHandle(this, sandbox);
|
|
92
|
+
}
|
|
93
|
+
/** Fetch one sandbox and wait for `ready` before returning the handle. */
|
|
94
|
+
async getReady(sandboxId, options = {}) {
|
|
95
|
+
const sandbox = await this.get(sandboxId, options.request);
|
|
96
|
+
await sandbox.waitUntilReady(options.wait);
|
|
97
|
+
return sandbox;
|
|
98
|
+
}
|
|
99
|
+
/** @internal Fetch raw sandbox payload by id. */
|
|
100
|
+
getData(sandboxId, options) {
|
|
101
|
+
return this.transport.requestJson({
|
|
102
|
+
endpoint: `/sandboxes/${sandboxId}`,
|
|
103
|
+
method: 'GET',
|
|
104
|
+
...options,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/** @internal Fetch raw paginated sandbox payload. */
|
|
108
|
+
listData(query = {}, options) {
|
|
109
|
+
const params = (0, pagination_1.toPaginationQuery)(query);
|
|
110
|
+
if (query.teamId) {
|
|
111
|
+
params.set('teamId', query.teamId);
|
|
112
|
+
}
|
|
113
|
+
return this.transport.requestJson({
|
|
114
|
+
endpoint: '/sandboxes',
|
|
115
|
+
method: 'GET',
|
|
116
|
+
query: params,
|
|
117
|
+
...options,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/** List regions where sandboxes can be provisioned. */
|
|
121
|
+
listRegions(options) {
|
|
122
|
+
return this.transport.requestJson({
|
|
123
|
+
endpoint: '/sandboxes/regions',
|
|
124
|
+
method: 'GET',
|
|
125
|
+
...options,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/** List sandbox templates available for create operations. */
|
|
129
|
+
async listTemplates(options) {
|
|
130
|
+
const payload = await this.transport.requestJson({
|
|
131
|
+
endpoint: '/sandbox/templates',
|
|
132
|
+
method: 'GET',
|
|
133
|
+
...options,
|
|
134
|
+
});
|
|
135
|
+
if (Array.isArray(payload)) {
|
|
136
|
+
return payload;
|
|
137
|
+
}
|
|
138
|
+
if (payload && typeof payload === 'object' && 'templates' in payload) {
|
|
139
|
+
const templates = payload.templates;
|
|
140
|
+
if (Array.isArray(templates)) {
|
|
141
|
+
return templates;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
/** Fetch one template by name from the template catalog. */
|
|
147
|
+
async getTemplate(templateName, options) {
|
|
148
|
+
const templates = await this.listTemplates(options);
|
|
149
|
+
return templates.find((template) => template.name === templateName);
|
|
150
|
+
}
|
|
151
|
+
/** Destroy a sandbox (idempotent). */
|
|
152
|
+
async destroy(sandboxId, options) {
|
|
153
|
+
await this.transport.requestJson({
|
|
154
|
+
endpoint: `/sandboxes/${sandboxId}`,
|
|
155
|
+
method: 'DELETE',
|
|
156
|
+
...options,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/** Request sandbox pause. */
|
|
160
|
+
pause(sandboxId, options) {
|
|
161
|
+
return this.transport.requestJson({
|
|
162
|
+
endpoint: `/sandboxes/${sandboxId}/pause`,
|
|
163
|
+
method: 'POST',
|
|
164
|
+
...options,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/** Request sandbox resume. */
|
|
168
|
+
resume(sandboxId, options) {
|
|
169
|
+
return this.transport.requestJson({
|
|
170
|
+
endpoint: `/sandboxes/${sandboxId}/resume`,
|
|
171
|
+
method: 'POST',
|
|
172
|
+
...options,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/** Use runtime operations for a specific sandbox id. */
|
|
176
|
+
use(sandboxId) {
|
|
177
|
+
return new scoped_sandbox_1.ScopedSandboxResource(this.transport, sandboxId);
|
|
178
|
+
}
|
|
179
|
+
/** Opinionated Node.js quickstart (persistent sandbox + optional wait). */
|
|
180
|
+
async quickstartNode(input = {}, options) {
|
|
181
|
+
return this.quickstart({
|
|
182
|
+
...input,
|
|
183
|
+
template: input.template ?? 'node-22',
|
|
184
|
+
persistentDiskGB: input.persistentDiskGB ?? 20,
|
|
185
|
+
}, options);
|
|
186
|
+
}
|
|
187
|
+
/** Opinionated Python quickstart (persistent sandbox + optional wait). */
|
|
188
|
+
async quickstartPython(input = {}, options) {
|
|
189
|
+
return this.quickstart({
|
|
190
|
+
...input,
|
|
191
|
+
template: input.template ?? 'python-3.12',
|
|
192
|
+
persistentDiskGB: input.persistentDiskGB ?? 20,
|
|
193
|
+
}, options);
|
|
194
|
+
}
|
|
195
|
+
async quickstart(input, options) {
|
|
196
|
+
const { waitUntilReady, persistentDiskGB, ...createInput } = input;
|
|
197
|
+
const sandbox = await this.create({
|
|
198
|
+
...createInput,
|
|
199
|
+
persistent: true,
|
|
200
|
+
persistentDiskGB,
|
|
201
|
+
}, options);
|
|
202
|
+
if (waitUntilReady === false) {
|
|
203
|
+
return sandbox;
|
|
204
|
+
}
|
|
205
|
+
if (typeof waitUntilReady === 'object') {
|
|
206
|
+
await sandbox.waitUntilReady(waitUntilReady);
|
|
207
|
+
return sandbox;
|
|
208
|
+
}
|
|
209
|
+
await sandbox.waitUntilReady();
|
|
210
|
+
return sandbox;
|
|
211
|
+
}
|
|
212
|
+
async resolveRegionId(region, options) {
|
|
213
|
+
if (region && region !== 'auto') {
|
|
214
|
+
return region;
|
|
215
|
+
}
|
|
216
|
+
const { regions } = await this.listRegions(options);
|
|
217
|
+
const regionId = regions[0]?.id;
|
|
218
|
+
if (!regionId) {
|
|
219
|
+
throw new Error('No sandbox regions available for this account.');
|
|
220
|
+
}
|
|
221
|
+
return regionId;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
exports.SandboxesResource = SandboxesResource;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ExecResource } from './exec';
|
|
2
|
+
import { FilesResource } from './files';
|
|
3
|
+
import { SnapshotScopeResource } from './snapshots';
|
|
4
|
+
import { StatsResource } from './stats';
|
|
5
|
+
import { HttpTransport } from '../transport/http';
|
|
6
|
+
import type { CodeInput, CreateSnapshotInput, ExecInput, ExecResult, FileUploadBody, Paginated, Pagination, Snapshot, Stats, StatsQuery } from '../types';
|
|
7
|
+
import type { RequestOptions } from '../transport/http';
|
|
8
|
+
export declare class ScopedSandboxResource {
|
|
9
|
+
/** Lower-level exec/code runner resource. */
|
|
10
|
+
readonly execResource: ExecResource;
|
|
11
|
+
/** File upload/download resource. */
|
|
12
|
+
readonly files: FilesResource;
|
|
13
|
+
/** Snapshot resource scoped to this sandbox. */
|
|
14
|
+
readonly snapshots: SnapshotScopeResource;
|
|
15
|
+
/** Stats resource scoped to this sandbox. */
|
|
16
|
+
readonly statsResource: StatsResource;
|
|
17
|
+
/** @internal Create a sandbox-scoped resource wrapper. */
|
|
18
|
+
constructor(transport: HttpTransport, sandboxId: string);
|
|
19
|
+
/** Run a shell command in this sandbox. */
|
|
20
|
+
exec(input: ExecInput & {
|
|
21
|
+
stream: true;
|
|
22
|
+
}, options?: RequestOptions): Promise<ReadableStream<Uint8Array>>;
|
|
23
|
+
exec(input: ExecInput, options?: RequestOptions): Promise<ExecResult>;
|
|
24
|
+
/** Run a code snippet in this sandbox. */
|
|
25
|
+
runCode(input: CodeInput & {
|
|
26
|
+
stream: true;
|
|
27
|
+
}, options?: RequestOptions): Promise<ReadableStream<Uint8Array>>;
|
|
28
|
+
runCode(input: CodeInput, options?: RequestOptions): Promise<ExecResult>;
|
|
29
|
+
/** Upload bytes to a file path inside this sandbox. */
|
|
30
|
+
putFile(path: string, body: FileUploadBody, options?: RequestOptions): Promise<void>;
|
|
31
|
+
/** Download file bytes from this sandbox as a stream. */
|
|
32
|
+
getFile(path: string, options?: RequestOptions): Promise<ReadableStream<Uint8Array>>;
|
|
33
|
+
/** Fetch CPU, memory, and network stats for this sandbox. */
|
|
34
|
+
stats(query?: StatsQuery, options?: RequestOptions): Promise<Stats>;
|
|
35
|
+
/** Create a snapshot for this sandbox. */
|
|
36
|
+
createSnapshot(input: CreateSnapshotInput, options?: RequestOptions): Promise<Snapshot>;
|
|
37
|
+
/** List snapshots for this sandbox. */
|
|
38
|
+
listSnapshots(query?: Pagination, options?: RequestOptions): Promise<Paginated<Snapshot>>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScopedSandboxResource = void 0;
|
|
4
|
+
const exec_1 = require("./exec");
|
|
5
|
+
const files_1 = require("./files");
|
|
6
|
+
const snapshots_1 = require("./snapshots");
|
|
7
|
+
const stats_1 = require("./stats");
|
|
8
|
+
class ScopedSandboxResource {
|
|
9
|
+
/** Lower-level exec/code runner resource. */
|
|
10
|
+
execResource;
|
|
11
|
+
/** File upload/download resource. */
|
|
12
|
+
files;
|
|
13
|
+
/** Snapshot resource scoped to this sandbox. */
|
|
14
|
+
snapshots;
|
|
15
|
+
/** Stats resource scoped to this sandbox. */
|
|
16
|
+
statsResource;
|
|
17
|
+
/** @internal Create a sandbox-scoped resource wrapper. */
|
|
18
|
+
constructor(transport, sandboxId) {
|
|
19
|
+
this.execResource = new exec_1.ExecResource(transport, sandboxId);
|
|
20
|
+
this.files = new files_1.FilesResource(transport, sandboxId);
|
|
21
|
+
this.snapshots = new snapshots_1.SnapshotScopeResource(transport, sandboxId);
|
|
22
|
+
this.statsResource = new stats_1.StatsResource(transport, sandboxId);
|
|
23
|
+
}
|
|
24
|
+
exec(input, options) {
|
|
25
|
+
return this.execResource.exec(input, options);
|
|
26
|
+
}
|
|
27
|
+
runCode(input, options) {
|
|
28
|
+
return this.execResource.runCode(input, options);
|
|
29
|
+
}
|
|
30
|
+
/** Upload bytes to a file path inside this sandbox. */
|
|
31
|
+
putFile(path, body, options) {
|
|
32
|
+
return this.files.put(path, body, options);
|
|
33
|
+
}
|
|
34
|
+
/** Download file bytes from this sandbox as a stream. */
|
|
35
|
+
getFile(path, options) {
|
|
36
|
+
return this.files.get(path, options);
|
|
37
|
+
}
|
|
38
|
+
/** Fetch CPU, memory, and network stats for this sandbox. */
|
|
39
|
+
stats(query = {}, options) {
|
|
40
|
+
return this.statsResource.stats(query, options);
|
|
41
|
+
}
|
|
42
|
+
/** Create a snapshot for this sandbox. */
|
|
43
|
+
createSnapshot(input, options) {
|
|
44
|
+
return this.snapshots.create(input, options);
|
|
45
|
+
}
|
|
46
|
+
/** List snapshots for this sandbox. */
|
|
47
|
+
listSnapshots(query = {}, options) {
|
|
48
|
+
return this.snapshots.list(query, options);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ScopedSandboxResource = ScopedSandboxResource;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RequestOptions } from '../transport/http';
|
|
2
|
+
import { HttpTransport } from '../transport/http';
|
|
3
|
+
import type { CreateSnapshotInput, Paginated, Pagination, Snapshot } from '../types';
|
|
4
|
+
export declare class SnapshotScopeResource {
|
|
5
|
+
private readonly transport;
|
|
6
|
+
private readonly sandboxId;
|
|
7
|
+
/** @internal Create a sandbox-scoped snapshots wrapper. */
|
|
8
|
+
constructor(transport: HttpTransport, sandboxId: string);
|
|
9
|
+
/** Create a snapshot for this specific sandbox. */
|
|
10
|
+
create(input: CreateSnapshotInput, options?: RequestOptions): Promise<Snapshot>;
|
|
11
|
+
/** List snapshots for this specific sandbox. */
|
|
12
|
+
list(query?: Pagination, options?: RequestOptions): Promise<Paginated<Snapshot>>;
|
|
13
|
+
/** Iterate over all snapshots for this sandbox across pages. */
|
|
14
|
+
iterate(query?: Pagination, options?: RequestOptions): AsyncGenerator<Snapshot>;
|
|
15
|
+
}
|
|
16
|
+
export declare class SnapshotsResource {
|
|
17
|
+
private readonly transport;
|
|
18
|
+
/** @internal Create the global snapshots resource wrapper. */
|
|
19
|
+
constructor(transport: HttpTransport);
|
|
20
|
+
/** List all snapshots owned by the current caller. */
|
|
21
|
+
listAll(query?: Pagination, options?: RequestOptions): Promise<Paginated<Snapshot>>;
|
|
22
|
+
/** Iterate over all snapshots owned by the caller across pages. */
|
|
23
|
+
iterateAll(query?: Pagination, options?: RequestOptions): AsyncGenerator<Snapshot>;
|
|
24
|
+
/** Delete a snapshot by id. */
|
|
25
|
+
delete(snapshotId: string, options?: RequestOptions): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SnapshotsResource = exports.SnapshotScopeResource = void 0;
|
|
4
|
+
const pagination_1 = require("../transport/pagination");
|
|
5
|
+
const constants_1 = require("../constants");
|
|
6
|
+
class SnapshotScopeResource {
|
|
7
|
+
transport;
|
|
8
|
+
sandboxId;
|
|
9
|
+
/** @internal Create a sandbox-scoped snapshots wrapper. */
|
|
10
|
+
constructor(transport, sandboxId) {
|
|
11
|
+
this.transport = transport;
|
|
12
|
+
this.sandboxId = sandboxId;
|
|
13
|
+
}
|
|
14
|
+
/** Create a snapshot for this specific sandbox. */
|
|
15
|
+
create(input, options) {
|
|
16
|
+
return this.transport.requestJson({
|
|
17
|
+
endpoint: `/sandboxes/${this.sandboxId}/snapshots`,
|
|
18
|
+
method: 'POST',
|
|
19
|
+
body: input,
|
|
20
|
+
...options,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/** List snapshots for this specific sandbox. */
|
|
24
|
+
list(query = {}, options) {
|
|
25
|
+
return this.transport.requestJson({
|
|
26
|
+
endpoint: `/sandboxes/${this.sandboxId}/snapshots`,
|
|
27
|
+
method: 'GET',
|
|
28
|
+
query: (0, pagination_1.toPaginationQuery)(query),
|
|
29
|
+
...options,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Iterate over all snapshots for this sandbox across pages. */
|
|
33
|
+
async *iterate(query = {}, options) {
|
|
34
|
+
const limit = query.limit ?? constants_1.DEFAULT_PAGE_LIMIT;
|
|
35
|
+
let page = query.page ?? constants_1.DEFAULT_PAGE;
|
|
36
|
+
while (true) {
|
|
37
|
+
const paginated = await this.list({ ...query, page, limit }, options);
|
|
38
|
+
for (const snapshot of paginated.data) {
|
|
39
|
+
yield snapshot;
|
|
40
|
+
}
|
|
41
|
+
if (page >= paginated.totalPages || paginated.data.length === 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
page += 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.SnapshotScopeResource = SnapshotScopeResource;
|
|
49
|
+
class SnapshotsResource {
|
|
50
|
+
transport;
|
|
51
|
+
/** @internal Create the global snapshots resource wrapper. */
|
|
52
|
+
constructor(transport) {
|
|
53
|
+
this.transport = transport;
|
|
54
|
+
}
|
|
55
|
+
/** List all snapshots owned by the current caller. */
|
|
56
|
+
listAll(query = {}, options) {
|
|
57
|
+
return this.transport.requestJson({
|
|
58
|
+
endpoint: '/sandboxes/snapshots',
|
|
59
|
+
method: 'GET',
|
|
60
|
+
query: (0, pagination_1.toPaginationQuery)(query),
|
|
61
|
+
...options,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** Iterate over all snapshots owned by the caller across pages. */
|
|
65
|
+
async *iterateAll(query = {}, options) {
|
|
66
|
+
const limit = query.limit ?? constants_1.DEFAULT_PAGE_LIMIT;
|
|
67
|
+
let page = query.page ?? constants_1.DEFAULT_PAGE;
|
|
68
|
+
while (true) {
|
|
69
|
+
const paginated = await this.listAll({ ...query, page, limit }, options);
|
|
70
|
+
for (const snapshot of paginated.data) {
|
|
71
|
+
yield snapshot;
|
|
72
|
+
}
|
|
73
|
+
if (page >= paginated.totalPages || paginated.data.length === 0) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
page += 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Delete a snapshot by id. */
|
|
80
|
+
async delete(snapshotId, options) {
|
|
81
|
+
await this.transport.requestJson({
|
|
82
|
+
endpoint: `/sandboxes/snapshots/${snapshotId}`,
|
|
83
|
+
method: 'DELETE',
|
|
84
|
+
...options,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.SnapshotsResource = SnapshotsResource;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Stats, StatsQuery } from '../types';
|
|
2
|
+
import type { RequestOptions } from '../transport/http';
|
|
3
|
+
import { HttpTransport } from '../transport/http';
|
|
4
|
+
export declare class StatsResource {
|
|
5
|
+
private readonly transport;
|
|
6
|
+
private readonly sandboxId;
|
|
7
|
+
/** @internal Create the stats wrapper for one sandbox. */
|
|
8
|
+
constructor(transport: HttpTransport, sandboxId: string);
|
|
9
|
+
/** Fetch sandbox usage stats for a lookback window. */
|
|
10
|
+
stats(query?: StatsQuery, options?: RequestOptions): Promise<Stats>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StatsResource = void 0;
|
|
4
|
+
class StatsResource {
|
|
5
|
+
transport;
|
|
6
|
+
sandboxId;
|
|
7
|
+
/** @internal Create the stats wrapper for one sandbox. */
|
|
8
|
+
constructor(transport, sandboxId) {
|
|
9
|
+
this.transport = transport;
|
|
10
|
+
this.sandboxId = sandboxId;
|
|
11
|
+
}
|
|
12
|
+
/** Fetch sandbox usage stats for a lookback window. */
|
|
13
|
+
stats(query = {}, options) {
|
|
14
|
+
const params = new URLSearchParams();
|
|
15
|
+
if (query.hoursAgo !== undefined) {
|
|
16
|
+
params.set('hoursAgo', String(query.hoursAgo));
|
|
17
|
+
}
|
|
18
|
+
return this.transport.requestJson({
|
|
19
|
+
endpoint: `/sandboxes/${this.sandboxId}/stats`,
|
|
20
|
+
method: 'GET',
|
|
21
|
+
query: params,
|
|
22
|
+
...options,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.StatsResource = StatsResource;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RequestOptions } from '../transport/http';
|
|
2
|
+
import { HttpTransport } from '../transport/http';
|
|
3
|
+
import type { CreateVolumeInput, Paginated, TeamScopedPagination, Volume } from '../types';
|
|
4
|
+
export declare class VolumesResource {
|
|
5
|
+
private readonly transport;
|
|
6
|
+
/** @internal Create the volumes resource wrapper. */
|
|
7
|
+
constructor(transport: HttpTransport);
|
|
8
|
+
/** List your volumes with pagination. */
|
|
9
|
+
list(query?: TeamScopedPagination, options?: RequestOptions): Promise<Paginated<Volume>>;
|
|
10
|
+
/** Iterate over all volumes across paginated results. */
|
|
11
|
+
iterate(query?: TeamScopedPagination, options?: RequestOptions): AsyncGenerator<Volume>;
|
|
12
|
+
/**
|
|
13
|
+
* Create a new volume.
|
|
14
|
+
* This SDK accepts only `type: "sandbox"` and defaults to it when omitted.
|
|
15
|
+
*/
|
|
16
|
+
create(input: CreateVolumeInput, options?: RequestOptions): Promise<Volume>;
|
|
17
|
+
/** Fetch one volume by id. */
|
|
18
|
+
get(volumeId: string, options?: RequestOptions): Promise<Volume>;
|
|
19
|
+
/** Delete a volume by id. */
|
|
20
|
+
delete(volumeId: string, options?: RequestOptions): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VolumesResource = void 0;
|
|
4
|
+
const pagination_1 = require("../transport/pagination");
|
|
5
|
+
const enums_1 = require("../enums");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
7
|
+
class VolumesResource {
|
|
8
|
+
transport;
|
|
9
|
+
/** @internal Create the volumes resource wrapper. */
|
|
10
|
+
constructor(transport) {
|
|
11
|
+
this.transport = transport;
|
|
12
|
+
}
|
|
13
|
+
/** List your volumes with pagination. */
|
|
14
|
+
list(query = {}, options) {
|
|
15
|
+
const params = (0, pagination_1.toPaginationQuery)(query);
|
|
16
|
+
if (query.teamId) {
|
|
17
|
+
params.set('teamId', query.teamId);
|
|
18
|
+
}
|
|
19
|
+
return this.transport.requestJson({
|
|
20
|
+
endpoint: '/volumes',
|
|
21
|
+
method: 'GET',
|
|
22
|
+
query: params,
|
|
23
|
+
...options,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** Iterate over all volumes across paginated results. */
|
|
27
|
+
async *iterate(query = {}, options) {
|
|
28
|
+
const limit = query.limit ?? constants_1.DEFAULT_PAGE_LIMIT;
|
|
29
|
+
let page = query.page ?? constants_1.DEFAULT_PAGE;
|
|
30
|
+
while (true) {
|
|
31
|
+
const paginated = await this.list({ ...query, page, limit }, options);
|
|
32
|
+
for (const volume of paginated.data) {
|
|
33
|
+
yield volume;
|
|
34
|
+
}
|
|
35
|
+
if (page >= paginated.totalPages || paginated.data.length === 0) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
page += 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a new volume.
|
|
43
|
+
* This SDK accepts only `type: "sandbox"` and defaults to it when omitted.
|
|
44
|
+
*/
|
|
45
|
+
create(input, options) {
|
|
46
|
+
if (input.type && input.type !== enums_1.VolumeType.Sandbox) {
|
|
47
|
+
throw new Error('Only volume type "sandbox" is supported by this package.');
|
|
48
|
+
}
|
|
49
|
+
if (input.sizeGB < constants_1.MIN_VOLUME_SIZE_GB) {
|
|
50
|
+
throw new Error(`Volume size must be at least ${constants_1.MIN_VOLUME_SIZE_GB}GB.`);
|
|
51
|
+
}
|
|
52
|
+
const body = {
|
|
53
|
+
...input,
|
|
54
|
+
type: enums_1.VolumeType.Sandbox,
|
|
55
|
+
};
|
|
56
|
+
return this.transport.requestJson({
|
|
57
|
+
endpoint: '/volumes',
|
|
58
|
+
method: 'POST',
|
|
59
|
+
body,
|
|
60
|
+
...options,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** Fetch one volume by id. */
|
|
64
|
+
get(volumeId, options) {
|
|
65
|
+
return this.transport.requestJson({
|
|
66
|
+
endpoint: `/volumes/${volumeId}`,
|
|
67
|
+
method: 'GET',
|
|
68
|
+
...options,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Delete a volume by id. */
|
|
72
|
+
async delete(volumeId, options) {
|
|
73
|
+
await this.transport.requestJson({
|
|
74
|
+
endpoint: `/volumes/${volumeId}`,
|
|
75
|
+
method: 'DELETE',
|
|
76
|
+
...options,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.VolumesResource = VolumesResource;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
2
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
3
|
+
[key: string]: JsonValue;
|
|
4
|
+
};
|
|
5
|
+
export type RetryOptions = {
|
|
6
|
+
maxAttempts?: number;
|
|
7
|
+
baseDelayMs?: number;
|
|
8
|
+
maxDelayMs?: number;
|
|
9
|
+
retryStatuses?: number[];
|
|
10
|
+
retryMethods?: HttpMethod[];
|
|
11
|
+
};
|
|
12
|
+
export type RequestOptions = {
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
idempotencyKey?: string;
|
|
16
|
+
retry?: RetryOptions | false;
|
|
17
|
+
};
|
|
18
|
+
export type JsonRequestArgs = RequestOptions & {
|
|
19
|
+
endpoint: string;
|
|
20
|
+
method: HttpMethod;
|
|
21
|
+
query?: URLSearchParams;
|
|
22
|
+
body?: JsonValue | undefined;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
};
|
|
25
|
+
export type BinaryRequestArgs = RequestOptions & {
|
|
26
|
+
endpoint: string;
|
|
27
|
+
method: HttpMethod;
|
|
28
|
+
query?: URLSearchParams;
|
|
29
|
+
body?: ReadableStream<Uint8Array> | Buffer | Uint8Array;
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
};
|
|
32
|
+
export type HttpTransportConfig = {
|
|
33
|
+
baseUrl: string;
|
|
34
|
+
apiKey: string;
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
fetchImpl?: typeof fetch;
|
|
37
|
+
retry?: RetryOptions;
|
|
38
|
+
};
|
|
39
|
+
export declare class HttpTransport {
|
|
40
|
+
private readonly baseUrl;
|
|
41
|
+
private readonly apiKey;
|
|
42
|
+
private readonly timeoutMs;
|
|
43
|
+
private readonly fetchImpl;
|
|
44
|
+
private readonly retry;
|
|
45
|
+
/** Create a transport used by all SDK resources. */
|
|
46
|
+
constructor(config: HttpTransportConfig);
|
|
47
|
+
/**
|
|
48
|
+
* Send a JSON request and return the unwrapped `data` payload.
|
|
49
|
+
* If the endpoint returns 204, this resolves to `undefined`.
|
|
50
|
+
*/
|
|
51
|
+
requestJson<T>(args: JsonRequestArgs): Promise<T | undefined>;
|
|
52
|
+
/**
|
|
53
|
+
* Send a binary upload request (for file writes).
|
|
54
|
+
* Returns when the API acknowledges success.
|
|
55
|
+
*/
|
|
56
|
+
requestBinary(args: BinaryRequestArgs): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Send a JSON request and return the raw response stream.
|
|
59
|
+
* Used for endpoints that stream SSE frames (`text/event-stream`).
|
|
60
|
+
*/
|
|
61
|
+
requestJsonStream(args: JsonRequestArgs): Promise<ReadableStream<Uint8Array>>;
|
|
62
|
+
/**
|
|
63
|
+
* Request a binary response stream (for file downloads).
|
|
64
|
+
* Throws if the API returns an error status.
|
|
65
|
+
*/
|
|
66
|
+
requestStream(args: RequestOptions & {
|
|
67
|
+
endpoint: string;
|
|
68
|
+
method: HttpMethod;
|
|
69
|
+
query?: URLSearchParams;
|
|
70
|
+
}): Promise<ReadableStream<Uint8Array>>;
|
|
71
|
+
private executeRequest;
|
|
72
|
+
private toApiError;
|
|
73
|
+
}
|