@yuno-payments/yuno-sdk-react-native 1.0.16 → 1.0.17-rc.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.
- package/README.md +795 -262
- package/YunoSdk.podspec +48 -0
- package/android/src/main/java/com/yunosdkreactnative/YunoSdkModule.kt +225 -0
- package/ios/YunoPaymentMethodsViewManager.m +10 -0
- package/ios/YunoPaymentMethodsViewManager.swift +324 -0
- package/ios/YunoSdk.m +42 -5
- package/ios/YunoSdk.swift +297 -70
- package/lib/commonjs/YunoPaymentMethods.js +9 -9
- package/lib/commonjs/YunoPaymentMethods.js.map +1 -1
- package/lib/commonjs/YunoSdk.js +138 -25
- package/lib/commonjs/YunoSdk.js.map +1 -1
- package/lib/commonjs/core/types/HeadlessTypes.js +16 -0
- package/lib/commonjs/core/types/HeadlessTypes.js.map +1 -0
- package/lib/module/YunoPaymentMethods.js +9 -9
- package/lib/module/YunoPaymentMethods.js.map +1 -1
- package/lib/module/YunoSdk.js +138 -25
- package/lib/module/YunoSdk.js.map +1 -1
- package/lib/module/core/types/HeadlessTypes.js +11 -0
- package/lib/module/core/types/HeadlessTypes.js.map +1 -0
- package/package.json +1 -1
- package/src/YunoPaymentMethods.tsx +17 -15
- package/src/YunoSdk.ts +159 -39
- package/src/core/types/HeadlessTypes.ts +89 -0
- package/src/core/types/OneTimeTokenInfo.ts +0 -1
- package/src/core/types/index.ts +14 -0
package/src/YunoSdk.ts
CHANGED
|
@@ -7,30 +7,37 @@ import type {
|
|
|
7
7
|
StartPayment,
|
|
8
8
|
SeamlessArguments,
|
|
9
9
|
OneTimeTokenInfo,
|
|
10
|
+
TokenCollectedData,
|
|
11
|
+
HeadlessTokenResponse,
|
|
12
|
+
ThreeDSecureChallengeResponse,
|
|
10
13
|
} from './core/types';
|
|
11
14
|
import { YunoStatus, YunoLanguage, CardFlow } from './core/enums';
|
|
12
15
|
|
|
13
16
|
const LINKING_ERROR =
|
|
14
|
-
`The package '@
|
|
17
|
+
`The package '@yuno/yuno-sdk-react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
15
18
|
Platform.select({ ios: "- Run 'pod install'\n", default: '' }) +
|
|
16
19
|
'- You rebuilt the app after installing the package\n' +
|
|
17
20
|
'- You are not using Expo Go\n';
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Devuelve el módulo nativo YunoSdk o lanza un error de linking
|
|
24
|
+
*/
|
|
25
|
+
function getYunoNative(): any {
|
|
26
|
+
const native = NativeModules.YunoSdk;
|
|
27
|
+
if (!native) {
|
|
28
|
+
throw new Error(LINKING_ERROR);
|
|
29
|
+
}
|
|
30
|
+
return native;
|
|
31
|
+
}
|
|
29
32
|
|
|
30
33
|
/**
|
|
31
|
-
*
|
|
34
|
+
* Devuelve un NativeEventEmitter para el módulo YunoSdk
|
|
35
|
+
* Se crea sólo cuando hace falta (no en top-level).
|
|
32
36
|
*/
|
|
33
|
-
|
|
37
|
+
function getYunoEventEmitter(): NativeEventEmitter {
|
|
38
|
+
const native = getYunoNative();
|
|
39
|
+
return new NativeEventEmitter(native);
|
|
40
|
+
}
|
|
34
41
|
|
|
35
42
|
/**
|
|
36
43
|
* Payment state event data.
|
|
@@ -85,13 +92,16 @@ export class YunoSdk {
|
|
|
85
92
|
/**
|
|
86
93
|
* Marks the SDK as initialized without calling the native initialize method.
|
|
87
94
|
* This is useful when the SDK has been initialized from the native side (e.g., in MainActivity/YunoActivity).
|
|
88
|
-
*
|
|
95
|
+
*
|
|
89
96
|
* @param countryCode - ISO country code (e.g., 'US', 'BR', 'CO')
|
|
90
97
|
* @param language - Optional language setting (defaults to EN)
|
|
91
|
-
*
|
|
98
|
+
*
|
|
92
99
|
* @internal
|
|
93
100
|
*/
|
|
94
|
-
static markAsInitialized(
|
|
101
|
+
static markAsInitialized(
|
|
102
|
+
countryCode: string = 'CO',
|
|
103
|
+
language: YunoLanguage = YunoLanguage.EN
|
|
104
|
+
): void {
|
|
95
105
|
this.countryCode = countryCode;
|
|
96
106
|
this.language = language;
|
|
97
107
|
this.isInitialized = true;
|
|
@@ -153,7 +163,7 @@ export class YunoSdk {
|
|
|
153
163
|
this.countryCode = countryCode;
|
|
154
164
|
this.language = config.lang!;
|
|
155
165
|
|
|
156
|
-
await
|
|
166
|
+
await getYunoNative().initialize(
|
|
157
167
|
apiKey,
|
|
158
168
|
countryCode,
|
|
159
169
|
config,
|
|
@@ -186,7 +196,7 @@ export class YunoSdk {
|
|
|
186
196
|
countryCode: params.countryCode ?? this.getCountryCode(),
|
|
187
197
|
};
|
|
188
198
|
|
|
189
|
-
return
|
|
199
|
+
return getYunoNative().enrollmentPayment(args);
|
|
190
200
|
}
|
|
191
201
|
|
|
192
202
|
/**
|
|
@@ -214,7 +224,7 @@ export class YunoSdk {
|
|
|
214
224
|
this.checkInitialized();
|
|
215
225
|
|
|
216
226
|
const code = countryCode ?? this.getCountryCode();
|
|
217
|
-
return
|
|
227
|
+
return getYunoNative().startPaymentLite(params, code);
|
|
218
228
|
}
|
|
219
229
|
|
|
220
230
|
/**
|
|
@@ -229,7 +239,7 @@ export class YunoSdk {
|
|
|
229
239
|
*/
|
|
230
240
|
static async startPayment(showPaymentStatus: boolean = true): Promise<void> {
|
|
231
241
|
this.checkInitialized();
|
|
232
|
-
return
|
|
242
|
+
return getYunoNative().startPayment(showPaymentStatus);
|
|
233
243
|
}
|
|
234
244
|
|
|
235
245
|
/**
|
|
@@ -251,7 +261,11 @@ export class YunoSdk {
|
|
|
251
261
|
): Promise<void> {
|
|
252
262
|
this.checkInitialized();
|
|
253
263
|
const code = countryCode ?? this.getCountryCode();
|
|
254
|
-
return
|
|
264
|
+
return getYunoNative().continuePayment(
|
|
265
|
+
checkoutSession,
|
|
266
|
+
code,
|
|
267
|
+
showPaymentStatus
|
|
268
|
+
);
|
|
255
269
|
}
|
|
256
270
|
|
|
257
271
|
/**
|
|
@@ -284,7 +298,7 @@ export class YunoSdk {
|
|
|
284
298
|
countryCode: params.countryCode ?? this.getCountryCode(),
|
|
285
299
|
};
|
|
286
300
|
|
|
287
|
-
const statusString = await
|
|
301
|
+
const statusString = await getYunoNative().startPaymentSeamlessLite(
|
|
288
302
|
args,
|
|
289
303
|
this.getLanguage()
|
|
290
304
|
);
|
|
@@ -302,7 +316,7 @@ export class YunoSdk {
|
|
|
302
316
|
*/
|
|
303
317
|
static async hideLoader(): Promise<void> {
|
|
304
318
|
this.checkInitialized();
|
|
305
|
-
return
|
|
319
|
+
return getYunoNative().hideLoader();
|
|
306
320
|
}
|
|
307
321
|
|
|
308
322
|
/**
|
|
@@ -326,7 +340,7 @@ export class YunoSdk {
|
|
|
326
340
|
}
|
|
327
341
|
|
|
328
342
|
this.checkInitialized();
|
|
329
|
-
return
|
|
343
|
+
return getYunoNative().receiveDeeplink(url);
|
|
330
344
|
}
|
|
331
345
|
|
|
332
346
|
/**
|
|
@@ -346,7 +360,7 @@ export class YunoSdk {
|
|
|
346
360
|
* ```
|
|
347
361
|
*/
|
|
348
362
|
static async getLastOneTimeToken(): Promise<string | null> {
|
|
349
|
-
return
|
|
363
|
+
return getYunoNative().getLastOneTimeToken();
|
|
350
364
|
}
|
|
351
365
|
|
|
352
366
|
/**
|
|
@@ -363,16 +377,16 @@ export class YunoSdk {
|
|
|
363
377
|
* ```
|
|
364
378
|
*/
|
|
365
379
|
static async getLastOneTimeTokenInfo(): Promise<OneTimeTokenInfo | null> {
|
|
366
|
-
return
|
|
380
|
+
return getYunoNative().getLastOneTimeTokenInfo();
|
|
367
381
|
}
|
|
368
382
|
|
|
369
383
|
/**
|
|
370
384
|
* Clears the last OTT tokens stored by the SDK.
|
|
371
385
|
* This is useful to ensure clean state before starting a new payment flow.
|
|
372
|
-
*
|
|
386
|
+
*
|
|
373
387
|
* Note: This is automatically called at the start of each payment/enrollment flow,
|
|
374
388
|
* but you can call it manually if needed.
|
|
375
|
-
*
|
|
389
|
+
*
|
|
376
390
|
* @example
|
|
377
391
|
* ```typescript
|
|
378
392
|
* // Clear OTT before starting a new payment
|
|
@@ -380,7 +394,25 @@ export class YunoSdk {
|
|
|
380
394
|
* ```
|
|
381
395
|
*/
|
|
382
396
|
static async clearLastOneTimeToken(): Promise<void> {
|
|
383
|
-
return
|
|
397
|
+
return getYunoNative().clearLastOneTimeToken();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Clears the last stored payment status.
|
|
402
|
+
* This should be called at the start of each new payment flow
|
|
403
|
+
* to prevent stale status from previous flows affecting new transactions.
|
|
404
|
+
*
|
|
405
|
+
* @returns Promise that resolves when the status is cleared
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* ```typescript
|
|
409
|
+
* // Clear payment status before starting a new flow
|
|
410
|
+
* await YunoSdk.clearLastPaymentStatus();
|
|
411
|
+
* await YunoSdk.startPayment({ checkoutSession, countryCode });
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
static async clearLastPaymentStatus(): Promise<void> {
|
|
415
|
+
return getYunoNative().clearLastPaymentStatus();
|
|
384
416
|
}
|
|
385
417
|
|
|
386
418
|
/**
|
|
@@ -408,10 +440,8 @@ export class YunoSdk {
|
|
|
408
440
|
static onPaymentStatus(listener: (state: YunoPaymentState) => void): {
|
|
409
441
|
remove: () => void;
|
|
410
442
|
} {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
listener
|
|
414
|
-
);
|
|
443
|
+
const emitter = getYunoEventEmitter();
|
|
444
|
+
const subscription = emitter.addListener('YunoPaymentStatus', listener);
|
|
415
445
|
return { remove: () => subscription.remove() };
|
|
416
446
|
}
|
|
417
447
|
|
|
@@ -440,10 +470,8 @@ export class YunoSdk {
|
|
|
440
470
|
static onEnrollmentStatus(listener: (state: YunoEnrollmentState) => void): {
|
|
441
471
|
remove: () => void;
|
|
442
472
|
} {
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
listener
|
|
446
|
-
);
|
|
473
|
+
const emitter = getYunoEventEmitter();
|
|
474
|
+
const subscription = emitter.addListener('YunoEnrollmentStatus', listener);
|
|
447
475
|
return { remove: () => subscription.remove() };
|
|
448
476
|
}
|
|
449
477
|
|
|
@@ -466,7 +494,8 @@ export class YunoSdk {
|
|
|
466
494
|
static onOneTimeToken(listener: (token: string) => void): {
|
|
467
495
|
remove: () => void;
|
|
468
496
|
} {
|
|
469
|
-
const
|
|
497
|
+
const emitter = getYunoEventEmitter();
|
|
498
|
+
const subscription = emitter.addListener('YunoOneTimeToken', listener);
|
|
470
499
|
return { remove: () => subscription.remove() };
|
|
471
500
|
}
|
|
472
501
|
|
|
@@ -490,7 +519,8 @@ export class YunoSdk {
|
|
|
490
519
|
static onOneTimeTokenInfo(listener: (tokenInfo: OneTimeTokenInfo) => void): {
|
|
491
520
|
remove: () => void;
|
|
492
521
|
} {
|
|
493
|
-
const
|
|
522
|
+
const emitter = getYunoEventEmitter();
|
|
523
|
+
const subscription = emitter.addListener('YunoOneTimeTokenInfo', listener);
|
|
494
524
|
return { remove: () => subscription.remove() };
|
|
495
525
|
}
|
|
496
526
|
|
|
@@ -515,4 +545,94 @@ export class YunoSdk {
|
|
|
515
545
|
}
|
|
516
546
|
return this.language;
|
|
517
547
|
}
|
|
548
|
+
|
|
549
|
+
// ==================== HEADLESS PAYMENT FLOW ====================
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Generate a one-time token (OTT) from collected payment data using the headless flow.
|
|
553
|
+
* This method allows you to tokenize payment information without using the UI components.
|
|
554
|
+
*
|
|
555
|
+
* @param tokenCollectedData The payment data to tokenize
|
|
556
|
+
* @param checkoutSession The checkout session ID
|
|
557
|
+
* @param countryCode The country code for the payment (optional, uses initialized value if not provided)
|
|
558
|
+
* @returns Promise resolving to the generated token or rejecting with an error
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```typescript
|
|
562
|
+
* import { YunoSdk, CardType } from '@yuno-payments/yuno-sdk-react-native';
|
|
563
|
+
*
|
|
564
|
+
* try {
|
|
565
|
+
* const result = await YunoSdk.generateToken({
|
|
566
|
+
* checkoutSession: '73ed16c5-4481-4dce-af42-404b68e21027',
|
|
567
|
+
* paymentMethod: {
|
|
568
|
+
* type: 'CARD',
|
|
569
|
+
* vaultedToken: null,
|
|
570
|
+
* card: {
|
|
571
|
+
* save: false,
|
|
572
|
+
* detail: {
|
|
573
|
+
* expirationMonth: 11,
|
|
574
|
+
* expirationYear: 25,
|
|
575
|
+
* number: '4000000000001091',
|
|
576
|
+
* securityCode: '123',
|
|
577
|
+
* holderName: 'John Doe',
|
|
578
|
+
* type: CardType.CREDIT,
|
|
579
|
+
* },
|
|
580
|
+
* },
|
|
581
|
+
* },
|
|
582
|
+
* }, 'checkoutSessionId', 'BR');
|
|
583
|
+
*
|
|
584
|
+
* console.log('Token:', result.token);
|
|
585
|
+
* } catch (error) {
|
|
586
|
+
* console.error('Token generation failed:', error);
|
|
587
|
+
* }
|
|
588
|
+
* ```
|
|
589
|
+
*/
|
|
590
|
+
static async generateToken(
|
|
591
|
+
tokenCollectedData: TokenCollectedData,
|
|
592
|
+
checkoutSession: string,
|
|
593
|
+
countryCode?: string
|
|
594
|
+
): Promise<HeadlessTokenResponse> {
|
|
595
|
+
const native = getYunoNative();
|
|
596
|
+
const country = countryCode || this.getCountryCode();
|
|
597
|
+
|
|
598
|
+
return native.generateToken(tokenCollectedData, checkoutSession, country);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Get the 3D Secure challenge URL for a checkout session using the headless flow.
|
|
603
|
+
* This is typically called after successfully generating a token to handle 3DS verification.
|
|
604
|
+
*
|
|
605
|
+
* @param checkoutSession The checkout session ID
|
|
606
|
+
* @param countryCode The country code for the payment (optional, uses initialized value if not provided)
|
|
607
|
+
* @returns Promise resolving to the 3DS challenge response
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* ```typescript
|
|
611
|
+
* import { YunoSdk } from '@yuno-payments/yuno-sdk-react-native';
|
|
612
|
+
*
|
|
613
|
+
* try {
|
|
614
|
+
* // First generate token
|
|
615
|
+
* const tokenResult = await YunoSdk.generateToken(paymentData, checkoutSession, 'BR');
|
|
616
|
+
*
|
|
617
|
+
* // Then get 3DS challenge URL if needed
|
|
618
|
+
* const challengeResult = await YunoSdk.getThreeDSecureChallenge(checkoutSession, 'BR');
|
|
619
|
+
*
|
|
620
|
+
* if (challengeResult.type === 'URL') {
|
|
621
|
+
* console.log('3DS URL:', challengeResult.data);
|
|
622
|
+
* // Open this URL in a WebView for the user to complete 3DS verification
|
|
623
|
+
* }
|
|
624
|
+
* } catch (error) {
|
|
625
|
+
* console.error('3DS challenge failed:', error);
|
|
626
|
+
* }
|
|
627
|
+
* ```
|
|
628
|
+
*/
|
|
629
|
+
static async getThreeDSecureChallenge(
|
|
630
|
+
checkoutSession: string,
|
|
631
|
+
countryCode?: string
|
|
632
|
+
): Promise<ThreeDSecureChallengeResponse> {
|
|
633
|
+
const native = getYunoNative();
|
|
634
|
+
const country = countryCode || this.getCountryCode();
|
|
635
|
+
|
|
636
|
+
return native.getThreeDSecureChallenge(checkoutSession, country);
|
|
637
|
+
}
|
|
518
638
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless Payment Flow Types
|
|
3
|
+
* These types mirror the native SDK's TokenCollectedData structure
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export enum CardType {
|
|
7
|
+
CREDIT = 'CREDIT',
|
|
8
|
+
DEBIT = 'DEBIT',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Detail {
|
|
12
|
+
expirationMonth?: number;
|
|
13
|
+
expirationYear?: number;
|
|
14
|
+
number?: string;
|
|
15
|
+
securityCode?: string;
|
|
16
|
+
holderName?: string;
|
|
17
|
+
type?: CardType;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface Installment {
|
|
21
|
+
id: string;
|
|
22
|
+
value: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface CardData {
|
|
26
|
+
save?: boolean;
|
|
27
|
+
detail?: Detail;
|
|
28
|
+
installment?: Installment;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface Document {
|
|
32
|
+
type: string;
|
|
33
|
+
number: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface Phone {
|
|
37
|
+
countryCode: string;
|
|
38
|
+
number: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Address {
|
|
42
|
+
street?: string;
|
|
43
|
+
number?: string;
|
|
44
|
+
complement?: string;
|
|
45
|
+
neighborhood?: string;
|
|
46
|
+
city?: string;
|
|
47
|
+
state?: string;
|
|
48
|
+
zipCode?: string;
|
|
49
|
+
country?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface Customer {
|
|
53
|
+
id: string;
|
|
54
|
+
merchantCustomerId: string;
|
|
55
|
+
firstName?: string;
|
|
56
|
+
lastName?: string;
|
|
57
|
+
dateOfBirth?: string;
|
|
58
|
+
email?: string;
|
|
59
|
+
country?: string;
|
|
60
|
+
createdAt?: string;
|
|
61
|
+
updatedAt?: string;
|
|
62
|
+
document?: Document;
|
|
63
|
+
phone?: Phone;
|
|
64
|
+
billingAddress?: Address;
|
|
65
|
+
shippingAddress?: Address;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PaymentMethod {
|
|
69
|
+
type: string;
|
|
70
|
+
vaultedToken?: string | null;
|
|
71
|
+
card?: CardData;
|
|
72
|
+
customer?: Customer;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface TokenCollectedData {
|
|
76
|
+
checkoutSession?: string;
|
|
77
|
+
customerSession?: string;
|
|
78
|
+
paymentMethod: PaymentMethod;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface ThreeDSecureChallengeResponse {
|
|
82
|
+
type: string;
|
|
83
|
+
data: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface HeadlessTokenResponse {
|
|
87
|
+
token?: string;
|
|
88
|
+
error?: string;
|
|
89
|
+
}
|
package/src/core/types/index.ts
CHANGED
|
@@ -5,3 +5,17 @@ export type { EnrollmentArguments } from './EnrollmentArguments';
|
|
|
5
5
|
export type { StartPayment, MethodSelected } from './StartPayment';
|
|
6
6
|
export type { SeamlessArguments } from './SeamlessArguments';
|
|
7
7
|
export type { OneTimeTokenInfo } from './OneTimeTokenInfo';
|
|
8
|
+
export type {
|
|
9
|
+
TokenCollectedData,
|
|
10
|
+
PaymentMethod,
|
|
11
|
+
CardData,
|
|
12
|
+
Detail,
|
|
13
|
+
Installment,
|
|
14
|
+
Customer,
|
|
15
|
+
Document,
|
|
16
|
+
Phone,
|
|
17
|
+
Address,
|
|
18
|
+
CardType,
|
|
19
|
+
ThreeDSecureChallengeResponse,
|
|
20
|
+
HeadlessTokenResponse,
|
|
21
|
+
} from './HeadlessTypes';
|