@blaxel/core 0.3.1-preview.211 → 0.3.1

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.
@@ -22,8 +22,8 @@ function missingCredentialsMessage() {
22
22
  return "No Blaxel credentials found. Set the BL_API_KEY and BL_WORKSPACE environment variables, or run `bl login`.";
23
23
  }
24
24
  // Build info - these placeholders are replaced at build time by build:replace-imports
25
- const BUILD_VERSION = "0.3.1-preview.211";
26
- const BUILD_COMMIT = "bec14a486d933a8311bb7cc2c7e4720c14ce2b44";
25
+ const BUILD_VERSION = "0.3.1";
26
+ const BUILD_COMMIT = "06b4bb451ef8797cbc2cd3e3a957d62c45f2cc12";
27
27
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
28
28
  const BLAXEL_API_VERSION = "2026-04-28";
29
29
  // Cache for config.yaml tracking value
@@ -373,6 +373,12 @@ export class SandboxInstance {
373
373
  static async createIfNotExists(sandbox) {
374
374
  const ATTEMPTS = 3;
375
375
  let lastStatus = "unknown";
376
+ // The 'vanished' window (create 409s while get 404s) is driven by the same
377
+ // transient causes as 'dying': an in-flight delete finishing, or a
378
+ // concurrent create whose row is not readable yet. Give it the same time
379
+ // budget as waitWhileSandboxDying instead of burning the attempt budget
380
+ // 500ms apart (~1s total), which threw on deletes taking >1s (ENG-3667).
381
+ const vanishedDeadline = Date.now() + TRANSIENT_STATUS_MAX_WAIT_MS;
376
382
  for (let i = 0; i < ATTEMPTS; ++i) {
377
383
  const finalAttempt = i === ATTEMPTS - 1;
378
384
  try {
@@ -384,6 +390,12 @@ export class SandboxInstance {
384
390
  if (!name) {
385
391
  throw new Error("Sandbox name is required");
386
392
  }
393
+ // The controlplane tags the creation-lock 409 with
394
+ // reason=CREATION_IN_PROGRESS when the conflict comes from a
395
+ // concurrent create still in flight (ENG-3776). The field is absent
396
+ // on older controlplanes and on real row conflicts, so it only
397
+ // sharpens the give-up error; the polling behavior is the same.
398
+ const creationInProgress = e.reason === "CREATION_IN_PROGRESS";
387
399
  // Get the existing sandbox to check its status
388
400
  let sandboxInstance;
389
401
  try {
@@ -391,10 +403,14 @@ export class SandboxInstance {
391
403
  }
392
404
  catch (getError) {
393
405
  if (isSandboxNotFound(getError)) {
394
- // The record vanished between the create conflict and this status check
395
- // (its deletion just finished); give the control plane a beat and retry.
396
- lastStatus = "vanished";
397
- if (!finalAttempt) {
406
+ // The record vanished between the create conflict and this status check.
407
+ lastStatus = creationInProgress ? "creation in progress" : "vanished";
408
+ if (Date.now() < vanishedDeadline) {
409
+ // Inside the transient window: poll without consuming attempts.
410
+ await new Promise((resolve) => setTimeout(resolve, TRANSIENT_STATUS_POLL_MS));
411
+ --i;
412
+ }
413
+ else if (!finalAttempt) {
398
414
  await new Promise((resolve) => setTimeout(resolve, TRANSIENT_STATUS_POLL_MS));
399
415
  }
400
416
  continue;