@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.
@@ -28,8 +28,8 @@ function missingCredentialsMessage() {
28
28
  return "No Blaxel credentials found. Set the BL_API_KEY and BL_WORKSPACE environment variables, or run `bl login`.";
29
29
  }
30
30
  // Build info - these placeholders are replaced at build time by build:replace-imports
31
- const BUILD_VERSION = "0.3.1-preview.211";
32
- const BUILD_COMMIT = "bec14a486d933a8311bb7cc2c7e4720c14ce2b44";
31
+ const BUILD_VERSION = "0.3.1";
32
+ const BUILD_COMMIT = "06b4bb451ef8797cbc2cd3e3a957d62c45f2cc12";
33
33
  const BUILD_SENTRY_DSN = "https://fd5e60e1c9820e1eef5ccebb84a07127@o4508714045276160.ingest.us.sentry.io/4510465864564736";
34
34
  const BLAXEL_API_VERSION = "2026-04-28";
35
35
  // Cache for config.yaml tracking value
@@ -409,6 +409,12 @@ class SandboxInstance {
409
409
  static async createIfNotExists(sandbox) {
410
410
  const ATTEMPTS = 3;
411
411
  let lastStatus = "unknown";
412
+ // The 'vanished' window (create 409s while get 404s) is driven by the same
413
+ // transient causes as 'dying': an in-flight delete finishing, or a
414
+ // concurrent create whose row is not readable yet. Give it the same time
415
+ // budget as waitWhileSandboxDying instead of burning the attempt budget
416
+ // 500ms apart (~1s total), which threw on deletes taking >1s (ENG-3667).
417
+ const vanishedDeadline = Date.now() + TRANSIENT_STATUS_MAX_WAIT_MS;
412
418
  for (let i = 0; i < ATTEMPTS; ++i) {
413
419
  const finalAttempt = i === ATTEMPTS - 1;
414
420
  try {
@@ -420,6 +426,12 @@ class SandboxInstance {
420
426
  if (!name) {
421
427
  throw new Error("Sandbox name is required");
422
428
  }
429
+ // The controlplane tags the creation-lock 409 with
430
+ // reason=CREATION_IN_PROGRESS when the conflict comes from a
431
+ // concurrent create still in flight (ENG-3776). The field is absent
432
+ // on older controlplanes and on real row conflicts, so it only
433
+ // sharpens the give-up error; the polling behavior is the same.
434
+ const creationInProgress = e.reason === "CREATION_IN_PROGRESS";
423
435
  // Get the existing sandbox to check its status
424
436
  let sandboxInstance;
425
437
  try {
@@ -427,10 +439,14 @@ class SandboxInstance {
427
439
  }
428
440
  catch (getError) {
429
441
  if (isSandboxNotFound(getError)) {
430
- // The record vanished between the create conflict and this status check
431
- // (its deletion just finished); give the control plane a beat and retry.
432
- lastStatus = "vanished";
433
- if (!finalAttempt) {
442
+ // The record vanished between the create conflict and this status check.
443
+ lastStatus = creationInProgress ? "creation in progress" : "vanished";
444
+ if (Date.now() < vanishedDeadline) {
445
+ // Inside the transient window: poll without consuming attempts.
446
+ await new Promise((resolve) => setTimeout(resolve, TRANSIENT_STATUS_POLL_MS));
447
+ --i;
448
+ }
449
+ else if (!finalAttempt) {
434
450
  await new Promise((resolve) => setTimeout(resolve, TRANSIENT_STATUS_POLL_MS));
435
451
  }
436
452
  continue;