dsteem Modernization Plan: Bringing a Core Steem Library into Latest Compatibility

in Steem Dev4 days ago (edited)

I am modernizing dsteem — the TypeScript RPC client for Steem — from its 2019 state to a 2026-ready v0.12.0, preserving 100% API compatibility while updating the toolchain, security, and developer experience. This post outlines the phased plan, technical decisions, and how you can follow along or contribute.

ChatGPT Image May 28, 2026, 03_37_04 PM.png
Thanks ChatGPT for image


dsteem (originally by @jnordberg) has been a robust, dual-environment (Node.js + browser) RPC client for the Steem blockchain [[1]]. However, the last meaningful commit was in November 2019. Today, that means:

  • 📦 Dependencies pinned to 2018–2019 versions
  • 🔧 Deprecated build toolchain (browserify + tsify + babelify + uglifyjs)
  • 🚫 Abandoned linter (tslint)
  • ⚠️ High-severity vulnerability in [email protected]
  • 🧪 Test pipeline targeting Node 8–10 (EOL)

For developers building on Steem in 2026 [[10]], this creates friction: security concerns, compatibility issues, and missed opportunities for modern TypeScript features.

Goal: Release v0.12.0 that is:

  • API-compatible: Zero breaking changes for existing consumers
  • 🔐 Secure: Replace vulnerable crypto dependencies with audited alternatives
  • 🚀 Modern: ESM + CJS dual output, Node ≥22, ES2020+ browser target
  • 🧪 Tested: 70%+ coverage gate, Playwright browser tests, GitHub Actions CI

Locked Technical Decisions

AreaDecisionRationale
Public APIPreserve exactlyExisting apps upgrade via version bump only
Crypto@noble/curves + @noble/hashesAudited, pure-JS, used by ethers/viem; removes native build risks
Module FormatDual ESM + CJSSupports modern bundlers and legacy CommonJS consumers
Node Floor≥22.0.0Leverages native fetch, modern V8, LTS support
Build Tooltsup (esbuild wrapper)Fast, emits ESM/CJS/.d.ts in one pass
Test RunnerMocha 11 + c8Minimal test churn, built-in coverage
Browser TestsPlaywright headlessReplaces deprecated Karma + Sauce Labs
CIGitHub ActionsUnified workflow, matrix testing on Node 22/24
Buffer Polyfillesbuild-plugin-polyfill-nodeZero consumer setup for browser builds
Test RPCapi.steemit.com (primary), api.moecki.online (fallback)Reliable mainnet endpoints for CI [[17]]

The Phased Modernization Plan

Each phase leaves CI green. All work is tracked in the blazeapps007/dsteem fork.

🔐 Phase 0: Capture Crypto Golden Fixtures (Load-bearing)

Before changing code, freeze current signing/hashing behavior:

  • Generate deterministic test vectors using existing [email protected] in a Node 16 container
  • Save to test/fixtures/crypto-golden.json
  • Assert bit-identical output throughout the migration via test/crypto-golden.ts

Why? Prevents silent signature drift that could break Steem network consensus.

🔄 Phase 1: CI Plumbing Only

  • Add .github/workflows/ci.yml with matrix: Node 22 + 24
  • Jobs: lint, test, build, coverage (upload to Codecov)
  • Delete .travis.yml, .circleci/config.yml
  • Baseline: Run existing tests on Node 16 to establish "green" starting point

🧹 Phase 2: tslint → ESLint Flat Config

  • Replace tslint.json with eslint.config.js (flat config)
  • Mirror existing rules: single quotes, no semicolons, 4-space indent
  • Update disable comments in source files
  • Update package.json scripts: npm run linteslint src test

📦 Phase 3: TypeScript 3 → 5

  • Bump typescript@^5.6, @types/node@^22, @types/mocha@^10
  • Modernize tsconfig.json: target: ES2022, moduleResolution: Bundler, strict: true
  • Fix TS5 errors (e.g., global['fetch'](globalThis as any).fetch)
  • Keep ts-node working temporarily for test execution

🔐 Phase 4: @noble Crypto Swap (Highest Risk)

Replace [email protected] + Node crypto.createHash with:

  • @noble/curves@^1 for secp256k1 operations
  • @noble/hashes@^1 for SHA256/RIPEMD160

Critical details:

  • Wrap new APIs to match old signatures exactly (internal helpers only)
  • Pass lowS: false to maintain Steem's canonical signature format
  • Verify recovery-bit domain {0,1,2,3} matches existing Signature.fromBuffer logic
  • Remove all native dependencies (node-gyp, prebuild binaries)

Gate: npm test -- --grep golden must pass — bit-identical output to Phase 0 fixtures.

🏗️ Phase 5: Build Modernization (tsup, Exports Map, Drop Dead Polyfills)

  • Add tsup@^8; remove browserify, babelify, uglify-js, dts-generator, etc.
  • New tsup.config.ts: dual builds
    • Node: src/index-node.tsdist/index.{mjs,cjs,d.ts}
    • Browser: src/index-browser.tsdist/dsteem.browser.js (IIFE, minified)
  • Replace src/version.ts with build-time __PACKAGE_VERSION__ define
  • Gut src/index-browser.ts: drop core-js, regenerator-runtime, whatwg-fetch (Edge Legacy is dead)
  • Update package.json:
    {
      "type": "module",
      "engines": { "node": ">=22.0.0" },
      "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "browser": "./dist/dsteem.browser.js",
          "import": "./dist/index.mjs",
          "require": "./dist/index.cjs"
        }
      }
    }
    
  • Delete Makefile

🎯 Expected win: Browser bundle drops from ~500KB → ~150KB.

🧪 Phase 6: Tests + Coverage + Browser Tests

  • Bump mocha@^11, add c8@^10, tsx@^4, playwright@^1
  • New .mocharc.cjs: use tsx ESM loader
  • New playwright.config.ts: headless Chromium/Firefox/WebKit tests against dist/dsteem.browser.js
  • Delete legacy test harnesses: test/_node.js, test/_karma*.js, etc.
  • Add fallback RPC logic in test/common.ts: retry against api.moecki.online if primary fails [[17]]
  • Gate testnet-dependent tests behind TEST_TESTNET=1 env flag

Coverage gate: npm run coverage fails if line coverage < 70%.

📚 Phase 7: Docs

  • Bump typedoc@^0.28, add typedoc.json
  • npm run build:docsdocs/index.html
  • Remove BSD-sed post-processing (no longer needed in Typedoc 0.28)

🚀 Phase 8: Cleanup + Release

  • Update README.md: install instructions, CDN URL, Node 22 minimum, RPC endpoint notes
  • Update CLAUDE.md: replace Makefile references with npm run * scripts
  • Bump version to 0.12.0, tag v0.12.0
  • npm publish --dry-run first to inspect file list

Security & Dependency Outcome

Removed (deprecated/vulnerable)

secp256k1, @types/secp256k1, core-js, regenerator-runtime, 
whatwg-fetch, node-fetch, tslint, browserify, tsify, babelify, 
@babel/core, uglify-js, dts-generator, nyc, ts-node, karma*, coveralls

Added (modern/audited)

@noble/curves, @noble/hashes, tsup, esbuild-plugin-polyfill-node,
eslint, typescript-eslint, tsx, c8, playwright

Upgraded

typescript 3.1.6 → ^5.6
@types/node 10 → ^22
mocha 5 → ^11
typedoc 0.13 → ^0.28
bs58 4 → ^6

Result: Eliminates the high-severity [email protected] advisory, removes native-build attack surface, and drops all deprecated/unmaintained packages.


Verification Checklist (Post-Release)

After all phases complete, we verify:

  1. npm test green on Node 22, ≥70% coverage, golden fixtures pass
  2. ✅ Mainnet round-trip: Client('https://api.steemit.com').database.getDynamicGlobalProperties() succeeds
  3. ✅ Browser bundle works: npm run test:browser passes in headless Chromium
  4. ✅ Dual-format install works for ESM and CJS consumers
  5. ✅ TypeScript types resolve correctly for import {Client, PrivateKey} from 'dsteem'
  6. dist/dsteem.browser.js < 200KB
  7. npm audit clean — no known advisories in production deps
  8. ✅ CI matrix green on Node 22 and 24

How You Can Help

This modernization benefits everyone building on Steem. Here's how to engage:

  • 🔍 Review the plan: Check the dsteem repo and open issues for feedback
  • 🧪 Test early builds: Once Phase 1 lands, try the CI artifacts in your Steem apps
  • 🐛 Report regressions: If your existing code breaks after upgrading to v0.12.0, file an issue — API compatibility is non-negotiable
  • 💡 Suggest improvements: Especially around browser usage, RPC fallbacks, or Steem-specific edge cases

Final Thoughts

Modernizing core infrastructure is unglamorous but essential work. By bringing dsteem into 2026, we:

  • Reduce security risks for all Steem developers
  • Enable modern TypeScript features and tooling
  • Improve bundle sizes and load times for browser apps
  • Future-proof the client for the next era of Steem development [[21]]

This plan was developed with Claude AI assistance, but every technical decision reflects Steem ecosystem needs and backward-compatibility priorities. The work is ongoing — follow the repo for progress updates.

Built for Steem, by the community.


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

Disclaimer: This post describes a work-in-progress plan. All code changes are subject to review and testing before release.