From fb57cb15ac7a8c64cedb73b48f0c70001a8bad33 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 8 Feb 2024 13:22:28 +0100 Subject: [PATCH] Fix parsing utf8 results --- packages/server/src/jsRunner/vm/index.ts | 49 ++++++++++++++++++++---- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/server/src/jsRunner/vm/index.ts b/packages/server/src/jsRunner/vm/index.ts index 2508f57a6c..06aa4fd9c1 100644 --- a/packages/server/src/jsRunner/vm/index.ts +++ b/packages/server/src/jsRunner/vm/index.ts @@ -141,14 +141,6 @@ export class IsolatedVM implements VM { bsonData: bson.BSON.serialize({ data }), }) - const bsonSource = loadBundle(BundleType.BSON) - const bsonModule = this.#isolate.compileModuleSync(bsonSource) - bsonModule.instantiateSync(this.#vm, specifier => { - throw new Error(`No imports allowed. Required: ${specifier}`) - }) - - this.#moduleHandler.registerModule(bsonModule, "{deserialize, toJson}") - // If we need to parse bson, we follow the next steps: // 1. Serialise the data from potential BSON to buffer before passing it to the isolate // 2. Deserialise the data within the isolate, to get the original data @@ -161,6 +153,47 @@ export class IsolatedVM implements VM { return toJson(result); })();` + const bsonSource = loadBundle(BundleType.BSON) + + this.#addToContext({ + textDecoderCb: new ivm.Callback( + (args: { + constructorArgs: any + functionArgs: Parameters["decode"]> + }) => { + const result = new TextDecoder(...args.constructorArgs).decode( + ...args.functionArgs + ) + return result + } + ), + }) + + // "Polyfilling" text decoder. `bson.deserialize` requires decoding. We are creating a bridge function so we don't need to inject the full library + const textDecoderPolyfill = class TextDecoder { + constructorArgs + + constructor(...constructorArgs: any) { + this.constructorArgs = constructorArgs + } + + decode(...input: any) { + // @ts-ignore + return textDecoderCb({ + constructorArgs: this.constructorArgs, + functionArgs: input, + }) + } + }.toString() + const bsonModule = this.#isolate.compileModuleSync( + `${textDecoderPolyfill};${bsonSource}` + ) + bsonModule.instantiateSync(this.#vm, specifier => { + throw new Error(`No imports allowed. Required: ${specifier}`) + }) + + this.#moduleHandler.registerModule(bsonModule, "{deserialize, toJson}") + return this }