@deuna/react-native-sdk 2.0.4 → 2.1.0-beta.1

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 (116) 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/helpers/ExternalUrlHelper.js +4 -1
  20. package/lib/module/helpers/ExternalUrlHelper.js.map +1 -1
  21. package/lib/module/index.js +1 -0
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/module/plugin/index.js +25 -0
  24. package/lib/module/plugin/index.js.map +1 -0
  25. package/lib/module/plugin/withAndroidGooglePay.js +20 -0
  26. package/lib/module/plugin/withAndroidGooglePay.js.map +1 -0
  27. package/lib/module/plugin/withIosApplePay.js +10 -0
  28. package/lib/module/plugin/withIosApplePay.js.map +1 -0
  29. package/lib/module/plugin/withIosFmtFix.js +34 -0
  30. package/lib/module/plugin/withIosFmtFix.js.map +1 -0
  31. package/lib/module/types/base.js +16 -0
  32. package/lib/module/types/base.js.map +1 -1
  33. package/lib/module/types/envs.js +12 -0
  34. package/lib/module/types/envs.js.map +1 -1
  35. package/lib/module/wallets/WalletModule.js +218 -0
  36. package/lib/module/wallets/WalletModule.js.map +1 -0
  37. package/lib/module/wallets/index.js +4 -0
  38. package/lib/module/wallets/index.js.map +1 -0
  39. package/lib/module/wallets/tokenize/applePay.js +24 -0
  40. package/lib/module/wallets/tokenize/applePay.js.map +1 -0
  41. package/lib/module/wallets/tokenize/googlePay.js +24 -0
  42. package/lib/module/wallets/tokenize/googlePay.js.map +1 -0
  43. package/lib/module/wallets/tokenize/index.js +12 -0
  44. package/lib/module/wallets/tokenize/index.js.map +1 -0
  45. package/lib/module/wallets/types.js +4 -0
  46. package/lib/module/wallets/types.js.map +1 -0
  47. package/lib/module/wallets/vaultApi.js +121 -0
  48. package/lib/module/wallets/vaultApi.js.map +1 -0
  49. package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts +12 -3
  50. package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts.map +1 -1
  51. package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts +1 -0
  52. package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts.map +1 -1
  53. package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts +7 -0
  54. package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts.map +1 -1
  55. package/lib/typescript/deuna-sdk-react-native/src/controllers/ElementsWidgetController.d.ts.map +1 -1
  56. package/lib/typescript/deuna-sdk-react-native/src/helpers/ExternalUrlHelper.d.ts +1 -0
  57. package/lib/typescript/deuna-sdk-react-native/src/helpers/ExternalUrlHelper.d.ts.map +1 -1
  58. package/lib/typescript/deuna-sdk-react-native/src/index.d.ts +1 -0
  59. package/lib/typescript/deuna-sdk-react-native/src/index.d.ts.map +1 -1
  60. package/lib/typescript/deuna-sdk-react-native/src/plugin/index.d.ts +8 -0
  61. package/lib/typescript/deuna-sdk-react-native/src/plugin/index.d.ts.map +1 -0
  62. package/lib/typescript/deuna-sdk-react-native/src/plugin/withAndroidGooglePay.d.ts +3 -0
  63. package/lib/typescript/deuna-sdk-react-native/src/plugin/withAndroidGooglePay.d.ts.map +1 -0
  64. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosApplePay.d.ts +5 -0
  65. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosApplePay.d.ts.map +1 -0
  66. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosFmtFix.d.ts +3 -0
  67. package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosFmtFix.d.ts.map +1 -0
  68. package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts +78 -14
  69. package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts.map +1 -1
  70. package/lib/typescript/deuna-sdk-react-native/src/types/envs.d.ts +12 -0
  71. package/lib/typescript/deuna-sdk-react-native/src/types/envs.d.ts.map +1 -1
  72. package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts +1 -1
  73. package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts.map +1 -1
  74. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts +11 -0
  75. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts.map +1 -1
  76. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts +3 -3
  77. package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts.map +1 -1
  78. package/lib/typescript/deuna-sdk-react-native/src/wallets/WalletModule.d.ts +29 -0
  79. package/lib/typescript/deuna-sdk-react-native/src/wallets/WalletModule.d.ts.map +1 -0
  80. package/lib/typescript/deuna-sdk-react-native/src/wallets/index.d.ts +3 -0
  81. package/lib/typescript/deuna-sdk-react-native/src/wallets/index.d.ts.map +1 -0
  82. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/applePay.d.ts +2 -0
  83. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/applePay.d.ts.map +1 -0
  84. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/googlePay.d.ts +2 -0
  85. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/googlePay.d.ts.map +1 -0
  86. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/index.d.ts +3 -0
  87. package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/index.d.ts.map +1 -0
  88. package/lib/typescript/deuna-sdk-react-native/src/wallets/types.d.ts +15 -0
  89. package/lib/typescript/deuna-sdk-react-native/src/wallets/types.d.ts.map +1 -0
  90. package/lib/typescript/deuna-sdk-react-native/src/wallets/vaultApi.d.ts +38 -0
  91. package/lib/typescript/deuna-sdk-react-native/src/wallets/vaultApi.d.ts.map +1 -0
  92. package/package.json +14 -2
  93. package/react-native.config.js +8 -0
  94. package/src/DeunaSDK.ts +65 -4
  95. package/src/components/DeunaWebView.tsx +4 -0
  96. package/src/components/DeunaWidget.tsx +2 -0
  97. package/src/controllers/BaseWebViewController.ts +15 -4
  98. package/src/controllers/ElementsWidgetController.ts +16 -1
  99. package/src/helpers/ExternalUrlHelper.ts +5 -1
  100. package/src/index.tsx +1 -0
  101. package/src/plugin/index.ts +29 -0
  102. package/src/plugin/withAndroidGooglePay.ts +15 -0
  103. package/src/plugin/withIosApplePay.ts +10 -0
  104. package/src/plugin/withIosFmtFix.ts +49 -0
  105. package/src/types/base.ts +92 -14
  106. package/src/types/envs.ts +14 -0
  107. package/src/types/helpers/urlConfig.ts +1 -1
  108. package/src/types/interfaces/callbacks.ts +15 -0
  109. package/src/types/interfaces/initWidgetBase.ts +3 -3
  110. package/src/wallets/WalletModule.ts +255 -0
  111. package/src/wallets/index.ts +13 -0
  112. package/src/wallets/tokenize/applePay.ts +22 -0
  113. package/src/wallets/tokenize/googlePay.ts +27 -0
  114. package/src/wallets/tokenize/index.ts +12 -0
  115. package/src/wallets/types.ts +17 -0
  116. package/src/wallets/vaultApi.ts +229 -0
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";
@@ -2,6 +2,20 @@ export type ClosedAction = "userAction" | "systemAction";
2
2
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
3
  export type Json = Record<string, any>;
4
4
 
5
+ export interface WalletPaymentData {
6
+ provider: "GOOGLE_PAY" | "APPLE_PAY";
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ paymentMethodData: Record<string, any>;
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ shippingAddress?: Record<string, any>;
11
+ email?: string;
12
+ }
13
+
14
+ export interface WalletPaymentAuthResult {
15
+ status: "SUCCESS" | "ERROR";
16
+ error?: string;
17
+ }
18
+
5
19
  export interface OnError {
6
20
  type: string;
7
21
  metadata: {
@@ -36,6 +50,7 @@ export interface PaymentWidgetCallbacks extends BaseCallbacks {
36
50
  onCardBinDetected?: (data: OnCardBinDetected) => void;
37
51
  onInstallmentSelected?: (data: OnInstallmentSelectedPayload) => void;
38
52
  onPaymentProcessing?: () => void;
53
+ onPaymentAuthorized?: (data: WalletPaymentData) => Promise<WalletPaymentAuthResult>;
39
54
  }
40
55
 
41
56
  export interface ElementsWidgetCallbacks extends BaseCallbacks {
@@ -11,9 +11,9 @@ type DeepPartial<T> = {
11
11
 
12
12
  export type Language = "es" | "pt" | "en";
13
13
 
14
- interface UserInfo {
15
- firstName: string;
16
- lastName: string;
14
+ export interface UserInfo {
15
+ firstName?: string;
16
+ lastName?: string;
17
17
  email: string;
18
18
  }
19
19
 
@@ -0,0 +1,255 @@
1
+ import type { EventSubscription as Subscription } from 'expo-modules-core';
2
+ import type {
3
+ InitElementsParams,
4
+ WalletProvider,
5
+ WalletsError,
6
+ } from './types';
7
+ import type { UserInfo } from '../types/interfaces/initWidgetBase';
8
+ import type {
9
+ GetWalletsAvailableParams,
10
+ WalletElementConfig,
11
+ } from '../types/base';
12
+ import { fetchVaultResult } from './vaultApi';
13
+ import { api as API_URLS } from '../types/envs';
14
+ import { buildTokenizeBody } from './tokenize';
15
+
16
+ // Lazy-load expo-modules-core so the SDK still works on environments without it.
17
+ function getNativeWallets() {
18
+ try {
19
+ const { requireNativeModule } = require('expo-modules-core');
20
+ return requireNativeModule('DeunaWallets');
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ function getEmitter() {
27
+ try {
28
+ const { EventEmitter } = require('expo-modules-core');
29
+ const mod = getNativeWallets();
30
+ return mod ? new EventEmitter(mod) : null;
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+
36
+ function isWalletElementConfig(params: GetWalletsAvailableParams): params is WalletElementConfig {
37
+ return 'GOOGLE_PAY' in params || 'APPLE_PAY' in params;
38
+ }
39
+
40
+ const WALLET_PROVIDER_MAP: Record<string, WalletProvider> = {
41
+ GOOGLE_PAY: 'google_pay',
42
+ APPLE_PAY: 'apple_pay',
43
+ };
44
+
45
+ /**
46
+ * Returns the list of wallet providers available on the current device for the given order.
47
+ *
48
+ * Two flows:
49
+ * - WalletElementConfig: credentials provided directly, no vault fetch.
50
+ * Native module checks device availability only.
51
+ * - { orderToken?, userInfo? }: fetches vault API to get providers + credentials,
52
+ * then native module filters by device availability.
53
+ */
54
+ export async function getWalletsAvailable(
55
+ publicApiKey: string,
56
+ environment: string,
57
+ params: GetWalletsAvailableParams
58
+ ): Promise<WalletProvider[]> {
59
+ const mod = getNativeWallets();
60
+ if (!mod) {
61
+ console.log('❌ [Wallets] No native module available');
62
+ return [];
63
+ }
64
+
65
+ if (isWalletElementConfig(params)) {
66
+ const providers = Object.keys(params).filter(
67
+ (k): k is keyof WalletElementConfig => k === 'GOOGLE_PAY' || k === 'APPLE_PAY'
68
+ );
69
+ console.log('[Wallets] WalletElementConfig flow — providers:', providers);
70
+
71
+ const available: string[] = await mod.checkAvailableProviders({
72
+ providers: providers.map((p) => WALLET_PROVIDER_MAP[p]),
73
+ environment,
74
+ });
75
+ console.log('[Wallets] checkAvailableProviders result:', available);
76
+
77
+ return available as WalletProvider[];
78
+ }
79
+
80
+ const { orderToken, userInfo } = params as { orderToken?: string; userInfo?: Partial<UserInfo> };
81
+ console.log('[Wallets] vault flow — orderToken:', orderToken, 'environment:', environment);
82
+
83
+ const vaultResult = await fetchVaultResult(environment, publicApiKey, orderToken, userInfo);
84
+ console.log('[Wallets] vault result — providers:', vaultResult.providers, 'hasUserToken:', !!vaultResult.userToken);
85
+
86
+ if (vaultResult.providers.length === 0) {
87
+ console.log('❌ [Wallets] No providers from vault API');
88
+ return [];
89
+ }
90
+
91
+ const available: string[] = await mod.checkAvailableProviders({
92
+ providers: vaultResult.providers,
93
+ environment,
94
+ });
95
+ console.log('[Wallets] checkAvailableProviders result:', available);
96
+
97
+ return available as WalletProvider[];
98
+ }
99
+
100
+ /**
101
+ * Launches the native wallet payment sheet for the given provider.
102
+ * - Resolves with `undefined` on payment success (tokenization complete if userToken present).
103
+ * - Resolves with `"closed"` when the user dismisses without paying.
104
+ * - Rejects with a `WalletsError` on failure.
105
+ *
106
+ * Credentials are re-used from a prior getWalletsAvailable call if available,
107
+ * otherwise the vault API is refetched.
108
+ */
109
+ export async function initElements(
110
+ params: InitElementsParams,
111
+ walletConfig?: WalletElementConfig
112
+ ): Promise<Record<string, unknown> | 'closed'> {
113
+ const mod = getNativeWallets();
114
+ if (!mod)
115
+ throw new Error(
116
+ 'DeunaWallets native module is not available on this platform. ' +
117
+ 'Ensure expo-modules-core is installed and the native module is linked.'
118
+ );
119
+
120
+ const { orderToken, publicApiKey, environment, walletProvider, userInfo } = params;
121
+
122
+ let credentials: Record<string, unknown> | undefined;
123
+ let userToken: string | undefined;
124
+ let userId: string | undefined;
125
+
126
+ if (walletConfig) {
127
+ const configKey = walletProvider === 'apple_pay' ? 'APPLE_PAY' : 'GOOGLE_PAY';
128
+ credentials = walletConfig[configKey] as Record<string, unknown> | undefined;
129
+ }
130
+
131
+ if (!credentials) {
132
+ console.log('[Wallets] initElements vault fetch — orderToken:', orderToken, 'hasUserInfo:', !!userInfo, 'email:', (userInfo as any)?.email);
133
+ const vaultResult = await fetchVaultResult(environment, publicApiKey, orderToken, userInfo);
134
+ console.log('[Wallets] initElements vault result — hasUserToken:', !!vaultResult.userToken, 'hasUserId:', !!vaultResult.userId, 'providers:', vaultResult.providers);
135
+ credentials = vaultResult.credentials[walletProvider] as Record<string, unknown> | undefined;
136
+ userToken = vaultResult.userToken;
137
+ userId = vaultResult.userId;
138
+ }
139
+
140
+ if (!credentials) {
141
+ throw {
142
+ code: 'WALLET_UNAVAILABLE',
143
+ message: `No credentials for ${walletProvider}`,
144
+ };
145
+ }
146
+
147
+ if (!userToken || !userId) {
148
+ throw { code: 'MISSING_USER_AUTH', message: 'userToken or userId is missing — cannot tokenize wallet payment.' };
149
+ }
150
+
151
+ console.log('[Wallets] launchWallet →', walletProvider, 'credentials keys:', Object.keys(credentials));
152
+
153
+ let result: Record<string, unknown> | 'closed';
154
+ try {
155
+ result = await mod.launchWallet({
156
+ provider: walletProvider,
157
+ credentials,
158
+ environment,
159
+ });
160
+ } catch (nativeErr: any) {
161
+ console.log('❌ [Wallets] launchWallet native error:', nativeErr?.message ?? JSON.stringify(nativeErr));
162
+ throw nativeErr;
163
+ }
164
+
165
+ if (result === 'closed') return 'closed';
166
+
167
+ console.log('[Wallets] launchWallet raw result:', JSON.stringify(result, null, 2));
168
+
169
+ return await tokenizeCard({
170
+ environment,
171
+ publicApiKey,
172
+ userId,
173
+ userToken,
174
+ provider: walletProvider,
175
+ paymentData: (result as Record<string, unknown>).paymentData,
176
+ });
177
+ }
178
+
179
+ async function tokenizeCard(params: {
180
+ environment: string;
181
+ publicApiKey: string;
182
+ userId: string;
183
+ userToken: string;
184
+ provider: WalletProvider;
185
+ paymentData: unknown;
186
+ }): Promise<Record<string, unknown>> {
187
+ const { environment, publicApiKey, userId, userToken, provider, paymentData } = params;
188
+ const base = API_URLS[environment as keyof typeof API_URLS] ?? API_URLS.develop;
189
+ const url = `${base}/users/${encodeURIComponent(userId)}/cards`;
190
+
191
+ const body = buildTokenizeBody(provider, paymentData);
192
+
193
+ console.log(`[Wallets] tokenizeCard → POST ${url} provider=${provider}`);
194
+ console.log('[Wallets] tokenizeCard body:', JSON.stringify(body, null, 2));
195
+
196
+ let response: Response;
197
+ try {
198
+ response = await fetch(url, {
199
+ method: 'POST',
200
+ headers: {
201
+ 'Content-Type': 'application/json',
202
+ Authorization: `Bearer ${userToken}`,
203
+ 'x-api-key': publicApiKey,
204
+ },
205
+ body: JSON.stringify(body),
206
+ });
207
+ } catch (networkErr: any) {
208
+ console.log(`❌ [Wallets] tokenizeCard network error: ${networkErr?.message ?? networkErr}`);
209
+ throw { code: 'NETWORK_ERROR', message: networkErr?.message ?? 'Network request failed' };
210
+ }
211
+
212
+ const responseText = await response.text().catch(() => '');
213
+ console.log(`[Wallets] tokenizeCard response: status=${response.status} body=${responseText}`);
214
+
215
+ let json: Record<string, unknown> = {};
216
+ try { json = JSON.parse(responseText); } catch { /* non-JSON body */ }
217
+
218
+ if (json?.error) {
219
+ const errPayload = json.error as Record<string, unknown>;
220
+ console.log(`❌ [Wallets] tokenizeCard API error: code=${errPayload.code} message=${errPayload.message}`);
221
+ throw {
222
+ code: errPayload.code ?? 'TOKENIZATION_ERROR',
223
+ message: errPayload.message ?? 'Card tokenization returned an error.',
224
+ };
225
+ }
226
+
227
+ if (!response.ok) {
228
+ console.log(`❌ [Wallets] tokenizeCard failed: HTTP ${response.status}`);
229
+ throw { code: 'TOKENIZATION_ERROR', message: `Tokenization failed: ${response.status}` };
230
+ }
231
+
232
+ console.log(`✅ [Wallets] tokenizeCard success`);
233
+ return json;
234
+ }
235
+
236
+ export function addWalletSuccessListener(
237
+ listener: (data: Record<string, unknown>) => void
238
+ ): Subscription | null {
239
+ const emitter = getEmitter();
240
+ return emitter?.addListener('onWalletSuccess', listener) ?? null;
241
+ }
242
+
243
+ export function addWalletErrorListener(
244
+ listener: (error: WalletsError) => void
245
+ ): Subscription | null {
246
+ const emitter = getEmitter();
247
+ return emitter?.addListener('onWalletError', listener) ?? null;
248
+ }
249
+
250
+ export function addWalletClosedListener(
251
+ listener: (payload: { action: 'userAction' | 'systemAction' }) => void
252
+ ): Subscription | null {
253
+ const emitter = getEmitter();
254
+ return emitter?.addListener('onWalletClosed', listener) ?? null;
255
+ }
@@ -0,0 +1,13 @@
1
+ export {
2
+ getWalletsAvailable,
3
+ initElements,
4
+ addWalletSuccessListener,
5
+ addWalletErrorListener,
6
+ addWalletClosedListener,
7
+ } from './WalletModule';
8
+
9
+ export type {
10
+ WalletProvider,
11
+ WalletsError,
12
+ InitElementsParams,
13
+ } from './types';
@@ -0,0 +1,22 @@
1
+ export function buildApplePayTokenizeBody(paymentData: unknown): Record<string, unknown> {
2
+ const pd = (paymentData ?? {}) as Record<string, unknown>;
3
+ const header = (pd['header'] ?? {}) as Record<string, unknown>;
4
+
5
+ return {
6
+ credential_source: 'apple_pay',
7
+ credential_source_config: {
8
+ type: 'apple_pay',
9
+ values: {
10
+ system: pd['version'] ?? '',
11
+ merchant_transaction_id: header['transactionId'] ?? '',
12
+ encrypted_data: pd['data'] ?? '',
13
+ encryption_header: {
14
+ signature: pd['signature'] ?? '',
15
+ public_key_hash: header['publicKeyHash'] ?? '',
16
+ ephemeral_public_key: header['ephemeralPublicKey'] ?? '',
17
+ },
18
+ src_cx_flow_id: 'mobile',
19
+ },
20
+ },
21
+ };
22
+ }
@@ -0,0 +1,27 @@
1
+ export function buildGooglePayTokenizeBody(paymentData: unknown): Record<string, unknown> {
2
+ const pd = (paymentData ?? {}) as Record<string, unknown>;
3
+
4
+ const rawPMD = pd['paymentMethodData'];
5
+ console.log(`[Wallets] paymentMethodData type=${typeof rawPMD} value=${JSON.stringify(rawPMD)}`);
6
+
7
+ const paymentMethodData = (rawPMD ?? {}) as Record<string, unknown>;
8
+
9
+ const rawTD = paymentMethodData['tokenizationData'];
10
+ console.log(`[Wallets] tokenizationData type=${typeof rawTD} value=${JSON.stringify(rawTD)}`);
11
+
12
+ const tokenizationData = (rawTD ?? {}) as Record<string, unknown>;
13
+ const encryptedData = (tokenizationData['token'] ?? '') as string;
14
+
15
+ console.log(`[Wallets] token type=${typeof tokenizationData['token']} length=${encryptedData.length}`);
16
+
17
+ return {
18
+ credential_source: 'google_pay',
19
+ credential_source_config: {
20
+ type: 'google_pay',
21
+ values: {
22
+ encrypted_data: encryptedData,
23
+ src_cx_flow_id: 'mobile',
24
+ },
25
+ },
26
+ };
27
+ }
@@ -0,0 +1,12 @@
1
+ import type { WalletProvider } from '../types';
2
+ import { buildGooglePayTokenizeBody } from './googlePay';
3
+ import { buildApplePayTokenizeBody } from './applePay';
4
+
5
+ const tokenizeBodyBuilders: Record<WalletProvider, (paymentData: unknown) => Record<string, unknown>> = {
6
+ google_pay: buildGooglePayTokenizeBody,
7
+ apple_pay: buildApplePayTokenizeBody,
8
+ };
9
+
10
+ export function buildTokenizeBody(provider: WalletProvider, paymentData: unknown): Record<string, unknown> {
11
+ return tokenizeBodyBuilders[provider](paymentData);
12
+ }
@@ -0,0 +1,17 @@
1
+ import type { Environment } from '../types/base';
2
+ import type { UserInfo } from '../types/interfaces/initWidgetBase';
3
+
4
+ export type WalletProvider = 'apple_pay' | 'google_pay';
5
+
6
+ export interface WalletsError {
7
+ code: string;
8
+ message: string;
9
+ }
10
+
11
+ export interface InitElementsParams {
12
+ orderToken: string;
13
+ publicApiKey: string;
14
+ environment: Environment;
15
+ walletProvider: WalletProvider;
16
+ userInfo?: Partial<UserInfo>;
17
+ }