(context: vscode.ExtensionContext)
| 17 | let _cachedUserImage: string | undefined = undefined |
| 18 | |
| 19 | export async function initZooCodeAuth(context: vscode.ExtensionContext): Promise<void> { |
| 20 | if (!context.secrets) { |
| 21 | // Secret storage unavailable (e.g. test environment without secrets mock). |
| 22 | // Treat as unauthenticated startup — all cached values remain undefined. |
| 23 | return |
| 24 | } |
| 25 | secretStorage = context.secrets |
| 26 | |
| 27 | // Pre-load the token and user info into memory on init so ZooCodeHandler can access them synchronously |
| 28 | _cachedToken = await secretStorage.get(ZOO_CODE_TOKEN_KEY) |
| 29 | _sessionCleared = false |
| 30 | _cachedUserName = await secretStorage.get(ZOO_CODE_USER_NAME_KEY) |
| 31 | _cachedUserEmail = await secretStorage.get(ZOO_CODE_USER_EMAIL_KEY) |
| 32 | _cachedUserImage = await secretStorage.get(ZOO_CODE_USER_IMAGE_KEY) |
| 33 | |
| 34 | // Validate persisted auth state on init before reporting the user as connected. |
| 35 | // Network errors / 5xx ("unreachable") leave the cached session in place so a |
| 36 | // transient backend blip doesn't force users to sign in again. |
| 37 | if (_cachedToken) { |
| 38 | const result = await verifyZooCodeToken() |
| 39 | if (result === "invalid") { |
| 40 | await clearZooCodeUserInfo() |
| 41 | await clearZooCodeToken() |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | // Watch for secret changes and update cache |
| 46 | context.secrets.onDidChange((e) => { |
| 47 | if (e.key === ZOO_CODE_TOKEN_KEY) { |
| 48 | secretStorage?.get(ZOO_CODE_TOKEN_KEY).then((token) => { |
| 49 | _cachedToken = token |
| 50 | }) |
| 51 | } |
| 52 | if (e.key === ZOO_CODE_USER_NAME_KEY) { |
| 53 | secretStorage?.get(ZOO_CODE_USER_NAME_KEY).then((name) => { |
| 54 | _cachedUserName = name |
| 55 | }) |
| 56 | } |
| 57 | if (e.key === ZOO_CODE_USER_EMAIL_KEY) { |
| 58 | secretStorage?.get(ZOO_CODE_USER_EMAIL_KEY).then((email) => { |
| 59 | _cachedUserEmail = email |
| 60 | }) |
| 61 | } |
| 62 | if (e.key === ZOO_CODE_USER_IMAGE_KEY) { |
| 63 | secretStorage?.get(ZOO_CODE_USER_IMAGE_KEY).then((image) => { |
| 64 | _cachedUserImage = image |
| 65 | }) |
| 66 | } |
| 67 | }) |
| 68 | } |
| 69 | |
| 70 | // Synchronous getter for use in ZooCodeHandler (called in hot path during API requests) |
| 71 | export function getCachedZooCodeToken(): string { |
no test coverage detected