@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.
- package/DeunaWalletsModule.podspec +19 -0
- package/README.md +141 -2
- package/android/build.gradle +43 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/java/com/deuna/wallets/DeunaWalletsModule.kt +103 -0
- package/app.plugin.js +1 -0
- package/expo-module.config.json +10 -0
- package/ios/DeunaWalletsModule.swift +56 -0
- package/lib/module/DeunaSDK.js +44 -3
- package/lib/module/DeunaSDK.js.map +1 -1
- package/lib/module/components/DeunaWebView.js +3 -0
- package/lib/module/components/DeunaWebView.js.map +1 -1
- package/lib/module/components/DeunaWidget.js +1 -0
- package/lib/module/components/DeunaWidget.js.map +1 -1
- package/lib/module/controllers/BaseWebViewController.js +17 -4
- package/lib/module/controllers/BaseWebViewController.js.map +1 -1
- package/lib/module/controllers/ElementsWidgetController.js +9 -1
- package/lib/module/controllers/ElementsWidgetController.js.map +1 -1
- package/lib/module/helpers/ExternalUrlHelper.js +4 -1
- package/lib/module/helpers/ExternalUrlHelper.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/plugin/index.js +25 -0
- package/lib/module/plugin/index.js.map +1 -0
- package/lib/module/plugin/withAndroidGooglePay.js +20 -0
- package/lib/module/plugin/withAndroidGooglePay.js.map +1 -0
- package/lib/module/plugin/withIosApplePay.js +10 -0
- package/lib/module/plugin/withIosApplePay.js.map +1 -0
- package/lib/module/plugin/withIosFmtFix.js +34 -0
- package/lib/module/plugin/withIosFmtFix.js.map +1 -0
- package/lib/module/types/base.js +16 -0
- package/lib/module/types/base.js.map +1 -1
- package/lib/module/types/envs.js +12 -0
- package/lib/module/types/envs.js.map +1 -1
- package/lib/module/wallets/WalletModule.js +218 -0
- package/lib/module/wallets/WalletModule.js.map +1 -0
- package/lib/module/wallets/index.js +4 -0
- package/lib/module/wallets/index.js.map +1 -0
- package/lib/module/wallets/tokenize/applePay.js +24 -0
- package/lib/module/wallets/tokenize/applePay.js.map +1 -0
- package/lib/module/wallets/tokenize/googlePay.js +24 -0
- package/lib/module/wallets/tokenize/googlePay.js.map +1 -0
- package/lib/module/wallets/tokenize/index.js +12 -0
- package/lib/module/wallets/tokenize/index.js.map +1 -0
- package/lib/module/wallets/types.js +4 -0
- package/lib/module/wallets/types.js.map +1 -0
- package/lib/module/wallets/vaultApi.js +121 -0
- package/lib/module/wallets/vaultApi.js.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts +12 -3
- package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts +7 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/controllers/ElementsWidgetController.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/helpers/ExternalUrlHelper.d.ts +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/ExternalUrlHelper.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/index.d.ts +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/index.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/plugin/index.d.ts +8 -0
- package/lib/typescript/deuna-sdk-react-native/src/plugin/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/plugin/withAndroidGooglePay.d.ts +3 -0
- package/lib/typescript/deuna-sdk-react-native/src/plugin/withAndroidGooglePay.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosApplePay.d.ts +5 -0
- package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosApplePay.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosFmtFix.d.ts +3 -0
- package/lib/typescript/deuna-sdk-react-native/src/plugin/withIosFmtFix.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts +78 -14
- package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/envs.d.ts +12 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/envs.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts +11 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts +3 -3
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/wallets/WalletModule.d.ts +29 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/WalletModule.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/index.d.ts +3 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/applePay.d.ts +2 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/applePay.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/googlePay.d.ts +2 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/googlePay.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/index.d.ts +3 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/tokenize/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/types.d.ts +15 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/types.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/vaultApi.d.ts +38 -0
- package/lib/typescript/deuna-sdk-react-native/src/wallets/vaultApi.d.ts.map +1 -0
- package/package.json +14 -2
- package/react-native.config.js +8 -0
- package/src/DeunaSDK.ts +65 -4
- package/src/components/DeunaWebView.tsx +4 -0
- package/src/components/DeunaWidget.tsx +2 -0
- package/src/controllers/BaseWebViewController.ts +15 -4
- package/src/controllers/ElementsWidgetController.ts +16 -1
- package/src/helpers/ExternalUrlHelper.ts +5 -1
- package/src/index.tsx +1 -0
- package/src/plugin/index.ts +29 -0
- package/src/plugin/withAndroidGooglePay.ts +15 -0
- package/src/plugin/withIosApplePay.ts +10 -0
- package/src/plugin/withIosFmtFix.ts +49 -0
- package/src/types/base.ts +92 -14
- package/src/types/envs.ts +14 -0
- package/src/types/helpers/urlConfig.ts +1 -1
- package/src/types/interfaces/callbacks.ts +15 -0
- package/src/types/interfaces/initWidgetBase.ts +3 -3
- package/src/wallets/WalletModule.ts +255 -0
- package/src/wallets/index.ts +13 -0
- package/src/wallets/tokenize/applePay.ts +22 -0
- package/src/wallets/tokenize/googlePay.ts +27 -0
- package/src/wallets/tokenize/index.ts +12 -0
- package/src/wallets/types.ts +17 -0
- 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
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
87
|
+
UserInfo,
|
|
88
|
+
} from "./interfaces/initWidgetBase";
|
|
13
89
|
import {
|
|
14
90
|
Merchant,
|
|
15
91
|
PaymentMethodTypes,
|
|
16
92
|
PaymentProcessorName,
|
|
17
|
-
} from
|
|
18
|
-
import { Order } from
|
|
19
|
-
import { User } from
|
|
20
|
-
import { InitFraudProvidersProps } from
|
|
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 =
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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',
|
|
@@ -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 {
|
|
@@ -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,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
|
+
}
|