@blaxel/core 0.3.31-preview.328 → 0.3.32-preview.330
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.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/common/settings.js +2 -2
- package/dist/cjs/sandbox/drift.js +60 -0
- package/dist/cjs/sandbox/sandbox.js +26 -0
- package/dist/cjs/types/sandbox/drift.d.ts +30 -0
- package/dist/cjs/types/sandbox/sandbox.d.ts +1 -0
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/sandbox/drift.js +60 -0
- package/dist/cjs-browser/sandbox/sandbox.js +26 -0
- package/dist/cjs-browser/types/sandbox/drift.d.ts +30 -0
- package/dist/cjs-browser/types/sandbox/sandbox.d.ts +1 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm/sandbox/drift.js +56 -0
- package/dist/esm/sandbox/sandbox.js +26 -0
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/common/settings.js +2 -2
- package/dist/esm-browser/sandbox/drift.js +56 -0
- package/dist/esm-browser/sandbox/sandbox.js +26 -0
- package/package.json +1 -1
|
@@ -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.
|
|
34
|
-
const BUILD_COMMIT = "
|
|
33
|
+
const BUILD_VERSION = "0.3.32-preview.330";
|
|
34
|
+
const BUILD_COMMIT = "4461bded7579866abc4dcbb166189e2ed15a7ea6";
|
|
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
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describeDrift = describeDrift;
|
|
4
|
+
exports.driftWarning = driftWarning;
|
|
5
|
+
// The control plane masks every env value it reads back, so values can only be compared when it did not.
|
|
6
|
+
const MASKED_ENV_VALUE = "****";
|
|
7
|
+
// The control plane keeps the image reference as submitted: "app" and "app:latest" are the same image.
|
|
8
|
+
function withTag(image) {
|
|
9
|
+
if (image.includes("@"))
|
|
10
|
+
return image;
|
|
11
|
+
return image.indexOf(":", image.lastIndexOf("/") + 1) === -1 ? `${image}:latest` : image;
|
|
12
|
+
}
|
|
13
|
+
function envDrift(requested, existing) {
|
|
14
|
+
const byName = new Map(existing.map((env) => [env.name, env]));
|
|
15
|
+
const missing = [];
|
|
16
|
+
const changed = [];
|
|
17
|
+
for (const env of requested) {
|
|
18
|
+
const current = byName.get(env.name);
|
|
19
|
+
if (!current)
|
|
20
|
+
missing.push(env.name ?? "");
|
|
21
|
+
else if (current.value !== undefined && current.value !== MASKED_ENV_VALUE && current.value !== env.value)
|
|
22
|
+
changed.push(env.name ?? "");
|
|
23
|
+
}
|
|
24
|
+
// Names only: env values are often secrets and never go into a log line.
|
|
25
|
+
const parts = [
|
|
26
|
+
missing.length ? `not set on the existing sandbox: ${missing.join(", ")}` : "",
|
|
27
|
+
changed.length ? `different value: ${changed.join(", ")}` : "",
|
|
28
|
+
].filter(Boolean);
|
|
29
|
+
return parts.length ? `envs (${parts.join("; ")})` : undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Describes how an existing sandbox differs from the configuration that was
|
|
33
|
+
* asked for, one entry per field (image, memory, region, envs). Empty when
|
|
34
|
+
* nothing differs. A field the existing sandbox does not report is not drift.
|
|
35
|
+
*/
|
|
36
|
+
function describeDrift(requested, existing) {
|
|
37
|
+
const drift = [];
|
|
38
|
+
const runtime = existing.spec?.runtime;
|
|
39
|
+
if (requested.image && runtime?.image && withTag(requested.image) !== withTag(runtime.image)) {
|
|
40
|
+
drift.push(`image (requested ${requested.image}, existing ${runtime.image})`);
|
|
41
|
+
}
|
|
42
|
+
if (requested.memory !== undefined && runtime?.memory !== undefined && requested.memory !== runtime.memory) {
|
|
43
|
+
drift.push(`memory (requested ${requested.memory} MB, existing ${runtime.memory} MB)`);
|
|
44
|
+
}
|
|
45
|
+
if (requested.region && existing.spec?.region && requested.region !== existing.spec.region) {
|
|
46
|
+
drift.push(`region (requested ${requested.region}, existing ${existing.spec.region})`);
|
|
47
|
+
}
|
|
48
|
+
if (requested.envs?.length && runtime?.envs) {
|
|
49
|
+
const envs = envDrift(requested.envs, runtime.envs);
|
|
50
|
+
if (envs)
|
|
51
|
+
drift.push(envs);
|
|
52
|
+
}
|
|
53
|
+
return drift;
|
|
54
|
+
}
|
|
55
|
+
/** The single warning createIfNotExists logs when the sandbox it returned is not the one that was asked for. */
|
|
56
|
+
function driftWarning(name, drift) {
|
|
57
|
+
return (`SandboxInstance.createIfNotExists: sandbox ${name ? `"${name}" ` : ""}already exists, so it was returned as is and the requested configuration was not applied. ` +
|
|
58
|
+
`It differs on: ${drift.join("; ")}. ` +
|
|
59
|
+
"Delete the sandbox and create it again to apply the new configuration.");
|
|
60
|
+
}
|
|
@@ -42,6 +42,7 @@ const pagination_js_1 = require("../common/pagination.js");
|
|
|
42
42
|
const settings_js_1 = require("../common/settings.js");
|
|
43
43
|
const index_js_2 = require("./codegen/index.js");
|
|
44
44
|
const index_js_3 = require("./drive/index.js");
|
|
45
|
+
const drift_js_1 = require("./drift.js");
|
|
45
46
|
const index_js_4 = require("./filesystem/index.js");
|
|
46
47
|
const index_js_5 = require("./network/index.js");
|
|
47
48
|
const preview_js_1 = require("./preview.js");
|
|
@@ -337,6 +338,9 @@ class SandboxInstance {
|
|
|
337
338
|
// creations become eligible for warm sandbox pools (ENG-3931).
|
|
338
339
|
const defaultImage = `blaxel/base-image:latest`;
|
|
339
340
|
const defaultMemory = 4096;
|
|
341
|
+
// What the caller asked for, read before the defaults below fill the gaps:
|
|
342
|
+
// createIfNotExists compares only these with the sandbox it gets back.
|
|
343
|
+
let requested = {};
|
|
340
344
|
// Handle SandboxCreateConfiguration or simple dict with name/image/memory/ports/envs/volumes keys
|
|
341
345
|
if (!sandbox ||
|
|
342
346
|
'name' in sandbox ||
|
|
@@ -354,6 +358,7 @@ class SandboxInstance {
|
|
|
354
358
|
'standbyGracePeriodSeconds' in sandbox) {
|
|
355
359
|
if (!sandbox)
|
|
356
360
|
sandbox = {};
|
|
361
|
+
requested = { image: sandbox.image, memory: sandbox.memory, region: sandbox.region, envs: (0, types_js_1.normalizeEnvs)(sandbox.envs) };
|
|
357
362
|
if (!sandbox.image)
|
|
358
363
|
sandbox.image = defaultImage;
|
|
359
364
|
if (!sandbox.memory)
|
|
@@ -400,6 +405,10 @@ class SandboxInstance {
|
|
|
400
405
|
sandbox.spec.runtime.expires = expires.toISOString();
|
|
401
406
|
}
|
|
402
407
|
}
|
|
408
|
+
else {
|
|
409
|
+
const { region, runtime } = sandbox.spec ?? {};
|
|
410
|
+
requested = { image: runtime?.image, memory: runtime?.memory, region, envs: runtime?.envs };
|
|
411
|
+
}
|
|
403
412
|
sandbox = sandbox;
|
|
404
413
|
if (!sandbox.metadata) {
|
|
405
414
|
// Leave name unset so the server assigns one (ENG-3931).
|
|
@@ -442,6 +451,8 @@ class SandboxInstance {
|
|
|
442
451
|
throw createResult.error;
|
|
443
452
|
}
|
|
444
453
|
}
|
|
454
|
+
if (createIfNotExist)
|
|
455
|
+
SandboxInstance.warnOnDrift(requested, data);
|
|
445
456
|
// Inject the H2 session into the config so subsystems can use it
|
|
446
457
|
const config = { ...data, h2Session, h2Domain: settings_js_1.settings.disableH2 ? null : edgeDomain };
|
|
447
458
|
const instance = new SandboxInstance(config);
|
|
@@ -679,6 +690,21 @@ class SandboxInstance {
|
|
|
679
690
|
static async createIfNotExists(sandbox, options = {}) {
|
|
680
691
|
return this.create(sandbox, { ...options, createIfNotExist: true });
|
|
681
692
|
}
|
|
693
|
+
// createIfNotExists hands back the sandbox already holding the name, whatever
|
|
694
|
+
// it was created with. Say so when it is not what was asked for; this only
|
|
695
|
+
// logs and never throws or changes what is returned.
|
|
696
|
+
static warnOnDrift(requested, existing) {
|
|
697
|
+
if (!existing)
|
|
698
|
+
return;
|
|
699
|
+
try {
|
|
700
|
+
const drift = (0, drift_js_1.describeDrift)(requested, existing);
|
|
701
|
+
if (drift.length)
|
|
702
|
+
console.warn((0, drift_js_1.driftWarning)(existing.metadata?.name, drift));
|
|
703
|
+
}
|
|
704
|
+
catch {
|
|
705
|
+
// Best-effort diagnostics: a failed comparison must not fail the create.
|
|
706
|
+
}
|
|
707
|
+
}
|
|
682
708
|
// Poll the record after a create was cut by the edge with a 504 while the
|
|
683
709
|
// control plane is still deploying it. Resolves with the sandbox once it
|
|
684
710
|
// reaches DEPLOYED; throws on FAILED or once the wait budget is spent.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Env } from "../client/index.js";
|
|
2
|
+
/** The fields of a create request that are compared with an existing sandbox. A field the caller did not set is not compared. */
|
|
3
|
+
export type RequestedSandbox = {
|
|
4
|
+
image?: string;
|
|
5
|
+
memory?: number;
|
|
6
|
+
region?: string;
|
|
7
|
+
envs?: Env[];
|
|
8
|
+
};
|
|
9
|
+
type ExistingSandbox = {
|
|
10
|
+
metadata?: {
|
|
11
|
+
name?: string;
|
|
12
|
+
};
|
|
13
|
+
spec?: {
|
|
14
|
+
region?: string;
|
|
15
|
+
runtime?: {
|
|
16
|
+
image?: string;
|
|
17
|
+
memory?: number;
|
|
18
|
+
envs?: Env[];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Describes how an existing sandbox differs from the configuration that was
|
|
24
|
+
* asked for, one entry per field (image, memory, region, envs). Empty when
|
|
25
|
+
* nothing differs. A field the existing sandbox does not report is not drift.
|
|
26
|
+
*/
|
|
27
|
+
export declare function describeDrift(requested: RequestedSandbox, existing: ExistingSandbox): string[];
|
|
28
|
+
/** The single warning createIfNotExists logs when the sandbox it returned is not the one that was asked for. */
|
|
29
|
+
export declare function driftWarning(name: string | undefined, drift: string[]): string;
|
|
30
|
+
export {};
|
|
@@ -276,6 +276,7 @@ export declare class SandboxInstance {
|
|
|
276
276
|
* `options` (e.g. `timeout`) are forwarded to `create`.
|
|
277
277
|
*/
|
|
278
278
|
static createIfNotExists(sandbox: SandboxModel | SandboxCreateConfiguration, options?: Omit<SandboxCreateOptions, "createIfNotExist">): Promise<SandboxInstance>;
|
|
279
|
+
private static warnOnDrift;
|
|
279
280
|
private static waitAfterCreateGatewayTimeout;
|
|
280
281
|
static fromSession(session: SessionWithToken): Promise<SandboxInstance>;
|
|
281
282
|
}
|