@viceme-ai/sdk 0.6.2 → 0.8.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.
Files changed (44) hide show
  1. package/README.md +65 -17
  2. package/dist/capability-mount.d.ts +2 -0
  3. package/dist/capability-mount.d.ts.map +1 -1
  4. package/dist/chunks/client-DbPCnwf-.js +1471 -0
  5. package/dist/chunks/client-DbPCnwf-.js.map +1 -0
  6. package/dist/chunks/integration-CTsnJ8mN.js +38 -0
  7. package/dist/chunks/integration-CTsnJ8mN.js.map +1 -0
  8. package/dist/chunks/version-DXLLix7K.js +6 -0
  9. package/dist/chunks/{version-BJiUVcir.js.map → version-DXLLix7K.js.map} +1 -1
  10. package/dist/core/access-bridge.d.ts +17 -0
  11. package/dist/core/access-bridge.d.ts.map +1 -0
  12. package/dist/core/capabilities.d.ts +12 -2
  13. package/dist/core/capabilities.d.ts.map +1 -1
  14. package/dist/core/client.d.ts.map +1 -1
  15. package/dist/core/presentation.d.ts +10 -1
  16. package/dist/core/presentation.d.ts.map +1 -1
  17. package/dist/danmaku/mount.d.ts.map +1 -1
  18. package/dist/danmaku.js +117 -91
  19. package/dist/danmaku.js.map +1 -1
  20. package/dist/engagement/integration.d.ts +15 -0
  21. package/dist/engagement/integration.d.ts.map +1 -0
  22. package/dist/generated/public-contract.d.ts +260 -12
  23. package/dist/generated/public-contract.d.ts.map +1 -1
  24. package/dist/index.js +29 -27
  25. package/dist/index.js.map +1 -1
  26. package/dist/loader/auto-loader.d.ts.map +1 -1
  27. package/dist/manifest.json +37 -28
  28. package/dist/session/session.d.ts +36 -3
  29. package/dist/session/session.d.ts.map +1 -1
  30. package/dist/testing.js +1 -1
  31. package/dist/tip/index.d.ts +2 -0
  32. package/dist/tip/index.d.ts.map +1 -1
  33. package/dist/tip/mount.d.ts.map +1 -1
  34. package/dist/tip.js +211 -194
  35. package/dist/tip.js.map +1 -1
  36. package/dist/transport/transport.d.ts +2 -0
  37. package/dist/transport/transport.d.ts.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/dist/viceme.min.js +51 -8
  40. package/dist/viceme.min.js.map +1 -1
  41. package/package.json +1 -1
  42. package/dist/chunks/client-DEg6YouY.js +0 -1027
  43. package/dist/chunks/client-DEg6YouY.js.map +0 -1
  44. package/dist/chunks/version-BJiUVcir.js +0 -6
package/dist/tip.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tip.js","sources":["../src/tip/headless.ts","../src/browser-events.ts","../src/tip/mount.ts","../src/tip/index.ts"],"sourcesContent":["import type { ViceMeClient } from '../core/client.ts';\nimport { BUILD_WIDGET_ORIGINS } from '../core/build-endpoints.ts';\nimport { clientDestroyed, ViceMeError } from '../core/errors.ts';\nimport type { TipClient, TipConfig, TipOpenOptions, TipOpenResult } from './index.ts';\nimport {\n isTipProvider,\n isValidTipWorkTitle,\n parseTipOpenOptions,\n tipOptionInvalid,\n} from './validation.ts';\n\nconst TIP_CONFIG_KEYS = ['work', 'workKey', 'environment', 'currency', 'amount', 'providers'];\nconst TIP_WORK_KEYS = ['id', 'title'];\nconst TIP_AMOUNT_KEYS = ['minCents', 'maxCents', 'stepCents'];\nconst PUBLIC_ERROR_KEYS = ['statusCode', 'code', 'message', 'requestId'];\nconst HEADLESS_READY_KEYS = ['type', 'channel', 'workKey'];\nconst HEADLESS_PAID_KEYS = [\n 'type',\n 'channel',\n 'workKey',\n 'status',\n 'work',\n 'amountCents',\n 'currency',\n];\nconst HEADLESS_TERMINAL_KEYS = ['type', 'channel', 'workKey', 'status'];\nconst HEADLESS_READY_TIMEOUT_MS = 8_000;\nconst TIP_CONFIG_TIMEOUT_MS = 8_000;\nconst TIP_CONFIG_MAX_BYTES = 16 * 1024;\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\ntype WidgetAppearance = 'light' | 'dark';\n\nfunction isStrictRecord(value: unknown, keys: string[]): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const actualKeys = Object.keys(value);\n return actualKeys.length === keys.length && keys.every((key) => actualKeys.includes(key));\n}\n\nfunction tipConfigInvalid(): ViceMeError {\n return new ViceMeError({\n code: 'TIP_CONFIG_INVALID',\n message: 'Shop returned an invalid Tip configuration.',\n retryable: false,\n capability: 'tip',\n });\n}\n\nfunction isCredentialsNotAllowedError(input: unknown): input is { requestId: string } {\n if (!isStrictRecord(input, PUBLIC_ERROR_KEYS)) return false;\n return (\n input.statusCode === 400 &&\n input.code === 'TIP_CONFIG_CREDENTIALS_NOT_ALLOWED' &&\n typeof input.message === 'string' &&\n typeof input.requestId === 'string' &&\n input.requestId.length >= 1 &&\n input.requestId.length <= 128\n );\n}\n\nfunction tipConfigCredentialsNotAllowed(requestId: string): ViceMeError {\n return new ViceMeError({\n code: 'TIP_CONFIG_CREDENTIALS_NOT_ALLOWED',\n message: 'Tip configuration requests must not include credentials.',\n retryable: false,\n requestId,\n capability: 'tip',\n });\n}\n\nfunction parseTipConfig(input: unknown, expectedWorkKey: string): TipConfig {\n if (!isStrictRecord(input, TIP_CONFIG_KEYS)) throw tipConfigInvalid();\n if (!isStrictRecord(input.work, TIP_WORK_KEYS)) throw tipConfigInvalid();\n if (\n typeof input.work.id !== 'string' ||\n !UUID_PATTERN.test(input.work.id) ||\n !isValidTipWorkTitle(input.work.title)\n ) {\n throw tipConfigInvalid();\n }\n if (input.workKey !== expectedWorkKey) {\n throw tipConfigInvalid();\n }\n if (input.environment !== 'SANDBOX' && input.environment !== 'PRODUCTION') {\n throw tipConfigInvalid();\n }\n if (\n (input.workKey.startsWith('wrk_test_') && input.environment !== 'SANDBOX') ||\n (input.workKey.startsWith('wrk_live_') && input.environment !== 'PRODUCTION')\n ) {\n throw tipConfigInvalid();\n }\n if (input.currency !== 'CNY') throw tipConfigInvalid();\n if (\n !isStrictRecord(input.amount, TIP_AMOUNT_KEYS) ||\n input.amount.minCents !== 100 ||\n input.amount.maxCents !== 20_000 ||\n input.amount.stepCents !== 1\n ) {\n throw tipConfigInvalid();\n }\n if (\n !Array.isArray(input.providers) ||\n input.providers.length < 1 ||\n !input.providers.every(isTipProvider) ||\n new Set(input.providers).size !== input.providers.length\n ) {\n throw tipConfigInvalid();\n }\n\n return {\n work: { id: input.work.id, title: input.work.title },\n workKey: input.workKey,\n environment: input.environment,\n currency: input.currency,\n amount: { minCents: 100, maxCents: 20_000, stepCents: 1 },\n providers: [...input.providers],\n };\n}\n\nfunction parseHeadlessResult(\n input: unknown,\n channel: string,\n config: TipConfig,\n amountCents: number,\n): TipOpenResult | undefined {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) return undefined;\n const message = input as Record<string, unknown>;\n if (\n message.type !== 'viceme:tip-headless-result' ||\n message.channel !== channel ||\n message.workKey !== config.workKey\n ) {\n return undefined;\n }\n if (message.status === 'PAID') {\n if (\n !isStrictRecord(message, HEADLESS_PAID_KEYS) ||\n !isStrictRecord(message.work, TIP_WORK_KEYS) ||\n message.work.id !== config.work.id ||\n message.work.title !== config.work.title ||\n message.amountCents !== amountCents ||\n message.currency !== 'CNY'\n ) {\n return undefined;\n }\n return {\n status: 'PAID',\n work: { id: config.work.id, title: config.work.title },\n amountCents,\n currency: 'CNY',\n };\n }\n if (\n (message.status === 'CANCELLED' || message.status === 'UNKNOWN') &&\n isStrictRecord(message, HEADLESS_TERMINAL_KEYS)\n ) {\n return { status: message.status };\n }\n return undefined;\n}\n\nfunction internalTipError(): ViceMeError {\n return new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Unable to open the hosted Tip flow.',\n capability: 'tip',\n });\n}\n\nfunction tipCapabilityDisabled(): ViceMeError {\n return new ViceMeError({\n code: 'CAPABILITY_DISABLED',\n message: 'Tip is not available for this Work or region.',\n retryable: false,\n capability: 'tip',\n });\n}\n\nasync function readTipConfigBody(response: Response): Promise<unknown> {\n const contentLength = response.headers.get('content-length');\n if (contentLength !== null) {\n const declaredBytes = Number(contentLength);\n if (\n !Number.isInteger(declaredBytes) ||\n declaredBytes < 0 ||\n declaredBytes > TIP_CONFIG_MAX_BYTES\n ) {\n await response.body?.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw tipConfigInvalid();\n\n const decoder = new TextDecoder('utf-8', { fatal: true });\n let bytes = 0;\n let text = '';\n try {\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) break;\n bytes += chunk.value.byteLength;\n if (bytes > TIP_CONFIG_MAX_BYTES) {\n await reader.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n try {\n text += decoder.decode(chunk.value, { stream: true });\n } catch {\n await reader.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n }\n try {\n text += decoder.decode();\n } catch {\n await reader.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n } finally {\n reader.releaseLock();\n }\n\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw tipConfigInvalid();\n }\n}\n\nasync function fetchTipConfig(client: ViceMeClient, ownerSignal: AbortSignal): Promise<TipConfig> {\n await client.ready();\n if (!client.hasCapability('tip')) throw tipCapabilityDisabled();\n if (client.region !== 'cn') throw tipCapabilityDisabled();\n if (ownerSignal.aborted) throw clientDestroyed();\n const controller = new AbortController();\n const abortRequest = (): void => controller.abort();\n ownerSignal.addEventListener('abort', abortRequest, { once: true });\n const timeout = globalThis.setTimeout(() => controller.abort(), TIP_CONFIG_TIMEOUT_MS);\n const widgetOrigin = BUILD_WIDGET_ORIGINS[client.region];\n const requestUrl = new URL(\n `/v1/work-sdk/${encodeURIComponent(client.workKey)}/tip-config`,\n widgetOrigin,\n );\n try {\n const response = await fetch(requestUrl.toString(), {\n method: 'GET',\n credentials: 'omit',\n redirect: 'error',\n headers: { accept: 'application/json' },\n signal: controller.signal,\n });\n const contentType = response.headers\n .get('content-type')\n ?.split(';', 1)[0]\n ?.trim()\n .toLowerCase();\n let responseOrigin: string | undefined;\n try {\n responseOrigin = response.url ? new URL(response.url).origin : undefined;\n } catch {\n responseOrigin = 'invalid';\n }\n if (response.status !== 200) {\n if (response.status === 404) {\n await response.body?.cancel().catch(() => undefined);\n throw tipCapabilityDisabled();\n }\n if (\n response.status === 400 &&\n contentType === 'application/json' &&\n (!responseOrigin || responseOrigin === widgetOrigin)\n ) {\n let body: unknown;\n try {\n body = await readTipConfigBody(response);\n } catch {\n throw internalTipError();\n }\n if (isCredentialsNotAllowedError(body)) {\n throw tipConfigCredentialsNotAllowed(body.requestId);\n }\n } else {\n await response.body?.cancel().catch(() => undefined);\n }\n throw new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Unable to load Tip configuration.',\n capability: 'tip',\n });\n }\n if (contentType !== 'application/json' || (responseOrigin && responseOrigin !== widgetOrigin)) {\n await response.body?.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n const body = await readTipConfigBody(response);\n return parseTipConfig(body, client.workKey);\n } catch (error) {\n if (ownerSignal.aborted) throw clientDestroyed();\n if (error instanceof ViceMeError) throw error;\n throw internalTipError();\n } finally {\n controller.abort();\n globalThis.clearTimeout(timeout);\n ownerSignal.removeEventListener('abort', abortRequest);\n }\n}\n\nfunction copyTipConfig(config: TipConfig): TipConfig {\n return {\n work: { ...config.work },\n workKey: config.workKey,\n environment: config.environment,\n currency: config.currency,\n amount: { ...config.amount },\n providers: [...config.providers],\n };\n}\n\nexport function createHeadlessTip(client: ViceMeClient): TipClient {\n let destroyed = false;\n let cancelActive: (() => void) | undefined;\n let configPromise: Promise<TipConfig> | undefined;\n const configController = new AbortController();\n const isDestroyed = (): boolean => destroyed || client.state === 'DESTROYED';\n\n const loadTrustedConfig = (): Promise<TipConfig> => {\n if (!configPromise) {\n const pending = fetchTipConfig(client, configController.signal);\n configPromise = pending;\n void pending.then(\n () => {\n if (configPromise === pending) configPromise = undefined;\n },\n () => {\n if (configPromise === pending) configPromise = undefined;\n },\n );\n }\n return configPromise;\n };\n\n return {\n async getConfig(): Promise<TipConfig> {\n if (isDestroyed()) throw clientDestroyed();\n const config = await loadTrustedConfig();\n if (isDestroyed()) throw clientDestroyed();\n return copyTipConfig(config);\n },\n\n open(input: TipOpenOptions): Promise<TipOpenResult> {\n if (isDestroyed()) return Promise.reject(clientDestroyed());\n if (cancelActive) {\n return Promise.reject(\n new ViceMeError({\n code: 'TIP_OPEN_IN_PROGRESS',\n message: 'This Tip client already has an open flow.',\n retryable: false,\n capability: 'tip',\n }),\n );\n }\n if (!client.hasCapability('tip')) {\n return Promise.reject(tipCapabilityDisabled());\n }\n if (client.region !== 'cn') return Promise.reject(tipCapabilityDisabled());\n\n let options: TipOpenOptions;\n try {\n options = parseTipOpenOptions(input);\n } catch (error) {\n return Promise.reject(error);\n }\n\n if (typeof document === 'undefined') {\n return Promise.reject(tipOptionInvalid());\n }\n const documentObject = document;\n const windowObject = documentObject.defaultView;\n if (!documentObject.body || !windowObject) return Promise.reject(tipOptionInvalid());\n const widgetOrigin = BUILD_WIDGET_ORIGINS[client.region];\n const hostLanguage = documentObject.documentElement.lang || windowObject.navigator.language;\n const locale =\n options.locale ?? (hostLanguage.toLowerCase().startsWith('zh') ? 'zh-CN' : 'en-US');\n const requestedAppearance = options.appearance ?? 'auto';\n const appearance: WidgetAppearance =\n requestedAppearance === 'auto'\n ? windowObject.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light'\n : requestedAppearance;\n\n let channel: string;\n let clientReady: Promise<void>;\n try {\n const channelBytes = new Uint8Array(16);\n windowObject.crypto.getRandomValues(channelBytes);\n channel = Array.from(channelBytes, (byte) => byte.toString(16).padStart(2, '0')).join('');\n clientReady = client.ready();\n } catch {\n return Promise.reject(internalTipError());\n }\n\n const portal = documentObject.createElement('div');\n portal.dataset.vicemeTipHeadless = 'open';\n portal.style.all = 'initial';\n portal.style.position = 'fixed';\n portal.style.inset = '0';\n portal.style.display = 'block';\n portal.style.width = '100vw';\n portal.style.height = '100vh';\n portal.style.zIndex = '2147483647';\n\n const frame = documentObject.createElement('iframe');\n const frameUrl = new URL(`/widget/tip/${encodeURIComponent(client.workKey)}`, widgetOrigin);\n frameUrl.searchParams.set('mode', 'headless');\n frameUrl.searchParams.set('channel', channel);\n frameUrl.searchParams.set('appearance', appearance);\n frameUrl.searchParams.set('locale', locale);\n frame.title = 'ViceMe Tip';\n frame.src = frameUrl.toString();\n frame.loading = 'eager';\n frame.referrerPolicy = 'strict-origin';\n frame.setAttribute(\n 'sandbox',\n 'allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts',\n );\n frame.setAttribute('allow', 'payment');\n frame.style.display = 'block';\n frame.style.width = '100%';\n frame.style.height = '100%';\n frame.style.border = '0';\n frame.style.background = 'transparent';\n frame.style.colorScheme = appearance;\n portal.attachShadow({ mode: 'open' }).append(frame);\n\n let settled = false;\n let ready = false;\n let initialized = false;\n let trustedConfig: TipConfig | undefined;\n let readyTimer: number | undefined;\n let resolveOpen: (result: TipOpenResult) => void;\n let rejectOpen: (error: unknown) => void;\n const pending = new Promise<TipOpenResult>((resolve, reject) => {\n resolveOpen = resolve;\n rejectOpen = reject;\n });\n\n const cleanup = (): void => {\n if (readyTimer !== undefined) {\n windowObject.clearTimeout(readyTimer);\n readyTimer = undefined;\n }\n windowObject.removeEventListener('message', onMessage);\n portal.remove();\n if (cancelActive === cancel) cancelActive = undefined;\n };\n const finish = (result: TipOpenResult): void => {\n if (settled) return;\n settled = true;\n cleanup();\n resolveOpen(result);\n };\n const fail = (error: unknown): void => {\n if (settled) return;\n settled = true;\n cleanup();\n rejectOpen(error);\n };\n const cancel = (): void => finish({ status: 'UNKNOWN' });\n const initialize = (): void => {\n if (!ready || !trustedConfig || initialized || settled) return;\n if (options.provider && !trustedConfig.providers.includes(options.provider)) {\n fail(tipOptionInvalid());\n return;\n }\n initialized = true;\n const init = {\n type: 'viceme:tip-headless-init',\n channel,\n workKey: client.workKey,\n amountCents: options.amountCents,\n ...(options.provider === undefined ? {} : { provider: options.provider }),\n locale,\n appearance,\n };\n try {\n const frameWindow = frame.contentWindow;\n if (!frameWindow) {\n fail(internalTipError());\n return;\n }\n frameWindow.postMessage(init, widgetOrigin);\n } catch {\n fail(internalTipError());\n }\n };\n const onMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== widgetOrigin || event.source !== frame.contentWindow) return;\n if (!initialized) {\n if (!isStrictRecord(event.data, HEADLESS_READY_KEYS)) return;\n if (\n event.data.type !== 'viceme:tip-headless-ready' ||\n event.data.channel !== channel ||\n event.data.workKey !== client.workKey\n ) {\n return;\n }\n ready = true;\n if (readyTimer !== undefined) {\n windowObject.clearTimeout(readyTimer);\n readyTimer = undefined;\n }\n initialize();\n return;\n }\n if (!trustedConfig) return;\n const result = parseHeadlessResult(event.data, channel, trustedConfig, options.amountCents);\n if (result && result.status !== 'UNKNOWN') finish(result);\n };\n\n cancelActive = cancel;\n windowObject.addEventListener('message', onMessage);\n readyTimer = windowObject.setTimeout(() => {\n fail(\n new ViceMeError({\n code: 'TIP_READY_TIMEOUT',\n message: 'Hosted Tip did not become ready in time.',\n retryable: true,\n capability: 'tip',\n }),\n );\n }, HEADLESS_READY_TIMEOUT_MS);\n documentObject.body.append(portal);\n void clientReady.catch((error: unknown) => {\n fail(error instanceof ViceMeError ? error : internalTipError());\n });\n void loadTrustedConfig()\n .then((config) => {\n trustedConfig = config;\n initialize();\n })\n .catch((error: unknown) => {\n fail(error instanceof ViceMeError ? error : internalTipError());\n });\n\n return pending;\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n configController.abort();\n cancelActive?.();\n },\n };\n}\n","/** Stable, allowlisted `viceme:*` DOM events shared by hosted capabilities. */\n\nimport type { ViceMeErrorCode } from './core/errors.ts';\n\nexport interface VicemeReadyDetail {\n clientKey: string;\n workKey: string;\n capabilities: string[];\n version: string;\n}\n\nexport interface VicemeCapabilityReadyDetail {\n clientKey: string;\n instanceKey: string;\n capability: string;\n version: string;\n}\n\nexport interface VicemeErrorDetail {\n clientKey?: string;\n instanceKey?: string;\n capability?: string;\n code: ViceMeErrorCode;\n retryable: boolean;\n requestId?: string;\n}\n\nexport interface VicemeDestroyedDetail {\n clientKey: string;\n instanceKey: string;\n capability: string;\n}\n\nexport interface VicemeWidgetCloseDetail {\n workId: string;\n}\n\nexport interface VicemeTipPaidDetail {\n status: 'PAID';\n work: {\n id: string;\n title: string;\n };\n amountCents: number;\n currency: 'CNY';\n}\n\nexport type VicemeEventType =\n | 'viceme:ready'\n | 'viceme:capability-ready'\n | 'viceme:error'\n | 'viceme:destroyed'\n | 'viceme:widget-close'\n | 'viceme:tip-paid';\n\nexport type VicemeEventDetailMap = {\n 'viceme:ready': VicemeReadyDetail;\n 'viceme:capability-ready': VicemeCapabilityReadyDetail;\n 'viceme:error': VicemeErrorDetail;\n 'viceme:destroyed': VicemeDestroyedDetail;\n 'viceme:widget-close': VicemeWidgetCloseDetail;\n 'viceme:tip-paid': VicemeTipPaidDetail;\n};\n\nconst ALLOWED_KEYS: ReadonlyMap<VicemeEventType, ReadonlySet<string>> = new Map([\n ['viceme:ready', new Set(['clientKey', 'workKey', 'capabilities', 'version'])],\n ['viceme:capability-ready', new Set(['clientKey', 'instanceKey', 'capability', 'version'])],\n [\n 'viceme:error',\n new Set(['clientKey', 'instanceKey', 'capability', 'code', 'retryable', 'requestId']),\n ],\n ['viceme:destroyed', new Set(['clientKey', 'instanceKey', 'capability'])],\n ['viceme:widget-close', new Set(['workId'])],\n ['viceme:tip-paid', new Set(['status', 'work', 'amountCents', 'currency'])],\n]);\n\n/** Strip anything outside the documented allowlist before dispatch. */\nexport function sanitizeDetail(\n type: VicemeEventType,\n detail: VicemeEventDetailMap[VicemeEventType],\n): VicemeEventDetailMap[VicemeEventType] {\n if (type === 'viceme:tip-paid') {\n const paid = detail as VicemeTipPaidDetail;\n return {\n status: paid.status,\n work: { id: paid.work.id, title: paid.work.title },\n amountCents: paid.amountCents,\n currency: paid.currency,\n };\n }\n const allowed = ALLOWED_KEYS.get(type)!;\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(detail)) {\n if (allowed.has(key) && value !== undefined) result[key] = value;\n }\n return result as unknown as VicemeEventDetailMap[VicemeEventType];\n}\n\nexport function dispatchViceMeEvent<K extends VicemeEventType>(\n target: EventTarget,\n type: K,\n detail: VicemeEventDetailMap[K],\n): void {\n const event = new CustomEvent(type, {\n detail: sanitizeDetail(type, detail),\n bubbles: true,\n composed: true,\n cancelable: false,\n });\n target.dispatchEvent(event);\n}\n","import type { ViceMeClient } from '../core/client.ts';\nimport { BUILD_WIDGET_ORIGINS } from '../core/build-endpoints.ts';\nimport { clientDestroyed, ViceMeError } from '../core/errors.ts';\nimport { dispatchViceMeEvent } from '../browser-events.ts';\nimport type { CapabilityMountHandle, CapabilityMountOptions } from '../capability-mount.ts';\nimport { isValidTipWorkTitle } from './validation.ts';\n\ntype WidgetAppearance = 'light' | 'dark';\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nconst TIP_AMOUNT_MIN = 100;\nconst TIP_AMOUNT_MAX = 20_000;\nconst WIDGET_HEIGHT_MAX = 2_048;\nexport const FRAME_READY_TIMEOUT_MS = 8_000;\nconst RESIZE_MESSAGE_KEYS = ['type', 'workId', 'work', 'height'];\nconst CLOSE_MESSAGE_KEYS = ['type', 'workId'];\nconst PAID_MESSAGE_KEYS = ['type', 'workKey', 'status', 'work', 'amountCents', 'currency'];\nconst WORK_KEYS = ['id', 'title'];\n\nfunction isStrictRecord(value: unknown, keys: string[]): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const actualKeys = Object.keys(value);\n return actualKeys.length === keys.length && keys.every((key) => actualKeys.includes(key));\n}\n\nexport async function mount(\n client: ViceMeClient,\n options: CapabilityMountOptions,\n): Promise<CapabilityMountHandle> {\n if (options.signal?.aborted) throw clientDestroyed();\n await client.ready();\n if (options.signal?.aborted) throw clientDestroyed();\n if (!client.hasCapability('tip')) {\n throw new ViceMeError({\n code: 'CAPABILITY_DISABLED',\n message: 'Tip is not available in this SDK build.',\n retryable: false,\n capability: 'tip',\n });\n }\n if (client.region !== 'cn') {\n throw new ViceMeError({\n code: 'CAPABILITY_DISABLED',\n message: 'Tip is not available in this region.',\n retryable: false,\n capability: 'tip',\n });\n }\n const documentObject = options.target.ownerDocument;\n const windowObject = documentObject.defaultView;\n if (!windowObject) {\n throw new ViceMeError({\n code: 'CONFIG_INVALID',\n message: 'Tip requires a browser document.',\n retryable: false,\n capability: 'tip',\n });\n }\n\n const widgetOrigin = BUILD_WIDGET_ORIGINS[client.region];\n const mediaQuery =\n options.theme === 'auto' ? windowObject.matchMedia('(prefers-color-scheme: dark)') : undefined;\n let appearance: WidgetAppearance =\n options.theme === 'auto' ? (mediaQuery?.matches ? 'dark' : 'light') : options.theme;\n let destroyed = false;\n let readyTimer: number | undefined;\n let boundWork: { id: string; title: string } | undefined;\n\n const portal = documentObject.createElement('div');\n portal.dataset.vicemeTip = 'mounted';\n portal.style.all = 'initial';\n portal.style.display = 'block';\n portal.style.width = '100%';\n portal.style.maxWidth = '100%';\n portal.style.contain = 'layout style';\n\n const shadow = portal.attachShadow({ mode: 'open' });\n const frame = documentObject.createElement('iframe');\n const frameUrl = new URL(`/widget/tip/${encodeURIComponent(client.workKey)}`, widgetOrigin);\n frameUrl.searchParams.set('appearance', appearance);\n frame.title = 'ViceMe Tip';\n frame.src = frameUrl.toString();\n frame.loading = 'eager';\n frame.referrerPolicy = 'strict-origin';\n frame.setAttribute(\n 'sandbox',\n 'allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts',\n );\n frame.setAttribute('allow', 'payment');\n frame.style.boxSizing = 'border-box';\n frame.style.display = 'block';\n frame.style.width = '100%';\n frame.style.height = '0px';\n frame.style.margin = '0';\n frame.style.border = '0';\n frame.style.background = 'transparent';\n frame.style.colorScheme = appearance;\n frame.style.pointerEvents = 'none';\n shadow.append(frame);\n\n let resolveReady: (() => void) | undefined;\n let rejectReady: ((error: ViceMeError) => void) | undefined;\n const readiness = new Promise<void>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n readyTimer = windowObject.setTimeout(() => {\n reject(\n new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Hosted Tip widget did not become ready in time.',\n retryable: true,\n capability: 'tip',\n }),\n );\n }, FRAME_READY_TIMEOUT_MS);\n });\n\n const onMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== widgetOrigin || event.source !== frame.contentWindow) return;\n const message = event.data;\n if (typeof message !== 'object' || message === null || Array.isArray(message)) return;\n\n if (isStrictRecord(message, RESIZE_MESSAGE_KEYS) && message.type === 'viceme:widget-resize') {\n if (\n typeof message.workId !== 'string' ||\n !UUID_PATTERN.test(message.workId) ||\n !isStrictRecord(message.work, WORK_KEYS) ||\n message.work.id !== message.workId ||\n !isValidTipWorkTitle(message.work.title) ||\n typeof message.height !== 'number' ||\n !Number.isInteger(message.height) ||\n message.height < 1 ||\n message.height > WIDGET_HEIGHT_MAX ||\n (boundWork !== undefined &&\n (message.work.id !== boundWork.id || message.work.title !== boundWork.title))\n ) {\n return;\n }\n frame.style.height = `${message.height}px`;\n if (boundWork === undefined) {\n boundWork = { id: message.workId, title: message.work.title };\n frame.style.pointerEvents = 'auto';\n if (readyTimer !== undefined) {\n windowObject.clearTimeout(readyTimer);\n readyTimer = undefined;\n }\n resolveReady?.();\n }\n return;\n }\n\n if (isStrictRecord(message, CLOSE_MESSAGE_KEYS) && message.type === 'viceme:widget-close') {\n if (typeof message.workId !== 'string' || message.workId !== boundWork?.id) return;\n dispatchViceMeEvent(options.target, 'viceme:widget-close', { workId: message.workId });\n return;\n }\n if (\n isStrictRecord(message, PAID_MESSAGE_KEYS) &&\n message.type === 'viceme:tip-paid' &&\n message.workKey === client.workKey &&\n isStrictRecord(message.work, WORK_KEYS) &&\n boundWork !== undefined &&\n typeof message.work.id === 'string' &&\n message.work.id === boundWork.id &&\n isValidTipWorkTitle(message.work.title) &&\n message.work.title === boundWork.title &&\n message.status === 'PAID' &&\n typeof message.amountCents === 'number' &&\n Number.isInteger(message.amountCents) &&\n message.amountCents >= TIP_AMOUNT_MIN &&\n message.amountCents <= TIP_AMOUNT_MAX &&\n message.currency === 'CNY'\n ) {\n dispatchViceMeEvent(options.target, 'viceme:tip-paid', {\n status: 'PAID',\n work: { id: message.work.id, title: message.work.title },\n amountCents: message.amountCents,\n currency: 'CNY',\n });\n }\n };\n\n const onAppearanceChange = (event: MediaQueryListEvent): void => {\n appearance = event.matches ? 'dark' : 'light';\n frame.style.colorScheme = appearance;\n frame.contentWindow?.postMessage(\n { type: 'viceme:widget-appearance', appearance },\n widgetOrigin,\n );\n };\n\n let removeAppearanceListener: (() => void) | undefined;\n const onAbort = (): void => {\n rejectReady?.(clientDestroyed());\n cleanup();\n };\n const cleanup = (): void => {\n if (destroyed) return;\n destroyed = true;\n if (readyTimer !== undefined) windowObject.clearTimeout(readyTimer);\n windowObject.removeEventListener('message', onMessage);\n removeAppearanceListener?.();\n options.signal?.removeEventListener('abort', onAbort);\n portal.remove();\n };\n\n try {\n windowObject.addEventListener('message', onMessage);\n if (mediaQuery) {\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onAppearanceChange);\n removeAppearanceListener = () =>\n mediaQuery.removeEventListener('change', onAppearanceChange);\n } else {\n mediaQuery.addListener(onAppearanceChange);\n removeAppearanceListener = () => mediaQuery.removeListener(onAppearanceChange);\n }\n }\n options.signal?.addEventListener('abort', onAbort, { once: true });\n if (options.signal?.aborted) throw clientDestroyed();\n options.target.appendChild(portal);\n await readiness;\n } catch (error) {\n cleanup();\n throw error;\n }\n\n return { capability: 'tip', destroy: cleanup };\n}\n","import type { ViceMeClient } from '../core/client.ts';\nimport { createHeadlessTip } from './headless.ts';\nimport { mount } from './mount.ts';\n\nexport type TipProvider = 'WECHAT_PAY' | 'ALIPAY';\n\nexport interface TipConfig {\n work: {\n id: string;\n title: string;\n };\n workKey: string;\n environment: 'SANDBOX' | 'PRODUCTION';\n currency: 'CNY';\n amount: {\n minCents: 100;\n maxCents: 20_000;\n stepCents: 1;\n };\n providers: TipProvider[];\n}\n\nexport interface TipOpenOptions {\n amountCents: number;\n provider?: TipProvider;\n locale?: 'zh-CN' | 'en-US';\n appearance?: 'light' | 'dark' | 'auto';\n}\n\nexport type TipOpenResult =\n | {\n status: 'PAID';\n work: {\n id: string;\n title: string;\n };\n amountCents: number;\n currency: 'CNY';\n }\n | { status: 'CANCELLED' }\n | { status: 'UNKNOWN' };\n\nexport interface TipClient {\n getConfig(): Promise<TipConfig>;\n open(options: TipOpenOptions): Promise<TipOpenResult>;\n destroy(): void;\n}\n\nexport interface TipMountOptions {\n target: Element;\n theme: 'light' | 'dark' | 'auto';\n signal?: AbortSignal;\n}\n\nexport interface TipMountHandle {\n readonly capability: 'tip';\n destroy(): void;\n}\n\nexport interface TipWidgetCloseDetail {\n workId: string;\n}\n\nexport interface TipPaidDetail {\n status: 'PAID';\n work: {\n id: string;\n title: string;\n };\n amountCents: number;\n currency: 'CNY';\n}\n\nconst mounts = new WeakMap<ViceMeClient, WeakMap<Element, Promise<TipMountHandle>>>();\n\n/** Create a framework-independent controller for a host-rendered Tip flow. */\nexport function createTip(client: ViceMeClient): TipClient {\n return createHeadlessTip(client);\n}\n\n/** Explicit ESM/npm entry point; the CDN loader calls the same mount function. */\nexport function mountTip(client: ViceMeClient, options: TipMountOptions): Promise<TipMountHandle> {\n let byTarget = mounts.get(client);\n if (!byTarget) {\n byTarget = new WeakMap();\n mounts.set(client, byTarget);\n }\n const existing = byTarget.get(options.target);\n if (existing) return existing;\n\n const pending: Promise<TipMountHandle> = mount(client, options)\n .then((raw) => {\n let destroyed = false;\n const handle: TipMountHandle = {\n capability: 'tip' as const,\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n options.signal?.removeEventListener('abort', handle.destroy);\n if (byTarget.get(options.target) === pending) byTarget.delete(options.target);\n raw.destroy();\n },\n };\n options.signal?.addEventListener('abort', handle.destroy, { once: true });\n if (options.signal?.aborted) handle.destroy();\n return handle;\n })\n .catch((error: unknown) => {\n if (byTarget.get(options.target) === pending) byTarget.delete(options.target);\n throw error;\n });\n byTarget.set(options.target, pending);\n return pending;\n}\n"],"names":["TIP_CONFIG_KEYS","TIP_WORK_KEYS","TIP_AMOUNT_KEYS","PUBLIC_ERROR_KEYS","HEADLESS_READY_KEYS","HEADLESS_PAID_KEYS","HEADLESS_TERMINAL_KEYS","HEADLESS_READY_TIMEOUT_MS","TIP_CONFIG_TIMEOUT_MS","TIP_CONFIG_MAX_BYTES","UUID_PATTERN","isStrictRecord","value","keys","actualKeys","key","tipConfigInvalid","ViceMeError","isCredentialsNotAllowedError","input","tipConfigCredentialsNotAllowed","requestId","parseTipConfig","expectedWorkKey","isValidTipWorkTitle","isTipProvider","parseHeadlessResult","channel","config","amountCents","message","internalTipError","tipCapabilityDisabled","readTipConfigBody","response","contentLength","declaredBytes","reader","decoder","bytes","text","chunk","fetchTipConfig","client","ownerSignal","clientDestroyed","controller","abortRequest","timeout","widgetOrigin","BUILD_WIDGET_ORIGINS","requestUrl","contentType","responseOrigin","body","error","copyTipConfig","createHeadlessTip","destroyed","cancelActive","configPromise","configController","isDestroyed","loadTrustedConfig","pending","options","parseTipOpenOptions","tipOptionInvalid","documentObject","windowObject","hostLanguage","locale","requestedAppearance","appearance","clientReady","channelBytes","byte","portal","frame","frameUrl","settled","ready","initialized","trustedConfig","readyTimer","resolveOpen","rejectOpen","resolve","reject","cleanup","onMessage","cancel","finish","result","fail","initialize","init","frameWindow","event","ALLOWED_KEYS","sanitizeDetail","type","detail","paid","allowed","dispatchViceMeEvent","target","TIP_AMOUNT_MIN","TIP_AMOUNT_MAX","WIDGET_HEIGHT_MAX","FRAME_READY_TIMEOUT_MS","RESIZE_MESSAGE_KEYS","CLOSE_MESSAGE_KEYS","PAID_MESSAGE_KEYS","WORK_KEYS","mount","mediaQuery","boundWork","shadow","resolveReady","rejectReady","readiness","onAppearanceChange","removeAppearanceListener","onAbort","mounts","createTip","mountTip","byTarget","existing","raw","handle"],"mappings":"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"}
1
+ {"version":3,"file":"tip.js","sources":["../src/tip/headless.ts","../src/browser-events.ts","../src/tip/mount.ts","../src/tip/index.ts"],"sourcesContent":["import type { ViceMeClient } from '../core/client.ts';\nimport { BUILD_WIDGET_ORIGINS } from '../core/build-endpoints.ts';\nimport { clientDestroyed, ViceMeError } from '../core/errors.ts';\nimport type { TipClient, TipConfig, TipOpenOptions, TipOpenResult } from './index.ts';\nimport {\n isTipProvider,\n isValidTipWorkTitle,\n parseTipOpenOptions,\n tipOptionInvalid,\n} from './validation.ts';\n\nconst TIP_CONFIG_KEYS = ['work', 'workKey', 'environment', 'currency', 'amount', 'providers'];\nconst TIP_WORK_KEYS = ['id', 'title'];\nconst TIP_AMOUNT_KEYS = ['minCents', 'maxCents', 'stepCents'];\nconst PUBLIC_ERROR_KEYS = ['statusCode', 'code', 'message', 'requestId'];\nconst HEADLESS_READY_KEYS = ['type', 'channel', 'workKey'];\nconst HEADLESS_PAID_KEYS = [\n 'type',\n 'channel',\n 'workKey',\n 'status',\n 'work',\n 'amountCents',\n 'currency',\n];\nconst HEADLESS_TERMINAL_KEYS = ['type', 'channel', 'workKey', 'status'];\nconst HEADLESS_READY_TIMEOUT_MS = 8_000;\nconst TIP_CONFIG_TIMEOUT_MS = 8_000;\nconst TIP_CONFIG_MAX_BYTES = 16 * 1024;\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\ntype WidgetAppearance = 'light' | 'dark';\n\nfunction isStrictRecord(value: unknown, keys: string[]): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const actualKeys = Object.keys(value);\n return actualKeys.length === keys.length && keys.every((key) => actualKeys.includes(key));\n}\n\nfunction tipConfigInvalid(): ViceMeError {\n return new ViceMeError({\n code: 'TIP_CONFIG_INVALID',\n message: 'Shop returned an invalid Tip configuration.',\n retryable: false,\n capability: 'tip',\n });\n}\n\nfunction isCredentialsNotAllowedError(input: unknown): input is { requestId: string } {\n if (!isStrictRecord(input, PUBLIC_ERROR_KEYS)) return false;\n return (\n input.statusCode === 400 &&\n input.code === 'TIP_CONFIG_CREDENTIALS_NOT_ALLOWED' &&\n typeof input.message === 'string' &&\n typeof input.requestId === 'string' &&\n input.requestId.length >= 1 &&\n input.requestId.length <= 128\n );\n}\n\nfunction tipConfigCredentialsNotAllowed(requestId: string): ViceMeError {\n return new ViceMeError({\n code: 'TIP_CONFIG_CREDENTIALS_NOT_ALLOWED',\n message: 'Tip configuration requests must not include credentials.',\n retryable: false,\n requestId,\n capability: 'tip',\n });\n}\n\nfunction parseTipConfig(input: unknown, expectedWorkKey: string): TipConfig {\n if (!isStrictRecord(input, TIP_CONFIG_KEYS)) throw tipConfigInvalid();\n if (!isStrictRecord(input.work, TIP_WORK_KEYS)) throw tipConfigInvalid();\n if (\n typeof input.work.id !== 'string' ||\n !UUID_PATTERN.test(input.work.id) ||\n !isValidTipWorkTitle(input.work.title)\n ) {\n throw tipConfigInvalid();\n }\n if (input.workKey !== expectedWorkKey) {\n throw tipConfigInvalid();\n }\n if (input.environment !== 'SANDBOX' && input.environment !== 'PRODUCTION') {\n throw tipConfigInvalid();\n }\n if (\n (input.workKey.startsWith('wrk_test_') && input.environment !== 'SANDBOX') ||\n (input.workKey.startsWith('wrk_live_') && input.environment !== 'PRODUCTION')\n ) {\n throw tipConfigInvalid();\n }\n if (input.currency !== 'CNY') throw tipConfigInvalid();\n if (\n !isStrictRecord(input.amount, TIP_AMOUNT_KEYS) ||\n input.amount.minCents !== 100 ||\n input.amount.maxCents !== 20_000 ||\n input.amount.stepCents !== 1\n ) {\n throw tipConfigInvalid();\n }\n if (\n !Array.isArray(input.providers) ||\n input.providers.length < 1 ||\n !input.providers.every(isTipProvider) ||\n new Set(input.providers).size !== input.providers.length\n ) {\n throw tipConfigInvalid();\n }\n\n return {\n work: { id: input.work.id, title: input.work.title },\n workKey: input.workKey,\n environment: input.environment,\n currency: input.currency,\n amount: { minCents: 100, maxCents: 20_000, stepCents: 1 },\n providers: [...input.providers],\n };\n}\n\nfunction parseHeadlessResult(\n input: unknown,\n channel: string,\n config: TipConfig,\n amountCents: number,\n): TipOpenResult | undefined {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) return undefined;\n const message = input as Record<string, unknown>;\n if (\n message.type !== 'viceme:tip-headless-result' ||\n message.channel !== channel ||\n message.workKey !== config.workKey\n ) {\n return undefined;\n }\n if (message.status === 'PAID') {\n if (\n !isStrictRecord(message, HEADLESS_PAID_KEYS) ||\n !isStrictRecord(message.work, TIP_WORK_KEYS) ||\n message.work.id !== config.work.id ||\n message.work.title !== config.work.title ||\n message.amountCents !== amountCents ||\n message.currency !== 'CNY'\n ) {\n return undefined;\n }\n return {\n status: 'PAID',\n work: { id: config.work.id, title: config.work.title },\n amountCents,\n currency: 'CNY',\n };\n }\n if (\n (message.status === 'CANCELLED' || message.status === 'UNKNOWN') &&\n isStrictRecord(message, HEADLESS_TERMINAL_KEYS)\n ) {\n return { status: message.status };\n }\n return undefined;\n}\n\nfunction internalTipError(): ViceMeError {\n return new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Unable to open the hosted Tip flow.',\n capability: 'tip',\n });\n}\n\nfunction tipCapabilityDisabled(): ViceMeError {\n return new ViceMeError({\n code: 'CAPABILITY_DISABLED',\n message: 'Tip is not available for this Work or region.',\n retryable: false,\n capability: 'tip',\n });\n}\n\nasync function readTipConfigBody(response: Response): Promise<unknown> {\n const contentLength = response.headers.get('content-length');\n if (contentLength !== null) {\n const declaredBytes = Number(contentLength);\n if (\n !Number.isInteger(declaredBytes) ||\n declaredBytes < 0 ||\n declaredBytes > TIP_CONFIG_MAX_BYTES\n ) {\n await response.body?.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw tipConfigInvalid();\n\n const decoder = new TextDecoder('utf-8', { fatal: true });\n let bytes = 0;\n let text = '';\n try {\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) break;\n bytes += chunk.value.byteLength;\n if (bytes > TIP_CONFIG_MAX_BYTES) {\n await reader.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n try {\n text += decoder.decode(chunk.value, { stream: true });\n } catch {\n await reader.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n }\n try {\n text += decoder.decode();\n } catch {\n await reader.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n } finally {\n reader.releaseLock();\n }\n\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw tipConfigInvalid();\n }\n}\n\nasync function fetchTipConfig(client: ViceMeClient, ownerSignal: AbortSignal): Promise<TipConfig> {\n await client.ready();\n if (!client.hasCapability('tip')) throw tipCapabilityDisabled();\n if (client.region !== 'cn') throw tipCapabilityDisabled();\n if (ownerSignal.aborted) throw clientDestroyed();\n const controller = new AbortController();\n const abortRequest = (): void => controller.abort();\n ownerSignal.addEventListener('abort', abortRequest, { once: true });\n const timeout = globalThis.setTimeout(() => controller.abort(), TIP_CONFIG_TIMEOUT_MS);\n const widgetOrigin = BUILD_WIDGET_ORIGINS[client.region];\n const requestUrl = new URL(\n `/v1/work-sdk/${encodeURIComponent(client.workKey)}/tip-config`,\n widgetOrigin,\n );\n try {\n const response = await fetch(requestUrl.toString(), {\n method: 'GET',\n credentials: 'omit',\n redirect: 'error',\n headers: { accept: 'application/json' },\n signal: controller.signal,\n });\n const contentType = response.headers\n .get('content-type')\n ?.split(';', 1)[0]\n ?.trim()\n .toLowerCase();\n let responseOrigin: string | undefined;\n try {\n responseOrigin = response.url ? new URL(response.url).origin : undefined;\n } catch {\n responseOrigin = 'invalid';\n }\n if (response.status !== 200) {\n if (response.status === 404) {\n await response.body?.cancel().catch(() => undefined);\n throw tipCapabilityDisabled();\n }\n if (\n response.status === 400 &&\n contentType === 'application/json' &&\n (!responseOrigin || responseOrigin === widgetOrigin)\n ) {\n let body: unknown;\n try {\n body = await readTipConfigBody(response);\n } catch {\n throw internalTipError();\n }\n if (isCredentialsNotAllowedError(body)) {\n throw tipConfigCredentialsNotAllowed(body.requestId);\n }\n } else {\n await response.body?.cancel().catch(() => undefined);\n }\n throw new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Unable to load Tip configuration.',\n capability: 'tip',\n });\n }\n if (contentType !== 'application/json' || (responseOrigin && responseOrigin !== widgetOrigin)) {\n await response.body?.cancel().catch(() => undefined);\n throw tipConfigInvalid();\n }\n const body = await readTipConfigBody(response);\n return parseTipConfig(body, client.workKey);\n } catch (error) {\n if (ownerSignal.aborted) throw clientDestroyed();\n if (error instanceof ViceMeError) throw error;\n throw internalTipError();\n } finally {\n controller.abort();\n globalThis.clearTimeout(timeout);\n ownerSignal.removeEventListener('abort', abortRequest);\n }\n}\n\nfunction copyTipConfig(config: TipConfig): TipConfig {\n return {\n work: { ...config.work },\n workKey: config.workKey,\n environment: config.environment,\n currency: config.currency,\n amount: { ...config.amount },\n providers: [...config.providers],\n };\n}\n\nexport function createHeadlessTip(client: ViceMeClient): TipClient {\n let destroyed = false;\n let cancelActive: (() => void) | undefined;\n let configPromise: Promise<TipConfig> | undefined;\n const configController = new AbortController();\n const isDestroyed = (): boolean => destroyed || client.state === 'DESTROYED';\n\n const loadTrustedConfig = (): Promise<TipConfig> => {\n if (!configPromise) {\n const pending = fetchTipConfig(client, configController.signal);\n configPromise = pending;\n void pending.then(\n () => {\n if (configPromise === pending) configPromise = undefined;\n },\n () => {\n if (configPromise === pending) configPromise = undefined;\n },\n );\n }\n return configPromise;\n };\n\n return {\n async getConfig(): Promise<TipConfig> {\n if (isDestroyed()) throw clientDestroyed();\n const config = await loadTrustedConfig();\n if (isDestroyed()) throw clientDestroyed();\n return copyTipConfig(config);\n },\n\n open(input: TipOpenOptions): Promise<TipOpenResult> {\n if (isDestroyed()) return Promise.reject(clientDestroyed());\n if (cancelActive) {\n return Promise.reject(\n new ViceMeError({\n code: 'TIP_OPEN_IN_PROGRESS',\n message: 'This Tip client already has an open flow.',\n retryable: false,\n capability: 'tip',\n }),\n );\n }\n if (!client.hasCapability('tip')) {\n return Promise.reject(tipCapabilityDisabled());\n }\n if (client.region !== 'cn') return Promise.reject(tipCapabilityDisabled());\n\n let options: TipOpenOptions;\n try {\n options = parseTipOpenOptions(input);\n } catch (error) {\n return Promise.reject(error);\n }\n\n if (typeof document === 'undefined') {\n return Promise.reject(tipOptionInvalid());\n }\n const documentObject = document;\n const windowObject = documentObject.defaultView;\n if (!documentObject.body || !windowObject) return Promise.reject(tipOptionInvalid());\n const widgetOrigin = BUILD_WIDGET_ORIGINS[client.region];\n const hostLanguage = documentObject.documentElement.lang || windowObject.navigator.language;\n const locale =\n options.locale ?? (hostLanguage.toLowerCase().startsWith('zh') ? 'zh-CN' : 'en-US');\n const requestedAppearance = options.appearance ?? 'auto';\n const appearance: WidgetAppearance =\n requestedAppearance === 'auto'\n ? windowObject.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light'\n : requestedAppearance;\n\n let channel: string;\n let clientReady: Promise<void>;\n try {\n const channelBytes = new Uint8Array(16);\n windowObject.crypto.getRandomValues(channelBytes);\n channel = Array.from(channelBytes, (byte) => byte.toString(16).padStart(2, '0')).join('');\n clientReady = client.ready();\n } catch {\n return Promise.reject(internalTipError());\n }\n\n const portal = documentObject.createElement('div');\n portal.dataset.vicemeTipHeadless = 'open';\n portal.style.all = 'initial';\n portal.style.position = 'fixed';\n portal.style.inset = '0';\n portal.style.display = 'block';\n portal.style.width = '100vw';\n portal.style.height = '100vh';\n portal.style.zIndex = '2147483647';\n\n const frame = documentObject.createElement('iframe');\n const frameUrl = new URL(`/widget/tip/${encodeURIComponent(client.workKey)}`, widgetOrigin);\n frameUrl.searchParams.set('mode', 'headless');\n frameUrl.searchParams.set('channel', channel);\n frameUrl.searchParams.set('appearance', appearance);\n frameUrl.searchParams.set('locale', locale);\n frame.title = 'ViceMe Tip';\n frame.src = frameUrl.toString();\n frame.loading = 'eager';\n frame.referrerPolicy = 'strict-origin';\n frame.setAttribute(\n 'sandbox',\n 'allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts',\n );\n frame.setAttribute('allow', 'payment');\n frame.style.display = 'block';\n frame.style.width = '100%';\n frame.style.height = '100%';\n frame.style.border = '0';\n frame.style.background = 'transparent';\n frame.style.colorScheme = appearance;\n portal.attachShadow({ mode: 'open' }).append(frame);\n\n let settled = false;\n let ready = false;\n let initialized = false;\n let trustedConfig: TipConfig | undefined;\n let readyTimer: number | undefined;\n let resolveOpen: (result: TipOpenResult) => void;\n let rejectOpen: (error: unknown) => void;\n const pending = new Promise<TipOpenResult>((resolve, reject) => {\n resolveOpen = resolve;\n rejectOpen = reject;\n });\n\n const cleanup = (): void => {\n if (readyTimer !== undefined) {\n windowObject.clearTimeout(readyTimer);\n readyTimer = undefined;\n }\n windowObject.removeEventListener('message', onMessage);\n portal.remove();\n if (cancelActive === cancel) cancelActive = undefined;\n };\n const finish = (result: TipOpenResult): void => {\n if (settled) return;\n settled = true;\n cleanup();\n resolveOpen(result);\n };\n const fail = (error: unknown): void => {\n if (settled) return;\n settled = true;\n cleanup();\n rejectOpen(error);\n };\n const cancel = (): void => finish({ status: 'UNKNOWN' });\n const initialize = (): void => {\n if (!ready || !trustedConfig || initialized || settled) return;\n if (options.provider && !trustedConfig.providers.includes(options.provider)) {\n fail(tipOptionInvalid());\n return;\n }\n initialized = true;\n const init = {\n type: 'viceme:tip-headless-init',\n channel,\n workKey: client.workKey,\n amountCents: options.amountCents,\n ...(options.provider === undefined ? {} : { provider: options.provider }),\n locale,\n appearance,\n };\n try {\n const frameWindow = frame.contentWindow;\n if (!frameWindow) {\n fail(internalTipError());\n return;\n }\n frameWindow.postMessage(init, widgetOrigin);\n } catch {\n fail(internalTipError());\n }\n };\n const onMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== widgetOrigin || event.source !== frame.contentWindow) return;\n if (!initialized) {\n if (!isStrictRecord(event.data, HEADLESS_READY_KEYS)) return;\n if (\n event.data.type !== 'viceme:tip-headless-ready' ||\n event.data.channel !== channel ||\n event.data.workKey !== client.workKey\n ) {\n return;\n }\n ready = true;\n if (readyTimer !== undefined) {\n windowObject.clearTimeout(readyTimer);\n readyTimer = undefined;\n }\n initialize();\n return;\n }\n if (!trustedConfig) return;\n const result = parseHeadlessResult(event.data, channel, trustedConfig, options.amountCents);\n if (result && result.status !== 'UNKNOWN') finish(result);\n };\n\n cancelActive = cancel;\n windowObject.addEventListener('message', onMessage);\n readyTimer = windowObject.setTimeout(() => {\n fail(\n new ViceMeError({\n code: 'TIP_READY_TIMEOUT',\n message: 'Hosted Tip did not become ready in time.',\n retryable: true,\n capability: 'tip',\n }),\n );\n }, HEADLESS_READY_TIMEOUT_MS);\n documentObject.body.append(portal);\n void clientReady.catch((error: unknown) => {\n fail(error instanceof ViceMeError ? error : internalTipError());\n });\n void loadTrustedConfig()\n .then((config) => {\n trustedConfig = config;\n initialize();\n })\n .catch((error: unknown) => {\n fail(error instanceof ViceMeError ? error : internalTipError());\n });\n\n return pending;\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n configController.abort();\n cancelActive?.();\n },\n };\n}\n","/** Stable, allowlisted `viceme:*` DOM events shared by hosted capabilities. */\n\nimport type { ViceMeErrorCode } from './core/errors.ts';\n\nexport interface VicemeReadyDetail {\n clientKey: string;\n workKey: string;\n capabilities: string[];\n version: string;\n}\n\nexport interface VicemeCapabilityReadyDetail {\n clientKey: string;\n instanceKey: string;\n capability: string;\n version: string;\n}\n\nexport interface VicemeErrorDetail {\n clientKey?: string;\n instanceKey?: string;\n capability?: string;\n code: ViceMeErrorCode;\n retryable: boolean;\n requestId?: string;\n}\n\nexport interface VicemeDestroyedDetail {\n clientKey: string;\n instanceKey: string;\n capability: string;\n}\n\nexport interface VicemeWidgetCloseDetail {\n workId: string;\n}\n\nexport interface VicemeTipPaidDetail {\n status: 'PAID';\n work: {\n id: string;\n title: string;\n };\n amountCents: number;\n currency: 'CNY';\n}\n\nexport type VicemeEventType =\n | 'viceme:ready'\n | 'viceme:capability-ready'\n | 'viceme:error'\n | 'viceme:destroyed'\n | 'viceme:widget-close'\n | 'viceme:tip-paid';\n\nexport type VicemeEventDetailMap = {\n 'viceme:ready': VicemeReadyDetail;\n 'viceme:capability-ready': VicemeCapabilityReadyDetail;\n 'viceme:error': VicemeErrorDetail;\n 'viceme:destroyed': VicemeDestroyedDetail;\n 'viceme:widget-close': VicemeWidgetCloseDetail;\n 'viceme:tip-paid': VicemeTipPaidDetail;\n};\n\nconst ALLOWED_KEYS: ReadonlyMap<VicemeEventType, ReadonlySet<string>> = new Map([\n ['viceme:ready', new Set(['clientKey', 'workKey', 'capabilities', 'version'])],\n ['viceme:capability-ready', new Set(['clientKey', 'instanceKey', 'capability', 'version'])],\n [\n 'viceme:error',\n new Set(['clientKey', 'instanceKey', 'capability', 'code', 'retryable', 'requestId']),\n ],\n ['viceme:destroyed', new Set(['clientKey', 'instanceKey', 'capability'])],\n ['viceme:widget-close', new Set(['workId'])],\n ['viceme:tip-paid', new Set(['status', 'work', 'amountCents', 'currency'])],\n]);\n\n/** Strip anything outside the documented allowlist before dispatch. */\nexport function sanitizeDetail(\n type: VicemeEventType,\n detail: VicemeEventDetailMap[VicemeEventType],\n): VicemeEventDetailMap[VicemeEventType] {\n if (type === 'viceme:tip-paid') {\n const paid = detail as VicemeTipPaidDetail;\n return {\n status: paid.status,\n work: { id: paid.work.id, title: paid.work.title },\n amountCents: paid.amountCents,\n currency: paid.currency,\n };\n }\n const allowed = ALLOWED_KEYS.get(type)!;\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(detail)) {\n if (allowed.has(key) && value !== undefined) result[key] = value;\n }\n return result as unknown as VicemeEventDetailMap[VicemeEventType];\n}\n\nexport function dispatchViceMeEvent<K extends VicemeEventType>(\n target: EventTarget,\n type: K,\n detail: VicemeEventDetailMap[K],\n): void {\n const event = new CustomEvent(type, {\n detail: sanitizeDetail(type, detail),\n bubbles: true,\n composed: true,\n cancelable: false,\n });\n target.dispatchEvent(event);\n}\n","import type { ViceMeClient } from '../core/client.ts';\nimport { BUILD_WIDGET_ORIGINS } from '../core/build-endpoints.ts';\nimport { clientDestroyed, ViceMeError } from '../core/errors.ts';\nimport { dispatchViceMeEvent } from '../browser-events.ts';\nimport type { CapabilityMountHandle, CapabilityMountOptions } from '../capability-mount.ts';\nimport { isValidTipWorkTitle } from './validation.ts';\nimport { focusIntegratedDanmaku, registerIntegratedTip } from '../engagement/integration.ts';\n\ntype WidgetAppearance = 'light' | 'dark';\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nconst TIP_AMOUNT_MIN = 100;\nconst TIP_AMOUNT_MAX = 20_000;\nconst WIDGET_HEIGHT_MAX = 2_048;\nexport const FRAME_READY_TIMEOUT_MS = 8_000;\nconst RESIZE_MESSAGE_KEYS = ['type', 'workId', 'work', 'height'];\nconst CLOSE_MESSAGE_KEYS = ['type', 'workId'];\nconst PAID_MESSAGE_KEYS = ['type', 'workKey', 'status', 'work', 'amountCents', 'currency'];\nconst WORK_KEYS = ['id', 'title'];\n\nfunction isStrictRecord(value: unknown, keys: string[]): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const actualKeys = Object.keys(value);\n return actualKeys.length === keys.length && keys.every((key) => actualKeys.includes(key));\n}\n\nexport async function mount(\n client: ViceMeClient,\n options: CapabilityMountOptions,\n): Promise<CapabilityMountHandle> {\n if (options.signal?.aborted) throw clientDestroyed();\n await client.ready();\n if (options.signal?.aborted) throw clientDestroyed();\n if (!client.hasCapability('tip')) {\n throw new ViceMeError({\n code: 'CAPABILITY_DISABLED',\n message: 'Tip is not available in this SDK build.',\n retryable: false,\n capability: 'tip',\n });\n }\n if (client.region !== 'cn') {\n throw new ViceMeError({\n code: 'CAPABILITY_DISABLED',\n message: 'Tip is not available in this region.',\n retryable: false,\n capability: 'tip',\n });\n }\n const documentObject = options.target.ownerDocument;\n const windowObject = documentObject.defaultView;\n if (!windowObject) {\n throw new ViceMeError({\n code: 'CONFIG_INVALID',\n message: 'Tip requires a browser document.',\n retryable: false,\n capability: 'tip',\n });\n }\n\n const widgetOrigin = BUILD_WIDGET_ORIGINS[client.region];\n const integrated = options.presentation === 'integrated';\n const mediaQuery =\n options.theme === 'auto' ? windowObject.matchMedia('(prefers-color-scheme: dark)') : undefined;\n let appearance: WidgetAppearance =\n options.theme === 'auto' ? (mediaQuery?.matches ? 'dark' : 'light') : options.theme;\n let destroyed = false;\n let readyTimer: number | undefined;\n let boundWork: { id: string; title: string } | undefined;\n let opened = false;\n let unregisterIntegration: (() => void) | undefined;\n\n const portal = documentObject.createElement('div');\n portal.dataset.vicemeTip = 'mounted';\n portal.style.all = 'initial';\n portal.style.display = integrated ? 'none' : 'block';\n portal.style.width = '100%';\n portal.style.maxWidth = '100%';\n portal.style.contain = integrated ? 'layout style size' : 'layout style';\n if (integrated) {\n portal.style.position = 'fixed';\n portal.style.inset = '0';\n portal.style.height = '100%';\n portal.style.pointerEvents = 'none';\n portal.style.zIndex = '2147483001';\n }\n\n const shadow = portal.attachShadow({ mode: 'open' });\n const frame = documentObject.createElement('iframe');\n const frameUrl = new URL(`/widget/tip/${encodeURIComponent(client.workKey)}`, widgetOrigin);\n frameUrl.searchParams.set('appearance', appearance);\n if (integrated) frameUrl.searchParams.set('mode', 'dialog');\n frame.title = 'ViceMe Tip';\n frame.src = frameUrl.toString();\n frame.loading = 'eager';\n frame.referrerPolicy = 'strict-origin';\n frame.setAttribute(\n 'sandbox',\n 'allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts',\n );\n frame.setAttribute('allow', 'payment');\n frame.style.boxSizing = 'border-box';\n frame.style.display = 'block';\n frame.style.width = '100%';\n frame.style.height = integrated ? '100%' : '0px';\n frame.style.margin = '0';\n frame.style.border = '0';\n frame.style.background = 'transparent';\n frame.style.colorScheme = appearance;\n frame.style.pointerEvents = 'none';\n shadow.append(frame);\n\n const openIntegrated = (): void => {\n if (destroyed || !boundWork) return;\n opened = true;\n portal.style.display = 'block';\n portal.style.pointerEvents = 'auto';\n frame.style.pointerEvents = 'auto';\n frame.contentWindow?.postMessage(\n { type: 'viceme:widget-open', workId: boundWork.id },\n widgetOrigin,\n );\n };\n\n const hideIntegrated = (restoreFocus: boolean): void => {\n if (!integrated) return;\n const wasOpen = opened;\n opened = false;\n portal.style.display = 'none';\n portal.style.pointerEvents = 'none';\n frame.style.pointerEvents = 'none';\n if (restoreFocus && wasOpen) focusIntegratedDanmaku(client, options.target);\n };\n\n let resolveReady: (() => void) | undefined;\n let rejectReady: ((error: ViceMeError) => void) | undefined;\n const readiness = new Promise<void>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n readyTimer = windowObject.setTimeout(() => {\n reject(\n new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Hosted Tip widget did not become ready in time.',\n retryable: true,\n capability: 'tip',\n }),\n );\n }, FRAME_READY_TIMEOUT_MS);\n });\n\n const onMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== widgetOrigin || event.source !== frame.contentWindow) return;\n const message = event.data;\n if (typeof message !== 'object' || message === null || Array.isArray(message)) return;\n\n if (isStrictRecord(message, RESIZE_MESSAGE_KEYS) && message.type === 'viceme:widget-resize') {\n if (\n typeof message.workId !== 'string' ||\n !UUID_PATTERN.test(message.workId) ||\n !isStrictRecord(message.work, WORK_KEYS) ||\n message.work.id !== message.workId ||\n !isValidTipWorkTitle(message.work.title) ||\n typeof message.height !== 'number' ||\n !Number.isInteger(message.height) ||\n message.height < 1 ||\n message.height > WIDGET_HEIGHT_MAX ||\n (boundWork !== undefined &&\n (message.work.id !== boundWork.id || message.work.title !== boundWork.title))\n ) {\n return;\n }\n if (!integrated) frame.style.height = `${message.height}px`;\n if (boundWork === undefined) {\n boundWork = { id: message.workId, title: message.work.title };\n if (!integrated) frame.style.pointerEvents = 'auto';\n if (readyTimer !== undefined) {\n windowObject.clearTimeout(readyTimer);\n readyTimer = undefined;\n }\n resolveReady?.();\n }\n return;\n }\n\n if (isStrictRecord(message, CLOSE_MESSAGE_KEYS) && message.type === 'viceme:widget-close') {\n if (typeof message.workId !== 'string' || message.workId !== boundWork?.id) return;\n hideIntegrated(true);\n dispatchViceMeEvent(options.target, 'viceme:widget-close', { workId: message.workId });\n return;\n }\n if (\n isStrictRecord(message, PAID_MESSAGE_KEYS) &&\n message.type === 'viceme:tip-paid' &&\n message.workKey === client.workKey &&\n isStrictRecord(message.work, WORK_KEYS) &&\n boundWork !== undefined &&\n typeof message.work.id === 'string' &&\n message.work.id === boundWork.id &&\n isValidTipWorkTitle(message.work.title) &&\n message.work.title === boundWork.title &&\n message.status === 'PAID' &&\n typeof message.amountCents === 'number' &&\n Number.isInteger(message.amountCents) &&\n message.amountCents >= TIP_AMOUNT_MIN &&\n message.amountCents <= TIP_AMOUNT_MAX &&\n message.currency === 'CNY'\n ) {\n dispatchViceMeEvent(options.target, 'viceme:tip-paid', {\n status: 'PAID',\n work: { id: message.work.id, title: message.work.title },\n amountCents: message.amountCents,\n currency: 'CNY',\n });\n }\n };\n\n const onAppearanceChange = (event: MediaQueryListEvent): void => {\n appearance = event.matches ? 'dark' : 'light';\n frame.style.colorScheme = appearance;\n frame.contentWindow?.postMessage(\n { type: 'viceme:widget-appearance', appearance },\n widgetOrigin,\n );\n };\n\n let removeAppearanceListener: (() => void) | undefined;\n const onAbort = (): void => {\n rejectReady?.(clientDestroyed());\n cleanup();\n };\n const cleanup = (): void => {\n if (destroyed) return;\n destroyed = true;\n if (readyTimer !== undefined) windowObject.clearTimeout(readyTimer);\n windowObject.removeEventListener('message', onMessage);\n removeAppearanceListener?.();\n const restoreFocus = opened;\n hideIntegrated(false);\n unregisterIntegration?.();\n unregisterIntegration = undefined;\n if (restoreFocus) focusIntegratedDanmaku(client, options.target);\n options.signal?.removeEventListener('abort', onAbort);\n portal.remove();\n };\n\n try {\n windowObject.addEventListener('message', onMessage);\n if (mediaQuery) {\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onAppearanceChange);\n removeAppearanceListener = () =>\n mediaQuery.removeEventListener('change', onAppearanceChange);\n } else {\n mediaQuery.addListener(onAppearanceChange);\n removeAppearanceListener = () => mediaQuery.removeListener(onAppearanceChange);\n }\n }\n options.signal?.addEventListener('abort', onAbort, { once: true });\n if (options.signal?.aborted) throw clientDestroyed();\n options.target.appendChild(portal);\n await readiness;\n if (destroyed || options.signal?.aborted) throw clientDestroyed();\n if (integrated) {\n unregisterIntegration = registerIntegratedTip(client, options.target, {\n open: openIntegrated,\n });\n }\n } catch (error) {\n cleanup();\n throw error;\n }\n\n return { capability: 'tip', destroy: cleanup };\n}\n","import type { ViceMeClient } from '../core/client.ts';\nimport { createHeadlessTip } from './headless.ts';\nimport { mount } from './mount.ts';\n\nexport type TipProvider = 'WECHAT_PAY' | 'ALIPAY';\n\nexport interface TipConfig {\n work: {\n id: string;\n title: string;\n };\n workKey: string;\n environment: 'SANDBOX' | 'PRODUCTION';\n currency: 'CNY';\n amount: {\n minCents: 100;\n maxCents: 20_000;\n stepCents: 1;\n };\n providers: TipProvider[];\n}\n\nexport interface TipOpenOptions {\n amountCents: number;\n provider?: TipProvider;\n locale?: 'zh-CN' | 'en-US';\n appearance?: 'light' | 'dark' | 'auto';\n}\n\nexport type TipOpenResult =\n | {\n status: 'PAID';\n work: {\n id: string;\n title: string;\n };\n amountCents: number;\n currency: 'CNY';\n }\n | { status: 'CANCELLED' }\n | { status: 'UNKNOWN' };\n\nexport interface TipClient {\n getConfig(): Promise<TipConfig>;\n open(options: TipOpenOptions): Promise<TipOpenResult>;\n destroy(): void;\n}\n\nexport interface TipMountOptions {\n target: Element;\n theme: 'light' | 'dark' | 'auto';\n /** Keep Tip hidden until the matching danmaku bar opens its official dialog. */\n presentation?: 'inline' | 'integrated';\n signal?: AbortSignal;\n}\n\nexport interface TipMountHandle {\n readonly capability: 'tip';\n destroy(): void;\n}\n\nexport interface TipWidgetCloseDetail {\n workId: string;\n}\n\nexport interface TipPaidDetail {\n status: 'PAID';\n work: {\n id: string;\n title: string;\n };\n amountCents: number;\n currency: 'CNY';\n}\n\nconst mounts = new WeakMap<ViceMeClient, WeakMap<Element, Promise<TipMountHandle>>>();\n\n/** Create a framework-independent controller for a host-rendered Tip flow. */\nexport function createTip(client: ViceMeClient): TipClient {\n return createHeadlessTip(client);\n}\n\n/** Explicit ESM/npm entry point; the CDN loader calls the same mount function. */\nexport function mountTip(client: ViceMeClient, options: TipMountOptions): Promise<TipMountHandle> {\n let byTarget = mounts.get(client);\n if (!byTarget) {\n byTarget = new WeakMap();\n mounts.set(client, byTarget);\n }\n const existing = byTarget.get(options.target);\n if (existing) return existing;\n\n const pending: Promise<TipMountHandle> = mount(client, options)\n .then((raw) => {\n let destroyed = false;\n const handle: TipMountHandle = {\n capability: 'tip' as const,\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n options.signal?.removeEventListener('abort', handle.destroy);\n if (byTarget.get(options.target) === pending) byTarget.delete(options.target);\n raw.destroy();\n },\n };\n options.signal?.addEventListener('abort', handle.destroy, { once: true });\n if (options.signal?.aborted) handle.destroy();\n return handle;\n })\n .catch((error: unknown) => {\n if (byTarget.get(options.target) === pending) byTarget.delete(options.target);\n throw error;\n });\n byTarget.set(options.target, pending);\n return pending;\n}\n"],"names":["TIP_CONFIG_KEYS","TIP_WORK_KEYS","TIP_AMOUNT_KEYS","PUBLIC_ERROR_KEYS","HEADLESS_READY_KEYS","HEADLESS_PAID_KEYS","HEADLESS_TERMINAL_KEYS","HEADLESS_READY_TIMEOUT_MS","TIP_CONFIG_TIMEOUT_MS","TIP_CONFIG_MAX_BYTES","UUID_PATTERN","isStrictRecord","value","keys","actualKeys","key","tipConfigInvalid","ViceMeError","isCredentialsNotAllowedError","input","tipConfigCredentialsNotAllowed","requestId","parseTipConfig","expectedWorkKey","isValidTipWorkTitle","isTipProvider","parseHeadlessResult","channel","config","amountCents","message","internalTipError","tipCapabilityDisabled","readTipConfigBody","response","contentLength","declaredBytes","reader","decoder","bytes","text","chunk","fetchTipConfig","client","ownerSignal","clientDestroyed","controller","abortRequest","timeout","widgetOrigin","BUILD_WIDGET_ORIGINS","requestUrl","contentType","responseOrigin","body","error","copyTipConfig","createHeadlessTip","destroyed","cancelActive","configPromise","configController","isDestroyed","loadTrustedConfig","pending","options","parseTipOpenOptions","tipOptionInvalid","documentObject","windowObject","hostLanguage","locale","requestedAppearance","appearance","clientReady","channelBytes","byte","portal","frame","frameUrl","settled","ready","initialized","trustedConfig","readyTimer","resolveOpen","rejectOpen","resolve","reject","cleanup","onMessage","cancel","finish","result","fail","initialize","init","frameWindow","event","ALLOWED_KEYS","sanitizeDetail","type","detail","paid","allowed","dispatchViceMeEvent","target","TIP_AMOUNT_MIN","TIP_AMOUNT_MAX","WIDGET_HEIGHT_MAX","FRAME_READY_TIMEOUT_MS","RESIZE_MESSAGE_KEYS","CLOSE_MESSAGE_KEYS","PAID_MESSAGE_KEYS","WORK_KEYS","mount","integrated","mediaQuery","boundWork","opened","unregisterIntegration","shadow","openIntegrated","hideIntegrated","restoreFocus","wasOpen","focusIntegratedDanmaku","resolveReady","rejectReady","readiness","onAppearanceChange","removeAppearanceListener","onAbort","registerIntegratedTip","mounts","createTip","mountTip","byTarget","existing","raw","handle"],"mappings":"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"}
@@ -16,6 +16,8 @@ export interface TransportRequest {
16
16
  authorization?: string;
17
17
  /** Optional memory-only signed-in widget token. */
18
18
  userAuthorization?: string;
19
+ /** Optional memory-only, Work-scoped anonymous purchase authorization. */
20
+ buyerAuthorization?: string;
19
21
  signal?: AbortSignal;
20
22
  /** Per-request timeout; defaults to the transport default. */
21
23
  timeoutMs?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC1C,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAC;CAClC;AAqED,qBAAa,cAAe,YAAW,SAAS;;gBAMlC,OAAO,EAAE,qBAAqB;IAOpC,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA0GrE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAE9E"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC1C,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAC;CAClC;AAqED,qBAAa,cAAe,YAAW,SAAS;;gBAMlC,OAAO,EAAE,qBAAqB;IAOpC,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAkHrE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAE9E"}
package/dist/version.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Kept in sync with `packages/sdk/package.json#version`; a unit test enforces
5
5
  * the match so the loader, release manifest, and npm metadata can never drift.
6
6
  */
7
- export declare const SDK_VERSION = "0.6.2";
7
+ export declare const SDK_VERSION = "0.8.0";
8
8
  /** Public API major carried by this build (loader namespace `v1`). */
9
9
  export declare const API_MAJOR = 1;
10
10
  //# sourceMappingURL=version.d.ts.map
@@ -1,4 +1,4 @@
1
- (function(){"use strict";const ne=new Set(["RATE_LIMITED","NETWORK_TIMEOUT","CHECKOUT_UNAVAILABLE","INTERNAL_ERROR"]);class w extends Error{code;retryable;requestId;capability;constructor(e){super(e.message),this.name="ViceMeError",this.code=e.code,this.retryable=e.retryable??ne.has(e.code),this.requestId=e.requestId,this.capability=e.capability}toJSON(){const e={code:this.code,retryable:this.retryable};return this.requestId!==void 0&&(e.requestId=this.requestId),this.capability!==void 0&&(e.capability=this.capability),e}}function ae(t){return t instanceof w}function g(t){return new w({code:"CONFIG_INVALID",message:t,retryable:!1})}function T(){return new w({code:"CLIENT_DESTROYED",message:"ViceMe client has been destroyed.",retryable:!1})}const G={cn:"https://api.viceme.cn",global:"https://api.viceme.ai"},oe={cn:"https://viceme.cn",global:"https://viceme.ai"},se=new Set(["cn","global"]),ce={cn:G.cn,global:G.global};function le(t){return ce[t]}function H(t){return typeof t=="string"&&/^wrk_(?:test|live)_[A-Za-z0-9_-]{4,119}$/.test(t)}function Y(t){return typeof t=="string"&&se.has(t)}function de(t){if(typeof t!="object"||t===null)throw g("createViceMe expects a configuration object.");const e=t,r=new Set(["workKey","region","signal"]);for(const i of Object.keys(e))if(!r.has(i))throw g(`Unknown configuration field "${i}".`);if(!H(e.workKey))throw g('Configuration field "workKey" must start with "wrk_test_" or "wrk_live_".');if(!Y(e.region))throw g('Configuration field "region" must be "cn" or "global".');if(e.signal!==void 0&&!(e.signal instanceof AbortSignal))throw g('Configuration field "signal" must be an AbortSignal.');return{workKey:e.workKey,region:e.region,signal:e.signal}}const ue=new Set(["data-viceme-work","data-viceme-region","data-viceme-features","data-viceme-target","data-viceme-theme","data-viceme-loader"]),fe=new Set(["light","dark","auto"]),z=["danmaku","tip"];function me(t){for(const b of t.getAttributeNames())if(b.startsWith("data-viceme-")&&!ue.has(b))throw g(`Unknown loader attribute "${b}".`);const e=t.getAttribute("data-viceme-work");if(!H(e))throw g('Loader attribute "data-viceme-work" must be a public Work key.');const r=t.getAttribute("data-viceme-region");if(!Y(r))throw g('Loader attribute "data-viceme-region" must be "cn" or "global".');const i=t.getAttribute("data-viceme-features"),a=i?.split(",")??[],f=new Set(a);if(!i||/\s/.test(i)||a.length!==f.size||a.some(b=>!z.includes(b)))throw g('Loader attribute "data-viceme-features" must contain each of "danmaku" and "tip" at most once.');const n=z.filter(b=>f.has(b)),c=t.getAttribute("data-viceme-target");if(c==="")throw g('Loader attribute "data-viceme-target" must be a CSS selector.');if(c===null)throw g('Loader attribute "data-viceme-target" is required when features are declared.');try{t.matches(c)}catch{throw g('Loader attribute "data-viceme-target" is not a valid CSS selector.')}const d=t.getAttribute("data-viceme-theme");if(d!==null&&!fe.has(d))throw g('Loader attribute "data-viceme-theme" must be "light", "dark", or "auto".');return{workKey:e,region:r,features:n,target:c,theme:d??"auto"}}function $(t,e,r){return`v${t}+${e}+${r}`}class he{#e=new Map;#t=new Map;#r=new Map;#i=0;getClient(e){return this.#e.get(e)}registerClient(e){this.#e.set(e.clientKey,e)}unregisterClient(e){this.#e.delete(e)}getInstance(e){return this.#t.get(e)}findInstance(e,r,i){return this.#r.get(`${e}::${r}`)?.get(i)}registerInstance(e,r,i,a){const f=`${e}::${r}`;let n=this.#r.get(f);n===void 0&&(n=new WeakMap,this.#r.set(f,n));const c=n.get(i);if(c)return c;this.#i+=1;const d={instanceKey:`${e}::${r}::el${this.#i}`,clientKey:e,capability:r,host:i,raw:a,destroyed:!1};return this.#t.set(d.instanceKey,d),n.set(i,d),d}removeInstance(e){const r=this.#t.get(e);if(r)return this.#t.delete(e),this.#r.get(`${r.clientKey}::${r.capability}`)?.delete(r.host),r}instancesForClient(e){return[...this.#t.values()].filter(r=>r.clientKey===e)}}const ye=new Map([["viceme:ready",new Set(["clientKey","workKey","capabilities","version"])],["viceme:capability-ready",new Set(["clientKey","instanceKey","capability","version"])],["viceme:error",new Set(["clientKey","instanceKey","capability","code","retryable","requestId"])],["viceme:destroyed",new Set(["clientKey","instanceKey","capability"])],["viceme:widget-close",new Set(["workId"])],["viceme:tip-paid",new Set(["status","work","amountCents","currency"])]]);function pe(t,e){if(t==="viceme:tip-paid"){const a=e;return{status:a.status,work:{id:a.work.id,title:a.work.title},amountCents:a.amountCents,currency:a.currency}}const r=ye.get(t),i={};for(const[a,f]of Object.entries(e))r.has(a)&&f!==void 0&&(i[a]=f);return i}function P(t,e,r){const i=new CustomEvent(e,{detail:pe(e,r),bubbles:!0,composed:!0,cancelable:!1});t.dispatchEvent(i)}const ge={CREATED:["READY","DESTROYED"],READY:["DEGRADED","DESTROYED"],DEGRADED:["DESTROYED"],DESTROYED:[]};class we{#e="CREATED";#t=new Set;get state(){return this.#e}get destroyed(){return this.#e==="DESTROYED"}transition(e){if(e!==this.#e){if(!ge[this.#e].includes(e))throw new w({code:"INTERNAL_ERROR",message:`Illegal lifecycle transition ${this.#e} -> ${e}.`,retryable:!1});this.#e=e;for(const r of this.#t)r(e)}}assertAlive(){if(this.destroyed)throw T()}subscribe(e){return this.#t.add(e),()=>{this.#t.delete(e)}}clearListeners(){this.#t.clear()}}function be(t,e){if(typeof t!="object"||t===null)throw x();const r=t;if(typeof r.workKey!="string"||!Array.isArray(r.capabilities)||!r.capabilities.every(a=>typeof a=="string"))throw x();if(r.workKey!==e)throw new w({code:"WORK_NOT_FOUND",message:"Work-session response did not match the requested work key.",retryable:!1});const i={work:{key:r.workKey,capabilities:r.capabilities}};if(typeof r.token=="string"&&(i.token=r.token),typeof r.expiresAt=="string"){const a=new Date(r.expiresAt).getTime();Number.isNaN(a)||(i.expiresAt=a)}return i}function x(){return new w({code:"INTERNAL_ERROR",message:"Malformed work-session response.",retryable:!0})}function ve(){return new w({code:"SESSION_EXPIRED",message:"The work session was invalidated before it completed.",retryable:!0})}class Ee{#e;#t;#r;#i;#n=0;#a=!1;constructor(e){this.#e=e,this.#t=e.now??(()=>Date.now())}get snapshot(){return this.#r}#s(){const e=this.#r?.expiresAt;return e!==void 0&&e<=this.#t()}establish(){if(this.#a)return Promise.reject(T());if(this.#r){if(!this.#s())return Promise.resolve(this.#r);this.#r=void 0}if(this.#i)return this.#i;const e=this.#n,r=this.#e.transport.request({method:"POST",path:"/v1/public/work-sdk/sessions",body:{workKey:this.#e.workKey},signal:this.#e.signal,timeoutMs:this.#e.timeoutMs}).then(i=>{this.#c(e);const a=be(i.body,this.#e.workKey);return this.#c(e),this.#r=a,a}).finally(()=>{this.#i===r&&(this.#i=void 0)});return this.#i=r,r}async request(e){const r=await this.establish();if(!r.token)throw x();try{return await this.#l(e,r)}catch(i){if(this.#a)throw T();if(!(i instanceof w)||i.code!=="SESSION_EXPIRED")throw i;this.#r===r&&this.invalidate();const a=await this.establish();if(!a.token)throw x();return this.#l(e,a)}}authenticate(e){if(this.#o(),!this.#r)throw x();this.#r={...this.#r,userToken:e.userToken,user:e.user}}async signOut(){this.#o(),this.invalidate(),await this.establish()}invalidate(){this.#n+=1,this.#r=void 0,this.#i=void 0}destroy(){this.#a||(this.#a=!0,this.#n+=1,this.#r=void 0,this.#i=void 0)}#o(){if(this.#a)throw T()}#c(e){if(this.#o(),e!==this.#n)throw ve()}async#l(e,r){this.#o();try{const i=await this.#e.transport.request({...e,authorization:r.token,userAuthorization:r.userToken,signal:this.#e.signal});return this.#o(),i}catch(i){throw this.#a?T():i}}}const X="0.6.2",K=1,j="viceme-access-layer",B=50;function Ie(t){switch(t){case"SIGN_IN":return{description:"",label:"授权"};case"FOLLOW":return{description:"",label:"关注"};case"CHECKOUT":return{description:"",label:"打开支付"}}}function ke(t){if(!ae(t))return"操作未完成,请重试。";switch(t.code){case"CONFIG_INVALID":return"微信授权配置无效,请稍后重试。";case"AUTH_CANCELLED":return"微信授权已取消,请重试。";case"SESSION_EXPIRED":return"授权会话已过期,请重试。";case"NETWORK_TIMEOUT":return"网络连接超时,请重试。";default:return t.requestId?`操作未完成,请重试。请求 ID:${t.requestId}`:"操作未完成,请重试。"}}function Ae(){if(customElements.get(j))return;class t extends HTMLElement{interaction;connectedCallback(){const r=Ie(this.interaction.action),i=this.attachShadow({mode:"open"});i.innerHTML=`
1
+ (function(){"use strict";const ve=new Set(["RATE_LIMITED","NETWORK_TIMEOUT","CHECKOUT_UNAVAILABLE","INTERNAL_ERROR"]);class w extends Error{code;retryable;requestId;capability;constructor(e){super(e.message),this.name="ViceMeError",this.code=e.code,this.retryable=e.retryable??ve.has(e.code),this.requestId=e.requestId,this.capability=e.capability}toJSON(){const e={code:this.code,retryable:this.retryable};return this.requestId!==void 0&&(e.requestId=this.requestId),this.capability!==void 0&&(e.capability=this.capability),e}}function Ee(t){return t instanceof w}function E(t){return new w({code:"CONFIG_INVALID",message:t,retryable:!1})}function T(){return new w({code:"CLIENT_DESTROYED",message:"ViceMe client has been destroyed.",retryable:!1})}const ie={cn:"https://api.viceme.cn",global:"https://api.viceme.ai"},Ie={cn:"https://viceme.cn",global:"https://viceme.ai"},Ae=new Set(["cn","global"]),ke={cn:ie.cn,global:ie.global};function Ne(t){return ke[t]}function ne(t){return typeof t=="string"&&/^wrk_(?:test|live)_[A-Za-z0-9_-]{4,119}$/.test(t)}function ae(t){return typeof t=="string"&&Ae.has(t)}function Te(t){if(typeof t!="object"||t===null)throw E("createViceMe expects a configuration object.");const e=t,r=new Set(["workKey","region","signal"]);for(const i of Object.keys(e))if(!r.has(i))throw E(`Unknown configuration field "${i}".`);if(!ne(e.workKey))throw E('Configuration field "workKey" must start with "wrk_test_" or "wrk_live_".');if(!ae(e.region))throw E('Configuration field "region" must be "cn" or "global".');if(e.signal!==void 0&&!(e.signal instanceof AbortSignal))throw E('Configuration field "signal" must be an AbortSignal.');return{workKey:e.workKey,region:e.region,signal:e.signal}}const Se=new Set(["data-viceme-work","data-viceme-region","data-viceme-features","data-viceme-target","data-viceme-theme","data-viceme-loader"]),Re=new Set(["light","dark","auto"]),oe=["danmaku","tip"];function Le(t){for(const v of t.getAttributeNames())if(v.startsWith("data-viceme-")&&!Se.has(v))throw E(`Unknown loader attribute "${v}".`);const e=t.getAttribute("data-viceme-work");if(!ne(e))throw E('Loader attribute "data-viceme-work" must be a public Work key.');const r=t.getAttribute("data-viceme-region");if(!ae(r))throw E('Loader attribute "data-viceme-region" must be "cn" or "global".');const i=t.getAttribute("data-viceme-features"),n=i?.split(",")??[],s=new Set(n);if(!i||/\s/.test(i)||n.length!==s.size||n.some(v=>!oe.includes(v)))throw E('Loader attribute "data-viceme-features" must contain each of "danmaku" and "tip" at most once.');const a=oe.filter(v=>s.has(v)),d=t.getAttribute("data-viceme-target");if(d==="")throw E('Loader attribute "data-viceme-target" must be a CSS selector.');if(d===null)throw E('Loader attribute "data-viceme-target" is required when features are declared.');try{t.matches(d)}catch{throw E('Loader attribute "data-viceme-target" is not a valid CSS selector.')}const f=t.getAttribute("data-viceme-theme");if(f!==null&&!Re.has(f))throw E('Loader attribute "data-viceme-theme" must be "light", "dark", or "auto".');return{workKey:e,region:r,features:a,target:d,theme:f??"auto"}}function H(t,e,r){return`v${t}+${e}+${r}`}class Ce{#e=new Map;#r=new Map;#t=new Map;#i=0;getClient(e){return this.#e.get(e)}registerClient(e){this.#e.set(e.clientKey,e)}unregisterClient(e){this.#e.delete(e)}getInstance(e){return this.#r.get(e)}findInstance(e,r,i){return this.#t.get(`${e}::${r}`)?.get(i)}registerInstance(e,r,i,n){const s=`${e}::${r}`;let a=this.#t.get(s);a===void 0&&(a=new WeakMap,this.#t.set(s,a));const d=a.get(i);if(d)return d;this.#i+=1;const f={instanceKey:`${e}::${r}::el${this.#i}`,clientKey:e,capability:r,host:i,raw:n,destroyed:!1};return this.#r.set(f.instanceKey,f),a.set(i,f),f}removeInstance(e){const r=this.#r.get(e);if(r)return this.#r.delete(e),this.#t.get(`${r.clientKey}::${r.capability}`)?.delete(r.host),r}instancesForClient(e){return[...this.#r.values()].filter(r=>r.clientKey===e)}}const Oe=new Map([["viceme:ready",new Set(["clientKey","workKey","capabilities","version"])],["viceme:capability-ready",new Set(["clientKey","instanceKey","capability","version"])],["viceme:error",new Set(["clientKey","instanceKey","capability","code","retryable","requestId"])],["viceme:destroyed",new Set(["clientKey","instanceKey","capability"])],["viceme:widget-close",new Set(["workId"])],["viceme:tip-paid",new Set(["status","work","amountCents","currency"])]]);function _e(t,e){if(t==="viceme:tip-paid"){const n=e;return{status:n.status,work:{id:n.work.id,title:n.work.title},amountCents:n.amountCents,currency:n.currency}}const r=Oe.get(t),i={};for(const[n,s]of Object.entries(e))r.has(n)&&s!==void 0&&(i[n]=s);return i}function j(t,e,r){const i=new CustomEvent(e,{detail:_e(e,r),bubbles:!0,composed:!0,cancelable:!1});t.dispatchEvent(i)}const Ue={CREATED:["READY","DESTROYED"],READY:["DEGRADED","DESTROYED"],DEGRADED:["DESTROYED"],DESTROYED:[]};class De{#e="CREATED";#r=new Set;get state(){return this.#e}get destroyed(){return this.#e==="DESTROYED"}transition(e){if(e!==this.#e){if(!Ue[this.#e].includes(e))throw new w({code:"INTERNAL_ERROR",message:`Illegal lifecycle transition ${this.#e} -> ${e}.`,retryable:!1});this.#e=e;for(const r of this.#r)r(e)}}assertAlive(){if(this.destroyed)throw T()}subscribe(e){return this.#r.add(e),()=>{this.#r.delete(e)}}clearListeners(){this.#r.clear()}}function xe(t,e,r){if(typeof t!="object"||t===null)throw K();const i=t;if(typeof i.workKey!="string"||!Array.isArray(i.capabilities)||!i.capabilities.every(s=>typeof s=="string"))throw K();if(i.workKey!==e)throw new w({code:"WORK_NOT_FOUND",message:"Work-session response did not match the requested work key.",retryable:!1});const n={work:{key:i.workKey,capabilities:i.capabilities}};if(i.accessProtocolVersion!==void 0){if(i.accessProtocolVersion!==3)throw K();const s=z(i.marketCapabilities);if(r!==void 0&&s.market!==(r==="cn"?"CN":"GLOBAL")||!["CN","GLOBAL"].includes(s.market)||!Array.isArray(s.loginMethods)||!s.loginMethods.every(a=>typeof a=="string")||!Array.isArray(s.supportedPriceCurrencies)||!s.supportedPriceCurrencies.every(a=>a==="CNY"||a==="USD")||!["AVAILABLE","PENDING_CHANNEL","DISABLED"].includes(s.checkoutAvailability)||typeof s.anonymousPurchase!="boolean")throw K();n.accessProtocolVersion=3,n.marketCapabilities=s}if(i.creator!==void 0||i.work!==void 0){const s=z(i.creator),a=z(i.work);if(typeof s.displayName!="string"||s.displayName.length===0||!se(s.avatarUrl)||!Number.isInteger(s.publishedWorkCount)||s.publishedWorkCount<0||typeof a.title!="string"||a.title.length===0||typeof a.summary!="string"||!se(a.coverUrl))throw K();n.work.creator={displayName:s.displayName,avatarUrl:s.avatarUrl,publishedWorkCount:s.publishedWorkCount},n.work.details={title:a.title,summary:a.summary,coverUrl:a.coverUrl}}if(typeof i.token=="string"&&(n.token=i.token),typeof i.expiresAt=="string"){const s=new Date(i.expiresAt).getTime();Number.isNaN(s)||(n.expiresAt=s)}return n}function z(t){if(typeof t!="object"||t===null)throw K();return t}function se(t){if(t===null)return!0;if(typeof t!="string")return!1;try{return new URL(t),!0}catch{return!1}}function K(){return new w({code:"INTERNAL_ERROR",message:"Malformed work-session response.",retryable:!0})}function Y(){return new w({code:"SESSION_EXPIRED",message:"The work session was invalidated before it completed.",retryable:!0})}class Pe{#e;#r;#t;#i;#n=0;#a=0;#o=!1;constructor(e){this.#e=e,this.#r=e.now??(()=>Date.now())}get snapshot(){return this.#t}get identityGeneration(){return this.#a}#d(){const e=this.#t?.expiresAt;return e!==void 0&&e<=this.#r()}establish(){if(this.#o)return Promise.reject(T());if(this.#t){if(!this.#d())return this.#t.userExpiresAt!==void 0&&this.#t.userExpiresAt<=this.#r()&&(this.#n+=1,this.#a+=1,this.#t={...this.#t,user:void 0,userToken:void 0,userExpiresAt:void 0}),this.#t.buyerExpiresAt!==void 0&&this.#t.buyerExpiresAt<=this.#r()&&(this.#n+=1,this.#a+=1,this.#t={...this.#t,buyerToken:void 0,buyerExpiresAt:void 0}),Promise.resolve(this.#t);this.#n+=1,this.#t=void 0}if(this.#i)return this.#i;const e=this.#n,r=this.#e.transport.request({method:"POST",path:"/v1/public/work-sdk/sessions",body:{workKey:this.#e.workKey,supportedAccessProtocolVersions:[3]},signal:this.#e.signal,timeoutMs:this.#e.timeoutMs}).then(i=>{this.#c(e);const n=xe(i.body,this.#e.workKey,this.#e.region);return this.#c(e),this.#t=n,n}).finally(()=>{this.#i===r&&(this.#i=void 0)});return this.#i=r,r}async request(e){const r=await this.establish();if(!r.token)throw K();try{return await this.#l(e,r)}catch(i){if(this.#o)throw T();if(e.signal?.aborted||this.#e.signal?.aborted||!(i instanceof w)||i.code!=="SESSION_EXPIRED")throw i;this.#t===r&&this.invalidate();const n=await this.establish();if(!n.token)throw K();return this.#l(e,n)}}authenticate(e){if(this.#s(),!this.#t)throw K();if(e.expiresAt!==void 0&&e.expiresAt<=this.#r())throw Y();this.#n+=1,this.#a+=1,this.#t={...this.#t,userToken:e.userToken,user:e.user,userExpiresAt:e.expiresAt,buyerToken:void 0,buyerExpiresAt:void 0}}identifyBuyer(e,r){if(this.#s(),r!==this.#a||!this.#t||e.expiresAt<=this.#r())throw Y();this.#n+=1,this.#a+=1,this.#t={...this.#t,user:void 0,userToken:void 0,userExpiresAt:void 0,buyerToken:e.buyerToken,buyerExpiresAt:e.expiresAt}}async signOut(){this.#s(),this.#a+=1,this.invalidate(),await this.establish()}invalidate(){this.#n+=1,this.#t=void 0,this.#i=void 0}destroy(){this.#o||(this.#o=!0,this.#n+=1,this.#a+=1,this.#t=void 0,this.#i=void 0)}#s(){if(this.#o)throw T()}#c(e){if(this.#s(),e!==this.#n)throw Y()}async#l(e,r){this.#s();const i=this.#n;try{const n=await this.#e.transport.request({...e,authorization:r.token,userAuthorization:r.userToken,buyerAuthorization:r.buyerExpiresAt!==void 0&&r.buyerExpiresAt>this.#r()?r.buyerToken:void 0,signal:e.signal&&this.#e.signal?AbortSignal.any([e.signal,this.#e.signal]):e.signal??this.#e.signal});return this.#s(),(e.method==="GET"||e.path==="/v1/public/work-sdk/access/check")&&this.#c(i),n}catch(n){throw this.#o?T():n}}}const ce="0.8.0",G=1,X="viceme-access-layer",Q=50;function N(){return typeof document<"u"&&document.documentElement.lang.toLowerCase().startsWith("en")}function Me(t){switch(t){case"SIGN_IN":return{description:"",label:N()?"Sign in":"授权"};case"FOLLOW":return{description:"",label:N()?"Follow":"关注"};case"CHECKOUT":return{description:"",label:N()?"Open checkout":"打开支付"};case"RESOLVE_BUYER":return{description:"",label:N()?"Continue or restore purchase":"继续购买或恢复权益"}}}function le(t){const e=N()?"Unable to complete this action. Please try again.":"操作未完成,请重试。";if(!Ee(t))return e;switch(t.code){case"CONFIG_INVALID":return N()?"This action is not configured correctly. Please try again later.":"操作配置无效,请稍后重试。";case"AUTH_CANCELLED":return N()?"This action was cancelled. Please try again.":"操作已取消,请重试。";case"SESSION_EXPIRED":return N()?"Your session expired. Please try again.":"授权会话已过期,请重试。";case"NETWORK_TIMEOUT":return N()?"The connection timed out. Please try again.":"网络连接超时,请重试。";default:return t.requestId?`${e} ${N()?"Request ID:":"请求 ID:"} ${t.requestId}`:e}}function Ke(){if(customElements.get(X))return;class t extends HTMLElement{interaction;connectedCallback(){const r=Me(this.interaction.action),i=this.attachShadow({mode:"open"});i.innerHTML=`
2
2
  <style>
3
3
  :host {
4
4
  position: fixed;
@@ -117,8 +117,43 @@
117
117
  font-size: 1.125rem;
118
118
  }
119
119
  [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='profile-description'] {
120
- margin-top: 0.75rem;
121
- line-height: 1.625;
120
+ display: none;
121
+ }
122
+ [data-viceme='work'] {
123
+ display: none;
124
+ overflow: hidden;
125
+ margin-top: 1.25rem;
126
+ border: 1px solid #e4e4e7;
127
+ border-radius: 1rem;
128
+ background: #fafafa;
129
+ text-align: left;
130
+ }
131
+ [data-viceme='work'][data-visible='true'] { display: block; }
132
+ [data-viceme='work-cover'] {
133
+ display: block;
134
+ width: 100%;
135
+ aspect-ratio: 16 / 9;
136
+ object-fit: cover;
137
+ background: #f4f4f5;
138
+ }
139
+ [data-viceme='work-cover'][hidden] { display: none; }
140
+ [data-viceme='work-copy'] { padding: 1rem; }
141
+ [data-viceme='work-title'] {
142
+ margin: 0;
143
+ color: #18181b;
144
+ font-size: 1rem;
145
+ font-weight: 700;
146
+ line-height: 1.5;
147
+ }
148
+ [data-viceme='work-summary'] {
149
+ display: -webkit-box;
150
+ overflow: hidden;
151
+ margin: 0.375rem 0 0;
152
+ color: #71717a;
153
+ font-size: 0.875rem;
154
+ line-height: 1.5;
155
+ -webkit-box-orient: vertical;
156
+ -webkit-line-clamp: 2;
122
157
  }
123
158
  [data-viceme='panel'][data-action='SIGN_IN'] [data-viceme='action'] {
124
159
  width: 100%;
@@ -188,12 +223,12 @@
188
223
  @keyframes viceme-enter { from { opacity: 0; transform: translateY(1rem); } }
189
224
  }
190
225
  </style>
191
- <button data-viceme="backdrop" type="button" tabindex="-1" aria-label="关闭"></button>
192
- <section data-viceme="panel" role="dialog" aria-modal="true" aria-label="ViceMe 授权">
193
- <button data-viceme="close" type="button" aria-label="关闭">×</button>
226
+ <button data-viceme="backdrop" type="button" tabindex="-1" aria-label="${N()?"Close":"关闭"}"></button>
227
+ <section data-viceme="panel" role="dialog" aria-modal="true" aria-label="${N()?"ViceMe access":"ViceMe 授权"}">
228
+ <button data-viceme="close" type="button" aria-label="${N()?"Close":"关闭"}">×</button>
194
229
  <div data-viceme="content">
195
230
  <p data-viceme="description"></p>
196
- <section data-viceme="profile" aria-label="创作者">
231
+ <section data-viceme="profile" aria-label="${N()?"Creator":"创作者"}">
197
232
  <div data-viceme="profile-header">
198
233
  <img data-viceme="avatar" hidden />
199
234
  <span data-viceme="avatar-fallback" aria-hidden="true"></span>
@@ -205,12 +240,20 @@
205
240
  </div>
206
241
  <p data-viceme="profile-description"></p>
207
242
  </section>
243
+ <article data-viceme="work">
244
+ <img data-viceme="work-cover" hidden />
245
+ <div data-viceme="work-copy">
246
+ <p data-viceme="work-title"></p>
247
+ <p data-viceme="work-summary"></p>
248
+ </div>
249
+ </article>
208
250
  <p data-viceme="error" role="alert" aria-live="polite"></p>
209
251
  <div data-viceme="actions">
210
252
  <button data-viceme="action" type="button"></button>
211
253
  </div>
212
254
  </div>
213
255
  <iframe data-viceme="frame" title="" referrerpolicy="no-referrer" allow="payment"></iframe>
256
+ <button data-viceme="continue" type="button" hidden>${N()?"Continue in this page":"在当前页面继续"}</button>
214
257
  </section>
215
- `;const a=i.querySelector("[data-viceme='panel']");a.dataset.action=this.interaction.action,a.dataset.frame="false";const f=i.querySelector("[data-viceme='description']");f.textContent=r.description;const n=i.querySelector("[data-viceme='action']"),c=n.parentElement,d=i.querySelector("[data-viceme='close']"),b=i.querySelector("[data-viceme='backdrop']"),N=i.querySelector("[data-viceme='error']"),o=i.querySelector("[data-viceme='frame']"),_=i.querySelector("[data-viceme='profile']"),D=i.querySelector("[data-viceme='avatar']"),l=i.querySelector("[data-viceme='avatar-fallback']"),u=i.querySelector("[data-viceme='profile-name']"),h=i.querySelector("[data-viceme='profile-description']"),s=i.querySelector("[data-viceme='profile-stats']");n.textContent=r.label,n.hidden=!1,c.dataset.single="true";const y=r.label;o.title=this.interaction.action==="SIGN_IN"?"登录授权":"支付";const p=this.interaction.followTarget;if(p){a.setAttribute("aria-label",this.interaction.action==="SIGN_IN"?`授权 ${p.displayName}`:`关注 ${p.displayName}`),_.dataset.visible="true",u.textContent=p.displayName;const m=[...p.description??""];h.textContent=m.length>B?`${m.slice(0,B).join("")}…`:m.join(""),m.length>B&&(h.title=p.description),s.textContent=`${p.workCount} 个作品`,l.textContent=p.displayName.trim().slice(0,1)||"V",p.avatarUrl&&(D.src=p.avatarUrl,D.alt=`${p.displayName}的头像`,D.hidden=!1,l.hidden=!0)}let E=null,S=!1;const U=m=>{S||(S=!0,this.interaction.signal?.removeEventListener("abort",A),this.dispatchEvent(new CustomEvent("viceme:access-layer-close",{detail:m})))},A=()=>{E?.cancel(),U("dismissed")};this.interaction.signal?.addEventListener("abort",A,{once:!0}),this.interaction.signal?.aborted&&queueMicrotask(A),b.addEventListener("click",A),d.addEventListener("click",A),this.addEventListener("keydown",m=>{if(m.key==="Escape"&&A(),m.key==="Tab"){if(m.preventDefault(),E?.type==="frame"){o.focus();return}const I=[d,...n.hidden?[]:[n]].filter(F=>!F.disabled&&!F.hidden);if(I.length===0)return;const q=I.indexOf(i.activeElement),O=m.shiftKey?-1:1;I[(q+O+I.length)%I.length]?.focus()}});const M=async()=>{n.disabled=!0,n.setAttribute("aria-busy","true"),n.textContent="正在打开…",N.textContent="";try{const m=await this.interaction.perform();if(S||this.interaction.signal?.aborted){m.type!=="completed"&&m.cancel();return}m.type==="frame"?(E=m,a.dataset.frame="true",o.src=m.url,o.focus(),await m.completion):m.type==="external"&&(E=m,await m.completion),U("acted")}catch(m){if(S)return;E?.cancel(),E=null,a.dataset.frame="false",o.removeAttribute("src"),N.textContent=ke(m),n.hidden=!1,n.disabled=!1,n.removeAttribute("aria-busy"),n.textContent=y,n.focus()}};n.addEventListener("click",M),queueMicrotask(()=>n.focus())}}customElements.define(j,t)}const Te=async t=>{if(typeof document>"u"||typeof customElements>"u"||t.signal?.aborted)return"dismissed";Ae();const e=document.createElement(j);e.interaction=t;const r=document.documentElement.style.overflow,i=document.activeElement instanceof HTMLElement?document.activeElement:null;document.documentElement.style.overflow="hidden",document.body.append(e);try{return await new Promise(a=>{e.addEventListener("viceme:access-layer-close",f=>a(f.detail),{once:!0})})}finally{e.remove(),document.documentElement.style.overflow=r,i?.focus()}};function L(t){if(typeof t!="object"||t===null)throw k();return t}function k(){return new w({code:"INTERNAL_ERROR",message:"Malformed public API response.",retryable:!0})}function Se(t){const e=L(t);if(typeof e.id!="string"||!(typeof e.displayName=="string"||e.displayName===null)||!(typeof e.avatarUrl=="string"||e.avatarUrl===null))throw k();return{subject:e.id,nickname:e.displayName,avatarUrl:e.avatarUrl}}function Q(t){const e=L(t);if(typeof e.following!="boolean"||!(typeof e.followedAt=="string"||e.followedAt===null))throw k();const r=L(e.creator);if(typeof r.displayName!="string"||!(typeof r.avatarUrl=="string"||r.avatarUrl===null)||!(typeof r.description=="string"||r.description===null)||!Number.isInteger(r.publishedWorkCount)||r.publishedWorkCount<0)throw k();return{following:e.following,followedAt:e.followedAt,target:{kind:"CREATOR",displayName:r.displayName,avatarUrl:r.avatarUrl,description:r.description,workCount:r.publishedWorkCount}}}function Re(t){const e=L(t),r=new Set(["PUBLIC","OWNER","FOLLOWING","ENTITLED","AUTH_REQUIRED","FOLLOW_REQUIRED","PURCHASE_REQUIRED","FEATURE_NOT_FOUND","FEATURE_DISABLED"]),i=new Set([null,"SIGN_IN","FOLLOW","CHECKOUT"]);if(typeof e.allowed!="boolean"||typeof e.reason!="string"||!r.has(e.reason)||!i.has(e.nextAction))throw k();return{allowed:e.allowed,reason:e.reason,nextAction:e.nextAction}}function Ne(t){const e=L(t);if(typeof e.featureKey!="string"||!/^[a-z][a-z0-9_-]{1,63}$/.test(e.featureKey)||typeof e.title!="string"||e.title.trim().length===0||e.title.length>120||!(e.policyType==="PUBLIC"||e.policyType==="FOLLOW_OWNER"||e.policyType==="WORK_ENTITLEMENT"))throw k();const r=e.price===null?null:L(e.price);if(r!==null&&(!Number.isInteger(r.amountCents)||r.amountCents<=0||r.currency!=="CNY")||e.policyType==="WORK_ENTITLEMENT"!=(r!==null))throw k();return{featureKey:e.featureKey,title:e.title,policy:{type:e.policyType},price:r===null?null:{amountCents:r.amountCents,currency:"CNY"}}}function Oe(){const t=crypto.getRandomValues(new Uint8Array(32));return Le(t)}function Le(t){let e="";for(const r of t)e+=String.fromCharCode(r);return btoa(e).replaceAll("+","-").replaceAll("/","_").replace(/=+$/,"")}function Ce(){return typeof document<"u"&&document.documentElement.lang.toLowerCase()==="en-us"?"en-US":"zh-CN"}function _e(t){const e=()=>new w({code:"AUTH_CANCELLED",message:"The interactive action was cancelled.",retryable:!1}),r=l=>{if(t.signal.aborted)return Promise.reject(T());let u;const h=new Promise((y,p)=>{u=()=>p(T()),t.signal.addEventListener("abort",u,{once:!0}),t.signal.aborted&&u()});let s;try{s=(t.presenter??Te)({...l,signal:t.signal})}catch(y){s=Promise.reject(y)}return Promise.race([s,h]).then(y=>{if(t.signal.aborted)throw T();return y}).finally(()=>{u&&t.signal.removeEventListener("abort",u)})},i=(l,u,h,s,y,p)=>{if(typeof window>"u")throw new w({code:"CONFIG_INVALID",message:"Interactive access requires a browser window.",retryable:!1});let E=!0,S,U;const A=()=>{E&&(E=!1,window.removeEventListener("message",m))},M=new Promise((R,I)=>{S=R,U=I}),m=R=>{if(!E||R.origin!==u||typeof R.data!="object"||R.data===null)return;const I=R.data;if(!(I.workKey!==t.workKey||I.channel!==h)){if(I.type===`viceme:${s}:ready`){R.source&&"postMessage"in R.source&&R.source.postMessage({type:`viceme:${s}:init`,workKey:t.workKey,channel:h,...y},u);return}if(I.type===`viceme:${s}:cancelled`){A(),U(e());return}I.type===`viceme:${s}:complete`&&(A(),p(I).then(S,U))}};return window.addEventListener("message",m),{type:"frame",url:l,completion:M,cancel(){A(),S()}}},a=async()=>{if(await t.ready(),typeof window>"u")throw new w({code:"CONFIG_INVALID",message:"Interactive access requires a browser window.",retryable:!1});const l=Oe(),u=new URL("/sdk/login",t.widgetOrigin);u.search=new URLSearchParams({workKey:t.workKey,channel:l,parentOrigin:window.location.origin,locale:Ce()}).toString();const h=t.session.snapshot?.token;if(!h)throw k();return i(u.toString(),t.widgetOrigin,l,"auth",{workSessionToken:h},async s=>{if(typeof s.userToken!="string")throw k();t.session.authenticate({userToken:s.userToken,user:Se(s.user)})})},f=async()=>(await t.ready(),Q((await t.session.request({method:"GET",path:"/v1/public/work-sdk/follow"})).body)),n=async()=>(await t.ready(),Q((await t.session.request({method:"PUT",path:"/v1/public/work-sdk/follow"})).body)),c={async getState(){await t.ready();const l=t.session.snapshot?.user??null;return{authenticated:l!==null,user:l}},async signIn(){if(await r({featureKey:"auth",reason:"AUTH_REQUIRED",action:"SIGN_IN",perform:a})==="dismissed")throw e();return this.getState()},async signOut(){await t.ready(),await t.session.signOut()}},d={getState:f,follow:n,unfollow:async()=>{throw new w({code:"CAPABILITY_DISABLED",message:"Unfollow is not exposed by website access.",retryable:!1})}},b=async l=>{await t.ready();const u=L((await t.session.request({method:"POST",path:"/v1/public/work-sdk/access/check",body:{featureKeys:l}})).body),h=L(u.decisions);return Object.fromEntries(Object.entries(h).map(([s,y])=>[s,Re(y)]))},N=async(l,u={})=>{await t.ready();const h={featureKey:l,locale:u.locale??"zh-CN"},s=L((await t.session.request({method:"POST",path:"/v1/public/work-sdk/checkout",body:h})).body);if(typeof s.checkoutUrl!="string"||typeof s.alreadyOwned!="boolean"||!(s.expiresAt===null||typeof s.expiresAt=="string"&&!Number.isNaN(Date.parse(s.expiresAt)))||s.alreadyOwned!==(s.expiresAt===null))throw k();let y;try{y=new URL(s.checkoutUrl)}catch{throw k()}if(!s.alreadyOwned&&(y.protocol!=="https:"||y.origin!==t.widgetOrigin))throw k();return{checkoutUrl:s.checkoutUrl,alreadyOwned:s.alreadyOwned,expiresAt:s.expiresAt}},o=(l,u)=>{if(l.alreadyOwned)return{type:"completed"};const h=Date.parse(l.expiresAt);if(typeof window>"u")throw new w({code:"CONFIG_INVALID",message:"Hosted checkout requires a browser window.",retryable:!1});let s=!0,y,p,E,S;const U=new Promise((O,F)=>{E=O,S=F}),A=()=>{y&&clearTimeout(y),p&&clearTimeout(p),document.removeEventListener("visibilitychange",I)},M=()=>{s&&(s=!1,A(),S(new w({code:"SESSION_EXPIRED",message:"Hosted checkout session expired.",retryable:!0})))},m=()=>{if(!s||document.visibilityState==="hidden")return;const O=h-t.now();if(O<=0){M();return}y=setTimeout(()=>{R()},Math.min(1500,O))},R=async()=>{if(s)try{const O=(await b([u]))[u];if(!O)throw k();if(O.allowed){s=!1,A(),E();return}m()}catch(O){s=!1,A(),S(O)}};function I(){if(s){if(document.visibilityState==="hidden"){y&&clearTimeout(y),y=void 0;return}m()}}document.addEventListener("visibilitychange",I);const q=h-t.now();return q<=0?M():(p=setTimeout(M,q),m()),{type:"frame",url:l.checkoutUrl,completion:U,cancel(){s&&(s=!1,A(),E())}}};return{auth:c,follow:d,access:{async getFeatures(){await t.ready();const l=L((await t.session.request({method:"GET",path:"/v1/public/work-sdk/access/features"})).body);if(!Array.isArray(l.features)||l.features.length>100)throw k();return l.features.map(Ne)},async check(l){const h=(await b([l]))[l];if(!h)throw k();return h},checkMany:b,async require(l){let u=await this.check(l);for(let h=0;!u.allowed&&u.nextAction&&h<3;h+=1){const s=u.nextAction,y=s==="FOLLOW"?(await d.getState()).target:void 0,p=s==="CHECKOUT"?await N(l):void 0;if(p?.alreadyOwned){u=await this.check(l);continue}if(await r({featureKey:l,reason:u.reason,action:s,...y?{followTarget:y}:{},perform:async()=>s==="SIGN_IN"?a():s==="FOLLOW"?(await d.follow(),{type:"completed"}):o(p,l)})==="dismissed")return u;u=await this.check(l)}return u},async refresh(){await t.ready()}},checkout:{async open(l){const u=await N(l.featureKey,l);if(u.alreadyOwned)return u;if(await r({featureKey:l.featureKey,reason:"PURCHASE_REQUIRED",action:"CHECKOUT",perform:async()=>o(u,l.featureKey)})==="dismissed")throw e();return u}}}}function J(t){t instanceof Z&&t.markDegraded()}class De extends DOMException{constructor(){super("ViceMe client destroyed.","AbortError")}}class Z{#e=new we;#t;#r;#i=new AbortController;#n;auth;access;checkout;#a;constructor(e){this.#r=e.config,this.#t=new Ee({workKey:e.config.workKey,transport:e.transport,signal:this.#i.signal,...e.now!==void 0?{now:e.now}:{}});const r=_e({session:this.#t,workKey:e.config.workKey,widgetOrigin:oe[e.config.region],now:e.now??(()=>Date.now()),presenter:e.presenter,signal:this.#i.signal,ready:()=>this.#s()});this.auth=r.auth,this.access=r.access,this.checkout=r.checkout;const i=e.config.signal;if(i){const a=()=>{this.#i.abort(i.reason instanceof Error?i.reason:new DOMException("Caller signal aborted.","AbortError"))};i.aborted?a():(i.addEventListener("abort",a,{once:!0}),this.#a=()=>{i.removeEventListener("abort",a)})}}get version(){return X}get workKey(){return this.#r.workKey}get region(){return this.#r.region}get state(){return this.#e.state}get apiMajor(){return K}ready(){return this.#e.destroyed?Promise.reject(T()):(this.#n||(this.#e.transition("READY"),this.#n=Promise.resolve()),this.#n)}async#s(){if(this.#e.destroyed)throw T();await this.ready();try{if(await this.#t.establish(),this.#e.destroyed)throw T()}catch(e){throw this.#e.destroyed?T():(this.#t.invalidate(),e)}}hasCapability(e){if(this.#e.destroyed)return!1;const r=this.#t.snapshot?.work.capabilities;return e==="danmaku"||e==="tip"||r?.includes(e)===!0}get capabilities(){return this.#t.snapshot?.work.capabilities??[]}markDegraded(){this.#e.state==="READY"&&this.#e.transition("DEGRADED")}get sessionSnapshot(){return this.#t.snapshot}destroy(){this.#e.destroyed||(this.#e.transition("DESTROYED"),this.#i.abort(new De),this.#t.destroy(),this.#e.clearListeners(),this.#n=void 0,this.#a?.(),this.#a=void 0)}}const Ue=1e4,Me=new Map([[400,"CONFIG_INVALID"],[401,"SESSION_EXPIRED"],[403,"CAPABILITY_DISABLED"],[404,"WORK_NOT_FOUND"],[409,"CONFIG_INVALID"],[422,"CONFIG_INVALID"],[429,"RATE_LIMITED"]]),xe=new Set(["CONFIG_INVALID","WORK_NOT_FOUND","CAPABILITY_DISABLED","SESSION_EXPIRED","AUTH_REQUIRED","AUTH_CANCELLED","RETURN_URL_NOT_ALLOWED","RATE_LIMITED","NETWORK_TIMEOUT","CHECKOUT_UNAVAILABLE","INTERNAL_ERROR"]);function Ke(t){if(typeof t!="object"||t===null)return{};const e=t,r=typeof e.error=="object"&&e.error!==null?e.error:e,i={};return typeof r.code=="string"&&xe.has(r.code)&&(i.code=r.code),typeof r.message=="string"&&(i.message=r.message.slice(0,200)),typeof r.retryable=="boolean"&&(i.retryable=r.retryable),typeof r.requestId=="string"&&(i.requestId=r.requestId),i}function Pe(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`req-${Math.random().toString(36).slice(2)}`}class qe{#e;#t;#r;#i;constructor(e){this.#e=e.apiBaseUrl.replace(/\/+$/,""),this.#t=e.fetchImpl??globalThis.fetch.bind(globalThis),this.#r=e.defaultTimeoutMs??Ue,this.#i=e.generateRequestId??Pe}async request(e){if(e.signal?.aborted)throw this.#n(e.signal);const r=e.timeoutMs??this.#r,i=new AbortController;let a=!1;const f=setTimeout(()=>{a=!0,i.abort(new ee)},r),n=()=>i.abort(new ee(!1));e.signal?.addEventListener("abort",n,{once:!0});const c=this.#i();try{const d=await this.#t(`${this.#e}${e.path}`,{method:e.method,credentials:"omit",mode:"cors",headers:{"content-type":"application/json","x-client-request-id":c,...e.authorization!==void 0?{authorization:`Bearer ${e.authorization}`}:{},...e.userAuthorization!==void 0?{"x-viceme-user-token":e.userAuthorization}:{}},body:e.body!==void 0?JSON.stringify(e.body):void 0,signal:i.signal});let b;try{b=await d.json()}catch(o){if(e.signal?.aborted||a)throw o;b=void 0}const N=d.headers.get("x-request-id")??void 0;if(!d.ok){const o=Ke(b),_=o.code??Me.get(d.status)??"INTERNAL_ERROR";throw new w({code:_,message:o.message??"Public API request failed.",retryable:o.retryable,requestId:o.requestId??N})}return{status:d.status,body:b,requestId:N}}catch(d){throw e.signal?.aborted?this.#n(e.signal):a?new w({code:"NETWORK_TIMEOUT",message:"Public API request timed out.",retryable:!0,requestId:c}):d instanceof w?d:d instanceof DOMException&&d.name==="AbortError"?new DOMException("ViceMe request aborted by caller.","AbortError"):new w({code:"INTERNAL_ERROR",message:"Public API request failed.",retryable:!0,requestId:c})}finally{clearTimeout(f),e.signal?.removeEventListener("abort",n)}}#n(e){return e.reason instanceof Error?e.reason:new DOMException("ViceMe request aborted by caller.","AbortError")}}function Fe(t){return new qe(t)}class ee extends DOMException{constructor(e=!0){super(e?"ViceMe request timed out.":"ViceMe request aborted.","AbortError")}}function $e(t){const e=de(t),r=le(e.region),i=Fe({apiBaseUrl:r});return new Z({config:e,transport:i})}const je=8e3,Be=8e3,te={danmaku:"danmaku.js",tip:"tip.js"},Ve={danmaku:"mountDanmaku",tip:"mountTip"},re=Symbol.for("viceme.loader.state.v1");function v(){const e=globalThis[re];if(e)return e;const r={registry:new he,queue:{current:Promise.resolve()}};return Object.defineProperty(globalThis,re,{value:r,writable:!0,configurable:!0,enumerable:!1}),r}function V(t){if(!t.destroyed){t.destroyed=!0,v().registry.removeInstance(t.instanceKey);try{t.raw.destroy()}finally{P(t.host,"viceme:destroyed",{clientKey:t.clientKey,instanceKey:t.instanceKey,capability:t.capability})}}}function We(t){return{instanceKey:t.instanceKey,capability:t.capability,destroy:()=>V(t)}}function W(t,e,r){Object.defineProperty(t,e,{value:r,writable:!0,configurable:!0,enumerable:!1})}function Ge(t){let r=globalThis.ViceMe;r||(r={},W(globalThis,"ViceMe",r));let i=r.versions;i||(i={},W(r,"versions",i));const a=i[`v${K}`];if(a)return a;const f={version:t,whenReady(n){const c=v().registry.getClient(n);return c?c.ready.then(()=>c.client):Promise.reject(g(`Unknown clientKey "${n}".`))},getInstance(n){const c=v().registry.getInstance(n);return c?We(c):void 0},destroyInstance(n){const c=v().registry.getInstance(n);c&&V(c)},destroyClient(n){for(const d of v().registry.instancesForClient(n))V(d);const c=v().registry.getClient(n);for(const d of c?.pendingMounts??[])d.abort();v().registry.unregisterClient(n),c?.client.destroy()}};return W(i,`v${K}`,f),f}function He(){return document.readyState!=="loading"?Promise.resolve():new Promise(t=>{document.addEventListener("DOMContentLoaded",()=>t(),{once:!0})})}async function Ye(t){const e=new AbortController,r=globalThis.setTimeout(()=>e.abort(),je);try{let i;try{i=await fetch(t,{credentials:"omit",signal:e.signal})}catch{if(e.signal.aborted)throw new w({code:"INTERNAL_ERROR",message:"Release manifest request timed out.",retryable:!0});i={ok:!1,status:0}}return{manifest:await ze(i),baseUrl:t}}finally{globalThis.clearTimeout(r)}}async function ze(t){if(!t.ok)throw g(`Release manifest is not available (HTTP ${t.status}).`);const e=await t.json();if(typeof e!="object"||e===null||typeof e.version!="string"||typeof e.apiMajor!="number"||typeof e.features!="object"||e.features===null)throw g("Release manifest is malformed.");const r=e;if(r.version!==X)throw g("Release manifest version does not match this loader.");if(r.apiMajor!==K)throw g("Release manifest major version does not match this loader.");const i=Object.keys(r.features).sort();if(i.length!==2||i[0]!=="danmaku"||i[1]!=="tip"||r.features.danmaku!==te.danmaku||r.features.tip!==te.tip)throw g("Release manifest features must be exactly danmaku.js and tip.js.");return r}const Xe=new Set(["CONFIG_INVALID","CAPABILITY_DISABLED","CLIENT_DESTROYED","INTERNAL_ERROR"]);function Qe(t){if(typeof t=="object"&&t!==null){const e=t;if(typeof e.code=="string"&&Xe.has(e.code)&&typeof e.retryable=="boolean"){const r={code:e.code,retryable:e.retryable};return typeof e.requestId=="string"&&(r.requestId=e.requestId),typeof e.capability=="string"&&(r.capability=e.capability),r}}return{code:"INTERNAL_ERROR",retryable:!0}}function C(t,e,r={}){P(t,"viceme:error",{...Qe(e),...r})}function Je(t,e,r){let i,a;const f=new Promise((n,c)=>{if(a=()=>c(T()),e.signal.aborted){a();return}e.signal.addEventListener("abort",a,{once:!0}),i=globalThis.setTimeout(()=>{c(new w({code:"INTERNAL_ERROR",message:`Capability "${r}" did not load and mount in time.`,retryable:!0,capability:r})),e.abort()},Be)});return Promise.race([t,f]).finally(()=>{i!==void 0&&globalThis.clearTimeout(i),a&&e.signal.removeEventListener("abort",a)})}async function Ze(t){let e;try{e=me(t)}catch(o){C(document,o);return}if(!t.src){C(document,g("Loader script requires a src URL."));return}const r=new URL("manifest.json",t.src);let i,a;try{({manifest:i,baseUrl:a}=await Ye(r))}catch(o){C(document,o,{clientKey:$(K,e.region,e.workKey)});return}await He();let f;try{const o=document.querySelectorAll(e.target);if(o.length===0)throw g(`Loader target "${e.target}" matched no element; no node was created.`);if(o.length>1)throw g(`Loader target "${e.target}" matched ${o.length} elements; exactly one is required.`);f=o[0]}catch(o){C(document,o,{clientKey:$(i.apiMajor,e.region,e.workKey)});return}const n=$(i.apiMajor,e.region,e.workKey);Ge(i.version);let c=v().registry.getClient(n),d;if(c)d=c.client;else{try{d=$e({workKey:e.workKey,region:e.region})}catch(_){C(f,_,{clientKey:n});return}const o=d.ready();o.catch(()=>{}),c={clientKey:n,client:d,ready:o,pendingMounts:new Set},v().registry.registerClient(c)}try{await c.ready}catch(o){v().registry.unregisterClient(n),d.destroy(),C(f,o,{clientKey:n});return}if(v().registry.getClient(n)!==c)return;const b=async o=>{if(v().registry.findInstance(n,o,f))return;const _=i.features[o];if(typeof _!="string"){J(d),C(f,new w({code:"CAPABILITY_DISABLED",message:`Capability "${o}" is not part of this release.`,retryable:!1,capability:o}),{clientKey:n,capability:o});return}const D=new AbortController;c.pendingMounts.add(D);try{const l=(async()=>{const y=await import(new URL(_,a).href),p=Ve[o],E=y[p];if(typeof E!="function")throw g(`Capability chunk "${o}" does not export ${p}().`);if(v().registry.getClient(n)!==c)throw T();return await E(d,{target:f,theme:e.theme,signal:D.signal})})(),u=await Je(l,D,o);if(v().registry.getClient(n)!==c){u.destroy();return}const h=v().registry.registerInstance(n,o,f,u);return P(f,"viceme:capability-ready",{clientKey:n,instanceKey:h.instanceKey,capability:o,version:i.version}),o}catch(l){if(v().registry.getClient(n)!==c)return;J(d),C(f,l,{clientKey:n,capability:o});return}finally{c.pendingMounts.delete(D)}},N=(await Promise.all(e.features.map(b))).filter(o=>o!==void 0);N.length>0&&v().registry.getClient(n)===c&&P(f,"viceme:ready",{clientKey:n,workKey:e.workKey,capabilities:N,version:i.version})}function et(t){const{queue:e}=v(),r=e.current.then(()=>Ze(t));return e.current=r.catch(()=>{}),r}function ie(){if(typeof document>"u")return;let t=document.currentScript instanceof HTMLScriptElement?document.currentScript:null;if(!t){const e=document.querySelectorAll("script[data-viceme-loader]");e.length===1&&(t=e[0]??null)}t&&et(t).catch(e=>{C(document,e)})}ie();const tt=ie})();
258
+ `;const n=i.querySelector("[data-viceme='panel']");n.dataset.action=this.interaction.action,n.dataset.frame="false";const s=i.querySelector("[data-viceme='description']");s.textContent=r.description;const a=i.querySelector("[data-viceme='action']"),d=a.parentElement,f=i.querySelector("[data-viceme='close']"),v=i.querySelector("[data-viceme='backdrop']"),S=i.querySelector("[data-viceme='error']"),u=i.querySelector("[data-viceme='frame']"),b=i.querySelector("[data-viceme='continue']"),x=i.querySelector("[data-viceme='profile']"),_=i.querySelector("[data-viceme='avatar']"),U=i.querySelector("[data-viceme='avatar-fallback']"),V=i.querySelector("[data-viceme='profile-name']"),F=i.querySelector("[data-viceme='profile-description']"),c=i.querySelector("[data-viceme='profile-stats']"),h=i.querySelector("[data-viceme='work']"),l=i.querySelector("[data-viceme='work-cover']"),o=i.querySelector("[data-viceme='work-title']"),m=i.querySelector("[data-viceme='work-summary']");a.textContent=r.label,a.hidden=!1,d.dataset.single="true";const g=r.label;u.title=this.interaction.action==="SIGN_IN"?"登录授权":this.interaction.action==="RESOLVE_BUYER"?"购买权益恢复":"支付";const p=this.interaction.followTarget;if(p){n.setAttribute("aria-label",this.interaction.action==="SIGN_IN"?`授权 ${p.displayName}`:`关注 ${p.displayName}`),x.dataset.visible="true",V.textContent=p.displayName;const y=[...p.description??""];F.textContent=y.length>Q?`${y.slice(0,Q).join("")}…`:y.join(""),y.length>Q&&(F.title=p.description),c.textContent=`${p.workCount} 个作品`,U.textContent=p.displayName.trim().slice(0,1)||"V",p.avatarUrl&&(_.src=p.avatarUrl,_.alt=`${p.displayName}的头像`,_.hidden=!1,U.hidden=!0)}const I=this.interaction.work;I&&(h.dataset.visible="true",o.textContent=I.title,m.textContent=I.summary,I.coverUrl&&(l.src=I.coverUrl,l.alt=I.title,l.hidden=!1));let R=null,C=!1;const q=y=>{C||(C=!0,this.interaction.signal?.removeEventListener("abort",D),this.dispatchEvent(new CustomEvent("viceme:access-layer-close",{detail:y})))},D=()=>{R?.cancel(),q("dismissed")};this.interaction.signal?.addEventListener("abort",D,{once:!0}),this.interaction.signal?.aborted&&queueMicrotask(D),v.addEventListener("click",D),f.addEventListener("click",D),b.addEventListener("click",()=>{try{R?.type==="frame"&&R.continueInSamePage?.()}catch(y){S.textContent=le(y),n.dataset.frame="false"}}),this.addEventListener("keydown",y=>{if(y.key==="Escape"&&D(),y.key==="Tab"){if(y.preventDefault(),R?.type==="frame"){const B=[f,u,...b.hidden?[]:[b]],yt=B.indexOf(i.activeElement);B[(yt+(y.shiftKey?-1:1)+B.length)%B.length]?.focus();return}const L=[f,...a.hidden?[]:[a]].filter(B=>!B.disabled&&!B.hidden);if(L.length===0)return;const re=L.indexOf(i.activeElement),mt=y.shiftKey?-1:1;L[(re+mt+L.length)%L.length]?.focus()}});const O=async()=>{a.disabled=!0,a.setAttribute("aria-busy","true"),a.textContent=N()?"Opening…":"正在打开…",S.textContent="";try{const y=await this.interaction.perform();if(C||this.interaction.signal?.aborted){y.type!=="completed"&&y.cancel();return}y.type==="frame"?(R=y,b.hidden=!y.continueInSamePage,n.dataset.frame="true",u.src=y.url,u.focus(),await y.completion):y.type==="external"&&(R=y,await y.completion),q("acted")}catch(y){if(C)return;R?.cancel(),R=null,b.hidden=!0,n.dataset.frame="false",u.removeAttribute("src"),S.textContent=le(y),a.hidden=!1,a.disabled=!1,a.removeAttribute("aria-busy"),a.textContent=g,a.focus()}};a.addEventListener("click",O),queueMicrotask(()=>{C||(this.interaction.autoStart?O():a.focus())})}}customElements.define(X,t)}const Ve=async t=>{if(typeof document>"u"||typeof customElements>"u"||t.signal?.aborted)return"dismissed";Ke();const e=document.createElement(X);e.interaction=t;const r=document.documentElement.style.overflow,i=document.activeElement instanceof HTMLElement?document.activeElement:null;document.documentElement.style.overflow="hidden",document.body.append(e);try{return await new Promise(n=>{e.addEventListener("viceme:access-layer-close",s=>n(s.detail),{once:!0})})}finally{e.remove(),document.documentElement.style.overflow=r,i?.focus()}};function P(){return new w({code:"INTERNAL_ERROR",message:"Malformed access bridge response.",retryable:!1})}function de(t){if(typeof t!="object"||t===null||Array.isArray(t))throw P();return t}function J(t){return btoa(String.fromCharCode(...t)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function ue(t,e){if(typeof t!="string")throw P();let r;try{r=new URL(t)}catch{throw P()}if(r.protocol!=="https:"||r.origin!==e||r.username||r.password)throw P();return r.href}function W(){return new w({code:"SESSION_EXPIRED",message:"Access recovery expired. Please try again.",retryable:!0})}function $e(t){const e=`viceme:access-bridge:v3:${t.widgetOrigin}:${t.workKey}`;let r;const i=()=>{r?.abort(t.signal.aborted?t.signal.reason:void 0),r=void 0;try{sessionStorage.removeItem(e)}catch{}};return t.signal.addEventListener("abort",i,{once:!0}),{clear:i,async start(n,s){if(t.signal.aborted)throw t.signal.reason??T();if(r)throw new w({code:"CONFIG_INVALID",message:"An access interaction is already open.",retryable:!0});if(typeof window>"u"||!globalThis.crypto?.subtle)throw new w({code:"CONFIG_INVALID",message:"Access recovery requires a browser with Web Crypto.",retryable:!1});const a=new AbortController;r=a;const d=AbortSignal.any([t.signal,a.signal]),f=()=>{if(d.aborted)throw d.reason??T()};try{await t.session.establish();const v=t.session.identityGeneration,S=async(l,o)=>{f();const m=await t.session.establish(),g=await t.session.request({method:"POST",path:l,signal:d,body:{...o,workSessionToken:m.token}});return f(),de(g.body)};let u;try{const l=JSON.parse(sessionStorage.getItem(e)??"null");l&&(l.purpose===n||n==="IDENTIFY"&&["RESTORE","CLAIM"].includes(l.purpose))&&l.featureKey===s&&typeof l.expiresAt=="number"&&l.expiresAt>t.now()&&l.expiresAt<=t.now()+3e5&&typeof l.challengeId=="string"&&/^[A-Za-z0-9_-]+$/.test(l.challengeId)&&typeof l.verifier=="string"&&/^[A-Za-z0-9_-]{43,128}$/.test(l.verifier)&&typeof l.state=="string"&&(u={...l,bridgeUrl:ue(l.bridgeUrl,t.widgetOrigin)},n=u.purpose)}catch{}if(!u){const l=J(crypto.getRandomValues(new Uint8Array(32))),o=J(crypto.getRandomValues(new Uint8Array(32))),m=J(new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(l))));f();const g=/^https?:$/.test(window.location.protocol)?window.location.href:void 0,p=await S("/v1/public/work-sdk/buyer/challenges",{purpose:n,...s?{featureKey:s}:{},codeChallenge:m,state:o,requestId:crypto.randomUUID(),...g?{returnUrl:g}:{}}),I=typeof p.expiresAt=="string"?Date.parse(p.expiresAt):NaN;if(typeof p.challengeId!="string"||!/^[A-Za-z0-9_-]+$/.test(p.challengeId)||!Number.isFinite(I)||I<=t.now())throw P();u={challengeId:p.challengeId,bridgeUrl:ue(p.bridgeUrl,t.widgetOrigin),expiresAt:Math.min(I,t.now()+3e5),verifier:l,state:o,purpose:n,featureKey:s}}const b=u;let x=!1;const _=()=>{if(r===a&&(r=void 0),!x)try{sessionStorage.removeItem(e)}catch{}};let U,V;const F=()=>new Promise((l,o)=>{const m=()=>{U&&clearTimeout(U),o(d.reason)};d.addEventListener("abort",m,{once:!0}),U=setTimeout(()=>{d.removeEventListener("abort",m),l()},1e3),d.aborted&&m()}),c=async()=>{V=setTimeout(()=>a.abort(W()),Math.max(0,b.expiresAt-t.now()));try{for(;t.now()<b.expiresAt;){f();const l=await S(`/v1/public/work-sdk/buyer/challenges/${b.challengeId}/result`,{codeVerifier:b.verifier});if(l.status==="EXPIRED")throw W();if(l.status==="PENDING"){await F();continue}if(l.status!=="READY"||typeof l.code!="string"||!l.code)throw P();const o=await S("/v1/public/work-sdk/buyer/exchange",{code:l.code,codeVerifier:b.verifier});if(f(),t.session.identityGeneration!==v)throw W();if(o.purpose!==n)throw P();const m=typeof o.expiresAt=="string"?Date.parse(o.expiresAt):NaN;if(!Number.isFinite(m)||m<=t.now())throw P();if(typeof o.userToken=="string"&&o.userToken){if(n!=="SIGN_IN"&&n!=="CLAIM")throw P();const g=de(o.user);if(typeof g.id!="string"||!(typeof g.displayName=="string"||g.displayName===null)||!(typeof g.avatarUrl=="string"||g.avatarUrl===null))throw P();const p={subject:g.id,nickname:g.displayName,avatarUrl:g.avatarUrl};t.session.authenticate({userToken:o.userToken,user:p,expiresAt:m})}else{const g=typeof o.expiresAt=="string"?Date.parse(o.expiresAt):NaN;if(n==="SIGN_IN"||n==="CLAIM"||typeof o.buyerToken!="string"||!o.buyerToken||!Number.isFinite(g))throw P();t.session.identifyBuyer({buyerToken:o.buyerToken,expiresAt:g},v)}return}throw W()}finally{V&&clearTimeout(V),U&&clearTimeout(U),_()}};let h;return{type:"frame",url:b.bridgeUrl,get completion(){return h??=c()},cancel:()=>{a.abort(),_()},continueInSamePage:()=>{f();try{sessionStorage.setItem(e,JSON.stringify(b))}catch{throw new w({code:"CONFIG_INVALID",message:"Browser storage is unavailable. Use the recovery page in another window.",retryable:!0})}x=!0,a.abort(),window.location.assign(b.bridgeUrl)}}}catch(v){throw r===a&&(r=void 0),a.abort(),v}}}}function M(t){if(typeof t!="object"||t===null)throw A();return t}function A(){return new w({code:"INTERNAL_ERROR",message:"Malformed public API response.",retryable:!0})}function Fe(t){const e=M(t);if(typeof e.id!="string"||!(typeof e.displayName=="string"||e.displayName===null)||!(typeof e.avatarUrl=="string"||e.avatarUrl===null))throw A();return{subject:e.id,nickname:e.displayName,avatarUrl:e.avatarUrl}}function fe(t){const e=M(t);if(typeof e.following!="boolean"||!(typeof e.followedAt=="string"||e.followedAt===null))throw A();const r=M(e.creator);if(typeof r.displayName!="string"||!(typeof r.avatarUrl=="string"||r.avatarUrl===null)||!(typeof r.description=="string"||r.description===null)||!Number.isInteger(r.publishedWorkCount)||r.publishedWorkCount<0)throw A();return{following:e.following,followedAt:e.followedAt,target:{kind:"CREATOR",displayName:r.displayName,avatarUrl:r.avatarUrl,description:r.description,workCount:r.publishedWorkCount}}}function qe(t,e){const r=M(t),i=new Set(["PUBLIC","OWNER","FOLLOWING","ENTITLED","AUTH_REQUIRED","FOLLOW_REQUIRED","PURCHASE_REQUIRED","FEATURE_NOT_FOUND","FEATURE_DISABLED"]),n=new Set([null,"SIGN_IN","FOLLOW","CHECKOUT"]);if(e===3&&(i.add("BUYER_REQUIRED").add("FEATURE_NOT_READY").add("PAYMENT_CHANNEL_UNAVAILABLE"),n.add("RESOLVE_BUYER")),typeof r.allowed!="boolean"||typeof r.reason!="string"||!i.has(r.reason)||!n.has(r.nextAction))throw A();return{allowed:r.allowed,reason:r.reason,nextAction:r.nextAction}}function Be(t,e){const r=M(t);if(typeof r.featureKey!="string"||!/^[a-z][a-z0-9_-]{1,63}$/.test(r.featureKey)||typeof r.title!="string"||r.title.trim().length===0||r.title.length>120||!(r.policyType==="PUBLIC"||r.policyType==="FOLLOW_OWNER"||r.policyType==="WORK_ENTITLEMENT"))throw A();const i=r.price===null?null:M(r.price);if(e===3){const n=d=>{if(d===null)return null;const f=M(d);if(!Number.isSafeInteger(f.amountMinor)||f.amountMinor<=0||!(f.currency==="CNY"||f.currency==="USD"))throw A();return{amountMinor:f.amountMinor,currency:f.currency}};if(r.status!=="ACTIVE"&&r.status!=="PENDING_CHANNEL"&&r.status!=="DISABLED")throw A();const s=n(i),a=n(r.pricingIntent);if(r.policyType!=="WORK_ENTITLEMENT"&&(s!==null||r.status==="PENDING_CHANNEL")||r.policyType==="WORK_ENTITLEMENT"&&r.status==="ACTIVE"&&s===null||r.status==="PENDING_CHANNEL"&&(s!==null||a===null))throw A();return{featureKey:r.featureKey,title:r.title,policy:{type:r.policyType},price:s,status:r.status,pricingIntent:a}}if(i!==null&&(!Number.isInteger(i.amountCents)||i.amountCents<=0||i.currency!=="CNY")||r.policyType==="WORK_ENTITLEMENT"!=(i!==null))throw A();return{featureKey:r.featureKey,title:r.title,policy:{type:r.policyType},price:i===null?null:{amountCents:i.amountCents,currency:"CNY"}}}function Ge(){const t=crypto.getRandomValues(new Uint8Array(32));return je(t)}function je(t){let e="";for(const r of t)e+=String.fromCharCode(r);return btoa(e).replaceAll("+","-").replaceAll("/","_").replace(/=+$/,"")}function he(){return typeof document<"u"&&document.documentElement.lang.toLowerCase()==="en-us"?"en-US":"zh-CN"}function Ye(t){const e=$e(t),r=()=>new w({code:"AUTH_CANCELLED",message:"The interactive action was cancelled.",retryable:!1}),i=()=>t.signal.reason instanceof Error?t.signal.reason:T(),n=c=>{if(t.signal.aborted)return Promise.reject(i());let h;const l=new Promise((m,g)=>{h=()=>g(i()),t.signal.addEventListener("abort",h,{once:!0}),t.signal.aborted&&h()});let o;try{o=(t.presenter??Ve)({...c,signal:t.signal})}catch(m){o=Promise.reject(m)}return Promise.race([o,l]).then(m=>{if(t.signal.aborted)throw i();return m}).finally(()=>{h&&t.signal.removeEventListener("abort",h)})},s=(c,h,l,o,m,g)=>{if(typeof window>"u")throw new w({code:"CONFIG_INVALID",message:"Interactive access requires a browser window.",retryable:!1});let p=!0,I,R;const C=()=>{p&&(p=!1,window.removeEventListener("message",D))},q=new Promise((O,y)=>{I=O,R=y}),D=O=>{if(!p||O.origin!==h||typeof O.data!="object"||O.data===null)return;const y=O.data;if(!(y.workKey!==t.workKey||y.channel!==l)){if(y.type===`viceme:${o}:ready`){O.source&&"postMessage"in O.source&&O.source.postMessage({type:`viceme:${o}:init`,workKey:t.workKey,channel:l,...m},h);return}if(y.type===`viceme:${o}:cancelled`){C(),R(r());return}y.type===`viceme:${o}:complete`&&(C(),g(y).then(I,R))}};return window.addEventListener("message",D),{type:"frame",url:c,completion:q,cancel(){C(),I()}}},a=async()=>{if(await t.ready(),t.session.snapshot?.accessProtocolVersion===3)return e.start("SIGN_IN");if(typeof window>"u")throw new w({code:"CONFIG_INVALID",message:"Interactive access requires a browser window.",retryable:!1});const c=Ge(),h=new URL("/sdk/login",t.widgetOrigin);h.search=new URLSearchParams({workKey:t.workKey,channel:c,parentOrigin:window.location.origin,locale:he()}).toString();const l=t.session.snapshot?.token;if(!l)throw A();return s(h.toString(),t.widgetOrigin,c,"auth",{workSessionToken:l},async o=>{if(typeof o.userToken!="string")throw A();t.session.authenticate({userToken:o.userToken,user:Fe(o.user)})})},d=async()=>(await t.ready(),fe((await t.session.request({method:"GET",path:"/v1/public/work-sdk/follow"})).body)),f=async()=>(await t.ready(),fe((await t.session.request({method:"PUT",path:"/v1/public/work-sdk/follow"})).body)),v=()=>{const c=t.session.snapshot?.work;return{...c?.creator?{followTarget:{kind:"CREATOR",displayName:c.creator.displayName,avatarUrl:c.creator.avatarUrl,description:null,workCount:c.creator.publishedWorkCount}}:{},...c?.details?{work:c.details}:{}}},S={async getState(){await t.ready();const c=t.session.snapshot?.user??null;return{authenticated:c!==null,user:c}},async signIn(){if(await t.ready(),await n({featureKey:"auth",reason:"AUTH_REQUIRED",action:"SIGN_IN",autoStart:t.session.snapshot?.accessProtocolVersion===3,...v(),perform:a})==="dismissed")throw r();return this.getState()},async signOut(){await t.ready(),e.clear(),await t.session.signOut()}},u={getState:d,follow:f,unfollow:async()=>{throw new w({code:"CAPABILITY_DISABLED",message:"Unfollow is not exposed by website access.",retryable:!1})}},b=async c=>{await t.ready();const h=M((await t.session.request({method:"POST",path:"/v1/public/work-sdk/access/check",body:{featureKeys:c}})).body),l=M(h.decisions);return Object.fromEntries(Object.entries(l).map(([o,m])=>[o,qe(m,t.session.snapshot?.accessProtocolVersion)]))},x=async(c,h={})=>{await t.ready();const l={featureKey:c,locale:h.locale??(t.session.snapshot?.accessProtocolVersion===3?he():"zh-CN"),...t.session.snapshot?.accessProtocolVersion===3&&typeof window<"u"&&/^https?:$/.test(window.location.protocol)?{returnUrl:window.location.href}:{}},o=M((await t.session.request({method:"POST",path:"/v1/public/work-sdk/checkout",body:l})).body);if(typeof o.checkoutUrl!="string"||typeof o.alreadyOwned!="boolean"||!(o.expiresAt===null||typeof o.expiresAt=="string"&&!Number.isNaN(Date.parse(o.expiresAt)))||o.alreadyOwned!==(o.expiresAt===null))throw A();let m;try{m=new URL(o.checkoutUrl)}catch{throw A()}if(!o.alreadyOwned&&(m.protocol!=="https:"||m.origin!==t.widgetOrigin))throw A();return{checkoutUrl:o.checkoutUrl,alreadyOwned:o.alreadyOwned,expiresAt:o.expiresAt}},_=(c,h)=>{if(c.alreadyOwned)return{type:"completed"};const l=Date.parse(c.expiresAt);if(typeof window>"u")throw new w({code:"CONFIG_INVALID",message:"Hosted checkout requires a browser window.",retryable:!1});let o=!0,m,g,p,I;const R=new Promise((L,re)=>{p=L,I=re}),C=()=>{m&&clearTimeout(m),g&&clearTimeout(g),document.removeEventListener("visibilitychange",y)},q=()=>{o&&(o=!1,C(),I(new w({code:"SESSION_EXPIRED",message:"Hosted checkout session expired.",retryable:!0})))},D=()=>{if(!o||document.visibilityState==="hidden")return;const L=l-t.now();if(L<=0){q();return}m=setTimeout(()=>{O()},Math.min(1500,L))},O=async()=>{if(o)try{const L=(await b([h]))[h];if(!L)throw A();if(L.allowed){o=!1,C(),p();return}D()}catch(L){o=!1,C(),I(L)}};function y(){if(o){if(document.visibilityState==="hidden"){m&&clearTimeout(m),m=void 0;return}D()}}document.addEventListener("visibilitychange",y);const te=l-t.now();return te<=0?q():(g=setTimeout(q,te),D()),{type:"frame",url:c.checkoutUrl,completion:R,cancel(){o&&(o=!1,C(),p())}}},U={async open(c){if(await t.ready(),t.session.snapshot?.accessProtocolVersion===3){const o=(await b([c.featureKey]))[c.featureKey];if(!o)throw A();if(o.nextAction==="RESOLVE_BUYER"){if(await n({featureKey:c.featureKey,reason:o.reason,action:"RESOLVE_BUYER",autoStart:!0,perform:()=>e.start("IDENTIFY",c.featureKey)})==="dismissed")throw r()}else if(!o.allowed&&o.nextAction!=="CHECKOUT")throw new w({code:"CHECKOUT_UNAVAILABLE",message:"Checkout is not available for this feature.",retryable:!1})}const h=await x(c.featureKey,c);if(h.alreadyOwned)return h;if(await n({featureKey:c.featureKey,reason:"PURCHASE_REQUIRED",action:"CHECKOUT",autoStart:t.session.snapshot?.accessProtocolVersion===3,perform:async()=>_(h,c.featureKey)})==="dismissed")throw r();return h}},V={async getFeatures(){await t.ready();const c=M((await t.session.request({method:"GET",path:"/v1/public/work-sdk/access/features"})).body);if(!Array.isArray(c.features)||c.features.length>100)throw A();return c.features.map(h=>Be(h,t.session.snapshot?.accessProtocolVersion))},async check(c){const l=(await b([c]))[c];if(!l)throw A();return l},checkMany:b,async require(c){let h=await this.check(c);const l=new Set;for(let o=0;!h.allowed&&h.nextAction&&o<6;o+=1){const m=h.nextAction,g=`${h.reason}:${m}`;if(l.has(g))return h;if(l.add(g),m==="FOLLOW"&&t.session.snapshot?.accessProtocolVersion===3){await u.follow(),h=await this.check(c);continue}const p=m==="FOLLOW"?(await u.getState()).target:void 0,I=m==="CHECKOUT"?await x(c):void 0;if(I?.alreadyOwned){h=await this.check(c);continue}if(await n({featureKey:c,reason:h.reason,action:m,autoStart:t.session.snapshot?.accessProtocolVersion===3,...m==="SIGN_IN"?v():p?{followTarget:p}:{},perform:async()=>m==="SIGN_IN"?a():m==="RESOLVE_BUYER"?e.start("IDENTIFY",c):m==="FOLLOW"?(await u.follow(),{type:"completed"}):_(I,c)})==="dismissed")return h;h=await this.check(c)}return h},async refresh(){await t.ready()},restorePurchase:c=>F("RESTORE",c),claimPurchase:c=>F("CLAIM",c)};async function F(c,h){if(await t.ready(),t.session.snapshot?.accessProtocolVersion!==3)throw new w({code:"CAPABILITY_DISABLED",message:"This website has not enabled purchase recovery.",retryable:!1});if(await n({featureKey:h,reason:"BUYER_REQUIRED",action:"RESOLVE_BUYER",autoStart:!0,perform:()=>e.start(c,h)})==="dismissed")throw r();return V.check(h)}return{auth:S,follow:u,access:V,checkout:U}}function me(t){t instanceof ye&&t.markDegraded()}class ye{#e=new De;#r;#t;#i=new AbortController;#n;auth;access;checkout;#a;constructor(e){this.#t=e.config,this.#r=new Pe({workKey:e.config.workKey,region:e.config.region,transport:e.transport,signal:this.#i.signal,...e.now!==void 0?{now:e.now}:{}});const r=Ye({session:this.#r,workKey:e.config.workKey,widgetOrigin:Ie[e.config.region],now:e.now??(()=>Date.now()),presenter:e.presenter,signal:this.#i.signal,ready:()=>this.#o()});this.auth=r.auth,this.access=r.access,this.checkout=r.checkout;const i=e.config.signal;if(i){const n=()=>{this.#i.abort(i.reason instanceof Error?i.reason:new DOMException("Caller signal aborted.","AbortError"))};i.aborted?n():(i.addEventListener("abort",n,{once:!0}),this.#a=()=>{i.removeEventListener("abort",n)})}}get version(){return ce}get workKey(){return this.#t.workKey}get region(){return this.#t.region}get state(){return this.#e.state}get apiMajor(){return G}ready(){return this.#e.destroyed?Promise.reject(T()):(this.#n||(this.#e.transition("READY"),this.#n=Promise.resolve()),this.#n)}async#o(){if(this.#e.destroyed)throw T();await this.ready();try{if(await this.#r.establish(),this.#e.destroyed)throw T()}catch(e){throw this.#e.destroyed?T():(this.#r.invalidate(),e)}}hasCapability(e){if(this.#e.destroyed)return!1;const r=this.#r.snapshot?.work.capabilities;return e==="danmaku"||e==="tip"||r?.includes(e)===!0}get capabilities(){return this.#r.snapshot?.work.capabilities??[]}markDegraded(){this.#e.state==="READY"&&this.#e.transition("DEGRADED")}get sessionSnapshot(){return this.#r.snapshot}destroy(){this.#e.destroyed||(this.#e.transition("DESTROYED"),this.#i.abort(T()),this.#r.destroy(),this.#e.clearListeners(),this.#n=void 0,this.#a?.(),this.#a=void 0)}}const We=1e4,He=new Map([[400,"CONFIG_INVALID"],[401,"SESSION_EXPIRED"],[403,"CAPABILITY_DISABLED"],[404,"WORK_NOT_FOUND"],[409,"CONFIG_INVALID"],[422,"CONFIG_INVALID"],[429,"RATE_LIMITED"]]),ze=new Set(["CONFIG_INVALID","WORK_NOT_FOUND","CAPABILITY_DISABLED","SESSION_EXPIRED","AUTH_REQUIRED","AUTH_CANCELLED","RETURN_URL_NOT_ALLOWED","RATE_LIMITED","NETWORK_TIMEOUT","CHECKOUT_UNAVAILABLE","INTERNAL_ERROR"]);function Xe(t){if(typeof t!="object"||t===null)return{};const e=t,r=typeof e.error=="object"&&e.error!==null?e.error:e,i={};return typeof r.code=="string"&&ze.has(r.code)&&(i.code=r.code),typeof r.message=="string"&&(i.message=r.message.slice(0,200)),typeof r.retryable=="boolean"&&(i.retryable=r.retryable),typeof r.requestId=="string"&&(i.requestId=r.requestId),i}function Qe(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`req-${Math.random().toString(36).slice(2)}`}class Je{#e;#r;#t;#i;constructor(e){this.#e=e.apiBaseUrl.replace(/\/+$/,""),this.#r=e.fetchImpl??globalThis.fetch.bind(globalThis),this.#t=e.defaultTimeoutMs??We,this.#i=e.generateRequestId??Qe}async request(e){if(e.signal?.aborted)throw this.#n(e.signal);const r=e.timeoutMs??this.#t,i=new AbortController;let n=!1;const s=setTimeout(()=>{n=!0,i.abort(new pe)},r),a=()=>i.abort(new pe(!1));e.signal?.addEventListener("abort",a,{once:!0});const d=this.#i();try{const f=await this.#r(`${this.#e}${e.path}`,{method:e.method,credentials:"omit",mode:"cors",headers:{"content-type":"application/json","x-client-request-id":d,...e.authorization!==void 0?{authorization:`Bearer ${e.authorization}`}:{},...e.userAuthorization!==void 0?{"x-viceme-user-token":e.userAuthorization}:{},...e.buyerAuthorization!==void 0?{"x-viceme-buyer-token":e.buyerAuthorization}:{}},body:e.body!==void 0?JSON.stringify(e.body):void 0,signal:i.signal});let v;try{v=await f.json()}catch(u){if(e.signal?.aborted||n)throw u;v=void 0}if(i.signal.aborted)throw i.signal.reason;const S=f.headers.get("x-request-id")??void 0;if(!f.ok){const u=Xe(v),b=u.code??He.get(f.status)??"INTERNAL_ERROR";throw new w({code:b,message:u.message??"Public API request failed.",retryable:u.retryable,requestId:u.requestId??S})}return{status:f.status,body:v,requestId:S}}catch(f){throw e.signal?.aborted?this.#n(e.signal):n?new w({code:"NETWORK_TIMEOUT",message:"Public API request timed out.",retryable:!0,requestId:d}):f instanceof w?f:f instanceof DOMException&&f.name==="AbortError"?new DOMException("ViceMe request aborted by caller.","AbortError"):new w({code:"INTERNAL_ERROR",message:"Public API request failed.",retryable:!0,requestId:d})}finally{clearTimeout(s),e.signal?.removeEventListener("abort",a)}}#n(e){return e.reason instanceof Error?e.reason:new DOMException("ViceMe request aborted by caller.","AbortError")}}function Ze(t){return new Je(t)}class pe extends DOMException{constructor(e=!0){super(e?"ViceMe request timed out.":"ViceMe request aborted.","AbortError")}}function et(t){const e=Te(t),r=Ne(e.region),i=Ze({apiBaseUrl:r});return new ye({config:e,transport:i})}const tt=8e3,rt=8e3,we={danmaku:"danmaku.js",tip:"tip.js"},it={danmaku:"mountDanmaku",tip:"mountTip"},ge=Symbol.for("viceme.loader.state.v1");function k(){const e=globalThis[ge];if(e)return e;const r={registry:new Ce,queue:{current:Promise.resolve()}};return Object.defineProperty(globalThis,ge,{value:r,writable:!0,configurable:!0,enumerable:!1}),r}function Z(t){if(!t.destroyed){t.destroyed=!0,k().registry.removeInstance(t.instanceKey);try{t.raw.destroy()}finally{j(t.host,"viceme:destroyed",{clientKey:t.clientKey,instanceKey:t.instanceKey,capability:t.capability})}}}function nt(t){return{instanceKey:t.instanceKey,capability:t.capability,destroy:()=>Z(t)}}function ee(t,e,r){Object.defineProperty(t,e,{value:r,writable:!0,configurable:!0,enumerable:!1})}function at(t){let r=globalThis.ViceMe;r||(r={},ee(globalThis,"ViceMe",r));let i=r.versions;i||(i={},ee(r,"versions",i));const n=i[`v${G}`];if(n)return n;const s={version:t,whenReady(a){const d=k().registry.getClient(a);return d?d.ready.then(()=>d.client):Promise.reject(E(`Unknown clientKey "${a}".`))},getInstance(a){const d=k().registry.getInstance(a);return d?nt(d):void 0},destroyInstance(a){const d=k().registry.getInstance(a);d&&Z(d)},destroyClient(a){for(const f of k().registry.instancesForClient(a))Z(f);const d=k().registry.getClient(a);for(const f of d?.pendingMounts??[])f.abort();k().registry.unregisterClient(a),d?.client.destroy()}};return ee(i,`v${G}`,s),s}function ot(){return document.readyState!=="loading"?Promise.resolve():new Promise(t=>{document.addEventListener("DOMContentLoaded",()=>t(),{once:!0})})}async function st(t){const e=new AbortController,r=globalThis.setTimeout(()=>e.abort(),tt);try{let i;try{i=await fetch(t,{credentials:"omit",signal:e.signal})}catch{if(e.signal.aborted)throw new w({code:"INTERNAL_ERROR",message:"Release manifest request timed out.",retryable:!0});i={ok:!1,status:0}}return{manifest:await ct(i),baseUrl:t}}finally{globalThis.clearTimeout(r)}}async function ct(t){if(!t.ok)throw E(`Release manifest is not available (HTTP ${t.status}).`);const e=await t.json();if(typeof e!="object"||e===null||typeof e.version!="string"||typeof e.apiMajor!="number"||typeof e.features!="object"||e.features===null)throw E("Release manifest is malformed.");const r=e;if(r.version!==ce)throw E("Release manifest version does not match this loader.");if(r.apiMajor!==G)throw E("Release manifest major version does not match this loader.");const i=Object.keys(r.features).sort();if(i.length!==2||i[0]!=="danmaku"||i[1]!=="tip"||r.features.danmaku!==we.danmaku||r.features.tip!==we.tip)throw E("Release manifest features must be exactly danmaku.js and tip.js.");return r}const lt=new Set(["CONFIG_INVALID","CAPABILITY_DISABLED","CLIENT_DESTROYED","INTERNAL_ERROR"]);function dt(t){if(typeof t=="object"&&t!==null){const e=t;if(typeof e.code=="string"&&lt.has(e.code)&&typeof e.retryable=="boolean"){const r={code:e.code,retryable:e.retryable};return typeof e.requestId=="string"&&(r.requestId=e.requestId),typeof e.capability=="string"&&(r.capability=e.capability),r}}return{code:"INTERNAL_ERROR",retryable:!0}}function $(t,e,r={}){j(t,"viceme:error",{...dt(e),...r})}function ut(t,e,r){let i,n;const s=new Promise((a,d)=>{if(n=()=>d(T()),e.signal.aborted){n();return}e.signal.addEventListener("abort",n,{once:!0}),i=globalThis.setTimeout(()=>{d(new w({code:"INTERNAL_ERROR",message:`Capability "${r}" did not load and mount in time.`,retryable:!0,capability:r})),e.abort()},rt)});return Promise.race([t,s]).finally(()=>{i!==void 0&&globalThis.clearTimeout(i),n&&e.signal.removeEventListener("abort",n)})}async function ft(t){let e;try{e=Le(t)}catch(u){$(document,u);return}if(!t.src){$(document,E("Loader script requires a src URL."));return}const r=new URL("manifest.json",t.src);let i,n;try{({manifest:i,baseUrl:n}=await st(r))}catch(u){$(document,u,{clientKey:H(G,e.region,e.workKey)});return}await ot();let s;try{const u=document.querySelectorAll(e.target);if(u.length===0)throw E(`Loader target "${e.target}" matched no element; no node was created.`);if(u.length>1)throw E(`Loader target "${e.target}" matched ${u.length} elements; exactly one is required.`);s=u[0]}catch(u){$(document,u,{clientKey:H(i.apiMajor,e.region,e.workKey)});return}const a=H(i.apiMajor,e.region,e.workKey);at(i.version);let d=k().registry.getClient(a),f;if(d)f=d.client;else{try{f=et({workKey:e.workKey,region:e.region})}catch(b){$(s,b,{clientKey:a});return}const u=f.ready();u.catch(()=>{}),d={clientKey:a,client:f,ready:u,pendingMounts:new Set},k().registry.registerClient(d)}try{await d.ready}catch(u){k().registry.unregisterClient(a),f.destroy(),$(s,u,{clientKey:a});return}if(k().registry.getClient(a)!==d)return;const v=async u=>{if(k().registry.findInstance(a,u,s))return;const b=i.features[u];if(typeof b!="string"){me(f),$(s,new w({code:"CAPABILITY_DISABLED",message:`Capability "${u}" is not part of this release.`,retryable:!1,capability:u}),{clientKey:a,capability:u});return}const x=new AbortController;d.pendingMounts.add(x);try{const _=(async()=>{const c=await import(new URL(b,n).href),h=it[u],l=c[h];if(typeof l!="function")throw E(`Capability chunk "${u}" does not export ${h}().`);if(k().registry.getClient(a)!==d)throw T();return await l(f,{target:s,theme:e.theme,signal:x.signal,...u==="tip"&&e.features.includes("danmaku")?{presentation:"integrated"}:{}})})(),U=await ut(_,x,u);if(k().registry.getClient(a)!==d){U.destroy();return}const V=k().registry.registerInstance(a,u,s,U);return j(s,"viceme:capability-ready",{clientKey:a,instanceKey:V.instanceKey,capability:u,version:i.version}),u}catch(_){if(k().registry.getClient(a)!==d)return;me(f),$(s,_,{clientKey:a,capability:u});return}finally{d.pendingMounts.delete(x)}},S=(await Promise.all(e.features.map(v))).filter(u=>u!==void 0);S.length>0&&k().registry.getClient(a)===d&&j(s,"viceme:ready",{clientKey:a,workKey:e.workKey,capabilities:S,version:i.version})}function ht(t){const{queue:e}=k(),r=e.current.then(()=>ft(t));return e.current=r.catch(()=>{}),r}function be(){if(typeof document>"u")return;let t=document.currentScript instanceof HTMLScriptElement?document.currentScript:null;if(!t){const e=document.querySelectorAll("script[data-viceme-loader]");e.length===1&&(t=e[0]??null)}t&&ht(t).catch(e=>{$(document,e)})}be();const pt=be})();
216
259
  //# sourceMappingURL=viceme.min.js.map