diff --git a/docs/content/messaging/api.md b/docs/content/messaging/api.md index 19aa8a5..0bfba50 100644 --- a/docs/content/messaging/api.md +++ b/docs/content/messaging/api.md @@ -143,6 +143,40 @@ websiteMessenger.onMessage("initInjectedScript", (...) => { }) ``` +## `getIgnoreNamespaces` + +```ts +function getIgnoreNamespaces(): string[] +``` + +Get the current list of ignored namespace prefixes that apply globally to all messaging instances. + +**Returns:** Array of namespace prefixes currently being ignored. + +## `setIgnoreNamespaces` + +```ts +function setIgnoreNamespaces(namespaces: string[]): void +``` + +Set the global list of namespace prefixes to ignore across all messaging instances. Messages with namespaces starting with any of these prefixes will be filtered out and not processed. + +**Important:** This function should be called in both your background script and content scripts to ensure consistent filtering across all contexts. + +### Parameters + +- ***`namespaces: string[]`***
Array of namespace prefixes to ignore globally. + +### Example + +```ts +import { setIgnoreNamespaces } from '@webext-core/messaging'; + +// Call this in both background.js and content scripts +// Ignore messages from external SDKs +setIgnoreNamespaces(['external-sdk:', 'analytics:', 'tracking:']); +``` + ## `ExtensionMessage` ```ts @@ -278,6 +312,7 @@ interface Message< data: GetDataType; type: TType; timestamp: number; + namespace?: string; } ``` @@ -293,6 +328,8 @@ Contains information about the message received. - ***`timestamp: number`***
The timestamp the message was sent in MS since epoch. +- ***`namespace?: string`***
Optional namespace for the message. Used by external libraries to identify message sources. + ## `MessageSender` ```ts diff --git a/packages/messaging/src/extension.test.ts b/packages/messaging/src/extension.test.ts index 18985c5..1d16176 100644 --- a/packages/messaging/src/extension.test.ts +++ b/packages/messaging/src/extension.test.ts @@ -2,6 +2,7 @@ import { describe, it, vi, beforeEach, expect } from 'vitest'; import { fakeBrowser } from '@webext-core/fake-browser'; import { ProtocolWithReturn } from './index'; import { defineExtensionMessaging } from './extension'; +import { setIgnoreNamespaces, getIgnoreNamespaces } from './generic'; /** * This is defined in `@webext-core/fake-browser` when there are no `Browser.runtime.onMessage` @@ -21,6 +22,8 @@ describe('Messaging Wrapper', () => { fakeBrowser.reset(); vi.resetAllMocks(); vi.restoreAllMocks(); + // Clear ignore namespaces before each test + setIgnoreNamespaces([]); }); it('should send and receive messages', async () => { @@ -163,4 +166,68 @@ describe('Messaging Wrapper', () => { onMessage1.mock.invocationCallOrder[0], ); }); + + it('should ignore messages with namespaces matching global ignore list', async () => { + // Set up ignore list + setIgnoreNamespaces(['global-external:', 'sdk:']); + + const { onMessage } = defineExtensionMessaging(); + const messageHandler = vi.fn(); + + onMessage('getLength', messageHandler); + + // Send messages with globally ignored namespaces - these should be filtered out + fakeBrowser.runtime.sendMessage({ + id: 1, + timestamp: Date.now(), + type: 'getLength', + data: 'test', + namespace: 'global-external:action', + }); + + fakeBrowser.runtime.sendMessage({ + id: 2, + timestamp: Date.now(), + type: 'getLength', + data: 'test', + namespace: 'sdk:analytics', + }); + + // Send a message without globally ignored namespace - this should be processed + fakeBrowser.runtime.sendMessage({ + id: 3, + timestamp: Date.now(), + type: 'getLength', + data: 'test', + namespace: 'app:action', + }); + + // Send a message without any namespace - this should be processed + fakeBrowser.runtime.sendMessage({ + id: 4, + timestamp: Date.now(), + type: 'getLength', + data: 'test', + }); + + // Wait for async message processing + await new Promise(resolve => setTimeout(resolve, 0)); + + // Only the non-ignored messages should have triggered the handler + expect(messageHandler).toBeCalledTimes(2); + }); + + it('should manage ignore namespaces correctly', () => { + // Initially empty + expect(getIgnoreNamespaces()).toEqual([]); + + // Set namespaces + const namespaces = ['test:', 'example:']; + setIgnoreNamespaces(namespaces); + expect(getIgnoreNamespaces()).toEqual(namespaces); + + // Clear namespaces + setIgnoreNamespaces([]); + expect(getIgnoreNamespaces()).toEqual([]); + }); }); diff --git a/packages/messaging/src/generic.ts b/packages/messaging/src/generic.ts index 1c5b113..989d663 100644 --- a/packages/messaging/src/generic.ts +++ b/packages/messaging/src/generic.ts @@ -8,6 +8,26 @@ import { } from './types'; import { serializeError, deserializeError } from 'serialize-error'; +/** + * Global ignore list for message namespaces. Messages with namespaces starting with + * any of these prefixes will be filtered out and not processed by any messenger. + */ +let ignoreNamespaces: string[] = []; + +/** + * Set ignore namespaces that apply to all messaging instances. + */ +export function setIgnoreNamespaces(namespaces: string[]) { + ignoreNamespaces = namespaces; +} + +/** + * Get current ignore namespaces. + */ +export function getIgnoreNamespaces() { + return ignoreNamespaces; +} + /** * Config required to call `defineGenericMessenger`. */ @@ -140,6 +160,15 @@ export function defineGenericMessanging< `[messaging] "${type as string}" initialized the message listener for this context`, ); removeRootListener = config.addRootListener(message => { + // Check global ignore namespaces + if (ignoreNamespaces.length > 0 && message.namespace) { + for (const prefix of ignoreNamespaces) { + if (message.namespace.startsWith(prefix)) { + return; + } + } + } + // Validate the message object if (typeof message.type != 'string' || typeof message.timestamp !== 'number') { // #77 When the message is invalid, we stop processing the message using return or throw an error (default) diff --git a/packages/messaging/src/index.ts b/packages/messaging/src/index.ts index 1e6e7a4..40129e5 100644 --- a/packages/messaging/src/index.ts +++ b/packages/messaging/src/index.ts @@ -1,2 +1,3 @@ export * from './types'; export * from './extension'; +export { setIgnoreNamespaces, getIgnoreNamespaces } from './generic'; diff --git a/packages/messaging/src/types.ts b/packages/messaging/src/types.ts index ff3dc3a..11af6d6 100644 --- a/packages/messaging/src/types.ts +++ b/packages/messaging/src/types.ts @@ -114,4 +114,8 @@ export interface Message< * The timestamp the message was sent in MS since epoch. */ timestamp: number; + /** + * Optional namespace for the message. Used by external libraries to identify message sources. + */ + namespace?: string; }