| … | … | @@ -0,0 +1,67 @@ | |
| 42 | + | if (current === undefined || !PAIRING_FORM_ROUTES.includes(current)) return; | |
| 43 | + | // Return to whatever the link opened the sheet over. | |
| 44 | + | if (rootNavigationRef.canGoBack()) rootNavigationRef.goBack(); | |
| 45 | + | else rootNavigationRef.dispatch(StackActions.replace("Home")); | |
🟡 Medium connection/devAutoConnect.ts:28
When link B starts before link A finishes, A's completion overwrites or clears B's progress, and A's queued success callback can close B's pairing form. The completion and navigation callback do not verify that A is still the active attempt; track an attempt identity and ignore stale results and callbacks.
| 1 | +let devAutoConnectAttemptId = 0; |
| 2 | + |
| 3 | async function connect(pairingUrl: string, expectedEnvironmentId: EnvironmentId | undefined) { |
| 4 | + const attemptId = ++devAutoConnectAttemptId; |
| 5 | appAtomRegistry.set(devAutoConnectAttemptAtom, { pairingUrl, status: "connecting" }); |
| 6 | const outcome = await pairEnvironment(pairingUrl, expectedEnvironmentId); |
| 7 | + if (attemptId !== devAutoConnectAttemptId) return; |
| 8 | if (!outcome.ok) { |
| 9 | @@ |
| 10 | appAtomRegistry.set(devAutoConnectAttemptAtom, null); |
| 11 | whenRootNavigationReady(() => { |
| 12 | + if (attemptId !== devAutoConnectAttemptId) return; |
| 13 | const current = rootNavigationRef.getCurrentRoute()?.name; |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/mobile/src/features/connection/devAutoConnect.ts around lines 28-45: |
| 2 | |
| 3 | When link B starts before link A finishes, A's completion overwrites or clears B's progress, and A's queued success callback can close B's pairing form. The completion and navigation callback do not verify that A is still the active attempt; track an attempt identity and ignore stale results and callbacks. |
Fixed in a28226f1d3 and 12de75269f. connect keeps its own attempt object and drops the result if the atom no longer holds it, so a superseded A can't overwrite B's progress. The queued success callback also returns early when a newer attempt is in the atom. Covered by "drops the result of a pairing that a later link superseded" in devAutoConnect.test.ts.
The stale result guard resolves the atom-overwrite case. One navigation race remains: after A succeeds and clears the atom, a later non-auto-connect link also leaves it null, so A's deferred callback can still close that form. The callback needs an attempt/link generation identity rather than checking only for null.