Skip to content

IITC-CE/lib-iitc-manager

Repository files navigation

lib IITC manager

Library for managing IITC and plugins.

Getting started

npm install lib-iitc-manager --save

Usage

Example code to use in WebExtension. Imports the library, passes environment parameters and starts loading IITC and plugins.

import { Manager } from 'lib-iitc-manager';

const manager = new Manager({
    storage: browser.storage.local,
    message: (message, args) => {
        console.log("Message for user:", message, args);
    },
    onProgress: isShow => {
        console.log(isShow ? "Show progress bar" : "Hide progress bar");
    },
    injectPlugin: plugin => {
        console.log("Injecting plugin:", plugin.name);
        console.log(plugin.code);
    },
    onPluginsViewChanged: ({ plugins, categories, core }) => {
        // Called whenever the plugin set or IITC core changes.
        // plugins - merged view of all plugins (catalog + state + user overrides).
        // categories - non-empty categories derived from plugins, sorted alphabetically.
        // core - current IITC core Plugin object, or null if not yet downloaded.
        console.log("Plugin list updated:", Object.keys(plugins).length, "plugins");
        console.log("Categories:", Object.keys(categories));
        console.log("IITC core version:", core?.version ?? "not downloaded");
    },
});

manager.run().then();

Getting the current plugin list, categories and core

const { plugins, categories, core } = await manager.getPluginsView();

// plugins is a PluginDict - keyed by uid, each entry is a merged Plugin object.
// Fields: uid, name, category, status ('on'/'off'), user, override, code, ...
for (const [uid, plugin] of Object.entries(plugins)) {
    console.log(uid, plugin.status, plugin.user ? '(user)' : '');
}

// categories is a CategoryViewDict - keyed by category name, sorted alphabetically.
// Each entry: { name: string, isNew: boolean }
// isNew is true if any plugin in that category was added within newPluginThreshold seconds.
for (const [name, cat] of Object.entries(categories)) {
    console.log(name, cat.isNew ? '(new)' : '');
}

// core is the active IITC core Plugin object, or null if not yet downloaded.
// core.override is true when the user has installed a custom IITC core script.
if (core) {
    console.log("IITC core version:", core.version, core.override ? "(user override)" : "");
}

Reacting to plugin list changes

Pass onPluginsViewChanged in the config (see above), or poll with getPluginsView() as needed.

GM API

When gmApi is provided in the config, the library injects a GM API service script once, before all other plugins. This script implements the Greasemonkey-compatible API (GM_getValue, GM_setValue, GM_xmlhttpRequest, etc.) and communicates with the host app via a message bridge.

const manager = new Manager({
    storage: browser.storage.local,
    gmApi: {
        // JavaScript that sets up window.__iitc_gm_bridge__ in the page context.
        // Must expose: send(data) and onResponse(callback).
        bridgeAdapterCode: `
            window.__iitc_gm_bridge__ = {
                send(data) { window.postMessage({ type: 'FROM_PAGE', data }, '*'); },
                onResponse(cb) {
                    window.addEventListener('message', e => {
                        if (e.data?.type === 'FROM_EXT') cb(e.data.payload);
                    });
                },
            };
        `,
    },
    injectPlugin: plugin => { /* inject plugin.code into the page */ },
    onPluginEvent: event => { /* see below */ },
});

GM API match patterns are scoped to enabled plugins

The GM API service script is only injected on pages that match the aggregated @match patterns of all currently enabled plugins. This avoids injecting it on every page in the browser.

https://intel.ingress.com/* is always included as a baseline. Additional patterns are added only when an enabled plugin declares a different @match. The onPluginEvent notification for gm_api therefore fires only when the match list actually changes - not on every plugin event.

Mode 1 - inject() per page load:

const plugins = await manager.getEnabledPlugins();
// plugins['gm_api'] is always first and contains:
//   .match - current aggregated @match patterns
//   .code  - bridge adapter + GM factory combined

Mode 2 - onPluginEvent for content-script registration:

When a plugin is added, removed, or updated and the aggregated match list changes, onPluginEvent fires a special event with uid === 'gm_api'. Use it to re-register the GM API content script:

onPluginEvent: event => {
    if (event.plugins['gm_api']) {
        const gmApi = event.plugins['gm_api'];
        // event.event is always 'update'
        // gmApi.match - new aggregated @match patterns
        // gmApi.code  - bridge adapter + GM factory to inject at document_start
        reregisterContentScript(gmApi.match, gmApi.code);
        return;
    }
    // handle regular plugin add/update/remove events...
},

Plugins without a @match header do not contribute to the GM API scope. https://intel.ingress.com/* is always present regardless of which plugins are enabled.

Example of use helpers

import { getUniqueId } from "lib-iitc-manager";

const uniqId = getUniqueId("tmp");

See more in documentation

Storage layout

The library uses two kinds of storage keys.

Global keys - shared across all channels:

Key Description
channel Active update channel (release, beta, or custom)
network_host Repository URLs per channel
storage_version Schema version; incremented automatically during migrations
last_check_update Unix timestamp of the last built-in plugin update check
last_check_external_update Unix timestamp of the last user-plugin update check
plugins_state { [uid]: { status, statusChangedAt? } } - enabled/disabled state for every plugin the user has ever touched
plugins_user { [uid]: Plugin } - user-installed scripts (custom plugins and IITC core overrides)
iitc_core_user Custom IITC core script uploaded by the user, or null

Channel-specific keys - {channel} is one of release, beta, custom:

Key Description
{channel}_iitc_core IITC core script downloaded from the channel server
{channel}_iitc_version IITC version string for the channel
{channel}_last_modified ETag / Last-Modified value from the channel's meta.json
{channel}_plugins_catalog { [uid]: Plugin } - plugin metadata fetched from the remote catalog
{channel}_plugins_local { [uid]: Plugin } - downloaded plugin code cache
{channel}_update_check_interval Update check interval in seconds for IITC and built-in plugins

Migrating from v1 to v2

camelCase naming convention

All public methods and configuration properties have been renamed to follow TypeScript camelCase naming conventions. For example:

  • progressbar -> onProgress
  • inject_plugin -> injectPlugin
  • plugins_view_changed -> onPluginsViewChanged
  • new_plugin_threshold -> newPluginThreshold

Internal storage keys (e.g., plugins_user, plugins_state) remain in snake_case to maintain compatibility with existing data.

Removed deprecated methods

The following deprecated methods have been removed:

  • inject_user_script: Use injectPlugin instead.
  • ajaxGet helper: Use fetchData or fetchResource instead.

plugins_flat and ${channel}_categories removed

${channel}_plugins_flat and ${channel}_categories is no longer written to storage. Plugins and categories are computed on demand from the plugin set and returned as part of PluginsView.

${channel}_plugins_state and ${channel}_plugins_user merged into global keys

Per-channel state keys (release_plugins_state, beta_plugins_state, …) and per-channel user-plugin keys (release_plugins_user, …) have been replaced by a single plugins_state and plugins_user shared across all channels. The migration runs automatically on the first run() call.

getIITCCore() removed

getIITCCore() is no longer part of the public API. Use getPluginsView() instead - it now returns a core: Plugin | null field alongside plugins and categories.

${channel}_iitc_core_user merged into global iitc_core_user

The custom IITC core script was previously stored under per-channel keys (release_iitc_core_user, …). It is now stored in a single iitc_core_user key shared across all channels. The migration runs automatically on the first run() call.

License

lib-iitc-manager is licensed under GNU General Public License v3.0 (GPL-3.0). For distribution through application stores (Apple App Store, Google Play Store, and others), please refer to the COPYING.STORE file, which provides an exception for the application store distribution requirements while maintaining GPL-3.0 compliance for the source code.

About

No description, website, or topics provided.

Resources

License

GPL-3.0, Unknown licenses found

Licenses found

GPL-3.0
LICENSE
Unknown
COPYING.STORE

Stars

Watchers

Forks

Packages

 
 
 

Contributors