@youidian/sdk 3.2.2 → 3.3.0
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 +80 -13
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/client.js +80 -13
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +118 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +118 -14
- package/dist/index.js.map +1 -1
- package/dist/{login-zl_PRUh9.d.cts → login-CrPTh4In.d.cts} +21 -6
- package/dist/{login-zl_PRUh9.d.ts → login-CrPTh4In.d.ts} +21 -6
- package/dist/login.cjs +177 -12
- 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 +177 -12
- package/dist/login.js.map +1 -1
- package/dist/server.cjs +38 -1
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +47 -1
- package/dist/server.d.ts +47 -1
- package/dist/server.js +38 -1
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/client.cjs
CHANGED
|
@@ -361,6 +361,11 @@ function extractLoginResult(data) {
|
|
|
361
361
|
legacyCasdoorId: data.legacyCasdoorId,
|
|
362
362
|
loginToken: data.loginToken,
|
|
363
363
|
name: data.name,
|
|
364
|
+
username: data.username,
|
|
365
|
+
phoneCountryCode: data.phoneCountryCode,
|
|
366
|
+
phoneNumber: data.phoneNumber,
|
|
367
|
+
phoneE164: data.phoneE164,
|
|
368
|
+
phoneVerifiedAt: data.phoneVerifiedAt,
|
|
364
369
|
userId: data.userId,
|
|
365
370
|
wechatOpenId: data.wechatOpenId,
|
|
366
371
|
wechatUnionId: data.wechatUnionId
|
|
@@ -499,12 +504,13 @@ function logLoginWarn(message, details) {
|
|
|
499
504
|
if (typeof console === "undefined") return;
|
|
500
505
|
console.warn(LOGIN_UI_LOG_PREFIX, message, details || {});
|
|
501
506
|
}
|
|
502
|
-
var LoginUI = class {
|
|
507
|
+
var LoginUI = class extends HostedFrameModal {
|
|
503
508
|
constructor() {
|
|
509
|
+
super(...arguments);
|
|
504
510
|
__publicField(this, "popup", null);
|
|
505
511
|
__publicField(this, "callbackChannel", null);
|
|
506
512
|
__publicField(this, "callbackStorageHandler", null);
|
|
507
|
-
__publicField(this, "
|
|
513
|
+
__publicField(this, "popupMessageHandler", null);
|
|
508
514
|
__publicField(this, "closeMonitor", null);
|
|
509
515
|
__publicField(this, "completed", false);
|
|
510
516
|
}
|
|
@@ -515,15 +521,15 @@ var LoginUI = class {
|
|
|
515
521
|
if (typeof window !== "undefined" && this.callbackStorageHandler) {
|
|
516
522
|
window.removeEventListener("storage", this.callbackStorageHandler);
|
|
517
523
|
}
|
|
518
|
-
if (typeof window !== "undefined" && this.
|
|
519
|
-
window.removeEventListener("message", this.
|
|
524
|
+
if (typeof window !== "undefined" && this.popupMessageHandler) {
|
|
525
|
+
window.removeEventListener("message", this.popupMessageHandler);
|
|
520
526
|
}
|
|
521
527
|
this.callbackChannel = null;
|
|
522
528
|
this.callbackStorageHandler = null;
|
|
523
529
|
if (typeof window !== "undefined" && this.closeMonitor) {
|
|
524
530
|
window.clearInterval(this.closeMonitor);
|
|
525
531
|
}
|
|
526
|
-
this.
|
|
532
|
+
this.popupMessageHandler = null;
|
|
527
533
|
this.closeMonitor = null;
|
|
528
534
|
this.popup = null;
|
|
529
535
|
this.completed = false;
|
|
@@ -566,12 +572,12 @@ var LoginUI = class {
|
|
|
566
572
|
case "LOGIN_CLOSE":
|
|
567
573
|
if (options?.autoClose === false) {
|
|
568
574
|
logLoginInfo(
|
|
569
|
-
"Login
|
|
575
|
+
"Login surface requested close; autoClose disabled, keeping it open"
|
|
570
576
|
);
|
|
571
577
|
options?.onClose?.();
|
|
572
578
|
break;
|
|
573
579
|
}
|
|
574
|
-
logLoginInfo("Login
|
|
580
|
+
logLoginInfo("Login surface requested close; autoClose enabled");
|
|
575
581
|
this.close();
|
|
576
582
|
options?.onClose?.();
|
|
577
583
|
break;
|
|
@@ -605,15 +611,15 @@ var LoginUI = class {
|
|
|
605
611
|
}
|
|
606
612
|
close() {
|
|
607
613
|
logLoginInfo("close() called", {
|
|
614
|
+
hasModal: Boolean(this.modal),
|
|
608
615
|
hasPopup: Boolean(this.popup),
|
|
609
616
|
popupClosed: safeIsPopupClosed(this.popup)
|
|
610
617
|
});
|
|
611
618
|
safeClosePopup(this.popup);
|
|
619
|
+
super.close();
|
|
612
620
|
this.cleanup();
|
|
613
621
|
}
|
|
614
|
-
|
|
615
|
-
if (typeof window === "undefined") return;
|
|
616
|
-
if (this.popup && !safeIsPopupClosed(this.popup)) return;
|
|
622
|
+
buildOpenContext(params, options) {
|
|
617
623
|
const callbackState = createLoginCallbackState();
|
|
618
624
|
const launchPayload = buildLoginLaunchPayload(
|
|
619
625
|
params,
|
|
@@ -621,6 +627,54 @@ var LoginUI = class {
|
|
|
621
627
|
callbackState
|
|
622
628
|
);
|
|
623
629
|
const finalUrl = buildLoginUrl(params, options, launchPayload);
|
|
630
|
+
return { callbackState, finalUrl, launchPayload };
|
|
631
|
+
}
|
|
632
|
+
openLoginModal(params, options) {
|
|
633
|
+
if (typeof document === "undefined") return;
|
|
634
|
+
if (this.modal) return;
|
|
635
|
+
const { callbackState, finalUrl, launchPayload } = this.buildOpenContext(
|
|
636
|
+
params,
|
|
637
|
+
options
|
|
638
|
+
);
|
|
639
|
+
const loginOrigin = getOrigin(finalUrl);
|
|
640
|
+
logLoginInfo("Opening hosted login iframe modal", {
|
|
641
|
+
appId: params.appId,
|
|
642
|
+
callbackState,
|
|
643
|
+
callbackUrl: launchPayload.callbackUrl || null,
|
|
644
|
+
hasCallbackUrl: Boolean(launchPayload.callbackUrl),
|
|
645
|
+
loginUrl: finalUrl,
|
|
646
|
+
allowedOrigin: options?.allowedOrigin || null,
|
|
647
|
+
autoClose: options?.autoClose ?? true,
|
|
648
|
+
displayMode: "modal",
|
|
649
|
+
pageUrl: typeof window !== "undefined" ? window.location.href : null,
|
|
650
|
+
parentOrigin: launchPayload.origin || null
|
|
651
|
+
});
|
|
652
|
+
this.completed = false;
|
|
653
|
+
this.listenForLoginCallback(callbackState, options);
|
|
654
|
+
this.openHostedFrame(finalUrl, {
|
|
655
|
+
allowedOrigin: options?.allowedOrigin || loginOrigin || void 0,
|
|
656
|
+
height: "min(760px, 94vh)",
|
|
657
|
+
onCloseButton: () => {
|
|
658
|
+
options?.onCancel?.();
|
|
659
|
+
options?.onClose?.();
|
|
660
|
+
},
|
|
661
|
+
onMessage: (data, container) => {
|
|
662
|
+
if (data.type === "LOGIN_RESIZE" && data.height) {
|
|
663
|
+
const maxHeight = window.innerHeight * 0.94;
|
|
664
|
+
container.style.height = `${Math.min(data.height, maxHeight)}px`;
|
|
665
|
+
}
|
|
666
|
+
this.handleLoginEvent(data, options);
|
|
667
|
+
},
|
|
668
|
+
width: "min(520px, 100%)"
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
openLoginPopup(params, options) {
|
|
672
|
+
if (typeof window === "undefined") return;
|
|
673
|
+
if (this.popup && !safeIsPopupClosed(this.popup)) return;
|
|
674
|
+
const { callbackState, finalUrl, launchPayload } = this.buildOpenContext(
|
|
675
|
+
params,
|
|
676
|
+
options
|
|
677
|
+
);
|
|
624
678
|
logLoginInfo("Opening hosted login popup", {
|
|
625
679
|
appId: params.appId,
|
|
626
680
|
callbackState,
|
|
@@ -629,6 +683,7 @@ var LoginUI = class {
|
|
|
629
683
|
loginUrl: finalUrl,
|
|
630
684
|
allowedOrigin: options?.allowedOrigin || null,
|
|
631
685
|
autoClose: options?.autoClose ?? true,
|
|
686
|
+
displayMode: "popup",
|
|
632
687
|
pageUrl: typeof window !== "undefined" ? window.location.href : null,
|
|
633
688
|
parentOrigin: launchPayload.origin || null
|
|
634
689
|
});
|
|
@@ -663,7 +718,7 @@ var LoginUI = class {
|
|
|
663
718
|
this.listenForLoginCallback(callbackState, options);
|
|
664
719
|
const allowedOrigin = options?.allowedOrigin;
|
|
665
720
|
const popupOrigin = getOrigin(finalUrl);
|
|
666
|
-
this.
|
|
721
|
+
this.popupMessageHandler = (event) => {
|
|
667
722
|
if (allowedOrigin && allowedOrigin !== "*" && event.origin !== allowedOrigin) {
|
|
668
723
|
logLoginWarn("Ignored message due to allowedOrigin mismatch", {
|
|
669
724
|
allowedOrigin,
|
|
@@ -689,7 +744,7 @@ var LoginUI = class {
|
|
|
689
744
|
});
|
|
690
745
|
this.handleLoginEvent(data, options);
|
|
691
746
|
};
|
|
692
|
-
window.addEventListener("message", this.
|
|
747
|
+
window.addEventListener("message", this.popupMessageHandler);
|
|
693
748
|
if (options?.monitorPopupClosed === true) {
|
|
694
749
|
this.closeMonitor = window.setInterval(() => {
|
|
695
750
|
if (!this.popup || safeIsPopupClosed(this.popup)) {
|
|
@@ -706,6 +761,15 @@ var LoginUI = class {
|
|
|
706
761
|
}, 500);
|
|
707
762
|
}
|
|
708
763
|
}
|
|
764
|
+
openLogin(params, options) {
|
|
765
|
+
if (typeof window === "undefined") return;
|
|
766
|
+
const displayMode = options?.displayMode ?? "modal";
|
|
767
|
+
if (displayMode === "popup") {
|
|
768
|
+
this.openLoginPopup(params, options);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
this.openLoginModal(params, options);
|
|
772
|
+
}
|
|
709
773
|
};
|
|
710
774
|
function createLoginUI() {
|
|
711
775
|
return new LoginUI();
|
|
@@ -746,7 +810,10 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
746
810
|
);
|
|
747
811
|
}
|
|
748
812
|
}
|
|
749
|
-
const finalUrl = applyLocaleToUrl(
|
|
813
|
+
const finalUrl = applyLocaleToUrl(
|
|
814
|
+
checkoutUrl,
|
|
815
|
+
getAutoResolvedLocale(options?.locale)
|
|
816
|
+
);
|
|
750
817
|
this.openHostedFrame(finalUrl, {
|
|
751
818
|
allowedOrigin: options?.allowedOrigin,
|
|
752
819
|
onCloseButton: () => options?.onCancel?.(),
|
package/dist/client.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/hosted-modal.ts","../src/login.ts"],"sourcesContent":["/**\n * Youidian Payment SDK - Client Module\n * 用于浏览器端集成,包含支付弹窗、状态轮询等功能\n * 不依赖 Node.js crypto 模块\n */\n\nimport { applyLocaleToUrl, HostedFrameModal } from \"./hosted-modal\"\n\n/**\n * Payment event types from checkout pages\n */\nexport type PaymentEventType =\n\t| \"PAYMENT_SUCCESS\"\n\t| \"PAYMENT_CANCELLED\"\n\t| \"PAYMENT_CLOSE\"\n\t| \"PAYMENT_RESIZE\"\n\n/**\n * Payment event data from postMessage\n */\nexport interface PaymentEventData {\n\ttype: PaymentEventType\n\torderId?: string\n\theight?: number\n}\n\n/**\n * Order status response\n */\nexport interface OrderStatus {\n\torderId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\n/**\n * Payment UI Options\n */\nexport interface PaymentUIOptions {\n\tlocale?: string\n\tonSuccess?: (orderId?: string) => void\n\tonCancel?: (orderId?: string) => void\n\tonClose?: () => void\n\t/** Origin to validate postMessage (defaults to '*', set for security) */\n\tallowedOrigin?: string\n}\n\n/**\n * Poll Options\n */\nexport interface PollOptions {\n\t/** Polling interval in ms (default: 3000) */\n\tinterval?: number\n\t/** Timeout in ms (default: 300000 = 5 minutes) */\n\ttimeout?: number\n\t/** Callback on each status check */\n\tonStatusChange?: (status: OrderStatus) => void\n}\n\n/**\n * Client-side Payment UI Helper\n * 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态\n */\n/**\n * Params for opening payment directly without manual URL construction\n */\nexport interface PaymentParams {\n\tappId: string\n\tuserId: string\n\t/** Product ID - use with priceId for direct ID-based payment */\n\tproductId?: string\n\t/** Price ID - use with productId for direct ID-based payment */\n\tpriceId?: string\n\t/** Product code - use with locale for code-based payment (alternative to productId/priceId) */\n\tproductCode?: string\n\n\t/**\n\t * @deprecated Use checkoutUrl instead\n\t * Defaults to https://pay.imgto.link\n\t */\n\tbaseUrl?: string\n\n\t/**\n\t * Checkout page URL (e.g. https://pay.youidian.com)\n\t * Defaults to https://pay.imgto.link\n\t */\n\tcheckoutUrl?: string\n}\n\n/**\n * Client-side Payment UI Helper\n * 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态\n */\nexport class PaymentUI extends HostedFrameModal<PaymentEventData> {\n\t/**\n\t * Opens the payment checkout page in an iframe modal.\n\t * @param urlOrParams - The checkout page URL or payment parameters\n\t * @param options - UI options\n\t */\n\topenPayment(urlOrParams: string | PaymentParams, options?: PaymentUIOptions) {\n\t\tif (typeof document === \"undefined\") return // Server-side guard\n\t\tif (this.modal) return // Prevent multiple modals\n\n\t\tlet checkoutUrl: string\n\t\tif (typeof urlOrParams === \"string\") {\n\t\t\tcheckoutUrl = urlOrParams\n\t\t} else {\n\t\t\tconst {\n\t\t\t\tappId,\n\t\t\t\tproductId,\n\t\t\t\tpriceId,\n\t\t\t\tproductCode,\n\t\t\t\tuserId,\n\t\t\t\tcheckoutUrl: checkoutUrlParam,\n\t\t\t\tbaseUrl = \"https://pay.imgto.link\",\n\t\t\t} = urlOrParams\n\n\t\t\t// 优先使用 checkoutUrl,其次 baseUrl,默认 https://pay.imgto.link\n\t\t\tconst base = (checkoutUrlParam || baseUrl).replace(/\\/$/, \"\")\n\n\t\t\tif (productCode) {\n\t\t\t\t// Use product code route\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/code/${productCode}?userId=${encodeURIComponent(userId)}`\n\t\t\t} else if (productId && priceId) {\n\t\t\t\t// Use ID-based route\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?userId=${encodeURIComponent(userId)}`\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Either productCode or both productId and priceId are required\",\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconst finalUrl = applyLocaleToUrl(checkoutUrl, options?.locale)\n\n\t\tthis.openHostedFrame(finalUrl, {\n\t\t\tallowedOrigin: options?.allowedOrigin,\n\t\t\tonCloseButton: () => options?.onCancel?.(),\n\t\t\tonMessage: (data, container) => {\n\t\t\t\tswitch (data.type) {\n\t\t\t\t\tcase \"PAYMENT_SUCCESS\":\n\t\t\t\t\t\toptions?.onSuccess?.(data.orderId)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_CANCELLED\":\n\t\t\t\t\t\toptions?.onCancel?.(data.orderId)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_RESIZE\":\n\t\t\t\t\t\tif (data.height) {\n\t\t\t\t\t\t\tconst maxHeight = window.innerHeight * 0.9\n\t\t\t\t\t\t\tconst newHeight = Math.min(data.height, maxHeight)\n\t\t\t\t\t\t\tcontainer.style.height = `${newHeight}px`\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_CLOSE\":\n\t\t\t\t\t\tthis.close()\n\t\t\t\t\t\toptions?.onClose?.()\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t}\n\n\t/**\n\t * Poll order status from integrator's API endpoint\n\t * @param statusUrl - The integrator's API endpoint to check order status\n\t * @param options - Polling options\n\t * @returns Promise that resolves when order is paid or rejects on timeout/failure\n\t */\n\tasync pollOrderStatus(\n\t\tstatusUrl: string,\n\t\toptions?: PollOptions,\n\t): Promise<OrderStatus> {\n\t\tconst interval = options?.interval || 3000\n\t\tconst timeout = options?.timeout || 300000\n\t\tconst startTime = Date.now()\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst poll = async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst response = await fetch(statusUrl)\n\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\tthrow new Error(`Status check failed: ${response.status}`)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst status: OrderStatus = await response.json()\n\t\t\t\t\toptions?.onStatusChange?.(status)\n\n\t\t\t\t\tif (status.status === \"PAID\") {\n\t\t\t\t\t\tresolve(status)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tif (status.status === \"CANCELLED\" || status.status === \"FAILED\") {\n\t\t\t\t\t\treject(new Error(`Order ${status.status.toLowerCase()}`))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(new Error(\"Polling timeout\"))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Continue polling\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// On network error, continue polling unless timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(error)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpoll()\n\t\t})\n\t}\n}\n\n/**\n * Convenience function to create a PaymentUI instance\n */\nexport function createPaymentUI(): PaymentUI {\n\treturn new PaymentUI()\n}\n\nexport type {\n\tLoginCallbackOptions,\n\tLoginEventData,\n\tLoginEventType,\n\tLoginParams,\n\tLoginResult,\n\tLoginUIOptions,\n} from \"./login\"\nexport { createLoginUI, handleLoginCallbackIfPresent, LoginUI } from \"./login\"\n","export interface HostedFrameMessage {\n\ttype: string\n\theight?: number\n}\n\ntype HostedFrameOptions<TData extends HostedFrameMessage> = {\n\tallowedOrigin?: string\n\theight?: string\n\tonCloseButton?: () => void\n\tonMessage: (data: TData, container: HTMLDivElement) => void\n\twidth?: string\n}\n\nconst SDK_SUPPORTED_LOCALES = [\n\t\"en\",\n\t\"zh-CN\",\n\t\"zh-Hant\",\n\t\"fr\",\n\t\"de\",\n\t\"ja\",\n\t\"es\",\n\t\"ko\",\n\t\"nl\",\n\t\"it\",\n\t\"pt\",\n] as const\n\nconst SDK_DEFAULT_LOCALE = \"zh-CN\"\n\nconst SDK_LOCALE_ALIASES: Record<string, string> = {\n\ten: \"en\",\n\t\"en-us\": \"en\",\n\t\"en-gb\": \"en\",\n\tzh: \"zh-CN\",\n\t\"zh-cn\": \"zh-CN\",\n\t\"zh-tw\": \"zh-Hant\",\n\t\"zh-hk\": \"zh-Hant\",\n\t\"zh-hant\": \"zh-Hant\",\n\t\"zh-hans\": \"zh-CN\",\n\tfr: \"fr\",\n\tde: \"de\",\n\tja: \"ja\",\n\tes: \"es\",\n\tko: \"ko\",\n\tnl: \"nl\",\n\tit: \"it\",\n\tpt: \"pt\",\n}\n\nfunction matchSupportedBaseLocale(locale: string): string | undefined {\n\tconst base = locale.toLowerCase().split(\"-\")[0]\n\treturn SDK_SUPPORTED_LOCALES.find((item) => item.toLowerCase() === base)\n}\n\nexport function normalizeSdkLocale(locale?: string): string | undefined {\n\tif (!locale) return\n\n\tconst sanitized = locale.trim().replace(/_/g, \"-\")\n\tif (!sanitized) return\n\n\tconst lower = sanitized.toLowerCase()\n\tif (SDK_LOCALE_ALIASES[lower]) {\n\t\treturn SDK_LOCALE_ALIASES[lower]\n\t}\n\n\tlet canonical: string | undefined\n\ttry {\n\t\tcanonical = Intl.getCanonicalLocales(sanitized)[0]\n\t} catch {\n\t\tcanonical = undefined\n\t}\n\n\tconst candidates = [canonical, sanitized].filter(Boolean) as string[]\n\n\tfor (const candidate of candidates) {\n\t\tconst candidateLower = candidate.toLowerCase()\n\n\t\tif (SDK_LOCALE_ALIASES[candidateLower]) {\n\t\t\treturn SDK_LOCALE_ALIASES[candidateLower]\n\t\t}\n\t\tif ((SDK_SUPPORTED_LOCALES as readonly string[]).includes(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\n\t\tconst baseMatch = matchSupportedBaseLocale(candidate)\n\t\tif (baseMatch) {\n\t\t\treturn baseMatch\n\t\t}\n\t}\n}\n\nexport function getBrowserLocale(): string | undefined {\n\tif (typeof navigator === \"undefined\") return\n\n\tfor (const candidate of navigator.languages || []) {\n\t\tconst normalized = normalizeSdkLocale(candidate)\n\t\tif (normalized) return normalized\n\t}\n\n\treturn normalizeSdkLocale(navigator.language)\n}\n\nexport function getAutoResolvedLocale(locale?: string): string {\n\treturn normalizeSdkLocale(locale) || getBrowserLocale() || SDK_DEFAULT_LOCALE\n}\n\nexport function applyLocaleToUrl(urlValue: string, locale?: string): string {\n\tif (!locale) return urlValue\n\n\ttry {\n\t\tconst url = new URL(urlValue)\n\t\tconst localePrefix = `/${locale}`\n\t\tif (\n\t\t\t!url.pathname.startsWith(`${localePrefix}/`) &&\n\t\t\turl.pathname !== localePrefix\n\t\t) {\n\t\t\turl.pathname = `${localePrefix}${url.pathname}`\n\t\t}\n\t\treturn url.toString()\n\t} catch (_error) {\n\t\tconst localePrefix = `/${locale}`\n\t\tif (!urlValue.startsWith(`${localePrefix}/`) && urlValue !== localePrefix) {\n\t\t\treturn `${localePrefix}${urlValue.startsWith(\"/\") ? \"\" : \"/\"}${urlValue}`\n\t\t}\n\t\treturn urlValue\n\t}\n}\n\nexport class HostedFrameModal<TData extends HostedFrameMessage> {\n\tprotected iframe: HTMLIFrameElement | null = null\n\tprotected modal: HTMLDivElement | null = null\n\tprotected messageHandler: ((event: MessageEvent) => void) | null = null\n\n\tprotected openHostedFrame(\n\t\turl: string,\n\t\toptions: HostedFrameOptions<TData>,\n\t): void {\n\t\tif (typeof document === \"undefined\") return\n\t\tif (this.modal) return\n\n\t\tthis.modal = document.createElement(\"div\")\n\t\tObject.assign(this.modal.style, {\n\t\t\tposition: \"fixed\",\n\t\t\ttop: \"0\",\n\t\t\tleft: \"0\",\n\t\t\twidth: \"100%\",\n\t\t\theight: \"100%\",\n\t\t\tbackgroundColor: \"rgba(15,23,42,0.52)\",\n\t\t\tdisplay: \"flex\",\n\t\t\talignItems: \"center\",\n\t\t\tjustifyContent: \"center\",\n\t\t\tzIndex: \"9999\",\n\t\t\ttransition: \"opacity 0.3s ease\",\n\t\t\tbackdropFilter: \"blur(14px)\",\n\t\t\tpadding: \"16px\",\n\t\t})\n\n\t\tconst container = document.createElement(\"div\")\n\t\tObject.assign(container.style, {\n\t\t\twidth: options.width || \"450px\",\n\t\t\theight: options.height || \"min(600px, 90vh)\",\n\t\t\tbackgroundColor: \"transparent\",\n\t\t\tborderRadius: \"28px\",\n\t\t\toverflow: \"visible\",\n\t\t\tposition: \"relative\",\n\t\t\tboxShadow: \"none\",\n\t\t\tmaxWidth: \"calc(100vw - 32px)\",\n\t\t\tmaxHeight: \"calc(100vh - 32px)\",\n\t\t\ttransition: \"height 180ms ease\",\n\t\t\twillChange: \"height\",\n\t\t})\n\n\t\tconst closeBtn = document.createElement(\"button\")\n\t\tcloseBtn.innerHTML = \"×\"\n\t\tObject.assign(closeBtn.style, {\n\t\t\tposition: \"absolute\",\n\t\t\tright: \"-14px\",\n\t\t\ttop: \"-14px\",\n\t\t\tfontSize: \"20px\",\n\t\t\twidth: \"36px\",\n\t\t\theight: \"36px\",\n\t\t\tborderRadius: \"9999px\",\n\t\t\tborder: \"1px solid rgba(255,255,255,0.5)\",\n\t\t\tbackground: \"rgba(255,255,255,0.9)\",\n\t\t\tcursor: \"pointer\",\n\t\t\tcolor: \"#475569\",\n\t\t\tzIndex: \"2\",\n\t\t\tboxShadow: \"0 10px 30px rgba(15,23,42,0.16)\",\n\t\t})\n\t\tcloseBtn.onclick = () => {\n\t\t\tthis.close()\n\t\t\toptions.onCloseButton?.()\n\t\t}\n\n\t\tthis.iframe = document.createElement(\"iframe\")\n\t\tthis.iframe.src = url\n\t\tObject.assign(this.iframe.style, {\n\t\t\twidth: \"100%\",\n\t\t\theight: \"100%\",\n\t\t\tborder: \"none\",\n\t\t\tborderRadius: \"28px\",\n\t\t\tbackground: \"transparent\",\n\t\t\tdisplay: \"block\",\n\t\t})\n\n\t\tcontainer.appendChild(closeBtn)\n\t\tcontainer.appendChild(this.iframe)\n\t\tthis.modal.appendChild(container)\n\t\tdocument.body.appendChild(this.modal)\n\n\t\tthis.messageHandler = (event: MessageEvent) => {\n\t\t\tif (options.allowedOrigin && options.allowedOrigin !== \"*\") {\n\t\t\t\tif (event.origin !== options.allowedOrigin) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst data = event.data as TData\n\t\t\tif (!data || typeof data !== \"object\" || !data.type) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\toptions.onMessage(data, container)\n\t\t}\n\n\t\twindow.addEventListener(\"message\", this.messageHandler)\n\t}\n\n\tclose() {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tif (this.messageHandler) {\n\t\t\twindow.removeEventListener(\"message\", this.messageHandler)\n\t\t\tthis.messageHandler = null\n\t\t}\n\n\t\tif (this.modal?.parentNode) {\n\t\t\tthis.modal.parentNode.removeChild(this.modal)\n\t\t}\n\n\t\tthis.modal = null\n\t\tthis.iframe = null\n\t}\n}\n","import {\n\tapplyLocaleToUrl,\n\tgetAutoResolvedLocale,\n\ttype HostedFrameMessage,\n} from \"./hosted-modal\"\n\nexport type LoginEventType =\n\t| \"LOGIN_SUCCESS\"\n\t| \"LOGIN_CANCELLED\"\n\t| \"LOGIN_CLOSE\"\n\t| \"LOGIN_RESIZE\"\n\t| \"LOGIN_ERROR\"\n\nexport interface LoginResult {\n\tavatar?: string | null\n\tchannel?: string\n\temail?: string | null\n\texpiresAt?: string\n\tlegacyCasdoorId?: string\n\tloginToken?: string\n\tname?: string | null\n\tuserId?: string\n\twechatOpenId?: string | null\n\twechatUnionId?: string | null\n}\n\nexport interface LoginEventData extends HostedFrameMessage, LoginResult {\n\ttype: LoginEventType\n\terror?: string\n\tmessage?: string\n}\n\nexport interface LoginUIOptions {\n\t/** Origin to validate postMessage (defaults to '*', set for security) */\n\tallowedOrigin?: string\n\t/** Whether the SDK should close the popup after receiving LOGIN_CLOSE. Defaults to true. */\n\tautoClose?: boolean\n\t/** Optional same-origin URL used as the no-API popup callback landing page. */\n\tcallbackUrl?: string\n\t/**\n\t * Whether to poll popup.closed to detect manual popup closure.\n\t * Defaults to false because COOP can make popup.closed unreliable.\n\t */\n\tmonitorPopupClosed?: boolean\n\tonCancel?: () => void\n\tonClose?: () => void\n\tonError?: (message?: string, data?: LoginEventData) => void\n\tonSuccess?: (result: LoginResult) => void\n}\n\nexport interface LoginCallbackOptions {\n\t/**\n\t * Whether the callback helper should close the current window after\n\t * publishing the login result. Defaults to false; LoginUI closes the popup\n\t * it opened after receiving the callback event.\n\t */\n\tautoClose?: boolean\n}\n\nexport interface LoginParams {\n\tappId: string\n\n\t/**\n\t * @deprecated Use loginUrl instead\n\t * Defaults to https://pay.imgto.link\n\t */\n\tbaseUrl?: string\n\n\t/**\n\t * Hosted login page base URL (e.g. https://pay.youidian.com)\n\t * Defaults to https://pay.imgto.link\n\t */\n\tloginUrl?: string\n\n\t/**\n\t * Optional locale prefix to prepend to the hosted login path.\n\t * If omitted, the SDK automatically resolves the locale from the browser language.\n\t */\n\tlocale?: string\n\n\t/** Preferred provider/channel code */\n\tpreferredChannel?: string\n}\n\nfunction getOrigin(value?: string): string | null {\n\tif (!value) return null\n\ttry {\n\t\treturn new URL(value).origin\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction createLoginCallbackState() {\n\tif (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n\t\treturn crypto.randomUUID().replace(/-/g, \"\")\n\t}\n\treturn `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`\n}\n\nfunction buildLoginCallbackUrl(callbackState: string, callbackUrl?: string) {\n\tconst baseUrl = callbackUrl || window.location.href\n\tconst url = new URL(baseUrl, window.location.href)\n\tconst returnHash = url.hash.replace(/^#/, \"\")\n\n\turl.hash = \"\"\n\turl.searchParams.set(LOGIN_CALLBACK_MARKER, \"1\")\n\turl.searchParams.set(LOGIN_CALLBACK_STATE_PARAM, callbackState)\n\tif (returnHash) {\n\t\turl.searchParams.set(LOGIN_CALLBACK_RETURN_HASH_PARAM, returnHash)\n\t} else {\n\t\turl.searchParams.delete(LOGIN_CALLBACK_RETURN_HASH_PARAM)\n\t}\n\n\treturn url.toString()\n}\n\nfunction buildLoginLaunchPayload(\n\tparams: LoginParams,\n\toptions?: LoginUIOptions,\n\tcallbackState?: string,\n) {\n\tconst parentOrigin =\n\t\ttypeof window !== \"undefined\" ? window.location.origin : undefined\n\tconst callbackUrl =\n\t\ttypeof window !== \"undefined\" && callbackState\n\t\t\t? buildLoginCallbackUrl(callbackState, options?.callbackUrl)\n\t\t\t: undefined\n\n\treturn {\n\t\tautoClose: options?.autoClose ?? true,\n\t\tcallbackUrl,\n\t\tcallbackState,\n\t\torigin: parentOrigin,\n\t\tpreferredChannel: params.preferredChannel,\n\t}\n}\n\nfunction appendLoginLaunchHash(\n\turlValue: string,\n\tpayload: ReturnType<typeof buildLoginLaunchPayload>,\n) {\n\tconst hashParams = new URLSearchParams()\n\tif (payload.autoClose === false) {\n\t\thashParams.set(\"ydAutoClose\", \"false\")\n\t}\n\tif (payload.origin) {\n\t\thashParams.set(\"ydOrigin\", payload.origin)\n\t}\n\tif (payload.callbackUrl) {\n\t\thashParams.set(\"ydCallbackUrl\", payload.callbackUrl)\n\t}\n\tif (payload.preferredChannel) {\n\t\thashParams.set(\"ydPreferredChannel\", payload.preferredChannel)\n\t}\n\tconst hash = hashParams.toString()\n\tif (!hash) {\n\t\treturn urlValue\n\t}\n\n\ttry {\n\t\tconst url = new URL(urlValue)\n\t\turl.hash = hash\n\t\treturn url.toString()\n\t} catch (_error) {\n\t\treturn `${urlValue}#${hash}`\n\t}\n}\n\nfunction buildLoginPopupName(payload: LoginLaunchPayload) {\n\treturn `youidian-login:${JSON.stringify(payload)}`\n}\n\nfunction buildLoginUrl(\n\tparams: LoginParams,\n\toptions: LoginUIOptions | undefined,\n\tlaunchPayload: LoginLaunchPayload,\n): string {\n\tconst { appId, baseUrl = \"https://pay.imgto.link\", loginUrl } = params\n\tconst rawBase = (loginUrl || baseUrl).replace(/\\/$/, \"\")\n\tconst parentOrigin = launchPayload.origin\n\n\tlet finalUrl: string\n\ttry {\n\t\tconst url = new URL(rawBase)\n\t\tif (!/\\/auth\\/connect\\/[^/]+$/.test(url.pathname)) {\n\t\t\turl.pathname =\n\t\t\t\t`${url.pathname.replace(/\\/$/, \"\")}/auth/connect/${appId}`.replace(\n\t\t\t\t\t/\\/{2,}/g,\n\t\t\t\t\t\"/\",\n\t\t\t\t)\n\t\t}\n\t\tfinalUrl = url.toString()\n\t} catch (_error) {\n\t\tif (/\\/auth\\/connect\\/[^/]+$/.test(rawBase)) {\n\t\t\tfinalUrl = rawBase\n\t\t} else {\n\t\t\tfinalUrl = `${rawBase}/auth/connect/${appId}`.replace(/\\/{2,}/g, \"/\")\n\t\t}\n\t}\n\n\tfinalUrl = applyLocaleToUrl(finalUrl, getAutoResolvedLocale(params.locale))\n\n\ttry {\n\t\tconst url = new URL(finalUrl)\n\t\tif (params.preferredChannel) {\n\t\t\turl.searchParams.set(\"preferredChannel\", params.preferredChannel)\n\t\t}\n\t\tif (options?.autoClose === false) {\n\t\t\turl.searchParams.set(\"autoClose\", \"false\")\n\t\t}\n\t\tif (parentOrigin) {\n\t\t\turl.searchParams.set(\"origin\", parentOrigin)\n\t\t}\n\t\treturn appendLoginLaunchHash(url.toString(), launchPayload)\n\t} catch (_error) {\n\t\tconst searchParams = new URLSearchParams()\n\t\tif (params.preferredChannel) {\n\t\t\tsearchParams.set(\"preferredChannel\", params.preferredChannel)\n\t\t}\n\t\tif (options?.autoClose === false) {\n\t\t\tsearchParams.set(\"autoClose\", \"false\")\n\t\t}\n\t\tif (parentOrigin) {\n\t\t\tsearchParams.set(\"origin\", parentOrigin)\n\t\t}\n\t\tconst query = searchParams.toString()\n\t\tif (!query) {\n\t\t\treturn appendLoginLaunchHash(finalUrl, launchPayload)\n\t\t}\n\t\tconst separator = finalUrl.includes(\"?\") ? \"&\" : \"?\"\n\t\treturn appendLoginLaunchHash(\n\t\t\t`${finalUrl}${separator}${query}`,\n\t\t\tlaunchPayload,\n\t\t)\n\t}\n}\n\nfunction extractLoginResult(data: LoginEventData): LoginResult {\n\treturn {\n\t\tavatar: data.avatar,\n\t\tchannel: data.channel,\n\t\temail: data.email,\n\t\texpiresAt: data.expiresAt,\n\t\tlegacyCasdoorId: data.legacyCasdoorId,\n\t\tloginToken: data.loginToken,\n\t\tname: data.name,\n\t\tuserId: data.userId,\n\t\twechatOpenId: data.wechatOpenId,\n\t\twechatUnionId: data.wechatUnionId,\n\t}\n}\n\nconst LOGIN_UI_LOG_PREFIX = \"[Youidian LoginUI]\"\nconst LOGIN_CALLBACK_MARKER = \"yd_login_callback\"\nconst LOGIN_CALLBACK_RESULT_PARAM = \"yd_login_result\"\nconst LOGIN_CALLBACK_RETURN_HASH_PARAM = \"yd_login_return_hash\"\nconst LOGIN_CALLBACK_STATE_PARAM = \"yd_login_state\"\nconst LOGIN_CALLBACK_STORAGE_PREFIX = \"yd-login-callback:\"\n\ntype LoginLaunchPayload = ReturnType<typeof buildLoginLaunchPayload>\n\nfunction decodeCallbackPayload(value: string): LoginEventData | null {\n\ttry {\n\t\tconst padded = value.padEnd(\n\t\t\tvalue.length + ((4 - (value.length % 4)) % 4),\n\t\t\t\"=\",\n\t\t)\n\t\tconst base64 = padded.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\")\n\t\tconst binary = atob(base64)\n\t\tconst json = decodeURIComponent(\n\t\t\tArray.from(\n\t\t\t\tbinary,\n\t\t\t\t(char) => `%${char.charCodeAt(0).toString(16).padStart(2, \"0\")}`,\n\t\t\t).join(\"\"),\n\t\t)\n\t\tconst parsed = JSON.parse(json) as LoginEventData\n\t\treturn parsed && typeof parsed === \"object\" && parsed.type ? parsed : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction getLoginCallbackChannelName(state: string) {\n\treturn `youidian-login:${state}`\n}\n\nfunction getLoginCallbackStorageKey(state: string) {\n\treturn `${LOGIN_CALLBACK_STORAGE_PREFIX}${state}`\n}\n\nfunction publishLoginCallback(state: string, data: LoginEventData) {\n\ttry {\n\t\tconst channel = new BroadcastChannel(getLoginCallbackChannelName(state))\n\t\tchannel.postMessage(data)\n\t\tchannel.close()\n\t} catch {\n\t\t// BroadcastChannel is not available in every embedded browser.\n\t}\n\n\ttry {\n\t\tconst storageKey = getLoginCallbackStorageKey(state)\n\t\twindow.localStorage.setItem(storageKey, JSON.stringify(data))\n\t\twindow.setTimeout(() => {\n\t\t\ttry {\n\t\t\t\twindow.localStorage.removeItem(storageKey)\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup failures.\n\t\t\t}\n\t\t}, 800)\n\t} catch {\n\t\t// localStorage may be disabled; postMessage remains available below.\n\t}\n\n\ttry {\n\t\twindow.opener?.postMessage(data, window.location.origin)\n\t} catch {\n\t\t// opener is only an opportunistic fast path.\n\t}\n}\n\nfunction safeIsPopupClosed(popup: Window | null) {\n\tif (!popup) return true\n\ttry {\n\t\treturn popup.closed\n\t} catch {\n\t\tlogLoginDebug(\"Unable to read popup.closed; treating popup as open\")\n\t\treturn false\n\t}\n}\n\nfunction safeClosePopup(popup: Window | null) {\n\tif (!popup) return\n\ttry {\n\t\tpopup.close()\n\t} catch {\n\t\tlogLoginDebug(\"Unable to close popup\")\n\t}\n}\n\nfunction cleanLoginCallbackUrl(url: URL) {\n\turl.searchParams.delete(LOGIN_CALLBACK_MARKER)\n\turl.searchParams.delete(LOGIN_CALLBACK_STATE_PARAM)\n\tconst returnHash = url.searchParams.get(LOGIN_CALLBACK_RETURN_HASH_PARAM)\n\turl.searchParams.delete(LOGIN_CALLBACK_RETURN_HASH_PARAM)\n\turl.hash = returnHash ? `#${returnHash}` : \"\"\n\treturn url.toString()\n}\n\nexport function handleLoginCallbackIfPresent(options?: LoginCallbackOptions) {\n\tif (typeof window === \"undefined\") {\n\t\treturn false\n\t}\n\n\tconst url = new URL(window.location.href)\n\tif (url.searchParams.get(LOGIN_CALLBACK_MARKER) !== \"1\") {\n\t\treturn false\n\t}\n\n\tconst state = url.searchParams.get(LOGIN_CALLBACK_STATE_PARAM) || \"\"\n\tconst hashParams = new URLSearchParams(url.hash.replace(/^#/, \"\"))\n\tconst rawResult = hashParams.get(LOGIN_CALLBACK_RESULT_PARAM)\n\tconst data: LoginEventData | null =\n\t\trawResult && state\n\t\t\t? decodeCallbackPayload(rawResult)\n\t\t\t: {\n\t\t\t\t\ttype: \"LOGIN_ERROR\",\n\t\t\t\t\tmessage: \"Missing login callback result\",\n\t\t\t\t}\n\n\ttry {\n\t\tdocument.documentElement.style.visibility = \"hidden\"\n\t} catch {\n\t\t// This is best-effort to avoid a visible callback-page flash.\n\t}\n\n\tif (state && data) {\n\t\tpublishLoginCallback(state, data)\n\t}\n\n\ttry {\n\t\twindow.history.replaceState(null, \"\", cleanLoginCallbackUrl(url))\n\t} catch {\n\t\t// Ignore history cleanup failures.\n\t}\n\n\tif (options?.autoClose === true) {\n\t\twindow.setTimeout(() => {\n\t\t\ttry {\n\t\t\t\twindow.close()\n\t\t\t} catch {\n\t\t\t\t// Some browsers disallow script-closing the current window.\n\t\t\t}\n\t\t}, 30)\n\t\treturn true\n\t}\n\n\ttry {\n\t\tdocument.documentElement.style.visibility = \"\"\n\t} catch {\n\t\t// Ignore visibility restoration failures.\n\t}\n\n\treturn true\n}\n\nfunction logLoginDebug(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.debug(LOGIN_UI_LOG_PREFIX, message, details || {})\n}\n\nfunction logLoginInfo(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.info(LOGIN_UI_LOG_PREFIX, message, details || {})\n}\n\nfunction logLoginWarn(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.warn(LOGIN_UI_LOG_PREFIX, message, details || {})\n}\n\nexport class LoginUI {\n\tprivate popup: Window | null = null\n\tprivate callbackChannel: BroadcastChannel | null = null\n\tprivate callbackStorageHandler: ((event: StorageEvent) => void) | null = null\n\tprivate messageHandler: ((event: MessageEvent) => void) | null = null\n\tprivate closeMonitor: number | null = null\n\tprivate completed = false\n\n\tprivate cleanup() {\n\t\tif (this.callbackChannel) {\n\t\t\tthis.callbackChannel.close()\n\t\t}\n\t\tif (typeof window !== \"undefined\" && this.callbackStorageHandler) {\n\t\t\twindow.removeEventListener(\"storage\", this.callbackStorageHandler)\n\t\t}\n\t\tif (typeof window !== \"undefined\" && this.messageHandler) {\n\t\t\twindow.removeEventListener(\"message\", this.messageHandler)\n\t\t}\n\t\tthis.callbackChannel = null\n\t\tthis.callbackStorageHandler = null\n\t\tif (typeof window !== \"undefined\" && this.closeMonitor) {\n\t\t\twindow.clearInterval(this.closeMonitor)\n\t\t}\n\t\tthis.messageHandler = null\n\t\tthis.closeMonitor = null\n\t\tthis.popup = null\n\t\tthis.completed = false\n\t}\n\n\tprivate handleLoginEvent(data: LoginEventData, options?: LoginUIOptions) {\n\t\tif (!data || typeof data !== \"object\" || !data.type) {\n\t\t\tlogLoginDebug(\"Ignored non-login event payload\")\n\t\t\treturn\n\t\t}\n\n\t\tlogLoginInfo(\"Received login event\", {\n\t\t\ttype: data.type,\n\t\t})\n\n\t\tswitch (data.type) {\n\t\t\tcase \"LOGIN_SUCCESS\":\n\t\t\t\tif (this.completed) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthis.completed = true\n\t\t\t\tlogLoginInfo(\"Login succeeded\", {\n\t\t\t\t\tchannel: data.channel || null,\n\t\t\t\t\tuserId: data.userId || null,\n\t\t\t\t})\n\t\t\t\toptions?.onSuccess?.(extractLoginResult(data))\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_CANCELLED\":\n\t\t\t\tlogLoginInfo(\"Login cancelled\")\n\t\t\t\toptions?.onCancel?.()\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_RESIZE\":\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_ERROR\":\n\t\t\t\tif (this.completed) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tlogLoginWarn(\"Login flow reported an error\", {\n\t\t\t\t\tmessage: data.message || data.error || null,\n\t\t\t\t})\n\t\t\t\toptions?.onError?.(data.message || data.error, data)\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_CLOSE\":\n\t\t\t\tif (options?.autoClose === false) {\n\t\t\t\t\tlogLoginInfo(\n\t\t\t\t\t\t\"Login popup requested close; autoClose disabled, keeping popup open\",\n\t\t\t\t\t)\n\t\t\t\t\toptions?.onClose?.()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tlogLoginInfo(\"Login popup requested close; autoClose enabled\")\n\t\t\t\tthis.close()\n\t\t\t\toptions?.onClose?.()\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate listenForLoginCallback(\n\t\tcallbackState: string,\n\t\toptions?: LoginUIOptions,\n\t) {\n\t\ttry {\n\t\t\tthis.callbackChannel = new BroadcastChannel(\n\t\t\t\tgetLoginCallbackChannelName(callbackState),\n\t\t\t)\n\t\t\tthis.callbackChannel.onmessage = (event) => {\n\t\t\t\tthis.handleLoginEvent(event.data as LoginEventData, options)\n\t\t\t\tthis.handleLoginEvent({ type: \"LOGIN_CLOSE\" }, options)\n\t\t\t}\n\t\t} catch {\n\t\t\tlogLoginDebug(\"BroadcastChannel is unavailable for login callback\")\n\t\t}\n\n\t\tthis.callbackStorageHandler = (event: StorageEvent) => {\n\t\t\tif (\n\t\t\t\tevent.key !== getLoginCallbackStorageKey(callbackState) ||\n\t\t\t\t!event.newValue\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(event.newValue) as LoginEventData\n\t\t\t\tthis.handleLoginEvent(data, options)\n\t\t\t\tthis.handleLoginEvent({ type: \"LOGIN_CLOSE\" }, options)\n\t\t\t} catch {\n\t\t\t\tlogLoginWarn(\"Failed to parse login callback storage payload\")\n\t\t\t}\n\t\t}\n\t\twindow.addEventListener(\"storage\", this.callbackStorageHandler)\n\t}\n\n\tclose() {\n\t\tlogLoginInfo(\"close() called\", {\n\t\t\thasPopup: Boolean(this.popup),\n\t\t\tpopupClosed: safeIsPopupClosed(this.popup),\n\t\t})\n\t\tsafeClosePopup(this.popup)\n\t\tthis.cleanup()\n\t}\n\n\topenLogin(params: LoginParams, options?: LoginUIOptions) {\n\t\tif (typeof window === \"undefined\") return\n\t\tif (this.popup && !safeIsPopupClosed(this.popup)) return\n\n\t\tconst callbackState = createLoginCallbackState()\n\t\tconst launchPayload = buildLoginLaunchPayload(\n\t\t\tparams,\n\t\t\toptions,\n\t\t\tcallbackState,\n\t\t)\n\t\tconst finalUrl = buildLoginUrl(params, options, launchPayload)\n\t\tlogLoginInfo(\"Opening hosted login popup\", {\n\t\t\tappId: params.appId,\n\t\t\tcallbackState,\n\t\t\tcallbackUrl: launchPayload.callbackUrl || null,\n\t\t\thasCallbackUrl: Boolean(launchPayload.callbackUrl),\n\t\t\tloginUrl: finalUrl,\n\t\t\tallowedOrigin: options?.allowedOrigin || null,\n\t\t\tautoClose: options?.autoClose ?? true,\n\t\t\tpageUrl: typeof window !== \"undefined\" ? window.location.href : null,\n\t\t\tparentOrigin: launchPayload.origin || null,\n\t\t})\n\t\tconst popupWidth = 520\n\t\tconst popupHeight = 720\n\t\tconst left = Math.max(\n\t\t\t0,\n\t\t\tMath.round(window.screenX + (window.outerWidth - popupWidth) / 2),\n\t\t)\n\t\tconst top = Math.max(\n\t\t\t0,\n\t\t\tMath.round(window.screenY + (window.outerHeight - popupHeight) / 2),\n\t\t)\n\t\tconst features = [\n\t\t\t\"popup=yes\",\n\t\t\t`width=${popupWidth}`,\n\t\t\t`height=${popupHeight}`,\n\t\t\t`left=${left}`,\n\t\t\t`top=${top}`,\n\t\t\t\"resizable=yes\",\n\t\t\t\"scrollbars=yes\",\n\t\t].join(\",\")\n\n\t\tconst popupName = buildLoginPopupName(launchPayload)\n\t\tconst popup = window.open(finalUrl, popupName, features)\n\t\tif (!popup) {\n\t\t\tlogLoginWarn(\"Popup blocked by the browser\")\n\t\t\toptions?.onError?.(\"Login popup was blocked\")\n\t\t\treturn\n\t\t}\n\n\t\tthis.popup = popup\n\t\tthis.completed = false\n\t\tthis.listenForLoginCallback(callbackState, options)\n\n\t\tconst allowedOrigin = options?.allowedOrigin\n\t\tconst popupOrigin = getOrigin(finalUrl)\n\n\t\tthis.messageHandler = (event: MessageEvent) => {\n\t\t\tif (\n\t\t\t\tallowedOrigin &&\n\t\t\t\tallowedOrigin !== \"*\" &&\n\t\t\t\tevent.origin !== allowedOrigin\n\t\t\t) {\n\t\t\t\tlogLoginWarn(\"Ignored message due to allowedOrigin mismatch\", {\n\t\t\t\t\tallowedOrigin,\n\t\t\t\t\teventOrigin: event.origin,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!allowedOrigin && popupOrigin && event.origin !== popupOrigin) {\n\t\t\t\tlogLoginWarn(\"Ignored message due to popup origin mismatch\", {\n\t\t\t\t\texpectedOrigin: popupOrigin,\n\t\t\t\t\teventOrigin: event.origin,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst data = event.data as LoginEventData\n\t\t\tif (!data || typeof data !== \"object\" || !data.type) {\n\t\t\t\tlogLoginDebug(\"Ignored non-login postMessage payload\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlogLoginInfo(\"Received login event\", {\n\t\t\t\ttype: data.type,\n\t\t\t\teventOrigin: event.origin,\n\t\t\t})\n\n\t\t\tthis.handleLoginEvent(data, options)\n\t\t}\n\n\t\twindow.addEventListener(\"message\", this.messageHandler)\n\n\t\tif (options?.monitorPopupClosed === true) {\n\t\t\tthis.closeMonitor = window.setInterval(() => {\n\t\t\t\tif (!this.popup || safeIsPopupClosed(this.popup)) {\n\t\t\t\t\tconst shouldTreatAsCancel = !this.completed\n\t\t\t\t\tlogLoginInfo(\"Detected popup closed\", {\n\t\t\t\t\t\tshouldTreatAsCancel,\n\t\t\t\t\t})\n\t\t\t\t\tthis.cleanup()\n\t\t\t\t\tif (shouldTreatAsCancel) {\n\t\t\t\t\t\toptions?.onCancel?.()\n\t\t\t\t\t}\n\t\t\t\t\toptions?.onClose?.()\n\t\t\t\t}\n\t\t\t}, 500)\n\t\t}\n\t}\n}\n\nexport function createLoginUI(): LoginUI {\n\treturn new LoginUI()\n}\n\nhandleLoginCallbackIfPresent({ autoClose: false })\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/hosted-modal.ts","../src/login.ts"],"sourcesContent":["/**\n * Youidian Payment SDK - Client Module\n * 用于浏览器端集成,包含支付弹窗、状态轮询等功能\n * 不依赖 Node.js crypto 模块\n */\n\nimport {\n\tapplyLocaleToUrl,\n\tgetAutoResolvedLocale,\n\tHostedFrameModal,\n} from \"./hosted-modal\"\n\n/**\n * Payment event types from checkout pages\n */\nexport type PaymentEventType =\n\t| \"PAYMENT_SUCCESS\"\n\t| \"PAYMENT_CANCELLED\"\n\t| \"PAYMENT_CLOSE\"\n\t| \"PAYMENT_RESIZE\"\n\n/**\n * Payment event data from postMessage\n */\nexport interface PaymentEventData {\n\ttype: PaymentEventType\n\torderId?: string\n\theight?: number\n}\n\n/**\n * Order status response\n */\nexport interface OrderStatus {\n\torderId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\n/**\n * Payment UI Options\n */\nexport interface PaymentUIOptions {\n\tlocale?: string\n\tonSuccess?: (orderId?: string) => void\n\tonCancel?: (orderId?: string) => void\n\tonClose?: () => void\n\t/** Origin to validate postMessage (defaults to '*', set for security) */\n\tallowedOrigin?: string\n}\n\n/**\n * Poll Options\n */\nexport interface PollOptions {\n\t/** Polling interval in ms (default: 3000) */\n\tinterval?: number\n\t/** Timeout in ms (default: 300000 = 5 minutes) */\n\ttimeout?: number\n\t/** Callback on each status check */\n\tonStatusChange?: (status: OrderStatus) => void\n}\n\n/**\n * Client-side Payment UI Helper\n * 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态\n */\n/**\n * Params for opening payment directly without manual URL construction\n */\nexport interface PaymentParams {\n\tappId: string\n\tuserId: string\n\t/** Product ID - use with priceId for direct ID-based payment */\n\tproductId?: string\n\t/** Price ID - use with productId for direct ID-based payment */\n\tpriceId?: string\n\t/** Product code - use with locale for code-based payment (alternative to productId/priceId) */\n\tproductCode?: string\n\n\t/**\n\t * @deprecated Use checkoutUrl instead\n\t * Defaults to https://pay.imgto.link\n\t */\n\tbaseUrl?: string\n\n\t/**\n\t * Checkout page URL (e.g. https://pay.youidian.com)\n\t * Defaults to https://pay.imgto.link\n\t */\n\tcheckoutUrl?: string\n}\n\n/**\n * Client-side Payment UI Helper\n * 浏览器端支付 UI 辅助类,用于弹出支付窗口和轮询订单状态\n */\nexport class PaymentUI extends HostedFrameModal<PaymentEventData> {\n\t/**\n\t * Opens the payment checkout page in an iframe modal.\n\t * @param urlOrParams - The checkout page URL or payment parameters\n\t * @param options - UI options\n\t */\n\topenPayment(urlOrParams: string | PaymentParams, options?: PaymentUIOptions) {\n\t\tif (typeof document === \"undefined\") return // Server-side guard\n\t\tif (this.modal) return // Prevent multiple modals\n\n\t\tlet checkoutUrl: string\n\t\tif (typeof urlOrParams === \"string\") {\n\t\t\tcheckoutUrl = urlOrParams\n\t\t} else {\n\t\t\tconst {\n\t\t\t\tappId,\n\t\t\t\tproductId,\n\t\t\t\tpriceId,\n\t\t\t\tproductCode,\n\t\t\t\tuserId,\n\t\t\t\tcheckoutUrl: checkoutUrlParam,\n\t\t\t\tbaseUrl = \"https://pay.imgto.link\",\n\t\t\t} = urlOrParams\n\n\t\t\t// 优先使用 checkoutUrl,其次 baseUrl,默认 https://pay.imgto.link\n\t\t\tconst base = (checkoutUrlParam || baseUrl).replace(/\\/$/, \"\")\n\n\t\t\tif (productCode) {\n\t\t\t\t// Use product code route\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/code/${productCode}?userId=${encodeURIComponent(userId)}`\n\t\t\t} else if (productId && priceId) {\n\t\t\t\t// Use ID-based route\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?userId=${encodeURIComponent(userId)}`\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Either productCode or both productId and priceId are required\",\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tconst finalUrl = applyLocaleToUrl(\n\t\t\tcheckoutUrl,\n\t\t\tgetAutoResolvedLocale(options?.locale),\n\t\t)\n\n\t\tthis.openHostedFrame(finalUrl, {\n\t\t\tallowedOrigin: options?.allowedOrigin,\n\t\t\tonCloseButton: () => options?.onCancel?.(),\n\t\t\tonMessage: (data, container) => {\n\t\t\t\tswitch (data.type) {\n\t\t\t\t\tcase \"PAYMENT_SUCCESS\":\n\t\t\t\t\t\toptions?.onSuccess?.(data.orderId)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_CANCELLED\":\n\t\t\t\t\t\toptions?.onCancel?.(data.orderId)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_RESIZE\":\n\t\t\t\t\t\tif (data.height) {\n\t\t\t\t\t\t\tconst maxHeight = window.innerHeight * 0.9\n\t\t\t\t\t\t\tconst newHeight = Math.min(data.height, maxHeight)\n\t\t\t\t\t\t\tcontainer.style.height = `${newHeight}px`\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_CLOSE\":\n\t\t\t\t\t\tthis.close()\n\t\t\t\t\t\toptions?.onClose?.()\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t}\n\n\t/**\n\t * Poll order status from integrator's API endpoint\n\t * @param statusUrl - The integrator's API endpoint to check order status\n\t * @param options - Polling options\n\t * @returns Promise that resolves when order is paid or rejects on timeout/failure\n\t */\n\tasync pollOrderStatus(\n\t\tstatusUrl: string,\n\t\toptions?: PollOptions,\n\t): Promise<OrderStatus> {\n\t\tconst interval = options?.interval || 3000\n\t\tconst timeout = options?.timeout || 300000\n\t\tconst startTime = Date.now()\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst poll = async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst response = await fetch(statusUrl)\n\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\tthrow new Error(`Status check failed: ${response.status}`)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst status: OrderStatus = await response.json()\n\t\t\t\t\toptions?.onStatusChange?.(status)\n\n\t\t\t\t\tif (status.status === \"PAID\") {\n\t\t\t\t\t\tresolve(status)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tif (status.status === \"CANCELLED\" || status.status === \"FAILED\") {\n\t\t\t\t\t\treject(new Error(`Order ${status.status.toLowerCase()}`))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(new Error(\"Polling timeout\"))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Continue polling\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// On network error, continue polling unless timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(error)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpoll()\n\t\t})\n\t}\n}\n\n/**\n * Convenience function to create a PaymentUI instance\n */\nexport function createPaymentUI(): PaymentUI {\n\treturn new PaymentUI()\n}\n\nexport type {\n\tLoginCallbackOptions,\n\tLoginDisplayMode,\n\tLoginEventData,\n\tLoginEventType,\n\tLoginParams,\n\tLoginResult,\n\tLoginUIOptions,\n} from \"./login\"\nexport { createLoginUI, handleLoginCallbackIfPresent, LoginUI } from \"./login\"\n","export interface HostedFrameMessage {\n\ttype: string\n\theight?: number\n}\n\ntype HostedFrameOptions<TData extends HostedFrameMessage> = {\n\tallowedOrigin?: string\n\theight?: string\n\tonCloseButton?: () => void\n\tonMessage: (data: TData, container: HTMLDivElement) => void\n\twidth?: string\n}\n\nconst SDK_SUPPORTED_LOCALES = [\n\t\"en\",\n\t\"zh-CN\",\n\t\"zh-Hant\",\n\t\"fr\",\n\t\"de\",\n\t\"ja\",\n\t\"es\",\n\t\"ko\",\n\t\"nl\",\n\t\"it\",\n\t\"pt\",\n] as const\n\nconst SDK_DEFAULT_LOCALE = \"zh-CN\"\n\nconst SDK_LOCALE_ALIASES: Record<string, string> = {\n\ten: \"en\",\n\t\"en-us\": \"en\",\n\t\"en-gb\": \"en\",\n\tzh: \"zh-CN\",\n\t\"zh-cn\": \"zh-CN\",\n\t\"zh-tw\": \"zh-Hant\",\n\t\"zh-hk\": \"zh-Hant\",\n\t\"zh-hant\": \"zh-Hant\",\n\t\"zh-hans\": \"zh-CN\",\n\tfr: \"fr\",\n\tde: \"de\",\n\tja: \"ja\",\n\tes: \"es\",\n\tko: \"ko\",\n\tnl: \"nl\",\n\tit: \"it\",\n\tpt: \"pt\",\n}\n\nfunction matchSupportedBaseLocale(locale: string): string | undefined {\n\tconst base = locale.toLowerCase().split(\"-\")[0]\n\treturn SDK_SUPPORTED_LOCALES.find((item) => item.toLowerCase() === base)\n}\n\nexport function normalizeSdkLocale(locale?: string): string | undefined {\n\tif (!locale) return\n\n\tconst sanitized = locale.trim().replace(/_/g, \"-\")\n\tif (!sanitized) return\n\n\tconst lower = sanitized.toLowerCase()\n\tif (SDK_LOCALE_ALIASES[lower]) {\n\t\treturn SDK_LOCALE_ALIASES[lower]\n\t}\n\n\tlet canonical: string | undefined\n\ttry {\n\t\tcanonical = Intl.getCanonicalLocales(sanitized)[0]\n\t} catch {\n\t\tcanonical = undefined\n\t}\n\n\tconst candidates = [canonical, sanitized].filter(Boolean) as string[]\n\n\tfor (const candidate of candidates) {\n\t\tconst candidateLower = candidate.toLowerCase()\n\n\t\tif (SDK_LOCALE_ALIASES[candidateLower]) {\n\t\t\treturn SDK_LOCALE_ALIASES[candidateLower]\n\t\t}\n\t\tif ((SDK_SUPPORTED_LOCALES as readonly string[]).includes(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\n\t\tconst baseMatch = matchSupportedBaseLocale(candidate)\n\t\tif (baseMatch) {\n\t\t\treturn baseMatch\n\t\t}\n\t}\n}\n\nexport function getBrowserLocale(): string | undefined {\n\tif (typeof navigator === \"undefined\") return\n\n\tfor (const candidate of navigator.languages || []) {\n\t\tconst normalized = normalizeSdkLocale(candidate)\n\t\tif (normalized) return normalized\n\t}\n\n\treturn normalizeSdkLocale(navigator.language)\n}\n\nexport function getAutoResolvedLocale(locale?: string): string {\n\treturn normalizeSdkLocale(locale) || getBrowserLocale() || SDK_DEFAULT_LOCALE\n}\n\nexport function applyLocaleToUrl(urlValue: string, locale?: string): string {\n\tif (!locale) return urlValue\n\n\ttry {\n\t\tconst url = new URL(urlValue)\n\t\tconst localePrefix = `/${locale}`\n\t\tif (\n\t\t\t!url.pathname.startsWith(`${localePrefix}/`) &&\n\t\t\turl.pathname !== localePrefix\n\t\t) {\n\t\t\turl.pathname = `${localePrefix}${url.pathname}`\n\t\t}\n\t\treturn url.toString()\n\t} catch (_error) {\n\t\tconst localePrefix = `/${locale}`\n\t\tif (!urlValue.startsWith(`${localePrefix}/`) && urlValue !== localePrefix) {\n\t\t\treturn `${localePrefix}${urlValue.startsWith(\"/\") ? \"\" : \"/\"}${urlValue}`\n\t\t}\n\t\treturn urlValue\n\t}\n}\n\nexport class HostedFrameModal<TData extends HostedFrameMessage> {\n\tprotected iframe: HTMLIFrameElement | null = null\n\tprotected modal: HTMLDivElement | null = null\n\tprotected messageHandler: ((event: MessageEvent) => void) | null = null\n\n\tprotected openHostedFrame(\n\t\turl: string,\n\t\toptions: HostedFrameOptions<TData>,\n\t): void {\n\t\tif (typeof document === \"undefined\") return\n\t\tif (this.modal) return\n\n\t\tthis.modal = document.createElement(\"div\")\n\t\tObject.assign(this.modal.style, {\n\t\t\tposition: \"fixed\",\n\t\t\ttop: \"0\",\n\t\t\tleft: \"0\",\n\t\t\twidth: \"100%\",\n\t\t\theight: \"100%\",\n\t\t\tbackgroundColor: \"rgba(15,23,42,0.52)\",\n\t\t\tdisplay: \"flex\",\n\t\t\talignItems: \"center\",\n\t\t\tjustifyContent: \"center\",\n\t\t\tzIndex: \"9999\",\n\t\t\ttransition: \"opacity 0.3s ease\",\n\t\t\tbackdropFilter: \"blur(14px)\",\n\t\t\tpadding: \"16px\",\n\t\t})\n\n\t\tconst container = document.createElement(\"div\")\n\t\tObject.assign(container.style, {\n\t\t\twidth: options.width || \"450px\",\n\t\t\theight: options.height || \"min(600px, 90vh)\",\n\t\t\tbackgroundColor: \"transparent\",\n\t\t\tborderRadius: \"28px\",\n\t\t\toverflow: \"visible\",\n\t\t\tposition: \"relative\",\n\t\t\tboxShadow: \"none\",\n\t\t\tmaxWidth: \"calc(100vw - 32px)\",\n\t\t\tmaxHeight: \"calc(100vh - 32px)\",\n\t\t\ttransition: \"height 180ms ease\",\n\t\t\twillChange: \"height\",\n\t\t})\n\n\t\tconst closeBtn = document.createElement(\"button\")\n\t\tcloseBtn.innerHTML = \"×\"\n\t\tObject.assign(closeBtn.style, {\n\t\t\tposition: \"absolute\",\n\t\t\tright: \"-14px\",\n\t\t\ttop: \"-14px\",\n\t\t\tfontSize: \"20px\",\n\t\t\twidth: \"36px\",\n\t\t\theight: \"36px\",\n\t\t\tborderRadius: \"9999px\",\n\t\t\tborder: \"1px solid rgba(255,255,255,0.5)\",\n\t\t\tbackground: \"rgba(255,255,255,0.9)\",\n\t\t\tcursor: \"pointer\",\n\t\t\tcolor: \"#475569\",\n\t\t\tzIndex: \"2\",\n\t\t\tboxShadow: \"0 10px 30px rgba(15,23,42,0.16)\",\n\t\t})\n\t\tcloseBtn.onclick = () => {\n\t\t\tthis.close()\n\t\t\toptions.onCloseButton?.()\n\t\t}\n\n\t\tthis.iframe = document.createElement(\"iframe\")\n\t\tthis.iframe.src = url\n\t\tObject.assign(this.iframe.style, {\n\t\t\twidth: \"100%\",\n\t\t\theight: \"100%\",\n\t\t\tborder: \"none\",\n\t\t\tborderRadius: \"28px\",\n\t\t\tbackground: \"transparent\",\n\t\t\tdisplay: \"block\",\n\t\t})\n\n\t\tcontainer.appendChild(closeBtn)\n\t\tcontainer.appendChild(this.iframe)\n\t\tthis.modal.appendChild(container)\n\t\tdocument.body.appendChild(this.modal)\n\n\t\tthis.messageHandler = (event: MessageEvent) => {\n\t\t\tif (options.allowedOrigin && options.allowedOrigin !== \"*\") {\n\t\t\t\tif (event.origin !== options.allowedOrigin) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst data = event.data as TData\n\t\t\tif (!data || typeof data !== \"object\" || !data.type) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\toptions.onMessage(data, container)\n\t\t}\n\n\t\twindow.addEventListener(\"message\", this.messageHandler)\n\t}\n\n\tclose() {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tif (this.messageHandler) {\n\t\t\twindow.removeEventListener(\"message\", this.messageHandler)\n\t\t\tthis.messageHandler = null\n\t\t}\n\n\t\tif (this.modal?.parentNode) {\n\t\t\tthis.modal.parentNode.removeChild(this.modal)\n\t\t}\n\n\t\tthis.modal = null\n\t\tthis.iframe = null\n\t}\n}\n","import {\n\tapplyLocaleToUrl,\n\tgetAutoResolvedLocale,\n\ttype HostedFrameMessage,\n\tHostedFrameModal,\n} from \"./hosted-modal\"\n\nexport type LoginEventType =\n\t| \"LOGIN_SUCCESS\"\n\t| \"LOGIN_CANCELLED\"\n\t| \"LOGIN_CLOSE\"\n\t| \"LOGIN_RESIZE\"\n\t| \"LOGIN_ERROR\"\n\nexport type LoginDisplayMode = \"modal\" | \"popup\"\n\nexport interface LoginResult {\n\tavatar?: string | null\n\tchannel?: string\n\temail?: string | null\n\texpiresAt?: string\n\tlegacyCasdoorId?: string\n\tloginToken?: string\n\tname?: string | null\n\tusername?: string | null\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164?: string | null\n\tphoneVerifiedAt?: string | null\n\tuserId?: string\n\twechatOpenId?: string | null\n\twechatUnionId?: string | null\n}\n\nexport interface LoginEventData extends HostedFrameMessage, LoginResult {\n\ttype: LoginEventType\n\terror?: string\n\tmessage?: string\n}\n\nexport interface LoginUIOptions {\n\t/** Origin to validate postMessage (defaults to '*', set for security) */\n\tallowedOrigin?: string\n\t/** Whether the SDK should close the login surface after receiving LOGIN_CLOSE. Defaults to true. */\n\tautoClose?: boolean\n\t/** Optional same-origin URL used as the no-API OAuth callback landing page. */\n\tcallbackUrl?: string\n\t/**\n\t * How to open the hosted login page. Defaults to \"modal\", which embeds the\n\t * login page in an iframe modal. Use \"popup\" to keep the legacy popup flow.\n\t */\n\tdisplayMode?: LoginDisplayMode\n\t/**\n\t * Whether to poll popup.closed to detect manual popup closure.\n\t * Only used when displayMode is \"popup\". Defaults to false because COOP can\n\t * make popup.closed unreliable.\n\t */\n\tmonitorPopupClosed?: boolean\n\tonCancel?: () => void\n\tonClose?: () => void\n\tonError?: (message?: string, data?: LoginEventData) => void\n\tonSuccess?: (result: LoginResult) => void\n}\n\nexport interface LoginCallbackOptions {\n\t/**\n\t * Whether the callback helper should close the current window after\n\t * publishing the login result. Defaults to false; LoginUI closes the popup\n\t * it opened after receiving the callback event.\n\t */\n\tautoClose?: boolean\n}\n\nexport interface LoginParams {\n\tappId: string\n\n\t/**\n\t * @deprecated Use loginUrl instead\n\t * Defaults to https://pay.imgto.link\n\t */\n\tbaseUrl?: string\n\n\t/**\n\t * Hosted login page base URL (e.g. https://pay.youidian.com)\n\t * Defaults to https://pay.imgto.link\n\t */\n\tloginUrl?: string\n\n\t/**\n\t * Optional locale prefix to prepend to the hosted login path.\n\t * If omitted, the SDK automatically resolves the locale from the browser language.\n\t */\n\tlocale?: string\n\n\t/** Preferred provider/channel code */\n\tpreferredChannel?: string\n}\n\nfunction getOrigin(value?: string): string | null {\n\tif (!value) return null\n\ttry {\n\t\treturn new URL(value).origin\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction createLoginCallbackState() {\n\tif (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n\t\treturn crypto.randomUUID().replace(/-/g, \"\")\n\t}\n\treturn `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`\n}\n\nfunction buildLoginCallbackUrl(callbackState: string, callbackUrl?: string) {\n\tconst baseUrl = callbackUrl || window.location.href\n\tconst url = new URL(baseUrl, window.location.href)\n\tconst returnHash = url.hash.replace(/^#/, \"\")\n\n\turl.hash = \"\"\n\turl.searchParams.set(LOGIN_CALLBACK_MARKER, \"1\")\n\turl.searchParams.set(LOGIN_CALLBACK_STATE_PARAM, callbackState)\n\tif (returnHash) {\n\t\turl.searchParams.set(LOGIN_CALLBACK_RETURN_HASH_PARAM, returnHash)\n\t} else {\n\t\turl.searchParams.delete(LOGIN_CALLBACK_RETURN_HASH_PARAM)\n\t}\n\n\treturn url.toString()\n}\n\nfunction buildLoginLaunchPayload(\n\tparams: LoginParams,\n\toptions?: LoginUIOptions,\n\tcallbackState?: string,\n) {\n\tconst parentOrigin =\n\t\ttypeof window !== \"undefined\" ? window.location.origin : undefined\n\tconst callbackUrl =\n\t\ttypeof window !== \"undefined\" && callbackState\n\t\t\t? buildLoginCallbackUrl(callbackState, options?.callbackUrl)\n\t\t\t: undefined\n\n\treturn {\n\t\tautoClose: options?.autoClose ?? true,\n\t\tcallbackUrl,\n\t\tcallbackState,\n\t\torigin: parentOrigin,\n\t\tpreferredChannel: params.preferredChannel,\n\t}\n}\n\nfunction appendLoginLaunchHash(\n\turlValue: string,\n\tpayload: ReturnType<typeof buildLoginLaunchPayload>,\n) {\n\tconst hashParams = new URLSearchParams()\n\tif (payload.autoClose === false) {\n\t\thashParams.set(\"ydAutoClose\", \"false\")\n\t}\n\tif (payload.origin) {\n\t\thashParams.set(\"ydOrigin\", payload.origin)\n\t}\n\tif (payload.callbackUrl) {\n\t\thashParams.set(\"ydCallbackUrl\", payload.callbackUrl)\n\t}\n\tif (payload.preferredChannel) {\n\t\thashParams.set(\"ydPreferredChannel\", payload.preferredChannel)\n\t}\n\tconst hash = hashParams.toString()\n\tif (!hash) {\n\t\treturn urlValue\n\t}\n\n\ttry {\n\t\tconst url = new URL(urlValue)\n\t\turl.hash = hash\n\t\treturn url.toString()\n\t} catch (_error) {\n\t\treturn `${urlValue}#${hash}`\n\t}\n}\n\nfunction buildLoginPopupName(payload: LoginLaunchPayload) {\n\treturn `youidian-login:${JSON.stringify(payload)}`\n}\n\nfunction buildLoginUrl(\n\tparams: LoginParams,\n\toptions: LoginUIOptions | undefined,\n\tlaunchPayload: LoginLaunchPayload,\n): string {\n\tconst { appId, baseUrl = \"https://pay.imgto.link\", loginUrl } = params\n\tconst rawBase = (loginUrl || baseUrl).replace(/\\/$/, \"\")\n\tconst parentOrigin = launchPayload.origin\n\n\tlet finalUrl: string\n\ttry {\n\t\tconst url = new URL(rawBase)\n\t\tif (!/\\/auth\\/connect\\/[^/]+$/.test(url.pathname)) {\n\t\t\turl.pathname =\n\t\t\t\t`${url.pathname.replace(/\\/$/, \"\")}/auth/connect/${appId}`.replace(\n\t\t\t\t\t/\\/{2,}/g,\n\t\t\t\t\t\"/\",\n\t\t\t\t)\n\t\t}\n\t\tfinalUrl = url.toString()\n\t} catch (_error) {\n\t\tif (/\\/auth\\/connect\\/[^/]+$/.test(rawBase)) {\n\t\t\tfinalUrl = rawBase\n\t\t} else {\n\t\t\tfinalUrl = `${rawBase}/auth/connect/${appId}`.replace(/\\/{2,}/g, \"/\")\n\t\t}\n\t}\n\n\tfinalUrl = applyLocaleToUrl(finalUrl, getAutoResolvedLocale(params.locale))\n\n\ttry {\n\t\tconst url = new URL(finalUrl)\n\t\tif (params.preferredChannel) {\n\t\t\turl.searchParams.set(\"preferredChannel\", params.preferredChannel)\n\t\t}\n\t\tif (options?.autoClose === false) {\n\t\t\turl.searchParams.set(\"autoClose\", \"false\")\n\t\t}\n\t\tif (parentOrigin) {\n\t\t\turl.searchParams.set(\"origin\", parentOrigin)\n\t\t}\n\t\treturn appendLoginLaunchHash(url.toString(), launchPayload)\n\t} catch (_error) {\n\t\tconst searchParams = new URLSearchParams()\n\t\tif (params.preferredChannel) {\n\t\t\tsearchParams.set(\"preferredChannel\", params.preferredChannel)\n\t\t}\n\t\tif (options?.autoClose === false) {\n\t\t\tsearchParams.set(\"autoClose\", \"false\")\n\t\t}\n\t\tif (parentOrigin) {\n\t\t\tsearchParams.set(\"origin\", parentOrigin)\n\t\t}\n\t\tconst query = searchParams.toString()\n\t\tif (!query) {\n\t\t\treturn appendLoginLaunchHash(finalUrl, launchPayload)\n\t\t}\n\t\tconst separator = finalUrl.includes(\"?\") ? \"&\" : \"?\"\n\t\treturn appendLoginLaunchHash(\n\t\t\t`${finalUrl}${separator}${query}`,\n\t\t\tlaunchPayload,\n\t\t)\n\t}\n}\n\nfunction extractLoginResult(data: LoginEventData): LoginResult {\n\treturn {\n\t\tavatar: data.avatar,\n\t\tchannel: data.channel,\n\t\temail: data.email,\n\t\texpiresAt: data.expiresAt,\n\t\tlegacyCasdoorId: data.legacyCasdoorId,\n\t\tloginToken: data.loginToken,\n\t\tname: data.name,\n\t\tusername: data.username,\n\t\tphoneCountryCode: data.phoneCountryCode,\n\t\tphoneNumber: data.phoneNumber,\n\t\tphoneE164: data.phoneE164,\n\t\tphoneVerifiedAt: data.phoneVerifiedAt,\n\t\tuserId: data.userId,\n\t\twechatOpenId: data.wechatOpenId,\n\t\twechatUnionId: data.wechatUnionId,\n\t}\n}\n\nconst LOGIN_UI_LOG_PREFIX = \"[Youidian LoginUI]\"\nconst LOGIN_CALLBACK_MARKER = \"yd_login_callback\"\nconst LOGIN_CALLBACK_RESULT_PARAM = \"yd_login_result\"\nconst LOGIN_CALLBACK_RETURN_HASH_PARAM = \"yd_login_return_hash\"\nconst LOGIN_CALLBACK_STATE_PARAM = \"yd_login_state\"\nconst LOGIN_CALLBACK_STORAGE_PREFIX = \"yd-login-callback:\"\n\ntype LoginLaunchPayload = ReturnType<typeof buildLoginLaunchPayload>\n\nfunction decodeCallbackPayload(value: string): LoginEventData | null {\n\ttry {\n\t\tconst padded = value.padEnd(\n\t\t\tvalue.length + ((4 - (value.length % 4)) % 4),\n\t\t\t\"=\",\n\t\t)\n\t\tconst base64 = padded.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\")\n\t\tconst binary = atob(base64)\n\t\tconst json = decodeURIComponent(\n\t\t\tArray.from(\n\t\t\t\tbinary,\n\t\t\t\t(char) => `%${char.charCodeAt(0).toString(16).padStart(2, \"0\")}`,\n\t\t\t).join(\"\"),\n\t\t)\n\t\tconst parsed = JSON.parse(json) as LoginEventData\n\t\treturn parsed && typeof parsed === \"object\" && parsed.type ? parsed : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction getLoginCallbackChannelName(state: string) {\n\treturn `youidian-login:${state}`\n}\n\nfunction getLoginCallbackStorageKey(state: string) {\n\treturn `${LOGIN_CALLBACK_STORAGE_PREFIX}${state}`\n}\n\nfunction publishLoginCallback(state: string, data: LoginEventData) {\n\ttry {\n\t\tconst channel = new BroadcastChannel(getLoginCallbackChannelName(state))\n\t\tchannel.postMessage(data)\n\t\tchannel.close()\n\t} catch {\n\t\t// BroadcastChannel is not available in every embedded browser.\n\t}\n\n\ttry {\n\t\tconst storageKey = getLoginCallbackStorageKey(state)\n\t\twindow.localStorage.setItem(storageKey, JSON.stringify(data))\n\t\twindow.setTimeout(() => {\n\t\t\ttry {\n\t\t\t\twindow.localStorage.removeItem(storageKey)\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup failures.\n\t\t\t}\n\t\t}, 800)\n\t} catch {\n\t\t// localStorage may be disabled; postMessage remains available below.\n\t}\n\n\ttry {\n\t\twindow.opener?.postMessage(data, window.location.origin)\n\t} catch {\n\t\t// opener is only an opportunistic fast path.\n\t}\n}\n\nfunction safeIsPopupClosed(popup: Window | null) {\n\tif (!popup) return true\n\ttry {\n\t\treturn popup.closed\n\t} catch {\n\t\tlogLoginDebug(\"Unable to read popup.closed; treating popup as open\")\n\t\treturn false\n\t}\n}\n\nfunction safeClosePopup(popup: Window | null) {\n\tif (!popup) return\n\ttry {\n\t\tpopup.close()\n\t} catch {\n\t\tlogLoginDebug(\"Unable to close popup\")\n\t}\n}\n\nfunction cleanLoginCallbackUrl(url: URL) {\n\turl.searchParams.delete(LOGIN_CALLBACK_MARKER)\n\turl.searchParams.delete(LOGIN_CALLBACK_STATE_PARAM)\n\tconst returnHash = url.searchParams.get(LOGIN_CALLBACK_RETURN_HASH_PARAM)\n\turl.searchParams.delete(LOGIN_CALLBACK_RETURN_HASH_PARAM)\n\turl.hash = returnHash ? `#${returnHash}` : \"\"\n\treturn url.toString()\n}\n\nexport function handleLoginCallbackIfPresent(options?: LoginCallbackOptions) {\n\tif (typeof window === \"undefined\") {\n\t\treturn false\n\t}\n\n\tconst url = new URL(window.location.href)\n\tif (url.searchParams.get(LOGIN_CALLBACK_MARKER) !== \"1\") {\n\t\treturn false\n\t}\n\n\tconst state = url.searchParams.get(LOGIN_CALLBACK_STATE_PARAM) || \"\"\n\tconst hashParams = new URLSearchParams(url.hash.replace(/^#/, \"\"))\n\tconst rawResult = hashParams.get(LOGIN_CALLBACK_RESULT_PARAM)\n\tconst data: LoginEventData | null =\n\t\trawResult && state\n\t\t\t? decodeCallbackPayload(rawResult)\n\t\t\t: {\n\t\t\t\t\ttype: \"LOGIN_ERROR\",\n\t\t\t\t\tmessage: \"Missing login callback result\",\n\t\t\t\t}\n\n\ttry {\n\t\tdocument.documentElement.style.visibility = \"hidden\"\n\t} catch {\n\t\t// This is best-effort to avoid a visible callback-page flash.\n\t}\n\n\tif (state && data) {\n\t\tpublishLoginCallback(state, data)\n\t}\n\n\ttry {\n\t\twindow.history.replaceState(null, \"\", cleanLoginCallbackUrl(url))\n\t} catch {\n\t\t// Ignore history cleanup failures.\n\t}\n\n\tif (options?.autoClose === true) {\n\t\twindow.setTimeout(() => {\n\t\t\ttry {\n\t\t\t\twindow.close()\n\t\t\t} catch {\n\t\t\t\t// Some browsers disallow script-closing the current window.\n\t\t\t}\n\t\t}, 30)\n\t\treturn true\n\t}\n\n\ttry {\n\t\tdocument.documentElement.style.visibility = \"\"\n\t} catch {\n\t\t// Ignore visibility restoration failures.\n\t}\n\n\treturn true\n}\n\nfunction logLoginDebug(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.debug(LOGIN_UI_LOG_PREFIX, message, details || {})\n}\n\nfunction logLoginInfo(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.info(LOGIN_UI_LOG_PREFIX, message, details || {})\n}\n\nfunction logLoginWarn(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.warn(LOGIN_UI_LOG_PREFIX, message, details || {})\n}\n\nexport class LoginUI extends HostedFrameModal<LoginEventData> {\n\tprivate popup: Window | null = null\n\tprivate callbackChannel: BroadcastChannel | null = null\n\tprivate callbackStorageHandler: ((event: StorageEvent) => void) | null = null\n\tprivate popupMessageHandler: ((event: MessageEvent) => void) | null = null\n\tprivate closeMonitor: number | null = null\n\tprivate completed = false\n\n\tprivate cleanup() {\n\t\tif (this.callbackChannel) {\n\t\t\tthis.callbackChannel.close()\n\t\t}\n\t\tif (typeof window !== \"undefined\" && this.callbackStorageHandler) {\n\t\t\twindow.removeEventListener(\"storage\", this.callbackStorageHandler)\n\t\t}\n\t\tif (typeof window !== \"undefined\" && this.popupMessageHandler) {\n\t\t\twindow.removeEventListener(\"message\", this.popupMessageHandler)\n\t\t}\n\t\tthis.callbackChannel = null\n\t\tthis.callbackStorageHandler = null\n\t\tif (typeof window !== \"undefined\" && this.closeMonitor) {\n\t\t\twindow.clearInterval(this.closeMonitor)\n\t\t}\n\t\tthis.popupMessageHandler = null\n\t\tthis.closeMonitor = null\n\t\tthis.popup = null\n\t\tthis.completed = false\n\t}\n\n\tprivate handleLoginEvent(data: LoginEventData, options?: LoginUIOptions) {\n\t\tif (!data || typeof data !== \"object\" || !data.type) {\n\t\t\tlogLoginDebug(\"Ignored non-login event payload\")\n\t\t\treturn\n\t\t}\n\n\t\tlogLoginInfo(\"Received login event\", {\n\t\t\ttype: data.type,\n\t\t})\n\n\t\tswitch (data.type) {\n\t\t\tcase \"LOGIN_SUCCESS\":\n\t\t\t\tif (this.completed) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthis.completed = true\n\t\t\t\tlogLoginInfo(\"Login succeeded\", {\n\t\t\t\t\tchannel: data.channel || null,\n\t\t\t\t\tuserId: data.userId || null,\n\t\t\t\t})\n\t\t\t\toptions?.onSuccess?.(extractLoginResult(data))\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_CANCELLED\":\n\t\t\t\tlogLoginInfo(\"Login cancelled\")\n\t\t\t\toptions?.onCancel?.()\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_RESIZE\":\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_ERROR\":\n\t\t\t\tif (this.completed) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tlogLoginWarn(\"Login flow reported an error\", {\n\t\t\t\t\tmessage: data.message || data.error || null,\n\t\t\t\t})\n\t\t\t\toptions?.onError?.(data.message || data.error, data)\n\t\t\t\tbreak\n\t\t\tcase \"LOGIN_CLOSE\":\n\t\t\t\tif (options?.autoClose === false) {\n\t\t\t\t\tlogLoginInfo(\n\t\t\t\t\t\t\"Login surface requested close; autoClose disabled, keeping it open\",\n\t\t\t\t\t)\n\t\t\t\t\toptions?.onClose?.()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tlogLoginInfo(\"Login surface requested close; autoClose enabled\")\n\t\t\t\tthis.close()\n\t\t\t\toptions?.onClose?.()\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate listenForLoginCallback(\n\t\tcallbackState: string,\n\t\toptions?: LoginUIOptions,\n\t) {\n\t\ttry {\n\t\t\tthis.callbackChannel = new BroadcastChannel(\n\t\t\t\tgetLoginCallbackChannelName(callbackState),\n\t\t\t)\n\t\t\tthis.callbackChannel.onmessage = (event) => {\n\t\t\t\tthis.handleLoginEvent(event.data as LoginEventData, options)\n\t\t\t\tthis.handleLoginEvent({ type: \"LOGIN_CLOSE\" }, options)\n\t\t\t}\n\t\t} catch {\n\t\t\tlogLoginDebug(\"BroadcastChannel is unavailable for login callback\")\n\t\t}\n\n\t\tthis.callbackStorageHandler = (event: StorageEvent) => {\n\t\t\tif (\n\t\t\t\tevent.key !== getLoginCallbackStorageKey(callbackState) ||\n\t\t\t\t!event.newValue\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(event.newValue) as LoginEventData\n\t\t\t\tthis.handleLoginEvent(data, options)\n\t\t\t\tthis.handleLoginEvent({ type: \"LOGIN_CLOSE\" }, options)\n\t\t\t} catch {\n\t\t\t\tlogLoginWarn(\"Failed to parse login callback storage payload\")\n\t\t\t}\n\t\t}\n\t\twindow.addEventListener(\"storage\", this.callbackStorageHandler)\n\t}\n\n\tclose() {\n\t\tlogLoginInfo(\"close() called\", {\n\t\t\thasModal: Boolean(this.modal),\n\t\t\thasPopup: Boolean(this.popup),\n\t\t\tpopupClosed: safeIsPopupClosed(this.popup),\n\t\t})\n\t\tsafeClosePopup(this.popup)\n\t\tsuper.close()\n\t\tthis.cleanup()\n\t}\n\n\tprivate buildOpenContext(params: LoginParams, options?: LoginUIOptions) {\n\t\tconst callbackState = createLoginCallbackState()\n\t\tconst launchPayload = buildLoginLaunchPayload(\n\t\t\tparams,\n\t\t\toptions,\n\t\t\tcallbackState,\n\t\t)\n\t\tconst finalUrl = buildLoginUrl(params, options, launchPayload)\n\t\treturn { callbackState, finalUrl, launchPayload }\n\t}\n\n\tprivate openLoginModal(params: LoginParams, options?: LoginUIOptions) {\n\t\tif (typeof document === \"undefined\") return\n\t\tif (this.modal) return\n\n\t\tconst { callbackState, finalUrl, launchPayload } = this.buildOpenContext(\n\t\t\tparams,\n\t\t\toptions,\n\t\t)\n\t\tconst loginOrigin = getOrigin(finalUrl)\n\t\tlogLoginInfo(\"Opening hosted login iframe modal\", {\n\t\t\tappId: params.appId,\n\t\t\tcallbackState,\n\t\t\tcallbackUrl: launchPayload.callbackUrl || null,\n\t\t\thasCallbackUrl: Boolean(launchPayload.callbackUrl),\n\t\t\tloginUrl: finalUrl,\n\t\t\tallowedOrigin: options?.allowedOrigin || null,\n\t\t\tautoClose: options?.autoClose ?? true,\n\t\t\tdisplayMode: \"modal\",\n\t\t\tpageUrl: typeof window !== \"undefined\" ? window.location.href : null,\n\t\t\tparentOrigin: launchPayload.origin || null,\n\t\t})\n\n\t\tthis.completed = false\n\t\tthis.listenForLoginCallback(callbackState, options)\n\t\tthis.openHostedFrame(finalUrl, {\n\t\t\tallowedOrigin: options?.allowedOrigin || loginOrigin || undefined,\n\t\t\theight: \"min(760px, 94vh)\",\n\t\t\tonCloseButton: () => {\n\t\t\t\toptions?.onCancel?.()\n\t\t\t\toptions?.onClose?.()\n\t\t\t},\n\t\t\tonMessage: (data, container) => {\n\t\t\t\tif (data.type === \"LOGIN_RESIZE\" && data.height) {\n\t\t\t\t\tconst maxHeight = window.innerHeight * 0.94\n\t\t\t\t\tcontainer.style.height = `${Math.min(data.height, maxHeight)}px`\n\t\t\t\t}\n\t\t\t\tthis.handleLoginEvent(data, options)\n\t\t\t},\n\t\t\twidth: \"min(520px, 100%)\",\n\t\t})\n\t}\n\n\tprivate openLoginPopup(params: LoginParams, options?: LoginUIOptions) {\n\t\tif (typeof window === \"undefined\") return\n\t\tif (this.popup && !safeIsPopupClosed(this.popup)) return\n\n\t\tconst { callbackState, finalUrl, launchPayload } = this.buildOpenContext(\n\t\t\tparams,\n\t\t\toptions,\n\t\t)\n\t\tlogLoginInfo(\"Opening hosted login popup\", {\n\t\t\tappId: params.appId,\n\t\t\tcallbackState,\n\t\t\tcallbackUrl: launchPayload.callbackUrl || null,\n\t\t\thasCallbackUrl: Boolean(launchPayload.callbackUrl),\n\t\t\tloginUrl: finalUrl,\n\t\t\tallowedOrigin: options?.allowedOrigin || null,\n\t\t\tautoClose: options?.autoClose ?? true,\n\t\t\tdisplayMode: \"popup\",\n\t\t\tpageUrl: typeof window !== \"undefined\" ? window.location.href : null,\n\t\t\tparentOrigin: launchPayload.origin || null,\n\t\t})\n\t\tconst popupWidth = 520\n\t\tconst popupHeight = 720\n\t\tconst left = Math.max(\n\t\t\t0,\n\t\t\tMath.round(window.screenX + (window.outerWidth - popupWidth) / 2),\n\t\t)\n\t\tconst top = Math.max(\n\t\t\t0,\n\t\t\tMath.round(window.screenY + (window.outerHeight - popupHeight) / 2),\n\t\t)\n\t\tconst features = [\n\t\t\t\"popup=yes\",\n\t\t\t`width=${popupWidth}`,\n\t\t\t`height=${popupHeight}`,\n\t\t\t`left=${left}`,\n\t\t\t`top=${top}`,\n\t\t\t\"resizable=yes\",\n\t\t\t\"scrollbars=yes\",\n\t\t].join(\",\")\n\n\t\tconst popupName = buildLoginPopupName(launchPayload)\n\t\tconst popup = window.open(finalUrl, popupName, features)\n\t\tif (!popup) {\n\t\t\tlogLoginWarn(\"Popup blocked by the browser\")\n\t\t\toptions?.onError?.(\"Login popup was blocked\")\n\t\t\treturn\n\t\t}\n\n\t\tthis.popup = popup\n\t\tthis.completed = false\n\t\tthis.listenForLoginCallback(callbackState, options)\n\n\t\tconst allowedOrigin = options?.allowedOrigin\n\t\tconst popupOrigin = getOrigin(finalUrl)\n\n\t\tthis.popupMessageHandler = (event: MessageEvent) => {\n\t\t\tif (\n\t\t\t\tallowedOrigin &&\n\t\t\t\tallowedOrigin !== \"*\" &&\n\t\t\t\tevent.origin !== allowedOrigin\n\t\t\t) {\n\t\t\t\tlogLoginWarn(\"Ignored message due to allowedOrigin mismatch\", {\n\t\t\t\t\tallowedOrigin,\n\t\t\t\t\teventOrigin: event.origin,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!allowedOrigin && popupOrigin && event.origin !== popupOrigin) {\n\t\t\t\tlogLoginWarn(\"Ignored message due to popup origin mismatch\", {\n\t\t\t\t\texpectedOrigin: popupOrigin,\n\t\t\t\t\teventOrigin: event.origin,\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst data = event.data as LoginEventData\n\t\t\tif (!data || typeof data !== \"object\" || !data.type) {\n\t\t\t\tlogLoginDebug(\"Ignored non-login postMessage payload\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlogLoginInfo(\"Received login event\", {\n\t\t\t\ttype: data.type,\n\t\t\t\teventOrigin: event.origin,\n\t\t\t})\n\n\t\t\tthis.handleLoginEvent(data, options)\n\t\t}\n\n\t\twindow.addEventListener(\"message\", this.popupMessageHandler)\n\n\t\tif (options?.monitorPopupClosed === true) {\n\t\t\tthis.closeMonitor = window.setInterval(() => {\n\t\t\t\tif (!this.popup || safeIsPopupClosed(this.popup)) {\n\t\t\t\t\tconst shouldTreatAsCancel = !this.completed\n\t\t\t\t\tlogLoginInfo(\"Detected popup closed\", {\n\t\t\t\t\t\tshouldTreatAsCancel,\n\t\t\t\t\t})\n\t\t\t\t\tthis.cleanup()\n\t\t\t\t\tif (shouldTreatAsCancel) {\n\t\t\t\t\t\toptions?.onCancel?.()\n\t\t\t\t\t}\n\t\t\t\t\toptions?.onClose?.()\n\t\t\t\t}\n\t\t\t}, 500)\n\t\t}\n\t}\n\n\topenLogin(params: LoginParams, options?: LoginUIOptions) {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tconst displayMode = options?.displayMode ?? \"modal\"\n\t\tif (displayMode === \"popup\") {\n\t\t\tthis.openLoginPopup(params, options)\n\t\t\treturn\n\t\t}\n\t\tthis.openLoginModal(params, options)\n\t}\n}\n\nexport function createLoginUI(): LoginUI {\n\treturn new LoginUI()\n}\n\nhandleLoginCallbackIfPresent({ autoClose: false })\n"],"mappings":"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","names":[]}
|
package/dist/client.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HostedFrameModal } from './login-
|
|
2
|
-
export { L as LoginCallbackOptions, a as
|
|
1
|
+
import { H as HostedFrameModal } from './login-CrPTh4In.cjs';
|
|
2
|
+
export { L as LoginCallbackOptions, a as LoginDisplayMode, b as LoginEventData, c as LoginEventType, d as LoginParams, e as LoginResult, f as LoginUI, g as LoginUIOptions, h as createLoginUI, i as handleLoginCallbackIfPresent } from './login-CrPTh4In.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Youidian Payment SDK - Client Module
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HostedFrameModal } from './login-
|
|
2
|
-
export { L as LoginCallbackOptions, a as
|
|
1
|
+
import { H as HostedFrameModal } from './login-CrPTh4In.js';
|
|
2
|
+
export { L as LoginCallbackOptions, a as LoginDisplayMode, b as LoginEventData, c as LoginEventType, d as LoginParams, e as LoginResult, f as LoginUI, g as LoginUIOptions, h as createLoginUI, i as handleLoginCallbackIfPresent } from './login-CrPTh4In.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Youidian Payment SDK - Client Module
|
package/dist/client.js
CHANGED
|
@@ -333,6 +333,11 @@ function extractLoginResult(data) {
|
|
|
333
333
|
legacyCasdoorId: data.legacyCasdoorId,
|
|
334
334
|
loginToken: data.loginToken,
|
|
335
335
|
name: data.name,
|
|
336
|
+
username: data.username,
|
|
337
|
+
phoneCountryCode: data.phoneCountryCode,
|
|
338
|
+
phoneNumber: data.phoneNumber,
|
|
339
|
+
phoneE164: data.phoneE164,
|
|
340
|
+
phoneVerifiedAt: data.phoneVerifiedAt,
|
|
336
341
|
userId: data.userId,
|
|
337
342
|
wechatOpenId: data.wechatOpenId,
|
|
338
343
|
wechatUnionId: data.wechatUnionId
|
|
@@ -471,12 +476,13 @@ function logLoginWarn(message, details) {
|
|
|
471
476
|
if (typeof console === "undefined") return;
|
|
472
477
|
console.warn(LOGIN_UI_LOG_PREFIX, message, details || {});
|
|
473
478
|
}
|
|
474
|
-
var LoginUI = class {
|
|
479
|
+
var LoginUI = class extends HostedFrameModal {
|
|
475
480
|
constructor() {
|
|
481
|
+
super(...arguments);
|
|
476
482
|
__publicField(this, "popup", null);
|
|
477
483
|
__publicField(this, "callbackChannel", null);
|
|
478
484
|
__publicField(this, "callbackStorageHandler", null);
|
|
479
|
-
__publicField(this, "
|
|
485
|
+
__publicField(this, "popupMessageHandler", null);
|
|
480
486
|
__publicField(this, "closeMonitor", null);
|
|
481
487
|
__publicField(this, "completed", false);
|
|
482
488
|
}
|
|
@@ -487,15 +493,15 @@ var LoginUI = class {
|
|
|
487
493
|
if (typeof window !== "undefined" && this.callbackStorageHandler) {
|
|
488
494
|
window.removeEventListener("storage", this.callbackStorageHandler);
|
|
489
495
|
}
|
|
490
|
-
if (typeof window !== "undefined" && this.
|
|
491
|
-
window.removeEventListener("message", this.
|
|
496
|
+
if (typeof window !== "undefined" && this.popupMessageHandler) {
|
|
497
|
+
window.removeEventListener("message", this.popupMessageHandler);
|
|
492
498
|
}
|
|
493
499
|
this.callbackChannel = null;
|
|
494
500
|
this.callbackStorageHandler = null;
|
|
495
501
|
if (typeof window !== "undefined" && this.closeMonitor) {
|
|
496
502
|
window.clearInterval(this.closeMonitor);
|
|
497
503
|
}
|
|
498
|
-
this.
|
|
504
|
+
this.popupMessageHandler = null;
|
|
499
505
|
this.closeMonitor = null;
|
|
500
506
|
this.popup = null;
|
|
501
507
|
this.completed = false;
|
|
@@ -538,12 +544,12 @@ var LoginUI = class {
|
|
|
538
544
|
case "LOGIN_CLOSE":
|
|
539
545
|
if (options?.autoClose === false) {
|
|
540
546
|
logLoginInfo(
|
|
541
|
-
"Login
|
|
547
|
+
"Login surface requested close; autoClose disabled, keeping it open"
|
|
542
548
|
);
|
|
543
549
|
options?.onClose?.();
|
|
544
550
|
break;
|
|
545
551
|
}
|
|
546
|
-
logLoginInfo("Login
|
|
552
|
+
logLoginInfo("Login surface requested close; autoClose enabled");
|
|
547
553
|
this.close();
|
|
548
554
|
options?.onClose?.();
|
|
549
555
|
break;
|
|
@@ -577,15 +583,15 @@ var LoginUI = class {
|
|
|
577
583
|
}
|
|
578
584
|
close() {
|
|
579
585
|
logLoginInfo("close() called", {
|
|
586
|
+
hasModal: Boolean(this.modal),
|
|
580
587
|
hasPopup: Boolean(this.popup),
|
|
581
588
|
popupClosed: safeIsPopupClosed(this.popup)
|
|
582
589
|
});
|
|
583
590
|
safeClosePopup(this.popup);
|
|
591
|
+
super.close();
|
|
584
592
|
this.cleanup();
|
|
585
593
|
}
|
|
586
|
-
|
|
587
|
-
if (typeof window === "undefined") return;
|
|
588
|
-
if (this.popup && !safeIsPopupClosed(this.popup)) return;
|
|
594
|
+
buildOpenContext(params, options) {
|
|
589
595
|
const callbackState = createLoginCallbackState();
|
|
590
596
|
const launchPayload = buildLoginLaunchPayload(
|
|
591
597
|
params,
|
|
@@ -593,6 +599,54 @@ var LoginUI = class {
|
|
|
593
599
|
callbackState
|
|
594
600
|
);
|
|
595
601
|
const finalUrl = buildLoginUrl(params, options, launchPayload);
|
|
602
|
+
return { callbackState, finalUrl, launchPayload };
|
|
603
|
+
}
|
|
604
|
+
openLoginModal(params, options) {
|
|
605
|
+
if (typeof document === "undefined") return;
|
|
606
|
+
if (this.modal) return;
|
|
607
|
+
const { callbackState, finalUrl, launchPayload } = this.buildOpenContext(
|
|
608
|
+
params,
|
|
609
|
+
options
|
|
610
|
+
);
|
|
611
|
+
const loginOrigin = getOrigin(finalUrl);
|
|
612
|
+
logLoginInfo("Opening hosted login iframe modal", {
|
|
613
|
+
appId: params.appId,
|
|
614
|
+
callbackState,
|
|
615
|
+
callbackUrl: launchPayload.callbackUrl || null,
|
|
616
|
+
hasCallbackUrl: Boolean(launchPayload.callbackUrl),
|
|
617
|
+
loginUrl: finalUrl,
|
|
618
|
+
allowedOrigin: options?.allowedOrigin || null,
|
|
619
|
+
autoClose: options?.autoClose ?? true,
|
|
620
|
+
displayMode: "modal",
|
|
621
|
+
pageUrl: typeof window !== "undefined" ? window.location.href : null,
|
|
622
|
+
parentOrigin: launchPayload.origin || null
|
|
623
|
+
});
|
|
624
|
+
this.completed = false;
|
|
625
|
+
this.listenForLoginCallback(callbackState, options);
|
|
626
|
+
this.openHostedFrame(finalUrl, {
|
|
627
|
+
allowedOrigin: options?.allowedOrigin || loginOrigin || void 0,
|
|
628
|
+
height: "min(760px, 94vh)",
|
|
629
|
+
onCloseButton: () => {
|
|
630
|
+
options?.onCancel?.();
|
|
631
|
+
options?.onClose?.();
|
|
632
|
+
},
|
|
633
|
+
onMessage: (data, container) => {
|
|
634
|
+
if (data.type === "LOGIN_RESIZE" && data.height) {
|
|
635
|
+
const maxHeight = window.innerHeight * 0.94;
|
|
636
|
+
container.style.height = `${Math.min(data.height, maxHeight)}px`;
|
|
637
|
+
}
|
|
638
|
+
this.handleLoginEvent(data, options);
|
|
639
|
+
},
|
|
640
|
+
width: "min(520px, 100%)"
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
openLoginPopup(params, options) {
|
|
644
|
+
if (typeof window === "undefined") return;
|
|
645
|
+
if (this.popup && !safeIsPopupClosed(this.popup)) return;
|
|
646
|
+
const { callbackState, finalUrl, launchPayload } = this.buildOpenContext(
|
|
647
|
+
params,
|
|
648
|
+
options
|
|
649
|
+
);
|
|
596
650
|
logLoginInfo("Opening hosted login popup", {
|
|
597
651
|
appId: params.appId,
|
|
598
652
|
callbackState,
|
|
@@ -601,6 +655,7 @@ var LoginUI = class {
|
|
|
601
655
|
loginUrl: finalUrl,
|
|
602
656
|
allowedOrigin: options?.allowedOrigin || null,
|
|
603
657
|
autoClose: options?.autoClose ?? true,
|
|
658
|
+
displayMode: "popup",
|
|
604
659
|
pageUrl: typeof window !== "undefined" ? window.location.href : null,
|
|
605
660
|
parentOrigin: launchPayload.origin || null
|
|
606
661
|
});
|
|
@@ -635,7 +690,7 @@ var LoginUI = class {
|
|
|
635
690
|
this.listenForLoginCallback(callbackState, options);
|
|
636
691
|
const allowedOrigin = options?.allowedOrigin;
|
|
637
692
|
const popupOrigin = getOrigin(finalUrl);
|
|
638
|
-
this.
|
|
693
|
+
this.popupMessageHandler = (event) => {
|
|
639
694
|
if (allowedOrigin && allowedOrigin !== "*" && event.origin !== allowedOrigin) {
|
|
640
695
|
logLoginWarn("Ignored message due to allowedOrigin mismatch", {
|
|
641
696
|
allowedOrigin,
|
|
@@ -661,7 +716,7 @@ var LoginUI = class {
|
|
|
661
716
|
});
|
|
662
717
|
this.handleLoginEvent(data, options);
|
|
663
718
|
};
|
|
664
|
-
window.addEventListener("message", this.
|
|
719
|
+
window.addEventListener("message", this.popupMessageHandler);
|
|
665
720
|
if (options?.monitorPopupClosed === true) {
|
|
666
721
|
this.closeMonitor = window.setInterval(() => {
|
|
667
722
|
if (!this.popup || safeIsPopupClosed(this.popup)) {
|
|
@@ -678,6 +733,15 @@ var LoginUI = class {
|
|
|
678
733
|
}, 500);
|
|
679
734
|
}
|
|
680
735
|
}
|
|
736
|
+
openLogin(params, options) {
|
|
737
|
+
if (typeof window === "undefined") return;
|
|
738
|
+
const displayMode = options?.displayMode ?? "modal";
|
|
739
|
+
if (displayMode === "popup") {
|
|
740
|
+
this.openLoginPopup(params, options);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
this.openLoginModal(params, options);
|
|
744
|
+
}
|
|
681
745
|
};
|
|
682
746
|
function createLoginUI() {
|
|
683
747
|
return new LoginUI();
|
|
@@ -718,7 +782,10 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
718
782
|
);
|
|
719
783
|
}
|
|
720
784
|
}
|
|
721
|
-
const finalUrl = applyLocaleToUrl(
|
|
785
|
+
const finalUrl = applyLocaleToUrl(
|
|
786
|
+
checkoutUrl,
|
|
787
|
+
getAutoResolvedLocale(options?.locale)
|
|
788
|
+
);
|
|
722
789
|
this.openHostedFrame(finalUrl, {
|
|
723
790
|
allowedOrigin: options?.allowedOrigin,
|
|
724
791
|
onCloseButton: () => options?.onCancel?.(),
|