controlled-proxy

controlledProxy
allows the behavior of any object to be modified & controlled non-destructively at runtime.
The developer can:
-
Alter the proxy's endpoint controls at runtime.
-
Specify a context-aware handler for disabled endpoints, also at runtime.
-
Create multiple proxies of an underlying object, each controlled differently.
-
Inject proxies into dependent code & control them from the outside.
Easy use case:
-
You have a utility library with extensive logging.
-
You consume that library from an application that uses a custom logger like winston
.
-
You want your utility library also to log to winston
.
-
You normally want debug logging from the utility library disabled, even when it is enabed in the outer application, but you want to enable it selectively to help debug the outer app.
API Documentation • CHANGELOG
Installation
npm install @karmaniverous/controlled-proxy
Basic Usage
The controlledProxy
function creates a type-safe proxy of any object
.
The options
parameter is an object with the following properties:
Property | Type | Default | Description |
---|
defaultControls | Record<PropertyKey, boolean> | {} | A map of controlled property keys to boolean values. When this value is true or the property is uncontrolled, the property will behave normally. When this value is false, the property will execute the disabled member handler or return undefined . |
defaultDisabledMemberHandler | DisabledMemberHandler | () => undefined | A function that is called when a disabled controlled property is accessed. |
target | object | required | The object to proxy. |
Example
import { controlledProxy } from '@karmaniverous/controlled-proxy';
const controlledConsoleLogger = controlledProxy({
defaultControls: { debug: true, info: false },
target: console,
});
controlledConsoleLogger.debug('debug log');
controlledConsoleLogger.info('info log');
Runtime Control
The proxy object has two special properties, keyed with symbols that can be imported from the package:
Property | Type | Description |
---|
[controlProp] | Record<PropertyKey, boolean> | A map of controlled property keys to boolean values. When this value is true or the property is uncontrolled, the property will behave normally. When this value is false, the property will execute the disabled member handler or return undefined . |
[disabledMemberHandlerProp] | DisabledMemberHandler | A function that is called when a disabled controlled property is accessed. Defaults to () => undefined . |
Example
import {
controlledProxy,
controlProp,
disabledMemberHandlerProp,
} from '@karmaniverous/controlled-proxy';
const controlledConsoleLogger = controlledProxy({
defaultControls: { debug: true, info: false },
target: console,
});
controlledConsoleLogger[controlProp].debug = false;
controlledConsoleLogger[controlProp].info = true;
controlledConsoleLogger.debug('debug log');
controlledConsoleLogger.info('info log');
controlledConsoleLogger[disabledMemberHandlerProp] = (
target: Console,
prop: PropertyKey,
) => target.log(`Accessed disabled member: ${prop.toString()}`);
controlledConsoleLogger.debug('debug log');
controlledConsoleLogger.info('info log');
Proxy Injection
Here's an example of the real power of the library: let's inject a controlled proxy into a class!
Example
import { controlledProxy, controlProp } from '@karmaniverous/controlled-proxy';
class MyClass {
constructor(private logger: Pick<Console, 'debug' | 'info'>) {}
myMethod() {
this.logger.debug('debug log');
this.logger.info('info log');
}
}
const controlledConsoleLogger = controlledProxy({
defaultControls: { debug: false, info: true },
defaultDisabledMemberHandler: (target: Console, prop: PropertyKey) =>
target.log(`Accessed disabled member: ${prop.toString()}`),
target: console,
});
const myConsoleInstance = new MyClass(controlledConsoleLogger);
controlledConsoleLogger[controlProp].debug = false;
myConsoleInstance.myMethod();
import { createLogger, type Logger } from 'winston';
const controlledWinstonLogger = controlledProxy({
defaultControls: { debug: true, info: true },
defaultDisabledMemberHandler: (target: Logger, prop: PropertyKey) =>
target.log('warn', `Accessed disabled member: ${prop.toString()}`),
target: createLogger(),
});
const myWinstonInstance = new MyClass(controlledWinstonLogger);
controlledWinstonLogger[controlProp].debug = false;
myWinstonInstance.myMethod();
Built for you with ❤️ on Bali! Find more great tools & templates on my GitHub Profile.