@dropp.cc/payment-sdk 1.0.23 โ 1.0.25
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 +137 -43
- package/dist/dropp-payment-sdk.esm.js +1 -1
- package/dist/dropp-payment-sdk.esm.js.map +1 -1
- package/dist/dropp-payment-sdk.js +1 -1
- package/dist/dropp-payment-sdk.js.map +1 -1
- package/dist/index.d.ts +1 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,44 @@ Install the SDK using npm:
|
|
|
19
19
|
npm install @dropp.cc/payment-sdk
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
For a full end-to-end merchant flow (architecture, backend callbacks, verification, and go-live checklist), see [Dropp Web Payment SDK Integration Guide](./INTEGRATION_GUIDE.md).
|
|
23
|
+
|
|
24
|
+
## Quick Start (2 minutes)
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { Dropp } from '@dropp.cc/payment-sdk';
|
|
28
|
+
|
|
29
|
+
await Dropp.init({
|
|
30
|
+
merchantId: 'YOUR_MERCHANT_ID',
|
|
31
|
+
apiKey: 'YOUR_API_KEY',
|
|
32
|
+
environment: 'qa'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const result = await Dropp.pay({
|
|
36
|
+
amount: 19.99,
|
|
37
|
+
currency: 'USD',
|
|
38
|
+
itemName: 'Test Product'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (result.status === 'success') {
|
|
42
|
+
// Verify on backend before fulfillment
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## SDK Methods
|
|
47
|
+
|
|
48
|
+
| Method | Description | Returns |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `Dropp.init(config)` | Initialize SDK and validate merchant credentials | `Promise<{ status, code, message, sdk }>` |
|
|
51
|
+
| `Dropp.pay(options)` | Start payment flow | `Promise<PaymentResult>` |
|
|
52
|
+
| `Dropp.dashboard(options?)` | Open hosted dashboard | `Promise<{ status, route }>` |
|
|
53
|
+
| `Dropp.open(moduleId, options?)` | Open supported hosted module | `Promise<{ status, route }>` |
|
|
54
|
+
| `Dropp.unlinkAccount(options?)` | Open unlink account page | `Promise<{ status, route }>` |
|
|
55
|
+
| `Dropp.transactions(options?)` | Open transactions page | `Promise<{ status, route }>` |
|
|
56
|
+
| `Dropp.offers(options?)` | Open offers page | `Promise<{ status, route }>` |
|
|
57
|
+
| `Dropp.status()` | Fetch account link status via hidden iframe | `Promise<{ type, data }>` |
|
|
58
|
+
| `Dropp.getInstance()` | Get current initialized SDK instance | `DroppPaymentSDK \| null` |
|
|
59
|
+
|
|
22
60
|
## Initialization
|
|
23
61
|
|
|
24
62
|
### `Dropp.init(config)`
|
|
@@ -30,8 +68,8 @@ Initializes the SDK with the required configuration.
|
|
|
30
68
|
- `config` (Object):
|
|
31
69
|
- `merchantId` (String) **Required**: Your Dropp merchant identifier, Will get from Dropp Merchant Portal after KYC.
|
|
32
70
|
- `apiKey` (String) **Required**: API key issued for your merchant, Will get from Dropp Merchant Portal after KYC.
|
|
33
|
-
- `
|
|
34
|
-
- `environment` (String) **
|
|
71
|
+
- `host domain` (Automatic): SDK auto-detects the current host domain (for example, `localhost` in local dev) and passes it for merchant validation.
|
|
72
|
+
- `environment` (String) **Optional**: The environment to use. Options: `'production'`, `'qa'`, `'sandbox'`. Defaults to `'qa'`.
|
|
35
73
|
- `getServerAuthToken` (Function) **Optional**: Async callback that returns a short-lived server-issued token.
|
|
36
74
|
- `requireServerAuthToken` (Boolean) **Optional**: Require server token for payment initialization. Defaults to `true` in production.
|
|
37
75
|
|
|
@@ -42,7 +80,6 @@ Initializes the SDK with the required configuration.
|
|
|
42
80
|
Dropp.init({
|
|
43
81
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
44
82
|
apiKey: 'YOUR_API_KEY',
|
|
45
|
-
packageName: 'com.example.webapp',
|
|
46
83
|
environment: 'production',
|
|
47
84
|
getServerAuthToken: async (context) => {
|
|
48
85
|
const response = await fetch('https://your-backend.com/dropp/auth-token', {
|
|
@@ -65,21 +102,21 @@ Initiates a payment process.
|
|
|
65
102
|
**Parameters:**
|
|
66
103
|
|
|
67
104
|
- `options` (Object):
|
|
68
|
-
- `merchantAccount` (String) **
|
|
105
|
+
- `merchantAccount` (String) **Not required**: Merchant account is derived from `Dropp.init({ merchantId })`.
|
|
69
106
|
- `amount` (Number) **Required**: The payment amount.
|
|
70
107
|
- `currency` (String) **Required**: The currency code (e.g., `'USD'`, `'HBAR'`, `'USDC'`). For `paymentType: 'preauth'`, only `'USD'` is allowed.
|
|
71
108
|
- `itemName` (String) **Required**: The name of the item or service.
|
|
72
|
-
- `paymentType` (String) **
|
|
109
|
+
- `paymentType` (String) **Optional**: The type of payment. Options: `'standard'`, `'preauth'`, `'recurring'`. Defaults to `'standard'`.
|
|
73
110
|
- `authHoldTimeInSeconds` (Number) **Required in Preauth Payments**: For preauth payments, the hold time in seconds.
|
|
74
|
-
- `callbackUrl` (String) **Required in Preauth & Recurring**:
|
|
75
|
-
- `
|
|
111
|
+
- `callbackUrl` (String) **Required in Preauth & Recurring**: Backend HTTPS callback endpoint used for signing. This must not be a frontend route.
|
|
112
|
+
- `frequency` (String) **Required in Recurring Payments**: One of `'NONE'`, `'HALF_HOURLY'`, `'HOURLY'`, `'DAILY'`, `'WEEKLY'`, `'MONTHLY'`, `'YEARLY'`.
|
|
113
|
+
- `recurringEndDate` (ISO datetime) **Required in Recurring Payments**: The date on which the recurring authorization will expire.
|
|
76
114
|
- `serverAuthToken` (String) **Optional**: A short-lived token issued by your backend for this payment.
|
|
77
115
|
|
|
78
116
|
### Example:
|
|
79
117
|
|
|
80
118
|
```javascript
|
|
81
119
|
Dropp.pay({
|
|
82
|
-
merchantAccount: '0.0.123456',
|
|
83
120
|
amount: 100.00,
|
|
84
121
|
currency: 'USD',
|
|
85
122
|
itemName: 'Premium Subscription',
|
|
@@ -125,9 +162,7 @@ Supported item IDs:
|
|
|
125
162
|
- `offers`
|
|
126
163
|
- `profile`
|
|
127
164
|
- `pinchange`
|
|
128
|
-
- `
|
|
129
|
-
- `accountsettings`
|
|
130
|
-
- `about`
|
|
165
|
+
- `aboutus`
|
|
131
166
|
|
|
132
167
|
The SDK passes this as a comma-separated query param in the webview URL for `#/firsttimeflow`.
|
|
133
168
|
|
|
@@ -152,9 +187,7 @@ Supported item IDs:
|
|
|
152
187
|
- `offers`
|
|
153
188
|
- `profile`
|
|
154
189
|
- `pinchange`
|
|
155
|
-
- `
|
|
156
|
-
- `accountsettings`
|
|
157
|
-
- `about`
|
|
190
|
+
- `aboutus`
|
|
158
191
|
|
|
159
192
|
This opens the module route directly as `#/${moduleId}`.
|
|
160
193
|
|
|
@@ -174,6 +207,11 @@ Loads the offers page.
|
|
|
174
207
|
|
|
175
208
|
- `options` (Object) Optional:
|
|
176
209
|
- `onClose` (Function) **Optional**: Callback invoked when the modal is closed.
|
|
210
|
+
- `onCancel` (Function) **Optional**: Callback invoked when the hosted page is cancelled.
|
|
211
|
+
- `onFailed` (Function) **Optional**: Callback invoked for hosted page failure.
|
|
212
|
+
- `onAccountChanged` (Function) **Optional**: Callback invoked for account changes.
|
|
213
|
+
- `onPageFailed` (Function) **Optional**: Callback invoked for page-level failure.
|
|
214
|
+
- `modules` (`string[]`) **Optional**: firsttimeflow sidebar modules.
|
|
177
215
|
|
|
178
216
|
### Hosted Page Example:
|
|
179
217
|
|
|
@@ -190,7 +228,7 @@ await Dropp.transactions();
|
|
|
190
228
|
await Dropp.offers();
|
|
191
229
|
|
|
192
230
|
await Dropp.dashboard({
|
|
193
|
-
modules: ['funding', 'profile', '
|
|
231
|
+
modules: ['funding', 'profile', 'aboutus']
|
|
194
232
|
});
|
|
195
233
|
|
|
196
234
|
await Dropp.open('linkbank');
|
|
@@ -203,7 +241,6 @@ await Dropp.open('profile');
|
|
|
203
241
|
const { sdk } = await Dropp.init({
|
|
204
242
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
205
243
|
apiKey: 'YOUR_API_KEY',
|
|
206
|
-
packageName: 'com.example.webapp',
|
|
207
244
|
environment: 'production'
|
|
208
245
|
});
|
|
209
246
|
|
|
@@ -249,7 +286,6 @@ console.log('Account status:', status);
|
|
|
249
286
|
const { sdk } = await Dropp.init({
|
|
250
287
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
251
288
|
apiKey: 'YOUR_API_KEY',
|
|
252
|
-
packageName: 'com.example.webapp',
|
|
253
289
|
environment: 'production'
|
|
254
290
|
});
|
|
255
291
|
|
|
@@ -257,6 +293,38 @@ const status = await sdk.status();
|
|
|
257
293
|
console.log(status);
|
|
258
294
|
```
|
|
259
295
|
|
|
296
|
+
## Payment Result Shapes
|
|
297
|
+
|
|
298
|
+
### Standard / Preauth / Recurring success
|
|
299
|
+
|
|
300
|
+
```javascript
|
|
301
|
+
{
|
|
302
|
+
status: 'success',
|
|
303
|
+
// plus payment app payload fields
|
|
304
|
+
sessionDuration: 1234
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Failed payment (business failure, not SDK exception)
|
|
309
|
+
|
|
310
|
+
```javascript
|
|
311
|
+
{
|
|
312
|
+
status: 'failed',
|
|
313
|
+
// plus failure payload fields
|
|
314
|
+
sessionDuration: 1234
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Cancelled payment
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
{
|
|
322
|
+
status: 'cancelled',
|
|
323
|
+
reason: 'user_cancelled' | 'app_close' | 'sdk_close' | 'user_closed',
|
|
324
|
+
sessionDuration: 1234
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
260
328
|
## Environments
|
|
261
329
|
|
|
262
330
|
The SDK supports the following environments:
|
|
@@ -269,26 +337,18 @@ Ensure you use the appropriate environment for your use case.
|
|
|
269
337
|
|
|
270
338
|
|
|
271
339
|
```javascript
|
|
272
|
-
import '@dropp/payment-sdk';
|
|
340
|
+
import { Dropp } from '@dropp.cc/payment-sdk';
|
|
273
341
|
|
|
274
342
|
Dropp.init({
|
|
275
343
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
276
344
|
apiKey: 'YOUR_API_KEY',
|
|
277
|
-
packageName: 'com.example.webapp',
|
|
278
345
|
environment: 'sandbox' // For testing payments (testnet)
|
|
279
346
|
});
|
|
280
347
|
|
|
281
|
-
Dropp.init({
|
|
282
|
-
merchantId: 'YOUR_MERCHANT_ID',
|
|
283
|
-
apiKey: 'YOUR_API_KEY',
|
|
284
|
-
packageName: 'com.example.webapp',
|
|
285
|
-
environment: 'qa' // For QA
|
|
286
|
-
});
|
|
287
348
|
|
|
288
349
|
Dropp.init({
|
|
289
350
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
290
351
|
apiKey: 'YOUR_API_KEY',
|
|
291
|
-
packageName: 'com.example.webapp',
|
|
292
352
|
environment: 'production' // For live payments (mainnet)
|
|
293
353
|
});
|
|
294
354
|
```
|
|
@@ -299,7 +359,6 @@ Dropp.init({
|
|
|
299
359
|
|
|
300
360
|
```javascript
|
|
301
361
|
Dropp.pay({
|
|
302
|
-
merchantAccount: '0.0.123456',
|
|
303
362
|
amount: 49.99,
|
|
304
363
|
currency: 'USD',
|
|
305
364
|
itemName: 'Premium Plan',
|
|
@@ -312,7 +371,6 @@ Dropp.pay({
|
|
|
312
371
|
|
|
313
372
|
```javascript
|
|
314
373
|
Dropp.pay({
|
|
315
|
-
merchantAccount: '0.0.123456',
|
|
316
374
|
amount: 100.00,
|
|
317
375
|
currency: 'USD',
|
|
318
376
|
itemName: 'Hotel Reservation',
|
|
@@ -328,14 +386,13 @@ Dropp.pay({
|
|
|
328
386
|
|
|
329
387
|
```javascript
|
|
330
388
|
Dropp.pay({
|
|
331
|
-
merchantAccount: '0.0.123456',
|
|
332
389
|
amount: 9.99,
|
|
333
390
|
currency: 'USD',
|
|
334
391
|
itemName: 'Monthly Subscription',
|
|
335
392
|
description: 'Recurring monthly payment',
|
|
336
393
|
paymentType: 'recurring',
|
|
337
394
|
frequency: 'monthly', // Frequency of the recurring payment
|
|
338
|
-
recurringEndDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(), //
|
|
395
|
+
recurringEndDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(), // Required: recurring authorization end date.
|
|
339
396
|
callbackUrl: 'https://your-server.com/recurring-callback'
|
|
340
397
|
});
|
|
341
398
|
```
|
|
@@ -343,7 +400,7 @@ Dropp.pay({
|
|
|
343
400
|
|
|
344
401
|
```jsx
|
|
345
402
|
import { useEffect, useState } from 'react';
|
|
346
|
-
import { Dropp } from '@dropp/payment-sdk';
|
|
403
|
+
import { Dropp } from '@dropp.cc/payment-sdk';
|
|
347
404
|
|
|
348
405
|
function CheckoutButton() {
|
|
349
406
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
@@ -352,7 +409,6 @@ function CheckoutButton() {
|
|
|
352
409
|
Dropp.init({
|
|
353
410
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
354
411
|
apiKey: 'YOUR_API_KEY',
|
|
355
|
-
packageName: 'com.example.webapp',
|
|
356
412
|
environment: 'production'
|
|
357
413
|
});
|
|
358
414
|
}, []);
|
|
@@ -362,7 +418,6 @@ function CheckoutButton() {
|
|
|
362
418
|
|
|
363
419
|
try {
|
|
364
420
|
const result = await Dropp.pay({
|
|
365
|
-
merchantAccount: '0.0.123456',
|
|
366
421
|
amount: 99.99,
|
|
367
422
|
currency: 'USD',
|
|
368
423
|
itemName: 'Product Purchase',
|
|
@@ -405,20 +460,18 @@ Use this when you are not using React/Vue/Angular.
|
|
|
405
460
|
<button id="payPreauth">Pay Preauth</button>
|
|
406
461
|
<button id="payRecurring">Pay Recurring</button>
|
|
407
462
|
|
|
408
|
-
<script src="https://unpkg.com/@dropp/payment-sdk/dist/dropp-payment-sdk.js"></script>
|
|
463
|
+
<script src="https://unpkg.com/@dropp.cc/payment-sdk/dist/dropp-payment-sdk.js"></script>
|
|
409
464
|
<script>
|
|
410
465
|
const { Dropp } = window.DroppPaymentSDK;
|
|
411
466
|
|
|
412
467
|
Dropp.init({
|
|
413
468
|
merchantId: 'YOUR_MERCHANT_ID',
|
|
414
469
|
apiKey: 'YOUR_API_KEY',
|
|
415
|
-
packageName: 'app.dropp.cc',
|
|
416
470
|
environment: 'production'
|
|
417
471
|
});
|
|
418
472
|
|
|
419
473
|
document.getElementById('payStandard').addEventListener('click', async () => {
|
|
420
474
|
await Dropp.pay({
|
|
421
|
-
merchantAccount: '0.0.123456',
|
|
422
475
|
amount: 49.99,
|
|
423
476
|
currency: 'USD',
|
|
424
477
|
itemName: 'One-time Purchase',
|
|
@@ -428,7 +481,6 @@ Use this when you are not using React/Vue/Angular.
|
|
|
428
481
|
|
|
429
482
|
document.getElementById('payPreauth').addEventListener('click', async () => {
|
|
430
483
|
await Dropp.pay({
|
|
431
|
-
merchantAccount: '0.0.123456',
|
|
432
484
|
amount: 100.00,
|
|
433
485
|
currency: 'USD',
|
|
434
486
|
itemName: 'Hotel Reservation',
|
|
@@ -440,7 +492,6 @@ Use this when you are not using React/Vue/Angular.
|
|
|
440
492
|
|
|
441
493
|
document.getElementById('payRecurring').addEventListener('click', async () => {
|
|
442
494
|
await Dropp.pay({
|
|
443
|
-
merchantAccount: '0.0.123456',
|
|
444
495
|
amount: 9.99,
|
|
445
496
|
currency: 'USD',
|
|
446
497
|
itemName: 'Monthly Subscription',
|
|
@@ -474,6 +525,37 @@ The SDK implements multiple security layers:
|
|
|
474
525
|
4. **Use invoice IDs** to track and deduplicate payments
|
|
475
526
|
5. **Implement proper error handling**
|
|
476
527
|
|
|
528
|
+
## Error Codes
|
|
529
|
+
|
|
530
|
+
The SDK may reject calls with these error codes:
|
|
531
|
+
|
|
532
|
+
| Code | Meaning | Typical action |
|
|
533
|
+
| --- | --- | --- |
|
|
534
|
+
| `INVALID_CONFIG` | Input or merchant validation failed | Check required fields, environment, credentials, callback URL |
|
|
535
|
+
| `ALREADY_OPEN` | Another SDK flow is active | Wait for active flow to finish, then retry |
|
|
536
|
+
| `INIT_TIMEOUT` | Payment app/status flow did not initialize in time | Check environment URL/connectivity, retry |
|
|
537
|
+
| `PAYMENT_TIMEOUT` | Payment did not complete within timeout | Ask user to retry and verify backend state |
|
|
538
|
+
| `UNKNOWN_ERROR` | Unexpected runtime/processing error | Log details, retry, contact support if persistent |
|
|
539
|
+
| `SDK_NOT_INITIALIZED` | `Dropp` global method used before `Dropp.init(...)` | Initialize first, then call `pay`/`dashboard`/`open`/`status` |
|
|
540
|
+
|
|
541
|
+
### Reserved error codes (defined, not currently emitted as SDK errors)
|
|
542
|
+
|
|
543
|
+
The following codes are defined for compatibility/extension, but current implementation does not reject with these codes:
|
|
544
|
+
|
|
545
|
+
- `ORIGIN_MISMATCH`
|
|
546
|
+
- `MESSAGE_VALIDATION_FAILED`
|
|
547
|
+
- `IFRAME_BLOCKED`
|
|
548
|
+
|
|
549
|
+
For these conditions, the SDK currently logs warnings/errors and ignores invalid messages.
|
|
550
|
+
|
|
551
|
+
### Additional plain `Error` throws
|
|
552
|
+
|
|
553
|
+
Some paths throw plain `Error` objects (not `createError(...)` output), for example:
|
|
554
|
+
|
|
555
|
+
- SDK used outside browser environment.
|
|
556
|
+
- Missing constructor credentials (`merchantId`, `apiKey`).
|
|
557
|
+
- Modal iframe creation failure.
|
|
558
|
+
|
|
477
559
|
## Browser Support
|
|
478
560
|
|
|
479
561
|
- Chrome 90+
|
|
@@ -487,7 +569,7 @@ The SDK implements multiple security layers:
|
|
|
487
569
|
|
|
488
570
|
- Check browser console for errors
|
|
489
571
|
- Verify all required fields are provided
|
|
490
|
-
- Ensure `
|
|
572
|
+
- Ensure `merchantId` passed to `Dropp.init(...)` is correct (`"0.0.123456"`)
|
|
491
573
|
|
|
492
574
|
### Messages not received
|
|
493
575
|
|
|
@@ -497,8 +579,14 @@ The SDK implements multiple security layers:
|
|
|
497
579
|
|
|
498
580
|
### TypeScript errors
|
|
499
581
|
|
|
500
|
-
- Ensure you have `@dropp/payment-sdk` installed
|
|
501
|
-
- If you use TypeScript types, import them from `@dropp/payment-sdk`
|
|
582
|
+
- Ensure you have `@dropp.cc/payment-sdk` installed
|
|
583
|
+
- If you use TypeScript types, import them from `@dropp.cc/payment-sdk`
|
|
584
|
+
|
|
585
|
+
### Session already in progress
|
|
586
|
+
|
|
587
|
+
- SDK allows only one active flow at a time (payment, hosted page, or status check).
|
|
588
|
+
- If another flow is active, calls may fail with `ALREADY_OPEN` / "A Dropp session is already in progress".
|
|
589
|
+
- Wait for the active flow to complete before launching a new one.
|
|
502
590
|
|
|
503
591
|
## Support
|
|
504
592
|
|
|
@@ -506,7 +594,7 @@ For issues or questions:
|
|
|
506
594
|
- Email: support@dropp.cc
|
|
507
595
|
|
|
508
596
|
|
|
509
|
-
|
|
597
|
+
License: UNLICENSED
|
|
510
598
|
|
|
511
599
|
## Changelog
|
|
512
600
|
|
|
@@ -534,4 +622,10 @@ MIT License - see LICENSE file for details
|
|
|
534
622
|
|
|
535
623
|
### v1.0.20 (2026-07-27)
|
|
536
624
|
- Added qa and sandbox api gateway support.
|
|
537
|
-
- Whitelabeling of the merchants.
|
|
625
|
+
- Whitelabeling of the merchants.
|
|
626
|
+
|
|
627
|
+
### v1.0.23 (2026-08-04)
|
|
628
|
+
- Added TypeScript declaration distribution in package dist.
|
|
629
|
+
|
|
630
|
+
### v1.0.24 (2026-08-07)
|
|
631
|
+
- Added stricter SDK-level session/concurrency guards.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e={READY:"DROPP_SDK_READY",PAYMENT_SUCCESS:"PAYMENT_SUCCESS",PAYMENT_FAILED:"PAYMENT_FAILED",PAYMENT_CANCELLED:"PAYMENT_CANCELLED",ACCOUNT_EVENT:"ACCOUNT_EVENT",PAGE_EVENT:"PAGE_EVENT",ACCOUNT_STATUS:"ACCOUNT_STATUS",CLOSE_WEBVIEW:"CLOSE_WEBVIEW",AUTO_CLOSE_WEBVIEW:"AUTO_CLOSE_WEBVIEW",PAYMENT_PAGE_LOADED:"PAYMENT_PAGE_LOADED",PAGE_LOADED:"PAGE_LOADED"},t="DROPP_SDK_INIT",n="DROPP_SDK_CLOSE",s={PRODUCTION:"production",QA:"qa",SANDBOX:"sandbox"},i={[s.PRODUCTION]:"https://wv.dropp.cc",[s.QA]:"https://wv.qa.dropp.cc",[s.SANDBOX]:"https://wv.sandbox.dropp.cc"},o={[s.PRODUCTION]:["https://wv.dropp.cc"],[s.QA]:["https://wv.qa.dropp.cc"],[s.SANDBOX]:["https://wv.sandbox.dropp.cc"]},r=3e4,a=6e5,l={STANDARD:"standard",PREAUTH:"preauth",RECURRING:"recurring"},c="INIT_TIMEOUT",u="PAYMENT_TIMEOUT",d="INVALID_CONFIG",h="ALREADY_OPEN",p="UNKNOWN_ERROR",m="1.0.2";const g=new class{constructor(e,t={}){this.environment=e,this.forceEnabled=!!t.enabled,this.enabled=this._shouldEnableLogging()}_shouldEnableLogging(){return this.forceEnabled}setEnvironment(e,t={}){this.environment=e,"boolean"==typeof t.enabled&&(this.forceEnabled=t.enabled),this.enabled=this._shouldEnableLogging()}setEnabled(e){this.forceEnabled=!!e,this.enabled=this._shouldEnableLogging()}log(...e){this.enabled&&console.log(...e)}warn(...e){this.enabled&&console.warn(...e)}error(...e){this.enabled&&console.error(...e)}debug(...e){this.enabled&&console.debug(...e)}info(...e){this.enabled&&console.info(...e)}}("qa",{enabled:!1}),f=["USD","HBAR","USDC"],y=["NONE","HALF_HOURLY","HOURLY","DAILY","WEEKLY","MONTHLY","YEARLY"],D=[l.STANDARD,l.PREAUTH,l.RECURRING];function S(e,t={}){const{isProduction:n=!1,allowLocalCallbacksInNonProd:s=!1}=t;if("string"!=typeof e||!e.trim())return!1;try{const t=new URL(e.trim()),i="https:"===t.protocol;if(!("http:"===t.protocol)&&!i)return!1;return function(e){if(!e)return!1;const t=e.trim().toLowerCase();if("localhost"===t||"127.0.0.1"===t||"::1"===t||t.endsWith(".local"))return!0;if(!/^(\d{1,3}\.){3}\d{1,3}$/.test(t))return!1;const n=t.split(".").map(e=>Number(e));if(n.some(e=>Number.isNaN(e)||e<0||e>255))return!1;const[s,i]=n;return 10===s||127===s||172===s&&i>=16&&i<=31||192===s&&168===i||169===s&&254===i}(t.hostname)?!n&&s:!n||i}catch{return!1}}function w(e={},t={}){const n=[],s=e.paymentType||l.STANDARD,i="production"===(t.environment||"").toLowerCase(),o=!!t.allowLocalCallbacksInNonProd,r="string"==typeof e.currency?e.currency.trim().toUpperCase():"";if(D.includes(s)||n.push(`paymentType must be one of: ${D.join(", ")}`),void 0===e.amount||null===e.amount||""===e.amount?n.push("amount is required"):function(e){const t="number"==typeof e?e:parseFloat(e);return"number"==typeof t&&!Number.isNaN(t)&&t>0}(e.amount)||n.push("amount must be a positive number"),e.currency&&"string"==typeof e.currency&&e.currency.trim()?f.includes(r)||n.push(`currency must be one of: ${f.join(", ")}`):n.push("currency is required"),e.itemName&&"string"==typeof e.itemName&&e.itemName.trim()||n.push("itemName is required"),s===l.PREAUTH&&(r&&"USD"!==r&&n.push("currency must be USD for preauth payments"),e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:i,allowLocalCallbacksInNonProd:o})||n.push(i?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for preauth payments"),void 0===e.authHoldTimeInSeconds||null===e.authHoldTimeInSeconds||""===e.authHoldTimeInSeconds?n.push("authHoldTimeInSeconds is required for preauth payments"):function(e){const t="number"==typeof e?e:parseInt(e,10);return Number.isInteger(t)&&t>0}(e.authHoldTimeInSeconds)||n.push("authHoldTimeInSeconds must be a positive integer (seconds)")),s===l.RECURRING){e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:i,allowLocalCallbacksInNonProd:o})||n.push(i?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for recurring payments");const t=(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase();t?y.includes(t)||n.push(`frequency must be one of: ${y.join(", ")}`):n.push("frequency is required for recurring payments"),e.recurringEndDate&&String(e.recurringEndDate).trim()?!function(e){if("string"!=typeof e||!e.trim())return!1;const t=new Date(e.trim());return!Number.isNaN(t.getTime())}(e.recurringEndDate)?n.push("recurringEndDate must be a valid ISO date-time string"):new Date(e.recurringEndDate.trim())<=new Date&&n.push("recurringEndDate must be in the future"):n.push("recurringEndDate (expiry) is required for recurring payments")}return{valid:0===n.length,errors:n}}function b(e,t,n={}){return{code:e,message:t,details:n,timestamp:(new Date).toISOString(),toString(){return this.message||"Dropp SDK error"}}}class T{constructor(e,t,n=null){this.environment=e,this.onMessage=t,this.sessionId=`dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2,15)}`,g.log("[MessageHandler] Session initialized"),this.iframe=null,this.allowedOrigins=n?.length>0?n:o[e]||[],this.messageListener=null,this.pendingMessages=new Map}init(e){this.iframe=e,this.messageListener=this._handleMessage.bind(this),window.addEventListener("message",this.messageListener)}destroy(){this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.iframe=null,this.pendingMessages.clear()}_handleMessage(e){if(g.log("[MessageHandler] Received postMessage event"),e.source===window)return void g.log("[MessageHandler] Ignoring message from self");if(!this._validateOrigin(e.origin))return void g.warn("[Dropp SDK] Rejected message from untrusted origin:",e.origin);if(!this.iframe||e.source!==this.iframe.contentWindow)return void g.warn("[Dropp SDK] Rejected message from unexpected source",{eventOrigin:e.origin});const t=e.data;this._validateMessageStructure(t)?t.sessionId&&t.sessionId!==this.sessionId?g.warn("[Dropp SDK] Rejected message with invalid session ID"):(g.log("[MessageHandler] Message passed validation"),this._processMessage(t)):g.warn("[Dropp SDK] Rejected message with invalid structure")}_validateOrigin(e){return!(!e.startsWith("http://localhost:")&&!e.startsWith("http://127.0.0.1:"))||this.allowedOrigins.includes(e)}_validateMessageStructure(t){if(!t||"object"!=typeof t)return!1;if(!t.type||"string"!=typeof t.type)return!1;return!!Object.values(e).includes(t.type)&&!(t.type!==e.ACCOUNT_STATUS&&!t.timestamp)}_processMessage(e){g.log("[Dropp SDK] Received message:",e.type),this.onMessage&&this.onMessage(e)}sendToPaymentApp(e,t={}){if(!this.iframe||!this.iframe.contentWindow)return g.error("[Dropp SDK] Cannot send message: iframe not ready"),!1;const n={type:e,data:t,sessionId:this.sessionId,timestamp:(new Date).toISOString(),sdkVersion:"1.0.0"},s=this.allowedOrigins[0]||"*";try{return this.iframe.contentWindow.postMessage(n,s),g.log("[Dropp SDK] Sent message:",e),!0}catch(e){return g.error("[Dropp SDK] Error sending message:",e),!1}}sendInit(e){return this.sendToPaymentApp(t,{mode:"sdk",config:e})}sendClose(){return this.sendToPaymentApp(n,{})}getSessionId(){return this.sessionId}}class v{constructor(e){this.onClose=e,this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,this.isOpen=!1,this.escapeListener=null}open(){return this.isOpen?(g.warn("[Dropp SDK] Modal is already open"),null):(this._createModal(),this._attachEventListeners(),this._show(),this.isOpen=!0,this.iframe)}close(){g.log("[ModalManager] ๐ฆ close() called, isOpen:",this.isOpen),this.isOpen?(g.log("[ModalManager] ๐ฆ Hiding modal..."),this._hide(),g.log("[ModalManager] ๐ฆ Removing event listeners..."),this._removeEventListeners(),g.log("[ModalManager] ๐ฆ Destroying modal..."),this._destroyModal(),this.isOpen=!1,g.log("[ModalManager] โ
Modal close sequence initiated")):g.log("[ModalManager] โ ๏ธ Modal is not open, skipping close")}_createModal(){this.overlay=document.createElement("div"),this.overlay.id="dropp-payment-overlay",this._applyOverlayStyles(this.overlay),this.container=document.createElement("div"),this.container.id="dropp-payment-container",this._applyContainerStyles(this.container),this.iframe=document.createElement("iframe"),this.iframe.id="dropp-payment-iframe",this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),this.iframe.setAttribute("referrerpolicy","no-referrer"),this.iframe.setAttribute("title","Dropp Payment"),this._applyIframeStyles(this.iframe),this.container.appendChild(this.iframe),this.overlay.appendChild(this.container),document.body.appendChild(this.overlay)}_applyOverlayStyles(e){Object.assign(e.style,{position:"fixed",inset:"0",width:"100vw",height:"100vh",margin:"0",padding:"20px",boxSizing:"border-box",backgroundColor:"rgba(0, 0, 0, 0.6)",zIndex:999999..toString(),display:"flex",alignItems:"center",justifyContent:"center",opacity:"0",transition:"opacity 0.3s ease",backdropFilter:"blur(4px)",overflow:"auto"})}_applyContainerStyles(e){const t=window.innerWidth<768;this._isMobile=t,Object.assign(e.style,{position:"relative",flex:"0 0 auto",alignSelf:"center",margin:"auto",width:"100%",maxWidth:t?"100%":"400px",height:t?"100%":"auto",minHeight:t?"100%":"800px",maxHeight:t?"100%":"min(1000px, calc(100vh - 40px))",backgroundColor:"#ffffff",borderRadius:t?"0":"16px",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.3)",overflow:"hidden",transform:"scale(0.95)",transition:"transform 0.3s ease, opacity 0.3s ease",display:"flex",flexDirection:"column"})}_getContainerTransform(e){return`scale(${e})`}_applyCloseButtonStyles(e){Object.assign(e.style,{position:"absolute",top:"16px",right:"16px",zIndex:"10",width:"40px",height:"40px",border:"none",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.9)",color:"#333",fontSize:"28px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",transition:"all 0.2s ease",fontFamily:"Arial, sans-serif",padding:"0"}),e.addEventListener("mouseenter",()=>{Object.assign(e.style,{backgroundColor:"#f5f5f5",transform:"scale(1.1)"})}),e.addEventListener("mouseleave",()=>{Object.assign(e.style,{backgroundColor:"rgba(255, 255, 255, 0.9)",transform:"scale(1)"})})}_applyIframeStyles(e){const t=this._isMobile;Object.assign(e.style,{width:"100%",flex:"1 1 auto",minHeight:t?"100%":"min(520px, calc(90vh - 40px))",height:t?"100%":"min(520px, calc(90vh - 40px))",border:"none",display:"block"})}_show(){document.body.style.overflow="hidden",requestAnimationFrame(()=>{this.overlay&&(this.overlay.style.opacity="1"),this.container&&(this.container.style.transform=this._getContainerTransform(1))})}_hide(){g.log("[ModalManager] ๐ญ _hide() called"),this.overlay&&(this.overlay.style.opacity="0",g.log("[ModalManager] ๐ญ Overlay opacity set to 0")),this.container&&(this.container.style.transform=this._getContainerTransform(.95),g.log("[ModalManager] ๐ญ Container transform set to scale(0.95)")),document.body.style.overflow="",g.log("[ModalManager] ๐ญ Body scroll restored")}_destroyModal(){g.log("[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation"),setTimeout(()=>{g.log("[ModalManager] ๐๏ธ Animation complete, removing from DOM"),this.overlay&&this.overlay.parentNode&&(this.overlay.parentNode.removeChild(this.overlay),g.log("[ModalManager] ๐๏ธ Overlay removed from DOM")),this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,g.log("[ModalManager] โ
Modal destroyed")},300)}_attachEventListeners(){}_removeEventListeners(){this.escapeListener&&(document.removeEventListener("keydown",this.escapeListener),this.escapeListener=null)}_handleCloseClick(e){e.stopPropagation(),this.onClose&&this.onClose("user_closed")}_handleOverlayClick(e){e.target===this.overlay&&this.onClose&&this.onClose("user_closed")}_handleEscapeKey(e){"Escape"===e.key&&this.isOpen&&this.onClose&&this.onClose("user_closed")}getIframe(){return this.iframe}getIsOpen(){return this.isOpen}}const E=["fundnow","linkbank","linkcard","redeemnow","fundcrypto","transferusdc","usdchistory","redeemcrypto","manageaccounts","transactions","merchantlist","favorites","offers","profile","pinchange","unlinkaccount","accountsettings","aboutus"];class _{constructor(e={}){if("undefined"==typeof window||"undefined"==typeof document)throw new Error("Dropp Payment SDK can only be used in a browser environment");if(!e.merchantId||!e.apiKey||!e.packageName)throw new Error("merchantId, apiKey, and packageName are required to initialize SDK");if(this.merchantId=e.merchantId,this.apiKey=e.apiKey,this.packageName=e.packageName,this.environment=e.environment||s.QA,this.baseUrl=e.paymentAppUrl||e.baseUrl||i[this.environment],this.isInitialized=!1,this.initializationPromise=null,this.getServerAuthToken="function"==typeof e.getServerAuthToken?e.getServerAuthToken:null,this.requireServerAuthToken="boolean"==typeof e.requireServerAuthToken?e.requireServerAuthToken:this.environment===s.PRODUCTION,this.allowLocalCallbacksInNonProd=!!e.allowLocalCallbacksInNonProd,e.allowedOrigins?.length)this.allowedOrigins=e.allowedOrigins;else try{this.allowedOrigins=[new URL(this.baseUrl).origin]}catch{this.allowedOrigins=o[this.environment]||[]}this.isOpen=!1,this.currentSession=null,this.currentFlowType=null,this.statusSession=null,this.hiddenIframe=null,this.statusTimeout=null,this.initTimeout=null,this.paymentTimeout=null,this.hostAppDomain=null,this.onAccountChanged=null,this.onPageFailed=null,this.messageHandler=null,this.modalManager=null,g.setEnvironment(this.environment,{enabled:!!e.debugLogging}),g.log(`[Dropp SDK] Initialized v${m} - Environment: ${this.environment}`)}pay(e={}){return new Promise((t,n)=>{if(this.isOpen){const e=b(h,"A payment session is already in progress",{currentSession:this.currentSession});return void n(e)}(async()=>{try{await this.initialize();const s=w(e,{environment:this.environment,allowLocalCallbacksInNonProd:this.allowLocalCallbacksInNonProd});if(!s.valid){const e=b(d,"Invalid payment configuration",{errors:s.errors});return void n(e)}this.onSuccess=e.onSuccess||null,this.onFailure=e.onFailure||null,this.onCancel=e.onCancel||null,this.onClose=e.onClose||null,this.currentSession={resolve:t,reject:n,options:e,startTime:Date.now()},await this._initializePayment(e)}catch(e){const t=e&&e.code===d?e:b(p,"Failed to initialize payment",{originalError:e?.message||String(e)});n(t),this._cleanup()}})()})}async initialize(){return this.initializationPromise||(this.initializationPromise=(async()=>{if(this.hostAppDomain=this._detectHostAppDomain(),!this.hostAppDomain)throw b(d,"Unable to detect host app domain for SDK validation");return await this._validateInitializationCredentials(),this.isInitialized=!0,{status:"success",code:"INITIALIZED",message:"Dropp SDK initialized successfully"}})().catch(e=>{throw this.isInitialized=!1,this.initializationPromise=null,e})),this.initializationPromise}_getValidationUrl(){const e={[s.QA]:"https://bc0qfqi8c9.execute-api.us-east-1.amazonaws.com/QA-test-app-sdk-gateway-stage/sdk/payer/webview/validateSdk",[s.SANDBOX]:"https://76xbxsi4kf.execute-api.us-east-1.amazonaws.com/sandbox/sdk/payer/webview/validateSdk",[s.PRODUCTION]:"https://api.dropp.cc/payer/webview/validateSdk"};return e[this.environment]||e[s.QA]}_detectHostAppDomain(){if("undefined"!=typeof window&&window.location)return window.location.hostname||void 0}_getHostedPageAuthToken(){const e="string"==typeof this.apiKey?this.apiKey.trim():"",t="string"==typeof this.merchantId?this.merchantId.trim():"";if(!e)return"";try{const n=JSON.stringify({apikey:e,merchantAccount:t});return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}catch{return""}}async _validateInitializationCredentials(){const e=this._getValidationUrl(),t=this.hostAppDomain,n={accept:"application/json, text/plain, */*","content-type":"application/json","x-api-key":this.apiKey,"x-app-package":this.packageName,"dropp-user-agent":"WEB"};if(!t)throw b(d,"Unable to resolve host app domain for SDK validation");let s;n["dropp-merchant-domain"]=t;let i=null;try{s=await fetch(e,{method:"POST",headers:n,body:JSON.stringify({id:this.merchantId})})}catch(t){throw b(d,"Unable to validate merchant credentials",{endpoint:e,originalError:t?.message||String(t)})}try{i=await s.json()}catch{i=null}if(!s.ok)throw b(d,"Merchant validation failed for merchantId/apiKey/packageName",{endpoint:e,status:s.status,response:i});const o=Number(i?.responseCode),r=i?.errors,a=!Array.isArray(r)||0===r.length;if(!(i&&0===o&&a))throw b(d,"Merchant validation returned an unsuccessful response",{endpoint:e,status:s.status,response:i});g.log("[Dropp SDK] Merchant credentials validated successfully")}closePayment(){if(this.isOpen){if("page"===this.currentFlowType)return void this._cleanup();this._handleCancel("sdk_close")}}dashboard(e={}){return this._openHostedPage("/firsttimeflow",e)}open(e,t={}){const n="string"==typeof e?e.trim():"";if(!n)throw b(d,"moduleId is required for Dropp.open(moduleId)",{moduleId:e});if(!E.includes(n))throw b(d,"Unsupported moduleId passed to Dropp.open(moduleId)",{moduleId:n,supportedModuleIds:[...E]});const s="about"===n?"/aboutus":`/${n}`;return this._openHostedPage(s,t)}unlinkAccount(e={}){return this._openHostedPage("/unlink",e)}transactions(e={}){return this._openHostedPage("/transactions",e)}offers(e={}){return this._openHostedPage("/offers",e)}status(){return new Promise((e,t)=>{this.isOpen||"status"===this.currentFlowType?t(b(h,"A Dropp session is already in progress",{currentSession:this.currentSession,currentFlowType:this.currentFlowType})):(async()=>{try{await this.initialize(),this.currentFlowType="status",this.currentSession=null,this.onSuccess=null,this.onFailure=null,this.onCancel=null,this.onClose=null,this.messageHandler=new T(this.environment,this._handleMessage.bind(this),this.allowedOrigins);const n=document.createElement("iframe");n.id="dropp-status-iframe",n.setAttribute("allow","payment"),n.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),n.setAttribute("referrerpolicy","no-referrer"),n.setAttribute("title","Dropp Account Status"),Object.assign(n.style,{position:"absolute",width:"1px",height:"1px",border:"0",opacity:"0",pointerEvents:"none",visibility:"hidden"}),document.body.appendChild(n),this.hiddenIframe=n,this.messageHandler.init(n);const s=new URLSearchParams({sdkMode:"true",sessionId:this.messageHandler.getSessionId(),sdkVersion:m,platform:"web",merchantDomain:this.hostAppDomain}),i=this._getHostedPageAuthToken();i&&s.set("auth",i);const o=this.baseUrl.replace(/\/+$/,"");n.src=`${o}/#/status?${s.toString()}`,this.statusSession={resolve:e,reject:t,startTime:Date.now()},this.statusTimeout=setTimeout(()=>{const e=b(c,"Account status request timed out",{type:"status",sessionDuration:this.statusSession?Date.now()-this.statusSession.startTime:0});this.statusSession&&this.statusSession.reject(e),this._cleanup()},r)}catch(e){t(b(p,"Failed to get account status",{originalError:e?.message||String(e)})),this._cleanup()}})()})}async _initializePayment(e){g.log("[Dropp SDK] Initializing payment session"),this.currentFlowType="payment",this.messageHandler=new T(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new v(this._handleModalClose.bind(this));const t=this.modalManager.open();if(!t)throw new Error("Failed to create modal iframe");this.messageHandler.init(t);const n=e.paymentType||l.STANDARD;let s="/payViaUrl";n===l.PREAUTH?s="/preAuthPayment":n===l.RECURRING&&(s="/recurringPayment");const i=n===l.RECURRING?(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase():"",o=n===l.RECURRING&&"NONE"===i,c=e.appUrl||("undefined"!=typeof window&&window.location?window.location.href:void 0),u={merchantAccount:this.merchantId,amount:n===l.PREAUTH?void 0:e.amount,maxAmount:n===l.PREAUTH||o?e.amount:void 0,fixAmount:n!==l.RECURRING||o?void 0:e.amount,acceptPaymentDelay:n===l.STANDARD&&!0===e.acceptPaymentDelay||void 0,currency:e.currency,itemName:e.itemName,description:e.description,invoiceId:e.invoiceId||`INV-${Date.now()}`,invoiceType:n===l.PREAUTH?"PREAUTH":void 0,apiKey:this.apiKey,packageName:this.packageName,merchantDomain:this.hostAppDomain,sdkVersion:m,platform:"web",appUrl:c,sessionId:this.messageHandler.getSessionId()};if(g.log("[Dropp SDK] Including SDK session context in payment params"),e.successURL&&(u.successURL=e.successURL),e.failureURL&&(u.failureURL=e.failureURL),n===l.RECURRING){const t=e.frequency||e.recurringInterval;t&&(u.frequency=t),e.recurringEndDate&&(u.expiry=e.recurringEndDate)}n===l.PREAUTH&&e.authHoldTimeInSeconds&&(u.authHoldTimeInSeconds=e.authHoldTimeInSeconds),e.callbackUrl&&(u.url=e.callbackUrl,u.submitToCallBack="post");const h={sessionId:u.sessionId,merchantAccount:this.merchantId,amount:e.amount,paymentType:n,invoiceId:u.invoiceId,expiry:e.recurringEndDate||null,issuedAt:Date.now()};let p="string"==typeof e.serverAuthToken?e.serverAuthToken.trim():"";if(!p&&this.getServerAuthToken)try{const e=await this.getServerAuthToken(h);p="string"==typeof e?e.trim():""}catch(e){throw b(d,"Failed to obtain server auth token",{originalError:e?.message||String(e)})}if(this.requireServerAuthToken&&!p)throw b(d,"serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.",{environment:this.environment,paymentType:n,invoiceId:u.invoiceId});const f=await async function(e,t,n,s,i={}){try{const{serverAuthToken:o=""}=i,r={};Object.keys(n).forEach(e=>{const t=n[e];null!=t&&(r[e]=t)}),g.log("[buildPaymentUrl] Building payment URL payload");const a=JSON.stringify(r),l=btoa(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),c=Date.now().toString(),u=new URLSearchParams({pay:l,sdkTs:c,sdkVersion:s,platform:"web"});return o&&u.set("authToken",o),`${e}/#${t}?${u.toString()}`}catch(e){throw g.error("Error building payment URL:",e),e}}(this.baseUrl,s,u,m,{serverAuthToken:p});g.log("[Dropp SDK] Loading payment flow iframe"),t.src=f,this.isOpen=!0,this.initTimeout=setTimeout(()=>{this._handleTimeout("init")},r),this.paymentTimeout=setTimeout(()=>{this._handleTimeout("payment")},a)}async _openHostedPage(e,t={}){if(this.isOpen){if("page"!==this.currentFlowType)throw b(h,"A Dropp session is already in progress",{currentSession:this.currentSession,route:e});this._cleanup()}await this.initialize(),this.currentFlowType="page",this.currentSession=null,this.onSuccess=null,this.onFailure="function"==typeof t.onFailed?t.onFailed:null,this.onCancel="function"==typeof t.onCancel?t.onCancel:null,this.onClose="function"==typeof t.onClose?t.onClose:null,this.onAccountChanged="function"==typeof t.onAccountChanged?t.onAccountChanged:null,this.onPageFailed="function"==typeof t.onPageFailed?t.onPageFailed:this.onFailure,this.messageHandler=new T(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new v(this._handleModalClose.bind(this));const n=this.modalManager.open();if(!n)throw new Error("Failed to create modal iframe");this.messageHandler.init(n);const s=new URLSearchParams({sdkMode:"true",sessionId:this.messageHandler.getSessionId(),sdkVersion:m,platform:"web",merchantDomain:this.hostAppDomain}),i=this._getHostedPageAuthToken();if(i&&s.set("auth",i),"/firsttimeflow"===e&&Array.isArray(t.modules)){const e=t.modules.map(e=>"string"==typeof e?e.trim():"").filter(Boolean);e.length>0&&s.set("modules",e.join(","))}const o=this.baseUrl.replace(/\/+$/,"");return n.src=`${o}/#${e}?${s.toString()}`,this.isOpen=!0,g.log("[Dropp SDK] Hosted page opened",{route:e}),{status:"opened",route:e}}_handleMessage(t){const{type:n,data:s}=t;switch(n){case e.READY:this._handleReady(s);break;case e.PAGE_LOADED:case e.PAYMENT_PAGE_LOADED:this._handlePageLoaded(s);break;case e.PAYMENT_SUCCESS:this._handleSuccess(s);break;case e.PAYMENT_FAILED:this._handleFailure(s);break;case e.PAYMENT_CANCELLED:this._handleCancel("user_cancelled");break;case e.ACCOUNT_STATUS:this._handleAccountStatus(s);break;case e.ACCOUNT_EVENT:this._handleAccountEvent(s);break;case e.PAGE_EVENT:this._handlePageEvent(s);break;case e.AUTO_CLOSE_WEBVIEW:g.log("[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal"),this._cleanup(),g.log("[Dropp SDK] Cleanup completed");break;case e.CLOSE_WEBVIEW:if(g.log("[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal"),"status"===this.currentFlowType&&this.statusSession){const e=b(p,"Account status request was closed before response was received",{type:"status",sessionDuration:Date.now()-this.statusSession.startTime});this.statusSession.reject(e),this._cleanup();break}this._handleCancel("app_close");break;default:g.warn("[Dropp SDK] Unknown message type:",n)}}_handleReady(e){if(g.log("[Dropp SDK] Payment app ready"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.messageHandler&&this.currentSession){const e={};Object.keys(this.currentSession.options).forEach(t=>{const n=this.currentSession.options[t];"function"!=typeof n&&(e[t]=n)}),g.log("[Dropp SDK] Sending init config to payment app"),this.messageHandler.sendInit(e)}}_handlePageLoaded(e){g.log("[Dropp SDK] Payment page loaded")}_getBridgeAction(e={}){return e&&"object"==typeof e?"string"==typeof e.action?e.action:e.result&&"object"==typeof e.result&&"string"==typeof e.result.action?e.result.action:"":""}_getSafeFailureMessage(e={},t="Request failed"){return e&&"string"==typeof e.message&&e.message.trim()?e.message.trim():e&&e.result&&"object"==typeof e.result&&"string"==typeof e.result.message&&e.result.message.trim()?e.result.message.trim():t}_getSafeResult(e={}){return e&&e.result&&"object"==typeof e.result?e.result:{}}_handleAccountEvent(e){const t=this._getBridgeAction(e),n=this._getSafeResult(e);if("onAccountChanged"!==t)if("onCancel"!==t){if("onFailed"===t){const t=this._getSafeFailureMessage(e,"Account request failed");return void(this.onFailure&&this.onFailure(t))}g.warn("[Dropp SDK] Unknown ACCOUNT_EVENT action:",t)}else this.onCancel&&this.onCancel();else this.onAccountChanged&&this.onAccountChanged({linked:!0===n.linked,rawData:n.rawData})}_handlePageEvent(e){const t=this._getBridgeAction(e);if("onFailed"===t){const t=this._getSafeFailureMessage(e,"Page request failed");return void(this.onPageFailed&&this.onPageFailed(t))}g.warn("[Dropp SDK] Unknown PAGE_EVENT action:",t)}_handleAccountStatus(t){g.log("[Dropp SDK] Account status received"),this.statusSession?(this.statusSession.resolve({type:e.ACCOUNT_STATUS,data:t}),this._cleanup()):g.warn("[Dropp SDK] ACCOUNT_STATUS received without active status session")}_handleSuccess(e){g.log("[Dropp SDK] Payment successful");const t={status:"success",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onSuccess&&this.onSuccess(t)}_handleFailure(e){g.log("[Dropp SDK] Payment failed");const t={status:"failed",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onFailure&&this.onFailure(t)}_handleCancel(e){if(g.log("[Dropp SDK] Payment cancelled"),"page"===this.currentFlowType)return this.onCancel&&this.onCancel(),void this._cleanup();const t={status:"cancelled",reason:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0};this.currentSession&&this.currentSession.resolve(t),this.onCancel&&this.onCancel(t),this._cleanup()}_handleModalClose(e){g.log("[Dropp SDK] Modal closed by user"),"page"!==this.currentFlowType?this._handleCancel(e):this._cleanup()}_handleTimeout(e){g.error("[Dropp SDK] Timeout:",e);const t=b("init"===e?c:u,"init"===e?"Payment app failed to load within timeout period":"Payment session timed out",{type:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0});this.currentSession&&this.currentSession.reject(t),this.onFailure&&this.onFailure({status:"failed",error:t}),this._cleanup()}_cleanup(){g.log("[Dropp SDK] ๐งน Cleaning up session - starting cleanup"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.paymentTimeout&&(clearTimeout(this.paymentTimeout),this.paymentTimeout=null),this.statusTimeout&&(clearTimeout(this.statusTimeout),this.statusTimeout=null),this.messageHandler&&(g.log("[Dropp SDK] ๐งน Destroying message handler"),this.messageHandler.destroy(),this.messageHandler=null),this.modalManager&&(g.log("[Dropp SDK] ๐งน Closing modal manager"),this.modalManager.close(),g.log("[Dropp SDK] ๐งน Modal manager closed"),this.modalManager=null),this.hiddenIframe&&this.hiddenIframe.parentNode&&this.hiddenIframe.parentNode.removeChild(this.hiddenIframe),this.hiddenIframe=null,this.currentSession=null,this.statusSession=null,this.currentFlowType=null,this.isOpen=!1,this.onClose&&this.onClose()}static getVersion(){return m}static getEnvironments(){return{...s}}static getPaymentTypes(){return{...l}}}let A=null;async function I(e){A=new _(e);return{...await A.initialize(),sdk:A}}function C(){return A}const N={init:e=>I(e),pay(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.pay(e)},dashboard(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.dashboard(e)},open(e,t){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.open(moduleId, options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.open(e,t)},unlinkAccount(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.unlinkAccount(e)},transactions(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.transactions(e)},offers(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.offers(e)},status(){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.status().");throw e.code="SDK_NOT_INITIALIZED",e}return A.status()},getInstance:()=>A};var O={DroppPaymentSDK:_,createPaymentSDK:I,Dropp:N,ENVIRONMENTS:s,PAYMENT_TYPES:l};export{N as Dropp,_ as DroppPaymentSDK,s as ENVIRONMENTS,l as PAYMENT_TYPES,I as createPaymentSDK,O as default,C as getDroppInstance};
|
|
1
|
+
const e={READY:"DROPP_SDK_READY",PAYMENT_SUCCESS:"PAYMENT_SUCCESS",PAYMENT_FAILED:"PAYMENT_FAILED",PAYMENT_CANCELLED:"PAYMENT_CANCELLED",ACCOUNT_EVENT:"ACCOUNT_EVENT",PAGE_EVENT:"PAGE_EVENT",ACCOUNT_STATUS:"ACCOUNT_STATUS",CLOSE_WEBVIEW:"CLOSE_WEBVIEW",AUTO_CLOSE_WEBVIEW:"AUTO_CLOSE_WEBVIEW",PAYMENT_PAGE_LOADED:"PAYMENT_PAGE_LOADED",PAGE_LOADED:"PAGE_LOADED"},t="DROPP_SDK_INIT",n="DROPP_SDK_CLOSE",s={PRODUCTION:"production",QA:"qa",SANDBOX:"sandbox"},i={[s.PRODUCTION]:"https://wv.dropp.cc",[s.QA]:"https://wv.qa.dropp.cc",[s.SANDBOX]:"https://wv.sandbox.dropp.cc"},o={[s.PRODUCTION]:["https://wv.dropp.cc"],[s.QA]:["https://wv.qa.dropp.cc"],[s.SANDBOX]:["https://wv.sandbox.dropp.cc"]},r=3e4,a=6e5,l={STANDARD:"standard",PREAUTH:"preauth",RECURRING:"recurring"},c="INIT_TIMEOUT",u="PAYMENT_TIMEOUT",d="INVALID_CONFIG",h="ALREADY_OPEN",p="UNKNOWN_ERROR",m="1.0.2";const g=new class{constructor(e,t={}){this.environment=e,this.forceEnabled=!!t.enabled,this.enabled=this._shouldEnableLogging()}_shouldEnableLogging(){return this.forceEnabled}setEnvironment(e,t={}){this.environment=e,"boolean"==typeof t.enabled&&(this.forceEnabled=t.enabled),this.enabled=this._shouldEnableLogging()}setEnabled(e){this.forceEnabled=!!e,this.enabled=this._shouldEnableLogging()}log(...e){this.enabled&&console.log(...e)}warn(...e){this.enabled&&console.warn(...e)}error(...e){this.enabled&&console.error(...e)}debug(...e){this.enabled&&console.debug(...e)}info(...e){this.enabled&&console.info(...e)}}("qa",{enabled:!1}),y=["USD","HBAR","USDC"],f=["NONE","HALF_HOURLY","HOURLY","DAILY","WEEKLY","MONTHLY","YEARLY"],D=[l.STANDARD,l.PREAUTH,l.RECURRING];function S(e,t={}){const{isProduction:n=!1,allowLocalCallbacksInNonProd:s=!1}=t;if("string"!=typeof e||!e.trim())return!1;try{const t=new URL(e.trim()),i="https:"===t.protocol;if(!("http:"===t.protocol)&&!i)return!1;return function(e){if(!e)return!1;const t=e.trim().toLowerCase();if("localhost"===t||"127.0.0.1"===t||"::1"===t||t.endsWith(".local"))return!0;if(!/^(\d{1,3}\.){3}\d{1,3}$/.test(t))return!1;const n=t.split(".").map(e=>Number(e));if(n.some(e=>Number.isNaN(e)||e<0||e>255))return!1;const[s,i]=n;return 10===s||127===s||172===s&&i>=16&&i<=31||192===s&&168===i||169===s&&254===i}(t.hostname)?!n&&s:!n||i}catch{return!1}}function w(e={},t={}){const n=[],s=e.paymentType||l.STANDARD,i="production"===(t.environment||"").toLowerCase(),o=!!t.allowLocalCallbacksInNonProd,r="string"==typeof e.currency?e.currency.trim().toUpperCase():"";if(D.includes(s)||n.push(`paymentType must be one of: ${D.join(", ")}`),void 0===e.amount||null===e.amount||""===e.amount?n.push("amount is required"):function(e){const t="number"==typeof e?e:parseFloat(e);return"number"==typeof t&&!Number.isNaN(t)&&t>0}(e.amount)||n.push("amount must be a positive number"),e.currency&&"string"==typeof e.currency&&e.currency.trim()?y.includes(r)||n.push(`currency must be one of: ${y.join(", ")}`):n.push("currency is required"),e.itemName&&"string"==typeof e.itemName&&e.itemName.trim()||n.push("itemName is required"),s===l.PREAUTH&&(r&&"USD"!==r&&n.push("currency must be USD for preauth payments"),e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:i,allowLocalCallbacksInNonProd:o})||n.push(i?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for preauth payments"),void 0===e.authHoldTimeInSeconds||null===e.authHoldTimeInSeconds||""===e.authHoldTimeInSeconds?n.push("authHoldTimeInSeconds is required for preauth payments"):function(e){const t="number"==typeof e?e:parseInt(e,10);return Number.isInteger(t)&&t>0}(e.authHoldTimeInSeconds)||n.push("authHoldTimeInSeconds must be a positive integer (seconds)")),s===l.RECURRING){e.callbackUrl&&String(e.callbackUrl).trim()?S(e.callbackUrl,{isProduction:i,allowLocalCallbacksInNonProd:o})||n.push(i?"callbackUrl must be HTTPS in production and cannot target loopback/private hosts":"callbackUrl must be a valid HTTP/HTTPS URL and cannot target loopback/private hosts unless explicitly enabled"):n.push("callbackUrl (signing URL) is required for recurring payments");const t=(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase();t?f.includes(t)||n.push(`frequency must be one of: ${f.join(", ")}`):n.push("frequency is required for recurring payments"),e.recurringEndDate&&String(e.recurringEndDate).trim()?!function(e){if("string"!=typeof e||!e.trim())return!1;const t=new Date(e.trim());return!Number.isNaN(t.getTime())}(e.recurringEndDate)?n.push("recurringEndDate must be a valid ISO date-time string"):new Date(e.recurringEndDate.trim())<=new Date&&n.push("recurringEndDate must be in the future"):n.push("recurringEndDate (expiry) is required for recurring payments")}return{valid:0===n.length,errors:n}}function T(e,t,n={}){return{code:e,message:t,details:n,timestamp:(new Date).toISOString(),toString(){return this.message||"Dropp SDK error"}}}class b{constructor(e,t,n=null){this.environment=e,this.onMessage=t,this.sessionId=`dropp-sdk-${Date.now()}-${Math.random().toString(36).substring(2,15)}`,g.log("[MessageHandler] Session initialized"),this.iframe=null,this.allowedOrigins=n?.length>0?n:o[e]||[],this.messageListener=null,this.pendingMessages=new Map}init(e){this.iframe=e,this.messageListener=this._handleMessage.bind(this),window.addEventListener("message",this.messageListener)}destroy(){this.messageListener&&(window.removeEventListener("message",this.messageListener),this.messageListener=null),this.iframe=null,this.pendingMessages.clear()}_handleMessage(e){if(g.log("[MessageHandler] Received postMessage event"),e.source===window)return void g.log("[MessageHandler] Ignoring message from self");if(!this._validateOrigin(e.origin))return void g.warn("[Dropp SDK] Rejected message from untrusted origin:",e.origin);if(!this.iframe||e.source!==this.iframe.contentWindow)return void g.warn("[Dropp SDK] Rejected message from unexpected source",{eventOrigin:e.origin});const t=e.data;this._validateMessageStructure(t)?t.sessionId&&t.sessionId!==this.sessionId?g.warn("[Dropp SDK] Rejected message with invalid session ID"):(g.log("[MessageHandler] Message passed validation"),this._processMessage(t)):g.warn("[Dropp SDK] Rejected message with invalid structure")}_validateOrigin(e){return!(!e.startsWith("http://localhost:")&&!e.startsWith("http://127.0.0.1:"))||this.allowedOrigins.includes(e)}_validateMessageStructure(t){if(!t||"object"!=typeof t)return!1;if(!t.type||"string"!=typeof t.type)return!1;return!!Object.values(e).includes(t.type)&&!(t.type!==e.ACCOUNT_STATUS&&!t.timestamp)}_processMessage(e){g.log("[Dropp SDK] Received message:",e.type),this.onMessage&&this.onMessage(e)}sendToPaymentApp(e,t={}){if(!this.iframe||!this.iframe.contentWindow)return g.error("[Dropp SDK] Cannot send message: iframe not ready"),!1;const n={type:e,data:t,sessionId:this.sessionId,timestamp:(new Date).toISOString(),sdkVersion:"1.0.0"},s=this.allowedOrigins[0]||"*";try{return this.iframe.contentWindow.postMessage(n,s),g.log("[Dropp SDK] Sent message:",e),!0}catch(e){return g.error("[Dropp SDK] Error sending message:",e),!1}}sendInit(e){return this.sendToPaymentApp(t,{mode:"sdk",config:e})}sendClose(){return this.sendToPaymentApp(n,{})}getSessionId(){return this.sessionId}}class v{constructor(e){this.onClose=e,this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,this.isOpen=!1,this.escapeListener=null}open(){return this.isOpen?(g.warn("[Dropp SDK] Modal is already open"),null):(this._createModal(),this._attachEventListeners(),this._show(),this.isOpen=!0,this.iframe)}close(){g.log("[ModalManager] ๐ฆ close() called, isOpen:",this.isOpen),this.isOpen?(g.log("[ModalManager] ๐ฆ Hiding modal..."),this._hide(),g.log("[ModalManager] ๐ฆ Removing event listeners..."),this._removeEventListeners(),g.log("[ModalManager] ๐ฆ Destroying modal..."),this._destroyModal(),this.isOpen=!1,g.log("[ModalManager] โ
Modal close sequence initiated")):g.log("[ModalManager] โ ๏ธ Modal is not open, skipping close")}_createModal(){this.overlay=document.createElement("div"),this.overlay.id="dropp-payment-overlay",this._applyOverlayStyles(this.overlay),this.container=document.createElement("div"),this.container.id="dropp-payment-container",this._applyContainerStyles(this.container),this.iframe=document.createElement("iframe"),this.iframe.id="dropp-payment-iframe",this.iframe.setAttribute("allow","payment"),this.iframe.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),this.iframe.setAttribute("referrerpolicy","no-referrer"),this.iframe.setAttribute("title","Dropp Payment"),this._applyIframeStyles(this.iframe),this.container.appendChild(this.iframe),this.overlay.appendChild(this.container),document.body.appendChild(this.overlay)}_applyOverlayStyles(e){Object.assign(e.style,{position:"fixed",inset:"0",width:"100vw",height:"100vh",margin:"0",padding:"20px",boxSizing:"border-box",backgroundColor:"rgba(0, 0, 0, 0.6)",zIndex:999999..toString(),display:"flex",alignItems:"center",justifyContent:"center",opacity:"0",transition:"opacity 0.3s ease",backdropFilter:"blur(4px)",overflow:"auto"})}_applyContainerStyles(e){const t=window.innerWidth<768;this._isMobile=t,Object.assign(e.style,{position:"relative",flex:"0 0 auto",alignSelf:"center",margin:"auto",width:"100%",maxWidth:t?"100%":"400px",height:t?"100%":"auto",minHeight:t?"100%":"800px",maxHeight:t?"100%":"min(1000px, calc(100vh - 40px))",backgroundColor:"#ffffff",borderRadius:t?"0":"16px",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.3)",overflow:"hidden",transform:"scale(0.95)",transition:"transform 0.3s ease, opacity 0.3s ease",display:"flex",flexDirection:"column"})}_getContainerTransform(e){return`scale(${e})`}_applyCloseButtonStyles(e){Object.assign(e.style,{position:"absolute",top:"16px",right:"16px",zIndex:"10",width:"40px",height:"40px",border:"none",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.9)",color:"#333",fontSize:"28px",lineHeight:"1",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",transition:"all 0.2s ease",fontFamily:"Arial, sans-serif",padding:"0"}),e.addEventListener("mouseenter",()=>{Object.assign(e.style,{backgroundColor:"#f5f5f5",transform:"scale(1.1)"})}),e.addEventListener("mouseleave",()=>{Object.assign(e.style,{backgroundColor:"rgba(255, 255, 255, 0.9)",transform:"scale(1)"})})}_applyIframeStyles(e){const t=this._isMobile;Object.assign(e.style,{width:"100%",flex:"1 1 auto",minHeight:t?"100%":"min(520px, calc(90vh - 40px))",height:t?"100%":"min(520px, calc(90vh - 40px))",border:"none",display:"block"})}_show(){document.body.style.overflow="hidden",requestAnimationFrame(()=>{this.overlay&&(this.overlay.style.opacity="1"),this.container&&(this.container.style.transform=this._getContainerTransform(1))})}_hide(){g.log("[ModalManager] ๐ญ _hide() called"),this.overlay&&(this.overlay.style.opacity="0",g.log("[ModalManager] ๐ญ Overlay opacity set to 0")),this.container&&(this.container.style.transform=this._getContainerTransform(.95),g.log("[ModalManager] ๐ญ Container transform set to scale(0.95)")),document.body.style.overflow="",g.log("[ModalManager] ๐ญ Body scroll restored")}_destroyModal(){g.log("[ModalManager] ๐๏ธ _destroyModal() called, waiting 300ms for animation"),setTimeout(()=>{g.log("[ModalManager] ๐๏ธ Animation complete, removing from DOM"),this.overlay&&this.overlay.parentNode&&(this.overlay.parentNode.removeChild(this.overlay),g.log("[ModalManager] ๐๏ธ Overlay removed from DOM")),this.overlay=null,this.container=null,this.iframe=null,this.closeButton=null,g.log("[ModalManager] โ
Modal destroyed")},300)}_attachEventListeners(){}_removeEventListeners(){this.escapeListener&&(document.removeEventListener("keydown",this.escapeListener),this.escapeListener=null)}_handleCloseClick(e){e.stopPropagation(),this.onClose&&this.onClose("user_closed")}_handleOverlayClick(e){e.target===this.overlay&&this.onClose&&this.onClose("user_closed")}_handleEscapeKey(e){"Escape"===e.key&&this.isOpen&&this.onClose&&this.onClose("user_closed")}getIframe(){return this.iframe}getIsOpen(){return this.isOpen}}const E=["fundnow","linkbank","linkcard","redeemnow","fundcrypto","transferusdc","usdchistory","redeemcrypto","manageaccounts","transactions","merchantlist","favorites","offers","profile","pinchange","unlinkaccount","accountsettings","aboutus"];class _{constructor(e={}){if("undefined"==typeof window||"undefined"==typeof document)throw new Error("Dropp Payment SDK can only be used in a browser environment");if(!e.merchantId||!e.apiKey)throw new Error("merchantId and apiKey are required to initialize SDK");if(this.merchantId=e.merchantId,this.apiKey=e.apiKey,this.environment=e.environment||s.QA,this.baseUrl=e.paymentAppUrl||e.baseUrl||i[this.environment],this.isInitialized=!1,this.initializationPromise=null,this.getServerAuthToken="function"==typeof e.getServerAuthToken?e.getServerAuthToken:null,this.requireServerAuthToken="boolean"==typeof e.requireServerAuthToken?e.requireServerAuthToken:this.environment===s.PRODUCTION,this.allowLocalCallbacksInNonProd=!!e.allowLocalCallbacksInNonProd,e.allowedOrigins?.length)this.allowedOrigins=e.allowedOrigins;else try{this.allowedOrigins=[new URL(this.baseUrl).origin]}catch{this.allowedOrigins=o[this.environment]||[]}this.isOpen=!1,this.currentSession=null,this.currentFlowType=null,this.statusSession=null,this.hiddenIframe=null,this.statusTimeout=null,this.initTimeout=null,this.paymentTimeout=null,this.hostAppDomain=null,this.onAccountChanged=null,this.onPageFailed=null,this.messageHandler=null,this.modalManager=null,g.setEnvironment(this.environment,{enabled:!!e.debugLogging}),g.log(`[Dropp SDK] Initialized v${m} - Environment: ${this.environment}`)}pay(e={}){return new Promise((t,n)=>{if(this.isOpen||this.currentFlowType){const e=T(h,"A payment session is already in progress",{currentSession:this.currentSession,currentFlowType:this.currentFlowType});return void n(e)}(async()=>{try{await this.initialize();const s=w(e,{environment:this.environment,allowLocalCallbacksInNonProd:this.allowLocalCallbacksInNonProd});if(!s.valid){const e=T(d,"Invalid payment configuration",{errors:s.errors});return void n(e)}this.onSuccess=e.onSuccess||null,this.onFailure=e.onFailure||null,this.onCancel=e.onCancel||null,this.onClose=e.onClose||null,this.currentSession={resolve:t,reject:n,options:e,startTime:Date.now()},await this._initializePayment(e)}catch(e){const t=e&&e.code===d?e:T(p,"Failed to initialize payment",{originalError:e?.message||String(e)});n(t),this._cleanup()}})()})}async initialize(){return this.initializationPromise||(this.initializationPromise=(async()=>{if(this.hostAppDomain=this._detectHostAppDomain(),!this.hostAppDomain)throw T(d,"Unable to detect host app domain for SDK validation");return await this._validateInitializationCredentials(),this.isInitialized=!0,{status:"success",code:"INITIALIZED",message:"Dropp SDK initialized successfully"}})().catch(e=>{throw this.isInitialized=!1,this.initializationPromise=null,e})),this.initializationPromise}_getValidationUrl(){const e={[s.QA]:"https://bc0qfqi8c9.execute-api.us-east-1.amazonaws.com/QA-test-app-sdk-gateway-stage/sdk/payer/webview/validateSdk",[s.SANDBOX]:"https://76xbxsi4kf.execute-api.us-east-1.amazonaws.com/sandbox/sdk/payer/webview/validateSdk",[s.PRODUCTION]:"https://api.dropp.cc/payer/webview/validateSdk"};return e[this.environment]||e[s.QA]}_detectHostAppDomain(){if("undefined"!=typeof window&&window.location)return window.location.hostname||void 0}_getHostedPageAuthToken(){const e="string"==typeof this.apiKey?this.apiKey.trim():"",t="string"==typeof this.merchantId?this.merchantId.trim():"";if(!e)return"";try{const n=JSON.stringify({apikey:e,merchantAccount:t});return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}catch{return""}}async _validateInitializationCredentials(){const e=this._getValidationUrl(),t=this.hostAppDomain;if(!t)throw T(d,"Unable to resolve host app domain for SDK validation");const n={accept:"application/json, text/plain, */*","content-type":"application/json","x-api-key":this.apiKey,"x-app-package":t,"dropp-user-agent":"WEB"};let s;n["dropp-merchant-domain"]=t;let i=null;try{s=await fetch(e,{method:"POST",headers:n,body:JSON.stringify({id:this.merchantId})})}catch(t){throw T(d,"Unable to validate merchant credentials",{endpoint:e,originalError:t?.message||String(t)})}try{i=await s.json()}catch{i=null}if(!s.ok)throw T(d,"Merchant validation failed for merchantId/apiKey/domain",{endpoint:e,status:s.status,response:i});const o=Number(i?.responseCode),r=i?.errors,a=!Array.isArray(r)||0===r.length;if(!(i&&0===o&&a))throw T(d,"Merchant validation returned an unsuccessful response",{endpoint:e,status:s.status,response:i});g.log("[Dropp SDK] Merchant credentials validated successfully")}closePayment(){if(this.isOpen){if("page"===this.currentFlowType)return void this._cleanup();this._handleCancel("sdk_close")}}dashboard(e={}){return this._openHostedPage("/firsttimeflow",e)}open(e,t={}){const n="string"==typeof e?e.trim():"";if(!n)throw T(d,"moduleId is required for Dropp.open(moduleId)",{moduleId:e});if(!E.includes(n))throw T(d,"Unsupported moduleId passed to Dropp.open(moduleId)",{moduleId:n,supportedModuleIds:[...E]});const s="about"===n?"/aboutus":`/${n}`;return this._openHostedPage(s,t)}unlinkAccount(e={}){return this._openHostedPage("/unlink",e)}transactions(e={}){return this._openHostedPage("/transactions",e)}offers(e={}){return this._openHostedPage("/offers",e)}status(){return new Promise((e,t)=>{this.isOpen||this.currentFlowType?t(T(h,"A Dropp session is already in progress",{currentSession:this.currentSession,currentFlowType:this.currentFlowType})):(async()=>{try{this.currentFlowType="status",await this.initialize(),this.currentSession=null,this.onSuccess=null,this.onFailure=null,this.onCancel=null,this.onClose=null,this.messageHandler=new b(this.environment,this._handleMessage.bind(this),this.allowedOrigins);const n=document.createElement("iframe");n.id="dropp-status-iframe",n.setAttribute("allow","payment"),n.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups"),n.setAttribute("referrerpolicy","no-referrer"),n.setAttribute("title","Dropp Account Status"),Object.assign(n.style,{position:"absolute",width:"1px",height:"1px",border:"0",opacity:"0",pointerEvents:"none",visibility:"hidden"}),document.body.appendChild(n),this.hiddenIframe=n,this.messageHandler.init(n);const s=new URLSearchParams({sdkMode:"true",sessionId:this.messageHandler.getSessionId(),sdkVersion:m,platform:"web",merchantDomain:this.hostAppDomain}),i=this._getHostedPageAuthToken();i&&s.set("auth",i);const o=this.baseUrl.replace(/\/+$/,"");n.src=`${o}/#/status?${s.toString()}`,this.statusSession={resolve:e,reject:t,startTime:Date.now()},this.statusTimeout=setTimeout(()=>{const e=T(c,"Account status request timed out",{type:"status",sessionDuration:this.statusSession?Date.now()-this.statusSession.startTime:0});this.statusSession&&this.statusSession.reject(e),this._cleanup()},r)}catch(e){t(T(p,"Failed to get account status",{originalError:e?.message||String(e)})),this._cleanup()}})()})}async _initializePayment(e){g.log("[Dropp SDK] Initializing payment session"),this.currentFlowType="payment",this.messageHandler=new b(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new v(this._handleModalClose.bind(this));const t=this.modalManager.open();if(!t)throw new Error("Failed to create modal iframe");this.messageHandler.init(t);const n=e.paymentType||l.STANDARD;let s="/payViaUrl";n===l.PREAUTH?s="/preAuthPayment":n===l.RECURRING&&(s="/recurringPayment");const i=n===l.RECURRING?(e.frequency||e.recurringInterval||"").toString().trim().toUpperCase():"",o=n===l.RECURRING&&"NONE"===i,c=e.appUrl||("undefined"!=typeof window&&window.location?window.location.href:void 0),u={merchantAccount:this.merchantId,amount:n===l.PREAUTH?void 0:e.amount,maxAmount:n===l.PREAUTH||o?e.amount:void 0,fixAmount:n!==l.RECURRING||o?void 0:e.amount,acceptPaymentDelay:n===l.STANDARD&&!0===e.acceptPaymentDelay||void 0,currency:e.currency,itemName:e.itemName,description:e.description,invoiceId:e.invoiceId||`INV-${Date.now()}`,invoiceType:n===l.PREAUTH?"PREAUTH":void 0,apiKey:this.apiKey,packageName:this.hostAppDomain,merchantDomain:this.hostAppDomain,sdkVersion:m,platform:"web",appUrl:c,sessionId:this.messageHandler.getSessionId()};if(g.log("[Dropp SDK] Including SDK session context in payment params"),e.successURL&&(u.successURL=e.successURL),e.failureURL&&(u.failureURL=e.failureURL),n===l.RECURRING){const t=e.frequency||e.recurringInterval;t&&(u.frequency=t),e.recurringEndDate&&(u.expiry=e.recurringEndDate)}n===l.PREAUTH&&e.authHoldTimeInSeconds&&(u.authHoldTimeInSeconds=e.authHoldTimeInSeconds),e.callbackUrl&&(u.url=e.callbackUrl,u.submitToCallBack="post");const h={sessionId:u.sessionId,merchantAccount:this.merchantId,amount:e.amount,paymentType:n,invoiceId:u.invoiceId,expiry:e.recurringEndDate||null,issuedAt:Date.now()};let p="string"==typeof e.serverAuthToken?e.serverAuthToken.trim():"";if(!p&&this.getServerAuthToken)try{const e=await this.getServerAuthToken(h);p="string"==typeof e?e.trim():""}catch(e){throw T(d,"Failed to obtain server auth token",{originalError:e?.message||String(e)})}if(this.requireServerAuthToken&&!p)throw T(d,"serverAuthToken is required. Provide options.serverAuthToken or config.getServerAuthToken.",{environment:this.environment,paymentType:n,invoiceId:u.invoiceId});const y=await async function(e,t,n,s,i={}){try{const{serverAuthToken:o=""}=i,r={};Object.keys(n).forEach(e=>{const t=n[e];null!=t&&(r[e]=t)}),g.log("[buildPaymentUrl] Building payment URL payload");const a=JSON.stringify(r),l=btoa(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),c=Date.now().toString(),u=new URLSearchParams({pay:l,sdkTs:c,sdkVersion:s,platform:"web"});return o&&u.set("authToken",o),`${e}/#${t}?${u.toString()}`}catch(e){throw g.error("Error building payment URL:",e),e}}(this.baseUrl,s,u,m,{serverAuthToken:p});g.log("[Dropp SDK] Loading payment flow iframe"),t.src=y,this.isOpen=!0,this.initTimeout=setTimeout(()=>{this._handleTimeout("init")},r),this.paymentTimeout=setTimeout(()=>{this._handleTimeout("payment")},a)}async _openHostedPage(e,t={}){if("status"===this.currentFlowType)throw T(h,"A Dropp session is already in progress",{currentSession:this.currentSession,currentFlowType:this.currentFlowType,route:e});if(this.isOpen){if("page"!==this.currentFlowType)throw T(h,"A Dropp session is already in progress",{currentSession:this.currentSession,route:e});this._cleanup()}await this.initialize(),this.currentFlowType="page",this.currentSession=null,this.onSuccess=null,this.onFailure="function"==typeof t.onFailed?t.onFailed:null,this.onCancel="function"==typeof t.onCancel?t.onCancel:null,this.onClose="function"==typeof t.onClose?t.onClose:null,this.onAccountChanged="function"==typeof t.onAccountChanged?t.onAccountChanged:null,this.onPageFailed="function"==typeof t.onPageFailed?t.onPageFailed:this.onFailure,this.messageHandler=new b(this.environment,this._handleMessage.bind(this),this.allowedOrigins),this.modalManager=new v(this._handleModalClose.bind(this));const n=this.modalManager.open();if(!n)throw new Error("Failed to create modal iframe");this.messageHandler.init(n);const s=new URLSearchParams({sdkMode:"true",sessionId:this.messageHandler.getSessionId(),sdkVersion:m,platform:"web",merchantDomain:this.hostAppDomain}),i=this._getHostedPageAuthToken();if(i&&s.set("auth",i),"/firsttimeflow"===e&&Array.isArray(t.modules)){const e=t.modules.map(e=>"string"==typeof e?e.trim():"").filter(Boolean);e.length>0&&s.set("modules",e.join(","))}const o=this.baseUrl.replace(/\/+$/,"");return n.src=`${o}/#${e}?${s.toString()}`,this.isOpen=!0,g.log("[Dropp SDK] Hosted page opened",{route:e}),{status:"opened",route:e}}_handleMessage(t){const{type:n,data:s}=t;switch(n){case e.READY:this._handleReady(s);break;case e.PAGE_LOADED:case e.PAYMENT_PAGE_LOADED:this._handlePageLoaded(s);break;case e.PAYMENT_SUCCESS:this._handleSuccess(s);break;case e.PAYMENT_FAILED:this._handleFailure(s);break;case e.PAYMENT_CANCELLED:this._handleCancel("user_cancelled");break;case e.ACCOUNT_STATUS:this._handleAccountStatus(s);break;case e.ACCOUNT_EVENT:this._handleAccountEvent(s);break;case e.PAGE_EVENT:this._handlePageEvent(s);break;case e.AUTO_CLOSE_WEBVIEW:g.log("[Dropp SDK] AUTO_CLOSE_WEBVIEW received - closing modal"),this._cleanup(),g.log("[Dropp SDK] Cleanup completed");break;case e.CLOSE_WEBVIEW:if(g.log("[Dropp SDK] CLOSE_WEBVIEW received from app - closing modal"),"status"===this.currentFlowType&&this.statusSession){const e=T(p,"Account status request was closed before response was received",{type:"status",sessionDuration:Date.now()-this.statusSession.startTime});this.statusSession.reject(e),this._cleanup();break}this._handleCancel("app_close");break;default:g.warn("[Dropp SDK] Unknown message type:",n)}}_handleReady(e){if(g.log("[Dropp SDK] Payment app ready"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.messageHandler&&this.currentSession){const e={};Object.keys(this.currentSession.options).forEach(t=>{const n=this.currentSession.options[t];"function"!=typeof n&&(e[t]=n)}),g.log("[Dropp SDK] Sending init config to payment app"),this.messageHandler.sendInit(e)}}_handlePageLoaded(e){g.log("[Dropp SDK] Payment page loaded")}_getBridgeAction(e={}){return e&&"object"==typeof e?"string"==typeof e.action?e.action:e.result&&"object"==typeof e.result&&"string"==typeof e.result.action?e.result.action:"":""}_getSafeFailureMessage(e={},t="Request failed"){return e&&"string"==typeof e.message&&e.message.trim()?e.message.trim():e&&e.result&&"object"==typeof e.result&&"string"==typeof e.result.message&&e.result.message.trim()?e.result.message.trim():t}_getSafeResult(e={}){return e&&e.result&&"object"==typeof e.result?e.result:{}}_handleAccountEvent(e){const t=this._getBridgeAction(e),n=this._getSafeResult(e);if("onAccountChanged"!==t)if("onCancel"!==t){if("onFailed"===t){const t=this._getSafeFailureMessage(e,"Account request failed");return void(this.onFailure&&this.onFailure(t))}g.warn("[Dropp SDK] Unknown ACCOUNT_EVENT action:",t)}else this.onCancel&&this.onCancel();else this.onAccountChanged&&this.onAccountChanged({linked:!0===n.linked,rawData:n.rawData})}_handlePageEvent(e){const t=this._getBridgeAction(e);if("onFailed"===t){const t=this._getSafeFailureMessage(e,"Page request failed");return void(this.onPageFailed&&this.onPageFailed(t))}g.warn("[Dropp SDK] Unknown PAGE_EVENT action:",t)}_handleAccountStatus(t){g.log("[Dropp SDK] Account status received"),this.statusSession?(this.statusSession.resolve({type:e.ACCOUNT_STATUS,data:t}),this._cleanup()):g.warn("[Dropp SDK] ACCOUNT_STATUS received without active status session")}_handleSuccess(e){g.log("[Dropp SDK] Payment successful");const t={status:"success",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onSuccess&&this.onSuccess(t)}_handleFailure(e){g.log("[Dropp SDK] Payment failed");const t={status:"failed",...e,sessionDuration:Date.now()-this.currentSession.startTime};this.currentSession&&this.currentSession.resolve(t),this.onFailure&&this.onFailure(t)}_handleCancel(e){if(g.log("[Dropp SDK] Payment cancelled"),"page"===this.currentFlowType)return this.onCancel&&this.onCancel(),void this._cleanup();const t={status:"cancelled",reason:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0};this.currentSession&&this.currentSession.resolve(t),this.onCancel&&this.onCancel(t),this._cleanup()}_handleModalClose(e){g.log("[Dropp SDK] Modal closed by user"),"page"!==this.currentFlowType?this._handleCancel(e):this._cleanup()}_handleTimeout(e){g.error("[Dropp SDK] Timeout:",e);const t=T("init"===e?c:u,"init"===e?"Payment app failed to load within timeout period":"Payment session timed out",{type:e,sessionDuration:this.currentSession?Date.now()-this.currentSession.startTime:0});this.currentSession&&this.currentSession.reject(t),this.onFailure&&this.onFailure({status:"failed",error:t}),this._cleanup()}_cleanup(){g.log("[Dropp SDK] ๐งน Cleaning up session - starting cleanup"),this.initTimeout&&(clearTimeout(this.initTimeout),this.initTimeout=null),this.paymentTimeout&&(clearTimeout(this.paymentTimeout),this.paymentTimeout=null),this.statusTimeout&&(clearTimeout(this.statusTimeout),this.statusTimeout=null),this.messageHandler&&(g.log("[Dropp SDK] ๐งน Destroying message handler"),this.messageHandler.destroy(),this.messageHandler=null),this.modalManager&&(g.log("[Dropp SDK] ๐งน Closing modal manager"),this.modalManager.close(),g.log("[Dropp SDK] ๐งน Modal manager closed"),this.modalManager=null),this.hiddenIframe&&this.hiddenIframe.parentNode&&this.hiddenIframe.parentNode.removeChild(this.hiddenIframe),this.hiddenIframe=null,this.currentSession=null,this.statusSession=null,this.currentFlowType=null,this.isOpen=!1,this.onClose&&this.onClose()}static getVersion(){return m}static getEnvironments(){return{...s}}static getPaymentTypes(){return{...l}}}let A=null;async function I(e){A=new _(e);return{...await A.initialize(),sdk:A}}function C(){return A}const N={init:e=>I(e),pay(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.pay(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.pay(e)},dashboard(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.dashboard(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.dashboard(e)},open(e,t){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.open(moduleId, options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.open(e,t)},unlinkAccount(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.unlinkAccount(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.unlinkAccount(e)},transactions(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.transactions(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.transactions(e)},offers(e){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.offers(options).");throw e.code="SDK_NOT_INITIALIZED",e}return A.offers(e)},status(){if(!A){const e=new Error("Dropp SDK is not initialized. Call Dropp.init(config) before Dropp.status().");throw e.code="SDK_NOT_INITIALIZED",e}return A.status()},getInstance:()=>A};var O={DroppPaymentSDK:_,createPaymentSDK:I,Dropp:N,ENVIRONMENTS:s,PAYMENT_TYPES:l};export{N as Dropp,_ as DroppPaymentSDK,s as ENVIRONMENTS,l as PAYMENT_TYPES,I as createPaymentSDK,O as default,C as getDroppInstance};
|
|
2
2
|
//# sourceMappingURL=dropp-payment-sdk.esm.js.map
|