Skip to content

Commit 76d0847

Browse files
t3dotggclaude
andcommitted
fix(server): expire the editor discovery cache on the monotonic clock
Matches the command-resolution cache in @t3tools/shared/shell so a backward wall-clock adjustment cannot keep an expired entry alive. Co-Authored-By: Claude <[email protected]>
1 parent c85b596 commit 76d0847

1 file changed

Lines changed: 8 additions & 6 deletions

File tree

‎apps/server/src/process/externalLauncher.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { isCommandAvailable, resolveSpawnCommand } from "@t3tools/shared/shell";
2222
import * as Clock from "effect/Clock";
2323
import * as Config from "effect/Config";
2424
import * as Context from "effect/Context";
25-
import * as Duration from "effect/Duration";
2625
import * as Effect from "effect/Effect";
2726
import * as Encoding from "effect/Encoding";
2827
import * as FileSystem from "effect/FileSystem";
@@ -313,11 +312,14 @@ const resolveAvailableEditors = Effect.fn("externalLauncher.resolveAvailableEdit
313312
// to every later connect for the whole TTL, breaking `server.getConfig`
314313
// permanently. Storing only on success means an interrupted scan leaves the
315314
// cache untouched and the next connect simply rescans.
316-
const EDITOR_DISCOVERY_CACHE_TTL = Duration.seconds(60);
315+
// Expiry uses the monotonic clock (Clock.currentTimeNanos), matching the
316+
// command-resolution cache in @t3tools/shared/shell, so a backward wall-clock
317+
// adjustment cannot keep an expired entry alive.
318+
const EDITOR_DISCOVERY_CACHE_TTL_NANOS = 60_000_000_000n;
317319

318320
interface EditorDiscoveryCacheEntry {
319321
readonly editors: ReadonlyArray<EditorId>;
320-
readonly expiresAtMillis: number;
322+
readonly expiresAtNanos: bigint;
321323
}
322324

323325
/**
@@ -469,17 +471,17 @@ export const make = Effect.gen(function* () {
469471
Option.none(),
470472
);
471473
const cachedAvailableEditors = Effect.gen(function* () {
472-
const nowMillis = yield* Clock.currentTimeMillis;
474+
const nowNanos = yield* Clock.currentTimeNanos;
473475
const entry = yield* Ref.get(editorDiscoveryCache);
474-
if (Option.isSome(entry) && entry.value.expiresAtMillis > nowMillis) {
476+
if (Option.isSome(entry) && entry.value.expiresAtNanos > nowNanos) {
475477
return entry.value.editors;
476478
}
477479
const editors = yield* provideCommandResolutionServices(resolveAvailableEditors());
478480
yield* Ref.set(
479481
editorDiscoveryCache,
480482
Option.some({
481483
editors,
482-
expiresAtMillis: nowMillis + Duration.toMillis(EDITOR_DISCOVERY_CACHE_TTL),
484+
expiresAtNanos: nowNanos + EDITOR_DISCOVERY_CACHE_TTL_NANOS,
483485
}),
484486
);
485487
return editors;

0 commit comments

Comments
 (0)