@narumitw/pi-sync 0.49.9 → 0.49.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narumitw/pi-sync",
3
- "version": "0.49.9",
3
+ "version": "0.49.10",
4
4
  "description": "Pi extension that syncs Pi configuration through Git, WebDAV, Cloudflare R2, or S3-compatible storage.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -22,6 +22,14 @@ interface StateDirectoryGuard {
22
22
  throwIfCompromised: () => void;
23
23
  }
24
24
 
25
+ interface SharedStateDirectoryGuard {
26
+ guard: Promise<StateDirectoryGuard>;
27
+ users: number;
28
+ closing?: Promise<void>;
29
+ }
30
+
31
+ const sharedStateDirectoryGuards = new Map<string, SharedStateDirectoryGuard>();
32
+
25
33
  export function stateDir() {
26
34
  const roots = inspectStateRoots();
27
35
  if (roots.canonical) return canonicalStateDir();
@@ -40,7 +48,9 @@ export function stateDirectoryMigrationNotice() {
40
48
  }
41
49
 
42
50
  export async function withStateDirectoryAccess<T>(fn: () => Promise<T>): Promise<T> {
43
- return runWithStateDirectoryGuard(await acquireStateDirectoryGuard(), fn);
51
+ const roots = inspectStateRoots();
52
+ if (!roots.legacy) return fn();
53
+ return runWithStateDirectoryGuard(await acquireSharedStateDirectoryGuard(), fn);
44
54
  }
45
55
 
46
56
  export async function migrateLegacyStateDirectory(): Promise<StateDirectoryPreparation> {
@@ -87,6 +97,50 @@ export async function migrateLegacyStateDirectory(): Promise<StateDirectoryPrepa
87
97
  });
88
98
  }
89
99
 
100
+ async function acquireSharedStateDirectoryGuard(): Promise<StateDirectoryGuard> {
101
+ const key = migrationLockPath();
102
+ for (;;) {
103
+ let shared = sharedStateDirectoryGuards.get(key);
104
+ if (shared?.closing) {
105
+ await shared.closing;
106
+ continue;
107
+ }
108
+ if (!shared) {
109
+ shared = { guard: acquireStateDirectoryGuard(), users: 0 };
110
+ sharedStateDirectoryGuards.set(key, shared);
111
+ }
112
+ shared.users += 1;
113
+ let guard: StateDirectoryGuard;
114
+ try {
115
+ guard = await shared.guard;
116
+ } catch (error) {
117
+ if (sharedStateDirectoryGuards.get(key) === shared) {
118
+ sharedStateDirectoryGuards.delete(key);
119
+ }
120
+ throw error;
121
+ }
122
+ let released = false;
123
+ return {
124
+ throwIfCompromised: guard.throwIfCompromised,
125
+ release: async () => {
126
+ if (released) return;
127
+ released = true;
128
+ shared.users -= 1;
129
+ if (shared.users > 0) return;
130
+ const closing = guard.release();
131
+ shared.closing = closing;
132
+ try {
133
+ await closing;
134
+ } finally {
135
+ if (sharedStateDirectoryGuards.get(key) === shared) {
136
+ sharedStateDirectoryGuards.delete(key);
137
+ }
138
+ }
139
+ },
140
+ };
141
+ }
142
+ }
143
+
90
144
  async function acquireStateDirectoryGuard(): Promise<StateDirectoryGuard> {
91
145
  let compromisedError: Error | undefined;
92
146
  const release = await lockfile.lock(getAgentDir(), {