refactor(cli-core): remove configstore dependency, use sync config I/O#752
refactor(cli-core): remove configstore dependency, use sync config I/O#752
Conversation
|
Claude finished @rexxars's task in 2m 31s —— View job PR Review
1.
|
7505e1b to
5f5c293
Compare
Coverage Delta
Comparing 15 changed files against main @ Overall Coverage
|
b00e512 to
2ba9bda
Compare
Replace the configstore-backed getUserConfig() with a dependency-free implementation that reads/writes the CLI config JSON file directly using sync I/O. This fixes a race condition in logout where concurrent async read-modify-write cycles on the same config file could silently lose data (e.g. telemetry consent surviving a logout). The getUserConfig() public API keeps its name. The return type narrows from configstore's ConfigStore class to a minimal ConfigStore interface with get/set/delete. Moves telemetry utilities from src/util/ to src/telemetry/ in cli-core. Removes 6 transitive packages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2ba9bda to
bdac322
Compare
…il tests Make setCliUserConfig explicitly remove the key when called with undefined instead of relying on JSON.stringify silently dropping it. Add unit tests for readJsonFileSync and writeJsonFileSync error paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ConfigStore.delete now skips the write when the key doesn't exist, avoiding creating an empty config file as a side effect. - writeJsonFileSync appends a trailing newline for POSIX compatibility and to avoid spurious diffs with files written by configstore. - Cleaned up dead code in readJsonFileSync tests and tightened writeJsonFileSync test assertions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The flush worker stdio was gated on `debug.enabled` (sanity:cli namespace), but the worker logs using `telemetryDebug` (telemetry:sanity:cli namespace). Running with DEBUG=telemetry:sanity:cli:* would not inherit stdio, so worker output went nowhere. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous tests spied on getCliToken and re-implemented its logic (incorrectly using async getCliUserConfig). Now uses vi.resetModules() + dynamic import to get a fresh module per test, exercises the real sync code path, and uses vi.stubEnv for cleaner env management. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t mkdirSync setCliUserConfig now calls clearCliTokenCache() so that subsequent getCliToken() calls in the same process pick up the new value. Also removes the redundant mkdirSync from ConfigStore.delete() - if readConfig() succeeded, the directory already exists. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tCliToken Extract token cache into a separate cliTokenCache module that both cliUserConfig.ts and getCliToken.ts can import without creating a cycle. Fixes the import-x/no-cycle lint error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Description
Removes the
configstorenpm dependency from@sanity/cli-coreand replaces it with a minimal sync implementation that reads/writes~/.config/sanity/config.jsondirectly.The motivation:
configstoreuses async I/O internally, and the logout command ran two concurrent async read-modify-write cycles viaPromise.all(clearing auth token + clearing telemetry consent). This created an intra-process race condition where one write could overwrite the other, leaving stale values in the config file - most notably, telemetry consent status ("denied") surviving a logout/re-login cycle.Switching to synchronous I/O makes each read-modify-write atomic within a single event loop tick, eliminating this class of bug. Cross-process races (two CLI processes writing simultaneously) are still theoretically possible but unchanged from before and unlikely in practice since config writes are rare and user-initiated.
Also moves telemetry utilities (
getCliTelemetry,readNDJSON) fromsrc/util/tosrc/telemetry/where they belong.What to review
packages/@sanity/cli-core/src/services/cliUserConfig.ts- core change. The newgetUserConfig()returns aConfigStorewith syncget/set/deletemethods. This is a subset of whatconfigstoreexposed (no.all,.path,.size), but those were unused.packages/@sanity/cli/src/commands/logout.ts- the bug fix.clearConfig()now uses sequential sync calls instead ofPromise.allwith async configstore.packages/@sanity/cli-core/src/util/readJsonFileSync.tsandwriteJsonFileSync.ts- new sync file utilities.Testing
The
cliUserConfig.test.tssuite was rewritten with 19 tests covering the sync API andConfigStoreinterface. All existing tests for callers (logout, login, telemetry, debug, etc.) were updated to mock the newgetUserConfigexport path.Run
pnpm testfrom the repo root to verify.