@blaxel/core 0.2.80-preview.138 → 0.2.80-preview.140

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 (35) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/client/interceptors.js +29 -0
  3. package/dist/cjs/common/autoload.js +8 -27
  4. package/dist/cjs/common/h2fetch.js +35 -33
  5. package/dist/cjs/common/h2pool.js +22 -2
  6. package/dist/cjs/common/lazyInit.js +98 -0
  7. package/dist/cjs/common/settings.js +18 -6
  8. package/dist/cjs/types/common/autoload.d.ts +6 -2
  9. package/dist/cjs/types/common/h2fetch.d.ts +5 -2
  10. package/dist/cjs/types/common/h2pool.d.ts +7 -2
  11. package/dist/cjs/types/common/lazyInit.d.ts +19 -0
  12. package/dist/cjs/types/common/settings.d.ts +3 -1
  13. package/dist/cjs-browser/.tsbuildinfo +1 -1
  14. package/dist/cjs-browser/client/interceptors.js +29 -0
  15. package/dist/cjs-browser/common/autoload.js +8 -27
  16. package/dist/cjs-browser/common/lazyInit.js +98 -0
  17. package/dist/cjs-browser/common/settings.js +18 -6
  18. package/dist/cjs-browser/types/common/autoload.d.ts +6 -2
  19. package/dist/cjs-browser/types/common/h2fetch.d.ts +5 -2
  20. package/dist/cjs-browser/types/common/h2pool.d.ts +7 -2
  21. package/dist/cjs-browser/types/common/lazyInit.d.ts +19 -0
  22. package/dist/cjs-browser/types/common/settings.d.ts +3 -1
  23. package/dist/esm/.tsbuildinfo +1 -1
  24. package/dist/esm/client/interceptors.js +29 -0
  25. package/dist/esm/common/autoload.js +6 -27
  26. package/dist/esm/common/h2fetch.js +35 -33
  27. package/dist/esm/common/h2pool.js +21 -2
  28. package/dist/esm/common/lazyInit.js +62 -0
  29. package/dist/esm/common/settings.js +18 -6
  30. package/dist/esm-browser/.tsbuildinfo +1 -1
  31. package/dist/esm-browser/client/interceptors.js +29 -0
  32. package/dist/esm-browser/common/autoload.js +6 -27
  33. package/dist/esm-browser/common/lazyInit.js +62 -0
  34. package/dist/esm-browser/common/settings.js +18 -6
  35. package/package.json +1 -1
@@ -1,10 +1,39 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.interceptors = void 0;
4
+ const lazyInit_js_1 = require("../common/lazyInit.js");
4
5
  const settings_js_1 = require("../common/settings.js");
6
+ // Default baseUrl baked into the generated control-plane client. Requests
7
+ // carrying this prefix came from the module-load client config, before
8
+ // `ensureAutoloaded()` had a chance to resolve the real env from
9
+ // `~/.blaxel/config.yaml`.
10
+ const DEFAULT_CONTROLPLANE_BASE_URL = "https://api.blaxel.ai/v0";
5
11
  exports.interceptors = [
6
12
  // Authentication interceptor
7
13
  async (request, options) => {
14
+ // Trigger deferred autoload side-effects (lazy credential resolution,
15
+ // client baseUrl sync, Sentry init, H2 warming) on the first actual SDK
16
+ // use, rather than at module-import time.
17
+ (0, lazyInit_js_1.ensureAutoloaded)();
18
+ // If lazy env resolution just moved the effective baseUrl off the
19
+ // module-load default (e.g. a user with `env: dev` in config.yaml but
20
+ // no BL_ENV env var), the very first request was built against the
21
+ // stale prod URL. Rebase it to the correct environment. Subsequent
22
+ // requests use the updated `client.setConfig()` applied in
23
+ // `ensureAutoloaded()`, so this branch only fires once.
24
+ //
25
+ // This must happen before the `authenticated === false` early return:
26
+ // the OAuth token request issued by `ClientCredentials.authenticate()`
27
+ // itself is unauthenticated, and if the user calls `authenticate()`
28
+ // before any other SDK call it is the very first request and also
29
+ // needs to be rebased to the correct environment.
30
+ const correctBase = settings_js_1.settings.baseUrl;
31
+ if (correctBase !== DEFAULT_CONTROLPLANE_BASE_URL &&
32
+ request.url.startsWith(DEFAULT_CONTROLPLANE_BASE_URL)) {
33
+ const newUrl = correctBase.replace(/\/$/, "") +
34
+ request.url.slice(DEFAULT_CONTROLPLANE_BASE_URL.length);
35
+ request = new Request(newUrl, request);
36
+ }
8
37
  if (options.authenticated === false) {
9
38
  return request;
10
39
  }
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ensureAutoloaded = void 0;
36
37
  exports.initialize = initialize;
37
38
  exports.authenticate = authenticate;
38
39
  exports.closeConnections = closeConnections;
@@ -40,8 +41,9 @@ const client_gen_js_1 = require("../client/client.gen.js");
40
41
  const interceptors_js_1 = require("../client/interceptors.js");
41
42
  const responseInterceptor_js_1 = require("../client/responseInterceptor.js");
42
43
  const client_gen_js_2 = require("../sandbox/client/client.gen.js");
43
- const sentry_js_1 = require("./sentry.js");
44
44
  const settings_js_1 = require("./settings.js");
45
+ var lazyInit_js_1 = require("./lazyInit.js");
46
+ Object.defineProperty(exports, "ensureAutoloaded", { enumerable: true, get: function () { return lazyInit_js_1.ensureAutoloaded; } });
45
47
  client_gen_js_1.client.setConfig({
46
48
  baseUrl: settings_js_1.settings.baseUrl,
47
49
  });
@@ -57,34 +59,15 @@ for (const interceptor of responseInterceptor_js_1.responseInterceptors) {
57
59
  client_gen_js_1.client.interceptors.response.use(interceptor);
58
60
  client_gen_js_2.client.interceptors.response.use(interceptor);
59
61
  }
60
- // Initialize Sentry for SDK error tracking immediately when module loads
61
- (0, sentry_js_1.initSentry)();
62
- // Background H2 connection warming (Node.js only)
63
- const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
64
- /* eslint-disable */
65
- const isBrowser = typeof globalThis !== "undefined" && globalThis?.window !== undefined;
66
- if (isNode && !isBrowser) {
67
- try {
68
- // Pre-warm edge H2 for the configured region so the first
69
- // SandboxInstance.create() gets an instant session via the pool.
70
- // The control-plane client (api.blaxel.ai) stays on regular fetch
71
- // which already benefits from undici's built-in connection pooling.
72
- const region = settings_js_1.settings.region;
73
- if (region) {
74
- Promise.resolve().then(() => __importStar(require("./h2pool.js"))).then(({ h2Pool }) => {
75
- const edgeSuffix = settings_js_1.settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
76
- h2Pool.warm(`any.${region}.${edgeSuffix}`);
77
- }).catch(() => { });
78
- }
79
- }
80
- catch {
81
- // Silently ignore warming failures
82
- }
83
- }
84
62
  /**
85
63
  * Configure the SDK programmatically at runtime, instead of relying on
86
64
  * environment variables or config files.
87
65
  *
66
+ * You do not need to call {@link authenticate} yourself: the SDK
67
+ * transparently authenticates (and refreshes tokens when needed) on every
68
+ * request. Only call `authenticate()` directly if you want to fail fast on
69
+ * invalid credentials before making any API call.
70
+ *
88
71
  * @example
89
72
  * // With an API key
90
73
  * initialize({ workspace: 'my-workspace', apiKey: 'bl_...' });
@@ -95,7 +78,6 @@ if (isNode && !isBrowser) {
95
78
  * workspace: 'my-workspace',
96
79
  * clientCredentials: { clientId: '...', clientSecret: '...' },
97
80
  * });
98
- * await authenticate();
99
81
  *
100
82
  * @example
101
83
  * // With client credentials (pre-encoded Base64 string)
@@ -103,7 +85,6 @@ if (isNode && !isBrowser) {
103
85
  * workspace: 'my-workspace',
104
86
  * clientCredentials: 'base64-encoded-string',
105
87
  * });
106
- * await authenticate();
107
88
  */
108
89
  function initialize(config) {
109
90
  settings_js_1.settings.setConfig(config);
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createH2Fetch = createH2Fetch;
4
4
  exports.createPoolBackedH2Fetch = createPoolBackedH2Fetch;
5
5
  exports.h2RequestDirect = h2RequestDirect;
6
- const H2_REQUEST_TIMEOUT_MS = 10_000;
7
6
  /**
8
7
  * Creates a fetch()-compatible function that sends requests over an existing
9
- * HTTP/2 session. Falls back to global fetch() if the session is closed,
10
- * destroyed, or if the H2 request times out.
8
+ * HTTP/2 session. Falls back to globalThis.fetch() only when the session is
9
+ * closed/destroyed at call time (pre-flight, nothing sent on the wire).
10
+ *
11
+ * Any failure after session.request() succeeds propagates to the caller:
12
+ * this transport never retries. Retry and timeout policy are caller concerns.
11
13
  */
12
14
  function createH2Fetch(session) {
13
15
  return (input) => {
@@ -78,7 +80,8 @@ function h2RequestDirect(session, url, init) {
78
80
  }
79
81
  else {
80
82
  // FormData, ReadableStream, Blob, etc. can't be serialized to Buffer
81
- // for manual H2 framing — fall back to regular fetch.
83
+ // for manual H2 framing — fall back to regular fetch (pre-flight,
84
+ // nothing has been sent on the wire yet).
82
85
  return globalThis.fetch(url, init);
83
86
  }
84
87
  if (!h2Headers["content-length"]) {
@@ -116,42 +119,49 @@ async function _h2Request(session, input) {
116
119
  }
117
120
  function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit) {
118
121
  return new Promise((resolve, reject) => {
122
+ let settled = false;
123
+ let responded = false;
124
+ let streamController = null;
125
+ let streamClosed = false;
119
126
  let req;
120
127
  try {
121
128
  req = session.request(h2Headers);
122
129
  }
123
130
  catch {
124
- return globalThis.fetch(fallbackUrl, fallbackInit).then(resolve, reject);
131
+ // Pre-flight fallback: session.request() threw synchronously, so no
132
+ // H2 frames were sent. Safe to retry over globalThis.fetch.
133
+ globalThis.fetch(fallbackUrl, fallbackInit).then(resolve, reject);
134
+ return;
125
135
  }
126
- const timer = setTimeout(() => {
127
- if (settled)
128
- return;
129
- settled = true;
136
+ const abort = () => {
130
137
  req.close();
131
- globalThis.fetch(fallbackUrl, fallbackInit).then(resolve, reject);
132
- }, H2_REQUEST_TIMEOUT_MS);
138
+ const abortError = new DOMException("The operation was aborted.", "AbortError");
139
+ if (!responded) {
140
+ if (!settled) {
141
+ settled = true;
142
+ reject(abortError);
143
+ }
144
+ return;
145
+ }
146
+ if (!streamClosed) {
147
+ streamClosed = true;
148
+ streamController?.error(abortError);
149
+ }
150
+ };
133
151
  if (signal) {
134
152
  if (signal.aborted) {
135
- clearTimeout(timer);
136
153
  req.close();
154
+ settled = true;
137
155
  reject(new DOMException("The operation was aborted.", "AbortError"));
138
156
  return;
139
157
  }
140
- signal.addEventListener("abort", () => {
141
- clearTimeout(timer);
142
- req.close();
143
- if (!settled) {
144
- settled = true;
145
- reject(new DOMException("The operation was aborted.", "AbortError"));
146
- }
147
- }, { once: true });
158
+ signal.addEventListener("abort", abort, { once: true });
148
159
  }
149
- let settled = false;
150
160
  req.on("response", (headers) => {
151
- clearTimeout(timer);
152
161
  if (settled)
153
162
  return;
154
163
  settled = true;
164
+ responded = true;
155
165
  const status = headers[":status"] ?? 200;
156
166
  const resHeaders = new Headers();
157
167
  for (const [k, v] of Object.entries(headers)) {
@@ -161,9 +171,9 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit) {
161
171
  continue;
162
172
  resHeaders.set(k, Array.isArray(v) ? v.join(", ") : String(v));
163
173
  }
164
- let streamClosed = false;
165
174
  const readable = new ReadableStream({
166
175
  start(controller) {
176
+ streamController = controller;
167
177
  req.on("data", (chunk) => {
168
178
  if (!streamClosed)
169
179
  controller.enqueue(new Uint8Array(chunk));
@@ -180,23 +190,15 @@ function _h2Send(session, h2Headers, body, signal, fallbackUrl, fallbackInit) {
180
190
  controller.error(err);
181
191
  }
182
192
  });
183
- signal?.addEventListener("abort", () => {
184
- req.close();
185
- if (!streamClosed) {
186
- streamClosed = true;
187
- controller.error(new DOMException("The operation was aborted.", "AbortError"));
188
- }
189
- }, { once: true });
190
193
  },
191
194
  });
192
195
  resolve(new Response(readable, { status, headers: resHeaders }));
193
196
  });
194
- req.on("error", () => {
195
- clearTimeout(timer);
197
+ req.on("error", (err) => {
196
198
  if (settled)
197
199
  return;
198
200
  settled = true;
199
- globalThis.fetch(fallbackUrl, fallbackInit).then(resolve, reject);
201
+ reject(err);
200
202
  });
201
203
  if (body) {
202
204
  req.end(body);
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.h2Pool = void 0;
36
+ exports.h2Pool = exports.H2Pool = void 0;
37
37
  /**
38
38
  * Singleton H2 session pool keyed by edge domain.
39
39
  *
@@ -49,13 +49,32 @@ class H2Pool {
49
49
  /**
50
50
  * Lazily resolve the establish function so the http2 / tls / dns modules
51
51
  * are only imported in Node.js environments.
52
+ *
53
+ * Wires up self-healing eviction: the session is removed from the cache
54
+ * as soon as it emits `goaway`, `error`, or `close`, so `tryGet()` never
55
+ * returns a dead session. This replaces the old behavior of papering
56
+ * over session failures at the fetch layer.
52
57
  */
53
58
  async establish(domain) {
54
59
  if (!this._establish) {
55
60
  const { establishH2 } = await Promise.resolve().then(() => __importStar(require("./h2warm.js")));
56
61
  this._establish = establishH2;
57
62
  }
58
- return this._establish(domain);
63
+ const session = await this._establish(domain);
64
+ this.attachEvictionListeners(domain, session);
65
+ return session;
66
+ }
67
+ attachEvictionListeners(domain, session) {
68
+ const evict = () => {
69
+ // Only evict if this specific session is still the cached one.
70
+ // A newer session may have taken its place after reconnect.
71
+ if (this.sessions.get(domain) === session) {
72
+ this.sessions.delete(domain);
73
+ }
74
+ };
75
+ session.on("goaway", evict);
76
+ session.on("error", evict);
77
+ session.on("close", evict);
59
78
  }
60
79
  /**
61
80
  * Fire-and-forget background warming. Safe to call multiple times for
@@ -134,4 +153,5 @@ class H2Pool {
134
153
  this.inflight.clear();
135
154
  }
136
155
  }
156
+ exports.H2Pool = H2Pool;
137
157
  exports.h2Pool = new H2Pool();
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ensureAutoloaded = ensureAutoloaded;
37
+ const client_gen_js_1 = require("../client/client.gen.js");
38
+ const client_gen_js_2 = require("../sandbox/client/client.gen.js");
39
+ const sentry_js_1 = require("./sentry.js");
40
+ const settings_js_1 = require("./settings.js");
41
+ let autoloaded = false;
42
+ /**
43
+ * Perform the observable side-effects that the SDK needs for error
44
+ * reporting, low-latency sandbox sessions, and correct environment
45
+ * routing:
46
+ *
47
+ * - Resolve credentials (which reads `~/.blaxel/config.yaml` once and
48
+ * populates `BL_ENV` if the user has a dev workspace configured).
49
+ * - Re-apply the control-plane and sandbox clients' `baseUrl` so they
50
+ * target the now-env-aware endpoint.
51
+ * - Initialize the lightweight Sentry client (registers
52
+ * `uncaughtExceptionMonitor` and patches `console.error` in Node).
53
+ * - Pre-warm the edge H2 connection pool for `settings.region`.
54
+ *
55
+ * These used to run at module load, but that meant `import "@blaxel/core"`
56
+ * alone had observable side-effects. They are now deferred until the SDK
57
+ * is first actually used — the request interceptor calls this on the
58
+ * first HTTP request.
59
+ */
60
+ function ensureAutoloaded() {
61
+ if (autoloaded)
62
+ return;
63
+ autoloaded = true;
64
+ // Trigger lazy credential resolution. This may read `~/.blaxel/config.yaml`
65
+ // and set `process.env.BL_ENV` if the user has a dev workspace configured,
66
+ // which in turn affects `settings.baseUrl`.
67
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
68
+ settings_js_1.settings.credentials;
69
+ // Keep the clients' baseUrl in sync with the now-resolved env. Without
70
+ // this, the module-load `client.setConfig({ baseUrl })` would be stuck on
71
+ // 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_2.client.setConfig({ baseUrl: settings_js_1.settings.baseUrl });
74
+ // Initialize Sentry for SDK error tracking.
75
+ (0, sentry_js_1.initSentry)();
76
+ // Background H2 connection warming (Node.js only)
77
+ const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
78
+ /* eslint-disable */
79
+ const isBrowser = typeof globalThis !== "undefined" && globalThis?.window !== undefined;
80
+ if (isNode && !isBrowser) {
81
+ try {
82
+ // 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.
86
+ const region = settings_js_1.settings.region;
87
+ if (region) {
88
+ Promise.resolve().then(() => __importStar(require("./h2pool.js"))).then(({ h2Pool }) => {
89
+ const edgeSuffix = settings_js_1.settings.env === "prod" ? "bl.run" : "runv2.blaxel.dev";
90
+ h2Pool.warm(`any.${region}.${edgeSuffix}`);
91
+ }).catch(() => { });
92
+ }
93
+ }
94
+ catch {
95
+ // Silently ignore warming failures
96
+ }
97
+ }
98
+ }
@@ -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.80-preview.138";
15
- const BUILD_COMMIT = "a58f8cc475d6ca3147ed31106d71a68e504c55a0";
14
+ const BUILD_VERSION = "0.2.80-preview.140";
15
+ const BUILD_COMMIT = "800934e57ec03de060b909ccb1f5599343cae9e5";
16
16
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
17
17
  // Cache for config.yaml tracking value
18
18
  let configTrackingValue = null;
@@ -72,20 +72,32 @@ function getOsArch() {
72
72
  return "browser/unknown";
73
73
  }
74
74
  class Settings {
75
- credentials;
75
+ _credentials;
76
76
  config;
77
77
  constructor() {
78
- this.credentials = (0, index_js_1.authentication)();
78
+ // `credentials` are resolved lazily on first access so that simply
79
+ // importing `@blaxel/core` does not read `~/.blaxel/config.yaml`
80
+ // or mutate `process.env.BL_ENV`. See the `credentials` getter.
81
+ this._credentials = null;
79
82
  this.config = {
80
83
  proxy: "",
81
84
  apikey: "",
82
85
  workspace: "",
83
86
  };
84
87
  }
88
+ get credentials() {
89
+ if (this._credentials === null) {
90
+ this._credentials = (0, index_js_1.authentication)();
91
+ }
92
+ return this._credentials;
93
+ }
94
+ set credentials(value) {
95
+ this._credentials = value;
96
+ }
85
97
  setConfig(config) {
86
98
  this.config = config;
87
99
  if (config.apiKey) {
88
- this.credentials = new apikey_js_1.ApiKey({
100
+ this._credentials = new apikey_js_1.ApiKey({
89
101
  apiKey: config.apiKey,
90
102
  workspace: config.workspace,
91
103
  });
@@ -94,7 +106,7 @@ class Settings {
94
106
  const encoded = typeof config.clientCredentials === 'string'
95
107
  ? config.clientCredentials
96
108
  : btoa(`${config.clientCredentials.clientId}:${config.clientCredentials.clientSecret}`);
97
- this.credentials = new clientcredentials_js_1.ClientCredentials({
109
+ this._credentials = new clientcredentials_js_1.ClientCredentials({
98
110
  clientCredentials: encoded,
99
111
  workspace: config.workspace,
100
112
  });
@@ -1,8 +1,14 @@
1
1
  import { Config } from "./settings.js";
2
+ export { ensureAutoloaded } from "./lazyInit.js";
2
3
  /**
3
4
  * Configure the SDK programmatically at runtime, instead of relying on
4
5
  * environment variables or config files.
5
6
  *
7
+ * You do not need to call {@link authenticate} yourself: the SDK
8
+ * transparently authenticates (and refreshes tokens when needed) on every
9
+ * request. Only call `authenticate()` directly if you want to fail fast on
10
+ * invalid credentials before making any API call.
11
+ *
6
12
  * @example
7
13
  * // With an API key
8
14
  * initialize({ workspace: 'my-workspace', apiKey: 'bl_...' });
@@ -13,7 +19,6 @@ import { Config } from "./settings.js";
13
19
  * workspace: 'my-workspace',
14
20
  * clientCredentials: { clientId: '...', clientSecret: '...' },
15
21
  * });
16
- * await authenticate();
17
22
  *
18
23
  * @example
19
24
  * // With client credentials (pre-encoded Base64 string)
@@ -21,7 +26,6 @@ import { Config } from "./settings.js";
21
26
  * workspace: 'my-workspace',
22
27
  * clientCredentials: 'base64-encoded-string',
23
28
  * });
24
- * await authenticate();
25
29
  */
26
30
  export declare function initialize(config: Config): void;
27
31
  export declare function authenticate(): Promise<void>;
@@ -2,8 +2,11 @@ import http2 from "http2";
2
2
  import type { h2Pool as H2PoolType } from "./h2pool.js";
3
3
  /**
4
4
  * Creates a fetch()-compatible function that sends requests over an existing
5
- * HTTP/2 session. Falls back to global fetch() if the session is closed,
6
- * destroyed, or if the H2 request times out.
5
+ * HTTP/2 session. Falls back to globalThis.fetch() only when the session is
6
+ * closed/destroyed at call time (pre-flight, nothing sent on the wire).
7
+ *
8
+ * Any failure after session.request() succeeds propagates to the caller:
9
+ * this transport never retries. Retry and timeout policy are caller concerns.
7
10
  */
8
11
  export declare function createH2Fetch(session: http2.ClientHttp2Session): (input: Request) => Promise<Response>;
9
12
  /**
@@ -7,15 +7,21 @@ import type http2 from "http2";
7
7
  * an in-flight warming, or establishes a fresh one.
8
8
  * - Closed / destroyed sessions are automatically evicted.
9
9
  */
10
- declare class H2Pool {
10
+ export declare class H2Pool {
11
11
  private sessions;
12
12
  private inflight;
13
13
  private _establish;
14
14
  /**
15
15
  * Lazily resolve the establish function so the http2 / tls / dns modules
16
16
  * are only imported in Node.js environments.
17
+ *
18
+ * Wires up self-healing eviction: the session is removed from the cache
19
+ * as soon as it emits `goaway`, `error`, or `close`, so `tryGet()` never
20
+ * returns a dead session. This replaces the old behavior of papering
21
+ * over session failures at the fetch layer.
17
22
  */
18
23
  private establish;
24
+ private attachEvictionListeners;
19
25
  /**
20
26
  * Fire-and-forget background warming. Safe to call multiple times for
21
27
  * the same domain — only one connection attempt per domain at a time.
@@ -35,4 +41,3 @@ declare class H2Pool {
35
41
  closeAll(): void;
36
42
  }
37
43
  export declare const h2Pool: H2Pool;
38
- export {};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Perform the observable side-effects that the SDK needs for error
3
+ * reporting, low-latency sandbox sessions, and correct environment
4
+ * routing:
5
+ *
6
+ * - Resolve credentials (which reads `~/.blaxel/config.yaml` once and
7
+ * populates `BL_ENV` if the user has a dev workspace configured).
8
+ * - Re-apply the control-plane and sandbox clients' `baseUrl` so they
9
+ * target the now-env-aware endpoint.
10
+ * - Initialize the lightweight Sentry client (registers
11
+ * `uncaughtExceptionMonitor` and patches `console.error` in Node).
12
+ * - Pre-warm the edge H2 connection pool for `settings.region`.
13
+ *
14
+ * These used to run at module load, but that meant `import "@blaxel/core"`
15
+ * alone had observable side-effects. They are now deferred until the SDK
16
+ * is first actually used — the request interceptor calls this on the
17
+ * first HTTP request.
18
+ */
19
+ export declare function ensureAutoloaded(): void;
@@ -23,9 +23,11 @@ export type Config = {
23
23
  apiKey?: string;
24
24
  };
25
25
  declare class Settings {
26
- credentials: Credentials;
26
+ private _credentials;
27
27
  config: Config;
28
28
  constructor();
29
+ get credentials(): Credentials;
30
+ set credentials(value: Credentials | null);
29
31
  setConfig(config: Config): void;
30
32
  get env(): string;
31
33
  get baseUrl(): string;