Debugging
Relevant source files
The following files were used as context for generating this wiki page:
webext-bridge is designed with robust internal mechanisms to handle message delivery, state synchronization, and error conditions, which are crucial for debugging complex web extension communication. The library ensures that messages are not lost during transient states, such as a service worker terminating or a recipient tab not being immediately available. It provides clear feedback on message status, including delivery, undeliverability, and recipient termination.
The core of this system is the background script, which acts as a central message router and state manager. It tracks all active connections, queues messages for temporarily unavailable endpoints, and notifies senders about the status of their messages. This centralized architecture, combined with persistent connection logic in other contexts, provides a reliable foundation for identifying and resolving communication issues.
Core Debugging Components
The library's debugging capabilities are built upon several key components that work together to track message state and handle failures.
The Delivery Logger
The DeliveryLogger is a utility responsible for tracking pending responses for messages that expect a reply. It maintains a log of DeliveryReceipt objects.
A DeliveryReceipt is created when a message is successfully delivered to its destination, containing information about the message, the sender, and the recipient. This log is essential for state synchronization when a port reconnects.
Sources: src/internal/delivery-logger.ts:1-24
The structure of a DeliveryReceipt is as follows:
| Field | Type | Description |
|---|---|---|
message | InternalMessage | The original message that was delivered. |
to | EndpointFingerprint | A unique identifier for the recipient's session. |
from | object | An object containing the sender's endpointId and fingerprint. |
Sources: src/internal/delivery-logger.ts:4-11
Persistent Port State Management
In Manifest V3, service workers can be terminated at any time. To handle this, webext-bridge uses a PersistentPort wrapper that automatically re-establishes a connection to the background script upon disconnection. When a port reconnects, it sends a sync request to the background script, including its lists of pending responses and undelivered messages. This ensures that state is not lost across service worker terminations.
Sources: src/internal/persistent-port.ts:13-18, src/internal/persistent-port.ts:114-124
The diagram below illustrates the reconnection and state synchronization logic of a PersistentPort.
This diagram shows the lifecycle of a persistent port, which automatically reconnects and syncs its state with the background script upon disconnection.
Sources: src/internal/persistent-port.ts:109-124
If a message cannot be delivered immediately, it is added to an undeliveredQueue within the PersistentPort. The background script later sends a deliverable status message when the recipient becomes available, at which point the queued message is re-sent.
Sources: src/internal/persistent-port.ts:46-57, src/internal/persistent-port.ts:61-75
Background Script as Central Hub
The background.ts script is the central nervous system of the bridge. It maintains a map of all active connections (connMap) and orchestrates message routing between different extension contexts.
Key responsibilities relevant to debugging include:
- Connection Management: Tracks all connected ports and their unique fingerprints.
- Message Routing: Forwards messages to the correct recipient port.
- Queuing: If a destination is not connected, it holds the message (if the sender is the background script) or notifies the sender that the message is undeliverable and will be deliverable later.
- State Notification: Sends
StatusMessageupdates to clients about message delivery, session terminations, and endpoint availability.
Sources: src/background.ts:18-21, src/background.ts:173-201
Message Status and Error Handling
The bridge provides a rich set of status messages and error-handling mechanisms to give developers insight into the communication lifecycle.
Status Messages
Communication between the background script and other contexts is managed via StatusMessage objects. These messages provide real-time feedback on the state of a message transaction.
| Status | Description |
|---|---|
undeliverable | Sent to a sender when the recipient endpoint is not currently connected. The message is queued on the sender's side. |
deliverable | Sent to a sender to indicate that a previously undeliverable endpoint is now connected and ready to receive messages. |
delivered | Sent to a sender as a receipt upon successful delivery of a message to the recipient. |
incoming | Sent to a recipient to deliver a new message. |
terminated | Sent to a sender when the recipient's session has ended (e.g., tab closed) before a reply could be sent. |
Sources: src/internal/port-message.ts:5-24
Transaction and Session Termination
A significant debugging challenge is handling cases where a recipient terminates before responding. webext-bridge explicitly handles this scenario. When a port disconnects, the background script identifies any pending messages that were expecting a response from that port. It then notifies the original senders that the session has terminated.
Sources: src/background.ts:251-265, CHANGELOG.md:19-21
This notification allows the sendMessage promise on the sender's side to be rejected, preventing indefinite waiting. The endTransaction function in the endpoint runtime is called to reject the promise associated with the transaction.
Sources: src/internal/endpoint-runtime.ts:30-33, src/window.ts:12-13
The following diagram shows how a terminated session is handled.
This sequence shows the background script notifying a content script that the popup's session was terminated, allowing the content script to handle the failed transaction.
Sources: src/background.ts:251-265, src/internal/persistent-port.ts:91-98
Error Propagation
When a message handler throws an error, webext-bridge catches it, serializes it using serialize-error, and sends it back to the caller as part of the reply message. The endpoint-runtime on the caller's side then re-hydrates the error and rejects the sendMessage promise with it. This ensures that errors from a recipient are correctly propagated back to the sender, simplifying debugging across different contexts.
Sources: src/internal/endpoint-runtime.ts:74-99
Window to Content Script Communication Errors
For communication between the page (window) and a content script, which uses postMessage, a special error flow exists. If a message forwarded by the content script to the background script fails (e.g., the recipient terminates), the onFailure handler in the content script's persistent port is triggered. The content script then posts an error message back to the window, which calls endTransaction to reject the original promise.
Sources: src/content-script.ts:25-35, src/internal/post-message.ts:5-9