@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.
Files changed (47) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/client/sdk.gen.js +124 -3
  3. package/dist/cjs/common/settings.js +2 -2
  4. package/dist/cjs/drive/index.js +182 -0
  5. package/dist/cjs/index.js +1 -0
  6. package/dist/cjs/sandbox/drive/drive.js +70 -0
  7. package/dist/cjs/sandbox/drive/index.js +17 -0
  8. package/dist/cjs/sandbox/sandbox.js +9 -6
  9. package/dist/cjs/types/client/sdk.gen.d.ts +47 -1
  10. package/dist/cjs/types/client/types.gen.d.ts +237 -0
  11. package/dist/cjs/types/drive/index.d.ts +34 -0
  12. package/dist/cjs/types/index.d.ts +1 -0
  13. package/dist/cjs/types/sandbox/drive/drive.d.ts +42 -0
  14. package/dist/cjs/types/sandbox/drive/index.d.ts +1 -0
  15. package/dist/cjs/types/sandbox/sandbox.d.ts +2 -0
  16. package/dist/cjs-browser/.tsbuildinfo +1 -1
  17. package/dist/cjs-browser/client/sdk.gen.js +124 -3
  18. package/dist/cjs-browser/common/settings.js +2 -2
  19. package/dist/cjs-browser/drive/index.js +182 -0
  20. package/dist/cjs-browser/index.js +1 -0
  21. package/dist/cjs-browser/sandbox/drive/drive.js +70 -0
  22. package/dist/cjs-browser/sandbox/drive/index.js +17 -0
  23. package/dist/cjs-browser/sandbox/sandbox.js +9 -6
  24. package/dist/cjs-browser/types/client/sdk.gen.d.ts +47 -1
  25. package/dist/cjs-browser/types/client/types.gen.d.ts +237 -0
  26. package/dist/cjs-browser/types/drive/index.d.ts +34 -0
  27. package/dist/cjs-browser/types/index.d.ts +1 -0
  28. package/dist/cjs-browser/types/sandbox/drive/drive.d.ts +42 -0
  29. package/dist/cjs-browser/types/sandbox/drive/index.d.ts +1 -0
  30. package/dist/cjs-browser/types/sandbox/sandbox.d.ts +2 -0
  31. package/dist/esm/.tsbuildinfo +1 -1
  32. package/dist/esm/client/sdk.gen.js +114 -0
  33. package/dist/esm/common/settings.js +2 -2
  34. package/dist/esm/drive/index.js +178 -0
  35. package/dist/esm/index.js +1 -0
  36. package/dist/esm/sandbox/drive/drive.js +66 -0
  37. package/dist/esm/sandbox/drive/index.js +1 -0
  38. package/dist/esm/sandbox/sandbox.js +3 -0
  39. package/dist/esm-browser/.tsbuildinfo +1 -1
  40. package/dist/esm-browser/client/sdk.gen.js +114 -0
  41. package/dist/esm-browser/common/settings.js +2 -2
  42. package/dist/esm-browser/drive/index.js +178 -0
  43. package/dist/esm-browser/index.js +1 -0
  44. package/dist/esm-browser/sandbox/drive/drive.js +66 -0
  45. package/dist/esm-browser/sandbox/drive/index.js +1 -0
  46. package/dist/esm-browser/sandbox/sandbox.js +3 -0
  47. 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.69";
7
- const BUILD_COMMIT = "a5d782ced9baa4585eefb6643399e73e504d3184";
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
+ }
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaxel/core",
3
- "version": "0.2.69",
3
+ "version": "0.2.70",
4
4
  "description": "Blaxel Core SDK for TypeScript",
5
5
  "license": "MIT",
6
6
  "author": "Blaxel, INC (https://blaxel.ai)",