@deuna/react-native-sdk 2.0.5 → 2.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/DeunaWalletsModule.podspec +19 -0
  2. package/README.md +141 -2
  3. package/android/build.gradle +43 -0
  4. package/android/src/main/AndroidManifest.xml +8 -0
  5. package/android/src/main/java/com/deuna/wallets/DeunaWalletsModule.kt +103 -0
  6. package/app.plugin.js +1 -0
  7. package/expo-module.config.json +10 -0
  8. package/ios/DeunaWalletsModule.swift +56 -0
  9. package/lib/module/DeunaSDK.js +44 -3
  10. package/lib/module/DeunaSDK.js.map +1 -1
  11. package/lib/module/components/DeunaWebView.js +3 -0
  12. package/lib/module/components/DeunaWebView.js.map +1 -1
  13. package/lib/module/components/DeunaWidget.js +1 -0
  14. package/lib/module/components/DeunaWidget.js.map +1 -1
  15. package/lib/module/controllers/BaseWebViewController.js +17 -4
  16. package/lib/module/controllers/BaseWebViewController.js.map +1 -1
  17. package/lib/module/controllers/ElementsWidgetController.js +9 -1
  18. package/lib/module/controllers/ElementsWidgetController.js.map +1 -1
  19. package/lib/module/index.js +1 -0
  20. package/lib/module/index.js.map +1 -1
  21. package/lib/module/plugin/index.js +25 -0
  22. package/lib/module/plugin/index.js.map +1 -0
  23. package/lib/module/plugin/withAndroidGooglePay.js +20 -0
  24. package/lib/module/plugin/withAndroidGooglePay.js.map +1 -0
  25. package/lib/module/plugin/withIosApplePay.js +10 -0
  26. package/lib/module/plugin/withIosApplePay.js.map +1 -0
  27. package/lib/module/plugin/withIosFmtFix.js +34 -0
  28. package/lib/module/plugin/withIosFmtFix.js.map +1 -0
  29. package/lib/module/types/base.js +16 -0
  30. package/lib/module/types/base.js.map +1 -1
  31. package/lib/module/types/envs.js +12 -0
  32. package/lib/module/types/envs.js.map +1 -1
  33. package/lib/module/wallets/WalletModule.js +218 -0
  34. package/lib/module/wallets/WalletModule.js.map +1 -0
  35. package/lib/module/wallets/index.js +4 -0
  36. package/lib/module/wallets/index.js.map +1 -0
  37. package/lib/module/wallets/tokenize/applePay.js +24 -0
  38. package/lib/module/wallets/tokenize/applePay.js.map +1 -0
  39. package/lib/module/wallets/tokenize/googlePay.js +24 -0
  40. package/lib/module/wallets/tokenize/googlePay.js.map +1 -0
  41. package/lib/module/wallets/tokenize/index.js +12 -0
  42. package/lib/module/wallets/tokenize/index.js.map +1 -0
  43. package/lib/module/wallets/types.js +4 -0
  44. package/lib/module/wallets/types.js.map +1 -0
  45. package/lib/module/wallets/vaultApi.js +121 -0
  46. package/lib/module/wallets/vaultApi.js.map +1 -0
  47. package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts +12 -3
  48. package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts.map +1 -1
  49. package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts +1 -0
  50. package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts.map +1 -1
  51. package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts +7 -0
  52. package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts.map +1 -1
  53. package/lib/typescript/deuna-sdk-react-native/src/controllers/ElementsWidgetController.d.ts.map +1 -1
  54. package/lib/typescript/deuna-sdk-react-native/src/index.d.ts +1 -0
  55. package/lib/typescript/deuna-sdk-react-native/src/index.d.ts.map +1 -1
  56. package/lib/typescript/deuna-sdk-react-native/src/plugin/index.d.ts +8 -0
  57. package/lib/typescript/deuna-sdk-react-native/src/plugin/index.d.ts.map +1 -0
  58. package/lib/typescript/deuna-sdk-react-native/src/plugin/withAndroidGooglePay.d.ts +3 -0
  59. package/lib/typescript/deuna-sdk-react-native/src/plugin/withAndroidGooglePay.d.ts.map +1 -0
  60. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosApplePay.d.ts +5 -0
  61. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosApplePay.d.ts.map +1 -0
  62. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosFmtFix.d.ts +3 -0
  63. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosFmtFix.d.ts.map +1 -0
  64. package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts +78 -14
  65. package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts.map +1 -1
  66. package/lib/typescript/deuna-sdk-react-native/src/types/envs.d.ts +12 -0
  67. package/lib/typescript/deuna-sdk-react-native/src/types/envs.d.ts.map +1 -1
  68. package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts +1 -1
  69. package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts.map +1 -1
  70. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts +11 -0
  71. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts.map +1 -1
  72. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts +3 -3
  73. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts.map +1 -1
  74. package/lib/typescript/deuna-sdk-react-native/src/wallets/WalletModule.d.ts +29 -0
  75. package/lib/typescript/deuna-sdk-react-native/src/wallets/WalletModule.d.ts.map +1 -0
  76. package/lib/typescript/deuna-sdk-react-native/src/wallets/index.d.ts +3 -0
  77. package/lib/typescript/deuna-sdk-react-native/src/wallets/index.d.ts.map +1 -0
  78. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/applePay.d.ts +2 -0
  79. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/applePay.d.ts.map +1 -0
  80. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/googlePay.d.ts +2 -0
  81. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/googlePay.d.ts.map +1 -0
  82. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/index.d.ts +3 -0
  83. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/index.d.ts.map +1 -0
  84. package/lib/typescript/deuna-sdk-react-native/src/wallets/types.d.ts +15 -0
  85. package/lib/typescript/deuna-sdk-react-native/src/wallets/types.d.ts.map +1 -0
  86. package/lib/typescript/deuna-sdk-react-native/src/wallets/vaultApi.d.ts +38 -0
  87. package/lib/typescript/deuna-sdk-react-native/src/wallets/vaultApi.d.ts.map +1 -0
  88. package/package.json +14 -2
  89. package/react-native.config.js +8 -0
  90. package/src/DeunaSDK.ts +65 -4
  91. package/src/components/DeunaWebView.tsx +4 -0
  92. package/src/components/DeunaWidget.tsx +2 -0
  93. package/src/controllers/BaseWebViewController.ts +15 -4
  94. package/src/controllers/ElementsWidgetController.ts +16 -1
  95. package/src/index.tsx +1 -0
  96. package/src/plugin/index.ts +29 -0
  97. package/src/plugin/withAndroidGooglePay.ts +15 -0
  98. package/src/plugin/withIosApplePay.ts +10 -0
  99. package/src/plugin/withIosFmtFix.ts +49 -0
  100. package/src/types/base.ts +92 -14
  101. package/src/types/envs.ts +14 -0
  102. package/src/types/helpers/urlConfig.ts +1 -1
  103. package/src/types/interfaces/callbacks.ts +15 -0
  104. package/src/types/interfaces/initWidgetBase.ts +3 -3
  105. package/src/wallets/WalletModule.ts +255 -0
  106. package/src/wallets/index.ts +13 -0
  107. package/src/wallets/tokenize/applePay.ts +22 -0
  108. package/src/wallets/tokenize/googlePay.ts +27 -0
  109. package/src/wallets/tokenize/index.ts +12 -0
  110. package/src/wallets/types.ts +17 -0
  111. package/src/wallets/vaultApi.ts +229 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"googlePay.d.ts","sourceRoot":"","sources":["../../../../../../src/wallets/tokenize/googlePay.ts"],"names":[],"mappings":"AAAA,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0BxF"}
@@ -0,0 +1,3 @@
1
+ import type { WalletProvider } from '../types';
2
+ export declare function buildTokenizeBody(provider: WalletProvider, paymentData: unknown): Record<string, unknown>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/wallets/tokenize/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAS/C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzG"}
@@ -0,0 +1,15 @@
1
+ import type { Environment } from '../types/base';
2
+ import type { UserInfo } from '../types/interfaces/initWidgetBase';
3
+ export type WalletProvider = 'apple_pay' | 'google_pay';
4
+ export interface WalletsError {
5
+ code: string;
6
+ message: string;
7
+ }
8
+ export interface InitElementsParams {
9
+ orderToken: string;
10
+ publicApiKey: string;
11
+ environment: Environment;
12
+ walletProvider: WalletProvider;
13
+ userInfo?: Partial<UserInfo>;
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/wallets/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAEnE,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,YAAY,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC9B"}
@@ -0,0 +1,38 @@
1
+ import type { UserInfo } from '../types/interfaces/initWidgetBase';
2
+ export interface ApplePayCredentials {
3
+ merchantIdentifier: string;
4
+ displayName: string;
5
+ supportedNetworks: string[];
6
+ merchantCapabilities: string[];
7
+ transactionInfo?: {
8
+ amount: string;
9
+ currencyCode: string;
10
+ countryCode: string;
11
+ label: string;
12
+ };
13
+ credentialId?: string;
14
+ }
15
+ export interface GooglePayCredentials {
16
+ merchantId: string;
17
+ merchantName: string;
18
+ gateway: string;
19
+ gatewayMerchantId: string;
20
+ tokenizationType: 'PAYMENT_GATEWAY' | 'DIRECT';
21
+ publicKey?: string;
22
+ allowedCardNetworks: string[];
23
+ allowedAuthMethods: string[];
24
+ transactionInfo?: {
25
+ totalPrice: string;
26
+ currencyCode: string;
27
+ countryCode: string;
28
+ };
29
+ }
30
+ export type WalletCredentials = ApplePayCredentials | GooglePayCredentials;
31
+ export interface VaultFetchResult {
32
+ providers: string[];
33
+ credentials: Record<string, WalletCredentials>;
34
+ userToken?: string;
35
+ userId?: string;
36
+ }
37
+ export declare function fetchVaultResult(environment: string, publicApiKey: string, orderToken?: string, userInfo?: Partial<UserInfo>): Promise<VaultFetchResult>;
38
+ //# sourceMappingURL=vaultApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vaultApi.d.ts","sourceRoot":"","sources":["../../../../../src/wallets/vaultApi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAMnE,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,iBAAiB,GAAG,QAAQ,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,GAAG,oBAAoB,CAAC;AAE3E,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAiC3B"}
package/package.json CHANGED
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "name": "@deuna/react-native-sdk",
3
- "version": "2.0.5",
3
+ "version": "2.1.0-beta.2",
4
4
  "description": "React Native SDK",
5
5
  "source": "./src/index.tsx",
6
6
  "react-native": "./src/index.tsx",
7
7
  "main": "./lib/module/index.js",
8
8
  "types": "./lib/typescript/deuna-sdk-react-native/src/index.d.ts",
9
9
  "peerDependencies": {
10
+ "expo-modules-core": ">=1.12.0",
10
11
  "react": "*",
11
12
  "react-native": "*",
12
13
  "react-native-webview": "*"
13
14
  },
15
+ "peerDependenciesMeta": {
16
+ "expo-modules-core": {
17
+ "optional": true
18
+ }
19
+ },
14
20
  "exports": {
15
21
  ".": {
16
22
  "types": "./lib/typescript/deuna-sdk-react-native/src/index.d.ts",
@@ -27,6 +33,8 @@
27
33
  "cpp",
28
34
  "*.podspec",
29
35
  "react-native.config.js",
36
+ "expo-module.config.json",
37
+ "app.plugin.js",
30
38
  "!ios/build",
31
39
  "!android/build",
32
40
  "!android/gradle",
@@ -40,6 +48,7 @@
40
48
  "!packages"
41
49
  ],
42
50
  "scripts": {
51
+ "postinstall": "node -e \"const fs=require('fs');fs.mkdirSync('examples/expo/node_modules/@deuna',{recursive:true});try{fs.symlinkSync('../../../../.',String.raw`examples/expo/node_modules/@deuna/react-native-sdk`,'junction')}catch(e){}\"",
43
52
  "copy-types": "bash copy-types.sh",
44
53
  "example:expo": "yarn workspace deuna-sdk-react-native-example-expo",
45
54
  "example:cli": "yarn workspace deuna-sdk-react-native-example-rn-cli",
@@ -58,7 +67,8 @@
58
67
  "example:cli:install": "yarn prepare && yarn example:cli install",
59
68
  "example:cli:start": "yarn example:cli start",
60
69
  "example:cli:android": "yarn example:cli android",
61
- "example:cli:ios": "yarn example:cli ios"
70
+ "example:cli:ios": "yarn example:cli ios",
71
+ "example:expo:prebuild": "yarn example:expo prebuild"
62
72
  },
63
73
  "keywords": [
64
74
  "react-native",
@@ -93,6 +103,8 @@
93
103
  "eslint": "^9.22.0",
94
104
  "eslint-config-prettier": "^10.1.1",
95
105
  "eslint-plugin-prettier": "^5.2.3",
106
+ "expo": "^55.0.19",
107
+ "expo-modules-core": "^55.0.24",
96
108
  "jest": "^29.7.0",
97
109
  "prettier": "^3.0.3",
98
110
  "react": "18.3.1",
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ ios: {},
5
+ android: { sourceDir: './android' },
6
+ },
7
+ },
8
+ };
package/src/DeunaSDK.ts CHANGED
@@ -19,6 +19,12 @@ import {
19
19
  SubmitResult,
20
20
  VoucherWidgetCallbacks,
21
21
  } from './types';
22
+ import {
23
+ getWalletsAvailable as getWalletsAvailableNative,
24
+ initElements as initElementsNative,
25
+ type WalletProvider,
26
+ } from './wallets';
27
+ import type { GetWalletsAvailableParams, WalletElementConfig } from './types';
22
28
  import { InitFraudProvidersProps } from './types/fraudProviders';
23
29
  import {
24
30
  DeunaWebViewController,
@@ -143,9 +149,25 @@ export class DeunaSDK extends BaseDeuna {
143
149
  }
144
150
 
145
151
  /**
146
- * Shows the elements widget
147
- * @param props - The parameters for the elements widget controller
148
- * @param props.mode - The mode for the widget
152
+ * Returns wallet providers available on the current device.
153
+ *
154
+ * - Pass `WalletElementConfig` to use explicit credentials (no vault fetch).
155
+ * - Pass `{ orderToken?, userInfo? }` to resolve credentials from the DEUNA vault API.
156
+ */
157
+ async getWalletsAvailable(
158
+ params: GetWalletsAvailableParams = {}
159
+ ): Promise<WalletProvider[]> {
160
+ return getWalletsAvailableNative(
161
+ this.config.publicApiKey,
162
+ this.config.environment ?? 'production',
163
+ params
164
+ );
165
+ }
166
+
167
+ /**
168
+ * Shows the elements widget or launches a native wallet payment sheet.
169
+ * Pass `types: [{ name: 'APPLE_PAY' }]` or `types: [{ name: 'GOOGLE_PAY' }]` to trigger
170
+ * the native payment sheet. Optionally include `walletConfig` with explicit credentials.
149
171
  */
150
172
  async initElements(
151
173
  props: InitElementsWidgetParams & {
@@ -154,7 +176,46 @@ export class DeunaSDK extends BaseDeuna {
154
176
  userAgent?: string;
155
177
  fraudCredentials?: Partial<InitFraudProvidersProps>;
156
178
  }
157
- ) {
179
+ ): Promise<void> {
180
+ const WALLET_TYPE_TO_PROVIDER: Record<string, WalletProvider> = {
181
+ APPLE_PAY: 'apple_pay',
182
+ GOOGLE_PAY: 'google_pay',
183
+ };
184
+ const firstType = props.types?.[0]?.name;
185
+ const walletProvider = firstType
186
+ ? WALLET_TYPE_TO_PROVIDER[firstType]
187
+ : undefined;
188
+
189
+ if (walletProvider) {
190
+ initElementsNative(
191
+ {
192
+ walletProvider,
193
+ orderToken: props.orderToken ?? '',
194
+ publicApiKey: this.config.publicApiKey,
195
+ environment: this.config.environment ?? 'production',
196
+ userInfo: props.userInfo,
197
+ },
198
+ props.walletConfig as WalletElementConfig | undefined
199
+ )
200
+ .then((result) => {
201
+ if (result === 'closed') {
202
+ props.callbacks?.onClosed?.('userAction');
203
+ } else {
204
+ props.callbacks?.onSuccess?.(result ?? {});
205
+ }
206
+ })
207
+ .catch((err: { code?: string; message?: string }) => {
208
+ props.callbacks?.onError?.({
209
+ type: err.code ?? 'WALLET_ERROR',
210
+ metadata: {
211
+ code: err.code ?? 'WALLET_ERROR',
212
+ message: err.message ?? 'Wallet payment failed',
213
+ },
214
+ });
215
+ });
216
+ return;
217
+ }
218
+
158
219
  this.setWidgetController({
159
220
  controller: buildDeunaWidgetController(this.config, {
160
221
  widget: 'elements',
@@ -10,6 +10,7 @@ interface DeunaWebViewProps {
10
10
  onLoad?: () => void;
11
11
  onError?: (error: any) => void;
12
12
  onShouldStartLoadWithRequest?: (request: any) => boolean;
13
+ onOpenWindow?: (targetUrl: string) => void;
13
14
  }
14
15
 
15
16
  export const DeunaWebView = (props: DeunaWebViewProps) => {
@@ -28,11 +29,14 @@ export const DeunaWebView = (props: DeunaWebViewProps) => {
28
29
  props.onLoad?.();
29
30
  }}
30
31
  startInLoadingState
32
+ paymentRequestEnabled
33
+ enableApplePay
31
34
  renderLoading={() => <WebViewLoader />}
32
35
  javaScriptEnabled={true}
33
36
  onError={props.onError}
34
37
  setSupportMultipleWindows={false}
35
38
  javaScriptCanOpenWindowsAutomatically={false}
39
+ onOpenWindow={(event) => props.onOpenWindow?.(event.nativeEvent.targetUrl)}
36
40
  onShouldStartLoadWithRequest={props.onShouldStartLoadWithRequest}
37
41
  />
38
42
  </View>
@@ -109,6 +109,7 @@ const DeunaWidgetContainer = (props: DeunaWidgetProps) => {
109
109
  onMessage={controller?.onMessage}
110
110
  onLoad={controller?.onLoad}
111
111
  onError={controller?.onError}
112
+
112
113
  onShouldStartLoadWithRequest={
113
114
  controller?.onShouldStartLoadWithRequest
114
115
  }
@@ -129,6 +130,7 @@ const DeunaWidgetContainer = (props: DeunaWidgetProps) => {
129
130
  onMessage={controller?.onMessage}
130
131
  onLoad={controller?.onLoad}
131
132
  onError={controller?.onError}
133
+ onOpenWindow={controller?.onOpenWindow}
132
134
  onShouldStartLoadWithRequest={
133
135
  controller?.onShouldStartLoadWithRequest
134
136
  }
@@ -105,6 +105,21 @@ export abstract class BaseWebViewController {
105
105
  return true;
106
106
  };
107
107
 
108
+ /**
109
+ * Called when window.open() is triggered inside the WebView (native event,
110
+ * no JS injection needed). window.open returns null to the page, which causes
111
+ * payment libraries like pay.js to fall back to the Payment Request API.
112
+ * Non-payment URLs (APM redirects, etc.) are forwarded as external URLs.
113
+ */
114
+ onOpenWindow = (targetUrl: string) => {
115
+ if (!targetUrl) return;
116
+ // Google Pay opens via the Payment Request API (paymentRequestEnabled=true).
117
+ // Intercepting pay.google.com here would open it in a WebView, which Google
118
+ // Pay blocks. Drop it and let the native Payment Request handler take over.
119
+ if (targetUrl.includes('pay.google.com')) return;
120
+ this.delegate?.onOpenExternalUrl?.(targetUrl, { userInitiated: true });
121
+ };
122
+
108
123
  /**
109
124
  * Release the web view resources
110
125
  */
@@ -246,10 +261,6 @@ export abstract class DeunaWebViewController extends BaseWebViewController {
246
261
  document.addEventListener('keydown', function() {
247
262
  window.__deunaLastUserInteractionAt = Date.now();
248
263
  }, true);
249
- window.open = function(url, target, features) {
250
- var isUserInitiated = Date.now() - (window.__deunaLastUserInteractionAt || 0) < 1500;
251
- window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.openExternalUrl}', url, userInitiated: isUserInitiated }));
252
- };
253
264
  window.ReactNativeWebView.postMessage(JSON.stringify({
254
265
  type: '${WebViewEventType.userAgentResolved}',
255
266
  userAgent: navigator.userAgent || null
@@ -5,6 +5,7 @@ import {
5
5
  } from '../interfaces/events/elements';
6
6
  import { ElementsWidgetCallbacks } from '../types';
7
7
  import { ElementsErrorType, WidgetConfig } from '../interfaces';
8
+ import { DeunaLogs } from '../DeunaLogs';
8
9
 
9
10
  export class ElementsWidgetController extends DeunaWebViewController {
10
11
  constructor(
@@ -15,11 +16,13 @@ export class ElementsWidgetController extends DeunaWebViewController {
15
16
  }
16
17
 
17
18
  onError = (event: any) => {
19
+ const message = event.message ?? 'Error while loading the URL';
20
+ DeunaLogs.error('Elements URL load error', message);
18
21
  this.callbacks.onError?.({
19
22
  type: ElementsErrorType.errorWhileLoadingTheURL,
20
23
  metadata: {
21
24
  code: ElementsErrorType.errorWhileLoadingTheURL,
22
- message: event.message ?? 'Error while loading the URL',
25
+ message,
23
26
  },
24
27
  });
25
28
  };
@@ -27,16 +30,20 @@ export class ElementsWidgetController extends DeunaWebViewController {
27
30
  onEventDispatch = (event: Record<string, any>) => {
28
31
  const elementsEvent = event as ElementsEvent;
29
32
 
33
+ DeunaLogs.info('Elements event', elementsEvent.type);
34
+
30
35
  if (this.callbacks.onEventDispatch) {
31
36
  this.callbacks.onEventDispatch(elementsEvent.type, elementsEvent.data);
32
37
  }
33
38
 
34
39
  const mapper: Partial<Record<ElementsEventType, () => void>> = {
35
40
  [ElementsEventType.vaultClosed]: () => {
41
+ DeunaLogs.info('Card tokenization', 'Widget closed by user');
36
42
  this.closedAction = 'userAction';
37
43
  this.delegate?.onCloseButtonPressed?.();
38
44
  },
39
45
  [ElementsEventType.vaultSaveSuccess]: () => {
46
+ DeunaLogs.info('Card tokenization', 'Card saved successfully');
40
47
  this.delegate?.onCloseExternalUrl?.();
41
48
  this.callbacks.onSuccess?.(this.buildSuccessPayload(event.data));
42
49
  },
@@ -56,6 +63,10 @@ export class ElementsWidgetController extends DeunaWebViewController {
56
63
  metadata.reason ??
57
64
  'unknown error';
58
65
 
66
+ DeunaLogs.error(
67
+ 'Card tokenization failed',
68
+ `code=${errorCode} message=${errorMessage} raw=${JSON.stringify(metadata)}`
69
+ );
59
70
  this.callbacks.onError?.({
60
71
  type: ElementsErrorType.vaultSaveError,
61
72
  metadata: {
@@ -64,6 +75,10 @@ export class ElementsWidgetController extends DeunaWebViewController {
64
75
  },
65
76
  });
66
77
  } else {
78
+ DeunaLogs.error(
79
+ 'Card tokenization failed',
80
+ `vaultSaveError fired with no metadata — raw event: ${JSON.stringify(elementsEvent.data)}`
81
+ );
67
82
  this.callbacks.onError?.({
68
83
  type: ElementsErrorType.unknownError,
69
84
  metadata: {
package/src/index.tsx CHANGED
@@ -3,3 +3,4 @@ export * from './components/DeunaWidget';
3
3
  export * from './types';
4
4
  export * from './interfaces';
5
5
  export * from './adapters';
6
+ export * from './wallets';
@@ -0,0 +1,29 @@
1
+ import { type ConfigPlugin } from 'expo/config-plugins';
2
+ import { withIosApplePay } from './withIosApplePay';
3
+ import { withAndroidGooglePay } from './withAndroidGooglePay';
4
+ import { withIosFmtFix } from './withIosFmtFix';
5
+
6
+ export interface DeunaWalletsPluginOptions {
7
+ merchantIdentifiers?: string[];
8
+ googlePay?: boolean;
9
+ }
10
+
11
+ const withDeunaWallets: ConfigPlugin<DeunaWalletsPluginOptions> = (
12
+ config,
13
+ options = {}
14
+ ) => {
15
+ const { merchantIdentifiers, googlePay = true } = options;
16
+
17
+ // Always apply — fixes fmt consteval build error with Xcode 16 / Clang 16+
18
+ config = withIosFmtFix(config);
19
+
20
+ if (merchantIdentifiers?.length) {
21
+ config = withIosApplePay(config, { merchantIdentifiers });
22
+ }
23
+ if (googlePay) {
24
+ config = withAndroidGooglePay(config);
25
+ }
26
+ return config;
27
+ };
28
+
29
+ export default withDeunaWallets;
@@ -0,0 +1,15 @@
1
+ import { type ConfigPlugin, withAndroidManifest } from 'expo/config-plugins';
2
+
3
+ export const withAndroidGooglePay: ConfigPlugin = (config) =>
4
+ withAndroidManifest(config, (mod) => {
5
+ const mainApp = mod.modResults.manifest.application?.[0];
6
+ if (!mainApp) return mod;
7
+
8
+ const metaData = mainApp['meta-data'] ?? [];
9
+ const KEY = 'com.google.android.gms.wallet.api.enabled';
10
+ if (!metaData.some((m: any) => m.$?.['android:name'] === KEY)) {
11
+ metaData.push({ $: { 'android:name': KEY, 'android:value': '1' } });
12
+ }
13
+ mainApp['meta-data'] = metaData;
14
+ return mod;
15
+ });
@@ -0,0 +1,10 @@
1
+ import { type ConfigPlugin, withEntitlementsPlist } from 'expo/config-plugins';
2
+
3
+ export const withIosApplePay: ConfigPlugin<{ merchantIdentifiers: string[] }> = (
4
+ config,
5
+ { merchantIdentifiers }
6
+ ) =>
7
+ withEntitlementsPlist(config, (mod) => {
8
+ mod.modResults['com.apple.developer.in-app-payments'] = merchantIdentifiers;
9
+ return mod;
10
+ });
@@ -0,0 +1,49 @@
1
+ import { type ConfigPlugin, withPodfile } from 'expo/config-plugins';
2
+
3
+ const FMT_FIX_MARKER = 'deuna-fmt-fix';
4
+
5
+ const FMT_FIX_LINES = [
6
+ ' # deuna-fmt-fix: fixes consteval build error with Xcode 16 / Clang 16+',
7
+ ' installer.pods_project.targets.each do |target|',
8
+ " if target.name == 'fmt'",
9
+ ' target.build_configurations.each do |config|',
10
+ " config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17'",
11
+ ' end',
12
+ ' end',
13
+ ' end',
14
+ ];
15
+
16
+ export const withIosFmtFix: ConfigPlugin = (config) =>
17
+ withPodfile(config, (mod) => {
18
+ const lines = mod.modResults.contents.split('\n');
19
+
20
+ if (lines.some((l) => l.includes(FMT_FIX_MARKER))) return mod;
21
+
22
+ let depth = 0;
23
+ let postInstallCloseIdx = -1;
24
+
25
+ for (let i = 0; i < lines.length; i++) {
26
+ const line = lines[i] ?? '';
27
+ if (line.includes('post_install do')) {
28
+ depth = 1;
29
+ continue;
30
+ }
31
+ if (depth > 0) {
32
+ if (/\bdo\b/.test(line)) depth++;
33
+ if (/^\s*end\b/.test(line)) {
34
+ depth--;
35
+ if (depth === 0) {
36
+ postInstallCloseIdx = i;
37
+ break;
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ if (postInstallCloseIdx >= 0) {
44
+ lines.splice(postInstallCloseIdx, 0, ...FMT_FIX_LINES);
45
+ mod.modResults.contents = lines.join('\n');
46
+ }
47
+
48
+ return mod;
49
+ });
package/src/types/base.ts CHANGED
@@ -3,29 +3,105 @@ import {
3
3
  NextActionWidgetCallbacks,
4
4
  PaymentWidgetCallbacks,
5
5
  VoucherWidgetCallbacks,
6
- } from './interfaces/callbacks';
7
- import { CustomStyles } from './interfaces/customStyle';
8
- import { ElementWidgetType } from './helpers/urlConfig';
6
+ } from "./interfaces/callbacks";
7
+
8
+ export interface GooglePayTransactionInfo {
9
+ totalPrice: string;
10
+ totalPriceStatus: string;
11
+ currencyCode: string;
12
+ countryCode: string;
13
+ totalPriceLabel?: string;
14
+ }
15
+
16
+ export interface ApplePayTransactionInfo {
17
+ label: string;
18
+ amount: string;
19
+ currencyCode: string;
20
+ countryCode: string;
21
+ }
22
+
23
+ export type GooglePayTokenizationType = "PAYMENT_GATEWAY" | "DIRECT";
24
+
25
+ export interface GooglePayWalletConfig {
26
+ merchantId: string;
27
+ merchantName: string;
28
+ /** Payment gateway identifier (e.g. 'deuna', 'adyen') — used with PAYMENT_GATEWAY tokenization */
29
+ gateway: string;
30
+ /** Merchant identifier within the payment gateway — used with PAYMENT_GATEWAY tokenization */
31
+ gatewayMerchantId: string;
32
+ /** Tokenization type: "PAYMENT_GATEWAY" (default) or "DIRECT" */
33
+ tokenizationType?: GooglePayTokenizationType;
34
+ /** Base64-encoded public key for DIRECT tokenization */
35
+ publicKey?: string;
36
+ /** Protocol version for DIRECT tokenization (defaults to "ECv2") */
37
+ protocolVersion?: string;
38
+ transactionInfo?: GooglePayTransactionInfo;
39
+ allowedCardNetworks?: Array<
40
+ "AMEX" | "DISCOVER" | "INTERAC" | "JCB" | "MASTERCARD" | "VISA"
41
+ >;
42
+ allowedCardAuthMethods?: Array<"PAN_ONLY" | "CRYPTOGRAM_3DS">;
43
+ }
44
+
45
+ export interface ApplePayWalletConfig {
46
+ /** Optional — under Option B (DEUNA-Managed), the backend resolves it via X-Api-Key. */
47
+ merchantIdentifier?: string;
48
+ displayName: string;
49
+ transactionInfo?: ApplePayTransactionInfo;
50
+ supportedNetworks?: string[];
51
+ merchantCapabilities?: string[];
52
+ }
53
+
54
+ export interface WalletElementConfig {
55
+ GOOGLE_PAY?: GooglePayWalletConfig;
56
+ APPLE_PAY?: ApplePayWalletConfig;
57
+ }
58
+
59
+ /**
60
+ * Parameters for `getWalletsAvailable()`.
61
+ *
62
+ * - **No arguments (Elements flow):** The SDK calls the DEUNA SSR endpoint
63
+ * with just the `publicApiKey` to resolve wallet credentials from the
64
+ * merchant configuration.
65
+ *
66
+ * - **`{ orderToken, userInfo }` (Elements flow with order):** Same SSR call
67
+ * but includes order data so transactionInfo is pre-resolved. This avoids
68
+ * a second SSR call during the click handler, which is critical for Apple Pay
69
+ * (user gesture must reach `session.begin()` within ~5 seconds).
70
+ *
71
+ * - **`WalletElementConfig` (Payment Widget / Modular Checkout):**
72
+ * Uses the provided credentials directly. No SSR call.
73
+ */
74
+ export type GetWalletsAvailableParams =
75
+ | WalletElementConfig
76
+ | {
77
+ orderToken?: string;
78
+ userInfo?: Partial<UserInfo>;
79
+ };
80
+
81
+
82
+ import { CustomStyles } from "./interfaces/customStyle";
83
+ import { ElementWidgetType } from "./helpers/urlConfig";
9
84
  import {
10
85
  InitWidgetBase,
11
86
  PaymentMethodConfigurationFlow,
12
- } from './interfaces/initWidgetBase';
87
+ UserInfo,
88
+ } from "./interfaces/initWidgetBase";
13
89
  import {
14
90
  Merchant,
15
91
  PaymentMethodTypes,
16
92
  PaymentProcessorName,
17
- } from './interfaces/merchant';
18
- import { Order } from './interfaces/order';
19
- import { User } from './interfaces/user';
20
- import { InitFraudProvidersProps } from './fraudProviders';
93
+ } from "./interfaces/merchant";
94
+ import { Order } from "./interfaces/order";
95
+ import { User } from "./interfaces/user";
96
+ import { InitFraudProvidersProps } from "./fraudProviders";
21
97
 
22
- export type Environment = 'production' | 'sandbox' | 'develop' | 'staging';
98
+ export type Environment = "production" | "sandbox" | "develop" | "staging";
23
99
 
24
100
  export interface InitializeParams {
25
101
  environment?: Environment;
26
102
  publicApiKey: string;
27
103
  }
28
- export type SubmitStatus = 'success' | 'error';
104
+ export type SubmitStatus = "success" | "error";
29
105
 
30
106
  export type SubmitResult = {
31
107
  status: SubmitStatus;
@@ -57,7 +133,7 @@ export type RefetchOrder = () => Promise<Order | null>;
57
133
  export type OrderData = { orderToken?: string; userToken?: string };
58
134
  export type SetOrderDataFn = (data: OrderData) => Promise<void>;
59
135
 
60
- export type InitPaymentWidgetParams = Omit<InitWidgetBase, 'callbacks'> & {
136
+ export type InitPaymentWidgetParams = Omit<InitWidgetBase, "callbacks"> & {
61
137
  orderToken: string;
62
138
  callbacks?: PaymentWidgetCallbacks;
63
139
  paymentMethods?: {
@@ -72,17 +148,19 @@ export type InitPaymentWidgetParams = Omit<InitWidgetBase, 'callbacks'> & {
72
148
  sessionId?: string;
73
149
  };
74
150
 
75
- export type InitElementsWidgetParams = Omit<InitWidgetBase, 'callbacks'> & {
151
+ export type InitElementsWidgetParams = Omit<InitWidgetBase, "callbacks"> & {
76
152
  callbacks?: ElementsWidgetCallbacks;
77
153
  types?: ElementWidgetType[];
154
+ /** Configuration for wallet payment providers (Google Pay, Apple Pay) */
155
+ walletConfig?: WalletElementConfig;
78
156
  };
79
157
 
80
- export type InitNextActionWidgetParams = Omit<InitWidgetBase, 'callbacks'> & {
158
+ export type InitNextActionWidgetParams = Omit<InitWidgetBase, "callbacks"> & {
81
159
  orderToken: string;
82
160
  callbacks: NextActionWidgetCallbacks;
83
161
  };
84
162
 
85
- export type InitVoucherWidgetParams = Omit<InitWidgetBase, 'callbacks'> & {
163
+ export type InitVoucherWidgetParams = Omit<InitWidgetBase, "callbacks"> & {
86
164
  orderToken: string;
87
165
  callbacks: VoucherWidgetCallbacks;
88
166
  };
package/src/types/envs.ts CHANGED
@@ -42,6 +42,20 @@ export const siftCred = {
42
42
  [Env.Sandbox]: 'b267dfc8a5'
43
43
  };
44
44
 
45
+ export const elements = {
46
+ [Env.Production]: 'https://elements.deuna.com',
47
+ [Env.Staging]: 'https://elements.stg.deuna.io',
48
+ [Env.Develop]: 'https://elements.dev.deuna.io',
49
+ [Env.Sandbox]: 'https://elements.sandbox.deuna.io',
50
+ };
51
+
52
+ export const api = {
53
+ [Env.Production]: 'https://api.deuna.io',
54
+ [Env.Staging]: 'https://api.stg.deuna.io',
55
+ [Env.Develop]: 'https://api.dev.deuna.io',
56
+ [Env.Sandbox]: 'https://api.sandbox.deuna.io',
57
+ };
58
+
45
59
  export const proxyUrls = {
46
60
  URL: 'mimos.vendodeuna.com',
47
61
  FPJS_BEHAVIOR_PATH: 'thomas',
@@ -81,4 +81,4 @@ export interface ElementWidgetType {
81
81
  name: ElementWidgetTypeName;
82
82
  }
83
83
 
84
- type ElementWidgetTypeName = "vault" | "click_to_pay";
84
+ type ElementWidgetTypeName = "vault" | "click_to_pay" | "GOOGLE_PAY" | "APPLE_PAY";