Modernizing Steem.js — Day 6: Cross-Runtime Verification & 100% Docs
Part 6 of my 7-part Steem.js modernization series. The code is modern, typed, and byte-compatible. But "it works on my machine" isn't good enough for a library that claims to run everywhere. Today: proving it runs everywhere, and documenting all of it.
Bundle hygiene: trust, but verify
The whole isomorphic promise rests on one fact: the shipped bundle must contain no Node built-ins, no Buffer, no process, no dynamic require. So I audited the built output directly for forbidden tokens:
- ❌ no
require('crypto')/ bare Node built-ins - ❌ no top-level
Buffer/process/window - ✅ only externals:
@noble/*,@scure/base,bs58,retry(+ optionalws)
Buffer is injected from a pure-JS polyfill at build time; assert / events / debug are aliased to tiny in-repo shims via a tsup onResolve plugin. Nothing Node-specific leaks into the ESM/edge output.
A byte-exact, cross-runtime smoke test
scripts/smoke.mjs loads the built bundle (not the source) and runs the critical path on multiple runtimes, asserting byte-exact results:
// scripts/smoke.mjs — runs under both Node and Deno
import steem from '../dist/index.mjs';
const wif = steem.auth.toWif('alice', 'password', 'active');
const sig = steem.auth.signTransaction(tx, [wif]);
const memo = steem.memo.encode(/* … */);
assertEqual(wif, EXPECTED_WIF); // identical on Node + Deno
assertEqual(sig, EXPECTED_SIG);
Running it under both node and deno run confirms the same keys, signatures, and memos come out on completely different runtimes.
CI matrix
.github/workflows/build.yml now builds and tests across a matrix:
- Node 18, 20, 22 —
import(ESM) andrequire(CJS), full Vitest suite - Deno — a dedicated job running the smoke script
Every push is verified on every supported runtime. The old Docker / circle.yml path is gone.
100% generated documentation
A modern library deserves documentation that can't go stale. The docs site at blazeapps007.github.io/steem-js is a Jekyll + just-the-docs site, and its reference pages are generated from the same descriptors that drive the runtime:
scripts/gen-docs.jsreadsmethods.js/operations.jsand emits the complete reference — 108 API methods + 67 broadcast entries, each with signature, required roles, RPC name, parameters, an example, and the return shape.- Per-method prose lives in
docs/_details/*.mdand is spliced in, so coverage can never drift below 100%. - Every guide and reference page now leads with modern ESM usage:
import steem from '@steemit/steem-js';
// CommonJS: const steem = require('@steemit/steem-js');
If a method is added to the descriptor but lacks a detail block, the generator tells you. Docs stay honest by construction.
Where that leaves us
Six phases in, Steem.js is:
- ✅ byte-for-byte compatible (golden vectors green throughout)
- ✅ running on Node 18/20/22, browsers, edge, and Deno — verified in CI
- ✅ typed, tree-shakeable, dependency-light
- ✅ 100% documented from source
Tomorrow, the finale: the official release post tying it all together.
Links
- 🛠️ Code (fork): https://github.com/blazeapps007/steem-js (
BlazeDevelopmentbranch) - 📖 Documentation: https://blazeapps007.github.io/steem-js/
Support Secure Steem Development
If you value proactive engineering, UX polish, and performance optimizations for the STEEM ecosystem, please consider supporting my witness: blaze.apps
🗳️ Vote Here:
Vote for blaze.apps Witness