Skip to content

Commit 07715c9

Browse files
committed
🥅 app: handle localized native auth errors
1 parent 3ef8499 commit 07715c9

3 files changed

Lines changed: 47 additions & 30 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@exactly/mobile": patch
3+
---
4+
5+
🥅 handle localized native auth errors by matching expo codes

‎src/components/add-funds/Bridge.tsx‎

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ import View from "../shared/View";
5757
import TokenInput from "../swaps/TokenInput";
5858

5959
import type { Chain, Token } from "@lifi/sdk";
60-
import type { TFunction } from "i18next";
6160

6261
export default function Bridge() {
6362
const router = useRouter();
@@ -416,8 +415,17 @@ export default function Bridge() {
416415
});
417416
await queryClient.invalidateQueries({ queryKey: ["bridge", "sources"] });
418417
},
419-
onError: (error: unknown) => {
420-
handleError(error, toast, t);
418+
onError(error) {
419+
if (classifyError(error).authKnown) {
420+
setBridgePreview(undefined);
421+
resetBridgeMutation();
422+
return;
423+
}
424+
toast.show(t("Bridge failed. Please try again."), {
425+
native: true,
426+
duration: 1000,
427+
burntOptions: { haptic: "error", preset: "error" },
428+
});
421429
},
422430
onSettled: () => {
423431
setBridgeStatus(undefined);
@@ -461,8 +469,17 @@ export default function Bridge() {
461469
});
462470
await queryClient.invalidateQueries({ queryKey: ["bridge", "sources"] });
463471
},
464-
onError: (error: unknown) => {
465-
handleError(error, toast, t, true);
472+
onError(error) {
473+
if (classifyError(error).authKnown) {
474+
setBridgePreview(undefined);
475+
resetTransferMutation();
476+
return;
477+
}
478+
toast.show(t("Transfer failed. Please try again."), {
479+
native: true,
480+
duration: 1000,
481+
burntOptions: { haptic: "error", preset: "error" },
482+
});
466483
},
467484
onSettled: () => {
468485
setBridgeStatus(undefined);
@@ -1038,12 +1055,3 @@ export default function Bridge() {
10381055
</SafeView>
10391056
);
10401057
}
1041-
1042-
function handleError(error: unknown, toast: ReturnType<typeof useToastController>, t: TFunction, isTransfer?: boolean) {
1043-
if (!reportError(error).authKnown)
1044-
toast.show(isTransfer ? t("Transfer failed. Please try again.") : t("Bridge failed. Please try again."), {
1045-
native: true,
1046-
duration: 1000,
1047-
burntOptions: { haptic: "error", preset: "error" },
1048-
});
1049-
}

‎src/utils/reportError.ts‎

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,19 @@ export default function reportError(error: unknown, hint?: Parameters<typeof cap
4444
return classification;
4545
}
4646

47-
const passkeyCancelledMessages = new Set([
48-
"The operation couldn’t be completed. (com.apple.AuthenticationServices.AuthorizationError error 1001.)",
49-
"The operation couldn’t be completed. (com.apple.AuthenticationServices.AuthorizationError error 1004.)",
50-
"The operation couldn’t be completed. Device must be unlocked to perform request.",
51-
"UserCancelled",
52-
]);
53-
const passkeyKnownMessages = new Set([
54-
...passkeyCancelledMessages,
55-
"The operation couldn’t be completed. Stolen Device Protection is enabled and biometry is required.",
56-
]);
47+
const passkeyCancelledCodes = new Set(["ERR_USER_CANCELLED", "ERR_PASSKEY_REQUEST_FAILED"]);
48+
const passkeyCancelledPatterns = [
49+
/com\.apple\.AuthenticationServices\.AuthorizationError\D+\b1001\b/i,
50+
/com\.apple\.AuthenticationServices\.AuthorizationError\D+\b1004\b/i,
51+
/^UserCancelled$/,
52+
];
53+
const passkeyKnownCodes = new Set([...passkeyCancelledCodes, "ERR_PENDING_PASSKEY_REQUEST"]);
54+
const passkeyKnownPatterns = [
55+
...passkeyCancelledPatterns,
56+
/com\.apple\.AuthenticationServices\.AuthorizationError/i,
57+
/Biometrics must be enabled/,
58+
/There is already a pending passkey request/,
59+
];
5760
const authPrefixes = ["androidx.credentials.exceptions.domerrors.NotAllowedError"];
5861
const networkTypes = [
5962
["ConnectionLost", /network connection was lost/i],
@@ -109,13 +112,14 @@ function parseError(error: unknown) {
109112
function classify({ code, message, name, reason, revert, status }: ParsedError) {
110113
const passkeyNotAllowed =
111114
name === "NotAllowedError" || (message !== undefined && authPrefixes.some((prefix) => message.startsWith(prefix)));
112-
const passkeyCancelled = message !== undefined && passkeyCancelledMessages.has(message);
115+
const passkeyCancelled =
116+
(code !== undefined && passkeyCancelledCodes.has(code)) ||
117+
(message !== undefined && passkeyCancelledPatterns.some((pattern) => pattern.test(message)));
113118
const passkeyKnown =
114-
message !== undefined &&
115-
(passkeyKnownMessages.has(message) ||
116-
message.includes("Biometrics must be enabled") ||
117-
message.includes("There is already a pending passkey request") ||
118-
authPrefixes.some((prefix) => message.startsWith(prefix)));
119+
(code !== undefined && passkeyKnownCodes.has(code)) ||
120+
(message !== undefined &&
121+
(passkeyKnownPatterns.some((pattern) => pattern.test(message)) ||
122+
authPrefixes.some((prefix) => message.startsWith(prefix))));
119123
const passkeyWarning = passkeyKnown && !passkeyCancelled && !passkeyNotAllowed;
120124
const biometric = code === "ERR_BIOMETRIC";
121125
const walletRejected = status === "4001" || status === "5000";

0 commit comments

Comments
 (0)