Execution Contexts
Relevant source files
The following files were used as context for generating this wiki page:The Ghostbird add-on, like most Thunderbird WebExtensions, is structured around several distinct JavaScript execution contexts. Each context has a specific role, a defined lifecycle, and limited access to Thunderbird APIs and other contexts. This separation is a core aspect of the WebExtension security model and architecture. Understanding these contexts is crucial for comprehending the add-on's operation, from user interaction to communication with the external GhostText server.
The primary execution contexts in Ghostbird are the Background Script, the Compose Script, and the Options Script. Each is built from a specific TypeScript entry point and bundled into a JavaScript file that runs in its designated environment.
Sources: doc/design.md:78-89, tools/tsdown_config.ts:74-95
Architectural Overview
The diagram below illustrates the high-level architecture, showing the different execution contexts and their interactions with Thunderbird, the user, and the external GhostText server.
This diagram shows the main components within each execution context and how they communicate, either directly via APIs like runtime.Port or indirectly through mechanisms like browser.storage.
Sources: doc/design.md:6-48
Background Script (background.js)
The background script is the central nervous system of the add-on. It runs in a persistent (or semi-persistent, due to MV3) background context, managing the add-on's state and coordinating actions between other parts of the extension and the external GhostText server.
Sources: doc/design.md:79-80
Key Responsibilities
- Connection Management: It initiates and manages the WebSocket connection to the GhostText server.
- Event Handling: It listens for high-level browser events, such as the user clicking the Ghostbird toolbar button (
composeAction) or using a keyboard shortcut (commands). - Orchestration: It injects the compose script into the compose window and establishes a communication channel (
runtime.Port) to it. - Data Relay: It relays text data between the compose script and the GhostText server.
- Configuration Loading: It reads settings saved by the options page from
browser.storage.localto configure its behavior (e.g., server port).
Core Components
| Component | Description | Source File |
|---|---|---|
BackgroundEventRouter | The main entry point for the background script. It routes incoming events from Thunderbird APIs to the appropriate handlers. | src/app-background/background_event_router.ts |
GhostTextConnector | A component responsible for handling the lifecycle of the WebSocket connection to the GhostText server. | doc/design.md:15 |
EmailEditor | A class that orchestrates the entire editing session for a specific compose window, kicking off the process. | doc/design.md:16 |
OptionHolder | A component that holds the configuration loaded from storage, making it available to other components like the GhostTextClient. | doc/design.md:18 |
Lifecycle and Limitations
Under the Manifest V3 (MV3) event-driven model, the background script can be suspended by Thunderbird to conserve resources and will be woken up only when specific events occur. This means its in-memory state, including active WebSocket connections, can be lost. The add-on must be designed to be resilient to these suspensions.
Sources: doc/design.md:112-114
Compose Script (compose.js)
The compose script is a content script that is programmatically injected by the background script into the Thunderbird mail compose window. Its primary role is to interact directly with the content of the email being composed.
Sources: doc/design.md:81-82
Key Responsibilities
- DOM Interaction: It reads the initial text from the compose editor and sends it to the background script. It also updates the editor's content when it receives new text from the background script.
- Inter-Context Communication: It communicates with the background script via a
runtime.Portconnection. - Window-Specific Logic: Since a new instance of the script runs for each open compose window, all its logic is scoped to a single email draft.
Core Components
| Component | Description | Source File |
|---|---|---|
ComposeEventRouter | The entry point for the compose script, responsible for setting up the connection back to the background script. | src/app-compose/compose_event_router.ts |
PortHandler | Manages the runtime.Port connection, listening for messages from the background script and relaying local events back. | doc/design.md:20 |
ComposeEditor | A dedicated class for manipulating the DOM of the compose window's text area. | doc/design.md:19 |
The following diagram shows the flow when the compose script is activated.
Sources: doc/design.md:52-60
Options Script (options.js)
The options script runs in the context of the add-on's options page (ext/options.html). Its sole purpose is to provide a user interface for configuring the add-on.
Sources: doc/design.md:83-84
Key Responsibilities
- Load Settings: It loads the current settings from
browser.storage.localand populates the form fields on the page. - Save Settings: When the user saves changes, it writes the new configuration back to
browser.storage.local. - UI Event Handling: It handles DOM events like button clicks and form submissions on the options page.
Core Components
| Component | Description | Source File |
|---|---|---|
OptionsEventRouter | The entry point for the options script. It initializes the options form and sets up event listeners for saving. | src/app-options/options_event_router.ts |
Options | A class, likely using a library like webext-options-sync, that abstracts the reading and writing of settings to storage. | doc/design.md:21 |
Communication is indirect: the options script writes to storage, and the background script reads from it upon the next session initialization.
Sources: doc/design.md:104-108
Build and Bundling
The TypeScript source files for each context are compiled and bundled into JavaScript files by the tsdown build tool. The configuration specifies a unique entry point for each context.
Sources: doc/building.md:3-5
| Context | Entry Point | Output File | Format |
|---|---|---|---|
| Background | src/root/background.ts | dist/ext/js/background.js | ES Module (es) |
| Options | src/root/options.ts | dist/ext/js/options.js | ES Module (es) |
| Compose | src/root/compose.ts | dist/ext/js/compose.js | IIFE (iife) |
The compose.js script is bundled as an Immediately Invoked Function Expression (IIFE) because it's a content script injected into a webpage, whereas the background and options scripts run in environments that support ES modules.
Sources: tools/tsdown_config.ts:74-106
The build process is defined in tools/tsdown_config.ts and orchestrated via scripts in package.json.
This diagram shows the transformation of TypeScript entry points into the final JavaScript bundles for each execution context.
Sources: doc/building.md:8-23