Skip to content

Commit 1c1db2f

Browse files
committed
Restore CWD symlink normalization in VcsStatusBroadcaster
The old GitStatusBroadcasterLive resolved symlinks via realpathSync.native before using the path as a cache key or PubSub filter. The new VcsStatusBroadcaster omitted this normalization, causing symlinked workspace paths to create duplicate cache entries and streamStatus event filtering to miss updates published under the resolved real path. Restore the normalizeCwd helper and call it in getStatus, refreshLocalStatus, refreshStatus, and streamStatus to match the old behavior.
1 parent a2b1bb4 commit 1c1db2f

1 file changed

Lines changed: 23 additions & 9 deletions

File tree

apps/server/src/vcs/VcsStatusBroadcaster.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { realpathSync } from "node:fs";
2+
13
import {
24
Duration,
35
Effect,
@@ -63,6 +65,14 @@ export class VcsStatusBroadcaster extends Context.Service<
6365
VcsStatusBroadcasterShape
6466
>()("t3/vcs/VcsStatusBroadcaster") {}
6567

68+
function normalizeCwd(cwd: string): string {
69+
try {
70+
return realpathSync.native(cwd);
71+
} catch {
72+
return cwd;
73+
}
74+
}
75+
6676
function fingerprintStatusPart(status: unknown): string {
6777
return JSON.stringify(status);
6878
}
@@ -188,16 +198,18 @@ export const layer = Layer.effect(
188198
const getStatus: VcsStatusBroadcasterShape["getStatus"] = Effect.fn(
189199
"VcsStatusBroadcaster.getStatus",
190200
)(function* (input) {
201+
const cwd = normalizeCwd(input.cwd);
191202
const [local, remote] = yield* Effect.all([
192-
getOrLoadLocalStatus(input.cwd),
193-
getOrLoadRemoteStatus(input.cwd),
203+
getOrLoadLocalStatus(cwd),
204+
getOrLoadRemoteStatus(cwd),
194205
]);
195206
return mergeGitStatusParts(local, remote);
196207
});
197208

198209
const refreshLocalStatus: VcsStatusBroadcasterShape["refreshLocalStatus"] = Effect.fn(
199210
"VcsStatusBroadcaster.refreshLocalStatus",
200-
)(function* (cwd) {
211+
)(function* (rawCwd) {
212+
const cwd = normalizeCwd(rawCwd);
201213
yield* workflow.invalidateLocalStatus(cwd);
202214
const local = yield* workflow.localStatus({ cwd });
203215
return yield* updateCachedLocalStatus(cwd, local, { publish: true });
@@ -213,7 +225,8 @@ export const layer = Layer.effect(
213225

214226
const refreshStatus: VcsStatusBroadcasterShape["refreshStatus"] = Effect.fn(
215227
"VcsStatusBroadcaster.refreshStatus",
216-
)(function* (cwd) {
228+
)(function* (rawCwd) {
229+
const cwd = normalizeCwd(rawCwd);
217230
const [local, remote] = yield* Effect.all([
218231
refreshLocalStatus(cwd),
219232
refreshRemoteStatus(cwd),
@@ -299,12 +312,13 @@ export const layer = Layer.effect(
299312
const streamStatus: VcsStatusBroadcasterShape["streamStatus"] = (input) =>
300313
Stream.unwrap(
301314
Effect.gen(function* () {
315+
const cwd = normalizeCwd(input.cwd);
302316
const subscription = yield* PubSub.subscribe(changesPubSub);
303-
const initialLocal = yield* getOrLoadLocalStatus(input.cwd);
304-
const initialRemote = (yield* getCachedStatus(input.cwd))?.remote?.value ?? null;
305-
yield* retainRemotePoller(input.cwd);
317+
const initialLocal = yield* getOrLoadLocalStatus(cwd);
318+
const initialRemote = (yield* getCachedStatus(cwd))?.remote?.value ?? null;
319+
yield* retainRemotePoller(cwd);
306320

307-
const release = releaseRemotePoller(input.cwd).pipe(Effect.ignore, Effect.asVoid);
321+
const release = releaseRemotePoller(cwd).pipe(Effect.ignore, Effect.asVoid);
308322

309323
return Stream.concat(
310324
Stream.make({
@@ -313,7 +327,7 @@ export const layer = Layer.effect(
313327
remote: initialRemote,
314328
}),
315329
Stream.fromSubscription(subscription).pipe(
316-
Stream.filter((event) => event.cwd === input.cwd),
330+
Stream.filter((event) => event.cwd === cwd),
317331
Stream.map((event) => event.event),
318332
),
319333
).pipe(Stream.ensuring(release));

0 commit comments

Comments
 (0)