From fce0b9bf509e6dcee30946adfdf6b73aab336bc7 Mon Sep 17 00:00:00 2001 From: guillermo dieguez Date: Fri, 23 Jan 2026 20:10:12 -0300 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9E=95=20app:=20install=20persona=20web?= =?UTF-8?q?=20sdk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/package.json b/package.json index 1d62aa567..ae5885cc5 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "i18n-iso-countries": "^7.14.0", "i18next": "^25.7.4", "moti": "^0.30.0", + "persona": "^5.0.0", "react": "19.1.0", "react-dom": "19.1.0", "react-i18next": "^16.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1e9c817b..6d7b47760 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -276,6 +276,9 @@ importers: moti: specifier: ^0.30.0 version: 0.30.0(react-dom@19.1.0(react@19.1.0))(react-native-reanimated@4.1.6(@babel/core@7.28.6)(react-native-worklets@0.5.1(@babel/core@7.28.6)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(bufferutil@4.1.0)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(bufferutil@4.1.0)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0))(react@19.1.0) + persona: + specifier: ^5.0.0 + version: 5.5.0 react: specifier: 19.1.0 version: 19.1.0 @@ -9817,6 +9820,9 @@ packages: lodash.isarray@3.0.4: resolution: {integrity: sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==} + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + lodash.keysin@3.0.8: resolution: {integrity: sha512-YDB/5xkL3fBKFMDaC+cfGV00pbiJ6XoJIfRmBhv7aR6wWtbCW6IzkiWnTfkiHTF6ALD7ff83dAtB3OEaSoyQPg==} @@ -10856,6 +10862,9 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + persona@5.5.0: + resolution: {integrity: sha512-sSayn72ppan7RGhMhBHbfUjQtIeWGGKL/AKA/2+bXGEBhNgkzaLBuLd+urcRLXmqjoZhFXsWgG5oVxTFvABhcw==} + pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -24567,6 +24576,8 @@ snapshots: lodash.isarray@3.0.4: {} + lodash.kebabcase@4.1.1: {} + lodash.keysin@3.0.8: dependencies: lodash.isarguments: 3.1.0 @@ -26245,6 +26256,11 @@ snapshots: pathe@2.0.3: {} + persona@5.5.0: + dependencies: + lodash.kebabcase: 4.1.1 + qs: 6.14.1 + pg-cloudflare@1.3.0: optional: true From 14420601a9888c466242eb9447a4b33c8e9f7d20 Mon Sep 17 00:00:00 2001 From: guillermo dieguez Date: Fri, 23 Jan 2026 20:10:43 -0300 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20app:=20implement=20persona=20we?= =?UTF-8?q?b=20sdk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/persona.ts | 95 +++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/src/utils/persona.ts b/src/utils/persona.ts index cae5a28f5..22b15cbe9 100644 --- a/src/utils/persona.ts +++ b/src/utils/persona.ts @@ -11,41 +11,72 @@ import queryClient, { type EmbeddingContext } from "./queryClient"; import reportError from "./reportError"; import { getKYCTokens } from "./server"; +import type * as PersonaWeb from "persona"; + export const environment = (__DEV__ || process.env.EXPO_PUBLIC_ENV === "e2e" ? "sandbox" : "production") as Environment; -export async function startKYC() { - const { otl: oneTimeLink, inquiryId, sessionToken } = await getKYCTokens("basic", await getRedirectURI()); - - if (Platform.OS === "web") { - if (await sdk.isInMiniApp()) { - await sdk.actions.openUrl(oneTimeLink); - return; - } - const embeddingContext = queryClient.getQueryData(["embedding-context"]); - if (embeddingContext && !embeddingContext.endsWith("-web")) { - window.location.replace(oneTimeLink); - return; - } - window.open(oneTimeLink, "_blank", "noopener,noreferrer"); // cspell:ignore noopener noreferrer - return; - } +export const startKYC = ( + Platform.OS === "web" + ? () => { + let activeClient: InstanceType | undefined; - const { Inquiry } = await import("react-native-persona"); - Inquiry.fromInquiry(inquiryId) - .sessionToken(sessionToken) - .onCanceled(() => { - queryClient.invalidateQueries({ queryKey: ["kyc", "status"] }).catch(reportError); - router.replace("/(main)/(home)"); - }) - .onComplete(() => { - queryClient.invalidateQueries({ queryKey: ["kyc", "status"] }).catch(reportError); - queryClient.setQueryData(["card-upgrade"], 1); - router.replace("/(main)/(home)"); - }) - .onError((error) => reportError(error)) - .build() - .start(); -} + return async () => { + const [{ Client }, { inquiryId, sessionToken }] = await Promise.all([ + import("persona"), + getKYCTokens("basic", await getRedirectURI()), + ]); + + activeClient?.destroy(); + + activeClient = new Client({ + inquiryId, + sessionToken, + environment: environment as "production" | "sandbox", // TODO deprecated - use environmentId instead + // environmentId: "", + onReady: () => activeClient?.open(), + onComplete: () => { + activeClient?.destroy(); + activeClient = undefined; + queryClient.invalidateQueries({ queryKey: ["kyc", "status"] }).catch(reportError); + queryClient.setQueryData(["card-upgrade"], 1); // TODO probably not needed unless the user is upgrading their card + router.replace("/(main)/(home)"); + }, + onCancel: () => { + activeClient?.destroy(); + activeClient = undefined; + queryClient.invalidateQueries({ queryKey: ["kyc", "status"] }).catch(reportError); + router.replace("/(main)/(home)"); + }, + onError: (error) => { + activeClient?.destroy(); + activeClient = undefined; + reportError(error); + }, + }); + }; + } + : () => { + // eslint-disable-next-line unicorn/consistent-function-scoping + return async () => { + const { inquiryId, sessionToken } = await getKYCTokens("basic", await getRedirectURI()); + const { Inquiry } = await import("react-native-persona"); + Inquiry.fromInquiry(inquiryId) + .sessionToken(sessionToken) + .onCanceled(() => { + queryClient.invalidateQueries({ queryKey: ["kyc", "status"] }).catch(reportError); + router.replace("/(main)/(home)"); + }) + .onComplete(() => { + queryClient.invalidateQueries({ queryKey: ["kyc", "status"] }).catch(reportError); + queryClient.setQueryData(["card-upgrade"], 1); + router.replace("/(main)/(home)"); + }) + .onError((error) => reportError(error)) + .build() + .start(); + }; + } +)(); async function getRedirectURI() { const miniappContext = (await sdk.context) as unknown as undefined | { client: { appUrl?: string } };