@blazeapps/steem — What's Inside and How to Use It (Node.js & Edge Runtimes)

in Steem Devyesterday

If you're building apps on the Steem blockchain, @blazeapps/steem is the JavaScript library you need. This post covers what the package contains and walks you through using it in two common environments: Node.js and Cloudflare Workers (edge).


What's in the Package?

The library is a single isomorphic package — the exact same code runs on Node.js 18+, browsers, Cloudflare Workers, Vercel Edge, and Deno with zero configuration switches.

steem.api — Read from the blockchain

Every read method from the Steem RPC API is available here. There are hundreds of them, all auto-generated from a descriptor list. You can call them with a callback or as a Promise (Async suffix):

steem.api.getAccounts(['ned', 'dan'], callback)
steem.api.getAccountsAsync(['ned', 'dan'])  // returns a Promise
steem.api.getBlock(12345678, callback)
steem.api.getDynamicGlobalPropertiesAsync()
steem.api.getDiscussionsByTrending({ tag: 'steem', limit: 10 }, callback)

Transport is JSON-RPC over the native global fetch by default (HTTP). A WebSocket transport is also available and is selected automatically when you pass a wss:// URL.

steem.broadcast — Write to the blockchain

Broadcast helpers are also auto-generated from operation descriptors. Every operation the chain supports has a corresponding method:

steem.broadcast.vote(wif, voter, author, permlink, weight)
steem.broadcast.comment(wif, parentAuthor, parentPermlink, author, permlink, title, body, jsonMetadata)
steem.broadcast.transfer(wif, from, to, amount, memo)
steem.broadcast.customJson(wif, requiredAuths, requiredPostingAuths, id, json)

All methods accept either a trailing callback or return a Promise when the callback is omitted. Internally, broadcast.send fetches the latest irreversible block to set ref_block_num/ref_block_prefix/expiration, signs the transaction offline, then broadcasts it.

steem.auth — Keys and signing

steem.auth.toWif(username, password, 'posting')      // derive WIF key
steem.auth.getPrivateKeys(username, password, ['posting', 'active'])
steem.auth.wifToPublic(wif)                          // WIF → public key string
steem.auth.isPubkey(pubkey)
steem.auth.verify(username, password, auths)         // check credentials
steem.auth.signTransaction(tx, { posting: wif })

All crypto is pure-JS via @noble/curves (secp256k1) and @noble/hashes — no native bindings, no OpenSSL dependency.

steem.memo — Encrypted memos

const encrypted = steem.memo.encode(senderWif, recipientPubkey, '#my private message')
const decrypted = steem.memo.decode(receiverWif, encrypted)
// decrypted === '#my private message'

steem.formatter — Blockchain display utilities

steem.formatter.reputation(account.reputation)    // raw reputation → display number
steem.formatter.vestingSteem(account, globalProps) // vesting shares → STEEM amount
steem.formatter.estimateAccountValue(account)      // total account value estimate

steem.config — Runtime configuration

steem.api.setOptions({
  url: 'https://api.steemit.com',
  chain_id: '0000000000000000000000000000000000000000000000000000000000000000',
})

Important: the default chain_id in the package is all zeros. Set it explicitly when signing real transactions. For the testnet, also set address_prefix: 'TST' and useTestNet: true.


Tutorial 1: Node.js

Install

npm install @blazeapps/steem

Read account info

import steem from '@blazeapps/steem';

steem.api.setOptions({ url: 'https://api.steemit.com' });

const [account] = await steem.api.getAccountsAsync(['ned']);
console.log(`${account.name} balance: ${account.balance}`);

No build step needed — the package ships both ESM (dist/index.mjs) and CJS (dist/index.js) so import and require both work.

Derive keys from a username and password

import steem from '@blazeapps/steem';

const keys = steem.auth.getPrivateKeys('myusername', 'mypassword', ['posting', 'active']);
console.log(keys.posting);       // 5J... (WIF)
console.log(keys.postingPubkey); // STM... (public key)

Cast a vote

import steem from '@blazeapps/steem';

steem.api.setOptions({
  url: 'https://api.steemit.com',
  chain_id: '0000000000000000000000000000000000000000000000000000000000000000',
});

const postingWif = steem.auth.toWif('myusername', 'mypassword', 'posting');

const result = await steem.broadcast.vote(
  postingWif,
  'myusername',     // voter
  'ned',            // author
  'a-post-permlink',// permlink
  10000             // weight: 10000 = 100% upvote
);

console.log('tx id:', result.id);

Publish a post

const postingWif = steem.auth.toWif('myusername', 'mypassword', 'posting');

await steem.broadcast.comment(
  postingWif,
  '',                    // parent_author (empty for a top-level post)
  'steem',              // parent_permlink (category/tag)
  'myusername',          // author
  'my-first-post',       // permlink
  'My First Post',       // title
  'Hello Steem world!',  // body
  '{"tags":["steem"]}',  // json_metadata
);

Stream new blocks

import steem from '@blazeapps/steem';

steem.api.setOptions({ url: 'https://api.steemit.com' });

const stop = steem.api.streamBlock('irreversible', (err, block) => {
  if (err) { console.error(err); return; }
  console.log(`block #${block.block_num} — ${block.transactions.length} txs`);
});

// Call stop() when done to end the polling loop.

Send an encrypted memo

const memoWif = steem.auth.toWif('sender', 'password', 'memo');
const recipientPubkey = 'STM...';  // recipient's public memo key

const encrypted = steem.memo.encode(memoWif, recipientPubkey, '#hello in secret');

await steem.broadcast.transfer(
  steem.auth.toWif('sender', 'password', 'active'),
  'sender', 'recipient', '0.001 STEEM', encrypted
);

Tutorial 2: Cloudflare Workers (Edge)

The library runs on Cloudflare Workers with no compatibility flags — no nodejs_compat, nothing. It uses the global fetch for networking and @noble for crypto (pure-JS, no Node built-ins).

Setup

npm create cloudflare@latest my-steem-worker
cd my-steem-worker
npm install @blazeapps/steem

Minimal Worker — read account info

// src/index.js
import steem from '@blazeapps/steem';

export default {
  async fetch(request, env) {
    steem.api.setOptions({ url: env.STEEM_RPC_NODE });

    const name = new URL(request.url).searchParams.get('account') || 'ned';
    const [account] = await steem.api.getAccountsAsync([name]);

    if (!account) return new Response('not found', { status: 404 });
    return Response.json({ name: account.name, balance: account.balance });
  },
};
# wrangler.toml
name = "my-steem-worker"
main = "src/index.js"
compatibility_date = "2024-09-23"

[vars]
STEEM_RPC_NODE = "https://api.steemit.com"
npx wrangler dev     # run locally
npx wrangler deploy  # ship to the edge

Store a signing key as a secret

Never hard-code a private key. Use Wrangler secrets — they're encrypted at rest and injected as env variables at runtime:

npx wrangler secret put STEEM_POSTING_WIF
# paste your 5J... WIF when prompted

Vote endpoint (authenticated POST)

// src/index.js
import steem from '@blazeapps/steem';

export default {
  async fetch(request, env) {
    steem.api.setOptions({ url: env.STEEM_RPC_NODE });

    // Simple auth gate — replace with your real auth strategy
    if (request.headers.get('authorization') !== `Bearer ${env.API_SECRET}`)
      return new Response('unauthorized', { status: 401 });

    const { author, permlink, weight = 10000 } = await request.json();

    try {
      const tx = await steem.broadcast.vote(
        env.STEEM_POSTING_WIF,
        env.BOT_ACCOUNT,
        author,
        permlink,
        weight,
      );
      return Response.json({ ok: true, id: tx.id });
    } catch (err) {
      return Response.json({ ok: false, error: err.message }, { status: 502 });
    }
  },
};

Scheduled Worker — cron task

Run something on the chain on a schedule (e.g. claim rewards every 15 minutes):

# wrangler.toml
[triggers]
crons = ["*/15 * * * *"]
export default {
  async scheduled(event, env, ctx) {
    steem.api.setOptions({ url: env.STEEM_RPC_NODE });
    const props = await steem.api.getDynamicGlobalPropertiesAsync();
    console.log('current block:', props.head_block_number);
    // add claim_reward_balance broadcast here
  },
};

Test locally: npx wrangler dev --test-scheduled then hit /__scheduled.

Key rules for edge deployments

  • No wss:// URLs — use the default HTTP transport on Workers (no outbound WebSockets).
  • Signing keys in env, not in module globals — each request should read the key from env.
  • steem.auth.*, steem.memo.*, steem.formatter.* are stateless — safe to call in any concurrent context with no setup.
  • CPU time — a signTransaction call takes a few milliseconds of @noble crypto work, well within the free plan's 10 ms CPU limit.

Installing in other environments

EnvironmentInstall
Node.js 18+npm install @blazeapps/steem
Browser (CDN)<script src="https://cdn.jsdelivr.net/npm/@blazeapps/steem/dist/steem.min.js"></script>
Denoimport steem from 'npm:@blazeapps/steem'
Cloudflare Workersnpm install @blazeapps/steem (no compat flags needed)
Vercel Edgenpm install @blazeapps/steem (works as-is)

Links


Posted using @blazeapps/steem

Sort:  
Loading...