Reading
Unified stream engine
hive.reader.stream() opens a single block reader and dispatches every operation to as many Custom JSON and payment filters as your application registers.
Try the unified streamOne connection, many filters
The engine reads blocks once, parses each operation once, detects its type, normalizes it, and only then applies your filters. Registering a filter — before or after start() — never opens another connection.
TypeScript
const stream = hive.reader.stream({ fromBlock: 90_000_000 });
stream.customJson({
id: "my-game",
actions: ["claim", "gift"],
handler: (event) => console.log(event.account, event.metadata),
});
stream.payment({
account: "my-shop",
actions: ["purchase", "topup"],
requireTrigger: true,
handler: (payment) => fulfilOrder(payment.trigger?.metadata),
onFailed: (payment) => console.warn(payment.error),
});
await stream.start();No network field
Payment filters have no
network option. The engine detects native HIVE/HBD transfers and Layer 2 token transfers itself and reports the origin on the event.Custom JSON filters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | No | custom_json id, e.g. "my-game". |
| actions | string[] | No | OR-matched standardized actions from the { action, metadata } payload. |
| standardizedOnly | boolean | No | Skip raw protocol payloads that do not follow the envelope. |
| handler | (event: CustomJsonStreamEvent) => void | Promise<void> | No | Required. Called for every matching operation. |
Payment filters
| Parameter | Type | Required | Description |
|---|---|---|---|
| from | string | No | Sender account. |
| account | string | No | Recipient account. |
| symbol | string | No | HIVE, HBD or a Layer 2 token. |
| quantity | string | No | Exact amount as a precision-safe decimal string — never a number. |
| actions | string[] | No | OR-matched trigger actions. Implies a valid standardized trigger; omit them to match payments with or without triggers. |
| requireTrigger | boolean | No | Only match transfers carrying a valid { action, metadata } trigger. |
| handler | (payment: PaymentStreamEvent) => void | No | Verified successful payments only. |
| onFailed | (payment: PaymentStreamEvent) => void | No | Matching payments whose Layer 2 execution failed. |
Hive Engine transfers are checked against the sidechain execution logs before handler fires, so a token transfer that was broadcast but reverted reaches onFailed instead.
Lifecycle
TypeScript
const unsubscribe = stream.customJson({ id: "my-game", handler });
unsubscribe(); // or unsubscribe.unsubscribe()
stream.onEvent((event) => log(event.type, event));
await stream.start(); // starts the single block loop
stream.pause(); // stop dispatching, keep the loop alive
stream.resume();
stream.stop(); // end the loop
stream.clearFilters();| Parameter | Type | Required | Description |
|---|---|---|---|
| fromBlock | number | No | First block to read. Defaults to the head block; history flows into live blocks without a gap. |
| signal | AbortSignal | No | Abort the block loop from the outside. |
| onError | (error: unknown) => void | No | Non-fatal transport or parse errors. |
| engineConfirmationAttempts | number | No | How many times a pending Layer 2 execution is re-read before giving up. Default 6 — the sidechain indexes a few seconds after the Hive block. |
| engineConfirmationDelayMs | number | No | Delay between Layer 2 execution reads. Default 2000. |
Event shapes
Every event carries its blockchain position — transactionId, blockNumber, blockTimestamp, transactionIndex and operationIndex — which together form a stable idempotency key.
TypeScript
type StreamEvent =
| CustomJsonStreamEvent // type: "custom_json"
| PaymentStreamEvent; // type: "payment"
stream.onEvent((event) => {
if (event.type === "payment") console.log(event.source.type, event.transfer.symbol);
});