quickjs-emscripten-sync 1.2.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 (59) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +13 -9
  3. package/dist/index.d.ts +106 -20
  4. package/dist/quickjs-emscripten-sync.es.js +951 -0
  5. package/dist/quickjs-emscripten-sync.umd.js +64 -2
  6. package/package.json +24 -46
  7. package/src/index.test.ts +70 -0
  8. package/src/index.ts +9 -4
  9. package/src/marshal/function.test.ts +8 -7
  10. package/src/marshal/index.test.ts +46 -5
  11. package/src/marshal/index.ts +9 -3
  12. package/src/marshal/json.test.ts +5 -3
  13. package/src/marshal/object.test.ts +9 -7
  14. package/src/marshal/primitive.test.ts +2 -0
  15. package/src/marshal/promise.test.ts +86 -0
  16. package/src/marshal/promise.ts +26 -0
  17. package/src/marshal/properties.test.ts +4 -2
  18. package/src/marshal/symbol.test.ts +3 -1
  19. package/src/unmarshal/function.test.ts +15 -16
  20. package/src/unmarshal/index.test.ts +81 -84
  21. package/src/unmarshal/index.ts +4 -2
  22. package/src/unmarshal/object.test.ts +11 -9
  23. package/src/unmarshal/primitive.test.ts +2 -0
  24. package/src/unmarshal/promise.test.ts +44 -0
  25. package/src/unmarshal/promise.ts +40 -0
  26. package/src/unmarshal/properties.test.ts +3 -1
  27. package/src/unmarshal/symbol.test.ts +3 -1
  28. package/src/util.test.ts +19 -2
  29. package/src/util.ts +15 -0
  30. package/src/vmmap.test.ts +22 -0
  31. package/src/vmmap.ts +4 -0
  32. package/src/vmutil.test.ts +44 -3
  33. package/src/vmutil.ts +47 -7
  34. package/src/wrapper.test.ts +24 -22
  35. package/dist/default.d.ts +0 -4
  36. package/dist/marshal/function.d.ts +0 -2
  37. package/dist/marshal/index.d.ts +0 -11
  38. package/dist/marshal/json.d.ts +0 -2
  39. package/dist/marshal/object.d.ts +0 -2
  40. package/dist/marshal/primitive.d.ts +0 -2
  41. package/dist/marshal/properties.d.ts +0 -2
  42. package/dist/marshal/symbol.d.ts +0 -2
  43. package/dist/quickjs-emscripten-sync.cjs +0 -2
  44. package/dist/quickjs-emscripten-sync.cjs.map +0 -1
  45. package/dist/quickjs-emscripten-sync.modern.js +0 -2
  46. package/dist/quickjs-emscripten-sync.modern.js.map +0 -1
  47. package/dist/quickjs-emscripten-sync.module.js +0 -2
  48. package/dist/quickjs-emscripten-sync.module.js.map +0 -1
  49. package/dist/quickjs-emscripten-sync.umd.js.map +0 -1
  50. package/dist/unmarshal/function.d.ts +0 -2
  51. package/dist/unmarshal/index.d.ts +0 -9
  52. package/dist/unmarshal/object.d.ts +0 -2
  53. package/dist/unmarshal/primitive.d.ts +0 -2
  54. package/dist/unmarshal/properties.d.ts +0 -2
  55. package/dist/unmarshal/symbol.d.ts +0 -2
  56. package/dist/util.d.ts +0 -7
  57. package/dist/vmmap.d.ts +0 -35
  58. package/dist/vmutil.d.ts +0 -11
  59. package/dist/wrapper.d.ts +0 -11
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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # quickjs-emscripten-sync
2
2
 
3
- We can build a plugin system that works safely in the web browser!
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
4
6
 
5
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.
6
8
 
@@ -31,7 +33,7 @@ class Cls {
31
33
  }
32
34
 
33
35
  const vm = (await getQuickJS()).createVm();
34
- const arena = new Arena(vm);
36
+ const arena = new Arena(vm, { isMarshalable: true });
35
37
 
36
38
  // We can pass objects to the VM and run code safely
37
39
  const exposed = {
@@ -41,10 +43,10 @@ const exposed = {
41
43
  };
42
44
  arena.expose(exposed);
43
45
 
44
- arena.evalCode(`cls instanceof Cls`)); // returns true
45
- arena.evalCode(`cls.field`)); // returns 0
46
- arena.evalCode(`cls.method()`)); // returns 1
47
- arena.evalCode(`cls.field`)); // returns 1
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
48
50
 
49
51
  arena.evalCode(`syncedCls.field`); // returns 0
50
52
  exposed.syncedCls.method(); // returns 1
@@ -74,7 +76,9 @@ import { Arena } from "quickjs-emscripten-sync";
74
76
  const vm = quickjs.createVm();
75
77
 
76
78
  // init Arena
77
- const arena = new Arena(vm);
79
+ // ⚠️ Marshaling is opt-in for security reasons.
80
+ // ⚠️ Be careful when activating marshalling.
81
+ const arena = new Arena(vm, { isMarshalable: true });
78
82
 
79
83
  // expose objects as global objects in QuickJS VM
80
84
  arena.expose({
@@ -87,12 +91,12 @@ import { Arena } from "quickjs-emscripten-sync";
87
91
 
88
92
  // expose objects but also enable sync
89
93
  const data = arena.sync({ hoge: "foo" });
90
- const exposed = arena.expose({ data });
94
+ arena.expose({ data });
91
95
 
92
96
  arena.evalCode(`data.hoge = "bar"`);
93
97
  // eval code and operations to exposed objects are automatically synced
94
98
  console.log(data.hoge); // "bar"
95
- exposed.hoge = "changed!";
99
+ data.hoge = "changed!";
96
100
  console.log(arena.evalCode(`data.hoge`)); // "changed!"
97
101
 
98
102
  // Don't forget calling arena.dispose() before disposing QuickJS VM!
package/dist/index.d.ts CHANGED
@@ -1,22 +1,9 @@
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, json, consumeAll } from "./vmutil";
9
- import { defaultRegisteredObjects } from "./default";
10
- export { VMMap, defaultRegisteredObjects, marshal, unmarshal, complexity, isES2015Class, isObject, walkObject, call, eq, isHandleObject, json, 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?: boolean | "json" | ((target: any) => boolean | "json");
14
- /** 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`.
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
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
  */
@@ -83,7 +70,7 @@ export declare class Arena {
83
70
  _unwrapResultAndUnmarshal(result: VmCallResult<QuickJSHandle> | undefined): any;
84
71
  _isMarshalable: (t: unknown) => boolean | "json";
85
72
  _marshalFind: (t: unknown) => QuickJSHandle | undefined;
86
- _marshalPre: (t: unknown, h: QuickJSHandle, mode: true | "json" | undefined) => Wrapped<QuickJSHandle> | undefined;
73
+ _marshalPre: (t: unknown, h: QuickJSHandle | QuickJSDeferredPromise, mode: true | "json" | undefined) => Wrapped<QuickJSHandle> | undefined;
87
74
  _marshalPreApply: (target: Function, that: unknown, args: unknown[]) => void;
88
75
  _marshal: (target: any) => [QuickJSHandle, boolean];
89
76
  _preUnmarshal: (t: any, h: QuickJSHandle) => Wrapped<any>;
@@ -97,3 +84,102 @@ export declare class Arena {
97
84
  _wrapHandle(handle: QuickJSHandle): [Wrapped<QuickJSHandle> | undefined, boolean];
98
85
  _unwrapHandle(target: QuickJSHandle): [QuickJSHandle, boolean];
99
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 { }