UNPKG

@wuchuheng/window-message

Version:

A modern TypeScript library for cross-window messaging

1 lines 9.21 kB
{"version":3,"sources":["../src/logger.ts","../src/index.ts"],"sourcesContent":["export const logger = {\r\n log: (...args: any[]) => {\r\n console.log(...args)\r\n },\r\n error: (...args: any[]) => {\r\n console.error(...args)\r\n }\r\n}","import { logger } from \"./logger\"\r\n\r\ntype ChannelMsg<T> = {\r\n success: boolean\r\n channel: string\r\n isSetup?: boolean\r\n data: T\r\n error?: { msg: string; stack: string }\r\n}\r\n\r\ntype CreateChannelReturn<Req, Res> = {\r\n request: (message: Req, windowObj: Window) => Promise<Res>\r\n handle: (callback: (req: Req) => Promise<Res>) => void\r\n}\r\n\r\n/**\r\n * Create a channel to communicate with the window.\r\n * @param channel - The channel to create.\r\n * @returns The request and handle functions.\r\n */\r\nexport const createChannel = <Req, Res>(\r\n channel: string\r\n): CreateChannelReturn<Req, Res> => {\r\n const requestChannel = `request:/${channel}`\r\n const responseChannel = `response:/${channel}`\r\n\r\n // 2. Handle logic.\r\n // 2.1 Check if the channel is setup.\r\n let isSetup = false\r\n\r\n // 2.1 Access the setup message from child window.\r\n const processSetupMsg = () =>\r\n new Promise<void>((resolve) => {\r\n const onMessage = (event: MessageEvent) => {\r\n // 1. Handle logic.\r\n if (event.origin !== window.location.origin) {\r\n return\r\n }\r\n\r\n const channelMsg = event.data as ChannelMsg<Req>\r\n if (channelMsg.channel !== requestChannel) {\r\n return\r\n }\r\n if (channelMsg.isSetup) {\r\n isSetup = true\r\n window.removeEventListener(\"message\", onMessage)\r\n resolve()\r\n logger.log(`[windows message: request side]: setup success`)\r\n return\r\n }\r\n }\r\n window.addEventListener(\"message\", onMessage)\r\n })\r\n\r\n processSetupMsg()\r\n\r\n const waitChildWindowSetup = async () => {\r\n // 2. Handle logic.\r\n if (isSetup) {\r\n return\r\n }\r\n await processSetupMsg()\r\n }\r\n\r\n // 3. Return the result.\r\n return {\r\n request: (message: Req, windowObj: Window = window) =>\r\n request(\r\n message,\r\n windowObj,\r\n responseChannel,\r\n requestChannel,\r\n waitChildWindowSetup\r\n ),\r\n\r\n handle: (callback: (req: Req) => Promise<Res>) =>\r\n handle(callback, requestChannel, responseChannel)\r\n }\r\n}\r\n\r\n/**\r\n * Handle the request from the window.\r\n * @param callback - The callback to handle the request.\r\n */\r\nconst handle = <Req, Res>(\r\n callback: (req: Req) => Promise<Res>,\r\n requestChannel: string,\r\n responseChannel: string\r\n) => {\r\n // 2. Handle logic.\r\n // 2.1 Send setup message to parent window.\r\n const setupMsg: ChannelMsg<Req> = {\r\n channel: requestChannel,\r\n success: true,\r\n isSetup: true,\r\n data: undefined as unknown as Req\r\n }\r\n window.parent.postMessage(setupMsg)\r\n logger.log(\r\n `[windows message: handle side]: setup: ${JSON.stringify(setupMsg)}`\r\n )\r\n\r\n const messageHandler = (event: MessageEvent) => {\r\n // 1. Handle logic.\r\n if (event.origin !== window.location.origin) {\r\n return\r\n }\r\n\r\n const channelMsg = event.data as ChannelMsg<Req>\r\n if (channelMsg.channel !== requestChannel) {\r\n return\r\n }\r\n \r\n // Skip setup messages - they are not actual requests\r\n if (channelMsg.isSetup) {\r\n return\r\n }\r\n \r\n logger.log(\r\n `[windows message: handle side]: Receive ${JSON.stringify(channelMsg)} `\r\n )\r\n\r\n // 2. Handle logic.\r\n callback(channelMsg.data)\r\n .then((res) => {\r\n const msg: ChannelMsg<Res> = {\r\n channel: responseChannel,\r\n success: true,\r\n data: res\r\n }\r\n\r\n event.source?.postMessage(msg, { targetOrigin: event.origin })\r\n\r\n logger.log(\r\n `[windows message: handle side]: Post ${JSON.stringify(msg)} `\r\n )\r\n })\r\n .catch((err) => {\r\n const errMsg: ChannelMsg<Res> = {\r\n channel: responseChannel,\r\n success: false,\r\n data: undefined as unknown as Res,\r\n error: {\r\n msg: err.message,\r\n stack: err.stack || \"\"\r\n }\r\n }\r\n event.source?.postMessage(errMsg, { targetOrigin: event.origin })\r\n logger.error(\r\n `[windows message: handle side]: Post ${JSON.stringify(errMsg)} `\r\n )\r\n })\r\n // Keep the handler active for multiple requests - don't remove listener\r\n }\r\n\r\n // 2.2 Listen to message from parent window.\r\n window.addEventListener(\"message\", messageHandler)\r\n}\r\n\r\n/**\r\n * Request the message to the window.\r\n * @param message - The message to request.\r\n * @returns The response from the window.\r\n */\r\nconst request = async <Req, Res>(\r\n message: Req,\r\n windowObj: Window = window,\r\n responseChannel: string,\r\n requestChannel: string,\r\n waitChildWindowSetup: () => Promise<void>\r\n): Promise<Res> => {\r\n // 2. Handle logic.\r\n await waitChildWindowSetup()\r\n\r\n // 2.2 Send message to child window.\r\n return new Promise<Res>((resolve, reject) => {\r\n const messageHandler = (event: MessageEvent) => {\r\n // 1. Handle input.\r\n if (event.origin !== window.location.origin) {\r\n return\r\n }\r\n // 1.2 If the channel is not the same, return.\r\n const channelMsg = event.data as ChannelMsg<Res>\r\n if (channelMsg.channel !== responseChannel) {\r\n return\r\n }\r\n\r\n // 2. Handle logic.\r\n logger.log(\r\n `[windows message: request side]: Receive ${JSON.stringify(channelMsg)} `\r\n )\r\n if (channelMsg.success) {\r\n resolve(channelMsg.data)\r\n } else {\r\n reject(channelMsg.error?.msg || \"Unknown error\")\r\n console.error(channelMsg.error?.msg)\r\n console.error(channelMsg.error?.stack)\r\n }\r\n\r\n // 3. Remove the listener.\r\n window.removeEventListener(\"message\", messageHandler)\r\n }\r\n\r\n window.addEventListener(\"message\", messageHandler)\r\n\r\n const msg: ChannelMsg<Req> = {\r\n channel: requestChannel,\r\n success: true,\r\n data: message\r\n }\r\n\r\n logger.log(`[windows message: request side]: Post ${JSON.stringify(msg)} `)\r\n windowObj.postMessage(msg, \"*\")\r\n })\r\n}\r\n"],"mappings":"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","names":[]}