Promise, ...) and what limitations your API will have to live with (i.e. potential complexity when passing functions or raw DOM elements).
registerListenerfunction might be a good idea in isolation, but it would be better to use events (that also simplifies the implementation!).
startupevent (which calls the
onStartup()method of that implementation's
ExtensionAPIobject once your add-on is loaded).
onShutdown()method of each loaded implementation's
ExtensionAPIobject. You should perform any cleanup tasks in that method, for example unloading loaded JSMs or native resources. You furthermore must invalidate Thunderbird's startup cache whenever your add-on is unloaded for a non-shutdown reason:
onShutdown()method of an Experiment that is always loaded.
getAPI(), and register context-specific unloading code through
asyncin the schema file.
Components.utils.cloneInto()or a related function with
context.cloneScopeas target scope. A notable exception is returning data from async API functions or wrapping Promises via
context.wrapPromise(), which causes automatic cloning of the result (unless the result is wrapped into a
context.cloneScopedirectly from the Experiment. Their results can be used from the WebExtension without further cloning.
moz-extension://*URLs obtained by
extension.getURL()in Experiments, but instead use
extension.rootURI.resolve()to get the raw
jar://*URL. Some calls may have issues with these raw URLs as well (e.g.
new ChromeWorker()). In that case you need to manually register a
chrome://*URL (see the enigmail add-on), and always use that URL when referring to the JSM.