extism / js-pdk

Write Extism plugins in JavaScript & TypeScript
42 stars 16 forks source link

Export mapping relies on the order of declarations #63

Closed Phault closed 2 months ago

Phault commented 2 months ago

Say I have the following two exports defined:

// src/index.ts

export function start() {
  console.log('start');
}

export function end() {
  console.log('end');
}
// src/index.d.ts

declare module "main" {
  export function start(): void;
  export function end(): void;
}

I bundle src/index.ts to /dist/index.js with esbuild using cjs format and es2020 as target, then build the wasm using extism-js like with dist/index.js and src/index.d.ts.

If I then call the start wasm export, surprise: end will be logged:

❯ extism call ../bundled.wasm start --wasi --log-level debug
2024/04/10 18:00:35 Calling function : start
2024/04/10 18:00:35 end

Part of the reason in this case, is that esbuild sorts the exports alphabetically in the module.exports object. So end is suddenly defined first, but it still points to the end function nonetheless:

// dist/index.js

// snip...

var src_exports = {};
__export(src_exports, {
  end: () => end,
  start: () => start
});
module.exports = __toCommonJS(src_exports);
function start() {
  console.log("start");
}
function end() {
  console.log("end");
}

Now the order in the declaration doesn't match module.exports though, so something in the wasm building step seems to rely on the order being 1:1.

bhelx commented 2 months ago

Thanks for reporting. It should be mapping them by name but perhaps we have a regression here. There is a trick we do where we need to sort the exports then map them by index. So there might be a regression there. We will look into it and fix.