@blaxel/core 0.3.32 → 0.3.34-preview.340

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 (43) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/common/posthog.js +2 -3
  3. package/dist/cjs/common/settings.js +2 -2
  4. package/dist/cjs/sandbox/client/sdk.gen.js +5 -1
  5. package/dist/cjs/sandbox/filesystem/filesystem.js +34 -1
  6. package/dist/cjs/sandbox/sandbox.dockerconfig.test.js +23 -0
  7. package/dist/cjs/sandbox/sandbox.js +5 -1
  8. package/dist/cjs/types/common/posthog.d.ts +1 -1
  9. package/dist/cjs/types/sandbox/client/sdk.gen.d.ts +5 -1
  10. package/dist/cjs/types/sandbox/client/types.gen.d.ts +49 -2
  11. package/dist/cjs/types/sandbox/filesystem/filesystem.d.ts +9 -0
  12. package/dist/cjs/types/sandbox/filesystem/types.d.ts +10 -0
  13. package/dist/cjs/types/sandbox/sandbox.dockerconfig.test.d.ts +1 -0
  14. package/dist/cjs/types/sandbox/types.d.ts +6 -0
  15. package/dist/cjs-browser/.tsbuildinfo +1 -1
  16. package/dist/cjs-browser/common/posthog.js +2 -3
  17. package/dist/cjs-browser/common/settings.js +2 -2
  18. package/dist/cjs-browser/sandbox/client/sdk.gen.js +5 -1
  19. package/dist/cjs-browser/sandbox/filesystem/filesystem.js +34 -1
  20. package/dist/cjs-browser/sandbox/sandbox.dockerconfig.test.js +23 -0
  21. package/dist/cjs-browser/sandbox/sandbox.js +5 -1
  22. package/dist/cjs-browser/types/common/posthog.d.ts +1 -1
  23. package/dist/cjs-browser/types/sandbox/client/sdk.gen.d.ts +5 -1
  24. package/dist/cjs-browser/types/sandbox/client/types.gen.d.ts +49 -2
  25. package/dist/cjs-browser/types/sandbox/filesystem/filesystem.d.ts +9 -0
  26. package/dist/cjs-browser/types/sandbox/filesystem/types.d.ts +10 -0
  27. package/dist/cjs-browser/types/sandbox/sandbox.dockerconfig.test.d.ts +1 -0
  28. package/dist/cjs-browser/types/sandbox/types.d.ts +6 -0
  29. package/dist/esm/.tsbuildinfo +1 -1
  30. package/dist/esm/common/posthog.js +2 -3
  31. package/dist/esm/common/settings.js +2 -2
  32. package/dist/esm/sandbox/client/sdk.gen.js +5 -1
  33. package/dist/esm/sandbox/filesystem/filesystem.js +35 -2
  34. package/dist/esm/sandbox/sandbox.dockerconfig.test.js +21 -0
  35. package/dist/esm/sandbox/sandbox.js +5 -1
  36. package/dist/esm-browser/.tsbuildinfo +1 -1
  37. package/dist/esm-browser/common/posthog.js +2 -3
  38. package/dist/esm-browser/common/settings.js +2 -2
  39. package/dist/esm-browser/sandbox/client/sdk.gen.js +5 -1
  40. package/dist/esm-browser/sandbox/filesystem/filesystem.js +35 -2
  41. package/dist/esm-browser/sandbox/sandbox.dockerconfig.test.js +21 -0
  42. package/dist/esm-browser/sandbox/sandbox.js +5 -1
  43. package/package.json +2 -2
@@ -8,14 +8,13 @@ const node_js_1 = require("../common/node.js");
8
8
  const settings_js_1 = require("./settings.js");
9
9
  // PostHog API key injected at build time via build:replace-imports
10
10
  const BUILD_POSTHOG_KEY = "";
11
- // PostHog API endpoint
12
- const POSTHOG_HOST = "https://us.i.posthog.com";
11
+ const POSTHOG_HOST = "https://events.blaxel.ai";
13
12
  /**
14
13
  * How long a capture may stay outstanding.
15
14
  *
16
15
  * Node keeps the event loop alive while a fetch is pending, so this is what a
17
16
  * short-lived script waits for before it can exit. A capture against
18
- * us.i.posthog.com takes ~250-350ms end to end (DNS + TLS handshake + POST), so
17
+ * events.blaxel.ai takes ~250-350ms end to end (DNS + TLS handshake + POST), so
19
18
  * a second covers the happy path with headroom. The ceiling matters because a
20
19
  * version is only recorded after a successful delivery: when the endpoint is
21
20
  * unreachable every later run tries again, and networks that silently drop
@@ -30,8 +30,8 @@ function missingCredentialsMessage() {
30
30
  return "No Blaxel credentials found. Set the BL_API_KEY and BL_WORKSPACE environment variables, or run `bl login`.";
31
31
  }
32
32
  // Build info - these placeholders are replaced at build time by build:replace-imports
33
- const BUILD_VERSION = "0.3.32";
34
- const BUILD_COMMIT = "85c4e5d52f8c501ac8db9409390611090a3e4df2";
33
+ const BUILD_VERSION = "0.3.34-preview.340";
34
+ const BUILD_COMMIT = "e1289af07e1a5c5efeb0af7b397d2c2fd138d89f";
35
35
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
36
36
  const BLAXEL_API_VERSION = "2026-09-22";
37
37
  // Bun < 1.3.11 never sends connection-level WINDOW_UPDATE: the pooled h2
@@ -466,7 +466,11 @@ const deleteFilesystemTreeByPath = (options) => {
466
466
  exports.deleteFilesystemTreeByPath = deleteFilesystemTreeByPath;
467
467
  /**
468
468
  * Get directory tree
469
- * Get a recursive directory tree structure starting from the specified path
469
+ * List a directory. Without query parameters, `files` and `subdirectories` hold its direct children.
470
+ *
471
+ * With `recursive=true`, they hold every file and directory below the path (flat, with full paths). With `content=true`, each regular file (or symlink to one) also carries its `content` as UTF-8 text, like a JSON file read; other entries have no `content`. `patterns`, `excludeDirs` and `excludeHidden` select entries the same way as find, but nothing is excluded by default.
472
+ *
473
+ * The response is all or nothing: when more than `maxFiles` files match, or `content=true` and they hold more than `maxBytes` bytes, the request fails with 422 before any content is read.
470
474
  */
471
475
  const getFilesystemTreeByPath = (options) => {
472
476
  return (options.client ?? client_gen_1.client).get({
@@ -207,12 +207,45 @@ class SandboxFileSystem extends action_js_1.SandboxAction {
207
207
  baseUrl: this.url,
208
208
  }));
209
209
  this.handleResponseError(response, data, error);
210
- if (data && 'content' in data) {
210
+ if (data && 'content' in data && typeof data.content === "string") {
211
211
  return data.content;
212
212
  }
213
213
  throw new Error("Unsupported file type");
214
214
  });
215
215
  }
216
+ /**
217
+ * Reads the whole tree under `path` in one request and returns the API's `Directory`: every
218
+ * file below `path` in `files`, each regular file (or symlink to one) with its `content` as
219
+ * UTF-8 text. The sandbox API applies `patterns`, `excludeDirs` and `excludeHidden`, and rejects,
220
+ * returning nothing partial, when more than `maxFiles` files match or they hold more than
221
+ * `maxBytes` bytes.
222
+ */
223
+ async readTree(path, options = {}) {
224
+ const { patterns, excludeDirs, excludeHidden, maxFiles, maxBytes } = options;
225
+ // Idempotent GET: self-heal a transient connection reset.
226
+ return (0, transient_retry_js_1.retryOnTransientReset)(async () => {
227
+ const { response, data, error } = await (0, index_js_1.getFilesystemTreeByPath)(this.withClient({
228
+ path: { path: this.formatPath(path) },
229
+ query: {
230
+ recursive: true,
231
+ content: true,
232
+ patterns: patterns?.join(","),
233
+ excludeDirs: excludeDirs?.join(","),
234
+ excludeHidden,
235
+ maxFiles,
236
+ maxBytes,
237
+ },
238
+ baseUrl: this.url,
239
+ }));
240
+ this.handleResponseError(response, data, error);
241
+ // An older sandbox API ignores the query and lists only direct children,
242
+ // without `recursive`. Fail instead of returning that as the whole tree.
243
+ if (data?.recursive !== true) {
244
+ throw new Error("readTree needs a newer sandbox API: this sandbox does not support recursive tree reads; update its image");
245
+ }
246
+ return data;
247
+ });
248
+ }
216
249
  async readBinary(path) {
217
250
  path = this.formatPath(path);
218
251
  // Idempotent GET: self-heal a transient connection reset.
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const sandbox_js_1 = require("./sandbox.js");
5
+ // toSandboxModel is private: reach it the same way the create path does, without a network call.
6
+ const { toSandboxModel } = sandbox_js_1.SandboxInstance;
7
+ const toRuntime = (config) => toSandboxModel(config).model.spec?.runtime;
8
+ (0, vitest_1.describe)("SandboxInstance.create dockerConfig", () => {
9
+ const auths = { auths: { "ghcr.io": { auth: "dXNlcjp0b2tlbg==" } } };
10
+ (0, vitest_1.it)("sends an object as a JSON string in spec.runtime.dockerConfig", () => {
11
+ const runtime = toRuntime({ image: "ghcr.io/org/private:v1", dockerConfig: auths, region: "us-pdx-1" });
12
+ (0, vitest_1.expect)(runtime.image).toBe("ghcr.io/org/private:v1");
13
+ (0, vitest_1.expect)(JSON.parse(runtime.dockerConfig)).toEqual(auths);
14
+ });
15
+ (0, vitest_1.it)("passes a string through unchanged", () => {
16
+ const raw = JSON.stringify(auths);
17
+ (0, vitest_1.expect)(toRuntime({ dockerConfig: raw, region: "us-pdx-1" }).dockerConfig).toBe(raw);
18
+ });
19
+ (0, vitest_1.it)("omits it from the request when not set", () => {
20
+ const body = JSON.parse(JSON.stringify(toRuntime({ image: "ghcr.io/org/private:v1", region: "us-pdx-1" })));
21
+ (0, vitest_1.expect)(body).not.toHaveProperty("dockerConfig");
22
+ });
23
+ });
@@ -381,7 +381,8 @@ class SandboxInstance {
381
381
  'labels' in sandbox ||
382
382
  'extraArgs' in sandbox ||
383
383
  'terminationGracePeriodSeconds' in sandbox ||
384
- 'standbyGracePeriodSeconds' in sandbox) {
384
+ 'standbyGracePeriodSeconds' in sandbox ||
385
+ 'dockerConfig' in sandbox) {
385
386
  if (!sandbox)
386
387
  sandbox = {};
387
388
  requested = { image: sandbox.image, memory: sandbox.memory, region: sandbox.region, envs: (0, types_js_1.normalizeEnvs)(sandbox.envs) };
@@ -404,6 +405,8 @@ class SandboxInstance {
404
405
  const snapshotEnabled = sandbox.snapshotEnabled;
405
406
  const extraArgs = sandbox.extraArgs;
406
407
  const { terminationGracePeriodSeconds, standbyGracePeriodSeconds } = sandbox;
408
+ // Not in the generated SandboxRuntime: the API reads it from the raw body, like the CLI sends it.
409
+ const dockerConfig = typeof sandbox.dockerConfig === "object" ? JSON.stringify(sandbox.dockerConfig) : sandbox.dockerConfig;
407
410
  sandbox = {
408
411
  metadata: { name: sandbox.name, labels: sandbox.labels, externalId: sandbox.externalId },
409
412
  spec: {
@@ -418,6 +421,7 @@ class SandboxInstance {
418
421
  extraArgs,
419
422
  terminationGracePeriodSeconds,
420
423
  standbyGracePeriodSeconds,
424
+ dockerConfig,
421
425
  },
422
426
  volumes: volumes,
423
427
  lifecycle: lifecycle,
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Node keeps the event loop alive while a fetch is pending, so this is what a
5
5
  * short-lived script waits for before it can exit. A capture against
6
- * us.i.posthog.com takes ~250-350ms end to end (DNS + TLS handshake + POST), so
6
+ * events.blaxel.ai takes ~250-350ms end to end (DNS + TLS handshake + POST), so
7
7
  * a second covers the happy path with headroom. The ceiling matters because a
8
8
  * version is only recorded after a successful delivery: when the endpoint is
9
9
  * unreachable every later run tries again, and networks that silently drop
@@ -170,7 +170,11 @@ export declare const putFilesystemByPath: <ThrowOnError extends boolean = false>
170
170
  export declare const deleteFilesystemTreeByPath: <ThrowOnError extends boolean = false>(options: Options<DeleteFilesystemTreeByPathData, ThrowOnError>) => import("@hey-api/client-fetch").RequestResult<import("./types.gen").SuccessResponse, import("./types.gen").ErrorResponse, ThrowOnError>;
171
171
  /**
172
172
  * Get directory tree
173
- * Get a recursive directory tree structure starting from the specified path
173
+ * List a directory. Without query parameters, `files` and `subdirectories` hold its direct children.
174
+ *
175
+ * With `recursive=true`, they hold every file and directory below the path (flat, with full paths). With `content=true`, each regular file (or symlink to one) also carries its `content` as UTF-8 text, like a JSON file read; other entries have no `content`. `patterns`, `excludeDirs` and `excludeHidden` select entries the same way as find, but nothing is excluded by default.
176
+ *
177
+ * The response is all or nothing: when more than `maxFiles` files match, or `content=true` and they hold more than `maxBytes` bytes, the request fails with 422 before any content is read.
174
178
  */
175
179
  export declare const getFilesystemTreeByPath: <ThrowOnError extends boolean = false>(options: Options<GetFilesystemTreeByPathData, ThrowOnError>) => import("@hey-api/client-fetch").RequestResult<import("./types.gen").Directory, import("./types.gen").ErrorResponse, ThrowOnError>;
176
180
  /**
@@ -68,6 +68,12 @@ export type Directory = {
68
68
  files: Array<File>;
69
69
  name: string;
70
70
  path: string;
71
+ /**
72
+ * Recursive is true when files and subdirectories hold every level below
73
+ * path (tree read with recursive=true). Older APIs ignore that parameter
74
+ * and omit this field, so clients can tell a one-level listing apart.
75
+ */
76
+ recursive?: boolean;
71
77
  /**
72
78
  * @name Subdirectories
73
79
  */
@@ -233,6 +239,10 @@ export type ExportResult = {
233
239
  uploaded?: boolean;
234
240
  };
235
241
  export type File = {
242
+ /**
243
+ * Content is set only by a tree read with content=true, for regular files.
244
+ */
245
+ content?: string;
236
246
  group: string;
237
247
  lastModified: string;
238
248
  name: string;
@@ -785,6 +795,10 @@ export type PostDrivesMountErrors = {
785
795
  * Internal Server Error
786
796
  */
787
797
  500: ErrorResponse;
798
+ /**
799
+ * Insufficient Storage
800
+ */
801
+ 507: ErrorResponse;
788
802
  };
789
803
  export type PostDrivesMountError = PostDrivesMountErrors[keyof PostDrivesMountErrors];
790
804
  export type PostDrivesMountResponses = {
@@ -810,6 +824,10 @@ export type DeleteDrivesMountByMountPathErrors = {
810
824
  * Bad Request
811
825
  */
812
826
  400: ErrorResponse;
827
+ /**
828
+ * Not Found
829
+ */
830
+ 404: ErrorResponse;
813
831
  /**
814
832
  * Internal Server Error
815
833
  */
@@ -1385,7 +1403,36 @@ export type GetFilesystemTreeByPathData = {
1385
1403
  */
1386
1404
  path: string;
1387
1405
  };
1388
- query?: never;
1406
+ query?: {
1407
+ /**
1408
+ * List every file and directory below the path, not only its direct children (default: false)
1409
+ */
1410
+ recursive?: boolean;
1411
+ /**
1412
+ * Include the content of each regular file, as UTF-8 text (default: false)
1413
+ */
1414
+ content?: boolean;
1415
+ /**
1416
+ * Comma-separated glob patterns matched against file names (e.g., *.json,*.md). Directories are not filtered.
1417
+ */
1418
+ patterns?: string;
1419
+ /**
1420
+ * Comma-separated directory names to skip with everything below them (default: none)
1421
+ */
1422
+ excludeDirs?: string;
1423
+ /**
1424
+ * Skip files and directories whose name starts with a dot (default: false)
1425
+ */
1426
+ excludeHidden?: boolean;
1427
+ /**
1428
+ * Fail with 422 when more files match (default: 10000 with recursive or content, otherwise unlimited; at most 100000)
1429
+ */
1430
+ maxFiles?: number;
1431
+ /**
1432
+ * With content=true, fail with 422 when the matching files hold more bytes (default: 33554432, 32 MiB; at most 268435456, 256 MiB)
1433
+ */
1434
+ maxBytes?: number;
1435
+ };
1389
1436
  url: '/filesystem/tree/{path}';
1390
1437
  };
1391
1438
  export type GetFilesystemTreeByPathErrors = {
@@ -1394,7 +1441,7 @@ export type GetFilesystemTreeByPathErrors = {
1394
1441
  */
1395
1442
  400: ErrorResponse;
1396
1443
  /**
1397
- * Unprocessable entity
1444
+ * Unprocessable entity, including a maxFiles or maxBytes limit
1398
1445
  */
1399
1446
  422: ErrorResponse;
1400
1447
  /**
@@ -4,6 +4,7 @@ import { SandboxAction } from "../action.js";
4
4
  import { ContentSearchResponse, Directory, FindResponse, FuzzySearchResponse, SuccessResponse } from "../client/index.js";
5
5
  import { SandboxProcess } from "../process/index.js";
6
6
  import { CopyResponse, FilesystemFindOptions, FilesystemGrepOptions, FilesystemSearchOptions, SandboxFilesystemFile, WatchEvent } from "./types.js";
7
+ import type { FilesystemReadTreeOptions } from "./types.js";
7
8
  export declare const isTransientUploadError: typeof isTransientResetError;
8
9
  export declare function retryOnTransient<T>(fn: () => Promise<T>): Promise<T>;
9
10
  export declare class SandboxFileSystem extends SandboxAction {
@@ -14,6 +15,14 @@ export declare class SandboxFileSystem extends SandboxAction {
14
15
  writeBinary(path: string, content: Buffer | Blob | File | Uint8Array | string): Promise<SuccessResponse>;
15
16
  writeTree(files: SandboxFilesystemFile[], destinationPath?: string | null): Promise<Directory | undefined>;
16
17
  read(path: string): Promise<string>;
18
+ /**
19
+ * Reads the whole tree under `path` in one request and returns the API's `Directory`: every
20
+ * file below `path` in `files`, each regular file (or symlink to one) with its `content` as
21
+ * UTF-8 text. The sandbox API applies `patterns`, `excludeDirs` and `excludeHidden`, and rejects,
22
+ * returning nothing partial, when more than `maxFiles` files match or they hold more than
23
+ * `maxBytes` bytes.
24
+ */
25
+ readTree(path: string, options?: FilesystemReadTreeOptions): Promise<Directory>;
17
26
  readBinary(path: string): Promise<Blob>;
18
27
  download(src: string, destinationPath: string, { mode }?: {
19
28
  mode?: number;
@@ -26,6 +26,16 @@ export interface FilesystemFindOptions {
26
26
  excludeDirs?: string[];
27
27
  excludeHidden?: boolean;
28
28
  }
29
+ export type FilesystemReadTreeOptions = Pick<FilesystemFindOptions, "patterns"> & {
30
+ /** Directory names to skip, with everything below them. Default: none. */
31
+ excludeDirs?: string[];
32
+ /** Skip files and directories whose name starts with a dot. Default: false. */
33
+ excludeHidden?: boolean;
34
+ /** Reject instead of truncating when more files match. Default 10000, at most 100000. */
35
+ maxFiles?: number;
36
+ /** Reject when the matching files hold more bytes. Default 32 MiB, at most 256 MiB. */
37
+ maxBytes?: number;
38
+ };
29
39
  export interface FilesystemGrepOptions {
30
40
  caseSensitive?: boolean;
31
41
  contextLines?: number;
@@ -81,6 +81,12 @@ export type SandboxCreateConfiguration = {
81
81
  terminationGracePeriodSeconds?: number;
82
82
  /** Seconds the sandbox gets after SIGUSR2 to prepare before standby. Defaults to 0. */
83
83
  standbyGracePeriodSeconds?: number;
84
+ /**
85
+ * Registry credentials to pull a private registry image (e.g. ghcr.io/org/image:tag),
86
+ * in Docker config.json format: { auths: { "ghcr.io": { auth: base64("user:token") } } }.
87
+ * Only used when image is a registry reference.
88
+ */
89
+ dockerConfig?: string | Record<string, unknown>;
84
90
  };
85
91
  export declare function normalizePorts(ports?: (Port | Record<string, any>)[]): Port[] | undefined;
86
92
  export declare function normalizeEnvs(envs?: EnvVar[]): EnvVar[] | undefined;