()
| 1116 | } |
| 1117 | |
| 1118 | export function getGlobalConfig(): GlobalConfig { |
| 1119 | if (process.env.NODE_ENV === 'test') { |
| 1120 | return TEST_GLOBAL_CONFIG_FOR_TESTING |
| 1121 | } |
| 1122 | |
| 1123 | // Fast path: pure memory read. After startup, this always hits — our own |
| 1124 | // writes go write-through and other instances' writes are picked up by the |
| 1125 | // background freshness watcher (never blocks this path). |
| 1126 | if (globalConfigCache.config) { |
| 1127 | configCacheHits++ |
| 1128 | return globalConfigCache.config |
| 1129 | } |
| 1130 | |
| 1131 | // Slow path: startup load. Sync I/O here is acceptable because it runs |
| 1132 | // exactly once, before any UI is rendered. Stat before read so any race |
| 1133 | // self-corrects (old mtime + new content → watcher re-reads next tick). |
| 1134 | configCacheMisses++ |
| 1135 | try { |
| 1136 | let stats: { mtimeMs: number; size: number } | null = null |
| 1137 | try { |
| 1138 | stats = getFsImplementation().statSync(getGlobalNcodeFile()) |
| 1139 | } catch { |
| 1140 | // File doesn't exist |
| 1141 | } |
| 1142 | const config = migrateConfigFields( |
| 1143 | getConfig(getGlobalNcodeFile(), createDefaultGlobalConfig), |
| 1144 | ) |
| 1145 | globalConfigCache = { |
| 1146 | config, |
| 1147 | mtime: stats?.mtimeMs ?? Date.now(), |
| 1148 | } |
| 1149 | lastReadFileStats = stats |
| 1150 | ? { mtime: stats.mtimeMs, size: stats.size } |
| 1151 | : null |
| 1152 | startGlobalConfigFreshnessWatcher() |
| 1153 | return config |
| 1154 | } catch { |
| 1155 | // If anything goes wrong, fall back to uncached behavior |
| 1156 | return migrateConfigFields( |
| 1157 | getConfig(getGlobalNcodeFile(), createDefaultGlobalConfig), |
| 1158 | ) |
| 1159 | } |
| 1160 | } |
| 1161 | |
| 1162 | /** |
| 1163 | * Returns the effective value of remoteControlAtStartup. Precedence: |
no test coverage detected