|
| 1 | +# @adnbn/remote-config-plugin |
| 2 | + |
| 3 | +[](https://www.npmjs.com/package/@adnbn/remote-config-plugin) |
| 4 | +[](https://www.npmjs.com/package/@adnbn/remote-config-plugin) |
| 5 | + |
| 6 | +Remote configuration plugin for [Addon Bone](https://github.com/addonbone). |
| 7 | + |
| 8 | +## Features |
| 9 | + |
| 10 | +- Fetch JSON configuration from a remote endpoint with transparent caching. |
| 11 | +- Configurable cache time-to-live (TTL) in minutes. |
| 12 | +- Fallback to default configuration on failure. |
| 13 | +- Access configuration in background scripts, content scripts, or service workers. |
| 14 | +- React context provider and hook for easy consumption in React apps. |
| 15 | + |
| 16 | +## Installation |
| 17 | + |
| 18 | +Using npm: |
| 19 | + |
| 20 | +```bash |
| 21 | + npm install @adnbn/remote-config-plugin |
| 22 | +``` |
| 23 | + |
| 24 | +Using Yarn: |
| 25 | + |
| 26 | +```bash |
| 27 | + yarn add @adnbn/remote-config-plugin |
| 28 | +``` |
| 29 | + |
| 30 | +## Usage |
| 31 | + |
| 32 | +### Plugin Configuration |
| 33 | + |
| 34 | +In your Addon Bone config (e.g., `adnbn.config.ts`), register the plugin: |
| 35 | + |
| 36 | +```ts |
| 37 | +import {defineConfig} from "adnbn"; |
| 38 | +import remoteConfig from "@adnbn/remote-config-plugin"; |
| 39 | + |
| 40 | +export default defineConfig({ |
| 41 | + plugins: [ |
| 42 | + remoteConfig({ |
| 43 | + url: "https://example.com/config.json", // or an env var name |
| 44 | + ttl: 60, // cache TTL in minutes (default: 1440) |
| 45 | + config: { |
| 46 | + // default/fallback config |
| 47 | + featureFlag: false, |
| 48 | + apiEndpoint: "https://api.example.com", |
| 49 | + }, |
| 50 | + }), |
| 51 | + ], |
| 52 | +}); |
| 53 | +``` |
| 54 | + |
| 55 | +### Accessing Configuration |
| 56 | + |
| 57 | +#### In a content script, background, or any other extension layer |
| 58 | + |
| 59 | +```ts |
| 60 | +import {getRemoteConfig} from "@adnbn/remote-config-plugin/api"; |
| 61 | + |
| 62 | +async function initialize() { |
| 63 | + try { |
| 64 | + const config = await getRemoteConfig<{apiEndpoint: string; featureFlag: boolean}>(); |
| 65 | + console.log("Remote config:", config); |
| 66 | + } catch (error) { |
| 67 | + console.error("Failed to load remote config:", error); |
| 68 | + } |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +#### In React |
| 73 | + |
| 74 | +Wrap your application with the `RemoteConfigProvider`, then use the `useRemoteConfig` hook: |
| 75 | + |
| 76 | +```tsx |
| 77 | +import React, {FC} from "react"; |
| 78 | +import ReactDOM from "react-dom"; |
| 79 | +import {RemoteConfigProvider} from "@adnbn/remote-config-plugin/react"; |
| 80 | +import App from "./App"; |
| 81 | + |
| 82 | +const Popup: FC = () => { |
| 83 | + return ( |
| 84 | + <RemoteConfigProvider> |
| 85 | + <App /> |
| 86 | + </RemoteConfigProvider> |
| 87 | + ); |
| 88 | +}; |
| 89 | + |
| 90 | +export default Popup; |
| 91 | +``` |
| 92 | + |
| 93 | +```tsx |
| 94 | +import {useRemoteConfig} from "@adnbn/remote-config-plugin/react"; |
| 95 | + |
| 96 | +function FeatureComponent() { |
| 97 | + const {featureFlag, apiEndpoint} = useRemoteConfig(); |
| 98 | + |
| 99 | + return ( |
| 100 | + <div> |
| 101 | + {featureFlag ? <p>New feature enabled!</p> : <p>Feature disabled.</p>} |
| 102 | + <p>API Endpoint: {apiEndpoint}</p> |
| 103 | + </div> |
| 104 | + ); |
| 105 | +} |
| 106 | +``` |
| 107 | + |
| 108 | +## Options |
| 109 | + |
| 110 | +The plugin accepts the following options: |
| 111 | + |
| 112 | +- `url?: string` — Remote endpoint URL or an environment variable key resolving to a URL. |
| 113 | +- `ttl?: number` — Cache time-to-live in minutes. Defaults to `1440` (1 day). |
| 114 | +- `config: RemoteConfig` — Default configuration object used as fallback. |
| 115 | + |
| 116 | +## TypeScript Configuration |
| 117 | + |
| 118 | +To enable proper TypeScript support and type safety for your configuration, you need to extend the `RemoteConfig` interface in your project. |
| 119 | + |
| 120 | +### Creating Type Definitions |
| 121 | + |
| 122 | +Create a declaration file in your project (e.g., `types/config.d.ts` or `config.d.ts`) and extend the `RemoteConfig` interface: |
| 123 | + |
| 124 | +```typescript |
| 125 | +import "@adnbn/remote-config-plugin"; |
| 126 | + |
| 127 | +declare module "@adnbn/remote-config-plugin" { |
| 128 | + interface RemoteConfig { |
| 129 | + featureFlag: boolean; |
| 130 | + apiEndpoint: string; |
| 131 | + theme: "light" | "dark"; |
| 132 | + maxRetries: number; |
| 133 | + endpoints: { |
| 134 | + auth: string; |
| 135 | + api: string; |
| 136 | + }; |
| 137 | + } |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +### Benefits of Type Definitions |
| 142 | + |
| 143 | +Once you've defined your configuration types, you'll get: |
| 144 | + |
| 145 | +- **IntelliSense support** - Auto-completion for configuration properties |
| 146 | +- **Type checking** - Compile-time validation of configuration usage |
| 147 | +- **Refactoring safety** - Automatic updates when renaming properties |
| 148 | + |
| 149 | +### Usage with Types |
| 150 | + |
| 151 | +After defining your types, you can use the configuration with full type safety: |
| 152 | + |
| 153 | +```typescript |
| 154 | +// No need for generic type parameter anymore |
| 155 | +const config = await getRemoteConfig(); |
| 156 | +console.log(config.featureFlag); // ✅ TypeScript knows this is boolean |
| 157 | +console.log(config.apiEndpoint); // ✅ TypeScript knows this is string |
| 158 | +console.log(config.theme); // ✅ TypeScript knows this is 'light' | 'dark' |
| 159 | +``` |
| 160 | + |
| 161 | +```tsx |
| 162 | +// In React components |
| 163 | +function MyComponent() { |
| 164 | + const config = useRemoteConfig(); |
| 165 | + |
| 166 | + return ( |
| 167 | + <div className={config.theme === "dark" ? "dark-theme" : "light-theme"}> |
| 168 | + {config.featureFlag && <NewFeature />} |
| 169 | + </div> |
| 170 | + ); |
| 171 | +} |
| 172 | +``` |
| 173 | + |
| 174 | +### Configuration Validation |
| 175 | + |
| 176 | +Make sure your default configuration in `adnbn.config.ts` matches your type definitions: |
| 177 | + |
| 178 | +```typescript |
| 179 | +export default defineConfig({ |
| 180 | + plugins: [ |
| 181 | + remoteConfig({ |
| 182 | + url: "https://example.com/config.json", |
| 183 | + ttl: 60, |
| 184 | + config: { |
| 185 | + featureFlag: false, |
| 186 | + apiEndpoint: "https://api.example.com", |
| 187 | + theme: "light", |
| 188 | + maxRetries: 3, |
| 189 | + endpoints: { |
| 190 | + auth: "https://auth.example.com", |
| 191 | + api: "https://api.example.com", |
| 192 | + }, |
| 193 | + } satisfies RemoteConfig, // ✅ Type validation |
| 194 | + }), |
| 195 | + ], |
| 196 | +}); |
| 197 | +``` |
| 198 | + |
| 199 | +## License |
| 200 | + |
| 201 | +MIT © Addon Bone |
0 commit comments