npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@adnbn/plugin-remote-config

v0.5.0

Published

Remote config plugin for Addon Bone

Readme

@adnbn/plugin-remote-config

Keep your extension configured through a remote JSON endpoint, with a persistent cache that remains useful when updates fail.

npm version npm downloads CI License: MIT

Purpose

Read remote JSON from background scripts, content scripts, extension pages, or React components. The background service merges responses with defaults and keeps the last working configuration when updates fail.

Installation

pnpm add @adnbn/plugin-remote-config

Quick start

import {defineConfig} from "adnbn";
import remoteConfig from "@adnbn/plugin-remote-config";

export default defineConfig({
    plugins: [remoteConfig({
        url: "https://example.com/config.json",
    })],
});

Read the configuration from any extension layer:

import {getRemoteConfig} from "@adnbn/plugin-remote-config/api";

const config = await getRemoteConfig();

Permissions

On Chrome and Firefox MV2/MV3, the plugin adds storage and host access for the resolved endpoint. It adds no other permissions or optional permission requests. With no endpoint, only storage is declared and reads return defaults.

storage

Caches the response, URL, and refresh metadata in ordinary storage.local under @adnbn/plugin-remote-config:cache. The cache is neither encrypted nor synchronized.

Suggested store justification:

The storage permission caches remote configuration and refresh metadata locally so configured features keep working
when the server is unavailable. This data is not synchronized between devices.

Endpoint host access

An endpoint such as https://example.com/config.json adds https://example.com/*: host_permissions in MV3 and permissions in MV2. Access covers the host, not just the JSON path.

Suggested store justification:

Host access lets the extension's background service retrieve JSON settings from its configuration server to configure
its features. The response contains data, not executable code.

Consumer-owned access

Other hosts, including redirect destinations, require consumer-owned access. Custom CSP must permit the request. Adapt the store justifications if your extension uses these permissions for additional features.

How it works

  • Options and environment values are resolved once at builder startup.
  • Reads use the same-URL cache until TTL expires; the next read refreshes it. Concurrent reads share one request.
  • Successful responses merge deeply with the original defaults, never with previous remote values. Missing fields keep defaults; arrays replace whole; false, 0, "", and null are preserved. An empty object restores defaults.
  • Failed refreshes retain the last working response, or defaults if none exists. Without either, reads return {}. Retries respect retryDelay. There is no background polling or maximum stale-cache age.

For example, defaults {banner: {enabled: false, text: "default"}} plus {banner: {text: "new"}} produce {banner: {enabled: false, text: "new"}}.

Options

| Option | Default | Meaning | | --- | --- | --- | | url | "REMOTE_CONFIG_URL" | HTTP(S) URL or environment variable name. "" disables the endpoint. | | config | {} | Optional, deeply partial defaults matching your RemoteConfig schema. | | ttl | 1440 | Cache freshness in minutes. Zero refreshes on every read, subject to retry delay. | | timeout | 10000 | Request and JSON-body timeout in milliseconds. Must be positive and within timer limits. | | retryDelay | 60000 | Delay after a failed refresh, in milliseconds. Zero disables it. | | credentials | "omit" | "omit", "same-origin", or "include"; use "include" for cookie authentication. |

Each option accepts a build-time getter. Numbers must be finite; TTL and retry delay cannot be negative. remoteConfig() uses REMOTE_CONFIG_URL without requiring defaults. Omitting config, passing undefined, or returning undefined from its getter uses {}; explicit null or an array is not a valid defaults object. A missing environment variable warns at startup and disables fetching. An empty URL or a URL getter returning undefined disables it silently. Changing the URL invalidates the previous cache.

TypeScript and selection

Augment the public interface in a declaration file included by your project:

import "@adnbn/plugin-remote-config";

declare module "@adnbn/plugin-remote-config" {
    interface RemoteConfig {
        featureFlag: boolean;
    }
}

getRemoteConfig accepts no argument, a typed dot path, or a selector. It also awaits async selectors:

const config = await getRemoteConfig(); // RemoteConfig
const enabled = await getRemoteConfig("featureFlag"); // boolean
const label = await getRemoteConfig(config => config.featureFlag ? "on" : "off");

Defaults may omit required root and nested fields; supplied values must match the schema. For fields with no default that may be absent before loading or when requests fail, prefer optional properties (field?: ...). Arrays and tuples, when supplied, retain their element types. Paths support numeric array indices (banners.0.title) and up to ten recursive steps; broad, deep schemas can increase type-checking time. Optional or nullable branches and unbounded array indices can yield undefined. Dictionary lookups also include undefined. Result types follow your interface and the standard type-fest Get behavior, independently of defaults. An absent value returns undefined at runtime even if declared required.

Use selectors for keys containing dots, brackets, or backslashes, reserved keys (__proto__, prototype, constructor), and values typed as unknown or any. Selection is local and always reads the full service result. getRemoteConfigOptions() exposes resolved build-time options; /service is the framework's background entrypoint.

React

React is an optional peer, used only by /react. The hook accepts the same paths and selectors:

import {useRemoteConfig} from "@adnbn/plugin-remote-config/react";

function Feature() {
    const enabled = useRemoteConfig("featureFlag");

    return <span>{enabled ? "Enabled" : "Disabled"}</span>;
}

The hook starts with defaults or {}, fetches on mount, and ignores results after unmounting. Missing dot paths initially return undefined. Changing the selection uses current state without refetching. Selectors must be synchronous; the hook neither polls nor subscribes to updates.

Limits and upgrading

  • TypeScript checks supplied defaults, not server data or the presence of required fields at runtime. Selectors receive an object but can throw when directly accessing an absent nested branch; use optional chaining as needed. Responses must be JSON objects with values matching your schema; explicit null replaces a default, and replacement array elements must contain their required fields.
  • Results are independent copies. Network and storage failures are handled separately; failed persistence leaves an in-memory cache, but configuration and retry metadata may be lost after a service-worker restart.
  • Upgrading from 0.3.x: use /react instead of /hooks and augment RemoteConfig instead of overriding it with a generic. Old caches are not migrated. Credentials now default to "omit".

For development, testing, and releases, see the monorepo contributing guide.