Targeting Specific Endpoints
Relevant source files
The following files were used as context for generating this wiki page:In webext-bridge, communication occurs between different parts of a web extension, known as "endpoints". The library provides a robust mechanism for targeting specific endpoints, allowing for precise message delivery from one context to another, such as from a content script to a specific devtools panel, or from the background script to a content script in a particular tab. This system is fundamental to the library's ability to manage complex communication patterns within an extension.
Targeting is achieved through a standardized endpoint identification system. Each endpoint is uniquely identified by its context, and where applicable, its tab ID and frame ID. This allows the central routing logic, primarily managed by the background script, to accurately forward messages to their intended recipients. The sendMessage function accepts a Destination parameter, which can be a simple context name or a detailed endpoint string, providing developers with flexible control over message routing.
Endpoint Identification
An "Endpoint" is a specific location within the web extension that can send or receive messages. The webext-bridge library defines several distinct runtime contexts that can act as endpoints. The core data structure for identifying an endpoint is the Endpoint interface.
Sources: src/types.ts:10-14
The Endpoint Interface
The Endpoint interface defines the unique address of a communicable part of the extension.
| Field | Type | Description |
|---|---|---|
context | RuntimeContext | The type of the extension context (e.g., 'background', 'content-script'). |
tabId | number | The ID of the tab associated with the context. |
frameId | number | (Optional) The ID of the frame within the tab. |
Sources: src/types.ts:10-14
Runtime Contexts
The RuntimeContext type alias lists all possible contexts that can serve as endpoints.
| Context | Description |
|---|---|
background | The extension's background script (or service worker in MV3). |
content-script | A script injected into a web page. |
popup | The script running in the browser action's popup window. |
options | The script running in the extension's options page. |
devtools | A script running in a devtools panel. |
window | A script running in the context of a web page, communicating via postMessage through a content script. |
Sources: src/types.ts:3-9
This diagram illustrates the defined runtime contexts within the extension environment.
Sources: src/types.ts:3-9, src/content-script.ts:13-19
Endpoint String Format & Parsing
To simplify targeting, webext-bridge uses a string representation for endpoints. This string format is parsed to and from the Endpoint object structure.
Format Syntax
The endpoint string follows the pattern: context[@tabId[.frameId]].
- Contexts that are singletons like
background,popup, andoptionsare represented just by their name. - Contexts that can have multiple instances, like
content-scriptanddevtools, require atabIdand optionally aframeIdfor unique identification.
Sources: src/internal/endpoint.ts:13-16
Key Functions
The library provides two utility functions in src/internal/endpoint.ts for handling this string format.
parseEndpoint(endpoint: string): Endpoint: Takes an endpoint string and returns anEndpointobject. It uses a regular expression (ENDPOINT_RE) to extract the context, tab ID, and frame ID.formatEndpoint(endpoint: Endpoint): string: Takes anEndpointobject and returns its string representation.
The following flowchart shows the logic of the parseEndpoint function.
Message Routing Architecture
The background script serves as the central hub for all message routing. It maintains a map of all active connections and forwards messages to the correct destination based on their endpoint identifier.
Sources: src/background.ts
Connection Management
When a part of the extension (like a content script or popup) initializes the bridge, it establishes a persistent connection with the background script using browser.runtime.connect. The name of this connection port is encoded with the endpoint's name and a unique fingerprint for session management.
The background script listens for these connections via browser.runtime.onConnect and stores them in a connMap, which maps the formatted endpoint string to the PortConnection object containing the port and fingerprint.
// src/background.ts:20
const connMap = new Map<string, PortConnection>()
// src/background.ts:258
browser.runtime.onConnect.addListener((incomingPort) => {
// ...
connMap.set(connArgs.endpointName, {
fingerprint: connArgs.fingerprint,
port: incomingPort,
})
// ...
});
Sources: src/background.ts:20, src/background.ts:258-271
Routing Logic
When sendMessage is called from any context, an InternalMessage is created. This message contains origin and destination Endpoint objects. The message is routed to the background script, which then performs the following steps:
- Resolve Destination: The background script formats the destination
Endpointobject from the message into a string key. - Lookup Connection: It looks up the destination string in the
connMapto find the corresponding port. - Forward Message: If a connection is found, the message is posted to that destination's port.
- Handle Undeliverable Messages: If no connection is found, the background script can queue the message (for non-background senders) and notify the sender that the destination is currently unavailable, but that it will attempt delivery once the destination becomes available.
This sequence diagram shows a message being sent from a content script to a popup.
Special Targeting Rules
-
From Background: When sending a message from the background script to a context like
content-scriptordevtools, thetabIdmust be specified in the destination. This is a hard requirement to avoid ambiguity.// src/background.ts:149-155 if ( message.origin.context === 'background' && ['content-script', 'devtools '].includes(message.destination.context) && !message.destination.tabId ) { throw new TypeError( 'When sending messages from background page, use @tabId syntax to target specific tab', ) }Sources: src/background.ts:149-155
-
Window to Content Script: Messages originating from a regular
windowscript are first sent to the corresponding content script viapostMessage. The content script then forwards the message to the background script, ensuring theorigincontext is correctly set to'window'. This prevents scripts on a webpage from spoofing their identity.
Sources: src/content-script.ts:13-19, src/window.ts:8-10
Conclusion
The webext-bridge library implements a clear and effective system for targeting specific endpoints within a browser extension. By leveraging a standardized string format for endpoint identification (context@tabId.frameId), a central routing mechanism in the background script, and well-defined Endpoint and RuntimeContext types, it provides a reliable way to direct messages precisely where they need to go. This architecture simplifies the complex task of inter-context communication, making it a powerful tool for extension developers.
Sources: src/internal/endpoint.ts, src/background.ts, src/types.ts