Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[webextension] Failed to load extension from: /A. Could not load file B.js for content script. It isn't UTF-8 encoded. #8877

Closed
fregante opened this issue Mar 11, 2023 · 8 comments · Fixed by #9243

Comments

@fregante
Copy link
Contributor

fregante commented Mar 11, 2023

🐛 bug report

Starting in v2.7, parcel started generating an invalid extension and I can't quite figure out why.

🎛 Configuration (.babelrc, package.json, cli command)

parcel watch # this broke in 2.7
parcel build # this was already broken
{
	"extends": "@parcel/config-webextension",
	"transformers": {
		"*.md": ["@parcel/transformer-raw"]
	}
}

😯 Current Behavior

When loading the extension into Chrome, the browser fails with this error:

Failed to load extension from: **. Could not load file ** for content script. It isn't UTF-8 encoded.

💻 Code Sample

Checkout https://github.com/pixiebrix/webext-messenger/tree/e5aee47f4c684b29cf75229f68ef3aa1de6599c5

npm install
npx parcel build

Then load the extension from the dist folder into Chrome, for example by running this in the root:

npx web-ext run --target=chromium

You can downgrade parcel to "fix" the issue:

npm install -D [email protected] @parcel/[email protected]

🌍 Your Environment

Software Version(s)
Parcel 2.7.0
Node v18.13.0
npm 9.2.0
Operating System macOS 13.2.1
@fregante
Copy link
Contributor Author

fregante commented Mar 11, 2023

The only difference I see is that Parcel stopped encoding some strings, or potentially decoded some incorrectly. Here's the diff between the two files. Green is the good version, 2.6.2:

reduced diff
diff --git a/background/api.test.js b/background/api.test.js
index 7055668..1ae17ee 100644
--- a/background/api.test.js
+++ b/background/api.test.js

@@ -4877,17 +4882,17 @@ function utf8CheckIncomplete(self, buf, i) {
 function utf8CheckExtraBytes(self, buf, p) {
     if ((buf[0] & 0xC0) !== 0x80) {
         self.lastNeed = 0;
-        return "�";
+        return "\uFFFD";
     }
     if (self.lastNeed > 1 && buf.length > 1) {
         if ((buf[1] & 0xC0) !== 0x80) {
             self.lastNeed = 1;
-            return "�";
+            return "\uFFFD";
         }
         if (self.lastNeed > 2 && buf.length > 2) {
             if ((buf[2] & 0xC0) !== 0x80) {
                 self.lastNeed = 2;
-                return "�";
+                return "\uFFFD";
             }
         }
     }
@@ -4919,7 +4924,7 @@ function utf8Text(buf, i) {
 // character.
 function utf8End(buf) {
     var r = buf && buf.length ? this.write(buf) : "";
-    if (this.lastNeed) return r + "�";
+    if (this.lastNeed) return r + "\uFFFD";
     return r;
 }
 // UTF-16LE typically needs two bytes per character, but even if we have an even
@@ -5023,8 +5028,8 @@ SafeBuffer.allocUnsafeSlow = function(size) {
 };
 
 },{"buffer":"aKkui"}],"FaDmO":[function(require,module,exports) {
-var process = require("process");
 "use strict";
+var process = require("process");
 var _Object$setPrototypeO;
 function _defineProperty(obj, key, value) {
     if (key in obj) Object.defineProperty(obj, key, {
@@ -5561,9 +5566,9 @@ function pipeline() {
 module.exports = pipeline;
 
 },{"../../../errors":"3RxKp","./end-of-stream":"1Ouyq"}],"6OySS":[function(require,module,exports) {
-var process = require("process");
-var __dirname = "node_modules/tape/lib";
 "use strict";
+var __dirname = "node_modules/tape/lib";
+var process = require("process");
 var deepEqual = require("deep-equal");
 var defined = require("defined");
 var path = require("path");
@@ -6482,7 +6487,7 @@ if (!Object.keys) {
             } catch (e) {
                 return true;
             }
-        } catch (e1) {
+        } catch (e) {
             return true;
         }
         return false;

@@ -8695,8 +8700,8 @@ module.exports = function shimAssign() {
 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 // USE OR OTHER DEALINGS IN THE SOFTWARE.
-var process = require("process");
 "use strict";
+var process = require("process");
 function assertPath(path) {
     if (typeof path !== "string") throw new TypeError("Path must be a string. Received " + JSON.stringify(path));
 }
@@ -9137,7 +9142,7 @@ var RequireObjectCoercible = require("es-abstract/2021/RequireObjectCoercible");
 var ToString = require("es-abstract/2021/ToString");
 var callBound = require("call-bind/callBound");
 var $replace = callBound("String.prototype.replace");
-var mvsIsWS = /^\s$/.test("᠎");
+var mvsIsWS = /^\s$/.test("\u180E");
 /* eslint-disable no-control-regex */ var leftWhitespace = mvsIsWS ? /^[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+/ : /^[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+/;
 var rightWhitespace = mvsIsWS ? /[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+$/ : /[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+$/;
 /* eslint-enable no-control-regex */ module.exports = function trim() {
@@ -9159,8 +9164,8 @@ module.exports = function ToString(argument) {
 },{"get-intrinsic":"ad4UE"}],"5e5aa":[function(require,module,exports) {
 "use strict";
 var implementation = require("./implementation");
-var zeroWidthSpace = "​";
-var mongolianVowelSeparator = "᠎";
+var zeroWidthSpace = "\u200B";
+var mongolianVowelSeparator = "\u180E";
 module.exports = function getPolyfill() {
     if (String.prototype.trim && zeroWidthSpace.trim() === zeroWidthSpace && mongolianVowelSeparator.trim() === mongolianVowelSeparator && ("_" + mongolianVowelSeparator).trim() === "_" + mongolianVowelSeparator && (mongolianVowelSeparator + "_").trim() === mongolianVowelSeparator + "_") return String.prototype.trim;
     return implementation;
@@ -9269,16 +9274,16 @@ var isOctal = regexTester(/^0o[0-7]+$/i);
 var isInvalidHexLiteral = regexTester(/^[-+]0x[0-9a-f]+$/i);
 var nonWS = [
     "\x85",
-    "​",
-    "�"
+    "\u200B",
+    "\uFFFE"
 ].join("");
 var nonWSregex = new $RegExp("[" + nonWS + "]", "g");
 var hasNonWS = regexTester(nonWSregex);
 // whitespace from: https://es5.github.io/#x15.5.4.20
 // implementation from https://github.com/es-shims/es5-shim/blob/v3.4.0/es5-shim.js#L1304-L1324
 var ws = [
-    "	\n\v\f\r \xa0 ᠎    ",
-    "          \u2028",
+    "	\n\v\f\r \xa0\u1680\u180E\u2000\u2001\u2002\u2003",
+    "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028",
     "\u2029\uFEFF"
 ].join("");
 var trimRegex = new RegExp("(^[" + ws + "]+)|([" + ws + "]+$)", "g");
@@ -9858,7 +9863,7 @@ const storeTabData = (0, _sharedJs.once)(async ()=>{
         tabDataStatus = "received";
     } catch (error) {
         tabDataStatus = "error";
-        throw new (0, _sharedJs.MessengerError)("Tab registration failed. This page won’t be able to receive messages that require tab information", // @ts-expect-error TODO: update lib to accept Error#cause
+        throw new (0, _sharedJs.MessengerError)("Tab registration failed. This page won\u2019t be able to receive messages that require tab information", // @ts-expect-error TODO: update lib to accept Error#cause
         {
             cause: error
         });
@@ -9942,7 +9947,7 @@ function manageConnection(type, options, target, sendMessage) {
     });
 }
 async function manageMessage(type, target, sendMessage) {
-    const response = await (0, _pRetryDefault.default)(async ()=>{
+    const response1 = await (0, _pRetryDefault.default)(async ()=>{
         const response = await sendMessage();
         if (isMessengerResponse(response)) return response;
         // If no one answers, `response` will be `undefined`
@@ -9979,12 +9984,12 @@ async function manageMessage(type, target, sendMessage) {
         if (error?.message === _errorNonExistingTarget) throw new (0, _sharedJs.MessengerError)(`The target ${JSON.stringify(target)} for ${type} was not found`);
         throw error;
     });
-    if ("error" in response) {
-        (0, _sharedJs.debug)(type, "↘️ replied with error", response.error);
-        throw (0, _serializeError.deserializeError)(response.error);
+    if ("error" in response1) {
+        (0, _sharedJs.debug)(type, "\u2198\uFE0F replied with error", response1.error);
+        throw (0, _serializeError.deserializeError)(response1.error);
     }
-    (0, _sharedJs.debug)(type, "↘️ replied successfully", response.value);
-    return response.value;
+    (0, _sharedJs.debug)(type, "\u2198\uFE0F replied successfully", response1.value);
+    return response1.value;
 }
 function messenger(type, options, target, ...args) {
     // Message goes to extension page

@@ -10901,21 +10906,21 @@ const backgroundOnly = (0, _indexJs.getMethod)("backgroundOnly", (0, _indexJs.ba
 const getSelf = (0, _indexJs.getMethod)("getSelf", (0, _indexJs.backgroundTarget));
 
 },{"../../index.js":"kOnKs","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"kOnKs":[function(require,module,exports) {
-// Imports must use the .js extension because ESM requires it and TS refuses to rewrite .ts to .js
 var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
 parcelHelpers.defineInteropFlag(exports);
 parcelHelpers.export(exports, "getThisFrame", ()=>(0, _thisTargetJs.getThisFrame));
 parcelHelpers.export(exports, "getTopLevelFrame", ()=>(0, _thisTargetJs.getTopLevelFrame));
+var _thisTargetJs = require("./thisTarget.js");
+// Imports must use the .js extension because ESM requires it and TS refuses to rewrite .ts to .js
 var _receiverJs = require("./receiver.js");
 parcelHelpers.exportAll(_receiverJs, exports);
 var _senderJs = require("./sender.js");
 parcelHelpers.exportAll(_senderJs, exports);
 var _typesJs = require("./types.js");
 parcelHelpers.exportAll(_typesJs, exports);
-var _thisTargetJs = require("./thisTarget.js");
 (0, _thisTargetJs.initPrivateApi)();
 
-},{"./receiver.js":"5R24O","./sender.js":"fkc9X","./types.js":"ah9ro","./thisTarget.js":"7l5QG","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"ah9ro":[function(require,module,exports) {
+},{"./thisTarget.js":"7l5QG","./receiver.js":"5R24O","./sender.js":"fkc9X","./types.js":"ah9ro","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"ah9ro":[function(require,module,exports) {
 var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
 parcelHelpers.defineInteropFlag(exports);
full diff
diff --git a/background/api.test.js b/background/api.test.js
index 7055668..1ae17ee 100644
--- a/background/api.test.js
+++ b/background/api.test.js
@@ -143,8 +143,8 @@
     }
   }
 })({"6QZYW":[function(require,module,exports) {
-/* eslint-disable unicorn/no-await-expression-member */ var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
-var _tape = require("tape");
+var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
+/* eslint-disable unicorn/no-await-expression-member */ var _tape = require("tape");
 var _tapeDefault = parcelHelpers.interopDefault(_tape);
 var _webextDetectPage = require("webext-detect-page");
 var _thisTargetJs = require("../../thisTarget.js");
@@ -190,7 +190,7 @@ else (0, _tapeDefault.default)("should receive information from the caller", asy
         error.stack.includes("at Object.throws") || error.stack.includes("throws@moz-"), "The stacktrace must include the original name of the method");
     }
 });
-(0, _tapeDefault.default)("should receive error from the background if it’s not registered", async (t)=>{
+(0, _tapeDefault.default)("should receive error from the background if it\u2019s not registered", async (t)=>{
     try {
         await (0, _apiJs.notRegistered)();
         t.fail("notRegistered() should have thrown but did not");
@@ -225,8 +225,8 @@ else {
 }
 
 },{"tape":"xTT0D","webext-detect-page":"2YdqU","../../thisTarget.js":"7l5QG","../helpers.js":"3NXFf","./api.js":"awqWQ","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"xTT0D":[function(require,module,exports) {
-var process = require("process");
 "use strict";
+var process = require("process");
 var defined = require("defined");
 var createDefaultStream = require("./lib/default_stream");
 var Test = require("./lib/test");
@@ -414,7 +414,7 @@ function runTimeout(fun) {
     try {
         // when when somebody has screwed with setTimeout but no I.E. maddness
         return cachedSetTimeout(fun, 0);
-    } catch (e1) {
+    } catch (e) {
         try {
             // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
             return cachedSetTimeout.call(null, fun, 0);
@@ -435,7 +435,7 @@ function runClearTimeout(marker) {
     try {
         // when when somebody has screwed with setTimeout but no I.E. maddness
         return cachedClearTimeout(marker);
-    } catch (e1) {
+    } catch (e) {
         try {
             // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
             return cachedClearTimeout.call(null, marker);
@@ -527,8 +527,8 @@ module.exports = function() {
 };
 
 },{}],"fX2Mf":[function(require,module,exports) {
-var process = require("process");
 "use strict";
+var process = require("process");
 var through = require("through");
 var fs = require("fs");
 module.exports = function() {
@@ -538,20 +538,26 @@ module.exports = function() {
     function write(buf) {
         for(var i = 0; i < buf.length; i++){
             var c = typeof buf === "string" ? buf.charAt(i) : String.fromCharCode(buf[i]);
-            if (c === "\n") flush();
-            else line += c;
+            if (c === "\n") {
+                flush();
+            } else {
+                line += c;
+            }
         }
     }
     function flush() {
-        if (fs.writeSync && /^win/.test(process.platform)) try {
-            fs.writeSync(1, line + "\n");
-        } catch (e) {
-            stream.emit("error", e);
-        }
-        else try {
-            console.log(line); // eslint-disable-line no-console
-        } catch (e1) {
-            stream.emit("error", e1);
+        if (fs.writeSync && /^win/.test(process.platform)) {
+            try {
+                fs.writeSync(1, line + "\n");
+            } catch (e) {
+                stream.emit("error", e);
+            }
+        } else {
+            try {
+                console.log(line); // eslint-disable-line no-console
+            } catch (e) {
+                stream.emit("error", e);
+            }
         }
         line = "";
     }
@@ -1148,9 +1154,9 @@ module.exports = function inherits(ctor, superCtor) {
 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 // USE OR OTHER DEALINGS IN THE SOFTWARE.
+"use strict";
 var global = arguments[3];
 var process = require("process");
-"use strict";
 module.exports = Readable;
 /*<replacement>*/ var Duplex;
 /*</replacement>*/ Readable.ReadableState = ReadableState;
@@ -1879,7 +1885,7 @@ Readable.prototype.wrap = function(stream) {
         };
     }(i);
      // proxy certain important events.
-    for(var n = 0; n < kProxyEvents.length; n++)stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));
+    for(var n1 = 0; n1 < kProxyEvents.length; n1++)stream.on(kProxyEvents[n1], this.emit.bind(this, kProxyEvents[n1]));
      // when we try to consume some more bytes, simply unpause the
     // underlying stream.
     this._read = function(n) {
@@ -2492,25 +2498,25 @@ function arrayIndexOf(arr, val, byteOffset, encoding, dir) {
         if (indexSize === 1) return buf[i];
         else return buf.readUInt16BE(i * indexSize);
     }
-    let i;
+    let i1;
     if (dir) {
         let foundIndex = -1;
-        for(i = byteOffset; i < arrLength; i++)if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
-            if (foundIndex === -1) foundIndex = i;
-            if (i - foundIndex + 1 === valLength) return foundIndex * indexSize;
+        for(i1 = byteOffset; i1 < arrLength; i1++)if (read(arr, i1) === read(val, foundIndex === -1 ? 0 : i1 - foundIndex)) {
+            if (foundIndex === -1) foundIndex = i1;
+            if (i1 - foundIndex + 1 === valLength) return foundIndex * indexSize;
         } else {
-            if (foundIndex !== -1) i -= i - foundIndex;
+            if (foundIndex !== -1) i1 -= i1 - foundIndex;
             foundIndex = -1;
         }
     } else {
         if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;
-        for(i = byteOffset; i >= 0; i--){
+        for(i1 = byteOffset; i1 >= 0; i1--){
             let found = true;
-            for(let j = 0; j < valLength; j++)if (read(arr, i + j) !== read(val, j)) {
+            for(let j = 0; j < valLength; j++)if (read(arr, i1 + j) !== read(val, j)) {
                 found = false;
                 break;
             }
-            if (found) return i;
+            if (found) return i1;
         }
     }
     return -1;
@@ -2735,23 +2741,23 @@ Buffer.prototype.slice = function slice(start, end) {
     if (offset % 1 !== 0 || offset < 0) throw new RangeError("offset is not uint");
     if (offset + ext > length) throw new RangeError("Trying to access beyond buffer length");
 }
-Buffer.prototype.readUintLE = Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) {
+Buffer.prototype.readUintLE = Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength1, noAssert) {
     offset = offset >>> 0;
-    byteLength = byteLength >>> 0;
-    if (!noAssert) checkOffset(offset, byteLength, this.length);
+    byteLength1 = byteLength1 >>> 0;
+    if (!noAssert) checkOffset(offset, byteLength1, this.length);
     let val = this[offset];
     let mul = 1;
     let i = 0;
-    while(++i < byteLength && (mul *= 0x100))val += this[offset + i] * mul;
+    while(++i < byteLength1 && (mul *= 0x100))val += this[offset + i] * mul;
     return val;
 };
-Buffer.prototype.readUintBE = Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) {
+Buffer.prototype.readUintBE = Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength2, noAssert) {
     offset = offset >>> 0;
-    byteLength = byteLength >>> 0;
-    if (!noAssert) checkOffset(offset, byteLength, this.length);
-    let val = this[offset + --byteLength];
+    byteLength2 = byteLength2 >>> 0;
+    if (!noAssert) checkOffset(offset, byteLength2, this.length);
+    let val = this[offset + --byteLength2];
     let mul = 1;
-    while(byteLength > 0 && (mul *= 0x100))val += this[offset + --byteLength] * mul;
+    while(byteLength2 > 0 && (mul *= 0x100))val += this[offset + --byteLength2] * mul;
     return val;
 };
 Buffer.prototype.readUint8 = Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) {
@@ -2785,8 +2791,8 @@ Buffer.prototype.readBigUInt64LE = defineBigIntMethod(function readBigUInt64LE(o
     const first = this[offset];
     const last = this[offset + 7];
     if (first === undefined || last === undefined) boundsError(offset, this.length - 8);
-    const lo = first + this[++offset] * 256 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24;
-    const hi = this[++offset] + this[++offset] * 256 + this[++offset] * 2 ** 16 + last * 2 ** 24;
+    const lo = first + this[++offset] * 256 + this[++offset] * 65536 + this[++offset] * 2 ** 24;
+    const hi = this[++offset] + this[++offset] * 256 + this[++offset] * 65536 + last * 2 ** 24;
     return BigInt(lo) + (BigInt(hi) << BigInt(32));
 });
 Buffer.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE(offset) {
@@ -2795,32 +2801,32 @@ Buffer.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE(o
     const first = this[offset];
     const last = this[offset + 7];
     if (first === undefined || last === undefined) boundsError(offset, this.length - 8);
-    const hi = first * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 256 + this[++offset];
-    const lo = this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 256 + last;
+    const hi = first * 2 ** 24 + this[++offset] * 65536 + this[++offset] * 256 + this[++offset];
+    const lo = this[++offset] * 2 ** 24 + this[++offset] * 65536 + this[++offset] * 256 + last;
     return (BigInt(hi) << BigInt(32)) + BigInt(lo);
 });
-Buffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) {
+Buffer.prototype.readIntLE = function readIntLE(offset, byteLength3, noAssert) {
     offset = offset >>> 0;
-    byteLength = byteLength >>> 0;
-    if (!noAssert) checkOffset(offset, byteLength, this.length);
+    byteLength3 = byteLength3 >>> 0;
+    if (!noAssert) checkOffset(offset, byteLength3, this.length);
     let val = this[offset];
     let mul = 1;
     let i = 0;
-    while(++i < byteLength && (mul *= 0x100))val += this[offset + i] * mul;
+    while(++i < byteLength3 && (mul *= 0x100))val += this[offset + i] * mul;
     mul *= 0x80;
-    if (val >= mul) val -= Math.pow(2, 8 * byteLength);
+    if (val >= mul) val -= Math.pow(2, 8 * byteLength3);
     return val;
 };
-Buffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) {
+Buffer.prototype.readIntBE = function readIntBE(offset, byteLength4, noAssert) {
     offset = offset >>> 0;
-    byteLength = byteLength >>> 0;
-    if (!noAssert) checkOffset(offset, byteLength, this.length);
-    let i = byteLength;
+    byteLength4 = byteLength4 >>> 0;
+    if (!noAssert) checkOffset(offset, byteLength4, this.length);
+    let i = byteLength4;
     let mul = 1;
     let val = this[offset + --i];
     while(i > 0 && (mul *= 0x100))val += this[offset + --i] * mul;
     mul *= 0x80;
-    if (val >= mul) val -= Math.pow(2, 8 * byteLength);
+    if (val >= mul) val -= Math.pow(2, 8 * byteLength4);
     return val;
 };
 Buffer.prototype.readInt8 = function readInt8(offset, noAssert) {
@@ -2857,9 +2863,9 @@ Buffer.prototype.readBigInt64LE = defineBigIntMethod(function readBigInt64LE(off
     const first = this[offset];
     const last = this[offset + 7];
     if (first === undefined || last === undefined) boundsError(offset, this.length - 8);
-    const val = this[offset + 4] + this[offset + 5] * 256 + this[offset + 6] * 2 ** 16 + (last << 24 // Overflow
+    const val = this[offset + 4] + this[offset + 5] * 256 + this[offset + 6] * 65536 + (last << 24 // Overflow
     );
-    return (BigInt(val) << BigInt(32)) + BigInt(first + this[++offset] * 256 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24);
+    return (BigInt(val) << BigInt(32)) + BigInt(first + this[++offset] * 256 + this[++offset] * 65536 + this[++offset] * 2 ** 24);
 });
 Buffer.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE(offset) {
     offset = offset >>> 0;
@@ -2867,9 +2873,8 @@ Buffer.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE(off
     const first = this[offset];
     const last = this[offset + 7];
     if (first === undefined || last === undefined) boundsError(offset, this.length - 8);
-    const val = (first << 24) + // Overflow
-    this[++offset] * 2 ** 16 + this[++offset] * 256 + this[++offset];
-    return (BigInt(val) << BigInt(32)) + BigInt(this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 256 + last);
+    const val = (first << 24) + this[++offset] * 65536 + this[++offset] * 256 + this[++offset];
+    return (BigInt(val) << BigInt(32)) + BigInt(this[++offset] * 2 ** 24 + this[++offset] * 65536 + this[++offset] * 256 + last);
 });
 Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
     offset = offset >>> 0;
@@ -2896,33 +2901,33 @@ function checkInt(buf, value, offset, ext, max, min) {
     if (value > max || value < min) throw new RangeError('"value" argument is out of bounds');
     if (offset + ext > buf.length) throw new RangeError("Index out of range");
 }
-Buffer.prototype.writeUintLE = Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) {
+Buffer.prototype.writeUintLE = Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength5, noAssert) {
     value = +value;
     offset = offset >>> 0;
-    byteLength = byteLength >>> 0;
+    byteLength5 = byteLength5 >>> 0;
     if (!noAssert) {
-        const maxBytes = Math.pow(2, 8 * byteLength) - 1;
-        checkInt(this, value, offset, byteLength, maxBytes, 0);
+        const maxBytes = Math.pow(2, 8 * byteLength5) - 1;
+        checkInt(this, value, offset, byteLength5, maxBytes, 0);
     }
     let mul = 1;
     let i = 0;
     this[offset] = value & 0xFF;
-    while(++i < byteLength && (mul *= 0x100))this[offset + i] = value / mul & 0xFF;
-    return offset + byteLength;
+    while(++i < byteLength5 && (mul *= 0x100))this[offset + i] = value / mul & 0xFF;
+    return offset + byteLength5;
 };
-Buffer.prototype.writeUintBE = Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) {
+Buffer.prototype.writeUintBE = Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength6, noAssert) {
     value = +value;
     offset = offset >>> 0;
-    byteLength = byteLength >>> 0;
+    byteLength6 = byteLength6 >>> 0;
     if (!noAssert) {
-        const maxBytes = Math.pow(2, 8 * byteLength) - 1;
-        checkInt(this, value, offset, byteLength, maxBytes, 0);
+        const maxBytes = Math.pow(2, 8 * byteLength6) - 1;
+        checkInt(this, value, offset, byteLength6, maxBytes, 0);
     }
-    let i = byteLength - 1;
+    let i = byteLength6 - 1;
     let mul = 1;
     this[offset + i] = value & 0xFF;
     while(--i >= 0 && (mul *= 0x100))this[offset + i] = value / mul & 0xFF;
-    return offset + byteLength;
+    return offset + byteLength6;
 };
 Buffer.prototype.writeUint8 = Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) {
     value = +value;
@@ -3013,31 +3018,31 @@ Buffer.prototype.writeBigUInt64LE = defineBigIntMethod(function writeBigUInt64LE
 Buffer.prototype.writeBigUInt64BE = defineBigIntMethod(function writeBigUInt64BE(value, offset = 0) {
     return wrtBigUInt64BE(this, value, offset, BigInt(0), BigInt("0xffffffffffffffff"));
 });
-Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) {
+Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength7, noAssert) {
     value = +value;
     offset = offset >>> 0;
     if (!noAssert) {
-        const limit = Math.pow(2, 8 * byteLength - 1);
-        checkInt(this, value, offset, byteLength, limit - 1, -limit);
+        const limit = Math.pow(2, 8 * byteLength7 - 1);
+        checkInt(this, value, offset, byteLength7, limit - 1, -limit);
     }
     let i = 0;
     let mul = 1;
     let sub = 0;
     this[offset] = value & 0xFF;
-    while(++i < byteLength && (mul *= 0x100)){
+    while(++i < byteLength7 && (mul *= 0x100)){
         if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) sub = 1;
         this[offset + i] = (value / mul >> 0) - sub & 0xFF;
     }
-    return offset + byteLength;
+    return offset + byteLength7;
 };
-Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) {
+Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength8, noAssert) {
     value = +value;
     offset = offset >>> 0;
     if (!noAssert) {
-        const limit = Math.pow(2, 8 * byteLength - 1);
-        checkInt(this, value, offset, byteLength, limit - 1, -limit);
+        const limit = Math.pow(2, 8 * byteLength8 - 1);
+        checkInt(this, value, offset, byteLength8, limit - 1, -limit);
     }
-    let i = byteLength - 1;
+    let i = byteLength8 - 1;
     let mul = 1;
     let sub = 0;
     this[offset + i] = value & 0xFF;
@@ -3045,7 +3050,7 @@ Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noA
         if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) sub = 1;
         this[offset + i] = (value / mul >> 0) - sub & 0xFF;
     }
-    return offset + byteLength;
+    return offset + byteLength8;
 };
 Buffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) {
     value = +value;
@@ -3258,21 +3263,21 @@ function addNumericalSeparator(val) {
 }
 // CHECK FUNCTIONS
 // ===============
-function checkBounds(buf, offset, byteLength) {
+function checkBounds(buf, offset, byteLength9) {
     validateNumber(offset, "offset");
-    if (buf[offset] === undefined || buf[offset + byteLength] === undefined) boundsError(offset, buf.length - (byteLength + 1));
+    if (buf[offset] === undefined || buf[offset + byteLength9] === undefined) boundsError(offset, buf.length - (byteLength9 + 1));
 }
-function checkIntBI(value, min, max, buf, offset, byteLength) {
+function checkIntBI(value, min, max, buf, offset, byteLength10) {
     if (value > max || value < min) {
         const n = typeof min === "bigint" ? "n" : "";
         let range;
-        if (byteLength > 3) {
-            if (min === 0 || min === BigInt(0)) range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`;
-            else range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and < 2 ** ` + `${(byteLength + 1) * 8 - 1}${n}`;
+        if (byteLength10 > 3) {
+            if (min === 0 || min === BigInt(0)) range = `>= 0${n} and < 2${n} ** ${(byteLength10 + 1) * 8}${n}`;
+            else range = `>= -(2${n} ** ${(byteLength10 + 1) * 8 - 1}${n}) and < 2 ** ` + `${(byteLength10 + 1) * 8 - 1}${n}`;
         } else range = `>= ${min}${n} and <= ${max}${n}`;
         throw new errors.ERR_OUT_OF_RANGE("value", range, value);
     }
-    checkBounds(buf, offset, byteLength);
+    checkBounds(buf, offset, byteLength10);
 }
 function validateNumber(value, name) {
     if (typeof value !== "number") throw new errors.ERR_INVALID_ARG_TYPE(name, "number", value);
@@ -3433,13 +3438,13 @@ for(var i = 0, len = code.length; i < len; ++i){
 revLookup["-".charCodeAt(0)] = 62;
 revLookup["_".charCodeAt(0)] = 63;
 function getLens(b64) {
-    var len = b64.length;
-    if (len % 4 > 0) throw new Error("Invalid string. Length must be a multiple of 4");
+    var len1 = b64.length;
+    if (len1 % 4 > 0) throw new Error("Invalid string. Length must be a multiple of 4");
     // Trim off extra bytes after placeholder bytes are found
     // See: https://github.com/beatgammit/base64-js/issues/42
     var validLen = b64.indexOf("=");
-    if (validLen === -1) validLen = len;
-    var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4;
+    if (validLen === -1) validLen = len1;
+    var placeHoldersLen = validLen === len1 ? 0 : 4 - validLen % 4;
     return [
         validLen,
         placeHoldersLen
@@ -3463,20 +3468,20 @@ function toByteArray(b64) {
     var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));
     var curByte = 0;
     // if there are placeholders, only get up to the last complete 4 chars
-    var len = placeHoldersLen > 0 ? validLen - 4 : validLen;
-    var i;
-    for(i = 0; i < len; i += 4){
-        tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];
+    var len2 = placeHoldersLen > 0 ? validLen - 4 : validLen;
+    var i1;
+    for(i1 = 0; i1 < len2; i1 += 4){
+        tmp = revLookup[b64.charCodeAt(i1)] << 18 | revLookup[b64.charCodeAt(i1 + 1)] << 12 | revLookup[b64.charCodeAt(i1 + 2)] << 6 | revLookup[b64.charCodeAt(i1 + 3)];
         arr[curByte++] = tmp >> 16 & 0xFF;
         arr[curByte++] = tmp >> 8 & 0xFF;
         arr[curByte++] = tmp & 0xFF;
     }
     if (placeHoldersLen === 2) {
-        tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;
+        tmp = revLookup[b64.charCodeAt(i1)] << 2 | revLookup[b64.charCodeAt(i1 + 1)] >> 4;
         arr[curByte++] = tmp & 0xFF;
     }
     if (placeHoldersLen === 1) {
-        tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;
+        tmp = revLookup[b64.charCodeAt(i1)] << 10 | revLookup[b64.charCodeAt(i1 + 1)] << 4 | revLookup[b64.charCodeAt(i1 + 2)] >> 2;
         arr[curByte++] = tmp >> 8 & 0xFF;
         arr[curByte++] = tmp & 0xFF;
     }
@@ -3488,28 +3493,28 @@ function tripletToBase64(num) {
 function encodeChunk(uint8, start, end) {
     var tmp;
     var output = [];
-    for(var i = start; i < end; i += 3){
-        tmp = (uint8[i] << 16 & 0xFF0000) + (uint8[i + 1] << 8 & 0xFF00) + (uint8[i + 2] & 0xFF);
+    for(var i2 = start; i2 < end; i2 += 3){
+        tmp = (uint8[i2] << 16 & 0xFF0000) + (uint8[i2 + 1] << 8 & 0xFF00) + (uint8[i2 + 2] & 0xFF);
         output.push(tripletToBase64(tmp));
     }
     return output.join("");
 }
 function fromByteArray(uint8) {
     var tmp;
-    var len = uint8.length;
-    var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
+    var len3 = uint8.length;
+    var extraBytes = len3 % 3 // if we have 1 byte left, pad 2 bytes
     ;
     var parts = [];
     var maxChunkLength = 16383 // must be multiple of 3
     ;
     // go through the array every three bytes, we'll deal with trailing stuff later
-    for(var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength)parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));
+    for(var i3 = 0, len2 = len3 - extraBytes; i3 < len2; i3 += maxChunkLength)parts.push(encodeChunk(uint8, i3, i3 + maxChunkLength > len2 ? len2 : i3 + maxChunkLength));
     // pad the end with zeros, but make sure to not forget the extra bytes
     if (extraBytes === 1) {
-        tmp = uint8[len - 1];
+        tmp = uint8[len3 - 1];
         parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 0x3F] + "==");
     } else if (extraBytes === 2) {
-        tmp = (uint8[len - 2] << 8) + uint8[len - 1];
+        tmp = (uint8[len3 - 2] << 8) + uint8[len3 - 1];
         parts.push(lookup[tmp >> 10] + lookup[tmp >> 4 & 0x3F] + lookup[tmp << 2 & 0x3F] + "=");
     }
     return parts.join("");
@@ -3820,19 +3825,19 @@ module.exports = /*#__PURE__*/ function() {
 }();
 
 },{"buffer":"aKkui","util":"9jlXV"}],"2wSxq":[function(require,module,exports) {
-var process = require("process");
 "use strict"; // undocumented cb() API, needed for core, not for public API
-function destroy(err, cb) {
+var process = require("process");
+function destroy(err1, cb) {
     var _this = this;
     var readableDestroyed = this._readableState && this._readableState.destroyed;
     var writableDestroyed = this._writableState && this._writableState.destroyed;
     if (readableDestroyed || writableDestroyed) {
-        if (cb) cb(err);
-        else if (err) {
-            if (!this._writableState) process.nextTick(emitErrorNT, this, err);
+        if (cb) cb(err1);
+        else if (err1) {
+            if (!this._writableState) process.nextTick(emitErrorNT, this, err1);
             else if (!this._writableState.errorEmitted) {
                 this._writableState.errorEmitted = true;
-                process.nextTick(emitErrorNT, this, err);
+                process.nextTick(emitErrorNT, this, err1);
             }
         }
         return this;
@@ -3841,7 +3846,7 @@ function destroy(err, cb) {
     if (this._readableState) this._readableState.destroyed = true;
      // if this is a duplex stream mark the writable part as destroyed as well
     if (this._writableState) this._writableState.destroyed = true;
-    this._destroy(err || null, function(err) {
+    this._destroy(err1 || null, function(err) {
         if (!cb && err) {
             if (!_this._writableState) process.nextTick(emitErrorAndCloseNT, _this, err);
             else if (!_this._writableState.errorEmitted) {
@@ -3936,16 +3941,16 @@ function createErrorType(code, message, Base) {
         if (typeof message === "string") return message;
         else return message(arg1, arg2, arg3);
     }
-    var NodeError = /*#__PURE__*/ function(_Base) {
+    var NodeError1 = /*#__PURE__*/ function(_Base) {
         _inheritsLoose(NodeError, _Base);
         function NodeError(arg1, arg2, arg3) {
             return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;
         }
         return NodeError;
     }(Base);
-    NodeError.prototype.name = Base.name;
-    NodeError.prototype.code = code;
-    codes[code] = NodeError;
+    NodeError1.prototype.name = Base.name;
+    NodeError1.prototype.code = code;
+    codes[code] = NodeError1;
 } // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js
 function oneOf(expected, thing) {
     if (Array.isArray(expected)) {
@@ -4033,12 +4038,12 @@ module.exports.codes = codes;
 // Since JS doesn't have multiple prototypal inheritance, this class
 // prototypally inherits from Readable, and then parasitically from
 // Writable.
-var process = require("process");
 "use strict";
+var process = require("process");
 /*<replacement>*/ var objectKeys = Object.keys || function(obj) {
-    var keys = [];
-    for(var key in obj)keys.push(key);
-    return keys;
+    var keys1 = [];
+    for(var key in obj)keys1.push(key);
+    return keys1;
 };
 /*</replacement>*/ module.exports = Duplex;
 var Readable = require("./_stream_readable");
@@ -4144,9 +4149,9 @@ Object.defineProperty(Duplex.prototype, "destroyed", {
 // A bit simpler than readable streams.
 // Implement an async ._write(chunk, encoding, cb), and it'll handle all
 // the drain event emission and buffering.
-var global = arguments[3];
-var process = require("process");
 "use strict";
+var process = require("process");
+var global = arguments[3];
 module.exports = Writable;
 /* <replacement> */ function WriteReq(chunk, encoding, cb) {
     this.chunk = chunk;
@@ -4647,10 +4652,10 @@ Writable.prototype._destroy = function(err, cb) {
 };
 
 },{"process":"1iSuU","util-deprecate":"jgCpG","./internal/streams/stream":"3QKOj","buffer":"aKkui","./internal/streams/destroy":"2wSxq","./internal/streams/state":"3oDIZ","../errors":"3RxKp","inherits":"1rQOC","./_stream_duplex":"augGc"}],"jgCpG":[function(require,module,exports) {
+var global = arguments[3];
 /**
  * Module exports.
- */ var global = arguments[3];
-module.exports = deprecate;
+ */ module.exports = deprecate;
 /**
  * Mark that a method should not be used.
  * Returns a modified function which warns once by default.
@@ -4877,17 +4882,17 @@ function utf8CheckIncomplete(self, buf, i) {
 function utf8CheckExtraBytes(self, buf, p) {
     if ((buf[0] & 0xC0) !== 0x80) {
         self.lastNeed = 0;
-        return "�";
+        return "\uFFFD";
     }
     if (self.lastNeed > 1 && buf.length > 1) {
         if ((buf[1] & 0xC0) !== 0x80) {
             self.lastNeed = 1;
-            return "�";
+            return "\uFFFD";
         }
         if (self.lastNeed > 2 && buf.length > 2) {
             if ((buf[2] & 0xC0) !== 0x80) {
                 self.lastNeed = 2;
-                return "�";
+                return "\uFFFD";
             }
         }
     }
@@ -4919,7 +4924,7 @@ function utf8Text(buf, i) {
 // character.
 function utf8End(buf) {
     var r = buf && buf.length ? this.write(buf) : "";
-    if (this.lastNeed) return r + "�";
+    if (this.lastNeed) return r + "\uFFFD";
     return r;
 }
 // UTF-16LE typically needs two bytes per character, but even if we have an even
@@ -5023,8 +5028,8 @@ SafeBuffer.allocUnsafeSlow = function(size) {
 };
 
 },{"buffer":"aKkui"}],"FaDmO":[function(require,module,exports) {
-var process = require("process");
 "use strict";
+var process = require("process");
 var _Object$setPrototypeO;
 function _defineProperty(obj, key, value) {
     if (key in obj) Object.defineProperty(obj, key, {
@@ -5561,9 +5566,9 @@ function pipeline() {
 module.exports = pipeline;
 
 },{"../../../errors":"3RxKp","./end-of-stream":"1Ouyq"}],"6OySS":[function(require,module,exports) {
-var process = require("process");
-var __dirname = "node_modules/tape/lib";
 "use strict";
+var __dirname = "node_modules/tape/lib";
+var process = require("process");
 var deepEqual = require("deep-equal");
 var defined = require("defined");
 var path = require("path");
@@ -6482,7 +6487,7 @@ if (!Object.keys) {
             } catch (e) {
                 return true;
             }
-        } catch (e1) {
+        } catch (e) {
             return true;
         }
         return false;
@@ -6694,16 +6699,16 @@ var INTRINSICS = {
     "%WeakRef%": typeof WeakRef === "undefined" ? undefined : WeakRef,
     "%WeakSet%": typeof WeakSet === "undefined" ? undefined : WeakSet
 };
-var doEval = function doEval(name) {
+var doEval = function doEval1(name) {
     var value;
     if (name === "%AsyncFunction%") value = getEvalledConstructor("async function () {}");
     else if (name === "%GeneratorFunction%") value = getEvalledConstructor("function* () {}");
     else if (name === "%AsyncGeneratorFunction%") value = getEvalledConstructor("async function* () {}");
     else if (name === "%AsyncGenerator%") {
-        var fn = doEval("%AsyncGeneratorFunction%");
+        var fn = doEval1("%AsyncGeneratorFunction%");
         if (fn) value = fn.prototype;
     } else if (name === "%AsyncIteratorPrototype%") {
-        var gen = doEval("%AsyncGenerator%");
+        var gen = doEval1("%AsyncGenerator%");
         if (gen) value = getProto(gen.prototype);
     }
     INTRINSICS[name] = value;
@@ -7567,7 +7572,7 @@ module.exports = exported || function isMap(x) {
             return true;
         }
         return x instanceof $Map; // core-js workaround, pre-v2.5.0
-    } catch (e1) {}
+    } catch (e) {}
     return false;
 };
 
@@ -7598,7 +7603,7 @@ module.exports = exported || function isSet(x) {
             return true;
         }
         return x instanceof $Set; // core-js workaround, pre-v2.5.0
-    } catch (e1) {}
+    } catch (e) {}
     return false;
 };
 
@@ -7629,7 +7634,7 @@ module.exports = exported || function isWeakMap(x) {
             return true;
         }
         return x instanceof $WeakMap; // core-js workaround, pre-v3
-    } catch (e1) {}
+    } catch (e) {}
     return false;
 };
 
@@ -7651,7 +7656,7 @@ if ($setHas) {
                 return true;
             }
             return x instanceof $WeakSet; // core-js workaround, pre-v3
-        } catch (e1) {}
+        } catch (e) {}
         return false;
     };
 } else // eslint-disable-next-line no-unused-vars
@@ -7661,8 +7666,8 @@ module.exports = function isWeakSet(x) {
 };
 
 },{"get-intrinsic":"ad4UE","call-bind/callBound":"kCpMa"}],"cbgIc":[function(require,module,exports) {
-var process = require("process");
 "use strict";
+var process = require("process");
 /* eslint global-require: 0 */ // the code is structured this way so that bundlers can
 // alias out `has-symbols` to `() => true` or `() => false` if your target
 // environments' Symbol capabilities are known, and then use
@@ -8309,8 +8314,8 @@ function arrObjKeys(obj, inspect) {
 }
 
 },{"./util.inspect":"9jlXV"}],"lfRW8":[function(require,module,exports) {
-var global = arguments[3];
 "use strict";
+var global = arguments[3];
 var forEach = require("for-each");
 var availableTypedArrays = require("available-typed-arrays");
 var callBound = require("call-bind/callBound");
@@ -8474,8 +8479,8 @@ module.exports = reflectApply ? function isCallable(value) {
 };
 
 },{}],"24gi0":[function(require,module,exports) {
-var global = arguments[3];
 "use strict";
+var global = arguments[3];
 var possibleNames = [
     "BigInt64Array",
     "BigUint64Array",
@@ -8509,8 +8514,8 @@ if ($gOPD) try {
 module.exports = $gOPD;
 
 },{"get-intrinsic":"ad4UE"}],"g8HMN":[function(require,module,exports) {
-var global = arguments[3];
 "use strict";
+var global = arguments[3];
 var forEach = require("for-each");
 var availableTypedArrays = require("available-typed-arrays");
 var callBound = require("call-bind/callBound");
@@ -8695,8 +8700,8 @@ module.exports = function shimAssign() {
 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 // USE OR OTHER DEALINGS IN THE SOFTWARE.
-var process = require("process");
 "use strict";
+var process = require("process");
 function assertPath(path) {
     if (typeof path !== "string") throw new TypeError("Path must be a string. Received " + JSON.stringify(path));
 }
@@ -9137,7 +9142,7 @@ var RequireObjectCoercible = require("es-abstract/2021/RequireObjectCoercible");
 var ToString = require("es-abstract/2021/ToString");
 var callBound = require("call-bind/callBound");
 var $replace = callBound("String.prototype.replace");
-var mvsIsWS = /^\s$/.test("᠎");
+var mvsIsWS = /^\s$/.test("\u180E");
 /* eslint-disable no-control-regex */ var leftWhitespace = mvsIsWS ? /^[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+/ : /^[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+/;
 var rightWhitespace = mvsIsWS ? /[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+$/ : /[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+$/;
 /* eslint-enable no-control-regex */ module.exports = function trim() {
@@ -9159,8 +9164,8 @@ module.exports = function ToString(argument) {
 },{"get-intrinsic":"ad4UE"}],"5e5aa":[function(require,module,exports) {
 "use strict";
 var implementation = require("./implementation");
-var zeroWidthSpace = "​";
-var mongolianVowelSeparator = "᠎";
+var zeroWidthSpace = "\u200B";
+var mongolianVowelSeparator = "\u180E";
 module.exports = function getPolyfill() {
     if (String.prototype.trim && zeroWidthSpace.trim() === zeroWidthSpace && mongolianVowelSeparator.trim() === mongolianVowelSeparator && ("_" + mongolianVowelSeparator).trim() === "_" + mongolianVowelSeparator && (mongolianVowelSeparator + "_").trim() === mongolianVowelSeparator + "_") return String.prototype.trim;
     return implementation;
@@ -9269,16 +9274,16 @@ var isOctal = regexTester(/^0o[0-7]+$/i);
 var isInvalidHexLiteral = regexTester(/^[-+]0x[0-9a-f]+$/i);
 var nonWS = [
     "\x85",
-    "​",
-    "�"
+    "\u200B",
+    "\uFFFE"
 ].join("");
 var nonWSregex = new $RegExp("[" + nonWS + "]", "g");
 var hasNonWS = regexTester(nonWSregex);
 // whitespace from: https://es5.github.io/#x15.5.4.20
 // implementation from https://github.com/es-shims/es5-shim/blob/v3.4.0/es5-shim.js#L1304-L1324
 var ws = [
-    "	\n\v\f\r \xa0 ᠎    ",
-    "          \u2028",
+    "	\n\v\f\r \xa0\u1680\u180E\u2000\u2001\u2002\u2003",
+    "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028",
     "\u2029\uFEFF"
 ].join("");
 var trimRegex = new RegExp("(^[" + ws + "]+)|([" + ws + "]+$)", "g");
@@ -9426,8 +9431,8 @@ module.exports = function shimArrayPrototypeEvery() {
 };
 
 },{"define-properties":"1jFx6","./polyfill":"hCBeL"}],"gG0aP":[function(require,module,exports) {
-var process = require("process");
 "use strict";
+var process = require("process");
 var defined = require("defined");
 var EventEmitter = require("events").EventEmitter;
 var inherits = require("inherits");
@@ -9811,12 +9816,12 @@ const thisTarget = (0, _webextDetectPage.isBackground)() ? {
 };
 let tabDataStatus = // The background page doesn't have a tab
 (0, _webextDetectPage.isBackground)() ? "not-needed" : "needed";
-function compareTargets(to, thisTarget) {
+function compareTargets(to, thisTarget1) {
     for (const [key, value] of Object.entries(to)){
-        if (thisTarget[key] === value) continue;
+        if (thisTarget1[key] === value) continue;
         if (key !== "page") return false;
         const toUrl = new URL(to.page, location.origin);
-        const thisUrl = new URL(thisTarget.page, location.origin);
+        const thisUrl = new URL(thisTarget1.page, location.origin);
         if (toUrl.pathname !== thisUrl.pathname) return false;
         for (const [parameterKey, parameterValue] of toUrl.searchParams){
             if (thisUrl.searchParams.get(parameterKey) !== parameterValue) return false;
@@ -9858,7 +9863,7 @@ const storeTabData = (0, _sharedJs.once)(async ()=>{
         tabDataStatus = "received";
     } catch (error) {
         tabDataStatus = "error";
-        throw new (0, _sharedJs.MessengerError)("Tab registration failed. This page won’t be able to receive messages that require tab information", // @ts-expect-error TODO: update lib to accept Error#cause
+        throw new (0, _sharedJs.MessengerError)("Tab registration failed. This page won\u2019t be able to receive messages that require tab information", // @ts-expect-error TODO: update lib to accept Error#cause
         {
             cause: error
         });
@@ -9942,7 +9947,7 @@ function manageConnection(type, options, target, sendMessage) {
     });
 }
 async function manageMessage(type, target, sendMessage) {
-    const response = await (0, _pRetryDefault.default)(async ()=>{
+    const response1 = await (0, _pRetryDefault.default)(async ()=>{
         const response = await sendMessage();
         if (isMessengerResponse(response)) return response;
         // If no one answers, `response` will be `undefined`
@@ -9979,12 +9984,12 @@ async function manageMessage(type, target, sendMessage) {
         if (error?.message === _errorNonExistingTarget) throw new (0, _sharedJs.MessengerError)(`The target ${JSON.stringify(target)} for ${type} was not found`);
         throw error;
     });
-    if ("error" in response) {
-        (0, _sharedJs.debug)(type, "↘️ replied with error", response.error);
-        throw (0, _serializeError.deserializeError)(response.error);
+    if ("error" in response1) {
+        (0, _sharedJs.debug)(type, "\u2198\uFE0F replied with error", response1.error);
+        throw (0, _serializeError.deserializeError)(response1.error);
     }
-    (0, _sharedJs.debug)(type, "↘️ replied successfully", response.value);
-    return response.value;
+    (0, _sharedJs.debug)(type, "\u2198\uFE0F replied successfully", response1.value);
+    return response1.value;
 }
 function messenger(type, options, target, ...args) {
     // Message goes to extension page
@@ -10000,21 +10005,21 @@ function messenger(type, options, target, ...args) {
             throw new (0, _sharedJs.MessengerError)("No handler registered locally for " + type);
         }
         const sendMessage = async ()=>{
-            (0, _sharedJs.debug)(type, "↗️ sending message to runtime");
+            (0, _sharedJs.debug)(type, "\u2197\uFE0F sending message to runtime");
             return browser.runtime.sendMessage(makeMessage(type, args, target, options));
         };
         return manageConnection(type, options, target, sendMessage);
     }
     // Contexts without direct Tab access must go through background
     if (!browser.tabs) return manageConnection(type, options, target, async ()=>{
-        (0, _sharedJs.debug)(type, "↗️ sending message to runtime");
+        (0, _sharedJs.debug)(type, "\u2197\uFE0F sending message to runtime");
         return browser.runtime.sendMessage(makeMessage(type, args, target, options));
     });
     // `frameId` must be specified. If missing, the message is sent to every frame
     const { tabId , frameId =0  } = target;
     // Message tab directly
     return manageConnection(type, options, target, async ()=>{
-        (0, _sharedJs.debug)(type, "↗️ sending message to tab", tabId, "frame", frameId);
+        (0, _sharedJs.debug)(type, "\u2197\uFE0F sending message to tab", tabId, "frame", frameId);
         return browser.tabs.sendMessage(tabId, makeMessage(type, args, target, options), {
             frameId
         });
@@ -10084,26 +10089,26 @@ async function pRetry(input, options) {
         operation.attempt(async (attemptNumber)=>{
             try {
                 resolve(await input(attemptNumber));
-            } catch (error1) {
-                if (!(error1 instanceof Error)) {
-                    reject(new TypeError(`Non-error was thrown: "${error1}". You should only throw errors.`));
+            } catch (error) {
+                if (!(error instanceof Error)) {
+                    reject(new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`));
                     return;
                 }
-                if (error1 instanceof AbortError) {
+                if (error instanceof AbortError) {
                     operation.stop();
-                    reject(error1.originalError);
-                } else if (error1 instanceof TypeError && !isNetworkError(error1.message)) {
+                    reject(error.originalError);
+                } else if (error instanceof TypeError && !isNetworkError(error.message)) {
                     operation.stop();
-                    reject(error1);
+                    reject(error);
                 } else {
-                    decorateErrorWithCounts(error1, attemptNumber, options);
+                    decorateErrorWithCounts(error, attemptNumber, options);
                     try {
-                        await options.onFailedAttempt(error1);
-                    } catch (error) {
-                        reject(error);
+                        await options.onFailedAttempt(error);
+                    } catch (error1) {
+                        reject(error1);
                         return;
                     }
-                    if (!operation.retry(error1)) reject(operation.mainError());
+                    if (!operation.retry(error)) reject(operation.mainError());
                 }
             }
         });
@@ -10168,7 +10173,7 @@ exports.wrap = function(obj, options, methods) {
     }
     for(var i = 0; i < methods.length; i++){
         var method = methods[i];
-        var original = obj[method];
+        var original1 = obj[method];
         obj[method] = (function retryWrapper(original) {
             var op = exports.operation(options);
             var args = Array.prototype.slice.call(arguments, 1);
@@ -10181,7 +10186,7 @@ exports.wrap = function(obj, options, methods) {
             op.attempt(function() {
                 original.apply(obj, args);
             });
-        }).bind(obj, original);
+        }).bind(obj, original1);
         obj[method].options = options;
     }
 };
@@ -10341,8 +10346,8 @@ async function doesTabExist(tabId) {
 },{"webext-polyfill-kinda":"eGPxr","webext-content-scripts":"aYayV","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"eGPxr":[function(require,module,exports) {
 var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
 parcelHelpers.defineInteropFlag(exports);
-function NestedProxy(target) {
-    return new Proxy(target, {
+function NestedProxy(target1) {
+    return new Proxy(target1, {
         get (target, prop) {
             if (typeof target[prop] !== "function") return new NestedProxy(target[prop]);
             return (...arguments_)=>new Promise((resolve, reject)=>{
@@ -10407,7 +10412,7 @@ function arrayOrUndefined(value) {
         value
     ];
 }
-function insertCSS({ tabId , frameId , files , allFrames , matchAboutBlank , runAt  }) {
+function insertCSS({ tabId , frameId , files , allFrames , matchAboutBlank , runAt ,  }) {
     for (let content of files){
         if (typeof content === "string") content = {
             file: content
@@ -10432,7 +10437,7 @@ function insertCSS({ tabId , frameId , files , allFrames , matchAboutBlank , run
         });
     }
 }
-async function executeScript({ tabId , frameId , files , allFrames , matchAboutBlank , runAt  }) {
+async function executeScript({ tabId , frameId , files , allFrames , matchAboutBlank , runAt ,  }) {
     let lastInjection;
     for (let content of files){
         if (typeof content === "string") content = {
@@ -10506,7 +10511,7 @@ const blockedPrefixes = [
     "profile.accounts.firefox.com",
     "support.mozilla.org",
     "sync.services.mozilla.com",
-    "testpilot.firefox.com"
+    "testpilot.firefox.com",
 ];
 function isScriptableUrl(url) {
     const cleanUrl = url.replace(/^https?:\/\//, "");
@@ -10516,11 +10521,11 @@ function isScriptableUrl(url) {
 },{"webext-polyfill-kinda":"eGPxr","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"2y9st":[function(require,module,exports) {
 var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
 parcelHelpers.defineInteropFlag(exports);
-parcelHelpers.export(exports, "errorConstructors", ()=>(0, _errorConstructorsJsDefault.default));
 parcelHelpers.export(exports, "NonError", ()=>NonError);
 parcelHelpers.export(exports, "serializeError", ()=>serializeError);
 parcelHelpers.export(exports, "deserializeError", ()=>deserializeError);
 parcelHelpers.export(exports, "isErrorLike", ()=>isErrorLike);
+parcelHelpers.export(exports, "errorConstructors", ()=>(0, _errorConstructorsJsDefault.default));
 var _errorConstructorsJs = require("./error-constructors.js");
 var _errorConstructorsJsDefault = parcelHelpers.interopDefault(_errorConstructorsJs);
 var Buffer = require("buffer").Buffer;
@@ -10557,7 +10562,7 @@ const commonProperties = [
     {
         property: "cause",
         enumerable: false
-    }
+    },
 ];
 const toJsonWasCalled = Symbol(".toJSON was called");
 const toJSON = (from)=>{
@@ -10568,12 +10573,12 @@ const toJSON = (from)=>{
 };
 const getErrorConstructor = (name)=>(0, _errorConstructorsJsDefault.default).get(name) ?? Error;
 // eslint-disable-next-line complexity
-const destroyCircular = ({ from , seen , to , forceEnumerable , maxDepth , depth , useToJSON , serialize  })=>{
+const destroyCircular = ({ from , seen , to , forceEnumerable , maxDepth , depth , useToJSON , serialize ,  })=>{
     if (!to) {
         if (Array.isArray(from)) to = [];
         else if (!serialize && isErrorLike(from)) {
-            const Error1 = getErrorConstructor(from.name);
-            to = new Error1();
+            const Error = getErrorConstructor(from.name);
+            to = new Error();
         } else to = {};
     }
     seen.push(from);
@@ -10590,20 +10595,20 @@ const destroyCircular = ({ from , seen , to , forceEnumerable , maxDepth , depth
             useToJSON,
             serialize
         });
-    for (const [key, value] of Object.entries(from)){
+    for (const [key, value1] of Object.entries(from)){
         // eslint-disable-next-line node/prefer-global/buffer
-        if (typeof Buffer === "function" && Buffer.isBuffer(value)) {
+        if (typeof Buffer === "function" && Buffer.isBuffer(value1)) {
             to[key] = "[object Buffer]";
             continue;
         }
         // TODO: Use `stream.isReadable()` when targeting Node.js 18.
-        if (value !== null && typeof value === "object" && typeof value.pipe === "function") {
+        if (value1 !== null && typeof value1 === "object" && typeof value1.pipe === "function") {
             to[key] = "[object Stream]";
             continue;
         }
-        if (typeof value === "function") continue;
-        if (!value || typeof value !== "object") {
-            to[key] = value;
+        if (typeof value1 === "function") continue;
+        if (!value1 || typeof value1 !== "object") {
+            to[key] = value1;
             continue;
         }
         if (!seen.includes(from[key])) {
@@ -10622,7 +10627,7 @@ const destroyCircular = ({ from , seen , to , forceEnumerable , maxDepth , depth
     return to;
 };
 function serializeError(value, options = {}) {
-    const { maxDepth =Number.POSITIVE_INFINITY , useToJSON =true  } = options;
+    const { maxDepth =Number.POSITIVE_INFINITY , useToJSON =true ,  } = options;
     if (typeof value === "object" && value !== null) return destroyCircular({
         from: value,
         seen: [],
@@ -10641,11 +10646,11 @@ function deserializeError(value, options = {}) {
     const { maxDepth =Number.POSITIVE_INFINITY  } = options;
     if (value instanceof Error) return value;
     if (isMinimumViableSerializedError(value)) {
-        const Error1 = getErrorConstructor(value.name);
+        const Error = getErrorConstructor(value.name);
         return destroyCircular({
             from: value,
             seen: [],
-            to: new Error1(),
+            to: new Error(),
             maxDepth,
             depth: 0,
             serialize: false
@@ -10660,7 +10665,7 @@ function isMinimumViableSerializedError(value) {
     return Boolean(value) && typeof value === "object" && "message" in value && !Array.isArray(value);
 }
 
-},{"buffer":"aKkui","./error-constructors.js":"5dTOz","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"5dTOz":[function(require,module,exports) {
+},{"./error-constructors.js":"5dTOz","buffer":"aKkui","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"5dTOz":[function(require,module,exports) {
 var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
 parcelHelpers.defineInteropFlag(exports);
 const list = [
@@ -10676,7 +10681,7 @@ const list = [
     // Node-specific errors
     // https://nodejs.org/api/errors.html
     globalThis.AssertionError,
-    globalThis.SystemError
+    globalThis.SystemError,
 ]// Non-native Errors are used with `globalThis` because they might be missing. This filter drops them when undefined.
 .filter(Boolean).map((constructor)=>[
         constructor.name,
@@ -10788,15 +10793,15 @@ action) {
     const meta = {
         trace
     };
-    let handleMessage;
+    let handleMessage1;
     if (action === "forward") {
         (0, _sharedJs.debug)(type, "\uD83D\uDD00 forwarded", {
             sender,
             target
         });
-        handleMessage = async ()=>(0, _senderJs.messenger)(type, meta, target, ...args);
+        handleMessage1 = async ()=>(0, _senderJs.messenger)(type, meta, target, ...args);
     } else {
-        (0, _sharedJs.debug)(type, "↘️ received in", (0, _webextDetectPage.getContextName)(), {
+        (0, _sharedJs.debug)(type, "\u2198\uFE0F received in", (0, _webextDetectPage.getContextName)(), {
             sender,
             args,
             wasForwarded: trace.length > 1
@@ -10808,16 +10813,16 @@ action) {
             throw new (0, _sharedJs.MessengerError)(`No handlers registered in ${(0, _webextDetectPage.getContextName)()}`);
             throw new (0, _sharedJs.MessengerError)(`No handler registered for ${type} in ${(0, _webextDetectPage.getContextName)()}`);
         }
-        handleMessage = async ()=>localHandler.apply(meta, args);
+        handleMessage1 = async ()=>localHandler.apply(meta, args);
     }
-    const response = await handleMessage().then((value)=>({
+    const response = await handleMessage1().then((value)=>({
             value
         }), (error)=>({
             // Errors must be serialized because the stack traces are currently lost on Chrome
             // and https://github.com/mozilla/webextension-polyfill/issues/210
             error: (0, _serializeError.serializeError)(error)
         }));
-    (0, _sharedJs.debug)(type, "↗️ responding", response);
+    (0, _sharedJs.debug)(type, "\u2197\uFE0F responding", response);
     return {
         ...response,
         __webextMessenger: (0, _sharedJs.__webextMessenger)
@@ -10901,21 +10906,21 @@ const backgroundOnly = (0, _indexJs.getMethod)("backgroundOnly", (0, _indexJs.ba
 const getSelf = (0, _indexJs.getMethod)("getSelf", (0, _indexJs.backgroundTarget));
 
 },{"../../index.js":"kOnKs","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"kOnKs":[function(require,module,exports) {
-// Imports must use the .js extension because ESM requires it and TS refuses to rewrite .ts to .js
 var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
 parcelHelpers.defineInteropFlag(exports);
 parcelHelpers.export(exports, "getThisFrame", ()=>(0, _thisTargetJs.getThisFrame));
 parcelHelpers.export(exports, "getTopLevelFrame", ()=>(0, _thisTargetJs.getTopLevelFrame));
+var _thisTargetJs = require("./thisTarget.js");
+// Imports must use the .js extension because ESM requires it and TS refuses to rewrite .ts to .js
 var _receiverJs = require("./receiver.js");
 parcelHelpers.exportAll(_receiverJs, exports);
 var _senderJs = require("./sender.js");
 parcelHelpers.exportAll(_senderJs, exports);
 var _typesJs = require("./types.js");
 parcelHelpers.exportAll(_typesJs, exports);
-var _thisTargetJs = require("./thisTarget.js");
 (0, _thisTargetJs.initPrivateApi)();
 
-},{"./receiver.js":"5R24O","./sender.js":"fkc9X","./types.js":"ah9ro","./thisTarget.js":"7l5QG","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"ah9ro":[function(require,module,exports) {
+},{"./thisTarget.js":"7l5QG","./receiver.js":"5R24O","./sender.js":"fkc9X","./types.js":"ah9ro","@parcel/transformer-js/src/esmodule-helpers.js":"boKlo"}],"ah9ro":[function(require,module,exports) {
 var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
 parcelHelpers.defineInteropFlag(exports);

To note:

  • some characters appear as � (search utf8CheckExtraBytes)

Those characters for example come from:

https://github.com/nodejs/string_decoder/blob/1f29dd715a6c829da89e869af7dafc231c20ed9f/lib/string_decoder.js#L181-L184

@fregante fregante changed the title [webextension] Failed to load extension from: **. Could not load file ** for content script. It isn't UTF-8 encoded. [webextension] Failed to load extension from: /A. Could not load file B.js for content script. It isn't UTF-8 encoded. Mar 11, 2023
@fregante
Copy link
Contributor Author

fregante commented Mar 11, 2023

My current solution:

  • use ascii_only in Terser (fixes build)
  • downgrade to 2.6.0 (fixes watch)
# .terserrc
{
 "output": {
   "ascii_only": true
  }
}

@OriginalEXE
Copy link

Just ran into this randomly 🤔, I'm on version 2.9.3

@fregante
Copy link
Contributor Author

I confirm it's still an issue for both watch and build in 2.9.3

@mischnic
Copy link
Member

The only difference I see is that Parcel stopped encoding some strings, or potentially decoded some incorrectly. Here's the diff between the two files.

The question is: which characters does Chrome not like here? Maybe try by replacing with \ufffd for a start and seeing if that fixes it already, or if there is more (like the ↗️ I saw in your diff)

swc emits for that input, but that in itself should be fine.

@fregante
Copy link
Contributor Author

I tried making a few replacements but I wasn't able to identify which/all breaking characters. The main issue here is that Parcel is actively replacing unicode sequences with their unicode equivalents. See the source here:

https://github.com/ljharb/es-abstract/blob/0b69f5fb86bcb6f01c4014b0e6e758263055c073/2020/ToNumber.js#L18

Which appears to be:

 var nonWS = [
     "\x85",
-    "​",
-    "�"
+    "\u200B",
+    "\uFFFE"
 ].join("");

As you see, the \u strings appear that way in the source

@mischnic
Copy link
Member

mischnic commented Sep 13, 2023

@fregante What do you think of the following solution?

  • Parcel itself emits only ascii (so escape sequences). This effectively means: watch mode
  • Then in most cases, the optimizer (swc/terser) will rewrite that to be the shorter unicode character. You'd then be able to use a terserrc with output.ascii_only to keep the escape sequences in build mode

@fregante
Copy link
Contributor Author

Sounds perfectly fine for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants