# Utilities for implementing APIs

This page covers some utility classes that are useful for
implementing WebExtension APIs:

## WindowManager

This class manages the mapping between the opaque window identifiers used
in the [browser.windows](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/windows) API.
See the reference docs [here](reference.md#windowmanager-class).

## TabManager

This class manages the mapping between the opaque tab identifiers used
in the [browser.tabs](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs) API.
See the reference docs [here](reference.md#tabmanager-class).

## ExtensionSettingsStore

ExtensionSettingsStore (ESS) is used for storing changes to settings that are
requested by extensions, and for finding out what the current value
of a setting should be, based on the precedence chain or a specific selection
made (typically) by the user.

When multiple extensions request to make a change to a particular
setting, the most recently installed extension will be given
precedence.

It is also possible to select a specific extension (or no extension, which
infers user-set) to control a setting. This will typically only happen via
ExtensionPreferencesManager described below. When this happens, precedence
control is not used until either a new extension is installed, or the controlling
extension is disabled or uninstalled. If user-set is specifically chosen,
precedence order will only be returned to by installing a new extension that
takes control of the setting.

ESS will manage what has control over a setting through any
extension state changes (ie. install, uninstall, enable, disable).

### Notifications

#### "extension-setting-changed"

When a setting changes an event is emitted via the apiManager. It contains
the following:

- *action*: one of select, remove, enable, disable
- *id*: the id of the extension for which the setting has changed, may be null
  if the setting has returned to default or user set.
- *type*: The type of setting altered. This is defined by the module using ESS.
  If the setting is controlled through the ExtensionPreferencesManager below,
  the value will be "prefs".
- *key*: The name of the setting altered.
- *item*: The new value, if any that has taken control of the setting.

## ExtensionPreferencesManager

ExtensionPreferencesManager (EPM) is used to manage what extensions may control a
setting that results in changing a preference. EPM adds additional logic on top
of ESS to help manage the preference values based on what is in control of a
setting.

### Defining a setting in an API

A preference setting is defined in an API module by calling EPM.addSetting. addSetting
allows the API to use callbacks that can handle setting preferences as needed. Since
the setting is defined at runtime, the API module must be loaded as necessary by EPM
to properly manage settings.

In the api module definition (e.g. ext-toolkit.json), the api must use `"settings": true`
so the management code can discover which API modules to load in order to manage a
setting. See browserSettings[1] as an example.

Settings that are exposed to the user in <about:preferences> also require special handling.
We typically show that an extension is in control of the preference, and prevent changes
to the setting. Some settings may allow the user to choose which extension (or none) has
control of the setting.

### Preferences behavior

To actually set a setting, the module must call EPM.setSetting. This is typically done
via an extension API, such as browserSettings.settingName.set({ ...value data... }), though
it may be done at other times, such as during extension startup or install in a modules
onManifest handler.

Preferences are not always changed when an extension uses an API that results in a call
to EPM.setSetting. When setSetting is called, the values are stored by ESS (above), and if
the extension currently has control, or the setting is controllable by the extension, then
the preferences would be updated.

The preferences would also potentially be updated when installing, enabling, disabling or
uninstalling an extension, or by a user action in <about:preferences> (or other UI that
allows controlling the preferences). If all extensions that use a preference setting are
disabled or uninstalled, the prior user-set or default values would be returned to.

An extension may watch for changes using the onChange api (e.g. browserSettings.settingName.onChange).

[1] {searchfox}`mozilla-central/rev/04d8e7629354bab9e6a285183e763410860c5006:toolkit/components/extensions/ext-toolkit.json#19`

### Notifications

#### "extension-setting-changed:*name*"

When a setting controlled by EPM changes an event is emitted via the apiManager. It contains
no other data. This is used primarily to implement the onChange API.

## ESS vs. EPM

An API may use ESS when it needs to allow an extension to store a setting value that
affects how Firefox works, but does not result in setting a preference. An example
is allowing an extension to change the newTab value in the newTab service.

An API should use EPM when it needs to allow an extension to change a preference.

## Using ESS/EPM with experimental APIs

Properly managing settings values depends on the ability to load any modules that
define a setting. Since experimental APIs are defined inside the extension, there
are situations where settings defined in experimental APIs may not be correctly
managed. The could result in a preference remaining set by the extension after
the extension is disabled or installed, especially when that state is updated during
safe mode.

Extensions making use of settings in an experimental API should practice caution,
potentially unsetting the values when the extension is shutdown. Values used for
the setting could be stored in the extensions locale storage, and restored into
EPM when the extension is started again.
