Reflux
Reflux is a powerful, universal request/response middleware engine designed for any BareMux compatible web proxy. It features a dynamic plugin system that allows you to load and execute custom JavaScript code on specific websites, making it a transport wrapper rather than a traditional transport.
Features
Section titled “Features”- Dynamic Plugin System: Load and execute custom plugins on specific sites or globally
- Request/Response Middleware: Intercept and modify HTTP requests and responses
- WebSocket Support: Middleware support for WebSocket connections
- Site-Specific Targeting: Run plugins only on specified domains with pattern matching
- Real-time Control: Add, remove, and manage plugins dynamically without reloading
- HTML Modification: Inject scripts, modify DOM, add custom functionality
- Browser & Server-Side Code: Execute code both in the middleware and browser context
Architecture
Section titled “Architecture”Reflux sits between BareMux and your base transport, providing a middleware layer:
┌─────────────────┐│ Application │└────────┬────────┘ │ ▼┌─────────────────┐│ BareMux │└────────┬────────┘ │ ▼┌─────────────────┐│ Reflux │ ◄── Plugin System│ Middleware │└────────┬────────┘ │ ▼┌─────────────────┐│ Base Transport ││ (Epoxy/Libcurl) │└─────────────────┘Installation
Section titled “Installation”npm install @nightnetwork/reflux
Dependencies
Section titled “Dependencies”Reflux requires the following peer dependencies:
@mercuryworkshop/bare-mux- BareMux transport multiplexer- A base transport (e.g.,
@mercuryworkshop/epoxy-transportor@mercuryworkshop/libcurl-transport)
npm install @mercuryworkshop/bare-mux @mercuryworkshop/epoxy-transport
Basic Usage
Section titled “Basic Usage”Setting Up Reflux Transport
Section titled “Setting Up Reflux Transport”import { BareMuxConnection } from "@mercuryworkshop/bare-mux";
// Initialize BareMux with Reflux wrapping EpoxyTransport
const connection = new BareMuxConnection("/baremux/worker.js");
await connection.setTransport("/reflux/index.mjs", [{
base: "/epoxy/index.mjs", // Base transport to wrap
wisp: "wss://example.com/wisp/"
}]);
Creating and Managing Plugins
Section titled “Creating and Managing Plugins”import { RefluxAPI } from "@nightnetwork/reflux";
// Create Reflux API instance
const api = new RefluxAPI();
// Add a plugin
await api.addPlugin({
name: "com.example.logger",
sites: ["example.com"], // Run only on example.com
function: `
/* @browser */
console.log('Plugin running on:', url);
console.log('Page title:', document.title);
/* @/browser */
`
});
// Enable the plugin
await api.enablePlugin("com.example.logger");
// List all plugins
const plugins = await api.listPlugins();
console.log("Installed plugins:", plugins);
// Disable a plugin
await api.disablePlugin("com.example.logger");
// Remove a plugin
await api.removePlugin("com.example.logger");
Plugin System
Section titled “Plugin System”Plugin Structure
Section titled “Plugin Structure”Plugins consist of JavaScript code with special markers for browser-side and server-side execution:
{
name: "com.example.my-plugin", // Unique identifier (use reverse domain notation)
sites: ["example.com", "*.example.com"], // Site patterns
function: `
// Server-side code (runs in middleware)
// Modify response before it reaches browser
if (body.includes('</head>')) {
body = body.replace('</head>', '<style>...</style></head>');
}
/* @browser */
// Browser-side code (injected into page)
console.log('Running on:', url);
document.body.style.backgroundColor = 'lightblue';
/* @/browser */
return body; // Must return body from server-side code
`
}
Site Pattern Matching
Section titled “Site Pattern Matching”"*"- Match all sites"example.com"- Exact domain match"*.example.com"- Wildcard subdomain match"example.*"- Wildcard TLD match
Available Variables
Section titled “Available Variables”Browser-Side Code
Section titled “Browser-Side Code”url(string): Current page URLpluginName(string): Name of the plugin- All standard browser APIs (document, window, etc.)
Server-Side Code
Section titled “Server-Side Code”body(string): HTML contenturl(string): Target URLheaders(Record<string, string>): Response headers
Use Cases
Section titled “Use Cases”Ad Blocking
Section titled “Ad Blocking”await api.addPlugin({
name: "com.example.adblocker",
sites: ["*"],
function: `
/* @browser */
document.querySelectorAll('.ad, [class*="advertisement"]').forEach(el => {
el.remove();
});
/* @/browser */
`
});
Custom UI Injection
Section titled “Custom UI Injection”await api.addPlugin({
name: "com.example.dark-mode",
sites: ["example.com"],
function: `
// Server-side: Inject CSS
if (body.includes('</head>')) {
const css = '<style>body { background: #1a1a1a; color: #fff; }</style>';
body = body.replace('</head>', css + '</head>');
}
/* @browser */
// Browser-side: Toggle button
const btn = document.createElement('button');
btn.textContent = '🌙 Dark Mode';
btn.style.cssText = 'position: fixed; top: 10px; right: 10px; z-index: 9999;';
document.body.appendChild(btn);
/* @/browser */
return body;
`
});
Request/Response Interception
Section titled “Request/Response Interception”await api.addPlugin({
name: "com.example.analytics",
sites: ["*"],
function: `
// Log all requests
console.log('[Reflux] Request to:', url);
/* @browser */
console.log('[Page] Loaded:', url);
console.log('[Page] Performance:', performance.timing);
/* @/browser */
return body;
`
});
API Reference
Section titled “API Reference”RefluxAPI Methods
Section titled “RefluxAPI Methods”addPlugin(plugin)
Section titled “addPlugin(plugin)”Adds a new plugin to the system.
await api.addPlugin({
name: string,
sites: string[],
function: string
});
removePlugin(name)
Section titled “removePlugin(name)”Removes a plugin from the system.
await api.removePlugin("com.example.plugin");
enablePlugin(name)
Section titled “enablePlugin(name)”Enables a disabled plugin.
await api.enablePlugin("com.example.plugin");
disablePlugin(name)
Section titled “disablePlugin(name)”Disables an enabled plugin.
await api.disablePlugin("com.example.plugin");
listPlugins()
Section titled “listPlugins()”Returns a list of all installed plugins.
const plugins = await api.listPlugins();
// Returns: Array<{ name, sites, enabled, function }>
getEnabledPlugins()
Section titled “getEnabledPlugins()”Returns an array of enabled plugin names.
const enabled = await api.getEnabledPlugins();
// Returns: string[]
updatePluginSites(name, sites)
Section titled “updatePluginSites(name, sites)”Updates the site patterns for a plugin.
await api.updatePluginSites("com.example.plugin", ["example.com", "*.test.com"]);
Advanced Features
Section titled “Advanced Features”WebSocket Middleware
Section titled “WebSocket Middleware”Reflux supports intercepting and modifying WebSocket messages:
// This is typically handled at a lower level
// Plugins can access WebSocket data through the middleware system
Request Middleware
Section titled “Request Middleware”Modify requests before they’re sent:
const middleware = {
id: "custom-headers",
onRequest: async (ctx, next) => {
ctx.headers["X-Custom"] = "value";
return await next(ctx);
}
};
Response Middleware
Section titled “Response Middleware”Transform responses before they reach the browser:
const middleware = {
id: "response-modifier",
onResponse: async (ctx, next) => {
const response = await next();
response.headers["X-Modified"] = "true";
return response;
}
};
Performance Considerations
Section titled “Performance Considerations”- Use specific site patterns instead of
["*"]when possible - Keep plugin code minimal and efficient
- Avoid heavy synchronous operations
- Test plugins individually to identify issues
- Clean up resources in browser-side code
Browser Compatibility
Section titled “Browser Compatibility”Required:
- ES6+ JavaScript support
- IndexedDB/LocalForage
- Service Worker support (for BareMux)
Tested:
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
Security Considerations
Section titled “Security Considerations”- 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
Troubleshooting
Section titled “Troubleshooting”Plugin Not Running
Section titled “Plugin Not Running”-
Check if plugin is enabled:
const enabled = await api.getEnabledPlugins(); console.log("Enabled plugins:", enabled); -
Verify plugin was added:
const plugins = await api.listPlugins(); console.log("All plugins:", plugins); -
Check site matching:
await api.updatePluginSites("plugin-name", ["example.com", "*.example.com"]);
Console Errors
Section titled “Console Errors”- “RefluxAPIModule not found”: Make sure
/reflux/api.jsis loaded before your script - “Plugin has no code”: Ensure the
functionproperty is not empty - Storage errors: Check browser console for IndexedDB/LocalForage errors
Related Projects
Section titled “Related Projects”- bare-mux - Transport multiplexer that Reflux builds on
- EpoxyTransport - Common base transport for Reflux
- CurlTransport - Alternative base transport using libcurl.js
Created and maintained by Night Network.