@youidian/sdk 3.4.6 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +17 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +17 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +26 -2
- package/dist/server.d.ts +26 -2
- package/dist/server.js +17 -0
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/brand-logo.ts","../src/hosted-modal.ts","../src/environment.ts","../src/login.ts","../src/client.ts","../src/feedback.ts","../src/server.ts"],"sourcesContent":["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\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","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] as const\n\nconst SDK_DEFAULT_LOCALE = \"zh-CN\"\n\nconst SDK_LOCALE_ALIASES: Record<string, string> = {\n\ten: \"en\",\n\t\"en-us\": \"en\",\n\t\"en-gb\": \"en\",\n\tzh: \"zh-CN\",\n\t\"zh-cn\": \"zh-CN\",\n\t\"zh-tw\": \"zh-Hant\",\n\t\"zh-hk\": \"zh-Hant\",\n\t\"zh-hant\": \"zh-Hant\",\n\t\"zh-hans\": \"zh-CN\",\n\tfr: \"fr\",\n\tde: \"de\",\n\tja: \"ja\",\n\tes: \"es\",\n\tko: \"ko\",\n\tnl: \"nl\",\n\tit: \"it\",\n\tpt: \"pt\",\n}\n\nfunction matchSupportedBaseLocale(locale: string): string | undefined {\n\tconst base = locale.toLowerCase().split(\"-\")[0]\n\treturn SDK_SUPPORTED_LOCALES.find((item) => item.toLowerCase() === base)\n}\n\nexport function normalizeSdkLocale(locale?: string): string | undefined {\n\tif (!locale) return\n\n\tconst sanitized = locale.trim().replace(/_/g, \"-\")\n\tif (!sanitized) return\n\n\tconst lower = sanitized.toLowerCase()\n\tif (SDK_LOCALE_ALIASES[lower]) {\n\t\treturn SDK_LOCALE_ALIASES[lower]\n\t}\n\n\tlet canonical: string | undefined\n\ttry {\n\t\tcanonical = Intl.getCanonicalLocales(sanitized)[0]\n\t} catch {\n\t\tcanonical = undefined\n\t}\n\n\tconst candidates = [canonical, sanitized].filter(Boolean) as string[]\n\n\tfor (const candidate of candidates) {\n\t\tconst candidateLower = candidate.toLowerCase()\n\n\t\tif (SDK_LOCALE_ALIASES[candidateLower]) {\n\t\t\treturn SDK_LOCALE_ALIASES[candidateLower]\n\t\t}\n\t\tif ((SDK_SUPPORTED_LOCALES as readonly string[]).includes(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\n\t\tconst baseMatch = matchSupportedBaseLocale(candidate)\n\t\tif (baseMatch) {\n\t\t\treturn baseMatch\n\t\t}\n\t}\n}\n\nexport function getBrowserLocale(): string | undefined {\n\tif (typeof navigator === \"undefined\") return\n\n\tfor (const candidate of navigator.languages || []) {\n\t\tconst normalized = normalizeSdkLocale(candidate)\n\t\tif (normalized) return normalized\n\t}\n\n\treturn normalizeSdkLocale(navigator.language)\n}\n\nexport function getAutoResolvedLocale(locale?: string): string {\n\treturn normalizeSdkLocale(locale) || getBrowserLocale() || SDK_DEFAULT_LOCALE\n}\n\nexport function applyLocaleToUrl(urlValue: string, locale?: string): string {\n\tif (!locale) return urlValue\n\n\ttry {\n\t\tconst url = new URL(urlValue)\n\t\tconst localePrefix = `/${locale}`\n\t\tif (\n\t\t\t!url.pathname.startsWith(`${localePrefix}/`) &&\n\t\t\turl.pathname !== localePrefix\n\t\t) {\n\t\t\turl.pathname = `${localePrefix}${url.pathname}`\n\t\t}\n\t\treturn url.toString()\n\t} catch (_error) {\n\t\tconst localePrefix = `/${locale}`\n\t\tif (!urlValue.startsWith(`${localePrefix}/`) && urlValue !== localePrefix) {\n\t\t\treturn `${localePrefix}${urlValue.startsWith(\"/\") ? \"\" : \"/\"}${urlValue}`\n\t\t}\n\t\treturn urlValue\n\t}\n}\n\nexport class HostedFrameModal<TData extends HostedFrameMessage> {\n\tprotected iframe: HTMLIFrameElement | null = null\n\tprotected modal: HTMLDivElement | null = null\n\tprotected messageHandler: ((event: MessageEvent) => void) | null = null\n\n\tprotected openHostedFrame(\n\t\turl: string,\n\t\toptions: HostedFrameOptions<TData>,\n\t): 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 { 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})\n\n\tconst badge = document.createElement(\"div\")\n\tbadge.textContent = \"YOUiDIAN\"\n\tObject.assign(badge.style, {\n\t\tdisplay: \"inline-flex\",\n\t\talignItems: \"center\",\n\t\tborder: \"1px solid rgba(229,229,229,0.92)\",\n\t\tborderRadius: \"9999px\",\n\t\tbackground: \"#fafafa\",\n\t\tcolor: \"#171717\",\n\t\tfontSize: \"11px\",\n\t\tfontWeight: \"700\",\n\t\tletterSpacing: \"0.22em\",\n\t\tlineHeight: \"1\",\n\t\tmarginBottom: \"18px\",\n\t\tpadding: \"8px 12px\",\n\t})\n\n\tcontent.appendChild(badge)\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\nfunction createBrandLoadingCopy() {\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 = \"优易点\"\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 = \"开发者服务中台\"\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() {\n\tensureLoginLoadingStyles()\n\tconst panel = document.createElement(\"div\")\n\tapplyLoginLoadingPanelStyle(panel)\n\tpanel.setAttribute(\"role\", \"status\")\n\tpanel.setAttribute(\"aria-label\", \"优易点开发者服务中台\")\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())\n\tpanel.appendChild(content)\n\n\treturn panel\n}\n\nfunction createLoginRedirectingPanel(_options: {\n\tdescription: string\n\ttitle: string\n}) {\n\treturn createLoginLoadingPanel()\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) {\n\t\tif (this.iframeLoadingPanel || this.iframeReady) {\n\t\t\treturn\n\t\t}\n\n\t\tconst panel = createLoginLoadingPanel()\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}) {\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\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}) {\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(hostedFrame.container)\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})\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 } 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\"\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\" | \"slow\") {\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: type === \"refresh\"\n\t\t\t\t? [\n\t\t\t\t\t\t\"M20 6V11H15\",\n\t\t\t\t\t\t\"M4 18V13H9\",\n\t\t\t\t\t\t\"M18.2 9A7 7 0 0 0 6.2 6.6L4 9\",\n\t\t\t\t\t\t\"M5.8 15A7 7 0 0 0 17.8 17.4L20 15\",\n\t\t\t\t\t]\n\t\t\t\t: [\"M12 7V12L15 14\", \"M21 12A9 9 0 1 1 3 12A9 9 0 0 1 21 12\"]\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 createPaymentFallbackArtwork(theme: ResolvedPaymentTheme) {\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\tconst icon = createPaymentIcon(\"slow\")\n\tObject.assign(icon.style, {\n\t\twidth: \"52px\",\n\t\theight: \"52px\",\n\t\ttransform: \"rotate(4deg)\",\n\t})\n\ttile.appendChild(icon)\n\n\tartwork.appendChild(wash)\n\tartwork.appendChild(blob)\n\tartwork.appendChild(tile)\n\treturn artwork\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(createPaymentFallbackArtwork(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 (status.status === \"CANCELLED\" || status.status === \"FAILED\") {\n\t\t\t\t\t\treject(new Error(`Order ${status.status.toLowerCase()}`))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(new Error(\"Polling timeout\"))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Continue polling\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// On network error, continue polling unless timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(error)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpoll()\n\t\t})\n\t}\n}\n\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, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\")\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\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\nexport type SubscriptionAction = \"NEW\" | \"UPGRADE\" | \"DOWNGRADE\"\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_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\tfromSubscriptionId?: string | null\n\tfromProductCode?: string | null\n\tremainingDays?: number | null\n\tcurrentRemainingValueAmount?: 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}\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\"\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}\n\nexport interface DiscountPolicy {\n\tcode: string\n\tname: string\n\tdescription: string | null\n\tqualificationCode: string\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}\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\tcallbackUrl?: string\n\tmetadata?: Record<string, any>\n\tmerchantOrderId?: string\n\topenid?: string\n\tlocale?: string\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}\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\"\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\"\n\torderId: string\n\tinternalId?: string | null\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\"\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\"\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\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}\n\n\t\tconst options: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody: body ? JSON.stringify(body) : 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}): 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\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 * 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\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":";;;;;AAqCA,SAAS,2BAA2B;AACnC,MAAI,SAAS,iBAAiB,+BAA+B,GAAG;AAC/D;AAAA,EACD;AAEA,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,KAAK;AACX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmFpB,WAAS,MAAM,YAAY,KAAK;AACjC;AAEO,SAAS,uBAAuB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACX,GAA4B;AAC3B,2BAAyB;AAEzB,QAAM,OAAO,SAAS,gBAAgB,8BAA8B,KAAK;AACzE,OAAK,aAAa,WAAW,aAAa;AAC1C,OAAK,aAAa,QAAQ,MAAM;AAChC,OAAK,aAAa,eAAe,MAAM;AACvC,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,OAAO,GAAG,IAAI;AAAA,IACd,QAAQ,GAAG,IAAI;AAAA,IACf,OAAO,WAAW,YAAY,MAAM;AAAA,IACpC,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,EACX,CAAC;AAED,QAAM,YAAY,SAAS,gBAAgB,8BAA8B,GAAG;AAC5E,YAAU;AAAA,IACT;AAAA,IACA,YAAY,SACT,oCACA;AAAA,EACJ;AAEA,QAAM,OAAO,SAAS,gBAAgB,8BAA8B,MAAM;AAC1E,OAAK,aAAa,SAAS,WAAW,kCAAkC,EAAE;AAC1E,OAAK,aAAa,QAAQ,WAAW,iBAAiB,MAAM,OAAO;AACnE,OAAK;AAAA,IACJ;AAAA,IACA;AAAA,EACD;AAEA,QAAM,MAAM,SAAS,gBAAgB,8BAA8B,QAAQ;AAC3E,MAAI,aAAa,SAAS,WAAW,iCAAiC,EAAE;AACxE,MAAI,aAAa,QAAQ,WAAW,iBAAiB,MAAM,SAAS;AACpE,MAAI,aAAa,MAAM,OAAO;AAC9B,MAAI,aAAa,MAAM,OAAO;AAC9B,MAAI,aAAa,KAAK,IAAI;AAC1B,MAAI,aAAa,WAAW,WAAW,SAAS,GAAG;AAEnD,YAAU,YAAY,IAAI;AAC1B,YAAU,YAAY,GAAG;AACzB,OAAK,YAAY,SAAS;AAC1B,SAAO;AACR;AAEO,SAAS,mBAAmB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB;AAAA,EACA,iBAAiB;AAAA,EACjB;AAAA,EACA,UAAU;AACX,GAAwB;AACvB,2BAAyB;AAEzB,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,UAAQ,YAAY;AACpB,UAAQ,aAAa,iBAAiB,WAAW,SAAS,OAAO;AACjE,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,KAAK,GAAG,GAAG;AAAA,IACX,OAAO,aAAa,GAAG,UAAU,OAAO;AAAA,EACzC,CAAC;AAED,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,OAAK,aAAa,qBAAqB,MAAM,QAAQ;AACrD,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,OAAO,YAAY,GAAG,SAAS,OAAO;AAAA,EACvC,CAAC;AAED,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,OAAK,cAAc,MAAM;AACzB,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,OAAO,MAAM;AAAA,IACb,YACC,MAAM,aAAa,OAChB,uFACA;AAAA,IACJ,UAAU,GAAG,QAAQ;AAAA,IACrB,YAAY,MAAM,aAAa,OAAO,QAAQ;AAAA,IAC9C,eAAe,MAAM,aAAa,OAAO,WAAW;AAAA,IACpD,YAAY;AAAA,IACZ,YAAY;AAAA,EACb,CAAC;AAED,QAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,WAAS,YAAY;AACrB,WAAS,cAAc,MAAM;AAC7B,SAAO,OAAO,SAAS,OAAO;AAAA,IAC7B,OAAO,MAAM;AAAA,IACb,YACC,MAAM,aAAa,OAChB,uFACA;AAAA,IACJ,UAAU,GAAG,YAAY;AAAA,IACzB,YAAY;AAAA,IACZ,eAAe,MAAM,aAAa,OAAO,WAAW;AAAA,IACpD,YAAY;AAAA,IACZ,WAAW,GAAG,iBAAiB;AAAA,IAC/B,eAAe,MAAM,aAAa,OAAO,SAAS;AAAA,IAClD,YAAY;AAAA,EACb,CAAC;AAED,OAAK,YAAY,IAAI;AACrB,OAAK,YAAY,QAAQ;AACzB,QAAM,OAAO,uBAAuB;AAAA,IACnC;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACD,CAAC;AACD,MAAI,OAAO,oBAAoB,UAAU;AACxC,SAAK,MAAM,cAAc,GAAG,eAAe;AAAA,EAC5C;AACA,UAAQ,YAAY,IAAI;AACxB,UAAQ,YAAY,IAAI;AACxB,SAAO;AACR;;;ACxPA,IAAM,wBAAwB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAEA,IAAM,qBAAqB;AAE3B,IAAM,qBAA6C;AAAA,EAClD,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACL;AAEA,SAAS,yBAAyB,QAAoC;AACrE,QAAM,OAAO,OAAO,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAC9C,SAAO,sBAAsB,KAAK,CAAC,SAAS,KAAK,YAAY,MAAM,IAAI;AACxE;AAEO,SAAS,mBAAmB,QAAqC;AACvE,MAAI,CAAC,OAAQ;AAEb,QAAM,YAAY,OAAO,KAAK,EAAE,QAAQ,MAAM,GAAG;AACjD,MAAI,CAAC,UAAW;AAEhB,QAAM,QAAQ,UAAU,YAAY;AACpC,MAAI,mBAAmB,KAAK,GAAG;AAC9B,WAAO,mBAAmB,KAAK;AAAA,EAChC;AAEA,MAAI;AACJ,MAAI;AACH,gBAAY,KAAK,oBAAoB,SAAS,EAAE,CAAC;AAAA,EAClD,QAAQ;AACP,gBAAY;AAAA,EACb;AAEA,QAAM,aAAa,CAAC,WAAW,SAAS,EAAE,OAAO,OAAO;AAExD,aAAW,aAAa,YAAY;AACnC,UAAM,iBAAiB,UAAU,YAAY;AAE7C,QAAI,mBAAmB,cAAc,GAAG;AACvC,aAAO,mBAAmB,cAAc;AAAA,IACzC;AACA,QAAK,sBAA4C,SAAS,SAAS,GAAG;AACrE,aAAO;AAAA,IACR;AAEA,UAAM,YAAY,yBAAyB,SAAS;AACpD,QAAI,WAAW;AACd,aAAO;AAAA,IACR;AAAA,EACD;AACD;AAEO,SAAS,mBAAuC;AACtD,MAAI,OAAO,cAAc,YAAa;AAEtC,aAAW,aAAa,UAAU,aAAa,CAAC,GAAG;AAClD,UAAM,aAAa,mBAAmB,SAAS;AAC/C,QAAI,WAAY,QAAO;AAAA,EACxB;AAEA,SAAO,mBAAmB,UAAU,QAAQ;AAC7C;AAEO,SAAS,sBAAsB,QAAyB;AAC9D,SAAO,mBAAmB,MAAM,KAAK,iBAAiB,KAAK;AAC5D;AAEO,SAAS,iBAAiB,UAAkB,QAAyB;AAC3E,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,QAAQ;AAC5B,UAAM,eAAe,IAAI,MAAM;AAC/B,QACC,CAAC,IAAI,SAAS,WAAW,GAAG,YAAY,GAAG,KAC3C,IAAI,aAAa,cAChB;AACD,UAAI,WAAW,GAAG,YAAY,GAAG,IAAI,QAAQ;AAAA,IAC9C;AACA,WAAO,IAAI,SAAS;AAAA,EACrB,SAAS,QAAQ;AAChB,UAAM,eAAe,IAAI,MAAM;AAC/B,QAAI,CAAC,SAAS,WAAW,GAAG,YAAY,GAAG,KAAK,aAAa,cAAc;AAC1E,aAAO,GAAG,YAAY,GAAG,SAAS,WAAW,GAAG,IAAI,KAAK,GAAG,GAAG,QAAQ;AAAA,IACxE;AACA,WAAO;AAAA,EACR;AACD;AAEO,IAAM,mBAAN,MAAyD;AAAA,EAAzD;AACN,wBAAU,UAAmC;AAC7C,wBAAU,SAA+B;AACzC,wBAAU,kBAAyD;AAAA;AAAA,EAEzD,gBACT,KACA,SAC6B;AAC7B,QAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,QAAI,KAAK,MAAO,QAAO;AAEvB,SAAK,QAAQ,SAAS,cAAc,KAAK;AACzC,WAAO,OAAO,KAAK,MAAM,OAAO;AAAA,MAC/B,UAAU;AAAA,MACV,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,SAAS;AAAA,IACV,CAAC;AAED,UAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,WAAO,OAAO,UAAU,OAAO;AAAA,MAC9B,OAAO,QAAQ,SAAS;AAAA,MACxB,QAAQ,QAAQ,UAAU;AAAA,MAC1B,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,UAAU;AAAA,MACV,UAAU;AAAA,MACV,WAAW;AAAA,MACX,UAAU;AAAA,MACV,WAAW;AAAA,MACX,YAAY;AAAA,IACb,CAAC;AAED,UAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,aAAS,YAAY;AACrB,WAAO,OAAO,SAAS,OAAO;AAAA,MAC7B,UAAU;AAAA,MACV,OAAO;AAAA,MACP,KAAK;AAAA,MACL,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,IACZ,CAAC;AACD,aAAS,UAAU,MAAM;AACxB,WAAK,MAAM;AACX,cAAQ,gBAAgB;AAAA,IACzB;AAEA,SAAK,SAAS,SAAS,cAAc,QAAQ;AAC7C,SAAK,OAAO,MAAM;AAClB,SAAK,OAAO,QAAQ;AACpB,WAAO,OAAO,KAAK,OAAO,OAAO;AAAA,MAChC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,YAAY;AAAA,MACZ,SAAS;AAAA,IACV,CAAC;AAED,cAAU,YAAY,QAAQ;AAC9B,cAAU,YAAY,KAAK,MAAM;AACjC,SAAK,MAAM,YAAY,SAAS;AAChC,aAAS,KAAK,YAAY,KAAK,KAAK;AAEpC,SAAK,iBAAiB,CAAC,UAAwB;AAC9C,UAAI,QAAQ,iBAAiB,QAAQ,kBAAkB,KAAK;AAC3D,YAAI,MAAM,WAAW,QAAQ,eAAe;AAC3C;AAAA,QACD;AAAA,MACD;AAEA,YAAM,OAAO,MAAM;AACnB,UAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,MAAM;AACpD;AAAA,MACD;AAEA,cAAQ,UAAU,MAAM,WAAW,KAAK;AAAA,IACzC;AAEA,WAAO,iBAAiB,WAAW,KAAK,cAAc;AAEtD,WAAO;AAAA,MACN;AAAA,MACA,QAAQ,KAAK;AAAA,IACd;AAAA,EACD;AAAA,EAEA,QAAQ;AACP,QAAI,OAAO,WAAW,YAAa;AAEnC,QAAI,KAAK,gBAAgB;AACxB,aAAO,oBAAoB,WAAW,KAAK,cAAc;AACzD,WAAK,iBAAiB;AAAA,IACvB;AAEA,QAAI,KAAK,OAAO,YAAY;AAC3B,WAAK,MAAM,WAAW,YAAY,KAAK,KAAK;AAAA,IAC7C;AAEA,SAAK,QAAQ;AACb,SAAK,SAAS;AAAA,EACf;AACD;;;AC7NA,SAAS,cAAc,OAAgB;AACtC,SAAO,SAAS;AACjB;AAEA,SAAS,kBAAyC;AACjD,MAAI,OAAO,cAAc,aAAa;AACrC,WAAO,CAAC;AAAA,EACT;AAEA,QAAM,MAAM;AACZ,QAAM,gBACL,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,aAC3D,OAAO,WAAW,mBAAmB,EAAE,UACvC;AAEJ,SAAO;AAAA,IACN;AAAA,IACA,gBAAgB,IAAI,kBAAkB;AAAA,IACtC,UAAU,IAAI,YAAY;AAAA,IAC1B,YAAY,IAAI;AAAA,IAChB,WAAW,IAAI,aAAa;AAAA,IAC5B,qBAAqB,IAAI,eAAe;AAAA,EACzC;AACD;AAEA,SAAS,YAAY,OAAe,UAAoB;AACvD,SAAO,SAAS,KAAK,CAAC,YAAY,QAAQ,KAAK,KAAK,CAAC;AACtD;AAEO,SAAS,uBACf,QAA+B,gBAAgB,GAC5B;AACnB,QAAM,YAAY,cAAc,MAAM,SAAS;AAC/C,QAAM,WAAW,cAAc,MAAM,QAAQ;AAC7C,QAAM,oBAAoB,MAAM,kBAAkB;AAClD,QAAM,iBAAiB,OAAO,SAAS,iBAAiB,IACrD,KAAK,IAAI,GAAG,iBAAiB,IAC7B;AACH,QAAM,kBAAkB,MAAM,kBAAkB;AAChD,QAAM,UAAU,iBAAiB,KAAK;AAEtC,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,QAAM,YAAY,eAAe,KAAK,SAAS;AAC/C,QAAM,uBAAuB,0BAA0B,KAAK,SAAS;AACrE,QAAM,wBAAwB,iBAAiB,KAAK,SAAS;AAC7D,QAAM,iBAAiB,QAAQ,KAAK,QAAQ;AAC5C,QAAM,WACL,CAAC,wBACD,yBACA,kBACA,OAAO,MAAM,eAAe,eAC5B,iBAAiB;AAClB,QAAM,QAAQ,wBAAwB;AAEtC,QAAM,eAAe,YAAY,WAAW;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AACD,QAAM,eAAe,YAAY,WAAW;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AACD,QAAM,kBAAkB,aAAa,CAAC,cAAc,KAAK,SAAS;AAClE,QAAM,WAAW,YAAY,gBAAgB;AAC7C,QAAM,WACL,MAAM,wBAAwB,QAC9B,gBACC,aAAa,CAAC,YACd,SAAS,CAAC;AACZ,QAAM,aAA8B,WACjC,WACA,WACC,WACA,aAAa,YAAY,UACxB,YACA;AAEL,QAAM,yBACL,eAAe,YAAY,eAAe,YAAY;AAEvD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,eAAe;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,MAAM,eAAe;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;ACnBA,SAAS,UAAU,OAA+B;AACjD,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACH,WAAO,IAAI,IAAI,KAAK,EAAE;AAAA,EACvB,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,wBAAwB,OAAiC;AACjE,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,WAAO,IAAI,aAAa,YAAY,IAAI,aAAa;AAAA,EACtD,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,2BAA2B;AACnC,MAAI,OAAO,WAAW,eAAe,OAAO,YAAY;AACvD,WAAO,OAAO,WAAW,EAAE,QAAQ,MAAM,EAAE;AAAA,EAC5C;AACA,SAAO,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AACxE;AAEA,SAAS,sBAAsB,eAAuB,aAAsB;AAC3E,QAAM,UAAU,eAAe,OAAO,SAAS;AAC/C,QAAM,MAAM,IAAI,IAAI,SAAS,OAAO,SAAS,IAAI;AACjD,QAAM,aAAa,IAAI,KAAK,QAAQ,MAAM,EAAE;AAE5C,MAAI,OAAO;AACX,MAAI,aAAa,IAAI,uBAAuB,GAAG;AAC/C,MAAI,aAAa,IAAI,4BAA4B,aAAa;AAC9D,MAAI,YAAY;AACf,QAAI,aAAa,IAAI,kCAAkC,UAAU;AAAA,EAClE,OAAO;AACN,QAAI,aAAa,OAAO,gCAAgC;AAAA,EACzD;AAEA,SAAO,IAAI,SAAS;AACrB;AAEA,SAAS,wBACR,QACA,SACA,eACC;AACD,QAAM,eACL,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAC1D,QAAM,cACL,OAAO,WAAW,eAAe,gBAC9B,sBAAsB,eAAe,SAAS,WAAW,IACzD;AAEJ,SAAO;AAAA,IACN,WAAW,SAAS,aAAa;AAAA,IACjC;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,kBAAkB,OAAO;AAAA,EAC1B;AACD;AAEA,SAAS,sBACR,UACA,SACC;AACD,QAAM,aAAa,IAAI,gBAAgB;AACvC,MAAI,QAAQ,cAAc,OAAO;AAChC,eAAW,IAAI,eAAe,OAAO;AAAA,EACtC;AACA,MAAI,QAAQ,QAAQ;AACnB,eAAW,IAAI,YAAY,QAAQ,MAAM;AAAA,EAC1C;AACA,MAAI,QAAQ,aAAa;AACxB,eAAW,IAAI,iBAAiB,QAAQ,WAAW;AAAA,EACpD;AACA,MAAI,QAAQ,kBAAkB;AAC7B,eAAW,IAAI,sBAAsB,QAAQ,gBAAgB;AAAA,EAC9D;AACA,QAAM,OAAO,WAAW,SAAS;AACjC,MAAI,CAAC,MAAM;AACV,WAAO;AAAA,EACR;AAEA,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,QAAQ;AAC5B,QAAI,OAAO;AACX,WAAO,IAAI,SAAS;AAAA,EACrB,SAAS,QAAQ;AAChB,WAAO,GAAG,QAAQ,IAAI,IAAI;AAAA,EAC3B;AACD;AAEA,SAAS,oBAAoB,SAA6B;AACzD,SAAO,kBAAkB,KAAK,UAAU,OAAO,CAAC;AACjD;AAEA,SAAS,cACR,QACA,SACA,eACS;AACT,QAAM,EAAE,OAAO,UAAU,0BAA0B,SAAS,IAAI;AAChE,QAAM,WAAW,YAAY,SAAS,QAAQ,OAAO,EAAE;AACvD,QAAM,eAAe,cAAc;AAEnC,MAAI;AACJ,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAI,CAAC,0BAA0B,KAAK,IAAI,QAAQ,GAAG;AAClD,UAAI,WACH,GAAG,IAAI,SAAS,QAAQ,OAAO,EAAE,CAAC,iBAAiB,KAAK,GAAG;AAAA,QAC1D;AAAA,QACA;AAAA,MACD;AAAA,IACF;AACA,eAAW,IAAI,SAAS;AAAA,EACzB,SAAS,QAAQ;AAChB,QAAI,0BAA0B,KAAK,OAAO,GAAG;AAC5C,iBAAW;AAAA,IACZ,OAAO;AACN,iBAAW,GAAG,OAAO,iBAAiB,KAAK,GAAG,QAAQ,WAAW,GAAG;AAAA,IACrE;AAAA,EACD;AAEA,aAAW,iBAAiB,UAAU,sBAAsB,OAAO,MAAM,CAAC;AAE1E,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,QAAQ;AAC5B,QAAI,OAAO,kBAAkB;AAC5B,UAAI,aAAa,IAAI,oBAAoB,OAAO,gBAAgB;AAAA,IACjE;AACA,QAAI,SAAS,cAAc,OAAO;AACjC,UAAI,aAAa,IAAI,aAAa,OAAO;AAAA,IAC1C;AACA,QAAI,cAAc;AACjB,UAAI,aAAa,IAAI,UAAU,YAAY;AAAA,IAC5C;AACA,WAAO,sBAAsB,IAAI,SAAS,GAAG,aAAa;AAAA,EAC3D,SAAS,QAAQ;AAChB,UAAM,eAAe,IAAI,gBAAgB;AACzC,QAAI,OAAO,kBAAkB;AAC5B,mBAAa,IAAI,oBAAoB,OAAO,gBAAgB;AAAA,IAC7D;AACA,QAAI,SAAS,cAAc,OAAO;AACjC,mBAAa,IAAI,aAAa,OAAO;AAAA,IACtC;AACA,QAAI,cAAc;AACjB,mBAAa,IAAI,UAAU,YAAY;AAAA,IACxC;AACA,UAAM,QAAQ,aAAa,SAAS;AACpC,QAAI,CAAC,OAAO;AACX,aAAO,sBAAsB,UAAU,aAAa;AAAA,IACrD;AACA,UAAM,YAAY,SAAS,SAAS,GAAG,IAAI,MAAM;AACjD,WAAO;AAAA,MACN,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK;AAAA,MAC/B;AAAA,IACD;AAAA,EACD;AACD;AAEA,SAAS,mBAAmB,MAAmC;AAC9D,SAAO;AAAA,IACN,QAAQ,KAAK;AAAA,IACb,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,IACZ,WAAW,KAAK;AAAA,IAChB,iBAAiB,KAAK;AAAA,IACtB,YAAY,KAAK;AAAA,IACjB,MAAM,KAAK;AAAA,IACX,UAAU,KAAK;AAAA,IACf,kBAAkB,KAAK;AAAA,IACvB,aAAa,KAAK;AAAA,IAClB,WAAW,KAAK;AAAA,IAChB,iBAAiB,KAAK;AAAA,IACtB,QAAQ,KAAK;AAAA,IACb,cAAc,KAAK;AAAA,IACnB,eAAe,KAAK;AAAA,EACrB;AACD;AAEA,IAAM,sBAAsB;AAC5B,IAAM,wBAAwB;AAC9B,IAAM,8BAA8B;AACpC,IAAM,mCAAmC;AACzC,IAAM,6BAA6B;AACnC,IAAM,gCAAgC;AACtC,IAAM,0CAA0C;AAChD,IAAM,iCAAiC;AAIvC,SAAS,sBAAsB,OAAsC;AACpE,MAAI;AACH,UAAM,SAAS,MAAM;AAAA,MACpB,MAAM,UAAW,IAAK,MAAM,SAAS,KAAM;AAAA,MAC3C;AAAA,IACD;AACA,UAAM,SAAS,OAAO,WAAW,KAAK,GAAG,EAAE,WAAW,KAAK,GAAG;AAC9D,UAAM,SAAS,KAAK,MAAM;AAC1B,UAAM,OAAO;AAAA,MACZ,MAAM;AAAA,QACL;AAAA,QACA,CAAC,SAAS,IAAI,KAAK,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,MAC/D,EAAE,KAAK,EAAE;AAAA,IACV;AACA,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,WAAO,UAAU,OAAO,WAAW,YAAY,OAAO,OAAO,SAAS;AAAA,EACvE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,4BAA4B,OAAe;AACnD,SAAO,kBAAkB,KAAK;AAC/B;AAEA,SAAS,2BAA2B,OAAe;AAClD,SAAO,GAAG,6BAA6B,GAAG,KAAK;AAChD;AAEA,SAAS,qBAAqB,OAAe,MAAsB;AAClE,MAAI;AACH,UAAM,UAAU,IAAI,iBAAiB,4BAA4B,KAAK,CAAC;AACvE,YAAQ,YAAY,IAAI;AACxB,YAAQ,MAAM;AAAA,EACf,QAAQ;AAAA,EAER;AAEA,MAAI;AACH,UAAM,aAAa,2BAA2B,KAAK;AACnD,WAAO,aAAa,QAAQ,YAAY,KAAK,UAAU,IAAI,CAAC;AAC5D,WAAO,WAAW,MAAM;AACvB,UAAI;AACH,eAAO,aAAa,WAAW,UAAU;AAAA,MAC1C,QAAQ;AAAA,MAER;AAAA,IACD,GAAG,GAAG;AAAA,EACP,QAAQ;AAAA,EAER;AAEA,MAAI;AACH,WAAO,QAAQ,YAAY,MAAM,OAAO,SAAS,MAAM;AAAA,EACxD,QAAQ;AAAA,EAER;AACD;AAEA,SAAS,kBAAkB,OAAsB;AAChD,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACH,WAAO,MAAM;AAAA,EACd,QAAQ;AACP,kBAAc,qDAAqD;AACnE,WAAO;AAAA,EACR;AACD;AAEA,SAAS,eAAe,OAAsB;AAC7C,MAAI,CAAC,MAAO;AACZ,MAAI;AACH,UAAM,MAAM;AAAA,EACb,QAAQ;AACP,kBAAc,uBAAuB;AAAA,EACtC;AACD;AAEA,SAAS,sBAAsB,KAAU;AACxC,MAAI,aAAa,OAAO,qBAAqB;AAC7C,MAAI,aAAa,OAAO,0BAA0B;AAClD,QAAM,aAAa,IAAI,aAAa,IAAI,gCAAgC;AACxE,MAAI,aAAa,OAAO,gCAAgC;AACxD,MAAI,OAAO,aAAa,IAAI,UAAU,KAAK;AAC3C,SAAO,IAAI,SAAS;AACrB;AAEA,SAAS,6BAA6B,MAAsB;AAC3D,MAAI;AACH,WAAO,eAAe;AAAA,MACrB;AAAA,MACA,KAAK,UAAU;AAAA,QACd,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD,QAAQ;AAAA,EAER;AACD;AAEA,SAAS,+BAA+B;AACvC,MAAI;AACH,UAAM,MAAM,OAAO,eAAe;AAAA,MACjC;AAAA,IACD;AACA,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,eAAe,WAAW,uCAAuC;AACxE,UAAM,SAAS,KAAK,MAAM,GAAG;AAI7B,UAAM,OAAO,QAAQ;AACrB,WAAO,QAAQ,OAAO,SAAS,YAAY,KAAK,OAAO,OAAO;AAAA,EAC/D,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,yBACR,MACA,SACC;AACD,WAAS,WAAW,IAAI;AACxB,UAAQ,KAAK,MAAM;AAAA,IAClB,KAAK;AACJ,eAAS,YAAY,mBAAmB,IAAI,CAAC;AAC7C;AAAA,IACD,KAAK;AACJ,eAAS,UAAU,KAAK,WAAW,KAAK,OAAO,IAAI;AACnD;AAAA,IACD;AACC;AAAA,EACF;AACD;AAEO,SAAS,6BAA6B,SAAgC;AAC5E,MAAI,OAAO,WAAW,aAAa;AAClC,WAAO;AAAA,EACR;AAEA,QAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,MAAI,IAAI,aAAa,IAAI,qBAAqB,MAAM,KAAK;AACxD,QAAI,SAAS,YAAY,SAAS,aAAa,SAAS,SAAS;AAChE,YAAM,cAAc,6BAA6B;AACjD,UAAI,aAAa;AAChB,iCAAyB,aAAa,OAAO;AAC7C,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAEA,QAAM,QAAQ,IAAI,aAAa,IAAI,0BAA0B,KAAK;AAClE,QAAM,aAAa,IAAI,gBAAgB,IAAI,KAAK,QAAQ,MAAM,EAAE,CAAC;AACjE,QAAM,YAAY,WAAW,IAAI,2BAA2B;AAC5D,QAAM,OACL,aAAa,QACV,sBAAsB,SAAS,IAC/B;AAAA,IACA,MAAM;AAAA,IACN,SAAS;AAAA,EACV;AAEH,MAAI;AACH,aAAS,gBAAgB,MAAM,aAAa;AAAA,EAC7C,QAAQ;AAAA,EAER;AAEA,MAAI,SAAS,MAAM;AAClB,yBAAqB,OAAO,IAAI;AAAA,EACjC;AACA,MAAI,SAAS,SAAS,YAAY,SAAS,aAAa,SAAS,UAAU;AAC1E,6BAAyB,MAAM,OAAO;AAAA,EACvC,WAAW,MAAM;AAChB,iCAA6B,IAAI;AAAA,EAClC;AAEA,MAAI;AACH,WAAO,QAAQ,aAAa,MAAM,IAAI,sBAAsB,GAAG,CAAC;AAAA,EACjE,QAAQ;AAAA,EAER;AAEA,MAAI,SAAS,cAAc,MAAM;AAChC,WAAO,WAAW,MAAM;AACvB,UAAI;AACH,eAAO,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACD,GAAG,EAAE;AACL,WAAO;AAAA,EACR;AAEA,MAAI;AACH,aAAS,gBAAgB,MAAM,aAAa;AAAA,EAC7C,QAAQ;AAAA,EAER;AAEA,SAAO;AACR;AAEA,SAAS,cAAc,SAAiB,SAAmC;AAC1E,MAAI,OAAO,YAAY,YAAa;AACpC,UAAQ,MAAM,qBAAqB,SAAS,WAAW,CAAC,CAAC;AAC1D;AAEA,SAAS,aAAa,SAAiB,SAAmC;AACzE,MAAI,OAAO,YAAY,YAAa;AACpC,UAAQ,KAAK,qBAAqB,SAAS,WAAW,CAAC,CAAC;AACzD;AAEA,SAAS,aAAa,SAAiB,SAAmC;AACzE,MAAI,OAAO,YAAY,YAAa;AACpC,UAAQ,KAAK,qBAAqB,SAAS,WAAW,CAAC,CAAC;AACzD;AAEA,SAAS,uBAAuB,SAA0B;AACzD,QAAM,UAAU,SAAS;AACzB,MAAI,OAAO,YAAY,YAAY,CAAC,OAAO,SAAS,OAAO,GAAG;AAC7D,WAAO;AAAA,EACR;AACA,SAAO,KAAK,IAAI,GAAG,OAAO;AAC3B;AAEA,SAAS,qBAAqB,OAAuB;AACpD,SAAO,OAAO,MAAM,OAAO;AAAA,IAC1B,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,SAAS;AAAA,IACT,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,gBAAgB;AAAA,EACjB,CAAC;AACF;AAEA,SAAS,4BAA4B,OAAuB;AAC3D,SAAO,OAAO,MAAM,OAAO;AAAA,IAC1B,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,SAAS;AAAA,IACT,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,gBAAgB;AAAA,EACjB,CAAC;AACF;AAEA,SAAS,0BAA0B;AAClC,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,UAAU;AAAA,EACX,CAAC;AAED,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,SAAS;AAAA,EACV,CAAC;AAED,UAAQ,YAAY,KAAK;AAEzB,SAAO;AACR;AAEA,SAAS,yBAAyB;AACjC,QAAM,OAAO,SAAS,gBAAgB,8BAA8B,KAAK;AACzE,OAAK,aAAa,WAAW,eAAe;AAC5C,OAAK,aAAa,QAAQ,MAAM;AAChC,OAAK,aAAa,eAAe,MAAM;AACvC,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,SAAS;AAAA,IACT,UAAU;AAAA,EACX,CAAC;AAED,QAAM,QAAQ,SAAS,gBAAgB,8BAA8B,GAAG;AACxE,QAAM,aAAa,QAAQ,cAAc;AAEzC,QAAM,OAAO,SAAS,gBAAgB,8BAA8B,MAAM;AAC1E,OAAK;AAAA,IACJ;AAAA,IACA;AAAA,EACD;AACA,OAAK,aAAa,SAAS,kCAAkC;AAE7D,QAAM,MAAM,SAAS,gBAAgB,8BAA8B,QAAQ;AAC3E,MAAI,aAAa,SAAS,iCAAiC;AAC3D,MAAI,aAAa,MAAM,OAAO;AAC9B,MAAI,aAAa,MAAM,OAAO;AAC9B,MAAI,aAAa,KAAK,IAAI;AAE1B,QAAM,YAAY,IAAI;AACtB,QAAM,YAAY,GAAG;AACrB,OAAK,YAAY,KAAK;AAEtB,SAAO;AACR;AAEA,SAAS,yBAAyB;AACjC,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,YAAY;AAClB,SAAO,OAAO,MAAM,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,YAAY;AAAA,EACb,CAAC;AAED,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,OAAK,cAAc;AACnB,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,YAAY;AAAA,EACb,CAAC;AAED,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,UAAQ,YAAY;AACpB,UAAQ,cAAc;AACtB,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,WAAW;AAAA,EACZ,CAAC;AAED,QAAM,YAAY,IAAI;AACtB,QAAM,YAAY,OAAO;AACzB,SAAO;AACR;AAEA,SAAS,sBAAsB,OAAe;AAC7C,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO;AAAA,IAC1B,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,cAAc;AAAA,EACf,CAAC;AACD,SAAO;AACR;AAEA,SAAS,4BAA4B,OAAe;AACnD,QAAM,cAAc,SAAS,cAAc,KAAK;AAChD,cAAY,cAAc;AAC1B,SAAO,OAAO,YAAY,OAAO;AAAA,IAChC,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EACf,CAAC;AACD,SAAO;AACR;AAEA,SAAS,2BAA2B;AACnC,MAAI,SAAS,eAAe,8BAA8B,GAAG;AAC5D;AAAA,EACD;AACA,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,KAAK;AACX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmFpB,WAAS,KAAK,YAAY,KAAK;AAChC;AAEA,SAAS,0BAA0B;AAClC,2BAAyB;AACzB,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,8BAA4B,KAAK;AACjC,QAAM,aAAa,QAAQ,QAAQ;AACnC,QAAM,aAAa,cAAc,8DAAY;AAE7C,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,KAAK;AAAA,EACN,CAAC;AACD,UAAQ,YAAY,uBAAuB,CAAC;AAC5C,UAAQ,YAAY,uBAAuB,CAAC;AAC5C,QAAM,YAAY,OAAO;AAEzB,SAAO;AACR;AAEA,SAAS,4BAA4B,UAGlC;AACF,SAAO,wBAAwB;AAChC;AAEA,SAAS,yBAAyB,SAK/B;AACF,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,uBAAqB,KAAK;AAE1B,QAAM,UAAU,wBAAwB;AAExC,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,OAAO;AACd,SAAO,cAAc,QAAQ;AAC7B,SAAO,OAAO,OAAO,OAAO;AAAA,IAC3B,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,SAAS;AAAA,IACT,WAAW;AAAA,EACZ,CAAC;AACD,SAAO,UAAU,QAAQ;AAEzB,UAAQ,YAAY,sBAAsB,QAAQ,KAAK,CAAC;AACxD,UAAQ,YAAY,4BAA4B,QAAQ,WAAW,CAAC;AACpE,UAAQ,YAAY,MAAM;AAC1B,QAAM,YAAY,OAAO;AAEzB,SAAO;AACR;AAEO,IAAM,UAAN,cAAsB,iBAAiC;AAAA,EAAvD;AAAA;AACN,wBAAQ,SAAuB;AAC/B,wBAAQ,mBAA2C;AACnD,wBAAQ,0BAAiE;AACzE,wBAAQ,uBAA8D;AACtE,wBAAQ,gBAA8B;AACtC,wBAAQ,uBAA6C;AACrD,wBAAQ,sBAA4C;AACpD,wBAAQ,mBAAiC;AACzC,wBAAQ,uBAAqC;AAC7C,wBAAQ,eAAc;AACtB,wBAAQ,aAAY;AAAA;AAAA,EAEZ,UAAU;AACjB,QAAI,KAAK,iBAAiB;AACzB,WAAK,gBAAgB,MAAM;AAAA,IAC5B;AACA,QAAI,OAAO,WAAW,eAAe,KAAK,wBAAwB;AACjE,aAAO,oBAAoB,WAAW,KAAK,sBAAsB;AAAA,IAClE;AACA,QAAI,OAAO,WAAW,eAAe,KAAK,qBAAqB;AAC9D,aAAO,oBAAoB,WAAW,KAAK,mBAAmB;AAAA,IAC/D;AACA,SAAK,kBAAkB;AACvB,SAAK,yBAAyB;AAC9B,QAAI,OAAO,WAAW,eAAe,KAAK,cAAc;AACvD,aAAO,cAAc,KAAK,YAAY;AAAA,IACvC;AACA,QAAI,OAAO,WAAW,eAAe,KAAK,iBAAiB;AAC1D,aAAO,aAAa,KAAK,eAAe;AAAA,IACzC;AACA,QAAI,OAAO,WAAW,eAAe,KAAK,qBAAqB;AAC9D,aAAO,aAAa,KAAK,mBAAmB;AAAA,IAC7C;AACA,QAAI,KAAK,qBAAqB,YAAY;AACzC,WAAK,oBAAoB,WAAW,YAAY,KAAK,mBAAmB;AAAA,IACzE;AACA,QAAI,KAAK,oBAAoB,YAAY;AACxC,WAAK,mBAAmB,WAAW,YAAY,KAAK,kBAAkB;AAAA,IACvE;AACA,SAAK,sBAAsB;AAC3B,SAAK,eAAe;AACpB,SAAK,sBAAsB;AAC3B,SAAK,qBAAqB;AAC1B,SAAK,kBAAkB;AACvB,SAAK,sBAAsB;AAC3B,SAAK,cAAc;AACnB,SAAK,QAAQ;AACb,SAAK,YAAY;AAAA,EAClB;AAAA,EAEQ,kBAAkB;AACzB,QAAI,KAAK,YAAa;AACtB,SAAK,cAAc;AACnB,QAAI,OAAO,WAAW,eAAe,KAAK,iBAAiB;AAC1D,aAAO,aAAa,KAAK,eAAe;AACxC,WAAK,kBAAkB;AAAA,IACxB;AACA,QAAI,OAAO,WAAW,eAAe,KAAK,qBAAqB;AAC9D,aAAO,aAAa,KAAK,mBAAmB;AAC5C,WAAK,sBAAsB;AAAA,IAC5B;AACA,QAAI,KAAK,qBAAqB,YAAY;AACzC,WAAK,oBAAoB,WAAW,YAAY,KAAK,mBAAmB;AAAA,IACzE;AACA,QAAI,KAAK,oBAAoB,YAAY;AACxC,WAAK,mBAAmB,WAAW,YAAY,KAAK,kBAAkB;AAAA,IACvE;AACA,SAAK,sBAAsB;AAC3B,SAAK,qBAAqB;AAAA,EAC3B;AAAA,EAEQ,kBAAkB,WAA2B;AACpD,QAAI,KAAK,sBAAsB,KAAK,aAAa;AAChD;AAAA,IACD;AAEA,UAAM,QAAQ,wBAAwB;AACtC,SAAK,qBAAqB;AAC1B,cAAU,YAAY,KAAK;AAAA,EAC5B;AAAA,EAEQ,mBAAmB,SAKxB;AACF,QAAI,KAAK,eAAe,KAAK,qBAAqB;AACjD;AAAA,IACD;AAEA,UAAM,EAAE,WAAW,UAAU,aAAa,IAAI;AAC9C,iBAAa,oDAAoD;AAAA,MAChE,UAAU;AAAA,IACX,CAAC;AACD,QAAI,KAAK,oBAAoB,YAAY;AACxC,WAAK,mBAAmB,WAAW,YAAY,KAAK,kBAAkB;AAAA,IACvE;AACA,SAAK,qBAAqB;AAE1B,QAAI,cAAc,yBAAyB,QAAQ;AAClD,YAAMA,SAAQ,4BAA4B;AAAA,QACzC,aACC,cAAc,uBACd;AAAA,QACD,OAAO,cAAc,iBAAiB;AAAA,MACvC,CAAC;AACD,WAAK,sBAAsBA;AAC3B,gBAAU,YAAYA,MAAK;AAC3B,oBAAc,oBAAoB;AAClC,WAAK,sBAAsB,OAAO,WAAW,MAAM;AAClD,aAAK,sBAAsB;AAC3B,qBAAa,6CAA6C;AAAA,UACzD,UAAU;AAAA,QACX,CAAC;AACD,eAAO,SAAS,OAAO,QAAQ;AAAA,MAChC,GAAG,GAAG;AACN;AAAA,IACD;AAEA,UAAM,QAAQ,yBAAyB;AAAA,MACtC,YAAY,cAAc,sBAAsB;AAAA,MAChD,aACC,cAAc,uBACd;AAAA,MACD,OAAO,cAAc,iBAAiB;AAAA,MACtC,YAAY,MAAM;AACjB,qBAAa,6CAA6C;AAAA,UACzD,UAAU;AAAA,QACX,CAAC;AACD,eAAO,SAAS,OAAO,QAAQ;AAAA,MAChC;AAAA,IACD,CAAC;AAED,SAAK,sBAAsB;AAC3B,cAAU,YAAY,KAAK;AAC3B,kBAAc,oBAAoB;AAAA,EACnC;AAAA,EAEQ,oBAAoB,SAKzB;AACF,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,YAAY,uBAAuB,QAAQ,YAAY;AAC7D,QAAI,cAAc,GAAG;AACpB,WAAK,mBAAmB,OAAO;AAC/B;AAAA,IACD;AAEA,SAAK,kBAAkB,OAAO,WAAW,MAAM;AAC9C,WAAK,kBAAkB;AACvB,WAAK,mBAAmB,OAAO;AAAA,IAChC,GAAG,SAAS;AAAA,EACb;AAAA,EAEQ,iBAAiB,MAAsB,SAA0B;AACxE,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,MAAM;AACpD,oBAAc,iCAAiC;AAC/C;AAAA,IACD;AAEA,iBAAa,wBAAwB;AAAA,MACpC,MAAM,KAAK;AAAA,IACZ,CAAC;AAED,YAAQ,KAAK,MAAM;AAAA,MAClB,KAAK;AACJ;AAAA,MACD,KAAK;AACJ,YAAI,KAAK,WAAW;AACnB;AAAA,QACD;AACA,aAAK,YAAY;AACjB,qBAAa,mBAAmB;AAAA,UAC/B,SAAS,KAAK,WAAW;AAAA,UACzB,QAAQ,KAAK,UAAU;AAAA,QACxB,CAAC;AACD,iBAAS,YAAY,mBAAmB,IAAI,CAAC;AAC7C;AAAA,MACD,KAAK;AACJ,qBAAa,iBAAiB;AAC9B,iBAAS,WAAW;AACpB;AAAA,MACD,KAAK;AACJ;AAAA,MACD,KAAK;AACJ,YAAI,CAAC,wBAAwB,KAAK,OAAO,GAAG;AAC3C,uBAAa,+CAA+C;AAC5D,mBAAS,UAAU,iCAAiC,IAAI;AACxD;AAAA,QACD;AACA,qBAAa,2CAA2C;AAAA,UACvD,WAAW,KAAK,aAAa;AAAA,UAC7B,SAAS,KAAK,WAAW;AAAA,UACzB,SAAS,KAAK;AAAA,QACf,CAAC;AACD,aAAK,MAAM;AACX,eAAO,SAAS,OAAO,KAAK,OAAO;AACnC;AAAA,MACD,KAAK;AACJ,YAAI,KAAK,WAAW;AACnB;AAAA,QACD;AACA,qBAAa,gCAAgC;AAAA,UAC5C,SAAS,KAAK,WAAW,KAAK,SAAS;AAAA,QACxC,CAAC;AACD,iBAAS,UAAU,KAAK,WAAW,KAAK,OAAO,IAAI;AACnD;AAAA,MACD,KAAK;AACJ,YAAI,SAAS,cAAc,OAAO;AACjC;AAAA,YACC;AAAA,UACD;AACA,mBAAS,UAAU;AACnB;AAAA,QACD;AACA,qBAAa,kDAAkD;AAC/D,aAAK,MAAM;AACX,iBAAS,UAAU;AACnB;AAAA,IACF;AAAA,EACD;AAAA,EAEQ,kBAAkB,QAAqB,SAA0B;AACxE,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,EAAE,eAAe,UAAU,cAAc,IAAI,KAAK;AAAA,MACvD;AAAA,MACA;AAAA,IACD;AACA,iBAAa,oCAAoC;AAAA,MAChD,OAAO,OAAO;AAAA,MACd;AAAA,MACA,aAAa,cAAc,eAAe;AAAA,MAC1C,gBAAgB,QAAQ,cAAc,WAAW;AAAA,MACjD,UAAU;AAAA,MACV,WAAW,SAAS,aAAa;AAAA,MACjC,aAAa;AAAA,MACb,SAAS,OAAO,SAAS;AAAA,MACzB,cAAc,cAAc,UAAU;AAAA,IACvC,CAAC;AACD,WAAO,SAAS,OAAO,QAAQ;AAAA,EAChC;AAAA,EAEQ,uBACP,eACA,SACC;AACD,QAAI;AACH,WAAK,kBAAkB,IAAI;AAAA,QAC1B,4BAA4B,aAAa;AAAA,MAC1C;AACA,WAAK,gBAAgB,YAAY,CAAC,UAAU;AAC3C,aAAK,iBAAiB,MAAM,MAAwB,OAAO;AAC3D,aAAK,iBAAiB,EAAE,MAAM,cAAc,GAAG,OAAO;AAAA,MACvD;AAAA,IACD,QAAQ;AACP,oBAAc,oDAAoD;AAAA,IACnE;AAEA,SAAK,yBAAyB,CAAC,UAAwB;AACtD,UACC,MAAM,QAAQ,2BAA2B,aAAa,KACtD,CAAC,MAAM,UACN;AACD;AAAA,MACD;AACA,UAAI;AACH,cAAM,OAAO,KAAK,MAAM,MAAM,QAAQ;AACtC,aAAK,iBAAiB,MAAM,OAAO;AACnC,aAAK,iBAAiB,EAAE,MAAM,cAAc,GAAG,OAAO;AAAA,MACvD,QAAQ;AACP,qBAAa,gDAAgD;AAAA,MAC9D;AAAA,IACD;AACA,WAAO,iBAAiB,WAAW,KAAK,sBAAsB;AAAA,EAC/D;AAAA,EAEA,QAAQ;AACP,iBAAa,kBAAkB;AAAA,MAC9B,UAAU,QAAQ,KAAK,KAAK;AAAA,MAC5B,UAAU,QAAQ,KAAK,KAAK;AAAA,MAC5B,aAAa,kBAAkB,KAAK,KAAK;AAAA,IAC1C,CAAC;AACD,mBAAe,KAAK,KAAK;AACzB,UAAM,MAAM;AACZ,SAAK,QAAQ;AAAA,EACd;AAAA,EAEQ,iBAAiB,QAAqB,SAA0B;AACvE,UAAM,gBAAgB,yBAAyB;AAC/C,UAAM,gBAAgB;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,UAAM,WAAW,cAAc,QAAQ,SAAS,aAAa;AAC7D,WAAO,EAAE,eAAe,UAAU,cAAc;AAAA,EACjD;AAAA,EAEQ,eAAe,QAAqB,SAA0B;AACrE,QAAI,OAAO,aAAa,YAAa;AACrC,QAAI,KAAK,MAAO;AAEhB,UAAM,EAAE,eAAe,UAAU,cAAc,IAAI,KAAK;AAAA,MACvD;AAAA,MACA;AAAA,IACD;AACA,UAAM,cAAc,UAAU,QAAQ;AACtC,iBAAa,qCAAqC;AAAA,MACjD,OAAO,OAAO;AAAA,MACd;AAAA,MACA,aAAa,cAAc,eAAe;AAAA,MAC1C,gBAAgB,QAAQ,cAAc,WAAW;AAAA,MACjD,UAAU;AAAA,MACV,eAAe,SAAS,iBAAiB;AAAA,MACzC,WAAW,SAAS,aAAa;AAAA,MACjC,aAAa;AAAA,MACb,SAAS,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,MAChE,cAAc,cAAc,UAAU;AAAA,IACvC,CAAC;AAED,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,uBAAuB,eAAe,OAAO;AAClD,UAAM,cAAc,KAAK,gBAAgB,UAAU;AAAA,MAClD,eAAe,SAAS,iBAAiB,eAAe;AAAA,MACxD,QAAQ;AAAA,MACR,eAAe,MAAM;AACpB,iBAAS,WAAW;AACpB,iBAAS,UAAU;AAAA,MACpB;AAAA,MACA,WAAW,CAAC,MAAM,YAAY,UAAU;AACvC,cAAM,gBAAgB,MAAM,WAAW,KAAK,QAAQ;AAMpD,YACC,CAAC,kBACA,KAAK,SAAS,iBAAiB,KAAK,SAAS,iBAC7C;AACD;AAAA,YACC;AAAA,YACA;AAAA,cACC,MAAM,KAAK;AAAA,cACX,aAAa,MAAM;AAAA,cACnB,WAAW,QAAQ,KAAK,MAAM;AAAA,cAC9B,wBAAwB,QAAQ,KAAK,QAAQ,aAAa;AAAA,YAC3D;AAAA,UACD;AAAA,QACD;AACA,YACE,kBACC,KAAK,SAAS,iBAAiB,KAAK,SAAS,mBAC/C,KAAK,SAAS,mBACd,KAAK,SAAS,eACb;AACD,eAAK,gBAAgB;AAAA,QACtB;AACA,aAAK,iBAAiB,MAAM,OAAO;AAAA,MACpC;AAAA,MACA,OAAO;AAAA,IACR,CAAC;AAED,QAAI,aAAa;AAChB,WAAK,kBAAkB,YAAY,SAAS;AAC5C,WAAK,oBAAoB;AAAA,QACxB,WAAW,YAAY;AAAA,QACvB;AAAA,QACA;AAAA,QACA,cAAc;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEQ,eAAe,QAAqB,SAA0B;AACrE,QAAI,OAAO,WAAW,YAAa;AACnC,QAAI,KAAK,SAAS,CAAC,kBAAkB,KAAK,KAAK,EAAG;AAElD,UAAM,EAAE,eAAe,UAAU,cAAc,IAAI,KAAK;AAAA,MACvD;AAAA,MACA;AAAA,IACD;AACA,iBAAa,8BAA8B;AAAA,MAC1C,OAAO,OAAO;AAAA,MACd;AAAA,MACA,aAAa,cAAc,eAAe;AAAA,MAC1C,gBAAgB,QAAQ,cAAc,WAAW;AAAA,MACjD,UAAU;AAAA,MACV,eAAe,SAAS,iBAAiB;AAAA,MACzC,WAAW,SAAS,aAAa;AAAA,MACjC,aAAa;AAAA,MACb,SAAS,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,MAChE,cAAc,cAAc,UAAU;AAAA,IACvC,CAAC;AACD,UAAM,aAAa;AACnB,UAAM,cAAc;AACpB,UAAM,OAAO,KAAK;AAAA,MACjB;AAAA,MACA,KAAK,MAAM,OAAO,WAAW,OAAO,aAAa,cAAc,CAAC;AAAA,IACjE;AACA,UAAM,MAAM,KAAK;AAAA,MAChB;AAAA,MACA,KAAK,MAAM,OAAO,WAAW,OAAO,cAAc,eAAe,CAAC;AAAA,IACnE;AACA,UAAM,WAAW;AAAA,MAChB;AAAA,MACA,SAAS,UAAU;AAAA,MACnB,UAAU,WAAW;AAAA,MACrB,QAAQ,IAAI;AAAA,MACZ,OAAO,GAAG;AAAA,MACV;AAAA,MACA;AAAA,IACD,EAAE,KAAK,GAAG;AAEV,UAAM,YAAY,oBAAoB,aAAa;AACnD,UAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,QAAQ;AACvD,QAAI,CAAC,OAAO;AACX,mBAAa,8BAA8B;AAC3C,eAAS,UAAU,yBAAyB;AAC5C;AAAA,IACD;AAEA,SAAK,QAAQ;AACb,SAAK,YAAY;AACjB,SAAK,uBAAuB,eAAe,OAAO;AAElD,UAAM,gBAAgB,SAAS;AAC/B,UAAM,cAAc,UAAU,QAAQ;AAEtC,SAAK,sBAAsB,CAAC,UAAwB;AACnD,UACC,iBACA,kBAAkB,OAClB,MAAM,WAAW,eAChB;AACD,qBAAa,iDAAiD;AAAA,UAC7D;AAAA,UACA,aAAa,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACD;AACA,UAAI,CAAC,iBAAiB,eAAe,MAAM,WAAW,aAAa;AAClE,qBAAa,gDAAgD;AAAA,UAC5D,gBAAgB;AAAA,UAChB,aAAa,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACD;AAEA,YAAM,OAAO,MAAM;AACnB,UAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,MAAM;AACpD,sBAAc,uCAAuC;AACrD;AAAA,MACD;AAEA,mBAAa,wBAAwB;AAAA,QACpC,MAAM,KAAK;AAAA,QACX,aAAa,MAAM;AAAA,MACpB,CAAC;AAED,WAAK,iBAAiB,MAAM,OAAO;AAAA,IACpC;AAEA,WAAO,iBAAiB,WAAW,KAAK,mBAAmB;AAE3D,QAAI,SAAS,uBAAuB,MAAM;AACzC,WAAK,eAAe,OAAO,YAAY,MAAM;AAC5C,YAAI,CAAC,KAAK,SAAS,kBAAkB,KAAK,KAAK,GAAG;AACjD,gBAAM,sBAAsB,CAAC,KAAK;AAClC,uBAAa,yBAAyB;AAAA,YACrC;AAAA,UACD,CAAC;AACD,eAAK,QAAQ;AACb,cAAI,qBAAqB;AACxB,qBAAS,WAAW;AAAA,UACrB;AACA,mBAAS,UAAU;AAAA,QACpB;AAAA,MACD,GAAG,GAAG;AAAA,IACP;AAAA,EACD;AAAA,EAEA,UAAU,QAAqB,SAA0B;AACxD,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,cAAc,SAAS,eAAe;AAC5C,QAAI,gBAAgB,YAAY;AAC/B,WAAK,kBAAkB,QAAQ,OAAO;AACtC;AAAA,IACD;AACA,QAAI,gBAAgB,SAAS;AAC5B,WAAK,eAAe,QAAQ,OAAO;AACnC;AAAA,IACD;AACA,QACC,gBAAgB,UAChB,uBAAuB,EAAE,wBACxB;AACD,WAAK,kBAAkB,QAAQ,OAAO;AACtC;AAAA,IACD;AACA,SAAK,eAAe,QAAQ,OAAO;AAAA,EACpC;AACD;AAEO,SAAS,gBAAyB;AACxC,SAAO,IAAI,QAAQ;AACpB;AAEA,6BAA6B,EAAE,WAAW,MAAM,CAAC;;;ACpyCjD,IAAM,yCAAyC;AAC/C,IAAM,wBAAwB;AAgB9B,SAAS,SAAS,OAAe;AAChC,QAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,MAAM,EAAE;AAChD,MAAI,CAAC,+BAA+B,KAAK,UAAU,EAAG,QAAO;AAC7D,QAAM,MACL,WAAW,WAAW,IACnB,WACC,MAAM,EAAE,EACR,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,IAAI,EAAE,EAC9B,KAAK,EAAE,IACR;AACJ,QAAM,SAAS,OAAO,SAAS,KAAK,EAAE;AACtC,SAAO;AAAA,IACN,GAAG,SAAS;AAAA,IACZ,GAAI,UAAU,IAAK;AAAA,IACnB,GAAI,UAAU,KAAM;AAAA,EACrB;AACD;AAEA,SAAS,WAAW,OAAe,OAAe;AACjD,QAAM,MAAM,SAAS,KAAK;AAC1B,MAAI,CAAC;AACJ,WAAO,sBAAsB,KAAK,IAAI,KAAK,MAAM,QAAQ,GAAG,CAAC;AAC9D,SAAO,QAAQ,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK;AAChD;AAEA,SAAS,oBAAoB,SAAkD;AAC9E,QAAM,UAAU,SAAS,OAAO,WAAW;AAC3C,QAAM,YACL,SAAS,OAAO,aAAa;AAC9B,QAAM,aAAa,SAAS,OAAO,cAAc;AACjD,QAAM,QAAQ,SAAS,OAAO,SAAS;AACvC,QAAM,UAAU,SAAS,OAAO,WAAW;AAE3C,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,WAAW,SAAS,GAAG;AAAA,IAClC,WAAW,WAAW,SAAS,IAAI;AAAA,IACnC,WAAW,WAAW,SAAS,GAAG;AAAA,IAClC,WAAW,WAAW,SAAS,IAAI;AAAA,IACnC,WAAW,WAAW,SAAS,IAAI;AAAA,IACnC,WAAW,WAAW,SAAS,IAAI;AAAA,IACnC;AAAA,IACA;AAAA,EACD;AACD;AAEA,SAAS,eAAe,SAAiB,SAAmC;AAC3E,MAAI,OAAO,YAAY,YAAa;AACpC,UAAQ,KAAK,uBAAuB,SAAS,WAAW,CAAC,CAAC;AAC3D;AAEA,SAAS,eAAe,SAAiB,SAAmC;AAC3E,MAAI,OAAO,YAAY,YAAa;AACpC,UAAQ,KAAK,uBAAuB,SAAS,WAAW,CAAC,CAAC;AAC3D;AAEA,SAAS,8BAA8B,SAA4B;AAClE,QAAM,UAAU,SAAS;AACzB,MAAI,OAAO,YAAY,YAAY,CAAC,OAAO,SAAS,OAAO,GAAG;AAC7D,WAAO;AAAA,EACR;AACA,SAAO,KAAK,IAAI,GAAG,OAAO;AAC3B;AAEA,SAAS,uBAAuB,QAAiB;AAChD,SAAO,QAAQ,YAAY,EAAE,WAAW,IAAI,KAAK;AAClD;AAEA,SAAS,uBAAuB,SAA4B;AAC3D,QAAM,YAAY,uBAAuB,SAAS,MAAM;AACxD,SAAO;AAAA,IACN,YACC,SAAS,uBACR,YAAY,+CAAY;AAAA,IAC1B,aAAa,YACV,6NACA;AAAA,IACH,WACC,SAAS,sBAAsB,YAAY,6BAAS;AAAA,IACrD,OAAO,YAAY,qDAAa;AAAA,EACjC;AACD;AAEA,SAAS,oBAAoB,SAA4B;AACxD,QAAM,YAAY,uBAAuB,SAAS,MAAM;AACxD,SAAO;AAAA,IACN,UAAU,YAAY,OAAO;AAAA,IAC7B,MAAM,YAAY,uBAAQ;AAAA,IAC1B,UAAU,YAAY,+CAAY;AAAA,EACnC;AACD;AAEA,SAAS,2BAA2B,SAA4B;AAC/D,QAAM,YAAY,uBAAuB,SAAS,MAAM;AACxD,SAAO;AAAA,IACN,UAAU,YAAY,OAAO;AAAA,IAC7B,MAAM,YAAY,uBAAQ;AAAA,IAC1B,UAAU,YAAY,+CAAY;AAAA,EACnC;AACD;AAEA,SAAS,sBAAsB,SAA4B;AAC1D,QAAM,YAAY,uBAAuB,SAAS,MAAM;AACxD,SACC,SAAS,gBACT,SAAS,uBACR,YAAY,0BAAW;AAE1B;AAEA,SAAS,uBACR,OACA,OACC;AACD,SAAO,OAAO,MAAM,OAAO;AAAA,IAC1B,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,YAAY,2BAA2B,MAAM,OAAO;AAAA,IACpD,OAAO,MAAM;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,gBAAgB;AAAA,EACjB,CAAC;AACF;AAEA,SAAS,kBAAkB,MAAuC;AACjE,QAAM,MAAM,SAAS,gBAAgB,8BAA8B,KAAK;AACxE,MAAI,aAAa,WAAW,WAAW;AACvC,MAAI,aAAa,QAAQ,MAAM;AAC/B,MAAI,aAAa,eAAe,MAAM;AACtC,SAAO,OAAO,IAAI,OAAO;AAAA,IACxB,SAAS;AAAA,IACT,MAAM;AAAA,EACP,CAAC;AAED,QAAM,QACL,SAAS,aACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IACC,SAAS,YACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IACC,CAAC,kBAAkB,uCAAuC;AAE/D,aAAW,SAAS,OAAO;AAC1B,UAAM,OAAO,SAAS,gBAAgB,8BAA8B,MAAM;AAC1E,SAAK,aAAa,KAAK,KAAK;AAC5B,SAAK,aAAa,UAAU,cAAc;AAC1C,SAAK,aAAa,gBAAgB,GAAG;AACrC,SAAK,aAAa,kBAAkB,OAAO;AAC3C,SAAK,aAAa,mBAAmB,OAAO;AAC5C,QAAI,YAAY,IAAI;AAAA,EACrB;AAEA,SAAO;AACR;AAEA,SAAS,6BAA6B,OAA6B;AAClE,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,OAAO;AAAA,EACR,CAAC;AAED,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY,sCAAsC,MAAM,SAAS,KAAK,MAAM,SAAS;AAAA,IACrF,QAAQ;AAAA,IACR,WAAW;AAAA,EACZ,CAAC;AAED,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY,2BAA2B,MAAM,SAAS,KAAK,MAAM,SAAS;AAAA,IAC1E,WAAW,eAAe,MAAM,SAAS;AAAA,IACzC,WAAW;AAAA,EACZ,CAAC;AAED,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,KAAK;AAAA,IACL,WAAW;AAAA,IACX,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY,2BAA2B,MAAM,OAAO,KAAK,MAAM,SAAS;AAAA,IACxE,QAAQ,aAAa,MAAM,SAAS;AAAA,IACpC,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,WAAW,eAAe,MAAM,SAAS;AAAA,EAC1C,CAAC;AACD,QAAM,OAAO,kBAAkB,MAAM;AACrC,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,EACZ,CAAC;AACD,OAAK,YAAY,IAAI;AAErB,UAAQ,YAAY,IAAI;AACxB,UAAQ,YAAY,IAAI;AACxB,UAAQ,YAAY,IAAI;AACxB,SAAO;AACR;AAEA,SAAS,0BACR,SACA,OACC;AACD,QAAM,QAAQ,2BAA2B,OAAO;AAChD,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,EACT,CAAC;AAED,UAAQ;AAAA,IACP,mBAAmB;AAAA,MAClB,UAAU;AAAA,MACV;AAAA,MACA,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,KAAK;AAAA,MACL,iBAAiB;AAAA,MACjB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,mBAAmB;AAAA,MACnB,cAAc;AAAA,MACd,gBAAgB;AAAA,MAChB;AAAA,MACA,SAAS;AAAA,IACV,CAAC;AAAA,EACF;AACA,SAAO;AACR;AAEA,SAAS,0BACR,SACA,OACC;AACD,QAAM,QAAQ,oBAAoB,OAAO;AACzC,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,EACT,CAAC;AACD,UAAQ;AAAA,IACP,mBAAmB;AAAA,MAClB;AAAA,MACA,UAAU;AAAA,MACV,UAAU,MAAM,aAAa,OAAO,KAAK;AAAA,MACzC,cAAc,MAAM,aAAa,OAAO,IAAI;AAAA,MAC5C;AAAA,IACD,CAAC;AAAA,EACF;AACA,SAAO;AACR;AAEA,SAAS,4BAA4B;AACpC,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,OAAO;AAAA,EACR,CAAC;AAED,SAAO;AACR;AAEA,SAAS,wBAAwB,OAAe,OAA8B;AAC7E,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO;AAAA,IAC1B,OAAO,OAAO,cAAc;AAAA,IAC5B,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,cAAc;AAAA,EACf,CAAC;AACD,SAAO;AACR;AAEA,SAAS,8BACR,OACA,OACC;AACD,QAAM,cAAc,SAAS,cAAc,KAAK;AAChD,cAAY,cAAc;AAC1B,SAAO,OAAO,YAAY,OAAO;AAAA,IAChC,OAAO,OAAO,SAAS;AAAA,IACvB,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,UAAU;AAAA,EACX,CAAC;AACD,SAAO;AACR;AAEA,SAAS,gCACR,OACA,OACC;AACD,QAAM,cAAc,SAAS,cAAc,KAAK;AAChD,cAAY,cAAc;AAC1B,SAAO,OAAO,YAAY,OAAO;AAAA,IAChC,OAAO,OAAO,SAAS;AAAA,IACvB,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,UAAU;AAAA,EACX,CAAC;AACD,SAAO;AACR;AAEA,SAAS,6BAA6B,SAInC;AACF,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,QAAQ;AAAA,IACR,WAAW;AAAA,EACZ,CAAC;AACD,UAAQ,YAAY,6BAA6B,QAAQ,KAAK,CAAC;AAC/D,UAAQ,YAAY,wBAAwB,QAAQ,OAAO,QAAQ,KAAK,CAAC;AACzE,UAAQ;AAAA,IACP,8BAA8B,QAAQ,aAAa,QAAQ,KAAK;AAAA,EACjE;AACA,SAAO;AACR;AAEA,SAAS,0BAA0B,SAA4B;AAC9D,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,QAAQ,oBAAoB,OAAO;AACzC,yBAAuB,OAAO,KAAK;AAEnC,QAAM,UAAU,0BAA0B;AAC1C,UAAQ,YAAY,0BAA0B,SAAS,KAAK,CAAC;AAC7D,UAAQ;AAAA,IACP,gCAAgC,sBAAsB,OAAO,GAAG,KAAK;AAAA,EACtE;AACA,QAAM,YAAY,OAAO;AACzB,SAAO;AACR;AAEA,SAAS,oBACR,OACA,SAKC;AACD,QAAM,UAAU,SAAS,WAAW;AACpC,QAAM,QAAQ,SAAS,SAAS,oBAAoB;AACpD,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,OAAO;AACd,SAAO,OAAO,OAAO,OAAO;AAAA,IAC3B,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,QAAQ,UACL,aAAa,MAAM,OAAO,KAC1B,aAAa,MAAM,SAAS;AAAA,IAC/B,YAAY,UACT,2BAA2B,MAAM,OAAO,KAAK,MAAM,SAAS,MAC5D;AAAA,IACH,OAAO,UAAU,YAAY,MAAM;AAAA,IACnC,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,KAAK;AAAA,IACL,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW,UAAU,SAAS;AAAA,IAC9B,WAAW,UAAU,eAAe,MAAM,SAAS,KAAK;AAAA,EACzD,CAAC;AACD,MAAI,SAAS,MAAM;AAClB,UAAM,OAAO,kBAAkB,QAAQ,IAAI;AAC3C,WAAO,OAAO,KAAK,OAAO;AAAA,MACzB,OAAO;AAAA,MACP,QAAQ;AAAA,IACT,CAAC;AACD,WAAO,YAAY,IAAI;AAAA,EACxB;AACA,QAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,QAAM,cAAc;AACpB,SAAO,YAAY,KAAK;AACxB,SAAO;AACR;AAEA,SAAS,2BAA2B,SAQjC;AACF,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,QAAQ,oBAAoB,QAAQ,cAAc;AACxD,yBAAuB,OAAO,KAAK;AAEnC,QAAM,UAAU,0BAA0B;AAC1C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,gBAAgB;AAAA,EACjB,CAAC;AAED,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAO,OAAO,KAAK,OAAO;AAAA,IACzB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,OAAO;AAAA,EACR,CAAC;AACD,OAAK;AAAA,IACJ,6BAA6B;AAAA,MAC5B,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA,OAAO,QAAQ;AAAA,IAChB,CAAC;AAAA,EACF;AAEA,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC5B,WAAW;AAAA,IACX,OAAO;AAAA,EACR,CAAC;AAED,QAAM,cAAc,oBAAoB,QAAQ,WAAW;AAAA,IAC1D,MAAM;AAAA,IACN;AAAA,EACD,CAAC;AACD,cAAY,UAAU,QAAQ;AAC9B,UAAQ,YAAY,WAAW;AAE/B,QAAM,aAAa,oBAAoB,QAAQ,YAAY;AAAA,IAC1D,MAAM;AAAA,IACN,SAAS;AAAA,IACT;AAAA,EACD,CAAC;AACD,aAAW,UAAU,QAAQ;AAC7B,UAAQ,YAAY,UAAU;AAE9B,OAAK,YAAY,OAAO;AACxB,UAAQ,YAAY,IAAI;AACxB,UAAQ,YAAY,0BAA0B,QAAQ,gBAAgB,KAAK,CAAC;AAC5E,QAAM,YAAY,OAAO;AACzB,SAAO;AACR;AAuDO,IAAM,YAAN,cAAwB,iBAAmC;AAAA,EAA3D;AAAA;AACN,wBAAQ,uBAAqC;AAC7C,wBAAQ,yBAAuC;AAC/C,wBAAQ,iBAA+B;AACvC,wBAAQ,oBAAmB;AAC3B,wBAAQ,0BAAwC;AAChD,wBAAQ,uBAA6C;AACrD,wBAAQ,sBAA4C;AACpD,wBAAQ,mBAAiC;AACzC,wBAAQ,eAAc;AAAA;AAAA,EAEd,2BAA2B;AAClC,QAAI,OAAO,WAAW,eAAe,KAAK,iBAAiB;AAC1D,aAAO,aAAa,KAAK,eAAe;AAAA,IACzC;AACA,QAAI,KAAK,qBAAqB,YAAY;AACzC,WAAK,oBAAoB,WAAW,YAAY,KAAK,mBAAmB;AAAA,IACzE;AACA,QAAI,KAAK,oBAAoB,YAAY;AACxC,WAAK,mBAAmB,WAAW,YAAY,KAAK,kBAAkB;AAAA,IACvE;AACA,SAAK,sBAAsB;AAC3B,SAAK,qBAAqB;AAC1B,SAAK,kBAAkB;AACvB,SAAK,cAAc;AAAA,EACpB;AAAA,EAEQ,yBAAyB;AAChC,QAAI,KAAK,YAAa;AACtB,SAAK,cAAc;AACnB,QAAI,OAAO,WAAW,eAAe,KAAK,iBAAiB;AAC1D,aAAO,aAAa,KAAK,eAAe;AACxC,WAAK,kBAAkB;AAAA,IACxB;AACA,QAAI,KAAK,qBAAqB,YAAY;AACzC,WAAK,oBAAoB,WAAW,YAAY,KAAK,mBAAmB;AAAA,IACzE;AACA,QAAI,KAAK,oBAAoB,YAAY;AACxC,WAAK,mBAAmB,WAAW,YAAY,KAAK,kBAAkB;AAAA,IACvE;AACA,SAAK,sBAAsB;AAC3B,SAAK,qBAAqB;AAAA,EAC3B;AAAA,EAEQ,yBACP,WACA,SACC;AACD,QAAI,KAAK,sBAAsB,KAAK,YAAa;AAEjD,UAAM,QAAQ,0BAA0B,OAAO;AAC/C,SAAK,qBAAqB;AAC1B,cAAU,YAAY,KAAK;AAAA,EAC5B;AAAA,EAEQ,wBACP,UACA,SACC;AACD,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,QAAQ,OAAO;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,QAAI,OAAO;AACV,qBAAe,wCAAwC;AAAA,QACtD,aAAa;AAAA,MACd,CAAC;AACD,eAAS,iBAAiB,QAAQ;AAClC,UAAI;AACH,cAAM,MAAM;AAAA,MACb,QAAQ;AAAA,MAER;AACA;AAAA,IACD;AAEA,mBAAe,8CAA8C;AAAA,MAC5D,aAAa;AAAA,IACd,CAAC;AACD,aAAS,oBAAoB,QAAQ;AACrC,WAAO,SAAS,OAAO,QAAQ;AAAA,EAChC;AAAA,EAEQ,0BAA0B,SAI/B;AACF,QAAI,KAAK,eAAe,KAAK,oBAAqB;AAElD,UAAM,EAAE,WAAW,UAAU,eAAe,IAAI;AAChD,mBAAe,uDAAuD;AAAA,MACrE,aAAa;AAAA,IACd,CAAC;AACD,QAAI,KAAK,oBAAoB,YAAY;AACxC,WAAK,mBAAmB,WAAW,YAAY,KAAK,kBAAkB;AAAA,IACvE;AACA,SAAK,qBAAqB;AAE1B,UAAM,eAAe,uBAAuB,cAAc;AAC1D,UAAM,QAAQ,2BAA2B;AAAA,MACxC,YAAY,aAAa;AAAA,MACzB,aAAa,aAAa;AAAA,MAC1B,QAAQ,MAAM;AACb,aAAK,wBAAwB,UAAU,cAAc;AAAA,MACtD;AAAA,MACA,SAAS,MAAM;AACd,aAAK,sBAAsB;AAC3B,YAAI,MAAM,YAAY;AACrB,gBAAM,WAAW,YAAY,KAAK;AAAA,QACnC;AACA,aAAK,cAAc;AACnB,aAAK,yBAAyB,WAAW,cAAc;AACvD,YAAI,KAAK,QAAQ;AAChB,eAAK,OAAO,MAAM;AAAA,QACnB;AACA,aAAK,2BAA2B;AAAA,UAC/B;AAAA,UACA;AAAA,UACA;AAAA,QACD,CAAC;AAAA,MACF;AAAA,MACA;AAAA,MACA,WAAW,aAAa;AAAA,MACxB,OAAO,aAAa;AAAA,IACrB,CAAC;AAED,SAAK,sBAAsB;AAC3B,cAAU,YAAY,KAAK;AAC3B,oBAAgB,oBAAoB;AAAA,EACrC;AAAA,EAEQ,2BAA2B,SAIhC;AACF,QAAI,OAAO,WAAW,YAAa;AAEnC,QAAI,KAAK,iBAAiB;AACzB,aAAO,aAAa,KAAK,eAAe;AAAA,IACzC;AACA,UAAM,YAAY,8BAA8B,QAAQ,cAAc;AACtE,QAAI,cAAc,GAAG;AACpB,WAAK,0BAA0B,OAAO;AACtC;AAAA,IACD;AAEA,SAAK,kBAAkB,OAAO,WAAW,MAAM;AAC9C,WAAK,kBAAkB;AACvB,WAAK,0BAA0B,OAAO;AAAA,IACvC,GAAG,SAAS;AAAA,EACb;AAAA,EAEQ,kBAAkB,SAAS,eAAe,SAAkB;AACnE,UAAM,gBAAgB,WAAW,KAAK;AACtC,QACC,CAAC,iBACD,CAAC,KAAK,uBACN,CAAC,KAAK,yBACN,KAAK,oBACL,KAAK,2BAA2B,eAC/B;AACD;AAAA,IACD;AAEA,SAAK,yBAAyB;AAC9B,UAAM,MAAM,GAAG,KAAK,qBAAqB;AACzC,UAAM,UAAU,KAAK,UAAU;AAAA,MAC9B,OAAO,KAAK;AAAA,MACZ,SAAS;AAAA,MACT;AAAA,IACD,CAAC;AAED,QAAI,OAAO,cAAc,eAAe,UAAU,YAAY;AAC7D,YAAM,OAAO,UAAU;AAAA,QACtB;AAAA,QACA,IAAI,KAAK,CAAC,OAAO,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAAA,MACjD;AACA,UAAI,KAAM;AAAA,IACX;AAEA,SAAK,MAAM,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS,EAAE,gBAAgB,2BAA2B;AAAA,MACtD,WAAW;AAAA,MACX,MAAM;AAAA,IACP,CAAC,EAAE,MAAM,MAAM;AACd,WAAK,yBAAyB;AAAA,IAC/B,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,aAAqC,SAA4B;AAC5E,QAAI,OAAO,aAAa,YAAa;AACrC,QAAI,KAAK,MAAO;AAEhB,QAAI;AACJ,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AACxB,SAAK,yBAAyB;AAC9B,SAAK,yBAAyB;AAC9B,QAAI,OAAO,gBAAgB,UAAU;AACpC,oBAAc;AACd,UAAI;AACH,cAAM,YAAY,IAAI,IAAI,WAAW;AACrC,aAAK,wBAAwB,UAAU;AACvC,cAAM,QAAQ,UAAU,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAC1D,cAAM,gBAAgB,MAAM,QAAQ,UAAU;AAC9C,aAAK,sBACJ,iBAAiB,IAAI,MAAM,gBAAgB,CAAC,KAAK,OAAO;AAAA,MAC1D,QAAQ;AACP,aAAK,sBAAsB;AAC3B,aAAK,wBAAwB;AAAA,MAC9B;AAAA,IACD,OAAO;AACN,YAAM;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa;AAAA,QACb,UAAU;AAAA,MACX,IAAI;AAGJ,YAAM,QAAQ,oBAAoB,SAAS,QAAQ,OAAO,EAAE;AAC5D,WAAK,sBAAsB;AAC3B,WAAK,wBAAwB;AAE7B,YAAM,QAAQ,IAAI,gBAAgB;AAClC,UAAI,OAAQ,OAAM,IAAI,UAAU,MAAM;AACtC,UAAI,cAAc;AACjB,cAAM,SAAS,OAAO,aAAa,MAAM;AACzC,cAAM,WAAW,aAAa,SAAS,KAAK,EAAE,YAAY;AAC1D,YAAI,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GAAG;AAC7C,gBAAM,IAAI;AAAA,YACT;AAAA,UACD;AAAA,QACD;AACA,YAAI,CAAC,aAAa,KAAK,QAAQ,GAAG;AACjC,gBAAM,IAAI;AAAA,YACT;AAAA,UACD;AAAA,QACD;AACA,cAAM,IAAI,gBAAgB,OAAO,MAAM,CAAC;AACxC,cAAM,IAAI,kBAAkB,QAAQ;AAAA,MACrC;AAEA,UAAI,SAAS;AACZ,cAAM,eAAe,QAAQ,KAAK;AAClC,YAAI,CAAC,cAAc;AAClB,gBAAM,IAAI,MAAM,qBAAqB;AAAA,QACtC;AACA,aAAK,gBAAgB;AACrB,sBAAc,GAAG,IAAI,aAAa,KAAK,WAAW,YAAY;AAC9D,cAAM,cAAc,MAAM,SAAS;AACnC,YAAI,YAAa,gBAAe,IAAI,WAAW;AAAA,MAChD,WAAW,aAAa;AAEvB,sBAAc,GAAG,IAAI,aAAa,KAAK,SAAS,WAAW,IAAI,MAAM,SAAS,CAAC;AAAA,MAChF,WAAW,aAAa,SAAS;AAEhC,sBAAc,GAAG,IAAI,aAAa,KAAK,IAAI,SAAS,IAAI,OAAO,IAAI,MAAM,SAAS,CAAC;AAAA,MACpF,OAAO;AACN,cAAM,IAAI;AAAA,UACT;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,UAAM,WAAW;AAAA,MAChB;AAAA,MACA,sBAAsB,SAAS,MAAM;AAAA,IACtC;AAEA,UAAM,cAAc,KAAK,gBAAgB,UAAU;AAAA,MAClD,eAAe,SAAS;AAAA,MACxB,QAAQ;AAAA,MACR,eAAe,MAAM;AACpB,aAAK,kBAAkB,aAAa;AACpC,iBAAS,WAAW,KAAK,iBAAiB,MAAS;AAAA,MACpD;AAAA,MACA,WAAW,CAAC,MAAM,WAAW,UAAU;AACtC,cAAM,kBAAkB,MAAM,WAAW,KAAK,QAAQ;AACtD,YACC,oBACC,KAAK,SAAS,mBACd,KAAK,SAAS,oBACd,KAAK,SAAS,oBACd;AACD,eAAK,uBAAuB;AAAA,QAC7B;AACA,gBAAQ,KAAK,MAAM;AAAA,UAClB,KAAK;AACJ;AAAA,UACD,KAAK;AACJ,gBAAI,KAAK,SAAS;AACjB,mBAAK,gBAAgB,KAAK;AAAA,YAC3B;AACA;AAAA,UACD,KAAK;AACJ,iBAAK,mBAAmB;AACxB,qBAAS,YAAY,KAAK,OAAO;AACjC;AAAA,UACD,KAAK;AACJ,iBAAK,kBAAkB,qBAAqB,KAAK,OAAO;AACxD,qBAAS,WAAW,KAAK,OAAO;AAChC;AAAA,UACD,KAAK;AACJ;AAAA,UACD,KAAK;AACJ,iBAAK,kBAAkB,iBAAiB,KAAK,OAAO;AACpD,iBAAK,MAAM;AACX,qBAAS,UAAU;AACnB;AAAA,QACF;AAAA,MACD;AAAA,MACA,OAAO;AAAA,IACR,CAAC;AAED,QAAI,aAAa;AAChB,WAAK,yBAAyB,YAAY,WAAW,OAAO;AAC5D,WAAK,2BAA2B;AAAA,QAC/B,WAAW,YAAY;AAAA,QACvB;AAAA,QACA,gBAAgB;AAAA,MACjB,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,QAAQ;AACP,UAAM,MAAM;AACZ,SAAK,yBAAyB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,gBACL,WACA,SACuB;AACvB,UAAM,WAAW,SAAS,YAAY;AACtC,UAAM,UAAU,SAAS,WAAW;AACpC,UAAM,YAAY,KAAK,IAAI;AAE3B,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,YAAM,OAAO,YAAY;AACxB,YAAI;AACH,gBAAM,WAAW,MAAM,MAAM,SAAS;AACtC,cAAI,CAAC,SAAS,IAAI;AACjB,kBAAM,IAAI,MAAM,wBAAwB,SAAS,MAAM,EAAE;AAAA,UAC1D;AAEA,gBAAM,SAAsB,MAAM,SAAS,KAAK;AAChD,mBAAS,iBAAiB,MAAM;AAEhC,cAAI,OAAO,WAAW,QAAQ;AAC7B,oBAAQ,MAAM;AACd;AAAA,UACD;AAEA,cAAI,OAAO,WAAW,eAAe,OAAO,WAAW,UAAU;AAChE,mBAAO,IAAI,MAAM,SAAS,OAAO,OAAO,YAAY,CAAC,EAAE,CAAC;AACxD;AAAA,UACD;AAGA,cAAI,KAAK,IAAI,IAAI,YAAY,SAAS;AACrC,mBAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC;AAAA,UACD;AAGA,qBAAW,MAAM,QAAQ;AAAA,QAC1B,SAAS,OAAO;AAEf,cAAI,KAAK,IAAI,IAAI,YAAY,SAAS;AACrC,mBAAO,KAAK;AACZ;AAAA,UACD;AACA,qBAAW,MAAM,QAAQ;AAAA,QAC1B;AAAA,MACD;AAEA,WAAK;AAAA,IACN,CAAC;AAAA,EACF;AACD;AAQO,IAAM,YAAN,MAAgB;AAAA,EACtB,kBAAkB,SAAwC;AACzD,UAAM,aAAa,QAAQ,YAAY,KAAK;AAC5C,QAAI,CAAC,YAAY;AAChB,YAAM,IAAI,MAAM,wBAAwB;AAAA,IACzC;AACA,QAAI,QAAQ,gBAAgB,SAAS;AACpC,YAAM,QAAQ,OAAO;AAAA,QACpB;AAAA,QACA,QAAQ,aAAa;AAAA,QACrB;AAAA,MACD;AACA,UAAI,CAAC,OAAO;AACX,eAAO,SAAS,OAAO;AAAA,MACxB;AACA;AAAA,IACD;AACA,WAAO,SAAS,OAAO;AAAA,EACxB;AACD;AAEO,SAAS,kBAAkB;AACjC,SAAO,IAAI,UAAU;AACtB;AAKO,SAAS,kBAA6B;AAC5C,SAAO,IAAI,UAAU;AACtB;;;AClgCA,IAAM,qBAA+C;AAAA,EACpD,EAAE,OAAO,OAAO,OAAO,2BAAO;AAAA,EAC9B,EAAE,OAAO,WAAW,OAAO,2BAAO;AAAA,EAClC,EAAE,OAAO,SAAS,OAAO,2BAAO;AAAA,EAChC,EAAE,OAAO,cAAc,OAAO,2BAAO;AAAA,EACrC,EAAE,OAAO,SAAS,OAAO,eAAK;AAC/B;AAEA,IAAM,WAAW;AACjB,IAAM,yBAAyB;AAC/B,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAC/B,IAAM,4BAA4B;AAClC,IAAM,gBAAgB;AACtB,IAAM,WAAW;AACjB,IAAM,YAAY;AAClB,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,eAAe;AAErB,SAAS,cAAc;AACtB,MAAI,OAAO,aAAa,YAAa;AACrC,MAAI,SAAS,eAAe,QAAQ,EAAG;AACvC,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,KAAK;AACX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsFpB,WAAS,KAAK,YAAY,KAAK;AAChC;AAEA,SAAS,WAAW,SAAgC;AACnD,UAAQ,QAAQ,cAAc,0BAA0B,QAAQ,OAAO,EAAE;AAC1E;AAEA,SAAS,SAAS,OAAgB;AACjC,MAAI;AACH,WAAO,KAAK,UAAU,KAAK;AAAA,EAC5B,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,WAAW,OAAe;AAClC,SAAO,MACL,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,OAAO;AACxB;AAEA,SAAS,kBAAkB,OAAuB;AACjD,SAAO,OAAO,gBAAgB,OAAO,gBAAgB;AACtD;AAEA,SAAS,oBACR,OACA,aAAuC,oBACtC;AACD,QAAM,UAAU,WAAW,KAAK,CAAC,SAAS,KAAK,UAAU,KAAK;AAC9D,SAAO,SAAS,SAAS,SAAS,mBAAmB,CAAC,GAAG,SAAS;AACnE;AAEA,SAAS,mBAAmB,OAAgB;AAC3C,QAAM,YAAoC;AAAA,IACzC,MAAM;AAAA,IACN,eAAe;AAAA,IACf,cAAc;AAAA,IACd,UAAU;AAAA,IACV,QAAQ;AAAA,EACT;AACA,SAAO,UAAU,SAAS,EAAE,KAAK,SAAS;AAC3C;AAEA,SAAS,iBAAiB,OAAe;AACxC,MAAI,UAAU,WAAY,QAAO;AACjC,MAAI,UAAU,QAAS,QAAO;AAC9B,SAAO;AACR;AAEA,SAAS,iBAAiB,OAAgB;AACzC,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,IAAI,KAAK,KAAK,EAAE,eAAe;AACvC;AAEA,eAAe,YAAe,KAAa,MAAgC;AAC1E,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IACjC,GAAG;AAAA,IACH,SAAS;AAAA,MACR,QAAQ;AAAA,MACR,GAAI,MAAM,OAAO,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,MAC3D,GAAI,MAAM,WAAW,CAAC;AAAA,IACvB;AAAA,EACD,CAAC;AACD,QAAM,UAAU,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,IAAI;AACtD,MAAI,CAAC,SAAS,MAAM,SAAS,SAAS,KAAK;AAC1C,UAAM,IAAI,MAAM,SAAS,WAAW,SAAS,cAAc,gBAAgB;AAAA,EAC5E;AACA,SAAO,QAAQ;AAChB;AAEA,SAAS,gBAAgB,SAAgC;AACxD,QAAM,OACL,OAAO,WAAW,cACf,CAAC,IACD;AAAA,IACA,SAAS,OAAO,SAAS;AAAA,IACzB,WAAW,SAAS;AAAA,IACpB,WAAW,UAAU;AAAA,EACtB;AACH,SAAO,EAAE,GAAG,MAAM,GAAI,QAAQ,YAAY,CAAC,EAAG;AAC/C;AAEA,eAAe,cAAc,MAA2B;AACvD,MAAI,OAAO,aAAa,eAAe,CAAC,KAAK,KAAK,WAAW,QAAQ,GAAG;AACvE,WAAO;AAAA,EACR;AACA,QAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,QAAM,UAAU;AAChB,QAAM,QAAQ,KAAK,IAAI,GAAG,UAAU,KAAK,IAAI,OAAO,OAAO,OAAO,MAAM,CAAC;AACzE,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,QAAQ,KAAK,CAAC;AAC3D,SAAO,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,SAAS,KAAK,CAAC;AAC7D,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,UAAU,QAAQ,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACvD,QAAM,OAAO,MAAM,IAAI,QAAqB,CAAC,YAAY;AACxD,WAAO,OAAO,SAAS,cAAc,IAAI;AAAA,EAC1C,CAAC;AACD,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK,KAAK,QAAQ,YAAY,OAAO,GAAG;AAAA,IAC/D,MAAM;AAAA,IACN,cAAc,KAAK,IAAI;AAAA,EACxB,CAAC;AACF;AAEO,SAAS,qBACf,WACA,SAC2B;AAC3B,MAAI,OAAO,aAAa,aAAa;AACpC,WAAO,EAAE,OAAO;AAAA,IAAC,GAAG,QAAQ;AAAA,IAAC,GAAG,UAAU;AAAA,IAAC,EAAE;AAAA,EAC9C;AACA,MAAI,CAAC,QAAQ,MAAO,OAAM,IAAI,MAAM,mBAAmB;AACvD,cAAY;AAEZ,MAAI,cAAkC;AACtC,MAAI,YAA2B;AAC/B,MAAI,aAAa;AACjB,MAAI,eAAuB,CAAC;AAC5B,MAAI,mBAAsC,CAAC;AAC3C,MAAI,qBAA0C;AAC9C,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,QAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,WAAS,OAAO;AAChB,WAAS,YAAY;AACrB,WAAS,aAAa,cAAc,QAAQ,gBAAgB,cAAI;AAChE,WAAS,YAAY;AACrB,OAAK,YAAY,QAAQ;AACzB,YAAU,YAAY,IAAI;AAE1B,QAAM,QAAQ,SAAS,cAAc,SAAS;AAC9C,QAAM,YAAY;AAClB,QAAM,aAAa,cAAc,QAAQ,cAAc,mBAAmB;AAC1E,QAAM,YAAY;AAAA;AAAA;AAAA,kCAGe,WAAW,QAAQ,cAAc,mBAAmB,CAAC;AAAA,oCACnD,WAAW,QAAQ,iBAAiB,sBAAsB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4CASnD,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDA2BT,QAAQ;AAAA,kDACN,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uCAOvB,SAAS;AAAA;AAAA,+EAE+B,WAAW,QAAQ,eAAe,8GAAoB,CAAC;AAAA;AAAA,yFAE7C,UAAU;AAAA;AAAA,+DAEpC,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA,uCAKjD,SAAS;AAAA,kEACkB,WAAW,kBAAkB,QAAQ,KAAK,CAAC,CAAC,kBAAkB,WAAW,QAAQ,sBAAsB,4FAAiB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAa1L,WAAS,YAAY;AACpB,QAAI,WAAY;AAChB,iBAAa;AACb,SAAK,YAAY,KAAK;AACtB,UAAM,iBAAiB,MAAM;AAAA,MAC5B;AAAA,IACD;AACA,UAAM,eAAe,MAAM;AAAA,MAC1B;AAAA,IACD;AACA,UAAM,gBAAgB,MAAM;AAAA,MAC3B;AAAA,IACD;AACA,QAAI,gBAAgB,eAAe;AAClC,YAAM,aAAa,QAAQ,cAAc;AACzC,oBAAc,cACb,WAAW,CAAC,GAAG,SAAS,mBAAmB,CAAC,GAAG,SAAS;AACzD,iBAAW,QAAQ,YAAY;AAC9B,cAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,eAAO,OAAO;AACd,eAAO,YAAY;AACnB,eAAO,QAAQ,QAAQ,KAAK;AAC5B,eAAO,QAAQ,WAAW,OAAO,KAAK,UAAU,WAAW,CAAC,GAAG,KAAK;AACpE,eAAO,YAAY,GAAG,QAAQ,SAAS,WAAW,KAAK,KAAK,CAAC;AAC7D,eAAO,iBAAiB,SAAS,MAAM;AACtC,qBAAW,QAAQ,aAAa;AAAA,YAC/B;AAAA,UACD,GAAG;AACF,iBAAK,QAAQ,WAAW,OAAO,SAAS,MAAM;AAAA,UAC/C;AACA,wBAAc,cAAc,KAAK;AACjC,cAAI,gBAAgB;AACnB,2BAAe,QAAQ,QAAQ,KAAK;AACpC,2BAAe,QAAQ,OAAO;AAAA,UAC/B;AAAA,QACD,CAAC;AACD,qBAAa,YAAY,MAAM;AAAA,MAChC;AACA,sBAAgB,aAAa,cAAc,WAAW,CAAC,GAAG,SAAS,KAAK;AAAA,IACzE;AACA,UACE,cAAiC,gCAAgC,GAChE,iBAAiB,SAAS,MAAM;AACjC,UAAI,CAAC,eAAgB;AACrB,qBAAe,QAAQ,OACtB,eAAe,QAAQ,SAAS,SAAS,UAAU;AAAA,IACrD,CAAC;AACF,UACE,cAAiC,oBAAoB,GACpD,iBAAiB,SAAS,KAAK;AAClC,UACE,cAAiC,qBAAqB,GACrD,iBAAiB,SAAS,WAAW;AACxC,UACE,cAAiC,+BAA+B,GAC/D,iBAAiB,SAAS,KAAK;AAClC,UACE,cAAiC,6BAA6B,GAC7D,iBAAiB,SAAS,MAAM;AACjC,YAAM,cAAgC,qBAAqB,GAAG,MAAM;AAAA,IACrE,CAAC;AACF,UACE,cAAgC,qBAAqB,GACpD,iBAAiB,UAAU,CAAC,UAAU;AACvC,sBAAiB,MAAM,OAA4B,KAAK;AAAA,IACzD,CAAC;AACF,UAAM,aAAa,MAAM;AAAA,MACxB;AAAA,IACD;AACA,gBAAY,iBAAiB,YAAY,CAAC,UAAU;AACnD,YAAM,eAAe;AAAA,IACtB,CAAC;AACD,gBAAY,iBAAiB,QAAQ,CAAC,UAAU;AAC/C,YAAM,eAAe;AACrB,sBAAgB,MAAM,cAAc,SAAS,IAAI;AAAA,IAClD,CAAC;AACD,gBAAY,iBAAiB,SAAS,CAAC,UAAU;AAChD,YAAM,QAAQ,MAAM,KAAK,MAAM,eAAe,SAAS,CAAC,CAAC,EAAE;AAAA,QAC1D,CAAC,SAAS,KAAK,KAAK,WAAW,QAAQ;AAAA,MACxC;AACA,UAAI,MAAM,SAAS,GAAG;AACrB,wBAAgB,KAAK;AAAA,MACtB;AAAA,IACD,CAAC;AACD,UACE,cAAiC,sBAAsB,GACtD,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AAAA,EACjD;AAEA,WAAS,gBAAgB,OAAiC;AACzD,mBAAe,MAAM,KAAK,SAAS,CAAC,CAAC,EACnC,OAAO,CAAC,SAAS,KAAK,KAAK,WAAW,QAAQ,CAAC,EAC/C,MAAM,GAAG,sBAAsB;AACjC,UAAM,QAAQ,MAAM,cAA2B,2BAA2B;AAC1E,QAAI,OAAO;AACV,YAAM,cACL,aAAa,SAAS,IACnB,sBAAO,aAAa,MAAM,wBAC1B;AAAA,IACL;AAAA,EACD;AAEA,WAAS,cAAc;AACtB,kBAAc;AACd,mBAAe,CAAC;AAChB,uBAAmB,CAAC;AACpB,mBAAe,CAAC,CAAC;AACjB,qBAAiB;AACjB,aAAS,EAAE;AACX,UAAM,WAAW,MAAM;AAAA,MACtB;AAAA,IACD;AACA,QAAI,SAAU,UAAS,QAAQ;AAC/B,UAAM,YAAY,MAAM;AAAA,MACvB;AAAA,IACD;AACA,QAAI,UAAW,WAAU,QAAQ;AACjC,UAAM,aAAa,MAAM;AAAA,MACxB;AAAA,IACD;AACA,QAAI,WAAY,YAAW,cAAc;AAAA,EAC1C;AAEA,WAAS,mBAAmB;AAC3B,UAAM,OAAO,MAAM,cAA2B,2BAA2B;AACzE,UAAM,QAAQ,MAAM,cAA2B,4BAA4B;AAC3E,QAAI,CAAC,QAAQ,CAAC,MAAO;AACrB,QAAI,CAAC,aAAa;AACjB,WAAK,QAAQ,UAAU;AACvB,YAAM,MAAM,UAAU;AACtB;AAAA,IACD;AACA,SAAK,QAAQ,UAAU;AACvB,UAAM,MAAM,UAAU;AACtB,UAAM,WAAW,KAAK;AAAA,MACrB;AAAA,IACD;AACA,UAAM,SAAS,KAAK;AAAA,MACnB;AAAA,IACD;AACA,UAAM,UAAU,KAAK;AAAA,MACpB;AAAA,IACD;AACA,UAAM,OAAO,KAAK,cAA2B,2BAA2B;AACxE,QAAI,UAAU;AACb,eAAS,cAAc;AAAA,QACtB,YAAY,YAAY,mBAAmB,CAAC,GAAG;AAAA,QAC/C,QAAQ,cAAc;AAAA,MACvB;AAAA,IACD;AACA,QAAI,OAAQ,QAAO,cAAc,mBAAmB,YAAY,MAAM;AACtE,QAAI,QAAS,SAAQ,cAAc,YAAY,kBAAkB;AACjE,QAAI,KAAM,MAAK,cAAc,iBAAiB,YAAY,SAAS;AAAA,EACpE;AAEA,WAAS,SAAS,SAAiB;AAClC,UAAM,OAAO,MAAM,cAA2B,qBAAqB;AACnE,QAAI,KAAM,MAAK,cAAc;AAC7B,QAAI,QAAS,SAAQ,UAAU,IAAI,MAAM,OAAO,CAAC;AAAA,EAClD;AAEA,WAAS,cAAc,OAAgB;AACtC,UAAM,SAAS,MAAM;AAAA,MACpB;AAAA,IACD;AACA,QAAI,OAAQ,QAAO,WAAW;AAAA,EAC/B;AAEA,WAAS,eAAe,UAA6B;AACpD,UAAM,OAAO,MAAM,cAA2B,wBAAwB;AACtE,QAAI,CAAC,KAAM;AACX,uBAAmB;AACnB,SAAK,YAAY;AACjB,eAAW,WAAW,UAAU;AAC/B,YAAM,OAAO,SAAS,cAAc,KAAK;AACzC,WAAK,YAAY;AACjB,WAAK,QAAQ,QAAQ,OAAO,QAAQ,eAAe,UAAU;AAC7D,WAAK,YAAY,yCAAyC,iBAAiB,QAAQ,UAAU,CAAC,SAAM,IAAI,KAAK,QAAQ,SAAS,EAAE,eAAe,CAAC;AAChJ,YAAM,UAAU,KAAK,cAAc,8BAA8B;AACjE,UAAI,SAAS;AACZ,gBAAQ,cACP,QAAQ,eAAe,aACpB,QAAQ,UACR,QAAQ,qBAAqB,QAAQ;AAAA,MAC1C;AACA,WAAK,YAAY,IAAI;AAAA,IACtB;AAAA,EACD;AAEA,WAAS,eAAe,UAA6B;AACpD,UAAM,OAAO,oBAAI,IAA6B;AAC9C,eAAW,WAAW,iBAAkB,MAAK,IAAI,QAAQ,IAAI,OAAO;AACpE,eAAW,WAAW,SAAU,MAAK,IAAI,QAAQ,IAAI,OAAO;AAC5D,mBAAe,MAAM,KAAK,KAAK,OAAO,CAAC,CAAC;AAAA,EACzC;AAEA,iBAAe,aAAa,OAAe;AAC1C,UAAM,WAAW,MAAM,MAAM,GAAG,sBAAsB;AACtD,UAAM,MAAgB,CAAC;AACvB,eAAW,QAAQ,UAAU;AAC5B,YAAM,aAAa,MAAM,cAAc,IAAI;AAC3C,YAAM,OAAO,IAAI,SAAS;AAC1B,WAAK,OAAO,QAAQ,UAAU;AAC9B,UAAI,YAAa,MAAK,OAAO,YAAY,YAAY,QAAQ;AAC7D,YAAM,UAAkC,CAAC;AACzC,UAAI,YAAa,SAAQ,kBAAkB,IAAI,YAAY;AAC3D,YAAM,WAAW,MAAM;AAAA,QACtB,GAAG,WAAW,OAAO,CAAC,oBAAoB,mBAAmB,QAAQ,KAAK,CAAC;AAAA,QAC3E,EAAE,QAAQ,QAAQ,MAAM,QAAQ;AAAA,MACjC;AACA,YAAM,UAAU,MAAM,SAAS,KAAK;AACpC,UAAI,CAAC,SAAS,MAAM,SAAS,SAAS,KAAK;AAC1C,cAAM,IAAI,MAAM,SAAS,WAAW,qBAAqB;AAAA,MAC1D;AACA,UAAI,KAAK,QAAQ,KAAK,SAAS,EAAE;AAAA,IAClC;AACA,WAAO;AAAA,EACR;AAEA,iBAAe,SAAS;AACvB,UAAM,UAAU,MACd,cAAmC,uBAAuB,GACzD,MAAM,KAAK;AACd,QAAI,CAAC,SAAS;AACb,eAAS,kDAAU;AACnB;AAAA,IACD;AACA,kBAAc,IAAI;AAClB,aAAS,EAAE;AACX,QAAI;AACH,YAAM,WACL,MAAM,cAA2B,+BAA+B,GAC7D,QAAQ,SAAS;AACrB,YAAM,UACL,MAAM,cAAgC,uBAAuB,GAAG,SAChE;AACD,YAAM,YAAY,MAAM;AAAA,QACvB;AAAA,MACD;AACA,YAAM,cAAc,MAAM,aAAa,YAAY;AACnD,UAAI,CAAC,aAAa;AACjB,cAAM,SAAS,MAAM;AAAA,UAKpB,GAAG,WAAW,OAAO,CAAC,oBAAoB,mBAAmB,QAAQ,KAAK,CAAC;AAAA,UAC3E;AAAA,YACC,QAAQ;AAAA,YACR,MAAM,SAAS;AAAA,cACd;AAAA,cACA;AAAA,cACA;AAAA,cACA,OAAO;AAAA,gBACN,GAAI,QAAQ,SAAS,CAAC;AAAA,gBACtB,cAAc,QAAQ,SAAS,GAAG,IAC/B,UACA,QAAQ,OAAO;AAAA,gBAClB,cACC,WAAW,CAAC,QAAQ,SAAS,GAAG,IAC7B,UACA,QAAQ,OAAO;AAAA,cACpB;AAAA,cACA,UAAU,gBAAgB,OAAO;AAAA,YAClC,CAAC;AAAA,UACF;AAAA,QACD;AACA,sBAAc;AAAA,UACb,UAAU,OAAO,OAAO;AAAA,UACxB,aAAa,OAAO;AAAA,UACpB,eAAe,OAAO,SAAS;AAAA,UAC/B,QAAQ,OAAO,OAAO;AAAA,UACtB;AAAA,UACA,gBAAgB;AAAA,UAChB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC;AACA,yBAAiB;AACjB,gBAAQ,kBAAkB,OAAO,OAAO,EAAE;AAC1C,gBAAQ,gBAAgB,OAAO,QAAQ,EAAE;AAAA,MAC1C,OAAO;AACN,cAAM,SAAS,MAAM;AAAA,UACpB,GAAG,WAAW,OAAO,CAAC,oBAAoB,mBAAmB,QAAQ,KAAK,CAAC,YAAY,mBAAmB,YAAY,QAAQ,CAAC;AAAA,UAC/H;AAAA,YACC,QAAQ;AAAA,YACR,SAAS,EAAE,oBAAoB,YAAY,YAAY;AAAA,YACvD,MAAM,SAAS;AAAA,cACd;AAAA,cACA;AAAA,cACA,UAAU,gBAAgB,OAAO;AAAA,YAClC,CAAC;AAAA,UACF;AAAA,QACD;AACA,oBAAY,gBAAgB,OAAO,QAAQ;AAC3C,oBAAY,iBAAiB;AAC7B,gBAAQ,gBAAgB,OAAO,QAAQ,EAAE;AAAA,MAC1C;AACA,YAAM,WAAW,MAAM;AAAA,QACtB;AAAA,MACD;AACA,UAAI,SAAU,UAAS,QAAQ;AAC/B,UAAI,UAAW,WAAU,QAAQ;AACjC,qBAAe,CAAC;AAChB,YAAM,aAAa,MAAM;AAAA,QACxB;AAAA,MACD;AACA,UAAI,WAAY,YAAW,cAAc;AACzC,YAAM,SAAS;AACf,mBAAa;AAAA,IACd,SAAS,OAAO;AACf,eAAS,iBAAiB,QAAQ,MAAM,UAAU,0BAAM;AAAA,IACzD,UAAE;AACD,oBAAc,KAAK;AAAA,IACpB;AAAA,EACD;AAEA,iBAAe,WAAW;AACzB,QAAI,CAAC,YAAa;AAClB,UAAM,gBAAgB;AACtB,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,cAAc,eAAe;AAChC,aAAO,IAAI,kBAAkB,cAAc,aAAa;AAAA,IACzD;AACA,WAAO,IAAI,iBAAiB,cAAc,WAAW;AACrD,UAAM,SAAS,MAAM;AAAA,MAKpB,GAAG,WAAW,OAAO,CAAC,oBAAoB,mBAAmB,QAAQ,KAAK,CAAC,YAAY,mBAAmB,cAAc,QAAQ,CAAC,aAAa,OAAO,SAAS,CAAC;AAAA,IAChK;AACA,kBAAc,SAAS,OAAO;AAC9B,qBAAiB;AACjB,QAAI,OAAO,SAAS,SAAS,GAAG;AAC/B,YAAM,gBAAgB,OAAO,SAAS,GAAG,EAAE;AAC3C,UAAI,cAAe,eAAc,gBAAgB,cAAc;AAC/D,qBAAe,OAAO,QAAQ;AAAA,IAC/B;AACA,QAAI,OAAO,iBAAiB,gBAAiB,aAAY;AAAA,QACpD,cAAa,OAAO,eAAe;AAAA,EACzC;AAEA,WAAS,aAAa,OAAe;AACpC,gBAAY;AACZ,QAAI,CAAC,SAAS,QAAQ,KAAK,SAAS,UAAU,CAAC,YAAa;AAC5D,gBAAY,OAAO,WAAW,MAAM,KAAK,SAAS,GAAG,KAAK;AAAA,EAC3D;AAEA,WAAS,eAAe;AACvB,QAAI,CAAC,eAAe,YAAY,WAAW,gBAAiB;AAC5D,iBAAa,GAAM;AAAA,EACpB;AAEA,WAAS,cAAc;AACtB,QAAI,UAAW,QAAO,aAAa,SAAS;AAC5C,gBAAY;AAAA,EACb;AAEA,WAAS,OAAO;AACf,cAAU;AACV,UAAM,QAAQ,OAAO;AACrB,WAAO,WAAW,MAAM;AACvB,YAAM,cAAmC,uBAAuB,GAAG,MAAM;AAAA,IAC1E,GAAG,CAAC;AAAA,EACL;AAEA,WAAS,QAAQ;AAChB,UAAM,QAAQ,OAAO;AACrB,gBAAY;AAAA,EACb;AAEA,WAAS,iBAAiB,SAAS,IAAI;AACvC,QAAM,yBAAyB,MAAM;AACpC,QAAI,SAAS,OAAQ,aAAY;AAAA,QAC5B,cAAa;AAAA,EACnB;AACA,QAAM,sBAAsB,CAAC,UAAsB;AAClD,UAAM,iBAAiB,MAAM;AAAA,MAC5B;AAAA,IACD;AACA,QACC,kBACA,MAAM,kBAAkB,QACxB,CAAC,eAAe,SAAS,MAAM,MAAM,GACpC;AACD,qBAAe,QAAQ,OAAO;AAAA,IAC/B;AAAA,EACD;AACA,WAAS,iBAAiB,oBAAoB,sBAAsB;AACpE,WAAS,iBAAiB,SAAS,mBAAmB;AAEtD,MAAI,OAAO,WAAW,aAAa;AAClC,UAAM,UAAU,MAAM;AACrB,UAAI,yBAAyB,QAAQ;AACpC;AAAC,QAAC,OAAe,oBAAoB,MAAM,UAAU,CAAC;AAAA,MACvD,OAAO;AACN,mBAAW,WAAW,MAAM,UAAU,GAAG,IAAI;AAAA,MAC9C;AAAA,IACD;AACA,QAAI,SAAS,eAAe,WAAY,SAAQ;AAAA,SAC3C;AACJ,aAAO,iBAAiB,QAAQ,SAAS,EAAE,MAAM,KAAK,CAAC;AACvD,2BAAqB,MAAM,OAAO,oBAAoB,QAAQ,OAAO;AAAA,IACtE;AAAA,EACD;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU;AACT,kBAAY;AACZ,eAAS,oBAAoB,oBAAoB,sBAAsB;AACvE,eAAS,oBAAoB,SAAS,mBAAmB;AACzD,2BAAqB;AACrB,WAAK,OAAO;AAAA,IACb;AAAA,EACD;AACD;AAEO,SAAS,oBACf,WACA,SACC;AACD,SAAO,qBAAqB,WAAW,OAAO;AAC/C;;;ACjyBA,OAAOC,aAAY;AAoGZ,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAI1C,YAAY,SAAiB,QAAgB,MAAe;AAC3D,UAAM,OAAO;AAJd,wBAAS;AACT,wBAAS;AAIR,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACb;AACD;AA2QO,SAAS,4BACf,SACA,UACkC;AAClC,MAAI,CAAC,WAAW,QAAQ,SAAS,SAAU,QAAO;AAClD,QAAM,qBAAqB,SAAS,KAAK,EAAE,YAAY;AACvD,MAAI,CAAC,aAAa,KAAK,kBAAkB,EAAG,QAAO;AAEnD,QAAM,eAAe,QAAQ,UAAU;AACvC,MAAI,cAAc,YAAY,KAAM,QAAO;AAE3C,QAAM,iBAAiB,aAAa,aAAa,kBAAkB;AACnE,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,qBACL,eAAe,8BAA8B,UAC1C,KAAK,KAAK,KAAK,eAAe,oBAAoB,IAClD,KAAK,KAAK,IAAI,eAAe,oBAAoB;AACrD,MAAI,YAAY,KAAK,IAAI,eAAe,WAAW,kBAAkB;AACrE,MAAI,eAAe,cAAc,YAAY,eAAe,WAAW;AACtE,UAAM,YAAY,KAAK;AAAA,OACrB,YAAY,eAAe,aAAa,eAAe;AAAA,IACzD;AACA,gBAAY,eAAe,YAAY,YAAY,eAAe;AAAA,EACnE;AAEA,SAAO;AAAA,IACN,GAAG;AAAA,IACH,WAAW,QAAQ;AAAA,IACnB,aAAa,QAAQ;AAAA,IACrB,gBAAgB,aAAa;AAAA,IAC7B,UAAU;AAAA,IACV,qBAAqB,eAAe;AAAA,IACpC;AAAA,IACA;AAAA,EACD;AACD;AAOO,SAAS,6BACf,SACA,cACuC;AACvC,QAAM,OAAO,4BAA4B,SAAS,aAAa,QAAQ;AACvE,MAAI,CAAC,MAAM;AACV,WAAO;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OACC;AAAA,IACF;AAAA,EACD;AAEA,QAAM,SAAS,OAAO,aAAa,MAAM;AACzC,MAAI,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GAAG;AAC7C,WAAO;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OACC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,MAAI,SAAS,KAAK,aAAa,SAAS,KAAK,WAAW;AACvD,WAAO;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO,iCAAiC,KAAK,SAAS,QAAQ,KAAK,SAAS;AAAA,MAC5E;AAAA,IACD;AAAA,EACD;AAEA,MACC,KAAK,eACJ,SAAS,KAAK,uBAAuB,KAAK,eAAe,GACzD;AACD,WAAO;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO,kCAAkC,KAAK,UAAU;AAAA,MACxD;AAAA,IACD;AAAA,EACD;AAEA,SAAO,EAAE,OAAO,MAAM,KAAK;AAC5B;AAqZO,IAAM,gBAAN,MAAoB;AAAA;AAAA,EAM1B,YAAY,SAA+B;AAL3C,wBAAiB;AACjB,wBAAiB;AACjB,wBAAiB;AACjB;AAAA,wBAAiB;AAGhB,QAAI,CAAC,QAAQ,MAAO,OAAM,IAAI,MAAM,mBAAmB;AACvD,QAAI,CAAC,QAAQ,UAAW,OAAM,IAAI,MAAM,uBAAuB;AAE/D,SAAK,QAAQ,QAAQ;AACrB,SAAK,YAAY,QAAQ;AAGzB,UAAM,SACL,QAAQ,UAAU,QAAQ,WAAW;AACtC,SAAK,SAAS,OAAO,QAAQ,OAAO,EAAE;AAGtC,UAAM,cACL,QAAQ,eAAe,QAAQ,WAAW;AAC3C,SAAK,cAAc,YAAY,QAAQ,OAAO,EAAE;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,WAA2B;AACpD,UAAM,MAAM,GAAG,KAAK,KAAK,GAAG,KAAK,SAAS,GAAG,SAAS;AACtD,WAAOC,QAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,QACb,QACA,MACA,MACa;AACb,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,YAAY,KAAK,kBAAkB,SAAS;AAElD,UAAM,MAAM,GAAG,KAAK,MAAM,mBAAmB,KAAK,KAAK,GAAG,IAAI;AAE9D,UAAM,UAAuB;AAAA,MAC5B,gBAAgB;AAAA,MAChB,mBAAmB,UAAU,SAAS;AAAA,MACtC,cAAc;AAAA,IACf;AAEA,UAAM,UAAuB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACrC;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK,OAAO;AAEzC,QAAI,CAAC,SAAS,IAAI;AACjB,YAAM,YAAY,MAAM,SAAS,KAAK;AACtC,UAAI,cAAmB;AACvB,UAAI;AACH,sBAAc,KAAK,MAAM,SAAS;AAAA,MACnC,QAAQ;AAAA,MAAC;AACT,YAAM,UACL,aAAa,WACb,aAAa,SACb,aACA;AACD,YAAM,IAAI;AAAA,QACT;AAAA,QACA,SAAS;AAAA,QACT,aAAa,QAAQ;AAAA,MACtB;AAAA,IACD;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,KAAK,OAAO;AACf,YAAM,IAAI;AAAA,QACT,sBAAsB,KAAK,KAAK;AAAA,QAChC,SAAS;AAAA,QACT,KAAK;AAAA,MACN;AAAA,IACD;AAEA,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,gBAAgB,cAAwD;AACvE,QAAI;AACH,YAAM,EAAE,IAAI,eAAe,QAAQ,IAAI;AACvC,YAAM,MAAMA,QAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,SAAS,EAAE,OAAO;AACtE,YAAM,WAAWA,QAAO;AAAA,QACvB;AAAA,QACA;AAAA,QACA,OAAO,KAAK,IAAI,KAAK;AAAA,MACtB;AAEA,eAAS,WAAW,OAAO,KAAK,SAAS,KAAK,CAAC;AAE/C,UAAI,YAAY,SAAS,OAAO,eAAe,OAAO,MAAM;AAC5D,mBAAa,SAAS,MAAM,MAAM;AAElC,aAAO,KAAK,MAAM,SAAS;AAAA,IAC5B,QAAQ;AACP,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,uBACC,SACA,WACA,WACA,SACU;AACV,QAAI;AACH,YAAM,cAAc,SAAS,eAAe,IAAI,KAAK;AACrD,YAAM,cAAc,OAAO,SAAS,WAAW,EAAE;AACjD,UACC,OAAO,MAAM,WAAW,KACxB,KAAK,IAAI,KAAK,IAAI,IAAI,WAAW,IAAI,aACpC;AACD,eAAO;AAAA,MACR;AAEA,YAAM,YAAY,GAAG,SAAS,IAAI,OAAO;AACzC,YAAM,WAAWA,QACf,WAAW,UAAU,KAAK,SAAS,EACnC,OAAO,SAAS,EAChB,OAAO,KAAK;AAEd,YAAM,kBAAkB,OAAO,KAAK,SAAS;AAC7C,YAAM,iBAAiB,OAAO,KAAK,QAAQ;AAC3C,UAAI,gBAAgB,WAAW,eAAe,QAAQ;AACrD,eAAO;AAAA,MACR;AACA,aAAOA,QAAO,gBAAgB,iBAAiB,cAAc;AAAA,IAC9D,QAAQ;AACP,aAAO;AAAA,IACR;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,SAGK;AACtB,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,SAAS,OAAQ,QAAO,OAAO,UAAU,QAAQ,MAAM;AAC3D,QAAI,SAAS,SAAU,QAAO,OAAO,YAAY,QAAQ,QAAQ;AAEjE,UAAM,OAAO,OAAO,SAAS,IAC1B,aAAa,OAAO,SAAS,CAAC,KAC9B;AACH,WAAO,KAAK,QAAQ,OAAO,IAAI;AAAA,EAChC;AAAA;AAAA,EAGA,MAAM,sBAAiD;AACtD,WAAO,KAAK,QAAQ,OAAO,oBAAoB;AAAA,EAChD;AAAA;AAAA,EAGA,MAAM,2BACL,iBAC4B;AAC5B,UAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,6BAA6B;AACzD,WAAO,KAAK;AAAA,MACX;AAAA,MACA,aAAa,mBAAmB,KAAK,CAAC;AAAA,IACvC;AAAA,EACD;AAAA;AAAA,EAGA,MAAM,kCACL,QACA,iBAC0C;AAC1C,UAAM,YAAY,QAAQ,KAAK;AAC/B,UAAM,eAAe,iBAAiB,KAAK;AAC3C,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,oBAAoB;AACpD,QAAI,CAAC,aAAc,OAAM,IAAI,MAAM,6BAA6B;AAChE,WAAO,KAAK;AAAA,MACX;AAAA,MACA,UAAU,mBAAmB,SAAS,CAAC,aAAa,mBAAmB,YAAY,CAAC;AAAA,IACrF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACL,iBACA,SACwB;AACxB,UAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAI,CAAC,OAAO;AACX,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC9C;AAEA,UAAM,SAAS,IAAI,gBAAgB;AACnC,WAAO,IAAI,mBAAmB,KAAK;AACnC,QAAI,SAAS,SAAU,QAAO,IAAI,YAAY,QAAQ,QAAQ;AAC9D,QAAI,SAAS,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACxD,QAAI,SAAS,SAAU,QAAO,IAAI,YAAY,QAAQ,QAAQ;AAE9D,WAAO,KAAK;AAAA,MACX;AAAA,MACA,aAAa,mBAAmB,KAAK,CAAC,UAAU,OAAO,SAAS,CAAC;AAAA,IAClE;AAAA,EACD;AAAA,EAYA,MAAM,iBACL,QACA,SAC0B;AAC1B,UAAM,aAAa;AAAA,MAClB,GAAG,IAAI;AAAA,SACL,OAAO,cAAc,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,MACpE;AAAA,IACD;AACA,UAAM,eAAe;AAAA,MACpB,GAAG,IAAI;AAAA,SACL,OAAO,gBAAgB,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,MACtE;AAAA,IACD;AACA,QAAI,WAAW,WAAW,KAAK,aAAa,WAAW,GAAG;AACzD,YAAM,IAAI,MAAM,wCAAwC;AAAA,IACzD;AAEA,UAAM,eAAe,WAAW;AAChC,UAAM,QAAQ,IAAI,gBAAgB;AAClC,QAAI,WAAW,SAAS,EAAG,OAAM,IAAI,cAAc,WAAW,KAAK,GAAG,CAAC;AACvE,QAAI,aAAa,SAAS;AACzB,YAAM,IAAI,gBAAgB,aAAa,KAAK,GAAG,CAAC;AACjD,QAAI,aAAa,SAAU,OAAM,IAAI,YAAY,aAAa,QAAQ;AACtE,QAAI,aAAa,OAAQ,OAAM,IAAI,UAAU,aAAa,MAAM;AAChE,QAAI,aAAa,SAAU,OAAM,IAAI,YAAY,aAAa,QAAQ;AAEtE,WAAO,KAAK,QAAQ,OAAO,oBAAoB,MAAM,SAAS,CAAC,EAAE;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YAAY,QAAyD;AAC1E,WAAO,KAAK,QAAQ,QAAQ,WAAW,MAAM;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,wBACL,QAC+B;AAC/B,WAAO,KAAK,QAAQ,QAAQ,WAAW;AAAA,MACtC,GAAG;AAAA,MACH,SAAS;AAAA,IACV,CAA6B;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,uBACL,QAC+B;AAC/B,UAAM,EAAE,QAAQ,GAAG,KAAK,IAAI;AAC5B,WAAO,KAAK,QAAQ,QAAQ,WAAW;AAAA,MACtC,GAAG;AAAA,MACH,SAAS;AAAA,MACT;AAAA,MACA,UAAU,EAAE,OAAO;AAAA,IACpB,CAA6B;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SACL,SACA,QAM+B;AAC/B,WAAO,KAAK,QAAQ,QAAQ,WAAW,OAAO,QAAQ,MAAM;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YACL,SACA,QAC+B;AAC/B,UAAM,QAAQ,SAAS,KAAK;AAC5B,QAAI,CAAC,OAAO;AACX,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACtC;AAEA,WAAO,KAAK;AAAA,MACX;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC;AAAA,MACpC,UAAU,CAAC;AAAA,IACZ;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAkB,SAAqD;AAC5E,UAAM,QAAQ,SAAS,KAAK;AAC5B,QAAI,CAAC,OAAO;AACX,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACtC;AAEA,WAAO,KAAK;AAAA,MACX;AAAA,MACA,WAAW,mBAAmB,KAAK,CAAC;AAAA,MACpC,CAAC;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,SAAuC;AAC3D,WAAO,KAAK,QAAQ,OAAO,WAAW,OAAO,EAAE;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,SAAwC;AAC7D,WAAO,KAAK,QAAQ,OAAO,WAAW,OAAO,UAAU;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAU,QAAsD;AACrE,UAAM,cAAc,IAAI,gBAAgB;AACxC,QAAI,QAAQ,KAAM,aAAY,OAAO,QAAQ,OAAO,KAAK,SAAS,CAAC;AACnE,QAAI,QAAQ;AACX,kBAAY,OAAO,YAAY,OAAO,SAAS,SAAS,CAAC;AAC1D,QAAI,QAAQ,OAAQ,aAAY,OAAO,UAAU,OAAO,MAAM;AAC9D,QAAI,QAAQ,OAAQ,aAAY,OAAO,UAAU,OAAO,MAAM;AAC9D,QAAI,QAAQ,UAAW,aAAY,OAAO,aAAa,OAAO,SAAS;AACvE,QAAI,QAAQ,QAAS,aAAY,OAAO,WAAW,OAAO,OAAO;AAEjE,UAAM,OAAO,YAAY,SAAS,IAC/B,WAAW,YAAY,SAAS,CAAC,KACjC;AACH,WAAO,KAAK,QAA2B,OAAO,IAAI;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,QAA8C;AACnE,WAAO,KAAK,QAAQ,OAAO,UAAU,MAAM,eAAe;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,sBAAsB,QAA4C;AACvE,WAAO,KAAK,QAAQ,OAAO,UAAU,MAAM,sBAAsB;AAAA,EAClE;AAAA,EAEA,MAAM,sBACL,QACyC;AACzC,WAAO,KAAK,QAAQ,OAAO,UAAU,MAAM,sBAAsB;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBACL,QACuC;AACvC,WAAO,KAAK,QAAQ,QAAQ,UAAU,MAAM,2BAA2B,CAAC,CAAC;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBAAoB,QAAgB,KAA2B;AACpE,UAAM,eAAe,MAAM,KAAK,gBAAgB,MAAM;AACtD,WAAO,aAAa,GAAG,KAAK;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,mBACL,QACA,KACA,QACA,SAI+B;AAC/B,WAAO,KAAK,QAAQ,QAAQ,UAAU,MAAM,yBAAyB;AAAA,MACpE;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACJ,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,uBACL,QACA,MACA,QACA,SAIwC;AACxC,WAAO,KAAK,QAAQ,QAAQ,UAAU,MAAM,8BAA8B;AAAA,MACzE;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACJ,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,4BACL,QACA,MACqC;AACrC,UAAM,QACL,QAAQ,KAAK,SAAS,IACnB,SAAS,mBAAmB,KAAK,KAAK,GAAG,CAAC,CAAC,KAC3C;AACJ,WAAO,KAAK;AAAA,MACX;AAAA,MACA,UAAU,MAAM,+BAA+B,KAAK;AAAA,IACrD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,eACL,QACA,KACA,QAC+B;AAC/B,WAAO,KAAK,QAAQ,QAAQ,UAAU,MAAM,qBAAqB;AAAA,MAChE;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,kBACL,QACA,KACA,SACkC;AAIlC,WAAO,KAAK,QAAQ,QAAQ,UAAU,MAAM,wBAAwB;AAAA,MACnE;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,WAAmB,SAAyB;AAC1D,WAAO,GAAG,KAAK,WAAW,aAAa,KAAK,KAAK,IAAI,SAAS,IAAI,OAAO;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAiB,OAA4C;AAClE,QAAI,CAAC,OAAO,KAAK,GAAG;AACnB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC1C;AACA,WAAO,KAAK,QAAQ,QAAQ,wBAAwB,EAAE,OAAO,MAAM,KAAK,EAAE,CAAC;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,0BACL,QAC6C;AAC7C,UAAM,SAAS,OAAO,QAAQ,KAAK;AACnC,UAAM,cAAc,OAAO,aAAa,KAAK;AAC7C,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,QAAI,CAAC,YAAa,OAAM,IAAI,MAAM,yBAAyB;AAE3D,WAAO,KAAK;AAAA,MACX;AAAA,MACA,gBAAgB,mBAAmB,MAAM,CAAC;AAAA,MAC1C;AAAA,QACC,kBAAkB,OAAO,oBAAoB,OAAO;AAAA,QACpD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,QAAsD;AAC3E,UAAM,SAAS,OAAO,QAAQ,KAAK;AACnC,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AAEjD,WAAO,KAAK;AAAA,MACX;AAAA,MACA,gBAAgB,mBAAmB,MAAM,CAAC;AAAA,IAC3C;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACL,QACmC;AACnC,UAAM,SAAS,OAAO,QAAQ,KAAK;AACnC,UAAM,cAAc,OAAO,aAAa,KAAK;AAC7C,UAAM,OAAO,OAAO,MAAM,KAAK;AAC/B,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,QAAI,CAAC,YAAa,OAAM,IAAI,MAAM,yBAAyB;AAC3D,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,kBAAkB;AAE7C,WAAO,KAAK;AAAA,MACX;AAAA,MACA,gBAAgB,mBAAmB,MAAM,CAAC;AAAA,MAC1C;AAAA,QACC;AAAA,QACA,kBAAkB,OAAO,oBAAoB,OAAO;AAAA,QACpD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACL,QACqC;AACrC,UAAM,SAAS,OAAO,QAAQ,KAAK;AACnC,UAAM,cAAc,OAAO,aAAa,KAAK;AAC7C,UAAM,OAAO,OAAO,MAAM,KAAK;AAC/B,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,QAAI,CAAC,YAAa,OAAM,IAAI,MAAM,yBAAyB;AAC3D,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,kBAAkB;AAE7C,WAAO,KAAK;AAAA,MACX;AAAA,MACA,gBAAgB,mBAAmB,MAAM,CAAC;AAAA,MAC1C;AAAA,QACC;AAAA,QACA,kBAAkB,OAAO,oBAAoB,OAAO;AAAA,QACpD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,2BACL,QAC8C;AAC9C,UAAM,sBACL,OAAO,qBAAqB,KAAK,KAAK,OAAO,QAAQ,KAAK;AAC3D,UAAM,iBAAiB,OAAO,gBAAgB,KAAK;AACnD,QAAI,CAAC,uBAAuB,CAAC,gBAAgB;AAC5C,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACvD;AAEA,WAAO,KAAK,QAAQ,QAAQ,6BAA6B;AAAA,MACxD,GAAG;AAAA,MACH;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,QAAyD;AAC1E,QAAI,CAAC,OAAO,YAAY,KAAK,KAAK,CAAC,OAAO,cAAc,KAAK,GAAG;AAC/D,YAAM,IAAI,MAAM,wCAAwC;AAAA,IACzD;AACA,QAAI,CAAC,OAAO,QAAQ,OAAO,OAAO,SAAS,UAAU;AACpD,YAAM,IAAI,MAAM,kBAAkB;AAAA,IACnC;AAEA,WAAO,KAAK,QAAQ,QAAQ,kBAAkB,MAAM;AAAA,EACrD;AACD;","names":["panel","crypto","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/brand-logo.ts","../src/hosted-modal.ts","../src/environment.ts","../src/login.ts","../src/client.ts","../src/feedback.ts","../src/server.ts"],"sourcesContent":["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\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","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] as const\n\nconst SDK_DEFAULT_LOCALE = \"zh-CN\"\n\nconst SDK_LOCALE_ALIASES: Record<string, string> = {\n\ten: \"en\",\n\t\"en-us\": \"en\",\n\t\"en-gb\": \"en\",\n\tzh: \"zh-CN\",\n\t\"zh-cn\": \"zh-CN\",\n\t\"zh-tw\": \"zh-Hant\",\n\t\"zh-hk\": \"zh-Hant\",\n\t\"zh-hant\": \"zh-Hant\",\n\t\"zh-hans\": \"zh-CN\",\n\tfr: \"fr\",\n\tde: \"de\",\n\tja: \"ja\",\n\tes: \"es\",\n\tko: \"ko\",\n\tnl: \"nl\",\n\tit: \"it\",\n\tpt: \"pt\",\n}\n\nfunction matchSupportedBaseLocale(locale: string): string | undefined {\n\tconst base = locale.toLowerCase().split(\"-\")[0]\n\treturn SDK_SUPPORTED_LOCALES.find((item) => item.toLowerCase() === base)\n}\n\nexport function normalizeSdkLocale(locale?: string): string | undefined {\n\tif (!locale) return\n\n\tconst sanitized = locale.trim().replace(/_/g, \"-\")\n\tif (!sanitized) return\n\n\tconst lower = sanitized.toLowerCase()\n\tif (SDK_LOCALE_ALIASES[lower]) {\n\t\treturn SDK_LOCALE_ALIASES[lower]\n\t}\n\n\tlet canonical: string | undefined\n\ttry {\n\t\tcanonical = Intl.getCanonicalLocales(sanitized)[0]\n\t} catch {\n\t\tcanonical = undefined\n\t}\n\n\tconst candidates = [canonical, sanitized].filter(Boolean) as string[]\n\n\tfor (const candidate of candidates) {\n\t\tconst candidateLower = candidate.toLowerCase()\n\n\t\tif (SDK_LOCALE_ALIASES[candidateLower]) {\n\t\t\treturn SDK_LOCALE_ALIASES[candidateLower]\n\t\t}\n\t\tif ((SDK_SUPPORTED_LOCALES as readonly string[]).includes(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\n\t\tconst baseMatch = matchSupportedBaseLocale(candidate)\n\t\tif (baseMatch) {\n\t\t\treturn baseMatch\n\t\t}\n\t}\n}\n\nexport function getBrowserLocale(): string | undefined {\n\tif (typeof navigator === \"undefined\") return\n\n\tfor (const candidate of navigator.languages || []) {\n\t\tconst normalized = normalizeSdkLocale(candidate)\n\t\tif (normalized) return normalized\n\t}\n\n\treturn normalizeSdkLocale(navigator.language)\n}\n\nexport function getAutoResolvedLocale(locale?: string): string {\n\treturn normalizeSdkLocale(locale) || getBrowserLocale() || SDK_DEFAULT_LOCALE\n}\n\nexport function applyLocaleToUrl(urlValue: string, locale?: string): string {\n\tif (!locale) return urlValue\n\n\ttry {\n\t\tconst url = new URL(urlValue)\n\t\tconst localePrefix = `/${locale}`\n\t\tif (\n\t\t\t!url.pathname.startsWith(`${localePrefix}/`) &&\n\t\t\turl.pathname !== localePrefix\n\t\t) {\n\t\t\turl.pathname = `${localePrefix}${url.pathname}`\n\t\t}\n\t\treturn url.toString()\n\t} catch (_error) {\n\t\tconst localePrefix = `/${locale}`\n\t\tif (!urlValue.startsWith(`${localePrefix}/`) && urlValue !== localePrefix) {\n\t\t\treturn `${localePrefix}${urlValue.startsWith(\"/\") ? \"\" : \"/\"}${urlValue}`\n\t\t}\n\t\treturn urlValue\n\t}\n}\n\nexport class HostedFrameModal<TData extends HostedFrameMessage> {\n\tprotected iframe: HTMLIFrameElement | null = null\n\tprotected modal: HTMLDivElement | null = null\n\tprotected messageHandler: ((event: MessageEvent) => void) | null = null\n\n\tprotected openHostedFrame(\n\t\turl: string,\n\t\toptions: HostedFrameOptions<TData>,\n\t): 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 { 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})\n\n\tconst badge = document.createElement(\"div\")\n\tbadge.textContent = \"YOUiDIAN\"\n\tObject.assign(badge.style, {\n\t\tdisplay: \"inline-flex\",\n\t\talignItems: \"center\",\n\t\tborder: \"1px solid rgba(229,229,229,0.92)\",\n\t\tborderRadius: \"9999px\",\n\t\tbackground: \"#fafafa\",\n\t\tcolor: \"#171717\",\n\t\tfontSize: \"11px\",\n\t\tfontWeight: \"700\",\n\t\tletterSpacing: \"0.22em\",\n\t\tlineHeight: \"1\",\n\t\tmarginBottom: \"18px\",\n\t\tpadding: \"8px 12px\",\n\t})\n\n\tcontent.appendChild(badge)\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\nfunction createBrandLoadingCopy() {\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 = \"优易点\"\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 = \"开发者服务中台\"\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() {\n\tensureLoginLoadingStyles()\n\tconst panel = document.createElement(\"div\")\n\tapplyLoginLoadingPanelStyle(panel)\n\tpanel.setAttribute(\"role\", \"status\")\n\tpanel.setAttribute(\"aria-label\", \"优易点开发者服务中台\")\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())\n\tpanel.appendChild(content)\n\n\treturn panel\n}\n\nfunction createLoginRedirectingPanel(_options: {\n\tdescription: string\n\ttitle: string\n}) {\n\treturn createLoginLoadingPanel()\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) {\n\t\tif (this.iframeLoadingPanel || this.iframeReady) {\n\t\t\treturn\n\t\t}\n\n\t\tconst panel = createLoginLoadingPanel()\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}) {\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\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}) {\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(hostedFrame.container)\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})\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 } 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\"\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\" | \"slow\") {\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: type === \"refresh\"\n\t\t\t\t? [\n\t\t\t\t\t\t\"M20 6V11H15\",\n\t\t\t\t\t\t\"M4 18V13H9\",\n\t\t\t\t\t\t\"M18.2 9A7 7 0 0 0 6.2 6.6L4 9\",\n\t\t\t\t\t\t\"M5.8 15A7 7 0 0 0 17.8 17.4L20 15\",\n\t\t\t\t\t]\n\t\t\t\t: [\"M12 7V12L15 14\", \"M21 12A9 9 0 1 1 3 12A9 9 0 0 1 21 12\"]\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 createPaymentFallbackArtwork(theme: ResolvedPaymentTheme) {\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\tconst icon = createPaymentIcon(\"slow\")\n\tObject.assign(icon.style, {\n\t\twidth: \"52px\",\n\t\theight: \"52px\",\n\t\ttransform: \"rotate(4deg)\",\n\t})\n\ttile.appendChild(icon)\n\n\tartwork.appendChild(wash)\n\tartwork.appendChild(blob)\n\tartwork.appendChild(tile)\n\treturn artwork\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(createPaymentFallbackArtwork(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 (status.status === \"CANCELLED\" || status.status === \"FAILED\") {\n\t\t\t\t\t\treject(new Error(`Order ${status.status.toLowerCase()}`))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(new Error(\"Polling timeout\"))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// Continue polling\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// On network error, continue polling unless timeout\n\t\t\t\t\tif (Date.now() - startTime > timeout) {\n\t\t\t\t\t\treject(error)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(poll, interval)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpoll()\n\t\t})\n\t}\n}\n\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, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\")\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\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\nexport type SubscriptionAction = \"NEW\" | \"UPGRADE\" | \"DOWNGRADE\"\nexport type SubscriptionIntent = \"STANDARD\" | \"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\tcurrentRemainingValueAmount?: 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}\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\"\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\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\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\"\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\"\n\torderId: string\n\tinternalId?: string | null\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\"\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\"\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\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}\n\n\t\tconst options: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody: body ? JSON.stringify(body) : 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 * 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?: { locale?: string; currency?: string },\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\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","crypto"]}
|