HiveXPH SDKhivexph-sdk
NPM
Developer toolkit for Hive Custom JSON and Hive Engine transactions.

Reading

Block stream

Streaming is an async iterator, not a callback soup. Break out of the loop or abort a signal and the stream stops immediately.

Open the unified stream

One canonical engine

There is exactly one block-reading implementation in the SDK. It owns RPC communication, head block tracking, block fetching, sequential ordering, historical backfill, the historical → live transition, poll intervals, retries, AbortSignal handling and normalization. Every watching API is a filtered view of it — none of them polls the chain itself.

Text
Hive RPC
  |
  v
Canonical block engine  (fetch, head tracking, retries, normalization, abort)
  |
  +-- hive.blocks.watch()        raw normalized blocks
  +-- hive.customJson.watch()    id + actions filter
  +-- hive.payments.watch()      transfer + trigger detection
  +-- hive.reader.stream()       one loop, many registered filters

A single nextBlock cursor drives history and live blocks, so there is no hand-off between backfill and polling: blocks are never skipped, duplicated or read out of order. A failed read retries the same height — the cursor only advances after a block has been yielded.

Streaming events

TypeScript
const controller = new AbortController();

for await (const event of hive.customJson.watch({
  id: "my-application",
  actions: ["claim"],
  signal: controller.signal,
  onInvalidPayload: ({ reason, blockNumber }) => console.warn(blockNumber, reason),
})) {
  console.log(event.blockNumber, event.action, event.metadata);
}

Without fromBlock the stream starts at the current head block. Pass a block number to backfill history and then continue live.

Blocks

TypeScript
for await (const block of hive.blocks.watch({ fromBlock: 90000000 })) {
  console.log(block.blockNumber, block.transactions.length);
}

Normalized block

RPC nodes expose blocks inconsistently (operation tuples versus typed objects, missing transaction_ids). The engine normalizes once, so parsers and filters never deal with that. Every event keeps its chain position for deduplication: transactionId, blockNumber, blockTimestamp, transactionIndex and operationIndex.

TypeScript
interface NormalizedBlock {
  blockNumber: number;
  blockId: string | null;
  timestamp: string;
  transactions: NormalizedTransaction[];
  raw: HiveBlock;              // exactly what the node returned
}

interface NormalizedTransaction {
  transactionId: string | null;
  transactionIndex: number;
  operations: NormalizedOperation[];
}

interface NormalizedOperation {
  operationIndex: number;
  operationType: string;       // "custom_json", "transfer", ...
  operation: HiveOperation;
}

Options

BlockStreamOptions / CustomJsonStreamOptions
ParameterTypeRequiredDescription
idstringYesCustom JSON stream only: application id to filter on.
actionsstring[]NoOptional action allow-list.
fromBlocknumberNoFirst block to read. Defaults to the head block.
signalAbortSignalNoStops the iterator cleanly.
pollIntervalMsnumberNoPoll interval while waiting for new blocks. Default 3000.
maxRetriesPerBlocknumberNoConsecutive failures before throwing. Default 5.
onError(error, blockNumber) => voidNoCalled on recoverable RPC errors instead of throwing.