@youidian/sdk 3.3.2 → 3.3.4
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/dist/client.cjs +288 -7
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +7 -2
- package/dist/client.d.ts +7 -2
- package/dist/client.js +288 -7
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +357 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +354 -8
- package/dist/index.js.map +1 -1
- package/dist/{login-CrPTh4In.d.cts → login-CoX4m-7_.d.cts} +40 -4
- package/dist/{login-CrPTh4In.d.ts → login-CoX4m-7_.d.ts} +40 -4
- package/dist/login.cjs +266 -5
- package/dist/login.cjs.map +1 -1
- package/dist/login.d.cts +1 -1
- package/dist/login.d.ts +1 -1
- package/dist/login.js +266 -5
- package/dist/login.js.map +1 -1
- package/dist/server.cjs +69 -2
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +55 -1
- package/dist/server.d.ts +55 -1
- package/dist/server.js +66 -1
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,7 +37,9 @@ __export(src_exports, {
|
|
|
37
37
|
PaymentUI: () => PaymentUI,
|
|
38
38
|
createLoginUI: () => createLoginUI,
|
|
39
39
|
createPaymentUI: () => createPaymentUI,
|
|
40
|
-
|
|
40
|
+
getCustomAmountRechargeRule: () => getCustomAmountRechargeRule,
|
|
41
|
+
handleLoginCallbackIfPresent: () => handleLoginCallbackIfPresent,
|
|
42
|
+
validateCustomAmountRecharge: () => validateCustomAmountRecharge
|
|
41
43
|
});
|
|
42
44
|
module.exports = __toCommonJS(src_exports);
|
|
43
45
|
|
|
@@ -143,8 +145,8 @@ var HostedFrameModal = class {
|
|
|
143
145
|
__publicField(this, "messageHandler", null);
|
|
144
146
|
}
|
|
145
147
|
openHostedFrame(url, options) {
|
|
146
|
-
if (typeof document === "undefined") return;
|
|
147
|
-
if (this.modal) return;
|
|
148
|
+
if (typeof document === "undefined") return null;
|
|
149
|
+
if (this.modal) return null;
|
|
148
150
|
this.modal = document.createElement("div");
|
|
149
151
|
Object.assign(this.modal.style, {
|
|
150
152
|
position: "fixed",
|
|
@@ -221,9 +223,13 @@ var HostedFrameModal = class {
|
|
|
221
223
|
if (!data || typeof data !== "object" || !data.type) {
|
|
222
224
|
return;
|
|
223
225
|
}
|
|
224
|
-
options.onMessage(data, container);
|
|
226
|
+
options.onMessage(data, container, event);
|
|
225
227
|
};
|
|
226
228
|
window.addEventListener("message", this.messageHandler);
|
|
229
|
+
return {
|
|
230
|
+
container,
|
|
231
|
+
iframe: this.iframe
|
|
232
|
+
};
|
|
227
233
|
}
|
|
228
234
|
close() {
|
|
229
235
|
if (typeof window === "undefined") return;
|
|
@@ -389,6 +395,7 @@ var LOGIN_CALLBACK_RESULT_PARAM = "yd_login_result";
|
|
|
389
395
|
var LOGIN_CALLBACK_RETURN_HASH_PARAM = "yd_login_return_hash";
|
|
390
396
|
var LOGIN_CALLBACK_STATE_PARAM = "yd_login_state";
|
|
391
397
|
var LOGIN_CALLBACK_STORAGE_PREFIX = "yd-login-callback:";
|
|
398
|
+
var DEFAULT_IFRAME_LOAD_TIMEOUT_MS = 6e3;
|
|
392
399
|
function decodeCallbackPayload(value) {
|
|
393
400
|
try {
|
|
394
401
|
const padded = value.padEnd(
|
|
@@ -516,6 +523,138 @@ function logLoginWarn(message, details) {
|
|
|
516
523
|
if (typeof console === "undefined") return;
|
|
517
524
|
console.warn(LOGIN_UI_LOG_PREFIX, message, details || {});
|
|
518
525
|
}
|
|
526
|
+
function getIframeLoadTimeoutMs(options) {
|
|
527
|
+
const timeout = options?.iframeLoadTimeoutMs;
|
|
528
|
+
if (typeof timeout !== "number" || !Number.isFinite(timeout)) {
|
|
529
|
+
return DEFAULT_IFRAME_LOAD_TIMEOUT_MS;
|
|
530
|
+
}
|
|
531
|
+
return Math.max(0, timeout);
|
|
532
|
+
}
|
|
533
|
+
function applyLoginPanelStyle(panel) {
|
|
534
|
+
Object.assign(panel.style, {
|
|
535
|
+
position: "absolute",
|
|
536
|
+
inset: "0",
|
|
537
|
+
display: "flex",
|
|
538
|
+
alignItems: "center",
|
|
539
|
+
justifyContent: "center",
|
|
540
|
+
border: "1px solid rgba(229,229,229,0.92)",
|
|
541
|
+
borderRadius: "28px",
|
|
542
|
+
background: "rgba(255,255,255,0.94)",
|
|
543
|
+
color: "#0f172a",
|
|
544
|
+
padding: "24px",
|
|
545
|
+
textAlign: "center",
|
|
546
|
+
zIndex: "1",
|
|
547
|
+
boxShadow: "0 18px 50px rgba(15,15,15,0.06)",
|
|
548
|
+
backdropFilter: "blur(16px)"
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
function createLoginPanelContent() {
|
|
552
|
+
const content = document.createElement("div");
|
|
553
|
+
Object.assign(content.style, {
|
|
554
|
+
maxWidth: "360px"
|
|
555
|
+
});
|
|
556
|
+
const badge = document.createElement("div");
|
|
557
|
+
badge.textContent = "YOUiDIAN";
|
|
558
|
+
Object.assign(badge.style, {
|
|
559
|
+
display: "inline-flex",
|
|
560
|
+
alignItems: "center",
|
|
561
|
+
border: "1px solid rgba(229,229,229,0.92)",
|
|
562
|
+
borderRadius: "9999px",
|
|
563
|
+
background: "#fafafa",
|
|
564
|
+
color: "#171717",
|
|
565
|
+
fontSize: "11px",
|
|
566
|
+
fontWeight: "700",
|
|
567
|
+
letterSpacing: "0.22em",
|
|
568
|
+
lineHeight: "1",
|
|
569
|
+
marginBottom: "18px",
|
|
570
|
+
padding: "8px 12px"
|
|
571
|
+
});
|
|
572
|
+
content.appendChild(badge);
|
|
573
|
+
return content;
|
|
574
|
+
}
|
|
575
|
+
function createLoginPanelTitle(value) {
|
|
576
|
+
const title = document.createElement("div");
|
|
577
|
+
title.textContent = value;
|
|
578
|
+
Object.assign(title.style, {
|
|
579
|
+
color: "#171717",
|
|
580
|
+
fontSize: "18px",
|
|
581
|
+
fontWeight: "700",
|
|
582
|
+
lineHeight: "1.35",
|
|
583
|
+
marginBottom: "10px"
|
|
584
|
+
});
|
|
585
|
+
return title;
|
|
586
|
+
}
|
|
587
|
+
function createLoginPanelDescription(value) {
|
|
588
|
+
const description = document.createElement("div");
|
|
589
|
+
description.textContent = value;
|
|
590
|
+
Object.assign(description.style, {
|
|
591
|
+
color: "#525252",
|
|
592
|
+
fontSize: "14px",
|
|
593
|
+
lineHeight: "1.6",
|
|
594
|
+
marginBottom: "20px"
|
|
595
|
+
});
|
|
596
|
+
return description;
|
|
597
|
+
}
|
|
598
|
+
function ensureLoginLoadingStyles() {
|
|
599
|
+
if (document.getElementById("youidian-login-loading-style")) {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
const style = document.createElement("style");
|
|
603
|
+
style.id = "youidian-login-loading-style";
|
|
604
|
+
style.textContent = "@keyframes youidian-login-spin{to{transform:rotate(360deg)}}";
|
|
605
|
+
document.head.appendChild(style);
|
|
606
|
+
}
|
|
607
|
+
function createLoginLoadingPanel(options) {
|
|
608
|
+
ensureLoginLoadingStyles();
|
|
609
|
+
const panel = document.createElement("div");
|
|
610
|
+
applyLoginPanelStyle(panel);
|
|
611
|
+
const content = createLoginPanelContent();
|
|
612
|
+
const spinner = document.createElement("div");
|
|
613
|
+
Object.assign(spinner.style, {
|
|
614
|
+
width: "22px",
|
|
615
|
+
height: "22px",
|
|
616
|
+
borderRadius: "9999px",
|
|
617
|
+
border: "2px solid rgba(23,23,23,0.16)",
|
|
618
|
+
borderTopColor: "#171717",
|
|
619
|
+
margin: "0 auto 18px",
|
|
620
|
+
animation: "youidian-login-spin 780ms linear infinite"
|
|
621
|
+
});
|
|
622
|
+
content.appendChild(spinner);
|
|
623
|
+
content.appendChild(createLoginPanelTitle(options.title));
|
|
624
|
+
content.appendChild(createLoginPanelDescription(options.description));
|
|
625
|
+
panel.appendChild(content);
|
|
626
|
+
return panel;
|
|
627
|
+
}
|
|
628
|
+
function createLoginRedirectingPanel(options) {
|
|
629
|
+
return createLoginLoadingPanel(options);
|
|
630
|
+
}
|
|
631
|
+
function createLoginFallbackPanel(options) {
|
|
632
|
+
const panel = document.createElement("div");
|
|
633
|
+
applyLoginPanelStyle(panel);
|
|
634
|
+
const content = createLoginPanelContent();
|
|
635
|
+
const button = document.createElement("button");
|
|
636
|
+
button.type = "button";
|
|
637
|
+
button.textContent = options.buttonText;
|
|
638
|
+
Object.assign(button.style, {
|
|
639
|
+
width: "100%",
|
|
640
|
+
border: "0",
|
|
641
|
+
borderRadius: "12px",
|
|
642
|
+
background: "#0a0a0a",
|
|
643
|
+
color: "#ffffff",
|
|
644
|
+
cursor: "pointer",
|
|
645
|
+
fontSize: "14px",
|
|
646
|
+
fontWeight: "700",
|
|
647
|
+
minHeight: "44px",
|
|
648
|
+
padding: "12px 16px",
|
|
649
|
+
boxShadow: "0 12px 28px rgba(17,17,17,0.14)"
|
|
650
|
+
});
|
|
651
|
+
button.onclick = options.onRedirect;
|
|
652
|
+
content.appendChild(createLoginPanelTitle(options.title));
|
|
653
|
+
content.appendChild(createLoginPanelDescription(options.description));
|
|
654
|
+
content.appendChild(button);
|
|
655
|
+
panel.appendChild(content);
|
|
656
|
+
return panel;
|
|
657
|
+
}
|
|
519
658
|
var LoginUI = class extends HostedFrameModal {
|
|
520
659
|
constructor() {
|
|
521
660
|
super(...arguments);
|
|
@@ -524,6 +663,11 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
524
663
|
__publicField(this, "callbackStorageHandler", null);
|
|
525
664
|
__publicField(this, "popupMessageHandler", null);
|
|
526
665
|
__publicField(this, "closeMonitor", null);
|
|
666
|
+
__publicField(this, "iframeFallbackPanel", null);
|
|
667
|
+
__publicField(this, "iframeLoadingPanel", null);
|
|
668
|
+
__publicField(this, "iframeLoadTimer", null);
|
|
669
|
+
__publicField(this, "iframeRedirectTimer", null);
|
|
670
|
+
__publicField(this, "iframeReady", false);
|
|
527
671
|
__publicField(this, "completed", false);
|
|
528
672
|
}
|
|
529
673
|
cleanup() {
|
|
@@ -541,11 +685,114 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
541
685
|
if (typeof window !== "undefined" && this.closeMonitor) {
|
|
542
686
|
window.clearInterval(this.closeMonitor);
|
|
543
687
|
}
|
|
688
|
+
if (typeof window !== "undefined" && this.iframeLoadTimer) {
|
|
689
|
+
window.clearTimeout(this.iframeLoadTimer);
|
|
690
|
+
}
|
|
691
|
+
if (typeof window !== "undefined" && this.iframeRedirectTimer) {
|
|
692
|
+
window.clearTimeout(this.iframeRedirectTimer);
|
|
693
|
+
}
|
|
694
|
+
if (this.iframeFallbackPanel?.parentNode) {
|
|
695
|
+
this.iframeFallbackPanel.parentNode.removeChild(this.iframeFallbackPanel);
|
|
696
|
+
}
|
|
697
|
+
if (this.iframeLoadingPanel?.parentNode) {
|
|
698
|
+
this.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel);
|
|
699
|
+
}
|
|
544
700
|
this.popupMessageHandler = null;
|
|
545
701
|
this.closeMonitor = null;
|
|
702
|
+
this.iframeFallbackPanel = null;
|
|
703
|
+
this.iframeLoadingPanel = null;
|
|
704
|
+
this.iframeLoadTimer = null;
|
|
705
|
+
this.iframeRedirectTimer = null;
|
|
706
|
+
this.iframeReady = false;
|
|
546
707
|
this.popup = null;
|
|
547
708
|
this.completed = false;
|
|
548
709
|
}
|
|
710
|
+
markIframeReady() {
|
|
711
|
+
this.iframeReady = true;
|
|
712
|
+
if (typeof window !== "undefined" && this.iframeLoadTimer) {
|
|
713
|
+
window.clearTimeout(this.iframeLoadTimer);
|
|
714
|
+
this.iframeLoadTimer = null;
|
|
715
|
+
}
|
|
716
|
+
if (typeof window !== "undefined" && this.iframeRedirectTimer) {
|
|
717
|
+
window.clearTimeout(this.iframeRedirectTimer);
|
|
718
|
+
this.iframeRedirectTimer = null;
|
|
719
|
+
}
|
|
720
|
+
if (this.iframeFallbackPanel?.parentNode) {
|
|
721
|
+
this.iframeFallbackPanel.parentNode.removeChild(this.iframeFallbackPanel);
|
|
722
|
+
}
|
|
723
|
+
if (this.iframeLoadingPanel?.parentNode) {
|
|
724
|
+
this.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel);
|
|
725
|
+
}
|
|
726
|
+
this.iframeFallbackPanel = null;
|
|
727
|
+
this.iframeLoadingPanel = null;
|
|
728
|
+
}
|
|
729
|
+
showIframeLoading(container, options) {
|
|
730
|
+
if (this.iframeLoadingPanel || this.iframeReady) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const panel = createLoginLoadingPanel({
|
|
734
|
+
description: options?.loadingDescription || "Please wait while the secure login page opens.",
|
|
735
|
+
title: options?.loadingTitle || "Opening login page"
|
|
736
|
+
});
|
|
737
|
+
this.iframeLoadingPanel = panel;
|
|
738
|
+
container.appendChild(panel);
|
|
739
|
+
}
|
|
740
|
+
showIframeFallback(options) {
|
|
741
|
+
if (this.iframeReady || this.iframeFallbackPanel) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
const { container, finalUrl, launchPayload, loginOptions } = options;
|
|
745
|
+
logLoginWarn("Hosted login iframe did not report ready in time", {
|
|
746
|
+
loginUrl: finalUrl
|
|
747
|
+
});
|
|
748
|
+
if (this.iframeLoadingPanel?.parentNode) {
|
|
749
|
+
this.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel);
|
|
750
|
+
}
|
|
751
|
+
this.iframeLoadingPanel = null;
|
|
752
|
+
if (loginOptions?.fallbackRedirectMode !== "manual") {
|
|
753
|
+
const panel2 = createLoginRedirectingPanel({
|
|
754
|
+
description: loginOptions?.fallbackDescription || "The embedded login page is taking longer than expected. Redirecting you to the login page now.",
|
|
755
|
+
title: loginOptions?.fallbackTitle || "Redirecting to login page"
|
|
756
|
+
});
|
|
757
|
+
this.iframeFallbackPanel = panel2;
|
|
758
|
+
container.appendChild(panel2);
|
|
759
|
+
loginOptions?.onFallbackVisible?.();
|
|
760
|
+
this.iframeRedirectTimer = window.setTimeout(() => {
|
|
761
|
+
this.iframeRedirectTimer = null;
|
|
762
|
+
logLoginInfo("Redirecting to hosted login fallback page", {
|
|
763
|
+
loginUrl: finalUrl
|
|
764
|
+
});
|
|
765
|
+
window.location.assign(finalUrl);
|
|
766
|
+
}, 350);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
const panel = createLoginFallbackPanel({
|
|
770
|
+
buttonText: loginOptions?.fallbackButtonText || "Continue to login",
|
|
771
|
+
description: loginOptions?.fallbackDescription || "The embedded login page is taking longer than expected. Continue on the login page to finish signing in.",
|
|
772
|
+
title: loginOptions?.fallbackTitle || "Login page is still loading",
|
|
773
|
+
onRedirect: () => {
|
|
774
|
+
logLoginInfo("Redirecting to hosted login fallback page", {
|
|
775
|
+
loginUrl: finalUrl
|
|
776
|
+
});
|
|
777
|
+
window.location.assign(finalUrl);
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
this.iframeFallbackPanel = panel;
|
|
781
|
+
container.appendChild(panel);
|
|
782
|
+
loginOptions?.onFallbackVisible?.();
|
|
783
|
+
}
|
|
784
|
+
startIframeWatchdog(options) {
|
|
785
|
+
if (typeof window === "undefined") return;
|
|
786
|
+
const timeoutMs = getIframeLoadTimeoutMs(options.loginOptions);
|
|
787
|
+
if (timeoutMs === 0) {
|
|
788
|
+
this.showIframeFallback(options);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
this.iframeLoadTimer = window.setTimeout(() => {
|
|
792
|
+
this.iframeLoadTimer = null;
|
|
793
|
+
this.showIframeFallback(options);
|
|
794
|
+
}, timeoutMs);
|
|
795
|
+
}
|
|
549
796
|
handleLoginEvent(data, options) {
|
|
550
797
|
if (!data || typeof data !== "object" || !data.type) {
|
|
551
798
|
logLoginDebug("Ignored non-login event payload");
|
|
@@ -555,6 +802,8 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
555
802
|
type: data.type
|
|
556
803
|
});
|
|
557
804
|
switch (data.type) {
|
|
805
|
+
case "LOGIN_READY":
|
|
806
|
+
break;
|
|
558
807
|
case "LOGIN_SUCCESS":
|
|
559
808
|
if (this.completed) {
|
|
560
809
|
break;
|
|
@@ -662,15 +911,20 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
662
911
|
parentOrigin: launchPayload.origin || null
|
|
663
912
|
});
|
|
664
913
|
this.completed = false;
|
|
914
|
+
this.iframeReady = false;
|
|
665
915
|
this.listenForLoginCallback(callbackState, options);
|
|
666
|
-
this.openHostedFrame(finalUrl, {
|
|
916
|
+
const hostedFrame = this.openHostedFrame(finalUrl, {
|
|
667
917
|
allowedOrigin: options?.allowedOrigin || loginOrigin || void 0,
|
|
668
918
|
height: "min(760px, 94vh)",
|
|
669
919
|
onCloseButton: () => {
|
|
670
920
|
options?.onCancel?.();
|
|
671
921
|
options?.onClose?.();
|
|
672
922
|
},
|
|
673
|
-
onMessage: (data, container) => {
|
|
923
|
+
onMessage: (data, container, event) => {
|
|
924
|
+
const isIframeEvent = event.source === this.iframe?.contentWindow;
|
|
925
|
+
if (isIframeEvent && (data.type === "LOGIN_READY" || data.type === "LOGIN_RESIZE") || data.type === "LOGIN_SUCCESS" || data.type === "LOGIN_ERROR") {
|
|
926
|
+
this.markIframeReady();
|
|
927
|
+
}
|
|
674
928
|
if (data.type === "LOGIN_RESIZE" && data.height) {
|
|
675
929
|
const maxHeight = window.innerHeight * 0.94;
|
|
676
930
|
container.style.height = `${Math.min(data.height, maxHeight)}px`;
|
|
@@ -679,6 +933,15 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
679
933
|
},
|
|
680
934
|
width: "min(520px, 100%)"
|
|
681
935
|
});
|
|
936
|
+
if (hostedFrame) {
|
|
937
|
+
this.showIframeLoading(hostedFrame.container, options);
|
|
938
|
+
this.startIframeWatchdog({
|
|
939
|
+
container: hostedFrame.container,
|
|
940
|
+
finalUrl,
|
|
941
|
+
launchPayload,
|
|
942
|
+
loginOptions: options
|
|
943
|
+
});
|
|
944
|
+
}
|
|
682
945
|
}
|
|
683
946
|
openLoginPopup(params, options) {
|
|
684
947
|
if (typeof window === "undefined") return;
|
|
@@ -808,14 +1071,34 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
808
1071
|
priceId,
|
|
809
1072
|
productCode,
|
|
810
1073
|
userId,
|
|
1074
|
+
customAmount,
|
|
811
1075
|
checkoutUrl: checkoutUrlParam,
|
|
812
1076
|
baseUrl = "https://pay.imgto.link"
|
|
813
1077
|
} = urlOrParams;
|
|
814
1078
|
const base = (checkoutUrlParam || baseUrl).replace(/\/$/, "");
|
|
1079
|
+
const query = new URLSearchParams({
|
|
1080
|
+
userId
|
|
1081
|
+
});
|
|
1082
|
+
if (customAmount) {
|
|
1083
|
+
const amount = Number(customAmount.amount);
|
|
1084
|
+
const currency = customAmount.currency.trim().toUpperCase();
|
|
1085
|
+
if (!Number.isInteger(amount) || amount <= 0) {
|
|
1086
|
+
throw new Error(
|
|
1087
|
+
"customAmount.amount must be a positive integer in the smallest currency unit"
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
if (!/^[A-Z]{3}$/.test(currency)) {
|
|
1091
|
+
throw new Error(
|
|
1092
|
+
"customAmount.currency must be a 3-letter currency code"
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
query.set("customAmount", String(amount));
|
|
1096
|
+
query.set("customCurrency", currency);
|
|
1097
|
+
}
|
|
815
1098
|
if (productCode) {
|
|
816
|
-
checkoutUrl = `${base}/checkout/${appId}/code/${productCode}
|
|
1099
|
+
checkoutUrl = `${base}/checkout/${appId}/code/${productCode}?${query.toString()}`;
|
|
817
1100
|
} else if (productId && priceId) {
|
|
818
|
-
checkoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}
|
|
1101
|
+
checkoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?${query.toString()}`;
|
|
819
1102
|
} else {
|
|
820
1103
|
throw new Error(
|
|
821
1104
|
"Either productCode or both productId and priceId are required"
|
|
@@ -902,6 +1185,69 @@ function createPaymentUI() {
|
|
|
902
1185
|
|
|
903
1186
|
// src/server.ts
|
|
904
1187
|
var import_crypto = __toESM(require("crypto"), 1);
|
|
1188
|
+
function getCustomAmountRechargeRule(product, currency) {
|
|
1189
|
+
if (!product || product.type !== "CREDIT") return null;
|
|
1190
|
+
const normalizedCurrency = currency.trim().toUpperCase();
|
|
1191
|
+
if (!/^[A-Z]{3}$/.test(normalizedCurrency)) return null;
|
|
1192
|
+
const customAmount = product.metadata?.customAmount;
|
|
1193
|
+
if (customAmount?.enabled !== true) return null;
|
|
1194
|
+
const currencyConfig = customAmount.currencies?.[normalizedCurrency];
|
|
1195
|
+
if (!currencyConfig) return null;
|
|
1196
|
+
const minimumGrantAmount = currencyConfig.unitsPerCurrencyUnitBasis === "MAJOR" ? Math.ceil(50 / currencyConfig.unitsPerCurrencyUnit) : Math.ceil(1 / currencyConfig.unitsPerCurrencyUnit);
|
|
1197
|
+
let minAmount = Math.max(currencyConfig.minAmount, minimumGrantAmount);
|
|
1198
|
+
if (currencyConfig.stepAmount && minAmount > currencyConfig.minAmount) {
|
|
1199
|
+
const stepCount = Math.ceil(
|
|
1200
|
+
(minAmount - currencyConfig.minAmount) / currencyConfig.stepAmount
|
|
1201
|
+
);
|
|
1202
|
+
minAmount = currencyConfig.minAmount + stepCount * currencyConfig.stepAmount;
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
...currencyConfig,
|
|
1206
|
+
productId: product.id,
|
|
1207
|
+
productCode: product.code,
|
|
1208
|
+
entitlementKey: customAmount.entitlementKey,
|
|
1209
|
+
currency: normalizedCurrency,
|
|
1210
|
+
configuredMinAmount: currencyConfig.minAmount,
|
|
1211
|
+
minimumGrantAmount,
|
|
1212
|
+
minAmount
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
function validateCustomAmountRecharge(product, customAmount) {
|
|
1216
|
+
const rule = getCustomAmountRechargeRule(product, customAmount.currency);
|
|
1217
|
+
if (!rule) {
|
|
1218
|
+
return {
|
|
1219
|
+
valid: false,
|
|
1220
|
+
code: "CUSTOM_AMOUNT_UNAVAILABLE",
|
|
1221
|
+
error: "Product does not support custom amount recharge for this currency."
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
const amount = Number(customAmount.amount);
|
|
1225
|
+
if (!Number.isInteger(amount) || amount <= 0) {
|
|
1226
|
+
return {
|
|
1227
|
+
valid: false,
|
|
1228
|
+
code: "CUSTOM_AMOUNT_INVALID_AMOUNT",
|
|
1229
|
+
error: "Custom amount must be a positive integer in the smallest currency unit.",
|
|
1230
|
+
rule
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
if (amount < rule.minAmount || amount > rule.maxAmount) {
|
|
1234
|
+
return {
|
|
1235
|
+
valid: false,
|
|
1236
|
+
code: "CUSTOM_AMOUNT_OUT_OF_RANGE",
|
|
1237
|
+
error: `Custom amount must be between ${rule.minAmount} and ${rule.maxAmount}.`,
|
|
1238
|
+
rule
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
if (rule.stepAmount && (amount - rule.configuredMinAmount) % rule.stepAmount !== 0) {
|
|
1242
|
+
return {
|
|
1243
|
+
valid: false,
|
|
1244
|
+
code: "CUSTOM_AMOUNT_INVALID_STEP",
|
|
1245
|
+
error: `Custom amount must follow step ${rule.stepAmount}.`,
|
|
1246
|
+
rule
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
return { valid: true, rule };
|
|
1250
|
+
}
|
|
905
1251
|
var PaymentClient = class {
|
|
906
1252
|
// 用于生成 checkout URL
|
|
907
1253
|
constructor(options) {
|
|
@@ -1194,6 +1540,8 @@ var PaymentClient = class {
|
|
|
1194
1540
|
PaymentUI,
|
|
1195
1541
|
createLoginUI,
|
|
1196
1542
|
createPaymentUI,
|
|
1197
|
-
|
|
1543
|
+
getCustomAmountRechargeRule,
|
|
1544
|
+
handleLoginCallbackIfPresent,
|
|
1545
|
+
validateCustomAmountRecharge
|
|
1198
1546
|
});
|
|
1199
1547
|
//# sourceMappingURL=index.cjs.map
|