BXM Canon 0.2.0 Brings the Same Bytes to JavaScript With One Rust Core Compiled to WebAssembly
BXM Canon 0.2.0 adds a JavaScript package. It runs in Node 18 and later and in browsers, and it gives exactly the bytes and hashes the bxm-canon command gives, because it is the same Rust code compiled to WebAssembly.
That matters more for Canon than for most libraries. A canonical encoding is only as good as the agreement between the programs that use it. If the Node service and the Go service each carry their own implementation, a single corner case they read differently, a float spelled one way or a key compared another, brings back the problem Canon exists to remove.
So the JavaScript package doesn’t reimplement anything. It moves bytes into the WebAssembly core and reads the answer back out. The rules live in one place.

Using it
npm install https://github.com/softdevstudio/bxm/releases/latest/download/bxm-canon-js.tgz
import { load } from "bxm-canon";
const canon = await load();
canon.hashText('{"b":1,"a":2}') === canon.hashText('{ "a": 2, "b": 1 }'); // true
const bytes = canon.fromText('{"name":"bxm","raw":h"cafe"}');
canon.isCanonical(bytes); // true
There’s an ES module and a CommonJS build, TypeScript types for both, and no dependencies. The WebAssembly is inside the package, so there’s nothing to fetch at run time. The whole API is on the Reference page.
What was tested
The package runs the spec’s conformance vectors on every change, on Node 18 and Node 22: 30 values that must encode to exact bytes and 30 byte strings that must be refused with the right error code. It also checks that nesting stops at exactly 512 levels inside WebAssembly, where the stack is smaller than on a desktop, and that the CommonJS build and an installed copy of the packed package both work.
The review before release turned up one JavaScript-specific trap worth knowing about. JavaScript strings can hold half of a surrogate pair, which isn’t valid Unicode. The browser’s text encoder quietly swaps it for a replacement character, so two different strings would have hashed the same. The package now refuses them with an error, the same way the core refuses the escaped form.
Next
A Python package built on the same core, so Python, Node, Rust, C and the command line all agree byte for byte.