@blaxel/core 0.2.82-preview.146 → 0.2.82

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/h2fetch.js +93 -13
  3. package/dist/cjs/common/h2pool.js +109 -14
  4. package/dist/cjs/common/lazyInit.js +1 -1
  5. package/dist/cjs/common/settings.js +11 -2
  6. package/dist/cjs/sandbox/action.js +12 -8
  7. package/dist/cjs/sandbox/interpreter.js +6 -3
  8. package/dist/cjs/sandbox/sandbox.js +22 -11
  9. package/dist/cjs/types/common/h2fetch.d.ts +6 -6
  10. package/dist/cjs/types/common/h2pool.d.ts +20 -0
  11. package/dist/cjs/types/common/settings.d.ts +2 -0
  12. package/dist/cjs/types/sandbox/action.d.ts +1 -0
  13. package/dist/cjs/types/sandbox/sandbox.d.ts +4 -1
  14. package/dist/cjs/types/sandbox/types.d.ts +1 -0
  15. package/dist/cjs-browser/.tsbuildinfo +1 -1
  16. package/dist/cjs-browser/common/h2fetch.js +1 -0
  17. package/dist/cjs-browser/common/lazyInit.js +1 -1
  18. package/dist/cjs-browser/common/settings.js +11 -2
  19. package/dist/cjs-browser/sandbox/action.js +12 -8
  20. package/dist/cjs-browser/sandbox/interpreter.js +6 -3
  21. package/dist/cjs-browser/sandbox/sandbox.js +22 -11
  22. package/dist/cjs-browser/types/common/h2fetch.d.ts +6 -6
  23. package/dist/cjs-browser/types/common/h2pool.d.ts +20 -0
  24. package/dist/cjs-browser/types/common/settings.d.ts +2 -0
  25. package/dist/cjs-browser/types/sandbox/action.d.ts +1 -0
  26. package/dist/cjs-browser/types/sandbox/sandbox.d.ts +4 -1
  27. package/dist/cjs-browser/types/sandbox/types.d.ts +1 -0
  28. package/dist/esm/.tsbuildinfo +1 -1
  29. package/dist/esm/common/h2fetch.js +92 -13
  30. package/dist/esm/common/h2pool.js +109 -14
  31. package/dist/esm/common/lazyInit.js +1 -1
  32. package/dist/esm/common/settings.js +11 -2
  33. package/dist/esm/sandbox/action.js +13 -9
  34. package/dist/esm/sandbox/interpreter.js +7 -4
  35. package/dist/esm/sandbox/sandbox.js +22 -11
  36. package/dist/esm-browser/.tsbuildinfo +1 -1
  37. package/dist/esm-browser/common/h2fetch.js +1 -0
  38. package/dist/esm-browser/common/lazyInit.js +1 -1
  39. package/dist/esm-browser/common/settings.js +11 -2
  40. package/dist/esm-browser/sandbox/action.js +13 -9
  41. package/dist/esm-browser/sandbox/interpreter.js +7 -4
  42. package/dist/esm-browser/sandbox/sandbox.js +22 -11
  43. package/package.json +1 -1
@@ -2,3 +2,4 @@
2
2
  export function createH2Fetch(session) { return (input) => globalThis.fetch(input); }
3
3
  export function createPoolBackedH2Fetch(pool, domain) { return (input) => globalThis.fetch(input); }
4
4
  export function h2RequestDirect(session, url, init) { return globalThis.fetch(url, init); }
5
+ export function h2RequestDirectFromPool(pool, domain, url, init) { return globalThis.fetch(url, init); }
@@ -77,7 +77,7 @@ function ensureAutoloaded() {
77
77
  const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
78
78
  /* eslint-disable */
79
79
  const isBrowser = typeof globalThis !== "undefined" && globalThis?.window !== undefined;
80
- if (isNode && !isBrowser) {
80
+ if (isNode && !isBrowser && !settings_js_1.settings.disableH2) {
81
81
  try {
82
82
  // Pre-warm edge H2 for the configured region so the first
83
83
  // SandboxInstance.create() gets an instant session via the pool.
@@ -11,8 +11,8 @@ const index_js_1 = require("../authentication/index.js");
11
11
  const env_js_1 = require("../common/env.js");
12
12
  const node_js_1 = require("../common/node.js");
13
13
  // Build info - these placeholders are replaced at build time by build:replace-imports
14
- const BUILD_VERSION = "0.2.82-preview.146";
15
- const BUILD_COMMIT = "bd1f2f080c52d701b0dcbcccd73d139be5740ef2";
14
+ const BUILD_VERSION = "0.2.82";
15
+ const BUILD_COMMIT = "4d2b3531bdb9d8a065f6d83822343840ae0b8d65";
16
16
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
17
17
  const BLAXEL_API_VERSION = "2026-04-16";
18
18
  // Cache for config.yaml tracking value
@@ -218,6 +218,15 @@ class Settings {
218
218
  get region() {
219
219
  return env_js_1.env.BL_REGION || undefined;
220
220
  }
221
+ get disableH2() {
222
+ if (typeof this.config.disableH2 === "boolean") {
223
+ return this.config.disableH2;
224
+ }
225
+ const value = env_js_1.env.BL_DISABLE_H2;
226
+ if (!value)
227
+ return false;
228
+ return ["1", "true", "yes", "on"].includes(value.toLowerCase());
229
+ }
221
230
  async authenticate() {
222
231
  await this.credentials.authenticate();
223
232
  }
@@ -5,6 +5,7 @@ const client_fetch_1 = require("@hey-api/client-fetch");
5
5
  const interceptors_js_1 = require("../client/interceptors.js");
6
6
  const responseInterceptor_js_1 = require("../client/responseInterceptor.js");
7
7
  const h2fetch_js_1 = require("../common/h2fetch.js");
8
+ const h2pool_js_1 = require("../common/h2pool.js");
8
9
  const internal_js_1 = require("../common/internal.js");
9
10
  const settings_js_1 = require("../common/settings.js");
10
11
  const client_gen_js_1 = require("./client/client.gen.js");
@@ -36,6 +37,7 @@ exports.ResponseError = ResponseError;
36
37
  class SandboxAction {
37
38
  sandbox;
38
39
  _h2Client = null;
40
+ _h2ClientDomain = null;
39
41
  constructor(sandbox) {
40
42
  this.sandbox = sandbox;
41
43
  }
@@ -62,12 +64,13 @@ class SandboxAction {
62
64
  headers: this.sandbox.headers,
63
65
  });
64
66
  }
65
- const session = this.sandbox.h2Session;
66
- if (session && !session.closed && !session.destroyed) {
67
- if (!this._h2Client) {
67
+ const h2Domain = this.sandbox.h2Domain;
68
+ if (h2Domain) {
69
+ if (!this._h2Client || this._h2ClientDomain !== h2Domain) {
68
70
  this._h2Client = (0, client_fetch_1.createClient)({
69
- fetch: (0, h2fetch_js_1.createH2Fetch)(session),
71
+ fetch: (0, h2fetch_js_1.createPoolBackedH2Fetch)(h2pool_js_1.h2Pool, h2Domain),
70
72
  });
73
+ this._h2ClientDomain = h2Domain;
71
74
  for (const interceptor of interceptors_js_1.interceptors) {
72
75
  // @ts-expect-error - Interceptor is not typed
73
76
  this._h2Client.interceptors.request.use(interceptor);
@@ -78,8 +81,9 @@ class SandboxAction {
78
81
  }
79
82
  return this._h2Client;
80
83
  }
81
- // Invalidate cached H2 client when session is no longer usable
84
+ // Invalidate cached H2 client when the sandbox no longer has an H2 domain.
82
85
  this._h2Client = null;
86
+ this._h2ClientDomain = null;
83
87
  return client_gen_js_1.client;
84
88
  }
85
89
  /**
@@ -87,9 +91,9 @@ class SandboxAction {
87
91
  * globalThis.fetch. Uses a direct H2 path that avoids Request allocation.
88
92
  */
89
93
  h2Fetch(input, init) {
90
- const session = this.sandbox.h2Session;
91
- if (session && !session.closed && !session.destroyed) {
92
- return (0, h2fetch_js_1.h2RequestDirect)(session, input.toString(), init);
94
+ const h2Domain = this.sandbox.h2Domain;
95
+ if (h2Domain) {
96
+ return (0, h2fetch_js_1.h2RequestDirectFromPool)(h2pool_js_1.h2Pool, h2Domain, input.toString(), init);
93
97
  }
94
98
  return globalThis.fetch(input, init);
95
99
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CodeInterpreter = void 0;
4
4
  const h2fetch_js_1 = require("../common/h2fetch.js");
5
+ const h2pool_js_1 = require("../common/h2pool.js");
5
6
  const logger_js_1 = require("../common/logger.js");
6
7
  const settings_js_1 = require("../common/settings.js");
7
8
  const sandbox_js_1 = require("./sandbox.js");
@@ -28,6 +29,7 @@ class CodeInterpreter extends sandbox_js_1.SandboxInstance {
28
29
  status: base.status,
29
30
  events: base.events,
30
31
  h2Session: base.h2Session,
32
+ h2Domain: base.h2Domain,
31
33
  };
32
34
  return new CodeInterpreter(config);
33
35
  }
@@ -72,6 +74,7 @@ class CodeInterpreter extends sandbox_js_1.SandboxInstance {
72
74
  status: baseInstance.status,
73
75
  events: baseInstance.events,
74
76
  h2Session: baseInstance.h2Session,
77
+ h2Domain: baseInstance.h2Domain,
75
78
  };
76
79
  // Preserve forceUrl, headers, and params from input if provided
77
80
  if (sandbox && typeof sandbox === "object" && !Array.isArray(sandbox)) {
@@ -94,9 +97,9 @@ class CodeInterpreter extends sandbox_js_1.SandboxInstance {
94
97
  return this.process.url;
95
98
  }
96
99
  _fetch(input, init) {
97
- const session = this._sandboxConfig.h2Session;
98
- if (session && !session.closed && !session.destroyed) {
99
- return (0, h2fetch_js_1.h2RequestDirect)(session, input.toString(), init);
100
+ const h2Domain = this._sandboxConfig.h2Domain;
101
+ if (h2Domain) {
102
+ return (0, h2fetch_js_1.h2RequestDirectFromPool)(h2pool_js_1.h2Pool, h2Domain, input.toString(), init);
100
103
  }
101
104
  return globalThis.fetch(input, init);
102
105
  }
@@ -57,7 +57,6 @@ class SandboxInstance {
57
57
  codegen;
58
58
  system;
59
59
  drives;
60
- /* eslint-disable @typescript-eslint/no-explicit-any */
61
60
  h2Session;
62
61
  constructor(sandbox) {
63
62
  this.sandbox = sandbox;
@@ -86,27 +85,35 @@ class SandboxInstance {
86
85
  get lastUsedAt() {
87
86
  return this.sandbox.lastUsedAt;
88
87
  }
88
+ get h2Domain() {
89
+ return this.sandbox.h2Domain ?? null;
90
+ }
89
91
  /**
90
92
  * Warm and attach an H2 session based on the sandbox's region.
91
93
  * Shared by create(), get(), list(), and update helpers.
92
94
  */
93
95
  static async attachH2Session(instance) {
94
- const region = instance.spec?.region;
95
- if (!region)
96
+ const edgeDomain = SandboxInstance.edgeDomainForRegion(instance.spec?.region);
97
+ if (!edgeDomain || settings_js_1.settings.disableH2)
96
98
  return instance;
97
- const edgeSuffix = settings_js_1.settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
98
- const edgeDomain = `any.${region}.${edgeSuffix}`;
99
99
  try {
100
100
  const { h2Pool } = await Promise.resolve().then(() => __importStar(require("../common/h2pool.js")));
101
101
  const h2Session = await h2Pool.get(edgeDomain);
102
102
  instance.h2Session = h2Session;
103
103
  instance.sandbox.h2Session = h2Session;
104
+ instance.sandbox.h2Domain = edgeDomain;
104
105
  }
105
106
  catch {
106
107
  // H2 warming is best-effort; fall back to regular fetch
107
108
  }
108
109
  return instance;
109
110
  }
111
+ static edgeDomainForRegion(region) {
112
+ if (!region)
113
+ return null;
114
+ const edgeSuffix = settings_js_1.settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
115
+ return `any.${region}.${edgeSuffix}`;
116
+ }
110
117
  get expiresIn() {
111
118
  return this.sandbox.expiresIn;
112
119
  }
@@ -201,10 +208,9 @@ class SandboxInstance {
201
208
  }
202
209
  sandbox.spec.runtime.image = sandbox.spec.runtime.image || defaultImage;
203
210
  sandbox.spec.runtime.memory = sandbox.spec.runtime.memory || defaultMemory;
204
- const edgeSuffix = settings_js_1.settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
205
- const edgeDomain = sandbox.spec?.region ? `any.${sandbox.spec.region}.${edgeSuffix}` : null;
211
+ const edgeDomain = SandboxInstance.edgeDomainForRegion(sandbox.spec?.region);
206
212
  // Kick off warming so h2Pool.get() can join it during the API call
207
- if (edgeDomain) {
213
+ if (edgeDomain && !settings_js_1.settings.disableH2) {
208
214
  Promise.resolve().then(() => __importStar(require("../common/h2pool.js"))).then(({ h2Pool }) => h2Pool.warm(edgeDomain)).catch(() => { });
209
215
  }
210
216
  const [{ data }, h2Session] = await Promise.all([
@@ -212,10 +218,10 @@ class SandboxInstance {
212
218
  body: sandbox,
213
219
  throwOnError: true,
214
220
  }),
215
- edgeDomain ? Promise.resolve().then(() => __importStar(require("../common/h2pool.js"))).then(({ h2Pool }) => h2Pool.get(edgeDomain)).catch(() => null) : Promise.resolve(null),
221
+ edgeDomain && !settings_js_1.settings.disableH2 ? Promise.resolve().then(() => __importStar(require("../common/h2pool.js"))).then(({ h2Pool }) => h2Pool.get(edgeDomain)).catch(() => null) : Promise.resolve(null),
216
222
  ]);
217
223
  // Inject the H2 session into the config so subsystems can use it
218
- const config = { ...data, h2Session };
224
+ const config = { ...data, h2Session, h2Domain: settings_js_1.settings.disableH2 ? null : edgeDomain };
219
225
  const instance = new SandboxInstance(config);
220
226
  instance.h2Session = h2Session;
221
227
  // Note: H2 session already attached via Promise.all above, no need for attachH2Session()
@@ -224,7 +230,10 @@ class SandboxInstance {
224
230
  try {
225
231
  await instance.fs.ls('/');
226
232
  }
227
- catch { }
233
+ catch (err) {
234
+ await SandboxInstance.delete(instance.metadata.name).catch(() => { });
235
+ throw err;
236
+ }
228
237
  }
229
238
  return instance;
230
239
  }
@@ -255,6 +264,8 @@ class SandboxInstance {
255
264
  async delete() {
256
265
  // Don't close the H2 session — it's shared via h2Pool
257
266
  this.h2Session = null;
267
+ this.sandbox.h2Session = null;
268
+ this.sandbox.h2Domain = null;
258
269
  return await SandboxInstance.delete(this.metadata.name);
259
270
  }
260
271
  static async updateMetadata(sandboxName, metadata) {
@@ -1,5 +1,5 @@
1
1
  import http2 from "http2";
2
- import type { h2Pool as H2PoolType } from "./h2pool.js";
2
+ import type { H2Pool } from "./h2pool.js";
3
3
  /**
4
4
  * Creates a fetch()-compatible function that sends requests over an existing
5
5
  * HTTP/2 session. Falls back to globalThis.fetch() only when the session is
@@ -12,12 +12,12 @@ export declare function createH2Fetch(session: http2.ClientHttp2Session): (input
12
12
  /**
13
13
  * Creates a fetch()-compatible function backed by the H2 session pool.
14
14
  *
15
- * Non-blocking: checks the pool cache synchronously. If a warm session is
16
- * available it's used immediately; otherwise the request goes through
17
- * regular fetch with zero delay (the pool keeps warming in the background
18
- * so subsequent calls get H2).
15
+ * The pool validates idle sessions before reuse. If no usable H2 session is
16
+ * available, the request falls back to regular fetch before any H2 frames
17
+ * are sent.
19
18
  */
20
- export declare function createPoolBackedH2Fetch(pool: typeof H2PoolType, domain: string): (input: Request) => Promise<Response>;
19
+ export declare function createPoolBackedH2Fetch(pool: H2Pool, domain: string): (input: Request) => Promise<Response>;
20
+ export declare function h2RequestDirectFromPool(pool: H2Pool, domain: string, url: string, init?: RequestInit): Promise<Response>;
21
21
  /**
22
22
  * Low-level H2 request that takes raw URL + init, skipping Request construction.
23
23
  * Used by SandboxAction.h2Fetch() for direct calls from subsystems.
@@ -1,4 +1,10 @@
1
1
  import type http2 from "http2";
2
+ type NowFn = () => number;
3
+ export type H2PoolOptions = {
4
+ maxIdleMs?: number;
5
+ pingTimeoutMs?: number;
6
+ now?: NowFn;
7
+ };
2
8
  /**
3
9
  * Singleton H2 session pool keyed by edge domain.
4
10
  *
@@ -11,6 +17,10 @@ export declare class H2Pool {
11
17
  private sessions;
12
18
  private inflight;
13
19
  private _establish;
20
+ private readonly maxIdleMs;
21
+ private readonly pingTimeoutMs;
22
+ private readonly now;
23
+ constructor(options?: H2PoolOptions);
14
24
  /**
15
25
  * Lazily resolve the establish function so the http2 / tls / dns modules
16
26
  * are only imported in Node.js environments.
@@ -22,6 +32,13 @@ export declare class H2Pool {
22
32
  */
23
33
  private establish;
24
34
  private attachEvictionListeners;
35
+ private isClosed;
36
+ private isIdle;
37
+ private cache;
38
+ private markUsed;
39
+ private evict;
40
+ private ping;
41
+ private validateEntry;
25
42
  /**
26
43
  * Fire-and-forget background warming. Safe to call multiple times for
27
44
  * the same domain — only one connection attempt per domain at a time.
@@ -32,6 +49,8 @@ export declare class H2Pool {
32
49
  * Never blocks, never establishes — use for non-blocking fast paths.
33
50
  */
34
51
  tryGet(domain: string): http2.ClientHttp2Session | null;
52
+ isUsable(session: http2.ClientHttp2Session): boolean;
53
+ evictSession(domain: string, session: http2.ClientHttp2Session): void;
35
54
  /**
36
55
  * Get a live H2 session for `domain`. Returns immediately from cache,
37
56
  * joins an in-flight warming, or starts a new one.
@@ -41,3 +60,4 @@ export declare class H2Pool {
41
60
  closeAll(): void;
42
61
  }
43
62
  export declare const h2Pool: H2Pool;
63
+ export {};
@@ -11,6 +11,7 @@ export type Config = {
11
11
  proxy?: string;
12
12
  apikey?: string;
13
13
  workspace?: string;
14
+ disableH2?: boolean;
14
15
  /**
15
16
  * Client credentials for OAuth2 client_credentials flow.
16
17
  *
@@ -49,6 +50,7 @@ declare class Settings {
49
50
  get loggerType(): string;
50
51
  get tracking(): boolean;
51
52
  get region(): string | undefined;
53
+ get disableH2(): boolean;
52
54
  authenticate(): Promise<void>;
53
55
  }
54
56
  export declare const settings: Settings;
@@ -9,6 +9,7 @@ export declare class ResponseError extends Error {
9
9
  export declare class SandboxAction {
10
10
  protected sandbox: SandboxConfiguration;
11
11
  private _h2Client;
12
+ private _h2ClientDomain;
12
13
  constructor(sandbox: SandboxConfiguration);
13
14
  get name(): string;
14
15
  get fallbackUrl(): string | null;
@@ -1,3 +1,4 @@
1
+ import type http2 from "http2";
1
2
  import { SandboxLifecycle, Sandbox as SandboxModel } from "../client/index.js";
2
3
  import { SandboxCodegen } from "./codegen/index.js";
3
4
  import { SandboxDrive } from "./drive/index.js";
@@ -18,18 +19,20 @@ export declare class SandboxInstance {
18
19
  codegen: SandboxCodegen;
19
20
  system: SandboxSystem;
20
21
  drives: SandboxDrive;
21
- h2Session: any;
22
+ h2Session: http2.ClientHttp2Session | null;
22
23
  constructor(sandbox: SandboxConfiguration);
23
24
  get metadata(): import("../client/types.gen.js").Metadata;
24
25
  get status(): import("../client/types.gen.js").Status | undefined;
25
26
  get events(): import("../client/types.gen.js").CoreEvents | undefined;
26
27
  get spec(): import("../client/types.gen.js").SandboxSpec;
27
28
  get lastUsedAt(): string | undefined;
29
+ get h2Domain(): string | null;
28
30
  /**
29
31
  * Warm and attach an H2 session based on the sandbox's region.
30
32
  * Shared by create(), get(), list(), and update helpers.
31
33
  */
32
34
  private static attachH2Session;
35
+ private static edgeDomainForRegion;
33
36
  get expiresIn(): number | undefined;
34
37
  /**
35
38
  * Fetch a resource served on a sandbox port.
@@ -26,6 +26,7 @@ export type SandboxConfiguration = {
26
26
  headers?: Record<string, string>;
27
27
  params?: Record<string, string>;
28
28
  h2Session?: http2.ClientHttp2Session | null;
29
+ h2Domain?: string | null;
29
30
  } & Sandbox;
30
31
  export type SandboxUpdateMetadata = {
31
32
  labels?: Record<string, string>;