From c30d5c5ab1dfe665e6c6ba9b8197a8a70e69849a Mon Sep 17 00:00:00 2001 From: Mykyta Chursin Date: Thu, 2 Apr 2026 15:25:51 +0300 Subject: [PATCH 1/3] fix: unwrap bridge envelope in ApplePayWebView message handler --- example/src/App.tsx | 5 ++++- src/payments/ApplePayWebView.tsx | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index 2993c7d..cb47327 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -62,7 +62,9 @@ const AddCardScreen = () => { showBillingZIPField: true, }); const threeDSecure = useThreeDSecure(); - const [tokenResult, setTokenResult] = useState(null); + const [tokenResult, setTokenResult] = useState< + TokenResult | ApplePayResult | null + >(null); const [threeDSRef, setThreeDSRef] = useState(null); const [loading, setLoading] = useState(false); const [cardValid, setCardValid] = useState(false); @@ -137,6 +139,7 @@ const AddCardScreen = () => { // Apple Pay: capture token + billing contact (including email for Bolt account creation) const handleApplePayComplete = useCallback((result: ApplePayResult) => { + setTokenResult(result); Alert.alert( 'Apple Pay Card Added', `Token: ${result.token.slice(0, 20)}...\n` + diff --git a/src/payments/ApplePayWebView.tsx b/src/payments/ApplePayWebView.tsx index c59d465..0c0fa0e 100644 --- a/src/payments/ApplePayWebView.tsx +++ b/src/payments/ApplePayWebView.tsx @@ -114,8 +114,19 @@ export const ApplePayWebView = ({ try { const outer = JSON.parse(raw); + // Unwrap bridge postMessage envelope produced by injectedBridge.ts + let unwrapped = outer; + if ( + unwrapped?.__boltBridge === true && + unwrapped.type === 'postMessage' && + unwrapped.data !== undefined + ) { + const inner = unwrapped.data; + unwrapped = typeof inner === 'string' ? JSON.parse(inner) : inner; + } + // Height change from iframe - let msg = outer; + let msg = unwrapped; if (typeof msg === 'string') { try { msg = JSON.parse(msg); @@ -129,7 +140,9 @@ export const ApplePayWebView = ({ } // Apple Pay result messages - const applePayMsg = parseBoltMessage(raw); + const applePayMsg = parseBoltMessage( + typeof unwrapped === 'string' ? unwrapped : JSON.stringify(unwrapped) + ); if (!applePayMsg) return; if (applePayMsg.type === 'addCardFromApplePaySuccess') { From d770ebff644b94ed8f4b5f0c33c45e4bc74f7351 Mon Sep 17 00:00:00 2001 From: Mykyta Chursin Date: Thu, 2 Apr 2026 18:24:16 +0300 Subject: [PATCH 2/3] recover example pubKey --- example/src/boltConfig.example.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/example/src/boltConfig.example.ts b/example/src/boltConfig.example.ts index 86951e6..a721129 100644 --- a/example/src/boltConfig.example.ts +++ b/example/src/boltConfig.example.ts @@ -7,6 +7,7 @@ // Or create it manually: // cp example/src/boltConfig.example.ts example/src/boltConfig.ts export const boltConfig = { - publishableKey: 'YOUR_PUBLISHABLE_KEY', - environment: 'sandbox' as const, // 'production' | 'sandbox' | 'staging' + publishableKey: + 'Q-5UMctK0oYN.ilCdYSP4NIPM.86e026dc5718eb7de83a55482f384cfcaf6be4c88df3b138d976188a4213e482', + environment: 'staging' as const, // 'production' | 'sandbox' | 'staging' }; From f80a4a55ddbfaa43dd00e090c616a64ebfc56d26 Mon Sep 17 00:00:00 2001 From: Mykyta Chursin Date: Thu, 2 Apr 2026 18:55:33 +0300 Subject: [PATCH 3/3] Apply suggestions from code review --- example/src/App.tsx | 5 +---- example/src/boltConfig.example.ts | 5 ++--- src/payments/ApplePayWebView.tsx | 16 +++++++++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index 1d30898..de9eb29 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -55,9 +55,7 @@ const AddCardScreen = () => { showBillingZIPField: true, }); const threeDSecure = useThreeDSecure(); - const [tokenResult, setTokenResult] = useState< - TokenResult | ApplePayResult | null - >(null); + const [tokenResult, setTokenResult] = useState(null); const [threeDSRef, setThreeDSRef] = useState(null); const [loading, setLoading] = useState(false); const [cardValid, setCardValid] = useState(false); @@ -136,7 +134,6 @@ const AddCardScreen = () => { // Apple Pay: capture token + billing contact (including email for Bolt account creation) const handleApplePayComplete = useCallback((result: ApplePayResult) => { - setTokenResult(result); const msg = `Token: ${result.token.slice(0, 20)}...\n` + `Email: ${result.billingContact?.emailAddress ?? 'N/A'}\n` + diff --git a/example/src/boltConfig.example.ts b/example/src/boltConfig.example.ts index a721129..86951e6 100644 --- a/example/src/boltConfig.example.ts +++ b/example/src/boltConfig.example.ts @@ -7,7 +7,6 @@ // Or create it manually: // cp example/src/boltConfig.example.ts example/src/boltConfig.ts export const boltConfig = { - publishableKey: - 'Q-5UMctK0oYN.ilCdYSP4NIPM.86e026dc5718eb7de83a55482f384cfcaf6be4c88df3b138d976188a4213e482', - environment: 'staging' as const, // 'production' | 'sandbox' | 'staging' + publishableKey: 'YOUR_PUBLISHABLE_KEY', + environment: 'sandbox' as const, // 'production' | 'sandbox' | 'staging' }; diff --git a/src/payments/ApplePayWebView.tsx b/src/payments/ApplePayWebView.tsx index 0c0fa0e..34fd3ce 100644 --- a/src/payments/ApplePayWebView.tsx +++ b/src/payments/ApplePayWebView.tsx @@ -122,7 +122,16 @@ export const ApplePayWebView = ({ unwrapped.data !== undefined ) { const inner = unwrapped.data; - unwrapped = typeof inner === 'string' ? JSON.parse(inner) : inner; + if (typeof inner === 'string') { + try { + unwrapped = JSON.parse(inner); + } catch { + // Inner payload is a plain string, keep as-is + unwrapped = inner; + } + } else { + unwrapped = inner; + } } // Height change from iframe @@ -140,11 +149,8 @@ export const ApplePayWebView = ({ } // Apple Pay result messages - const applePayMsg = parseBoltMessage( - typeof unwrapped === 'string' ? unwrapped : JSON.stringify(unwrapped) - ); + const applePayMsg = parseBoltMessage(unwrapped); if (!applePayMsg) return; - if (applePayMsg.type === 'addCardFromApplePaySuccess') { const message = applePayMsg.message as Record; const tokenResult = message.token as