UNPKG

iframe-connect

Version:

A lightweight, type-safe cross-frame communication library with plugin system and multi-window isolation

481 lines (474 loc) 13.9 kB
'use strict'; var chunkLKKWNJE4_js = require('./chunk-LKKWNJE4.js'); // src/message-handler.ts var MessageHandler = class { // 检查间隔(毫秒) constructor(targetOrigin, timeout, debug = false) { this.pendingRequests = /* @__PURE__ */ new Map(); this.eventListeners = /* @__PURE__ */ new Map(); this.messageId = 0; this.timeoutChecker = null; // 集中式超时检查器 this.checkInterval = 1e3; this.targetOrigin = targetOrigin; this.timeout = timeout; this.debug = debug; this.startTimeoutChecker(); } /** * 启动集中式超时检查器 */ startTimeoutChecker() { if (this.timeoutChecker !== null) return; this.timeoutChecker = setInterval(() => { this.checkTimeouts(); }, this.checkInterval); } /** * 检查所有待处理请求的超时 */ checkTimeouts() { if (this.pendingRequests.size === 0) return; const now = Date.now(); const timedOutIds = []; this.pendingRequests.forEach((request, id) => { if (request.expirationTime && now >= request.expirationTime) { timedOutIds.push(id); } }); timedOutIds.forEach((id) => { const request = this.pendingRequests.get(id); if (request) { this.pendingRequests.delete(id); request.reject(new Error(`Request timeout: ${id}`)); if (this.debug) { this.log(`\u8BF7\u6C42\u8D85\u65F6: ${id}`); } } }); } /** * 生成唯一的消息ID */ generateMessageId() { return `msg_${Date.now()}_${++this.messageId}`; } /** * 调试日志 */ log(...args) { if (this.debug) { console.log("[CrossFrame]", ...args); } } /** * 处理响应消息 */ handleResponse(response) { const pending = this.pendingRequests.get(response.id); if (!pending) { return; } this.pendingRequests.delete(response.id); if (response.success) { pending.resolve(response.data); } else { pending.reject(new Error(response.error || "Unknown error")); } } /** * 处理请求消息 */ async handleRequest(request, source) { this.log("Received request:", request); const listeners = this.eventListeners.get(request.type); if (!listeners || listeners.size === 0) { const response = { id: request.id, success: false, error: `No handler for message type: ${request.type}`, isResponse: true, timestamp: Date.now() }; source.postMessage(response, this.targetOrigin); return; } try { const results = await Promise.all( Array.from(listeners).map((listener) => listener(request.payload)) ); const response = { id: request.id, success: true, data: results[0], isResponse: true, timestamp: Date.now() }; source.postMessage(response, this.targetOrigin); } catch (error) { const response = { id: request.id, success: false, error: error instanceof Error ? error.message : "Unknown error", isResponse: true, timestamp: Date.now() }; source.postMessage(response, this.targetOrigin); } } /** * 创建待处理的请求 * @param id 请求ID * @param resolve 成功回调 * @param reject 失败回调 * @param requestTimeout 可选的单个请求超时时间,覆盖全局设置 */ createPendingRequest(id, resolve, reject, requestTimeout) { const timeout = requestTimeout !== void 0 ? requestTimeout : this.timeout; const expirationTime = timeout !== void 0 ? Date.now() + timeout : void 0; this.pendingRequests.set(id, { resolve, reject, expirationTime }); } /** * 添加事件监听器 */ addEventListener(type, listener) { if (!this.eventListeners.has(type)) { this.eventListeners.set(type, /* @__PURE__ */ new Set()); } this.eventListeners.get(type).add(listener); return () => { const listeners = this.eventListeners.get(type); if (listeners) { listeners.delete(listener); if (listeners.size === 0) { this.eventListeners.delete(type); } } }; } /** * 移除事件监听器 */ removeEventListener(type, listener) { const listeners = this.eventListeners.get(type); if (!listeners) { return; } if (listener) { listeners.delete(listener); if (listeners.size === 0) { this.eventListeners.delete(type); } } else { this.eventListeners.delete(type); } } /** * 清理所有待处理的请求 */ cleanup() { if (this.timeoutChecker !== null) { clearInterval(this.timeoutChecker); this.timeoutChecker = null; } this.pendingRequests.forEach(({ reject }) => { reject(new Error("Bridge destroyed")); }); this.pendingRequests.clear(); this.eventListeners.clear(); } /** * 获取待处理请求数量(用于调试) */ getPendingRequestsCount() { return this.pendingRequests.size; } /** * 获取监听器数量(用于调试) */ getListenersCount() { return this.eventListeners.size; } }; // src/base-bridge.ts var IframeBridge = class { constructor(config = {}) { this.config = chunkLKKWNJE4_js.__spreadValues({ targetOrigin: "*", timeout: 5e3, debug: false, enableMultiWindow: false, windowId: "" }, config); if (this.config.enableMultiWindow) { this.windowId = this.config.windowId || this.generateWindowId(); if (this.config.debug) { console.log(`[CrossFrame] \u591A\u7A97\u53E3\u6A21\u5F0F\u542F\u7528\uFF0C\u7A97\u53E3ID: ${this.windowId}`); } } this.messageHandler = new MessageHandler( this.config.targetOrigin, this.config.timeout, this.config.debug ); this.setupMessageListener(); } /** * 生成唯一窗口ID */ generateWindowId() { return `window_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * 发送消息(无返回值) */ send(type, payload) { const targetWindow = this.getTargetWindow(); if (!targetWindow) { this.messageHandler.log("\u76EE\u6807\u7A97\u53E3\u4E0D\u53EF\u7528"); return; } const message = { type, payload, timestamp: Date.now() }; if (this.config.enableMultiWindow && this.windowId) { message.windowId = this.windowId; } this.messageHandler.log("\u53D1\u9001\u6D88\u606F:", message); targetWindow.postMessage(message, this.config.targetOrigin); } /** * 发送请求(有返回值) * @param type 消息类型 * @param payload 消息负载 * @param requestTimeout 单个请求的超时时间(毫秒),覆盖全局设置 */ request(type, payload, requestTimeout) { return new Promise((resolve, reject) => { const targetWindow = this.getTargetWindow(); if (!targetWindow) { reject(new Error("\u76EE\u6807\u7A97\u53E3\u4E0D\u53EF\u7528")); return; } const messageId = this.messageHandler.generateMessageId(); this.messageHandler.createPendingRequest( messageId, resolve, reject, requestTimeout !== void 0 ? requestTimeout : void 0 ); const message = { id: messageId, type, payload, needResponse: true, timestamp: Date.now() }; if (this.config.enableMultiWindow && this.windowId) { message.windowId = this.windowId; } this.messageHandler.log("\u53D1\u9001\u8BF7\u6C42:", message); targetWindow.postMessage(message, this.config.targetOrigin); }); } /** * 监听消息 */ on(type, listener) { return this.messageHandler.addEventListener(type, listener); } /** * 取消监听 */ off(type, listener) { this.messageHandler.removeEventListener(type, listener); } /** * 处理接收到的消息 */ handleIncomingMessage(event) { const targetWindow = this.getTargetWindow(); if (!targetWindow || event.source !== targetWindow) { return; } if (this.config.enableMultiWindow) { if (!event.data || !event.data.windowId || event.data.windowId !== this.windowId) { if (this.config.debug) { this.messageHandler.log("\u5FFD\u7565\u5176\u4ED6\u7A97\u53E3\u6D88\u606F:", event.data); } return; } } if (event.data && event.data.isResponse) { this.messageHandler.handleResponse(event.data); return; } if (event.data && event.data.needResponse) { this.messageHandler.handleRequest( event.data, targetWindow ); return; } if (event.data && event.data.type) { const listeners = this.messageHandler.eventListeners.get( event.data.type ); if (listeners && listeners.size > 0) { listeners.forEach((listener) => { try { listener(event.data.payload); } catch (error) { this.messageHandler.log("\u4E8B\u4EF6\u76D1\u542C\u5668\u6267\u884C\u9519\u8BEF:", error); } }); } } } /** * 获取调试信息 */ getDebugInfo() { return { config: this.config, windowId: this.windowId, pendingRequests: this.messageHandler.getPendingRequestsCount(), listeners: this.messageHandler.getListenersCount() }; } /** * 销毁桥梁 */ destroy() { this.messageHandler.cleanup(); window.removeEventListener( "message", this.handleIncomingMessage.bind(this) ); } }; // src/host-bridge.ts var HostBridge = class extends IframeBridge { constructor(iframe, config = {}) { super(config); this.iframe = iframe; } setupMessageListener() { window.addEventListener("message", this.handleIncomingMessage.bind(this)); } getTargetWindow() { return this.iframe.contentWindow; } }; // src/child-bridge.ts var ChildBridge = class extends IframeBridge { constructor(config = {}) { super(config); } setupMessageListener() { window.addEventListener("message", this.handleIncomingMessage.bind(this)); } getTargetWindow() { return window.parent; } }; // src/factory.ts function createEnhancedHostBridge(iframe, config = {}) { const _a = config, { plugins: pluginsConfig } = _a, bridgeConfig = chunkLKKWNJE4_js.__objRest(_a, ["plugins"]); const bridge = new HostBridge(iframe, bridgeConfig); if (pluginsConfig) { applyPlugins(bridge, pluginsConfig); } return bridge; } function createEnhancedChildBridge(config = {}) { const _a = config, { plugins: pluginsConfig } = _a, bridgeConfig = chunkLKKWNJE4_js.__objRest(_a, ["plugins"]); const bridge = new ChildBridge(bridgeConfig); if (pluginsConfig) { applyPlugins(bridge, pluginsConfig); } return bridge; } function createEnhancedBridge(iframeOrConfig, config) { if (window !== window.parent) { const bridgeConfig = iframeOrConfig instanceof HTMLElement ? config : iframeOrConfig; return createEnhancedChildBridge(bridgeConfig); } if (iframeOrConfig instanceof HTMLElement) { return createEnhancedHostBridge(iframeOrConfig, config); } throw new Error("\u5728\u4E3B\u7A97\u53E3\u73AF\u5883\u4E2D\u5FC5\u987B\u63D0\u4F9B iframe \u5143\u7D20"); } function applyPlugins(bridge, config) { if (config.logger) { const options = config.logger === true ? {} : config.logger; chunkLKKWNJE4_js.createLogger(bridge, options); } if (config.retry) { const options = config.retry === true ? {} : config.retry; chunkLKKWNJE4_js.createRetryManager(bridge, options); } if (config.queue) { const options = config.queue === true ? {} : config.queue; chunkLKKWNJE4_js.createQueueManager(bridge, options); } } function createHostBridge(iframe, config) { return new HostBridge(iframe, config); } function createChildBridge(config) { return new ChildBridge(config); } function createAutoBridge(iframeOrConfig, config) { if (window !== window.parent) { const bridgeConfig = iframeOrConfig instanceof HTMLElement ? config : iframeOrConfig; return new ChildBridge(bridgeConfig); } if (iframeOrConfig instanceof HTMLElement) { return new HostBridge(iframeOrConfig, config); } throw new Error("\u5728\u4E3B\u7A97\u53E3\u73AF\u5883\u4E2D\u5FC5\u987B\u63D0\u4F9B iframe \u5143\u7D20"); } Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return chunkLKKWNJE4_js.Logger; } }); Object.defineProperty(exports, "QueueManager", { enumerable: true, get: function () { return chunkLKKWNJE4_js.QueueManager; } }); Object.defineProperty(exports, "RetryManager", { enumerable: true, get: function () { return chunkLKKWNJE4_js.RetryManager; } }); Object.defineProperty(exports, "createLogger", { enumerable: true, get: function () { return chunkLKKWNJE4_js.createLogger; } }); Object.defineProperty(exports, "createQueueManager", { enumerable: true, get: function () { return chunkLKKWNJE4_js.createQueueManager; } }); Object.defineProperty(exports, "createRetryManager", { enumerable: true, get: function () { return chunkLKKWNJE4_js.createRetryManager; } }); exports.ChildBridge = ChildBridge; exports.HostBridge = HostBridge; exports.IframeBridge = IframeBridge; exports.MessageHandler = MessageHandler; exports.createAutoBridge = createAutoBridge; exports.createBridge = createEnhancedBridge; exports.createChildBridge = createChildBridge; exports.createEnhancedBridge = createEnhancedBridge; exports.createEnhancedChildBridge = createEnhancedChildBridge; exports.createEnhancedHostBridge = createEnhancedHostBridge; exports.createHostBridge = createHostBridge; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map