"clean": "rm -rf {build,dist}",
"compile": "node scripts/blake2b-gen.mjs && asc ./src/assembly/index.ts && tsc",
"prepublishOnly": "npm run test:prod",
- "test": "npm run build && node ./test/node.mjs",
- "test:prod": "npm run build:prod && node ./test/node.mjs"
+ "test": "npm run build && npm run test:all",
+ "test:all": "npm run test:be && npm run test:le",
+ "test:be": "node --import ./test/big-endian.mjs ./test/node.mjs",
+ "test:le": "node ./test/node.mjs",
+ "test:prod": "npm run build:prod && npm run test:all"
},
"devDependencies": {
"@types/node": "26.2.0",
--- /dev/null
+//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
+//! SPDX-License-Identifier: GPL-3.0-or-later
+
+/**
+ * Preload that makes the package take its big-endian marshalling path on a
+ * little-endian host: `node --import ./test/big-endian.mjs ./test/node.mjs`
+ *
+ * The package probes byte order once, at load, by writing `1` into a
+ * `Uint32Array` and reading its first byte. This swaps the global constructor
+ * before the package captures it, so that one probe sees the big-endian layout
+ * and every other construction passes straight through to the real one.
+ *
+ * Forcing the path here is a faithful test of it, not an approximation: the
+ * big-endian path packs words from individual bytes with shifts, which gives
+ * the same result on either byte order. What this cannot cover is the probe
+ * itself, or V8's own wasm memory handling, on real big-endian hardware; for
+ * that, run the suite under s390x emulation.
+ */
+
+const RealWords = globalThis.Uint32Array
+let intercepted = 0
+
+/** @this {unknown} */
+function Words (...args) {
+ if (new.target === undefined) {
+ return RealWords(...args)
+ }
+ const [a] = args
+ if (args.length === 1 && Array.isArray(a) && a.length === 1 && a[0] === 1) {
+ intercepted++
+ // 1 laid out big-endian: the low byte comes last
+ return new RealWords([0x01000000])
+ }
+ return new RealWords(...args)
+}
+Object.setPrototypeOf(Words, RealWords)
+Words.prototype = RealWords.prototype
+globalThis.Uint32Array = /** @type {Uint32ArrayConstructor} */ (/** @type {unknown} */ (Words))
+
+console.log('\x1b[33mBIG-ENDIAN\x1b[0m: byte order probe forced, testing the big-endian marshalling path')
+
+// Without this, a change to the probe would silently fall back to the
+// little-endian path, and this run would pass while testing nothing new.
+process.on('exit', () => {
+ if (intercepted === 0) {
+ console.log('\x1b[31mFAIL\x1b[0m: big-endian preload never intercepted the byte order probe')
+ process.exitCode = 1
+ }
+})