From cfe296bcc904c589a28a8bd918279ef60ab5357c Mon Sep 17 00:00:00 2001 From: Adria Navarro <adria@budibase.com> Date: Thu, 30 Jan 2025 10:55:57 +0100 Subject: [PATCH] Add polyfills --- .../bundles/bson-polyfills.ivm.bundle.js | 52 ++++++++++++++----- .../server/src/jsRunner/vm/isolated-vm.ts | 14 ----- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/packages/server/src/jsRunner/bundles/bson-polyfills.ivm.bundle.js b/packages/server/src/jsRunner/bundles/bson-polyfills.ivm.bundle.js index e7949042c8..94d08b84ed 100644 --- a/packages/server/src/jsRunner/bundles/bson-polyfills.ivm.bundle.js +++ b/packages/server/src/jsRunner/bundles/bson-polyfills.ivm.bundle.js @@ -78,17 +78,45 @@ if (typeof btoa !== "function") { } } -class TextDecoder { - constructorArgs - - constructor(...constructorArgs) { - this.constructorArgs = constructorArgs - } - - decode(...input) { - return textDecoderCb({ - constructorArgs: this.constructorArgs, - functionArgs: input, - }) +if (typeof TextDecoder === "undefined") { + globalThis.TextDecoder = class { + constructor(encoding = "utf8") { + if (encoding !== "utf8") { + throw new Error( + `Only UTF-8 is supported in this polyfill. Recieved: ${encoding}` + ) + } + } + decode(buffer) { + return String.fromCharCode(...buffer) + } + } +} + +if (typeof TextEncoder === "undefined") { + globalThis.TextEncoder = class { + encode(str) { + const utf8 = [] + for (const i = 0; i < str.length; i++) { + const codePoint = str.charCodeAt(i) + + if (codePoint < 0x80) { + utf8.push(codePoint) + } else if (codePoint < 0x800) { + utf8.push(0xc0 | (codePoint >> 6)) + utf8.push(0x80 | (codePoint & 0x3f)) + } else if (codePoint < 0x10000) { + utf8.push(0xe0 | (codePoint >> 12)) + utf8.push(0x80 | ((codePoint >> 6) & 0x3f)) + utf8.push(0x80 | (codePoint & 0x3f)) + } else { + utf8.push(0xf0 | (codePoint >> 18)) + utf8.push(0x80 | ((codePoint >> 12) & 0x3f)) + utf8.push(0x80 | ((codePoint >> 6) & 0x3f)) + utf8.push(0x80 | (codePoint & 0x3f)) + } + } + return new Uint8Array(utf8) + } } } diff --git a/packages/server/src/jsRunner/vm/isolated-vm.ts b/packages/server/src/jsRunner/vm/isolated-vm.ts index 3123bcaa44..37ee048dc2 100644 --- a/packages/server/src/jsRunner/vm/isolated-vm.ts +++ b/packages/server/src/jsRunner/vm/isolated-vm.ts @@ -161,21 +161,7 @@ export class IsolatedVM implements VM { const bsonSource = loadBundle(BundleType.BSON) - // "Polyfilling" text decoder and other utils. `bson.deserialize` requires decoding. We are creating a bridge function so we don't need to inject the full library const bsonPolyfills = loadBundle(BundleType.BSON_POLYFILLS) - this.addToContext({ - textDecoderCb: new ivm.Callback( - (args: { - constructorArgs: any - functionArgs: Parameters<InstanceType<typeof TextDecoder>["decode"]> - }) => { - const result = new TextDecoder(...args.constructorArgs).decode( - ...args.functionArgs - ) - return result - } - ), - }) const script = this.isolate.compileScriptSync( `${bsonPolyfills};${bsonSource}`