suioutkit 1.0.1 → 1.0.3
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 +2 -3
- package/assets/slush.jpeg +0 -0
- package/dist/components/modal.d.ts +6 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2138 -50
- package/dist/types/index.d.ts +11 -0
- package/package.json +3 -1
- package/src/components/modal.ts +56 -46
- package/src/components/style.css +264 -300
- package/src/index.ts +9 -10
- package/src/types/index.ts +13 -0
package/dist/types/index.d.ts
CHANGED
|
@@ -55,3 +55,14 @@ export interface CheckoutStatusResponse {
|
|
|
55
55
|
walrusBlobId?: string;
|
|
56
56
|
error?: string;
|
|
57
57
|
}
|
|
58
|
+
export interface PaymentResult {
|
|
59
|
+
nonce: string;
|
|
60
|
+
txDigest: string;
|
|
61
|
+
walrusBlobId: string;
|
|
62
|
+
}
|
|
63
|
+
export interface SuiOutKitModalOptions {
|
|
64
|
+
onClose?: () => void;
|
|
65
|
+
onPaymentComplete?: (result: PaymentResult) => void;
|
|
66
|
+
redirectUrl?: string;
|
|
67
|
+
autoCloseOnSuccess?: boolean;
|
|
68
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suioutkit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Premium Universal Payment Gateway SDK for instant settlement on Sui",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
"@mysten/sui": "^2.17.0",
|
|
26
26
|
"@stripe/stripe-js": "^9.7.0",
|
|
27
27
|
"lucide-react": "^1.17.0",
|
|
28
|
+
"qrcode": "^1.5.4",
|
|
28
29
|
"react": "^19.2.7",
|
|
29
30
|
"react-dom": "^19.2.7"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
33
|
+
"@types/qrcode": "^1.5.6",
|
|
32
34
|
"@types/react": "^19.2.16",
|
|
33
35
|
"@types/react-dom": "^19.2.3",
|
|
34
36
|
"esbuild": "^0.28.0",
|
package/src/components/modal.ts
CHANGED
|
@@ -10,8 +10,9 @@ import { createPaymentTransactionUri } from "@mysten/payment-kit";
|
|
|
10
10
|
import { paymentKit } from "@mysten/payment-kit";
|
|
11
11
|
import { createDAppKit } from "@mysten/dapp-kit-core";
|
|
12
12
|
import "@mysten/dapp-kit-core/web";
|
|
13
|
+
import QRCode from "qrcode";
|
|
13
14
|
import { loadStripe, StripeElements, Stripe } from "@stripe/stripe-js";
|
|
14
|
-
import { CheckoutSession, ChargeResponse, CheckoutStatusResponse, CryptoIntentResponse } from "../types/index.js";
|
|
15
|
+
import { CheckoutSession, ChargeResponse, CheckoutStatusResponse, CryptoIntentResponse, SuiOutKitModalOptions, PaymentResult } from "../types/index.js";
|
|
15
16
|
import PaymentStatusUI from "./PaymentStatusUI";
|
|
16
17
|
import { joinApiPath } from "../config/api.js";
|
|
17
18
|
|
|
@@ -33,17 +34,23 @@ export class SuiOutKitModal {
|
|
|
33
34
|
private backendUrl: string;
|
|
34
35
|
private pollInterval: any = null;
|
|
35
36
|
private walletConnectionUnsubscribe: (() => void) | null = null;
|
|
36
|
-
private onCloseCallback
|
|
37
|
+
private onCloseCallback?: () => void;
|
|
38
|
+
private onPaymentCompleteCallback?: (result: PaymentResult) => void;
|
|
39
|
+
private redirectUrl?: string;
|
|
40
|
+
private autoCloseOnSuccess?: boolean;
|
|
37
41
|
private cryptoIntent: CryptoIntentResponse | null = null;
|
|
38
42
|
private dAppKit: any | null = null;
|
|
39
43
|
private paymentClient: any | null = null;
|
|
40
44
|
private stripeInstance: Stripe | null = null;
|
|
41
45
|
private stripeElements: StripeElements | null = null;
|
|
42
46
|
|
|
43
|
-
constructor(session: CheckoutSession, backendUrl: string,
|
|
47
|
+
constructor(session: CheckoutSession, backendUrl: string, options?: SuiOutKitModalOptions) {
|
|
44
48
|
this.session = session;
|
|
45
49
|
this.backendUrl = backendUrl;
|
|
46
|
-
this.onCloseCallback = onClose;
|
|
50
|
+
this.onCloseCallback = options?.onClose;
|
|
51
|
+
this.onPaymentCompleteCallback = options?.onPaymentComplete;
|
|
52
|
+
this.redirectUrl = options?.redirectUrl;
|
|
53
|
+
this.autoCloseOnSuccess = options?.autoCloseOnSuccess;
|
|
47
54
|
this.ensureDAppKit(); // Initialize early so wallets have time to inject
|
|
48
55
|
this.injectStyles();
|
|
49
56
|
this.createModal();
|
|
@@ -271,8 +278,8 @@ export class SuiOutKitModal {
|
|
|
271
278
|
<h2 class="suioutkit-title">OPay Direct</h2>
|
|
272
279
|
<p class="suioutkit-subtitle">Enter your OPay registered phone number</p>
|
|
273
280
|
</div>
|
|
274
|
-
<div class="
|
|
275
|
-
<form class="sok-form" id="sok-opay-form">
|
|
281
|
+
<div class="suioutkit-panel">
|
|
282
|
+
<form class="sok-form" id="sok-opay-form" style="width: 100%;">
|
|
276
283
|
<input type="tel" class="sok-input" placeholder="e.g. 08012345678" id="sok-phone-input" required />
|
|
277
284
|
<button type="submit" class="sok-btn">Send Prompt</button>
|
|
278
285
|
</form>
|
|
@@ -348,12 +355,12 @@ export class SuiOutKitModal {
|
|
|
348
355
|
<h2 class="suioutkit-title">Global Checkout</h2>
|
|
349
356
|
<p class="suioutkit-subtitle">Secured by Stripe</p>
|
|
350
357
|
</div>
|
|
351
|
-
<div class="suioutkit-panel"
|
|
358
|
+
<div class="suioutkit-panel">
|
|
352
359
|
<form id="payment-form" style="width: 100%;">
|
|
353
360
|
<div id="payment-element" style="min-height: 200px; margin-bottom: 16px;">
|
|
354
361
|
<div class="sok-spinner" style="margin: 0 auto;"></div>
|
|
355
362
|
</div>
|
|
356
|
-
<button class="sok-btn" id="submit-stripe-btn"
|
|
363
|
+
<button class="sok-btn sok-btn-indigo" id="submit-stripe-btn">
|
|
357
364
|
Pay Now
|
|
358
365
|
</button>
|
|
359
366
|
<div id="payment-message" style="color: #ef4444; font-size: 13px; margin-top: 8px; text-align: center; display: none;"></div>
|
|
@@ -413,29 +420,20 @@ export class SuiOutKitModal {
|
|
|
413
420
|
const container = this.overlay?.querySelector("#sok-content-panel");
|
|
414
421
|
if (!container) return;
|
|
415
422
|
|
|
416
|
-
this.renderLoadingPanel("Preparing crypto payment...");
|
|
417
|
-
|
|
418
|
-
try {
|
|
419
|
-
this.cryptoIntent = await this.loadCryptoIntent("sui_wallet");
|
|
420
|
-
} catch (err: any) {
|
|
421
|
-
this.renderErrorPanel(err.message || "Failed to prepare crypto payment.");
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
423
|
container.innerHTML = `
|
|
426
424
|
<button class="suioutkit-back" id="sok-back-btn">← Back to methods</button>
|
|
427
425
|
<div class="suioutkit-header">
|
|
428
426
|
<h2 class="suioutkit-title">Pay with Sui Wallet</h2>
|
|
429
427
|
<p class="suioutkit-subtitle">Choose SUI payment channel</p>
|
|
430
428
|
</div>
|
|
431
|
-
<div class="suioutkit-panel"
|
|
429
|
+
<div class="suioutkit-panel">
|
|
432
430
|
<p class="sok-status-text" style="margin-bottom: 12px;">
|
|
433
431
|
Choose whether to pay via a desktop extension wallet or scan a dynamic QR Code with your mobile wallet.
|
|
434
432
|
</p>
|
|
435
|
-
<button class="sok-btn" id="sok-connect-extension-btn" style="
|
|
433
|
+
<button class="sok-btn sok-btn-blue" id="sok-connect-extension-btn" style="margin-bottom: 4px;">
|
|
436
434
|
Standard Connect Wallet
|
|
437
435
|
</button>
|
|
438
|
-
<button class="sok-btn" id="sok-outpay-qr-btn"
|
|
436
|
+
<button class="sok-btn sok-btn-green" id="sok-outpay-qr-btn">
|
|
439
437
|
outPay (Scan QR Code)
|
|
440
438
|
</button>
|
|
441
439
|
</div>
|
|
@@ -443,9 +441,12 @@ export class SuiOutKitModal {
|
|
|
443
441
|
|
|
444
442
|
container.querySelector("#sok-back-btn")?.addEventListener("click", () => this.renderSelectionPanel());
|
|
445
443
|
|
|
446
|
-
container.querySelector("#sok-connect-extension-btn")?.addEventListener("click", () => {
|
|
447
|
-
|
|
448
|
-
|
|
444
|
+
container.querySelector("#sok-connect-extension-btn")?.addEventListener("click", async () => {
|
|
445
|
+
this.renderLoadingPanel("Preparing crypto payment...");
|
|
446
|
+
try {
|
|
447
|
+
this.cryptoIntent = await this.loadCryptoIntent("sui_wallet");
|
|
448
|
+
} catch (err: any) {
|
|
449
|
+
this.renderErrorPanel(err.message || "Failed to prepare crypto payment.");
|
|
449
450
|
return;
|
|
450
451
|
}
|
|
451
452
|
void this.openStandardConnectWallet();
|
|
@@ -517,10 +518,10 @@ export class SuiOutKitModal {
|
|
|
517
518
|
<h2 class="suioutkit-title">Connect Wallet</h2>
|
|
518
519
|
<p class="suioutkit-subtitle">Choose the extension you want to use</p>
|
|
519
520
|
</div>
|
|
520
|
-
<div
|
|
521
|
+
<div class="suioutkit-wallet-list">
|
|
521
522
|
${walletCardsHtml}
|
|
522
523
|
</div>
|
|
523
|
-
<p class="sok-status-text" style="
|
|
524
|
+
<p class="sok-status-text sok-text-sm sok-op-75" style="margin-top: 14px; text-align: center;">
|
|
524
525
|
Wallets are filtered from the browser extensions detected by dApp Kit.
|
|
525
526
|
</p>
|
|
526
527
|
`;
|
|
@@ -598,15 +599,15 @@ export class SuiOutKitModal {
|
|
|
598
599
|
|
|
599
600
|
container.innerHTML = `
|
|
600
601
|
<button class="suioutkit-back" id="sok-back-btn">← Back to Sui options</button>
|
|
601
|
-
<div class="suioutkit-panel"
|
|
602
|
-
<div class="sok-
|
|
602
|
+
<div class="suioutkit-panel">
|
|
603
|
+
<div class="sok-icon-wrap sok-text-amber">
|
|
603
604
|
<i data-lucide="alert-circle" style="width: 48px; height: 48px;"></i>
|
|
604
605
|
</div>
|
|
605
606
|
<h2 class="sok-success-title">Open this demo from localhost</h2>
|
|
606
607
|
<p class="sok-status-text" style="max-width: 320px;">
|
|
607
608
|
This page is running from a local file URL. Browser extension wallets like Slush and Phantom do not reliably inject into file:// pages, so dApp Kit cannot list them here.
|
|
608
609
|
</p>
|
|
609
|
-
<p class="sok-status-text" style="max-width: 320px;
|
|
610
|
+
<p class="sok-status-text sok-text-sm sok-op-75" style="max-width: 320px;">
|
|
610
611
|
Open the demo over http://localhost or another web server, then reload. That is the supported origin for wallet detection and connection.
|
|
611
612
|
</p>
|
|
612
613
|
</div>
|
|
@@ -624,14 +625,13 @@ export class SuiOutKitModal {
|
|
|
624
625
|
<button
|
|
625
626
|
class="sok-wallet-card"
|
|
626
627
|
data-wallet-index="${index}"
|
|
627
|
-
style="display: flex; align-items: center; gap: 14px; width: 100%; padding: 14px 16px; border-radius: 18px; border: 1px solid rgba(255,255,255,0.08); background: linear-gradient(135deg, rgba(17,24,39,0.88), rgba(15,23,42,0.96)); color: #fff; text-align: left; box-shadow: 0 18px 40px rgba(0,0,0,0.22);"
|
|
628
628
|
>
|
|
629
|
-
<img src="${icon}" alt="${walletName}" class="sok-wallet-icon"
|
|
630
|
-
<span
|
|
631
|
-
<span class="sok-wallet-name"
|
|
632
|
-
<span
|
|
629
|
+
<img src="${icon}" alt="${walletName}" class="sok-wallet-icon" />
|
|
630
|
+
<span class="sok-wallet-info">
|
|
631
|
+
<span class="sok-wallet-name">${walletName}</span>
|
|
632
|
+
<span class="sok-wallet-desc">Detected browser wallet</span>
|
|
633
633
|
</span>
|
|
634
|
-
<span
|
|
634
|
+
<span class="sok-wallet-connect">Connect</span>
|
|
635
635
|
</button>
|
|
636
636
|
`;
|
|
637
637
|
}
|
|
@@ -643,14 +643,14 @@ export class SuiOutKitModal {
|
|
|
643
643
|
container.innerHTML = `
|
|
644
644
|
<button class="suioutkit-back" id="sok-back-btn">← Back to Sui options</button>
|
|
645
645
|
<div class="suioutkit-panel">
|
|
646
|
-
<div class="sok-
|
|
646
|
+
<div class="sok-icon-wrap sok-text-amber">
|
|
647
647
|
<i data-lucide="alert-circle" style="width: 48px; height: 48px;"></i>
|
|
648
648
|
</div>
|
|
649
649
|
<h2 class="sok-success-title">No Wallets Detected</h2>
|
|
650
|
-
<p class="sok-status-text
|
|
650
|
+
<p class="sok-status-text sok-mt-16">
|
|
651
651
|
We couldn't find any installed Sui wallets. Please install a wallet extension like Phantom, Slush, or others from the app store and refresh the page.
|
|
652
652
|
</p>
|
|
653
|
-
<p class="sok-status-text
|
|
653
|
+
<p class="sok-status-text sok-text-sm sok-op-75 sok-mt-12">
|
|
654
654
|
Alternatively, you can use the outPay QR option to pay from a mobile wallet.
|
|
655
655
|
</p>
|
|
656
656
|
</div>
|
|
@@ -676,7 +676,7 @@ export class SuiOutKitModal {
|
|
|
676
676
|
<h2 class="suioutkit-title">Confirm Payment</h2>
|
|
677
677
|
<p class="suioutkit-subtitle">Review and approve this transaction</p>
|
|
678
678
|
</div>
|
|
679
|
-
<div class="suioutkit-panel"
|
|
679
|
+
<div class="suioutkit-panel">
|
|
680
680
|
<div class="sok-va-card">
|
|
681
681
|
<div class="sok-va-row">
|
|
682
682
|
<div class="sok-va-lbl">Amount</div>
|
|
@@ -691,7 +691,7 @@ export class SuiOutKitModal {
|
|
|
691
691
|
<div class="sok-va-val">${network}</div>
|
|
692
692
|
</div>
|
|
693
693
|
</div>
|
|
694
|
-
<button class="sok-btn" id="sok-confirm-pay-btn"
|
|
694
|
+
<button class="sok-btn sok-btn-green" id="sok-confirm-pay-btn">
|
|
695
695
|
Confirm & Pay
|
|
696
696
|
</button>
|
|
697
697
|
</div>
|
|
@@ -809,7 +809,7 @@ export class SuiOutKitModal {
|
|
|
809
809
|
}
|
|
810
810
|
|
|
811
811
|
const paymentUri = this.buildPaymentUri(this.cryptoIntent);
|
|
812
|
-
const qrCodeUrl =
|
|
812
|
+
const qrCodeUrl = await QRCode.toDataURL(paymentUri, { width: 180, margin: 1 });
|
|
813
813
|
|
|
814
814
|
container.innerHTML = `
|
|
815
815
|
<button class="suioutkit-back" id="sok-back-btn">← Back to Sui options</button>
|
|
@@ -823,7 +823,7 @@ export class SuiOutKitModal {
|
|
|
823
823
|
<div class="sok-qr-frame">
|
|
824
824
|
<img src="${qrCodeUrl}" alt="outPay QR Code" class="sok-qr-img" />
|
|
825
825
|
<div class="sok-qr-logo-badge">
|
|
826
|
-
<
|
|
826
|
+
<img src="${this.backendUrl}/assets/slush.jpeg" alt="Slush" style="width: 35px; height: 35px; border-radius: 16px;" />
|
|
827
827
|
</div>
|
|
828
828
|
<div class="sok-qr-scan-pulse"></div>
|
|
829
829
|
</div>
|
|
@@ -899,8 +899,9 @@ export class SuiOutKitModal {
|
|
|
899
899
|
const walrusNetworkPath = getExplorerNetworkPath();
|
|
900
900
|
|
|
901
901
|
container.innerHTML = `
|
|
902
|
+
<button class="suioutkit-back" id="sok-back-btn">← Back to methods</button>
|
|
902
903
|
<div class="suioutkit-panel">
|
|
903
|
-
<div class="sok-
|
|
904
|
+
<div class="sok-icon-wrap sok-text-green">
|
|
904
905
|
<i data-lucide="check-circle" style="width: 48px; height: 48px;"></i>
|
|
905
906
|
</div>
|
|
906
907
|
<h2 class="sok-success-title">Payment Successful!</h2>
|
|
@@ -909,7 +910,7 @@ export class SuiOutKitModal {
|
|
|
909
910
|
<div class="sok-success-details">
|
|
910
911
|
<div class="sok-receipt-row">
|
|
911
912
|
<span class="sok-receipt-lbl">Amount Paid</span>
|
|
912
|
-
<span class="sok-receipt-val" style="
|
|
913
|
+
<span class="sok-receipt-val sok-text-green" style="font-weight:700;">
|
|
913
914
|
${this.session.currency === "NGN" ? "₦" : ""}${this.session.amount.toLocaleString()}
|
|
914
915
|
</span>
|
|
915
916
|
</div>
|
|
@@ -932,6 +933,15 @@ export class SuiOutKitModal {
|
|
|
932
933
|
`;
|
|
933
934
|
|
|
934
935
|
this.renderIcons();
|
|
936
|
+
container.querySelector("#sok-back-btn")?.addEventListener("click", () => this.renderSelectionPanel());
|
|
937
|
+
|
|
938
|
+
const result: PaymentResult = { nonce: this.session.nonce, txDigest, walrusBlobId };
|
|
939
|
+
this.onPaymentCompleteCallback?.(result);
|
|
940
|
+
if (this.redirectUrl) {
|
|
941
|
+
window.location.href = this.redirectUrl;
|
|
942
|
+
} else if (this.autoCloseOnSuccess) {
|
|
943
|
+
this.destroy();
|
|
944
|
+
}
|
|
935
945
|
}
|
|
936
946
|
|
|
937
947
|
private renderErrorPanel(message: string) {
|
|
@@ -941,11 +951,11 @@ export class SuiOutKitModal {
|
|
|
941
951
|
container.innerHTML = `
|
|
942
952
|
<button class="suioutkit-back" id="sok-back-btn">← Back to methods</button>
|
|
943
953
|
<div class="suioutkit-panel">
|
|
944
|
-
<div class="sok-
|
|
954
|
+
<div class="sok-icon-wrap sok-text-red">
|
|
945
955
|
<i data-lucide="x-circle" style="width: 48px; height: 48px;"></i>
|
|
946
956
|
</div>
|
|
947
957
|
<h2 class="sok-success-title">Payment Failed</h2>
|
|
948
|
-
<p class="sok-status-text
|
|
958
|
+
<p class="sok-status-text sok-mb-20 sok-text-red">${message}</p>
|
|
949
959
|
</div>
|
|
950
960
|
`;
|
|
951
961
|
|
|
@@ -986,7 +996,7 @@ export class SuiOutKitModal {
|
|
|
986
996
|
this.overlay?.classList.remove("active");
|
|
987
997
|
setTimeout(() => {
|
|
988
998
|
this.overlay?.remove();
|
|
989
|
-
this.onCloseCallback();
|
|
999
|
+
this.onCloseCallback?.();
|
|
990
1000
|
}, 300);
|
|
991
1001
|
}
|
|
992
1002
|
}
|