├── .github
└── workflows
│ └── node.js.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── LICENSE
├── README.md
├── cjs
└── package.json
├── esm
├── heap.js
├── index.js
├── mitm.js
├── traps.js
└── types.js
├── package-lock.json
├── package.json
├── readme.js
└── test
├── heap.js
├── index.js
├── mitm.js
├── test.js
└── utils.js
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: build
5 |
6 | on: [push, pull_request]
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [20]
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v2
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | cache: 'npm'
24 | - run: npm ci
25 | - run: npm run build --if-present
26 | - run: npm test
27 | - run: npm run coverage --if-present
28 | - name: Coveralls
29 | uses: coverallsapp/github-action@master
30 | with:
31 | github-token: ${{ secrets.GITHUB_TOKEN }}
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nyc_output
3 | v8.log
4 | coverage/
5 | node_modules/
6 | cjs/*
7 | !cjs/package.json
8 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nyc_output
3 | .eslintrc.json
4 | .github/
5 | .travis.yml
6 | v8.log
7 | coverage/
8 | node_modules/
9 | rollup/
10 | test/
11 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 | package-lock=true
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright © 2024-today, Andrea Giammarchi, @WebReflection
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the “Software”), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included
13 | in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 | IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/WebReflection/js-proxy/actions) [](https://coveralls.io/github/WebReflection/js-proxy?branch=main)
2 |
3 | **Social Media Photo by [Vinu T](https://unsplash.com/@happy_pixel?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash) on [Unsplash](https://unsplash.com/photos/a-small-waterfall-in-the-middle-of-a-forest-DHo1nNUI0y4?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash)**
4 |
5 | The "*one-stop shop*" solution for JS Proxies and FFI APIs.
6 |
7 | **[Documentation](https://webreflection.github.io/js-proxy/)**
8 |
9 | - - -
10 |
11 | ### Table of content
12 |
13 | * **[API](#api)** that describes the default exported utility
14 | * **[jsProxy](#jsproxy)** that describes the namespace returned by the utility
15 | * **[MITM](#mitm)** that describes what `js-proxy/mitm` exports as extra utility
16 | * **[Heap](#heap)** that describes what `js-proxy/heap` exports as extra utility
17 | * **[Traps](#traps)** that describes what `js-proxy/traps` exports
18 | * **[Types](#types)** that describes what `js-proxy/types` exports
19 |
20 | ## API
21 |
22 | ### `define(namespace):jsProxy`
23 |
24 | The default export provides an utility to define various handlers for any kind of proxied value and returns a [jsProxy](#jsproxy) object literal.
25 |
26 | Each handler can have zero, one or more [proxy traps](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy#handler_functions) *plus* the following extra handlers:
27 |
28 | * **destruct** which, if present, will orchestrate automatically a [FinalizationRegistry](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) logic to invoke such trap once its proxied value is not used anymore in the wild.
29 | * **valueOf** which, if present, allows the `valueOf(proxy)` utility to retrieve directly the underlying proxied value.
30 |
31 | > [!Important]
32 | >
33 | > If the namespace contains `object`, `array`, or `function` as own entries the value can be either a reference to those types or actually a number or any other primitive which goal is to reflect proxies across worlds (boundaries, workers, realms, interpreters).
34 | >
35 | > In case those references are primitives it is mandatory to define all native traps otherwise the `Reflect` methods would fail at dealing with numbers, strings, or any other kind of primitive.
36 | >
37 | > Any other name will simply directly accept references, but not primitives, still providing the special methods that are indeed available to every type of proxy.
38 |
39 | #### Example
40 |
41 | ```js
42 | import define from 'js-proxy';
43 |
44 | // simply returns whatever value is received
45 | const identity = value => value;
46 |
47 | // te jsProxy is an object with these fields / utilities:
48 | const { proxy, release, typeOf, valueOf } = define({
49 | object: { valueOf: identity },
50 | array: { valueOf: identity },
51 | function: { valueOf: identity },
52 | direct: {
53 | destruct(ref) {
54 | console.log('this reference is no longer needed', ref);
55 | }
56 | },
57 | });
58 |
59 | // object, array and function always act
60 | // like proxies and values for objects, arrays or functions
61 | // any other namespace entry uses directly the referenced value.
62 | const object = proxy.object([]); // still an object
63 | const array = proxy.array({}); // still an array
64 | const fn = proxy.function(123); // still a function
65 |
66 | let any = proxy.direct({});
67 |
68 | // all true
69 | typeOf(object) === "object" && !Array.isArray(object);
70 | typeOf(array) === "array" && Array.isArray(array);
71 | typeOf(fn) === "function" && typeof fn === "function";
72 | typeOf(any) === "direct"; // <-- !!!
73 |
74 | // retrieve the original value
75 | valueOf(object).length; // 0
76 | valueOf(fn) === 123; // true
77 |
78 | // no valueOf trap defined:
79 | valueOf(any) === any; // true
80 |
81 | any = null;
82 | // will eventually log:
83 | // "this reference is no longer needed", {}
84 | ```
85 |
86 | The reason for `object`, `array`, and `function` to have a special treatment is the fact both `typeof` and `Array.isArray` can actually drill into the proxied type so that this module guarantees that if you meant to proxy an *array* or a *function*, these will reflect their entity across introspection related operations, also providing a way to simply proxy memory addresses or any other kind of identity, and deal with [Foreign Function Interfaces](https://en.wikipedia.org/wiki/Foreign_function_interface) for non *JS* related programming languages.
87 |
88 |
89 | ## jsProxy
90 |
91 | ### `jsProxy.proxy.type(value, ...rest)`
92 |
93 | The `proxy` literal will contain all defined proxy types able to bootstrap related proxies directly.
94 |
95 | The definition can contain any valid object literal key, including symbols.
96 |
97 |
Example
98 |
99 | ```js
100 | import define from 'js-proxy';
101 |
102 | const secret = Symbol('secret');
103 |
104 | const { proxy } = define({
105 | object: {
106 | // ... one or more traps ...
107 | },
108 | custom: {
109 | // ... one or more traps ...
110 | },
111 | [secret]: {
112 | // ... one or more traps ...
113 | },
114 | });
115 |
116 | // create 3 different proxies
117 | proxy.object({}); // typeOf(...) === "object"
118 | proxy.custom({}); // typeOf(...) === "custom"
119 | proxy[secret]({}); // typeOf(...) === secret
120 | ```
121 |
122 | #### Dealing with primitives
123 |
124 | The `proxy` namespace is able to bootstrap even primitives but with the following constraints:
125 |
126 | * at least common traps must be well defined otherwise the *Reflect* fallback might fail
127 | * if passed as primitive, the value will be proxied automatically as an `Object(primitive)` and there won't be any way to `release(primitive)` later on
128 | * if passed as reference, it's still needed to define common traps
129 |
130 | #### Example
131 |
132 | ```js
133 | import define from 'js-proxy';
134 |
135 | const { proxy, release } = define({
136 | string: {
137 | get(str, key) {
138 | const value = str[key];
139 | return typeof value === 'function' ?
140 | value.bind(str) : value;
141 | },
142 | destruct(str) {
143 | console.log(`wrap for ${str} released`);
144 | },
145 | },
146 | });
147 |
148 | // works but release won't be effective
149 | proxy.string('test').slice(0, 1); // "t"
150 | release('test'); // ⚠️ WRONG
151 | // throws: Invalid unregisterToken ('test')
152 |
153 | // this works better and it's possible to release
154 | const wrap = Object('test'); // new String('test')
155 | proxy.string(wrap).slice(0, 1);
156 | release(wrap); // 👍 OK
157 | // destruct trap won't ever be invoked
158 | ```
159 |
160 | #### Dealing with foreign programming languages
161 |
162 | Usually most primitive types are exchanged as such in the *ForeignPL* to *JS* world, so that numbers are converted, boolean are converted, strings are (likely) converted (but they don't really need to be) but objects, arrays, and functions cannot really be converted retaining their reference in the *ForeignPL* counterpart.
163 |
164 | If it's desired to both deal with these cases and have a way to `release(token)` later on, there are at least two different approaches:
165 |
166 | * wrap that primitive identifier as object itself such as `{_ref: 123}`, requiring for each trap to extract that `_ref` each time
167 | * retain the token a part, passing it as second proxy argument
168 |
169 | It is really up to you how you prefer handling references to your current *foreign PL* but at least there are a couple of options.
170 |
171 | #### Example
172 |
173 | ```js
174 | import define from 'js-proxy';
175 |
176 | const { proxy, release } = define({
177 | object: {
178 | destruct(ref) {
179 | // {_ref: 123} in case No.1
180 | // 456 in case No.2
181 | console.log(ref, 'proxy is gone');
182 | },
183 | },
184 | });
185 |
186 | // case No.1
187 | const trapped1 = {_ref: 123};
188 | let proxied1 = proxy.object(trapped1);
189 | setTimeout(release, 1000, trapped1);
190 |
191 | // case No.2
192 | const trapped2 = 456;
193 | const token2 = Object(456);
194 | let proxied2 = proxy.object(trapped2, token2);
195 | setTimeout(release, 1000, token2);
196 | ```
197 |
198 | ### `jsProxy.release(token)`
199 |
200 | This utility is particularly handy for *FFI* related use cases or whenever an explicit `destroy()` or `destruct()` method is meant by the code that provides the proxy.
201 |
202 | When the token is known and released, the `destruct` trap won't happen again, effectively avoiding double invokes of potentially the same procedure.
203 |
204 | The `token` reference is, by default, the same proxied object so that it's easy behind the scene to hold it internally and eventually procedurally release that reference from the garbage collector.
205 |
206 | Use cases could be a terminated worker that was holding delivered proxies or users defined explicit actions to signal some reference is not needed anymore and won't be accessed again.
207 |
208 | #### Example
209 |
210 | ```js
211 | import define from 'js-proxy';
212 |
213 | const { proxy, release } = define({
214 | direct: {
215 | destruct(ref) {
216 | console.log(ref, 'not used anymore');
217 | }
218 | }
219 | });
220 |
221 | const myRef = {ref: 123};
222 | const outProxy = proxy.direct(myRef);
223 |
224 | // any time later we want to drop myRef on GC
225 | release(myRef);
226 | ```
227 |
228 | ### `jsProxy.typeOf(unknown)`
229 |
230 | Differently from the [typeof operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof), the `typeOf` utility does the following:
231 |
232 | * it retrieves the current `typeof` of the generic, *unknown*, value
233 | * if the resulting *type* is `"object"`:
234 | * if the namespace had such type defined in it, it returns that brand name instead
235 | * if the value is an *array*, it returns `"array"`
236 | * if the value is `null`, it returns `"null"`
237 | * otherwise returns the string that `typeof` originally returned
238 |
239 | > [!Note]
240 | >
241 | > This utility is not necessarily that useful with this module but it's especially handy to branch out specific proxies handlers and behavior whenever the type of proxy is known in the namespace.
242 |
243 | #### Example
244 |
245 | ```js
246 | import define from 'js-proxy';
247 |
248 | const { proxy, typeOf } = define({
249 | object: {},
250 | string: {},
251 | promise: {},
252 | });
253 |
254 | const object = proxy.object({});
255 | const str = proxy.string(new String(''));
256 | const promise = proxy.promise(Promise.resolve(true));
257 |
258 | // all true
259 | typeOf(object) === "object";
260 | typeOf(str) === "string";
261 | typeOf(promise) === "promise";
262 | ```
263 |
264 |
265 | ### `jsProxy.valueOf(unknown)`
266 |
267 | If a defined proxy handler has its own `valueOf` trap, this utility will call that trap directly and return whatever that method decided to return.
268 |
269 | It's literally a transparent *pass through* operation that will not involve native traps.
270 |
271 | If the handler did not provide its own `valueOf` trap, this utility simply perform a `ref.valueOf()` operation.
272 |
273 | #### Example
274 |
275 | ```js
276 | import define from 'js-proxy';
277 |
278 | const identity = value => value;
279 |
280 | const { proxy, valueOf } = define({
281 | object: {
282 | valueOf: identity,
283 | },
284 | direct: {
285 | valueOf: identity,
286 | },
287 | unknown: {},
288 | });
289 |
290 | const object = proxy.object(123);
291 | const array = [1, 2, 3];
292 | const direct = proxy.direct(array);
293 | const unknown = proxy.unknown([4, 5, 6]);
294 |
295 | // all true
296 | valueOf(object) === 123;
297 | valueOf(direct) === array;
298 | valueOf(unknown) === unknown;
299 | ```
300 |
301 |
302 | ## MITM
303 |
304 | The [MITM](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) utility puts a proxy handler behind the reference and not upfront. Usually, proxies are transparent until they are not:
305 |
306 | * DOM operations are not allowed with proxies
307 | * `typeof` or `isArray` or anything else drilling the proxied type might reveal the proxy or fail
308 | * references need to be proxied before others can consume these, as opposite of hooking any extra feature/utility/observability without requiring 3rd party to change their reference to the real target
309 |
310 | Accordingly, the *MITM* export allows anything to have a proxy between its reference and its prototype, which requires extra careful handling, but it can be summarized as such:
311 |
312 | ```js
313 | import mitm from 'js-proxy/mitm';
314 |
315 | // generic DOM handler for text property
316 | const textHandler = {
317 | get(__proto__, name, target) {
318 | if (name === 'text')
319 | return target.textContent;
320 | return Reflect.get(__proto__, name, target);
321 | },
322 | set(__proto__, name, value, target) {
323 | if (name === 'text') {
324 | target.textContent = value;
325 | return true;
326 | }
327 | return Reflect.set(__proto__, name, value, target);
328 | }
329 | };
330 |
331 | // pollute (once) any DOM node
332 | mitm(document.body, textHandler);
333 |
334 | // see magic
335 | document.body.text = 'Hello MITM';
336 | document.body.text; // 'Hello MITM'
337 | ```
338 |
339 | The rule of thumb for *MITM* is that last come is the first to intercept but it's possible to add multiple *MITM* although performance will degrade proportionally as more logic will be involved per each property.
340 |
341 |
342 | ## Heap
343 |
344 | As extra utility, the `js-proxy/heap` exports is particularly useful for cross realm *JS* proxied interactions.
345 |
346 | As example, if your worker, or your main, would like to expose a reference to another worker or main thread, it is possible to associate the current reference to a unique identifier that can then be destroyed once the other world won't need it anymore.
347 |
348 | #### Example
349 |
350 | ```js
351 | import { drop, get, hold } from 'js-proxy/heap';
352 |
353 | let thisWorldReference = {};
354 |
355 | // traps forever the reference until drop
356 | let refID = hold(thisWorldReference);
357 | // it's always unique by reference
358 | // hold(thisWorldReference) === hold(thisWorldReference)
359 |
360 | postMessage({ type: 'object', value: refID });
361 |
362 | addEventListener('message', ({ data }) => {
363 | const { value, trap, args } = data;
364 | // drop the reference, not needed out there anymore
365 | if (trap === 'destruct') {
366 | drop(value);
367 | }
368 | else {
369 | // retrieve the original reference by id
370 | const ref = get(value);
371 | postMessage(Reflect[trap](ref, ...args));
372 | }
373 | });
374 | ```
375 |
376 | In the outer world, the `proxy.object({_ref: value})` could forward back via `postMessage` all traps, including the `destruct` when it happens, so that the worker can apply and reply with the result.
377 |
378 | As summary, this export helps relating any reference to a unique identifier and it holds such reference until it's dropped. This is particularly useful to avoid the current realm collecting that reference, as it might be used solely in the outer world, still enabling, via `destruct` ability, to free memory on occasion.
379 |
380 |
381 | ## Traps
382 |
383 | The `js-proxy/traps` exports the following:
384 |
385 | ```js
386 | // Standard Proxy Traps
387 | export const APPLY = 'apply';
388 | export const CONSTRUCT = 'construct';
389 | export const DEFINE_PROPERTY = 'defineProperty';
390 | export const DELETE_PROPERTY = 'deleteProperty';
391 | export const GET = 'get';
392 | export const GET_OWN_PROPERTY_DESCRIPTOR = 'getOwnPropertyDescriptor';
393 | export const GET_PROTOTYPE_OF = 'getPrototypeOf';
394 | export const HAS = 'has';
395 | export const IS_EXTENSIBLE = 'isExtensible';
396 | export const OWN_KEYS = 'ownKeys';
397 | export const PREVENT_EXTENSION = 'preventExtensions';
398 | export const SET = 'set';
399 | export const SET_PROTOTYPE_OF = 'setPrototypeOf';
400 |
401 | // Custom (JS)Proxy Traps
402 | export const DESTRUCT = 'destruct';
403 | export const VALUE_OF = 'valueOf';
404 | ```
405 |
406 |
407 | ## Types
408 |
409 | The `js-proxy/types` exports the following:
410 |
411 | ```js
412 | export const ARRAY = 'array';
413 | export const BIGINT = 'bigint';
414 | export const BOOLEAN = 'boolean';
415 | export const FUNCTION = 'function';
416 | export const NULL = 'null';
417 | export const NUMBER = 'number';
418 | export const OBJECT = 'object';
419 | export const STRING = 'string';
420 | export const SYMBOL = 'symbol';
421 | export const UNDEFINED = 'undefined';
422 | ```
423 |
--------------------------------------------------------------------------------
/cjs/package.json:
--------------------------------------------------------------------------------
1 | {"type":"commonjs"}
--------------------------------------------------------------------------------
/esm/heap.js:
--------------------------------------------------------------------------------
1 | import { NUMBER } from 'proxy-target/types';
2 |
3 | export const create = () => {
4 | const ids = new Map;
5 | const values = new Map;
6 | let uid = 0;
7 | return {
8 | /**
9 | * Clear all references retained in the current heap.
10 | */
11 | clear: () => {
12 | ids.clear();
13 | values.clear();
14 | },
15 |
16 | /**
17 | * Remove by id or value any previously stored reference.
18 | * @param {number | unknown} id the held value by id or the value itself.
19 | * @returns {boolean} `true` if the operation was successful, `false` otherwise.
20 | */
21 | drop: id => {
22 | const [a, b] = typeof id === NUMBER ? [values, ids] : [ids, values];
23 | const had = a.has(id);
24 | if (had) {
25 | b.delete(a.get(id));
26 | a.delete(id);
27 | }
28 | return had;
29 | },
30 |
31 | /**
32 | * Return the held value reference by its unique identifier.
33 | * @param {number} id the unique identifier for the value reference.
34 | * @returns {unknown} the related value / reference or undefined.
35 | */
36 | get: id => values.get(id),
37 |
38 | /**
39 | * Create once a unique number id for a generic value reference.
40 | * @param {unknown} value a reference used to create a unique identifier.
41 | * @returns {number} a unique identifier for that reference.
42 | */
43 | hold: value => {
44 | if (!ids.has(value)) {
45 | let id;
46 | // a bit apocalyptic scenario but if this thread runs forever
47 | // and the id does a whole int32 roundtrip we might have still
48 | // some reference dangling around
49 | while (/* c8 ignore next */ values.has(id = uid++));
50 | ids.set(value, id);
51 | values.set(id, value);
52 | }
53 | return ids.get(value);
54 | },
55 | };
56 | };
57 |
58 | // globally shared heap
59 | const { clear, drop, get, hold } = create();
60 | export { clear, drop, get, hold };
61 |
--------------------------------------------------------------------------------
/esm/index.js:
--------------------------------------------------------------------------------
1 | import { ARRAY, FUNCTION, NULL, OBJECT, UNDEFINED } from 'proxy-target/types';
2 | import * as handlerTraps from 'proxy-target/traps';
3 | import { bound } from 'proxy-target';
4 | import { create, drop } from 'gc-hook';
5 |
6 | const { Object, Proxy, Reflect } = globalThis;
7 |
8 | const { isArray } = Array;
9 | const { ownKeys } = Reflect;
10 | const { create: extend, hasOwn, values } = Object;
11 |
12 | const wrapOf = (ref, type) => (
13 | type === ARRAY ? ref[0] : (
14 | type === FUNCTION ? ref() : (
15 | type === OBJECT ? ref.$ : ref
16 | )
17 | )
18 | );
19 |
20 | const extendHandler = (handler, type, direct, value) => {
21 | const descriptors = { type: { value: type } };
22 | const hasValueOf = hasOwn(handler, 'valueOf');
23 | for(const trap of values(handlerTraps)) {
24 | let descriptor = value(handler[trap] || Reflect[trap]);
25 | if (hasValueOf && trap === handlerTraps.GET) {
26 | const { valueOf } = handler;
27 | const { value } = descriptor;
28 | descriptor = {
29 | value($, s, ..._) {
30 | return s === direct ?
31 | valueOf.call(this, wrapOf($, type)) :
32 | value.call(this, $, s, ..._);
33 | }
34 | };
35 | }
36 | descriptors[trap] = descriptor;
37 | }
38 | return extend(handler, descriptors);
39 | };
40 |
41 | const JSProxy = ($, target, handler, token = $) => {
42 | if (token === $) {
43 | switch (typeof $) {
44 | case OBJECT:
45 | case UNDEFINED: if (!token) token = false;
46 | case FUNCTION: break;
47 | default: {
48 | token = false;
49 | if (target === $) target = Object($);
50 | }
51 | }
52 | }
53 | const p = new Proxy(target, handler);
54 | const { destruct } = handler;
55 | return destruct ? create($, destruct, { token, return: p }) : p;
56 | };
57 |
58 | const asArrayType = value => (isArray(value) ? ARRAY : OBJECT);
59 |
60 | const typeOfFor = typesOf => value => {
61 | const type = typeof value;
62 | return type === OBJECT ?
63 | (value ?
64 | (typesOf.get(value)?.[0] ?? asArrayType(value)) :
65 | NULL
66 | ) :
67 | type;
68 | };
69 |
70 | const pairFor = typesOf => value => {
71 | let type = typeof value;
72 | switch (type) {
73 | case OBJECT:
74 | if (!value) {
75 | type = NULL;
76 | break;
77 | }
78 | case FUNCTION:
79 | const t = typesOf.get(value);
80 | if (t) [type, value] = t;
81 | break;
82 | }
83 | return [type, value];
84 | };
85 |
86 | const release = token => (drop(token), token);
87 |
88 | export default namespace => {
89 | const typesOf = new WeakMap;
90 | const direct = Symbol();
91 | const proxy = {};
92 | const set = (p, type, value) => {
93 | typesOf.set(p, [type, value]);
94 | return p;
95 | };
96 | const utils = {
97 | proxy,
98 | release,
99 | pair: pairFor(typesOf),
100 | typeOf: typeOfFor(typesOf),
101 | isProxy: value => typesOf.has(value),
102 | valueOf: value => (value[direct] ?? value.valueOf()),
103 | };
104 | for (const type of ownKeys(namespace)) {
105 | if (hasOwn(utils, type)) continue;
106 | const traps = namespace[type];
107 | switch (type) {
108 | case ARRAY: {
109 | const handler = extendHandler(traps, type, direct, value => ({
110 | value([ $ ], ..._) {
111 | return value.call(this, $, ..._);
112 | }
113 | }));
114 | proxy[type] = ($, ..._) => set(JSProxy($, [ $ ], handler, ..._), ARRAY, $);
115 | break;
116 | }
117 | case FUNCTION: {
118 | const handler = extendHandler(traps, type, direct, value => ({
119 | value($, ..._) {
120 | return value.call(this, $(), ..._);
121 | }
122 | }));
123 | proxy[type] = ($, ..._) => set(JSProxy($, bound($), handler, ..._), FUNCTION, $);
124 | break;
125 | }
126 | case OBJECT: {
127 | const handler = extendHandler(traps, type, direct, value => ({
128 | value({ $ }, ..._) {
129 | return value.call(this, $, ..._);
130 | }
131 | }));
132 | proxy[type] = ($, ..._) => set(JSProxy($, { $ }, handler, ..._), OBJECT, $);
133 | break;
134 | }
135 | default: {
136 | const handler = extendHandler(traps, type, direct, value => ({
137 | value
138 | }));
139 | proxy[type] = ($, ..._) => set(JSProxy($, $, handler, ..._), type, $);
140 | break;
141 | }
142 | }
143 | }
144 | return utils;
145 | };
146 |
--------------------------------------------------------------------------------
/esm/mitm.js:
--------------------------------------------------------------------------------
1 | const { getPrototypeOf, setPrototypeOf } = Object;
2 |
3 | const handlers = new WeakMap;
4 |
5 | const set = (handlers, handler) => {
6 | const ws = new WeakSet;
7 | handlers.set(handler, ws);
8 | return ws;
9 | };
10 |
11 | /**
12 | * Given a reference `target`, it sets a proxy between that `target`
13 | * reference and its prototype, allowing interception of all not-own
14 | * properties. The `handler` will receive the `__proto__` as first
15 | * argument of any of its trap and, where passed along, the target itself.
16 | * @template T
17 | * @param {T} target
18 | * @param {ProxyHandler} handler
19 | */
20 | const mitm = (target, handler) => {
21 | const ws = handlers.get(handler) || set(handlers, handler);
22 | return ws.has(target) ? target : (
23 | ws.add(target),
24 | setPrototypeOf(target, new Proxy(getPrototypeOf(target), handler))
25 | );
26 | };
27 |
28 | export default mitm;
29 |
--------------------------------------------------------------------------------
/esm/traps.js:
--------------------------------------------------------------------------------
1 | export * from 'proxy-target/traps';
2 | export const DESTRUCT = 'destruct';
3 | export const VALUE_OF = 'valueOf';
4 |
--------------------------------------------------------------------------------
/esm/types.js:
--------------------------------------------------------------------------------
1 | export * from 'proxy-target/types';
2 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "js-proxy",
3 | "version": "0.5.2",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "js-proxy",
9 | "version": "0.5.2",
10 | "license": "MIT",
11 | "dependencies": {
12 | "gc-hook": "^0.4.1",
13 | "proxy-target": "^3.0.2"
14 | },
15 | "devDependencies": {
16 | "ascjs": "^6.0.3",
17 | "c8": "^10.1.3"
18 | }
19 | },
20 | "node_modules/@babel/helper-string-parser": {
21 | "version": "7.25.9",
22 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
23 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
24 | "dev": true,
25 | "license": "MIT",
26 | "engines": {
27 | "node": ">=6.9.0"
28 | }
29 | },
30 | "node_modules/@babel/helper-validator-identifier": {
31 | "version": "7.25.9",
32 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
33 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
34 | "dev": true,
35 | "license": "MIT",
36 | "engines": {
37 | "node": ">=6.9.0"
38 | }
39 | },
40 | "node_modules/@babel/parser": {
41 | "version": "7.26.9",
42 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
43 | "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
44 | "dev": true,
45 | "license": "MIT",
46 | "dependencies": {
47 | "@babel/types": "^7.26.9"
48 | },
49 | "bin": {
50 | "parser": "bin/babel-parser.js"
51 | },
52 | "engines": {
53 | "node": ">=6.0.0"
54 | }
55 | },
56 | "node_modules/@babel/types": {
57 | "version": "7.26.9",
58 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
59 | "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
60 | "dev": true,
61 | "license": "MIT",
62 | "dependencies": {
63 | "@babel/helper-string-parser": "^7.25.9",
64 | "@babel/helper-validator-identifier": "^7.25.9"
65 | },
66 | "engines": {
67 | "node": ">=6.9.0"
68 | }
69 | },
70 | "node_modules/@bcoe/v8-coverage": {
71 | "version": "1.0.2",
72 | "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
73 | "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
74 | "dev": true,
75 | "license": "MIT",
76 | "engines": {
77 | "node": ">=18"
78 | }
79 | },
80 | "node_modules/@isaacs/cliui": {
81 | "version": "8.0.2",
82 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
83 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
84 | "dev": true,
85 | "license": "ISC",
86 | "dependencies": {
87 | "string-width": "^5.1.2",
88 | "string-width-cjs": "npm:string-width@^4.2.0",
89 | "strip-ansi": "^7.0.1",
90 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
91 | "wrap-ansi": "^8.1.0",
92 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
93 | },
94 | "engines": {
95 | "node": ">=12"
96 | }
97 | },
98 | "node_modules/@istanbuljs/schema": {
99 | "version": "0.1.3",
100 | "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
101 | "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
102 | "dev": true,
103 | "license": "MIT",
104 | "engines": {
105 | "node": ">=8"
106 | }
107 | },
108 | "node_modules/@jridgewell/resolve-uri": {
109 | "version": "3.1.2",
110 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
111 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
112 | "dev": true,
113 | "license": "MIT",
114 | "engines": {
115 | "node": ">=6.0.0"
116 | }
117 | },
118 | "node_modules/@jridgewell/sourcemap-codec": {
119 | "version": "1.5.0",
120 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
121 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
122 | "dev": true,
123 | "license": "MIT"
124 | },
125 | "node_modules/@jridgewell/trace-mapping": {
126 | "version": "0.3.25",
127 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
128 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
129 | "dev": true,
130 | "license": "MIT",
131 | "dependencies": {
132 | "@jridgewell/resolve-uri": "^3.1.0",
133 | "@jridgewell/sourcemap-codec": "^1.4.14"
134 | }
135 | },
136 | "node_modules/@pkgjs/parseargs": {
137 | "version": "0.11.0",
138 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
139 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
140 | "dev": true,
141 | "license": "MIT",
142 | "optional": true,
143 | "engines": {
144 | "node": ">=14"
145 | }
146 | },
147 | "node_modules/@types/istanbul-lib-coverage": {
148 | "version": "2.0.6",
149 | "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
150 | "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
151 | "dev": true,
152 | "license": "MIT"
153 | },
154 | "node_modules/ansi-regex": {
155 | "version": "6.1.0",
156 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
157 | "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
158 | "dev": true,
159 | "license": "MIT",
160 | "engines": {
161 | "node": ">=12"
162 | },
163 | "funding": {
164 | "url": "https://github.com/chalk/ansi-regex?sponsor=1"
165 | }
166 | },
167 | "node_modules/ansi-styles": {
168 | "version": "6.2.1",
169 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
170 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
171 | "dev": true,
172 | "license": "MIT",
173 | "engines": {
174 | "node": ">=12"
175 | },
176 | "funding": {
177 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
178 | }
179 | },
180 | "node_modules/ascjs": {
181 | "version": "6.0.3",
182 | "resolved": "https://registry.npmjs.org/ascjs/-/ascjs-6.0.3.tgz",
183 | "integrity": "sha512-lAIyi1j7oT0OtF9yFLiRf93LEcK7xTb/gPFwmfdi2T/BQmxJi1YcIES+VnP/kgGJkxq9Oh2DEK6GrZ6l2OVhVQ==",
184 | "dev": true,
185 | "license": "ISC",
186 | "dependencies": {
187 | "@babel/parser": "^7.12.5"
188 | },
189 | "bin": {
190 | "ascjs": "bin.js"
191 | }
192 | },
193 | "node_modules/balanced-match": {
194 | "version": "1.0.2",
195 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
196 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
197 | "dev": true,
198 | "license": "MIT"
199 | },
200 | "node_modules/brace-expansion": {
201 | "version": "2.0.1",
202 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
203 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
204 | "dev": true,
205 | "license": "MIT",
206 | "dependencies": {
207 | "balanced-match": "^1.0.0"
208 | }
209 | },
210 | "node_modules/c8": {
211 | "version": "10.1.3",
212 | "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz",
213 | "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==",
214 | "dev": true,
215 | "license": "ISC",
216 | "dependencies": {
217 | "@bcoe/v8-coverage": "^1.0.1",
218 | "@istanbuljs/schema": "^0.1.3",
219 | "find-up": "^5.0.0",
220 | "foreground-child": "^3.1.1",
221 | "istanbul-lib-coverage": "^3.2.0",
222 | "istanbul-lib-report": "^3.0.1",
223 | "istanbul-reports": "^3.1.6",
224 | "test-exclude": "^7.0.1",
225 | "v8-to-istanbul": "^9.0.0",
226 | "yargs": "^17.7.2",
227 | "yargs-parser": "^21.1.1"
228 | },
229 | "bin": {
230 | "c8": "bin/c8.js"
231 | },
232 | "engines": {
233 | "node": ">=18"
234 | },
235 | "peerDependencies": {
236 | "monocart-coverage-reports": "^2"
237 | },
238 | "peerDependenciesMeta": {
239 | "monocart-coverage-reports": {
240 | "optional": true
241 | }
242 | }
243 | },
244 | "node_modules/cliui": {
245 | "version": "8.0.1",
246 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
247 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
248 | "dev": true,
249 | "license": "ISC",
250 | "dependencies": {
251 | "string-width": "^4.2.0",
252 | "strip-ansi": "^6.0.1",
253 | "wrap-ansi": "^7.0.0"
254 | },
255 | "engines": {
256 | "node": ">=12"
257 | }
258 | },
259 | "node_modules/cliui/node_modules/ansi-regex": {
260 | "version": "5.0.1",
261 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
262 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
263 | "dev": true,
264 | "license": "MIT",
265 | "engines": {
266 | "node": ">=8"
267 | }
268 | },
269 | "node_modules/cliui/node_modules/ansi-styles": {
270 | "version": "4.3.0",
271 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
272 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
273 | "dev": true,
274 | "license": "MIT",
275 | "dependencies": {
276 | "color-convert": "^2.0.1"
277 | },
278 | "engines": {
279 | "node": ">=8"
280 | },
281 | "funding": {
282 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
283 | }
284 | },
285 | "node_modules/cliui/node_modules/emoji-regex": {
286 | "version": "8.0.0",
287 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
288 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
289 | "dev": true,
290 | "license": "MIT"
291 | },
292 | "node_modules/cliui/node_modules/string-width": {
293 | "version": "4.2.3",
294 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
295 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
296 | "dev": true,
297 | "license": "MIT",
298 | "dependencies": {
299 | "emoji-regex": "^8.0.0",
300 | "is-fullwidth-code-point": "^3.0.0",
301 | "strip-ansi": "^6.0.1"
302 | },
303 | "engines": {
304 | "node": ">=8"
305 | }
306 | },
307 | "node_modules/cliui/node_modules/strip-ansi": {
308 | "version": "6.0.1",
309 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
310 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
311 | "dev": true,
312 | "license": "MIT",
313 | "dependencies": {
314 | "ansi-regex": "^5.0.1"
315 | },
316 | "engines": {
317 | "node": ">=8"
318 | }
319 | },
320 | "node_modules/cliui/node_modules/wrap-ansi": {
321 | "version": "7.0.0",
322 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
323 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
324 | "dev": true,
325 | "license": "MIT",
326 | "dependencies": {
327 | "ansi-styles": "^4.0.0",
328 | "string-width": "^4.1.0",
329 | "strip-ansi": "^6.0.0"
330 | },
331 | "engines": {
332 | "node": ">=10"
333 | },
334 | "funding": {
335 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
336 | }
337 | },
338 | "node_modules/color-convert": {
339 | "version": "2.0.1",
340 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
341 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
342 | "dev": true,
343 | "license": "MIT",
344 | "dependencies": {
345 | "color-name": "~1.1.4"
346 | },
347 | "engines": {
348 | "node": ">=7.0.0"
349 | }
350 | },
351 | "node_modules/color-name": {
352 | "version": "1.1.4",
353 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
354 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
355 | "dev": true,
356 | "license": "MIT"
357 | },
358 | "node_modules/convert-source-map": {
359 | "version": "2.0.0",
360 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
361 | "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
362 | "dev": true,
363 | "license": "MIT"
364 | },
365 | "node_modules/cross-spawn": {
366 | "version": "7.0.6",
367 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
368 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
369 | "dev": true,
370 | "license": "MIT",
371 | "dependencies": {
372 | "path-key": "^3.1.0",
373 | "shebang-command": "^2.0.0",
374 | "which": "^2.0.1"
375 | },
376 | "engines": {
377 | "node": ">= 8"
378 | }
379 | },
380 | "node_modules/eastasianwidth": {
381 | "version": "0.2.0",
382 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
383 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
384 | "dev": true,
385 | "license": "MIT"
386 | },
387 | "node_modules/emoji-regex": {
388 | "version": "9.2.2",
389 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
390 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
391 | "dev": true,
392 | "license": "MIT"
393 | },
394 | "node_modules/escalade": {
395 | "version": "3.2.0",
396 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
397 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
398 | "dev": true,
399 | "license": "MIT",
400 | "engines": {
401 | "node": ">=6"
402 | }
403 | },
404 | "node_modules/find-up": {
405 | "version": "5.0.0",
406 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
407 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
408 | "dev": true,
409 | "license": "MIT",
410 | "dependencies": {
411 | "locate-path": "^6.0.0",
412 | "path-exists": "^4.0.0"
413 | },
414 | "engines": {
415 | "node": ">=10"
416 | },
417 | "funding": {
418 | "url": "https://github.com/sponsors/sindresorhus"
419 | }
420 | },
421 | "node_modules/foreground-child": {
422 | "version": "3.3.1",
423 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
424 | "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
425 | "dev": true,
426 | "license": "ISC",
427 | "dependencies": {
428 | "cross-spawn": "^7.0.6",
429 | "signal-exit": "^4.0.1"
430 | },
431 | "engines": {
432 | "node": ">=14"
433 | },
434 | "funding": {
435 | "url": "https://github.com/sponsors/isaacs"
436 | }
437 | },
438 | "node_modules/gc-hook": {
439 | "version": "0.4.1",
440 | "resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.4.1.tgz",
441 | "integrity": "sha512-uiF+uUftDVLr+VRdudsdsT3/LQYnv2ntwhRH964O7xXDI57Smrek5olv75Wb8Nnz6U+7iVTRXsBlxKcsaDTJTQ==",
442 | "license": "ISC"
443 | },
444 | "node_modules/get-caller-file": {
445 | "version": "2.0.5",
446 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
447 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
448 | "dev": true,
449 | "license": "ISC",
450 | "engines": {
451 | "node": "6.* || 8.* || >= 10.*"
452 | }
453 | },
454 | "node_modules/glob": {
455 | "version": "10.4.5",
456 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
457 | "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
458 | "dev": true,
459 | "license": "ISC",
460 | "dependencies": {
461 | "foreground-child": "^3.1.0",
462 | "jackspeak": "^3.1.2",
463 | "minimatch": "^9.0.4",
464 | "minipass": "^7.1.2",
465 | "package-json-from-dist": "^1.0.0",
466 | "path-scurry": "^1.11.1"
467 | },
468 | "bin": {
469 | "glob": "dist/esm/bin.mjs"
470 | },
471 | "funding": {
472 | "url": "https://github.com/sponsors/isaacs"
473 | }
474 | },
475 | "node_modules/has-flag": {
476 | "version": "4.0.0",
477 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
478 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
479 | "dev": true,
480 | "license": "MIT",
481 | "engines": {
482 | "node": ">=8"
483 | }
484 | },
485 | "node_modules/html-escaper": {
486 | "version": "2.0.2",
487 | "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
488 | "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
489 | "dev": true,
490 | "license": "MIT"
491 | },
492 | "node_modules/is-fullwidth-code-point": {
493 | "version": "3.0.0",
494 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
495 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
496 | "dev": true,
497 | "license": "MIT",
498 | "engines": {
499 | "node": ">=8"
500 | }
501 | },
502 | "node_modules/isexe": {
503 | "version": "2.0.0",
504 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
505 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
506 | "dev": true,
507 | "license": "ISC"
508 | },
509 | "node_modules/istanbul-lib-coverage": {
510 | "version": "3.2.2",
511 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
512 | "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
513 | "dev": true,
514 | "license": "BSD-3-Clause",
515 | "engines": {
516 | "node": ">=8"
517 | }
518 | },
519 | "node_modules/istanbul-lib-report": {
520 | "version": "3.0.1",
521 | "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
522 | "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
523 | "dev": true,
524 | "license": "BSD-3-Clause",
525 | "dependencies": {
526 | "istanbul-lib-coverage": "^3.0.0",
527 | "make-dir": "^4.0.0",
528 | "supports-color": "^7.1.0"
529 | },
530 | "engines": {
531 | "node": ">=10"
532 | }
533 | },
534 | "node_modules/istanbul-reports": {
535 | "version": "3.1.7",
536 | "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
537 | "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
538 | "dev": true,
539 | "license": "BSD-3-Clause",
540 | "dependencies": {
541 | "html-escaper": "^2.0.0",
542 | "istanbul-lib-report": "^3.0.0"
543 | },
544 | "engines": {
545 | "node": ">=8"
546 | }
547 | },
548 | "node_modules/jackspeak": {
549 | "version": "3.4.3",
550 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
551 | "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
552 | "dev": true,
553 | "license": "BlueOak-1.0.0",
554 | "dependencies": {
555 | "@isaacs/cliui": "^8.0.2"
556 | },
557 | "funding": {
558 | "url": "https://github.com/sponsors/isaacs"
559 | },
560 | "optionalDependencies": {
561 | "@pkgjs/parseargs": "^0.11.0"
562 | }
563 | },
564 | "node_modules/locate-path": {
565 | "version": "6.0.0",
566 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
567 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
568 | "dev": true,
569 | "license": "MIT",
570 | "dependencies": {
571 | "p-locate": "^5.0.0"
572 | },
573 | "engines": {
574 | "node": ">=10"
575 | },
576 | "funding": {
577 | "url": "https://github.com/sponsors/sindresorhus"
578 | }
579 | },
580 | "node_modules/lru-cache": {
581 | "version": "10.4.3",
582 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
583 | "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
584 | "dev": true,
585 | "license": "ISC"
586 | },
587 | "node_modules/make-dir": {
588 | "version": "4.0.0",
589 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
590 | "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
591 | "dev": true,
592 | "license": "MIT",
593 | "dependencies": {
594 | "semver": "^7.5.3"
595 | },
596 | "engines": {
597 | "node": ">=10"
598 | },
599 | "funding": {
600 | "url": "https://github.com/sponsors/sindresorhus"
601 | }
602 | },
603 | "node_modules/minimatch": {
604 | "version": "9.0.5",
605 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
606 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
607 | "dev": true,
608 | "license": "ISC",
609 | "dependencies": {
610 | "brace-expansion": "^2.0.1"
611 | },
612 | "engines": {
613 | "node": ">=16 || 14 >=14.17"
614 | },
615 | "funding": {
616 | "url": "https://github.com/sponsors/isaacs"
617 | }
618 | },
619 | "node_modules/minipass": {
620 | "version": "7.1.2",
621 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
622 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
623 | "dev": true,
624 | "license": "ISC",
625 | "engines": {
626 | "node": ">=16 || 14 >=14.17"
627 | }
628 | },
629 | "node_modules/p-limit": {
630 | "version": "3.1.0",
631 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
632 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
633 | "dev": true,
634 | "license": "MIT",
635 | "dependencies": {
636 | "yocto-queue": "^0.1.0"
637 | },
638 | "engines": {
639 | "node": ">=10"
640 | },
641 | "funding": {
642 | "url": "https://github.com/sponsors/sindresorhus"
643 | }
644 | },
645 | "node_modules/p-locate": {
646 | "version": "5.0.0",
647 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
648 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
649 | "dev": true,
650 | "license": "MIT",
651 | "dependencies": {
652 | "p-limit": "^3.0.2"
653 | },
654 | "engines": {
655 | "node": ">=10"
656 | },
657 | "funding": {
658 | "url": "https://github.com/sponsors/sindresorhus"
659 | }
660 | },
661 | "node_modules/package-json-from-dist": {
662 | "version": "1.0.1",
663 | "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
664 | "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
665 | "dev": true,
666 | "license": "BlueOak-1.0.0"
667 | },
668 | "node_modules/path-exists": {
669 | "version": "4.0.0",
670 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
671 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
672 | "dev": true,
673 | "license": "MIT",
674 | "engines": {
675 | "node": ">=8"
676 | }
677 | },
678 | "node_modules/path-key": {
679 | "version": "3.1.1",
680 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
681 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
682 | "dev": true,
683 | "license": "MIT",
684 | "engines": {
685 | "node": ">=8"
686 | }
687 | },
688 | "node_modules/path-scurry": {
689 | "version": "1.11.1",
690 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
691 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
692 | "dev": true,
693 | "license": "BlueOak-1.0.0",
694 | "dependencies": {
695 | "lru-cache": "^10.2.0",
696 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
697 | },
698 | "engines": {
699 | "node": ">=16 || 14 >=14.18"
700 | },
701 | "funding": {
702 | "url": "https://github.com/sponsors/isaacs"
703 | }
704 | },
705 | "node_modules/proxy-target": {
706 | "version": "3.0.2",
707 | "resolved": "https://registry.npmjs.org/proxy-target/-/proxy-target-3.0.2.tgz",
708 | "integrity": "sha512-FFE1XNwXX/FNC3/P8HiKaJSy/Qk68RitG/QEcLy/bVnTAPlgTAWPZKh0pARLAnpfXQPKyalBhk009NRTgsk8vQ==",
709 | "license": "MIT"
710 | },
711 | "node_modules/require-directory": {
712 | "version": "2.1.1",
713 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
714 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
715 | "dev": true,
716 | "license": "MIT",
717 | "engines": {
718 | "node": ">=0.10.0"
719 | }
720 | },
721 | "node_modules/semver": {
722 | "version": "7.7.1",
723 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
724 | "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
725 | "dev": true,
726 | "license": "ISC",
727 | "bin": {
728 | "semver": "bin/semver.js"
729 | },
730 | "engines": {
731 | "node": ">=10"
732 | }
733 | },
734 | "node_modules/shebang-command": {
735 | "version": "2.0.0",
736 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
737 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
738 | "dev": true,
739 | "license": "MIT",
740 | "dependencies": {
741 | "shebang-regex": "^3.0.0"
742 | },
743 | "engines": {
744 | "node": ">=8"
745 | }
746 | },
747 | "node_modules/shebang-regex": {
748 | "version": "3.0.0",
749 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
750 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
751 | "dev": true,
752 | "license": "MIT",
753 | "engines": {
754 | "node": ">=8"
755 | }
756 | },
757 | "node_modules/signal-exit": {
758 | "version": "4.1.0",
759 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
760 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
761 | "dev": true,
762 | "license": "ISC",
763 | "engines": {
764 | "node": ">=14"
765 | },
766 | "funding": {
767 | "url": "https://github.com/sponsors/isaacs"
768 | }
769 | },
770 | "node_modules/string-width": {
771 | "version": "5.1.2",
772 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
773 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
774 | "dev": true,
775 | "license": "MIT",
776 | "dependencies": {
777 | "eastasianwidth": "^0.2.0",
778 | "emoji-regex": "^9.2.2",
779 | "strip-ansi": "^7.0.1"
780 | },
781 | "engines": {
782 | "node": ">=12"
783 | },
784 | "funding": {
785 | "url": "https://github.com/sponsors/sindresorhus"
786 | }
787 | },
788 | "node_modules/string-width-cjs": {
789 | "name": "string-width",
790 | "version": "4.2.3",
791 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
792 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
793 | "dev": true,
794 | "license": "MIT",
795 | "dependencies": {
796 | "emoji-regex": "^8.0.0",
797 | "is-fullwidth-code-point": "^3.0.0",
798 | "strip-ansi": "^6.0.1"
799 | },
800 | "engines": {
801 | "node": ">=8"
802 | }
803 | },
804 | "node_modules/string-width-cjs/node_modules/ansi-regex": {
805 | "version": "5.0.1",
806 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
807 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
808 | "dev": true,
809 | "license": "MIT",
810 | "engines": {
811 | "node": ">=8"
812 | }
813 | },
814 | "node_modules/string-width-cjs/node_modules/emoji-regex": {
815 | "version": "8.0.0",
816 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
817 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
818 | "dev": true,
819 | "license": "MIT"
820 | },
821 | "node_modules/string-width-cjs/node_modules/strip-ansi": {
822 | "version": "6.0.1",
823 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
824 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
825 | "dev": true,
826 | "license": "MIT",
827 | "dependencies": {
828 | "ansi-regex": "^5.0.1"
829 | },
830 | "engines": {
831 | "node": ">=8"
832 | }
833 | },
834 | "node_modules/strip-ansi": {
835 | "version": "7.1.0",
836 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
837 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
838 | "dev": true,
839 | "license": "MIT",
840 | "dependencies": {
841 | "ansi-regex": "^6.0.1"
842 | },
843 | "engines": {
844 | "node": ">=12"
845 | },
846 | "funding": {
847 | "url": "https://github.com/chalk/strip-ansi?sponsor=1"
848 | }
849 | },
850 | "node_modules/strip-ansi-cjs": {
851 | "name": "strip-ansi",
852 | "version": "6.0.1",
853 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
854 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
855 | "dev": true,
856 | "license": "MIT",
857 | "dependencies": {
858 | "ansi-regex": "^5.0.1"
859 | },
860 | "engines": {
861 | "node": ">=8"
862 | }
863 | },
864 | "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
865 | "version": "5.0.1",
866 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
867 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
868 | "dev": true,
869 | "license": "MIT",
870 | "engines": {
871 | "node": ">=8"
872 | }
873 | },
874 | "node_modules/supports-color": {
875 | "version": "7.2.0",
876 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
877 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
878 | "dev": true,
879 | "license": "MIT",
880 | "dependencies": {
881 | "has-flag": "^4.0.0"
882 | },
883 | "engines": {
884 | "node": ">=8"
885 | }
886 | },
887 | "node_modules/test-exclude": {
888 | "version": "7.0.1",
889 | "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz",
890 | "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==",
891 | "dev": true,
892 | "license": "ISC",
893 | "dependencies": {
894 | "@istanbuljs/schema": "^0.1.2",
895 | "glob": "^10.4.1",
896 | "minimatch": "^9.0.4"
897 | },
898 | "engines": {
899 | "node": ">=18"
900 | }
901 | },
902 | "node_modules/v8-to-istanbul": {
903 | "version": "9.3.0",
904 | "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
905 | "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
906 | "dev": true,
907 | "license": "ISC",
908 | "dependencies": {
909 | "@jridgewell/trace-mapping": "^0.3.12",
910 | "@types/istanbul-lib-coverage": "^2.0.1",
911 | "convert-source-map": "^2.0.0"
912 | },
913 | "engines": {
914 | "node": ">=10.12.0"
915 | }
916 | },
917 | "node_modules/which": {
918 | "version": "2.0.2",
919 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
920 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
921 | "dev": true,
922 | "license": "ISC",
923 | "dependencies": {
924 | "isexe": "^2.0.0"
925 | },
926 | "bin": {
927 | "node-which": "bin/node-which"
928 | },
929 | "engines": {
930 | "node": ">= 8"
931 | }
932 | },
933 | "node_modules/wrap-ansi": {
934 | "version": "8.1.0",
935 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
936 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
937 | "dev": true,
938 | "license": "MIT",
939 | "dependencies": {
940 | "ansi-styles": "^6.1.0",
941 | "string-width": "^5.0.1",
942 | "strip-ansi": "^7.0.1"
943 | },
944 | "engines": {
945 | "node": ">=12"
946 | },
947 | "funding": {
948 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
949 | }
950 | },
951 | "node_modules/wrap-ansi-cjs": {
952 | "name": "wrap-ansi",
953 | "version": "7.0.0",
954 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
955 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
956 | "dev": true,
957 | "license": "MIT",
958 | "dependencies": {
959 | "ansi-styles": "^4.0.0",
960 | "string-width": "^4.1.0",
961 | "strip-ansi": "^6.0.0"
962 | },
963 | "engines": {
964 | "node": ">=10"
965 | },
966 | "funding": {
967 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
968 | }
969 | },
970 | "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
971 | "version": "5.0.1",
972 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
973 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
974 | "dev": true,
975 | "license": "MIT",
976 | "engines": {
977 | "node": ">=8"
978 | }
979 | },
980 | "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
981 | "version": "4.3.0",
982 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
983 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
984 | "dev": true,
985 | "license": "MIT",
986 | "dependencies": {
987 | "color-convert": "^2.0.1"
988 | },
989 | "engines": {
990 | "node": ">=8"
991 | },
992 | "funding": {
993 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
994 | }
995 | },
996 | "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
997 | "version": "8.0.0",
998 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
999 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1000 | "dev": true,
1001 | "license": "MIT"
1002 | },
1003 | "node_modules/wrap-ansi-cjs/node_modules/string-width": {
1004 | "version": "4.2.3",
1005 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1006 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1007 | "dev": true,
1008 | "license": "MIT",
1009 | "dependencies": {
1010 | "emoji-regex": "^8.0.0",
1011 | "is-fullwidth-code-point": "^3.0.0",
1012 | "strip-ansi": "^6.0.1"
1013 | },
1014 | "engines": {
1015 | "node": ">=8"
1016 | }
1017 | },
1018 | "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
1019 | "version": "6.0.1",
1020 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1021 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1022 | "dev": true,
1023 | "license": "MIT",
1024 | "dependencies": {
1025 | "ansi-regex": "^5.0.1"
1026 | },
1027 | "engines": {
1028 | "node": ">=8"
1029 | }
1030 | },
1031 | "node_modules/y18n": {
1032 | "version": "5.0.8",
1033 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
1034 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
1035 | "dev": true,
1036 | "license": "ISC",
1037 | "engines": {
1038 | "node": ">=10"
1039 | }
1040 | },
1041 | "node_modules/yargs": {
1042 | "version": "17.7.2",
1043 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
1044 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
1045 | "dev": true,
1046 | "license": "MIT",
1047 | "dependencies": {
1048 | "cliui": "^8.0.1",
1049 | "escalade": "^3.1.1",
1050 | "get-caller-file": "^2.0.5",
1051 | "require-directory": "^2.1.1",
1052 | "string-width": "^4.2.3",
1053 | "y18n": "^5.0.5",
1054 | "yargs-parser": "^21.1.1"
1055 | },
1056 | "engines": {
1057 | "node": ">=12"
1058 | }
1059 | },
1060 | "node_modules/yargs-parser": {
1061 | "version": "21.1.1",
1062 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
1063 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
1064 | "dev": true,
1065 | "license": "ISC",
1066 | "engines": {
1067 | "node": ">=12"
1068 | }
1069 | },
1070 | "node_modules/yargs/node_modules/ansi-regex": {
1071 | "version": "5.0.1",
1072 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
1073 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
1074 | "dev": true,
1075 | "license": "MIT",
1076 | "engines": {
1077 | "node": ">=8"
1078 | }
1079 | },
1080 | "node_modules/yargs/node_modules/emoji-regex": {
1081 | "version": "8.0.0",
1082 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
1083 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1084 | "dev": true,
1085 | "license": "MIT"
1086 | },
1087 | "node_modules/yargs/node_modules/string-width": {
1088 | "version": "4.2.3",
1089 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1090 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1091 | "dev": true,
1092 | "license": "MIT",
1093 | "dependencies": {
1094 | "emoji-regex": "^8.0.0",
1095 | "is-fullwidth-code-point": "^3.0.0",
1096 | "strip-ansi": "^6.0.1"
1097 | },
1098 | "engines": {
1099 | "node": ">=8"
1100 | }
1101 | },
1102 | "node_modules/yargs/node_modules/strip-ansi": {
1103 | "version": "6.0.1",
1104 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1105 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1106 | "dev": true,
1107 | "license": "MIT",
1108 | "dependencies": {
1109 | "ansi-regex": "^5.0.1"
1110 | },
1111 | "engines": {
1112 | "node": ">=8"
1113 | }
1114 | },
1115 | "node_modules/yocto-queue": {
1116 | "version": "0.1.0",
1117 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
1118 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
1119 | "dev": true,
1120 | "license": "MIT",
1121 | "engines": {
1122 | "node": ">=10"
1123 | },
1124 | "funding": {
1125 | "url": "https://github.com/sponsors/sindresorhus"
1126 | }
1127 | }
1128 | }
1129 | }
1130 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "js-proxy",
3 | "version": "0.5.2",
4 | "description": "The one-stop shop solution for JS Proxies and FFI APIs",
5 | "main": "./cjs/index.js",
6 | "scripts": {
7 | "build": "npm run cjs && npm run test",
8 | "cjs": "ascjs --no-default esm cjs",
9 | "test": "c8 node --expose-gc test/index.js",
10 | "coverage": "mkdir -p ./coverage; c8 report --reporter=text-lcov > ./coverage/lcov.info"
11 | },
12 | "keywords": [
13 | "proxy",
14 | "ffi",
15 | "gc",
16 | "destruct"
17 | ],
18 | "author": "Andrea Giammarchi",
19 | "license": "MIT",
20 | "devDependencies": {
21 | "ascjs": "^6.0.3",
22 | "c8": "^10.1.3"
23 | },
24 | "module": "./esm/index.js",
25 | "type": "module",
26 | "exports": {
27 | ".": {
28 | "import": "./esm/index.js",
29 | "default": "./cjs/index.js"
30 | },
31 | "./heap": {
32 | "import": "./esm/heap.js",
33 | "default": "./cjs/heap.js"
34 | },
35 | "./mitm": {
36 | "import": "./esm/mitm.js",
37 | "default": "./cjs/mitm.js"
38 | },
39 | "./traps": {
40 | "import": "./esm/traps.js",
41 | "default": "./cjs/traps.js"
42 | },
43 | "./types": {
44 | "import": "./esm/types.js",
45 | "default": "./cjs/types.js"
46 | },
47 | "./package.json": "./package.json"
48 | },
49 | "dependencies": {
50 | "gc-hook": "^0.4.1",
51 | "proxy-target": "^3.0.2"
52 | },
53 | "repository": {
54 | "type": "git",
55 | "url": "git+https://github.com/WebReflection/js-proxy.git"
56 | },
57 | "bugs": {
58 | "url": "https://github.com/WebReflection/js-proxy/issues"
59 | },
60 | "homepage": "https://github.com/WebReflection/js-proxy#readme"
61 | }
62 |
--------------------------------------------------------------------------------
/readme.js:
--------------------------------------------------------------------------------
1 | console.log('There we go');
2 |
--------------------------------------------------------------------------------
/test/heap.js:
--------------------------------------------------------------------------------
1 | import { clear, drop, get, hold } from '../esm/heap.js';
2 | import { assert, collect } from './utils.js';
3 |
4 | let o = {};
5 |
6 | let id = hold(o);
7 |
8 | assert(typeof id, 'number');
9 | assert(id, hold(o));
10 | assert(hold(o), hold(o));
11 | await collect();
12 | assert(get(id), o);
13 |
14 | o = null;
15 | await collect();
16 | assert(typeof get(id), 'object');
17 |
18 | assert(drop(id), true);
19 | assert(drop(id), false);
20 | await collect();
21 | assert(typeof get(id), 'undefined');
22 |
23 | o = {};
24 | assert(id !== hold(o), true);
25 | assert(drop(o), true);
26 | assert(drop(o), false);
27 | assert(drop(id), false);
28 |
29 | hold(o);
30 | clear();
31 | assert(drop(o), false);
32 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | import define from '../esm/index.js';
2 | import { assert, collect } from './utils.js';
3 | import './heap.js';
4 | import './mitm.js';
5 |
6 | // 🦄 typeOf coverage related
7 | let { proxy, release, pair, typeOf, valueOf } = define({
8 | // native cases
9 | array: {},
10 | function: {},
11 | object: {},
12 |
13 | // custom primitives
14 | bigint: {
15 | get(target, key, ..._) {
16 | return key === Symbol.toPrimitive ?
17 | () => target.valueOf() :
18 | Reflect.get(target, key, ..._);
19 | },
20 | },
21 | boolean: {},
22 | null: {},
23 | number: {},
24 | string: {},
25 | symbol: {},
26 | undefined: {},
27 |
28 | // custom direct/defined
29 | direct: {},
30 |
31 | // simply ignored ...
32 | valueOf: {},
33 | });
34 |
35 | // typeOf native cases
36 | assert(pair('a').join('-'), 'string-a');
37 | assert(pair(null).join('-'), 'null-');
38 | assert(pair(void 0).join('-'), 'undefined-');
39 | assert(typeOf([]), 'array');
40 | assert(typeOf(proxy.array(0)), 'array');
41 | assert(pair(proxy.array(0)).join('-'), 'array-0');
42 | assert(typeOf(()=>{}), 'function');
43 | assert(typeOf(proxy.function(0)), 'function');
44 | assert(pair(proxy.function(0)).join('-'), 'function-0');
45 | assert(typeOf({}), 'object');
46 | assert(typeOf(proxy.object(0)), 'object');
47 | assert(pair(proxy.object(0)).join('-'), 'object-0');
48 | assert(valueOf(proxy.object({})).toString(), '[object Object]');
49 |
50 | // typeOf extra primitives
51 | assert(typeOf(1n), 'bigint');
52 | assert(typeOf(proxy.bigint(0)), 'bigint');
53 | assert(typeOf(false), 'boolean');
54 | assert(typeOf(proxy.boolean(0)), 'boolean');
55 | assert(typeOf(null), 'null');
56 | assert(typeOf(proxy.null(0)), 'null');
57 | assert(typeOf(1), 'number');
58 | assert(typeOf(proxy.number(0)), 'number');
59 | assert(typeOf(''), 'string');
60 | assert(typeOf(proxy.string(0)), 'string');
61 | assert(typeOf(Symbol()), 'symbol');
62 | assert(typeOf(proxy.symbol(0)), 'symbol');
63 | assert(typeOf(), 'undefined');
64 | assert(typeOf(proxy.undefined(0)), 'undefined');
65 |
66 | // typeOf custom direct/defined
67 | assert(typeOf(proxy.direct({})), 'direct');
68 |
69 | assert(proxy.bigint(2n) == 2n, true, 'bigint');
70 | assert(proxy.bigint(2n) instanceof BigInt, true, 'bigint instanceof');
71 |
72 | // 🦄 define coverage related
73 | assert(proxy.array([1, 2, 3]).length, 3);
74 | assert(proxy.direct([1, 2, 3]).length, 3);
75 | assert(proxy.object({a: 1}).a, 1);
76 | assert(proxy.direct({a: 1}).a, 1);
77 | assert(proxy.function(() => 1)(), 1);
78 | assert(proxy.direct(() => 1)(), 1);
79 |
80 | let i = 0;
81 |
82 | const gcdo = Object(1);
83 | const gcdd = {b: 2};
84 |
85 | const hidden = Symbol('direct');
86 |
87 | ({ proxy, release, typeOf, valueOf } = define({
88 | array: {
89 | valueOf(i) {
90 | return i;
91 | }
92 | },
93 | function: {
94 | valueOf(i) {
95 | return i;
96 | }
97 | },
98 | object: {
99 | destruct(ref) {
100 | assert(ref, gcdo.valueOf());
101 | assert(ref, 1);
102 | i++;
103 | },
104 | valueOf(i) {
105 | return i;
106 | }
107 | },
108 | direct: {
109 | destruct(ref) {
110 | assert(ref, gcdd);
111 | i++;
112 | }
113 | },
114 | [hidden]: {
115 | destruct() {
116 | i++;
117 | },
118 | valueOf() {
119 | return 'anything-really';
120 | },
121 | },
122 | }));
123 |
124 | let pgcdo = proxy.object(gcdo.valueOf(), gcdo);
125 | let pgcdd = proxy.direct(gcdd);
126 |
127 | await collect();
128 | assert(valueOf(proxy.array(3)), 3);
129 | assert(valueOf(proxy.function(2)), 2);
130 | assert(valueOf(pgcdo), 1);
131 | assert(!!pgcdo, true);
132 | assert(!!pgcdd, true);
133 | pgcdo = pgcdd = null;
134 | await collect();
135 | assert(i, 2);
136 | pgcdo = proxy.object(gcdo.valueOf(), gcdo);
137 | pgcdd = proxy.direct(gcdd);
138 | await collect();
139 | release(gcdo);
140 | release(gcdd);
141 | await collect();
142 | assert(i, 2);
143 | let h = proxy[hidden]({});
144 | assert(h.valueOf(), h);
145 | assert(valueOf(h), 'anything-really');
146 | h = null;
147 | await collect();
148 | assert(i, 3);
149 | proxy.object(null);
150 | proxy.object(void 0);
151 | console.log('OK');
152 |
--------------------------------------------------------------------------------
/test/mitm.js:
--------------------------------------------------------------------------------
1 | import { assert } from './utils.js';
2 | import mitm from '../esm/mitm.js';
3 |
4 | const calls = [];
5 |
6 | const handler = {
7 | test: Math.random(),
8 | get(__proto__, name, target) {
9 | calls.push(name);
10 | if (name === 'test')
11 | return this.test;
12 | return Reflect.get(__proto__, name, target);
13 | }
14 | };
15 |
16 | let object = mitm({own: 'OK'}, handler);
17 | assert(object, mitm(object, handler));
18 | calls.splice(0);
19 |
20 | assert(object.own, 'OK');
21 | assert(calls.length, 0);
22 |
23 | assert(object.test, handler.test);
24 | assert(calls.length, 1);
25 | assert(calls.splice(0).join(','), 'test');
26 |
27 | object = mitm(object, {
28 | get(__proto__, name, target) {
29 | calls.push(name);
30 | if (name === 'extra')
31 | return 123;
32 | return Reflect.get(__proto__, name, target);
33 | }
34 | });
35 |
36 | assert(object.extra, 123);
37 | assert(calls.length, 1);
38 | assert(calls.splice(0).join(','), 'extra');
39 |
40 | assert(object.test, handler.test);
41 | assert(calls.length, 2);
42 | assert(calls.splice(0).join(','), 'test,test');
43 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | import define from '../esm/index.js';
2 |
3 |
4 | const { proxy, release } = define({
5 | object: {
6 | destruct(ref) {
7 | // {_ref: 123} in case No.1
8 | // 456 in case No.2
9 | console.log(ref, 'proxy is gone');
10 | },
11 | },
12 | });
13 |
14 | // case No.1
15 | const trapped1 = {_ref: 123};
16 | let proxied1 = proxy.object(trapped1);
17 | //setTimeout(release, 500, trapped1);
18 |
19 | // case No.2
20 | const trapped2 = 456;
21 | const token2 = Object(456);
22 | let proxied2 = proxy.object(trapped2, token2);
23 | //setTimeout(release, 500, token2);
24 |
25 | setTimeout(gc, 1000);
26 |
--------------------------------------------------------------------------------
/test/utils.js:
--------------------------------------------------------------------------------
1 | export const assert = (current, expected, message = `expected ${expected} - got ${current}`) => {
2 | if (!Object.is(current, expected))
3 | throw new Error(message);
4 | };
5 |
6 | export const collect = () => {
7 | gc();
8 | return new Promise(resolve => {
9 | setTimeout(() => {
10 | gc();
11 | resolve();
12 | }, 100);
13 | });
14 | };
15 |
--------------------------------------------------------------------------------