@player-tools/devtools-messenger 0.10.0-next.0 → 0.10.1
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.
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/index.test.ts +36 -36
- package/src/index.ts +11 -11
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/messenger/src/index.ts"],"sourcesContent":["import uid from \"tiny-uid\";\nimport type {\n BaseEvent,\n Connection,\n DisconnectEvent,\n EventsBatchEvent,\n InternalEvent,\n MessengerEvent,\n MessengerOptions,\n RequestLostEventsEvent,\n Transaction,\n TransactionMetadata,\n} from \"@player-tools/devtools-types\";\n\nconst internalEvents: Array<InternalEvent<BaseEvent<string, unknown>>[\"type\"]> =\n [\n \"MESSENGER_BEACON\",\n \"MESSENGER_DISCONNECT\",\n \"MESSENGER_REQUEST_LOST_EVENTS\",\n \"MESSENGER_EVENT_BATCH\",\n ];\n\n/**\n * Messenger<EventsType>\n *\n * Self-sufficient, lossless communication between instances.\n *\n * @param options\n * @param options.context - context to use for this instance\n * @param options.id - unique id for this instance, will be generated if not provided\n * @param options.beaconIntervalMS - time to wait between beacons in milliseconds, defaults to 1000\n * @param options.debug - if true, will log debug messages to console, defaults to false\n * @param options.messageCallback - callback to handle messages\n * @param options.sendMessage - function to send messages\n * @param options.addListener - function to add a listener\n * @param options.removeListener - function to remove a listener\n * @param options.handleFailedMessage - function to handle failed messages\n * @param option.log - function to handle logging\n * @returns Messenger\n * @example\n * ```typescript\n * const messenger = new Messenger({{\n * context: \"devtools\",\n * target: \"player\",\n * messageCallback: (message) => dispatch(message),\n * sendMessage: (message) =>\n * browser.tabs\n * ? browser.tabs\n * .query({ active: true, currentWindow: true })\n * .then((tabs) => {\n * if (tabs[0].id) {\n * browser.tabs.sendMessage(tabs[0].id, message);\n * }\n * })\n * : browser.runtime.sendMessage(message),\n * addListener: (callback) => {\n * browser.runtime.onMessage.addListener(callback);\n * },\n * removeListener: (callback) => {\n * browser.runtime.onMessage.removeListener(callback);\n * },\n * });\n * ```\n */\nexport class Messenger<T extends BaseEvent<string, unknown>> {\n /** static record of events by isntance ID */\n private static events: Record<\n string,\n Array<MessageEvent<BaseEvent<string, unknown>>>\n > = {};\n\n /** static connections record by instance ID */\n private static connections: Record<string, Record<string, Connection>> = {};\n\n /** beacon interval */\n private beaconInterval: NodeJS.Timeout | null = null;\n\n /** time between beacons milliseconds */\n private beaconIntervalMS: number;\n\n /** callback to handle messages, here for instance binding */\n private handleMessage: (\n message: TransactionMetadata & MessengerEvent<T>\n ) => void;\n\n /** unique id */\n private id: string;\n\n constructor(private options: MessengerOptions<T>) {\n // set defaults:\n this.id = options.id || uid();\n this.beaconIntervalMS = options.beaconIntervalMS || 1000;\n\n // start beacon interval:\n this.beaconInterval = setInterval(\n this.beacon.bind(this),\n this.beaconIntervalMS\n );\n\n // bind message handler:\n this.handleMessage = this._handleMessage.bind(this);\n\n // add listener:\n this.options.addListener(this.handleMessage);\n }\n\n private log(message: string) {\n if (this.options.debug) {\n this.options.logger.log(\n `[MESSENGER-${this.id}](${this.options.context}): ${message}`\n );\n }\n }\n\n private getConnection(id: string) {\n if (!Messenger.connections[this.id]) {\n Messenger.connections[this.id] = {};\n }\n\n return Messenger.connections[this.id][id];\n }\n\n private addConnection(id: string) {\n Messenger.connections[this.id][id] = {\n id,\n messagesReceived: 0,\n messagesSent: 0,\n desync: false,\n };\n }\n\n private getEvents() {\n if (!Messenger.events[this.id]) {\n Messenger.events[this.id] = [];\n }\n\n return Messenger.events[this.id] as unknown as MessengerEvent<T>[];\n }\n\n private addEvent(event: MessengerEvent<T>) {\n const events = this.getEvents();\n events.push(event);\n }\n\n /** generate a sequential id for each non-internal message */\n private getTransactionID(message: MessengerEvent<T>) {\n if (\n !message.target ||\n internalEvents.includes(message.type as InternalEvent<T>[\"type\"])\n ) {\n return -1;\n }\n\n if (!this.getConnection(message.target)) {\n this.addConnection(message.target);\n }\n\n const connection = this.getConnection(message.target);\n connection.messagesSent += 1;\n return connection.messagesSent;\n }\n\n private addTransactionMetadata(event: MessengerEvent<T>): Transaction<T> {\n const metadata = {\n _messenger_: true,\n id: this.getTransactionID(event),\n sender: this.id,\n timestamp: Date.now(),\n context: this.options.context,\n ...(event.target && { target: event.target }),\n };\n\n return {\n ...metadata,\n ...event,\n };\n }\n\n /** there is no persistent layer bookkeeping connections,\n * so beacon to inform others of its presence */\n private beacon() {\n this.options.sendMessage(\n this.addTransactionMetadata({\n type: \"MESSENGER_BEACON\",\n payload: null,\n })\n );\n }\n\n private _handleMessage(transaction: Transaction<T>) {\n const parsed: Transaction<T> =\n typeof transaction === \"string\" ? JSON.parse(transaction) : transaction;\n\n const isFromMessenger = parsed._messenger_;\n const isFromSelf = parsed.sender === this.id;\n const isFromSameContext = parsed.context === this.options.context;\n const isTargetingOthers = parsed.target ? parsed.target !== this.id : false;\n const connection = this.getConnection(parsed.sender);\n const isKnownConnection = Boolean(connection);\n\n if (\n !isFromMessenger ||\n isFromSelf ||\n isFromSameContext ||\n isTargetingOthers ||\n (isKnownConnection && parsed.type === \"MESSENGER_BEACON\")\n ) {\n return;\n }\n\n const handlers: Record<string, (parsed: Transaction<T>) => void> = {\n MESSENGER_BEACON: this.handleBeaconMessage.bind(this),\n MESSENGER_DISCONNECT: this.handleDisconnectMessage.bind(this),\n MESSENGER_REQUEST_LOST_EVENTS: this.handleLostEventsRequest.bind(this),\n };\n\n const handler = handlers[(parsed as BaseEvent<string, unknown>).type];\n\n if (handler) {\n handler(parsed);\n return;\n }\n\n if (isKnownConnection) {\n const isBatch = parsed.type === \"MESSENGER_EVENT_BATCH\";\n\n const transactionID = isBatch\n ? (parsed.payload as EventsBatchEvent<T>[\"payload\"]).events[0].id\n : parsed.id;\n\n const { messagesReceived, desync } = connection;\n\n // if we already received this message, ignore:\n if (transactionID > -1 && transactionID <= messagesReceived) {\n return;\n }\n\n // if we missed messages, request them, unless we already did:\n if (\n !desync &&\n transactionID > -1 &&\n transactionID > messagesReceived + 1\n ) {\n const message: RequestLostEventsEvent = {\n type: \"MESSENGER_REQUEST_LOST_EVENTS\",\n payload: {\n messagesReceived,\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `requesting lost messages from ${parsed.context}:${parsed.sender}`\n );\n\n // set desync, so we don't request again:\n connection.desync = true;\n\n // don't process this message, since we requested missing ones:\n return;\n }\n\n if (isBatch) {\n // clear desync flag on event batch:\n connection.desync = false;\n connection.messagesReceived += (\n parsed.payload as EventsBatchEvent<T>[\"payload\"]\n ).events.length;\n } else {\n connection.messagesReceived += 1;\n }\n }\n\n this.options.messageCallback(parsed);\n\n this.log(\n `message received: ${(parsed as BaseEvent<string, unknown>).type}`\n );\n }\n\n private handleBeaconMessage(parsed: Transaction<T>) {\n if (this.getConnection(parsed.sender)) {\n return;\n }\n\n this.addConnection(parsed.sender);\n const events = this.getEvents();\n\n if (events.length > 0) {\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: events.map((event) => this.addTransactionMetadata(event)),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`\n );\n\n const connection = this.getConnection(parsed.sender);\n connection.messagesSent = events.length;\n }\n\n this.log(`new connection added - ${parsed.context}:${parsed.sender}`);\n }\n\n private handleLostEventsRequest(parsed: Transaction<T>) {\n const connection = this.getConnection(parsed.sender);\n const events = this.getEvents();\n\n if (!connection || events.length === 0) {\n return;\n }\n\n const missingEvents = events.slice(connection.messagesSent, events.length);\n\n if (missingEvents.length === 0) {\n return;\n }\n\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: missingEvents.map((event) =>\n this.addTransactionMetadata(event)\n ),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n connection.messagesSent = events.length;\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`\n );\n }\n\n private handleDisconnectMessage(\n parsed: TransactionMetadata & MessengerEvent<T>\n ) {\n delete Messenger.connections[parsed.sender];\n\n this.log(`disconnected - ${parsed.context}:${parsed.sender}`);\n }\n\n public sendMessage(message: T | string) {\n const parsed: T =\n typeof message === \"string\" ? JSON.parse(message) : message;\n\n this.addEvent(parsed);\n\n const target = parsed.target || null;\n const msg = this.addTransactionMetadata(parsed);\n const connection = target ? this.getConnection(target) : null;\n\n if (connection) {\n connection.messagesSent += 1;\n }\n\n this.options.sendMessage(msg).catch(() => {\n this.options.handleFailedMessage?.(msg);\n\n this.log(\n `failed to send message: ${\n (parsed as BaseEvent<string, unknown>).type\n } from ${this.id} to ${target || \"all\"}`\n );\n });\n }\n\n public destroy() {\n if (this.beaconInterval) {\n clearInterval(this.beaconInterval);\n }\n\n this.options.removeListener(this.handleMessage);\n\n Object.keys(Messenger.connections).forEach((connection) => {\n const event: DisconnectEvent = {\n type: \"MESSENGER_DISCONNECT\",\n payload: null,\n target: connection,\n };\n const message = this.addTransactionMetadata(event);\n this.options.sendMessage(message);\n });\n\n Messenger.reset();\n this.log(\"destroyed\");\n }\n\n /** reset static records */\n static reset() {\n Messenger.events = {};\n Messenger.connections = {};\n }\n}\n"],"mappings":"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","names":["uid"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/messenger/src/index.ts"],"sourcesContent":["import uid from \"tiny-uid\";\nimport type {\n BaseEvent,\n Connection,\n DisconnectEvent,\n EventsBatchEvent,\n InternalEvent,\n MessengerEvent,\n MessengerOptions,\n RequestLostEventsEvent,\n Transaction,\n TransactionMetadata,\n} from \"@player-tools/devtools-types\";\n\nconst internalEvents: Array<InternalEvent<BaseEvent<string, unknown>>[\"type\"]> =\n [\n \"MESSENGER_BEACON\",\n \"MESSENGER_DISCONNECT\",\n \"MESSENGER_REQUEST_LOST_EVENTS\",\n \"MESSENGER_EVENT_BATCH\",\n ];\n\n/**\n * Messenger<EventsType>\n *\n * Self-sufficient, lossless communication between instances.\n *\n * @param options\n * @param options.context - context to use for this instance\n * @param options.id - unique id for this instance, will be generated if not provided\n * @param options.beaconIntervalMS - time to wait between beacons in milliseconds, defaults to 1000\n * @param options.debug - if true, will log debug messages to console, defaults to false\n * @param options.messageCallback - callback to handle messages\n * @param options.sendMessage - function to send messages\n * @param options.addListener - function to add a listener\n * @param options.removeListener - function to remove a listener\n * @param options.handleFailedMessage - function to handle failed messages\n * @param option.log - function to handle logging\n * @returns Messenger\n * @example\n * ```typescript\n * const messenger = new Messenger({{\n * context: \"devtools\",\n * target: \"player\",\n * messageCallback: (message) => dispatch(message),\n * sendMessage: (message) =>\n * browser.tabs\n * ? browser.tabs\n * .query({ active: true, currentWindow: true })\n * .then((tabs) => {\n * if (tabs[0].id) {\n * browser.tabs.sendMessage(tabs[0].id, message);\n * }\n * })\n * : browser.runtime.sendMessage(message),\n * addListener: (callback) => {\n * browser.runtime.onMessage.addListener(callback);\n * },\n * removeListener: (callback) => {\n * browser.runtime.onMessage.removeListener(callback);\n * },\n * });\n * ```\n */\nexport class Messenger<T extends BaseEvent<string, unknown>> {\n /** static record of events by isntance ID */\n private static events: Record<\n string,\n Array<MessageEvent<BaseEvent<string, unknown>>>\n > = {};\n\n /** static connections record by instance ID */\n private static connections: Record<string, Record<string, Connection>> = {};\n\n /** beacon interval */\n private beaconInterval: NodeJS.Timeout | null = null;\n\n /** time between beacons milliseconds */\n private beaconIntervalMS: number;\n\n /** callback to handle messages, here for instance binding */\n private handleMessage: (\n message: TransactionMetadata & MessengerEvent<T>,\n ) => void;\n\n /** unique id */\n private id: string;\n\n constructor(private options: MessengerOptions<T>) {\n // set defaults:\n this.id = options.id || uid();\n this.beaconIntervalMS = options.beaconIntervalMS || 1000;\n\n // start beacon interval:\n this.beaconInterval = setInterval(\n this.beacon.bind(this),\n this.beaconIntervalMS,\n );\n\n // bind message handler:\n this.handleMessage = this._handleMessage.bind(this);\n\n // add listener:\n this.options.addListener(this.handleMessage);\n }\n\n private log(message: string) {\n if (this.options.debug) {\n this.options.logger.log(\n `[MESSENGER-${this.id}](${this.options.context}): ${message}`,\n );\n }\n }\n\n private getConnection(id: string) {\n if (!Messenger.connections[this.id]) {\n Messenger.connections[this.id] = {};\n }\n\n return Messenger.connections[this.id][id];\n }\n\n private addConnection(id: string) {\n Messenger.connections[this.id][id] = {\n id,\n messagesReceived: 0,\n messagesSent: 0,\n desync: false,\n };\n }\n\n private getEvents() {\n if (!Messenger.events[this.id]) {\n Messenger.events[this.id] = [];\n }\n\n return Messenger.events[this.id] as unknown as MessengerEvent<T>[];\n }\n\n private addEvent(event: MessengerEvent<T>) {\n const events = this.getEvents();\n events.push(event);\n }\n\n /** generate a sequential id for each non-internal message */\n private getTransactionID(message: MessengerEvent<T>) {\n if (\n !message.target ||\n internalEvents.includes(message.type as InternalEvent<T>[\"type\"])\n ) {\n return -1;\n }\n\n if (!this.getConnection(message.target)) {\n this.addConnection(message.target);\n }\n\n const connection = this.getConnection(message.target);\n connection.messagesSent += 1;\n return connection.messagesSent;\n }\n\n private addTransactionMetadata(event: MessengerEvent<T>): Transaction<T> {\n const metadata = {\n _messenger_: true,\n id: this.getTransactionID(event),\n sender: this.id,\n timestamp: Date.now(),\n context: this.options.context,\n ...(event.target && { target: event.target }),\n };\n\n return {\n ...metadata,\n ...event,\n };\n }\n\n /** there is no persistent layer bookkeeping connections,\n * so beacon to inform others of its presence */\n private beacon() {\n this.options.sendMessage(\n this.addTransactionMetadata({\n type: \"MESSENGER_BEACON\",\n payload: null,\n }),\n );\n }\n\n private _handleMessage(transaction: Transaction<T>) {\n const parsed: Transaction<T> =\n typeof transaction === \"string\" ? JSON.parse(transaction) : transaction;\n\n const isFromMessenger = parsed._messenger_;\n const isFromSelf = parsed.sender === this.id;\n const isFromSameContext = parsed.context === this.options.context;\n const isTargetingOthers = parsed.target ? parsed.target !== this.id : false;\n const connection = this.getConnection(parsed.sender);\n const isKnownConnection = Boolean(connection);\n\n if (\n !isFromMessenger ||\n isFromSelf ||\n isFromSameContext ||\n isTargetingOthers ||\n (isKnownConnection && parsed.type === \"MESSENGER_BEACON\")\n ) {\n return;\n }\n\n const handlers: Record<string, (parsed: Transaction<T>) => void> = {\n MESSENGER_BEACON: this.handleBeaconMessage.bind(this),\n MESSENGER_DISCONNECT: this.handleDisconnectMessage.bind(this),\n MESSENGER_REQUEST_LOST_EVENTS: this.handleLostEventsRequest.bind(this),\n };\n\n const handler = handlers[(parsed as BaseEvent<string, unknown>).type];\n\n if (handler) {\n handler(parsed);\n return;\n }\n\n if (isKnownConnection) {\n const isBatch = parsed.type === \"MESSENGER_EVENT_BATCH\";\n\n const transactionID = isBatch\n ? (parsed.payload as EventsBatchEvent<T>[\"payload\"]).events[0].id\n : parsed.id;\n\n const { messagesReceived, desync } = connection;\n\n // if we already received this message, ignore:\n if (transactionID > -1 && transactionID <= messagesReceived) {\n return;\n }\n\n // if we missed messages, request them, unless we already did:\n if (\n !desync &&\n transactionID > -1 &&\n transactionID > messagesReceived + 1\n ) {\n const message: RequestLostEventsEvent = {\n type: \"MESSENGER_REQUEST_LOST_EVENTS\",\n payload: {\n messagesReceived,\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `requesting lost messages from ${parsed.context}:${parsed.sender}`,\n );\n\n // set desync, so we don't request again:\n connection.desync = true;\n\n // don't process this message, since we requested missing ones:\n return;\n }\n\n if (isBatch) {\n // clear desync flag on event batch:\n connection.desync = false;\n connection.messagesReceived += (\n parsed.payload as EventsBatchEvent<T>[\"payload\"]\n ).events.length;\n } else {\n connection.messagesReceived += 1;\n }\n }\n\n this.options.messageCallback(parsed);\n\n this.log(\n `message received: ${(parsed as BaseEvent<string, unknown>).type}`,\n );\n }\n\n private handleBeaconMessage(parsed: Transaction<T>) {\n if (this.getConnection(parsed.sender)) {\n return;\n }\n\n this.addConnection(parsed.sender);\n const events = this.getEvents();\n\n if (events.length > 0) {\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: events.map((event) => this.addTransactionMetadata(event)),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`,\n );\n\n const connection = this.getConnection(parsed.sender);\n connection.messagesSent = events.length;\n }\n\n this.log(`new connection added - ${parsed.context}:${parsed.sender}`);\n }\n\n private handleLostEventsRequest(parsed: Transaction<T>) {\n const connection = this.getConnection(parsed.sender);\n const events = this.getEvents();\n\n if (!connection || events.length === 0) {\n return;\n }\n\n const missingEvents = events.slice(connection.messagesSent, events.length);\n\n if (missingEvents.length === 0) {\n return;\n }\n\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: missingEvents.map((event) =>\n this.addTransactionMetadata(event),\n ),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n connection.messagesSent = events.length;\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`,\n );\n }\n\n private handleDisconnectMessage(\n parsed: TransactionMetadata & MessengerEvent<T>,\n ) {\n delete Messenger.connections[parsed.sender];\n\n this.log(`disconnected - ${parsed.context}:${parsed.sender}`);\n }\n\n public sendMessage(message: T | string) {\n const parsed: T =\n typeof message === \"string\" ? JSON.parse(message) : message;\n\n this.addEvent(parsed);\n\n const target = parsed.target || null;\n const msg = this.addTransactionMetadata(parsed);\n const connection = target ? this.getConnection(target) : null;\n\n if (connection) {\n connection.messagesSent += 1;\n }\n\n this.options.sendMessage(msg).catch(() => {\n this.options.handleFailedMessage?.(msg);\n\n this.log(\n `failed to send message: ${\n (parsed as BaseEvent<string, unknown>).type\n } from ${this.id} to ${target || \"all\"}`,\n );\n });\n }\n\n public destroy() {\n if (this.beaconInterval) {\n clearInterval(this.beaconInterval);\n }\n\n this.options.removeListener(this.handleMessage);\n\n Object.keys(Messenger.connections).forEach((connection) => {\n const event: DisconnectEvent = {\n type: \"MESSENGER_DISCONNECT\",\n payload: null,\n target: connection,\n };\n const message = this.addTransactionMetadata(event);\n this.options.sendMessage(message);\n });\n\n Messenger.reset();\n this.log(\"destroyed\");\n }\n\n /** reset static records */\n static reset() {\n Messenger.events = {};\n Messenger.connections = {};\n }\n}\n"],"mappings":"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","names":["uid"]}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/messenger/src/index.ts"],"sourcesContent":["import uid from \"tiny-uid\";\nimport type {\n BaseEvent,\n Connection,\n DisconnectEvent,\n EventsBatchEvent,\n InternalEvent,\n MessengerEvent,\n MessengerOptions,\n RequestLostEventsEvent,\n Transaction,\n TransactionMetadata,\n} from \"@player-tools/devtools-types\";\n\nconst internalEvents: Array<InternalEvent<BaseEvent<string, unknown>>[\"type\"]> =\n [\n \"MESSENGER_BEACON\",\n \"MESSENGER_DISCONNECT\",\n \"MESSENGER_REQUEST_LOST_EVENTS\",\n \"MESSENGER_EVENT_BATCH\",\n ];\n\n/**\n * Messenger<EventsType>\n *\n * Self-sufficient, lossless communication between instances.\n *\n * @param options\n * @param options.context - context to use for this instance\n * @param options.id - unique id for this instance, will be generated if not provided\n * @param options.beaconIntervalMS - time to wait between beacons in milliseconds, defaults to 1000\n * @param options.debug - if true, will log debug messages to console, defaults to false\n * @param options.messageCallback - callback to handle messages\n * @param options.sendMessage - function to send messages\n * @param options.addListener - function to add a listener\n * @param options.removeListener - function to remove a listener\n * @param options.handleFailedMessage - function to handle failed messages\n * @param option.log - function to handle logging\n * @returns Messenger\n * @example\n * ```typescript\n * const messenger = new Messenger({{\n * context: \"devtools\",\n * target: \"player\",\n * messageCallback: (message) => dispatch(message),\n * sendMessage: (message) =>\n * browser.tabs\n * ? browser.tabs\n * .query({ active: true, currentWindow: true })\n * .then((tabs) => {\n * if (tabs[0].id) {\n * browser.tabs.sendMessage(tabs[0].id, message);\n * }\n * })\n * : browser.runtime.sendMessage(message),\n * addListener: (callback) => {\n * browser.runtime.onMessage.addListener(callback);\n * },\n * removeListener: (callback) => {\n * browser.runtime.onMessage.removeListener(callback);\n * },\n * });\n * ```\n */\nexport class Messenger<T extends BaseEvent<string, unknown>> {\n /** static record of events by isntance ID */\n private static events: Record<\n string,\n Array<MessageEvent<BaseEvent<string, unknown>>>\n > = {};\n\n /** static connections record by instance ID */\n private static connections: Record<string, Record<string, Connection>> = {};\n\n /** beacon interval */\n private beaconInterval: NodeJS.Timeout | null = null;\n\n /** time between beacons milliseconds */\n private beaconIntervalMS: number;\n\n /** callback to handle messages, here for instance binding */\n private handleMessage: (\n message: TransactionMetadata & MessengerEvent<T>\n ) => void;\n\n /** unique id */\n private id: string;\n\n constructor(private options: MessengerOptions<T>) {\n // set defaults:\n this.id = options.id || uid();\n this.beaconIntervalMS = options.beaconIntervalMS || 1000;\n\n // start beacon interval:\n this.beaconInterval = setInterval(\n this.beacon.bind(this),\n this.beaconIntervalMS\n );\n\n // bind message handler:\n this.handleMessage = this._handleMessage.bind(this);\n\n // add listener:\n this.options.addListener(this.handleMessage);\n }\n\n private log(message: string) {\n if (this.options.debug) {\n this.options.logger.log(\n `[MESSENGER-${this.id}](${this.options.context}): ${message}`\n );\n }\n }\n\n private getConnection(id: string) {\n if (!Messenger.connections[this.id]) {\n Messenger.connections[this.id] = {};\n }\n\n return Messenger.connections[this.id][id];\n }\n\n private addConnection(id: string) {\n Messenger.connections[this.id][id] = {\n id,\n messagesReceived: 0,\n messagesSent: 0,\n desync: false,\n };\n }\n\n private getEvents() {\n if (!Messenger.events[this.id]) {\n Messenger.events[this.id] = [];\n }\n\n return Messenger.events[this.id] as unknown as MessengerEvent<T>[];\n }\n\n private addEvent(event: MessengerEvent<T>) {\n const events = this.getEvents();\n events.push(event);\n }\n\n /** generate a sequential id for each non-internal message */\n private getTransactionID(message: MessengerEvent<T>) {\n if (\n !message.target ||\n internalEvents.includes(message.type as InternalEvent<T>[\"type\"])\n ) {\n return -1;\n }\n\n if (!this.getConnection(message.target)) {\n this.addConnection(message.target);\n }\n\n const connection = this.getConnection(message.target);\n connection.messagesSent += 1;\n return connection.messagesSent;\n }\n\n private addTransactionMetadata(event: MessengerEvent<T>): Transaction<T> {\n const metadata = {\n _messenger_: true,\n id: this.getTransactionID(event),\n sender: this.id,\n timestamp: Date.now(),\n context: this.options.context,\n ...(event.target && { target: event.target }),\n };\n\n return {\n ...metadata,\n ...event,\n };\n }\n\n /** there is no persistent layer bookkeeping connections,\n * so beacon to inform others of its presence */\n private beacon() {\n this.options.sendMessage(\n this.addTransactionMetadata({\n type: \"MESSENGER_BEACON\",\n payload: null,\n })\n );\n }\n\n private _handleMessage(transaction: Transaction<T>) {\n const parsed: Transaction<T> =\n typeof transaction === \"string\" ? JSON.parse(transaction) : transaction;\n\n const isFromMessenger = parsed._messenger_;\n const isFromSelf = parsed.sender === this.id;\n const isFromSameContext = parsed.context === this.options.context;\n const isTargetingOthers = parsed.target ? parsed.target !== this.id : false;\n const connection = this.getConnection(parsed.sender);\n const isKnownConnection = Boolean(connection);\n\n if (\n !isFromMessenger ||\n isFromSelf ||\n isFromSameContext ||\n isTargetingOthers ||\n (isKnownConnection && parsed.type === \"MESSENGER_BEACON\")\n ) {\n return;\n }\n\n const handlers: Record<string, (parsed: Transaction<T>) => void> = {\n MESSENGER_BEACON: this.handleBeaconMessage.bind(this),\n MESSENGER_DISCONNECT: this.handleDisconnectMessage.bind(this),\n MESSENGER_REQUEST_LOST_EVENTS: this.handleLostEventsRequest.bind(this),\n };\n\n const handler = handlers[(parsed as BaseEvent<string, unknown>).type];\n\n if (handler) {\n handler(parsed);\n return;\n }\n\n if (isKnownConnection) {\n const isBatch = parsed.type === \"MESSENGER_EVENT_BATCH\";\n\n const transactionID = isBatch\n ? (parsed.payload as EventsBatchEvent<T>[\"payload\"]).events[0].id\n : parsed.id;\n\n const { messagesReceived, desync } = connection;\n\n // if we already received this message, ignore:\n if (transactionID > -1 && transactionID <= messagesReceived) {\n return;\n }\n\n // if we missed messages, request them, unless we already did:\n if (\n !desync &&\n transactionID > -1 &&\n transactionID > messagesReceived + 1\n ) {\n const message: RequestLostEventsEvent = {\n type: \"MESSENGER_REQUEST_LOST_EVENTS\",\n payload: {\n messagesReceived,\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `requesting lost messages from ${parsed.context}:${parsed.sender}`\n );\n\n // set desync, so we don't request again:\n connection.desync = true;\n\n // don't process this message, since we requested missing ones:\n return;\n }\n\n if (isBatch) {\n // clear desync flag on event batch:\n connection.desync = false;\n connection.messagesReceived += (\n parsed.payload as EventsBatchEvent<T>[\"payload\"]\n ).events.length;\n } else {\n connection.messagesReceived += 1;\n }\n }\n\n this.options.messageCallback(parsed);\n\n this.log(\n `message received: ${(parsed as BaseEvent<string, unknown>).type}`\n );\n }\n\n private handleBeaconMessage(parsed: Transaction<T>) {\n if (this.getConnection(parsed.sender)) {\n return;\n }\n\n this.addConnection(parsed.sender);\n const events = this.getEvents();\n\n if (events.length > 0) {\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: events.map((event) => this.addTransactionMetadata(event)),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`\n );\n\n const connection = this.getConnection(parsed.sender);\n connection.messagesSent = events.length;\n }\n\n this.log(`new connection added - ${parsed.context}:${parsed.sender}`);\n }\n\n private handleLostEventsRequest(parsed: Transaction<T>) {\n const connection = this.getConnection(parsed.sender);\n const events = this.getEvents();\n\n if (!connection || events.length === 0) {\n return;\n }\n\n const missingEvents = events.slice(connection.messagesSent, events.length);\n\n if (missingEvents.length === 0) {\n return;\n }\n\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: missingEvents.map((event) =>\n this.addTransactionMetadata(event)\n ),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n connection.messagesSent = events.length;\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`\n );\n }\n\n private handleDisconnectMessage(\n parsed: TransactionMetadata & MessengerEvent<T>\n ) {\n delete Messenger.connections[parsed.sender];\n\n this.log(`disconnected - ${parsed.context}:${parsed.sender}`);\n }\n\n public sendMessage(message: T | string) {\n const parsed: T =\n typeof message === \"string\" ? JSON.parse(message) : message;\n\n this.addEvent(parsed);\n\n const target = parsed.target || null;\n const msg = this.addTransactionMetadata(parsed);\n const connection = target ? this.getConnection(target) : null;\n\n if (connection) {\n connection.messagesSent += 1;\n }\n\n this.options.sendMessage(msg).catch(() => {\n this.options.handleFailedMessage?.(msg);\n\n this.log(\n `failed to send message: ${\n (parsed as BaseEvent<string, unknown>).type\n } from ${this.id} to ${target || \"all\"}`\n );\n });\n }\n\n public destroy() {\n if (this.beaconInterval) {\n clearInterval(this.beaconInterval);\n }\n\n this.options.removeListener(this.handleMessage);\n\n Object.keys(Messenger.connections).forEach((connection) => {\n const event: DisconnectEvent = {\n type: \"MESSENGER_DISCONNECT\",\n payload: null,\n target: connection,\n };\n const message = this.addTransactionMetadata(event);\n this.options.sendMessage(message);\n });\n\n Messenger.reset();\n this.log(\"destroyed\");\n }\n\n /** reset static records */\n static reset() {\n Messenger.events = {};\n Messenger.connections = {};\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/messenger/src/index.ts"],"sourcesContent":["import uid from \"tiny-uid\";\nimport type {\n BaseEvent,\n Connection,\n DisconnectEvent,\n EventsBatchEvent,\n InternalEvent,\n MessengerEvent,\n MessengerOptions,\n RequestLostEventsEvent,\n Transaction,\n TransactionMetadata,\n} from \"@player-tools/devtools-types\";\n\nconst internalEvents: Array<InternalEvent<BaseEvent<string, unknown>>[\"type\"]> =\n [\n \"MESSENGER_BEACON\",\n \"MESSENGER_DISCONNECT\",\n \"MESSENGER_REQUEST_LOST_EVENTS\",\n \"MESSENGER_EVENT_BATCH\",\n ];\n\n/**\n * Messenger<EventsType>\n *\n * Self-sufficient, lossless communication between instances.\n *\n * @param options\n * @param options.context - context to use for this instance\n * @param options.id - unique id for this instance, will be generated if not provided\n * @param options.beaconIntervalMS - time to wait between beacons in milliseconds, defaults to 1000\n * @param options.debug - if true, will log debug messages to console, defaults to false\n * @param options.messageCallback - callback to handle messages\n * @param options.sendMessage - function to send messages\n * @param options.addListener - function to add a listener\n * @param options.removeListener - function to remove a listener\n * @param options.handleFailedMessage - function to handle failed messages\n * @param option.log - function to handle logging\n * @returns Messenger\n * @example\n * ```typescript\n * const messenger = new Messenger({{\n * context: \"devtools\",\n * target: \"player\",\n * messageCallback: (message) => dispatch(message),\n * sendMessage: (message) =>\n * browser.tabs\n * ? browser.tabs\n * .query({ active: true, currentWindow: true })\n * .then((tabs) => {\n * if (tabs[0].id) {\n * browser.tabs.sendMessage(tabs[0].id, message);\n * }\n * })\n * : browser.runtime.sendMessage(message),\n * addListener: (callback) => {\n * browser.runtime.onMessage.addListener(callback);\n * },\n * removeListener: (callback) => {\n * browser.runtime.onMessage.removeListener(callback);\n * },\n * });\n * ```\n */\nexport class Messenger<T extends BaseEvent<string, unknown>> {\n /** static record of events by isntance ID */\n private static events: Record<\n string,\n Array<MessageEvent<BaseEvent<string, unknown>>>\n > = {};\n\n /** static connections record by instance ID */\n private static connections: Record<string, Record<string, Connection>> = {};\n\n /** beacon interval */\n private beaconInterval: NodeJS.Timeout | null = null;\n\n /** time between beacons milliseconds */\n private beaconIntervalMS: number;\n\n /** callback to handle messages, here for instance binding */\n private handleMessage: (\n message: TransactionMetadata & MessengerEvent<T>,\n ) => void;\n\n /** unique id */\n private id: string;\n\n constructor(private options: MessengerOptions<T>) {\n // set defaults:\n this.id = options.id || uid();\n this.beaconIntervalMS = options.beaconIntervalMS || 1000;\n\n // start beacon interval:\n this.beaconInterval = setInterval(\n this.beacon.bind(this),\n this.beaconIntervalMS,\n );\n\n // bind message handler:\n this.handleMessage = this._handleMessage.bind(this);\n\n // add listener:\n this.options.addListener(this.handleMessage);\n }\n\n private log(message: string) {\n if (this.options.debug) {\n this.options.logger.log(\n `[MESSENGER-${this.id}](${this.options.context}): ${message}`,\n );\n }\n }\n\n private getConnection(id: string) {\n if (!Messenger.connections[this.id]) {\n Messenger.connections[this.id] = {};\n }\n\n return Messenger.connections[this.id][id];\n }\n\n private addConnection(id: string) {\n Messenger.connections[this.id][id] = {\n id,\n messagesReceived: 0,\n messagesSent: 0,\n desync: false,\n };\n }\n\n private getEvents() {\n if (!Messenger.events[this.id]) {\n Messenger.events[this.id] = [];\n }\n\n return Messenger.events[this.id] as unknown as MessengerEvent<T>[];\n }\n\n private addEvent(event: MessengerEvent<T>) {\n const events = this.getEvents();\n events.push(event);\n }\n\n /** generate a sequential id for each non-internal message */\n private getTransactionID(message: MessengerEvent<T>) {\n if (\n !message.target ||\n internalEvents.includes(message.type as InternalEvent<T>[\"type\"])\n ) {\n return -1;\n }\n\n if (!this.getConnection(message.target)) {\n this.addConnection(message.target);\n }\n\n const connection = this.getConnection(message.target);\n connection.messagesSent += 1;\n return connection.messagesSent;\n }\n\n private addTransactionMetadata(event: MessengerEvent<T>): Transaction<T> {\n const metadata = {\n _messenger_: true,\n id: this.getTransactionID(event),\n sender: this.id,\n timestamp: Date.now(),\n context: this.options.context,\n ...(event.target && { target: event.target }),\n };\n\n return {\n ...metadata,\n ...event,\n };\n }\n\n /** there is no persistent layer bookkeeping connections,\n * so beacon to inform others of its presence */\n private beacon() {\n this.options.sendMessage(\n this.addTransactionMetadata({\n type: \"MESSENGER_BEACON\",\n payload: null,\n }),\n );\n }\n\n private _handleMessage(transaction: Transaction<T>) {\n const parsed: Transaction<T> =\n typeof transaction === \"string\" ? JSON.parse(transaction) : transaction;\n\n const isFromMessenger = parsed._messenger_;\n const isFromSelf = parsed.sender === this.id;\n const isFromSameContext = parsed.context === this.options.context;\n const isTargetingOthers = parsed.target ? parsed.target !== this.id : false;\n const connection = this.getConnection(parsed.sender);\n const isKnownConnection = Boolean(connection);\n\n if (\n !isFromMessenger ||\n isFromSelf ||\n isFromSameContext ||\n isTargetingOthers ||\n (isKnownConnection && parsed.type === \"MESSENGER_BEACON\")\n ) {\n return;\n }\n\n const handlers: Record<string, (parsed: Transaction<T>) => void> = {\n MESSENGER_BEACON: this.handleBeaconMessage.bind(this),\n MESSENGER_DISCONNECT: this.handleDisconnectMessage.bind(this),\n MESSENGER_REQUEST_LOST_EVENTS: this.handleLostEventsRequest.bind(this),\n };\n\n const handler = handlers[(parsed as BaseEvent<string, unknown>).type];\n\n if (handler) {\n handler(parsed);\n return;\n }\n\n if (isKnownConnection) {\n const isBatch = parsed.type === \"MESSENGER_EVENT_BATCH\";\n\n const transactionID = isBatch\n ? (parsed.payload as EventsBatchEvent<T>[\"payload\"]).events[0].id\n : parsed.id;\n\n const { messagesReceived, desync } = connection;\n\n // if we already received this message, ignore:\n if (transactionID > -1 && transactionID <= messagesReceived) {\n return;\n }\n\n // if we missed messages, request them, unless we already did:\n if (\n !desync &&\n transactionID > -1 &&\n transactionID > messagesReceived + 1\n ) {\n const message: RequestLostEventsEvent = {\n type: \"MESSENGER_REQUEST_LOST_EVENTS\",\n payload: {\n messagesReceived,\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `requesting lost messages from ${parsed.context}:${parsed.sender}`,\n );\n\n // set desync, so we don't request again:\n connection.desync = true;\n\n // don't process this message, since we requested missing ones:\n return;\n }\n\n if (isBatch) {\n // clear desync flag on event batch:\n connection.desync = false;\n connection.messagesReceived += (\n parsed.payload as EventsBatchEvent<T>[\"payload\"]\n ).events.length;\n } else {\n connection.messagesReceived += 1;\n }\n }\n\n this.options.messageCallback(parsed);\n\n this.log(\n `message received: ${(parsed as BaseEvent<string, unknown>).type}`,\n );\n }\n\n private handleBeaconMessage(parsed: Transaction<T>) {\n if (this.getConnection(parsed.sender)) {\n return;\n }\n\n this.addConnection(parsed.sender);\n const events = this.getEvents();\n\n if (events.length > 0) {\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: events.map((event) => this.addTransactionMetadata(event)),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`,\n );\n\n const connection = this.getConnection(parsed.sender);\n connection.messagesSent = events.length;\n }\n\n this.log(`new connection added - ${parsed.context}:${parsed.sender}`);\n }\n\n private handleLostEventsRequest(parsed: Transaction<T>) {\n const connection = this.getConnection(parsed.sender);\n const events = this.getEvents();\n\n if (!connection || events.length === 0) {\n return;\n }\n\n const missingEvents = events.slice(connection.messagesSent, events.length);\n\n if (missingEvents.length === 0) {\n return;\n }\n\n const message: EventsBatchEvent<T> = {\n type: \"MESSENGER_EVENT_BATCH\",\n payload: {\n events: missingEvents.map((event) =>\n this.addTransactionMetadata(event),\n ),\n },\n target: parsed.sender,\n };\n\n this.options.sendMessage(this.addTransactionMetadata(message));\n\n connection.messagesSent = events.length;\n\n this.log(\n `messages [0 - ${events.length - 1}] sent to ${parsed.context}:${\n parsed.sender\n }`,\n );\n }\n\n private handleDisconnectMessage(\n parsed: TransactionMetadata & MessengerEvent<T>,\n ) {\n delete Messenger.connections[parsed.sender];\n\n this.log(`disconnected - ${parsed.context}:${parsed.sender}`);\n }\n\n public sendMessage(message: T | string) {\n const parsed: T =\n typeof message === \"string\" ? JSON.parse(message) : message;\n\n this.addEvent(parsed);\n\n const target = parsed.target || null;\n const msg = this.addTransactionMetadata(parsed);\n const connection = target ? this.getConnection(target) : null;\n\n if (connection) {\n connection.messagesSent += 1;\n }\n\n this.options.sendMessage(msg).catch(() => {\n this.options.handleFailedMessage?.(msg);\n\n this.log(\n `failed to send message: ${\n (parsed as BaseEvent<string, unknown>).type\n } from ${this.id} to ${target || \"all\"}`,\n );\n });\n }\n\n public destroy() {\n if (this.beaconInterval) {\n clearInterval(this.beaconInterval);\n }\n\n this.options.removeListener(this.handleMessage);\n\n Object.keys(Messenger.connections).forEach((connection) => {\n const event: DisconnectEvent = {\n type: \"MESSENGER_DISCONNECT\",\n payload: null,\n target: connection,\n };\n const message = this.addTransactionMetadata(event);\n this.options.sendMessage(message);\n });\n\n Messenger.reset();\n this.log(\"destroyed\");\n }\n\n /** reset static records */\n static reset() {\n Messenger.events = {};\n Messenger.connections = {};\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
"types"
|
|
7
7
|
],
|
|
8
8
|
"name": "@player-tools/devtools-messenger",
|
|
9
|
-
"version": "0.10.
|
|
9
|
+
"version": "0.10.1",
|
|
10
10
|
"main": "dist/cjs/index.cjs",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@player-tools/devtools-types": "0.10.
|
|
12
|
+
"@player-tools/devtools-types": "0.10.1",
|
|
13
13
|
"@types/node": "^18.18.0",
|
|
14
14
|
"tiny-uid": "^1.1.2",
|
|
15
15
|
"tslib": "^2.6.2"
|
|
@@ -29,7 +29,7 @@ describe("Messenger", () => {
|
|
|
29
29
|
vi.advanceTimersByTime(1000);
|
|
30
30
|
|
|
31
31
|
expect(spies.web1.sendMessage).toHaveBeenCalledWith(
|
|
32
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
32
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
33
33
|
);
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -75,37 +75,37 @@ describe("Messenger", () => {
|
|
|
75
75
|
|
|
76
76
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
77
77
|
1,
|
|
78
|
-
expect.objectContaining({ ...events[0], sender: "test2" })
|
|
78
|
+
expect.objectContaining({ ...events[0], sender: "test2" }),
|
|
79
79
|
);
|
|
80
80
|
|
|
81
81
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
82
82
|
2,
|
|
83
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
83
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
84
84
|
);
|
|
85
85
|
|
|
86
86
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
87
87
|
3,
|
|
88
|
-
expect.objectContaining({ ...events[1], sender: "test2" })
|
|
88
|
+
expect.objectContaining({ ...events[1], sender: "test2" }),
|
|
89
89
|
);
|
|
90
90
|
|
|
91
91
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
92
92
|
4,
|
|
93
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
93
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
94
94
|
);
|
|
95
95
|
|
|
96
96
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
97
97
|
5,
|
|
98
|
-
expect.objectContaining({ ...events[2], sender: "test2" })
|
|
98
|
+
expect.objectContaining({ ...events[2], sender: "test2" }),
|
|
99
99
|
);
|
|
100
100
|
|
|
101
101
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
102
102
|
6,
|
|
103
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
103
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
104
104
|
);
|
|
105
105
|
|
|
106
106
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
107
107
|
7,
|
|
108
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
108
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
109
109
|
);
|
|
110
110
|
|
|
111
111
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
@@ -120,7 +120,7 @@ describe("Messenger", () => {
|
|
|
120
120
|
expect.objectContaining({ ...events[2] }),
|
|
121
121
|
],
|
|
122
122
|
},
|
|
123
|
-
})
|
|
123
|
+
}),
|
|
124
124
|
);
|
|
125
125
|
});
|
|
126
126
|
|
|
@@ -177,22 +177,22 @@ describe("Messenger", () => {
|
|
|
177
177
|
|
|
178
178
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
179
179
|
1,
|
|
180
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
180
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
181
181
|
);
|
|
182
182
|
|
|
183
183
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
184
184
|
2,
|
|
185
|
-
expect.objectContaining({ ...eventsweb1[0], sender: "web1" })
|
|
185
|
+
expect.objectContaining({ ...eventsweb1[0], sender: "web1" }),
|
|
186
186
|
);
|
|
187
187
|
|
|
188
188
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
189
189
|
3,
|
|
190
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
190
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
191
191
|
);
|
|
192
192
|
|
|
193
193
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
194
194
|
4,
|
|
195
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
195
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
196
196
|
);
|
|
197
197
|
|
|
198
198
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
@@ -203,42 +203,42 @@ describe("Messenger", () => {
|
|
|
203
203
|
payload: {
|
|
204
204
|
events: [expect.objectContaining({ ...eventsweb1[0] })],
|
|
205
205
|
},
|
|
206
|
-
})
|
|
206
|
+
}),
|
|
207
207
|
);
|
|
208
208
|
|
|
209
209
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
210
210
|
6,
|
|
211
|
-
expect.objectContaining({ ...eventsDevtools[0], sender: "devtools1" })
|
|
211
|
+
expect.objectContaining({ ...eventsDevtools[0], sender: "devtools1" }),
|
|
212
212
|
);
|
|
213
213
|
|
|
214
214
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
215
215
|
7,
|
|
216
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
216
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
217
217
|
);
|
|
218
218
|
|
|
219
219
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
220
220
|
8,
|
|
221
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
221
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
222
222
|
);
|
|
223
223
|
|
|
224
224
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
225
225
|
9,
|
|
226
|
-
expect.objectContaining({ ...eventsweb1[1], sender: "web1" })
|
|
226
|
+
expect.objectContaining({ ...eventsweb1[1], sender: "web1" }),
|
|
227
227
|
);
|
|
228
228
|
|
|
229
229
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
230
230
|
10,
|
|
231
|
-
expect.objectContaining({ ...eventsDevtools[1], sender: "devtools1" })
|
|
231
|
+
expect.objectContaining({ ...eventsDevtools[1], sender: "devtools1" }),
|
|
232
232
|
);
|
|
233
233
|
|
|
234
234
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
235
235
|
11,
|
|
236
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
236
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
237
237
|
);
|
|
238
238
|
|
|
239
239
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
240
240
|
12,
|
|
241
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
241
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
242
242
|
);
|
|
243
243
|
});
|
|
244
244
|
|
|
@@ -309,63 +309,63 @@ describe("Messenger", () => {
|
|
|
309
309
|
expect(spies.devtools.sendMessage).toHaveBeenCalledTimes(15);
|
|
310
310
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
311
311
|
1,
|
|
312
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
312
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
313
313
|
);
|
|
314
314
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
315
315
|
2,
|
|
316
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
316
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
317
317
|
);
|
|
318
318
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
319
319
|
3,
|
|
320
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
320
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
321
321
|
);
|
|
322
322
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
323
323
|
4,
|
|
324
|
-
expect.objectContaining({ ...eventsWeb1[0], target: "web2" })
|
|
324
|
+
expect.objectContaining({ ...eventsWeb1[0], target: "web2" }),
|
|
325
325
|
);
|
|
326
326
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
327
327
|
5,
|
|
328
|
-
expect.objectContaining({ ...eventsWeb2[0], target: "web1" })
|
|
328
|
+
expect.objectContaining({ ...eventsWeb2[0], target: "web1" }),
|
|
329
329
|
);
|
|
330
330
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
331
331
|
6,
|
|
332
|
-
expect.objectContaining({ ...eventsDevtools[0], target: "web1" })
|
|
332
|
+
expect.objectContaining({ ...eventsDevtools[0], target: "web1" }),
|
|
333
333
|
);
|
|
334
334
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
335
335
|
7,
|
|
336
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
336
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
337
337
|
);
|
|
338
338
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
339
339
|
8,
|
|
340
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
340
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
341
341
|
);
|
|
342
342
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
343
343
|
9,
|
|
344
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
344
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
345
345
|
);
|
|
346
346
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
347
347
|
10,
|
|
348
|
-
expect.objectContaining({ ...eventsWeb1[1], target: "devtools" })
|
|
348
|
+
expect.objectContaining({ ...eventsWeb1[1], target: "devtools" }),
|
|
349
349
|
);
|
|
350
350
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
351
351
|
11,
|
|
352
|
-
expect.objectContaining({ ...eventsWeb2[1], target: "devtools" })
|
|
352
|
+
expect.objectContaining({ ...eventsWeb2[1], target: "devtools" }),
|
|
353
353
|
);
|
|
354
354
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
355
355
|
12,
|
|
356
|
-
expect.objectContaining({ ...eventsDevtools[1], target: "web2" })
|
|
356
|
+
expect.objectContaining({ ...eventsDevtools[1], target: "web2" }),
|
|
357
357
|
);
|
|
358
358
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
359
359
|
13,
|
|
360
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
360
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
361
361
|
);
|
|
362
362
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
363
363
|
14,
|
|
364
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
364
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
365
365
|
);
|
|
366
366
|
expect(spies.web1.sendMessage).toHaveBeenNthCalledWith(
|
|
367
367
|
15,
|
|
368
|
-
expect.objectContaining({ type: "MESSENGER_BEACON" })
|
|
368
|
+
expect.objectContaining({ type: "MESSENGER_BEACON" }),
|
|
369
369
|
);
|
|
370
370
|
});
|
|
371
371
|
});
|
package/src/index.ts
CHANGED
|
@@ -80,7 +80,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
80
80
|
|
|
81
81
|
/** callback to handle messages, here for instance binding */
|
|
82
82
|
private handleMessage: (
|
|
83
|
-
message: TransactionMetadata & MessengerEvent<T
|
|
83
|
+
message: TransactionMetadata & MessengerEvent<T>,
|
|
84
84
|
) => void;
|
|
85
85
|
|
|
86
86
|
/** unique id */
|
|
@@ -94,7 +94,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
94
94
|
// start beacon interval:
|
|
95
95
|
this.beaconInterval = setInterval(
|
|
96
96
|
this.beacon.bind(this),
|
|
97
|
-
this.beaconIntervalMS
|
|
97
|
+
this.beaconIntervalMS,
|
|
98
98
|
);
|
|
99
99
|
|
|
100
100
|
// bind message handler:
|
|
@@ -107,7 +107,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
107
107
|
private log(message: string) {
|
|
108
108
|
if (this.options.debug) {
|
|
109
109
|
this.options.logger.log(
|
|
110
|
-
`[MESSENGER-${this.id}](${this.options.context}): ${message}
|
|
110
|
+
`[MESSENGER-${this.id}](${this.options.context}): ${message}`,
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -183,7 +183,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
183
183
|
this.addTransactionMetadata({
|
|
184
184
|
type: "MESSENGER_BEACON",
|
|
185
185
|
payload: null,
|
|
186
|
-
})
|
|
186
|
+
}),
|
|
187
187
|
);
|
|
188
188
|
}
|
|
189
189
|
|
|
@@ -252,7 +252,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
252
252
|
this.options.sendMessage(this.addTransactionMetadata(message));
|
|
253
253
|
|
|
254
254
|
this.log(
|
|
255
|
-
`requesting lost messages from ${parsed.context}:${parsed.sender}
|
|
255
|
+
`requesting lost messages from ${parsed.context}:${parsed.sender}`,
|
|
256
256
|
);
|
|
257
257
|
|
|
258
258
|
// set desync, so we don't request again:
|
|
@@ -276,7 +276,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
276
276
|
this.options.messageCallback(parsed);
|
|
277
277
|
|
|
278
278
|
this.log(
|
|
279
|
-
`message received: ${(parsed as BaseEvent<string, unknown>).type}
|
|
279
|
+
`message received: ${(parsed as BaseEvent<string, unknown>).type}`,
|
|
280
280
|
);
|
|
281
281
|
}
|
|
282
282
|
|
|
@@ -302,7 +302,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
302
302
|
this.log(
|
|
303
303
|
`messages [0 - ${events.length - 1}] sent to ${parsed.context}:${
|
|
304
304
|
parsed.sender
|
|
305
|
-
}
|
|
305
|
+
}`,
|
|
306
306
|
);
|
|
307
307
|
|
|
308
308
|
const connection = this.getConnection(parsed.sender);
|
|
@@ -330,7 +330,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
330
330
|
type: "MESSENGER_EVENT_BATCH",
|
|
331
331
|
payload: {
|
|
332
332
|
events: missingEvents.map((event) =>
|
|
333
|
-
this.addTransactionMetadata(event)
|
|
333
|
+
this.addTransactionMetadata(event),
|
|
334
334
|
),
|
|
335
335
|
},
|
|
336
336
|
target: parsed.sender,
|
|
@@ -343,12 +343,12 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
343
343
|
this.log(
|
|
344
344
|
`messages [0 - ${events.length - 1}] sent to ${parsed.context}:${
|
|
345
345
|
parsed.sender
|
|
346
|
-
}
|
|
346
|
+
}`,
|
|
347
347
|
);
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
private handleDisconnectMessage(
|
|
351
|
-
parsed: TransactionMetadata & MessengerEvent<T
|
|
351
|
+
parsed: TransactionMetadata & MessengerEvent<T>,
|
|
352
352
|
) {
|
|
353
353
|
delete Messenger.connections[parsed.sender];
|
|
354
354
|
|
|
@@ -375,7 +375,7 @@ export class Messenger<T extends BaseEvent<string, unknown>> {
|
|
|
375
375
|
this.log(
|
|
376
376
|
`failed to send message: ${
|
|
377
377
|
(parsed as BaseEvent<string, unknown>).type
|
|
378
|
-
} from ${this.id} to ${target || "all"}
|
|
378
|
+
} from ${this.id} to ${target || "all"}`,
|
|
379
379
|
);
|
|
380
380
|
});
|
|
381
381
|
}
|