| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- /**
- * Leaf state module for the remote-managed-settings sync cache.
- *
- * Split from syncCache.ts to break the settings.ts → syncCache.ts → auth.ts →
- * settings.ts cycle. auth.ts sits inside the large settings SCC; importing it
- * from settings.ts's own dependency chain pulls hundreds of modules into the
- * eagerly-evaluated SCC at startup.
- *
- * This module imports only leaves (path, envUtils, file, json, types,
- * settings/settingsCache — also a leaf, only type-imports validation). settings.ts
- * reads the cache from here. syncCache.ts keeps isRemoteManagedSettingsEligible
- * (the auth-touching part) and re-exports everything from here for callers that
- * don't care about the cycle.
- *
- * Eligibility is a tri-state here: undefined (not yet determined — return
- * null), false (ineligible — return null), true (proceed). managedEnv.ts
- * calls isRemoteManagedSettingsEligible() just before the policySettings
- * read — after userSettings/flagSettings env vars are applied, so the check
- * sees config-provided CLAUDE_CODE_USE_BEDROCK/ANTHROPIC_BASE_URL. That call
- * computes once and mirrors the result here via setEligibility(). Every
- * subsequent read hits the cached bool instead of re-running the auth chain.
- */
- import { join } from 'path'
- import { getClaudeConfigHomeDir } from '../../utils/envUtils.js'
- import { readFileSync } from '../../utils/fileRead.js'
- import { stripBOM } from '../../utils/jsonRead.js'
- import { resetSettingsCache } from '../../utils/settings/settingsCache.js'
- import type { SettingsJson } from '../../utils/settings/types.js'
- import { jsonParse } from '../../utils/slowOperations.js'
- const SETTINGS_FILENAME = 'remote-settings.json'
- let sessionCache: SettingsJson | null = null
- let eligible: boolean | undefined
- export function setSessionCache(value: SettingsJson | null): void {
- sessionCache = value
- }
- export function resetSyncCache(): void {
- sessionCache = null
- eligible = undefined
- }
- export function setEligibility(v: boolean): boolean {
- eligible = v
- return v
- }
- export function getSettingsPath(): string {
- return join(getClaudeConfigHomeDir(), SETTINGS_FILENAME)
- }
- // sync IO — settings pipeline is sync. fileRead and jsonRead are leaves;
- // file.ts and json.ts both sit in the settings SCC.
- function loadSettings(): SettingsJson | null {
- try {
- const content = readFileSync(getSettingsPath())
- const data: unknown = jsonParse(stripBOM(content))
- if (!data || typeof data !== 'object' || Array.isArray(data)) {
- return null
- }
- return data as SettingsJson
- } catch {
- return null
- }
- }
- export function getRemoteManagedSettingsSyncFromCache(): SettingsJson | null {
- if (eligible !== true) return null
- if (sessionCache) return sessionCache
- const cachedSettings = loadSettings()
- if (cachedSettings) {
- sessionCache = cachedSettings
- // Remote settings just became available for the first time. Any merged
- // getSettings_DEPRECATED() result cached before this moment is missing
- // the policySettings layer (the `eligible !== true` guard above returned
- // null). Flush so the next merged read re-merges with this layer visible.
- //
- // Fires at most once: subsequent calls hit `if (sessionCache)` above.
- // When called from loadSettingsFromDisk() (settings.ts:546), the merged
- // cache is still null (setSessionSettingsCache runs at :732 after
- // loadSettingsFromDisk returns) — no-op. The async-fetch arm (index.ts
- // setSessionCache + notifyChange) already handles its own reset.
- //
- // gh-23085: isBridgeEnabled() at main.tsx Commander-definition time
- // (before preAction → init() → isRemoteManagedSettingsEligible()) reached
- // getSettings_DEPRECATED() at auth.ts:115. The try/catch in bridgeEnabled
- // swallowed the later getGlobalConfig() throw, but the merged settings
- // cache was already poisoned. See managedSettingsHeadless.int.test.ts.
- resetSettingsCache()
- return cachedSettings
- }
- return null
- }
|