@blaxel/core 0.3.23 → 0.3.24
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/sandbox.js +69 -4
- package/dist/cjs/types/sandbox/sandbox.d.ts +41 -5
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/sandbox/sandbox.js +69 -4
- package/dist/cjs-browser/types/sandbox/sandbox.d.ts +41 -5
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm/sandbox/sandbox.js +66 -3
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/common/settings.js +2 -2
- package/dist/esm-browser/sandbox/sandbox.js +66 -3
- 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.24";
|
|
34
|
+
const BUILD_COMMIT = "d3dcd1599047a3cadaacac6805f29e210e57aaad";
|
|
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
|
|
@@ -33,7 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.SandboxInstance = void 0;
|
|
36
|
+
exports.SandboxInstance = exports.SandboxCreationTimeoutError = exports.MAX_CREATION_TIMEOUT_SECONDS = void 0;
|
|
37
|
+
exports.isCreationTimeoutError = isCreationTimeoutError;
|
|
37
38
|
const index_js_1 = require("../client/index.js");
|
|
38
39
|
const logger_js_1 = require("../common/logger.js");
|
|
39
40
|
const transient_retry_js_1 = require("../common/transient-retry.js");
|
|
@@ -94,6 +95,63 @@ const ARCHIVE_ENTRY_MAX_WAIT_MS = 30_000;
|
|
|
94
95
|
const CREATE_GATEWAY_TIMEOUT_MAX_WAIT_MS = 120_000;
|
|
95
96
|
const CREATE_GATEWAY_TIMEOUT_BASE_POLL_MS = 1_000;
|
|
96
97
|
const CREATE_GATEWAY_TIMEOUT_MAX_POLL_MS = 5_000;
|
|
98
|
+
// A creation deadline the caller sets per request through an undocumented
|
|
99
|
+
// header; it can only shorten the control plane's default. Capped below the
|
|
100
|
+
// edge's 60s origin-read timeout so the control plane's 408 always reaches the
|
|
101
|
+
// client instead of being masked by an edge 504.
|
|
102
|
+
const CREATION_TIMEOUT_HEADER = "X-Blaxel-Creation-Timeout";
|
|
103
|
+
exports.MAX_CREATION_TIMEOUT_SECONDS = 50;
|
|
104
|
+
/**
|
|
105
|
+
* Thrown by SandboxInstance.create / createIfNotExists when the sandbox was
|
|
106
|
+
* not ready within the creation deadline. The control plane has released the
|
|
107
|
+
* sandbox, so the name is free again and the creation can simply be started
|
|
108
|
+
* over. Catch it with `err instanceof SandboxCreationTimeoutError` or
|
|
109
|
+
* `isCreationTimeoutError(err)`.
|
|
110
|
+
*/
|
|
111
|
+
class SandboxCreationTimeoutError extends Error {
|
|
112
|
+
sandboxName;
|
|
113
|
+
timeout;
|
|
114
|
+
code = "CREATION_TIMEOUT";
|
|
115
|
+
status = 408;
|
|
116
|
+
/** Raw error body returned by the control plane. */
|
|
117
|
+
data;
|
|
118
|
+
constructor(
|
|
119
|
+
/** Name of the sandbox that was being created, if one was requested. */
|
|
120
|
+
sandboxName,
|
|
121
|
+
/** The `timeout` option of the call, in seconds; undefined when the control plane's default applied. */
|
|
122
|
+
timeout, data) {
|
|
123
|
+
const detail = typeof data === "object" && data !== null && typeof data.message === "string"
|
|
124
|
+
? data.message
|
|
125
|
+
: undefined;
|
|
126
|
+
const target = sandboxName ? `Sandbox ${sandboxName}` : "Sandbox";
|
|
127
|
+
const deadline = timeout !== undefined ? ` within ${timeout}s` : " within the creation deadline";
|
|
128
|
+
super(`${target} was not ready${deadline}; the creation was cancelled.${detail ? ` ${detail}` : ""}`);
|
|
129
|
+
this.sandboxName = sandboxName;
|
|
130
|
+
this.timeout = timeout;
|
|
131
|
+
this.name = "SandboxCreationTimeoutError";
|
|
132
|
+
this.data = data;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.SandboxCreationTimeoutError = SandboxCreationTimeoutError;
|
|
136
|
+
/** True when `err` is a sandbox creation timeout (408 CREATION_TIMEOUT). */
|
|
137
|
+
function isCreationTimeoutError(err) {
|
|
138
|
+
return err instanceof SandboxCreationTimeoutError;
|
|
139
|
+
}
|
|
140
|
+
const isCreationTimeoutResponse = (status, e) => {
|
|
141
|
+
if (status === 408)
|
|
142
|
+
return true;
|
|
143
|
+
if (typeof e !== "object" || e === null)
|
|
144
|
+
return false;
|
|
145
|
+
return e.code === "CREATION_TIMEOUT";
|
|
146
|
+
};
|
|
147
|
+
function validateCreateOptions({ timeout }) {
|
|
148
|
+
if (timeout === undefined)
|
|
149
|
+
return {};
|
|
150
|
+
if (!Number.isInteger(timeout) || timeout < 1 || timeout > exports.MAX_CREATION_TIMEOUT_SECONDS) {
|
|
151
|
+
throw new Error(`SandboxInstance.create: 'timeout' must be a whole number of seconds between 1 and ${exports.MAX_CREATION_TIMEOUT_SECONDS}, got ${timeout}.`);
|
|
152
|
+
}
|
|
153
|
+
return { timeout };
|
|
154
|
+
}
|
|
97
155
|
const isSandboxNotFound = (e) => {
|
|
98
156
|
if (typeof e !== "object" || e === null)
|
|
99
157
|
return false;
|
|
@@ -288,7 +346,9 @@ class SandboxInstance {
|
|
|
288
346
|
logger_js_1.logger.warn("⚠️ Warning: sandbox.wait() is deprecated. You don't need to wait for the sandbox to be deployed anymore.");
|
|
289
347
|
return this;
|
|
290
348
|
}
|
|
291
|
-
static async create(sandbox,
|
|
349
|
+
static async create(sandbox, options = {}) {
|
|
350
|
+
const { safe = false, createIfNotExist = false } = options;
|
|
351
|
+
const { timeout } = validateCreateOptions(options);
|
|
292
352
|
// No client-side default name: when the caller omits a name we send the
|
|
293
353
|
// creation without metadata.name so the server can assign one and unnamed
|
|
294
354
|
// creations become eligible for warm sandbox pools (ENG-3931).
|
|
@@ -370,16 +430,21 @@ class SandboxInstance {
|
|
|
370
430
|
if (edgeDomain && !settings_js_1.settings.disableH2) {
|
|
371
431
|
Promise.resolve().then(() => __importStar(require("../common/h2pool.js"))).then(({ h2Pool }) => h2Pool.warm(edgeDomain)).catch(() => { });
|
|
372
432
|
}
|
|
433
|
+
const headers = timeout !== undefined ? { [CREATION_TIMEOUT_HEADER]: String(timeout) } : undefined;
|
|
373
434
|
const [createResult, h2Session] = await Promise.all([
|
|
374
435
|
(0, index_js_1.createSandbox)({
|
|
375
436
|
body: sandbox,
|
|
376
437
|
query: createIfNotExist ? { createIfNotExist } : undefined,
|
|
438
|
+
headers,
|
|
377
439
|
}),
|
|
378
440
|
edgeDomain && !settings_js_1.settings.disableH2 ? Promise.resolve().then(() => __importStar(require("../common/h2pool.js"))).then(({ h2Pool }) => h2Pool.get(edgeDomain)).catch(() => null) : Promise.resolve(null),
|
|
379
441
|
]);
|
|
380
442
|
let data = createResult.data;
|
|
381
443
|
if (createResult.error !== undefined) {
|
|
382
444
|
const name = sandbox.metadata.name;
|
|
445
|
+
if (isCreationTimeoutResponse(createResult.response.status, createResult.error)) {
|
|
446
|
+
throw new SandboxCreationTimeoutError(name, timeout, createResult.error);
|
|
447
|
+
}
|
|
383
448
|
if (createResult.response.status === 504 && name) {
|
|
384
449
|
// The edge gave up on the connection but the creation is still running
|
|
385
450
|
// server-side; wait for the record instead of failing (ENG-3662).
|
|
@@ -614,7 +679,7 @@ class SandboxInstance {
|
|
|
614
679
|
const instance = new SandboxInstance(data);
|
|
615
680
|
return SandboxInstance.attachH2Session(instance);
|
|
616
681
|
}
|
|
617
|
-
static async createIfNotExists(sandbox) {
|
|
682
|
+
static async createIfNotExists(sandbox, options = {}) {
|
|
618
683
|
const ATTEMPTS = 3;
|
|
619
684
|
let lastStatus = "unknown";
|
|
620
685
|
// The 'vanished' window (create 409s while get 404s) is driven by the same
|
|
@@ -626,7 +691,7 @@ class SandboxInstance {
|
|
|
626
691
|
for (let i = 0; i < ATTEMPTS; ++i) {
|
|
627
692
|
const finalAttempt = i === ATTEMPTS - 1;
|
|
628
693
|
try {
|
|
629
|
-
return await this.create(sandbox, { createIfNotExist: true });
|
|
694
|
+
return await this.create(sandbox, { ...options, createIfNotExist: true });
|
|
630
695
|
}
|
|
631
696
|
catch (e) {
|
|
632
697
|
if (typeof e === "object" && e !== null && "code" in e && (e.code === 409 || e.code === 'SANDBOX_ALREADY_EXISTS')) {
|
|
@@ -46,6 +46,45 @@ export type SandboxArchiveOptions = {
|
|
|
46
46
|
/** Milliseconds between two reads of the sandbox. Defaults to 2 seconds. */
|
|
47
47
|
interval?: number;
|
|
48
48
|
};
|
|
49
|
+
export declare const MAX_CREATION_TIMEOUT_SECONDS = 50;
|
|
50
|
+
/** Options of SandboxInstance.create / createIfNotExists. */
|
|
51
|
+
export type SandboxCreateOptions = {
|
|
52
|
+
/** Check the sandbox answers (fs.ls) and delete it if it does not. Defaults to false. */
|
|
53
|
+
safe?: boolean;
|
|
54
|
+
/** Return the existing sandbox instead of failing when the name is taken. */
|
|
55
|
+
createIfNotExist?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Give up on the creation after this many seconds (whole number, 1 to
|
|
58
|
+
* MAX_CREATION_TIMEOUT_SECONDS). The control plane releases the sandbox
|
|
59
|
+
* and the call rejects with a SandboxCreationTimeoutError. Unset, the
|
|
60
|
+
* control plane's default deadline applies.
|
|
61
|
+
*/
|
|
62
|
+
timeout?: number;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Thrown by SandboxInstance.create / createIfNotExists when the sandbox was
|
|
66
|
+
* not ready within the creation deadline. The control plane has released the
|
|
67
|
+
* sandbox, so the name is free again and the creation can simply be started
|
|
68
|
+
* over. Catch it with `err instanceof SandboxCreationTimeoutError` or
|
|
69
|
+
* `isCreationTimeoutError(err)`.
|
|
70
|
+
*/
|
|
71
|
+
export declare class SandboxCreationTimeoutError extends Error {
|
|
72
|
+
/** Name of the sandbox that was being created, if one was requested. */
|
|
73
|
+
readonly sandboxName: string | undefined;
|
|
74
|
+
/** The `timeout` option of the call, in seconds; undefined when the control plane's default applied. */
|
|
75
|
+
readonly timeout: number | undefined;
|
|
76
|
+
readonly code = "CREATION_TIMEOUT";
|
|
77
|
+
readonly status = 408;
|
|
78
|
+
/** Raw error body returned by the control plane. */
|
|
79
|
+
readonly data: unknown;
|
|
80
|
+
constructor(
|
|
81
|
+
/** Name of the sandbox that was being created, if one was requested. */
|
|
82
|
+
sandboxName: string | undefined,
|
|
83
|
+
/** The `timeout` option of the call, in seconds; undefined when the control plane's default applied. */
|
|
84
|
+
timeout: number | undefined, data: unknown);
|
|
85
|
+
}
|
|
86
|
+
/** True when `err` is a sandbox creation timeout (408 CREATION_TIMEOUT). */
|
|
87
|
+
export declare function isCreationTimeoutError(err: unknown): err is SandboxCreationTimeoutError;
|
|
49
88
|
export declare class SandboxInstance {
|
|
50
89
|
private sandbox;
|
|
51
90
|
fs: SandboxFileSystem;
|
|
@@ -142,10 +181,7 @@ export declare class SandboxInstance {
|
|
|
142
181
|
maxWait?: number;
|
|
143
182
|
interval?: number;
|
|
144
183
|
}): Promise<this>;
|
|
145
|
-
static create(sandbox?: SandboxModel | SandboxCreateConfiguration,
|
|
146
|
-
safe?: boolean;
|
|
147
|
-
createIfNotExist?: boolean;
|
|
148
|
-
}): Promise<SandboxInstance>;
|
|
184
|
+
static create(sandbox?: SandboxModel | SandboxCreateConfiguration, options?: SandboxCreateOptions): Promise<SandboxInstance>;
|
|
149
185
|
/**
|
|
150
186
|
* Archive a sandbox: keep its filesystem, stop the sandbox.
|
|
151
187
|
*
|
|
@@ -224,7 +260,7 @@ export declare class SandboxInstance {
|
|
|
224
260
|
static updateTtl(sandboxName: string, ttl: string | null): Promise<SandboxInstance>;
|
|
225
261
|
static updateLifecycle(sandboxName: string, lifecycle: SandboxLifecycle | null): Promise<SandboxInstance>;
|
|
226
262
|
static updateNetwork(sandboxName: string, network: SandboxUpdateNetwork): Promise<SandboxInstance>;
|
|
227
|
-
static createIfNotExists(sandbox: SandboxModel | SandboxCreateConfiguration): Promise<SandboxInstance>;
|
|
263
|
+
static createIfNotExists(sandbox: SandboxModel | SandboxCreateConfiguration, options?: Omit<SandboxCreateOptions, "createIfNotExist">): Promise<SandboxInstance>;
|
|
228
264
|
private static waitAfterCreateGatewayTimeout;
|
|
229
265
|
private static waitWhileSandboxDying;
|
|
230
266
|
static fromSession(session: SessionWithToken): Promise<SandboxInstance>;
|