Complete API documentation for Reflux.
The main API for managing plugins.
new RefluxAPI()Creates a new instance of the RefluxAPI.
Example:
const api = new RefluxAPI();async addPlugin(plugin: RefluxPlugin): Promise<void>Adds a new plugin to the system.
Parameters:
plugin(RefluxPlugin): The plugin configuration
RefluxPlugin Interface:
interface RefluxPlugin {
name: string; // Unique plugin identifier
sites: string[]; // Array of site patterns
function: string; // Plugin code as string
}Example:
await api.addPlugin({
name: "com.example.my-plugin",
sites: ["example.com", "*.example.com"],
function: `
/* @browser */
console.log('Plugin active on:', url);
/* @/browser */
`
});Site Patterns:
"*"- Match all sites"example.com"- Exact domain match"*.example.com"- Wildcard subdomain match"example.*"- Wildcard TLD match
async removePlugin(name: string): Promise<void>Removes a plugin from the system.
Parameters:
name(string): Plugin name to remove
Example:
await api.removePlugin("com.example.my-plugin");async enablePlugin(name: string): Promise<void>Enables a disabled plugin.
Parameters:
name(string): Plugin name to enable
Example:
await api.enablePlugin("com.example.my-plugin");async disablePlugin(name: string): Promise<void>Disables an enabled plugin.
Parameters:
name(string): Plugin name to disable
Example:
await api.disablePlugin("com.example.my-plugin");async listPlugins(): Promise<PluginInfo[]>Returns a list of all installed plugins.
Returns:
Promise<PluginInfo[]>- Array of plugin information objects
PluginInfo Interface:
interface PluginInfo {
name: string;
sites: string[];
enabled: boolean;
function: string;
}Example:
const plugins = await api.listPlugins();
console.log("Installed plugins:", plugins);
// Output:
// [
// {
// name: "com.example.plugin1",
// sites: ["example.com"],
// enabled: true,
// function: "/* plugin code */"
// },
// ...
// ]async getEnabledPlugins(): Promise<string[]>Returns an array of enabled plugin names.
Returns:
Promise<string[]>- Array of enabled plugin names
Example:
const enabled = await api.getEnabledPlugins();
console.log("Enabled plugins:", enabled);
// Output: ["com.example.plugin1", "com.example.plugin2"]async updatePluginSites(name: string, sites: string[]): Promise<void>Updates the site patterns for a plugin.
Parameters:
name(string): Plugin namesites(string[]): New array of site patterns
Example:
await api.updatePluginSites(
"com.example.my-plugin",
["example.com", "test.com", "*.example.org"]
);Plugins are JavaScript code stored as strings with special markers.
Code between /* @browser */ and /* @/browser */ runs in the browser context.
function: `
/* @browser */
// This code runs in the page context
console.log('Running on:', url);
console.log('Plugin name:', pluginName);
// Available variables:
// - url: Current page URL
// - pluginName: Name of this plugin
document.body.style.background = 'lightblue';
/* @/browser */
`Available Variables:
url(string): Current page URLpluginName(string): Name of the plugin- All standard browser APIs (document, window, etc.)
Code outside browser markers runs in the middleware (server-side).
function: `
// This code runs in the middleware
// Available variables:
// - body: HTML content as string
// - url: Target URL
// - headers: Response headers object
if (body.includes('</head>')) {
return body.replace('</head>', '<style>...</style></head>');
}
return body;
`Available Variables:
body(string): HTML contenturl(string): Target URLheaders(Record<string, string>): Response headers
Must return:
- Modified
bodystring, or originalbodyif no changes
function: `
// Server-side: Inject CSS
if (body.includes('</head>')) {
const css = '<style>.enhanced { color: red; }</style>';
body = body.replace('</head>', css + '</head>');
}
/* @browser */
// Browser-side: Apply CSS class
document.querySelectorAll('h1').forEach(h1 => {
h1.classList.add('enhanced');
});
/* @/browser */
return body;
`For advanced middleware (not typically used directly by plugins).
interface MiddlewareFunction {
id: string;
enabled?: boolean | (() => boolean);
onRequest?: (ctx: RequestContext, next: NextFunction) => Promise<RequestContext | void>;
onResponse?: (ctx: ResponseContext, next: NextResponseFunction) => Promise<TransferrableResponse | void>;
modifyWebSocketMessage?: (data: string | Blob | ArrayBuffer, direction: "send" | "receive") => Promise<string | Blob | ArrayBuffer> | string | Blob | ArrayBuffer;
}Intercepts requests before they're sent.
onRequest?: (ctx: RequestContext, next: NextFunction) => Promise<RequestContext | void>RequestContext:
interface RequestContext {
remote: URL;
method: string;
body: BodyInit | null;
headers: Record<string, string>;
signal?: AbortSignal;
}Example:
const middleware = {
id: "my-middleware",
onRequest: async (ctx, next) => {
ctx.headers["X-Custom"] = "value";
return await next(ctx);
}
};Intercepts responses before they reach the browser.
onResponse?: (ctx: ResponseContext, next: NextResponseFunction) => Promise<TransferrableResponse | void>ResponseContext:
interface ResponseContext {
request: RequestContext;
}TransferrableResponse:
interface TransferrableResponse {
body: string | Blob | ArrayBuffer | ReadableStream | null;
headers: Record<string, string>;
status: number;
statusText: string;
}Example:
const middleware = {
id: "my-middleware",
onResponse: async (ctx, next) => {
const response = await next();
response.headers["X-Modified"] = "true";
return response;
}
};Intercepts WebSocket messages.
modifyWebSocketMessage?: (
data: string | Blob | ArrayBuffer,
direction: "send" | "receive"
) => Promise<string | Blob | ArrayBuffer> | string | Blob | ArrayBufferExample:
const middleware = {
id: "my-middleware",
modifyWebSocketMessage: async (data, direction) => {
console.log(`WebSocket ${direction}:`, data);
return data;
}
};All API methods may throw errors. Always use try-catch:
try {
await api.addPlugin(plugin);
console.log("✅ Plugin added successfully");
} catch (error) {
console.error("❌ Failed to add plugin:", error);
}Common Errors:
- Storage unavailable (IndexedDB/LocalForage issues)
- Plugin name already exists
- Invalid plugin format
- Permission errors
Reflux uses LocalForage (IndexedDB) for persistence:
Stores:
plugins- Plugin codepluginMetadata- Plugin configuration (sites, name)status- Enabled/disabled state
Database Name: Reflux
- Plugin added via
addPlugin() - Stored in IndexedDB
- Enabled via
enablePlugin()or disabled by default - Loaded into middleware on next request or via
reloadPlugins() - Executed when request matches site pattern
- Request middleware (all enabled)
- Inner transport request
- Server receives request
- Server sends response
- Response middleware (all enabled)
- HTML plugins execute here
- Browser receives response
- Browser-side plugin code executes
// Import types
import type {
RefluxPlugin,
MiddlewareFunction,
RequestContext,
ResponseContext,
TransferrableResponse
} from "@nightnetwork/reflux";
// Use in your code
const plugin: RefluxPlugin = {
name: "com.example.plugin",
sites: ["*"],
function: "/* code */"
};Required:
- ES6+ JavaScript support
- IndexedDB/LocalForage
- Service Worker support (for BareMux)
Tested:
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
Do:
- ✅ Use specific site patterns instead of
["*"] - ✅ Keep plugin code minimal
- ✅ Use async operations wisely
- ✅ Check content types before processing
- ✅ Cache expensive computations
Don't:
- ❌ Use heavy synchronous operations
- ❌ Modify every response unnecessarily
- ❌ Create memory leaks in browser-side code
- ❌ Block the request/response chain
// ❌ Bad: Memory leak
/* @browser */
setInterval(() => {
// Runs forever
}, 1000);
/* @/browser */
// ✅ Good: Cleanup
/* @browser */
const interval = setInterval(() => {
// Do work
}, 1000);
window.addEventListener('unload', () => {
clearInterval(interval);
});
/* @/browser */- Plugins execute with full permissions
- Be careful with untrusted plugin code
- Server-side code runs in middleware context
- Browser-side code runs in page context
Plugins can modify CSP headers:
onResponse: async (ctx, next) => {
const response = await next();
response.headers["content-security-policy"] = "default-src 'self'";
return response;
}Reflux logs are prefixed with RF:
// Console output example:
// %cRF%c Plugin loaded: com.example.pluginawait api.addPlugin({
name: "com.debug.inspector",
sites: ["*"],
function: `
console.log("=== Debug Info ===");
console.log("URL:", url);
console.log("Plugin:", pluginName);
/* @browser */
console.log("Document:", {
title: document.title,
readyState: document.readyState,
url: window.location.href
});
/* @/browser */
return body;
`
});Before:
// Manual middleware registration (complex)
const middleware = { /* ... */ };
transport.middleware.set("my-plugin", middleware);After:
// Simple plugin API
await api.addPlugin({
name: "com.example.my-plugin",
sites: ["*"],
function: "/* code */"
});
await api.enablePlugin("com.example.my-plugin");- Getting Started - Setup guide
- HTML Modification - Modify website content
- WebSocket Middleware - WebSocket interception
- Request/Response Middleware - HTTP interception
- Examples - Complete examples