()
| 61 | } |
| 62 | deviceCodeReference.current = undefined; |
| 63 | void clearPendingExternalAuth(); |
| 64 | }, []); |
| 65 | |
| 66 | // Cleanup on unmount |
| 67 | useEffect(() => cleanup, [cleanup]); |
| 68 | |
| 69 | // Android opens a plain browser and returns via AppState 'active', so poll |
| 70 | // once immediately on foreground while pending — bounded by pollNow (one per |
| 71 | // foreground, never within 1 s of the previous poll). |
| 72 | useEffect(() => { |
| 73 | const handleChange = (nextState: AppStateStatus) => { |
| 74 | if (nextState !== 'active') { |
| 75 | return; |
| 76 | } |
| 77 | if (state.status !== 'pending') { |
| 78 | return; |
| 79 | } |
| 80 | pollCleanupRef.current?.pollNow(); |
| 81 | }; |
| 82 | const subscription = AppState.addEventListener('change', handleChange); |
| 83 | return () => { |
| 84 | subscription.remove(); |
| 85 | }; |
| 86 | }, [state.status]); |
| 87 | |
| 88 | // Restore a pending transaction that survived process death. The record is |
| 89 | // read once on mount; an absent or expired record leaves the screen idle. |
| 90 | useEffect(() => { |
| 91 | let cancelled = false; |
| 92 | |
| 93 | async function restorePending() { |
| 94 | const epochAtRead = flowEpochRef.current; |
| 95 | const result = await readPendingExternalAuth(); |
| 96 | if (cancelled || flowEpochRef.current !== epochAtRead) { |
| 97 | return; |
| 98 | } |
| 99 | if (result.kind === 'stale') { |
| 100 | await clearPendingExternalAuth(); |
| 101 | return; |
| 102 | } |
| 103 | if (result.kind === 'none') { |
| 104 | return; |
| 105 | } |
| 106 | const record = result.record; |
| 107 | deviceCodeReference.current = record.deviceCode; |
| 108 | setState(pendingDeviceAuthState(record.userCode, record.verificationUrl, true)); |
| 109 | const abort = new AbortController(); |
| 110 | abortReference.current = abort; |
| 111 | pollCleanupRef.current = startDeviceAuthPoll({ |
| 112 | code: record.userCode, |
| 113 | deviceCode: record.deviceCode, |
| 114 | signal: abort.signal, |
| 115 | setState, |
| 116 | cleanup, |
| 117 | browserKind: resolveAuthBrowserKind(record.verificationUrl), |
| 118 | startedAt: record.startedAt, |
| 119 | }); |
| 120 | } |
no test coverage detected