forked from mirrors/gecko-dev
Bug 1666534 - [devtools] Listen to extension storages via a server side watcher. r=devtools-reviewers,nchevobbe,jdescottes
This was the last resource type requiring to keep the old storage actor as-is. This will help drastically simplify it and move storage type code into each Resource Watcher class. Differential Revision: https://phabricator.services.mozilla.com/D166661
This commit is contained in:
parent
7539d4e3f4
commit
94e02496ef
14 changed files with 191 additions and 307 deletions
|
|
@ -315,17 +315,22 @@ class StorageUI {
|
||||||
this._onResourceListAvailable = this._onResourceListAvailable.bind(this);
|
this._onResourceListAvailable = this._onResourceListAvailable.bind(this);
|
||||||
|
|
||||||
const { resourceCommand } = this._toolbox;
|
const { resourceCommand } = this._toolbox;
|
||||||
await this._toolbox.resourceCommand.watchResources(
|
|
||||||
[
|
this._listenedResourceTypes = [
|
||||||
// The first item in this list will be the first selected storage item
|
// The first item in this list will be the first selected storage item
|
||||||
// Tests assume Cookie -- moving cookie will break tests
|
// Tests assume Cookie -- moving cookie will break tests
|
||||||
resourceCommand.TYPES.COOKIE,
|
resourceCommand.TYPES.COOKIE,
|
||||||
resourceCommand.TYPES.CACHE_STORAGE,
|
resourceCommand.TYPES.CACHE_STORAGE,
|
||||||
resourceCommand.TYPES.EXTENSION_STORAGE,
|
|
||||||
resourceCommand.TYPES.INDEXED_DB,
|
resourceCommand.TYPES.INDEXED_DB,
|
||||||
resourceCommand.TYPES.LOCAL_STORAGE,
|
resourceCommand.TYPES.LOCAL_STORAGE,
|
||||||
resourceCommand.TYPES.SESSION_STORAGE,
|
resourceCommand.TYPES.SESSION_STORAGE,
|
||||||
],
|
];
|
||||||
|
// EXTENSION_STORAGE is only relevant when debugging web extensions
|
||||||
|
if (this._commands.descriptorFront.isWebExtensionDescriptor) {
|
||||||
|
this._listenedResourceTypes.push(resourceCommand.TYPES.EXTENSION_STORAGE);
|
||||||
|
}
|
||||||
|
await this._toolbox.resourceCommand.watchResources(
|
||||||
|
this._listenedResourceTypes,
|
||||||
{
|
{
|
||||||
onAvailable: this._onResourceListAvailable,
|
onAvailable: this._onResourceListAvailable,
|
||||||
}
|
}
|
||||||
|
|
@ -443,19 +448,9 @@ class StorageUI {
|
||||||
this._destroyed = true;
|
this._destroyed = true;
|
||||||
|
|
||||||
const { resourceCommand } = this._toolbox;
|
const { resourceCommand } = this._toolbox;
|
||||||
resourceCommand.unwatchResources(
|
resourceCommand.unwatchResources(this._listenedResourceTypes, {
|
||||||
[
|
|
||||||
resourceCommand.TYPES.COOKIE,
|
|
||||||
resourceCommand.TYPES.CACHE_STORAGE,
|
|
||||||
resourceCommand.TYPES.EXTENSION_STORAGE,
|
|
||||||
resourceCommand.TYPES.INDEXED_DB,
|
|
||||||
resourceCommand.TYPES.LOCAL_STORAGE,
|
|
||||||
resourceCommand.TYPES.SESSION_STORAGE,
|
|
||||||
],
|
|
||||||
{
|
|
||||||
onAvailable: this._onResourceListAvailable,
|
onAvailable: this._onResourceListAvailable,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
this.table.off(TableWidget.EVENTS.ROW_SELECTED, this.updateObjectSidebar);
|
this.table.off(TableWidget.EVENTS.ROW_SELECTED, this.updateObjectSidebar);
|
||||||
this.table.off(TableWidget.EVENTS.SCROLL_END, this.loadMoreItems);
|
this.table.off(TableWidget.EVENTS.SCROLL_END, this.loadMoreItems);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ const TYPES = {
|
||||||
// storage types
|
// storage types
|
||||||
CACHE_STORAGE: "Cache",
|
CACHE_STORAGE: "Cache",
|
||||||
COOKIE: "cookies",
|
COOKIE: "cookies",
|
||||||
|
EXTENSION_STORAGE: "extension-storage",
|
||||||
INDEXED_DB: "indexed-db",
|
INDEXED_DB: "indexed-db",
|
||||||
LOCAL_STORAGE: "local-storage",
|
LOCAL_STORAGE: "local-storage",
|
||||||
SESSION_STORAGE: "session-storage",
|
SESSION_STORAGE: "session-storage",
|
||||||
|
|
@ -160,6 +161,9 @@ const ParentProcessResources = augmentResourceDictionary({
|
||||||
[TYPES.COOKIE]: {
|
[TYPES.COOKIE]: {
|
||||||
path: "devtools/server/actors/resources/storage-cookie",
|
path: "devtools/server/actors/resources/storage-cookie",
|
||||||
},
|
},
|
||||||
|
[TYPES.EXTENSION_STORAGE]: {
|
||||||
|
path: "devtools/server/actors/resources/storage-extension",
|
||||||
|
},
|
||||||
[TYPES.INDEXED_DB]: {
|
[TYPES.INDEXED_DB]: {
|
||||||
path: "devtools/server/actors/resources/storage-indexed-db",
|
path: "devtools/server/actors/resources/storage-indexed-db",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ DevToolsModules(
|
||||||
"sources.js",
|
"sources.js",
|
||||||
"storage-cache.js",
|
"storage-cache.js",
|
||||||
"storage-cookie.js",
|
"storage-cookie.js",
|
||||||
|
"storage-extension.js",
|
||||||
"storage-indexed-db.js",
|
"storage-indexed-db.js",
|
||||||
"storage-local-storage.js",
|
"storage-local-storage.js",
|
||||||
"storage-session-storage.js",
|
"storage-session-storage.js",
|
||||||
|
|
|
||||||
27
devtools/server/actors/resources/storage-extension.js
Normal file
27
devtools/server/actors/resources/storage-extension.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const {
|
||||||
|
TYPES: { EXTENSION_STORAGE },
|
||||||
|
} = require("resource://devtools/server/actors/resources/index.js");
|
||||||
|
|
||||||
|
const ParentProcessStorage = require("resource://devtools/server/actors/resources/utils/parent-process-storage.js");
|
||||||
|
|
||||||
|
class ExtensionStorageWatcher extends ParentProcessStorage {
|
||||||
|
constructor() {
|
||||||
|
super("extensionStorage", EXTENSION_STORAGE);
|
||||||
|
}
|
||||||
|
async watch(watcherActor, { onAvailable }) {
|
||||||
|
if (watcherActor.sessionContext.type != "webextension") {
|
||||||
|
throw new Error(
|
||||||
|
"EXTENSION_STORAGE should only be listened when debugging a webextension"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return super.watch(watcherActor, { onAvailable });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ExtensionStorageWatcher;
|
||||||
|
|
@ -407,7 +407,10 @@ class StorageActorMock extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
get parentActor() {
|
get parentActor() {
|
||||||
return { isRootActor: this.watcherActor.sessionContext.type == "all" };
|
return {
|
||||||
|
isRootActor: this.watcherActor.sessionContext.type == "all",
|
||||||
|
addonId: this.watcherActor.sessionContext.addonId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1488,14 +1488,6 @@ StorageActors.createActor(
|
||||||
);
|
);
|
||||||
|
|
||||||
const extensionStorageHelpers = {
|
const extensionStorageHelpers = {
|
||||||
unresolvedPromises: new Map(),
|
|
||||||
// Map of addonId => onStorageChange listeners in the parent process. Each addon toolbox targets
|
|
||||||
// a single addon, and multiple addon toolboxes could be open at the same time.
|
|
||||||
onChangedParentListeners: new Map(),
|
|
||||||
// Set of onStorageChange listeners in the extension child process. Each addon toolbox will create
|
|
||||||
// a separate extensionStorage actor targeting that addon. The addonId is passed into the listener,
|
|
||||||
// so that changes propagate only if the storage actor has a matching addonId.
|
|
||||||
onChangedChildListeners: new Set(),
|
|
||||||
/**
|
/**
|
||||||
* Editing is supported only for serializable types. Examples of unserializable
|
* Editing is supported only for serializable types. Examples of unserializable
|
||||||
* types include Map, Set and ArrayBuffer.
|
* types include Map, Set and ArrayBuffer.
|
||||||
|
|
@ -1610,172 +1602,6 @@ const extensionStorageHelpers = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sets the parent process message manager
|
|
||||||
setPpmm(ppmm) {
|
|
||||||
this.ppmm = ppmm;
|
|
||||||
},
|
|
||||||
|
|
||||||
// A promise in the main process has resolved, and we need to pass the return value(s)
|
|
||||||
// back to the child process
|
|
||||||
backToChild(...args) {
|
|
||||||
Services.mm.broadcastAsyncMessage(
|
|
||||||
"debug:storage-extensionStorage-request-child",
|
|
||||||
{
|
|
||||||
method: "backToChild",
|
|
||||||
args,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Send a message from the main process to a listener in the child process that the
|
|
||||||
// extension has modified storage local data
|
|
||||||
fireStorageOnChanged({ addonId, changes }) {
|
|
||||||
Services.mm.broadcastAsyncMessage(
|
|
||||||
"debug:storage-extensionStorage-request-child",
|
|
||||||
{
|
|
||||||
addonId,
|
|
||||||
changes,
|
|
||||||
method: "storageOnChanged",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Subscribe a listener for event notifications from the WE storage API when
|
|
||||||
// storage local data has been changed by the extension, and keep track of the
|
|
||||||
// listener to remove it when the debugger is being disconnected.
|
|
||||||
subscribeOnChangedListenerInParent(addonId) {
|
|
||||||
if (!this.onChangedParentListeners.has(addonId)) {
|
|
||||||
const onChangedListener = changes => {
|
|
||||||
this.fireStorageOnChanged({ addonId, changes });
|
|
||||||
};
|
|
||||||
ExtensionStorageIDB.addOnChangedListener(addonId, onChangedListener);
|
|
||||||
this.onChangedParentListeners.set(addonId, onChangedListener);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// The main process does not require an extension context to select the backend
|
|
||||||
// Bug 1542038, 1542039: Each storage area will need its own implementation, as
|
|
||||||
// they use different storage backends.
|
|
||||||
async setupStorageInParent(addonId) {
|
|
||||||
const { extension } = WebExtensionPolicy.getByID(addonId);
|
|
||||||
try {
|
|
||||||
// Make sure the extension storage APIs have been loaded,
|
|
||||||
// otherwise the DevTools storage panel would not be updated
|
|
||||||
// automatically when the extension storage data is being changed
|
|
||||||
// if the parent ext-storage.js module wasn't already loaded
|
|
||||||
// (See Bug 1802929).
|
|
||||||
await extension.apiManager.asyncGetAPI("storage", extension);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
const parentResult = await ExtensionStorageIDB.selectBackend({ extension });
|
|
||||||
const result = {
|
|
||||||
...parentResult,
|
|
||||||
// Received as a StructuredCloneHolder, so we need to deserialize
|
|
||||||
storagePrincipal: parentResult.storagePrincipal.deserialize(this, true),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.subscribeOnChangedListenerInParent(addonId);
|
|
||||||
return this.backToChild("setupStorageInParent", result);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDisconnected() {
|
|
||||||
for (const [addonId, listener] of this.onChangedParentListeners) {
|
|
||||||
ExtensionStorageIDB.removeOnChangedListener(addonId, listener);
|
|
||||||
}
|
|
||||||
this.onChangedParentListeners.clear();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Runs in the main process. This determines what code to execute based on the message
|
|
||||||
// received from the child process.
|
|
||||||
async handleChildRequest(msg) {
|
|
||||||
switch (msg.json.method) {
|
|
||||||
case "setupStorageInParent":
|
|
||||||
const addonId = msg.data.args[0];
|
|
||||||
const result = await extensionStorageHelpers.setupStorageInParent(
|
|
||||||
addonId
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
default:
|
|
||||||
console.error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD", msg.json.method);
|
|
||||||
throw new Error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Runs in the child process. This determines what code to execute based on the message
|
|
||||||
// received from the parent process.
|
|
||||||
handleParentRequest(msg) {
|
|
||||||
switch (msg.json.method) {
|
|
||||||
case "backToChild": {
|
|
||||||
const [func, rv] = msg.json.args;
|
|
||||||
const resolve = this.unresolvedPromises.get(func);
|
|
||||||
if (resolve) {
|
|
||||||
this.unresolvedPromises.delete(func);
|
|
||||||
resolve(rv);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "storageOnChanged": {
|
|
||||||
const { addonId, changes } = msg.data;
|
|
||||||
for (const listener of this.onChangedChildListeners) {
|
|
||||||
try {
|
|
||||||
listener({ addonId, changes });
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
// Ignore errors raised from listeners.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
console.error("ERR_DIRECTOR_CLIENT_UNKNOWN_METHOD", msg.json.method);
|
|
||||||
throw new Error("ERR_DIRECTOR_CLIENT_UNKNOWN_METHOD");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
callParentProcessAsync(methodName, ...args) {
|
|
||||||
const promise = new Promise(resolve => {
|
|
||||||
this.unresolvedPromises.set(methodName, resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ppmm.sendAsyncMessage(
|
|
||||||
"debug:storage-extensionStorage-request-parent",
|
|
||||||
{
|
|
||||||
method: methodName,
|
|
||||||
args,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* E10S parent/child setup helpers
|
|
||||||
* Add a message listener in the parent process to receive messages from the child
|
|
||||||
* process.
|
|
||||||
*/
|
|
||||||
exports.setupParentProcessForExtensionStorage = function({ mm, prefix }) {
|
|
||||||
// listen for director-script requests from the child process
|
|
||||||
mm.addMessageListener(
|
|
||||||
"debug:storage-extensionStorage-request-parent",
|
|
||||||
extensionStorageHelpers.handleChildRequest
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
onDisconnected: () => {
|
|
||||||
// Although "disconnected-from-child" implies that the child is already
|
|
||||||
// disconnected this is not the case. The disconnection takes place after
|
|
||||||
// this method has finished. This gives us chance to clean up items within
|
|
||||||
// the parent process e.g. observers.
|
|
||||||
mm.removeMessageListener(
|
|
||||||
"debug:storage-extensionStorage-request-parent",
|
|
||||||
extensionStorageHelpers.handleChildRequest
|
|
||||||
);
|
|
||||||
extensionStorageHelpers.onDisconnected();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1815,8 +1641,6 @@ StorageActors.createActor(
|
||||||
|
|
||||||
this.onStorageChange = this.onStorageChange.bind(this);
|
this.onStorageChange = this.onStorageChange.bind(this);
|
||||||
|
|
||||||
this.setupChildProcess();
|
|
||||||
|
|
||||||
this.onWindowReady = this.onWindowReady.bind(this);
|
this.onWindowReady = this.onWindowReady.bind(this);
|
||||||
this.onWindowDestroyed = this.onWindowDestroyed.bind(this);
|
this.onWindowDestroyed = this.onWindowDestroyed.bind(this);
|
||||||
this.storageActor.on("window-ready", this.onWindowReady);
|
this.storageActor.on("window-ready", this.onWindowReady);
|
||||||
|
|
@ -1828,7 +1652,8 @@ StorageActors.createActor(
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
extensionStorageHelpers.onChangedChildListeners.delete(
|
ExtensionStorageIDB.removeOnChangedListener(
|
||||||
|
this.addonId,
|
||||||
this.onStorageChange
|
this.onStorageChange
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1841,42 +1666,12 @@ StorageActors.createActor(
|
||||||
this.storageActor = null;
|
this.storageActor = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
setupChildProcess() {
|
|
||||||
const ppmm = this.conn.parentMessageManager;
|
|
||||||
extensionStorageHelpers.setPpmm(ppmm);
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-properties
|
|
||||||
this.conn.setupInParent({
|
|
||||||
module: "devtools/server/actors/storage",
|
|
||||||
setupParent: "setupParentProcessForExtensionStorage",
|
|
||||||
});
|
|
||||||
|
|
||||||
extensionStorageHelpers.onChangedChildListeners.add(this.onStorageChange);
|
|
||||||
this.setupStorageInParent = extensionStorageHelpers.callParentProcessAsync.bind(
|
|
||||||
extensionStorageHelpers,
|
|
||||||
"setupStorageInParent"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add a message listener in the child process to receive messages from the parent
|
|
||||||
// process
|
|
||||||
ppmm.addMessageListener(
|
|
||||||
"debug:storage-extensionStorage-request-child",
|
|
||||||
extensionStorageHelpers.handleParentRequest.bind(
|
|
||||||
extensionStorageHelpers
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This fires when the extension changes storage data while the storage
|
* This fires when the extension changes storage data while the storage
|
||||||
* inspector is open. Ensures this.hostVsStores stays up-to-date and
|
* inspector is open. Ensures this.hostVsStores stays up-to-date and
|
||||||
* passes the changes on to update the client.
|
* passes the changes on to update the client.
|
||||||
*/
|
*/
|
||||||
onStorageChange({ addonId, changes }) {
|
onStorageChange(changes) {
|
||||||
if (addonId !== this.addonId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const host = this.extensionHostURL;
|
const host = this.extensionHostURL;
|
||||||
const storeMap = this.hostVsStores.get(host);
|
const storeMap = this.hostVsStores.get(host);
|
||||||
|
|
||||||
|
|
@ -1922,10 +1717,32 @@ StorageActors.createActor(
|
||||||
*/
|
*/
|
||||||
async preListStores() {
|
async preListStores() {
|
||||||
// Ensure the actor's target is an extension and it is enabled
|
// Ensure the actor's target is an extension and it is enabled
|
||||||
if (!this.addonId || !WebExtensionPolicy.getByID(this.addonId)) {
|
if (!this.addonId || !this.getExtensionPolicy()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subscribe a listener for event notifications from the WE storage API when
|
||||||
|
// storage local data has been changed by the extension, and keep track of the
|
||||||
|
// listener to remove it when the debugger is being disconnected.
|
||||||
|
ExtensionStorageIDB.addOnChangedListener(
|
||||||
|
this.addonId,
|
||||||
|
this.onStorageChange
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
// Make sure the extension storage APIs have been loaded,
|
||||||
|
// otherwise the DevTools storage panel would not be updated
|
||||||
|
// automatically when the extension storage data is being changed
|
||||||
|
// if the parent ext-storage.js module wasn't already loaded
|
||||||
|
// (See Bug 1802929).
|
||||||
|
const { extension } = WebExtensionPolicy.getByID(this.addonId);
|
||||||
|
await extension.apiManager.asyncGetAPI("storage", extension);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
"Exception while trying to initialize webext storage API",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await this.populateStoresForHost(this.extensionHostURL);
|
await this.populateStoresForHost(this.extensionHostURL);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1956,7 +1773,7 @@ StorageActors.createActor(
|
||||||
const storeMap = new Map();
|
const storeMap = new Map();
|
||||||
this.hostVsStores.set(host, storeMap);
|
this.hostVsStores.set(host, storeMap);
|
||||||
|
|
||||||
const storagePrincipal = await this.getStoragePrincipal(extension.id);
|
const storagePrincipal = await this.getStoragePrincipal();
|
||||||
|
|
||||||
if (!storagePrincipal) {
|
if (!storagePrincipal) {
|
||||||
// This could happen if the extension fails to be migrated to the
|
// This could happen if the extension fails to be migrated to the
|
||||||
|
|
@ -1982,17 +1799,20 @@ StorageActors.createActor(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async getStoragePrincipal(addonId) {
|
async getStoragePrincipal() {
|
||||||
|
const { extension } = this.getExtensionPolicy();
|
||||||
const {
|
const {
|
||||||
backendEnabled,
|
backendEnabled,
|
||||||
storagePrincipal,
|
storagePrincipal,
|
||||||
} = await this.setupStorageInParent(addonId);
|
} = await ExtensionStorageIDB.selectBackend({ extension });
|
||||||
|
|
||||||
if (!backendEnabled) {
|
if (!backendEnabled) {
|
||||||
// IDB backend disabled; give up.
|
// IDB backend disabled; give up.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return storagePrincipal;
|
|
||||||
|
// Received as a StructuredCloneHolder, so we need to deserialize
|
||||||
|
return storagePrincipal.deserialize(this, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
getValuesForHost(host, name) {
|
getValuesForHost(host, name) {
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ function getWatcherSupportedResources(type) {
|
||||||
[Resources.TYPES.CACHE_STORAGE]: true,
|
[Resources.TYPES.CACHE_STORAGE]: true,
|
||||||
[Resources.TYPES.COOKIE]: true,
|
[Resources.TYPES.COOKIE]: true,
|
||||||
[Resources.TYPES.ERROR_MESSAGE]: true,
|
[Resources.TYPES.ERROR_MESSAGE]: true,
|
||||||
|
[Resources.TYPES.EXTENSION_STORAGE]: true,
|
||||||
[Resources.TYPES.INDEXED_DB]: true,
|
[Resources.TYPES.INDEXED_DB]: true,
|
||||||
[Resources.TYPES.LOCAL_STORAGE]: true,
|
[Resources.TYPES.LOCAL_STORAGE]: true,
|
||||||
[Resources.TYPES.SESSION_STORAGE]: true,
|
[Resources.TYPES.SESSION_STORAGE]: true,
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,13 @@ add_setup(async function setup() {
|
||||||
add_task(async function test_extension_store_exists() {
|
add_task(async function test_extension_store_exists() {
|
||||||
const extension = await startupExtension(getExtensionConfig());
|
const extension = await startupExtension(getExtensionConfig());
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(extensionStorage, "Should have an extensionStorage store");
|
ok(extensionStorage, "Should have an extensionStorage store");
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(
|
add_task(
|
||||||
|
|
@ -86,7 +86,7 @@ add_task(
|
||||||
getExtensionConfig({ background })
|
getExtensionConfig({ background })
|
||||||
);
|
);
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ add_task(
|
||||||
"Should have the expected extension host in the extensionStorage store"
|
"Should have the expected extension host in the extensionStorage store"
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ add_task(async function test_panel_live_updates() {
|
||||||
getExtensionConfig({ background: extensionScriptWithMessageListener })
|
getExtensionConfig({ background: extensionScriptWithMessageListener })
|
||||||
);
|
);
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -319,7 +319,7 @@ add_task(async function test_panel_live_updates() {
|
||||||
"Got the expected results on populated storage.local"
|
"Got the expected results on populated storage.local"
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -347,7 +347,7 @@ add_task(
|
||||||
extension.sendMessage("storage-local-set", { a: 123 });
|
extension.sendMessage("storage-local-set", { a: 123 });
|
||||||
await extension.awaitMessage("storage-local-set:done");
|
await extension.awaitMessage("storage-local-set:done");
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -366,7 +366,7 @@ add_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
await contentPage.close();
|
await contentPage.close();
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -396,7 +396,7 @@ add_task(async function test_panel_data_matches_extension_with_no_pages_open() {
|
||||||
await extension.awaitMessage("storage-local-onChanged");
|
await extension.awaitMessage("storage-local-onChanged");
|
||||||
await contentPage.close();
|
await contentPage.close();
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -414,7 +414,7 @@ add_task(async function test_panel_data_matches_extension_with_no_pages_open() {
|
||||||
"Got the expected results on populated storage.local"
|
"Got the expected results on populated storage.local"
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -434,7 +434,7 @@ add_task(
|
||||||
getExtensionConfig({ files: ext_no_bg.files })
|
getExtensionConfig({ files: ext_no_bg.files })
|
||||||
);
|
);
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -493,7 +493,7 @@ add_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
await contentPage.close();
|
await contentPage.close();
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -516,7 +516,7 @@ add_task(
|
||||||
|
|
||||||
const host = await extension.awaitMessage("extension-origin");
|
const host = await extension.awaitMessage("extension-origin");
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -588,7 +588,7 @@ add_task(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -610,11 +610,9 @@ add_task(
|
||||||
|
|
||||||
const host = await extension.awaitMessage("extension-origin");
|
const host = await extension.awaitMessage("extension-origin");
|
||||||
|
|
||||||
const {
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
target,
|
extension.id
|
||||||
extensionStorage,
|
);
|
||||||
storageFront,
|
|
||||||
} = await openAddonStoragePanel(extension.id);
|
|
||||||
|
|
||||||
const DEFAULT_VALUE = "value"; // global in devtools/server/actors/storage.js
|
const DEFAULT_VALUE = "value"; // global in devtools/server/actors/storage.js
|
||||||
let items = {
|
let items = {
|
||||||
|
|
@ -624,7 +622,7 @@ add_task(
|
||||||
};
|
};
|
||||||
|
|
||||||
info("Adding storage items from the extension");
|
info("Adding storage items from the extension");
|
||||||
let storesUpdate = storageFront.once("stores-update");
|
let storesUpdate = extensionStorage.once("single-store-update");
|
||||||
extension.sendMessage("storage-local-set", items);
|
extension.sendMessage("storage-local-set", items);
|
||||||
await extension.awaitMessage("storage-local-set:done");
|
await extension.awaitMessage("storage-local-set:done");
|
||||||
|
|
||||||
|
|
@ -637,13 +635,15 @@ add_task(
|
||||||
[host]: ["guid_1", "guid_2", "guid_3"],
|
[host]: ["guid_1", "guid_2", "guid_3"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
changed: undefined,
|
||||||
|
deleted: undefined,
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
"The change data from the storage actor's 'stores-update' event matches the changes made in the client."
|
"The change data from the storage actor's 'stores-update' event matches the changes made in the client."
|
||||||
);
|
);
|
||||||
|
|
||||||
info("Waiting for panel to edit some items");
|
info("Waiting for panel to edit some items");
|
||||||
storesUpdate = storageFront.once("stores-update");
|
storesUpdate = extensionStorage.once("single-store-update");
|
||||||
await extensionStorage.editItem({
|
await extensionStorage.editItem({
|
||||||
host,
|
host,
|
||||||
field: "value",
|
field: "value",
|
||||||
|
|
@ -655,11 +655,13 @@ add_task(
|
||||||
data = await storesUpdate;
|
data = await storesUpdate;
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
{
|
{
|
||||||
|
added: undefined,
|
||||||
changed: {
|
changed: {
|
||||||
extensionStorage: {
|
extensionStorage: {
|
||||||
[host]: ["guid_1"],
|
[host]: ["guid_1"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
deleted: undefined,
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
"The change data from the storage actor's 'stores-update' event matches the changes made in the client."
|
"The change data from the storage actor's 'stores-update' event matches the changes made in the client."
|
||||||
|
|
@ -679,13 +681,15 @@ add_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
info("Waiting for panel to remove an item");
|
info("Waiting for panel to remove an item");
|
||||||
storesUpdate = storageFront.once("stores-update");
|
storesUpdate = extensionStorage.once("single-store-update");
|
||||||
await extensionStorage.removeItem(host, "guid_3");
|
await extensionStorage.removeItem(host, "guid_3");
|
||||||
|
|
||||||
info("Waiting for the storage actor to emit a 'stores-update' event");
|
info("Waiting for the storage actor to emit a 'stores-update' event");
|
||||||
data = await storesUpdate;
|
data = await storesUpdate;
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
{
|
{
|
||||||
|
added: undefined,
|
||||||
|
changed: undefined,
|
||||||
deleted: {
|
deleted: {
|
||||||
extensionStorage: {
|
extensionStorage: {
|
||||||
[host]: ["guid_3"],
|
[host]: ["guid_3"],
|
||||||
|
|
@ -709,14 +713,14 @@ add_task(
|
||||||
);
|
);
|
||||||
|
|
||||||
info("Waiting for panel to remove all items");
|
info("Waiting for panel to remove all items");
|
||||||
const storesCleared = storageFront.once("stores-cleared");
|
const storesCleared = extensionStorage.once("single-store-cleared");
|
||||||
await extensionStorage.removeAll(host);
|
await extensionStorage.removeAll(host);
|
||||||
|
|
||||||
info("Waiting for the storage actor to emit a 'stores-cleared' event");
|
info("Waiting for the storage actor to emit a 'stores-cleared' event");
|
||||||
data = await storesCleared;
|
data = await storesCleared;
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
{
|
{
|
||||||
extensionStorage: {
|
clearedHostsOrPaths: {
|
||||||
[host]: [],
|
[host]: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -733,7 +737,7 @@ add_task(
|
||||||
`The storage items in the extension match the items in the panel`
|
`The storage items in the extension match the items in the panel`
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -780,7 +784,7 @@ add_task(
|
||||||
|
|
||||||
await extension.awaitMessage("extension-origin");
|
await extension.awaitMessage("extension-origin");
|
||||||
|
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -829,7 +833,7 @@ add_task(
|
||||||
Services.prefs.setBoolPref(LEAVE_STORAGE_PREF, false);
|
Services.prefs.setBoolPref(LEAVE_STORAGE_PREF, false);
|
||||||
Services.prefs.setBoolPref(LEAVE_UUID_PREF, false);
|
Services.prefs.setBoolPref(LEAVE_UUID_PREF, false);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -884,7 +888,7 @@ add_task(async function test_panel_live_reload_for_extension_without_bg_page() {
|
||||||
await contentPage.close();
|
await contentPage.close();
|
||||||
|
|
||||||
info("Opening storage panel");
|
info("Opening storage panel");
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -915,7 +919,7 @@ add_task(async function test_panel_live_reload_for_extension_without_bg_page() {
|
||||||
"Got the expected results on populated storage.local"
|
"Got the expected results on populated storage.local"
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -953,7 +957,7 @@ add_task(
|
||||||
const host = await extension.awaitMessage("extension-origin");
|
const host = await extension.awaitMessage("extension-origin");
|
||||||
|
|
||||||
info("Opening storage panel");
|
info("Opening storage panel");
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -994,7 +998,7 @@ add_task(
|
||||||
"Got the expected results on populated storage.local"
|
"Got the expected results on populated storage.local"
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1034,7 +1038,7 @@ add_task(
|
||||||
const host = await extension.awaitMessage("extension-origin");
|
const host = await extension.awaitMessage("extension-origin");
|
||||||
|
|
||||||
info("Opening storage panel");
|
info("Opening storage panel");
|
||||||
const { target, extensionStorage } = await openAddonStoragePanel(
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
extension.id
|
extension.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1052,7 +1056,7 @@ add_task(
|
||||||
"Got the expected results on populated storage.local"
|
"Got the expected results on populated storage.local"
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,9 @@ add_task(async function test_panel_live_reload() {
|
||||||
extension.sendMessage("storage-local-set", { a: 123 });
|
extension.sendMessage("storage-local-set", { a: 123 });
|
||||||
await extension.awaitMessage("storage-local-set:done");
|
await extension.awaitMessage("storage-local-set:done");
|
||||||
|
|
||||||
const {
|
const { commands, extensionStorage } = await openAddonStoragePanel(
|
||||||
target,
|
extension.id
|
||||||
extensionStorage,
|
);
|
||||||
storageFront,
|
|
||||||
} = await openAddonStoragePanel(extension.id);
|
|
||||||
|
|
||||||
manifest = {
|
manifest = {
|
||||||
...manifest,
|
...manifest,
|
||||||
|
|
@ -99,11 +97,13 @@ add_task(async function test_panel_live_reload() {
|
||||||
// Wait for the storage front to receive an event for the storage panel refresh
|
// Wait for the storage front to receive an event for the storage panel refresh
|
||||||
// when the extension has been reloaded.
|
// when the extension has been reloaded.
|
||||||
const promiseStoragePanelUpdated = new Promise(resolve => {
|
const promiseStoragePanelUpdated = new Promise(resolve => {
|
||||||
storageFront.on("stores-update", function updateListener(updates) {
|
extensionStorage.on("single-store-update", function updateListener(
|
||||||
|
updates
|
||||||
|
) {
|
||||||
info(`Got stores-update event: ${JSON.stringify(updates)}`);
|
info(`Got stores-update event: ${JSON.stringify(updates)}`);
|
||||||
const extStorageAdded = updates.added?.extensionStorage;
|
const extStorageAdded = updates.added?.extensionStorage;
|
||||||
if (host in extStorageAdded && extStorageAdded[host].length) {
|
if (host in extStorageAdded && extStorageAdded[host].length) {
|
||||||
storageFront.off("stores-update", updateListener);
|
extensionStorage.off("single-store-update", updateListener);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -137,5 +137,5 @@ add_task(async function test_panel_live_reload() {
|
||||||
"Got the expected results on populated storage.local"
|
"Got the expected results on populated storage.local"
|
||||||
);
|
);
|
||||||
|
|
||||||
await shutdown(extension, target);
|
await shutdown(extension, commands);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,21 +20,6 @@ const {
|
||||||
CommandsFactory,
|
CommandsFactory,
|
||||||
} = require("resource://devtools/shared/commands/commands-factory.js");
|
} = require("resource://devtools/shared/commands/commands-factory.js");
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the equivalent of an `about:debugging` toolbox for a given extension, minus
|
|
||||||
* the toolbox.
|
|
||||||
*
|
|
||||||
* @param {String} id - The id for the extension to be targeted by the toolbox.
|
|
||||||
* @return {Object} Resolves with the web extension actor front and target objects when
|
|
||||||
* the debugger has been connected to the extension.
|
|
||||||
*/
|
|
||||||
async function setupExtensionDebugging(id) {
|
|
||||||
const commands = await CommandsFactory.forAddon(id);
|
|
||||||
const target = await commands.descriptorFront.getTarget();
|
|
||||||
return { front: commands.descriptorFront, target };
|
|
||||||
}
|
|
||||||
exports.setupExtensionDebugging = setupExtensionDebugging;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads and starts up a test extension given the provided extension configuration.
|
* Loads and starts up a test extension given the provided extension configuration.
|
||||||
*
|
*
|
||||||
|
|
@ -52,21 +37,32 @@ async function startupExtension(extConfig) {
|
||||||
exports.startupExtension = startupExtension;
|
exports.startupExtension = startupExtension;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the extensionStorage actor for a target extension. This is effectively
|
* Initializes the extensionStorage actor for a given extension. This is effectively
|
||||||
* what happens when the addon storage panel is opened in the browser.
|
* what happens when the addon storage panel is opened in the browser.
|
||||||
*
|
*
|
||||||
* @param {String} - id, The addon id
|
* @param {String} - id, The addon id
|
||||||
* @return {Object} - Resolves with the web extension actor target and extensionStorage
|
* @return {Object} - Resolves with the DevTools "commands" objact and the extensionStorage
|
||||||
* store objects when the panel has been opened.
|
* resource/front.
|
||||||
*/
|
*/
|
||||||
async function openAddonStoragePanel(id) {
|
async function openAddonStoragePanel(id) {
|
||||||
const { target } = await setupExtensionDebugging(id);
|
const commands = await CommandsFactory.forAddon(id);
|
||||||
|
await commands.targetCommand.startListening();
|
||||||
|
|
||||||
const storageFront = await target.getFront("storage");
|
// Fetch the EXTENSION_STORAGE resource.
|
||||||
const stores = await storageFront.listStores();
|
// Unfortunately, we can't use resourceCommand.waitForNextResource as it would destroy
|
||||||
const extensionStorage = stores.extensionStorage || null;
|
// the actor by immediately unwatching for the resource type.
|
||||||
|
const extensionStorage = await new Promise(resolve => {
|
||||||
|
commands.resourceCommand.watchResources(
|
||||||
|
[commands.resourceCommand.TYPES.EXTENSION_STORAGE],
|
||||||
|
{
|
||||||
|
onAvailable(resources) {
|
||||||
|
resolve(resources[0]);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return { target, extensionStorage, storageFront };
|
return { commands, extensionStorage };
|
||||||
}
|
}
|
||||||
exports.openAddonStoragePanel = openAddonStoragePanel;
|
exports.openAddonStoragePanel = openAddonStoragePanel;
|
||||||
|
|
||||||
|
|
@ -170,11 +166,11 @@ exports.extensionScriptWithMessageListener = extensionScriptWithMessageListener;
|
||||||
* Shutdown procedure common to all tasks.
|
* Shutdown procedure common to all tasks.
|
||||||
*
|
*
|
||||||
* @param {Object} extension - The test extension
|
* @param {Object} extension - The test extension
|
||||||
* @param {Object} target - The web extension actor targeted by the DevTools client
|
* @param {Object} commands - The web extension commands used by the DevTools to interact with the backend
|
||||||
*/
|
*/
|
||||||
async function shutdown(extension, target) {
|
async function shutdown(extension, commands) {
|
||||||
if (target) {
|
if (commands) {
|
||||||
await target.destroy();
|
await commands.destroy();
|
||||||
}
|
}
|
||||||
await extension.unload();
|
await extension.unload();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1372,6 +1372,11 @@ loader.lazyRequireGetter(
|
||||||
ResourceCommand.TYPES.COOKIE,
|
ResourceCommand.TYPES.COOKIE,
|
||||||
"resource://devtools/shared/commands/resource/transformers/storage-cookie.js"
|
"resource://devtools/shared/commands/resource/transformers/storage-cookie.js"
|
||||||
);
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
ResourceTransformers,
|
||||||
|
ResourceCommand.TYPES.EXTENSION_STORAGE,
|
||||||
|
"resource://devtools/shared/commands/resource/transformers/storage-extension.js"
|
||||||
|
);
|
||||||
loader.lazyRequireGetter(
|
loader.lazyRequireGetter(
|
||||||
ResourceTransformers,
|
ResourceTransformers,
|
||||||
ResourceCommand.TYPES.INDEXED_DB,
|
ResourceCommand.TYPES.INDEXED_DB,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ DevToolsModules(
|
||||||
"network-events.js",
|
"network-events.js",
|
||||||
"storage-cache.js",
|
"storage-cache.js",
|
||||||
"storage-cookie.js",
|
"storage-cookie.js",
|
||||||
|
"storage-extension.js",
|
||||||
"storage-indexed-db.js",
|
"storage-indexed-db.js",
|
||||||
"storage-local-storage.js",
|
"storage-local-storage.js",
|
||||||
"storage-session-storage.js",
|
"storage-session-storage.js",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const {
|
||||||
|
TYPES: { EXTENSION_STORAGE },
|
||||||
|
} = require("resource://devtools/shared/commands/resource/resource-command.js");
|
||||||
|
|
||||||
|
const { Front, types } = require("resource://devtools/shared/protocol.js");
|
||||||
|
|
||||||
|
module.exports = function({ resource, watcherFront, targetFront }) {
|
||||||
|
if (!(resource instanceof Front) && watcherFront) {
|
||||||
|
const { innerWindowId } = resource;
|
||||||
|
|
||||||
|
// it's safe to instantiate the front now, so we do it.
|
||||||
|
resource = types.getType("extensionStorage").read(resource, targetFront);
|
||||||
|
resource.resourceType = EXTENSION_STORAGE;
|
||||||
|
resource.resourceId = `${EXTENSION_STORAGE}-${targetFront.browsingContextID}`;
|
||||||
|
resource.resourceKey = "extensionStorage";
|
||||||
|
resource.innerWindowId = innerWindowId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
};
|
||||||
|
|
@ -227,11 +227,12 @@ const Types = (exports.__TypesForTests = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
types: [
|
types: [
|
||||||
|
"Cache",
|
||||||
"cookies",
|
"cookies",
|
||||||
"localStorage",
|
"localStorage",
|
||||||
"sessionStorage",
|
"extensionStorage",
|
||||||
"Cache",
|
|
||||||
"indexedDB",
|
"indexedDB",
|
||||||
|
"sessionStorage",
|
||||||
"storage",
|
"storage",
|
||||||
],
|
],
|
||||||
spec: "devtools/shared/specs/storage",
|
spec: "devtools/shared/specs/storage",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue