@tinycloud/operations 0.6.1-beta.4 → 0.6.1-beta.5

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/index.cjs CHANGED
@@ -4246,9 +4246,9 @@ var init_authority = __esm({
4246
4246
 
4247
4247
  // src/state.ts
4248
4248
  function processWideContext(key) {
4249
- var _a4;
4249
+ var _a5;
4250
4250
  const registry = globalThis;
4251
- return registry[_a4 = Symbol.for(key)] ?? (registry[_a4] = new import_node_async_hooks.AsyncLocalStorage());
4251
+ return registry[_a5 = Symbol.for(key)] ?? (registry[_a5] = new import_node_async_hooks.AsyncLocalStorage());
4252
4252
  }
4253
4253
  function processOrigin() {
4254
4254
  if (cachedProcessOrigin !== void 0) return cachedProcessOrigin;
@@ -4419,9 +4419,14 @@ function tinycloudConfigPath() {
4419
4419
  function profilesPath() {
4420
4420
  return (0, import_node_path2.join)(tinycloudHomePath(), "profiles");
4421
4421
  }
4422
- function profilePath(profile) {
4422
+ function namedProfilePath(profile) {
4423
4423
  return (0, import_node_path2.join)(profilesPath(), validateProfileName(profile));
4424
4424
  }
4425
+ function profilePath(profile) {
4426
+ const named = namedProfilePath(profile);
4427
+ const pinned = pinnedProfiles.getStore()?.get(named);
4428
+ return pinned ? livePinnedPath(profile, pinned) : named;
4429
+ }
4425
4430
  function profileConfigPath(profile) {
4426
4431
  return (0, import_node_path2.join)(profilePath(profile), "profile.json");
4427
4432
  }
@@ -4438,10 +4443,12 @@ function profileStoreMetadataPath(profile, store) {
4438
4443
  return `${profileStorePath(profile, store)}.metadata.json`;
4439
4444
  }
4440
4445
  function profileLockPath(profile) {
4441
- return (0, import_node_path2.join)(profilePath(profile), ".lock");
4446
+ return (0, import_node_path2.join)(namedProfilePath(profile), ".lock");
4442
4447
  }
4443
4448
  function profileTurnLockPath(profile) {
4444
- return (0, import_node_path2.join)(tinycloudHomePath(), "profile-locks", validateProfileName(profile));
4449
+ const home = tinycloudHomePath();
4450
+ const pinned = pinnedHomes.getStore()?.get(home);
4451
+ return (0, import_node_path2.join)(pinned ? livePinnedPath(profile, pinned) : home, "profile-locks", validateProfileName(profile));
4445
4452
  }
4446
4453
  async function readJson(filePath) {
4447
4454
  try {
@@ -4451,6 +4458,44 @@ async function readJson(filePath) {
4451
4458
  throw error;
4452
4459
  }
4453
4460
  }
4461
+ async function readProfileJson(profile, filePath) {
4462
+ const before = process.platform !== "linux" ? await (0, import_promises.lstat)(filePath, { bigint: true }).catch((error) => {
4463
+ if (error.code === "ENOENT") return null;
4464
+ throw error;
4465
+ }) : null;
4466
+ if (process.platform !== "linux" && !before) return null;
4467
+ if (before && !before.isFile()) throw new ProfileSymlinkError(profile);
4468
+ const dev = before && exactFileId(before.dev);
4469
+ const ino = before && exactFileId(before.ino);
4470
+ try {
4471
+ const handle = await (0, import_promises.open)(filePath, import_node_fs.constants.O_RDONLY | (import_node_fs.constants.O_NOFOLLOW ?? 0));
4472
+ try {
4473
+ if (before) {
4474
+ const opened = await handle.stat({ bigint: true });
4475
+ if (!opened.isFile() || dev === null || ino === null || dev !== exactFileId(opened.dev) || ino !== exactFileId(opened.ino)) {
4476
+ throw new ProfileSymlinkError(profile, "changed while opening its file");
4477
+ }
4478
+ }
4479
+ const contents = await handle.readFile("utf8");
4480
+ if (before) {
4481
+ const named = await (0, import_promises.lstat)(filePath, { bigint: true }).catch((error) => {
4482
+ if (error.code === "ENOENT") return null;
4483
+ throw error;
4484
+ });
4485
+ if (!named?.isFile() || dev !== exactFileId(named.dev) || ino !== exactFileId(named.ino)) {
4486
+ throw new ProfileSymlinkError(profile, "changed while reading its file");
4487
+ }
4488
+ }
4489
+ return JSON.parse(contents);
4490
+ } finally {
4491
+ await handle.close();
4492
+ }
4493
+ } catch (error) {
4494
+ if (isErrno(error, "ENOENT")) return null;
4495
+ if (isErrno(error, "ELOOP") || isErrno(error, "ENOTDIR")) throw new ProfileSymlinkError(profile);
4496
+ throw error;
4497
+ }
4498
+ }
4454
4499
  async function writeJsonAtomic(filePath, value) {
4455
4500
  await replaceJson(filePath, value, false);
4456
4501
  }
@@ -4484,11 +4529,14 @@ async function writeFileDurably(path, contents) {
4484
4529
  }
4485
4530
  }
4486
4531
  async function readProfile(profile) {
4487
- return readJson(profileConfigPath(profile));
4532
+ return withPinnedProfileDirectory(profile, (directory) => directory ? readProfileJson(profile, (0, import_node_path2.join)(directory, "profile.json")) : Promise.resolve(null));
4488
4533
  }
4489
4534
  async function readSession(profile) {
4490
- await readStoreMetadata(profile, "session");
4491
- return readJson(sessionPath(profile));
4535
+ return withPinnedProfileDirectory(profile, async (directory) => {
4536
+ if (!directory) return null;
4537
+ await readStoreMetadata(profile, "session");
4538
+ return readProfileJson(profile, sessionPath(profile));
4539
+ });
4492
4540
  }
4493
4541
  async function readAdditionalDelegations(profile) {
4494
4542
  return (await readProfileStore(profile, "additional-delegations")).records;
@@ -4497,42 +4545,186 @@ async function readAuthRequests(profile) {
4497
4545
  return (await readProfileStore(profile, "auth-requests")).records;
4498
4546
  }
4499
4547
  async function readStoreMetadata(profile, store) {
4500
- const metadata = await readJson(profileStoreMetadataPath(profile, store));
4501
- if (metadata === null) return { formatVersion: 1 };
4502
- if (typeof metadata !== "object" || metadata.formatVersion !== 1) {
4503
- throw new TypeError(`Unsupported store format for "${store}".`);
4504
- }
4505
- return metadata;
4548
+ return withPinnedProfileDirectory(profile, async (directory) => {
4549
+ const metadata = directory ? await readProfileJson(profile, profileStoreMetadataPath(profile, store)) : null;
4550
+ if (metadata === null) return { formatVersion: 1 };
4551
+ if (typeof metadata !== "object" || metadata.formatVersion !== 1) {
4552
+ throw new TypeError(`Unsupported store format for "${store}".`);
4553
+ }
4554
+ return metadata;
4555
+ });
4506
4556
  }
4507
4557
  async function readProfileStore(profile, store) {
4508
- const [metadata, raw] = await Promise.all([
4509
- readStoreMetadata(profile, store),
4510
- readJson(profileStorePath(profile, store))
4511
- ]);
4512
- return {
4513
- formatVersion: metadata.formatVersion,
4514
- records: Array.isArray(raw) ? raw : []
4515
- };
4558
+ return withPinnedProfileDirectory(profile, async (directory) => {
4559
+ if (!directory) return { formatVersion: 1, records: [] };
4560
+ const [metadata, raw] = await Promise.all([
4561
+ readStoreMetadata(profile, store),
4562
+ readProfileJson(profile, profileStorePath(profile, store))
4563
+ ]);
4564
+ return {
4565
+ formatVersion: metadata.formatVersion,
4566
+ records: Array.isArray(raw) ? raw : []
4567
+ };
4568
+ });
4516
4569
  }
4517
- async function withProfileLock(profile, action, options = {}) {
4518
- const normalizedProfile = validateProfileName(profile);
4519
- const lockPath = profileLockPath(normalizedProfile);
4520
- const held = (heldProfileLocks.getStore() ?? []).filter((ownership2) => ownership2.active);
4521
- if (held.some((ownership2) => ownership2.lockPath === lockPath)) return action();
4522
- const acquired = await acquireProfileLock(normalizedProfile, options);
4523
- const ownership = {
4524
- lockPath,
4525
- turnSlot: acquired.turnSlot,
4526
- deletedWhileWaiting: acquired.deletedWhileWaiting,
4527
- active: true
4528
- };
4570
+ function exactFileId(value) {
4571
+ if (typeof value === "bigint") return value >= 0n ? value : null;
4572
+ return Number.isSafeInteger(value) && value >= 0 ? BigInt(value) : null;
4573
+ }
4574
+ function isPinnedLive(pinned) {
4575
+ if (!pinned.active) return false;
4576
+ try {
4577
+ const stats = (0, import_node_fs.fstatSync)(pinned.fd, { bigint: true });
4578
+ return exactFileId(stats.dev) === pinned.dev && exactFileId(stats.ino) === pinned.ino;
4579
+ } catch {
4580
+ return false;
4581
+ }
4582
+ }
4583
+ function livePinnedPath(profile, pinned) {
4584
+ if (isPinnedLive(pinned)) return pinned.path;
4585
+ throw new ProfileSymlinkError(profile, "its pinned directory is no longer active or changed during use");
4586
+ }
4587
+ async function withPinnedProfileDirectory(profile, action, options = {}) {
4588
+ const named = namedProfilePath(profile);
4589
+ const existing = pinnedProfiles.getStore()?.get(named);
4590
+ if (existing) return action(livePinnedPath(profile, existing));
4591
+ if (process.platform !== "linux") {
4592
+ if (options.create) await (0, import_promises.mkdir)(named, { recursive: true, mode: PRIVATE_DIR_MODE });
4593
+ const stats = await (0, import_promises.lstat)(named).catch((error) => {
4594
+ if (error.code === "ENOENT") return null;
4595
+ throw error;
4596
+ });
4597
+ if (!stats) return action(null);
4598
+ if (!stats.isDirectory() || stats.isSymbolicLink()) throw new ProfileSymlinkError(profile);
4599
+ return action(named);
4600
+ }
4601
+ const home = tinycloudHomePath();
4602
+ const handles = [];
4603
+ const fdPath = (fd) => `/proc/self/fd/${fd}`;
4604
+ const flags = import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_DIRECTORY | import_node_fs.constants.O_NOFOLLOW;
4529
4605
  try {
4530
- return await heldProfileLocks.run([...held, ownership], action);
4606
+ if (options.create) await (0, import_promises.mkdir)(home, { recursive: true, mode: PRIVATE_DIR_MODE });
4607
+ const resolved = canonicalHomes.get(home) ?? await (0, import_promises.realpath)(home).catch((error) => {
4608
+ if (error.code === "ENOENT" && !options.create) return null;
4609
+ if (error.code === "ELOOP" || error.code === "ENOTDIR") throw new ProfileSymlinkError(profile);
4610
+ throw error;
4611
+ });
4612
+ if (!resolved) return await action(null);
4613
+ const root = canonicalHomes.get(home) ?? resolved;
4614
+ canonicalHomes.set(home, root);
4615
+ const segments = [root, "profiles", validateProfileName(profile)];
4616
+ for (let index = 0; index < segments.length; index++) {
4617
+ const path = handles.length ? (0, import_node_path2.join)(fdPath(handles[handles.length - 1].fd), segments[index]) : segments[index];
4618
+ if (options.create && handles.length) {
4619
+ await (0, import_promises.mkdir)(path, { mode: PRIVATE_DIR_MODE }).catch((error) => {
4620
+ if (error.code !== "EEXIST") throw error;
4621
+ });
4622
+ }
4623
+ const handle = await (0, import_promises.open)(path, index === 1 ? flags & ~import_node_fs.constants.O_NOFOLLOW : flags).catch((error) => {
4624
+ if (error.code === "ENOENT" && !options.create) return null;
4625
+ if (error.code === "ELOOP" || error.code === "ENOTDIR") throw new ProfileSymlinkError(profile);
4626
+ throw error;
4627
+ });
4628
+ if (!handle) return await action(null);
4629
+ handles.push(handle);
4630
+ if (options.create) await handle.chmod(PRIVATE_DIR_MODE);
4631
+ }
4632
+ const opened = handles[2];
4633
+ const [actual, namedStats] = await Promise.all([opened.stat({ bigint: true }), (0, import_promises.lstat)(named, { bigint: true })]);
4634
+ const dev = exactFileId(actual.dev);
4635
+ const ino = exactFileId(actual.ino);
4636
+ if (!namedStats.isDirectory() || dev === null || ino === null || dev !== exactFileId(namedStats.dev) || ino !== exactFileId(namedStats.ino)) {
4637
+ throw new ProfileSymlinkError(profile, "changed while opening its directory");
4638
+ }
4639
+ const directory = fdPath(opened.fd);
4640
+ const pinned = {
4641
+ path: directory,
4642
+ fd: opened.fd,
4643
+ dev,
4644
+ ino,
4645
+ active: true
4646
+ };
4647
+ const homeHandle = handles[0];
4648
+ const homeStats = await homeHandle.stat({ bigint: true });
4649
+ const homeDev = exactFileId(homeStats.dev);
4650
+ const homeIno = exactFileId(homeStats.ino);
4651
+ if (homeDev === null || homeIno === null) throw new ProfileSymlinkError(profile, "has an unverified home directory identity");
4652
+ const homePinned = {
4653
+ path: fdPath(homeHandle.fd),
4654
+ fd: homeHandle.fd,
4655
+ dev: homeDev,
4656
+ ino: homeIno,
4657
+ active: true
4658
+ };
4659
+ const context = new Map(pinnedProfiles.getStore());
4660
+ context.set(named, pinned);
4661
+ const homes = new Map(pinnedHomes.getStore());
4662
+ homes.set(home, homePinned);
4663
+ try {
4664
+ return await pinnedHomes.run(homes, () => pinnedProfiles.run(context, () => action(directory)));
4665
+ } finally {
4666
+ pinned.active = false;
4667
+ homePinned.active = false;
4668
+ }
4531
4669
  } finally {
4532
- ownership.active = false;
4533
- await acquired.release();
4534
- if (acquired.deletedWhileWaiting) await (0, import_promises.rmdir)(profilePath(normalizedProfile)).catch(() => void 0);
4670
+ for (const handle of handles.reverse()) await handle.close();
4671
+ }
4672
+ }
4673
+ async function assertRealProfileDirectory(profile) {
4674
+ const named = namedProfilePath(profile);
4675
+ const pinned = pinnedProfiles.getStore()?.get(named);
4676
+ if (pinned) {
4677
+ livePinnedPath(profile, pinned);
4678
+ return;
4535
4679
  }
4680
+ const stats = await (0, import_promises.lstat)(named).catch((error) => {
4681
+ if (error.code === "ENOENT") return null;
4682
+ throw error;
4683
+ });
4684
+ if (stats && (!stats.isDirectory() || stats.isSymbolicLink())) throw new ProfileSymlinkError(profile);
4685
+ }
4686
+ async function withProfileLock(profile, action, options = {}) {
4687
+ const normalizedProfile = validateProfileName(profile);
4688
+ const lockPath = profileLockPath(normalizedProfile);
4689
+ const held = (heldProfileLocks.getStore() ?? []).filter((ownership) => ownership.active);
4690
+ if (held.some((ownership) => ownership.lockPath === lockPath)) {
4691
+ await assertRealProfileDirectory(normalizedProfile);
4692
+ return action();
4693
+ }
4694
+ const named = namedProfilePath(normalizedProfile);
4695
+ const inherited = pinnedProfiles.getStore()?.get(named);
4696
+ if (inherited && !isPinnedLive(inherited)) {
4697
+ const profiles = new Map(pinnedProfiles.getStore());
4698
+ profiles.delete(named);
4699
+ const homes = new Map(pinnedHomes.getStore());
4700
+ homes.delete(tinycloudHomePath());
4701
+ return pinnedHomes.run(homes, () => pinnedProfiles.run(profiles, () => withProfileLock(normalizedProfile, action, options)));
4702
+ }
4703
+ return withPinnedProfileDirectory(normalizedProfile, async (directory) => {
4704
+ if (!directory) throw new ProfileDeletedError(normalizedProfile);
4705
+ const acquired = await acquireProfileLock(normalizedProfile, options);
4706
+ const ownership = {
4707
+ lockPath,
4708
+ turnSlot: acquired.turnSlot,
4709
+ deletedWhileWaiting: acquired.deletedWhileWaiting,
4710
+ active: true
4711
+ };
4712
+ try {
4713
+ return await heldProfileLocks.run([...held, ownership], action);
4714
+ } finally {
4715
+ ownership.active = false;
4716
+ await acquired.release();
4717
+ if (ownership.deletedProfile || acquired.deletedWhileWaiting) {
4718
+ const current = await (0, import_promises.lstat)(namedProfilePath(normalizedProfile), { bigint: true }).catch(() => null);
4719
+ const original = await (0, import_promises.stat)(directory, { bigint: true }).catch(() => null);
4720
+ const currentDev = current && exactFileId(current.dev);
4721
+ const currentIno = current && exactFileId(current.ino);
4722
+ if (currentDev !== null && currentIno !== null && original && currentDev === exactFileId(original.dev) && currentIno === exactFileId(original.ino)) {
4723
+ await (0, import_promises.rmdir)(namedProfilePath(normalizedProfile)).catch(() => void 0);
4724
+ }
4725
+ }
4726
+ }
4727
+ }, { create: !options.requireProfile });
4536
4728
  }
4537
4729
  async function refuseWriteToDeletedProfile(profile) {
4538
4730
  const lockPath = profileLockPath(profile);
@@ -4566,17 +4758,15 @@ async function acquireProfileLock(profile, options) {
4566
4758
  retryMs: options.retryMs ?? DEFAULT_LOCK_RETRY_MS
4567
4759
  };
4568
4760
  const staleAfterMs = options.staleAfterMs ?? DEFAULT_STALE_LOCK_MS;
4569
- const lockPath = profileLockPath(profile);
4761
+ const lockPath = (0, import_node_path2.join)(profilePath(profile), ".lock");
4570
4762
  const turnDirectory = profileTurnLockPath(profile);
4571
4763
  const directory = profilePath(profile);
4764
+ await assertRealProfileDirectory(profile);
4572
4765
  if (options.requireProfile && !await exists(profileConfigPath(profile))) throw new ProfileDeletedError(profile);
4573
4766
  if (!options.requireProfile) await (0, import_promises.mkdir)(directory, { recursive: true, mode: PRIVATE_DIR_MODE });
4767
+ await assertRealProfileDirectory(profile);
4574
4768
  await (0, import_promises.mkdir)((0, import_node_path2.dirname)(turnDirectory), { recursive: true, mode: PRIVATE_DIR_MODE });
4575
- for (const path of [tinycloudHomePath(), profilesPath(), directory]) {
4576
- await (0, import_promises.chmod)(path, PRIVATE_DIR_MODE).catch((error) => {
4577
- if (path !== directory || !isErrno(error, "ENOENT")) throw error;
4578
- });
4579
- }
4769
+ await (0, import_promises.chmod)(directory, PRIVATE_DIR_MODE);
4580
4770
  const liveness = { directory: turnDirectory, held: void 0 };
4581
4771
  const closeAcquisitionLiveness = async () => {
4582
4772
  if (liveness.held) await closeLiveness(liveness.held);
@@ -4596,6 +4786,7 @@ async function acquireProfileLock(profile, options) {
4596
4786
  }
4597
4787
  const deletion = await readJson((0, import_node_path2.join)(turnDirectory, "deleted.json")).catch(() => null);
4598
4788
  const deletedWhileWaiting = typeof deletion?.slot === "number" && deletion.slot >= firstWaitedTurn;
4789
+ if (deletedWhileWaiting && !await exists(profileConfigPath(profile))) throw new ProfileDeletedError(profile);
4599
4790
  while (true) {
4600
4791
  const token = (0, import_node_crypto.randomUUID)();
4601
4792
  if (await publishProfileLock(profile, lockPath, token, options.requireProfile === true, liveness.held ?? null)) {
@@ -4741,7 +4932,7 @@ async function takeTurn(profile, directory, latest, liveness) {
4741
4932
  if (published) await markTurn(path, token, "done");
4742
4933
  return null;
4743
4934
  } catch (error) {
4744
- if (published) settleOwnTurn(directory, slot, token);
4935
+ if (published) await settleOwnTurn(directory, slot, token);
4745
4936
  throw error;
4746
4937
  }
4747
4938
  }
@@ -4752,17 +4943,25 @@ async function settleAbandonedTurn(directory, abandoned) {
4752
4943
  }
4753
4944
  await markTurn(path, abandoned.token, "done");
4754
4945
  }
4755
- function settleOwnTurn(directory, slot, token, retries = SETTLE_RETRIES) {
4946
+ async function settleOwnTurn(directory, slot, token) {
4756
4947
  relinquishedTurns.add(token);
4757
- void (async () => {
4758
- try {
4759
- const turn = await readTurn(directory, slot);
4760
- if (turn !== null && turn !== "damaged" && turn.token === token && !turn.done) await settleAbandonedTurn(directory, turn);
4761
- relinquishedTurns.delete(token);
4762
- } catch {
4763
- if (retries > 0) setTimeout(() => settleOwnTurn(directory, slot, token, retries - 1), SETTLE_RETRY_MS).unref();
4764
- }
4765
- })();
4948
+ const pinned = await pinDirectory(directory).catch(() => null);
4949
+ const path = pinned?.path(".") ?? directory;
4950
+ let retries = SETTLE_RETRIES;
4951
+ const attempt = () => {
4952
+ void (async () => {
4953
+ try {
4954
+ const turn = await readTurn(path, slot);
4955
+ if (turn !== null && turn !== "damaged" && turn.token === token && !turn.done) await settleAbandonedTurn(path, turn);
4956
+ relinquishedTurns.delete(token);
4957
+ await pinned?.close();
4958
+ } catch {
4959
+ if (retries-- > 0) setTimeout(attempt, SETTLE_RETRY_MS).unref();
4960
+ else await pinned?.close();
4961
+ }
4962
+ })();
4963
+ };
4964
+ attempt();
4766
4965
  }
4767
4966
  async function markTurn(path, token, kind) {
4768
4967
  for (let attempt = 0; ; attempt++) {
@@ -4807,7 +5006,7 @@ async function releaseTurn(profile, turn, liveness) {
4807
5006
  try {
4808
5007
  await markTurn((0, import_node_path2.join)(turn.directory, String(turn.slot)), turn.token, "done");
4809
5008
  } catch {
4810
- settleOwnTurn(turn.directory, turn.slot, turn.token);
5009
+ await settleOwnTurn(turn.directory, turn.slot, turn.token);
4811
5010
  return;
4812
5011
  }
4813
5012
  await collectTurns(profile, turn, liveness).catch(() => void 0);
@@ -5091,7 +5290,7 @@ function isErrno(error, code) {
5091
5290
  function sleep(milliseconds) {
5092
5291
  return new Promise((resolve2) => setTimeout(resolve2, milliseconds));
5093
5292
  }
5094
- var import_node_crypto, import_node_async_hooks, import_node_fs, import_promises, import_node_net, import_node_os, import_node_path2, DEFAULT_PROFILE, DEFAULT_LOCK_TIMEOUT_MS, DEFAULT_LOCK_RETRY_MS, DEFAULT_STALE_LOCK_MS, TEST_LOCK_CONTENTION_SIGNAL_PATH, PRIVATE_FILE_MODE, PRIVATE_DIR_MODE, TEST_LOCK_RECOVERY_BARRIER_DIR, TEST_LOCK_OWNERLESS_BARRIER_DIR, TEST_LOCK_PUBLISH_BARRIER_DIR, TEST_LOCK_RELEASE_BARRIER_DIR, TEST_LOCK_CLAIM_BARRIER_DIR, TEST_LOCK_CLAIMED_BARRIER_DIR, TEST_LOCK_VERIFIED_BARRIER_DIR, TEST_LOCK_MOVED_BARRIER_DIR, TEST_LOCK_TURN_PUBLISH_BARRIER_DIR, TEST_LOCK_TURN_SETTLE_BARRIER_DIR, TEST_LOCK_TURN_COLLECT_BARRIER_DIR, TEST_LOCK_LIVENESS_BARRIER_DIR, invocationStateRoot, heldProfileLocks, _a2, processInstanceId, cachedProcessOrigin, LIVENESS_SOCKET, LIVENESS_PROBE_TIMEOUT_MS, ProfileLockTimeoutError, ProfileDeletedError, TURN, _a3, relinquishedTurns, MARKER_RETRY_DELAYS_MS, SETTLE_RETRY_MS, SETTLE_RETRIES, NO_HARD_LINK_ERRORS, ABANDONED_CLAIM, RECOVERY_CLAIM, STAGED_OWNER;
5293
+ var import_node_crypto, import_node_async_hooks, import_node_fs, import_promises, import_node_net, import_node_os, import_node_path2, DEFAULT_PROFILE, DEFAULT_LOCK_TIMEOUT_MS, DEFAULT_LOCK_RETRY_MS, DEFAULT_STALE_LOCK_MS, TEST_LOCK_CONTENTION_SIGNAL_PATH, PRIVATE_FILE_MODE, PRIVATE_DIR_MODE, TEST_LOCK_RECOVERY_BARRIER_DIR, TEST_LOCK_OWNERLESS_BARRIER_DIR, TEST_LOCK_PUBLISH_BARRIER_DIR, TEST_LOCK_RELEASE_BARRIER_DIR, TEST_LOCK_CLAIM_BARRIER_DIR, TEST_LOCK_CLAIMED_BARRIER_DIR, TEST_LOCK_VERIFIED_BARRIER_DIR, TEST_LOCK_MOVED_BARRIER_DIR, TEST_LOCK_TURN_PUBLISH_BARRIER_DIR, TEST_LOCK_TURN_SETTLE_BARRIER_DIR, TEST_LOCK_TURN_COLLECT_BARRIER_DIR, TEST_LOCK_LIVENESS_BARRIER_DIR, invocationStateRoot, heldProfileLocks, pinnedProfiles, pinnedHomes, _a2, canonicalHomes, _a3, processInstanceId, cachedProcessOrigin, LIVENESS_SOCKET, LIVENESS_PROBE_TIMEOUT_MS, ProfileLockTimeoutError, ProfileDeletedError, ProfileSymlinkError, TURN, _a4, relinquishedTurns, MARKER_RETRY_DELAYS_MS, SETTLE_RETRY_MS, SETTLE_RETRIES, NO_HARD_LINK_ERRORS, ABANDONED_CLAIM, RECOVERY_CLAIM, STAGED_OWNER;
5095
5294
  var init_state = __esm({
5096
5295
  "src/state.ts"() {
5097
5296
  "use strict";
@@ -5123,7 +5322,10 @@ var init_state = __esm({
5123
5322
  TEST_LOCK_LIVENESS_BARRIER_DIR = "TC_TEST_PROFILE_LOCK_LIVENESS_BARRIER_DIR";
5124
5323
  invocationStateRoot = processWideContext("tinycloud.operations.invocationStateRoot.v1");
5125
5324
  heldProfileLocks = processWideContext("tinycloud.operations.heldProfileLocks.v2");
5126
- processInstanceId = globalThis[_a2 = /* @__PURE__ */ Symbol.for("tinycloud.operations.profileLockInstance.v1")] ?? (globalThis[_a2] = (0, import_node_crypto.randomUUID)());
5325
+ pinnedProfiles = processWideContext("tinycloud.operations.pinnedProfiles.v2");
5326
+ pinnedHomes = processWideContext("tinycloud.operations.pinnedHomes.v2");
5327
+ canonicalHomes = globalThis[_a2 = /* @__PURE__ */ Symbol.for("tinycloud.operations.canonicalHomes.v1")] ?? (globalThis[_a2] = /* @__PURE__ */ new Map());
5328
+ processInstanceId = globalThis[_a3 = /* @__PURE__ */ Symbol.for("tinycloud.operations.profileLockInstance.v1")] ?? (globalThis[_a3] = (0, import_node_crypto.randomUUID)());
5127
5329
  LIVENESS_SOCKET = /^\.live-([0-9a-f]+)-([0-9a-f]+)-[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}(\.new)?$/;
5128
5330
  LIVENESS_PROBE_TIMEOUT_MS = 1e3;
5129
5331
  ProfileLockTimeoutError = class extends Error {
@@ -5141,8 +5343,15 @@ var init_state = __esm({
5141
5343
  this.name = "ProfileDeletedError";
5142
5344
  }
5143
5345
  };
5346
+ ProfileSymlinkError = class extends Error {
5347
+ constructor(profile, detail = "must be a real directory, not a symlink or another file type") {
5348
+ super(`Profile "${profile}" ${detail}.`);
5349
+ this.code = "PROFILE_SYMLINK";
5350
+ this.name = "ProfileSymlinkError";
5351
+ }
5352
+ };
5144
5353
  TURN = /^(?:0|[1-9][0-9]*)$/;
5145
- relinquishedTurns = globalThis[_a3 = /* @__PURE__ */ Symbol.for("tinycloud.operations.relinquishedProfileTurns.v1")] ?? (globalThis[_a3] = /* @__PURE__ */ new Set());
5354
+ relinquishedTurns = globalThis[_a4 = /* @__PURE__ */ Symbol.for("tinycloud.operations.relinquishedProfileTurns.v1")] ?? (globalThis[_a4] = /* @__PURE__ */ new Set());
5146
5355
  MARKER_RETRY_DELAYS_MS = [10, 50, 250];
5147
5356
  SETTLE_RETRY_MS = 1e3;
5148
5357
  SETTLE_RETRIES = 300;