UNPKG

passerelle

Version:

TypeScript BroadcastChannel wrapper for structured Events and Async/Await.

112 lines (110 loc) 3.21 kB
// src/channel/channel.ts var createChannel = (channelName) => { const channel = new BroadcastChannel(channelName); const eventHandlers = /* @__PURE__ */ new Map(); const awaitHandlers = /* @__PURE__ */ new Map(); const pendingRequests = /* @__PURE__ */ new Map(); const handleEventMessage = (message) => { const handlers = eventHandlers.get(message.action); if (!handlers) return; for (const handler of handlers) { handler(message.payload); } }; const handleRequestMessage = async (message) => { const handler = awaitHandlers.get(message.action); if (!handler) { throw new Error(`No handler registered for action "${message.action}"`); } const result = await handler(message.payload); channel.postMessage({ type: "response", requestId: message.requestId, result }); }; const handleResponseMessage = (message) => { const pending = pendingRequests.get(message.requestId); if (!pending) return; clearTimeout(pending.timeout); pendingRequests.delete(message.requestId); pending.resolve(message.result); }; const handleMessage = (message) => { switch (message.data.type) { case "event": handleEventMessage(message.data); break; case "request": handleRequestMessage(message.data); break; case "response": handleResponseMessage(message.data); break; default: throw new Error(`Unknown message type received "${message}"`); } }; const onEvent = (action, handler) => { if (!eventHandlers.has(action)) { eventHandlers.set(action, /* @__PURE__ */ new Set()); } const handlers = eventHandlers.get(action); if (handlers) { handlers.add(handler); } }; const onAwait = (action, handler) => { awaitHandlers.set(action, handler); }; const sendEvent = (action, payload) => { const handlers = eventHandlers.get(action); if (handlers) { for (const handler of handlers) { handler(payload); } } channel.postMessage({ type: "event", action, payload }); }; const sendAwait = (action, payload) => { return new Promise((resolve, reject) => { const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2); const timeout = setTimeout(() => { if (pendingRequests.has(requestId)) { pendingRequests.delete(requestId); reject(new Error(`Request timeout: ${action}`)); } }, 5e3); pendingRequests.set(requestId, { resolve, reject, timeout }); channel.postMessage({ type: "request", requestId, action, payload }); }); }; const destroy = () => { channel.removeEventListener("message", handleMessage); for (const [_id, { reject }] of pendingRequests.entries()) { reject(new Error("Channel closed")); } pendingRequests.clear(); eventHandlers.clear(); awaitHandlers.clear(); channel.close(); }; channel.addEventListener("message", handleMessage); return { onEvent, onAwait, sendEvent, sendAwait, destroy }; }; export { createChannel };