@blaxel/core 0.2.89 → 0.2.90-preview.182

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.
@@ -41,11 +41,13 @@ const client_gen_js_1 = require("../client/client.gen.js");
41
41
  const interceptors_js_1 = require("../client/interceptors.js");
42
42
  const responseInterceptor_js_1 = require("../client/responseInterceptor.js");
43
43
  const client_gen_js_2 = require("../sandbox/client/client.gen.js");
44
+ const controlPlaneFetch_js_1 = require("./controlPlaneFetch.js");
44
45
  const settings_js_1 = require("./settings.js");
45
46
  var lazyInit_js_1 = require("./lazyInit.js");
46
47
  Object.defineProperty(exports, "ensureAutoloaded", { enumerable: true, get: function () { return lazyInit_js_1.ensureAutoloaded; } });
47
48
  client_gen_js_1.client.setConfig({
48
49
  baseUrl: settings_js_1.settings.baseUrl,
50
+ fetch: controlPlaneFetch_js_1.controlPlaneFetch,
49
51
  });
50
52
  // Register request interceptors
51
53
  for (const interceptor of interceptors_js_1.interceptors) {
@@ -90,6 +92,7 @@ function initialize(config) {
90
92
  settings_js_1.settings.setConfig(config);
91
93
  client_gen_js_1.client.setConfig({
92
94
  baseUrl: settings_js_1.settings.baseUrl,
95
+ fetch: controlPlaneFetch_js_1.controlPlaneFetch,
93
96
  });
94
97
  client_gen_js_2.client.setConfig({
95
98
  baseUrl: settings_js_1.settings.baseUrl,
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nativeFetchSupportsH2 = void 0;
4
+ exports.undiciSupportsNativeH2 = undiciSupportsNativeH2;
5
+ exports.shouldUseControlPlaneH2 = shouldUseControlPlaneH2;
6
+ exports.controlPlaneFetch = controlPlaneFetch;
7
+ const h2fetch_js_1 = require("./h2fetch.js");
8
+ const h2pool_js_1 = require("./h2pool.js");
9
+ const settings_js_1 = require("./settings.js");
10
+ const h2FetchByHost = new Map();
11
+ // Node's global fetch dispatcher only negotiates HTTP/2 by default starting
12
+ // with undici 8 (Node 26+); undici 7 (Node 24) and undici 6 (Node 22) still
13
+ // ALPN to HTTP/1.1 for fetch, verified empirically against api.blaxel.ai. On
14
+ // undici >= 8 the pooled wrapper is redundant, so we prefer the native path.
15
+ function undiciSupportsNativeH2(undiciVersion) {
16
+ const major = Number(undiciVersion?.split(".")[0] ?? 0);
17
+ return major >= 8;
18
+ }
19
+ // `process`/`process.versions` is absent on Cloudflare Workers and other
20
+ // non-Node runtimes, and `process.versions.undici` is undefined on Bun/Deno;
21
+ // all of those resolve to `false` and keep the wrapper as the fallback.
22
+ exports.nativeFetchSupportsH2 = typeof process !== "undefined" && undiciSupportsNativeH2(process.versions?.undici);
23
+ function shouldUseControlPlaneH2(url, h2Disabled, proxyConfigured = false, nativeH2 = false, forceWrapper = false) {
24
+ if (h2Disabled || proxyConfigured)
25
+ return false;
26
+ if (url.protocol !== "https:")
27
+ return false;
28
+ // Token refresh is sequential and unauthenticated; it cannot contribute to
29
+ // the create burst TLS storm, and device-mode refresh currently relies on the
30
+ // native fetch path.
31
+ if (url.pathname.endsWith("/oauth/token"))
32
+ return false;
33
+ if (!(url.hostname.endsWith("blaxel.ai") || url.hostname.endsWith("blaxel.dev"))) {
34
+ return false;
35
+ }
36
+ // Native fetch already negotiates HTTP/2: skip the redundant wrapper unless
37
+ // explicitly forced (e.g. to exercise the pooled path on a modern runtime).
38
+ if (nativeH2 && !forceWrapper)
39
+ return false;
40
+ return true;
41
+ }
42
+ function controlPlaneFetch(input) {
43
+ const url = new URL(input.url);
44
+ const proxyConfigured = Boolean(settings_js_1.settings.config.proxy);
45
+ // Global disableH2 still wins; disableControlPlaneH2 opts out of just the
46
+ // control-plane wrapper while leaving data-plane H2 in place.
47
+ const h2Disabled = settings_js_1.settings.disableH2 || settings_js_1.settings.disableControlPlaneH2;
48
+ if (!shouldUseControlPlaneH2(url, h2Disabled, proxyConfigured, exports.nativeFetchSupportsH2, settings_js_1.settings.forceControlPlaneH2)) {
49
+ return globalThis.fetch(input);
50
+ }
51
+ let h2Fetch = h2FetchByHost.get(url.hostname);
52
+ if (!h2Fetch) {
53
+ h2Fetch = (0, h2fetch_js_1.createPoolBackedH2Fetch)(h2pool_js_1.h2Pool, url.hostname);
54
+ h2FetchByHost.set(url.hostname, h2Fetch);
55
+ }
56
+ return h2Fetch(input);
57
+ }
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ensureAutoloaded = ensureAutoloaded;
37
37
  const client_gen_js_1 = require("../client/client.gen.js");
38
38
  const client_gen_js_2 = require("../sandbox/client/client.gen.js");
39
+ const controlPlaneFetch_js_1 = require("./controlPlaneFetch.js");
39
40
  const sentry_js_1 = require("./sentry.js");
40
41
  const settings_js_1 = require("./settings.js");
41
42
  let autoloaded = false;
@@ -69,7 +70,7 @@ function ensureAutoloaded() {
69
70
  // Keep the clients' baseUrl in sync with the now-resolved env. Without
70
71
  // this, the module-load `client.setConfig({ baseUrl })` would be stuck on
71
72
  // the prod default for users who rely on `config.yaml` (no env vars).
72
- client_gen_js_1.client.setConfig({ baseUrl: settings_js_1.settings.baseUrl });
73
+ client_gen_js_1.client.setConfig({ baseUrl: settings_js_1.settings.baseUrl, fetch: controlPlaneFetch_js_1.controlPlaneFetch });
73
74
  client_gen_js_2.client.setConfig({ baseUrl: settings_js_1.settings.baseUrl });
74
75
  // Initialize Sentry for SDK error tracking.
75
76
  (0, sentry_js_1.initSentry)();
@@ -80,9 +81,9 @@ function ensureAutoloaded() {
80
81
  if (isNode && !isBrowser && !settings_js_1.settings.disableH2) {
81
82
  try {
82
83
  // Pre-warm edge H2 for the configured region so the first
83
- // SandboxInstance.create() gets an instant session via the pool.
84
- // The control-plane client (api.blaxel.ai) stays on regular fetch
85
- // which already benefits from undici's built-in connection pooling.
84
+ // SandboxInstance.create() gets an instant data-plane session via the
85
+ // pool. Control-plane H2 is intentionally not warmed; its cold burst
86
+ // relies on pool deduplication instead.
86
87
  const region = settings_js_1.settings.region;
87
88
  if (region) {
88
89
  Promise.resolve().then(() => __importStar(require("./h2pool.js"))).then(({ h2Pool }) => {
@@ -28,8 +28,8 @@ function missingCredentialsMessage() {
28
28
  return "No Blaxel credentials found. Set the BL_API_KEY and BL_WORKSPACE environment variables, or run `bl login`.";
29
29
  }
30
30
  // Build info - these placeholders are replaced at build time by build:replace-imports
31
- const BUILD_VERSION = "0.2.89";
32
- const BUILD_COMMIT = "c481e2f6670b3cef6832875dbc9f2bc6b0b198f4";
31
+ const BUILD_VERSION = "0.2.90-preview.182";
32
+ const BUILD_COMMIT = "78dad6b3e2d47dcf5d8464b9688b0829ddc3369c";
33
33
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
34
34
  const BLAXEL_API_VERSION = "2026-04-16";
35
35
  // Cache for config.yaml tracking value
@@ -250,6 +250,31 @@ class Settings {
250
250
  }
251
251
  return isDenoRuntime();
252
252
  }
253
+ // Control-plane-only escape hatch: disables the control-plane H2 wrapper
254
+ // without affecting data-plane (edge) H2. `disableH2` is the global override
255
+ // and is checked separately by callers, so it always wins.
256
+ get disableControlPlaneH2() {
257
+ if (typeof this.config.disableControlPlaneH2 === "boolean") {
258
+ return this.config.disableControlPlaneH2;
259
+ }
260
+ const value = env_js_1.env.BL_DISABLE_CONTROL_PLANE_H2;
261
+ if (value) {
262
+ return ["1", "true", "yes", "on"].includes(value.toLowerCase());
263
+ }
264
+ return false;
265
+ }
266
+ // Forces the control-plane H2 wrapper on even when native fetch already
267
+ // supports H2 (undici >= 7). `disableH2`/`disableControlPlaneH2` still win.
268
+ get forceControlPlaneH2() {
269
+ if (typeof this.config.forceControlPlaneH2 === "boolean") {
270
+ return this.config.forceControlPlaneH2;
271
+ }
272
+ const value = env_js_1.env.BL_FORCE_CONTROL_PLANE_H2;
273
+ if (value) {
274
+ return ["1", "true", "yes", "on"].includes(value.toLowerCase());
275
+ }
276
+ return false;
277
+ }
253
278
  get maxConcurrentH2Requests() {
254
279
  if (typeof this.config.maxConcurrentH2Requests === "number") {
255
280
  return this.config.maxConcurrentH2Requests;
@@ -0,0 +1,4 @@
1
+ export declare function undiciSupportsNativeH2(undiciVersion: string | undefined): boolean;
2
+ export declare const nativeFetchSupportsH2: boolean;
3
+ export declare function shouldUseControlPlaneH2(url: URL, h2Disabled: boolean, proxyConfigured?: boolean, nativeH2?: boolean, forceWrapper?: boolean): boolean;
4
+ export declare function controlPlaneFetch(input: Request): Promise<Response>;
@@ -12,6 +12,22 @@ export type Config = {
12
12
  apikey?: string;
13
13
  workspace?: string;
14
14
  disableH2?: boolean;
15
+ /**
16
+ * Disables only the control-plane HTTP/2 wrapper, leaving data-plane (edge)
17
+ * H2 untouched. Use this to route control-plane calls (api.blaxel.{ai,dev})
18
+ * over native fetch while keeping sandbox/data-plane traffic on the H2 pool.
19
+ * The global `disableH2` flag still wins: when it is true, both planes use
20
+ * native fetch regardless of this value. Defaults to `false` (wrapper on).
21
+ */
22
+ disableControlPlaneH2?: boolean;
23
+ /**
24
+ * Forces the control-plane HTTP/2 wrapper on even when the runtime's native
25
+ * fetch already negotiates HTTP/2 (undici >= 8 / Node 26+), where it is
26
+ * otherwise skipped as redundant. Mainly for exercising the pooled path on a
27
+ * modern runtime. `disableH2` and `disableControlPlaneH2` still win.
28
+ * Defaults to `false`.
29
+ */
30
+ forceControlPlaneH2?: boolean;
15
31
  /**
16
32
  * Maximum number of concurrent in-flight HTTP/2 requests across the shared
17
33
  * H2 session pool. `0` or `undefined` means unlimited (current behavior).
@@ -93,6 +109,8 @@ declare class Settings {
93
109
  get tracking(): boolean;
94
110
  get region(): string | undefined;
95
111
  get disableH2(): boolean;
112
+ get disableControlPlaneH2(): boolean;
113
+ get forceControlPlaneH2(): boolean;
96
114
  get maxConcurrentH2Requests(): number;
97
115
  get maxConcurrentUploadH2Requests(): number;
98
116
  get h2StreamWindowSize(): number;