@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.
@@ -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"]}
@@ -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.0-next.0",
9
+ "version": "0.10.1",
10
10
  "main": "dist/cjs/index.cjs",
11
11
  "dependencies": {
12
- "@player-tools/devtools-types": "0.10.0-next.0",
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
  }