Error reading local storage (Possibly Permission Issue)

This is my first time building a Google Chrome Extension, so I am still learning and possibly doing something silly. Thank you for any help in advance.

Some background context:

Google Cloud Console IAM Admin page (https://console.cloud.google.com/iam-admin/) lists principles based on their project number. For example, a principle may be listed as [email protected], where 123456789012 is a project id. Obviously, 123456789012 isn’t very human readable, so I wanted to build a chrome extension that would create tooltips over strings containing the project id where the tooltip text would be the project name.

I created a background.js script. This script is used to toggle the chrome extension on / off.

let extensionEnabled = false; // Variable to track extension state

chrome.action.onClicked.addListener((tab) => {
    extensionEnabled = !extensionEnabled; // Toggle extension state

    // Save the state of extensionEnabled to storage
    chrome.storage.local.set({ isEnabled: extensionEnabled });

    // Update the extension icon to indicate the current state
    const iconPath = extensionEnabled
        ? { '16': 'images/icon_enabled16.png', '48': 'images/icon_enabled48.png', '128': 'images/icon_enabled128.png' }
        : { '16': 'images/icon16.png', '48': 'images/icon48.png', '128': 'images/icon128.png' };
    chrome.action.setIcon({ path: iconPath });
});

I also created a contentScript.js file that contains the script logic.

const wordMap = {
    // At present I am just hard-coding the project id number and project name
    "123456789012": "project-name",
};

let extensionEnabled = false;
// Load the state from storage
chrome.storage.local.get('isEnabled', (result) => {
    extensionEnabled = result.isEnabled || false;
    if (extensionEnabled) processPage();
});


function processPage() {
    // Create a new style element
    const style = document.createElement('style');

    // Set the CSS for tooltips
    style.textContent = `
...
`;

    // Append the style element to the head of the document
    document.head.appendChild(style);

    // Find occurrences of keys in wordMap in the text nodes of the document and put them in the textNodes array
    const textNodes = [];
    findTextNodes(document.body, textNodes);
    // This creates tooltips for all nodes in the textNodes array
    createTooltips(textNodes);
}

I’ve tested the logic on a test HTML document and processPage() works correctly on a simple static HTML document.

However, the extension wasn’t working properly when using it in Google cloud console. The textNodes array was never being populated with any nodes. I suspect it’s because in the Google console IAM page, they are populated / hydrated by the page’s JS scripts.

Upon googling, I found some tips online that this is because the extension runs in an isolated environment. I tried changing the world key in my Manifest to MAIN. However this causes an error in the extension: Uncaught TypeError: Cannot read properties of undefined (reading 'local') for the line chrome.storage.local.get('isEnabled', (result)

Here’s my manifest file:

{
    "manifest_version": 3,
    "name": "GCP Project ID Tooltip Chrome Extension",
    "version": "0.1",
    "description": "Chrome Extension that adds a tooltip with project names over project ID's in GCP console webpages.",
    "action": {},
    "permissions": [
        "cookies",
        "activeTab",
        "storage",
        "scripting"
    ],
    "host_permissions": [
        "https://console.cloud.google.com/*"
      ],
      "optional_host_permissions":[
        "https://*/*",
        "http://*/*"
      ],
    "background": {
        "service_worker": "background.js",
        "type": "module"
    },
    "content_scripts": [
        {
            "matches": [
                "<all_urls>"
            ],
            "js": [
                "contentScript.js"
            ],
            "all_frames": true,
            "world": "MAIN"
        }
    ],
    "icons": {
        "16": "images/icon16.png",
        "48": "images/icon48.png",
        "128": "images/icon128.png"
    }
}

My few questions are:

  • Do I need "world": "MAIN" set for my use case? or is ISOLATED good enough?
    • If I don’t, I think that would resolve my Cannot read properties of undefined (reading 'local'), but then I am left with the textNodes array not being populated?
  • What permissions do I need for my use-case? I’m still unclear on the various permissions requirements for google chrome extensions.
  • Do I need host_permissions or optional_host_permissions
  • What should I put for content_scripts.matches? I suspect it’s https://console.cloud.google.com/, but I want to confirm.
  • Am I doing anything stupid here? Maybe there is a better/simpler way to accomplish this?

Thank you again for any insight!