@sunbay/checkout-sdk-js 0.0.0-stage → 0.0.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/transport/MainFrameTransport.ts","../src/Element.ts","../src/CheckoutInstance.ts","../src/config/env.ts","../src/createCheckout.ts"],"sourcesContent":["/**\n * @sunbay/checkout-js 公共入口(真源)。\n *\n * 导出 `createCheckout` 入口、`CheckoutInstance` / `CheckoutElement` 句柄类型,\n * 以及协议公开类型(供 TS 使用者消费)。\n * IIFE 产物下,额外在 `window.SunbayCheckout` 暴露 `{ createCheckout }`。\n */\n\nexport { createCheckout } from './createCheckout';\nexport type {\n CreateCheckoutOptions,\n TransportFactory,\n} from './createCheckout';\n\nexport { CheckoutInstance } from './CheckoutInstance';\nexport type {\n CheckoutInstanceOptions,\n ConfirmOptions,\n InstanceTransport,\n} from './CheckoutInstance';\n\nexport { CheckoutElement } from './Element';\nexport type { CheckoutElementOptions, ElementTransport } from './Element';\n\nexport type { Env } from './config/env';\n\n// 协议公开类型(面向 TS 使用者的契约)。\nexport {\n ErrorCode,\n type ErrorCodeValue,\n type CheckoutError,\n type CheckoutErrorCategory,\n type PaymentOutcome,\n type PublicSessionView,\n type PublicPaymentMethod,\n type PublicProductLine,\n type PaymentMethod,\n type PaymentMethodFilter,\n type Appearance,\n type AddressInfo,\n type TxnStatus,\n type ElementType,\n type ElementOptions,\n type ElementStatus,\n type CardElementOptions,\n type CardFieldElementOptions,\n type AddressElementOptions,\n type ExpressCheckoutElementOptions,\n} from '@sunbay/checkout-sdk-protocol';\n\nimport { createCheckout } from './createCheckout';\n\n/**\n * IIFE / 浏览器全局:挂载 `window.SunbayCheckout = { createCheckout }`。\n *\n * tsup 的 IIFE 产物已以 `globalName: 'SunbayCheckout'` 暴露模块导出,此处显式确保\n * `window.SunbayCheckout.createCheckout` 可用(同时兼容未来再导出更多入口)。\n */\nif (typeof window !== 'undefined') {\n const w = window as typeof window & {\n SunbayCheckout?: { createCheckout: typeof createCheckout };\n };\n w.SunbayCheckout = { ...(w.SunbayCheckout ?? {}), createCheckout };\n}\n\n/**\n * 包版本。构建期由 tsup 的 `define` 从 `package.json` 注入 `__SDK_VERSION__`\n * (见 tsup.config.ts),使代码版本号永远与 package.json 同步。未经构建的环境\n * (如 vitest 直接跑 src)无此 define,回退到 `'0.0.0'`。\n */\ndeclare const __SDK_VERSION__: string;\nexport const version: string =\n typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : '0.0.0';\n","/**\n * MainFrameTransport —— 商户 SDK 与托管 main iframe 的传输层(spec 5)。\n *\n * 职责:\n * - 创建隐藏 0 尺寸的 main iframe(`${hostOrigin}/sdk/main?checkoutId=...`)。\n * - 发送 request 信封并按 `requestId` 配对响应(resolve/reject)。\n * - 分发 `kind:'event'` 信封到 `on` 注册的 handler。\n * - 过滤安全边界:仅接受 `event.origin === hostOrigin` 且信封 `checkoutId` 匹配的消息。\n * - `destroy()` 清理 iframe/监听,并以 INSTANCE_DESTROYED reject 所有未决 request。\n *\n * 安全约束(AGENTS/spec):信封中**绝不含卡值**;本层只搬运协议信封,不触碰卡数据。\n * RuntimeHello(`kind:'hello'`)在握手阶段尚无 checkoutId,由本层**单独**识别处理,\n * 不交给 `decodeEnvelope`(后者要求 checkoutId 必填)。\n */\n\nimport {\n decodeEnvelope,\n encodeEnvelope,\n PROTOCOL_MAJOR,\n PROTOCOL_NAME,\n type CheckoutError,\n type CommandName,\n type Envelope,\n type EventName,\n type RuntimeHello,\n} from '@sunbay/checkout-sdk-protocol';\nimport { ErrorCode } from '@sunbay/checkout-sdk-protocol';\n\n/** 构造参数。 */\nexport interface MainFrameTransportOptions {\n checkoutId: string;\n hostOrigin: string;\n}\n\n/** 可配置超时(毫秒)。 */\nexport interface RequestTimeoutConfig {\n /** 普通命令默认超时。 */\n default: number;\n /** initialize 命令超时。 */\n initialize: number;\n /** 握手(hello)超时。 */\n handshake: number;\n}\n\n/** 默认超时时长:普通 10s、initialize 30s、握手 15s。 */\nexport const DEFAULT_REQUEST_TIMEOUTS: RequestTimeoutConfig = {\n default: 10_000,\n initialize: 30_000,\n handshake: 15_000,\n};\n\n/** 事件 handler 签名(payload 为未知结构,由调用方按 EventName 细化)。 */\nexport type EventHandler = (payload: unknown) => void;\n\n/** 未决请求的配对记录。 */\ninterface PendingRequest {\n resolve: (value: unknown) => void;\n reject: (reason: CheckoutError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\n/** 生成唯一 id(requestId / errorId)。 */\nfunction genId(prefix: string): string {\n const rand = Math.random().toString(36).slice(2);\n return `${prefix}_${Date.now().toString(36)}_${rand}`;\n}\n\n/** 构造一个结构化 CheckoutError(运行时分类)。 */\nfunction makeError(code: string, message: string): CheckoutError {\n return {\n code,\n message,\n category: 'runtime',\n errorId: genId('err'),\n };\n}\n\n/**\n * 判断一个未知对象是否为 RuntimeHello(握手阶段,无 checkoutId)。\n *\n * 不依赖 decodeEnvelope —— hello 不属于 Envelope 联合。\n */\nfunction isRuntimeHello(value: unknown): value is RuntimeHello {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const record = value as Record<string, unknown>;\n return record.protocol === PROTOCOL_NAME && record.kind === 'hello';\n}\n\nexport class MainFrameTransport {\n private readonly checkoutId: string;\n private readonly hostOrigin: string;\n private readonly timeouts: RequestTimeoutConfig;\n\n private iframe: HTMLIFrameElement | null = null;\n private readonly pending = new Map<string, PendingRequest>();\n private readonly eventHandlers = new Map<EventName, Set<EventHandler>>();\n private helloHandler: ((hello: RuntimeHello) => void) | null = null;\n /**\n * 握手协商出的运行时 id;未注入前为空串。出站 request 信封据此填充,\n * main 端点仅处理 runtimeId 与自身一致的请求,空串会被静默丢弃。\n */\n private runtimeId = '';\n\n private readonly messageListener: (event: MessageEvent) => void;\n private destroyed = false;\n\n constructor(\n options: MainFrameTransportOptions,\n timeouts: RequestTimeoutConfig = DEFAULT_REQUEST_TIMEOUTS\n ) {\n this.checkoutId = options.checkoutId;\n this.hostOrigin = options.hostOrigin;\n this.timeouts = timeouts;\n this.messageListener = (event: MessageEvent): void => {\n this.handleMessage(event);\n };\n window.addEventListener('message', this.messageListener);\n }\n\n /**\n * 创建隐藏 0 尺寸 main iframe,append 到 document.body。\n *\n * @returns 已挂载的 iframe 元素。\n * @example\n * const iframe = transport.createHiddenIframe();\n */\n createHiddenIframe(): HTMLIFrameElement {\n if (this.iframe) {\n return this.iframe;\n }\n const iframe = document.createElement('iframe');\n iframe.src = `${this.hostOrigin}/sdk/main?checkoutId=${this.checkoutId}`;\n iframe.setAttribute('aria-hidden', 'true');\n iframe.title = 'sunbay-checkout-main';\n iframe.style.position = 'absolute';\n iframe.style.width = '0';\n iframe.style.height = '0';\n iframe.style.border = '0';\n iframe.style.visibility = 'hidden';\n document.body.appendChild(iframe);\n this.iframe = iframe;\n return iframe;\n }\n\n /**\n * 发送一条 request 信封,按 requestId 配对响应。\n *\n * @param name - 命令名。\n * @param payload - 命令载荷(JSON 可序列化)。\n * @returns 响应 data;失败(ok:false / 超时 / destroy)reject 一个 CheckoutError。\n * @example\n * const session = await transport.request('getSession', {});\n */\n request(name: CommandName, payload: unknown): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n if (this.destroyed) {\n reject(makeError(ErrorCode.INSTANCE_DESTROYED, 'Checkout instance has been destroyed'));\n return;\n }\n const contentWindow = this.iframe?.contentWindow;\n if (!contentWindow) {\n reject(\n makeError(\n ErrorCode.RUNTIME_LOAD_FAILED,\n 'main iframe not created or contentWindow unavailable'\n )\n );\n return;\n }\n\n const requestId = genId('req');\n const envelope: Envelope = {\n protocol: PROTOCOL_NAME,\n major: PROTOCOL_MAJOR,\n runtimeId: this.runtimeId,\n checkoutId: this.checkoutId,\n kind: 'request',\n requestId,\n name,\n payload,\n };\n\n const timeoutMs = this.resolveTimeout(name);\n const timer = setTimeout(() => {\n this.pending.delete(requestId);\n reject(makeError(ErrorCode.REQUEST_TIMEOUT, `Command ${name} timed out`));\n }, timeoutMs);\n\n this.pending.set(requestId, { resolve, reject, timer });\n contentWindow.postMessage(encodeEnvelope(envelope), this.hostOrigin);\n });\n }\n\n /**\n * 注册事件 handler(分发 kind:'event' 信封的 payload)。\n *\n * @param event - 事件名。\n * @param handler - 回调。\n */\n on(event: EventName, handler: EventHandler): void {\n let set = this.eventHandlers.get(event);\n if (!set) {\n set = new Set<EventHandler>();\n this.eventHandlers.set(event, set);\n }\n set.add(handler);\n }\n\n /**\n * 注销事件 handler。\n *\n * @param event - 事件名。\n * @param handler - 先前注册的回调。\n */\n off(event: EventName, handler: EventHandler): void {\n const set = this.eventHandlers.get(event);\n if (set) {\n set.delete(handler);\n if (set.size === 0) {\n this.eventHandlers.delete(event);\n }\n }\n }\n\n /**\n * 注册握手(RuntimeHello)回调。hello 阶段尚无 checkoutId,单独处理。\n *\n * @param handler - 收到 hello 时调用。\n */\n onHello(handler: (hello: RuntimeHello) => void): void {\n this.helloHandler = handler;\n }\n\n /**\n * 注入握手协商出的运行时 id。必须在发送首个 request(initialize)之前调用,\n * 否则出站信封 runtimeId 为空串、被 main 端点静默丢弃导致请求超时。\n *\n * @param runtimeId - RuntimeHello 中的 runtimeId。\n */\n setRuntimeId(runtimeId: string): void {\n this.runtimeId = runtimeId;\n }\n\n /**\n * 销毁:移除 iframe、清监听,未决 request 以 INSTANCE_DESTROYED reject。\n */\n destroy(): void {\n if (this.destroyed) {\n return;\n }\n this.destroyed = true;\n window.removeEventListener('message', this.messageListener);\n\n for (const [, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(makeError(ErrorCode.INSTANCE_DESTROYED, 'Checkout instance has been destroyed'));\n }\n this.pending.clear();\n this.eventHandlers.clear();\n this.helloHandler = null;\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n }\n this.iframe = null;\n }\n\n /** 按命令名解析超时时长。 */\n private resolveTimeout(name: CommandName): number {\n if (name === 'initialize') {\n return this.timeouts.initialize;\n }\n return this.timeouts.default;\n }\n\n /**\n * 点对点 port relay(父窗口中继,Stripe controller 模型)。\n *\n * 兄弟 iframe(main 与各 Element iframe)之间拿不到彼此 window 引用,无法直接\n * transfer MessagePort。本层(商户页,唯一同时可达两端且知其 origin 的角色)在\n * 收到某 Element iframe 的 `element-online` 时:\n * 1. 建 `MessageChannel`;\n * 2. `port1` → main iframe(`relay-port`,targetOrigin=hostOrigin);\n * 3. `port2` → 发起的 Element iframe(即 `event.source`,targetOrigin=hostOrigin)。\n *\n * 两端 origin 均为 hostOrigin,targetOrigin 恒正确(跨域亦不被丢弃)。\n * 本层只搬运**空 port**,绝不接触卡值(卡值在 port 建立后端到端传输)。\n *\n * @param event 入站 message(origin 已校验为 hostOrigin)\n * @returns 是否作为 element-online 处理(是则调用方应 return)\n */\n private tryHandleElementOnline(event: MessageEvent): boolean {\n const data = event.data as unknown;\n if (typeof data !== 'object' || data === null) {\n return false;\n }\n const msg = data as Record<string, unknown>;\n if (msg.kind !== 'element-online') {\n return false;\n }\n // 校验:checkoutId 匹配、fieldType 合法、来源窗口存在。\n if (msg.checkoutId !== this.checkoutId || typeof msg.fieldType !== 'string') {\n return true;\n }\n const mainWin = this.iframe?.contentWindow;\n const elementWin = event.source as Window | null;\n if (!mainWin || !elementWin) {\n return true;\n }\n\n const channel = new MessageChannel();\n const relayMsg = {\n kind: 'relay-port' as const,\n checkoutId: this.checkoutId,\n fieldType: msg.fieldType,\n };\n // port1 → main iframe;port2 → 发起的 Element iframe。\n mainWin.postMessage(relayMsg, this.hostOrigin, [channel.port1]);\n elementWin.postMessage(relayMsg, this.hostOrigin, [channel.port2]);\n return true;\n }\n\n /** 处理入站 message:过滤 origin,识别 relay / hello / Envelope 并分发。 */\n private handleMessage(event: MessageEvent): void {\n if (this.destroyed) {\n return;\n }\n // 安全边界:只接受来自托管页面 origin 的消息。\n if (event.origin !== this.hostOrigin) {\n return;\n }\n\n // 点对点 port relay:Element iframe 上线 → 本层(父窗口)建 channel,\n // 把两个 port 分别 transfer 给 main iframe 与该 Element iframe(见下)。\n // relay 消息为对象(非 string 信封),且须先于 string 校验识别。\n if (this.tryHandleElementOnline(event)) {\n return;\n }\n\n if (typeof event.data !== 'string') {\n return;\n }\n\n // 握手 hello 单独解析(不走 Envelope 联合,此阶段无 checkoutId)。\n let raw: unknown;\n try {\n raw = JSON.parse(event.data);\n } catch {\n return;\n }\n if (isRuntimeHello(raw)) {\n if (this.helloHandler) {\n this.helloHandler(raw);\n }\n return;\n }\n\n // 其余按 Envelope 校验解码。\n let envelope: Envelope;\n try {\n envelope = decodeEnvelope(event.data);\n } catch {\n return;\n }\n\n // 安全边界:信封 checkoutId 必须匹配本实例。\n if (envelope.checkoutId !== this.checkoutId) {\n return;\n }\n\n if (envelope.kind === 'response') {\n this.handleResponse(envelope);\n } else if (envelope.kind === 'event') {\n this.handleEvent(envelope);\n }\n // kind:'request' 由 main → SDK 不应出现,忽略。\n }\n\n /** 分发 response 到配对的未决 request。 */\n private handleResponse(envelope: Extract<Envelope, { kind: 'response' }>): void {\n const entry = this.pending.get(envelope.requestId);\n if (!entry) {\n return;\n }\n this.pending.delete(envelope.requestId);\n clearTimeout(entry.timer);\n if (envelope.ok) {\n entry.resolve(envelope.data);\n } else {\n entry.reject(envelope.error);\n }\n }\n\n /** 分发 event 到注册的 handler。 */\n private handleEvent(envelope: Extract<Envelope, { kind: 'event' }>): void {\n const set = this.eventHandlers.get(envelope.name as EventName);\n if (!set) {\n return;\n }\n for (const handler of set) {\n handler(envelope.payload);\n }\n }\n}\n","/**\n * CheckoutElement —— 商户侧 Element 句柄(spec 6)。\n *\n * 职责:\n * - 由 `CheckoutInstance.create` 构造(单测时以 mock transport + 构造参注入)。\n * - 在商户 DOM 目标挂载**可见** iframe,并通过 transport 转发 Element 命令。\n * - 维护状态机 `created → loading → ready → destroyed`(`loadError` 为旁支)。\n * - 订阅 transport 的 `elementReady` / `loadError` 事件,按**自身 elementId** 过滤,\n * 驱动 `mount()` 的 resolve / reject。\n *\n * 安全约束(AGENTS/spec):本层只做 DOM 挂载与协议命令转发,**绝不触碰卡值**。\n * 卡数据仅存在于托管 iframe 内,不经由本句柄或 transport 传输。\n */\n\nimport {\n ErrorCode,\n isIframeResizeMessage,\n type Appearance,\n type AvailableWallets,\n type CheckoutError,\n type CommandName,\n type ElementOptions,\n type ElementStatus,\n type ElementType,\n type EventName,\n type ExpressAvailabilityChangeEvent,\n type ExpressCheckoutElementOptions,\n} from '@sunbay/checkout-sdk-protocol';\n\n/**\n * transport 依赖的最小接口(由 MainFrameTransport 满足)。\n *\n * 仅声明 Element 句柄需要的方法,便于单测注入 mock。\n */\nexport interface ElementTransport {\n request(name: CommandName, payload: unknown): Promise<unknown>;\n on(event: EventName, handler: (payload: unknown) => void): void;\n off(event: EventName, handler: (payload: unknown) => void): void;\n}\n\n/** CheckoutElement 构造参数(由 CheckoutInstance.create 组装)。 */\nexport interface CheckoutElementOptions {\n /** Element 唯一 id(由实例生成,用于命令/事件配对)。 */\n elementId: string;\n /** Element 类型(决定 iframe 路径与可用动作)。 */\n type: ElementType;\n /** 托管页面 origin(不带尾部斜杠)。 */\n hostOrigin: string;\n /**\n * 当前 checkout 会话 id。随 iframe src 以 `?checkoutId=` 下发,供托管字段/element\n * iframe 加入正确的同源信令频道(`sunbay-checkout:<checkoutId>`)与 main 配对;\n * 缺失会导致字段频道名不匹配、永不就绪。\n */\n checkoutId: string;\n /** 传输层。 */\n transport: ElementTransport;\n /** 初始 Element 配置(随 createElement 下发)。 */\n initialOptions?: ElementOptions;\n /**\n * 句柄销毁回调(由 CheckoutInstance 注入)。`destroy()` 成功销毁时以本 elementId 调用,\n * 使实例从互斥注册表(elements Map)移除自身,从而允许销毁后重建同类互斥 Element\n * (如切换 expressCheckout 的 buttonType/buttonHeight 需重建 iframe)。`unmount()` 不调用\n * (保留句柄、仍占名额、可 remount)。\n */\n onDestroy?: (elementId: string) => void;\n /**\n * 初始配色方案(来自 createCheckout 的 appearance.colorScheme)。\n * 仅当提供时拼进 iframe src 的 `&colorScheme=<值>`,使托管 iframe 在首帧即按该\n * 配色渲染(无闪)。缺省时不拼接,由托管侧按默认(light)处理。运行时切换走\n * updateCheckout 命令,不走此处。\n */\n colorScheme?: 'light' | 'dark' | 'auto';\n /**\n * 初始外观定制(来自 createCheckout 的 appearance)。\n * 仅当含 `variables` 或 `rules` 时序列化进 iframe src 的\n * `&appearance=<encodeURIComponent(JSON)>`,使托管 iframe 在首帧即按该外观渲染(无闪)。\n * 仅含 `colorScheme`(无 variables/rules)时不拼接,避免空外观字符串;colorScheme 走独立\n * `&colorScheme=`。运行时切换走 updateCheckout 命令,不走此处。\n */\n appearance?: Appearance;\n}\n\n/** 事件 payload 的公共结构(含 elementId,用于按自身句柄过滤)。 */\ninterface WithElementId {\n elementId?: string;\n}\n\n/** loadError 事件 payload 结构。 */\ninterface LoadErrorPayload extends WithElementId {\n error: CheckoutError;\n}\n\n/** elementReady 事件 payload 结构(expressCheckout 额外携 availableWallets)。 */\ninterface ElementReadyPayload extends WithElementId {\n availableWallets?: AvailableWallets;\n}\n\n/** 拆分字段类型(走 /sdk/field/<type>)。 */\nconst FIELD_TYPES: readonly ElementType[] = ['cardNumber', 'cardExpiry', 'cardCvc'];\n\n/** 提供 focus/blur/clear 的输入类(expressCheckout 不含)。 */\nconst INPUT_TYPES: readonly ElementType[] = [\n 'cardNumber',\n 'cardExpiry',\n 'cardCvc',\n 'card',\n 'address',\n];\n\n/** 生成一个结构化 CheckoutError(configuration 分类,供句柄本地报错)。 */\nfunction makeError(code: string, message: string, elementId?: string): CheckoutError {\n const rand = Math.random().toString(36).slice(2);\n return {\n code,\n message,\n category: 'configuration',\n errorId: `err_${Date.now().toString(36)}_${rand}`,\n elementId,\n };\n}\n\n/**\n * 判断 payload 是否指向本 elementId(**严格匹配**)。\n *\n * 仅当 `payload.elementId === elementId` 才视为本 Element 的 elementReady/loadError。\n * 无 elementId 或不等均不匹配,避免 T6 多 Element 共享同一 transport 时事件串扰。\n * (协议保证 elementReady/loadError 始终携带 elementId。)\n */\nfunction matchesElement(payload: unknown, elementId: string): boolean {\n if (typeof payload !== 'object' || payload === null) {\n return false;\n }\n return (payload as WithElementId).elementId === elementId;\n}\n\nexport class CheckoutElement {\n /** Element 唯一 id。 */\n readonly elementId: string;\n /** Element 类型。 */\n readonly type: ElementType;\n /** 地址 Element 的 mode(billing/shipping;仅 address 有意义),供实例按 mode 判互斥。 */\n readonly mode: string | undefined;\n\n private readonly hostOrigin: string;\n private readonly checkoutId: string;\n private readonly transport: ElementTransport;\n private options: ElementOptions | undefined;\n /** 初始配色方案(拼进 iframe src;缺省不拼)。 */\n private readonly colorScheme: 'light' | 'dark' | 'auto' | undefined;\n /** 初始外观定制(含 variables/rules 时拼进 iframe src;缺省或仅 colorScheme 不拼)。 */\n private readonly appearance: Appearance | undefined;\n /** 销毁回调(实例注入):destroy() 末尾调用,使实例从互斥注册表移除自身以释放名额。 */\n private readonly onDestroy: ((elementId: string) => void) | undefined;\n\n private status: ElementStatus = 'created';\n private container: HTMLElement | null = null;\n private iframe: HTMLIFrameElement | null = null;\n\n /** mount 期间临时订阅的事件 handler(resolve/reject 后解绑)。 */\n private readyHandler: ((payload: unknown) => void) | null = null;\n private loadErrorHandler: ((payload: unknown) => void) | null = null;\n\n /**\n * 仅 expressCheckout:各钱包可用性快照。\n * 初次来自 elementReady.availableWallets,之后随 expressAvailabilityChange 更新。\n */\n private availableWallets: AvailableWallets | undefined;\n /** 仅 expressCheckout:常驻订阅的 expressAvailabilityChange handler(destroy 时解绑)。 */\n private availabilityHandler: ((payload: unknown) => void) | null = null;\n\n /**\n * iframe 自适应高度:挂载期间常驻的 window 'message' 监听器(iframe 消失/销毁时解绑)。\n * 存引用以便 removeEventListener;null 表示未监听。\n */\n private resizeHandler: ((e: MessageEvent) => void) | null = null;\n /** 最近一次已应用的 iframe 高度(px),用于去重,避免冗余 style 写入;null 表示尚未设置。 */\n private lastHeight: number | null = null;\n\n constructor(opts: CheckoutElementOptions) {\n this.elementId = opts.elementId;\n this.type = opts.type;\n this.hostOrigin = opts.hostOrigin;\n this.checkoutId = opts.checkoutId;\n this.transport = opts.transport;\n this.options = opts.initialOptions;\n this.colorScheme = opts.colorScheme;\n this.appearance = opts.appearance;\n this.mode = (opts.initialOptions as { mode?: string } | undefined)?.mode;\n this.onDestroy = opts.onDestroy;\n this.installInputActions();\n this.installExpressAvailability();\n }\n\n /** 当前状态(只读快照,供外部/测试观测)。 */\n getStatus(): ElementStatus {\n return this.status;\n }\n\n /**\n * 仅 expressCheckout:返回当前各钱包可用性快照(其他类型恒为 undefined)。\n *\n * 初值来自 elementReady 的 availableWallets,之后由 expressAvailabilityChange 更新。\n *\n * @returns 可用性快照;尚未就绪或非 express 时为 undefined。\n */\n getAvailableWallets(): AvailableWallets | undefined {\n return this.availableWallets;\n }\n\n /**\n * 挂载到商户 DOM 目标:插入可见 iframe、发 createElement、等 elementReady。\n *\n * @param selectorOrEl - CSS 选择器或 HTMLElement 容器;容器须唯一且为空。\n * @returns elementReady 后 resolve;失败移除节点并 reject(loadError / INVALID_OPTIONS)。\n * @throws 已销毁时抛 INSTANCE_DESTROYED。\n * @example\n * await element.mount('#card-field');\n */\n mount(selectorOrEl: string | HTMLElement): Promise<void> {\n this.assertAlive();\n\n if (this.status === 'loading' || this.status === 'ready') {\n return Promise.reject(\n makeError(\n ErrorCode.ELEMENT_CONFLICT,\n 'This Element is already mounted; mount cannot be called twice',\n this.elementId\n )\n );\n }\n\n const container = this.resolveContainer(selectorOrEl);\n if (!container) {\n return Promise.reject(\n makeError(\n ErrorCode.INVALID_OPTIONS,\n 'Target container not found or not uniquely resolvable',\n this.elementId\n )\n );\n }\n if (container.childElementCount > 0) {\n return Promise.reject(\n makeError(ErrorCode.INVALID_OPTIONS, 'Target container is not empty', this.elementId)\n );\n }\n\n this.status = 'loading';\n this.container = container;\n\n const iframe = document.createElement('iframe');\n iframe.src = this.resolveSrc();\n iframe.title = `sunbay-checkout-${this.type}`;\n iframe.setAttribute('data-element-id', this.elementId);\n iframe.style.border = '0';\n iframe.style.width = '100%';\n iframe.style.display = 'block';\n container.appendChild(iframe);\n this.iframe = iframe;\n this.installResizeListener();\n\n return new Promise<void>((resolve, reject) => {\n const cleanup = (): void => {\n if (this.readyHandler) {\n this.transport.off('elementReady', this.readyHandler);\n this.readyHandler = null;\n }\n if (this.loadErrorHandler) {\n this.transport.off('loadError', this.loadErrorHandler);\n this.loadErrorHandler = null;\n }\n };\n\n const onReady = (payload: unknown): void => {\n if (!matchesElement(payload, this.elementId)) {\n return;\n }\n cleanup();\n // expressCheckout:捕获 ready 携带的初始钱包可用性。\n const wallets = (payload as ElementReadyPayload).availableWallets;\n if (wallets) {\n this.availableWallets = wallets;\n }\n this.status = 'ready';\n resolve();\n };\n\n const onLoadError = (payload: unknown): void => {\n if (!matchesElement(payload, this.elementId)) {\n return;\n }\n cleanup();\n this.status = 'loadError';\n this.removeIframe();\n const err = (payload as LoadErrorPayload)?.error;\n reject(\n err ??\n makeError(\n ErrorCode.RUNTIME_LOAD_FAILED,\n 'Failed to load Element',\n this.elementId\n )\n );\n };\n\n this.readyHandler = onReady;\n this.loadErrorHandler = onLoadError;\n this.transport.on('elementReady', onReady);\n this.transport.on('loadError', onLoadError);\n\n // 发 createElement 命令;命令级失败同样走 loadError 旁支。\n this.transport\n .request('createElement', {\n elementId: this.elementId,\n type: this.type,\n options: this.options,\n })\n .catch((cmdErr: unknown) => {\n cleanup();\n this.status = 'loadError';\n this.removeIframe();\n reject(cmdErr as CheckoutError);\n });\n });\n }\n\n /**\n * 卸载:发 destroyElement、移除 iframe;幂等;保留句柄与配置。\n *\n * @returns 完成后 resolve(未挂载时直接 resolve)。\n * @throws 已销毁时抛 INSTANCE_DESTROYED。\n */\n async unmount(): Promise<void> {\n this.assertAlive();\n if (this.status !== 'ready' && this.status !== 'loading') {\n // 未挂载:幂等 no-op。\n return;\n }\n try {\n await this.transport.request('destroyElement', { elementId: this.elementId });\n } finally {\n this.removeIframe();\n this.container = null;\n this.status = 'created';\n }\n }\n\n /**\n * 销毁句柄:幂等;移除 iframe;此后非 destroy/off 调用抛 INSTANCE_DESTROYED。\n */\n destroy(): void {\n if (this.status === 'destroyed') {\n return;\n }\n if (this.readyHandler) {\n this.transport.off('elementReady', this.readyHandler);\n this.readyHandler = null;\n }\n if (this.loadErrorHandler) {\n this.transport.off('loadError', this.loadErrorHandler);\n this.loadErrorHandler = null;\n }\n if (this.availabilityHandler) {\n this.transport.off('expressAvailabilityChange', this.availabilityHandler);\n this.availabilityHandler = null;\n }\n this.removeIframe();\n this.container = null;\n this.status = 'destroyed';\n // 通知实例从互斥注册表移除自身,释放名额以允许销毁后重建同类互斥 Element。\n this.onDestroy?.(this.elementId);\n }\n\n /**\n * 更新 Element 配置:发 updateElement;非法字段由托管侧整次拒绝。\n *\n * @param patch - 配置增量。\n * @returns 成功写回本地 options 后 resolve。\n * @throws 已销毁时抛 INSTANCE_DESTROYED。\n */\n async update(patch: Partial<ElementOptions>): Promise<void> {\n this.assertAlive();\n const resp = await this.transport.request('updateElement', {\n elementId: this.elementId,\n patch,\n });\n const next = (resp as { options?: ElementOptions } | undefined)?.options;\n if (next) {\n this.options = next;\n }\n }\n\n /**\n * 注册事件 handler(透传到 transport,按事件名分发)。\n *\n * @param event - 事件名。\n * @param handler - 回调。\n * @throws 已销毁时抛 INSTANCE_DESTROYED。\n */\n on(event: EventName, handler: (payload: unknown) => void): void {\n this.assertAlive();\n this.transport.on(event, handler);\n }\n\n /**\n * 注销事件 handler(销毁后仍可安全调用)。\n *\n * @param event - 事件名。\n * @param handler - 先前注册的回调。\n */\n off(event: EventName, handler: (payload: unknown) => void): void {\n this.transport.off(event, handler);\n }\n\n /** 聚焦(仅输入类,expressCheckout 不提供)。 */\n focus?: () => Promise<void>;\n /** 失焦(仅输入类,expressCheckout 不提供)。 */\n blur?: () => Promise<void>;\n /** 清空(仅输入类,expressCheckout 不提供)。 */\n clear?: () => Promise<void>;\n\n /** 已挂载后安装输入类动作方法(由构造后自动调用)。 */\n private installInputActions(): void {\n if (!INPUT_TYPES.includes(this.type)) {\n return;\n }\n this.focus = (): Promise<void> => this.sendAction('focus');\n this.blur = (): Promise<void> => this.sendAction('blur');\n this.clear = (): Promise<void> => this.sendAction('clear');\n }\n\n /**\n * 仅 expressCheckout:常驻订阅 expressAvailabilityChange,更新本地可用性快照。\n *\n * 该事件载荷不含 elementId;express 为单例(由 CheckoutInstance 保证),\n * 故无需按 elementId 过滤。非 express 类型不订阅。\n */\n private installExpressAvailability(): void {\n if (this.type !== 'expressCheckout') {\n return;\n }\n const handler = (payload: unknown): void => {\n if (typeof payload !== 'object' || payload === null) {\n return;\n }\n const wallets = (payload as ExpressAvailabilityChangeEvent).availableWallets;\n if (wallets) {\n this.availableWallets = wallets;\n }\n };\n this.availabilityHandler = handler;\n this.transport.on('expressAvailabilityChange', handler);\n }\n\n /** 发送一条输入类动作命令(销毁后同步抛 INSTANCE_DESTROYED)。 */\n private sendAction(name: 'focus' | 'blur' | 'clear'): Promise<void> {\n this.assertAlive();\n return this.transport.request(name, { elementId: this.elementId }).then(() => undefined);\n }\n\n /** 若已销毁则抛 INSTANCE_DESTROYED。 */\n private assertAlive(): void {\n if (this.status === 'destroyed') {\n throw makeError(ErrorCode.INSTANCE_DESTROYED, 'Checkout instance has been destroyed', this.elementId);\n }\n }\n\n /** 解析挂载容器(选择器须唯一命中一个元素)。 */\n private resolveContainer(selectorOrEl: string | HTMLElement): HTMLElement | null {\n if (typeof selectorOrEl !== 'string') {\n return selectorOrEl;\n }\n const nodes = document.querySelectorAll(selectorOrEl);\n if (nodes.length !== 1) {\n return null;\n }\n const node = nodes[0];\n return node instanceof HTMLElement ? node : null;\n }\n\n /**\n * 解析 iframe src:拆分字段走 /sdk/field/,其余走 /sdk/element/,带 checkoutId 与 elementId;\n * 若提供了初始 colorScheme,则追加 `&colorScheme=<值>`(首帧无闪);\n * 若初始 appearance 含 variables 或 rules,则追加\n * `&appearance=<encodeURIComponent(JSON.stringify(appearance))>`(首帧即生效,无闪)。\n * 仅含 colorScheme(无 variables/rules)的 appearance 不拼接,避免空外观串。\n * 对 expressCheckout,另追加钱包开关 / 每钱包 buttonType / 全局 buttonHeight\n * (见 {@link resolveExpressQuery})。\n *\n * elementId 随 src 下发,供托管 child 在 iframe-resize 消息中原样回传,父窗口据此在\n * 同页多个 iframe 间按句柄分发高度。\n */\n private resolveSrc(): string {\n const segment = FIELD_TYPES.includes(this.type) ? 'field' : 'element';\n let query = `?checkoutId=${encodeURIComponent(this.checkoutId)}`;\n query += `&elementId=${encodeURIComponent(this.elementId)}`;\n if (this.colorScheme) {\n query += `&colorScheme=${encodeURIComponent(this.colorScheme)}`;\n }\n // 仅当 appearance 含 variables 或 rules 时序列化(避免空外观串;colorScheme 已单独透传)。\n if (this.appearance && (this.appearance.variables || this.appearance.rules)) {\n query += `&appearance=${encodeURIComponent(JSON.stringify(this.appearance))}`;\n }\n // expressCheckout:把 create 第二参的 express options(钱包开关 / buttonType /\n // buttonHeight)透传给托管 iframe,使商户配置在首帧即生效(C1 断链修复)。\n if (this.type === 'expressCheckout') {\n query += this.resolveExpressQuery();\n }\n return `${this.hostOrigin}/sdk/${segment}/${this.type}${query}`;\n }\n\n /**\n * 构造 expressCheckout 专属 query 片段(仅 expressCheckout 调用):\n * - 钱包显式置为 `false` → `&applePay=false` / `&googlePay=false`(强制隐藏,保持\n * 既有开关语义;`true` / 缺省 → 自动,不拼开关);\n * - 钱包以对象形态配置且含 `buttonType` → `&applePayButtonType=<v>` /\n * `&googlePayButtonType=<v>`(布尔开关 / 缺省 → 不拼);\n * - 全局 `buttonHeight`(有限数)→ `&buttonHeight=<n>`。\n *\n * 仅在有值时拼接;不拼空串。本片段不触碰卡值,仅承载展示配置。\n *\n * @returns 以 `&` 起始的 query 片段(无可拼项时返回空串)。\n */\n private resolveExpressQuery(): string {\n const options = this.options as ExpressCheckoutElementOptions | undefined;\n if (!options) {\n return '';\n }\n let query = '';\n const applePay = options.paymentMethods?.applePay;\n const googlePay = options.paymentMethods?.googlePay;\n // 钱包开关:仅显式 false(强制隐藏)才下发,保持既有开关语义。\n if (applePay === false) {\n query += `&applePay=false`;\n }\n if (googlePay === false) {\n query += `&googlePay=false`;\n }\n // 每钱包 buttonType:仅对象形态且含 buttonType 时下发。\n if (typeof applePay === 'object' && applePay.buttonType) {\n query += `&applePayButtonType=${encodeURIComponent(applePay.buttonType)}`;\n }\n if (typeof googlePay === 'object' && googlePay.buttonType) {\n query += `&googlePayButtonType=${encodeURIComponent(googlePay.buttonType)}`;\n }\n // 全局按钮高度:仅有限数时下发(托管侧再 clamp 到 [30,64])。\n if (typeof options.buttonHeight === 'number' && Number.isFinite(options.buttonHeight)) {\n query += `&buttonHeight=${encodeURIComponent(String(options.buttonHeight))}`;\n }\n return query;\n }\n\n /**\n * 安装 iframe 自适应高度监听:订阅 window 'message',仅采信来自本 iframe\n * `contentWindow` 且 origin === hostOrigin 的合法 {@link IframeResizeMessage},\n * 且 elementId 与本句柄匹配时,将外层 iframe 高度调整为内容真实高度(宽度保持 100%)。\n *\n * 安全:先校验 `event.source === iframe.contentWindow`(关键来源校验),\n * 再校验 `event.origin === hostOrigin`(更严格的同源校验),防跨源伪造。\n * 高度去重:与上次相同则跳过,避免冗余 style 写入。\n */\n private installResizeListener(): void {\n const handler = (event: MessageEvent): void => {\n if (!this.iframe) {\n return;\n }\n if (event.source !== this.iframe.contentWindow) {\n return;\n }\n if (event.origin !== this.hostOrigin) {\n return;\n }\n if (!isIframeResizeMessage(event.data)) {\n return;\n }\n if (event.data.elementId !== this.elementId) {\n return;\n }\n const { height } = event.data;\n if (height === this.lastHeight) {\n return;\n }\n this.lastHeight = height;\n this.iframe.style.height = `${height}px`;\n };\n this.resizeHandler = handler;\n window.addEventListener('message', handler);\n }\n\n /** 解绑 iframe 自适应高度监听并重置去重状态(幂等)。 */\n private teardownResizeListener(): void {\n if (this.resizeHandler) {\n window.removeEventListener('message', this.resizeHandler);\n this.resizeHandler = null;\n }\n this.lastHeight = null;\n }\n\n /** 移除 iframe DOM 节点(若存在),并解绑自适应高度监听。 */\n private removeIframe(): void {\n this.teardownResizeListener();\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n }\n this.iframe = null;\n }\n\n /** 工厂:等价于 `new CheckoutElement(opts)`(供 CheckoutInstance 统一入口)。 */\n static create(opts: CheckoutElementOptions): CheckoutElement {\n return new CheckoutElement(opts);\n }\n}\n","/**\n * CheckoutInstance —— 商户侧结账实例句柄(spec 4 / 7 / 8)。\n *\n * 职责:\n * - 由 `createCheckout` 在握手 + initialize 成功后构造(持有已就绪 transport、\n * runtimeId、capabilities、初始 PublicSessionView)。\n * - `create` 组装并返回 {@link CheckoutElement},维护**互斥注册表**(card 与拆分\n * 字段互斥、同 mode 地址互斥、expressCheckout 单例 → `ELEMENT_CONFLICT`)。\n * - `confirm` 生成 operationId、发 confirm 命令拿 accepted,Promise 由后续同\n * operationId 的 `paymentResult` 事件兑现;进行中再 confirm → `CHECKOUT_BUSY`。\n * - `getSession/refresh/getPaymentStatus/updateCheckout` 透传对应命令。\n * - `destroy` 幂等:释放 Element、解绑监听、以 INSTANCE_DESTROYED reject 未决 confirm、\n * 发 destroy 命令并销毁 transport;此后迟到的 `paymentResult` 一律忽略。\n *\n * 安全约束(AGENTS/spec):本层只搬运协议命令/事件,**绝不触碰卡值**。\n */\n\nimport { CheckoutElement, type CheckoutElementOptions } from './Element';\nimport {\n ErrorCode,\n type Appearance,\n type CheckoutError,\n type CommandName,\n type ConfirmReq,\n type ElementOptions,\n type ElementType,\n type EventName,\n type GetPaymentStatusResp,\n type PaymentOutcome,\n type PaymentResultEvent,\n type PublicSessionView,\n type UpdateCheckoutReq,\n} from '@sunbay/checkout-sdk-protocol';\n\n/**\n * CheckoutInstance 依赖的最小 transport 接口(由 MainFrameTransport 满足)。\n *\n * 比 ElementTransport 多出 `onHello/createHiddenIframe/destroy`,供 createCheckout\n * 握手接线与实例销毁使用。单测可注入 mock。\n */\nexport interface InstanceTransport {\n request(name: CommandName, payload: unknown): Promise<unknown>;\n on(event: EventName, handler: (payload: unknown) => void): void;\n off(event: EventName, handler: (payload: unknown) => void): void;\n onHello(handler: (hello: unknown) => void): void;\n setRuntimeId(runtimeId: string): void;\n createHiddenIframe(): unknown;\n destroy(): void;\n}\n\n/** CheckoutInstance 构造参数(由 createCheckout 组装)。 */\nexport interface CheckoutInstanceOptions {\n /** 结账唯一 id。 */\n checkoutId: string;\n /** 协商后的运行时 id(来自 RuntimeHello)。 */\n runtimeId: string;\n /** 托管页面 origin(不带尾部斜杠)。 */\n hostOrigin: string;\n /** 已就绪 transport。 */\n transport: InstanceTransport;\n /** initialize 返回的 capabilities。 */\n capabilities: string[];\n /** initialize 返回的初始会话视图。 */\n session: PublicSessionView;\n /**\n * 初始外观定制(来自 createCheckout 的 appearance)。\n * 透传给每个 create 出的 Element,序列化进其 iframe src(首帧无闪):\n * - colorScheme 拼 `&colorScheme=`;\n * - variables/rules 拼 `&appearance=`(仅当非空)。\n * 缺省不拼接。运行时切换走 updateCheckout 命令。\n */\n appearance?: Appearance;\n}\n\n/** confirm 可选参数(对齐 ConfirmReq,去掉由实例生成的 operationId)。 */\nexport type ConfirmOptions = Omit<ConfirmReq, 'operationId'>;\n\n/** 未决 confirm 的配对记录。 */\ninterface PendingConfirm {\n operationId: string;\n resolve: (outcome: PaymentOutcome) => void;\n reject: (reason: CheckoutError) => void;\n}\n\n/** 拆分卡字段类型集合。 */\nconst CARD_FIELD_TYPES: readonly ElementType[] = ['cardNumber', 'cardExpiry', 'cardCvc'];\n\n/** 生成唯一 id。 */\nfunction genId(prefix: string): string {\n const rand = Math.random().toString(36).slice(2);\n return `${prefix}_${Date.now().toString(36)}_${rand}`;\n}\n\n/** 构造一个结构化 CheckoutError。 */\nfunction makeError(\n code: string,\n message: string,\n category: CheckoutError['category'] = 'configuration'\n): CheckoutError {\n return {\n code,\n message,\n category,\n errorId: genId('err'),\n };\n}\n\nexport class CheckoutInstance {\n /** 结账唯一 id。 */\n readonly checkoutId: string;\n /** 协商后的运行时 id。 */\n readonly runtimeId: string;\n /** 协商后的能力集合。 */\n readonly capabilities: readonly string[];\n\n private readonly hostOrigin: string;\n private readonly transport: InstanceTransport;\n private session: PublicSessionView;\n /** 初始外观定制(透传给 create 出的每个 Element 的 iframe src)。 */\n private readonly appearance: Appearance | undefined;\n\n /** 已创建的 Element(按 elementId 索引)。 */\n /**\n * 互斥注册表的**单一数据源**:elementId → 已创建的 CheckoutElement。\n * 互斥判定由本 Map 实时推导(见 {@link assertNoConflict}),元素 `destroy()` 经\n * {@link releaseElement} 从本 Map 移除以释放名额(允许销毁后重建同类互斥 Element)。\n */\n private readonly elements = new Map<string, CheckoutElement>();\n\n /** 当前未决 confirm(同一时刻至多一个)。 */\n private pendingConfirm: PendingConfirm | null = null;\n /** paymentResult 事件订阅 handler(destroy 时解绑)。 */\n private readonly paymentResultHandler: (payload: unknown) => void;\n\n private destroyed = false;\n\n constructor(opts: CheckoutInstanceOptions) {\n this.checkoutId = opts.checkoutId;\n this.runtimeId = opts.runtimeId;\n this.capabilities = opts.capabilities;\n this.hostOrigin = opts.hostOrigin;\n this.transport = opts.transport;\n this.session = opts.session;\n this.appearance = opts.appearance;\n\n this.paymentResultHandler = (payload: unknown): void => {\n this.handlePaymentResult(payload);\n };\n this.transport.on('paymentResult', this.paymentResultHandler);\n }\n\n /**\n * 创建一个 Element 句柄(不自动挂载;互斥冲突抛 ELEMENT_CONFLICT)。\n *\n * 互斥规则(spec 6):\n * - 聚合 `card` 与任一拆分字段(cardNumber/cardExpiry/cardCvc)互斥。\n * - 同 `mode`(billing/shipping)的 address 不可重复。\n * - `expressCheckout` 单例。\n *\n * @param type - Element 类型。\n * @param options - 初始 Element 配置。\n * @returns 新建的 CheckoutElement。\n * @throws 已销毁时抛 INSTANCE_DESTROYED;互斥冲突抛 ELEMENT_CONFLICT。\n */\n create(type: ElementType, options?: ElementOptions): CheckoutElement {\n this.assertAlive();\n this.assertNoConflict(type, options);\n\n const elementId = genId('el');\n const elementOpts: CheckoutElementOptions = {\n elementId,\n type,\n hostOrigin: this.hostOrigin,\n checkoutId: this.checkoutId,\n transport: this.transport,\n initialOptions: options,\n colorScheme: this.appearance?.colorScheme,\n appearance: this.appearance,\n onDestroy: (id: string) => this.releaseElement(id),\n };\n const element = CheckoutElement.create(elementOpts);\n this.elements.set(elementId, element);\n return element;\n }\n\n /**\n * 发起支付确认。生成 operationId,发 confirm 命令拿 accepted,返回的 Promise\n * 由后续同 operationId 的 paymentResult 事件兑现。进行中再次调用 → CHECKOUT_BUSY。\n *\n * @param opts - 账单/配送地址、姓名、邮箱、returnUrl 等可选参数。\n * @returns 支付终态结果 PaymentOutcome。\n * @throws 已销毁时 reject INSTANCE_DESTROYED;进行中 reject CHECKOUT_BUSY。\n */\n confirm(opts?: ConfirmOptions): Promise<PaymentOutcome> {\n if (this.destroyed) {\n return Promise.reject(\n makeError(ErrorCode.INSTANCE_DESTROYED, 'Checkout instance has been destroyed', 'runtime')\n );\n }\n if (this.pendingConfirm) {\n return Promise.reject(\n makeError(ErrorCode.CHECKOUT_BUSY, 'A payment confirmation is already in progress', 'runtime')\n );\n }\n\n const operationId = genId('op');\n const payload: ConfirmReq = { ...opts, operationId };\n\n return new Promise<PaymentOutcome>((resolve, reject) => {\n // 先占位,防止 accepted 之前并发 confirm。\n this.pendingConfirm = { operationId, resolve, reject };\n this.transport.request('confirm', payload).catch((err: unknown) => {\n // confirm 命令本身失败:清理占位并 reject(paymentResult 不会到来)。\n if (this.pendingConfirm && this.pendingConfirm.operationId === operationId) {\n this.pendingConfirm = null;\n }\n reject(err as CheckoutError);\n });\n });\n }\n\n /**\n * 获取最新会话视图(透传 getSession 命令并写回本地快照)。\n *\n * @returns 最新 PublicSessionView。\n * @throws 已销毁时 reject INSTANCE_DESTROYED。\n */\n async getSession(): Promise<PublicSessionView> {\n this.assertAlive();\n const resp = (await this.transport.request('getSession', {})) as PublicSessionView;\n this.session = resp;\n return resp;\n }\n\n /**\n * 刷新会话(透传 refresh 命令并写回本地快照)。\n *\n * @returns 刷新后的 PublicSessionView。\n * @throws 已销毁时 reject INSTANCE_DESTROYED。\n */\n async refresh(): Promise<PublicSessionView> {\n this.assertAlive();\n const resp = (await this.transport.request('refresh', {})) as PublicSessionView;\n this.session = resp;\n return resp;\n }\n\n /**\n * 查询支付状态(原样返回 TxnStatus,不转义)。\n *\n * @returns txnStatus(可能含 txnId)。\n * @throws 已销毁时 reject INSTANCE_DESTROYED。\n */\n async getPaymentStatus(): Promise<GetPaymentStatusResp> {\n this.assertAlive();\n return (await this.transport.request('getPaymentStatus', {})) as GetPaymentStatusResp;\n }\n\n /**\n * 更新结账外观/语言(不改会话或金额)。\n *\n * @param patch - locale / appearance 增量。\n * @throws 已销毁时 reject INSTANCE_DESTROYED。\n */\n async updateCheckout(patch: { locale?: string; appearance?: Appearance }): Promise<void> {\n this.assertAlive();\n const payload: UpdateCheckoutReq = patch;\n await this.transport.request('updateCheckout', payload);\n }\n\n /**\n * 注册 Checkout 级事件 handler(透传 transport)。\n *\n * @param event - 事件名。\n * @param handler - 回调。\n * @throws 已销毁时抛 INSTANCE_DESTROYED。\n */\n on(event: EventName, handler: (payload: unknown) => void): void {\n this.assertAlive();\n this.transport.on(event, handler);\n }\n\n /**\n * 注销事件 handler(销毁后仍可安全调用)。\n *\n * @param event - 事件名。\n * @param handler - 先前注册的回调。\n */\n off(event: EventName, handler: (payload: unknown) => void): void {\n this.transport.off(event, handler);\n }\n\n /**\n * 销毁实例:幂等。释放全部 Element、解绑 paymentResult 监听、以\n * INSTANCE_DESTROYED reject 未决 confirm、发 destroy 命令并销毁 transport。\n * 此后迟到的 paymentResult 一律忽略,不改写已结束的 Promise。\n */\n destroy(): void {\n if (this.destroyed) {\n return;\n }\n this.destroyed = true;\n\n // 释放全部 Element 句柄。\n for (const element of this.elements.values()) {\n element.destroy();\n }\n this.elements.clear();\n\n // 解绑 paymentResult 监听(之后迟到结果无 handler 可达)。\n this.transport.off('paymentResult', this.paymentResultHandler);\n\n // 以 INSTANCE_DESTROYED reject 未决 confirm。\n if (this.pendingConfirm) {\n this.pendingConfirm.reject(\n makeError(ErrorCode.INSTANCE_DESTROYED, 'Checkout instance has been destroyed', 'runtime')\n );\n this.pendingConfirm = null;\n }\n\n // 通知托管侧并销毁 transport(request 在 destroy 后由 transport 自行拒绝)。\n void Promise.resolve(this.transport.request('destroy', {})).catch(() => undefined);\n this.transport.destroy();\n }\n\n /** 若已销毁则抛 INSTANCE_DESTROYED。 */\n private assertAlive(): void {\n if (this.destroyed) {\n throw makeError(ErrorCode.INSTANCE_DESTROYED, 'Checkout instance has been destroyed', 'runtime');\n }\n }\n\n /** 互斥检查:冲突时抛 ELEMENT_CONFLICT(由 elements Map 实时推导,不改变注册表)。 */\n private assertNoConflict(type: ElementType, options?: ElementOptions): void {\n const existing = [...this.elements.values()];\n const has = (t: ElementType): boolean => existing.some((e) => e.type === t);\n const hasCardField = (): boolean => existing.some((e) => CARD_FIELD_TYPES.includes(e.type));\n\n if (type === 'card') {\n if (has('card')) {\n throw makeError(ErrorCode.ELEMENT_CONFLICT, 'A combined card Element already exists');\n }\n if (hasCardField()) {\n throw makeError(\n ErrorCode.ELEMENT_CONFLICT,\n 'Combined card and split card fields are mutually exclusive; split card fields already exist'\n );\n }\n return;\n }\n if (CARD_FIELD_TYPES.includes(type)) {\n if (has('card')) {\n throw makeError(\n ErrorCode.ELEMENT_CONFLICT,\n 'Split card fields and combined card are mutually exclusive; a combined card already exists'\n );\n }\n // 同一拆分字段类型不可重复。\n if (has(type)) {\n throw makeError(\n ErrorCode.ELEMENT_CONFLICT,\n `A split card field of type ${type} already exists`\n );\n }\n return;\n }\n if (type === 'address') {\n const mode = (options as { mode?: string } | undefined)?.mode;\n if (mode && existing.some((e) => e.type === 'address' && e.mode === mode)) {\n throw makeError(\n ErrorCode.ELEMENT_CONFLICT,\n `An address Element with mode=${mode} already exists`\n );\n }\n return;\n }\n if (type === 'expressCheckout') {\n if (has('expressCheckout')) {\n throw makeError(ErrorCode.ELEMENT_CONFLICT, 'An expressCheckout Element already exists');\n }\n return;\n }\n }\n\n /**\n * 元素 `destroy()` 回调:从互斥注册表(elements Map)移除该 elementId,释放名额。\n * 幂等;实例整体 destroy 时(已置 destroyed)走统一 `elements.clear()` 路径,此处 no-op,\n * 避免遍历 elements 调 element.destroy() 时的并发修改。\n */\n private releaseElement(elementId: string): void {\n if (this.destroyed) {\n return;\n }\n this.elements.delete(elementId);\n }\n\n /** 处理 paymentResult 事件:按 operationId 兑现未决 confirm;迟到/不匹配忽略。 */\n private handlePaymentResult(payload: unknown): void {\n if (this.destroyed) {\n return;\n }\n if (typeof payload !== 'object' || payload === null) {\n return;\n }\n const evt = payload as Partial<PaymentResultEvent>;\n const pending = this.pendingConfirm;\n if (!pending) {\n return;\n }\n if (evt.operationId !== pending.operationId) {\n return;\n }\n if (!evt.outcome) {\n return;\n }\n this.pendingConfirm = null;\n pending.resolve(evt.outcome);\n }\n}\n","/**\n * 运行环境标识。\n * - `dev`:开发/测试托管页面。\n * - `prod`:生产托管页面。\n */\nexport type Env = 'dev' | 'prod';\n\n/**\n * 内置托管页面 origin(统一不带尾部斜杠)。\n */\nconst HOST_ORIGINS: Record<Env, string> = {\n dev: 'https://checkout.sunbay-dev.com',\n prod: 'https://checkout.sunbay.us',\n};\n\n/**\n * 解析托管页面 origin。\n *\n * @param env - 运行环境,默认 `'dev'`。\n * @param override - 覆盖地址(供环境变量/测试使用);非空时优先返回。\n * @returns 托管页面 origin(不带尾部斜杠)。\n * @example\n * resolveHostOrigin(); // 'https://checkout.sunbay-dev.com'\n * resolveHostOrigin('prod'); // 'https://checkout.sunbay.us'\n * resolveHostOrigin('dev', 'http://localhost:3000'); // 'http://localhost:3000'\n */\nexport function resolveHostOrigin(env: Env = 'dev', override?: string): string {\n if (override) {\n return override;\n }\n return HOST_ORIGINS[env];\n}\n","/**\n * createCheckout —— 商户 SDK 的唯一异步入口(spec 4)。\n *\n * 流程:\n * 1. 生成 `checkoutId`,`resolveHostOrigin(env, hostOrigin)` 得托管 origin。\n * 2. 建 transport、`createHiddenIframe()` 加载托管 main iframe。\n * 3. 注册 onHello;等 RuntimeHello(超时 15s → reject RUNTIME_LOAD_FAILED)。\n * 4. 选共同主版本(无交集 → reject PROTOCOL_UNSUPPORTED)。\n * 5. 发 `initialize`(sessionId/locale/appearance/paymentMethods),拿\n * capabilities + PublicSessionView;任一步失败 reject 并销毁 transport。\n * 6. 用握手 runtimeId 注入 transport,构造并 resolve {@link CheckoutInstance}。\n *\n * 安全约束(AGENTS/spec):本层只做握手/初始化编排,**绝不触碰卡值**。\n */\n\nimport { MainFrameTransport } from './transport/MainFrameTransport';\nimport { CheckoutInstance, type InstanceTransport } from './CheckoutInstance';\nimport { resolveHostOrigin, type Env } from './config/env';\nimport {\n ErrorCode,\n PROTOCOL_MAJOR,\n type Appearance,\n type CheckoutError,\n type InitializeReq,\n type InitializeResp,\n type PaymentMethodFilter,\n type RuntimeHello,\n} from '@sunbay/checkout-sdk-protocol';\n\n/** 握手超时(毫秒):与 transport handshake 超时一致(15s)。 */\nconst HANDSHAKE_TIMEOUT_MS = 15_000;\n\n/**\n * 创建 CheckoutInstance 时可注入的内部 transport 工厂(仅供测试/高级定制)。\n *\n * 真实场景使用内置 MainFrameTransport;测试可注入 mock 以驱动 hello/事件。\n */\nexport type TransportFactory = (args: {\n checkoutId: string;\n hostOrigin: string;\n}) => InstanceTransport;\n\n/** createCheckout 参数。 */\nexport interface CreateCheckoutOptions {\n /** 后端创建的结账会话 id(必填)。 */\n sessionId: string;\n /** 运行环境(dev/prod),默认 dev。 */\n env?: Env;\n /** 覆盖托管 origin(优先于 env)。 */\n hostOrigin?: string;\n /** 语言。 */\n locale?: string;\n /** 外观定制。 */\n appearance?: Appearance;\n /** 支付方式过滤(只做减法/排序)。 */\n paymentMethods?: PaymentMethodFilter;\n /** 内部注入点:自定义 transport 工厂(测试用,不属于公开 API 契约)。 */\n __transportFactory?: TransportFactory;\n}\n\n/** 生成唯一 id。 */\nfunction genId(prefix: string): string {\n const rand = Math.random().toString(36).slice(2);\n return `${prefix}_${Date.now().toString(36)}_${rand}`;\n}\n\n/** 构造一个结构化 CheckoutError(runtime 分类)。 */\nfunction makeError(code: string, message: string): CheckoutError {\n return {\n code,\n message,\n category: 'runtime',\n errorId: genId('err'),\n };\n}\n\n/** 默认 transport 工厂:内置 MainFrameTransport。 */\nconst defaultTransportFactory: TransportFactory = ({ checkoutId, hostOrigin }) =>\n new MainFrameTransport({ checkoutId, hostOrigin });\n\n/**\n * 创建一个结账实例:握手 + 初始化成功后 resolve。\n *\n * @param opts - 结账参数。\n * @returns 就绪的 CheckoutInstance。\n * @throws reject RUNTIME_LOAD_FAILED(握手超时)/ PROTOCOL_UNSUPPORTED(无共同主版本)\n * / 或 initialize 的业务错误。\n * @example\n * const checkout = await createCheckout({ sessionId: 'sess_x', env: 'prod' });\n */\nexport async function createCheckout(opts: CreateCheckoutOptions): Promise<CheckoutInstance> {\n const checkoutId = genId('co');\n const hostOrigin = resolveHostOrigin(opts.env, opts.hostOrigin);\n const factory = opts.__transportFactory ?? defaultTransportFactory;\n const transport = factory({ checkoutId, hostOrigin });\n\n // 启动托管 main iframe(隐藏 0 尺寸)。\n transport.createHiddenIframe();\n\n let hello: RuntimeHello;\n try {\n hello = await waitForHello(transport);\n } catch (err) {\n transport.destroy();\n throw err;\n }\n\n // 选共同主版本。\n if (!hello.supportedMajorVersions.includes(PROTOCOL_MAJOR)) {\n transport.destroy();\n throw makeError(\n ErrorCode.PROTOCOL_UNSUPPORTED,\n `No common major protocol version: SDK=${PROTOCOL_MAJOR}, runtime=${JSON.stringify(hello.supportedMajorVersions)}`\n );\n }\n\n // 注入协商出的 runtimeId:必须在发送 initialize 之前,否则出站信封 runtimeId\n // 为空串,被 main 端点静默丢弃,导致 initialize 超时。\n transport.setRuntimeId(hello.runtimeId);\n\n // 发 initialize。\n const initReq: InitializeReq = {\n sessionId: opts.sessionId,\n locale: opts.locale,\n appearance: opts.appearance,\n paymentMethods: opts.paymentMethods,\n };\n let initResp: InitializeResp;\n try {\n initResp = (await transport.request('initialize', initReq)) as InitializeResp;\n } catch (err) {\n transport.destroy();\n throw err as CheckoutError;\n }\n\n return new CheckoutInstance({\n checkoutId,\n runtimeId: hello.runtimeId,\n hostOrigin,\n transport,\n capabilities: initResp.capabilities,\n session: initResp.session,\n appearance: opts.appearance,\n });\n}\n\n/** 等待 RuntimeHello;超时 reject RUNTIME_LOAD_FAILED。 */\nfunction waitForHello(transport: InstanceTransport): Promise<RuntimeHello> {\n return new Promise<RuntimeHello>((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) {\n return;\n }\n settled = true;\n reject(makeError(ErrorCode.RUNTIME_LOAD_FAILED, 'Timed out waiting for hosted runtime handshake'));\n }, HANDSHAKE_TIMEOUT_MS);\n\n transport.onHello((raw: unknown) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n resolve(raw as RuntimeHello);\n });\n });\n}\n"],"mappings":"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","names":["import_checkout_sdk_protocol","import_checkout_sdk_protocol","makeError","import_checkout_sdk_protocol","genId","makeError","import_checkout_sdk_protocol","genId","makeError","import_checkout_sdk_protocol"]}