()
| 155 | * false and the Grove dialog won't show until the next session. |
| 156 | */ |
| 157 | export async function isQualifiedForGrove(): Promise<boolean> { |
| 158 | if (!isConsumerSubscriber()) { |
| 159 | return false |
| 160 | } |
| 161 | |
| 162 | const accountId = getOauthAccountInfo()?.accountUuid |
| 163 | if (!accountId) { |
| 164 | return false |
| 165 | } |
| 166 | |
| 167 | const globalConfig = getGlobalConfig() |
| 168 | const cachedEntry = globalConfig.groveConfigCache?.[accountId] |
| 169 | const now = Date.now() |
| 170 | |
| 171 | // No cache - trigger background fetch and return false (non-blocking) |
| 172 | // The Grove dialog won't show this session, but will next time if eligible |
| 173 | if (!cachedEntry) { |
| 174 | logForDebugging( |
| 175 | 'Grove: No cache, fetching config in background (dialog skipped this session)', |
| 176 | ) |
| 177 | void fetchAndStoreGroveConfig(accountId) |
| 178 | return false |
| 179 | } |
| 180 | |
| 181 | // Cache exists but is stale - return cached value and refresh in background |
| 182 | if (now - cachedEntry.timestamp > GROVE_CACHE_EXPIRATION_MS) { |
| 183 | logForDebugging( |
| 184 | 'Grove: Cache stale, returning cached data and refreshing in background', |
| 185 | ) |
| 186 | void fetchAndStoreGroveConfig(accountId) |
| 187 | return cachedEntry.grove_enabled |
| 188 | } |
| 189 | |
| 190 | // Cache is fresh - return it immediately |
| 191 | logForDebugging('Grove: Using fresh cached config') |
| 192 | return cachedEntry.grove_enabled |
| 193 | } |
| 194 | |
| 195 | /** |
| 196 | * Fetch Grove config from API and store in cache |
no test coverage detected