quickjs-emscripten-sync 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +303 -0
  3. package/dist/index.d.ts +129 -29
  4. package/dist/quickjs-emscripten-sync.es.js +951 -0
  5. package/dist/quickjs-emscripten-sync.umd.js +64 -0
  6. package/package.json +28 -40
  7. package/src/default.ts +6 -2
  8. package/src/index.test.ts +266 -51
  9. package/src/index.ts +123 -66
  10. package/src/marshal/function.test.ts +11 -10
  11. package/src/marshal/function.ts +3 -3
  12. package/src/marshal/index.test.ts +75 -10
  13. package/src/marshal/index.ts +28 -14
  14. package/src/marshal/json.test.ts +94 -0
  15. package/src/marshal/json.ts +15 -0
  16. package/src/marshal/object.test.ts +49 -6
  17. package/src/marshal/object.ts +2 -2
  18. package/src/marshal/primitive.test.ts +2 -0
  19. package/src/marshal/primitive.ts +8 -2
  20. package/src/marshal/promise.test.ts +86 -0
  21. package/src/marshal/promise.ts +26 -0
  22. package/src/marshal/properties.test.ts +7 -5
  23. package/src/marshal/properties.ts +2 -2
  24. package/src/marshal/symbol.test.ts +3 -1
  25. package/src/unmarshal/function.test.ts +28 -21
  26. package/src/unmarshal/function.ts +31 -23
  27. package/src/unmarshal/index.test.ts +86 -86
  28. package/src/unmarshal/index.ts +5 -4
  29. package/src/unmarshal/object.test.ts +36 -8
  30. package/src/unmarshal/object.ts +8 -4
  31. package/src/unmarshal/primitive.test.ts +2 -0
  32. package/src/unmarshal/primitive.ts +1 -2
  33. package/src/unmarshal/promise.test.ts +44 -0
  34. package/src/unmarshal/promise.ts +40 -0
  35. package/src/unmarshal/properties.test.ts +4 -2
  36. package/src/unmarshal/properties.ts +11 -9
  37. package/src/unmarshal/symbol.test.ts +3 -1
  38. package/src/util.test.ts +22 -5
  39. package/src/util.ts +15 -0
  40. package/src/vmmap.test.ts +22 -0
  41. package/src/vmmap.ts +6 -2
  42. package/src/vmutil.test.ts +116 -8
  43. package/src/vmutil.ts +76 -8
  44. package/src/wrapper.test.ts +44 -31
  45. package/src/wrapper.ts +47 -30
  46. package/dist/default.d.ts +0 -4
  47. package/dist/index.js +0 -8
  48. package/dist/marshal/array.d.ts +0 -2
  49. package/dist/marshal/function.d.ts +0 -2
  50. package/dist/marshal/index.d.ts +0 -11
  51. package/dist/marshal/object.d.ts +0 -2
  52. package/dist/marshal/primitive.d.ts +0 -2
  53. package/dist/marshal/properties.d.ts +0 -2
  54. package/dist/marshal/symbol.d.ts +0 -2
  55. package/dist/quickjs-emscripten-sync.cjs.development.js +0 -1302
  56. package/dist/quickjs-emscripten-sync.cjs.development.js.map +0 -1
  57. package/dist/quickjs-emscripten-sync.cjs.production.min.js +0 -2
  58. package/dist/quickjs-emscripten-sync.cjs.production.min.js.map +0 -1
  59. package/dist/quickjs-emscripten-sync.esm.js +0 -1285
  60. package/dist/quickjs-emscripten-sync.esm.js.map +0 -1
  61. package/dist/unmarshal/array.d.ts +0 -2
  62. package/dist/unmarshal/function.d.ts +0 -2
  63. package/dist/unmarshal/index.d.ts +0 -9
  64. package/dist/unmarshal/object.d.ts +0 -2
  65. package/dist/unmarshal/primitive.d.ts +0 -2
  66. package/dist/unmarshal/properties.d.ts +0 -2
  67. package/dist/unmarshal/symbol.d.ts +0 -2
  68. package/dist/util.d.ts +0 -7
  69. package/dist/vmmap.d.ts +0 -35
  70. package/dist/vmutil.d.ts +0 -7
  71. package/dist/wrapper.d.ts +0 -11
  72. package/src/marshal/array.test.ts +0 -40
  73. package/src/marshal/array.ts +0 -24
  74. package/src/unmarshal/array.test.ts +0 -45
  75. package/src/unmarshal/array.ts +0 -32
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 rot1024
3
+ Copyright (c) 2022 rot1024
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # quickjs-emscripten-sync
2
+
3
+ [![CI](https://github.com/reearth/quickjs-emscripten-sync/actions/workflows/ci.yml/badge.svg)](https://github.com/reearth/quickjs-emscripten-sync/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/reearth/quickjs-emscripten-sync/branch/main/graph/badge.svg)](https://codecov.io/gh/reearth/quickjs-emscripten-sync)
4
+
5
+ Build a secure plugin system in web browsers
6
+
7
+ This library wraps [quickjs-emscripten](https://github.com/justjake/quickjs-emscripten) and provides a way to sync object state between the browser and sandboxed QuickJS.
8
+
9
+ - Exchange and sync values between the browser (host) and QuickJS seamlessly
10
+ - Primitives (number, boolean, string, symbol)
11
+ - Arrays
12
+ - Functions
13
+ - Classes and instances
14
+ - Objects with prototypes and any property descriptors
15
+ - Expose objects as a global object in QuickJS
16
+ - Marshaling limitation for specific objects
17
+ - Register a pair of objects that will be considered the same between the browser and QuickJS
18
+
19
+ ```
20
+ npm install quickjs-emscripten quickjs-emscripten-sync
21
+ ```
22
+
23
+ ```js
24
+ import { getQuickJS } from "quickjs-emscripten";
25
+ import { Arena } from "quickjs-emscripten-sync";
26
+
27
+ class Cls {
28
+ field = 0;
29
+
30
+ method() {
31
+ return ++this.field;
32
+ }
33
+ }
34
+
35
+ const vm = (await getQuickJS()).createVm();
36
+ const arena = new Arena(vm, { isMarshalable: true });
37
+
38
+ // We can pass objects to the VM and run code safely
39
+ const exposed = {
40
+ Cls,
41
+ cls: new Cls(),
42
+ syncedCls: arena.sync(new Cls()),
43
+ };
44
+ arena.expose(exposed);
45
+
46
+ arena.evalCode(`cls instanceof Cls`); // returns true
47
+ arena.evalCode(`cls.field`); // returns 0
48
+ arena.evalCode(`cls.method()`); // returns 1
49
+ arena.evalCode(`cls.field`); // returns 1
50
+
51
+ arena.evalCode(`syncedCls.field`); // returns 0
52
+ exposed.syncedCls.method(); // returns 1
53
+ arena.evalCode(`syncedCls.field`); // returns 1
54
+
55
+ arena.dispose();
56
+ vm.dispose();
57
+ ```
58
+
59
+ [Example code](src/index.test.ts) is available as the unit test code.
60
+
61
+ ## Operating Environment
62
+
63
+ - Web browsers that support WebAssembly
64
+ - Node.js
65
+
66
+ If you want to run quickjs-emscripten and quickjs-emscripten-sync in a web browser, they have to be bundled with a bundler tool such as webpack, because quickjs-emscripten is now written in CommonJS format and web browsers cannot load it directly.
67
+
68
+ ## Usage
69
+
70
+ ```js
71
+ import { getQuickJS } from "quickjs-emscripten";
72
+ import { Arena } from "quickjs-emscripten-sync";
73
+
74
+ (async function() {
75
+ const quickjs = await getQuickJS();
76
+ const vm = quickjs.createVm();
77
+
78
+ // init Arena
79
+ // ⚠️ Marshaling is opt-in for security reasons.
80
+ // ⚠️ Be careful when activating marshalling.
81
+ const arena = new Arena(vm, { isMarshalable: true });
82
+
83
+ // expose objects as global objects in QuickJS VM
84
+ arena.expose({
85
+ console: {
86
+ log: console.log
87
+ }
88
+ });
89
+ arena.evalCode(`console.log("hello, world");`); // run console.log
90
+ arena.evalCode(`1 + 1`); // 2
91
+
92
+ // expose objects but also enable sync
93
+ const data = arena.sync({ hoge: "foo" });
94
+ arena.expose({ data });
95
+
96
+ arena.evalCode(`data.hoge = "bar"`);
97
+ // eval code and operations to exposed objects are automatically synced
98
+ console.log(data.hoge); // "bar"
99
+ data.hoge = "changed!";
100
+ console.log(arena.evalCode(`data.hoge`)); // "changed!"
101
+
102
+ // Don't forget calling arena.dispose() before disposing QuickJS VM!
103
+ arena.dispose();
104
+ vm.dispose();
105
+ })();
106
+ ```
107
+
108
+ ## Marshaling Limitations
109
+
110
+ Objects are automatically converted when they cross between the host and the QuickJS VM. The conversion of a host's object to a VM handle is called marshaling, and the conversion of a VM handle to a host's object is called unmarshaling.
111
+
112
+ And for marshalling, it is possible to control whether the conversion is performed or not.
113
+
114
+ For example, exposing the host's global object to QuickJS is very heavy and dangerous. This exposure can be limited and controlled with the `isMarshalable` option. If `false` is returned, just `undefined` is passed to QuickJS.
115
+
116
+ ```js
117
+ import { Arena, complexity } from "quickjs-emscripten-sync";
118
+
119
+ const arena = new Arena(vm, {
120
+ isMarshalable: (target: any) => {
121
+ // prevent passing globalThis to QuickJS
122
+ if (target === window) return false;
123
+ // complexity is a helper function to detect whether the object is heavy
124
+ if (complexity(target, 30) >= 30) return false;
125
+ return true; // other objects are OK
126
+ }
127
+ });
128
+
129
+ arena.evalCode(`a => a === undefined`)({}); // false
130
+ arena.evalCode(`a => a === undefined`)(window); // true
131
+ arena.evalCode(`a => a === undefined`)(document); // true
132
+ ```
133
+
134
+ The `complexity` function is useful to detect whether the object is too heavy to be passed to QuickJS.
135
+
136
+ ## Security Warning
137
+
138
+ QuickJS has an environment isolated from the browser, so any code can be executed safely, but there are edge cases where some exposed objects by quickjs-emscripten-sync may break security.
139
+
140
+ quickjs-emscripten-sync cannot prevent such dangerous case, so **PLEASE be very careful and deliberate about what you expose to QuickJS!**
141
+
142
+ ### Case 1: Prototype pollution
143
+
144
+ ```js
145
+ import { set } from "lodash-es";
146
+
147
+ arena.expose({
148
+ danger: (keys, value) => {
149
+ // This function may cause prototype pollution in the browser by QuickJS
150
+ set({}, keys, value)
151
+ }
152
+ });
153
+
154
+ arena.evalCode(`danger("__proto__.a", () => { /* injected */ })`);
155
+ ```
156
+
157
+ ### Case 2: Unintended HTTP request
158
+
159
+ It is very dangerous to expose or use directly or indirectly the `window` object, `localStorage`, `fetch`, `XMLHttpRequest` ...
160
+
161
+ This is because it enables the execution of unintended code such as XSS attacks, such as reading local storage, sending unintended HTTP requests, and manipulating DOM objects.
162
+
163
+ ```js
164
+ arena.expose({
165
+ // This function may cause unintended HTTP requests
166
+ danger: (url, body) => {
167
+ fetch(url, {
168
+ method: "POST",
169
+ headers: {
170
+ "Content-Type": "application/json"
171
+ },
172
+ body: JSON.stringify(body)
173
+ });
174
+ }
175
+ });
176
+
177
+ arena.evalCode(`danger("/api", { dangerous: true })`);
178
+ ```
179
+
180
+ By default, quickjs-emscripten-sync doesn't prevent any marshaling, even in such cases. And there are many built-in objects in the host, so please note that it's hard to prevent all dangerous cases with the `isMarshalable` option alone.
181
+
182
+ ## API
183
+
184
+ ### `Arena`
185
+
186
+ The Arena class manages all generated handles at once by quickjs-emscripten and automatically converts objects between the host and the QuickJS VM.
187
+
188
+ #### `new Arena(vm: QuickJSVm, options?: Options)`
189
+
190
+ Constructs a new Arena instance. It requires a quickjs-emscripten VM initialized with `quickjs.createVM()`.
191
+
192
+ Options accepted:
193
+
194
+ ```ts
195
+ type Options = {
196
+ isMarshalable?: boolean | "json" | ((target: any) => boolean | "json");
197
+ registeredObjects?: Iterable<[any, QuickJSHandle | string]>;
198
+ }
199
+ ```
200
+
201
+ - **`isMarshalable`**: Determines how marshalling will be done when sending objects from the host to the VM. **Make sure to set the marshalling to be the minimum necessary as it may reduce the security of your application.** [Please read the section on security above.](#security-warning)
202
+ - `"json"` (**default**, safety): Target object will be serialized as JSON in host and then parsed in VM. Functions and classes will be lost in the process.
203
+ - `false` (safety): Target object will not be always marshalled as `undefined`.
204
+ - `(target: any) => boolean | "json"` (recoomended): You can control marshalling mode for each objects. If you want to do marshalling, usually use this method. Allow partial marshalling by returning `true` only for some objects.
205
+ - `true` (**risky and not recommended**): Target object will be always marshaled. This setting may reduce security.
206
+ - **`registeredObjects`**: You can pre-register a pair of objects that will be considered the same between the host and the QuickJS VM. This will be used automatically during the conversion. By default, it will be registered automatically with [`defaultRegisteredObjects`](src/default.ts). If you want to add a new pair to this, please do the following:
207
+
208
+ ```js
209
+ import { defaultRegisteredObjects } from "quickjs-emscripten-sync";
210
+
211
+ const arena = new Arena(vm, {
212
+ registeredObjects: [
213
+ ...defaultRegisteredObjects,
214
+ [Math, "Math"]
215
+ ]
216
+ });
217
+ ```
218
+
219
+ Instead of a string, you can also pass a QuickJSHandle directly. In that case, however, you have to dispose of them manually when destroying the VM.
220
+
221
+ #### `dispose()`
222
+
223
+ Dispose of the arena and managed handles. This method won't dispose the VM itself, so the VM has to be disposed of manually.
224
+
225
+ #### `evalCode<T = any>(code: string): T | undefined`
226
+
227
+ Evaluate JS code in the VM and get the result as an object on the host side. It also converts and re-throws error objects when an error is thrown during evaluation.
228
+
229
+ #### `executePendingJobs(): number`
230
+
231
+ Almost same as `vm.executePendingJobs()`, but it converts and re-throws error objects when an error is thrown during evaluation.
232
+
233
+ #### `expose(obj: { [k: string]: any })`
234
+
235
+ Expose objects as global objects in the VM.
236
+
237
+ By default, exposed objects are not synchronized between the host and the VM.
238
+ If you want to sync an objects, first wrap the object with `sync` method, and then expose the wrapped object.
239
+
240
+ #### `sync<T>(target: T): T`
241
+
242
+ Enables sync for the object between the host and the VM and returns objects wrapped with proxies.
243
+
244
+ The return value is necessary in order to reflect changes to the object from the host to the VM. Please note that setting a value in the field or deleting a field in the original object will not synchronize it.
245
+
246
+ #### `register(target: any, code: string | QuickJSHandle)`
247
+
248
+ Register a pair of objects that will be considered the same between the host and the QuickJS VM.
249
+
250
+ #### `unregisterAll(targets: Iterable<[any, string | QuickJSHandle]>)`
251
+
252
+ Execute `register` methods for each pair.
253
+
254
+ #### `unregister(target: any)`
255
+
256
+ Unregister a pair of objects that were registered with `registeredObjects` option and `register` method.
257
+
258
+ #### `unregisterAll(targets: Iterable<any>)`
259
+
260
+ Execute `unregister` methods for each target.
261
+
262
+ ### `defaultRegisteredObjects: [any, string][]`
263
+
264
+ Default value of registeredObjects option of the Arena class constructor.
265
+
266
+ ### `complexity(target: any, max?: number): number`
267
+
268
+ Measure the complexity of an object as you traverse the field and prototype chain. If max is specified, when the complexity reaches max, the traversal is terminated and it returns the max. In this function, one object and function are counted as a complexity of 1, and primitives are not counted as a complexity.
269
+
270
+ ## Advanced
271
+
272
+ ### How to work
273
+
274
+ quickjs-emscripten can execute JS code safely, but it requires to deal with a lot of handles and lifetimes. Also, when destroying the VM, any un-destroyed handle will result in an error.
275
+
276
+ quickjs-emscripten-sync will automatically manage all handles once generated by QuickJS VM in an Arena class.
277
+ And it will automatically "marshal" objects as handles and "unmarshal" handles as objects to enable seamless data exchange between the browser and QuickJS. It recursively traverses the object properties and prototype chain to transform objects. A function is called after its arguments and this arg are automatically converted for the environment in which the function is defined. The return value will be automatically converted to match the environment of the caller.
278
+ Most objects are wrapped by proxies during conversion, allowing "set" and "delete" operations on objects to be synchronized between the browser and QuickJS.
279
+
280
+ ### Limitations
281
+
282
+ #### Class constructor
283
+
284
+ When initializing a new instance, it is not possible to fully proxy this arg (a.k.a. `new.target`) inside the class constructor. Therefore, after the constructor call, the fields set for this are re-set to this on the VM side. Therefore, there may be some edge cases where the constructor may not work properly.
285
+
286
+ ```js
287
+ class Cls {
288
+ constructor() {
289
+ this.hoge = "foo";
290
+ }
291
+ }
292
+
293
+ arena.expose({ Cls });
294
+ arena.evalCode(`new Cls()`); // Cls { hoge: "foo" }
295
+ ```
296
+
297
+ #### Operation synchronization
298
+
299
+ For now, only the `set` and `deleteProperty` operations on objects are subject to synchronization. The result of `Object.defineProperty` on a proxied object will not be synchronized to the other side.
300
+
301
+ ## License
302
+
303
+ [MIT License](LICENSE)
package/dist/index.d.ts CHANGED
@@ -1,26 +1,13 @@
1
- import { QuickJSHandle, QuickJSVm } from "quickjs-emscripten";
2
- import { SuccessOrFail, VmCallResult } from "quickjs-emscripten/dist/vm-interface";
3
- import VMMap from "./vmmap";
4
- import marshal from "./marshal";
5
- import unmarshal from "./unmarshal";
6
- import { Wrapped } from "./wrapper";
7
- import { complexity, isES2015Class, isObject, walkObject } from "./util";
8
- import { call, eq, isHandleObject, send, consumeAll } from "./vmutil";
9
- import { defaultRegisteredObjects } from "./default";
10
- export { Arena, VMMap, defaultRegisteredObjects, marshal, unmarshal, complexity, isES2015Class, isObject, walkObject, call, eq, isHandleObject, send, consumeAll, };
11
- export declare type Options = {
12
- /** A callback that returns a boolean value that determines whether an object is marshalled or not. If false, no marshaling will be done and undefined will be passed to the QuickJS VM, otherwise marshaling will be done. By default, all objects will be marshalled. */
13
- isMarshalable?: (target: any) => boolean;
14
- /** You can pre-register a pair of objects that will be considered the same between the browser and the QuickJS VM. This will be used automatically during the conversion. By default, it will be registered automatically with `defaultRegisteredObjects`.
15
- *
16
- * Instead of a string, you can also pass a QuickJSHandle directly. In that case, however, you have to dispose of them manually when destroying the VM.
17
- */
18
- registeredObjects?: Iterable<[any, QuickJSHandle | string]>;
19
- };
1
+ import type { QuickJSDeferredPromise } from 'quickjs-emscripten';
2
+ import { QuickJSHandle } from 'quickjs-emscripten';
3
+ import { QuickJSVm } from 'quickjs-emscripten';
4
+ import type { SuccessOrFail } from 'quickjs-emscripten/dist/vm-interface';
5
+ import type { VmCallResult } from 'quickjs-emscripten/dist/vm-interface';
6
+
20
7
  /**
21
- * The Arena class manages all generated handles at once by quickjs-emscripten and automatically converts objects between browser and QuickJS.
8
+ * The Arena class manages all generated handles at once by quickjs-emscripten and automatically converts objects between the host and the QuickJS VM.
22
9
  */
23
- export default class Arena {
10
+ export declare class Arena {
24
11
  vm: QuickJSVm;
25
12
  _map: VMMap;
26
13
  _registeredMap: VMMap;
@@ -37,7 +24,7 @@ export default class Arena {
37
24
  */
38
25
  dispose(): void;
39
26
  /**
40
- * Evaluate JS code in the VM and get the result as an object on the browser side. It also converts and re-throws error objects when an error is thrown during evaluation.
27
+ * Evaluate JS code in the VM and get the result as an object on the host side. It also converts and re-throws error objects when an error is thrown during evaluation.
41
28
  */
42
29
  evalCode<T = any>(code: string): T;
43
30
  /**
@@ -47,13 +34,20 @@ export default class Arena {
47
34
  /**
48
35
  * Expose objects as global objects in the VM.
49
36
  *
50
- * If sync is true, this function returns objects wrapped with proxies. This is necessary in order to reflect changes to the object from the browser side to the VM side. Please note that setting a value in the field or deleting a field in the original object will not synchronize it.
37
+ * By default, exposed objects are not synchronized between the host and the VM.
38
+ * If you want to sync an objects, first wrap the object with sync method, and then expose the wrapped object.
51
39
  */
52
- expose<T extends {
40
+ expose(obj: {
53
41
  [k: string]: any;
54
- }>(obj: T, sync?: boolean): T;
42
+ }): void;
55
43
  /**
56
- * Register a pair of objects that will be considered the same between the browser and the QuickJS VM.
44
+ * Enables sync for the object between the host and the VM and returns objects wrapped with proxies.
45
+ *
46
+ * The return value is necessary in order to reflect changes to the object from the host to the VM. Please note that setting a value in the field or deleting a field in the original object will not synchronize it.
47
+ */
48
+ sync<T>(target: T): T;
49
+ /**
50
+ * Register a pair of objects that will be considered the same between the host and the QuickJS VM.
57
51
  *
58
52
  * Instead of a string, you can also pass a QuickJSHandle directly. In that case, however, when you have to dispose them manually when destroying the VM.
59
53
  */
@@ -74,12 +68,118 @@ export default class Arena {
74
68
  endSync(target: any): void;
75
69
  _unwrapResult<T>(result: SuccessOrFail<T, QuickJSHandle>): T;
76
70
  _unwrapResultAndUnmarshal(result: VmCallResult<QuickJSHandle> | undefined): any;
77
- _marshal(target: any): QuickJSHandle;
78
- _unmarshal(handle: QuickJSHandle): any;
71
+ _isMarshalable: (t: unknown) => boolean | "json";
72
+ _marshalFind: (t: unknown) => QuickJSHandle | undefined;
73
+ _marshalPre: (t: unknown, h: QuickJSHandle | QuickJSDeferredPromise, mode: true | "json" | undefined) => Wrapped<QuickJSHandle> | undefined;
74
+ _marshalPreApply: (target: Function, that: unknown, args: unknown[]) => void;
75
+ _marshal: (target: any) => [QuickJSHandle, boolean];
76
+ _preUnmarshal: (t: any, h: QuickJSHandle) => Wrapped<any>;
77
+ _unmarshalFind: (h: QuickJSHandle) => unknown;
78
+ _unmarshal: (handle: QuickJSHandle) => any;
79
79
  _register(t: any, h: QuickJSHandle, map?: VMMap, sync?: boolean): [Wrapped<any>, Wrapped<QuickJSHandle>] | undefined;
80
- _syncMode(obj: any): "both" | undefined;
80
+ _syncMode: (obj: any) => "both" | undefined;
81
81
  _wrap<T>(target: T): Wrapped<T> | undefined;
82
82
  _unwrap<T>(target: T): T;
83
+ _unwrapIfNotSynced: <T>(target: T) => T;
83
84
  _wrapHandle(handle: QuickJSHandle): [Wrapped<QuickJSHandle> | undefined, boolean];
84
85
  _unwrapHandle(target: QuickJSHandle): [QuickJSHandle, boolean];
85
86
  }
87
+
88
+ export declare function call(vm: QuickJSVm, code: string, thisArg?: QuickJSHandle, ...args: QuickJSHandle[]): QuickJSHandle;
89
+
90
+ /**
91
+ * Measure the complexity of an object as you traverse the field and prototype chain. If max is specified, when the complexity reaches max, the traversal is terminated and it returns the max. In this function, one object and function are counted as a complexity of 1, and primitives are not counted as a complexity.
92
+ */
93
+ export declare function complexity(value: any, max?: number): number;
94
+
95
+ export declare function consumeAll<T extends QuickJSHandle[], K>(handles: T, cb: (handles: T) => K): K;
96
+
97
+ /**
98
+ * Default value of registeredObjects option of the Arena class constructor.
99
+ */
100
+ export declare const defaultRegisteredObjects: [any, string][];
101
+
102
+ export declare function eq(vm: QuickJSVm, a: QuickJSHandle, b: QuickJSHandle): boolean;
103
+
104
+ export declare function isES2015Class(cls: any): cls is new (...args: any[]) => any;
105
+
106
+ export declare function isHandleObject(vm: QuickJSVm, a: QuickJSHandle): boolean;
107
+
108
+ export declare function isObject(value: any): value is object | Function;
109
+
110
+ export declare function json(vm: QuickJSVm, target: any): QuickJSHandle;
111
+
112
+ export declare function marshal(target: unknown, options: Options_2): QuickJSHandle;
113
+
114
+ export declare type Options = {
115
+ /** A callback that returns a boolean value that determines whether an object is marshalled or not. If false, no marshaling will be done and undefined will be passed to the QuickJS VM, otherwise marshaling will be done. By default, all objects will be marshalled. */
116
+ isMarshalable?: boolean | "json" | ((target: any) => boolean | "json");
117
+ /** You can pre-register a pair of objects that will be considered the same between the host and the QuickJS VM. This will be used automatically during the conversion. By default, it will be registered automatically with `defaultRegisteredObjects`.
118
+ *
119
+ * Instead of a string, you can also pass a QuickJSHandle directly. In that case, however, you have to dispose of them manually when destroying the VM.
120
+ */
121
+ registeredObjects?: Iterable<[any, QuickJSHandle | string]>;
122
+ };
123
+
124
+ declare type Options_2 = {
125
+ vm: QuickJSVm;
126
+ unmarshal: (handle: QuickJSHandle) => unknown;
127
+ isMarshalable?: (target: unknown) => boolean | "json";
128
+ find: (target: unknown) => QuickJSHandle | undefined;
129
+ pre: (target: unknown, handle: QuickJSHandle | QuickJSDeferredPromise, mode: true | "json" | undefined) => QuickJSHandle | undefined;
130
+ preApply?: (target: Function, thisArg: unknown, args: unknown[]) => any;
131
+ };
132
+
133
+ declare type Options_3 = {
134
+ vm: QuickJSVm;
135
+ /** marshal returns handle and boolean indicates that the handle should be disposed after use */
136
+ marshal: (target: unknown) => [QuickJSHandle, boolean];
137
+ find: (handle: QuickJSHandle) => unknown | undefined;
138
+ pre: <T = unknown>(target: T, handle: QuickJSHandle) => T | undefined;
139
+ };
140
+
141
+ export declare function unmarshal(handle: QuickJSHandle, options: Options_3): any;
142
+
143
+ export declare class VMMap {
144
+ vm: QuickJSVm;
145
+ _map1: Map<any, number>;
146
+ _map2: Map<any, number>;
147
+ _map3: Map<number, QuickJSHandle>;
148
+ _map4: Map<number, QuickJSHandle>;
149
+ _counterMap: Map<number, any>;
150
+ _disposables: Set<QuickJSHandle>;
151
+ _mapGet: QuickJSHandle;
152
+ _mapSet: QuickJSHandle;
153
+ _mapDelete: QuickJSHandle;
154
+ _mapClear: QuickJSHandle;
155
+ _counter: number;
156
+ constructor(vm: QuickJSVm);
157
+ set(key: any, handle: QuickJSHandle, key2?: any, handle2?: QuickJSHandle): boolean;
158
+ merge(iteratable: Iterable<[any, QuickJSHandle | undefined] | [any, QuickJSHandle | undefined, any, QuickJSHandle | undefined]> | undefined): void;
159
+ get(key: any): QuickJSHandle | undefined;
160
+ getByHandle(handle: QuickJSHandle): any;
161
+ has(key: any): boolean;
162
+ hasHandle(handle: QuickJSHandle): boolean;
163
+ keys(): IterableIterator<any>;
164
+ delete(key: any, dispose?: boolean): void;
165
+ deleteByHandle(handle: QuickJSHandle, dispose?: boolean): void;
166
+ clear(): void;
167
+ dispose(): void;
168
+ get size(): number;
169
+ [Symbol.iterator](): Iterator<[
170
+ any,
171
+ QuickJSHandle,
172
+ any,
173
+ QuickJSHandle | undefined
174
+ ]>;
175
+ _get2(num: number): any;
176
+ _call(fn: QuickJSHandle, thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]): QuickJSHandle;
177
+ }
178
+
179
+ export declare function walkObject(value: any, callback?: (target: any, set: Set<any>) => boolean | void): Set<any>;
180
+
181
+ declare type Wrapped<T> = T & {
182
+ __qes_wrapped: never;
183
+ };
184
+
185
+ export { }