{"version":3,"sources":["../src/index.ts","../src/brand-logo.ts","../src/hosted-modal.ts","../src/environment.ts","../src/login.ts","../src/client.ts","../src/feedback.ts","../src/server.ts"],"sourcesContent":["/**\n * Youidian SDK\n * Unified payment and hosted login SDK\n *\n * @packageDocumentation\n */\n\nexport type {\n\tOrderStatus as ClientOrderStatus,\n\tPaymentEventData,\n\tPaymentEventType,\n\tPaymentParams,\n\tPaymentUIOptions,\n\tPollOptions,\n\tWechatMessageBindingUIOptions,\n} from \"./client\"\nexport {\n\tcreateMessageUI,\n\tcreatePaymentUI,\n\tMessageUI,\n\tPaymentUI,\n} from \"./client\"\nexport type {\n\tLoginDeviceType,\n\tLoginEnvironment,\n\tLoginEnvironmentInput,\n} from \"./environment\"\nexport { detectLoginEnvironment } from \"./environment\"\nexport type {\n\tFeedbackActor,\n\tFeedbackCategoryOption,\n\tFeedbackIdentityKind,\n\tFeedbackWidgetController,\n\tFeedbackWidgetOptions,\n} from \"./feedback\"\nexport { createFeedbackWidget, mountFeedbackWidget } from \"./feedback\"\nexport type {\n\tLoginCallbackOptions,\n\tLoginDisplayMode,\n\tLoginEventData,\n\tLoginEventType,\n\tLoginFallbackRedirectMode,\n\tLoginParams,\n\tLoginResult,\n\tLoginUIOptions,\n} from \"./login\"\nexport { createLoginUI, handleLoginCallbackIfPresent, LoginUI } from \"./login\"\nexport type {\n\tActiveSubscriptionInfo,\n\tBillingSnapshot,\n\tBindPhoneNumberParams,\n\tBindPhoneNumberResponse,\n\tCancelOrderResponse,\n\tCompleteFreeOrderResponse,\n\tCreateBankTransferOrderParams,\n\tCreateMiniProgramOrderParams,\n\tCreateOrderParams,\n\tCreateOrderResponse,\n\tCreateWechatMessageBindingParams,\n\tCreateWechatMessageBindingResponse,\n\tCustomAmountRechargeRule,\n\tCustomAmountRechargeValidationResult,\n\tDiscountPolicy,\n\tGetPhoneBindingParams,\n\tMerchantPricing,\n\tMerchantPricingBreakdownItem,\n\tMerchantPricingSnapshot,\n\tMessageTemplateDataValue,\n\tOrderDetails,\n\tOrderStatus,\n\tPaymentCallbackData,\n\tPaymentClientOptions,\n\tPaymentNotification,\n\tPhoneBinding,\n\tPricingBreakdown,\n\tProduct,\n\tProductCustomAmount,\n\tProductCustomAmountCurrency,\n\tProductEntitlements,\n\tProductInventory,\n\tProductMetadata,\n\tProductPrice,\n\tProductResetRule,\n\tProductStock,\n\tProductStockLookupMode,\n\tProductStockQueryOptions,\n\tProductStocksQueryParams,\n\tProductSubscriptionPeriod,\n\tRefundOrderParams,\n\tRefundOrderResponse,\n\tSendMessageParams,\n\tSendMessageResponse,\n\tSendPhoneVerificationCodeParams,\n\tSendPhoneVerificationCodeResponse,\n\tSubscriptionAction,\n\tSubscriptionAutoRefundStatus,\n\tSubscriptionBillingSnapshot,\n\tSubscriptionDetails,\n\tSubscriptionErrorCode,\n\tSubscriptionStatus,\n\tUpdatePhoneNumberParams,\n\tUpdatePhoneNumberResponse,\n\tUserProductDiscountEligibility,\n\tVerifiedLoginToken,\n\tWebhookPayload,\n\tWechatJsapiPayParams,\n} from \"./server\"\nexport {\n\tgetCustomAmountRechargeRule,\n\tPaymentApiError,\n\tPaymentClient,\n\tvalidateCustomAmountRecharge,\n} from \"./server\"\n","export type SdkBrandLogoCopy = {\n\tlanguage: string\n\tname: string\n\tsubtitle: string\n}\n\nexport type SdkBrandLogoTheme = {\n\tforeground: string\n\tmuted: string\n\tprimary: string\n\tsecondary: string\n}\n\nexport type SdkFallbackArtworkTheme = {\n\tprimary: string\n\tprimary10: string\n\tprimary14: string\n\tprimary20: string\n\tprimary28: string\n\tprimary36: string\n\tsecondary: string\n}\n\ntype SdkBrandLogoMarkOptions = {\n\tanimated?: boolean\n\tinverted?: boolean\n\tsize: number\n\ttheme: SdkBrandLogoTheme\n\tvariant?: \"brand\" | \"mark\"\n}\n\ntype SdkBrandLogoOptions = {\n\tanimated?: boolean\n\tbrand: SdkBrandLogoCopy\n\tbrandWidth?: number\n\tcopyWidth?: number\n\tgap?: number\n\tmarkMarginRight?: number\n\tmarkSize: number\n\tnameSize: number\n\tsubtitleMarginTop?: number\n\tsubtitleSize: number\n\tsubtitleWeight?: string\n\ttheme: SdkBrandLogoTheme\n\tvariant?: \"brand\" | \"mark\"\n}\n\nfunction ensureSdkBrandLogoStyles() {\n\tif (document.getElementById?.(\"youidian-sdk-brand-logo-style\")) {\n\t\treturn\n\t}\n\n\tconst style = document.createElement(\"style\")\n\tstyle.id = \"youidian-sdk-brand-logo-style\"\n\tstyle.textContent = `\n\t\t.youidian-sdk-brand-logo__ring,\n\t\t.youidian-sdk-brand-logo__dot,\n\t\t.youidian-sdk-brand-logo__copy,\n\t\t.youidian-sdk-brand-logo__tagline {\n\t\t\ttransform-box: fill-box;\n\t\t\ttransform-origin: center;\n\t\t\twill-change: opacity, transform;\n\t\t}\n\n\t\t.youidian-sdk-brand-logo[data-animated=\"true\"] .youidian-sdk-brand-logo__ring {\n\t\t\tanimation: youidian-sdk-brand-logo-ring 1400ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t.youidian-sdk-brand-logo[data-animated=\"true\"] .youidian-sdk-brand-logo__dot {\n\t\t\tanimation: youidian-sdk-brand-logo-dot 1400ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t.youidian-sdk-brand-logo[data-animated=\"true\"] .youidian-sdk-brand-logo__copy {\n\t\t\tanimation: youidian-sdk-brand-logo-copy 1600ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t.youidian-sdk-brand-logo[data-animated=\"true\"] .youidian-sdk-brand-logo__tagline {\n\t\t\tanimation: youidian-sdk-brand-logo-tagline 1600ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-logo-ring {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.72;\n\t\t\t\ttransform: rotate(0deg) scale(0.98);\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: rotate(8deg) scale(1.02);\n\t\t\t}\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-logo-dot {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.58;\n\t\t\t\ttransform: scale(0.9);\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: scale(1.08);\n\t\t\t}\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-logo-copy {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.86;\n\t\t\t\ttransform: translateY(0);\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: translateY(-1px);\n\t\t\t}\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-logo-tagline {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.64;\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 0.92;\n\t\t\t}\n\t\t}\n\n\t\t@media (prefers-reduced-motion: reduce) {\n\t\t\t.youidian-sdk-brand-logo__ring,\n\t\t\t.youidian-sdk-brand-logo__dot,\n\t\t\t.youidian-sdk-brand-logo__copy,\n\t\t\t.youidian-sdk-brand-logo__tagline {\n\t\t\t\tanimation: none;\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: none;\n\t\t\t}\n\t\t}\n\t`\n\tdocument.head?.appendChild(style)\n}\n\nexport function createSdkBrandLogoMark({\n\tanimated,\n\tinverted,\n\tsize,\n\ttheme,\n\tvariant = \"brand\",\n}: SdkBrandLogoMarkOptions) {\n\tensureSdkBrandLogoStyles()\n\n\tconst mark = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\")\n\tmark.setAttribute(\"viewBox\", \"0 0 512 512\")\n\tmark.setAttribute(\"fill\", \"none\")\n\tmark.setAttribute(\"aria-hidden\", \"true\")\n\tObject.assign(mark.style, {\n\t\twidth: `${size}px`,\n\t\theight: `${size}px`,\n\t\tcolor: inverted ? \"#ffffff\" : theme.primary,\n\t\tdisplay: \"block\",\n\t\tflex: \"0 0 auto\",\n\t\toverflow: \"visible\",\n\t})\n\n\tconst logoGroup = document.createElementNS(\"http://www.w3.org/2000/svg\", \"g\")\n\tlogoGroup.setAttribute(\n\t\t\"transform\",\n\t\tvariant === \"mark\"\n\t\t\t? \"matrix(0.74 0 0 0.74 -124 -114)\"\n\t\t\t: \"matrix(0.58 0 0 0.58 -40 -31)\",\n\t)\n\n\tconst ring = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\")\n\tring.setAttribute(\"class\", animated ? \"youidian-sdk-brand-logo__ring\" : \"\")\n\tring.setAttribute(\"fill\", inverted ? \"currentColor\" : theme.primary)\n\tring.setAttribute(\n\t\t\"d\",\n\t\t\"M704.298 679.54A264 264 0 1 1 704.298 309.46A49 49 0 0 1 634.4 378.149A166 166 0 1 0 634.4 610.851A49 49 0 0 1 704.298 679.54Z\",\n\t)\n\n\tconst dot = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\")\n\tdot.setAttribute(\"class\", animated ? \"youidian-sdk-brand-logo__dot\" : \"\")\n\tdot.setAttribute(\"fill\", inverted ? \"currentColor\" : theme.secondary)\n\tdot.setAttribute(\"cx\", \"714.5\")\n\tdot.setAttribute(\"cy\", \"490.5\")\n\tdot.setAttribute(\"r\", \"68\")\n\tdot.setAttribute(\"opacity\", inverted ? \"0.78\" : \"1\")\n\n\tlogoGroup.appendChild(ring)\n\tlogoGroup.appendChild(dot)\n\tmark.appendChild(logoGroup)\n\treturn mark\n}\n\nexport function createSdkBrandLogo({\n\tanimated,\n\tbrand,\n\tbrandWidth,\n\tcopyWidth,\n\tgap = 10,\n\tmarkMarginRight,\n\tmarkSize,\n\tnameSize,\n\tsubtitleMarginTop = 6,\n\tsubtitleSize,\n\tsubtitleWeight = \"800\",\n\ttheme,\n\tvariant = \"brand\",\n}: SdkBrandLogoOptions) {\n\tensureSdkBrandLogoStyles()\n\n\tconst wrapper = document.createElement(\"div\")\n\twrapper.className = \"youidian-sdk-brand-logo\"\n\twrapper.setAttribute(\"data-animated\", animated ? \"true\" : \"false\")\n\tObject.assign(wrapper.style, {\n\t\tdisplay: \"inline-flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tgap: `${gap}px`,\n\t\twidth: brandWidth ? `${brandWidth}px` : undefined,\n\t})\n\n\tconst copy = document.createElement(\"div\")\n\tcopy.className = \"youidian-sdk-brand-logo__copy\"\n\tcopy.setAttribute(\"data-brand-locale\", brand.language)\n\tObject.assign(copy.style, {\n\t\tdisplay: \"flex\",\n\t\tflexDirection: \"column\",\n\t\talignItems: \"flex-start\",\n\t\tjustifyContent: \"center\",\n\t\tlineHeight: \"1\",\n\t\twidth: copyWidth ? `${copyWidth}px` : undefined,\n\t})\n\n\tconst name = document.createElement(\"div\")\n\tname.className = \"youidian-sdk-brand-logo__name\"\n\tname.textContent = brand.name\n\tObject.assign(name.style, {\n\t\tcolor: theme.foreground,\n\t\tfontFamily:\n\t\t\tbrand.language === \"zh\"\n\t\t\t\t? '\"Noto Sans TC\", \"Inter\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif'\n\t\t\t\t: '\"Unbounded\", \"Space Grotesk\", \"Inter\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif',\n\t\tfontSize: `${nameSize}px`,\n\t\tfontWeight: brand.language === \"zh\" ? \"900\" : \"800\",\n\t\tletterSpacing: brand.language === \"zh\" ? \"0.08em\" : \"0.01em\",\n\t\tlineHeight: \"1\",\n\t\twhiteSpace: \"nowrap\",\n\t})\n\n\tconst subtitle = document.createElement(\"div\")\n\tsubtitle.className = \"youidian-sdk-brand-logo__tagline\"\n\tsubtitle.textContent = brand.subtitle\n\tObject.assign(subtitle.style, {\n\t\tcolor: theme.muted,\n\t\tfontFamily:\n\t\t\tbrand.language === \"zh\"\n\t\t\t\t? '\"Noto Sans TC\", \"Inter\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif'\n\t\t\t\t: '\"Space Grotesk\", \"Inter\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif',\n\t\tfontSize: `${subtitleSize}px`,\n\t\tfontWeight: subtitleWeight,\n\t\tletterSpacing: brand.language === \"zh\" ? \"0.24em\" : \"0.07em\",\n\t\tlineHeight: \"1\",\n\t\tmarginTop: `${subtitleMarginTop}px`,\n\t\ttextTransform: brand.language === \"zh\" ? \"none\" : \"uppercase\",\n\t\twhiteSpace: \"nowrap\",\n\t})\n\n\tcopy.appendChild(name)\n\tcopy.appendChild(subtitle)\n\tconst mark = createSdkBrandLogoMark({\n\t\tanimated,\n\t\tsize: markSize,\n\t\ttheme,\n\t\tvariant,\n\t})\n\tif (typeof markMarginRight === \"number\") {\n\t\tmark.style.marginRight = `${markMarginRight}px`\n\t}\n\twrapper.appendChild(mark)\n\twrapper.appendChild(copy)\n\treturn wrapper\n}\n\nexport function createSdkFallbackArtwork(theme: SdkFallbackArtworkTheme) {\n\tconst artwork = document.createElement(\"div\")\n\tObject.assign(artwork.style, {\n\t\theight: \"164px\",\n\t\tmargin: \"0 auto 34px\",\n\t\tposition: \"relative\",\n\t\twidth: \"184px\",\n\t})\n\n\tconst wash = document.createElement(\"div\")\n\tObject.assign(wash.style, {\n\t\tposition: \"absolute\",\n\t\tleft: \"16px\",\n\t\ttop: \"20px\",\n\t\twidth: \"152px\",\n\t\theight: \"126px\",\n\t\tborderRadius: \"48% 52% 43% 57% / 54% 42% 58% 46%\",\n\t\tbackground: `radial-gradient(circle at 48% 42%, ${theme.primary20}, ${theme.primary10} 52%, transparent 76%)`,\n\t\tfilter: \"blur(1px)\",\n\t\ttransform: \"rotate(-10deg)\",\n\t})\n\n\tconst blob = document.createElement(\"div\")\n\tObject.assign(blob.style, {\n\t\tposition: \"absolute\",\n\t\tleft: \"26px\",\n\t\ttop: \"28px\",\n\t\twidth: \"132px\",\n\t\theight: \"116px\",\n\t\tborderRadius: \"42% 58% 53% 47% / 45% 39% 61% 55%\",\n\t\tbackground: `linear-gradient(150deg, ${theme.primary14}, ${theme.primary10})`,\n\t\tboxShadow: `0 30px 64px ${theme.primary14}`,\n\t\ttransform: \"rotate(8deg)\",\n\t})\n\n\tconst tile = document.createElement(\"div\")\n\tObject.assign(tile.style, {\n\t\tposition: \"absolute\",\n\t\tleft: \"50%\",\n\t\ttop: \"50%\",\n\t\ttransform: \"translate(-50%, -50%) rotate(-4deg)\",\n\t\twidth: \"112px\",\n\t\theight: \"106px\",\n\t\tborderRadius: \"38% 62% 50% 50% / 44% 43% 57% 56%\",\n\t\tbackground: `linear-gradient(145deg, ${theme.primary}, ${theme.secondary})`,\n\t\tborder: `1px solid ${theme.primary36}`,\n\t\tcolor: \"#ffffff\",\n\t\tdisplay: \"inline-flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tboxShadow: `0 26px 54px ${theme.primary28}`,\n\t})\n\n\tconst icon = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\")\n\ticon.setAttribute(\"viewBox\", \"0 0 24 24\")\n\ticon.setAttribute(\"fill\", \"none\")\n\ticon.setAttribute(\"aria-hidden\", \"true\")\n\tObject.assign(icon.style, {\n\t\tdisplay: \"block\",\n\t\tflex: \"0 0 auto\",\n\t\theight: \"52px\",\n\t\ttransform: \"rotate(4deg)\",\n\t\twidth: \"52px\",\n\t})\n\n\tfor (const value of [\n\t\t\"M12 7V12L15 14\",\n\t\t\"M21 12A9 9 0 1 1 3 12A9 9 0 0 1 21 12\",\n\t]) {\n\t\tconst path = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\")\n\t\tpath.setAttribute(\"d\", value)\n\t\tpath.setAttribute(\"stroke\", \"currentColor\")\n\t\tpath.setAttribute(\"stroke-width\", \"2\")\n\t\tpath.setAttribute(\"stroke-linecap\", \"round\")\n\t\tpath.setAttribute(\"stroke-linejoin\", \"round\")\n\t\ticon.appendChild(path)\n\t}\n\n\ttile.appendChild(icon)\n\tartwork.appendChild(wash)\n\tartwork.appendChild(blob)\n\tartwork.appendChild(tile)\n\treturn artwork\n}\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: (\n\t\tdata: TData,\n\t\tcontainer: HTMLDivElement,\n\t\tevent: MessageEvent,\n\t) => void\n\twidth?: string\n}\n\ntype HostedFrameInstance = {\n\tcontainer: HTMLDivElement\n\tiframe: HTMLIFrameElement\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\t\"pt-BR\",\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\t\"pt-br\": \"pt-BR\",\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 getDocumentLocale(): string | undefined {\n\tif (typeof document === \"undefined\") return\n\treturn normalizeSdkLocale(document.documentElement?.lang)\n}\n\nexport function getAutoResolvedLocale(locale?: string): string {\n\treturn (\n\t\tnormalizeSdkLocale(locale) ||\n\t\tgetDocumentLocale() ||\n\t\tgetBrowserLocale() ||\n\t\tSDK_DEFAULT_LOCALE\n\t)\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): HostedFrameInstance | null {\n\t\tif (typeof document === \"undefined\") return null\n\t\tif (this.modal) return null\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(680px, calc(100vh - 32px))\",\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: \"none\",\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\tthis.iframe.allow = \"local-network-access\"\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, event)\n\t\t}\n\n\t\twindow.addEventListener(\"message\", this.messageHandler)\n\n\t\treturn {\n\t\t\tcontainer,\n\t\t\tiframe: this.iframe,\n\t\t}\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","export type LoginDeviceType = \"desktop\" | \"mobile\" | \"tablet\" | \"unknown\"\n\nexport type LoginEnvironmentInput = {\n\tcoarsePointer?: boolean\n\tmaxTouchPoints?: number\n\tplatform?: string\n\tstandalone?: boolean\n\tuserAgent?: string\n\tuserAgentDataMobile?: boolean\n}\n\nexport type LoginEnvironment = {\n\tdeviceType: LoginDeviceType\n\tisAndroid: boolean\n\tisCoarsePointer: boolean\n\tisDesktop: boolean\n\tisIOS: boolean\n\tisIPadOS: boolean\n\tisMobile: boolean\n\tisStandalone: boolean\n\tisTablet: boolean\n\tisTouch: boolean\n\tisWeChat: boolean\n\tmaxTouchPoints: number\n\tplatform: string\n\tshouldUseRedirectLogin: boolean\n\tuserAgent: string\n}\n\ntype NavigatorWithLoginSignals = Navigator & {\n\tstandalone?: boolean\n\tuserAgentData?: {\n\t\tmobile?: boolean\n\t}\n}\n\nfunction normalizeText(value?: string) {\n\treturn value || \"\"\n}\n\nfunction getRuntimeInput(): LoginEnvironmentInput {\n\tif (typeof navigator === \"undefined\") {\n\t\treturn {}\n\t}\n\n\tconst nav = navigator as NavigatorWithLoginSignals\n\tconst coarsePointer =\n\t\ttypeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n\t\t\t? window.matchMedia(\"(pointer: coarse)\").matches\n\t\t\t: undefined\n\n\treturn {\n\t\tcoarsePointer,\n\t\tmaxTouchPoints: nav.maxTouchPoints || 0,\n\t\tplatform: nav.platform || \"\",\n\t\tstandalone: nav.standalone,\n\t\tuserAgent: nav.userAgent || \"\",\n\t\tuserAgentDataMobile: nav.userAgentData?.mobile,\n\t}\n}\n\nfunction includesAny(value: string, patterns: RegExp[]) {\n\treturn patterns.some((pattern) => pattern.test(value))\n}\n\nexport function detectLoginEnvironment(\n\tinput: LoginEnvironmentInput = getRuntimeInput(),\n): LoginEnvironment {\n\tconst userAgent = normalizeText(input.userAgent)\n\tconst platform = normalizeText(input.platform)\n\tconst rawMaxTouchPoints = input.maxTouchPoints ?? 0\n\tconst maxTouchPoints = Number.isFinite(rawMaxTouchPoints)\n\t\t? Math.max(0, rawMaxTouchPoints)\n\t\t: 0\n\tconst isCoarsePointer = input.coarsePointer === true\n\tconst isTouch = maxTouchPoints > 0 || isCoarsePointer\n\n\tconst isWeChat = /micromessenger/i.test(userAgent)\n\tconst isAndroid = /\\bandroid\\b/i.test(userAgent)\n\tconst hasExplicitIOSDevice = /\\b(iPad|iPhone|iPod)\\b/i.test(userAgent)\n\tconst hasMacintoshUserAgent = /\\bMacintosh\\b/i.test(userAgent)\n\tconst hasMacPlatform = /^Mac/i.test(platform)\n\tconst isIPadOS =\n\t\t!hasExplicitIOSDevice &&\n\t\thasMacintoshUserAgent &&\n\t\thasMacPlatform &&\n\t\ttypeof input.standalone !== \"undefined\" &&\n\t\tmaxTouchPoints > 2\n\tconst isIOS = hasExplicitIOSDevice || isIPadOS\n\n\tconst isTabletByUa = includesAny(userAgent, [\n\t\t/\\biPad\\b/i,\n\t\t/\\btablet\\b/i,\n\t\t/\\bplaybook\\b/i,\n\t\t/\\bsilk\\b(?!.*\\bmobile\\b)/i,\n\t\t/\\bkindle\\b/i,\n\t\t/\\bnexus 7\\b/i,\n\t\t/\\bnexus 9\\b/i,\n\t\t/\\bxoom\\b/i,\n\t\t/\\bsm-t\\d+/i,\n\t\t/\\bgt-p\\d+/i,\n\t\t/\\bmi pad\\b/i,\n\t])\n\tconst isMobileByUa = includesAny(userAgent, [\n\t\t/\\bMobile\\b/i,\n\t\t/\\biPhone\\b/i,\n\t\t/\\biPod\\b/i,\n\t\t/\\bWindows Phone\\b/i,\n\t\t/\\bIEMobile\\b/i,\n\t\t/\\bBlackBerry\\b/i,\n\t\t/\\bBB10\\b/i,\n\t\t/\\bOpera Mini\\b/i,\n\t\t/\\bOpera Mobi\\b/i,\n\t\t/\\bwebOS\\b/i,\n\t])\n\tconst isAndroidTablet = isAndroid && !/\\bMobile\\b/i.test(userAgent)\n\tconst isTablet = isIPadOS || isTabletByUa || isAndroidTablet\n\tconst isMobile =\n\t\tinput.userAgentDataMobile === true ||\n\t\tisMobileByUa ||\n\t\t(isAndroid && !isTablet) ||\n\t\t(isIOS && !isTablet)\n\tconst deviceType: LoginDeviceType = isTablet\n\t\t? \"tablet\"\n\t\t: isMobile\n\t\t\t? \"mobile\"\n\t\t\t: userAgent || platform || isTouch\n\t\t\t\t? \"desktop\"\n\t\t\t\t: \"unknown\"\n\n\tconst shouldUseRedirectLogin =\n\t\tdeviceType === \"mobile\" || deviceType === \"tablet\" || isWeChat\n\n\treturn {\n\t\tdeviceType,\n\t\tisAndroid,\n\t\tisCoarsePointer,\n\t\tisDesktop: deviceType === \"desktop\",\n\t\tisIOS,\n\t\tisIPadOS,\n\t\tisMobile,\n\t\tisStandalone: input.standalone === true,\n\t\tisTablet,\n\t\tisTouch,\n\t\tisWeChat,\n\t\tmaxTouchPoints,\n\t\tplatform,\n\t\tshouldUseRedirectLogin,\n\t\tuserAgent,\n\t}\n}\n","import { createSdkFallbackArtwork } from \"./brand-logo\"\nimport { detectLoginEnvironment } from \"./environment\"\nimport {\n\tapplyLocaleToUrl,\n\tgetAutoResolvedLocale,\n\ttype HostedFrameMessage,\n\tHostedFrameModal,\n} from \"./hosted-modal\"\n\nexport type LoginEventType =\n\t| \"LOGIN_READY\"\n\t| \"LOGIN_SUCCESS\"\n\t| \"LOGIN_CANCELLED\"\n\t| \"LOGIN_CLOSE\"\n\t| \"LOGIN_RESIZE\"\n\t| \"LOGIN_REDIRECT_REQUIRED\"\n\t| \"LOGIN_ERROR\"\n\nexport type LoginDisplayMode = \"auto\" | \"modal\" | \"popup\" | \"redirect\"\nexport type LoginFallbackRedirectMode = \"auto\" | \"manual\"\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\tattemptId?: string\n\tauthUrl?: string\n\tchannel?: string\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 \"auto\", which uses an\n\t * iframe modal on desktop and redirects on mobile/embedded browsers.\n\t */\n\tdisplayMode?: LoginDisplayMode\n\t/** Text for the fallback button shown when the iframe does not report readiness. */\n\tfallbackButtonText?: string\n\t/** Description for the fallback panel shown when the iframe does not report readiness. */\n\tfallbackDescription?: string\n\t/**\n\t * Whether the SDK should redirect automatically when iframe loading times out.\n\t * Defaults to \"manual\" to avoid taking over the integrator page when the\n\t * hosted page is only slow to report readiness.\n\t */\n\tfallbackRedirectMode?: LoginFallbackRedirectMode\n\t/** Title for the fallback panel shown when the iframe does not report readiness. */\n\tfallbackTitle?: string\n\t/**\n\t * How long the SDK waits for LOGIN_READY or LOGIN_RESIZE before showing the\n\t * fallback redirect button. Only used when displayMode is \"modal\".\n\t * Defaults to 6000ms.\n\t */\n\tiframeLoadTimeoutMs?: number\n\t/** Description shown while the hosted login iframe is loading. */\n\tloadingDescription?: string\n\t/** Title shown while the hosted login iframe is loading. */\n\tloadingTitle?: string\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\tonFallbackVisible?: () => 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\tonError?: (message?: string, data?: LoginEventData) => void\n\tonResult?: (data: LoginEventData) => void\n\tonSuccess?: (result: LoginResult) => void\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 isValidLoginRedirectUrl(value?: string): value is string {\n\tif (!value) return false\n\ttry {\n\t\tconst url = new URL(value)\n\t\treturn url.protocol === \"https:\" || url.protocol === \"http:\"\n\t} catch {\n\t\treturn false\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:\"\nconst LOGIN_CALLBACK_CURRENT_PAGE_STORAGE_KEY = \"yd-login-current-page-callback\"\nconst DEFAULT_IFRAME_LOAD_TIMEOUT_MS = 6000\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\nfunction saveCurrentPageLoginCallback(data: LoginEventData) {\n\ttry {\n\t\twindow.sessionStorage.setItem(\n\t\t\tLOGIN_CALLBACK_CURRENT_PAGE_STORAGE_KEY,\n\t\t\tJSON.stringify({\n\t\t\t\tcreatedAt: Date.now(),\n\t\t\t\tdata,\n\t\t\t}),\n\t\t)\n\t} catch {\n\t\t// sessionStorage may be disabled in some embedded browsers.\n\t}\n}\n\nfunction readCurrentPageLoginCallback() {\n\ttry {\n\t\tconst raw = window.sessionStorage.getItem(\n\t\t\tLOGIN_CALLBACK_CURRENT_PAGE_STORAGE_KEY,\n\t\t)\n\t\tif (!raw) return null\n\t\twindow.sessionStorage.removeItem(LOGIN_CALLBACK_CURRENT_PAGE_STORAGE_KEY)\n\t\tconst parsed = JSON.parse(raw) as {\n\t\t\tcreatedAt?: number\n\t\t\tdata?: LoginEventData\n\t\t} | null\n\t\tconst data = parsed?.data\n\t\treturn data && typeof data === \"object\" && data.type ? data : null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction deliverLoginCallbackData(\n\tdata: LoginEventData,\n\toptions?: LoginCallbackOptions,\n) {\n\toptions?.onResult?.(data)\n\tswitch (data.type) {\n\t\tcase \"LOGIN_SUCCESS\":\n\t\t\toptions?.onSuccess?.(extractLoginResult(data))\n\t\t\tbreak\n\t\tcase \"LOGIN_ERROR\":\n\t\t\toptions?.onError?.(data.message || data.error, data)\n\t\t\tbreak\n\t\tdefault:\n\t\t\tbreak\n\t}\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\tif (options?.onResult || options?.onSuccess || options?.onError) {\n\t\t\tconst pendingData = readCurrentPageLoginCallback()\n\t\t\tif (pendingData) {\n\t\t\t\tdeliverLoginCallbackData(pendingData, options)\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\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\tif (data && (options?.onResult || options?.onSuccess || options?.onError)) {\n\t\tdeliverLoginCallbackData(data, options)\n\t} else if (data) {\n\t\tsaveCurrentPageLoginCallback(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\nfunction getIframeLoadTimeoutMs(options?: LoginUIOptions) {\n\tconst timeout = options?.iframeLoadTimeoutMs\n\tif (typeof timeout !== \"number\" || !Number.isFinite(timeout)) {\n\t\treturn DEFAULT_IFRAME_LOAD_TIMEOUT_MS\n\t}\n\treturn Math.max(0, timeout)\n}\n\nfunction applyLoginPanelStyle(panel: HTMLDivElement) {\n\tObject.assign(panel.style, {\n\t\tposition: \"absolute\",\n\t\tinset: \"0\",\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tborder: \"1px solid rgba(229,229,229,0.92)\",\n\t\tborderRadius: \"28px\",\n\t\tbackground: \"rgba(255,255,255,0.94)\",\n\t\tcolor: \"#0f172a\",\n\t\tpadding: \"24px\",\n\t\ttextAlign: \"center\",\n\t\tzIndex: \"1\",\n\t\tboxShadow: \"0 18px 50px rgba(15,15,15,0.06)\",\n\t\tbackdropFilter: \"blur(16px)\",\n\t})\n}\n\nfunction applyLoginLoadingPanelStyle(panel: HTMLDivElement) {\n\tObject.assign(panel.style, {\n\t\tposition: \"absolute\",\n\t\tinset: \"0\",\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tborder: \"0\",\n\t\tborderRadius: \"28px\",\n\t\tbackground: \"rgba(255,255,255,0.94)\",\n\t\tcolor: \"#0f172a\",\n\t\tpadding: \"24px\",\n\t\ttextAlign: \"center\",\n\t\tzIndex: \"1\",\n\t\tboxShadow: \"none\",\n\t\tbackdropFilter: \"blur(16px)\",\n\t})\n}\n\nfunction createLoginPanelContent() {\n\tconst content = document.createElement(\"div\")\n\tObject.assign(content.style, {\n\t\tmaxWidth: \"360px\",\n\t\twidth: \"100%\",\n\t})\n\tcontent.appendChild(\n\t\tcreateSdkFallbackArtwork({\n\t\t\tprimary: \"#171717\",\n\t\t\tprimary10: \"rgba(23,23,23,0.1)\",\n\t\t\tprimary14: \"rgba(23,23,23,0.14)\",\n\t\t\tprimary20: \"rgba(23,23,23,0.2)\",\n\t\t\tprimary28: \"rgba(23,23,23,0.28)\",\n\t\t\tprimary36: \"rgba(23,23,23,0.36)\",\n\t\t\tsecondary: \"#525252\",\n\t\t}),\n\t)\n\n\treturn content\n}\n\nfunction createBrandLoadingMark() {\n\tconst logo = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\")\n\tlogo.setAttribute(\"viewBox\", \"0 0 1024 1024\")\n\tlogo.setAttribute(\"fill\", \"none\")\n\tlogo.setAttribute(\"aria-hidden\", \"true\")\n\tObject.assign(logo.style, {\n\t\twidth: \"112px\",\n\t\theight: \"112px\",\n\t\tcolor: \"#22c55e\",\n\t\tdisplay: \"block\",\n\t\toverflow: \"visible\",\n\t})\n\n\tconst group = document.createElementNS(\"http://www.w3.org/2000/svg\", \"g\")\n\tgroup.setAttribute(\"fill\", \"currentColor\")\n\n\tconst ring = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\")\n\tring.setAttribute(\n\t\t\"d\",\n\t\t\"M704.298 679.54A264 264 0 1 1 704.298 309.46A49 49 0 0 1 634.4 378.149A166 166 0 1 0 634.4 610.851A49 49 0 0 1 704.298 679.54Z\",\n\t)\n\tring.setAttribute(\"class\", \"youidian-sdk-brand-loading__ring\")\n\n\tconst dot = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\")\n\tdot.setAttribute(\"class\", \"youidian-sdk-brand-loading__dot\")\n\tdot.setAttribute(\"cx\", \"714.5\")\n\tdot.setAttribute(\"cy\", \"490.5\")\n\tdot.setAttribute(\"r\", \"68\")\n\n\tgroup.appendChild(ring)\n\tgroup.appendChild(dot)\n\tlogo.appendChild(group)\n\n\treturn logo\n}\n\ntype LoginLoadingBrandText = { name: string; tagline: string }\n\nconst DEFAULT_LOGIN_LOADING_BRAND_TEXT: LoginLoadingBrandText = {\n\tname: \"Youidian\",\n\ttagline: \"Developer Service\",\n}\n\nconst LOGIN_LOADING_BRAND_TEXT: Record<string, LoginLoadingBrandText> = {\n\tde: { name: \"Youidian\", tagline: \"Entwicklerservice\" },\n\ten: DEFAULT_LOGIN_LOADING_BRAND_TEXT,\n\tes: { name: \"Youidian\", tagline: \"Servicios para desarrolladores\" },\n\tfr: { name: \"Youidian\", tagline: \"Services pour développeurs\" },\n\tit: { name: \"Youidian\", tagline: \"Servizi per sviluppatori\" },\n\tja: { name: \"Youidian\", tagline: \"開発者サービス\" },\n\tko: { name: \"Youidian\", tagline: \"개발자 서비스\" },\n\tnl: { name: \"Youidian\", tagline: \"Ontwikkelaarsservice\" },\n\tpt: { name: \"Youidian\", tagline: \"Serviço para desenvolvedores\" },\n\t\"pt-BR\": { name: \"Youidian\", tagline: \"Serviço para desenvolvedores\" },\n\t\"zh-CN\": { name: \"优易点\", tagline: \"开发者服务中台\" },\n\t\"zh-Hant\": { name: \"優易點\", tagline: \"開發者服務平台\" },\n}\n\nfunction getLoginLoadingBrandText(locale: string) {\n\treturn LOGIN_LOADING_BRAND_TEXT[locale] || DEFAULT_LOGIN_LOADING_BRAND_TEXT\n}\n\nfunction createBrandLoadingCopy(locale: string) {\n\tconst text = getLoginLoadingBrandText(locale)\n\tconst brand = document.createElement(\"div\")\n\tbrand.className = \"youidian-sdk-brand-loading__copy\"\n\tObject.assign(brand.style, {\n\t\tdisplay: \"flex\",\n\t\tflexDirection: \"column\",\n\t\talignItems: \"flex-start\",\n\t\tjustifyContent: \"center\",\n\t\tlineHeight: \"1\",\n\t})\n\n\tconst name = document.createElement(\"div\")\n\tname.className = \"youidian-sdk-brand-loading__name\"\n\tname.textContent = text.name\n\tObject.assign(name.style, {\n\t\tcolor: \"#0f172a\",\n\t\tfontSize: \"34px\",\n\t\tfontWeight: \"900\",\n\t\tletterSpacing: \"0\",\n\t\tlineHeight: \"1\",\n\t})\n\n\tconst tagline = document.createElement(\"div\")\n\ttagline.className = \"youidian-sdk-brand-loading__tagline\"\n\ttagline.textContent = text.tagline\n\tObject.assign(tagline.style, {\n\t\tcolor: \"#64748b\",\n\t\tfontSize: \"16px\",\n\t\tfontWeight: \"700\",\n\t\tletterSpacing: \"0.24em\",\n\t\tlineHeight: \"1\",\n\t\tmarginTop: \"6px\",\n\t})\n\n\tbrand.appendChild(name)\n\tbrand.appendChild(tagline)\n\treturn brand\n}\n\nfunction createLoginPanelTitle(value: string) {\n\tconst title = document.createElement(\"div\")\n\ttitle.textContent = value\n\tObject.assign(title.style, {\n\t\tcolor: \"#171717\",\n\t\tfontSize: \"18px\",\n\t\tfontWeight: \"700\",\n\t\tlineHeight: \"1.35\",\n\t\tmarginBottom: \"10px\",\n\t})\n\treturn title\n}\n\nfunction createLoginPanelDescription(value: string) {\n\tconst description = document.createElement(\"div\")\n\tdescription.textContent = value\n\tObject.assign(description.style, {\n\t\tcolor: \"#525252\",\n\t\tfontSize: \"14px\",\n\t\tlineHeight: \"1.6\",\n\t\tmarginBottom: \"20px\",\n\t})\n\treturn description\n}\n\nfunction ensureLoginLoadingStyles() {\n\tif (document.getElementById(\"youidian-login-loading-style\")) {\n\t\treturn\n\t}\n\tconst style = document.createElement(\"style\")\n\tstyle.id = \"youidian-login-loading-style\"\n\tstyle.textContent = `\n\t\t.youidian-sdk-brand-loading__ring,\n\t\t.youidian-sdk-brand-loading__dot {\n\t\t\ttransform-box: fill-box;\n\t\t\ttransform-origin: center;\n\t\t\twill-change: opacity, transform;\n\t\t}\n\n\t\t.youidian-sdk-brand-loading__ring {\n\t\t\tanimation: youidian-sdk-brand-loading-ring 1400ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t.youidian-sdk-brand-loading__dot {\n\t\t\tanimation: youidian-sdk-brand-loading-dot 1400ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t.youidian-sdk-brand-loading__copy {\n\t\t\twill-change: opacity, transform;\n\t\t\tanimation: youidian-sdk-brand-loading-copy 1600ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t.youidian-sdk-brand-loading__tagline {\n\t\t\twill-change: opacity;\n\t\t\tanimation: youidian-sdk-brand-loading-tagline 1600ms cubic-bezier(0.4, 0, 0.2, 1) infinite;\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-loading-ring {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.72;\n\t\t\t\ttransform: rotate(0deg) scale(0.98);\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: rotate(8deg) scale(1.02);\n\t\t\t}\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-loading-dot {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.55;\n\t\t\t\ttransform: scale(0.9);\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: scale(1.08);\n\t\t\t}\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-loading-copy {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.86;\n\t\t\t\ttransform: translateY(0);\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: translateY(-1px);\n\t\t\t}\n\t\t}\n\n\t\t@keyframes youidian-sdk-brand-loading-tagline {\n\t\t\t0%,\n\t\t\t100% {\n\t\t\t\topacity: 0.64;\n\t\t\t}\n\t\t\t50% {\n\t\t\t\topacity: 0.92;\n\t\t\t}\n\t\t}\n\n\t\t@media (prefers-reduced-motion: reduce) {\n\t\t\t.youidian-sdk-brand-loading__ring,\n\t\t\t.youidian-sdk-brand-loading__dot,\n\t\t\t.youidian-sdk-brand-loading__copy,\n\t\t\t.youidian-sdk-brand-loading__tagline {\n\t\t\t\tanimation: none;\n\t\t\t\topacity: 1;\n\t\t\t\ttransform: none;\n\t\t\t}\n\t\t}\n\t`\n\tdocument.head.appendChild(style)\n}\n\nfunction createLoginLoadingPanel(locale: string) {\n\tensureLoginLoadingStyles()\n\tconst text = getLoginLoadingBrandText(locale)\n\tconst panel = document.createElement(\"div\")\n\tapplyLoginLoadingPanelStyle(panel)\n\tpanel.setAttribute(\"role\", \"status\")\n\tpanel.setAttribute(\"aria-label\", `${text.name} ${text.tagline}`)\n\n\tconst content = document.createElement(\"div\")\n\tObject.assign(content.style, {\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tgap: \"12px\",\n\t})\n\tcontent.appendChild(createBrandLoadingMark())\n\tcontent.appendChild(createBrandLoadingCopy(locale))\n\tpanel.appendChild(content)\n\n\treturn panel\n}\n\nfunction createLoginRedirectingPanel(_options: {\n\tdescription: string\n\tlocale: string\n\ttitle: string\n}) {\n\treturn createLoginLoadingPanel(_options.locale)\n}\n\nfunction createLoginFallbackPanel(options: {\n\tbuttonText: string\n\tdescription: string\n\tonRedirect: () => void\n\ttitle: string\n}) {\n\tconst panel = document.createElement(\"div\")\n\tapplyLoginPanelStyle(panel)\n\n\tconst content = createLoginPanelContent()\n\n\tconst button = document.createElement(\"button\")\n\tbutton.type = \"button\"\n\tbutton.textContent = options.buttonText\n\tObject.assign(button.style, {\n\t\twidth: \"100%\",\n\t\tborder: \"0\",\n\t\tborderRadius: \"12px\",\n\t\tbackground: \"#0a0a0a\",\n\t\tcolor: \"#ffffff\",\n\t\tcursor: \"pointer\",\n\t\tfontSize: \"14px\",\n\t\tfontWeight: \"700\",\n\t\tminHeight: \"44px\",\n\t\tpadding: \"12px 16px\",\n\t\tboxShadow: \"0 12px 28px rgba(17,17,17,0.14)\",\n\t})\n\tbutton.onclick = options.onRedirect\n\n\tcontent.appendChild(createLoginPanelTitle(options.title))\n\tcontent.appendChild(createLoginPanelDescription(options.description))\n\tcontent.appendChild(button)\n\tpanel.appendChild(content)\n\n\treturn panel\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 iframeFallbackPanel: HTMLDivElement | null = null\n\tprivate iframeLoadingPanel: HTMLDivElement | null = null\n\tprivate iframeLoadTimer: number | null = null\n\tprivate iframeRedirectTimer: number | null = null\n\tprivate iframeReady = false\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\tif (typeof window !== \"undefined\" && this.iframeLoadTimer) {\n\t\t\twindow.clearTimeout(this.iframeLoadTimer)\n\t\t}\n\t\tif (typeof window !== \"undefined\" && this.iframeRedirectTimer) {\n\t\t\twindow.clearTimeout(this.iframeRedirectTimer)\n\t\t}\n\t\tif (this.iframeFallbackPanel?.parentNode) {\n\t\t\tthis.iframeFallbackPanel.parentNode.removeChild(this.iframeFallbackPanel)\n\t\t}\n\t\tif (this.iframeLoadingPanel?.parentNode) {\n\t\t\tthis.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel)\n\t\t}\n\t\tthis.popupMessageHandler = null\n\t\tthis.closeMonitor = null\n\t\tthis.iframeFallbackPanel = null\n\t\tthis.iframeLoadingPanel = null\n\t\tthis.iframeLoadTimer = null\n\t\tthis.iframeRedirectTimer = null\n\t\tthis.iframeReady = false\n\t\tthis.popup = null\n\t\tthis.completed = false\n\t}\n\n\tprivate markIframeReady() {\n\t\tif (this.iframeReady) return\n\t\tthis.iframeReady = true\n\t\tif (typeof window !== \"undefined\" && this.iframeLoadTimer) {\n\t\t\twindow.clearTimeout(this.iframeLoadTimer)\n\t\t\tthis.iframeLoadTimer = null\n\t\t}\n\t\tif (typeof window !== \"undefined\" && this.iframeRedirectTimer) {\n\t\t\twindow.clearTimeout(this.iframeRedirectTimer)\n\t\t\tthis.iframeRedirectTimer = null\n\t\t}\n\t\tif (this.iframeFallbackPanel?.parentNode) {\n\t\t\tthis.iframeFallbackPanel.parentNode.removeChild(this.iframeFallbackPanel)\n\t\t}\n\t\tif (this.iframeLoadingPanel?.parentNode) {\n\t\t\tthis.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel)\n\t\t}\n\t\tthis.iframeFallbackPanel = null\n\t\tthis.iframeLoadingPanel = null\n\t}\n\n\tprivate showIframeLoading(container: HTMLDivElement, locale: string) {\n\t\tif (this.iframeLoadingPanel || this.iframeReady) {\n\t\t\treturn\n\t\t}\n\n\t\tconst panel = createLoginLoadingPanel(locale)\n\t\tthis.iframeLoadingPanel = panel\n\t\tcontainer.appendChild(panel)\n\t}\n\n\tprivate showIframeFallback(options: {\n\t\tcontainer: HTMLDivElement\n\t\tfinalUrl: string\n\t\tlaunchPayload: LoginLaunchPayload\n\t\tloginOptions?: LoginUIOptions\n\t\tlocale: string\n\t}) {\n\t\tif (this.iframeReady || this.iframeFallbackPanel) {\n\t\t\treturn\n\t\t}\n\n\t\tconst { container, finalUrl, loginOptions } = options\n\t\tlogLoginWarn(\"Hosted login iframe did not report ready in time\", {\n\t\t\tloginUrl: finalUrl,\n\t\t})\n\t\tif (this.iframeLoadingPanel?.parentNode) {\n\t\t\tthis.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel)\n\t\t}\n\t\tthis.iframeLoadingPanel = null\n\n\t\tif (loginOptions?.fallbackRedirectMode === \"auto\") {\n\t\t\tconst panel = createLoginRedirectingPanel({\n\t\t\t\tdescription:\n\t\t\t\t\tloginOptions?.fallbackDescription ||\n\t\t\t\t\t\"The embedded login page is taking longer than expected. Redirecting you to the login page now.\",\n\t\t\t\tlocale: options.locale,\n\t\t\t\ttitle: loginOptions?.fallbackTitle || \"Redirecting to login page\",\n\t\t\t})\n\t\t\tthis.iframeFallbackPanel = panel\n\t\t\tcontainer.appendChild(panel)\n\t\t\tloginOptions?.onFallbackVisible?.()\n\t\t\tthis.iframeRedirectTimer = window.setTimeout(() => {\n\t\t\t\tthis.iframeRedirectTimer = null\n\t\t\t\tlogLoginInfo(\"Redirecting to hosted login fallback page\", {\n\t\t\t\t\tloginUrl: finalUrl,\n\t\t\t\t})\n\t\t\t\twindow.location.assign(finalUrl)\n\t\t\t}, 350)\n\t\t\treturn\n\t\t}\n\n\t\tconst panel = createLoginFallbackPanel({\n\t\t\tbuttonText: loginOptions?.fallbackButtonText || \"Continue to login\",\n\t\t\tdescription:\n\t\t\t\tloginOptions?.fallbackDescription ||\n\t\t\t\t\"The embedded login page is taking longer than expected. Continue on the login page to finish signing in.\",\n\t\t\ttitle: loginOptions?.fallbackTitle || \"Login page is still loading\",\n\t\t\tonRedirect: () => {\n\t\t\t\tlogLoginInfo(\"Redirecting to hosted login fallback page\", {\n\t\t\t\t\tloginUrl: finalUrl,\n\t\t\t\t})\n\t\t\t\twindow.location.assign(finalUrl)\n\t\t\t},\n\t\t})\n\n\t\tthis.iframeFallbackPanel = panel\n\t\tcontainer.appendChild(panel)\n\t\tloginOptions?.onFallbackVisible?.()\n\t}\n\n\tprivate startIframeWatchdog(options: {\n\t\tcontainer: HTMLDivElement\n\t\tfinalUrl: string\n\t\tlaunchPayload: LoginLaunchPayload\n\t\tloginOptions?: LoginUIOptions\n\t\tlocale: string\n\t}) {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tconst timeoutMs = getIframeLoadTimeoutMs(options.loginOptions)\n\t\tif (timeoutMs === 0) {\n\t\t\tthis.showIframeFallback(options)\n\t\t\treturn\n\t\t}\n\n\t\tthis.iframeLoadTimer = window.setTimeout(() => {\n\t\t\tthis.iframeLoadTimer = null\n\t\t\tthis.showIframeFallback(options)\n\t\t}, timeoutMs)\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_READY\":\n\t\t\t\tbreak\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_REDIRECT_REQUIRED\":\n\t\t\t\tif (!isValidLoginRedirectUrl(data.authUrl)) {\n\t\t\t\t\tlogLoginWarn(\"Login redirect requested with invalid authUrl\")\n\t\t\t\t\toptions?.onError?.(\"Login redirect URL is invalid\", data)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tlogLoginInfo(\"Login redirect requested by hosted page\", {\n\t\t\t\t\tattemptId: data.attemptId || null,\n\t\t\t\t\tchannel: data.channel || null,\n\t\t\t\t\tauthUrl: data.authUrl,\n\t\t\t\t})\n\t\t\t\tthis.close()\n\t\t\t\twindow.location.assign(data.authUrl)\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 openLoginRedirect(params: LoginParams, options?: LoginUIOptions) {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tconst { callbackState, finalUrl, launchPayload } = this.buildOpenContext(\n\t\t\tparams,\n\t\t\toptions,\n\t\t)\n\t\tlogLoginInfo(\"Redirecting to hosted login page\", {\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\tautoClose: options?.autoClose ?? true,\n\t\t\tdisplayMode: \"redirect\",\n\t\t\tpageUrl: window.location.href,\n\t\t\tparentOrigin: launchPayload.origin || null,\n\t\t})\n\t\twindow.location.assign(finalUrl)\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.iframeReady = false\n\t\tthis.listenForLoginCallback(callbackState, options)\n\t\tconst hostedFrame = this.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, event) => {\n\t\t\t\tconst isIframeEvent = event.source === this.iframe?.contentWindow\n\t\t\t\t// 诊断：LOGIN_READY/LOGIN_RESIZE 到达但 event.source 不匹配当前 iframe\n\t\t\t\t// 时，markIframeReady 不会执行，loading 面板会卡住直至 6s fallback。\n\t\t\t\t// 这类「iframe 不出现」曾无任何日志，加 warn 便于线上定位根因\n\t\t\t\t// （常见诱因：iframe 加载了被缓存/重定向的旧文档导致 contentWindow\n\t\t\t\t// 身份变化，或同一页面挂了多个 SDK 实例）。\n\t\t\t\tif (\n\t\t\t\t\t!isIframeEvent &&\n\t\t\t\t\t(data.type === \"LOGIN_READY\" || data.type === \"LOGIN_RESIZE\")\n\t\t\t\t) {\n\t\t\t\t\tlogLoginWarn(\n\t\t\t\t\t\t\"Login lifecycle event ignored: event.source does not match iframe contentWindow\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: data.type,\n\t\t\t\t\t\t\teventOrigin: event.origin,\n\t\t\t\t\t\t\thasIframe: Boolean(this.iframe),\n\t\t\t\t\t\t\thasIframeContentWindow: Boolean(this.iframe?.contentWindow),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\t(isIframeEvent &&\n\t\t\t\t\t\t(data.type === \"LOGIN_READY\" || data.type === \"LOGIN_RESIZE\")) ||\n\t\t\t\t\tdata.type === \"LOGIN_SUCCESS\" ||\n\t\t\t\t\tdata.type === \"LOGIN_ERROR\"\n\t\t\t\t) {\n\t\t\t\t\tthis.markIframeReady()\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\n\t\tif (hostedFrame) {\n\t\t\tthis.showIframeLoading(\n\t\t\t\thostedFrame.container,\n\t\t\t\tgetAutoResolvedLocale(params.locale),\n\t\t\t)\n\t\t\tthis.startIframeWatchdog({\n\t\t\t\tcontainer: hostedFrame.container,\n\t\t\t\tfinalUrl,\n\t\t\t\tlaunchPayload,\n\t\t\t\tloginOptions: options,\n\t\t\t\tlocale: getAutoResolvedLocale(params.locale),\n\t\t\t})\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 ?? \"auto\"\n\t\tif (displayMode === \"redirect\") {\n\t\t\tthis.openLoginRedirect(params, options)\n\t\t\treturn\n\t\t}\n\t\tif (displayMode === \"popup\") {\n\t\t\tthis.openLoginPopup(params, options)\n\t\t\treturn\n\t\t}\n\t\tif (\n\t\t\tdisplayMode === \"auto\" &&\n\t\t\tdetectLoginEnvironment().shouldUseRedirectLogin\n\t\t) {\n\t\t\tthis.openLoginRedirect(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","/**\n * Youidian Payment SDK - Client Module\n * 用于浏览器端集成，包含支付弹窗、状态轮询等功能\n * 不依赖 Node.js crypto 模块\n */\n\nimport { createSdkBrandLogo, createSdkFallbackArtwork } from \"./brand-logo\"\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_READY\"\n\t| \"PAYMENT_SUCCESS\"\n\t| \"PAYMENT_CANCELLED\"\n\t| \"PAYMENT_CLOSE\"\n\t| \"PAYMENT_RESIZE\"\n\t| \"PAYMENT_STARTED\"\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\" | \"EXPIRED\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\nexport interface PaymentUIThemeColors {\n\tprimary?: string\n\tsecondary?: string\n\tforeground?: string\n\tmuted?: string\n\tsurface?: 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\tonFallbackBlocked?: (url: string) => void\n\tonFallbackOpen?: (url: string) => void\n\tonFallbackVisible?: () => void\n\t/** Origin to validate postMessage (defaults to '*', set for security) */\n\tallowedOrigin?: string\n\t/** Theme colors for SDK fallback/loading chrome. Defaults to Youidian green. */\n\ttheme?: PaymentUIThemeColors\n\t/** Text for the fallback button shown when the checkout iframe is slow. */\n\tfallbackButtonText?: string\n\t/** Text for retrying the embedded checkout iframe. */\n\tfallbackRetryText?: string\n\t/** How long to wait for PAYMENT_READY or PAYMENT_RESIZE. Defaults to 8000ms. */\n\tiframeLoadTimeoutMs?: number\n\t/** Description shown while the hosted checkout iframe is loading. */\n\tloadingDescription?: string\n\t/** Title shown while the hosted checkout iframe is loading. */\n\tloadingTitle?: string\n}\n\nconst DEFAULT_PAYMENT_IFRAME_LOAD_TIMEOUT_MS = 8000\nconst PAYMENT_UI_LOG_PREFIX = \"[Youidian PaymentUI]\"\n\ntype ResolvedPaymentTheme = {\n\tforeground: string\n\tmuted: string\n\tprimary: string\n\tprimary10: string\n\tprimary14: string\n\tprimary20: string\n\tprimary28: string\n\tprimary36: string\n\tprimary64: string\n\tsecondary: string\n\tsurface: string\n}\n\nfunction hexToRgb(value: string) {\n\tconst normalized = value.trim().replace(/^#/, \"\")\n\tif (!/^[0-9a-f]{3}([0-9a-f]{3})?$/i.test(normalized)) return null\n\tconst hex =\n\t\tnormalized.length === 3\n\t\t\t? normalized\n\t\t\t\t\t.split(\"\")\n\t\t\t\t\t.map((char) => `${char}${char}`)\n\t\t\t\t\t.join(\"\")\n\t\t\t: normalized\n\tconst number = Number.parseInt(hex, 16)\n\treturn {\n\t\tb: number & 255,\n\t\tg: (number >> 8) & 255,\n\t\tr: (number >> 16) & 255,\n\t}\n}\n\nfunction alphaColor(value: string, alpha: number) {\n\tconst rgb = hexToRgb(value)\n\tif (!rgb)\n\t\treturn `color-mix(in srgb, ${value} ${Math.round(alpha * 100)}%, transparent)`\n\treturn `rgba(${rgb.r},${rgb.g},${rgb.b},${alpha})`\n}\n\nfunction resolvePaymentTheme(options?: PaymentUIOptions): ResolvedPaymentTheme {\n\tconst primary = options?.theme?.primary || \"#16a34a\"\n\tconst secondary =\n\t\toptions?.theme?.secondary || \"color-mix(in srgb, #16a34a 78%, white)\"\n\tconst foreground = options?.theme?.foreground || \"#0f172a\"\n\tconst muted = options?.theme?.muted || \"#64748b\"\n\tconst surface = options?.theme?.surface || \"#ffffff\"\n\n\treturn {\n\t\tforeground,\n\t\tmuted,\n\t\tprimary,\n\t\tprimary10: alphaColor(primary, 0.1),\n\t\tprimary14: alphaColor(primary, 0.14),\n\t\tprimary20: alphaColor(primary, 0.2),\n\t\tprimary28: alphaColor(primary, 0.28),\n\t\tprimary36: alphaColor(primary, 0.36),\n\t\tprimary64: alphaColor(primary, 0.64),\n\t\tsecondary,\n\t\tsurface,\n\t}\n}\n\nfunction logPaymentInfo(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.info(PAYMENT_UI_LOG_PREFIX, message, details || {})\n}\n\nfunction logPaymentWarn(message: string, details?: Record<string, unknown>) {\n\tif (typeof console === \"undefined\") return\n\tconsole.warn(PAYMENT_UI_LOG_PREFIX, message, details || {})\n}\n\nfunction getPaymentIframeLoadTimeoutMs(options?: PaymentUIOptions) {\n\tconst timeout = options?.iframeLoadTimeoutMs\n\tif (typeof timeout !== \"number\" || !Number.isFinite(timeout)) {\n\t\treturn DEFAULT_PAYMENT_IFRAME_LOAD_TIMEOUT_MS\n\t}\n\treturn Math.max(0, timeout)\n}\n\nfunction isChinesePaymentLocale(locale?: string) {\n\treturn locale?.toLowerCase().startsWith(\"zh\") || false\n}\n\nfunction getPaymentFallbackText(options?: PaymentUIOptions) {\n\tconst isChinese = isChinesePaymentLocale(options?.locale)\n\treturn {\n\t\tbuttonText:\n\t\t\toptions?.fallbackButtonText ||\n\t\t\t(isChinese ? \"在新页面中打开\" : \"Open in new page\"),\n\t\tdescription: isChinese\n\t\t\t? \"当前网络可能较慢，建议重新尝试或在新页面中打开，以获得更流畅的支付体验。\"\n\t\t\t: \"Your network may be slow. Try again or open the payment page in a new page to continue.\",\n\t\tretryText:\n\t\t\toptions?.fallbackRetryText || (isChinese ? \"重新尝试\" : \"Try again\"),\n\t\ttitle: isChinese ? \"支付页面打开较慢\" : \"Payment page is taking longer\",\n\t}\n}\n\nfunction getPaymentBrandText(options?: PaymentUIOptions) {\n\tconst isChinese = isChinesePaymentLocale(options?.locale)\n\treturn {\n\t\tlanguage: isChinese ? \"zh\" : \"en\",\n\t\tname: isChinese ? \"优易点\" : \"Youidian\",\n\t\tsubtitle: isChinese ? \"开发者服务平台\" : \"Developer Service Platform\",\n\t}\n}\n\nfunction getPaymentBrandLoadingText(options?: PaymentUIOptions) {\n\tconst isChinese = isChinesePaymentLocale(options?.locale)\n\treturn {\n\t\tlanguage: isChinese ? \"zh\" : \"en\",\n\t\tname: isChinese ? \"优易点\" : \"Youidian\",\n\t\tsubtitle: isChinese ? \"开发者服务中台\" : \"Developer Service\",\n\t}\n}\n\nfunction getPaymentLoadingText(options?: PaymentUIOptions) {\n\tconst isChinese = isChinesePaymentLocale(options?.locale)\n\treturn (\n\t\toptions?.loadingTitle ||\n\t\toptions?.loadingDescription ||\n\t\t(isChinese ? \"加载中...\" : \"Loading...\")\n\t)\n}\n\nfunction applyPaymentPanelStyle(\n\tpanel: HTMLDivElement,\n\ttheme: ResolvedPaymentTheme,\n) {\n\tObject.assign(panel.style, {\n\t\tposition: \"absolute\",\n\t\tinset: \"0\",\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tborderRadius: \"28px\",\n\t\tbackground: `linear-gradient(180deg, ${theme.surface} 0%, rgba(248,250,252,0.98) 100%)`,\n\t\tcolor: theme.foreground,\n\t\tpadding: \"28px 24px\",\n\t\ttextAlign: \"center\",\n\t\tzIndex: \"1\",\n\t\tboxShadow: \"none\",\n\t\tbackdropFilter: \"blur(16px)\",\n\t})\n}\n\nfunction createPaymentIcon(type: \"external\" | \"refresh\") {\n\tconst svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\")\n\tsvg.setAttribute(\"viewBox\", \"0 0 24 24\")\n\tsvg.setAttribute(\"fill\", \"none\")\n\tsvg.setAttribute(\"aria-hidden\", \"true\")\n\tObject.assign(svg.style, {\n\t\tdisplay: \"block\",\n\t\tflex: \"0 0 auto\",\n\t})\n\n\tconst paths =\n\t\ttype === \"external\"\n\t\t\t? [\n\t\t\t\t\t\"M7 17L17 7\",\n\t\t\t\t\t\"M10 7H17V14\",\n\t\t\t\t\t\"M6.5 6.5H5.5A2.5 2.5 0 0 0 3 9V18.5A2.5 2.5 0 0 0 5.5 21H15A2.5 2.5 0 0 0 17.5 18.5V17.5\",\n\t\t\t\t]\n\t\t\t: [\n\t\t\t\t\t\"M20 6V11H15\",\n\t\t\t\t\t\"M4 18V13H9\",\n\t\t\t\t\t\"M18.2 9A7 7 0 0 0 6.2 6.6L4 9\",\n\t\t\t\t\t\"M5.8 15A7 7 0 0 0 17.8 17.4L20 15\",\n\t\t\t\t]\n\n\tfor (const value of paths) {\n\t\tconst path = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\")\n\t\tpath.setAttribute(\"d\", value)\n\t\tpath.setAttribute(\"stroke\", \"currentColor\")\n\t\tpath.setAttribute(\"stroke-width\", \"2\")\n\t\tpath.setAttribute(\"stroke-linecap\", \"round\")\n\t\tpath.setAttribute(\"stroke-linejoin\", \"round\")\n\t\tsvg.appendChild(path)\n\t}\n\n\treturn svg\n}\n\nfunction createPaymentBrandLoading(\n\toptions: PaymentUIOptions | undefined,\n\ttheme: ResolvedPaymentTheme,\n) {\n\tconst brand = getPaymentBrandLoadingText(options)\n\tconst wrapper = document.createElement(\"div\")\n\tObject.assign(wrapper.style, {\n\t\tdisplay: \"flex\",\n\t\tflexDirection: \"column\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tmargin: \"0 auto 16px\",\n\t})\n\n\twrapper.appendChild(\n\t\tcreateSdkBrandLogo({\n\t\t\tanimated: true,\n\t\t\tbrand,\n\t\t\tbrandWidth: 292,\n\t\t\tcopyWidth: 176,\n\t\t\tgap: 6,\n\t\t\tmarkMarginRight: -10,\n\t\t\tmarkSize: 112,\n\t\t\tnameSize: 39,\n\t\t\tsubtitleMarginTop: 8,\n\t\t\tsubtitleSize: 14,\n\t\t\tsubtitleWeight: \"700\",\n\t\t\ttheme,\n\t\t\tvariant: \"brand\",\n\t\t}),\n\t)\n\treturn wrapper\n}\n\nfunction createPaymentPlatformLogo(\n\toptions: PaymentUIOptions | undefined,\n\ttheme: ResolvedPaymentTheme,\n) {\n\tconst brand = getPaymentBrandText(options)\n\tconst wrapper = document.createElement(\"div\")\n\tObject.assign(wrapper.style, {\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tmargin: \"0 auto 10px\",\n\t})\n\twrapper.appendChild(\n\t\tcreateSdkBrandLogo({\n\t\t\tbrand,\n\t\t\tmarkSize: 48,\n\t\t\tnameSize: brand.language === \"zh\" ? 22 : 22,\n\t\t\tsubtitleSize: brand.language === \"zh\" ? 9 : 9,\n\t\t\ttheme,\n\t\t}),\n\t)\n\treturn wrapper\n}\n\nfunction createPaymentPanelContent() {\n\tconst content = document.createElement(\"div\")\n\tObject.assign(content.style, {\n\t\tdisplay: \"flex\",\n\t\tflexDirection: \"column\",\n\t\tjustifyContent: \"center\",\n\t\tmaxWidth: \"364px\",\n\t\tminHeight: \"100%\",\n\t\twidth: \"100%\",\n\t})\n\n\treturn content\n}\n\nfunction createPaymentPanelTitle(value: string, theme?: ResolvedPaymentTheme) {\n\tconst title = document.createElement(\"div\")\n\ttitle.textContent = value\n\tObject.assign(title.style, {\n\t\tcolor: theme?.foreground || \"#0f172a\",\n\t\tfontSize: \"24px\",\n\t\tfontWeight: \"900\",\n\t\tlineHeight: \"1.22\",\n\t\tmarginBottom: \"16px\",\n\t})\n\treturn title\n}\n\nfunction createPaymentPanelDescription(\n\tvalue: string,\n\ttheme?: ResolvedPaymentTheme,\n) {\n\tconst description = document.createElement(\"div\")\n\tdescription.textContent = value\n\tObject.assign(description.style, {\n\t\tcolor: theme?.muted || \"#64748b\",\n\t\tfontSize: \"14px\",\n\t\tfontWeight: \"600\",\n\t\tlineHeight: \"1.62\",\n\t\tmargin: \"0 auto\",\n\t\tmaxWidth: \"320px\",\n\t})\n\treturn description\n}\n\nfunction createPaymentLoadingDescription(\n\tvalue: string,\n\ttheme?: ResolvedPaymentTheme,\n) {\n\tconst description = document.createElement(\"div\")\n\tdescription.textContent = value\n\tObject.assign(description.style, {\n\t\tcolor: theme?.muted || \"#64748b\",\n\t\tfontSize: \"14px\",\n\t\tfontWeight: \"500\",\n\t\tlineHeight: \"1.25\",\n\t\tmargin: \"12px auto 0\",\n\t\tmaxWidth: \"320px\",\n\t})\n\treturn description\n}\n\nfunction createPaymentFallbackMessage(options: {\n\tdescription: string\n\ttheme: ResolvedPaymentTheme\n\ttitle: string\n}) {\n\tconst message = document.createElement(\"div\")\n\tObject.assign(message.style, {\n\t\tmargin: \"0 auto\",\n\t\ttextAlign: \"center\",\n\t})\n\tmessage.appendChild(createSdkFallbackArtwork(options.theme))\n\tmessage.appendChild(createPaymentPanelTitle(options.title, options.theme))\n\tmessage.appendChild(\n\t\tcreatePaymentPanelDescription(options.description, options.theme),\n\t)\n\treturn message\n}\n\nfunction createPaymentLoadingPanel(options?: PaymentUIOptions) {\n\tconst panel = document.createElement(\"div\")\n\tconst theme = resolvePaymentTheme(options)\n\tapplyPaymentPanelStyle(panel, theme)\n\n\tconst content = createPaymentPanelContent()\n\tcontent.appendChild(createPaymentBrandLoading(options, theme))\n\tcontent.appendChild(\n\t\tcreatePaymentLoadingDescription(getPaymentLoadingText(options), theme),\n\t)\n\tpanel.appendChild(content)\n\treturn panel\n}\n\nfunction createPaymentButton(\n\tvalue: string,\n\toptions?: {\n\t\ticon?: \"external\" | \"refresh\"\n\t\tprimary?: boolean\n\t\ttheme?: ResolvedPaymentTheme\n\t},\n) {\n\tconst primary = options?.primary || false\n\tconst theme = options?.theme || resolvePaymentTheme()\n\tconst button = document.createElement(\"button\")\n\tbutton.type = \"button\"\n\tObject.assign(button.style, {\n\t\twidth: \"100%\",\n\t\theight: \"50px\",\n\t\tborderRadius: \"14px\",\n\t\tborder: primary\n\t\t\t? `1px solid ${theme.primary}`\n\t\t\t: `1px solid ${theme.primary64}`,\n\t\tbackground: primary\n\t\t\t? `linear-gradient(135deg, ${theme.primary}, ${theme.secondary})`\n\t\t\t: \"#ffffff\",\n\t\tcolor: primary ? \"#ffffff\" : theme.primary,\n\t\tcursor: \"pointer\",\n\t\tdisplay: \"inline-flex\",\n\t\talignItems: \"center\",\n\t\tjustifyContent: \"center\",\n\t\tgap: \"10px\",\n\t\tfontSize: \"15px\",\n\t\tfontWeight: \"800\",\n\t\tmarginTop: primary ? \"12px\" : \"0\",\n\t\tboxShadow: primary ? `0 14px 28px ${theme.primary20}` : \"none\",\n\t})\n\tif (options?.icon) {\n\t\tconst icon = createPaymentIcon(options.icon)\n\t\tObject.assign(icon.style, {\n\t\t\twidth: \"17px\",\n\t\t\theight: \"17px\",\n\t\t})\n\t\tbutton.appendChild(icon)\n\t}\n\tconst label = document.createElement(\"span\")\n\tlabel.textContent = value\n\tbutton.appendChild(label)\n\treturn button\n}\n\nfunction createPaymentFallbackPanel(options: {\n\tbuttonText: string\n\tdescription: string\n\tpaymentOptions?: PaymentUIOptions\n\tonOpen: () => void\n\tonRetry: () => void\n\tretryText: string\n\ttitle: string\n}) {\n\tconst panel = document.createElement(\"div\")\n\tconst theme = resolvePaymentTheme(options.paymentOptions)\n\tapplyPaymentPanelStyle(panel, theme)\n\n\tconst content = createPaymentPanelContent()\n\tObject.assign(content.style, {\n\t\tjustifyContent: \"space-between\",\n\t})\n\n\tconst main = document.createElement(\"div\")\n\tObject.assign(main.style, {\n\t\tdisplay: \"flex\",\n\t\tflexDirection: \"column\",\n\t\talignItems: \"center\",\n\t\tmarginTop: \"38px\",\n\t\twidth: \"100%\",\n\t})\n\tmain.appendChild(\n\t\tcreatePaymentFallbackMessage({\n\t\t\tdescription: options.description,\n\t\t\ttheme,\n\t\t\ttitle: options.title,\n\t\t}),\n\t)\n\n\tconst actions = document.createElement(\"div\")\n\tObject.assign(actions.style, {\n\t\tmarginTop: \"46px\",\n\t\twidth: \"100%\",\n\t})\n\n\tconst retryButton = createPaymentButton(options.retryText, {\n\t\ticon: \"refresh\",\n\t\ttheme,\n\t})\n\tretryButton.onclick = options.onRetry\n\tactions.appendChild(retryButton)\n\n\tconst openButton = createPaymentButton(options.buttonText, {\n\t\ticon: \"external\",\n\t\tprimary: true,\n\t\ttheme,\n\t})\n\topenButton.onclick = options.onOpen\n\tactions.appendChild(openButton)\n\n\tmain.appendChild(actions)\n\tcontent.appendChild(main)\n\tcontent.appendChild(createPaymentPlatformLogo(options.paymentOptions, theme))\n\tpanel.appendChild(content)\n\treturn panel\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/** Existing Youidian order ID - opens checkout for an already-created order */\n\torderId?: 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\t/** Optional custom recharge amount in the smallest currency unit */\n\tcustomAmount?: {\n\t\tamount: number\n\t\tcurrency: string\n\t}\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\tprivate activeCheckoutAppId: string | null = null\n\tprivate activeCheckoutBaseUrl: string | null = null\n\tprivate activeOrderId: string | null = null\n\tprivate paymentCompleted = false\n\tprivate cancelRequestedOrderId: string | null = null\n\tprivate iframeFallbackPanel: HTMLDivElement | null = null\n\tprivate iframeLoadingPanel: HTMLDivElement | null = null\n\tprivate iframeLoadTimer: number | null = null\n\tprivate iframeReady = false\n\n\tprivate cleanupPaymentFrameState() {\n\t\tif (typeof window !== \"undefined\" && this.iframeLoadTimer) {\n\t\t\twindow.clearTimeout(this.iframeLoadTimer)\n\t\t}\n\t\tif (this.iframeFallbackPanel?.parentNode) {\n\t\t\tthis.iframeFallbackPanel.parentNode.removeChild(this.iframeFallbackPanel)\n\t\t}\n\t\tif (this.iframeLoadingPanel?.parentNode) {\n\t\t\tthis.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel)\n\t\t}\n\t\tthis.iframeFallbackPanel = null\n\t\tthis.iframeLoadingPanel = null\n\t\tthis.iframeLoadTimer = null\n\t\tthis.iframeReady = false\n\t}\n\n\tprivate markPaymentIframeReady() {\n\t\tif (this.iframeReady) return\n\t\tthis.iframeReady = true\n\t\tif (typeof window !== \"undefined\" && this.iframeLoadTimer) {\n\t\t\twindow.clearTimeout(this.iframeLoadTimer)\n\t\t\tthis.iframeLoadTimer = null\n\t\t}\n\t\tif (this.iframeFallbackPanel?.parentNode) {\n\t\t\tthis.iframeFallbackPanel.parentNode.removeChild(this.iframeFallbackPanel)\n\t\t}\n\t\tif (this.iframeLoadingPanel?.parentNode) {\n\t\t\tthis.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel)\n\t\t}\n\t\tthis.iframeFallbackPanel = null\n\t\tthis.iframeLoadingPanel = null\n\t}\n\n\tprivate showPaymentIframeLoading(\n\t\tcontainer: HTMLDivElement,\n\t\toptions?: PaymentUIOptions,\n\t) {\n\t\tif (this.iframeLoadingPanel || this.iframeReady) return\n\n\t\tconst panel = createPaymentLoadingPanel(options)\n\t\tthis.iframeLoadingPanel = panel\n\t\tcontainer.appendChild(panel)\n\t}\n\n\tprivate openFallbackPaymentPage(\n\t\tfinalUrl: string,\n\t\toptions?: PaymentUIOptions,\n\t) {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tconst popup = window.open(\n\t\t\tfinalUrl,\n\t\t\t\"youidian-payment-checkout\",\n\t\t\t\"popup=yes,width=480,height=760,resizable=yes,scrollbars=yes\",\n\t\t)\n\t\tif (popup) {\n\t\t\tlogPaymentInfo(\"Opened hosted checkout fallback page\", {\n\t\t\t\tcheckoutUrl: finalUrl,\n\t\t\t})\n\t\t\toptions?.onFallbackOpen?.(finalUrl)\n\t\t\ttry {\n\t\t\t\tpopup.focus()\n\t\t\t} catch {\n\t\t\t\t// Ignore focus failures in restrictive browsers.\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tlogPaymentWarn(\"Hosted checkout fallback popup was blocked\", {\n\t\t\tcheckoutUrl: finalUrl,\n\t\t})\n\t\toptions?.onFallbackBlocked?.(finalUrl)\n\t\twindow.location.assign(finalUrl)\n\t}\n\n\tprivate showPaymentIframeFallback(options: {\n\t\tcontainer: HTMLDivElement\n\t\tfinalUrl: string\n\t\tpaymentOptions?: PaymentUIOptions\n\t}) {\n\t\tif (this.iframeReady || this.iframeFallbackPanel) return\n\n\t\tconst { container, finalUrl, paymentOptions } = options\n\t\tlogPaymentWarn(\"Hosted checkout iframe did not report ready in time\", {\n\t\t\tcheckoutUrl: finalUrl,\n\t\t})\n\t\tif (this.iframeLoadingPanel?.parentNode) {\n\t\t\tthis.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel)\n\t\t}\n\t\tthis.iframeLoadingPanel = null\n\n\t\tconst fallbackText = getPaymentFallbackText(paymentOptions)\n\t\tconst panel = createPaymentFallbackPanel({\n\t\t\tbuttonText: fallbackText.buttonText,\n\t\t\tdescription: fallbackText.description,\n\t\t\tonOpen: () => {\n\t\t\t\tthis.openFallbackPaymentPage(finalUrl, paymentOptions)\n\t\t\t},\n\t\t\tonRetry: () => {\n\t\t\t\tthis.iframeFallbackPanel = null\n\t\t\t\tif (panel.parentNode) {\n\t\t\t\t\tpanel.parentNode.removeChild(panel)\n\t\t\t\t}\n\t\t\t\tthis.iframeReady = false\n\t\t\t\tthis.showPaymentIframeLoading(container, paymentOptions)\n\t\t\t\tif (this.iframe) {\n\t\t\t\t\tthis.iframe.src = finalUrl\n\t\t\t\t}\n\t\t\t\tthis.startPaymentIframeWatchdog({\n\t\t\t\t\tcontainer,\n\t\t\t\t\tfinalUrl,\n\t\t\t\t\tpaymentOptions,\n\t\t\t\t})\n\t\t\t},\n\t\t\tpaymentOptions,\n\t\t\tretryText: fallbackText.retryText,\n\t\t\ttitle: fallbackText.title,\n\t\t})\n\n\t\tthis.iframeFallbackPanel = panel\n\t\tcontainer.appendChild(panel)\n\t\tpaymentOptions?.onFallbackVisible?.()\n\t}\n\n\tprivate startPaymentIframeWatchdog(options: {\n\t\tcontainer: HTMLDivElement\n\t\tfinalUrl: string\n\t\tpaymentOptions?: PaymentUIOptions\n\t}) {\n\t\tif (typeof window === \"undefined\") return\n\n\t\tif (this.iframeLoadTimer) {\n\t\t\twindow.clearTimeout(this.iframeLoadTimer)\n\t\t}\n\t\tconst timeoutMs = getPaymentIframeLoadTimeoutMs(options.paymentOptions)\n\t\tif (timeoutMs === 0) {\n\t\t\tthis.showPaymentIframeFallback(options)\n\t\t\treturn\n\t\t}\n\n\t\tthis.iframeLoadTimer = window.setTimeout(() => {\n\t\t\tthis.iframeLoadTimer = null\n\t\t\tthis.showPaymentIframeFallback(options)\n\t\t}, timeoutMs)\n\t}\n\n\tprivate cancelHostedOrder(reason = \"user_cancel\", orderId?: string) {\n\t\tconst targetOrderId = orderId || this.activeOrderId\n\t\tif (\n\t\t\t!targetOrderId ||\n\t\t\t!this.activeCheckoutAppId ||\n\t\t\t!this.activeCheckoutBaseUrl ||\n\t\t\tthis.paymentCompleted ||\n\t\t\tthis.cancelRequestedOrderId === targetOrderId\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tthis.cancelRequestedOrderId = targetOrderId\n\t\tconst url = `${this.activeCheckoutBaseUrl}/api/internal/checkout/cancel-order`\n\t\tconst payload = JSON.stringify({\n\t\t\tappId: this.activeCheckoutAppId,\n\t\t\torderId: targetOrderId,\n\t\t\treason,\n\t\t})\n\n\t\tif (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n\t\t\tconst sent = navigator.sendBeacon(\n\t\t\t\turl,\n\t\t\t\tnew Blob([payload], { type: \"application/json\" }),\n\t\t\t)\n\t\t\tif (sent) return\n\t\t}\n\n\t\tvoid fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: payload,\n\t\t\theaders: { \"Content-Type\": \"text/plain;charset=UTF-8\" },\n\t\t\tkeepalive: true,\n\t\t\tmode: \"no-cors\",\n\t\t}).catch(() => {\n\t\t\tthis.cancelRequestedOrderId = null\n\t\t})\n\t}\n\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\tthis.activeOrderId = null\n\t\tthis.paymentCompleted = false\n\t\tthis.cancelRequestedOrderId = null\n\t\tthis.cleanupPaymentFrameState()\n\t\tif (typeof urlOrParams === \"string\") {\n\t\t\tcheckoutUrl = urlOrParams\n\t\t\ttry {\n\t\t\t\tconst parsedUrl = new URL(checkoutUrl)\n\t\t\t\tthis.activeCheckoutBaseUrl = parsedUrl.origin\n\t\t\t\tconst parts = parsedUrl.pathname.split(\"/\").filter(Boolean)\n\t\t\t\tconst checkoutIndex = parts.indexOf(\"checkout\")\n\t\t\t\tthis.activeCheckoutAppId =\n\t\t\t\t\tcheckoutIndex >= 0 ? parts[checkoutIndex + 1] || null : null\n\t\t\t} catch {\n\t\t\t\tthis.activeCheckoutAppId = null\n\t\t\t\tthis.activeCheckoutBaseUrl = null\n\t\t\t}\n\t\t} else {\n\t\t\tconst {\n\t\t\t\tappId,\n\t\t\t\torderId,\n\t\t\t\tproductId,\n\t\t\t\tpriceId,\n\t\t\t\tproductCode,\n\t\t\t\tuserId,\n\t\t\t\tcustomAmount,\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\t\t\tthis.activeCheckoutAppId = appId\n\t\t\tthis.activeCheckoutBaseUrl = base\n\n\t\t\tconst query = new URLSearchParams()\n\t\t\tif (userId) query.set(\"userId\", userId)\n\t\t\tif (customAmount) {\n\t\t\t\tconst amount = Number(customAmount.amount)\n\t\t\t\tconst currency = customAmount.currency.trim().toUpperCase()\n\t\t\t\tif (!Number.isInteger(amount) || amount <= 0) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"customAmount.amount must be a positive integer in the smallest currency unit\",\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tif (!/^[A-Z]{3}$/.test(currency)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"customAmount.currency must be a 3-letter currency code\",\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tquery.set(\"customAmount\", String(amount))\n\t\t\t\tquery.set(\"customCurrency\", currency)\n\t\t\t}\n\n\t\t\tif (orderId) {\n\t\t\t\tconst cleanOrderId = orderId.trim()\n\t\t\t\tif (!cleanOrderId) {\n\t\t\t\t\tthrow new Error(\"orderId is required\")\n\t\t\t\t}\n\t\t\t\tthis.activeOrderId = cleanOrderId\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/orders/${cleanOrderId}`\n\t\t\t\tconst queryString = query.toString()\n\t\t\t\tif (queryString) checkoutUrl += `?${queryString}`\n\t\t\t} else if (productCode) {\n\t\t\t\t// Use product code route\n\t\t\t\tcheckoutUrl = `${base}/checkout/${appId}/code/${productCode}?${query.toString()}`\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}?${query.toString()}`\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Either orderId, 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\tconst hostedFrame = this.openHostedFrame(finalUrl, {\n\t\t\tallowedOrigin: options?.allowedOrigin,\n\t\t\theight: \"min(680px, calc(100vh - 32px))\",\n\t\t\tonCloseButton: () => {\n\t\t\t\tthis.cancelHostedOrder(\"modal_close\")\n\t\t\t\toptions?.onCancel?.(this.activeOrderId || undefined)\n\t\t\t},\n\t\t\tonMessage: (data, container, event) => {\n\t\t\t\tconst isIframeMessage = event.source === this.iframe?.contentWindow\n\t\t\t\tif (\n\t\t\t\t\tisIframeMessage &&\n\t\t\t\t\t(data.type === \"PAYMENT_READY\" ||\n\t\t\t\t\t\tdata.type === \"PAYMENT_RESIZE\" ||\n\t\t\t\t\t\tdata.type === \"PAYMENT_STARTED\")\n\t\t\t\t) {\n\t\t\t\t\tthis.markPaymentIframeReady()\n\t\t\t\t}\n\t\t\t\tswitch (data.type) {\n\t\t\t\t\tcase \"PAYMENT_READY\":\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_STARTED\":\n\t\t\t\t\t\tif (data.orderId) {\n\t\t\t\t\t\t\tthis.activeOrderId = data.orderId\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"PAYMENT_SUCCESS\":\n\t\t\t\t\t\tthis.paymentCompleted = true\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\tthis.cancelHostedOrder(\"payment_cancelled\", data.orderId)\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\tbreak\n\t\t\t\t\tcase \"PAYMENT_CLOSE\":\n\t\t\t\t\t\tthis.cancelHostedOrder(\"payment_close\", data.orderId)\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\twidth: \"min(450px, 100%)\",\n\t\t})\n\n\t\tif (hostedFrame) {\n\t\t\tthis.showPaymentIframeLoading(hostedFrame.container, options)\n\t\t\tthis.startPaymentIframeWatchdog({\n\t\t\t\tcontainer: hostedFrame.container,\n\t\t\t\tfinalUrl,\n\t\t\t\tpaymentOptions: options,\n\t\t\t})\n\t\t}\n\t}\n\n\tclose() {\n\t\tsuper.close()\n\t\tthis.cleanupPaymentFrameState()\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 (\n\t\t\t\t\t\tstatus.status === \"CANCELLED\" ||\n\t\t\t\t\t\tstatus.status === \"FAILED\" ||\n\t\t\t\t\t\tstatus.status === \"EXPIRED\"\n\t\t\t\t\t) {\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\nexport interface WechatMessageBindingUIOptions {\n\tbindingUrl: string\n\tdisplayMode?: \"redirect\" | \"popup\"\n\tpopupName?: string\n}\n\nexport class MessageUI {\n\topenWechatBinding(options: WechatMessageBindingUIOptions) {\n\t\tconst bindingUrl = options.bindingUrl?.trim()\n\t\tif (!bindingUrl) {\n\t\t\tthrow new Error(\"bindingUrl is required\")\n\t\t}\n\t\tif (options.displayMode === \"popup\") {\n\t\t\tconst popup = window.open(\n\t\t\t\tbindingUrl,\n\t\t\t\toptions.popupName || \"youidian-wechat-message-binding\",\n\t\t\t\t\"width=480,height=720,noopener,noreferrer\",\n\t\t\t)\n\t\t\tif (!popup) {\n\t\t\t\twindow.location.href = bindingUrl\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\twindow.location.href = bindingUrl\n\t}\n}\n\nexport function createMessageUI() {\n\treturn new MessageUI()\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\tLoginDeviceType,\n\tLoginEnvironment,\n\tLoginEnvironmentInput,\n} from \"./environment\"\nexport { detectLoginEnvironment } from \"./environment\"\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 type FeedbackIdentityKind =\n\t| \"ANONYMOUS\"\n\t| \"HOSTED_LOGIN\"\n\t| \"MERCHANT_USER\"\n\t| \"UNKNOWN\"\n\nexport type FeedbackActor = {\n\tidentityKind?: FeedbackIdentityKind | Lowercase<FeedbackIdentityKind>\n\tanonymousUserId?: string | null\n\tloginExternalUserId?: string | null\n\tmerchantUserId?: string | null\n\tcontactEmail?: string | null\n\tcontactPhone?: string | null\n\tdisplayName?: string | null\n}\n\nexport type FeedbackCategoryOption = {\n\tvalue: string\n\tlabel: string\n}\n\nexport type FeedbackWidgetOptions = {\n\tappId: string\n\tapiBaseUrl?: string\n\tactor?: FeedbackActor\n\tmetadata?: Record<string, unknown>\n\tcategories?: FeedbackCategoryOption[]\n\tlauncherText?: string\n\tpanelTitle?: string\n\tpanelSubtitle?: string\n\tplaceholder?: string\n\tcontactPlaceholder?: string\n\tonThreadCreated?: (threadId: string) => void\n\tonMessageSent?: (messageId: string) => void\n\tonError?: (error: Error) => void\n}\n\nexport type FeedbackWidgetController = {\n\topen: () => void\n\tclose: () => void\n\tdestroy: () => void\n}\n\ntype FeedbackMessage = {\n\tid: string\n\tsenderType: string\n\tcontent: string\n\ttranslatedContent?: string | null\n\tcreatedAt: string\n}\n\ntype ThreadState = {\n\tthreadId: string\n\tclientToken: string\n\tlastMessageId?: string\n\tstatus: string\n\tcategory?: string\n\tcontentPreview?: string\n\tcreatedAt?: string\n}\n\nconst DEFAULT_CATEGORIES: FeedbackCategoryOption[] = [\n\t{ value: \"BUG\", label: \"问题反馈\" },\n\t{ value: \"PAYMENT\", label: \"支付问题\" },\n\t{ value: \"LOGIN\", label: \"登录问题\" },\n\t{ value: \"SUGGESTION\", label: \"功能建议\" },\n\t{ value: \"OTHER\", label: \"其他\" },\n]\n\nconst STYLE_ID = \"youidian-feedback-widget-style\"\nconst MAX_IMAGES_PER_MESSAGE = 4\nconst DEFAULT_PANEL_TITLE = \"反馈\"\nconst DEFAULT_PANEL_SUBTITLE = \"提交问题、建议或使用反馈。\"\nconst DEFAULT_ATTACHMENTS_LABEL = \"支持粘贴、拖入或上传截图，最多 4 张\"\nconst FEEDBACK_ICON = `<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M21 11.5a8.4 8.4 0 0 1-.9 3.8 8.6 8.6 0 0 1-7.7 4.7 8.5 8.5 0 0 1-3.8-.9L3 21l1.9-5.2a8.5 8.5 0 0 1-1-4.1 8.6 8.6 0 0 1 8.6-8.6 8.5 8.5 0 0 1 8.5 8.4Z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8.4 10.2h7.2M8.4 13.5h4.7\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" stroke-linecap=\"round\"/></svg>`\nconst BUG_ICON = `<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M8 8.5a4 4 0 0 1 8 0v6a4 4 0 0 1-8 0v-6Z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"/><path d=\"M5 9h3m8 0h3M5.5 15H8m8 0h2.5M7 5.5 5.5 4M17 5.5 18.5 4M12 4.5V2.8M12 20.5v-12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"/></svg>`\nconst NOTE_ICON = `<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M7 3.5h7l3.5 3.5v13.5H7A2.5 2.5 0 0 1 4.5 18V6A2.5 2.5 0 0 1 7 3.5Z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"/><path d=\"M14 3.8V7h3.2M8 11h8M8 15h6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"/></svg>`\nconst MAIL_ICON = `<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M4.5 6.5h15v11h-15v-11Z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linejoin=\"round\"/><path d=\"m5 7 7 6 7-6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`\nconst IMAGE_ICON = `<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M5 5h14v14H5V5Z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linejoin=\"round\"/><path d=\"m7.5 16 3.2-3.2 2.4 2.4 1.7-1.7L18 16.8\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M15.8 8.2h.01\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"/></svg>`\nconst CHEVRON_ICON = `<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"m7 10 5 5 5-5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`\n\nfunction ensureStyle() {\n\tif (typeof document === \"undefined\") return\n\tif (document.getElementById(STYLE_ID)) return\n\tconst style = document.createElement(\"style\")\n\tstyle.id = STYLE_ID\n\tstyle.textContent = `\n.yd-feedback-root,.yd-feedback-root *{box-sizing:border-box}\n.yd-feedback-root{--yd-feedback-bg:hsl(var(--background,0 0% 100%));--yd-feedback-fg:hsl(var(--foreground,240 10% 3.9%));--yd-feedback-card:hsl(var(--card,0 0% 100%));--yd-feedback-card-fg:hsl(var(--card-foreground,240 10% 3.9%));--yd-feedback-muted:hsl(var(--muted,240 4.8% 95.9%));--yd-feedback-muted-fg:hsl(var(--muted-foreground,240 3.8% 46.1%));--yd-feedback-border:hsl(var(--border,240 5.9% 90%));--yd-feedback-primary:hsl(var(--primary,142 76% 36%));--yd-feedback-primary-fg:hsl(var(--primary-foreground,0 0% 100%));--yd-feedback-ring:hsl(var(--ring,142 76% 36%));font:14px/1.5 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;color:var(--yd-feedback-fg)}\n.yd-feedback-root button,.yd-feedback-root input,.yd-feedback-root textarea{font:inherit}\n.yd-feedback-launcher{position:fixed;right:22px;bottom:22px;z-index:2147483000;width:54px;height:54px;display:grid;place-items:center;border:1px solid color-mix(in srgb,var(--yd-feedback-primary) 24%,var(--yd-feedback-border));border-radius:999px;background:var(--yd-feedback-primary);color:var(--yd-feedback-primary-fg);box-shadow:0 18px 45px color-mix(in srgb,var(--yd-feedback-primary) 22%,transparent);cursor:pointer;transition:transform .18s ease,box-shadow .18s ease,background .18s ease}\n.yd-feedback-launcher:hover{transform:translateY(-2px);box-shadow:0 22px 56px color-mix(in srgb,var(--yd-feedback-primary) 30%,transparent)}\n.yd-feedback-launcher:focus-visible{outline:3px solid color-mix(in srgb,var(--yd-feedback-ring) 32%,transparent);outline-offset:3px}\n.yd-feedback-launcher svg{width:27px;height:27px}\n.yd-feedback-panel{position:fixed;inset:auto 22px 86px auto;z-index:2147483000;width:min(760px,calc(100vw - 44px));height:min(560px,calc(100vh - 108px));display:none;grid-template-rows:auto minmax(0,1fr);overflow:hidden;border:1px solid var(--yd-feedback-border);border-radius:18px;background:var(--yd-feedback-card);color:var(--yd-feedback-card-fg);box-shadow:0 24px 70px rgba(15,23,42,.18)}\n.yd-feedback-panel[data-open=\"true\"]{display:grid}\n.yd-feedback-header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:18px 20px 16px;border-bottom:1px solid var(--yd-feedback-border);background:var(--yd-feedback-card)}\n.yd-feedback-title{margin:0;font-size:22px;line-height:1.15;font-weight:760;letter-spacing:0;color:var(--yd-feedback-fg)}\n.yd-feedback-subtitle{margin:8px 0 0;color:var(--yd-feedback-muted-fg);font-size:13px;line-height:1.45}\n.yd-feedback-close{display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:10px;background:transparent;color:var(--yd-feedback-muted-fg);cursor:pointer;transition:background .16s ease,color .16s ease}\n.yd-feedback-close:hover{background:var(--yd-feedback-muted);color:var(--yd-feedback-fg)}\n.yd-feedback-close svg{width:24px;height:24px}\n.yd-feedback-shell{display:grid;min-height:0;grid-template-columns:230px minmax(0,1fr)}\n.yd-feedback-sidebar{min-width:0;border-right:1px solid var(--yd-feedback-border);background:var(--yd-feedback-muted)}\n.yd-feedback-sidebar-toolbar{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 14px;border-bottom:1px solid var(--yd-feedback-border)}\n.yd-feedback-sidebar-title{display:flex;align-items:center;gap:9px;color:var(--yd-feedback-fg);font-size:15px;font-weight:720}\n.yd-feedback-sidebar-title svg{width:20px;height:20px;color:var(--yd-feedback-primary)}\n.yd-feedback-icon-button{display:grid;place-items:center;width:34px;height:34px;border:1px solid var(--yd-feedback-border);border-radius:999px;background:var(--yd-feedback-card);color:var(--yd-feedback-fg);cursor:pointer;transition:background .16s ease,border-color .16s ease}\n.yd-feedback-icon-button:hover{background:color-mix(in srgb,var(--yd-feedback-primary) 8%,var(--yd-feedback-card));border-color:color-mix(in srgb,var(--yd-feedback-primary) 38%,var(--yd-feedback-border))}\n.yd-feedback-icon-button svg{width:18px;height:18px}\n.yd-feedback-thread-list{padding:12px}\n.yd-feedback-thread-card{display:none;border:1px solid var(--yd-feedback-border);border-radius:14px;background:var(--yd-feedback-card);padding:12px}\n.yd-feedback-thread-card[data-visible=\"true\"]{display:block}\n.yd-feedback-thread-badges{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:10px}\n.yd-feedback-badge{display:inline-flex;align-items:center;border:1px solid var(--yd-feedback-border);border-radius:999px;background:var(--yd-feedback-muted);color:var(--yd-feedback-fg);padding:4px 9px;font-size:11px;font-weight:700;line-height:1}\n.yd-feedback-badge[data-status=\"true\"]{border-color:color-mix(in srgb,var(--yd-feedback-primary) 45%,var(--yd-feedback-border));background:color-mix(in srgb,var(--yd-feedback-primary) 12%,var(--yd-feedback-card));color:var(--yd-feedback-primary)}\n.yd-feedback-thread-preview{margin:0;color:var(--yd-feedback-fg);font-size:13px;line-height:1.45;word-break:break-word}\n.yd-feedback-thread-meta{display:flex;justify-content:space-between;gap:10px;margin-top:10px;color:var(--yd-feedback-muted-fg);font-size:11px}\n.yd-feedback-empty-thread{border:1px dashed var(--yd-feedback-border);border-radius:14px;padding:14px;color:var(--yd-feedback-muted-fg);font-size:12px}\n.yd-feedback-main{min-width:0;min-height:0;background:var(--yd-feedback-card);overflow:hidden}\n.yd-feedback-form{height:100%;display:grid;grid-template-rows:auto auto auto minmax(0,1fr) auto auto;gap:14px;padding:16px 18px 0}\n.yd-feedback-row{display:grid;gap:14px;grid-template-columns:180px minmax(0,1fr)}\n.yd-feedback-field{display:flex;min-width:0;flex-direction:column;gap:8px}\n.yd-feedback-label{display:flex;align-items:center;gap:8px;color:var(--yd-feedback-fg);font-size:13px;font-weight:720}\n.yd-feedback-label svg{width:17px;height:17px;color:var(--yd-feedback-fg)}\n.yd-feedback-input,.yd-feedback-textarea{width:100%;border:1px solid var(--yd-feedback-border);border-radius:13px;background:var(--yd-feedback-card);color:var(--yd-feedback-fg);outline:none;transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}\n.yd-feedback-input{height:40px;padding:0 13px;font-size:14px}\n.yd-feedback-textarea{min-height:118px;padding:13px 14px;font-size:14px;resize:none}\n.yd-feedback-input::placeholder,.yd-feedback-textarea::placeholder{color:var(--yd-feedback-muted-fg)}\n.yd-feedback-input:focus,.yd-feedback-textarea:focus{border-color:var(--yd-feedback-ring);box-shadow:0 0 0 3px color-mix(in srgb,var(--yd-feedback-ring) 18%,transparent);background:var(--yd-feedback-card)}\n.yd-feedback-compose-box{overflow:hidden;border:1px solid var(--yd-feedback-border);border-radius:15px;background:var(--yd-feedback-card)}\n.yd-feedback-compose-box .yd-feedback-textarea{border:0;border-radius:0;box-shadow:none;background:transparent}\n.yd-feedback-attachment-row{display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--yd-feedback-border);padding:9px 12px;color:var(--yd-feedback-muted-fg)}\n.yd-feedback-file-trigger{display:inline-flex;align-items:center;gap:8px;border:0;background:transparent;color:var(--yd-feedback-fg);cursor:pointer;padding:7px 8px;border-radius:10px}\n.yd-feedback-file-trigger:hover{background:var(--yd-feedback-muted)}\n.yd-feedback-file-trigger svg{width:18px;height:18px}\n.yd-feedback-file-input{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;clip-path:inset(50%)}\n.yd-feedback-files{min-width:0;text-align:right;color:var(--yd-feedback-muted-fg);font-size:12px}\n.yd-feedback-select{position:relative;width:142px}\n.yd-feedback-select-button{width:100%;height:40px;display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid var(--yd-feedback-border);border-radius:13px;background:var(--yd-feedback-card);color:var(--yd-feedback-fg);padding:0 12px;cursor:pointer}\n.yd-feedback-select-value{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:700}\n.yd-feedback-select-value svg{width:18px;height:18px;color:var(--yd-feedback-muted-fg)}\n.yd-feedback-select-chevron{width:17px;height:17px;color:var(--yd-feedback-muted-fg)}\n.yd-feedback-select-menu{position:absolute;left:0;top:calc(100% + 7px);z-index:2;display:none;min-width:176px;max-height:220px;overflow:auto;border:1px solid var(--yd-feedback-border);border-radius:13px;background:var(--yd-feedback-card);box-shadow:0 18px 45px rgba(15,23,42,.16);padding:5px}\n.yd-feedback-select[data-open=\"true\"] .yd-feedback-select-menu{display:block}\n.yd-feedback-select-option{width:100%;min-height:38px;display:flex;align-items:center;gap:8px;border:0;border-radius:10px;background:transparent;color:var(--yd-feedback-fg);text-align:left;padding:9px 10px;cursor:pointer}\n.yd-feedback-select-option svg{width:18px;height:18px;flex:0 0 18px;color:var(--yd-feedback-muted-fg)}\n.yd-feedback-select-option span{line-height:1.2;white-space:nowrap}\n.yd-feedback-select-option:hover,.yd-feedback-select-option[data-selected=\"true\"]{background:color-mix(in srgb,var(--yd-feedback-primary) 10%,var(--yd-feedback-card));color:var(--yd-feedback-fg)}\n.yd-feedback-messages{display:flex;min-height:0;flex-direction:column;gap:8px;overflow:auto}\n.yd-feedback-message{border:1px solid var(--yd-feedback-border);border-radius:12px;padding:9px 10px;background:var(--yd-feedback-muted)}\n.yd-feedback-message[data-admin=\"true\"]{background:color-mix(in srgb,var(--yd-feedback-primary) 10%,var(--yd-feedback-card));border-color:color-mix(in srgb,var(--yd-feedback-primary) 24%,var(--yd-feedback-border))}\n.yd-feedback-message-meta{margin-bottom:4px;color:var(--yd-feedback-muted-fg);font-size:11px}\n.yd-feedback-message-content{color:var(--yd-feedback-fg);font-size:12px;line-height:1.45;word-break:break-word}\n.yd-feedback-actions{position:sticky;bottom:0;display:flex;align-items:center;justify-content:flex-end;gap:12px;margin:0 -18px;padding:12px 18px 16px;border-top:1px solid var(--yd-feedback-border);background:var(--yd-feedback-card)}\n.yd-feedback-submit{min-width:104px;height:44px;border:0;border-radius:13px;background:var(--yd-feedback-primary);color:var(--yd-feedback-primary-fg);padding:0 18px;font-size:14px;font-weight:800;cursor:pointer;box-shadow:0 12px 24px color-mix(in srgb,var(--yd-feedback-primary) 18%,transparent);transition:background .16s ease,transform .16s ease}\n.yd-feedback-submit:hover{transform:translateY(-1px)}\n.yd-feedback-submit:disabled{opacity:.55;cursor:not-allowed;transform:none}\n.yd-feedback-secondary{height:38px;border:0;border-radius:12px;background:transparent;color:var(--yd-feedback-fg);padding:0 12px;font-size:14px;font-weight:760;cursor:pointer}\n.yd-feedback-secondary:hover{background:var(--yd-feedback-muted)}\n.yd-feedback-error{min-height:18px;color:#fb7185;font-size:13px}\n@media (max-width:760px){\n\t.yd-feedback-panel{inset:auto 14px 78px 14px;width:auto;height:min(560px,calc(100vh - 96px));border-radius:16px}\n\t.yd-feedback-header{padding:16px 16px 14px}\n\t.yd-feedback-title{font-size:20px}\n\t.yd-feedback-shell{grid-template-columns:1fr}\n\t.yd-feedback-sidebar{display:none}\n\t.yd-feedback-form{padding:14px 14px 0;gap:12px}\n\t.yd-feedback-row{grid-template-columns:1fr}\n\t.yd-feedback-actions{justify-content:space-between}\n}\n`\n\tdocument.head.appendChild(style)\n}\n\nfunction getBaseUrl(options: FeedbackWidgetOptions) {\n\treturn (options.apiBaseUrl || \"https://pay.imgto.link\").replace(/\\/$/, \"\")\n}\n\nfunction safeJson(value: unknown) {\n\ttry {\n\t\treturn JSON.stringify(value)\n\t} catch {\n\t\treturn \"{}\"\n\t}\n}\n\nfunction escapeHtml(value: string) {\n\treturn value\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&#39;\")\n}\n\nfunction getInitialContact(actor?: FeedbackActor) {\n\treturn actor?.contactEmail || actor?.contactPhone || \"\"\n}\n\nfunction formatCategoryLabel(\n\tvalue?: string,\n\tcategories: FeedbackCategoryOption[] = DEFAULT_CATEGORIES,\n) {\n\tconst matched = categories.find((item) => item.value === value)\n\treturn matched?.label || value || DEFAULT_CATEGORIES[0]?.label || \"反馈\"\n}\n\nfunction formatThreadStatus(value?: string) {\n\tconst statusMap: Record<string, string> = {\n\t\tOPEN: \"已提交\",\n\t\tWAITING_ADMIN: \"等待回复\",\n\t\tWAITING_USER: \"待补充\",\n\t\tRESOLVED: \"已处理\",\n\t\tCLOSED: \"已关闭\",\n\t}\n\treturn statusMap[value || \"\"] || value || \"已提交\"\n}\n\nfunction formatSenderType(value: string) {\n\tif (value === \"END_USER\") return \"用户\"\n\tif (value === \"ADMIN\") return \"管理员\"\n\treturn \"系统\"\n}\n\nfunction formatThreadTime(value?: string) {\n\tif (!value) return \"\"\n\treturn new Date(value).toLocaleString()\n}\n\nasync function requestJson<T>(url: string, init?: RequestInit): Promise<T> {\n\tconst response = await fetch(url, {\n\t\t...init,\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t...(init?.body ? { \"Content-Type\": \"application/json\" } : {}),\n\t\t\t...(init?.headers || {}),\n\t\t},\n\t})\n\tconst payload = await response.json().catch(() => null)\n\tif (!response.ok || payload?.code !== 200) {\n\t\tthrow new Error(payload?.message || response.statusText || \"Request failed\")\n\t}\n\treturn payload.data as T\n}\n\nfunction collectMetadata(options: FeedbackWidgetOptions) {\n\tconst page =\n\t\ttypeof window === \"undefined\"\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tpageUrl: window.location.href,\n\t\t\t\t\tpageTitle: document.title,\n\t\t\t\t\tuserAgent: navigator.userAgent,\n\t\t\t\t}\n\treturn { ...page, ...(options.metadata || {}) }\n}\n\nasync function compressImage(file: File): Promise<File> {\n\tif (typeof document === \"undefined\" || !file.type.startsWith(\"image/\")) {\n\t\treturn file\n\t}\n\tconst bitmap = await createImageBitmap(file)\n\tconst maxSize = 1600\n\tconst scale = Math.min(1, maxSize / Math.max(bitmap.width, bitmap.height))\n\tconst canvas = document.createElement(\"canvas\")\n\tcanvas.width = Math.max(1, Math.round(bitmap.width * scale))\n\tcanvas.height = Math.max(1, Math.round(bitmap.height * scale))\n\tconst ctx = canvas.getContext(\"2d\")\n\tif (!ctx) return file\n\tctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height)\n\tconst blob = await new Promise<Blob | null>((resolve) => {\n\t\tcanvas.toBlob(resolve, \"image/webp\", 0.82)\n\t})\n\tif (!blob) return file\n\treturn new File([blob], file.name.replace(/\\.[^.]+$/, \".webp\"), {\n\t\ttype: \"image/webp\",\n\t\tlastModified: Date.now(),\n\t})\n}\n\nexport function createFeedbackWidget(\n\tcontainer: HTMLElement,\n\toptions: FeedbackWidgetOptions,\n): FeedbackWidgetController {\n\tif (typeof document === \"undefined\") {\n\t\treturn { open() {}, close() {}, destroy() {} }\n\t}\n\tif (!options.appId) throw new Error(\"appId is required\")\n\tensureStyle()\n\n\tlet threadState: ThreadState | null = null\n\tlet pollTimer: number | null = null\n\tlet panelReady = false\n\tlet pendingFiles: File[] = []\n\tlet renderedMessages: FeedbackMessage[] = []\n\tlet removeLoadListener: (() => void) | null = null\n\tconst root = document.createElement(\"div\")\n\troot.className = \"yd-feedback-root\"\n\tconst launcher = document.createElement(\"button\")\n\tlauncher.type = \"button\"\n\tlauncher.className = \"yd-feedback-launcher\"\n\tlauncher.setAttribute(\"aria-label\", options.launcherText || \"反馈\")\n\tlauncher.innerHTML = FEEDBACK_ICON\n\troot.appendChild(launcher)\n\tcontainer.appendChild(root)\n\n\tconst panel = document.createElement(\"section\")\n\tpanel.className = \"yd-feedback-panel\"\n\tpanel.setAttribute(\"aria-label\", options.panelTitle || DEFAULT_PANEL_TITLE)\n\tpanel.innerHTML = `\n<div class=\"yd-feedback-header\">\n\t<div>\n\t\t<h2 class=\"yd-feedback-title\">${escapeHtml(options.panelTitle || DEFAULT_PANEL_TITLE)}</h2>\n\t\t<p class=\"yd-feedback-subtitle\">${escapeHtml(options.panelSubtitle || DEFAULT_PANEL_SUBTITLE)}</p>\n\t</div>\n\t<button type=\"button\" class=\"yd-feedback-close\" aria-label=\"关闭\">\n\t\t<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M6 6l12 12M18 6 6 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\"/></svg>\n\t</button>\n</div>\n<div class=\"yd-feedback-shell\">\n\t<aside class=\"yd-feedback-sidebar\">\n\t\t<div class=\"yd-feedback-sidebar-toolbar\">\n\t\t\t<div class=\"yd-feedback-sidebar-title\">${FEEDBACK_ICON}<span>反馈记录</span></div>\n\t\t\t<button type=\"button\" class=\"yd-feedback-icon-button\" data-role=\"clear\" aria-label=\"新建反馈\">\n\t\t\t\t<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M12 5v14M5 12h14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\"/></svg>\n\t\t\t</button>\n\t\t</div>\n\t\t<div class=\"yd-feedback-thread-list\">\n\t\t\t<div class=\"yd-feedback-thread-card\" data-role=\"thread-card\">\n\t\t\t\t<div class=\"yd-feedback-thread-badges\">\n\t\t\t\t\t<span class=\"yd-feedback-badge\" data-role=\"thread-category\">问题反馈</span>\n\t\t\t\t\t<span class=\"yd-feedback-badge\" data-status=\"true\" data-role=\"thread-status\">已提交</span>\n\t\t\t\t</div>\n\t\t\t\t<p class=\"yd-feedback-thread-preview\" data-role=\"thread-preview\"></p>\n\t\t\t\t<div class=\"yd-feedback-thread-meta\">\n\t\t\t\t\t<span data-role=\"thread-time\"></span>\n\t\t\t\t\t<span>我的反馈</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"yd-feedback-empty-thread\" data-role=\"thread-empty\">提交反馈后，记录会显示在这里。</div>\n\t\t</div>\n\t</aside>\n\t<div class=\"yd-feedback-main\">\n\t\t<div class=\"yd-feedback-form\">\n\t\t\t<div class=\"yd-feedback-row\">\n\t\t\t\t<div class=\"yd-feedback-field\">\n\t\t\t\t\t<label class=\"yd-feedback-label\">反馈类型</label>\n\t\t\t\t\t<div class=\"yd-feedback-select\" data-role=\"category-select\">\n\t\t\t\t\t\t<button type=\"button\" class=\"yd-feedback-select-button\" data-role=\"category-trigger\">\n\t\t\t\t\t\t\t<span class=\"yd-feedback-select-value\">${BUG_ICON}<span data-role=\"category-value\">问题反馈</span></span>\n\t\t\t\t\t\t\t<span class=\"yd-feedback-select-chevron\">${CHEVRON_ICON}</span>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<div class=\"yd-feedback-select-menu\" data-role=\"category-menu\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"yd-feedback-field\">\n\t\t\t\t<label class=\"yd-feedback-label\">${NOTE_ICON}<span>反馈内容</span></label>\n\t\t\t\t<div class=\"yd-feedback-compose-box\">\n\t\t\t\t\t<textarea class=\"yd-feedback-textarea\" data-role=\"content\" placeholder=\"${escapeHtml(options.placeholder || \"请描述问题现象、操作步骤或建议内容。\")}\"></textarea>\n\t\t\t\t\t<div class=\"yd-feedback-attachment-row\">\n\t\t\t\t\t\t<button type=\"button\" class=\"yd-feedback-file-trigger\" data-role=\"files-trigger\">${IMAGE_ICON}<span>上传图片</span></button>\n\t\t\t\t\t\t<input class=\"yd-feedback-file-input\" type=\"file\" accept=\"image/png,image/jpeg,image/webp\" multiple data-role=\"files\" />\n\t\t\t\t\t\t<div class=\"yd-feedback-files\" data-role=\"files-label\">${DEFAULT_ATTACHMENTS_LABEL}</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"yd-feedback-field\">\n\t\t\t\t<label class=\"yd-feedback-label\">${MAIL_ICON}<span>联系方式（选填）</span></label>\n\t\t\t\t<input class=\"yd-feedback-input\" data-role=\"contact\" value=\"${escapeHtml(getInitialContact(options.actor))}\" placeholder=\"${escapeHtml(options.contactPlaceholder || \"邮箱或电话号码，仅用于反馈跟进\")}\" />\n\t\t\t</div>\n\t\t\t<div class=\"yd-feedback-messages\" data-role=\"messages\"></div>\n\t\t\t<div class=\"yd-feedback-error\" data-role=\"error\"></div>\n\t\t\t<div class=\"yd-feedback-actions\">\n\t\t\t\t<button type=\"button\" class=\"yd-feedback-secondary\" data-role=\"clear-secondary\">关闭</button>\n\t\t\t\t<button type=\"button\" class=\"yd-feedback-submit\" data-role=\"submit\">提交反馈</button>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n`\n\n\tfunction initPanel() {\n\t\tif (panelReady) return\n\t\tpanelReady = true\n\t\troot.appendChild(panel)\n\t\tconst categorySelect = panel.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"category-select\"]',\n\t\t)\n\t\tconst categoryMenu = panel.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"category-menu\"]',\n\t\t)\n\t\tconst categoryValue = panel.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"category-value\"]',\n\t\t)\n\t\tif (categoryMenu && categoryValue) {\n\t\t\tconst categories = options.categories || DEFAULT_CATEGORIES\n\t\t\tcategoryValue.textContent =\n\t\t\t\tcategories[0]?.label || DEFAULT_CATEGORIES[0]?.label || \"反馈\"\n\t\t\tfor (const item of categories) {\n\t\t\t\tconst option = document.createElement(\"button\")\n\t\t\t\toption.type = \"button\"\n\t\t\t\toption.className = \"yd-feedback-select-option\"\n\t\t\t\toption.dataset.value = item.value\n\t\t\t\toption.dataset.selected = String(item.value === categories[0]?.value)\n\t\t\t\toption.innerHTML = `${BUG_ICON}<span>${escapeHtml(item.label)}</span>`\n\t\t\t\toption.addEventListener(\"click\", () => {\n\t\t\t\t\tfor (const node of categoryMenu.querySelectorAll<HTMLElement>(\n\t\t\t\t\t\t\".yd-feedback-select-option\",\n\t\t\t\t\t)) {\n\t\t\t\t\t\tnode.dataset.selected = String(node === option)\n\t\t\t\t\t}\n\t\t\t\t\tcategoryValue.textContent = item.label\n\t\t\t\t\tif (categorySelect) {\n\t\t\t\t\t\tcategorySelect.dataset.value = item.value\n\t\t\t\t\t\tcategorySelect.dataset.open = \"false\"\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\tcategoryMenu.appendChild(option)\n\t\t\t}\n\t\t\tcategorySelect?.setAttribute(\"data-value\", categories[0]?.value || \"BUG\")\n\t\t}\n\t\tpanel\n\t\t\t.querySelector<HTMLButtonElement>('[data-role=\"category-trigger\"]')\n\t\t\t?.addEventListener(\"click\", () => {\n\t\t\t\tif (!categorySelect) return\n\t\t\t\tcategorySelect.dataset.open =\n\t\t\t\t\tcategorySelect.dataset.open === \"true\" ? \"false\" : \"true\"\n\t\t\t})\n\t\tpanel\n\t\t\t.querySelector<HTMLButtonElement>(\".yd-feedback-close\")\n\t\t\t?.addEventListener(\"click\", close)\n\t\tpanel\n\t\t\t.querySelector<HTMLButtonElement>('[data-role=\"clear\"]')\n\t\t\t?.addEventListener(\"click\", resetThread)\n\t\tpanel\n\t\t\t.querySelector<HTMLButtonElement>('[data-role=\"clear-secondary\"]')\n\t\t\t?.addEventListener(\"click\", close)\n\t\tpanel\n\t\t\t.querySelector<HTMLButtonElement>('[data-role=\"files-trigger\"]')\n\t\t\t?.addEventListener(\"click\", () => {\n\t\t\t\tpanel.querySelector<HTMLInputElement>('[data-role=\"files\"]')?.click()\n\t\t\t})\n\t\tpanel\n\t\t\t.querySelector<HTMLInputElement>('[data-role=\"files\"]')\n\t\t\t?.addEventListener(\"change\", (event) => {\n\t\t\t\tsetPendingFiles((event.target as HTMLInputElement).files)\n\t\t\t})\n\t\tconst composeBox = panel.querySelector<HTMLElement>(\n\t\t\t\".yd-feedback-compose-box\",\n\t\t)\n\t\tcomposeBox?.addEventListener(\"dragover\", (event) => {\n\t\t\tevent.preventDefault()\n\t\t})\n\t\tcomposeBox?.addEventListener(\"drop\", (event) => {\n\t\t\tevent.preventDefault()\n\t\t\tsetPendingFiles(event.dataTransfer?.files || null)\n\t\t})\n\t\tcomposeBox?.addEventListener(\"paste\", (event) => {\n\t\t\tconst files = Array.from(event.clipboardData?.files || []).filter(\n\t\t\t\t(file) => file.type.startsWith(\"image/\"),\n\t\t\t)\n\t\t\tif (files.length > 0) {\n\t\t\t\tsetPendingFiles(files)\n\t\t\t}\n\t\t})\n\t\tpanel\n\t\t\t.querySelector<HTMLButtonElement>('[data-role=\"submit\"]')\n\t\t\t?.addEventListener(\"click\", () => void submit())\n\t}\n\n\tfunction setPendingFiles(files: FileList | File[] | null) {\n\t\tpendingFiles = Array.from(files || [])\n\t\t\t.filter((file) => file.type.startsWith(\"image/\"))\n\t\t\t.slice(0, MAX_IMAGES_PER_MESSAGE)\n\t\tconst label = panel.querySelector<HTMLElement>('[data-role=\"files-label\"]')\n\t\tif (label) {\n\t\t\tlabel.textContent =\n\t\t\t\tpendingFiles.length > 0\n\t\t\t\t\t? `已选择 ${pendingFiles.length} 张图片`\n\t\t\t\t\t: DEFAULT_ATTACHMENTS_LABEL\n\t\t}\n\t}\n\n\tfunction resetThread() {\n\t\tthreadState = null\n\t\tpendingFiles = []\n\t\trenderedMessages = []\n\t\trenderMessages([])\n\t\tupdateThreadCard()\n\t\tsetError(\"\")\n\t\tconst textarea = panel.querySelector<HTMLTextAreaElement>(\n\t\t\t'[data-role=\"content\"]',\n\t\t)\n\t\tif (textarea) textarea.value = \"\"\n\t\tconst fileInput = panel.querySelector<HTMLInputElement>(\n\t\t\t'[data-role=\"files\"]',\n\t\t)\n\t\tif (fileInput) fileInput.value = \"\"\n\t\tconst filesLabel = panel.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"files-label\"]',\n\t\t)\n\t\tif (filesLabel) filesLabel.textContent = DEFAULT_ATTACHMENTS_LABEL\n\t}\n\n\tfunction updateThreadCard() {\n\t\tconst card = panel.querySelector<HTMLElement>('[data-role=\"thread-card\"]')\n\t\tconst empty = panel.querySelector<HTMLElement>('[data-role=\"thread-empty\"]')\n\t\tif (!card || !empty) return\n\t\tif (!threadState) {\n\t\t\tcard.dataset.visible = \"false\"\n\t\t\tempty.style.display = \"block\"\n\t\t\treturn\n\t\t}\n\t\tcard.dataset.visible = \"true\"\n\t\tempty.style.display = \"none\"\n\t\tconst category = card.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"thread-category\"]',\n\t\t)\n\t\tconst status = card.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"thread-status\"]',\n\t\t)\n\t\tconst preview = card.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"thread-preview\"]',\n\t\t)\n\t\tconst time = card.querySelector<HTMLElement>('[data-role=\"thread-time\"]')\n\t\tif (category) {\n\t\t\tcategory.textContent = formatCategoryLabel(\n\t\t\t\tthreadState.category || DEFAULT_CATEGORIES[0]?.value,\n\t\t\t\toptions.categories || DEFAULT_CATEGORIES,\n\t\t\t)\n\t\t}\n\t\tif (status) status.textContent = formatThreadStatus(threadState.status)\n\t\tif (preview) preview.textContent = threadState.contentPreview || \"\"\n\t\tif (time) time.textContent = formatThreadTime(threadState.createdAt)\n\t}\n\n\tfunction setError(message: string) {\n\t\tconst node = panel.querySelector<HTMLElement>('[data-role=\"error\"]')\n\t\tif (node) node.textContent = message\n\t\tif (message) options.onError?.(new Error(message))\n\t}\n\n\tfunction setSubmitting(value: boolean) {\n\t\tconst button = panel.querySelector<HTMLButtonElement>(\n\t\t\t'[data-role=\"submit\"]',\n\t\t)\n\t\tif (button) button.disabled = value\n\t}\n\n\tfunction renderMessages(messages: FeedbackMessage[]) {\n\t\tconst node = panel.querySelector<HTMLElement>('[data-role=\"messages\"]')\n\t\tif (!node) return\n\t\trenderedMessages = messages\n\t\tnode.innerHTML = \"\"\n\t\tfor (const message of messages) {\n\t\t\tconst item = document.createElement(\"div\")\n\t\t\titem.className = \"yd-feedback-message\"\n\t\t\titem.dataset.admin = String(message.senderType !== \"END_USER\")\n\t\t\titem.innerHTML = `<div class=\"yd-feedback-message-meta\">${formatSenderType(message.senderType)} · ${new Date(message.createdAt).toLocaleString()}</div><div class=\"yd-feedback-message-content\"></div>`\n\t\t\tconst content = item.querySelector(\".yd-feedback-message-content\")\n\t\t\tif (content) {\n\t\t\t\tcontent.textContent =\n\t\t\t\t\tmessage.senderType === \"END_USER\"\n\t\t\t\t\t\t? message.content\n\t\t\t\t\t\t: message.translatedContent || message.content\n\t\t\t}\n\t\t\tnode.appendChild(item)\n\t\t}\n\t}\n\n\tfunction appendMessages(messages: FeedbackMessage[]) {\n\t\tconst byId = new Map<string, FeedbackMessage>()\n\t\tfor (const message of renderedMessages) byId.set(message.id, message)\n\t\tfor (const message of messages) byId.set(message.id, message)\n\t\trenderMessages(Array.from(byId.values()))\n\t}\n\n\tasync function uploadImages(files: File[]) {\n\t\tconst selected = files.slice(0, MAX_IMAGES_PER_MESSAGE)\n\t\tconst ids: string[] = []\n\t\tfor (const file of selected) {\n\t\t\tconst compressed = await compressImage(file)\n\t\t\tconst body = new FormData()\n\t\t\tbody.append(\"file\", compressed)\n\t\t\tif (threadState) body.append(\"threadId\", threadState.threadId)\n\t\t\tconst headers: Record<string, string> = {}\n\t\t\tif (threadState) headers[\"x-feedback-token\"] = threadState.clientToken\n\t\t\tconst response = await fetch(\n\t\t\t\t`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/resources/images`,\n\t\t\t\t{ method: \"POST\", body, headers },\n\t\t\t)\n\t\t\tconst payload = await response.json()\n\t\t\tif (!response.ok || payload?.code !== 200) {\n\t\t\t\tthrow new Error(payload?.message || \"Image upload failed\")\n\t\t\t}\n\t\t\tids.push(payload.data.resource.id)\n\t\t}\n\t\treturn ids\n\t}\n\n\tasync function submit() {\n\t\tconst content = panel\n\t\t\t.querySelector<HTMLTextAreaElement>('[data-role=\"content\"]')\n\t\t\t?.value.trim()\n\t\tif (!content) {\n\t\t\tsetError(\"请输入反馈内容。\")\n\t\t\treturn\n\t\t}\n\t\tsetSubmitting(true)\n\t\tsetError(\"\")\n\t\ttry {\n\t\t\tconst category =\n\t\t\t\tpanel.querySelector<HTMLElement>('[data-role=\"category-select\"]')\n\t\t\t\t\t?.dataset.value || \"OTHER\"\n\t\t\tconst contact =\n\t\t\t\tpanel.querySelector<HTMLInputElement>('[data-role=\"contact\"]')?.value ||\n\t\t\t\t\"\"\n\t\t\tconst fileInput = panel.querySelector<HTMLInputElement>(\n\t\t\t\t'[data-role=\"files\"]',\n\t\t\t)\n\t\t\tconst attachments = await uploadImages(pendingFiles)\n\t\t\tif (!threadState) {\n\t\t\t\tconst result = await requestJson<{\n\t\t\t\t\tthread: { id: string; status: string }\n\t\t\t\t\tmessage: { id: string }\n\t\t\t\t\tclientToken: string\n\t\t\t\t}>(\n\t\t\t\t\t`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/threads`,\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\tbody: safeJson({\n\t\t\t\t\t\t\tcategory,\n\t\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t\tattachments,\n\t\t\t\t\t\t\tactor: {\n\t\t\t\t\t\t\t\t...(options.actor || {}),\n\t\t\t\t\t\t\t\tcontactEmail: contact.includes(\"@\")\n\t\t\t\t\t\t\t\t\t? contact\n\t\t\t\t\t\t\t\t\t: options.actor?.contactEmail,\n\t\t\t\t\t\t\t\tcontactPhone:\n\t\t\t\t\t\t\t\t\tcontact && !contact.includes(\"@\")\n\t\t\t\t\t\t\t\t\t\t? contact\n\t\t\t\t\t\t\t\t\t\t: options.actor?.contactPhone,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmetadata: collectMetadata(options),\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tthreadState = {\n\t\t\t\t\tthreadId: result.thread.id,\n\t\t\t\t\tclientToken: result.clientToken,\n\t\t\t\t\tlastMessageId: result.message?.id,\n\t\t\t\t\tstatus: result.thread.status,\n\t\t\t\t\tcategory,\n\t\t\t\t\tcontentPreview: content,\n\t\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\t}\n\t\t\t\tupdateThreadCard()\n\t\t\t\toptions.onThreadCreated?.(result.thread.id)\n\t\t\t\toptions.onMessageSent?.(result.message.id)\n\t\t\t} else {\n\t\t\t\tconst result = await requestJson<{ message: { id: string } }>(\n\t\t\t\t\t`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/threads/${encodeURIComponent(threadState.threadId)}/messages`,\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: { \"x-feedback-token\": threadState.clientToken },\n\t\t\t\t\t\tbody: safeJson({\n\t\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t\tattachments,\n\t\t\t\t\t\t\tmetadata: collectMetadata(options),\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tthreadState.lastMessageId = result.message.id\n\t\t\t\tthreadState.contentPreview = content\n\t\t\t\toptions.onMessageSent?.(result.message.id)\n\t\t\t}\n\t\t\tconst textarea = panel.querySelector<HTMLTextAreaElement>(\n\t\t\t\t'[data-role=\"content\"]',\n\t\t\t)\n\t\t\tif (textarea) textarea.value = \"\"\n\t\t\tif (fileInput) fileInput.value = \"\"\n\t\t\tpendingFiles = []\n\t\t\tconst filesLabel = panel.querySelector<HTMLElement>(\n\t\t\t\t'[data-role=\"files-label\"]',\n\t\t\t)\n\t\t\tif (filesLabel) filesLabel.textContent = DEFAULT_ATTACHMENTS_LABEL\n\t\t\tawait pollOnce()\n\t\t\tstartPolling()\n\t\t} catch (error) {\n\t\t\tsetError(error instanceof Error ? error.message : \"提交失败\")\n\t\t} finally {\n\t\t\tsetSubmitting(false)\n\t\t}\n\t}\n\n\tasync function pollOnce() {\n\t\tif (!threadState) return\n\t\tconst currentThread = threadState\n\t\tconst params = new URLSearchParams()\n\t\tif (currentThread.lastMessageId) {\n\t\t\tparams.set(\"afterMessageId\", currentThread.lastMessageId)\n\t\t}\n\t\tparams.set(\"feedbackToken\", currentThread.clientToken)\n\t\tconst result = await requestJson<{\n\t\t\tthreadStatus: string\n\t\t\tmessages: FeedbackMessage[]\n\t\t\tnextPollAfterMs: number\n\t\t}>(\n\t\t\t`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/threads/${encodeURIComponent(currentThread.threadId)}/messages?${params.toString()}`,\n\t\t)\n\t\tcurrentThread.status = result.threadStatus\n\t\tupdateThreadCard()\n\t\tif (result.messages.length > 0) {\n\t\t\tconst latestMessage = result.messages.at(-1)\n\t\t\tif (latestMessage) currentThread.lastMessageId = latestMessage.id\n\t\t\tappendMessages(result.messages)\n\t\t}\n\t\tif (result.threadStatus !== \"WAITING_ADMIN\") stopPolling()\n\t\telse schedulePoll(result.nextPollAfterMs)\n\t}\n\n\tfunction schedulePoll(delay: number) {\n\t\tstopPolling()\n\t\tif (!delay || delay < 1 || document.hidden || !threadState) return\n\t\tpollTimer = window.setTimeout(() => void pollOnce(), delay)\n\t}\n\n\tfunction startPolling() {\n\t\tif (!threadState || threadState.status !== \"WAITING_ADMIN\") return\n\t\tschedulePoll(10_000)\n\t}\n\n\tfunction stopPolling() {\n\t\tif (pollTimer) window.clearTimeout(pollTimer)\n\t\tpollTimer = null\n\t}\n\n\tfunction open() {\n\t\tinitPanel()\n\t\tpanel.dataset.open = \"true\"\n\t\twindow.setTimeout(() => {\n\t\t\tpanel.querySelector<HTMLTextAreaElement>('[data-role=\"content\"]')?.focus()\n\t\t}, 0)\n\t}\n\n\tfunction close() {\n\t\tpanel.dataset.open = \"false\"\n\t\tstopPolling()\n\t}\n\n\tlauncher.addEventListener(\"click\", open)\n\tconst handleVisibilityChange = () => {\n\t\tif (document.hidden) stopPolling()\n\t\telse startPolling()\n\t}\n\tconst handleDocumentClick = (event: MouseEvent) => {\n\t\tconst categorySelect = panel.querySelector<HTMLElement>(\n\t\t\t'[data-role=\"category-select\"]',\n\t\t)\n\t\tif (\n\t\t\tcategorySelect &&\n\t\t\tevent.target instanceof Node &&\n\t\t\t!categorySelect.contains(event.target)\n\t\t) {\n\t\t\tcategorySelect.dataset.open = \"false\"\n\t\t}\n\t}\n\tdocument.addEventListener(\"visibilitychange\", handleVisibilityChange)\n\tdocument.addEventListener(\"click\", handleDocumentClick)\n\n\tif (typeof window !== \"undefined\") {\n\t\tconst preload = () => {\n\t\t\tif (\"requestIdleCallback\" in window) {\n\t\t\t\t;(window as any).requestIdleCallback(() => initPanel())\n\t\t\t} else {\n\t\t\t\tglobalThis.setTimeout(() => initPanel(), 1200)\n\t\t\t}\n\t\t}\n\t\tif (document.readyState === \"complete\") preload()\n\t\telse {\n\t\t\twindow.addEventListener(\"load\", preload, { once: true })\n\t\t\tremoveLoadListener = () => window.removeEventListener(\"load\", preload)\n\t\t}\n\t}\n\n\treturn {\n\t\topen,\n\t\tclose,\n\t\tdestroy() {\n\t\t\tstopPolling()\n\t\t\tdocument.removeEventListener(\"visibilitychange\", handleVisibilityChange)\n\t\t\tdocument.removeEventListener(\"click\", handleDocumentClick)\n\t\t\tremoveLoadListener?.()\n\t\t\troot.remove()\n\t\t},\n\t}\n}\n\nexport function mountFeedbackWidget(\n\tcontainer: HTMLElement,\n\toptions: FeedbackWidgetOptions,\n) {\n\treturn createFeedbackWidget(container, options)\n}\n","/**\n * Youidian Payment SDK - Server Module\n * 用于服务端集成，包含签名、订单创建、回调解密等功能\n */\n\nimport crypto from \"crypto\"\n\n/**\n * Order status response\n */\nexport interface OrderStatus {\n\torderId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\" | \"EXPIRED\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\nexport type SubscriptionAction = \"NEW\" | \"UPGRADE\" | \"DOWNGRADE\"\nexport type SubscriptionIntent = \"STANDARD\" | \"UPGRADE\" | \"QUEUED_UPGRADE\"\n\nexport type SubscriptionStatus =\n\t| \"PENDING\"\n\t| \"ACTIVE\"\n\t| \"EXPIRED\"\n\t| \"REPLACED\"\n\t| \"CANCELLED\"\n\nexport type SubscriptionAutoRefundStatus = \"PROCESSING\" | \"SUCCEEDED\" | \"FAILED\"\n\nexport type SubscriptionErrorCode =\n\t| \"SUBSCRIPTION_UPGRADE_NOT_AVAILABLE\"\n\t| \"SUBSCRIPTION_SAME_LEVEL_NOT_ALLOWED\"\n\t| \"SUBSCRIPTION_DOWNGRADE_NOT_ALLOWED\"\n\t| \"SUBSCRIPTION_PENDING_ORDER_EXISTS\"\n\t| \"SUBSCRIPTION_NO_REMAINING_DAYS\"\n\t| \"SUBSCRIPTION_CURRENCY_MISMATCH\"\n\t| \"SUBSCRIPTION_PERIOD_MISMATCH\"\n\t| \"SUBSCRIPTION_PRICING_MANAGED\"\n\nexport interface SubscriptionBillingSnapshot {\n\tversion: number\n\taction: SubscriptionAction\n\tisUpgrade: boolean\n\tquoteBusinessDate: string\n\ttimezone: string\n\tperiodDays: number\n\tsubscriptionGroup: string\n\tsubscriptionLevel: number\n\tproductCode: string\n\tstandardAmount: number\n\tpolicyDiscountAmount: number\n\tpolicyId: string | null\n\tpolicyCode: string | null\n\tpolicyName: string | null\n\tpolicyRevision: number | null\n\tqualificationCode: string | null\n\tintent?: SubscriptionIntent | null\n\tfromSubscriptionId?: string | null\n\tmanagedSubscription?: boolean\n\tfromProductCode?: string | null\n\tremainingDays?: number | null\n\tcurrentFullPlanValueAmount?: number | null\n\tcurrentRemainingValueAmount?: number | null\n\ttargetFullPlanValueAmount?: number | null\n\ttargetRemainingValueAmount?: number | null\n\tappliedDiscountAmount?: number | null\n\tfinalAmount?: number | null\n\tstartsAt?: string | null\n\tcycleStartsAt?: string | null\n\texpiresAt?: string | null\n\tpreviousSubscriptionExpiresAt?: string | null\n\tqueueMode?: \"INSERT_AFTER_ACTIVE\" | null\n\tqueueAdjustments?: SubscriptionQueueAdjustment[]\n}\n\nexport interface SubscriptionQueueAdjustment {\n\tsubscriptionId: string\n\tsourceOrderId: string\n\tstartsAt: string\n\tcycleStartsAt: string\n\texpiresAt: string\n\treplacesSubscriptionId: string | null\n}\n\nexport interface BillingSnapshot {\n\tversion: number\n\tstandardAmount: number\n\tdiscountAmount: number\n\tupgradeCreditAmount: number\n\ttargetRemainingValueAmount: number | null\n\tfullPlanValueAmount: number | null\n\tdiscountPolicyCode: string | null\n\tdiscountPolicyRevision: number | null\n\tqualificationCode: string | null\n\trefundRequired: boolean\n\tautoRefundStatus: SubscriptionAutoRefundStatus | null\n\tsubscription: SubscriptionBillingSnapshot | null\n\tcustomAmount: Record<string, unknown> | null\n\tmerchantPricing: MerchantPricingSnapshot | null\n}\n\nexport interface SubscriptionDetails {\n\tid: string\n\taction: SubscriptionAction\n\tstatus: SubscriptionStatus\n\tproductId: string\n\tproductCode: string\n\tpriceId: string\n\tsubscriptionGroup: string\n\tsubscriptionLevel: number\n\tstartsAt: string\n\tcycleStartsAt: string\n\texpiresAt: string\n\tperiodDays: number\n\ttimezone: string\n\tfullPlanValueAmount: number\n\tcurrency: string\n\treplacesSubscriptionId: string | null\n\tactivatedAt: string | null\n\treplacedAt: string | null\n\tcancelledAt: string | null\n}\n\nexport class PaymentApiError extends Error {\n\treadonly status: number\n\treadonly code?: string\n\n\tconstructor(message: string, status: number, code?: string) {\n\t\tsuper(message)\n\t\tthis.name = \"PaymentApiError\"\n\t\tthis.status = status\n\t\tthis.code = code\n\t}\n}\n\n/**\n * Order details response (full order information)\n */\nexport interface OrderDetails {\n\torderId: string\n\tinternalId: string\n\tmerchantUserId: string\n\tproductCode: string | null\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\" | \"EXPIRED\"\n\tamount: number\n\tcurrency: string\n\tdescription?: string\n\tpaidAt?: string\n\tcreatedAt: string\n\tchannel?: string\n\tmerchantPricing?: MerchantPricingSnapshot\n\tbilling: BillingSnapshot\n\tsubscription: SubscriptionDetails | null\n\tpricingBreakdown?: PricingBreakdown\n\tupgrade?: {\n\t\tisUpgrade: boolean\n\t\tfromProductId?: string | null\n\t\tfromProductCode?: string | null\n\t\tfromPriceId?: string | null\n\t\tfromOrderId?: string | null\n\t\tfromSourceKind?: string | null\n\t\tfromSortOrder?: number | null\n\t\ttoSortOrder?: number | null\n\t\toriginalAmount?: number | null\n\t\tcreditAmount?: number | null\n\t\tfinalPayableAmount?: number | null\n\t\tremainingRatio?: number | null\n\t\tnewPeriodStartsAt?: string | null\n\t\tnewPeriodValue?: number | null\n\t\tnewPeriodUnit?: \"days\" | \"months\" | \"years\" | null\n\t} | null\n\tproduct?: {\n\t\tcode: string\n\t\ttype: string\n\t\tname: string\n\t\tdescription?: string\n\t\tentitlements: ProductEntitlements\n\t\tmetadata?: ProductMetadata | null\n\t}\n}\n\n/**\n * Product Entitlements\n */\nexport interface ProductEntitlements {\n\t[key: string]: any\n}\n\n/**\n * Product Price\n */\nexport interface ProductPrice {\n\tid: string\n\tcurrency: string\n\tamount: number\n\tdisplayAmount: string\n\tlocale: string | null\n\tisDefault: boolean\n}\n\nexport interface ProductSubscriptionPeriod {\n\tvalue: number\n\tunit: \"days\" | \"months\" | \"years\"\n}\n\nexport interface ProductResetRule {\n\tresetInterval: \"day\" | \"month\"\n}\n\nexport interface ProductCustomAmountCurrency {\n\tminAmount: number\n\tmaxAmount: number\n\tstepAmount?: number\n\tunitsPerCurrencyUnit: number\n\tunitsPerCurrencyUnitBasis?: \"MINOR\" | \"MAJOR\"\n}\n\nexport interface ProductCustomAmount {\n\tenabled: boolean\n\tentitlementKey: string\n\tcurrencies: Record<string, ProductCustomAmountCurrency>\n}\n\nexport interface ProductInventory {\n\tenabled: boolean\n\ttotalQuantity: number\n\treserveTimeoutSeconds?: number\n}\n\nexport interface ProductMetadata {\n\tsubscriptionPeriod?: ProductSubscriptionPeriod\n\tsubscriptionGroup?: string\n\trestrictSubscriptionPurchase?: boolean\n\texpiringEntitlements?: string[]\n\tresetEntitlements?: Record<string, ProductResetRule>\n\tautoAssignOnNewUser?: boolean\n\ttrialDurationDays?: number\n\tcustomAmount?: ProductCustomAmount\n\tinventory?: ProductInventory\n}\n\nexport type ProductStockLookupMode = \"auto\" | \"id\" | \"code\"\n\nexport interface ProductStock {\n\tproductId: string\n\tproductCode: string\n\tlimited: boolean\n\ttotal: number | null\n\treserved: number\n\tsold: number\n\tavailable: number | null\n\tupdatedAt: string\n\treserveTimeoutSeconds: number | null\n}\n\nexport interface ProductStockQueryOptions {\n\tlookupBy?: ProductStockLookupMode\n\tlocale?: string\n\tcurrency?: string\n}\n\nexport interface ProductStocksQueryParams {\n\tproductIds?: string[]\n\tproductCodes?: string[]\n}\n\nexport interface PricingBreakdown {\n\tisUpgrade: boolean\n\toriginalAmount: number\n\tcreditAmount: number\n\tfinalPayableAmount: number\n\tfromProductCode?: string | null\n}\n\nexport interface ConsumeEntitlementPoolResult {\n\tbalance: number\n\tbalances: Record<string, number>\n\tconsumed: Record<string, number>\n\tconsumedBuckets?: EntitlementCreditBucketConsumption[]\n}\n\nexport interface EntitlementCreditBucket {\n\tkey: string\n\tgrantId: string | null\n\tsourceKind: string\n\tsourceProductId: string | null\n\tsourceOrderId: string | null\n\tamount: number\n\tremaining: number\n\texpiresAt: string | null\n\tgrantedAt: string | null\n\tmetadata?: Record<string, any> | null\n}\n\nexport interface EntitlementCreditBucketConsumption {\n\tkey: string\n\tgrantId: string | null\n\tamount: number\n\texpiresAt: string | null\n\tsourceProductId: string | null\n\tsourceOrderId: string | null\n}\n\nexport interface ActiveSubscriptionInfo {\n\tsubscriptionId?: string\n\tproductId: string\n\tproductCode: string\n\tsortOrder: number\n\tsubscriptionLevel?: number\n\tsubscriptionGroup?: string | null\n\tpaidAt?: string | null\n\tcycleStartsAt?: string\n\texpiresAt: string\n\tperiodDays?: number\n\ttimezone?: string\n\tpriceId?: string | null\n\torderId?: string | null\n\tsourceKind?: string | null\n\tcurrency?: string | null\n}\n\nexport interface DiscountPolicy {\n\tcode: string\n\tname: string\n\tdescription: string | null\n\tqualificationCode: string\n\tbalancePackThresholdAmount: number | null\n\tproductId: string\n\tproductCode: string\n\tpriceId: string\n\tcurrency: string\n\tstandardAmount: number\n\tdiscountAmount: number\n\tstartsAt: string | null\n\tendsAt: string | null\n}\n\nexport interface UserProductDiscountEligibility {\n\tuserId: string\n\tproductId: string\n\tproductCode: string\n\teligible: boolean\n\tcoupons: Array<{\n\t\tcoupon: DiscountPolicy\n\t\teligible: boolean\n\t\tgrantedAt: string | null\n\t}>\n}\n\n/**\n * Product Data\n */\nexport interface Product {\n\tid: string\n\tcode: string\n\ttype: string\n\tname: string\n\tdescription?: string\n\tentitlements: ProductEntitlements\n\tprices: ProductPrice[]\n\tsubscriptionGroup?: string | null\n\tsubscriptionLevel?: number | null\n\tsubscriptionPeriodDays?: number | null\n\tsubscriptionTimezone?: string | null\n\tmetadata?: ProductMetadata | null\n\tdiscountEligibility?: ProductDiscountEligibility\n}\n\nexport interface ProductDiscountEligibility {\n\teligible: boolean\n\tcoupons: Array<{\n\t\tcode: string\n\t\tname: string\n\t\tcurrency: string\n\t\tstandardAmount: number\n\t\tdiscountAmount: number\n\t\tdiscountedAmount: number\n\t\tgrantedAt: string | null\n\t}>\n}\n\nexport interface CustomAmountRechargeRule extends ProductCustomAmountCurrency {\n\tproductId: string\n\tproductCode: string\n\tentitlementKey: string\n\tcurrency: string\n\tconfiguredMinAmount: number\n\tminimumGrantAmount: number\n}\n\nexport type CustomAmountRechargeValidationResult =\n\t| {\n\t\t\tvalid: true\n\t\t\trule: CustomAmountRechargeRule\n\t  }\n\t| {\n\t\t\tvalid: false\n\t\t\tcode:\n\t\t\t\t| \"CUSTOM_AMOUNT_UNAVAILABLE\"\n\t\t\t\t| \"CUSTOM_AMOUNT_INVALID_AMOUNT\"\n\t\t\t\t| \"CUSTOM_AMOUNT_OUT_OF_RANGE\"\n\t\t\t\t| \"CUSTOM_AMOUNT_INVALID_STEP\"\n\t\t\terror: string\n\t\t\trule?: CustomAmountRechargeRule\n\t  }\n\n/**\n * Resolve the custom amount recharge rule for a product and currency.\n *\n * Amounts are in the smallest currency unit. `unitsPerCurrencyUnit` defaults\n * to the smallest currency unit. When `unitsPerCurrencyUnitBasis` is `MAJOR`,\n * fractional entitlement amounts are rounded to the nearest whole unit. The\n * returned `minAmount` is the effective lower bound that both satisfies product\n * metadata and grants at least one entitlement unit. `configuredMinAmount`\n * keeps the raw product metadata value for display or diagnostics.\n */\nexport function getCustomAmountRechargeRule(\n\tproduct: Product | null | undefined,\n\tcurrency: string,\n): CustomAmountRechargeRule | null {\n\tif (!product || product.type !== \"CREDIT\") return null\n\tconst normalizedCurrency = currency.trim().toUpperCase()\n\tif (!/^[A-Z]{3}$/.test(normalizedCurrency)) return null\n\n\tconst customAmount = product.metadata?.customAmount\n\tif (customAmount?.enabled !== true) return null\n\n\tconst currencyConfig = customAmount.currencies?.[normalizedCurrency]\n\tif (!currencyConfig) return null\n\n\tconst minimumGrantAmount =\n\t\tcurrencyConfig.unitsPerCurrencyUnitBasis === \"MAJOR\"\n\t\t\t? Math.ceil(50 / currencyConfig.unitsPerCurrencyUnit)\n\t\t\t: Math.ceil(1 / currencyConfig.unitsPerCurrencyUnit)\n\tlet minAmount = Math.max(currencyConfig.minAmount, minimumGrantAmount)\n\tif (currencyConfig.stepAmount && minAmount > currencyConfig.minAmount) {\n\t\tconst stepCount = Math.ceil(\n\t\t\t(minAmount - currencyConfig.minAmount) / currencyConfig.stepAmount,\n\t\t)\n\t\tminAmount = currencyConfig.minAmount + stepCount * currencyConfig.stepAmount\n\t}\n\n\treturn {\n\t\t...currencyConfig,\n\t\tproductId: product.id,\n\t\tproductCode: product.code,\n\t\tentitlementKey: customAmount.entitlementKey,\n\t\tcurrency: normalizedCurrency,\n\t\tconfiguredMinAmount: currencyConfig.minAmount,\n\t\tminimumGrantAmount,\n\t\tminAmount,\n\t}\n}\n\n/**\n * Validate a custom recharge amount before calling `PaymentUI.openPayment`.\n * This is an SDK-side guardrail for integrator-owned amount inputs; the worker\n * still performs authoritative server-side validation when creating the order.\n */\nexport function validateCustomAmountRecharge(\n\tproduct: Product | null | undefined,\n\tcustomAmount: { amount: number; currency: string },\n): CustomAmountRechargeValidationResult {\n\tconst rule = getCustomAmountRechargeRule(product, customAmount.currency)\n\tif (!rule) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_UNAVAILABLE\",\n\t\t\terror:\n\t\t\t\t\"Product does not support custom amount recharge for this currency.\",\n\t\t}\n\t}\n\n\tconst amount = Number(customAmount.amount)\n\tif (!Number.isInteger(amount) || amount <= 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_INVALID_AMOUNT\",\n\t\t\terror:\n\t\t\t\t\"Custom amount must be a positive integer in the smallest currency unit.\",\n\t\t\trule,\n\t\t}\n\t}\n\n\tif (amount < rule.minAmount || amount > rule.maxAmount) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_OUT_OF_RANGE\",\n\t\t\terror: `Custom amount must be between ${rule.minAmount} and ${rule.maxAmount}.`,\n\t\t\trule,\n\t\t}\n\t}\n\n\tif (\n\t\trule.stepAmount &&\n\t\t(amount - rule.configuredMinAmount) % rule.stepAmount !== 0\n\t) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_INVALID_STEP\",\n\t\t\terror: `Custom amount must follow step ${rule.stepAmount}.`,\n\t\t\trule,\n\t\t}\n\t}\n\n\treturn { valid: true, rule }\n}\n\n/**\n * WeChat JSAPI Payment Parameters (for wx.requestPayment)\n */\nexport interface WechatJsapiPayParams {\n\tappId: string\n\ttimeStamp: string\n\tnonceStr: string\n\tpackage: string\n\tsignType: \"RSA\"\n\tpaySign: string\n}\n\n/**\n * Verified hosted login token payload.\n */\nexport interface VerifiedLoginToken {\n\tappId: string\n\tuserId: string\n\tlegacyCasdoorId?: string | null\n\tchannel: string\n\temail?: string | null\n\temailVerified?: boolean | null\n\tname?: string | null\n\tusername?: string | null\n\tavatar?: string | null\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164?: string | null\n\tphoneVerifiedAt?: string | null\n\twechatOpenId?: string | null\n\twechatUnionId?: string | null\n\texpiresAt: string\n}\n\nexport interface SendPhoneVerificationCodeParams {\n\tuserId: string\n\tphoneCountryCode?: string\n\tcountryCode?: string\n\tphoneNumber: string\n}\n\nexport interface SendPhoneVerificationCodeResponse {\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164: string\n\texpiresAt: string\n\tcooldownSeconds?: number\n\tresendAfterSeconds?: number\n}\n\nexport interface PhoneBinding {\n\tuserId: string\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164?: string | null\n\tphoneVerifiedAt?: string | null\n\tbound: boolean\n}\n\nexport interface GetPhoneBindingParams {\n\tuserId: string\n}\n\nexport interface BindPhoneNumberParams {\n\tuserId: string\n\tphoneCountryCode?: string\n\tcountryCode?: string\n\tphoneNumber: string\n\tcode: string\n}\n\nexport type UpdatePhoneNumberParams = BindPhoneNumberParams\n\nexport interface BindPhoneNumberResponse {\n\tuser: {\n\t\tuserId: string\n\t\tphoneCountryCode?: string | null\n\t\tphoneNumber?: string | null\n\t\tphoneE164?: string | null\n\t\tphoneVerifiedAt?: string | null\n\t}\n\tmerged: boolean\n\tmergeSummary?: Record<string, any>\n}\n\nexport type UpdatePhoneNumberResponse = BindPhoneNumberResponse\n\nexport interface CreateWechatMessageBindingParams {\n\t/** Hosted login external user ID returned by Youidian login. */\n\tuserId?: string\n\tloginExternalUserId?: string\n\t/** Integrator-owned user ID when hosted login is not used. */\n\tmerchantUserId?: string\n\t/** Optional linked template ID or code to infer the WeChat channel. */\n\ttemplateId?: string\n\ttemplateCode?: string\n\t/** Optional direct channel ID when no template is selected yet. */\n\tchannelId?: string\n\t/** Optional locale for the hosted binding page. */\n\tlocale?: string\n\t/** Optional URL to return to after binding succeeds. */\n\treturnUrl?: string\n}\n\nexport interface CreateWechatMessageBindingResponse {\n\tticketId: string\n\tstatus: \"PENDING\" | \"BOUND\" | \"EXPIRED\" | \"FAILED\"\n\tbindingUrl: string\n\tqrCodeUrl?: string | null\n\texpiresAt: string\n}\n\nexport type MessageTemplateDataValue =\n\t| string\n\t| number\n\t| boolean\n\t| {\n\t\t\tvalue: string | number | boolean\n\t\t\tcolor?: string\n\t  }\n\nexport interface SendMessageParams {\n\ttemplateId?: string\n\ttemplateCode?: string\n\tuserId?: string\n\tloginExternalUserId?: string\n\tmerchantUserId?: string\n\t/** Direct SMS recipient phone number. When provided for SMS templates, binding is not required before sending. */\n\tphoneNumber?: string\n\t/** Country/region code for phoneNumber. Defaults to +86 on the gateway. */\n\tphoneCountryCode?: string\n\t/** Alias for phoneCountryCode. */\n\tcountryCode?: string\n\t/** Direct E.164 SMS recipient. Alternative to phoneNumber. */\n\tphoneE164?: string\n\tdata: Record<string, MessageTemplateDataValue> | MessageTemplateDataValue[]\n\turl?: string\n\tredirectUrl?: string\n\tminiProgram?: {\n\t\tappid: string\n\t\tpagepath?: string\n\t}\n\tidempotencyKey?: string\n}\n\nexport interface SendMessageResponse {\n\tlogId: string\n\tstatus: \"PENDING\" | \"SENT\" | \"FAILED\" | \"SKIPPED\"\n\tproviderMessageId?: string | null\n\terrorCode?: string | null\n\terrorMessage?: string | null\n\tbindRequired?: boolean\n\tidempotent?: boolean\n\tphoneBinding?: {\n\t\tbound: boolean\n\t\tuserId?: string\n\t\tphoneE164?: string | null\n\t\tmerged?: boolean\n\t\talreadyBound?: boolean\n\t\terror?: string\n\t} | null\n}\n\n/**\n * SDK Client Options\n */\nexport interface PaymentClientOptions {\n\t/** Application ID (Required) */\n\tappId: string\n\t/** Application Secret (Required for server-side operations) */\n\tappSecret: string\n\n\t/**\n\t * @deprecated Use apiUrl and checkoutUrl instead\n\t * API Base URL (e.g. https://pay.youidian.com)\n\t * If apiUrl or checkoutUrl is not provided, this will be used as fallback\n\t * Default: https://pay.imgto.link\n\t */\n\tbaseUrl?: string\n\n\t/**\n\t * API server URL for backend requests (e.g. https://api.youidian.com)\n\t * Default: https://pay-api.imgto.link\n\t */\n\tapiUrl?: string\n\n\t/**\n\t * Checkout page URL for client-side payment (e.g. https://pay.youidian.com)\n\t * Default: https://pay.imgto.link\n\t */\n\tcheckoutUrl?: string\n}\n\nexport interface MerchantPricingBreakdownItem {\n\ttype: \"coupon\" | \"promotion\" | \"membership\" | \"manual\" | \"other\"\n\tamount: number\n\tlabel?: string\n\tcode?: string\n}\n\nexport interface MerchantPricing {\n\tamount: number\n\tcurrency: string\n\toriginalAmount?: number\n\tdiscountAmount?: number\n\tdiscountReason?: string\n\tdiscountCode?: string\n\tbreakdown?: MerchantPricingBreakdownItem[]\n}\n\nexport interface MerchantPricingSnapshot extends MerchantPricing {\n\toriginalAmount: number\n\tdiscountAmount: number\n\tpriceId: string\n\tproductId: string\n\tproductCode: string\n}\n\n/**\n * Create Order Parameters\n */\nexport interface CreateOrderParams {\n\tproductId?: string\n\tpriceId?: string\n\tchannel?: string\n\tuserId: string\n\treturnUrl?: string\n\t/** Public server endpoint used for both payment and refund webhooks. */\n\tcallbackUrl?: string\n\tmetadata?: Record<string, any>\n\tmerchantOrderId?: string\n\topenid?: string\n\tlocale?: string\n\tsubscriptionIntent?: SubscriptionIntent\n\tcustomAmount?: {\n\t\tamount: number\n\t\tcurrency: string\n\t}\n\tmerchantPricing?: MerchantPricing\n}\n\nexport type CreateBankTransferOrderParams = Omit<CreateOrderParams, \"channel\">\n\n/**\n * Create WeChat Mini Program Order Parameters\n */\nexport type CreateMiniProgramOrderParams = {\n\tuserId: string\n\topenid: string\n\tmerchantOrderId?: string\n\tpriceId: string\n\tsubscriptionIntent?: SubscriptionIntent\n}\n\n/**\n * Create Order Response\n */\nexport interface CreateOrderResponse {\n\torderId: string\n\tinternalId: string\n\tamount: number\n\tcurrency: string\n\tpayParams: any\n\tpricingBreakdown?: PricingBreakdown\n\tstatus?: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\" | \"EXPIRED\"\n\tpaidAt?: string | null\n\tchannel?: string\n\tisSandbox?: boolean\n\tmerchantPricing?: MerchantPricingSnapshot\n\tbilling?: BillingSnapshot\n\tsubscription?: SubscriptionDetails | null\n}\n\nexport interface CancelOrderResponse {\n\tcancelled: boolean\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\" | \"EXPIRED\"\n\torderId: string\n\tinternalId?: string | null\n}\n\nexport interface RefundOrderParams {\n\t/** Refund amount in the currency's smallest unit. Omit for the full remainder. */\n\tamount?: number\n\t/** A unique key for this refund attempt. */\n\tidempotencyKey: string\n\t/** Send an ORDER_REFUNDED webhook after the refund is recorded. */\n\tnotifyIntegrator?: boolean\n\t/** Revoke entitlements granted by this order after a full refund. */\n\trevokeEntitlements?: boolean\n}\n\nexport interface RefundOrderResponse {\n\torderId: string\n\tinternalId: string\n\tstatus: \"PAID\" | \"REFUNDED\" | \"PROCESSING\"\n\trefundAmount: number\n\trefundId: string\n\tnotifyIntegrator: boolean\n\trevokeEntitlements: boolean\n\tidempotentReplay: boolean\n}\n\nexport interface CompleteFreeOrderResponse {\n\tcompleted: boolean\n\tstatus: \"paid\" | \"pending\" | \"cancelled\" | \"refunded\" | \"failed\" | \"unknown\"\n\torderId: string\n\tinternalId?: string | null\n}\n\n/**\n * Payment Callback Notification\n */\nexport interface PaymentNotification {\n\tiv: string\n\tencryptedData: string\n\tauthTag: string\n}\n\n/**\n * Decrypted Payment Callback Data\n */\nexport interface PaymentCallbackData {\n\torderId: string\n\tmerchantOrderId?: string\n\tstatus: \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tamount: number\n\tcurrency: string\n\tpaidAt: string\n\tchannelTransactionId?: string\n\tmetadata?: Record<string, any>\n}\n\n/**\n * Platform webhook payload.\n *\n * The platform delivers this object as plaintext JSON in the webhook request\n * body, signed with `X-UniPay-Signature` / `X-UniPay-Timestamp` headers.\n * Validate with {@link PaymentClient.verifyWebhookSignature} using the raw\n * body string before parsing.\n */\nexport interface WebhookPayload {\n\tevent: \"ORDER_PAID\" | \"ORDER_CANCELLED\" | \"ORDER_REFUNDED\" | \"ORDER_FAILED\"\n\torderId: string\n\tmerchantOrderId: string\n\tmerchantUserId: string\n\tproductCode: string\n\tbilling: BillingSnapshot\n\tsubscription: SubscriptionDetails | null\n\tamount: number\n\tcurrency: string\n\tpaidAt: string | null\n\tchannelTransactionId?: string\n\tcancelSubscription?: boolean\n\trevokeEntitlements?: boolean\n}\n\n/**\n * Get Orders Parameters\n */\nexport interface GetOrdersParams {\n\tpage?: number\n\tpageSize?: number\n\tuserId?: string\n\tstatus?: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\" | \"EXPIRED\"\n\tstartDate?: string\n\tendDate?: string\n}\n\n/**\n * Order List Item\n */\nexport interface OrderListItem {\n\torderId: string\n\tinternalId: string\n\tmerchantUserId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\" | \"EXPIRED\"\n\tamount: number\n\tcurrency: string\n\tchannel?: string\n\tpaidAt?: string\n\tcreatedAt: string\n}\n\n/**\n * Get Orders Response\n */\nexport interface GetOrdersResponse {\n\torders: OrderListItem[]\n\tpagination: {\n\t\ttotal: number\n\t\tpage: number\n\t\tpageSize: number\n\t\ttotalPages: number\n\t}\n}\n\n/**\n * Entitlement Detail Item\n */\nexport interface EntitlementDetailItem {\n\ttype: string\n\tcurrent: number | boolean\n\tlimit?: number\n\texpiresAt?: string | null\n\tresetInterval?: string | null\n\tnextResetAt?: string | null\n\tsourceKind?: string | null\n}\n\n/**\n * Entitlement Detail - returned by getEntitlementsDetail\n */\nexport type EntitlementDetail = Record<string, EntitlementDetailItem>\n\n/**\n * Ensure User With Trial Response\n */\nexport interface EnsureUserWithTrialResponse {\n\tisNew: boolean\n\ttrialAssigned: boolean\n\ttrialProductCode?: string\n\tentitlements: EntitlementDetail\n}\n\n/**\n * Server-side Payment Client\n * 服务端支付客户端，用于创建订单、查询状态、解密回调\n */\nexport class PaymentClient {\n\tprivate readonly appId: string\n\tprivate readonly appSecret: string\n\tprivate readonly apiUrl: string // 用于 API 调用\n\tprivate readonly checkoutUrl: string // 用于生成 checkout URL\n\n\tconstructor(options: PaymentClientOptions) {\n\t\tif (!options.appId) throw new Error(\"appId is required\")\n\t\tif (!options.appSecret) throw new Error(\"appSecret is required\")\n\n\t\tthis.appId = options.appId\n\t\tthis.appSecret = options.appSecret\n\n\t\t// apiUrl: 优先使用 apiUrl，其次 baseUrl，默认 https://pay-api.imgto.link\n\t\tconst apiUrl =\n\t\t\toptions.apiUrl || options.baseUrl || \"https://pay-api.imgto.link\"\n\t\tthis.apiUrl = apiUrl.replace(/\\/$/, \"\") // Remove trailing slash\n\n\t\t// checkoutUrl: 优先使用 checkoutUrl，其次 baseUrl，默认 https://pay.imgto.link\n\t\tconst checkoutUrl =\n\t\t\toptions.checkoutUrl || options.baseUrl || \"https://pay.imgto.link\"\n\t\tthis.checkoutUrl = checkoutUrl.replace(/\\/$/, \"\") // Remove trailing slash\n\t}\n\n\t/**\n\t * Generate SHA256 signature for the request\n\t * Logic: SHA256(appId + appSecret + timestamp)\n\t */\n\tprivate generateSignature(timestamp: number): string {\n\t\tconst str = `${this.appId}${this.appSecret}${timestamp}`\n\t\treturn crypto.createHash(\"sha256\").update(str).digest(\"hex\")\n\t}\n\n\t/**\n\t * Internal request helper for Gateway API\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\tbody?: any,\n\t): Promise<T> {\n\t\tconst timestamp = Date.now()\n\t\tconst signature = this.generateSignature(timestamp)\n\t\tconst serializedBody = body ? JSON.stringify(body) : \"\"\n\t\tconst contentSignature = crypto\n\t\t\t.createHmac(\"sha256\", this.appSecret)\n\t\t\t.update(`${timestamp}.${method.toUpperCase()}.${path}.${serializedBody}`)\n\t\t\t.digest(\"hex\")\n\n\t\tconst url = `${this.apiUrl}/api/v1/gateway/${this.appId}${path}`\n\n\t\tconst headers: HeadersInit = {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"X-Pay-Timestamp\": timestamp.toString(),\n\t\t\t\"X-Pay-Sign\": signature,\n\t\t\t\"X-Pay-Sign-V2\": contentSignature,\n\t\t}\n\n\t\tconst options: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody: body ? serializedBody : undefined,\n\t\t}\n\n\t\tconst response = await fetch(url, options)\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text()\n\t\t\tlet parsedError: any = null\n\t\t\ttry {\n\t\t\t\tparsedError = JSON.parse(errorText)\n\t\t\t} catch {}\n\t\t\tconst message =\n\t\t\t\tparsedError?.message ||\n\t\t\t\tparsedError?.error ||\n\t\t\t\terrorText ||\n\t\t\t\t\"Request failed\"\n\t\t\tthrow new PaymentApiError(\n\t\t\t\tmessage,\n\t\t\t\tresponse.status,\n\t\t\t\tparsedError?.code || undefined,\n\t\t\t)\n\t\t}\n\n\t\tconst json = await response.json()\n\t\tif (json.error) {\n\t\t\tthrow new PaymentApiError(\n\t\t\t\t`Payment API Error: ${json.error}`,\n\t\t\t\tresponse.status,\n\t\t\t\tjson.code,\n\t\t\t)\n\t\t}\n\n\t\treturn json.data as T\n\t}\n\n\t/**\n\t * Decrypts the callback notification payload using AES-256-GCM.\n\t *\n\t * @deprecated This legacy encrypted-envelope protocol is NOT what the platform\n\t * actually delivers. The platform sends an HMAC-signed plaintext JSON webhook\n\t * with `X-UniPay-Signature` / `X-UniPay-Timestamp` headers; use\n\t * {@link PaymentClient.verifyWebhookSignature} to validate those instead.\n\t *\n\t * @param notification - The encrypted notification from payment webhook\n\t * @returns Decrypted payment callback data\n\t */\n\tdecryptCallback(notification: PaymentNotification): PaymentCallbackData {\n\t\ttry {\n\t\t\tconst { iv, encryptedData, authTag } = notification\n\t\t\tconst key = crypto.createHash(\"sha256\").update(this.appSecret).digest()\n\t\t\tconst decipher = crypto.createDecipheriv(\n\t\t\t\t\"aes-256-gcm\",\n\t\t\t\tkey,\n\t\t\t\tBuffer.from(iv, \"hex\"),\n\t\t\t)\n\n\t\t\tdecipher.setAuthTag(Buffer.from(authTag, \"hex\"))\n\n\t\t\tlet decrypted = decipher.update(encryptedData, \"hex\", \"utf8\")\n\t\t\tdecrypted += decipher.final(\"utf8\")\n\n\t\t\treturn JSON.parse(decrypted)\n\t\t} catch {\n\t\t\tthrow new Error(\n\t\t\t\t\"Failed to decrypt payment callback: Invalid secret or tampered data.\",\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Verify an inbound platform webhook signature.\n\t *\n\t * The platform delivers webhooks as plaintext JSON with two headers:\n\t * `X-UniPay-Signature` (HMAC-SHA256 of `${timestamp}.${rawBodyString}`) and\n\t * `X-UniPay-Timestamp`. The body itself is NOT encrypted; verify the signature\n\t * then `JSON.parse` the body to obtain a {@link WebhookPayload}.\n\t *\n\t * @param rawBody - The raw request body string (exactly as received)\n\t * @param signature - The `X-UniPay-Signature` header value (hex)\n\t * @param timestamp - The `X-UniPay-Timestamp` header value (ms epoch string)\n\t * @param options - Optional `toleranceMs` for timestamp freshness (default 5 min)\n\t * @returns `true` if the signature is valid and the timestamp is fresh\n\t */\n\tverifyWebhookSignature(\n\t\trawBody: string,\n\t\tsignature: string,\n\t\ttimestamp: string,\n\t\toptions?: { toleranceMs?: number },\n\t): boolean {\n\t\ttry {\n\t\t\tconst toleranceMs = options?.toleranceMs ?? 5 * 60 * 1000\n\t\t\tconst timestampMs = Number.parseInt(timestamp, 10)\n\t\t\tif (\n\t\t\t\tNumber.isNaN(timestampMs) ||\n\t\t\t\tMath.abs(Date.now() - timestampMs) > toleranceMs\n\t\t\t) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tconst rawString = `${timestamp}.${rawBody}`\n\t\t\tconst expected = crypto\n\t\t\t\t.createHmac(\"sha256\", this.appSecret)\n\t\t\t\t.update(rawString)\n\t\t\t\t.digest(\"hex\")\n\n\t\t\tconst signatureBuffer = Buffer.from(signature)\n\t\t\tconst expectedBuffer = Buffer.from(expected)\n\t\t\tif (signatureBuffer.length !== expectedBuffer.length) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn crypto.timingSafeEqual(signatureBuffer, expectedBuffer)\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Fetch products for the configured app.\n\t */\n\tasync getProducts(options?: {\n\t\tlocale?: string\n\t\tcurrency?: string\n\t\tuserId?: string\n\t}): Promise<Product[]> {\n\t\tconst params = new URLSearchParams()\n\t\tif (options?.locale) params.append(\"locale\", options.locale)\n\t\tif (options?.currency) params.append(\"currency\", options.currency)\n\t\tif (options?.userId !== undefined) {\n\t\t\tconst userId = options.userId.trim()\n\t\t\tif (!userId) throw new Error(\"userId must be a non-empty string\")\n\t\t\tparams.append(\"userId\", userId)\n\t\t}\n\n\t\tconst path = params.toString()\n\t\t\t? `/products?${params.toString()}`\n\t\t\t: \"/products\"\n\t\treturn this.request(\"GET\", path)\n\t}\n\n\t/** Fetch all currently active discount policies for the configured app. */\n\tasync getDiscountPolicies(): Promise<DiscountPolicy[]> {\n\t\treturn this.request(\"GET\", \"/discount-policies\")\n\t}\n\n\t/** Fetch currently active discount policies for one product. */\n\tasync getProductDiscountPolicies(\n\t\tproductIdOrCode: string,\n\t): Promise<DiscountPolicy[]> {\n\t\tconst value = productIdOrCode?.trim()\n\t\tif (!value) throw new Error(\"productIdOrCode is required\")\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/products/${encodeURIComponent(value)}/discount-policies`,\n\t\t)\n\t}\n\n\t/** Query one user's discount eligibility for one product. */\n\tasync getUserProductDiscountEligibility(\n\t\tuserId: string,\n\t\tproductIdOrCode: string,\n\t): Promise<UserProductDiscountEligibility> {\n\t\tconst userValue = userId?.trim()\n\t\tconst productValue = productIdOrCode?.trim()\n\t\tif (!userValue) throw new Error(\"userId is required\")\n\t\tif (!productValue) throw new Error(\"productIdOrCode is required\")\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/users/${encodeURIComponent(userValue)}/products/${encodeURIComponent(productValue)}/discount-eligibility`,\n\t\t)\n\t}\n\n\t/**\n\t * Fetch the realtime stock snapshot for a single product.\n\t */\n\tasync getProductStock(\n\t\tproductIdOrCode: string,\n\t\toptions?: ProductStockQueryOptions,\n\t): Promise<ProductStock> {\n\t\tconst value = productIdOrCode?.trim()\n\t\tif (!value) {\n\t\t\tthrow new Error(\"productIdOrCode is required\")\n\t\t}\n\n\t\tconst params = new URLSearchParams()\n\t\tparams.set(\"productIdOrCode\", value)\n\t\tif (options?.lookupBy) params.set(\"lookupBy\", options.lookupBy)\n\t\tif (options?.locale) params.set(\"locale\", options.locale)\n\t\tif (options?.currency) params.set(\"currency\", options.currency)\n\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/products/${encodeURIComponent(value)}/stock?${params.toString()}`,\n\t\t)\n\t}\n\n\t/**\n\t * Fetch realtime stock snapshots for multiple products.\n\t */\n\tasync getProductStocks(\n\t\tparams: ProductStocksQueryParams,\n\t\toptions?: ProductStockQueryOptions,\n\t): Promise<ProductStock[]>\n\tasync getProductStocks(\n\t\tparams: ProductStocksQueryParams & ProductStockQueryOptions,\n\t): Promise<ProductStock[]>\n\tasync getProductStocks(\n\t\tparams: ProductStocksQueryParams & ProductStockQueryOptions,\n\t\toptions?: ProductStockQueryOptions,\n\t): Promise<ProductStock[]> {\n\t\tconst productIds = [\n\t\t\t...new Set(\n\t\t\t\t(params.productIds || []).map((item) => item.trim()).filter(Boolean),\n\t\t\t),\n\t\t]\n\t\tconst productCodes = [\n\t\t\t...new Set(\n\t\t\t\t(params.productCodes || []).map((item) => item.trim()).filter(Boolean),\n\t\t\t),\n\t\t]\n\t\tif (productIds.length === 0 && productCodes.length === 0) {\n\t\t\tthrow new Error(\"productIds or productCodes is required\")\n\t\t}\n\n\t\tconst queryOptions = options || params\n\t\tconst query = new URLSearchParams()\n\t\tif (productIds.length > 0) query.set(\"productIds\", productIds.join(\",\"))\n\t\tif (productCodes.length > 0)\n\t\t\tquery.set(\"productCodes\", productCodes.join(\",\"))\n\t\tif (queryOptions.lookupBy) query.set(\"lookupBy\", queryOptions.lookupBy)\n\t\tif (queryOptions.locale) query.set(\"locale\", queryOptions.locale)\n\t\tif (queryOptions.currency) query.set(\"currency\", queryOptions.currency)\n\n\t\treturn this.request(\"GET\", `/products/stocks?${query.toString()}`)\n\t}\n\n\t/**\n\t * Create a new order\n\t * @param params - Order creation parameters\n\t * @returns Order details with payment parameters\n\t */\n\tasync createOrder(params: CreateOrderParams): Promise<CreateOrderResponse> {\n\t\treturn this.request(\"POST\", \"/orders\", params)\n\t}\n\n\t/**\n\t * Create a paid manual bank transfer order.\n\t * @param params - Order creation parameters without channel\n\t * @returns Paid order details\n\t */\n\tasync createBankTransferOrder(\n\t\tparams: CreateBankTransferOrderParams,\n\t): Promise<CreateOrderResponse> {\n\t\treturn this.request(\"POST\", \"/orders\", {\n\t\t\t...params,\n\t\t\tchannel: \"BANK_TRANSFER\",\n\t\t} satisfies CreateOrderParams)\n\t}\n\n\t/**\n\t * Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)\n\t * @param params - Mini program order parameters\n\t * @returns Order details with payment parameters\n\t */\n\tasync createMiniProgramOrder(\n\t\tparams: CreateMiniProgramOrderParams,\n\t): Promise<CreateOrderResponse> {\n\t\tconst { openid, ...rest } = params\n\t\treturn this.request(\"POST\", \"/orders\", {\n\t\t\t...rest,\n\t\t\tchannel: \"WECHAT_MINI\",\n\t\t\topenid,\n\t\t\tmetadata: { openid },\n\t\t} satisfies CreateOrderParams)\n\t}\n\n\t/**\n\t * Pay for an existing order\n\t * @param orderId - The order ID to pay\n\t * @param params - Payment parameters including channel\n\t */\n\tasync payOrder(\n\t\torderId: string,\n\t\tparams: {\n\t\t\tchannel: string\n\t\t\treturnUrl?: string\n\t\t\topenid?: string\n\t\t\t[key: string]: any\n\t\t},\n\t): Promise<CreateOrderResponse> {\n\t\treturn this.request(\"POST\", `/orders/${orderId}/pay`, params)\n\t}\n\n\t/**\n\t * Cancel a pending order and release its inventory reservation.\n\t * Paid/refunded/failed orders are returned unchanged by the gateway.\n\t */\n\tasync cancelOrder(\n\t\torderId: string,\n\t\tparams?: { reason?: string },\n\t): Promise<CancelOrderResponse> {\n\t\tconst value = orderId?.trim()\n\t\tif (!value) {\n\t\t\tthrow new Error(\"orderId is required\")\n\t\t}\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/orders/${encodeURIComponent(value)}/cancel`,\n\t\t\tparams || {},\n\t\t)\n\t}\n\n\t/**\n\t * Refund a paid order owned by this app.\n\t *\n\t * Orders carrying subscriptions or entitlements require a full refund and\n\t * entitlement revocation. Reuse the same idempotency key when retrying.\n\t */\n\tasync refundOrder(\n\t\torderId: string,\n\t\tparams: RefundOrderParams,\n\t): Promise<RefundOrderResponse> {\n\t\tconst value = orderId?.trim()\n\t\tif (!value) throw new Error(\"orderId is required\")\n\t\tif (!/^[A-Za-z0-9._:-]{8,120}$/.test(params.idempotencyKey?.trim())) {\n\t\t\tthrow new Error(\"A valid idempotencyKey is required\")\n\t\t}\n\t\tif (\n\t\t\tparams.amount !== undefined &&\n\t\t\t(!Number.isInteger(params.amount) || params.amount <= 0)\n\t\t) {\n\t\t\tthrow new Error(\"amount must be a positive integer\")\n\t\t}\n\n\t\treturn this.request(\"POST\", `/orders/${encodeURIComponent(value)}/refund`, {\n\t\t\t...params,\n\t\t\tidempotencyKey: params.idempotencyKey.trim(),\n\t\t})\n\t}\n\n\t/**\n\t * Complete a zero-amount FREE order.\n\t * This marks the pending order as paid and triggers normal paid-order side effects.\n\t */\n\tasync completeFreeOrder(orderId: string): Promise<CompleteFreeOrderResponse> {\n\t\tconst value = orderId?.trim()\n\t\tif (!value) {\n\t\t\tthrow new Error(\"orderId is required\")\n\t\t}\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/orders/${encodeURIComponent(value)}/free/complete`,\n\t\t\t{},\n\t\t)\n\t}\n\n\t/**\n\t * Query order status\n\t * @param orderId - The order ID to query\n\t */\n\tasync getOrderStatus(orderId: string): Promise<OrderStatus> {\n\t\treturn this.request(\"GET\", `/orders/${orderId}`)\n\t}\n\n\t/**\n\t * Get order details (full order information)\n\t * @param orderId - The order ID to query\n\t */\n\tasync getOrderDetails(orderId: string): Promise<OrderDetails> {\n\t\treturn this.request(\"GET\", `/orders/${orderId}/details`)\n\t}\n\n\t/**\n\t * Get orders list with pagination\n\t * @param params - Query parameters (pagination, filters)\n\t * @returns Orders list and pagination info\n\t */\n\tasync getOrders(params?: GetOrdersParams): Promise<GetOrdersResponse> {\n\t\tconst queryParams = new URLSearchParams()\n\t\tif (params?.page) queryParams.append(\"page\", params.page.toString())\n\t\tif (params?.pageSize)\n\t\t\tqueryParams.append(\"pageSize\", params.pageSize.toString())\n\t\tif (params?.userId) queryParams.append(\"userId\", params.userId)\n\t\tif (params?.status) queryParams.append(\"status\", params.status)\n\t\tif (params?.startDate) queryParams.append(\"startDate\", params.startDate)\n\t\tif (params?.endDate) queryParams.append(\"endDate\", params.endDate)\n\n\t\tconst path = queryParams.toString()\n\t\t\t? `/orders?${queryParams.toString()}`\n\t\t\t: \"/orders\"\n\t\treturn this.request<GetOrdersResponse>(\"GET\", path)\n\t}\n\n\t/**\n\t * Get user entitlements in the legacy flat shape.\n\t * @param userId - User ID\n\t */\n\tasync getEntitlements(userId: string): Promise<Record<string, any>> {\n\t\treturn this.request(\"GET\", `/users/${userId}/entitlements`)\n\t}\n\n\t/**\n\t * Get user entitlements with full details (type, expiry, reset config, source)\n\t * @param userId - User ID\n\t */\n\tasync getEntitlementsDetail(userId: string): Promise<EntitlementDetail> {\n\t\treturn this.request(\"GET\", `/users/${userId}/entitlements/detail`)\n\t}\n\n\tasync getActiveSubscription(\n\t\tuserId: string,\n\t): Promise<ActiveSubscriptionInfo | null> {\n\t\treturn this.request(\"GET\", `/users/${userId}/active-subscription`)\n\t}\n\n\tasync getSubscriptionUpgradeOptions(\n\t\tuserId: string,\n\t\toptions?: {\n\t\t\tlocale?: string\n\t\t\tcurrency?: string\n\t\t\tsubscriptionIntent?: Extract<\n\t\t\t\tSubscriptionIntent,\n\t\t\t\t\"UPGRADE\" | \"QUEUED_UPGRADE\"\n\t\t\t>\n\t\t},\n\t): Promise<Product[]> {\n\t\tconst value = userId?.trim()\n\t\tif (!value) throw new Error(\"userId is required\")\n\t\tconst params = new URLSearchParams()\n\t\tif (options?.locale) params.set(\"locale\", options.locale)\n\t\tif (options?.currency) params.set(\"currency\", options.currency)\n\t\tif (options?.subscriptionIntent) {\n\t\t\tparams.set(\"subscriptionIntent\", options.subscriptionIntent)\n\t\t}\n\t\tconst query = params.toString() ? `?${params.toString()}` : \"\"\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/users/${encodeURIComponent(value)}/subscription-upgrade-options${query}`,\n\t\t)\n\t}\n\n\t/**\n\t * Ensure user exists and auto-assign trial product if new user\n\t * This should be called when user first logs in or registers\n\t * @param userId - User ID\n\t */\n\tasync ensureUserWithTrial(\n\t\tuserId: string,\n\t): Promise<EnsureUserWithTrialResponse> {\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/bootstrap`, {})\n\t}\n\n\t/**\n\t * Get a single entitlement value\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t */\n\tasync getEntitlementValue(userId: string, key: string): Promise<any> {\n\t\tconst entitlements = await this.getEntitlements(userId)\n\t\treturn entitlements[key] ?? null\n\t}\n\n\t/**\n\t * Consume numeric entitlement\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t * @param amount - Amount to consume\n\t */\n\tasync consumeEntitlement(\n\t\tuserId: string,\n\t\tkey: string,\n\t\tamount: number,\n\t\toptions?: {\n\t\t\tidempotencyKey?: string\n\t\t\tmetadata?: Record<string, any>\n\t\t},\n\t): Promise<{ balance: number }> {\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/consume`, {\n\t\t\tkey,\n\t\t\tamount,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Consume numeric entitlements from an ordered key pool.\n\t * Useful when subscription credits and perpetual credits use separate keys.\n\t */\n\tasync consumeEntitlementPool(\n\t\tuserId: string,\n\t\tkeys: string[],\n\t\tamount: number,\n\t\toptions?: {\n\t\t\tidempotencyKey?: string\n\t\t\tmetadata?: Record<string, any>\n\t\t},\n\t): Promise<ConsumeEntitlementPoolResult> {\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/consume-pool`, {\n\t\t\tkeys,\n\t\t\tamount,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Get active numeric entitlement buckets ordered by expiration.\n\t */\n\tasync getEntitlementCreditBuckets(\n\t\tuserId: string,\n\t\tkeys?: string[],\n\t): Promise<EntitlementCreditBucket[]> {\n\t\tconst query =\n\t\t\tkeys && keys.length > 0\n\t\t\t\t? `?keys=${encodeURIComponent(keys.join(\",\"))}`\n\t\t\t\t: \"\"\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/users/${userId}/entitlements/credit-buckets${query}`,\n\t\t)\n\t}\n\n\t/**\n\t * Add numeric entitlement (e.g. refund)\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t * @param amount - Amount to add\n\t */\n\tasync addEntitlement(\n\t\tuserId: string,\n\t\tkey: string,\n\t\tamount: number,\n\t): Promise<{ balance: number }> {\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/add`, {\n\t\t\tkey,\n\t\t\tamount,\n\t\t})\n\t}\n\n\t/**\n\t * Toggle boolean entitlement\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t * @param enabled - Whether to enable\n\t */\n\tasync toggleEntitlement(\n\t\tuserId: string,\n\t\tkey: string,\n\t\tenabled: boolean,\n\t): Promise<{ isEnabled: boolean }> {\n\t\t// Toggle endpoint expects POST with enabled flag\n\t\t// However, looking at list_dir, we have toggle/route.ts\n\t\t// I should verify its contract, but assuming standard toggle pattern:\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/toggle`, {\n\t\t\tkey,\n\t\t\tenabled,\n\t\t})\n\t}\n\n\t/**\n\t * Generate checkout URL for client-side payment\n\t * @param productId - Product ID\n\t * @param priceId - Price ID\n\t * @returns Checkout page URL\n\t */\n\tgetCheckoutUrl(productId: string, priceId: string): string {\n\t\treturn `${this.checkoutUrl}/checkout/${this.appId}/${productId}/${priceId}`\n\t}\n\n\t/**\n\t * Verify a hosted login token and return the normalized login profile.\n\t * This request is signed with your app credentials and routed through the worker API.\n\t */\n\tasync verifyLoginToken(token: string): Promise<VerifiedLoginToken> {\n\t\tif (!token?.trim()) {\n\t\t\tthrow new Error(\"login token is required\")\n\t\t}\n\t\treturn this.request(\"POST\", \"/login/tokens/verify\", { token: token.trim() })\n\t}\n\n\t/**\n\t * Send a phone verification code for binding a phone number to a hosted login user.\n\t */\n\tasync sendPhoneVerificationCode(\n\t\tparams: SendPhoneVerificationCodeParams,\n\t): Promise<SendPhoneVerificationCodeResponse> {\n\t\tconst userId = params.userId?.trim()\n\t\tconst phoneNumber = params.phoneNumber?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\t\tif (!phoneNumber) throw new Error(\"phoneNumber is required\")\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone/code`,\n\t\t\t{\n\t\t\t\tphoneCountryCode: params.phoneCountryCode || params.countryCode,\n\t\t\t\tphoneNumber,\n\t\t\t},\n\t\t)\n\t}\n\n\t/**\n\t * Query the verified phone binding for a hosted login user.\n\t */\n\tasync getPhoneBinding(params: GetPhoneBindingParams): Promise<PhoneBinding> {\n\t\tconst userId = params.userId?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone`,\n\t\t)\n\t}\n\n\t/**\n\t * Bind a verified phone number to a hosted login user, merging existing accounts when needed.\n\t */\n\tasync bindPhoneNumber(\n\t\tparams: BindPhoneNumberParams,\n\t): Promise<BindPhoneNumberResponse> {\n\t\tconst userId = params.userId?.trim()\n\t\tconst phoneNumber = params.phoneNumber?.trim()\n\t\tconst code = params.code?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\t\tif (!phoneNumber) throw new Error(\"phoneNumber is required\")\n\t\tif (!code) throw new Error(\"code is required\")\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone/bind`,\n\t\t\t{\n\t\t\t\tcode,\n\t\t\t\tphoneCountryCode: params.phoneCountryCode || params.countryCode,\n\t\t\t\tphoneNumber,\n\t\t\t},\n\t\t)\n\t}\n\n\t/**\n\t * Update a hosted login user's phone number after verifying the new number by SMS code.\n\t */\n\tasync updatePhoneNumber(\n\t\tparams: UpdatePhoneNumberParams,\n\t): Promise<UpdatePhoneNumberResponse> {\n\t\tconst userId = params.userId?.trim()\n\t\tconst phoneNumber = params.phoneNumber?.trim()\n\t\tconst code = params.code?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\t\tif (!phoneNumber) throw new Error(\"phoneNumber is required\")\n\t\tif (!code) throw new Error(\"code is required\")\n\n\t\treturn this.request(\n\t\t\t\"PUT\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone`,\n\t\t\t{\n\t\t\t\tcode,\n\t\t\t\tphoneCountryCode: params.phoneCountryCode || params.countryCode,\n\t\t\t\tphoneNumber,\n\t\t\t},\n\t\t)\n\t}\n\n\t/**\n\t * Create a hosted WeChat official account binding URL for a user.\n\t */\n\tasync createWechatMessageBinding(\n\t\tparams: CreateWechatMessageBindingParams,\n\t): Promise<CreateWechatMessageBindingResponse> {\n\t\tconst loginExternalUserId =\n\t\t\tparams.loginExternalUserId?.trim() || params.userId?.trim()\n\t\tconst merchantUserId = params.merchantUserId?.trim()\n\t\tif (!loginExternalUserId && !merchantUserId) {\n\t\t\tthrow new Error(\"userId or merchantUserId is required\")\n\t\t}\n\n\t\treturn this.request(\"POST\", \"/messages/wechat/bindings\", {\n\t\t\t...params,\n\t\t\tloginExternalUserId,\n\t\t\tmerchantUserId,\n\t\t})\n\t}\n\n\t/**\n\t * Send an app-linked message template to a bound recipient.\n\t */\n\tasync sendMessage(params: SendMessageParams): Promise<SendMessageResponse> {\n\t\tif (!params.templateId?.trim() && !params.templateCode?.trim()) {\n\t\t\tthrow new Error(\"templateId or templateCode is required\")\n\t\t}\n\t\tif (!params.data || typeof params.data !== \"object\") {\n\t\t\tthrow new Error(\"data is required\")\n\t\t}\n\n\t\treturn this.request(\"POST\", \"/messages/send\", params)\n\t}\n}\n"],"mappings":"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","names":["panel","crypto"]}