
Security News
Node.js Drops Bug Bounty Rewards After Funding Dries Up
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.
contextual-proxy
Advanced tools
An enhanced JavaScript Proxy that not only wraps a JavaScript object, but also adds additional contextual variables and parent chain.
An enhanced JavaScript Proxy that not only wraps a JavaScript object, but also adds additional contextual variables and parent chain.
Using Proxy, this is a simpler implementation of Aurelia's scope (binding context and override context) (Aurelia 1, Aurelia 2).
Not only implementation is simplified, but also the usage. Now this kind of proxy can be used as if it's a plain JavaScript object.
| Contextual Proxy | Aurelia Scope |
|---|---|
| The proxied object | Binding context |
| Contextual variables | Override context |
| Parent object | Parent Scope |
Proxy also means IE is not supported.
Aurelia needs a full AST to implement a subset of JavaScript in order to execute an expression utilising scope (binding context and override context), because it's not transparent to access through parent chain. With contextual proxy, it's now transparent. There is no need of an implementation of AST at runtime to execute an expression utilising this proxy, see scoped-eval for more details.
npm install contextual-proxy
import proxy from "contextual-proxy";
// Or in CommonJS:
// const proxy = require("contextual-proxy").default;
It exposes just one API.
JavaScript Proxy class can not be extended (Proxy is special because of no prototype), so we have to design it as a function.
export default function proxy(target: any, parent?: any, context?: {
[key: string]: any;
}): any;
const obj = {a: 1, b: 2};
const wrapped = proxy(obj);
This is almost same as the plain Proxy created by const wrapped = new Proxy(obj, {});.
Note Proxy can only wrap
object, not primitive value (string, number, boolean) ornull(which is anobject).
const parent = {b: 1, c: 2};
const obj = {a: 1, b: 2};
const wrapped = proxy(obj, parent);
Now the parent object is somehow behave like a back-store (think about prototype chain), it can be explicitly accessed by $parent property.
Note we didn't change anything on
objandparentobjects themselves, contextual proxy chained them together without touching the original objects.
wrapped.a; // 1
wrapped.b; // 2
wrapped.c; // 2
wrapped.$parent.a; // undefined
wrapped.$parent.b; // 1
wrapped.$parent.c; // 2
If parent contexts are all prepared by contextual proxy, it can support chain of parent objects.
Use $parent, $parent.$parent... or $parents to access the chain of parent objects.
const grandParent = {foo: 'Foo'};
const wrappedGP = proxy(grandParent);
const parent = {b: 1, c: 2};
const wrappedP = proxy(parent, wrappedGP);
const obj = {a: 1, b: 2};
const wrapped = proxy(obj, wrappedP);
wrapped.foo; // 'Foo'
wrapped.$parent.foo; // 'Foo'
wrapped.$parent.$parent.foo; // 'Foo'
// Same as above two lines
wrapped.$parents[0].foo; // 'Foo'
wrapped.$parents[1].foo; // 'Foo'
wrapped.$parents.length; // 2
wrapped.$parent.$parents.length; // 1
When wrapping target object, you can add contextual variables which only live in the proxy, not in the original target object.
By convention, contextual variables starts with $ such as $index.
The following example is the kind of usage of contextual proxy in a view rendering or model validation.
const classRoom = {
year: 2,
name: 'Courageous Kingfishers',
students: [
{ name: 'Michael' },
{ name: 'Emma' }
]
];
const wrappedClassRoom = proxy(classRoom);
classRoom.students.forEach((student, i) => {
const wrapped = proxy(
student,
wrappedClassRoom,
{
$index: i,
$first: i === 0,
$last: i === classRoom.students.length - 1
}
);
wrapped.year; // 2
wrapped.name; // Michael or Emma
wrapped.$index: // 0 or 1
wrapped.$parent.name; // Courageous Kingfishers
});
const parent = {b: 1, c: 2};
const obj = {a: 1, b: 2};
const wrapped = proxy(obj, proxy(parent), {$index: 1});
wrapped.b = 3; // obj is now {a: 1, b: 3}
wrapped.c = 3; // parent is now {b: 1, c: 3}
wrapped.$parent.b = 2; // parent is now {b: 2, c: 3}
// obj and parent are unchanged, but contextual
// variable $index is changed from 1 to 2;
wrapped.$index = 2;
When you assign some variable not exists in wrapped object, parent object and contextual variables, the proxy will create a new property on the object or contextual variables.
// Create contextual variable $foo with value 1.
// This doesn't mutate the original object at all.
wrapped.$foo = 1;
// Add a new property to original obj.
wrapped.foo = 2;
// Original obj is now {a: 1, b: 3, foo: 2}
To access property foo with wrapped.foo, contextual-proxy first checks contextual variables, then the original object itself, finally checks the parent object. If the parent object is another contextual-proxy wrapper, it will do the same checks and go up the chain to the next level of parent object if there is any.
If the original object has a property $length, and the wrapped proxy also has a contextual variable $length, the original $length will be hidden behind the contextual variable of the same name.
// This will access the contextual variable.
wrapped.$length;
// Use $this to explicitly access original object.
wrapped.$this.$length;
Note
$thisbehaves differently from Aurelia's$this. In Aurelia,$this.foocan still access propertyfooin the parent objects chain. Here in contextual proxy,$thislocks the access to just the original object, we think this is the less surprising behaviour.
$parentcan access the parent object and deeper parent objects chain. To lock the access to that parent object, there is a trick: use$thison the parent proxywrapped.$parent.$this.foo.
Same story goes for accessing the hidden property on parent objects chain. If both wrapped object and parent object has same name property foo, you can use $parent to explicitly skip original object.
// This will access foo on the original object.
wrapped.foo;
// use $parent to explicitly access property on
// parent context (or deeper in the chain).
wrapped.$parent.foo;
There is also $contextual to lock the access to the contextual variables.
// Only access contextual variable.
wrapped.$contextual.$foo;
// If parent context is also a contextual proxy.
wrapped.$parent.$contextual.$foo;
MIT.
FAQs
An enhanced JavaScript Proxy that not only wraps a JavaScript object, but also adds additional contextual variables and parent chain.
We found that contextual-proxy demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.