@or3/cloud 0.1.112 → 0.1.116

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/cli.mjs CHANGED
@@ -133,7 +133,7 @@ import { basename as basename8, resolve as resolve17 } from "node:path";
133
133
 
134
134
  // src/commands/adopt.ts
135
135
  import { chmod as chmod5, mkdir as mkdir5 } from "node:fs/promises";
136
- import { basename as basename3, join as join16, resolve as resolve7 } from "node:path";
136
+ import { basename as basename3, join as join17, resolve as resolve7 } from "node:path";
137
137
 
138
138
  // src/backup/archive.ts
139
139
  import { createReadStream as createReadStream3 } from "node:fs";
@@ -194,7 +194,7 @@ import { readFileSync } from "node:fs";
194
194
  import { join, resolve } from "node:path";
195
195
  import { fileURLToPath } from "node:url";
196
196
  var PACKAGE_ROOT = resolve(fileURLToPath(new URL("../", import.meta.url)));
197
- var PACKAGE_VERSION = "0.1.112";
197
+ var PACKAGE_VERSION = "0.1.116";
198
198
  var IMAGE_REPOSITORY = "ghcr.io/saluana/or3-chat";
199
199
  var ASSET_ROOT = resolve(fileURLToPath(new URL("../assets/", import.meta.url)));
200
200
  var SHA256_DIGEST = /^sha256:[0-9a-f]{64}$/;
@@ -1866,12 +1866,12 @@ END {
1866
1866
  }
1867
1867
 
1868
1868
  // src/backup/manifests.ts
1869
- import { createHash as createHash3, createHmac, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
1869
+ import { createHmac, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
1870
1870
  import { lstat as lstat3, readdir as readdir2 } from "node:fs/promises";
1871
- import { isAbsolute as isAbsolute3, join as join12, resolve as resolve4 } from "node:path";
1871
+ import { isAbsolute as isAbsolute3, join as join14, resolve as resolve4 } from "node:path";
1872
1872
 
1873
1873
  // src/deployment/assets.ts
1874
- import { randomBytes as randomBytes4 } from "node:crypto";
1874
+ import { createHash as createHash2, randomBytes as randomBytes4 } from "node:crypto";
1875
1875
  import { chmod as chmod3, copyFile as copyFile2, mkdir as mkdir3, readFile as readFile2, rm as rm3, writeFile as writeFile2 } from "node:fs/promises";
1876
1876
  import { join as join8 } from "node:path";
1877
1877
  var MANAGED_ASSET_INVENTORY_VERSION = 4;
@@ -1998,11 +1998,12 @@ async function verifiedManagedAssetContents(backupPath, manifest2) {
1998
1998
  throw new Error(`Backup ${manifest2.backupId} has an invalid checksum for managed asset ${name}.`);
1999
1999
  }
2000
2000
  const source = join8(backupPath, "managed-assets", name);
2001
- const actualSha = await sha256File(source);
2001
+ const contents = await readFile2(source);
2002
+ const actualSha = createHash2("sha256").update(contents).digest("hex");
2002
2003
  if (actualSha !== expectedSha) {
2003
2004
  throw new Error(`Backup managed asset checksum mismatch for ${name}. Expected ${expectedSha}, got ${actualSha}.`);
2004
2005
  }
2005
- assets.set(name, await readFile2(source));
2006
+ assets.set(name, contents);
2006
2007
  }
2007
2008
  return assets;
2008
2009
  }
@@ -2405,10 +2406,236 @@ async function captureRemoteSnapshot(directory, state, env, backupDir) {
2405
2406
  }
2406
2407
 
2407
2408
  // src/backup/vault.ts
2408
- import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
2409
+ import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
2409
2410
  import { constants } from "node:fs";
2410
- import { lstat as lstat2, open as open2, readFile as readFile4 } from "node:fs/promises";
2411
- import { isAbsolute as isAbsolute2, join as join11 } from "node:path";
2411
+ import { lstat as lstat2, open as open2 } from "node:fs/promises";
2412
+ import { isAbsolute as isAbsolute2, join as join13 } from "node:path";
2413
+
2414
+ // src/runtime/project.ts
2415
+ import { readFileSync as readFileSync5 } from "node:fs";
2416
+ import { join as join11 } from "node:path";
2417
+
2418
+ // src/runtime/health.ts
2419
+ var DEEP_HEALTH_TIMEOUT_MS = 180000;
2420
+ var HEALTH_SCRIPT = "const fs=require('node:fs');try{const auth=process.env.AUTH_PROVIDER||process.env.OR3_AUTH_PROVIDER||'basic-auth',storage=process.env.NUXT_PUBLIC_STORAGE_PROVIDER||'fs',sync=process.env.OR3_SYNC_PROVIDER||'sqlite';if(sync!=='sqlite'||!(auth==='basic-auth'&&storage==='fs'||auth==='clerk'&&storage==='s3')||process.env.AUTH_PROVIDER&&process.env.OR3_AUTH_PROVIDER&&process.env.AUTH_PROVIDER!==process.env.OR3_AUTH_PROVIDER)throw Error('profile');fs.accessSync('/data',fs.constants.R_OK|fs.constants.W_OK);const paths=auth==='basic-auth'?[process.env.OR3_BASIC_AUTH_DB_PATH,process.env.OR3_SQLITE_DB_PATH]:[process.env.OR3_SQLITE_DB_PATH];if(paths.some(p=>!p))throw Error('database path');for(const path of paths){const fd=fs.openSync(path,'r+');fs.closeSync(fd)}}catch{process.exit(1)}fetch('http://127.0.0.1:3000/api/health?deep=true').then(async response=>{const body=await response.json().catch(()=>({}));if(!response.ok||body.status!=='ok'||body.providers?.auth?.provider!==(process.env.AUTH_PROVIDER||process.env.OR3_AUTH_PROVIDER||'basic-auth')||body.providers?.sync?.provider!=='sqlite'||body.providers?.storage?.provider!==(process.env.NUXT_PUBLIC_STORAGE_PROVIDER||'fs'))process.exit(1)}).catch(()=>process.exit(1))";
2421
+ var VERIFY_DATABASES_SCRIPT = `
2422
+ const fs = require('node:fs');
2423
+ const Database = require('/app/.output/server/node_modules/better-sqlite3');
2424
+ const results = [];
2425
+ const auth = process.env.AUTH_PROVIDER || process.env.OR3_AUTH_PROVIDER || 'basic-auth';
2426
+ const storage = process.env.NUXT_PUBLIC_STORAGE_PROVIDER || 'fs', sync = process.env.OR3_SYNC_PROVIDER || 'sqlite';
2427
+ if (sync !== 'sqlite' || !(auth === 'basic-auth' && storage === 'fs' || auth === 'clerk' && storage === 's3') || process.env.AUTH_PROVIDER && process.env.OR3_AUTH_PROVIDER && process.env.AUTH_PROVIDER !== process.env.OR3_AUTH_PROVIDER) throw new Error('Unsupported auth profile');
2428
+ const paths = auth === 'basic-auth' ? [process.env.OR3_BASIC_AUTH_DB_PATH, process.env.OR3_SQLITE_DB_PATH] : [process.env.OR3_SQLITE_DB_PATH];
2429
+ if (paths.some(path => !path)) throw new Error('Missing managed database path');
2430
+ for (const path of paths) {
2431
+ const info = fs.statSync(path);
2432
+ if (info.uid !== 65532 || info.gid !== 65532) throw new Error(path + ' must be owned by 65532:65532');
2433
+ const db = new Database(path, { readonly: true, fileMustExist: true });
2434
+ const quickCheck = db.pragma('quick_check', { simple: true });
2435
+ const tables = db.prepare("select count(*) as count from sqlite_master where type = 'table'").get().count;
2436
+ db.close();
2437
+ if (quickCheck !== 'ok') throw new Error(path + ' quick_check failed: ' + quickCheck);
2438
+ results.push({ path, quickCheck, tables });
2439
+ }
2440
+ if (process.env.OR3_FORCE_HTTPS === 'true' && process.env.NUXT_SECURITY_PROXY_TRUST_PROXY !== 'true') {
2441
+ throw new Error('NUXT_SECURITY_PROXY_TRUST_PROXY must be true for a managed public deployment');
2442
+ }
2443
+ console.log(JSON.stringify(results));
2444
+ `;
2445
+ var CONTAINER_NODE = "/nodejs/bin/node";
2446
+ var LEGACY_CONTAINER_NODE = "/usr/local/bin/node";
2447
+ var CONTAINER_NODE_SHELL = `if [ -x ${CONTAINER_NODE} ]; then exec ${CONTAINER_NODE} -e "$1"; elif [ -x ${LEGACY_CONTAINER_NODE} ]; then exec ${LEGACY_CONTAINER_NODE} -e "$1"; else exit 127; fi`;
2448
+ function containerNodeCommand(script) {
2449
+ return ["sh", "-c", CONTAINER_NODE_SHELL, "or3-node", script];
2450
+ }
2451
+ async function waitForDeepHealthWithArgs(composeCommand, directory, secrets = []) {
2452
+ const startedAt = Date.now();
2453
+ const deadline = startedAt + DEEP_HEALTH_TIMEOUT_MS;
2454
+ let lastError = "health check did not complete";
2455
+ let lastProgressAt = startedAt;
2456
+ while (Date.now() < deadline) {
2457
+ const result = await run("docker", [
2458
+ ...composeCommand,
2459
+ "exec",
2460
+ "-T",
2461
+ "or3",
2462
+ ...containerNodeCommand(HEALTH_SCRIPT)
2463
+ ], directory);
2464
+ if (result.ok)
2465
+ return;
2466
+ lastError = redact(result.stderr, secrets);
2467
+ if (Date.now() - lastProgressAt >= 15000) {
2468
+ console.error(`Waiting for OR3 deep health (${Math.round((Date.now() - startedAt) / 1000)}s elapsed)…`);
2469
+ lastProgressAt = Date.now();
2470
+ }
2471
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, 1000));
2472
+ }
2473
+ throw new Error(`OR3 deep health did not pass within ${DEEP_HEALTH_TIMEOUT_MS / 1000} seconds. Last error: ${lastError}`);
2474
+ }
2475
+ async function waitForDeepHealth(directory, mode, secrets = []) {
2476
+ try {
2477
+ await waitForDeepHealthWithArgs(composeArgs(directory, mode), directory, secrets);
2478
+ } catch (error) {
2479
+ const captured = await captureComposeDiagnostics(directory, mode, secrets).catch((captureError) => redact(`Diagnostics capture failed: ${captureError instanceof Error ? captureError.message : String(captureError)}`, secrets));
2480
+ throw new Error(`${error instanceof Error ? error.message : String(error)}
2481
+ Captured Docker diagnostics:
2482
+ ${captured}
2483
+ Diagnostics: ${diagnostics(directory, mode)}`);
2484
+ }
2485
+ }
2486
+ async function probeDeepHealth(directory, mode) {
2487
+ const result = await run("docker", [...composeArgs(directory, mode, ["exec", "-T", "or3", ...containerNodeCommand(HEALTH_SCRIPT)])], directory);
2488
+ if (result.ok)
2489
+ return "ok";
2490
+ const ps = await run("docker", [...composeArgs(directory, mode, ["ps", "-q", "or3"])], directory);
2491
+ if (ps.ok && ps.stdout.trim())
2492
+ return "degraded";
2493
+ return "unreachable";
2494
+ }
2495
+
2496
+ // src/runtime/project.ts
2497
+ function managedVaultEnabled(directory, env) {
2498
+ const selected = env ?? parseEnv(readFileSync5(join11(directory, ".env"), "utf8"));
2499
+ return selected.SSR_AUTH_ENABLED === "true" && (selected.NUXT_SECRETS_PROVIDER ?? "or3-secrets") === "or3-secrets" && readFileSync5(join11(directory, "compose.yaml"), "utf8").includes(`
2500
+ or3-vault:
2501
+ `);
2502
+ }
2503
+ async function stopProject(directory, mode) {
2504
+ await compose(directory, mode, ["stop", "or3", ...managedVaultEnabled(directory) ? ["or3-vault"] : []]);
2505
+ }
2506
+ async function projectServiceRunning(directory, mode) {
2507
+ const result = await run("docker", composeArgs(directory, mode, ["ps", "--status", "running", "-q", "or3"]), directory);
2508
+ if (!result.ok)
2509
+ throw new Error(`Could not determine whether OR3 is running. ${result.stderr.trim()}`);
2510
+ return Boolean(result.stdout.trim());
2511
+ }
2512
+ async function startProject(directory, mode, env) {
2513
+ await assertSafeComposeBinding(directory, mode, env);
2514
+ const services = process.env.OR3_DASHBOARD_UPDATE_JOB_ID ? ["or3"] : [];
2515
+ await compose(directory, mode, ["up", "-d", "--wait", "--wait-timeout", "180", ...services], secretValues(env));
2516
+ await waitForDeepHealth(directory, mode, secretValues(env));
2517
+ await assertRunningAppImage(directory, mode, env.OR3_IMAGE);
2518
+ }
2519
+
2520
+ // src/backup/config.ts
2521
+ import { createHash as createHash3 } from "node:crypto";
2522
+ import { readFile as readFile4 } from "node:fs/promises";
2523
+ import { join as join12 } from "node:path";
2524
+ async function readAuthenticatedBackupConfig(backupPath, manifest2) {
2525
+ const bytes = await readFile4(join12(backupPath, "config.env"));
2526
+ if (!manifest2.configSha256 || createHash3("sha256").update(bytes).digest("hex") !== manifest2.configSha256) {
2527
+ throw new Error(`Backup configuration checksum mismatch for ${manifest2.backupId}.`);
2528
+ }
2529
+ const text = bytes.toString("utf8");
2530
+ if (!Buffer.from(text, "utf8").equals(bytes))
2531
+ throw new Error("Backup configuration has invalid UTF-8.");
2532
+ return text;
2533
+ }
2534
+ function hasUnambiguousEnvSyntax(text, allowedKeys) {
2535
+ const keys = new Set;
2536
+ for (const source of text.split(/\r?\n/)) {
2537
+ const line = source.trim();
2538
+ if (!line || line.startsWith("#"))
2539
+ continue;
2540
+ const match = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(line);
2541
+ if (!match || keys.has(match[1]) || allowedKeys && !allowedKeys.has(match[1]))
2542
+ return false;
2543
+ keys.add(match[1]);
2544
+ const value = match[2];
2545
+ if (!/^'(?:[^'\\\x00\r\n]|\\['\\])*'$/.test(value) && !/^[A-Za-z0-9._:@%+=/-]*$/.test(value))
2546
+ return false;
2547
+ }
2548
+ return true;
2549
+ }
2550
+
2551
+ // src/backup/vault.ts
2552
+ var LEGACY_IMAGE = "ghcr.io/saluana/or3-chat:0.1.90";
2553
+ var LEGACY_DIGEST = "sha256:d50b70d6522574798f1a3081894b5bf8fe9eca7aa5f183ad5a562de2e4f41c12";
2554
+ var LEGACY_ASSETS = {
2555
+ "compose.yaml": "6f4bdb7901eb997710501ef46c4c837870a830b6b835ea7fcc9a2036f9e51fc8",
2556
+ "compose.public.yaml": "08e7b9a6e64c6d7df526a8a1372815c153765b098cdffe3af9086dd19e00b0d1",
2557
+ Caddyfile: "623bd4a05b89530cff6a88e33cb6bf0b98b0561de6dd734d2d5b187abc1c48dd",
2558
+ "compose.operator.yaml": "36ff63bed54f11b8e46daadd2dab2c5fa4b2fadde1e3d6dbd9bf9f1c37e9de86",
2559
+ "dashboard-operator.mjs": "47dd5d186f4e87edd962d45cdfc274fea4c95533d676e4eddf59bdc59bb51308",
2560
+ "dashboard-lifecycle.mjs": "628b903e290786aca97ef94ef9c0452f396b10edb11f14e620500671981ffbd2"
2561
+ };
2562
+ var LEGACY_OPERATOR_IMAGE = "ghcr.io/saluana/or3-chat@sha256:7148fc08014a0a35c1bd211243c3cf7cecb4b25cce9ec0dac1ecd7e50a61121a";
2563
+ var LEGACY_ENV_KEYS = new Set([
2564
+ "OR3_VERSION",
2565
+ "OR3_IMAGE",
2566
+ "OR3_DEPLOYMENT_ID",
2567
+ "OR3_COMPOSE_PROJECT",
2568
+ "OR3_VOLUME_NAME",
2569
+ "OR3_CADDY_DATA_VOLUME",
2570
+ "OR3_CADDY_CONFIG_VOLUME",
2571
+ "OR3_PORT",
2572
+ "SSR_AUTH_ENABLED",
2573
+ "AUTH_PROVIDER",
2574
+ "OR3_AUTH_PROVIDER",
2575
+ "OR3_AUTH_REGISTRATION_MODE",
2576
+ "OR3_AUTH_AUTO_PROVISION",
2577
+ "OR3_GUEST_ACCESS_ENABLED",
2578
+ "OR3_PLUGIN_ZIP_INSTALL_ENABLED",
2579
+ "OR3_ADMIN_ALLOW_REBUILD",
2580
+ "OR3_BASIC_AUTH_JWT_SECRET",
2581
+ "OR3_BASIC_AUTH_REFRESH_SECRET",
2582
+ "OR3_BASIC_AUTH_ACCESS_TTL_SECONDS",
2583
+ "OR3_BASIC_AUTH_REFRESH_TTL_SECONDS",
2584
+ "OR3_BASIC_AUTH_DB_PATH",
2585
+ "OR3_BASIC_AUTH_BOOTSTRAP_EMAIL",
2586
+ "OR3_BASIC_AUTH_BOOTSTRAP_PASSWORD",
2587
+ "OR3_MANAGED_OWNER_EMAIL",
2588
+ "OR3_AUTH_INVITE_TOKEN_SECRET",
2589
+ "OR3_SYNC_ENABLED",
2590
+ "OR3_CLOUD_SYNC_ENABLED",
2591
+ "OR3_SYNC_PROVIDER",
2592
+ "OR3_SQLITE_DB_PATH",
2593
+ "OR3_SQLITE_PRAGMA_JOURNAL_MODE",
2594
+ "OR3_SQLITE_PRAGMA_SYNCHRONOUS",
2595
+ "OR3_SQLITE_ALLOW_IN_MEMORY",
2596
+ "OR3_SQLITE_STRICT",
2597
+ "OR3_STORAGE_ENABLED",
2598
+ "OR3_CLOUD_STORAGE_ENABLED",
2599
+ "NUXT_PUBLIC_STORAGE_PROVIDER",
2600
+ "OR3_STORAGE_FS_ROOT",
2601
+ "OR3_STORAGE_FS_TOKEN_SECRET",
2602
+ "OR3_STORAGE_FS_URL_TTL_SECONDS",
2603
+ "OR3_ADMIN_USERNAME",
2604
+ "OR3_ADMIN_PASSWORD",
2605
+ "OR3_ADMIN_JWT_SECRET",
2606
+ "OR3_ADMIN_JWT_EXPIRY",
2607
+ "OR3_PUBLIC_DOMAIN",
2608
+ "OR3_ALLOWED_ORIGINS",
2609
+ "OR3_FORCE_HTTPS",
2610
+ "OR3_TRUST_PROXY",
2611
+ "OR3_FORWARDED_FOR_HEADER",
2612
+ "OR3_DASHBOARD_UPDATES_ENABLED",
2613
+ "OR3_OPERATOR_IMAGE",
2614
+ "OR3_DEPLOYMENT_DIR",
2615
+ "OR3_OPERATOR_UID",
2616
+ "OR3_OPERATOR_GID",
2617
+ "OR3_DOCKER_SOCKET",
2618
+ "OR3_DOCKER_GID"
2619
+ ]);
2620
+ var LEGACY_FIXED_PROFILE = {
2621
+ SSR_AUTH_ENABLED: "true",
2622
+ AUTH_PROVIDER: "basic-auth",
2623
+ OR3_AUTH_PROVIDER: "basic-auth",
2624
+ OR3_AUTH_REGISTRATION_MODE: "invite_only",
2625
+ OR3_AUTH_AUTO_PROVISION: "false",
2626
+ OR3_GUEST_ACCESS_ENABLED: "false",
2627
+ OR3_PLUGIN_ZIP_INSTALL_ENABLED: "false",
2628
+ OR3_ADMIN_ALLOW_REBUILD: "false",
2629
+ OR3_BASIC_AUTH_DB_PATH: "/data/auth.sqlite",
2630
+ OR3_SYNC_ENABLED: "true",
2631
+ OR3_CLOUD_SYNC_ENABLED: "true",
2632
+ OR3_SYNC_PROVIDER: "sqlite",
2633
+ OR3_SQLITE_DB_PATH: "/data/sync.sqlite",
2634
+ OR3_STORAGE_ENABLED: "true",
2635
+ OR3_CLOUD_STORAGE_ENABLED: "true",
2636
+ NUXT_PUBLIC_STORAGE_PROVIDER: "fs",
2637
+ OR3_STORAGE_FS_ROOT: "/data/storage"
2638
+ };
2412
2639
  async function readAuthenticatedVaultId(path, expectedSha256) {
2413
2640
  if (!/^[a-f0-9]{64}$/.test(expectedSha256))
2414
2641
  throw new Error("Invalid vault backup checksum.");
@@ -2419,7 +2646,7 @@ async function readAuthenticatedVaultId(path, expectedSha256) {
2419
2646
  const pathInfo = await lstat2(path, { bigint: true });
2420
2647
  if (!before.isFile() || !pathInfo.isFile() || pathInfo.isSymbolicLink() || before.nlink !== 1n || before.size < 113n || before.size > BigInt(2 ** 30 + 112) || identity(before) !== identity(pathInfo))
2421
2648
  throw new Error("invalid vault backup");
2422
- const hash = createHash2("sha256"), buffer = Buffer.alloc(1024 * 1024), header = Buffer.alloc(96);
2649
+ const hash = createHash4("sha256"), buffer = Buffer.alloc(1024 * 1024), header = Buffer.alloc(96);
2423
2650
  let offset = 0;
2424
2651
  while (offset < Number(before.size)) {
2425
2652
  const count = (await file.read(buffer, 0, Math.min(buffer.length, Number(before.size) - offset), offset)).bytesRead;
@@ -2442,22 +2669,31 @@ async function readAuthenticatedVaultId(path, expectedSha256) {
2442
2669
  await file.close();
2443
2670
  }
2444
2671
  }
2445
- function backupHasVaultCoverage(manifest2, env, archivedConfig) {
2672
+ async function backupHasVaultCoverage(manifest2, archivedConfig, backupPath) {
2673
+ if (!manifest2.configSha256 || createHash4("sha256").update(archivedConfig).digest("hex") !== manifest2.configSha256)
2674
+ return false;
2675
+ const env = parseEnv(archivedConfig);
2446
2676
  if (Object.keys(env).some((key) => /^(?:RUNTIME_CONFIG|NUXT_SECRETS|NITRO_ENV_(?:PREFIX|EXPANSION)|NITRO_SECRETS(?:_.*)?)$/.test(key)))
2447
2677
  return false;
2448
2678
  const provider = env.NUXT_SECRETS_PROVIDER;
2449
- if (provider === undefined && manifest2.appVersion === "0.1.90" && manifest2.image === "ghcr.io/saluana/or3-chat:0.1.90" && manifest2.imageDigest === "sha256:d50b70d6522574798f1a3081894b5bf8fe9eca7aa5f183ad5a562de2e4f41c12" && archivedConfig !== undefined && createHash2("sha256").update(archivedConfig).digest("hex") === manifest2.configSha256) {
2450
- const keys = new Set;
2451
- for (const line of archivedConfig.split(/\r?\n/)) {
2452
- const text = line.trim();
2453
- if (!text || text.startsWith("#"))
2454
- continue;
2455
- const match = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(text);
2456
- if (!match || keys.has(match[1]) || !/^(?:'[^'\r\n]*'|"[^"$\\\r\n]*"|[^'"$\\\s]*)$/.test(match[2]))
2679
+ if (!manifest2.vaultSha256 && (!hasUnambiguousEnvSyntax(archivedConfig) || Object.keys(env).some((key) => /^(?:NUXT_SECRETS_(?!PROVIDER$)|OR3_MANAGED_VAULT(?:_|$)|NODE_|BUN_|LD_|DYLD_|PATH$)/.test(key))))
2680
+ return false;
2681
+ if (provider === undefined && manifest2.appVersion === "0.1.90" && manifest2.image === LEGACY_IMAGE && manifest2.imageDigest === LEGACY_DIGEST && !manifest2.vaultSha256) {
2682
+ if (!["local", "public"].includes(manifest2.mode) || env.OR3_VERSION !== manifest2.appVersion || env.OR3_IMAGE !== manifest2.image || !hasUnambiguousEnvSyntax(archivedConfig, LEGACY_ENV_KEYS) || Object.entries(LEGACY_FIXED_PROFILE).some(([key, value]) => env[key] !== value) || env.OR3_FORCE_HTTPS !== (manifest2.mode === "public" ? "true" : "false") || env.OR3_TRUST_PROXY !== (manifest2.mode === "public" ? "true" : "false") || env.OR3_DASHBOARD_UPDATES_ENABLED !== undefined && !["true", "false"].includes(env.OR3_DASHBOARD_UPDATES_ENABLED))
2683
+ return false;
2684
+ const names = ["compose.yaml", ...manifest2.mode === "public" ? ["compose.public.yaml", "Caddyfile"] : []];
2685
+ if (env.OR3_DASHBOARD_UPDATES_ENABLED === "true") {
2686
+ if (env.OR3_OPERATOR_IMAGE !== LEGACY_OPERATOR_IMAGE)
2457
2687
  return false;
2458
- keys.add(match[1]);
2688
+ names.push("compose.operator.yaml", "dashboard-operator.mjs", "dashboard-lifecycle.mjs");
2459
2689
  }
2460
- return !keys.has("NUXT_SECRETS_PROVIDER");
2690
+ if (names.some((name) => manifest2.managedAssetSha256?.[name] !== LEGACY_ASSETS[name]))
2691
+ return false;
2692
+ const assets = await verifiedManagedAssetContents(backupPath, manifest2);
2693
+ return names.every((name) => {
2694
+ const bytes = assets?.get(name);
2695
+ return bytes !== undefined && createHash4("sha256").update(bytes).digest("hex") === LEGACY_ASSETS[name];
2696
+ });
2461
2697
  }
2462
2698
  return provider === "" || (provider === undefined || provider === "or3-secrets") && Boolean(manifest2.vaultSha256);
2463
2699
  }
@@ -2470,13 +2706,15 @@ async function assertVaultVolumesExist(directory, state) {
2470
2706
  throw new Error("Vault custody is missing or cannot be inspected. The operation is refused; preserve the encrypted backup and recover the vault key and volumes first.");
2471
2707
  }
2472
2708
  }
2473
- async function assertExistingVaultCustody(directory, state, manifest2, backupPath, backupEnv) {
2474
- const archivedConfig = await readFile4(join11(backupPath, "config.env"), "utf8");
2475
- if (!backupHasVaultCoverage(manifest2, backupEnv, archivedConfig))
2709
+ async function assertExistingVaultCustody(directory, state, manifest2, backupPath, archivedConfig) {
2710
+ if (!await backupHasVaultCoverage(manifest2, archivedConfig, backupPath))
2476
2711
  throw new Error("Backup lacks the vault archive required by its saved configuration. Preserve it and use a separately reviewed recovery procedure.");
2477
- if (!manifest2.vaultSha256)
2712
+ if (!manifest2.vaultSha256) {
2713
+ if (managedVaultEnabled(directory))
2714
+ await assertVaultVolumesExist(directory, state);
2478
2715
  return;
2479
- const expectedVaultId = await readAuthenticatedVaultId(join11(backupPath, "vault.backup"), manifest2.vaultSha256);
2716
+ }
2717
+ const expectedVaultId = await readAuthenticatedVaultId(join13(backupPath, "vault.backup"), manifest2.vaultSha256);
2480
2718
  const dataVolume = `${state.volumeName}-vault-data`;
2481
2719
  const keyVolume = `${state.volumeName}-vault-key`;
2482
2720
  await assertVaultVolumesExist(directory, state);
@@ -2621,14 +2859,14 @@ function backupAuthenticationTag(key, manifestContents) {
2621
2859
  }
2622
2860
  async function writeBackupAuthentication(directory, backupPath, manifestContents) {
2623
2861
  const key = await backupAuthenticationKey(directory, true);
2624
- await writeSecure(join12(backupPath, "manifest.auth"), `${backupAuthenticationTag(key, manifestContents)}
2862
+ await writeSecure(join14(backupPath, "manifest.auth"), `${backupAuthenticationTag(key, manifestContents)}
2625
2863
  `);
2626
2864
  }
2627
2865
  async function assertBackupAuthentication(directory, backupPath, manifestContents) {
2628
2866
  const key = await backupAuthenticationKey(directory);
2629
2867
  let provided;
2630
2868
  try {
2631
- const value = (await readText(join12(backupPath, "manifest.auth"))).trim();
2869
+ const value = (await readText(join14(backupPath, "manifest.auth"))).trim();
2632
2870
  if (!/^[0-9a-f]{64}$/i.test(value))
2633
2871
  throw new Error("invalid authentication tag");
2634
2872
  provided = Buffer.from(value, "hex");
@@ -2657,7 +2895,7 @@ function classifyBackupError(error) {
2657
2895
  return { code: "backup-entry-invalid", message };
2658
2896
  }
2659
2897
  async function inspectBackupEntry(backupsRoot, entry, directory) {
2660
- const path = join12(backupsRoot, entry);
2898
+ const path = join14(backupsRoot, entry);
2661
2899
  let info;
2662
2900
  try {
2663
2901
  info = await lstat3(path);
@@ -2689,7 +2927,7 @@ async function inspectBackupEntry(backupsRoot, entry, directory) {
2689
2927
  };
2690
2928
  }
2691
2929
  try {
2692
- await lstat3(join12(path, "manifest.auth"));
2930
+ await lstat3(join14(path, "manifest.auth"));
2693
2931
  } catch (error) {
2694
2932
  if (error.code === "ENOENT") {
2695
2933
  return {
@@ -2702,7 +2940,7 @@ async function inspectBackupEntry(backupsRoot, entry, directory) {
2702
2940
  return { kind: "unreadable", entryName: entry, ...classifyBackupError(error) };
2703
2941
  }
2704
2942
  try {
2705
- const raw = JSON.parse(await readText(join12(path, "manifest.json")));
2943
+ const raw = JSON.parse(await readText(join14(path, "manifest.json")));
2706
2944
  if (typeof raw.schemaVersion === "number" && raw.schemaVersion > 2) {
2707
2945
  return {
2708
2946
  kind: "unsupported",
@@ -2734,12 +2972,10 @@ async function inspectBackupEntry(backupsRoot, entry, directory) {
2734
2972
  }
2735
2973
  let bytes = 0;
2736
2974
  for (const file of ["data.tgz", "config.env", "manifest.json", "manifest.auth", ...manifest2.vaultSha256 ? ["vault.backup"] : [], ...manifest2.schemaVersion === 2 ? [manifest2.remote.file] : []]) {
2737
- bytes += (await lstat3(join12(path, file))).size;
2975
+ bytes += (await lstat3(join14(path, file))).size;
2738
2976
  }
2739
- const savedConfig = await readText(join12(path, "config.env"));
2740
- if (createHash3("sha256").update(savedConfig).digest("hex") !== manifest2.configSha256)
2741
- throw new Error(`Backup configuration changed during inventory for ${manifest2.backupId}.`);
2742
- const recoveryArtifactsComplete = Boolean(manifest2.managedAssetSha256) && backupHasVaultCoverage(manifest2, parseEnv(savedConfig), savedConfig);
2977
+ const savedConfig = await readAuthenticatedBackupConfig(path, manifest2);
2978
+ const recoveryArtifactsComplete = Boolean(manifest2.managedAssetSha256) && await backupHasVaultCoverage(manifest2, savedConfig, path);
2743
2979
  return {
2744
2980
  kind: "verified",
2745
2981
  backup: {
@@ -2849,7 +3085,7 @@ function assertBackupMatchesDeployment(manifest2, backupEnv, state, env) {
2849
3085
  }
2850
3086
  async function readManifest(backupPath, authenticatedForDirectory) {
2851
3087
  await lifecycleFaults.beforeArchiveRead?.();
2852
- const manifestContents = await readText(join12(backupPath, "manifest.json"));
3088
+ const manifestContents = await readText(join14(backupPath, "manifest.json"));
2853
3089
  if (authenticatedForDirectory)
2854
3090
  await assertBackupAuthentication(authenticatedForDirectory, backupPath, manifestContents);
2855
3091
  const manifest2 = JSON.parse(manifestContents);
@@ -2857,15 +3093,10 @@ async function readManifest(backupPath, authenticatedForDirectory) {
2857
3093
  if (unvalidated.schemaVersion !== 1 && unvalidated.schemaVersion !== 2 || !BACKUP_ID_PATTERN.test(manifest2.backupId) || unvalidated.snapshotKind !== undefined && unvalidated.snapshotKind !== "full" && unvalidated.snapshotKind !== "safety" || !Number.isFinite(Date.parse(manifest2.createdAt)) || !isVersion(manifest2.appVersion) || !manifest2.image || !/^sha256:[0-9a-f]{64}$/i.test(manifest2.imageDigest) || !/^[0-9a-f]{64}$/i.test(manifest2.dataSha256) || !/^[0-9a-f]{64}$/i.test(manifest2.configSha256 ?? "") || manifest2.vaultSha256 !== undefined && !/^[0-9a-f]{64}$/i.test(manifest2.vaultSha256) || manifest2.dataBytes !== undefined && (!Number.isSafeInteger(manifest2.dataBytes) || manifest2.dataBytes < 0)) {
2858
3094
  throw new Error(`Invalid backup manifest at ${backupPath}.`);
2859
3095
  }
2860
- const actual = await sha256File(join12(backupPath, "data.tgz"));
3096
+ const actual = await sha256File(join14(backupPath, "data.tgz"));
2861
3097
  if (actual !== manifest2.dataSha256)
2862
3098
  throw new Error(`Backup checksum mismatch for ${manifest2.backupId}. Expected ${manifest2.dataSha256}, got ${actual}.`);
2863
- if (manifest2.configSha256) {
2864
- const configActual = await sha256File(join12(backupPath, "config.env"));
2865
- if (configActual !== manifest2.configSha256)
2866
- throw new Error(`Backup configuration checksum mismatch for ${manifest2.backupId}.`);
2867
- }
2868
- const config = parseEnv(await readText(join12(backupPath, "config.env")));
3099
+ const config = parseEnv(await readAuthenticatedBackupConfig(backupPath, manifest2));
2869
3100
  const storage = (config.NUXT_PUBLIC_STORAGE_PROVIDER ?? "").trim().toLowerCase();
2870
3101
  if (manifest2.schemaVersion === 1 && storage === "s3") {
2871
3102
  throw new Error(`Invalid backup manifest for ${manifest2.backupId}: schema-1 S3 snapshots do not contain recoverable remote objects.`);
@@ -2879,13 +3110,13 @@ async function readManifest(backupPath, authenticatedForDirectory) {
2879
3110
  if (!remote.source || remote.source.endpointOrigin !== source.endpointOrigin || remote.source.bucket !== source.bucket || remote.source.keyPrefix !== source.keyPrefix) {
2880
3111
  throw new Error(`Invalid backup manifest for ${manifest2.backupId}: S3 source differs from the authenticated configuration.`);
2881
3112
  }
2882
- const file = join12(backupPath, remote.file);
3113
+ const file = join14(backupPath, remote.file);
2883
3114
  const info = await lstat3(file);
2884
3115
  if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1 || info.size !== remote.bytes || await sha256File(file) !== remote.sha256) {
2885
3116
  throw new Error(`Backup remote checksum mismatch or size mismatch for ${manifest2.backupId}.`);
2886
3117
  }
2887
3118
  }
2888
- if (manifest2.vaultSha256 && await sha256File(join12(backupPath, "vault.backup")) !== manifest2.vaultSha256)
3119
+ if (manifest2.vaultSha256 && await sha256File(join14(backupPath, "vault.backup")) !== manifest2.vaultSha256)
2889
3120
  throw new Error(`Vault backup checksum mismatch for ${manifest2.backupId}.`);
2890
3121
  await verifiedManagedAssetContents(backupPath, manifest2);
2891
3122
  return manifest2;
@@ -2895,7 +3126,7 @@ async function resolveBackup(directory, value) {
2895
3126
  throw new Error(`Backup ID "${value}" is invalid. Use an OR3-generated backup ID or an absolute external backup path.`);
2896
3127
  }
2897
3128
  const candidate = isAbsolute3(value) ? value : backupDirectory(directory, value);
2898
- if (!await fileExists(join12(candidate, "manifest.json")))
3129
+ if (!await fileExists(join14(candidate, "manifest.json")))
2899
3130
  throw new Error(`Backup ${value} was not found in ${deploymentPaths(directory).backups}.`);
2900
3131
  return resolve4(candidate);
2901
3132
  }
@@ -2904,7 +3135,7 @@ async function recordedBackupPath(directory, pending) {
2904
3135
  const path = previous ? pending.previousBackupPath : pending.backupPath;
2905
3136
  const backupId = previous ? pending.previousBackupId : pending.backupId;
2906
3137
  const resolved = path ? resolve4(path) : backupId ? await resolveBackup(directory, backupId) : undefined;
2907
- if (!resolved || !await fileExists(join12(resolved, "manifest.json"))) {
3138
+ if (!resolved || !await fileExists(join14(resolved, "manifest.json"))) {
2908
3139
  throw new Error(`The incomplete ${pending.operation} has no readable ${previous ? "pre-mutation" : "target"} backup source.`);
2909
3140
  }
2910
3141
  const manifest2 = await readManifest(resolved, directory);
@@ -3046,87 +3277,7 @@ async function maskedQuestion(question) {
3046
3277
 
3047
3278
  // src/deployment/adoption-source.ts
3048
3279
  import { existsSync as existsSync2 } from "node:fs";
3049
- import { basename as basename2, join as join13 } from "node:path";
3050
-
3051
- // src/runtime/health.ts
3052
- var DEEP_HEALTH_TIMEOUT_MS = 180000;
3053
- var HEALTH_SCRIPT = "const fs=require('node:fs');try{const auth=process.env.AUTH_PROVIDER||process.env.OR3_AUTH_PROVIDER||'basic-auth',storage=process.env.NUXT_PUBLIC_STORAGE_PROVIDER||'fs',sync=process.env.OR3_SYNC_PROVIDER||'sqlite';if(sync!=='sqlite'||!(auth==='basic-auth'&&storage==='fs'||auth==='clerk'&&storage==='s3')||process.env.AUTH_PROVIDER&&process.env.OR3_AUTH_PROVIDER&&process.env.AUTH_PROVIDER!==process.env.OR3_AUTH_PROVIDER)throw Error('profile');fs.accessSync('/data',fs.constants.R_OK|fs.constants.W_OK);const paths=auth==='basic-auth'?[process.env.OR3_BASIC_AUTH_DB_PATH,process.env.OR3_SQLITE_DB_PATH]:[process.env.OR3_SQLITE_DB_PATH];if(paths.some(p=>!p))throw Error('database path');for(const path of paths){const fd=fs.openSync(path,'r+');fs.closeSync(fd)}}catch{process.exit(1)}fetch('http://127.0.0.1:3000/api/health?deep=true').then(async response=>{const body=await response.json().catch(()=>({}));if(!response.ok||body.status!=='ok'||body.providers?.auth?.provider!==(process.env.AUTH_PROVIDER||process.env.OR3_AUTH_PROVIDER||'basic-auth')||body.providers?.sync?.provider!=='sqlite'||body.providers?.storage?.provider!==(process.env.NUXT_PUBLIC_STORAGE_PROVIDER||'fs'))process.exit(1)}).catch(()=>process.exit(1))";
3054
- var VERIFY_DATABASES_SCRIPT = `
3055
- const fs = require('node:fs');
3056
- const Database = require('/app/.output/server/node_modules/better-sqlite3');
3057
- const results = [];
3058
- const auth = process.env.AUTH_PROVIDER || process.env.OR3_AUTH_PROVIDER || 'basic-auth';
3059
- const storage = process.env.NUXT_PUBLIC_STORAGE_PROVIDER || 'fs', sync = process.env.OR3_SYNC_PROVIDER || 'sqlite';
3060
- if (sync !== 'sqlite' || !(auth === 'basic-auth' && storage === 'fs' || auth === 'clerk' && storage === 's3') || process.env.AUTH_PROVIDER && process.env.OR3_AUTH_PROVIDER && process.env.AUTH_PROVIDER !== process.env.OR3_AUTH_PROVIDER) throw new Error('Unsupported auth profile');
3061
- const paths = auth === 'basic-auth' ? [process.env.OR3_BASIC_AUTH_DB_PATH, process.env.OR3_SQLITE_DB_PATH] : [process.env.OR3_SQLITE_DB_PATH];
3062
- if (paths.some(path => !path)) throw new Error('Missing managed database path');
3063
- for (const path of paths) {
3064
- const info = fs.statSync(path);
3065
- if (info.uid !== 65532 || info.gid !== 65532) throw new Error(path + ' must be owned by 65532:65532');
3066
- const db = new Database(path, { readonly: true, fileMustExist: true });
3067
- const quickCheck = db.pragma('quick_check', { simple: true });
3068
- const tables = db.prepare("select count(*) as count from sqlite_master where type = 'table'").get().count;
3069
- db.close();
3070
- if (quickCheck !== 'ok') throw new Error(path + ' quick_check failed: ' + quickCheck);
3071
- results.push({ path, quickCheck, tables });
3072
- }
3073
- if (process.env.OR3_FORCE_HTTPS === 'true' && process.env.NUXT_SECURITY_PROXY_TRUST_PROXY !== 'true') {
3074
- throw new Error('NUXT_SECURITY_PROXY_TRUST_PROXY must be true for a managed public deployment');
3075
- }
3076
- console.log(JSON.stringify(results));
3077
- `;
3078
- var CONTAINER_NODE = "/nodejs/bin/node";
3079
- var LEGACY_CONTAINER_NODE = "/usr/local/bin/node";
3080
- var CONTAINER_NODE_SHELL = `if [ -x ${CONTAINER_NODE} ]; then exec ${CONTAINER_NODE} -e "$1"; elif [ -x ${LEGACY_CONTAINER_NODE} ]; then exec ${LEGACY_CONTAINER_NODE} -e "$1"; else exit 127; fi`;
3081
- function containerNodeCommand(script) {
3082
- return ["sh", "-c", CONTAINER_NODE_SHELL, "or3-node", script];
3083
- }
3084
- async function waitForDeepHealthWithArgs(composeCommand, directory, secrets = []) {
3085
- const startedAt = Date.now();
3086
- const deadline = startedAt + DEEP_HEALTH_TIMEOUT_MS;
3087
- let lastError = "health check did not complete";
3088
- let lastProgressAt = startedAt;
3089
- while (Date.now() < deadline) {
3090
- const result = await run("docker", [
3091
- ...composeCommand,
3092
- "exec",
3093
- "-T",
3094
- "or3",
3095
- ...containerNodeCommand(HEALTH_SCRIPT)
3096
- ], directory);
3097
- if (result.ok)
3098
- return;
3099
- lastError = redact(result.stderr, secrets);
3100
- if (Date.now() - lastProgressAt >= 15000) {
3101
- console.error(`Waiting for OR3 deep health (${Math.round((Date.now() - startedAt) / 1000)}s elapsed)…`);
3102
- lastProgressAt = Date.now();
3103
- }
3104
- await new Promise((resolvePromise) => setTimeout(resolvePromise, 1000));
3105
- }
3106
- throw new Error(`OR3 deep health did not pass within ${DEEP_HEALTH_TIMEOUT_MS / 1000} seconds. Last error: ${lastError}`);
3107
- }
3108
- async function waitForDeepHealth(directory, mode, secrets = []) {
3109
- try {
3110
- await waitForDeepHealthWithArgs(composeArgs(directory, mode), directory, secrets);
3111
- } catch (error) {
3112
- const captured = await captureComposeDiagnostics(directory, mode, secrets).catch((captureError) => redact(`Diagnostics capture failed: ${captureError instanceof Error ? captureError.message : String(captureError)}`, secrets));
3113
- throw new Error(`${error instanceof Error ? error.message : String(error)}
3114
- Captured Docker diagnostics:
3115
- ${captured}
3116
- Diagnostics: ${diagnostics(directory, mode)}`);
3117
- }
3118
- }
3119
- async function probeDeepHealth(directory, mode) {
3120
- const result = await run("docker", [...composeArgs(directory, mode, ["exec", "-T", "or3", ...containerNodeCommand(HEALTH_SCRIPT)])], directory);
3121
- if (result.ok)
3122
- return "ok";
3123
- const ps = await run("docker", [...composeArgs(directory, mode, ["ps", "-q", "or3"])], directory);
3124
- if (ps.ok && ps.stdout.trim())
3125
- return "degraded";
3126
- return "unreachable";
3127
- }
3128
-
3129
- // src/deployment/adoption-source.ts
3280
+ import { basename as basename2, join as join15 } from "node:path";
3130
3281
  async function sourceServiceRunning(directory, composeFiles) {
3131
3282
  const result = await run("docker", [...sourceComposeArgs(directory, composeFiles), "ps", "--status", "running", "-q", "or3"], directory);
3132
3283
  if (!result.ok)
@@ -3236,9 +3387,9 @@ async function readSourceVolume(sourceDirectory) {
3236
3387
  "--project-directory",
3237
3388
  sourceDirectory,
3238
3389
  "--env-file",
3239
- join13(sourceDirectory, ".env"),
3390
+ join15(sourceDirectory, ".env"),
3240
3391
  "-f",
3241
- join13(sourceDirectory, "compose.yaml"),
3392
+ join15(sourceDirectory, "compose.yaml"),
3242
3393
  "ps",
3243
3394
  "-aq",
3244
3395
  "or3"
@@ -3259,7 +3410,7 @@ async function readSourceVolume(sourceDirectory) {
3259
3410
  }
3260
3411
  function sourceMode(sourceDirectory, sourceEnv) {
3261
3412
  const publicDeployment = sourceEnv.OR3_PUBLIC_DOMAIN && sourceEnv.OR3_PUBLIC_DOMAIN !== "localhost" && sourceEnv.OR3_FORCE_HTTPS !== "false";
3262
- return publicDeployment && existsSync2(join13(sourceDirectory, "compose.public.yaml")) ? "public" : "local";
3413
+ return publicDeployment && existsSync2(join15(sourceDirectory, "compose.public.yaml")) ? "public" : "local";
3263
3414
  }
3264
3415
  function sourceComposeArgs(sourceDirectory, sourceComposeFiles) {
3265
3416
  return [
@@ -3267,7 +3418,7 @@ function sourceComposeArgs(sourceDirectory, sourceComposeFiles) {
3267
3418
  "--project-directory",
3268
3419
  sourceDirectory,
3269
3420
  "--env-file",
3270
- join13(sourceDirectory, ".env"),
3421
+ join15(sourceDirectory, ".env"),
3271
3422
  ...sourceComposeFiles
3272
3423
  ];
3273
3424
  }
@@ -3414,7 +3565,7 @@ function assertSupportedSourceCompose(configText, sourceVolume, expectedPort, so
3414
3565
  // src/runtime/dashboard-operator.ts
3415
3566
  import { randomBytes as randomBytes6 } from "node:crypto";
3416
3567
  import { chmod as chmod4, mkdir as mkdir4, rm as rm5, stat as stat3 } from "node:fs/promises";
3417
- import { isAbsolute as isAbsolute4, join as join14, resolve as resolve6 } from "node:path";
3568
+ import { isAbsolute as isAbsolute4, join as join16, resolve as resolve6 } from "node:path";
3418
3569
 
3419
3570
  // src/runtime/images.ts
3420
3571
  async function pullImage(image, expectedDigest2) {
@@ -3679,7 +3830,7 @@ function dashboardOperatorHandoffArgs(directory, env, jobId) {
3679
3830
  "--entrypoint",
3680
3831
  "/usr/local/bin/node",
3681
3832
  env.OR3_OPERATOR_IMAGE,
3682
- join14(directory, "dashboard-operator.mjs"),
3833
+ join16(directory, "dashboard-operator.mjs"),
3683
3834
  "--complete-handoff",
3684
3835
  jobId,
3685
3836
  project
@@ -3763,34 +3914,8 @@ async function checkPublicPrerequisites(domain) {
3763
3914
  return address;
3764
3915
  }
3765
3916
 
3766
- // src/runtime/project.ts
3767
- import { readFileSync as readFileSync5 } from "node:fs";
3768
- import { join as join15 } from "node:path";
3769
- function managedVaultEnabled(directory, env) {
3770
- const selected = env ?? parseEnv(readFileSync5(join15(directory, ".env"), "utf8"));
3771
- return selected.SSR_AUTH_ENABLED === "true" && (selected.NUXT_SECRETS_PROVIDER ?? "or3-secrets") === "or3-secrets" && readFileSync5(join15(directory, "compose.yaml"), "utf8").includes(`
3772
- or3-vault:
3773
- `);
3774
- }
3775
- async function stopProject(directory, mode) {
3776
- await compose(directory, mode, ["stop", "or3", ...managedVaultEnabled(directory) ? ["or3-vault"] : []]);
3777
- }
3778
- async function projectServiceRunning(directory, mode) {
3779
- const result = await run("docker", composeArgs(directory, mode, ["ps", "--status", "running", "-q", "or3"]), directory);
3780
- if (!result.ok)
3781
- throw new Error(`Could not determine whether OR3 is running. ${result.stderr.trim()}`);
3782
- return Boolean(result.stdout.trim());
3783
- }
3784
- async function startProject(directory, mode, env) {
3785
- await assertSafeComposeBinding(directory, mode, env);
3786
- const services = process.env.OR3_DASHBOARD_UPDATE_JOB_ID ? ["or3"] : [];
3787
- await compose(directory, mode, ["up", "-d", "--wait", "--wait-timeout", "180", ...services], secretValues(env));
3788
- await waitForDeepHealth(directory, mode, secretValues(env));
3789
- await assertRunningAppImage(directory, mode, env.OR3_IMAGE);
3790
- }
3791
-
3792
3917
  // src/runtime/verification.ts
3793
- import { createHash as createHash4, randomBytes as randomBytes7, randomUUID as randomUUID4 } from "node:crypto";
3918
+ import { createHash as createHash5, randomBytes as randomBytes7, randomUUID as randomUUID4 } from "node:crypto";
3794
3919
  function validateVerificationHealth(value, profile = "basic-sqlite-fs") {
3795
3920
  const health = value;
3796
3921
  if (!health || health.status !== "ok" || health.providers?.auth?.provider !== (profile === "basic-sqlite-fs" ? "basic-auth" : "clerk") || health.providers.sync?.provider !== "sqlite" || health.providers.storage?.provider !== (profile === "basic-sqlite-fs" ? "fs" : "s3")) {
@@ -3889,7 +4014,7 @@ async function verifyPublicApplication(baseUrl, credentials) {
3889
4014
  Buffer.from("89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c489", "hex"),
3890
4015
  randomBytes7(8)
3891
4016
  ]);
3892
- const hash = `sha256:${createHash4("sha256").update(probeBytes).digest("hex")}`;
4017
+ const hash = `sha256:${createHash5("sha256").update(probeBytes).digest("hex")}`;
3893
4018
  let storageId;
3894
4019
  let metadataAttempted = false;
3895
4020
  let physicalCleanupDeferred = false;
@@ -4081,31 +4206,31 @@ async function adoptCommand(positionals, flags) {
4081
4206
  if (targetDirectory === sourceDirectory)
4082
4207
  throw new Error("Choose a separate target directory for adoption.");
4083
4208
  await readDirectoryEmpty(targetDirectory);
4084
- if (!await fileExists(join16(sourceDirectory, "or3-release.json")))
4209
+ if (!await fileExists(join17(sourceDirectory, "or3-release.json")))
4085
4210
  throw new Error(`V1 release metadata is missing at ${sourceDirectory}/or3-release.json.`);
4086
- const release = JSON.parse(await readText(join16(sourceDirectory, "or3-release.json")));
4211
+ const release = JSON.parse(await readText(join17(sourceDirectory, "or3-release.json")));
4087
4212
  if (!release.or3Version || !isVersion(release.or3Version))
4088
4213
  throw new Error("V1 release metadata does not contain a usable OR3 version.");
4089
4214
  if (release.or3Version !== PACKAGE_VERSION) {
4090
4215
  throw new Error(`V1 is on OR3 ${release.or3Version}, but this CLI ships managed assets for ${PACKAGE_VERSION}. Run the matching @or3/cloud version or perform a qualified host CLI update before adoption.`);
4091
4216
  }
4092
- const sourceEnv = parseEnv(await readText(join16(sourceDirectory, ".env")));
4093
- const providers = await readText(join16(sourceDirectory, "or3.providers.generated.ts"));
4217
+ const sourceEnv = parseEnv(await readText(join17(sourceDirectory, ".env")));
4218
+ const providers = await readText(join17(sourceDirectory, "or3.providers.generated.ts"));
4094
4219
  assertSupportedSource(sourceDirectory, sourceEnv, providers);
4095
4220
  const mode = sourceMode(sourceDirectory, sourceEnv);
4096
4221
  const domain = mode === "public" ? sourceEnv.OR3_PUBLIC_DOMAIN : undefined;
4097
4222
  if (domain)
4098
4223
  await checkPublicPrerequisites(domain);
4099
- const sourceComposeFiles = ["-f", join16(sourceDirectory, "compose.yaml")];
4224
+ const sourceComposeFiles = ["-f", join17(sourceDirectory, "compose.yaml")];
4100
4225
  if (mode === "public")
4101
- sourceComposeFiles.push("-f", join16(sourceDirectory, "compose.public.yaml"));
4226
+ sourceComposeFiles.push("-f", join17(sourceDirectory, "compose.public.yaml"));
4102
4227
  await ensureDocker();
4103
4228
  const sourceConfig = await run("docker", [
4104
4229
  "compose",
4105
4230
  "--project-directory",
4106
4231
  sourceDirectory,
4107
4232
  "--env-file",
4108
- join16(sourceDirectory, ".env"),
4233
+ join17(sourceDirectory, ".env"),
4109
4234
  ...sourceComposeFiles,
4110
4235
  "config",
4111
4236
  "--format",
@@ -4193,7 +4318,7 @@ ${existing.stderr}`)) {
4193
4318
  OR3_GUEST_ACCESS_ENABLED: "false"
4194
4319
  });
4195
4320
  await writeSecure(deploymentPaths(targetDirectory).env, serializeEnv(targetEnv));
4196
- await writeSecure(join16(targetDirectory, ".or3-initial-credentials"), serializeInitialCredentials({
4321
+ await writeSecure(join17(targetDirectory, ".or3-initial-credentials"), serializeInitialCredentials({
4197
4322
  bootstrapEmail: email,
4198
4323
  bootstrapPassword: password,
4199
4324
  adminUsername: targetEnv.OR3_ADMIN_USERNAME,
@@ -4230,7 +4355,7 @@ ${existing.stderr}`)) {
4230
4355
  }
4231
4356
  }
4232
4357
  await mkdir5(sourceBackupDir, { recursive: true, mode: 448 });
4233
- await copySecure(join16(sourceDirectory, ".env"), join16(sourceBackupDir, "config.env"));
4358
+ await copySecure(join17(sourceDirectory, ".env"), join17(sourceBackupDir, "config.env"));
4234
4359
  await archiveExternalVolume(sourceImage, sourceVolume, sourceBackupDir);
4235
4360
  const sourceManifest = {
4236
4361
  schemaVersion: 1,
@@ -4239,8 +4364,8 @@ ${existing.stderr}`)) {
4239
4364
  appVersion: release.or3Version,
4240
4365
  image,
4241
4366
  imageDigest: digest,
4242
- dataSha256: await sha256File(join16(sourceBackupDir, "data.tgz")),
4243
- configSha256: await sha256File(join16(sourceBackupDir, "config.env")),
4367
+ dataSha256: await sha256File(join17(sourceBackupDir, "data.tgz")),
4368
+ configSha256: await sha256File(join17(sourceBackupDir, "config.env")),
4244
4369
  mode,
4245
4370
  domain,
4246
4371
  composeProject: sourceEnv.OR3_COMPOSE_PROJECT ?? sanitizeName(basename3(sourceDirectory)),
@@ -4251,7 +4376,7 @@ ${existing.stderr}`)) {
4251
4376
  };
4252
4377
  const sourceManifestContents = `${JSON.stringify(sourceManifest, null, 2)}
4253
4378
  `;
4254
- await writeSecure(join16(sourceBackupDir, "manifest.json"), sourceManifestContents);
4379
+ await writeSecure(join17(sourceBackupDir, "manifest.json"), sourceManifestContents);
4255
4380
  await writeBackupAuthentication(targetDirectory, sourceBackupDir, sourceManifestContents);
4256
4381
  await readManifest(sourceBackupDir, targetDirectory);
4257
4382
  await updatePending(targetDirectory, state, { phase: "snapshot-created" });
@@ -4291,10 +4416,10 @@ ${recoveryDetail}Managed files remain at ${targetDirectory}.${sourceBackupDir ?
4291
4416
 
4292
4417
  // src/backup/create.ts
4293
4418
  import { chmod as chmod6, lstat as lstat4, mkdir as mkdir6 } from "node:fs/promises";
4294
- import { join as join19, resolve as resolve10 } from "node:path";
4419
+ import { join as join20, resolve as resolve10 } from "node:path";
4295
4420
 
4296
4421
  // src/backup/references.ts
4297
- import { join as join17, resolve as resolve8 } from "node:path";
4422
+ import { join as join18, resolve as resolve8 } from "node:path";
4298
4423
  var INSPECTOR3 = "/app/scripts/docker/backup-inspect.mjs";
4299
4424
  var NODE3 = 'if [ -x /nodejs/bin/node ]; then exec /nodejs/bin/node "$@"; else exec node "$@"; fi';
4300
4425
  function assertBackupOperatorMount(directory, enabled, composeMounts, actualMounts) {
@@ -4564,7 +4689,7 @@ async function assertBackupSourceProfile(directory, state, env) {
4564
4689
  async function validateCanonicalBackupReferences(directory, env, backupPath) {
4565
4690
  assertSupportedBackupProfile(env);
4566
4691
  await withBackupHelper(directory, env.OR3_IMAGE, env, { network: "none" }, async (helper) => {
4567
- await helper.loadSqlite(join17(backupPath, "data.tgz"));
4692
+ await helper.loadSqlite(join18(backupPath, "data.tgz"));
4568
4693
  const result = JSON.parse(await helper.exec(["sh", "-c", NODE3, "or3-backup-inspection", INSPECTOR3, "references", env.OR3_STORAGE_FS_ROOT ?? "/data/storage"]));
4569
4694
  if (result.contract !== 1 || result.complete !== true || !Number.isSafeInteger(result.liveAttachments) || result.liveAttachments < 0)
4570
4695
  throw new Error("Offline canonical backup reference inspection did not complete.");
@@ -4573,7 +4698,7 @@ async function validateCanonicalBackupReferences(directory, env, backupPath) {
4573
4698
 
4574
4699
  // src/backup/retention.ts
4575
4700
  import { rm as rm6 } from "node:fs/promises";
4576
- import { basename as basename4, dirname as dirname4, join as join18, resolve as resolve9 } from "node:path";
4701
+ import { basename as basename4, dirname as dirname4, join as join19, resolve as resolve9 } from "node:path";
4577
4702
  var BACKUP_RETENTION_KEEP = 5;
4578
4703
  function assertRemovableArtifactName(name) {
4579
4704
  if (!BACKUP_ID_PATTERN.test(name)) {
@@ -4589,7 +4714,7 @@ async function removeNamedBackupArtifact(directory, backupId) {
4589
4714
  throw new Error(`Refusing to remove a path outside the backups directory: ${target}.`);
4590
4715
  }
4591
4716
  await rm6(target, { recursive: true, force: true });
4592
- await rm6(join18(deploymentPaths(directory).exports, `${backupId}.json`), { force: true });
4717
+ await rm6(join19(deploymentPaths(directory).exports, `${backupId}.json`), { force: true });
4593
4718
  }
4594
4719
  async function removeEnumeratedBackupArtifact(directory, backup) {
4595
4720
  await lifecycleFaults.beforeArtifactDelete?.();
@@ -4599,7 +4724,7 @@ async function removeEnumeratedBackupArtifact(directory, backup) {
4599
4724
  throw new Error(`Refusing to prune an untrusted backup path ${backup.path}.`);
4600
4725
  }
4601
4726
  await rm6(target, { recursive: true, force: true });
4602
- await rm6(join18(deploymentPaths(directory).exports, `${backup.backupId}.json`), { force: true });
4727
+ await rm6(join19(deploymentPaths(directory).exports, `${backup.backupId}.json`), { force: true });
4603
4728
  }
4604
4729
  function planRetention(entries, keep, protectedIds, options = {}) {
4605
4730
  if (!Number.isInteger(keep) || keep < 1)
@@ -4710,7 +4835,7 @@ async function cleanupPartialBackup(directory, backupId) {
4710
4835
  }
4711
4836
  const statuses = await Promise.all([
4712
4837
  artifactStatus(backupDirectory(directory, backupId)),
4713
- artifactStatus(join19(deploymentPaths(directory).exports, `${backupId}.json`))
4838
+ artifactStatus(join20(deploymentPaths(directory).exports, `${backupId}.json`))
4714
4839
  ]);
4715
4840
  const removed = statuses.every((status) => status.absent);
4716
4841
  const detail = statuses.map((status) => status.detail).join(" ");
@@ -4780,9 +4905,9 @@ async function createBackup(directory, state, env, options = {}) {
4780
4905
  "or3-vault",
4781
4906
  "/app/vault/entrypoint.mjs",
4782
4907
  "backup"
4783
- ]), join19(backupDir, "vault.backup"), directory, secretValues(env));
4908
+ ]), join20(backupDir, "vault.backup"), directory, secretValues(env));
4784
4909
  }
4785
- await copySecure(deploymentPaths(directory).env, join19(backupDir, "config.env"));
4910
+ await copySecure(deploymentPaths(directory).env, join20(backupDir, "config.env"));
4786
4911
  managedAssetSha256 = await snapshotManagedAssets(directory, state.mode, backupDir);
4787
4912
  artifact = "captured";
4788
4913
  } catch (error) {
@@ -4827,10 +4952,10 @@ async function createBackup(directory, state, env, options = {}) {
4827
4952
  appVersion: state.appVersion,
4828
4953
  image: state.image,
4829
4954
  imageDigest: state.imageDigest,
4830
- dataSha256: await sha256File(join19(backupDir, "data.tgz")),
4831
- ...managedVaultEnabled(directory, env) ? { vaultSha256: await sha256File(join19(backupDir, "vault.backup")) } : {},
4955
+ dataSha256: await sha256File(join20(backupDir, "data.tgz")),
4956
+ ...managedVaultEnabled(directory, env) ? { vaultSha256: await sha256File(join20(backupDir, "vault.backup")) } : {},
4832
4957
  dataBytes: volumeSize,
4833
- configSha256: await sha256File(join19(backupDir, "config.env")),
4958
+ configSha256: await sha256File(join20(backupDir, "config.env")),
4834
4959
  managedAssetSha256,
4835
4960
  managedAssetInventoryVersion: managedAssetSha256?.["dashboard-lifecycle.mjs"] ? MANAGED_ASSET_INVENTORY_VERSION : managedAssetSha256?.["compose.operator.yaml"] ? 3 : managedAssetSha256?.["dashboard-operator.mjs"] ? 2 : undefined,
4836
4961
  mode: state.mode,
@@ -4844,7 +4969,7 @@ async function createBackup(directory, state, env, options = {}) {
4844
4969
  };
4845
4970
  const manifestContents = `${JSON.stringify(manifest2, null, 2)}
4846
4971
  `;
4847
- await writeSecure(join19(backupDir, "manifest.json"), manifestContents);
4972
+ await writeSecure(join20(backupDir, "manifest.json"), manifestContents);
4848
4973
  await writeBackupAuthentication(directory, backupDir, manifestContents);
4849
4974
  verifiedManifest = await readManifest(backupDir, directory);
4850
4975
  artifact = "verified";
@@ -4899,7 +5024,7 @@ async function inspectUnclaimedBackupArtifacts(directory, backupId, backupPath)
4899
5024
  return;
4900
5025
  const statuses = await Promise.all([
4901
5026
  artifactStatus(expectedPath),
4902
- artifactStatus(join19(deploymentPaths(directory).exports, `${backupId}.json`))
5027
+ artifactStatus(join20(deploymentPaths(directory).exports, `${backupId}.json`))
4903
5028
  ]);
4904
5029
  const detail = statuses.map((status) => status.detail).join(" ");
4905
5030
  return statuses.every((status) => status.absent) ? detail : `Maintenance warning: backup artifact ownership was not recorded. ${detail} This recovery did not verify or remove these paths. Inspect them with "npx @or3/cloud backup list".`;
@@ -4926,7 +5051,7 @@ async function createPreMutationSnapshot(directory, state, env, backupId) {
4926
5051
 
4927
5052
  // src/backup/export.ts
4928
5053
  import { chmod as chmod7, mkdir as mkdir7, realpath as realpath2, rm as rm7, stat as stat4 } from "node:fs/promises";
4929
- import { basename as basename5, dirname as dirname5, isAbsolute as isAbsolute5, join as join20, resolve as resolve11, sep } from "node:path";
5054
+ import { basename as basename5, dirname as dirname5, isAbsolute as isAbsolute5, join as join21, resolve as resolve11, sep } from "node:path";
4930
5055
  var PURGE_REQUIRES_BACKUP_WITHIN_MS = 24 * 60 * 60 * 1000;
4931
5056
  async function exportBackup(directory, backupId, destination) {
4932
5057
  const backupPath = await resolveBackup(directory, backupId);
@@ -4942,7 +5067,7 @@ async function exportBackup(directory, backupId, destination) {
4942
5067
  if (await fileExists(dest))
4943
5068
  throw new Error(`Destination ${dest} already exists. Choose a new empty destination so an export can never merge with unrelated files.`);
4944
5069
  await mkdir7(dirname5(dest), { recursive: true, mode: 448 });
4945
- const canonicalDestination = join20(await realpath2(dirname5(dest)), basename5(dest));
5070
+ const canonicalDestination = join21(await realpath2(dirname5(dest)), basename5(dest));
4946
5071
  if (canonicalDestination === deploymentRoot || canonicalDestination.startsWith(`${deploymentRoot}${sep}`)) {
4947
5072
  throw new Error("Backup exports must live outside the managed deployment directory so `remove --purge-data` can never delete the remaining copy.");
4948
5073
  }
@@ -4953,19 +5078,19 @@ async function exportBackup(directory, backupId, destination) {
4953
5078
  }
4954
5079
  await chmod7(dest, 448);
4955
5080
  for (const file of ["data.tgz", "config.env", "manifest.json", "manifest.auth", ...manifest2.vaultSha256 ? ["vault.backup"] : [], ...manifest2.schemaVersion === 2 ? [manifest2.remote.file] : []]) {
4956
- await copySecure(join20(backupPath, file), join20(dest, file));
5081
+ await copySecure(join21(backupPath, file), join21(dest, file));
4957
5082
  }
4958
5083
  if (manifest2.managedAssetSha256) {
4959
5084
  for (const name of managedAssetNamesForInventory(manifest2.mode, manifest2.managedAssetInventoryVersion)) {
4960
- await copySecure(join20(backupPath, "managed-assets", name), join20(dest, "managed-assets", name));
5085
+ await copySecure(join21(backupPath, "managed-assets", name), join21(dest, "managed-assets", name));
4961
5086
  }
4962
5087
  }
4963
- const dataSha = await sha256File(join20(dest, "data.tgz"));
5088
+ const dataSha = await sha256File(join21(dest, "data.tgz"));
4964
5089
  if (dataSha !== manifest2.dataSha256) {
4965
5090
  throw new Error(`Exported data.tgz checksum mismatch for ${manifest2.backupId}. Expected ${manifest2.dataSha256}, got ${dataSha}.`);
4966
5091
  }
4967
5092
  if (manifest2.configSha256) {
4968
- const configSha = await sha256File(join20(dest, "config.env"));
5093
+ const configSha = await sha256File(join21(dest, "config.env"));
4969
5094
  if (configSha !== manifest2.configSha256) {
4970
5095
  throw new Error(`Exported config.env checksum mismatch for ${manifest2.backupId}.`);
4971
5096
  }
@@ -4982,14 +5107,14 @@ async function exportBackup(directory, backupId, destination) {
4982
5107
  dataSha256: manifest2.dataSha256,
4983
5108
  configSha256: manifest2.configSha256
4984
5109
  };
4985
- await writeSecure(join20(deploymentPaths(directory).exports, `${manifest2.backupId}.json`), `${JSON.stringify(receipt, null, 2)}
5110
+ await writeSecure(join21(deploymentPaths(directory).exports, `${manifest2.backupId}.json`), `${JSON.stringify(receipt, null, 2)}
4986
5111
  `);
4987
- let bytes = (manifest2.vaultSha256 ? (await stat4(join20(dest, "vault.backup"))).size : 0) + (await stat4(join20(dest, "data.tgz"))).size + (await stat4(join20(dest, "config.env"))).size + (await stat4(join20(dest, "manifest.json"))).size + (await stat4(join20(dest, "manifest.auth"))).size;
5112
+ let bytes = (manifest2.vaultSha256 ? (await stat4(join21(dest, "vault.backup"))).size : 0) + (await stat4(join21(dest, "data.tgz"))).size + (await stat4(join21(dest, "config.env"))).size + (await stat4(join21(dest, "manifest.json"))).size + (await stat4(join21(dest, "manifest.auth"))).size;
4988
5113
  if (manifest2.schemaVersion === 2)
4989
- bytes += (await stat4(join20(dest, manifest2.remote.file))).size;
5114
+ bytes += (await stat4(join21(dest, manifest2.remote.file))).size;
4990
5115
  if (manifest2.managedAssetSha256) {
4991
5116
  for (const name of managedAssetNamesForInventory(manifest2.mode, manifest2.managedAssetInventoryVersion)) {
4992
- bytes += (await stat4(join20(dest, "managed-assets", name))).size;
5117
+ bytes += (await stat4(join21(dest, "managed-assets", name))).size;
4993
5118
  }
4994
5119
  }
4995
5120
  console.log(`Exported backup ${manifest2.backupId} (${bytes} bytes) to ${dest}`);
@@ -5191,7 +5316,7 @@ async function backupCommand(directory, positionals, flags) {
5191
5316
 
5192
5317
  // src/credentials/reset.ts
5193
5318
  import { rm as rm8 } from "node:fs/promises";
5194
- import { join as join21 } from "node:path";
5319
+ import { join as join22 } from "node:path";
5195
5320
 
5196
5321
  // src/credentials/reset-script.ts
5197
5322
  function buildCredentialsResetScript(input2) {
@@ -5387,7 +5512,7 @@ async function applyCredentialReset(directory, state, nextEnv) {
5387
5512
  await runCredentialsResetScript(directory, state.mode, values);
5388
5513
  const runtimeEnv = withoutProvisioningCredentials(nextEnv);
5389
5514
  await writeSecure(deploymentPaths(directory).env, serializeEnv(runtimeEnv));
5390
- const initialCredentials = join21(directory, ".or3-initial-credentials");
5515
+ const initialCredentials = join22(directory, ".or3-initial-credentials");
5391
5516
  await rm8(initialCredentials, { force: true });
5392
5517
  await stopProject(directory, state.mode);
5393
5518
  if (managedVaultEnabled(directory, runtimeEnv))
@@ -5455,7 +5580,7 @@ async function credentialsCommand(directory, positionals, flags) {
5455
5580
  // src/commands/doctor.ts
5456
5581
  import { existsSync as existsSync3 } from "node:fs";
5457
5582
  import { stat as stat5 } from "node:fs/promises";
5458
- import { basename as basename6, join as join22, resolve as resolve12 } from "node:path";
5583
+ import { basename as basename6, join as join23, resolve as resolve12 } from "node:path";
5459
5584
  async function doctorCommand(directory) {
5460
5585
  const resolved = resolve12(directory);
5461
5586
  const paths = deploymentPaths(resolved);
@@ -5480,7 +5605,7 @@ async function doctorCommand(directory) {
5480
5605
  failures.push(error instanceof Error ? error.message : String(error));
5481
5606
  console.log("✗ Managed state or .env is missing/invalid");
5482
5607
  }
5483
- for (const file of [paths.env, paths.state, join22(resolved, ".or3-initial-credentials")]) {
5608
+ for (const file of [paths.env, paths.state, join23(resolved, ".or3-initial-credentials")]) {
5484
5609
  if (!existsSync3(file))
5485
5610
  continue;
5486
5611
  const mode = (await stat5(file)).mode & 511;
@@ -5552,7 +5677,7 @@ async function doctorCommand(directory) {
5552
5677
  }
5553
5678
  assertDashboardOperatorMounts(container.Mounts ?? [], resolved);
5554
5679
  const ipcDirectory = await stat5(paths.operatorIpc);
5555
- const operatorSocket = await stat5(join22(paths.operatorIpc, "operator.sock"));
5680
+ const operatorSocket = await stat5(join23(paths.operatorIpc, "operator.sock"));
5556
5681
  const operatorUid = Number(env.OR3_OPERATOR_UID);
5557
5682
  const operatorGid = Number(env.OR3_OPERATOR_GID);
5558
5683
  if ((ipcDirectory.mode & 511) !== 456 || ipcDirectory.uid !== operatorUid || ipcDirectory.gid !== operatorGid || !operatorSocket.isSocket() || (operatorSocket.mode & 511) !== 432 || operatorSocket.uid !== operatorUid || operatorSocket.gid !== operatorGid) {
@@ -5611,7 +5736,7 @@ async function doctorCommand(directory) {
5611
5736
 
5612
5737
  // src/commands/init.ts
5613
5738
  import { chmod as chmod8, mkdir as mkdir8 } from "node:fs/promises";
5614
- import { join as join23, relative, resolve as resolve13 } from "node:path";
5739
+ import { join as join24, relative, resolve as resolve13 } from "node:path";
5615
5740
  async function initCommand(positionals, flags) {
5616
5741
  const hasLocal = boolFlag(flags, "local");
5617
5742
  const hasPublic = boolFlag(flags, "public");
@@ -5619,7 +5744,7 @@ async function initCommand(positionals, flags) {
5619
5744
  throw new Error("Choose exactly one of --local or --public.");
5620
5745
  const mode = hasPublic ? "public" : "local";
5621
5746
  const directory = resolve13(process.cwd(), positionals[0] ?? "or3-cloud");
5622
- if (await fileExists(join23(directory, ".or3-cloud", "state.json"))) {
5747
+ if (await fileExists(join24(directory, ".or3-cloud", "state.json"))) {
5623
5748
  throw new Error(`${directory} is already a managed deployment. Use update, doctor, or adopt.`);
5624
5749
  }
5625
5750
  await readDirectoryEmpty(directory);
@@ -5670,7 +5795,7 @@ ${existing.stderr}`)) {
5670
5795
  await copyAssets(directory, mode);
5671
5796
  const env = buildEnv({ mode, version, directory, image, email, password, domain, port, dashboardOperator: operator });
5672
5797
  await writeSecure(deploymentPaths(directory).env, serializeEnv(env));
5673
- await writeSecure(join23(directory, ".or3-initial-credentials"), serializeInitialCredentials({
5798
+ await writeSecure(join24(directory, ".or3-initial-credentials"), serializeInitialCredentials({
5674
5799
  bootstrapEmail: email,
5675
5800
  bootstrapPassword: password,
5676
5801
  adminUsername: email,
@@ -5695,7 +5820,7 @@ ${existing.stderr}`)) {
5695
5820
  const folder = relative(process.cwd(), directory) || ".";
5696
5821
  console.log(`
5697
5822
  OR3 Cloud ${version} is running at ${url}`);
5698
- console.log(`Sign in as ${email} with the password in ${join23(folder, ".or3-initial-credentials")}; the same login opens ${url}/admin.`);
5823
+ console.log(`Sign in as ${email} with the password in ${join24(folder, ".or3-initial-credentials")}; the same login opens ${url}/admin.`);
5699
5824
  console.log("Save it in a password manager, then delete that file.");
5700
5825
  console.log(`
5701
5826
  Run later commands from the deployment folder: cd ${quote(folder)} && npx @or3/cloud doctor`);
@@ -5754,7 +5879,7 @@ async function restartCommand(directory, lifecycle) {
5754
5879
  }
5755
5880
 
5756
5881
  // src/backup/restore.ts
5757
- import { join as join24 } from "node:path";
5882
+ import { join as join25 } from "node:path";
5758
5883
 
5759
5884
  // src/backup/generation-restore.ts
5760
5885
  function rebindRestoredGenerations(fs, path, crypto, db, root, options = {}) {
@@ -5950,14 +6075,14 @@ if (root !== '/data' && !root.startsWith('/data/')) throw new Error('Generation
5950
6075
  if (!result.ok)
5951
6076
  throw new Error(`Restored generation verification failed. ${redact(result.stderr, secretValues(env))}`);
5952
6077
  }
5953
- function assertFilesystemPayloadHash(key, readChunk, createHash5) {
6078
+ function assertFilesystemPayloadHash(key, readChunk, createHash6) {
5954
6079
  const match = /^(sha256|md5)_([a-fA-F0-9]+)$/.exec(key);
5955
6080
  const algorithm = match?.[1];
5956
6081
  const expected = match?.[2];
5957
6082
  if (algorithm !== "sha256" && algorithm !== "md5" || expected?.length !== (algorithm === "sha256" ? 64 : 32)) {
5958
6083
  throw new Error("Invalid canonical filesystem payload key");
5959
6084
  }
5960
- const hash = createHash5(algorithm);
6085
+ const hash = createHash6(algorithm);
5961
6086
  for (let chunk = readChunk();chunk !== undefined; chunk = readChunk())
5962
6087
  hash.update(chunk);
5963
6088
  if (hash.digest("hex") !== expected.toLowerCase())
@@ -6013,7 +6138,7 @@ if (storage === 'fs' && (storageRoot === '/data' || storageRoot.startsWith('/dat
6013
6138
  }
6014
6139
  `;
6015
6140
  async function assertRestoreFreeSpace(directory, state, env, manifest2, backupPath) {
6016
- const archiveBytes = await gzipUncompressedBytes(join24(backupPath, "data.tgz"));
6141
+ const archiveBytes = await gzipUncompressedBytes(join25(backupPath, "data.tgz"));
6017
6142
  const requiredBytes = Math.max(manifest2.dataBytes ?? 0, archiveBytes);
6018
6143
  const freeBytes = await dataVolumeFreeBytes(directory, state.mode, env);
6019
6144
  const reclaimableBytes = await dataVolumeSize(directory, state.mode, env, "allocated");
@@ -6022,7 +6147,8 @@ async function assertRestoreFreeSpace(directory, state, env, manifest2, backupPa
6022
6147
  async function restoreBackupData(directory, state, env, backupPath, options = {}) {
6023
6148
  const manifest2 = await readManifest(backupPath, directory);
6024
6149
  assertRestorableManagedAssets(manifest2);
6025
- const backupEnv = parseEnv(await readText(join24(backupPath, "config.env")));
6150
+ const backupConfig = await readAuthenticatedBackupConfig(backupPath, manifest2);
6151
+ const backupEnv = parseEnv(backupConfig);
6026
6152
  if (backupEnv.OR3_VERSION !== manifest2.appVersion || backupEnv.OR3_IMAGE !== manifest2.image) {
6027
6153
  throw new Error(`Backup ${manifest2.backupId} configuration does not match its manifest.`);
6028
6154
  }
@@ -6034,7 +6160,7 @@ async function restoreBackupData(directory, state, env, backupPath, options = {}
6034
6160
  }
6035
6161
  if (manifest2.imageDigest)
6036
6162
  await requireImageDigest(manifest2.image, manifest2.imageDigest, `Backup ${manifest2.backupId}`);
6037
- await assertExistingVaultCustody(directory, state, manifest2, backupPath, backupEnv);
6163
+ await assertExistingVaultCustody(directory, state, manifest2, backupPath, backupConfig);
6038
6164
  await validateVolumeArchive(directory, state.mode, env, backupPath, backupEnv.OR3_STORAGE_FS_ROOT);
6039
6165
  if (manifest2.schemaVersion === 2 && manifest2.remote.kind === "s3-copy-v1") {
6040
6166
  const result = await checkRemoteCopyTarget(directory, manifest2, env, backupPath, manifest2.remote);
@@ -6136,18 +6262,18 @@ async function restorePreMutationSnapshot(directory, state, env) {
6136
6262
  }
6137
6263
 
6138
6264
  // src/deployment/observation.ts
6139
- import { createHash as createHash6 } from "node:crypto";
6265
+ import { createHash as createHash7 } from "node:crypto";
6140
6266
  import { resolve as resolve14 } from "node:path";
6141
6267
 
6142
6268
  // src/deployment/lease.ts
6143
6269
  import { randomBytes as randomBytes8 } from "node:crypto";
6144
6270
  import { mkdir as mkdir10, rename as rename3, rm as rm10 } from "node:fs/promises";
6145
- import { dirname as dirname7, join as join26 } from "node:path";
6271
+ import { dirname as dirname7, join as join27 } from "node:path";
6146
6272
 
6147
6273
  // ../../shared/server/restarts/controller.ts
6148
- import { randomUUID as randomUUID5, createHash as createHash5 } from "node:crypto";
6274
+ import { randomUUID as randomUUID5, createHash as createHash6 } from "node:crypto";
6149
6275
  import { mkdir as mkdir9, open as open4, readFile as readFile5, rename as rename2, rm as rm9 } from "node:fs/promises";
6150
- import { dirname as dirname6, join as join25 } from "node:path";
6276
+ import { dirname as dirname6, join as join26 } from "node:path";
6151
6277
 
6152
6278
  // ../../node_modules/zod/v4/classic/external.js
6153
6279
  var exports_external = {};
@@ -25596,7 +25722,7 @@ var recordSchema = exports_external.object({
25596
25722
  expected: exports_external.record(exports_external.string(), exports_external.union([exports_external.string().max(128), exports_external.boolean()])),
25597
25723
  executionIntent: exports_external.boolean(),
25598
25724
  runtimeIdentity: exports_external.string().max(512).optional()
25599
- }).strict().refine((record2) => record2.requestId === record2.request.requestId && record2.fingerprint === createHash5("sha256").update(JSON.stringify(record2.request)).digest("hex"), "Receipt identity mismatch");
25725
+ }).strict().refine((record2) => record2.requestId === record2.request.requestId && record2.fingerprint === createHash6("sha256").update(JSON.stringify(record2.request)).digest("hex"), "Receipt identity mismatch");
25600
25726
 
25601
25727
  class RestartError extends Error {
25602
25728
  code;
@@ -25660,7 +25786,7 @@ class RestartController {
25660
25786
  constructor(directory, driver) {
25661
25787
  this.directory = directory;
25662
25788
  this.driver = driver;
25663
- this.path = join25(directory, "restarts.json");
25789
+ this.path = join26(directory, "restarts.json");
25664
25790
  }
25665
25791
  lock(action) {
25666
25792
  const next = this.serial.then(action, action);
@@ -25750,7 +25876,7 @@ class RestartController {
25750
25876
  if (!parsed.success)
25751
25877
  throw new RestartError("invalid_request", 400);
25752
25878
  const request = parsed.data;
25753
- const fingerprint = createHash5("sha256").update(JSON.stringify(request)).digest("hex");
25879
+ const fingerprint = createHash6("sha256").update(JSON.stringify(request)).digest("hex");
25754
25880
  return this.lock(async () => {
25755
25881
  const old = this.operations.find((o2) => o2.requestId === request.requestId);
25756
25882
  if (old) {
@@ -25958,7 +26084,7 @@ class RestartController {
25958
26084
  var DASHBOARD_LEASE_STALE_MS = 30000;
25959
26085
  async function readLeaseOwner(leasePath) {
25960
26086
  try {
25961
- const owner = JSON.parse(await readText(join26(leasePath, "owner.json")));
26087
+ const owner = JSON.parse(await readText(join27(leasePath, "owner.json")));
25962
26088
  if (owner.schemaVersion !== 1 || typeof owner.nonce !== "string" || typeof owner.command !== "string" || owner.origin !== "cli" && owner.origin !== "dashboard" || !Number.isSafeInteger(owner.pid) || typeof owner.acquiredAt !== "string" || typeof owner.heartbeatAt !== "string")
25963
26089
  return;
25964
26090
  return owner;
@@ -26017,7 +26143,7 @@ async function acquireDeploymentLease(directory, command, dashboardJobId) {
26017
26143
  }
26018
26144
  }
26019
26145
  try {
26020
- await writeSecure(join26(leasePath, "owner.json"), `${JSON.stringify(owner, null, 2)}
26146
+ await writeSecure(join27(leasePath, "owner.json"), `${JSON.stringify(owner, null, 2)}
26021
26147
  `);
26022
26148
  } catch (error62) {
26023
26149
  await rm10(leasePath, { recursive: true, force: true }).catch(() => {
@@ -26027,7 +26153,7 @@ async function acquireDeploymentLease(directory, command, dashboardJobId) {
26027
26153
  }
26028
26154
  const heartbeat = setInterval(() => {
26029
26155
  owner.heartbeatAt = now();
26030
- writeSecure(join26(leasePath, "owner.json"), `${JSON.stringify(owner, null, 2)}
26156
+ writeSecure(join27(leasePath, "owner.json"), `${JSON.stringify(owner, null, 2)}
26031
26157
  `).catch(() => {
26032
26158
  return;
26033
26159
  });
@@ -26052,7 +26178,7 @@ async function withDeploymentLease(directory, command, action) {
26052
26178
  }
26053
26179
  async function assertRestartJournalSettled(directory) {
26054
26180
  try {
26055
- const journal = await readRestartJournal(join26(directory, ".or3-cloud", "restarts", "restarts.json"));
26181
+ const journal = await readRestartJournal(join27(directory, ".or3-cloud", "restarts", "restarts.json"));
26056
26182
  if (journal.operations.some((operation) => !["succeeded", "cancelled", "failed"].includes(operation.phase))) {
26057
26183
  throw new Error("A dashboard restart is unresolved. Run the compatible CLI recover --dry-run to inspect and recover --finish to reconcile it before another mutation.");
26058
26184
  }
@@ -26235,7 +26361,7 @@ function observationFindings(observation) {
26235
26361
  return findings;
26236
26362
  }
26237
26363
  function stateFingerprint(state) {
26238
- return createHash6("sha256").update(JSON.stringify({
26364
+ return createHash7("sha256").update(JSON.stringify({
26239
26365
  schema: state.schemaVersion,
26240
26366
  appVersion: state.appVersion,
26241
26367
  image: state.image,
@@ -26738,7 +26864,6 @@ async function removeCommand(directory, flags) {
26738
26864
  }
26739
26865
 
26740
26866
  // src/commands/restore.ts
26741
- import { join as join27 } from "node:path";
26742
26867
  async function restoreCommand(directory, flags, positionals) {
26743
26868
  if (!boolFlag(flags, "yes"))
26744
26869
  throw new Error("Restore replaces live data. Re-run with --yes after confirming the backup and data-loss boundary.");
@@ -26751,7 +26876,8 @@ async function restoreCommand(directory, flags, positionals) {
26751
26876
  const backupPath = await resolveBackup(loaded.directory, backupValue);
26752
26877
  const manifest2 = await readManifest(backupPath, loaded.directory);
26753
26878
  assertRestorableManagedAssets(manifest2);
26754
- const backupEnv = parseEnv(await readText(join27(backupPath, "config.env")));
26879
+ const backupConfig = await readAuthenticatedBackupConfig(backupPath, manifest2);
26880
+ const backupEnv = parseEnv(backupConfig);
26755
26881
  if (backupEnv.OR3_VERSION !== manifest2.appVersion || backupEnv.OR3_IMAGE !== manifest2.image) {
26756
26882
  throw new Error(`Backup ${manifest2.backupId} configuration does not match its manifest.`);
26757
26883
  }
@@ -26762,7 +26888,7 @@ async function restoreCommand(directory, flags, positionals) {
26762
26888
  if (manifest2.imageDigest)
26763
26889
  await pullAndRequireImage(manifest2.image, manifest2.imageDigest, `Backup ${manifest2.backupId}`);
26764
26890
  await assertSupportedHostArchitecture(manifest2.image);
26765
- await assertExistingVaultCustody(loaded.directory, loaded.state, manifest2, backupPath, backupEnv);
26891
+ await assertExistingVaultCustody(loaded.directory, loaded.state, manifest2, backupPath, backupConfig);
26766
26892
  await assertRestoreFreeSpace(loaded.directory, loaded.state, loaded.env, manifest2, backupPath);
26767
26893
  await validateVolumeArchive(loaded.directory, loaded.state.mode, loaded.env, backupPath, backupEnv.OR3_STORAGE_FS_ROOT);
26768
26894
  const remotePreflight = manifest2.schemaVersion === 2 ? await preflightRemoteRestore(loaded.directory, manifest2, loaded.env, backupPath) : undefined;
@@ -26852,7 +26978,6 @@ async function restoreCommand(directory, flags, positionals) {
26852
26978
  }
26853
26979
 
26854
26980
  // src/commands/rollback.ts
26855
- import { join as join28 } from "node:path";
26856
26981
  async function rollbackCommand(directory, flags) {
26857
26982
  if (!boolFlag(flags, "yes"))
26858
26983
  throw new Error("Rollback restores the previous image and data snapshot. Re-run with --yes after confirming post-update data loss.");
@@ -26868,7 +26993,8 @@ async function rollbackCommand(directory, flags) {
26868
26993
  if (manifest2.appVersion !== point.appVersion || manifest2.image !== point.image || manifest2.imageDigest !== point.imageDigest) {
26869
26994
  throw new Error(`Rollback point ${point.backupId} no longer matches its recorded image/version. Refusing to mutate the deployment.`);
26870
26995
  }
26871
- const backupEnv = parseEnv(await readText(join28(backupPath, "config.env")));
26996
+ const backupConfig = await readAuthenticatedBackupConfig(backupPath, manifest2);
26997
+ const backupEnv = parseEnv(backupConfig);
26872
26998
  if (backupEnv.OR3_VERSION !== manifest2.appVersion || backupEnv.OR3_IMAGE !== manifest2.image) {
26873
26999
  throw new Error(`Backup ${manifest2.backupId} configuration does not match its manifest.`);
26874
27000
  }
@@ -26878,7 +27004,7 @@ async function rollbackCommand(directory, flags) {
26878
27004
  const recreateDataVolume = restoreRequiresVolumeRecreation(loaded.env, backupEnv);
26879
27005
  await pullAndRequireImage(point.image, point.imageDigest, "Rollback");
26880
27006
  await assertSupportedHostArchitecture(point.image);
26881
- await assertExistingVaultCustody(loaded.directory, loaded.state, manifest2, backupPath, backupEnv);
27007
+ await assertExistingVaultCustody(loaded.directory, loaded.state, manifest2, backupPath, backupConfig);
26882
27008
  await assertRestoreFreeSpace(loaded.directory, loaded.state, loaded.env, manifest2, backupPath);
26883
27009
  await validateVolumeArchive(loaded.directory, loaded.state.mode, loaded.env, backupPath, backupEnv.OR3_STORAGE_FS_ROOT);
26884
27010
  const remotePreflight = manifest2.schemaVersion === 2 ? await preflightRemoteRestore(loaded.directory, manifest2, loaded.env, backupPath) : undefined;
@@ -27090,7 +27216,7 @@ ${result.stderr}`);
27090
27216
 
27091
27217
  // src/commands/update.ts
27092
27218
  import { readFile as readFile6, statfs as statfs2 } from "node:fs/promises";
27093
- import { join as join29, resolve as resolve15 } from "node:path";
27219
+ import { join as join28, resolve as resolve15 } from "node:path";
27094
27220
  async function assessUpdate(directory, targetVersion, options = {}) {
27095
27221
  const checkDocker = options.checkDocker ?? false;
27096
27222
  const observation = await observeDeployment(directory, { checkDocker, checkImage: false });
@@ -27155,7 +27281,7 @@ async function assessUpdate(directory, targetVersion, options = {}) {
27155
27281
  for (const name of managedAssetNames(state?.mode ?? "local")) {
27156
27282
  let desired;
27157
27283
  try {
27158
- desired = await readFile6(join29(ASSET_ROOT, name));
27284
+ desired = await readFile6(join28(ASSET_ROOT, name));
27159
27285
  } catch (error62) {
27160
27286
  findings.push({
27161
27287
  code: "managed-asset-unreadable",
@@ -27166,7 +27292,7 @@ async function assessUpdate(directory, targetVersion, options = {}) {
27166
27292
  continue;
27167
27293
  }
27168
27294
  try {
27169
- const installedPath = join29(directory, name);
27295
+ const installedPath = join28(directory, name);
27170
27296
  if (!await fileExists(installedPath)) {
27171
27297
  changed.push(`${name} (add)`);
27172
27298
  continue;
@@ -27525,7 +27651,7 @@ async function runUpdateCommand(directory, flags, asJson) {
27525
27651
  }
27526
27652
 
27527
27653
  // src/commands/verify.ts
27528
- import { join as join30, resolve as resolve16 } from "node:path";
27654
+ import { join as join29, resolve as resolve16 } from "node:path";
27529
27655
  async function verificationCredentials(directory, flags, env) {
27530
27656
  const passwordFile = stringFlag(flags, "verification-password-file");
27531
27657
  if (flags["verification-email"] !== undefined && !stringFlag(flags, "verification-email")) {
@@ -27537,7 +27663,7 @@ async function verificationCredentials(directory, flags, env) {
27537
27663
  const configuredEmail = stringFlag(flags, "verification-email")?.trim() || env.OR3_MANAGED_OWNER_EMAIL || env.OR3_BASIC_AUTH_BOOTSTRAP_EMAIL;
27538
27664
  let initialCredentials = {};
27539
27665
  if (!configuredEmail || !passwordFile && !env.OR3_BASIC_AUTH_BOOTSTRAP_PASSWORD) {
27540
- const initialCredentialsPath = join30(directory, ".or3-initial-credentials");
27666
+ const initialCredentialsPath = join29(directory, ".or3-initial-credentials");
27541
27667
  if (await fileExists(initialCredentialsPath)) {
27542
27668
  initialCredentials = parseEnv(await readOwnerOnlyText(initialCredentialsPath, "The initial credentials file"));
27543
27669
  }
@@ -27659,10 +27785,10 @@ async function verifyReadOnlyCommand(directory, flags) {
27659
27785
 
27660
27786
  // src/commands/vault-key.ts
27661
27787
  import { spawn as spawn2 } from "node:child_process";
27662
- import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
27788
+ import { createHash as createHash8, randomUUID as randomUUID6 } from "node:crypto";
27663
27789
  import { constants as constants2 } from "node:fs";
27664
27790
  import { open as open5, realpath as realpath3, stat as stat6 } from "node:fs/promises";
27665
- import { basename as basename7, dirname as dirname8, isAbsolute as isAbsolute6, join as join31, sep as sep2 } from "node:path";
27791
+ import { basename as basename7, dirname as dirname8, isAbsolute as isAbsolute6, join as join30, sep as sep2 } from "node:path";
27666
27792
  async function vaultKeyCommand(directory, positionals, flags) {
27667
27793
  if (positionals.length !== 1 || positionals[0] !== "export")
27668
27794
  throw new Error("Use vault-key export --out <absolute-path>.");
@@ -27677,7 +27803,7 @@ async function vaultKeyCommand(directory, positionals, flags) {
27677
27803
  if (!parentInfo.isDirectory() || (parentInfo.mode & 511) !== 448 || typeof process.getuid === "function" && parentInfo.uid !== process.getuid()) {
27678
27804
  throw new Error("Vault key destination parent must be an owner-only directory (0700).");
27679
27805
  }
27680
- const target = join31(parent, basename7(destination));
27806
+ const target = join30(parent, basename7(destination));
27681
27807
  const deployment = await realpath3(directory);
27682
27808
  if (target === deployment || target.startsWith(`${deployment}${sep2}`))
27683
27809
  throw new Error("Vault key destination must be outside the managed deployment directory.");
@@ -27765,7 +27891,7 @@ async function vaultKeyCommand(directory, positionals, flags) {
27765
27891
  await parentHandle.close();
27766
27892
  }
27767
27893
  written = true;
27768
- console.log(`Exported vault master key to ${target} (SHA-256 ${createHash7("sha256").update(key).digest("hex")}). Protect it separately from the backup.`);
27894
+ console.log(`Exported vault master key to ${target} (SHA-256 ${createHash8("sha256").update(key).digest("hex")}). Protect it separately from the backup.`);
27769
27895
  } finally {
27770
27896
  key.fill(0);
27771
27897
  }
@@ -27905,11 +28031,11 @@ The installer never changes firewall, DNS, Cloudflare, or Tailscale settings.`);
27905
28031
 
27906
28032
  // src/commands/recover-restart.ts
27907
28033
  import { request } from "node:http";
27908
- import { join as join32 } from "node:path";
28034
+ import { join as join31 } from "node:path";
27909
28035
  async function recoverRestart(directory, flags) {
27910
28036
  let journal;
27911
28037
  try {
27912
- journal = await readRestartJournal(join32(directory, ".or3-cloud", "restarts", "restarts.json"));
28038
+ journal = await readRestartJournal(join31(directory, ".or3-cloud", "restarts", "restarts.json"));
27913
28039
  } catch (error62) {
27914
28040
  if (error62.code === "ENOENT")
27915
28041
  return false;
@@ -27934,7 +28060,7 @@ async function recoverRestart(directory, flags) {
27934
28060
  const value = JSON.stringify({ requestId: operation.requestId });
27935
28061
  await new Promise((resolve18, reject) => {
27936
28062
  const req = request({
27937
- socketPath: join32(deploymentPaths(directory).operatorIpc, "operator.sock"),
28063
+ socketPath: join31(deploymentPaths(directory).operatorIpc, "operator.sock"),
27938
28064
  path: "/lifecycle/v1/reconcile",
27939
28065
  method: "POST",
27940
28066
  headers: { "content-type": "application/json", "content-length": Buffer.byteLength(value) }