()
| 145 | * an extra one during the 24h window is acceptable. |
| 146 | */ |
| 147 | export async function checkMetricsEnabled(): Promise<MetricsStatus> { |
| 148 | const session = getAuthRuntime().getCurrentSession() |
| 149 | // Service key OAuth sessions lack user:profile scope → would 403. |
| 150 | // API key users (non-subscribers) fall through and use x-api-key auth. |
| 151 | // This check runs before the disk read so we never persist auth-state-derived |
| 152 | // answers — only real API responses go to disk. Otherwise a service-key |
| 153 | // session would poison the cache for a later full-OAuth session. |
| 154 | if (shouldSkipMetricsEnabledFetchForSession(session)) { |
| 155 | return { enabled: false, hasError: false } |
| 156 | } |
| 157 | |
| 158 | const cached = getGlobalConfig().metricsStatusCache |
| 159 | if (cached) { |
| 160 | if (Date.now() - cached.timestamp > DISK_CACHE_TTL_MS) { |
| 161 | // saveGlobalConfig's fallback path (config.ts:731) can throw if both |
| 162 | // locked and fallback writes fail — catch here so fire-and-forget |
| 163 | // doesn't become an unhandled rejection. |
| 164 | void refreshMetricsStatus().catch(logError) |
| 165 | } |
| 166 | return { |
| 167 | enabled: cached.enabled, |
| 168 | hasError: false, |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | // First-ever run on this machine: block on the network to populate disk. |
| 173 | return refreshMetricsStatus() |
| 174 | } |
| 175 | |
| 176 | // Export for testing purposes only |
| 177 | export const _clearMetricsEnabledCacheForTesting = (): void => { |
no test coverage detected