@blaxel/core 0.2.69 → 0.2.70
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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/client/sdk.gen.js +124 -3
- package/dist/cjs/common/settings.js +2 -2
- package/dist/cjs/drive/index.js +182 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/sandbox/drive/drive.js +70 -0
- package/dist/cjs/sandbox/drive/index.js +17 -0
- package/dist/cjs/sandbox/sandbox.js +9 -6
- package/dist/cjs/types/client/sdk.gen.d.ts +47 -1
- package/dist/cjs/types/client/types.gen.d.ts +237 -0
- package/dist/cjs/types/drive/index.d.ts +34 -0
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/sandbox/drive/drive.d.ts +42 -0
- package/dist/cjs/types/sandbox/drive/index.d.ts +1 -0
- package/dist/cjs/types/sandbox/sandbox.d.ts +2 -0
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/client/sdk.gen.js +124 -3
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/drive/index.js +182 -0
- package/dist/cjs-browser/index.js +1 -0
- package/dist/cjs-browser/sandbox/drive/drive.js +70 -0
- package/dist/cjs-browser/sandbox/drive/index.js +17 -0
- package/dist/cjs-browser/sandbox/sandbox.js +9 -6
- package/dist/cjs-browser/types/client/sdk.gen.d.ts +47 -1
- package/dist/cjs-browser/types/client/types.gen.d.ts +237 -0
- package/dist/cjs-browser/types/drive/index.d.ts +34 -0
- package/dist/cjs-browser/types/index.d.ts +1 -0
- package/dist/cjs-browser/types/sandbox/drive/drive.d.ts +42 -0
- package/dist/cjs-browser/types/sandbox/drive/index.d.ts +1 -0
- package/dist/cjs-browser/types/sandbox/sandbox.d.ts +2 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/client/sdk.gen.js +114 -0
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm/drive/index.js +178 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/sandbox/drive/drive.js +66 -0
- package/dist/esm/sandbox/drive/index.js +1 -0
- package/dist/esm/sandbox/sandbox.js +3 -0
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/client/sdk.gen.js +114 -0
- package/dist/esm-browser/common/settings.js +2 -2
- package/dist/esm-browser/drive/index.js +178 -0
- package/dist/esm-browser/index.js +1 -0
- package/dist/esm-browser/sandbox/drive/drive.js +66 -0
- package/dist/esm-browser/sandbox/drive/index.js +1 -0
- package/dist/esm-browser/sandbox/sandbox.js +3 -0
- package/package.json +1 -1
|
@@ -219,6 +219,120 @@ export const verifyCustomDomain = (options) => {
|
|
|
219
219
|
...options
|
|
220
220
|
});
|
|
221
221
|
};
|
|
222
|
+
/**
|
|
223
|
+
* List drives
|
|
224
|
+
* Returns all drives in the workspace. Drives provide persistent storage that can be attached to agents, functions, and sandboxes.
|
|
225
|
+
*/
|
|
226
|
+
export const listDrives = (options) => {
|
|
227
|
+
return (options?.client ?? _heyApiClient).get({
|
|
228
|
+
security: [
|
|
229
|
+
{
|
|
230
|
+
scheme: 'bearer',
|
|
231
|
+
type: 'http'
|
|
232
|
+
}
|
|
233
|
+
],
|
|
234
|
+
url: '/drives',
|
|
235
|
+
...options
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Create a drive
|
|
240
|
+
* Creates a new drive in the workspace. Drives are backed by SeaweedFS buckets and can be mounted at runtime to sandboxes.
|
|
241
|
+
*/
|
|
242
|
+
export const createDrive = (options) => {
|
|
243
|
+
return (options.client ?? _heyApiClient).post({
|
|
244
|
+
security: [
|
|
245
|
+
{
|
|
246
|
+
scheme: 'bearer',
|
|
247
|
+
type: 'http'
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
url: '/drives',
|
|
251
|
+
...options,
|
|
252
|
+
headers: {
|
|
253
|
+
'Content-Type': 'application/json',
|
|
254
|
+
...options?.headers
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Delete a drive
|
|
260
|
+
* Deletes a drive immediately. The drive record is removed from the database synchronously.
|
|
261
|
+
*/
|
|
262
|
+
export const deleteDrive = (options) => {
|
|
263
|
+
return (options.client ?? _heyApiClient).delete({
|
|
264
|
+
security: [
|
|
265
|
+
{
|
|
266
|
+
scheme: 'bearer',
|
|
267
|
+
type: 'http'
|
|
268
|
+
}
|
|
269
|
+
],
|
|
270
|
+
url: '/drives/{driveName}',
|
|
271
|
+
...options
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Get a drive
|
|
276
|
+
* Retrieves details of a specific drive including its status and events.
|
|
277
|
+
*/
|
|
278
|
+
export const getDrive = (options) => {
|
|
279
|
+
return (options.client ?? _heyApiClient).get({
|
|
280
|
+
security: [
|
|
281
|
+
{
|
|
282
|
+
scheme: 'bearer',
|
|
283
|
+
type: 'http'
|
|
284
|
+
}
|
|
285
|
+
],
|
|
286
|
+
url: '/drives/{driveName}',
|
|
287
|
+
...options
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
/**
|
|
291
|
+
* Update a drive
|
|
292
|
+
* Updates an existing drive. Metadata fields like displayName and labels can be changed. Size can be set if not already configured.
|
|
293
|
+
*/
|
|
294
|
+
export const updateDrive = (options) => {
|
|
295
|
+
return (options.client ?? _heyApiClient).put({
|
|
296
|
+
security: [
|
|
297
|
+
{
|
|
298
|
+
scheme: 'bearer',
|
|
299
|
+
type: 'http'
|
|
300
|
+
}
|
|
301
|
+
],
|
|
302
|
+
url: '/drives/{driveName}',
|
|
303
|
+
...options,
|
|
304
|
+
headers: {
|
|
305
|
+
'Content-Type': 'application/json',
|
|
306
|
+
...options?.headers
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Create drive access token
|
|
312
|
+
* Issues a short-lived JWT access token scoped to a specific drive. The token can be used as Bearer authentication for direct S3 operations against the drive's SeaweedFS bucket.
|
|
313
|
+
*/
|
|
314
|
+
export const createDriveAccessToken = (options) => {
|
|
315
|
+
return (options.client ?? _heyApiClient).post({
|
|
316
|
+
security: [
|
|
317
|
+
{
|
|
318
|
+
scheme: 'bearer',
|
|
319
|
+
type: 'http'
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
url: '/drives/{driveName}/access-token',
|
|
323
|
+
...options
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
/**
|
|
327
|
+
* Get drive token JWKS
|
|
328
|
+
* Returns the JSON Web Key Set containing the Ed25519 public key used to verify drive access tokens. SeaweedFS or other S3-compatible storage can use this endpoint to validate Bearer tokens.
|
|
329
|
+
*/
|
|
330
|
+
export const getDriveJwks = (options) => {
|
|
331
|
+
return (options?.client ?? _heyApiClient).get({
|
|
332
|
+
url: '/drives/jwks.json',
|
|
333
|
+
...options
|
|
334
|
+
});
|
|
335
|
+
};
|
|
222
336
|
/**
|
|
223
337
|
* List all egress gateways across all VPCs in the workspace
|
|
224
338
|
*/
|
|
@@ -3,8 +3,8 @@ import { authentication } from "../authentication/index.js";
|
|
|
3
3
|
import { env } from "../common/env.js";
|
|
4
4
|
import { fs, os, path } from "../common/node.js";
|
|
5
5
|
// Build info - these placeholders are replaced at build time by build:replace-imports
|
|
6
|
-
const BUILD_VERSION = "0.2.
|
|
7
|
-
const BUILD_COMMIT = "
|
|
6
|
+
const BUILD_VERSION = "0.2.70";
|
|
7
|
+
const BUILD_COMMIT = "a3bbb13aa4ec149d33f1662d30dfb10ce3683baf";
|
|
8
8
|
const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
|
|
9
9
|
// Cache for config.yaml tracking value
|
|
10
10
|
let configTrackingValue = null;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
import { createDrive, deleteDrive, getDrive, listDrives, updateDrive } from "../client/index.js";
|
|
3
|
+
import { settings } from "../common/settings.js";
|
|
4
|
+
export class DriveInstance {
|
|
5
|
+
drive;
|
|
6
|
+
constructor(drive) {
|
|
7
|
+
this.drive = drive;
|
|
8
|
+
}
|
|
9
|
+
get metadata() {
|
|
10
|
+
return this.drive.metadata;
|
|
11
|
+
}
|
|
12
|
+
get spec() {
|
|
13
|
+
return this.drive.spec;
|
|
14
|
+
}
|
|
15
|
+
get state() {
|
|
16
|
+
return this.drive.state;
|
|
17
|
+
}
|
|
18
|
+
get status() {
|
|
19
|
+
return this.drive.status;
|
|
20
|
+
}
|
|
21
|
+
get name() {
|
|
22
|
+
return this.drive.metadata.name;
|
|
23
|
+
}
|
|
24
|
+
get displayName() {
|
|
25
|
+
return this.drive.metadata.displayName;
|
|
26
|
+
}
|
|
27
|
+
get size() {
|
|
28
|
+
return this.drive.spec.size;
|
|
29
|
+
}
|
|
30
|
+
get region() {
|
|
31
|
+
return this.drive.spec.region;
|
|
32
|
+
}
|
|
33
|
+
static async create(config) {
|
|
34
|
+
const defaultName = `drive-${uuidv4().replace(/-/g, '').substring(0, 8)}`;
|
|
35
|
+
let drive;
|
|
36
|
+
// Handle DriveCreateConfiguration or simple config object
|
|
37
|
+
if ('spec' in config && 'metadata' in config) {
|
|
38
|
+
// It's already a Drive object
|
|
39
|
+
drive = config;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
drive = {
|
|
43
|
+
metadata: {
|
|
44
|
+
name: config.name || defaultName,
|
|
45
|
+
displayName: config.displayName || config.name || defaultName,
|
|
46
|
+
labels: config.labels
|
|
47
|
+
},
|
|
48
|
+
spec: {
|
|
49
|
+
size: config.size,
|
|
50
|
+
region: config.region || settings.region
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Ensure required fields have defaults
|
|
55
|
+
if (!drive.metadata) {
|
|
56
|
+
drive.metadata = { name: defaultName };
|
|
57
|
+
}
|
|
58
|
+
if (!drive.metadata.name) {
|
|
59
|
+
drive.metadata.name = defaultName;
|
|
60
|
+
}
|
|
61
|
+
if (!drive.spec) {
|
|
62
|
+
drive.spec = {};
|
|
63
|
+
}
|
|
64
|
+
if (!drive.spec.region && settings.region) {
|
|
65
|
+
drive.spec.region = settings.region;
|
|
66
|
+
}
|
|
67
|
+
if (!drive.spec.region) {
|
|
68
|
+
console.warn("DriveInstance.create: 'region' is not set. In a future version, 'region' will be a required parameter. " +
|
|
69
|
+
"Please specify a region (e.g. 'us-pdx-1', 'eu-lon-1', 'eu-dub-1') in the drive configuration or set the BL_REGION environment variable.");
|
|
70
|
+
}
|
|
71
|
+
const { data } = await createDrive({
|
|
72
|
+
body: drive,
|
|
73
|
+
throwOnError: true,
|
|
74
|
+
});
|
|
75
|
+
return new DriveInstance(data);
|
|
76
|
+
}
|
|
77
|
+
static async get(driveName) {
|
|
78
|
+
const { data } = await getDrive({
|
|
79
|
+
path: {
|
|
80
|
+
driveName,
|
|
81
|
+
},
|
|
82
|
+
throwOnError: true,
|
|
83
|
+
});
|
|
84
|
+
return new DriveInstance(data);
|
|
85
|
+
}
|
|
86
|
+
static async list() {
|
|
87
|
+
const { data } = await listDrives({ throwOnError: true });
|
|
88
|
+
return data.map((drive) => new DriveInstance(drive));
|
|
89
|
+
}
|
|
90
|
+
static async delete(driveName) {
|
|
91
|
+
const { data } = await deleteDrive({
|
|
92
|
+
path: {
|
|
93
|
+
driveName,
|
|
94
|
+
},
|
|
95
|
+
throwOnError: true,
|
|
96
|
+
});
|
|
97
|
+
return data;
|
|
98
|
+
}
|
|
99
|
+
async delete() {
|
|
100
|
+
return await DriveInstance.delete(this.metadata.name);
|
|
101
|
+
}
|
|
102
|
+
static async update(driveName, updates) {
|
|
103
|
+
const drive = await DriveInstance.get(driveName);
|
|
104
|
+
const metadataUpdates = {};
|
|
105
|
+
const specUpdates = {};
|
|
106
|
+
if ('spec' in updates && 'metadata' in updates) {
|
|
107
|
+
// It's a Drive object - only include defined fields
|
|
108
|
+
if (updates.metadata) {
|
|
109
|
+
if (updates.metadata.displayName !== undefined)
|
|
110
|
+
metadataUpdates.displayName = updates.metadata.displayName;
|
|
111
|
+
if (updates.metadata.labels !== undefined)
|
|
112
|
+
metadataUpdates.labels = updates.metadata.labels;
|
|
113
|
+
}
|
|
114
|
+
if (updates.spec) {
|
|
115
|
+
if (updates.spec.size !== undefined)
|
|
116
|
+
specUpdates.size = updates.spec.size;
|
|
117
|
+
if (updates.spec.region !== undefined)
|
|
118
|
+
specUpdates.region = updates.spec.region;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// It's a DriveCreateConfiguration - only include defined fields
|
|
123
|
+
if (updates.displayName !== undefined)
|
|
124
|
+
metadataUpdates.displayName = updates.displayName;
|
|
125
|
+
if (updates.labels !== undefined)
|
|
126
|
+
metadataUpdates.labels = updates.labels;
|
|
127
|
+
if (updates.size !== undefined)
|
|
128
|
+
specUpdates.size = updates.size;
|
|
129
|
+
if (updates.region !== undefined)
|
|
130
|
+
specUpdates.region = updates.region;
|
|
131
|
+
}
|
|
132
|
+
const body = {
|
|
133
|
+
metadata: {
|
|
134
|
+
...drive.metadata,
|
|
135
|
+
...metadataUpdates,
|
|
136
|
+
},
|
|
137
|
+
spec: {
|
|
138
|
+
...drive.spec,
|
|
139
|
+
...specUpdates,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
const { data } = await updateDrive({
|
|
143
|
+
path: { driveName },
|
|
144
|
+
body,
|
|
145
|
+
throwOnError: true,
|
|
146
|
+
});
|
|
147
|
+
const newDrive = {
|
|
148
|
+
metadata: data.metadata,
|
|
149
|
+
spec: data.spec,
|
|
150
|
+
events: data.events,
|
|
151
|
+
state: data.state,
|
|
152
|
+
status: data.status,
|
|
153
|
+
};
|
|
154
|
+
// This is for safe update
|
|
155
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
156
|
+
return new DriveInstance(newDrive);
|
|
157
|
+
}
|
|
158
|
+
async update(updates) {
|
|
159
|
+
const updated = await DriveInstance.update(this.metadata.name, updates);
|
|
160
|
+
return updated;
|
|
161
|
+
}
|
|
162
|
+
static async createIfNotExists(config) {
|
|
163
|
+
try {
|
|
164
|
+
return await DriveInstance.create(config);
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
if (typeof e === "object" && e !== null && "code" in e && (e.code === 409 || e.code === 'DRIVE_ALREADY_EXISTS')) {
|
|
168
|
+
const name = 'name' in config ? config.name : config.metadata.name;
|
|
169
|
+
if (!name) {
|
|
170
|
+
throw new Error("Drive name is required");
|
|
171
|
+
}
|
|
172
|
+
const driveInstance = await DriveInstance.get(name);
|
|
173
|
+
return driveInstance;
|
|
174
|
+
}
|
|
175
|
+
throw e;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./common/internal.js";
|
|
|
9
9
|
export * from "./common/logger.js";
|
|
10
10
|
export * from "./common/settings.js";
|
|
11
11
|
export * from "./common/webhook.js";
|
|
12
|
+
export * from "./drive/index.js";
|
|
12
13
|
export * from "./image/index.js";
|
|
13
14
|
export * from "./jobs/index.js";
|
|
14
15
|
export * from "./mcp/index.js";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { settings } from "../../common/settings.js";
|
|
2
|
+
import { SandboxAction } from "../action.js";
|
|
3
|
+
export class SandboxDrive extends SandboxAction {
|
|
4
|
+
constructor(sandbox) {
|
|
5
|
+
super(sandbox);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Mount a drive to the sandbox at a specific mount path
|
|
9
|
+
*/
|
|
10
|
+
async mount(request) {
|
|
11
|
+
const headers = this.sandbox.forceUrl ? this.sandbox.headers : settings.headers;
|
|
12
|
+
const body = {
|
|
13
|
+
driveName: request.driveName,
|
|
14
|
+
mountPath: request.mountPath,
|
|
15
|
+
drivePath: request.drivePath || "/",
|
|
16
|
+
};
|
|
17
|
+
const response = await fetch(`${this.url}/drives/mount`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
...headers,
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify(body),
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
const errorText = await response.text();
|
|
27
|
+
throw new Error(`Failed to mount drive: ${errorText}`);
|
|
28
|
+
}
|
|
29
|
+
return await response.json();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Unmount a drive from the sandbox by mount path
|
|
33
|
+
*/
|
|
34
|
+
async unmount(mountPath) {
|
|
35
|
+
const headers = this.sandbox.forceUrl ? this.sandbox.headers : settings.headers;
|
|
36
|
+
// Ensure mountPath starts with /
|
|
37
|
+
const normalizedPath = mountPath.startsWith('/') ? mountPath : `/${mountPath}`;
|
|
38
|
+
// Remove leading slash for URL (DELETE /drives/mnt/test not /drives//mnt/test)
|
|
39
|
+
const urlPath = normalizedPath.substring(1);
|
|
40
|
+
const response = await fetch(`${this.url}/drives/mount/${urlPath}`, {
|
|
41
|
+
method: 'DELETE',
|
|
42
|
+
headers,
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const errorText = await response.text();
|
|
46
|
+
throw new Error(`Failed to unmount drive: ${errorText}`);
|
|
47
|
+
}
|
|
48
|
+
return await response.json();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* List all mounted drives in the sandbox
|
|
52
|
+
*/
|
|
53
|
+
async list() {
|
|
54
|
+
const headers = this.sandbox.forceUrl ? this.sandbox.headers : settings.headers;
|
|
55
|
+
const response = await fetch(`${this.url}/drives/mount`, {
|
|
56
|
+
method: 'GET',
|
|
57
|
+
headers,
|
|
58
|
+
});
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const errorText = await response.text();
|
|
61
|
+
throw new Error(`Failed to list drives: ${errorText}`);
|
|
62
|
+
}
|
|
63
|
+
const data = await response.json();
|
|
64
|
+
return data.mounts || [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./drive.js";
|
|
@@ -3,6 +3,7 @@ import { createSandbox, deleteSandbox, getSandbox, listSandboxes, updateSandbox
|
|
|
3
3
|
import { logger } from "../common/logger.js";
|
|
4
4
|
import { settings } from "../common/settings.js";
|
|
5
5
|
import { SandboxCodegen } from "./codegen/index.js";
|
|
6
|
+
import { SandboxDrive } from "./drive/index.js";
|
|
6
7
|
import { SandboxFileSystem } from "./filesystem/index.js";
|
|
7
8
|
import { SandboxNetwork } from "./network/index.js";
|
|
8
9
|
import { SandboxPreviews } from "./preview.js";
|
|
@@ -19,6 +20,7 @@ export class SandboxInstance {
|
|
|
19
20
|
sessions;
|
|
20
21
|
codegen;
|
|
21
22
|
system;
|
|
23
|
+
drives;
|
|
22
24
|
constructor(sandbox) {
|
|
23
25
|
this.sandbox = sandbox;
|
|
24
26
|
this.process = new SandboxProcess(sandbox);
|
|
@@ -28,6 +30,7 @@ export class SandboxInstance {
|
|
|
28
30
|
this.sessions = new SandboxSessions(sandbox);
|
|
29
31
|
this.codegen = new SandboxCodegen(sandbox);
|
|
30
32
|
this.system = new SandboxSystem(sandbox);
|
|
33
|
+
this.drives = new SandboxDrive(sandbox);
|
|
31
34
|
}
|
|
32
35
|
get metadata() {
|
|
33
36
|
return this.sandbox.metadata;
|