laverdet / isolated-vm

Secure & isolated JS environments for nodejs
ISC License
2.19k stars 154 forks source link

Running async code, gives me Promise can not be clonned #384

Closed demon-user closed 1 year ago

demon-user commented 1 year ago

I have a simple use case, and am a complete beginner here. 1.I have an async function

 const code = `
   async function add(a, b) {
      return a + b;
    }
`;

I need to run the above code and return the result.

import ivm from 'isolated-vm';

(async () => {
  const isolate = new ivm.Isolate();
  const context = await isolate.createContext();
  const script = await isolate.compileScript(code);

  const addFn = await context.global.get('add', { reference: true });
  const result = await addFn.apply(undefined, [1, 2]);

  console.log(result)
})()
laverdet commented 1 year ago

promise: true https://github.com/laverdet/isolated-vm#transferoptions

demon-user commented 1 year ago
 async function getSourceScript() {
   return `
     async function add(a, b) {
       return a + b;
     }
   `;
  }

  const vm = new ivm.Isolate({ memoryLimit: 128 });
  const context = await vm.createContext();
  const sourceScript = await getSourceScript();

  await vm.compileScript(sourceScript);

  const runFn = await context.global.get('add', { reference: true, promise: true });

  const result = await runFn.apply(undefined, [1, 2]);

  console.log(result);

Produces the following error:

/src/executor.ts:14
  meta: Request['meta'];
                               ^
TypeError: Reference is not a function
    at (<isolated-vm boundary>)
    at functionExecutor (
regmish commented 1 year ago

You could use a small helper script and run it like this.

const helperScript = `
  helper = async (num1, num2) => {
    const result = await add(num1, num2);
    callback.applySync(undefined, [ result ]);
  };
`;

 async function getSourceScript() {
   return `
     async function add(a, b) {
       return a + b;
     }
   `;
  }

  const vm = new ivm.Isolate({ memoryLimit: 128 });
  const context = await vm.createContext();

  const sourceScript = await getSourceScript();

 // we define a callback in global scope of isolate context to get the result back
  await context.global.set('callback', new ivm.Reference(function(result) {
     console.log('output of the code', result);
  }));

  await vm.compileScript(sourceScript).run(context);

  // Run our helper code, which eventually calls the code
  await context.evalClosure(helperScript);

 const helper = await context.global.get('helper', { reference: true, promise: true });

 try {
    await helper.apply(undefined, [100, 200]);
  } catch (error) {
    console.log('error', error);
  }