@blaxel/core 0.3.17 → 0.3.18-dev.283

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.
@@ -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.17";
34
- const BUILD_COMMIT = "3e03a965bdb4d5aa9d2c5105cd1f4d8018198df2";
33
+ const BUILD_VERSION = "0.3.18-dev.283";
34
+ const BUILD_COMMIT = "fed607fe45d4a15407e77f7c40f31815d763df5a";
35
35
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
36
36
  const BLAXEL_API_VERSION = "2026-04-28";
37
37
  // Bun < 1.3.11 never sends connection-level WINDOW_UPDATE: the pooled h2
@@ -100,6 +100,11 @@ function getOsArch() {
100
100
  }
101
101
  return "browser/unknown";
102
102
  }
103
+ /**
104
+ * An integration built on this SDK identifies itself with one User-Agent
105
+ * product token: `<name>/<semver>`, lowercase name.
106
+ */
107
+ const INTEGRATION_TOKEN_PATTERN = /^[a-z0-9][a-z0-9._-]*\/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
103
108
  class Settings {
104
109
  _credentials;
105
110
  config;
@@ -196,14 +201,34 @@ class Settings {
196
201
  get apiVersion() {
197
202
  return env_js_1.env.BL_API_VERSION || BLAXEL_API_VERSION;
198
203
  }
204
+ /**
205
+ * Product token identifying the integration built on this SDK, or `""`.
206
+ * Resolved from `config.integration`, then `BL_INTEGRATION`. See `Config.integration`.
207
+ */
208
+ get integration() {
209
+ const value = this.config.integration ?? env_js_1.env.BL_INTEGRATION ?? "";
210
+ if (!value) {
211
+ return "";
212
+ }
213
+ if (!INTEGRATION_TOKEN_PATTERN.test(value)) {
214
+ logger_js_1.logger.warn(`Ignoring invalid Blaxel integration token "${value}": expected <name>/<semver> with a lowercase name`);
215
+ return "";
216
+ }
217
+ return value;
218
+ }
219
+ set integration(value) {
220
+ this.config.integration = value;
221
+ }
199
222
  get headers() {
200
223
  this.assertCredentials();
201
224
  const osArch = getOsArch();
225
+ const sdkUserAgent = `blaxel/sdk/typescript/${this.version} (${osArch}) blaxel/${this.commit}`;
226
+ const integration = this.integration;
202
227
  return {
203
228
  "x-blaxel-authorization": this.authorization,
204
229
  "x-blaxel-workspace": this.workspace || "",
205
230
  "Blaxel-Version": this.apiVersion,
206
- "User-Agent": `blaxel/sdk/typescript/${this.version} (${osArch}) blaxel/${this.commit}`,
231
+ "User-Agent": integration ? `${sdkUserAgent} ${integration}` : sdkUserAgent,
207
232
  };
208
233
  }
209
234
  get name() {
@@ -251,3 +251,53 @@ const h2_runtime_js_1 = require("./h2-runtime.js");
251
251
  });
252
252
  });
253
253
  });
254
+ (0, vitest_1.describe)('Settings.integration', () => {
255
+ const sdkUserAgent = /^blaxel\/sdk\/typescript\/\S+ \([^)]+\) blaxel\/\S+/;
256
+ async function authenticated() {
257
+ const { settings } = await Promise.resolve().then(() => __importStar(require('./settings.js')));
258
+ settings.credentials = new apikey_js_1.ApiKey({ apiKey: 'test-key', workspace: 'test-ws' });
259
+ delete settings.config.integration;
260
+ delete process.env.BL_INTEGRATION;
261
+ return settings;
262
+ }
263
+ (0, vitest_1.afterEach)(async () => {
264
+ const { settings } = await Promise.resolve().then(() => __importStar(require('./settings.js')));
265
+ delete settings.config.integration;
266
+ delete process.env.BL_INTEGRATION;
267
+ });
268
+ (0, vitest_1.it)('sends the plain SDK User-Agent by default', async () => {
269
+ const settings = await authenticated();
270
+ (0, vitest_1.expect)(settings.integration).toBe('');
271
+ (0, vitest_1.expect)(settings.headers['User-Agent']).toMatch(new RegExp(sdkUserAgent.source + '$'));
272
+ });
273
+ (0, vitest_1.it)('appends the token set programmatically, once', async () => {
274
+ const settings = await authenticated();
275
+ settings.integration = 'deepseek-harness-blaxel-sandbox/0.1.2';
276
+ const userAgent = settings.headers['User-Agent'];
277
+ (0, vitest_1.expect)(userAgent).toMatch(sdkUserAgent);
278
+ (0, vitest_1.expect)(userAgent.endsWith(' deepseek-harness-blaxel-sandbox/0.1.2')).toBe(true);
279
+ (0, vitest_1.expect)(userAgent.split('deepseek-harness-blaxel-sandbox').length).toBe(2);
280
+ });
281
+ (0, vitest_1.it)('reads BL_INTEGRATION when nothing is set programmatically, and config wins', async () => {
282
+ const settings = await authenticated();
283
+ process.env.BL_INTEGRATION = 'herdr/1.4.0-rc.1';
284
+ (0, vitest_1.expect)(settings.headers['User-Agent'].endsWith(' herdr/1.4.0-rc.1')).toBe(true);
285
+ settings.setConfig({ ...settings.config, integration: 'deepseek-harness-blaxel-sandbox/0.1.2' });
286
+ (0, vitest_1.expect)(settings.headers['User-Agent'].endsWith(' deepseek-harness-blaxel-sandbox/0.1.2')).toBe(true);
287
+ });
288
+ vitest_1.it.each(['Deepseek/0.1.2', 'deepseek-harness', 'deepseek/0.1', 'a/1.0.0 b/1.0.0', 'deepseek/0.1.2 (extra)', ' x/1.0.0'])('ignores the invalid token %j', async (value) => {
289
+ const settings = await authenticated();
290
+ settings.integration = value;
291
+ (0, vitest_1.expect)(settings.integration).toBe('');
292
+ (0, vitest_1.expect)(settings.headers['User-Agent']).toMatch(new RegExp(sdkUserAgent.source + '$'));
293
+ });
294
+ (0, vitest_1.it)('changes no header other than User-Agent', async () => {
295
+ const settings = await authenticated();
296
+ const plain = { ...settings.headers };
297
+ settings.integration = 'deepseek-harness-blaxel-sandbox/0.1.2';
298
+ const tagged = { ...settings.headers };
299
+ delete plain['User-Agent'];
300
+ delete tagged['User-Agent'];
301
+ (0, vitest_1.expect)(tagged).toEqual(plain);
302
+ });
303
+ });
@@ -11,6 +11,15 @@ export type Config = {
11
11
  proxy?: string;
12
12
  apikey?: string;
13
13
  workspace?: string;
14
+ /**
15
+ * Product token identifying the integration built on this SDK, appended to
16
+ * the `User-Agent` so Blaxel can attribute traffic to it. Format
17
+ * `<name>/<semver>` with a lowercase name, e.g.
18
+ * `"deepseek-harness-blaxel-sandbox/0.1.2"`. Also settable through
19
+ * `BL_INTEGRATION` or `settings.integration`. An invalid value is ignored
20
+ * with a warning.
21
+ */
22
+ integration?: string;
14
23
  /**
15
24
  * Disables the SDK-managed HTTP/2 transport. Defaults to `false` (H2 on);
16
25
  * set this to `true` (or `BL_DISABLE_H2=1`) to opt out of H2. Note that H2 is
@@ -104,6 +113,12 @@ declare class Settings {
104
113
  get commit(): string;
105
114
  get sentryDsn(): string;
106
115
  get apiVersion(): string;
116
+ /**
117
+ * Product token identifying the integration built on this SDK, or `""`.
118
+ * Resolved from `config.integration`, then `BL_INTEGRATION`. See `Config.integration`.
119
+ */
120
+ get integration(): string;
121
+ set integration(value: string | undefined);
107
122
  get headers(): Record<string, string>;
108
123
  get name(): string;
109
124
  get type(): string;