@blazeapps/steem — What's Inside and How to Use It (Node.js & Edge Runtimes)
If you're building apps on the Steem blockchain,
@blazeapps/steemis 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_idin the package is all zeros. Set it explicitly when signing real transactions. For the testnet, also setaddress_prefix: 'TST'anduseTestNet: 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 fromenv. steem.auth.*,steem.memo.*,steem.formatter.*are stateless — safe to call in any concurrent context with no setup.- CPU time — a
signTransactioncall takes a few milliseconds of@noblecrypto work, well within the free plan's 10 ms CPU limit.
Installing in other environments
| Environment | Install |
|---|---|
| Node.js 18+ | npm install @blazeapps/steem |
| Browser (CDN) | <script src="https://cdn.jsdelivr.net/npm/@blazeapps/steem/dist/steem.min.js"></script> |
| Deno | import steem from 'npm:@blazeapps/steem' |
| Cloudflare Workers | npm install @blazeapps/steem (no compat flags needed) |
| Vercel Edge | npm install @blazeapps/steem (works as-is) |
Links
- Package: @blazeapps/steem on npm
- Docs: blazeapps007.github.io/steem-js
- Source: github.com/blazeapps007/steem-js
Posted using @blazeapps/steem