Steem.js, Modernized & Published: `@blazeapps/steem` is Live on npm

in Steem Dev5 hours ago

This is the finale of my 7-part series on modernizing Steem.js. Over the past six days I walked through each engineering phase — today it ships. The modernized library is published to npm and running in production-ready form across every major JavaScript runtime.


What we did, in one screen

AreaBeforeAfter
RuntimesNode + a browser bundleNode 18+, browsers, Cloudflare/Vercel edge, Deno — one package
Cryptobigi + ecurve + browserify-aesaudited, pure-JS @noble/curves + @noble/hashes + @noble/ciphers
Serializerbytebufferin-repo bytebuffer-lite (Uint8Array + native BigInt)
Networkingcross-fetch, static wsglobal fetch, lazy/optional ws
Promisesbluebirdtiny native-promise helper (dual callback/Promise API kept)
Buildwebpack 4 + Babeltsup (esbuild) → ESM + CJS + IIFE + types
Typesnoneshipped dist/index.d.ts
Docspartial100% generated from source + edge/Deno guides
Dependencies~25 legacy shimsa handful, all bundled into a self-contained dist

Backwards compatible — byte for byte

The whole rewrite was gated by a golden-vector test that froze the exact outputs of the old library: WIFs, public keys, a canonical signature, serialized transaction hex, and an encrypted-memo roundtrip. Every phase kept those identical. Same keys, same signatures, same wire format — existing accounts and transactions just work.

The public API is unchanged, too: steem.api.*, steem.broadcast.*, steem.auth, steem.memo, steem.formatter, steem.utils, steem.config; callbacks and promises; the singleton and the Steem class.

import steem from '@blazeapps/steem';            // ESM — Vite, edge, Deno, modern Node
// const steem = require('@blazeapps/steem');     // CommonJS

const [account] = await steem.api.getAccountsAsync(['blaze.apps']);
const wif = steem.auth.toWif('alice', 'password', 'active'); // offline, every runtime
await steem.broadcast.voteAsync(wif, 'alice', 'author', 'permlink', 10000);

The journey (the six phases)

  1. Foundation & tooling — golden-vector safety net first, then tsup + Vitest.
  2. Crypto core — swapped to @noble, preserving graphene's canonical RFC6979 signing byte-for-byte.
  3. Serializerbytebuffer-lite with native BigInt, wire format untouched.
  4. Transports & runtime — native fetch, lazy ws, feature-detected globals, Bluebird removed.
  5. Types.d.ts generated from the same descriptors that drive the runtime, so they never drift.
  6. Verification & docs — cross-runtime smoke tests, CI on Node 18/20/22 + Deno, and 100% generated docs.

Battle-tested on the way to release

Shipping surfaced — and fixed — the gnarly real-world edge cases:

  • Node 18 has no default globalThis.crypto → a build-time banner wires it up via a non-literal node:crypto specifier, so edge/Deno bundles stay clean.
  • @noble v2 is ESM-only → bundling deps into dist so require() works on Node 18 CJS.
  • Deno's permission model → the serializer no longer trips the env check; no --allow-env needed.
  • CI → npm → every push runs the full matrix + Deno, then auto-publishes a new version.

All verified on real Node 18.20.8, Node 20/22, and Deno.

Try it

npm install @blazeapps/steem

Then head to the docs — there are dedicated Cloudflare Workers and Deno guides with complete, worked examples.

Issues, PRs, and feedback against the fork are very welcome. If this work is useful to you, the best way to support continued development is below. 🙌

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