Install and develop built-in plugins

Install a built extension into Provision, verify its Service Worker, add a toolbar popup, and update or remove plugins safely.

A built-in SDK plugin is a Chrome extension loaded from <Provision root>/Extensions/<plugin-name>. Built-in plugins are installed automatically; use --show-component-extension-options to display them on chrome://extensions. Installing a plugin does not grant its License capabilities.

Install an existing plugin

  1. Fully quit the browser installation's running instances.
  2. Obtain the plugin's built extension files, including its Chrome manifest.json, JavaScript, and referenced assets. Extract archives first; do not copy a .zip or .crx as the plugin directory.
  3. Copy the directory into Extensions under the actual Provision root.
  4. Check that Extensions/my-plugin/manifest.json exists directly. Avoid an accidental extra level such as my-plugin/dist/manifest.json.
  5. Keep the supplied directory name, install the required License capabilities and EP configuration, then relaunch.
Extensions/
  chrovia-infra/
    manifest.json
    background.js
  my-plugin/
    manifest.json
    background.js
    popup.html
    popup.js

Keep chrovia-infra for online License renewal. Other bundled plugins vary by archive; check Extensions and the plugin's documentation before using them.

Do not use Load unpacked to install a License. A normally loaded development extension also does not automatically receive Provision Service Worker identity. Use the Provision path for this guide.

Minimal plugin with a popup

This example needs extendedPrefs. The popup requests only one operation from its Service Worker; it never reads the privileged API directly.

manifest.json:

{
  "manifest_version": 3,
  "name": "My SDK Plugin",
  "version": "1.0.0",
  "background": { "service_worker": "background.js" },
  "action": { "default_popup": "popup.html" },
  "toolbar_pin": "default_pinned"
}

toolbar_pin: "default_pinned" pins the toolbar icon whenever the Provision plugin loads, including after you manually unpin it and restart. Add standard permissions or host_permissions only for the Chrome APIs and external origins you actually use.

background.js:

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (sender.id !== chrome.runtime.id || message?.type !== 'read-label') {
    return;
  }
  const prefs = globalThis.chrovia?.prefs;
  if (!prefs) {
    sendResponse({ error: 'extendedPrefs unavailable' });
    return;
  }
  prefs.get('internal.instance_appearance.label').then(
    label => sendResponse({ label: typeof label === 'string' ? label : '' }),
    () => sendResponse({ error: 'Unable to read label' }),
  );
  return true;
});

popup.html:

<!doctype html>
<html>
  <body>
    <p id="label">Loading...</p>
    <script src="popup.js"></script>
  </body>
</html>

popup.js:

chrome.runtime.sendMessage({ type: 'read-label' }).then(
  result => {
    document.getElementById('label').textContent = result.error || result.label || 'No label';
  },
  () => {
    document.getElementById('label').textContent = 'Service Worker unavailable';
  },
);

Configure the label using instance appearance. Reading its field uses extendedPrefs; displaying the browser badge also needs instanceAppearance. Store rendering text with textContent, and do not expose a generic privileged-method dispatcher to arbitrary messages.

Verify installation

Launch with --show-component-extension-options, open chrome://extensions, enable Developer mode, and inspect your plugin's Service Worker. Run globalThis.chrovia there. A missing root object usually indicates the wrong context or installation location; a missing domain indicates its entitlement is absent.

A popup or extension tab does not get chrovia by default. Do not enable unrestrictedApi merely to fix a popup; use the message pattern above. Ensure your debugging instance does not enable disable_devtools.

Update and remove

For updates, keep the directory name stable, replace the built files while the browser is closed, increment the extension manifest version for release tracking, and relaunch. Changing only source files or only the root Provision manifest does not update the installed script. Check the executable actually launched, especially if a desktop client extracted its own browser copy.

To remove a plugin, close the browser, remove its immediate directory from Extensions, then relaunch. Confirm that the plugin is no longer listed after restarting. Removal does not guarantee erasure of all extension settings or product data. Do not remove Infra from a lease-based distribution without a working authorized renewal integration.

Service Workers can restart. Register handlers each time the script executes, not only in onInstalled. Avoid multiple plugins claiming the single network interceptor or the same startup reply channel.