quickjs-emscripten-sync 1.6.0 → 1.7.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.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Intrinsics } from 'quickjs-emscripten';
1
2
  import { QuickJSContext } from 'quickjs-emscripten';
2
3
  import { QuickJSDeferredPromise } from 'quickjs-emscripten';
3
4
  import { QuickJSHandle } from 'quickjs-emscripten';
@@ -28,22 +29,38 @@ export declare class Arena {
28
29
  */
29
30
  evalCode<T = any>(code: string): T;
30
31
  /**
31
- * Evaluate ES module code in the VM. The module can import/export, but the return value
32
- * depends on whether the module exports are accessible (implementation varies by quickjs-emscripten version).
33
- * Use this for side effects or when you don't need access to exports.
32
+ * Evaluate ES module code in the VM and get the module's exports.
33
+ *
34
+ * Requires quickjs-emscripten >= 0.29.0 for export access.
34
35
  *
35
36
  * @param code - The ES module code to evaluate
36
37
  * @param filename - Optional filename for debugging purposes (default: "module.js")
37
- * @returns Undefined in most cases (module side effects are applied)
38
+ * @returns The module's exports object, or a Promise resolving to exports if using top-level await
38
39
  *
39
40
  * @example
40
41
  * ```js
41
- * // Execute module code with side effects
42
- * arena.expose({ data: { count: 0 } });
43
- * arena.evalModule('import { data } from "globals"; data.count = 42;'); // undefined, but data.count is now 42
42
+ * // Simple module with exports
43
+ * const exports = arena.evalModule(`
44
+ * export const value = 42;
45
+ * export function greet(name) {
46
+ * return "Hello, " + name;
47
+ * }
48
+ * `);
49
+ * console.log(exports.value); // 42
50
+ * console.log(exports.greet("World")); // "Hello, World"
51
+ *
52
+ * // Module with default export
53
+ * const mod = arena.evalModule('export default function(x) { return x * 2; }');
54
+ * console.log(mod.default(21)); // 42
55
+ *
56
+ * // Module with top-level await
57
+ * const promise = arena.evalModule('export const data = await Promise.resolve(123);');
58
+ * arena.executePendingJobs();
59
+ * const exports = await promise;
60
+ * console.log(exports.data); // 123
44
61
  * ```
45
62
  */
46
- evalModule(code: string, filename?: string): void;
63
+ evalModule<T = any>(code: string, filename?: string): T | Promise<T>;
47
64
  /**
48
65
  * Almost same as `vm.executePendingJobs()`, but it converts and re-throws error objects when an error is thrown during evaluation.
49
66
  */
@@ -216,6 +233,8 @@ export declare const defaultRegisteredObjects: [any, string][];
216
233
 
217
234
  export declare function eq(ctx: QuickJSContext, a: QuickJSHandle, b: QuickJSHandle): boolean;
218
235
 
236
+ export { Intrinsics }
237
+
219
238
  export declare function isES2015Class(cls: any): cls is new (...args: any[]) => any;
220
239
 
221
240
  export declare function isHandleObject(ctx: QuickJSContext, h: QuickJSHandle): boolean;
@@ -85,8 +85,8 @@ const I = [
85
85
  ...Object.getOwnPropertyNames(Symbol).filter((n) => typeof Symbol[n] == "symbol").map((n) => [Symbol[n], `Symbol.${n}`])
86
86
  ];
87
87
  function T(n, e) {
88
- const t = n.unwrapResult(n.evalCode(e)), r = (s, ...o) => n.unwrapResult(n.callFunction(t, s != null ? s : n.undefined, ...o));
89
- return r.dispose = () => t.dispose(), r.alive = !0, Object.defineProperty(r, "alive", {
88
+ const t = n.unwrapResult(n.evalCode(e)), r = (o, ...i) => n.unwrapResult(n.callFunction(t, o != null ? o : n.undefined, ...i)), s = () => t.dispose();
89
+ return r.dispose = s, r[Symbol.dispose] = s, r.alive = !0, Object.defineProperty(r, "alive", {
90
90
  get: () => t.alive
91
91
  }), r;
92
92
  }
@@ -811,24 +811,40 @@ class we {
811
811
  return this._unwrapResultAndUnmarshal(t);
812
812
  }
813
813
  /**
814
- * Evaluate ES module code in the VM. The module can import/export, but the return value
815
- * depends on whether the module exports are accessible (implementation varies by quickjs-emscripten version).
816
- * Use this for side effects or when you don't need access to exports.
814
+ * Evaluate ES module code in the VM and get the module's exports.
815
+ *
816
+ * Requires quickjs-emscripten >= 0.29.0 for export access.
817
817
  *
818
818
  * @param code - The ES module code to evaluate
819
819
  * @param filename - Optional filename for debugging purposes (default: "module.js")
820
- * @returns Undefined in most cases (module side effects are applied)
820
+ * @returns The module's exports object, or a Promise resolving to exports if using top-level await
821
821
  *
822
822
  * @example
823
823
  * ```js
824
- * // Execute module code with side effects
825
- * arena.expose({ data: { count: 0 } });
826
- * arena.evalModule('import { data } from "globals"; data.count = 42;'); // undefined, but data.count is now 42
824
+ * // Simple module with exports
825
+ * const exports = arena.evalModule(`
826
+ * export const value = 42;
827
+ * export function greet(name) {
828
+ * return "Hello, " + name;
829
+ * }
830
+ * `);
831
+ * console.log(exports.value); // 42
832
+ * console.log(exports.greet("World")); // "Hello, World"
833
+ *
834
+ * // Module with default export
835
+ * const mod = arena.evalModule('export default function(x) { return x * 2; }');
836
+ * console.log(mod.default(21)); // 42
837
+ *
838
+ * // Module with top-level await
839
+ * const promise = arena.evalModule('export const data = await Promise.resolve(123);');
840
+ * arena.executePendingJobs();
841
+ * const exports = await promise;
842
+ * console.log(exports.data); // 123
827
843
  * ```
828
844
  */
829
845
  evalModule(e, t = "module.js") {
830
846
  const r = this.context.evalCode(e, t, { type: "module" });
831
- this._unwrapResultAndUnmarshal(r);
847
+ return this._unwrapResultAndUnmarshal(r);
832
848
  }
833
849
  /**
834
850
  * Almost same as `vm.executePendingJobs()`, but it converts and re-throws error objects when an error is thrown during evaluation.
@@ -5,7 +5,7 @@
5
5
  fn.name = name;
6
6
  fn.length = length;
7
7
  return fn;
8
- })`))}disposeEx(){this.fnGenerator.dispose(),this.fn.dispose()}}const k=[[Symbol,"Symbol"],[Symbol.prototype,"Symbol.prototype"],[Object,"Object"],[Object.prototype,"Object.prototype"],[Function,"Function"],[Function.prototype,"Function.prototype"],[Boolean,"Boolean"],[Boolean.prototype,"Boolean.prototype"],[Array,"Array"],[Array.prototype,"Array.prototype"],[Error,"Error"],[Error.prototype,"Error.prototype"],[EvalError,"EvalError"],[EvalError.prototype,"EvalError.prototype"],[RangeError,"RangeError"],[RangeError.prototype,"RangeError.prototype"],[ReferenceError,"ReferenceError"],[ReferenceError.prototype,"ReferenceError.prototype"],[SyntaxError,"SyntaxError"],[SyntaxError.prototype,"SyntaxError.prototype"],[TypeError,"TypeError"],[TypeError.prototype,"TypeError.prototype"],[URIError,"URIError"],[URIError.prototype,"URIError.prototype"],...Object.getOwnPropertyNames(Symbol).filter(n=>typeof Symbol[n]=="symbol").map(n=>[Symbol[n],`Symbol.${n}`])];function J(n,e){const t=n.unwrapResult(n.evalCode(e)),r=(s,...o)=>n.unwrapResult(n.callFunction(t,s!=null?s:n.undefined,...o));return r.dispose=()=>t.dispose(),r.alive=!0,Object.defineProperty(r,"alive",{get:()=>t.alive}),r}function _(n,e,t,...r){const s=J(n,e);try{return s(t,...r)}finally{s.dispose()}}function C(n,e,t){return n.dump(_(n,"Object.is",void 0,e,t))}function W(n,e,t){return n.dump(_(n,"(a, b) => a instanceof b",void 0,e,t))}function F(n,e){return n.dump(_(n,'a => typeof a === "object" && a !== null || typeof a === "function"',void 0,e))}function H(n,e){const t=JSON.stringify(e);return t?_(n,"JSON.parse",void 0,n.newString(t)):n.undefined}function z(n,e){try{return e(n)}finally{for(const t of n)t.alive&&t.dispose()}}function $([n,e],t){try{return t(n)}finally{e&&n.dispose()}}function S(n,e){try{return e(...n.map(t=>t[0]))}finally{for(const[t,r]of n)r&&t.dispose()}}function q(n){return"handle"in n}function L(n){return q(n)?n.handle:n}function Q(n,e,t,r){var o;let s;for(const i of r)if(s=i(e,n),s)break;return s?(o=t(e,s))!=null?o:s:void 0}function V(n,e){return typeof n!="symbol"?void 0:_(e,"d => Symbol(d)",void 0,n.description?e.newString(n.description):e.undefined)}function X(n,e){return n instanceof Date?_(e,"d => new Date(d)",void 0,e.newNumber(n.getTime())):void 0}const Y=[V,X];function N(n){return typeof n=="function"&&/^class\s/.test(Function.prototype.toString.call(n))}function g(n){return typeof n=="function"||typeof n=="object"&&n!==null}function O(n,e){const t=new Set,r=s=>{if(!(!g(s)||t.has(s)||(e==null?void 0:e(s,t))===!1)){if(t.add(s),Array.isArray(s)){for(const o of s)r(o);return}if(typeof s=="object"){const o=Object.getPrototypeOf(s);o&&o!==Object.prototype&&r(o)}for(const o of Object.values(Object.getOwnPropertyDescriptors(s)))"value"in o&&r(o.value),"get"in o&&r(o.get),"set"in o&&r(o.set)}};return r(n),t}function Z(n,e){return O(n,e?(t,r)=>r.size<e:void 0).size}function K(){let n=()=>{},e=()=>{};return{promise:new Promise((r,s)=>{n=r,e=s}),resolve:n,reject:e}}function A(n,e,t,r){const s=n.newObject(),o=(a,u)=>{const p=r(a),l=typeof u.value=="undefined"?void 0:r(u.value),f=typeof u.get=="undefined"?void 0:r(u.get),d=typeof u.set=="undefined"?void 0:r(u.set);n.newObject().consume(h=>{Object.entries(u).forEach(([y,b])=>{const w=y==="value"?l:y==="get"?f:y==="set"?d:b?n.true:n.false;w&&n.setProp(h,y,w)}),n.setProp(s,p,h)})},i=Object.getOwnPropertyDescriptors(e);Object.entries(i).forEach(([a,u])=>o(a,u)),Object.getOwnPropertySymbols(i).forEach(a=>o(a,i[a])),_(n,"Object.defineProperties",void 0,t,s).dispose(),s.dispose()}function x(n,e,t,r,s,o){var u;if(typeof e!="function")return;const i=n.newFunction(e.name,function(...p){const l=r(this),f=p.map(d=>r(d));if(N(e)&&g(l)){const d=new e(...f);return Object.entries(d).forEach(([h,y])=>{n.setProp(this,h,t(y))}),this}return t(o?o(e,l,f):e.apply(l,f))}).consume(p=>_(n,`Cls => {
8
+ })`))}disposeEx(){this.fnGenerator.dispose(),this.fn.dispose()}}const k=[[Symbol,"Symbol"],[Symbol.prototype,"Symbol.prototype"],[Object,"Object"],[Object.prototype,"Object.prototype"],[Function,"Function"],[Function.prototype,"Function.prototype"],[Boolean,"Boolean"],[Boolean.prototype,"Boolean.prototype"],[Array,"Array"],[Array.prototype,"Array.prototype"],[Error,"Error"],[Error.prototype,"Error.prototype"],[EvalError,"EvalError"],[EvalError.prototype,"EvalError.prototype"],[RangeError,"RangeError"],[RangeError.prototype,"RangeError.prototype"],[ReferenceError,"ReferenceError"],[ReferenceError.prototype,"ReferenceError.prototype"],[SyntaxError,"SyntaxError"],[SyntaxError.prototype,"SyntaxError.prototype"],[TypeError,"TypeError"],[TypeError.prototype,"TypeError.prototype"],[URIError,"URIError"],[URIError.prototype,"URIError.prototype"],...Object.getOwnPropertyNames(Symbol).filter(n=>typeof Symbol[n]=="symbol").map(n=>[Symbol[n],`Symbol.${n}`])];function J(n,e){const t=n.unwrapResult(n.evalCode(e)),r=(o,...i)=>n.unwrapResult(n.callFunction(t,o!=null?o:n.undefined,...i)),s=()=>t.dispose();return r.dispose=s,r[Symbol.dispose]=s,r.alive=!0,Object.defineProperty(r,"alive",{get:()=>t.alive}),r}function _(n,e,t,...r){const s=J(n,e);try{return s(t,...r)}finally{s.dispose()}}function C(n,e,t){return n.dump(_(n,"Object.is",void 0,e,t))}function W(n,e,t){return n.dump(_(n,"(a, b) => a instanceof b",void 0,e,t))}function F(n,e){return n.dump(_(n,'a => typeof a === "object" && a !== null || typeof a === "function"',void 0,e))}function H(n,e){const t=JSON.stringify(e);return t?_(n,"JSON.parse",void 0,n.newString(t)):n.undefined}function z(n,e){try{return e(n)}finally{for(const t of n)t.alive&&t.dispose()}}function $([n,e],t){try{return t(n)}finally{e&&n.dispose()}}function S(n,e){try{return e(...n.map(t=>t[0]))}finally{for(const[t,r]of n)r&&t.dispose()}}function q(n){return"handle"in n}function L(n){return q(n)?n.handle:n}function Q(n,e,t,r){var o;let s;for(const i of r)if(s=i(e,n),s)break;return s?(o=t(e,s))!=null?o:s:void 0}function V(n,e){return typeof n!="symbol"?void 0:_(e,"d => Symbol(d)",void 0,n.description?e.newString(n.description):e.undefined)}function X(n,e){return n instanceof Date?_(e,"d => new Date(d)",void 0,e.newNumber(n.getTime())):void 0}const Y=[V,X];function N(n){return typeof n=="function"&&/^class\s/.test(Function.prototype.toString.call(n))}function g(n){return typeof n=="function"||typeof n=="object"&&n!==null}function O(n,e){const t=new Set,r=s=>{if(!(!g(s)||t.has(s)||(e==null?void 0:e(s,t))===!1)){if(t.add(s),Array.isArray(s)){for(const o of s)r(o);return}if(typeof s=="object"){const o=Object.getPrototypeOf(s);o&&o!==Object.prototype&&r(o)}for(const o of Object.values(Object.getOwnPropertyDescriptors(s)))"value"in o&&r(o.value),"get"in o&&r(o.get),"set"in o&&r(o.set)}};return r(n),t}function Z(n,e){return O(n,e?(t,r)=>r.size<e:void 0).size}function K(){let n=()=>{},e=()=>{};return{promise:new Promise((r,s)=>{n=r,e=s}),resolve:n,reject:e}}function A(n,e,t,r){const s=n.newObject(),o=(a,u)=>{const p=r(a),l=typeof u.value=="undefined"?void 0:r(u.value),f=typeof u.get=="undefined"?void 0:r(u.get),d=typeof u.set=="undefined"?void 0:r(u.set);n.newObject().consume(h=>{Object.entries(u).forEach(([y,b])=>{const w=y==="value"?l:y==="get"?f:y==="set"?d:b?n.true:n.false;w&&n.setProp(h,y,w)}),n.setProp(s,p,h)})},i=Object.getOwnPropertyDescriptors(e);Object.entries(i).forEach(([a,u])=>o(a,u)),Object.getOwnPropertySymbols(i).forEach(a=>o(a,i[a])),_(n,"Object.defineProperties",void 0,t,s).dispose(),s.dispose()}function x(n,e,t,r,s,o){var u;if(typeof e!="function")return;const i=n.newFunction(e.name,function(...p){const l=r(this),f=p.map(d=>r(d));if(N(e)&&g(l)){const d=new e(...f);return Object.entries(d).forEach(([h,y])=>{n.setProp(this,h,t(y))}),this}return t(o?o(e,l,f):e.apply(l,f))}).consume(p=>_(n,`Cls => {
9
9
  const fn = function(...args) { return Cls.apply(this, args); };
10
10
  fn.name = Cls.name;
11
11
  fn.length = Cls.length;
@@ -68,4 +68,4 @@
68
68
  },
69
69
  });
70
70
  return rec;
71
- }`,void 0,e,r,l),!0])}function P(n,e){var t;return g(n)&&(t=n[e])!=null?t:n}function R(n,e,t){return U(n,e,t)?[n.getProp(e,t),!0]:[e,!1]}function he(n,e){return g(n)&&!!n[e]}function U(n,e,t){return!!n.dump(_(n,'(a, s) => (a instanceof Promise) || (a instanceof Date) || (typeof a === "object" && a !== null || typeof a === "function") && !!a[s]',void 0,e,t))}class ye{constructor(e,t){c(this,"context");c(this,"_map");c(this,"_registeredMap");c(this,"_registeredMapDispose",new Set);c(this,"_sync",new Set);c(this,"_temporalSync",new Set);c(this,"_symbol",Symbol());c(this,"_symbolHandle");c(this,"_options");c(this,"_isMarshalable",e=>{var r,s;const t=(r=this._options)==null?void 0:r.isMarshalable;return(s=typeof t=="function"?t(this._unwrap(e)):t)!=null?s:"json"});c(this,"_marshalFind",e=>{var s,o,i;const t=this._unwrap(e);return(i=(o=(s=this._registeredMap.get(e))!=null?s:t!==e?this._registeredMap.get(t):void 0)!=null?o:this._map.get(e))!=null?i:t!==e?this._map.get(t):void 0});c(this,"_marshalPre",(e,t,r)=>{var s;if(r!=="json")return(s=this._register(e,L(t),this._map))==null?void 0:s[1]});c(this,"_marshalPreApply",(e,t,r)=>{const s=g(t)?this._unwrap(t):void 0;s&&this._temporalSync.add(s);try{return e.apply(t,r)}finally{s&&this._temporalSync.delete(s)}});c(this,"_marshal",e=>{var s,o;const t=this._registeredMap.get(e);if(t)return[t,!1];const r=E((s=this._wrap(e))!=null?s:e,{ctx:this.context,unmarshal:this._unmarshal,isMarshalable:this._isMarshalable,find:this._marshalFind,pre:this._marshalPre,preApply:this._marshalPreApply,custom:(o=this._options)==null?void 0:o.customMarshaller});return[r,!this._map.hasHandle(r)]});c(this,"_preUnmarshal",(e,t)=>{var r;return(r=this._register(e,t,void 0,!0))==null?void 0:r[0]});c(this,"_unmarshalFind",e=>{var t;return(t=this._registeredMap.getByHandle(e))!=null?t:this._map.getByHandle(e)});c(this,"_unmarshal",e=>{var s;const t=this._registeredMap.getByHandle(e);if(typeof t!="undefined")return t;const[r]=this._wrapHandle(e);return B(r!=null?r:e,{ctx:this.context,marshal:this._marshal,find:this._unmarshalFind,pre:this._preUnmarshal,custom:(s=this._options)==null?void 0:s.customUnmarshaller})});c(this,"_syncMode",e=>{const t=this._unwrap(e);return this._sync.has(t)||this._temporalSync.has(t)?"both":void 0});c(this,"_unwrapIfNotSynced",e=>{const t=this._unwrap(e);return t instanceof Promise||!this._sync.has(t)?t:e});var r;t!=null&&t.compat&&!("runtime"in e)&&(e.runtime={hasPendingJob:()=>e.hasPendingJob(),executePendingJobs:s=>e.executePendingJobs(s)}),this.context=t!=null&&t.experimentalContextEx?v(e):e,this._options=t,this._symbolHandle=e.unwrapResult(e.evalCode("Symbol()")),this._map=new M(e),this._registeredMap=new M(e),this.registerAll((r=t==null?void 0:t.registeredObjects)!=null?r:k)}dispose(){var e,t;this._map.dispose(),this._registeredMap.dispose(),this._symbolHandle.dispose(),(t=(e=this.context).disposeEx)==null||t.call(e)}evalCode(e){const t=this.context.evalCode(e);return this._unwrapResultAndUnmarshal(t)}evalModule(e,t="module.js"){const r=this.context.evalCode(e,t,{type:"module"});this._unwrapResultAndUnmarshal(r)}executePendingJobs(e){const t=this.context.runtime.executePendingJobs(e);if("value"in t)return t.value;throw this._unwrapIfNotSynced(t.error.consume(this._unmarshal))}setMemoryLimit(e){this.context.runtime.setMemoryLimit(e)}setMaxStackSize(e){this.context.runtime.setMaxStackSize(e)}getMemoryUsage(){const e=this.context.runtime.computeMemoryUsage();try{return this.context.dump(e)}finally{e.dispose()}}dumpMemoryUsage(){return this.context.runtime.dumpMemoryUsage()}expose(e){for(const[t,r]of Object.entries(e))$(this._marshal(r),s=>{this.context.setProp(this.context.global,t,s)})}sync(e){const t=this._wrap(e);return typeof t=="undefined"?e:(O(t,r=>{const s=this._unwrap(r);this._sync.add(s)}),t)}register(e,t){if(this._registeredMap.has(e))return;const r=typeof t=="string"?this._unwrapResult(this.context.evalCode(t)):t;C(this.context,r,this.context.undefined)||(typeof t=="string"&&this._registeredMapDispose.add(e),this._registeredMap.set(e,r))}registerAll(e){for(const[t,r]of e)this.register(t,r)}unregister(e,t){this._registeredMap.delete(e,this._registeredMapDispose.has(e)||t),this._registeredMapDispose.delete(e)}unregisterAll(e,t){for(const r of e)this.unregister(r,t)}startSync(e){if(!g(e))return;const t=this._unwrap(e);this._sync.add(t)}endSync(e){this._sync.delete(this._unwrap(e))}_unwrapResult(e){if("value"in e)return e.value;throw this._unwrapIfNotSynced(e.error.consume(this._unmarshal))}_unwrapResultAndUnmarshal(e){if(e)return this._unwrapIfNotSynced(this._unwrapResult(e).consume(this._unmarshal))}_register(e,t,r=this._map,s){if(this._registeredMap.has(e)||this._registeredMap.hasHandle(t))return;let o=this._wrap(e);const[i]=this._wrapHandle(t),a=e instanceof Promise;if(!i||!o&&!a)return;a&&(o=e);const u=this._unwrap(e),[p,l]=this._unwrapHandle(t);if(r.set(o,i,u,p))s&&this._sync.add(u);else throw l&&p.dispose(),new Error("already registered");return[o,i]}_wrap(e){var t;return de(this.context,e,this._symbol,this._symbolHandle,this._marshal,this._syncMode,(t=this._options)==null?void 0:t.isWrappable)}_unwrap(e){return P(e,this._symbol)}_wrapHandle(e){var t;return me(this.context,e,this._symbol,this._symbolHandle,this._unmarshal,this._syncMode,(t=this._options)==null?void 0:t.isHandleWrappable)}_unwrapHandle(e){return R(this.context,e,this._symbolHandle)}}m.Arena=ye,m.VMMap=M,m.call=_,m.complexity=Z,m.consumeAll=z,m.defaultRegisteredObjects=k,m.eq=C,m.isES2015Class=N,m.isHandleObject=F,m.isObject=g,m.json=H,m.marshal=E,m.unmarshal=B,m.walkObject=O,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
71
+ }`,void 0,e,r,l),!0])}function P(n,e){var t;return g(n)&&(t=n[e])!=null?t:n}function R(n,e,t){return U(n,e,t)?[n.getProp(e,t),!0]:[e,!1]}function he(n,e){return g(n)&&!!n[e]}function U(n,e,t){return!!n.dump(_(n,'(a, s) => (a instanceof Promise) || (a instanceof Date) || (typeof a === "object" && a !== null || typeof a === "function") && !!a[s]',void 0,e,t))}class ye{constructor(e,t){c(this,"context");c(this,"_map");c(this,"_registeredMap");c(this,"_registeredMapDispose",new Set);c(this,"_sync",new Set);c(this,"_temporalSync",new Set);c(this,"_symbol",Symbol());c(this,"_symbolHandle");c(this,"_options");c(this,"_isMarshalable",e=>{var r,s;const t=(r=this._options)==null?void 0:r.isMarshalable;return(s=typeof t=="function"?t(this._unwrap(e)):t)!=null?s:"json"});c(this,"_marshalFind",e=>{var s,o,i;const t=this._unwrap(e);return(i=(o=(s=this._registeredMap.get(e))!=null?s:t!==e?this._registeredMap.get(t):void 0)!=null?o:this._map.get(e))!=null?i:t!==e?this._map.get(t):void 0});c(this,"_marshalPre",(e,t,r)=>{var s;if(r!=="json")return(s=this._register(e,L(t),this._map))==null?void 0:s[1]});c(this,"_marshalPreApply",(e,t,r)=>{const s=g(t)?this._unwrap(t):void 0;s&&this._temporalSync.add(s);try{return e.apply(t,r)}finally{s&&this._temporalSync.delete(s)}});c(this,"_marshal",e=>{var s,o;const t=this._registeredMap.get(e);if(t)return[t,!1];const r=E((s=this._wrap(e))!=null?s:e,{ctx:this.context,unmarshal:this._unmarshal,isMarshalable:this._isMarshalable,find:this._marshalFind,pre:this._marshalPre,preApply:this._marshalPreApply,custom:(o=this._options)==null?void 0:o.customMarshaller});return[r,!this._map.hasHandle(r)]});c(this,"_preUnmarshal",(e,t)=>{var r;return(r=this._register(e,t,void 0,!0))==null?void 0:r[0]});c(this,"_unmarshalFind",e=>{var t;return(t=this._registeredMap.getByHandle(e))!=null?t:this._map.getByHandle(e)});c(this,"_unmarshal",e=>{var s;const t=this._registeredMap.getByHandle(e);if(typeof t!="undefined")return t;const[r]=this._wrapHandle(e);return B(r!=null?r:e,{ctx:this.context,marshal:this._marshal,find:this._unmarshalFind,pre:this._preUnmarshal,custom:(s=this._options)==null?void 0:s.customUnmarshaller})});c(this,"_syncMode",e=>{const t=this._unwrap(e);return this._sync.has(t)||this._temporalSync.has(t)?"both":void 0});c(this,"_unwrapIfNotSynced",e=>{const t=this._unwrap(e);return t instanceof Promise||!this._sync.has(t)?t:e});var r;t!=null&&t.compat&&!("runtime"in e)&&(e.runtime={hasPendingJob:()=>e.hasPendingJob(),executePendingJobs:s=>e.executePendingJobs(s)}),this.context=t!=null&&t.experimentalContextEx?v(e):e,this._options=t,this._symbolHandle=e.unwrapResult(e.evalCode("Symbol()")),this._map=new M(e),this._registeredMap=new M(e),this.registerAll((r=t==null?void 0:t.registeredObjects)!=null?r:k)}dispose(){var e,t;this._map.dispose(),this._registeredMap.dispose(),this._symbolHandle.dispose(),(t=(e=this.context).disposeEx)==null||t.call(e)}evalCode(e){const t=this.context.evalCode(e);return this._unwrapResultAndUnmarshal(t)}evalModule(e,t="module.js"){const r=this.context.evalCode(e,t,{type:"module"});return this._unwrapResultAndUnmarshal(r)}executePendingJobs(e){const t=this.context.runtime.executePendingJobs(e);if("value"in t)return t.value;throw this._unwrapIfNotSynced(t.error.consume(this._unmarshal))}setMemoryLimit(e){this.context.runtime.setMemoryLimit(e)}setMaxStackSize(e){this.context.runtime.setMaxStackSize(e)}getMemoryUsage(){const e=this.context.runtime.computeMemoryUsage();try{return this.context.dump(e)}finally{e.dispose()}}dumpMemoryUsage(){return this.context.runtime.dumpMemoryUsage()}expose(e){for(const[t,r]of Object.entries(e))$(this._marshal(r),s=>{this.context.setProp(this.context.global,t,s)})}sync(e){const t=this._wrap(e);return typeof t=="undefined"?e:(O(t,r=>{const s=this._unwrap(r);this._sync.add(s)}),t)}register(e,t){if(this._registeredMap.has(e))return;const r=typeof t=="string"?this._unwrapResult(this.context.evalCode(t)):t;C(this.context,r,this.context.undefined)||(typeof t=="string"&&this._registeredMapDispose.add(e),this._registeredMap.set(e,r))}registerAll(e){for(const[t,r]of e)this.register(t,r)}unregister(e,t){this._registeredMap.delete(e,this._registeredMapDispose.has(e)||t),this._registeredMapDispose.delete(e)}unregisterAll(e,t){for(const r of e)this.unregister(r,t)}startSync(e){if(!g(e))return;const t=this._unwrap(e);this._sync.add(t)}endSync(e){this._sync.delete(this._unwrap(e))}_unwrapResult(e){if("value"in e)return e.value;throw this._unwrapIfNotSynced(e.error.consume(this._unmarshal))}_unwrapResultAndUnmarshal(e){if(e)return this._unwrapIfNotSynced(this._unwrapResult(e).consume(this._unmarshal))}_register(e,t,r=this._map,s){if(this._registeredMap.has(e)||this._registeredMap.hasHandle(t))return;let o=this._wrap(e);const[i]=this._wrapHandle(t),a=e instanceof Promise;if(!i||!o&&!a)return;a&&(o=e);const u=this._unwrap(e),[p,l]=this._unwrapHandle(t);if(r.set(o,i,u,p))s&&this._sync.add(u);else throw l&&p.dispose(),new Error("already registered");return[o,i]}_wrap(e){var t;return de(this.context,e,this._symbol,this._symbolHandle,this._marshal,this._syncMode,(t=this._options)==null?void 0:t.isWrappable)}_unwrap(e){return P(e,this._symbol)}_wrapHandle(e){var t;return me(this.context,e,this._symbol,this._symbolHandle,this._unmarshal,this._syncMode,(t=this._options)==null?void 0:t.isHandleWrappable)}_unwrapHandle(e){return R(this.context,e,this._symbolHandle)}}m.Arena=ye,m.VMMap=M,m.call=_,m.complexity=Z,m.consumeAll=z,m.defaultRegisteredObjects=k,m.eq=C,m.isES2015Class=N,m.isHandleObject=F,m.isObject=g,m.json=H,m.marshal=E,m.unmarshal=B,m.walkObject=O,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quickjs-emscripten-sync",
3
3
  "author": "rot1024",
4
- "version": "1.6.0",
4
+ "version": "1.7.0",
5
5
  "license": "MIT",
6
6
  "source": "./src/index.ts",
7
7
  "main": "./dist/quickjs-emscripten-sync.umd.js",
@@ -35,7 +35,7 @@
35
35
  "eslint": "^8.57.1",
36
36
  "eslint-config-reearth": "^0.2.1",
37
37
  "prettier": "^2.8.8",
38
- "quickjs-emscripten": "^0.25.0",
38
+ "quickjs-emscripten": "^0.29.0",
39
39
  "typescript": "^5.7.2",
40
40
  "vite": "^6.0.3",
41
41
  "vite-plugin-dts": "^4.3.0",
package/src/index.test.ts CHANGED
@@ -715,6 +715,107 @@ describe("evalModule", () => {
715
715
  arena.dispose();
716
716
  ctx.dispose();
717
717
  });
718
+
719
+ test("module returns exported values (0.29+)", async () => {
720
+ const ctx = (await getQuickJS()).newContext();
721
+ const arena = new Arena(ctx, { isMarshalable: true });
722
+
723
+ const exports = arena.evalModule(`
724
+ export const value = 42;
725
+ export const message = "Hello";
726
+ export const obj = { a: 1, b: 2 };
727
+ `);
728
+
729
+ expect(exports.value).toBe(42);
730
+ expect(exports.message).toBe("Hello");
731
+ expect(exports.obj).toEqual({ a: 1, b: 2 });
732
+
733
+ arena.dispose();
734
+ ctx.dispose();
735
+ });
736
+
737
+ test("module returns exported functions (0.29+)", async () => {
738
+ const ctx = (await getQuickJS()).newContext();
739
+ const arena = new Arena(ctx, { isMarshalable: true });
740
+
741
+ const exports = arena.evalModule(`
742
+ export function greet(name) {
743
+ return "Hello, " + name;
744
+ }
745
+ export function add(a, b) {
746
+ return a + b;
747
+ }
748
+ `);
749
+
750
+ expect(exports.greet("World")).toBe("Hello, World");
751
+ expect(exports.add(2, 3)).toBe(5);
752
+
753
+ arena.dispose();
754
+ ctx.dispose();
755
+ });
756
+
757
+ test("module with default export (0.29+)", async () => {
758
+ const ctx = (await getQuickJS()).newContext();
759
+ const arena = new Arena(ctx, { isMarshalable: true });
760
+
761
+ const exports = arena.evalModule(`
762
+ export default function(x) {
763
+ return x * 2;
764
+ }
765
+ `);
766
+
767
+ expect(exports.default(21)).toBe(42);
768
+
769
+ arena.dispose();
770
+ ctx.dispose();
771
+ });
772
+
773
+ test("module with class export (0.29+)", async () => {
774
+ const ctx = (await getQuickJS()).newContext();
775
+ const arena = new Arena(ctx, { isMarshalable: true });
776
+
777
+ // Export objects and static methods from a class
778
+ const exports = arena.evalModule(`
779
+ export class Counter {
780
+ static create(initial = 0) {
781
+ return { count: initial };
782
+ }
783
+ static increment(obj) {
784
+ return ++obj.count;
785
+ }
786
+ }
787
+ `);
788
+
789
+ // Static methods can be called from the host
790
+ const counter = exports.Counter.create(10);
791
+ expect(counter.count).toBe(10);
792
+ expect(exports.Counter.increment(counter)).toBe(11);
793
+ expect(counter.count).toBe(11);
794
+
795
+ arena.dispose();
796
+ ctx.dispose();
797
+ });
798
+
799
+ test("module with top-level await (0.29+)", async () => {
800
+ const ctx = (await getQuickJS()).newContext();
801
+ const arena = new Arena(ctx, { isMarshalable: true });
802
+
803
+ const exportsPromise = arena.evalModule(`
804
+ export const data = await Promise.resolve(123);
805
+ export const message = "loaded";
806
+ `);
807
+
808
+ expect(exportsPromise).toBeInstanceOf(Promise);
809
+
810
+ arena.executePendingJobs();
811
+
812
+ const exports = await exportsPromise;
813
+ expect(exports.data).toBe(123);
814
+ expect(exports.message).toBe("loaded");
815
+
816
+ arena.dispose();
817
+ ctx.dispose();
818
+ });
718
819
  });
719
820
 
720
821
  describe("memory management", () => {
@@ -911,3 +1012,23 @@ describe("memory management", () => {
911
1012
  ctx.dispose();
912
1013
  });
913
1014
  });
1015
+
1016
+ describe("intrinsics configuration", () => {
1017
+ test("intrinsics can be configured when creating context", async () => {
1018
+ const quickjs = await getQuickJS();
1019
+ const runtime = quickjs.newRuntime();
1020
+
1021
+ // Example: disable eval for sandboxing
1022
+ const ctx = runtime.newContext({ intrinsics: { Eval: false } });
1023
+ const arena = new Arena(ctx, { isMarshalable: true });
1024
+
1025
+ // This test demonstrates that intrinsics are configured at context creation
1026
+ // The actual restrictions would be enforced by quickjs-emscripten
1027
+ expect(arena).toBeDefined();
1028
+ expect(arena.context).toBeDefined();
1029
+
1030
+ arena.dispose();
1031
+ ctx.dispose();
1032
+ runtime.dispose();
1033
+ });
1034
+ });
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import type {
4
4
  QuickJSContext,
5
5
  SuccessOrFail,
6
6
  VmCallResult,
7
+ Intrinsics,
7
8
  } from "quickjs-emscripten";
8
9
 
9
10
  import { wrapContext, QuickJSContextEx } from "./contextex";
@@ -31,6 +32,8 @@ export {
31
32
  consumeAll,
32
33
  };
33
34
 
35
+ export type { Intrinsics };
36
+
34
37
  export type Options = {
35
38
  /** 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. */
36
39
  isMarshalable?: boolean | "json" | ((target: any) => boolean | "json");
@@ -104,24 +107,40 @@ export class Arena {
104
107
  }
105
108
 
106
109
  /**
107
- * Evaluate ES module code in the VM. The module can import/export, but the return value
108
- * depends on whether the module exports are accessible (implementation varies by quickjs-emscripten version).
109
- * Use this for side effects or when you don't need access to exports.
110
+ * Evaluate ES module code in the VM and get the module's exports.
111
+ *
112
+ * Requires quickjs-emscripten >= 0.29.0 for export access.
110
113
  *
111
114
  * @param code - The ES module code to evaluate
112
115
  * @param filename - Optional filename for debugging purposes (default: "module.js")
113
- * @returns Undefined in most cases (module side effects are applied)
116
+ * @returns The module's exports object, or a Promise resolving to exports if using top-level await
114
117
  *
115
118
  * @example
116
119
  * ```js
117
- * // Execute module code with side effects
118
- * arena.expose({ data: { count: 0 } });
119
- * arena.evalModule('import { data } from "globals"; data.count = 42;'); // undefined, but data.count is now 42
120
+ * // Simple module with exports
121
+ * const exports = arena.evalModule(`
122
+ * export const value = 42;
123
+ * export function greet(name) {
124
+ * return "Hello, " + name;
125
+ * }
126
+ * `);
127
+ * console.log(exports.value); // 42
128
+ * console.log(exports.greet("World")); // "Hello, World"
129
+ *
130
+ * // Module with default export
131
+ * const mod = arena.evalModule('export default function(x) { return x * 2; }');
132
+ * console.log(mod.default(21)); // 42
133
+ *
134
+ * // Module with top-level await
135
+ * const promise = arena.evalModule('export const data = await Promise.resolve(123);');
136
+ * arena.executePendingJobs();
137
+ * const exports = await promise;
138
+ * console.log(exports.data); // 123
120
139
  * ```
121
140
  */
122
- evalModule(code: string, filename = "module.js"): void {
141
+ evalModule<T = any>(code: string, filename = "module.js"): T | Promise<T> {
123
142
  const handle = this.context.evalCode(code, filename, { type: "module" });
124
- this._unwrapResultAndUnmarshal(handle);
143
+ return this._unwrapResultAndUnmarshal(handle);
125
144
  }
126
145
 
127
146
  /**
package/src/vmutil.ts CHANGED
@@ -10,10 +10,12 @@ export function fn(
10
10
  code: string,
11
11
  ): ((thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]) => QuickJSHandle) & Disposable {
12
12
  const handle = ctx.unwrapResult(ctx.evalCode(code));
13
- const f = (thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]): any => {
13
+ const f: any = (thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]): any => {
14
14
  return ctx.unwrapResult(ctx.callFunction(handle, thisArg ?? ctx.undefined, ...args));
15
15
  };
16
- f.dispose = () => handle.dispose();
16
+ const disposeFn = () => handle.dispose();
17
+ f.dispose = disposeFn;
18
+ f[Symbol.dispose] = disposeFn;
17
19
  f.alive = true;
18
20
  Object.defineProperty(f, "alive", {
19
21
  get: () => handle.alive,