TypeScript SDK
The public package is @smart-byte/leani-sdk, for Node 20.3+ and Bun 1.2+. In a source
checkout, run bun install --cwd packages/sdk and bun run --cwd packages/sdk build.
The query/follow guide includes an executable
client, a matching node config, and pagination/reset handling.
For a node started with leani init blocks and leani serve:
import { createLeaniClient } from "@smart-byte/leani-sdk";
const leani = createLeaniClient({ baseUrl: "http://127.0.0.1:18080" });const stop = new AbortController();for await (const change of leani.blocks.subscribe({ signal: stop.signal })) { if (change.operation === "apply" && change.data) { console.log(change.data.blockNumber); }}Pass an AbortSignal to cancel an idle subscription; breaking out of the loop
also cancels its response body. Transport disconnects reconnect from the last
yielded cursor. Protocol errors and expired history require application action.
An incomplete final event is discarded before reconnecting. Retryable HTTP
errors, including rate limiting, use the configured reconnect backoff, and so
do error events marked retryable; after five of them in a row without a new
change, the subscription throws the last one. A stream that sends nothing, not
even the node’s 15-second keep-alive comments, for idleTimeoutMs (default
60,000) while the loop waits reconnects too. An event over 8 MiB fails the
subscription with a non-retryable invalid_response error.
This print-only example does not maintain state; stateful consumers must apply
undo mutations too.
A request that fails below HTTP rejects with TransportError, a LeaniError
with status 0, code: "transport", retryable: true, and the runtime’s error
as cause: a refused or reset connection, a response body that breaks off, a
passed deadline, or a silent stream. Aborting your own signal rejects with its
reason instead, and the SDK never retries it. The SDK does not follow
redirects: a 3xx answer rejects with the non-retryable redirect_refused, with
the target in details.location, so configure the final URL as baseUrl.
Every request path resolves under the base URL’s path, one starting with /
included. A path segment that decodes to . or .., or holds a backslash, an
encoded slash or backslash (%2F, %5C), or an encoded percent sign (%25),
and a control character anywhere in the path, are refused before any request.
request() applies the same rule to a custom query extension’s path, so a
path parameter whose value can hold / or % must move to the query string,
request()’s params.
Typed subscriptions accept processor to select a configured instance, for
example leani.blobs.subscribe({ processor: "blobs-production" }). The blobs
apply payload is { block, transactions }. Narrow operation before reading
processor data: finalized carries { throughBlock } instead, or, when
isLiveGapChange() holds, the { fromBlock, toBlock } the live lane skipped.
liveGapBackfill() in @smart-byte/leani-sdk/backfill turns that range into an
idempotent fill_missing subscription request; see
Keep your application in sync.
Discover canonical query paths with capabilities() and pass queryBasePaths
when aliases are ambiguous.
queryAndFollow() returns the first page of an immutable snapshot and its
stream boundary. Follow every nextCursor with queryEntities(), release the
snapshot in finally, then subscribe from boundaryCursor. SSE resets throw
ResetRequiredError; HTTP expiry throws LeaniError with code: "cursor_expired"
or "query_snapshot_expired". Rebuild the seed for either case.
queryEntities() also works when delivery is disabled; its boundaryCursor
and recovery.follow are then null. queryAndFollow() requires delivery and
returns a FollowSnapshotPage with a non-null boundary, or HTTP 409
delivery_disabled. The stream and change endpoints return the same error
when delivery is disabled.
Durable live/history sessions live in @smart-byte/leani-sdk/backfill. Construct them with
createBackfillSubscriptionClient({ baseUrl, token, fetch, timeoutMs }); both
entry points use the same LeaniError and TransportError classes and HTTP
error fields (status, code, retryable, requestId). The deadline applies
to JSON requests, lease renewals, and acknowledgements, and to a stream until
its hello arrives. An established stream that sends nothing, heartbeats
included, for three heartbeatIntervalMs while its iterator waits fails with a
TransportError; time spent handling a record does not count. A lease renewal
that fails with a retryable error is retried with backoff while the lease
holds; one that fails otherwise, or keeps failing until the lease would lapse,
ends the session at once, and the iterator throws its error. The lanes of
subscribe() reconnect after either, and after any other retryable error. A
stream record over 65 MiB fails the session with a non-retryable
invalid_response error. A backfill stream can request smaller batches with
batching.maximumEncodedBytes; streamLive() takes no batching option, so a
live stream’s batches follow the node’s
api.delivery.live_batches.maximum_encoded_bytes. Always close delivery
sessions in finally. Commit
idempotent destination writes before acknowledging a batch. Acknowledge a
batch’s boundary, never a change’s own cursor: the node refuses one inside a
live block or a history progress unit. A backfill session’s deliveryBatches()
yields every boundary as ackCursor with the events it covers, including
batches without changes and the completion; events() flattens the changes
without boundaries. A consumer with a credential passes it as credential
on every call and stream. retry(subscription) re-queues a failed subscription
to resume from its committed progress, and delete(subscription, { discardUnacknowledged: true }) deletes a failed or cancelled one whose
consumer has not acknowledged every record. See
durable delivery for lease and reset semantics.
Run a history subscription in one call
runBackfill(client, request, options) in @smart-byte/leani-sdk/backfill
runs an application-owned subscription to its end; request must name its
consumer. It creates the subscription, applies each history batch with
options.onBatch and acknowledges it once that resolves, acknowledges the
completion, closes the session, and deletes the subscription. It resolves with
the outcome (completed, cancelled, or failed), the subscription as it
ended, the completion record it received, if it streamed one, and the
deletion. Creation is idempotent by idempotencyKey: running the identical
request again, as after a crash, resumes the same subscription after its last
acknowledged batch, and the node refuses a different request under the same
key. A batch applied but not acknowledged is delivered again, so onBatch
must be idempotent. A subscription already complete when created is deleted
without opening its stream.
After a lost connection or consumer session, or while another connection
still holds the consumer’s session, it waits a backoff of 1 second, doubling
up to 30 seconds, and reads the subscription’s state before it opens the
stream again: a subscription that ended meanwhile, as when the node applied
the completion’s acknowledgement but its answer was lost, ends the run
instead. A failed subscription follows options.onFailure. "retry", the
default, re-queues it with retry(), up to maxRetries times (3 by default),
then throws a BackfillStreamError with code: "backfill_failed" and leaves it
failed. "discard" deletes it with discardUnacknowledged: true and resolves
with the outcome failed, and "throw" throws at once. A cancelled
subscription is deleted with discardUnacknowledged: true. An error from
onBatch, a reset_required stream, any other failure, and an abort of
options.signal or request.signal close the session and reject without
deleting the subscription, so the identical request can run again once the
cause is fixed. The stream presents options.credential, by default the
request’s consumer.credential.
Inventory
The inventory below is generated from both public entry points and shared error
types. The backfill.* members belong to the backfill client.
baseUrl
| Member | Contract |
|---|---|
baseUrl | readonly baseUrl: URL |
request
| Member | Contract |
|---|---|
request | request<T>( path: string, params?: Record<string, QueryValue>, options?: { signal?: AbortSignal }, ): Promise<T> |
health
| Member | Contract |
|---|---|
health.live | live(options?: { signal?: AbortSignal }): Promise<Health> |
health.ready | ready(options?: { signal?: AbortSignal }): Promise<Health> |
status
| Member | Contract |
|---|---|
status | status(options?: { signal?: AbortSignal }): Promise<NodeStatus> |
capabilities
| Member | Contract |
|---|---|
capabilities | capabilities(options?: { signal?: AbortSignal }): Promise<Capabilities> |
processors
| Member | Contract |
|---|---|
processors.list | list(options?: { signal?: AbortSignal }): Promise<ProcessorSummary[]> |
processors.status | status( id: string, options?: { signal?: AbortSignal }, ): Promise<ProcessorCoverage> |
processors.changes | changes<T = unknown>( id: string, options?: ChangesOptions, ): Promise<Page<ChangeEnvelope<T>>> |
processors.changeHead | changeHead( id: string, options?: { signal?: AbortSignal }, ): Promise<ChangeHead> |
processors.resetLiveLane | resetLiveLane( id: string, options?: { signal?: AbortSignal }, ): Promise<LiveLaneReset> |
processors.listCollections | listCollections( id: string, options?: { signal?: AbortSignal }, ): Promise<{ processor: ProcessorSummary; outputMode: "none" | "latest" | "window" | "full"; retained: boolean; data: string[]; }> |
processors.queryEntities | queryEntities<T = unknown>( id: string, collection: string, options?: OutputQueryOptions, ): Promise<GenericSnapshotPage<T>> |
processors.queryAndFollow | queryAndFollow<T = unknown>( id: string, collection: string, options?: Omit<OutputQueryOptions, "cursor">, ): Promise<FollowSnapshotPage<T>> |
processors.getEntity | getEntity<T = unknown>( id: string, collection: string, key: Hex, options?: { signal?: AbortSignal }, ): Promise<GenericOutputEntity<T>> |
processors.releaseSnapshot | releaseSnapshot( id: string, snapshotId: string, options?: { signal?: AbortSignal }, ): Promise<void> |
processors.consumers.list | list( id: string, options?: { signal?: AbortSignal }, ): Promise<DurableConsumer[]> |
processors.consumers.create | create( id: string, options: CreateConsumerOptions, ): Promise<DurableConsumer> |
processors.consumers.inspect | inspect( id: string, consumer: string, options?: { signal?: AbortSignal }, ): Promise<DurableConsumer> |
processors.consumers.revoke | revoke( id: string, consumer: string, options?: { signal?: AbortSignal }, ): Promise<DurableConsumer> |
processors.consumers.renew | renew( id: string, consumer: string, credential: string, options?: { signal?: AbortSignal }, ): Promise<DurableConsumer> |
processors.consumers.changes | changes<T = unknown>( id: string, consumer: string, credential: string, options?: { limit?: number; signal?: AbortSignal }, ): Promise<Page<ChangeEnvelope<T>>> |
processors.consumers.acknowledge | acknowledge( id: string, consumer: string, credential: string, cursor: string, options?: { signal?: AbortSignal }, ): Promise<DurableConsumer> |
processors.subscribe | subscribe<T = unknown>( id: string, options?: SubscribeOptions, ): AsyncGenerator<ChangeEnvelope<T>> |
blobs
| Member | Contract |
|---|---|
blobs.getBlock | getBlock( number: number, options?: { signal?: AbortSignal }, ): Promise<BlobsBlock> |
blobs.listBlocks | listBlocks(options: ListBlocksOptions): Promise<Page<BlobsBlock>> |
blobs.listSnapshot | listSnapshot( options: ListBlocksOptions, ): Promise<Page<BlobsSnapshotEntry>> |
blobs.getTransaction | getTransaction( hash: Hex, options?: { signal?: AbortSignal }, ): Promise<BlobTransaction> |
blobs.listTransactions | listTransactions( options: ListTransactionsOptions, ): Promise<Page<BlobTransaction>> |
blobs.getSchedule | getSchedule(options?: { atBlock?: number; signal?: AbortSignal; }): Promise<BlobSchedule> |
blobs.subscribe | subscribe( options?: ProcessorSubscribeOptions, ): AsyncGenerator<ChangeEnvelope<BlobsSnapshotEntry>> |
erc20
| Member | Contract |
|---|---|
erc20.getBalance | getBalance( token: Hex, address: Hex, options?: { signal?: AbortSignal }, ): Promise<Erc20Balance> |
erc20.subscribe | subscribe( options?: ProcessorSubscribeOptions, ): AsyncGenerator<ChangeEnvelope<Erc20Balance>> |
uniswap
| Member | Contract |
|---|---|
uniswap.getPool | getPool( address: Hex, options?: { signal?: AbortSignal }, ): Promise<UniswapPoolPrice> |
uniswap.getLatestObservation | getLatestObservation( address: Hex, options?: { processor?: string; signal?: AbortSignal }, ): Promise<LatestUniswapObservation> |
uniswap.listConfiguredPools | listConfiguredPools(options?: { processor?: string; signal?: AbortSignal; }): Promise<ConfiguredUniswapPools> |
uniswap.subscribe | subscribe( options?: ProcessorSubscribeOptions, ): AsyncGenerator<ChangeEnvelope<UniswapPoolPrice>> |
blocks
| Member | Contract |
|---|---|
blocks.getLatest | getLatest(options?: { processor?: string; signal?: AbortSignal; }): Promise<LatestBlockSummary> |
blocks.getByNumber | getByNumber( number: number, options?: { processor?: string; signal?: AbortSignal }, ): Promise<LatestBlockSummary> |
blocks.subscribe | subscribe( options?: ProcessorSubscribeOptions, ): AsyncGenerator<ChangeEnvelope<BlockSummary>> |
backfill
| Member | Contract |
|---|---|
backfill.baseUrl | readonly baseUrl: URL |
backfill.create | create(request: CreateBackfillSubscription): Promise<BackfillStatus> |
backfill.list | list(options?: { signal?: AbortSignal }): Promise<BackfillStatus[]> |
backfill.inspect | inspect( subscription: string, options?: { signal?: AbortSignal }, ): Promise<BackfillStatus> |
backfill.cancel | cancel( subscription: string, options?: { signal?: AbortSignal }, ): Promise<BackfillStatus> |
backfill.retry | retry( subscription: string, options?: { signal?: AbortSignal }, ): Promise<BackfillStatus> |
backfill.delete | delete( subscription: string, options?: { signal?: AbortSignal; discardUnacknowledged?: boolean }, ): Promise<HistoricalWorkDeletion> |
backfill.changes | changes<T = unknown>( subscription: string, consumer: string, options?: { credential?: string; limit?: number; signal?: AbortSignal; }, ): Promise<{ data: ChangeEnvelope<T>[]; nextCursor: string | null; coverage: unknown; }> |
backfill.stream | stream<T = unknown>( subscription: string, consumer: string, options?: { credential?: string; batching?: BackfillBatchingRequest; signal?: AbortSignal; }, ): Promise<BackfillDeliverySession<T>> |
backfill.streamLive | streamLive<T = unknown>( processor: string, consumer: string, options?: { credential?: string; signal?: AbortSignal }, ): Promise<LiveDeliverySession<T>> |
backfill.subscribe | subscribe<T = unknown>( request: MultiLaneSubscriptionRequest, ): Promise<MultiLaneDelivery<T>> |
Exported types and helpers
Hex@smart-byte/leani-sdk
export type Hex = `0x${string}`;Finality@smart-byte/leani-sdk
export type Finality = "unattested" | "attested" | "finalized";ChangeOperation@smart-byte/leani-sdk
export type ChangeOperation =
| "apply"
| "undo"
| "attested"
| "finalized"
| "reset_required";LeaniClientOptions@smart-byte/leani-sdk
export interface LeaniClientOptions {
baseUrl: string | URL;
token?: string;
timeoutMs?: number;
fetch?: FetchLike;
/**
* Override typed query-extension mounts with canonical `basePath` values
* returned by `capabilities()` when an ergonomic alias is unavailable.
*/
queryBasePaths?: {
blobs?: string;
erc20?: string;
uniswap?: string;
};
reconnect?: {
initialDelayMs?: number;
maxDelayMs?: number;
jitter?: number;
};
}FetchLike@smart-byte/leani-sdk
export type FetchLike = (
input: RequestInfo | URL,
init?: RequestInit,
) => Promise<Response>;ProcessorSummary@smart-byte/leani-sdk
export interface ProcessorSummary {
id: string;
instance: string;
version: string;
codeHash: Hex;
configHash: Hex;
genericApi: "processor-v1";
changeSchema: string;
queryExtensions: QueryExtensionSummary[];
subscriptions: boolean;
artifactRetention: "none" | "window" | "full";
deliveryOrdering: "canonical" | "block_versioned_idempotent";
}QueryExtensionSummary@smart-byte/leani-sdk
export interface QueryExtensionSummary {
id: string;
basePath: string;
aliasPath: string | null;
}QueryExtensionCapability@smart-byte/leani-sdk
export interface QueryExtensionCapability extends QueryExtensionSummary {
processor: string;
}Capabilities@smart-byte/leani-sdk
export interface Capabilities {
chainId: number;
ethereumRpc: Record<string, unknown>;
processors: ProcessorSummary[];
queryExtensions: QueryExtensionCapability[];
}NodeStatus@smart-byte/leani-sdk
export interface NodeStatus {
apiVersion: "1";
project: string;
version: string;
chainId: number;
uptimeSeconds: number;
databaseBytes: number;
processor: ProcessorSummary;
processors: ProcessorSummary[];
readiness: Readiness;
}Readiness@smart-byte/leani-sdk
export interface Readiness {
liveRequired: boolean;
liveReady: boolean;
finalityRequired: boolean;
finalityReady: boolean;
ready: boolean;
}Health@smart-byte/leani-sdk
export interface Health {
status: "live" | "ready" | "not_ready" | "failed";
uptimeSeconds: number;
database: "available" | "unavailable";
readiness: Readiness;
reasons: string[];
}CoverageInterval@smart-byte/leani-sdk
export interface CoverageInterval {
fromBlock: number;
toBlock: number;
finality: Finality;
}ProcessorCoverage@smart-byte/leani-sdk
export interface ProcessorCoverage {
chainId: number;
chainFinalizedHead: {
number: number;
hash: string;
} | null;
requested?: {
fromBlock: number;
toBlock: number;
} | null;
available: CoverageInterval[];
configuredStartBlock: number;
processedThrough: number | null;
finalizedThrough: number | null;
complete: boolean;
state:
| "starting"
| "backfilling"
| "catching_up"
| "live"
| "degraded"
| "paused"
| "failed";
}Page@smart-byte/leani-sdk
export interface Page<T> {
data: T[];
nextCursor: string | null;
coverage: ProcessorCoverage;
}BlobsBlock@smart-byte/leani-sdk
export interface BlobsBlock {
network: string;
blockNumber: number;
blockHash: Hex;
parentHash: Hex;
timestamp: number;
size: string;
blobCount: number;
blobGasUsed: string;
excessBlobGas: string;
/**
* Protocol blob base fee in wei per blob gas: the EIP-4844 fee for
* `excessBlobGas` under the fork active at `timestamp`. EIP-7918 does not
* change it.
*/
blobBaseFee: string;
executionBaseFee: string;
gasUsed: string;
gasLimit: string;
executionEthBurnedWei: string;
/** `blobBaseFee` times `blobGasUsed`. */
blobEthBurnedWei: string;
/**
* EIP-7918 reserve price in wei per blob gas from Fusaka on, `null` before.
* It only changes how excess blob gas evolves and is not applied to
* `blobBaseFee`.
*/
reserveFeeWei: string | null;
transactionCount: number;
targetBlobsPerBlock: number;
maxBlobsPerBlock: number;
transformVersion: number;
finality: Finality;
}BlobTransaction@smart-byte/leani-sdk
export interface BlobTransaction {
network: string;
blockNumber: number;
blockHash: Hex;
txHash: Hex;
transactionIndex: number;
senderAddress: Hex;
/**
* The transaction's to address. Every blob transaction has one: a rollup's
* inbox, or a contract that routes the call, such as Multicall3.
*/
toAddress: Hex;
blobVersionedHashes: Hex[];
blobCount: number;
totalBurnedWei: string;
executionBurnedWei: string;
/** The block's `blobBaseFee` times this transaction's blob gas. */
blobBurnedWei: string;
}BlobsSnapshotEntry@smart-byte/leani-sdk
export interface BlobsSnapshotEntry {
block: BlobsBlock;
transactions: BlobTransaction[];
}ChangeHead@smart-byte/leani-sdk
export interface ChangeHead {
earliestSequence: string | null;
latestSequence: string | null;
cursor: string | null;
}GenericOutputEntity@smart-byte/leani-sdk
export interface GenericOutputEntity<T = unknown> {
ordinal: string;
key: Hex;
schema: string;
data: T;
blockNumber: number;
blockTimestamp: number;
finality: Finality;
}OutputBounds@smart-byte/leani-sdk
export interface OutputBounds {
earliestBlock: number;
latestBlock: number;
earliestTimestamp: number;
latestTimestamp: number;
}GenericSnapshotPage@smart-byte/leani-sdk
export interface GenericSnapshotPage<T = unknown> {
data: GenericOutputEntity<T>[];
nextCursor: string | null;
snapshotId: string;
boundaryCursor: string | null;
rowCount: string;
valueBytes: string;
expiresAtUnixMs: string;
retainedBounds: OutputBounds | null;
coverage: ProcessorCoverage;
recovery: {
follow: string | null;
outsideRetention: "create_processor_instance_or_source_scan";
};
}FollowSnapshotPage@smart-byte/leani-sdk
export interface FollowSnapshotPage<T = unknown> extends GenericSnapshotPage<T> {
boundaryCursor: string;
recovery: GenericSnapshotPage<T>["recovery"] & { follow: string };
}OutputQueryOptions@smart-byte/leani-sdk
export interface OutputQueryOptions {
fromBlock?: number;
toBlock?: number;
fromTimestamp?: number;
toTimestamp?: number;
limit?: number;
cursor?: string;
signal?: AbortSignal;
}ConsumerRole@smart-byte/leani-sdk
export type ConsumerRole = "required" | "best_effort";ConsumerState@smart-byte/leani-sdk
export type ConsumerState = "active" | "reset_required" | "revoked";ConsumerStart@smart-byte/leani-sdk
export type ConsumerStart =
| { position: "earliest_retained" }
| { position: "current_head" }
| { position: "cursor"; cursor: string };CreateConsumerOptions@smart-byte/leani-sdk
export interface CreateConsumerOptions {
id: string;
role: ConsumerRole;
start: ConsumerStart;
leaseTtlSeconds: number;
credential: string;
signal?: AbortSignal;
}DurableConsumer@smart-byte/leani-sdk
export interface DurableConsumer {
id: string;
processorInstance: string;
/** The delivery stream this consumer reads. */
streamId: string;
role: ConsumerRole;
state: ConsumerState;
acknowledgedSequence: string;
deliveredSequence: string;
acknowledgedCursor: string;
deliveredCursor: string;
/** Stream sessions that have taken the lease; `"0"` before the first. */
leaseGeneration: string;
leaseTtlMs: string;
leaseExpiresAtUnixMs: string;
leaseActive: boolean;
lagChanges: string;
lagBlocks: string;
lagBytes: string;
lagAgeMs: string;
createdAtUnixMs: string;
updatedAtUnixMs: string;
}BlobSchedule@smart-byte/leani-sdk
export interface BlobSchedule {
name: string;
/**
* Block-number label for `atBlock` lookups. For Dencun it is 19426589, the
* first block the blobs processor covers.
*/
activationBlock: number;
/** The fork's parameters apply to blocks from this timestamp on. */
activationTimestamp: number;
forkId: Hex;
targetBlobsPerBlock: number;
maxBlobsPerBlock: number;
baseFeeUpdateFraction: string;
eip7918: boolean;
source: "chain_spec" | "eth_config" | "configured";
}Erc20Balance@smart-byte/leani-sdk
export interface Erc20Balance {
token: Hex;
address: Hex;
balance: string;
asOfBlock: number;
blockHash: Hex;
finality: Finality;
coverageFrom: number;
complete: boolean;
/**
* Block whose transfer proved the ledger incomplete for this token and
* holder. From that block the pair is no longer derived and `balance` keeps
* its last derived value; `null` while the pair is derived.
*/
incompleteFrom: number | null;
method: "erc20_transfer_ledger";
}EvmEvent@smart-byte/leani-sdk
export interface EvmEvent {
schemaVersion: number;
contract: Hex;
event: string;
signature: string;
blockNumber: number;
blockHash: Hex;
blockTimestamp: number;
bucketStartTimestamp?: number;
transactionHash: Hex;
transactionIndex: number;
logIndex: number;
finality: Finality;
values: Record<string, string>;
}TransactionStats@smart-byte/leani-sdk
export interface TransactionStats {
from: Hex;
to: Hex;
/** Submitted transactions from `from` to `to`, reverted ones included. */
count: number;
/** Submitted value in wei, including the value of reverted transactions. */
totalValueWei: string;
asOfBlock: number;
blockHash: Hex;
finality: Finality;
coverageFrom: number;
complete: boolean;
}UniswapPoolPrice@smart-byte/leani-sdk
export interface UniswapPoolPrice {
pool: Hex;
kind: "v2" | "v3";
reserve0: string | null;
reserve1: string | null;
/** Signed token0 pool delta for a V3 swap, in raw token units. */
amount0: string | null;
/** Signed token1 pool delta for a V3 swap, in raw token units. */
amount1: string | null;
sqrtPriceX96: string | null;
blockNumber: number;
blockHash: Hex;
logIndex: number;
finality: Finality;
}LatestUniswapObservation@smart-byte/leani-sdk
export interface LatestUniswapObservation {
data: UniswapPoolPrice;
timestamp: number;
}ConfiguredUniswapPool@smart-byte/leani-sdk
export interface ConfiguredUniswapPool {
address: Hex;
kind: "v2" | "v3";
}ConfiguredUniswapPools@smart-byte/leani-sdk
export interface ConfiguredUniswapPools {
data: ConfiguredUniswapPool[];
}BlockSummary@smart-byte/leani-sdk
export interface BlockSummary {
chainId: number;
blockNumber: number;
blockHash: Hex;
parentHash: Hex;
timestamp: number;
gasLimit: number | null;
gasUsed: number | null;
baseFeePerGas: string | null;
blobGasUsed: number | null;
excessBlobGas: number | null;
transactionCount: number | null;
sizeBytes: number | null;
finality: Finality;
}LatestBlockSummary@smart-byte/leani-sdk
export interface LatestBlockSummary {
data: BlockSummary;
}ChangeMetadata@smart-byte/leani-sdk
export interface ChangeMetadata {
apiVersion: "1";
sequence: string;
cursor: string;
originKind:
| "live"
| "live_recovery"
| "historical_backfill"
| "recompute";
originId: string;
publicationRevision: string;
chainId: number;
block: {
number: number;
hash: Hex;
parentHash: Hex;
timestamp: number;
} | null;
finality: Finality;
kind: string;
schema: string;
key: string | null;
/** Present only on `reset_required` events, as the current coverage hint. */
coverage?: ProcessorCoverage;
/** RFC 3339 UTC emission time with millisecond precision. */
emittedAt: string;
}LiveGapChangeData@smart-byte/leani-sdk
export interface LiveGapChangeData {
fromBlock: number;
toBlock: number;
/**
* Leani did not fill the range: the processor's history is on demand, and a
* `live_gap_fill` limit, if it has one, did not cover or complete it.
*/
reason: "not_filled";
}ChangeEnvelope@smart-byte/leani-sdk
export type ChangeEnvelope<T = unknown> = ChangeMetadata & (
| { operation: "apply" | "undo"; data: T | null }
| { operation: "attested"; data: { throughBlock: number } }
| { operation: "finalized"; data: { throughBlock: number } }
| { operation: "finalized"; data: LiveGapChangeData }
| { operation: "reset_required"; data: {
earliestAvailableSequence: string;
latestAvailableSequence: string;
action: "query_snapshot_then_resume";
} }
);isLiveGapChange@smart-byte/leani-sdk
export function isLiveGapChange<T>(
change: ChangeEnvelope<T>,
): change is Extract<ChangeEnvelope<T>, { data: LiveGapChangeData }>;LiveLaneReset@smart-byte/leani-sdk
export interface LiveLaneReset {
processor: string;
state: "paused";
reason: "operator_reset_pending_replay";
firstUnappliedBlock: number;
firstUnappliedHash: Hex;
requiredDeliveryBytes: string;
}StreamHello@smart-byte/leani-sdk
export interface StreamHello {
apiVersion: "1";
chainId: number;
processor: ProcessorSummary;
coverage: ProcessorCoverage;
}ListBlocksOptions@smart-byte/leani-sdk
export interface ListBlocksOptions {
fromBlock: number;
toBlock: number;
limit?: number;
cursor?: string;
allowPartial?: boolean;
signal?: AbortSignal;
}ListTransactionsOptions@smart-byte/leani-sdk
export interface ListTransactionsOptions {
blockNumber: number;
limit?: number;
cursor?: string;
signal?: AbortSignal;
}ChangesOptions@smart-byte/leani-sdk
export interface ChangesOptions {
after?: string;
limit?: number;
signal?: AbortSignal;
}SubscribeOptions@smart-byte/leani-sdk
export interface SubscribeOptions {
after?: string;
signal?: AbortSignal;
/** Receives the connection handshake frame; called once per (re)connect. */
onHello?: (hello: StreamHello) => void;
/**
* Reconnect when the stream sends nothing, not even the node's 15-second
* keep-alive comments, for this long while the loop waits for a change.
* Defaults to 60,000 ms.
*/
idleTimeoutMs?: number;
}ProcessorSubscribeOptions@smart-byte/leani-sdk
export interface ProcessorSubscribeOptions extends SubscribeOptions {
processor?: string;
}LeaniClient@smart-byte/leani-sdk
export interface LeaniClient {
readonly baseUrl: URL;
request<T>(
path: string,
params?: Record<string, QueryValue>,
options?: { signal?: AbortSignal },
): Promise<T>;
health: {
live(options?: { signal?: AbortSignal }): Promise<Health>;
ready(options?: { signal?: AbortSignal }): Promise<Health>;
};
status(options?: { signal?: AbortSignal }): Promise<NodeStatus>;
capabilities(options?: { signal?: AbortSignal }): Promise<Capabilities>;
processors: {
list(options?: { signal?: AbortSignal }): Promise<ProcessorSummary[]>;
status(
id: string,
options?: { signal?: AbortSignal },
): Promise<ProcessorCoverage>;
changes<T = unknown>(
id: string,
options?: ChangesOptions,
): Promise<Page<ChangeEnvelope<T>>>;
changeHead(
id: string,
options?: { signal?: AbortSignal },
): Promise<ChangeHead>;
resetLiveLane(
id: string,
options?: { signal?: AbortSignal },
): Promise<LiveLaneReset>;
listCollections(
id: string,
options?: { signal?: AbortSignal },
): Promise<{
processor: ProcessorSummary;
outputMode: "none" | "latest" | "window" | "full";
retained: boolean;
data: string[];
}>;
queryEntities<T = unknown>(
id: string,
collection: string,
options?: OutputQueryOptions,
): Promise<GenericSnapshotPage<T>>;
/** First snapshot page plus an atomic stream boundary. Read all nextCursor pages and releaseSnapshot before following. */
queryAndFollow<T = unknown>(
id: string,
collection: string,
options?: Omit<OutputQueryOptions, "cursor">,
): Promise<FollowSnapshotPage<T>>;
getEntity<T = unknown>(
id: string,
collection: string,
key: Hex,
options?: { signal?: AbortSignal },
): Promise<GenericOutputEntity<T>>;
releaseSnapshot(
id: string,
snapshotId: string,
options?: { signal?: AbortSignal },
): Promise<void>;
consumers: {
list(
id: string,
options?: { signal?: AbortSignal },
): Promise<DurableConsumer[]>;
create(
id: string,
options: CreateConsumerOptions,
): Promise<DurableConsumer>;
inspect(
id: string,
consumer: string,
options?: { signal?: AbortSignal },
): Promise<DurableConsumer>;
revoke(
id: string,
consumer: string,
options?: { signal?: AbortSignal },
): Promise<DurableConsumer>;
renew(
id: string,
consumer: string,
credential: string,
options?: { signal?: AbortSignal },
): Promise<DurableConsumer>;
changes<T = unknown>(
id: string,
consumer: string,
credential: string,
options?: { limit?: number; signal?: AbortSignal },
): Promise<Page<ChangeEnvelope<T>>>;
acknowledge(
id: string,
consumer: string,
credential: string,
cursor: string,
options?: { signal?: AbortSignal },
): Promise<DurableConsumer>;
};
subscribe<T = unknown>(
id: string,
options?: SubscribeOptions,
): AsyncGenerator<ChangeEnvelope<T>>;
};
blobs: {
getBlock(
number: number,
options?: { signal?: AbortSignal },
): Promise<BlobsBlock>;
listBlocks(options: ListBlocksOptions): Promise<Page<BlobsBlock>>;
listSnapshot(
options: ListBlocksOptions,
): Promise<Page<BlobsSnapshotEntry>>;
getTransaction(
hash: Hex,
options?: { signal?: AbortSignal },
): Promise<BlobTransaction>;
listTransactions(
options: ListTransactionsOptions,
): Promise<Page<BlobTransaction>>;
getSchedule(options?: {
atBlock?: number;
signal?: AbortSignal;
}): Promise<BlobSchedule>;
subscribe(
options?: ProcessorSubscribeOptions,
): AsyncGenerator<ChangeEnvelope<BlobsSnapshotEntry>>;
};
erc20: {
getBalance(
token: Hex,
address: Hex,
options?: { signal?: AbortSignal },
): Promise<Erc20Balance>;
subscribe(
options?: ProcessorSubscribeOptions,
): AsyncGenerator<ChangeEnvelope<Erc20Balance>>;
};
uniswap: {
getPool(
address: Hex,
options?: { signal?: AbortSignal },
): Promise<UniswapPoolPrice>;
getLatestObservation(
address: Hex,
options?: { processor?: string; signal?: AbortSignal },
): Promise<LatestUniswapObservation>;
listConfiguredPools(options?: {
processor?: string;
signal?: AbortSignal;
}): Promise<ConfiguredUniswapPools>;
subscribe(
options?: ProcessorSubscribeOptions,
): AsyncGenerator<ChangeEnvelope<UniswapPoolPrice>>;
};
blocks: {
getLatest(options?: {
processor?: string;
signal?: AbortSignal;
}): Promise<LatestBlockSummary>;
getByNumber(
number: number,
options?: { processor?: string; signal?: AbortSignal },
): Promise<LatestBlockSummary>;
subscribe(
options?: ProcessorSubscribeOptions,
): AsyncGenerator<ChangeEnvelope<BlockSummary>>;
};
}createLeaniClient@smart-byte/leani-sdk
export function createLeaniClient(
options: LeaniClientOptions,
): LeaniClient;QueryValue@smart-byte/leani-sdk
export type QueryValue = string | number | boolean | undefined;parseSse@smart-byte/leani-sdk
export async function* parseSse(
body: ReadableStream<Uint8Array>,
signal?: AbortSignal,
): AsyncGenerator<SseMessage>;compareSequences@smart-byte/leani-sdk
export function compareSequences(left: string, right: string): -1 | 0 | 1;isResetRequired@smart-byte/leani-sdk
export function isResetRequired(
change: ChangeEnvelope,
): change is ChangeEnvelope & { operation: "reset_required" };EntityChangeTarget@smart-byte/leani-sdk
export interface EntityChangeTarget<T> {
put(key: string, value: T): void | Promise<void>;
delete(key: string): void | Promise<void>;
}applyEntityChange@smart-byte/leani-sdk
export async function applyEntityChange<T>(
target: EntityChangeTarget<T>,
change: ChangeEnvelope<T>,
): Promise<void>;commitThenAcknowledge@smart-byte/leani-sdk
export async function commitThenAcknowledge<T>(
destinationCommit: () => Promise<T>,
acknowledge: (committed: T) => Promise<unknown>,
): Promise<T>;CursorStore@smart-byte/leani-sdk
export interface CursorStore {
get(): string | undefined;
set(cursor: string): void;
clear(): void;
}createInMemoryCursorStore@smart-byte/leani-sdk
export function createInMemoryCursorStore(initial?: string): CursorStore;BackfillExecutionMode@smart-byte/leani-sdk/backfill
export type BackfillExecutionMode = "fill_missing" | "recompute";BackfillState@smart-byte/leani-sdk/backfill
export type BackfillState =
| "waiting_for_consumer"
| "queued"
| "running"
| "backpressured"
| "storage_backpressured"
| "draining"
| "complete_reclaimable"
| "completed"
| "failed"
| "cancelled";BackfillRange@smart-byte/leani-sdk/backfill
export interface BackfillRange {
fromBlock: number;
toBlock: number;
}RequestedBackfillRange@smart-byte/leani-sdk/backfill
export interface RequestedBackfillRange {
fromBlock: number;
toBlock: number | "finalized";
}BackfillStatus@smart-byte/leani-sdk/backfill
export interface BackfillStatus {
id: string;
owner: "subscription";
processor: string;
/**
* Whether the node configures the processor instance `processor` now.
* Without it, the stream and acknowledgement routes refuse the
* subscription. That can be temporary; if the instance will not return,
* cancel the subscription and delete it with `discardUnacknowledged: true`,
* which discards its unacknowledged records.
*/
processorConfigured: boolean;
/** The required consumer; tell your subscriptions apart by it, not by `id`. */
consumer: string | null;
deliveryStreamId?: string;
publicationRevision?: string;
fromBlock: number;
toBlock: number;
ranges: BackfillRange[];
requestedBlocks: number;
processedBlocks: number;
remainingBlocks: number;
capturedFinalizedTarget?: number;
mode: BackfillExecutionMode;
batching?: EffectiveBackfillBatching;
state: BackfillState;
attempts: number;
updatedAtUnixMs: number;
report: unknown | null;
lastError: string | null;
}HistoricalWorkDeletion@smart-byte/leani-sdk/backfill
export interface HistoricalWorkDeletion {
id: string;
owner: "subscription";
removedJobs: number;
removedSubscriptionRanges: number;
removedConsumers: number;
removedDeliveryRecords: number;
removedDeliveryStreams: number;
removedCoverageIntervals: number;
removedCoverageSegments: number;
removedExactCoverage: number;
removedAppliedBlocks: number;
removedFinalizedUndo: number;
retainedProcessorOutput: boolean;
retainedLiveStream: boolean;
}BackfillBatchingRequest@smart-byte/leani-sdk/backfill
export type BackfillBatchingRequest = Partial<
Omit<
EffectiveBackfillBatching,
"maximumBufferedBatches" | "maximumBufferedBytes"
>
>;BackfillBatchingProfile@smart-byte/leani-sdk/backfill
export type BackfillBatchingProfile = "latency" | "balanced" | "throughput";backfillBatchingProfile@smart-byte/leani-sdk/backfill
export function backfillBatchingProfile(
profile: BackfillBatchingProfile,
): Required<BackfillBatchingRequest>;EffectiveBackfillBatching@smart-byte/leani-sdk/backfill
export interface EffectiveBackfillBatching {
targetEncodedBytes: number;
maximumEncodedBytes: number;
maximumEvents: number;
maximumProcessedBlocks: number;
maximumDelayMs: number;
maximumBufferedBatches: number;
maximumBufferedBytes: number;
compression: "none" | "gzip";
}CreateBackfillSubscription@smart-byte/leani-sdk/backfill
export type CreateBackfillSubscription = CreateBackfillSubscriptionBase &
(
| {
fromBlock: number;
toBlock: number | "finalized";
ranges?: never;
}
| {
ranges: RequestedBackfillRange[];
fromBlock?: never;
toBlock?: never;
}
);liveGapBackfill@smart-byte/leani-sdk/backfill
export function liveGapBackfill(
range: BackfillRange,
request: Omit<CreateBackfillSubscriptionBase, "mode" | "idempotencyKey"> & {
consumer: NonNullable<CreateBackfillSubscriptionBase["consumer"]>;
},
): CreateBackfillSubscription;BackfillStreamHello@smart-byte/leani-sdk/backfill
export interface BackfillStreamHello {
type: "hello";
apiVersion: "1";
chainId: number;
processor: ProcessorSummary;
subscriptionId: string;
streamId: string;
streamKind: "backfill";
publicationRevision: string;
ranges: BackfillRange[];
acknowledgedCursor: string;
storeEpoch: string;
heartbeatIntervalMs: string;
sessionExpiresAtUnixMs: string;
leaseTtlMs: string;
}BackfillStreamBatch@smart-byte/leani-sdk/backfill
export interface BackfillStreamBatch<T = unknown> {
type: "batch";
streamId: string;
originKind: "historical_backfill" | "recompute";
originId: string;
publicationRevision: string;
fromBlock: number;
throughBlock: number;
processedBlockCount: string;
domainChangeCount: string;
progressUnitCount: string;
rawPayloadBytes: string;
uncompressedEncodedBytes: string;
transmittedBytes: string;
buildDelayMs: string;
firstCursor: string | null;
lastCursor: string | null;
acknowledgeableCursor: string;
changes: ChangeEnvelope<T>[];
}BackfillStreamCompletion@smart-byte/leani-sdk/backfill
export interface BackfillStreamCompletion {
type: "backfill_complete";
subscriptionId: string;
streamId: string;
ranges: BackfillRange[];
throughBlock: number;
cursor: string;
mode: BackfillExecutionMode;
disposition:
| "published_all"
| "published_missing_only"
| "already_covered_noop";
requestedBlockCount: string;
coveredBeforeRequestBlockCount: string;
coveredBeforeRequestRanges: BackfillRange[];
newlyProcessedBlockCount: string;
republishedBlockCount: string;
domainChangeCount: string;
preexistingCoverageSkipped: boolean;
repairHint?: "recompute";
}BackfillStreamHeartbeat@smart-byte/leani-sdk/backfill
export interface BackfillStreamHeartbeat {
type: "heartbeat";
emittedAt: string;
}BackfillStreamReset@smart-byte/leani-sdk/backfill
export interface BackfillStreamReset {
type: "reset_required";
code: "reset_required";
message: string;
earliestAvailableSequence: string | null;
latestAvailableSequence: string | null;
}BackfillStreamFailure@smart-byte/leani-sdk/backfill
export interface BackfillStreamFailure {
type: "error";
code: string;
message: string;
earliestAvailableSequence: string | null;
latestAvailableSequence: string | null;
}BackfillStreamRecord@smart-byte/leani-sdk/backfill
export type BackfillStreamRecord<T = unknown> =
| BackfillStreamBatch<T>
| BackfillStreamCompletion
| BackfillStreamHeartbeat;LiveStreamHello@smart-byte/leani-sdk/backfill
export interface LiveStreamHello {
type: "hello";
apiVersion: "1";
chainId: number;
processor: ProcessorSummary;
streamId: string;
streamKind: "live";
acknowledgedCursor: string;
storeEpoch: string;
heartbeatIntervalMs: string;
sessionExpiresAtUnixMs: string;
leaseTtlMs: string;
/** What the processor covers as the session starts: diff it against the
* destination to find blocks to request as history. */
coverage: ProcessorCoverage;
}LiveStreamBatch@smart-byte/leani-sdk/backfill
export interface LiveStreamBatch<T = unknown> {
type: "batch";
streamId: string;
originKind: "live" | "live_recovery";
originId: string;
publicationRevision: "0";
fromBlock: number;
throughBlock: number;
processedBlockCount: "1";
domainChangeCount: string;
progressUnitCount: "1";
rawPayloadBytes: string;
uncompressedEncodedBytes: string;
transmittedBytes: string;
buildDelayMs: string;
firstCursor: string;
lastCursor: string;
acknowledgeableCursor: string;
changes: ChangeEnvelope<T>[];
}LiveStreamRecord@smart-byte/leani-sdk/backfill
export type LiveStreamRecord<T = unknown> =
| LiveStreamBatch<T>
| BackfillStreamHeartbeat;DeliverySession@smart-byte/leani-sdk/backfill
export interface DeliverySession<THello, TRecord>
extends AsyncIterable<TRecord> {
readonly hello: THello;
acknowledge(
cursor: string,
options?: { signal?: AbortSignal },
): Promise<DurableConsumer>;
close(): Promise<void>;
}BackfillDeliverySession@smart-byte/leani-sdk/backfill
export interface BackfillDeliverySession<T = unknown>
extends DeliverySession<BackfillStreamHello, BackfillStreamRecord<T>> {
batches(): AsyncIterable<BackfillStreamBatch<T>>;
/**
* Every acknowledgement boundary with the changes it covers: each batch,
* including one without changes, then the completion. Commit `events`,
* then acknowledge `ackCursor`.
*/
deliveryBatches(): AsyncIterable<HistoryDeliveryBatch<T>>;
/**
* The batches' changes, flattened. They carry no acknowledgement
* boundary; acknowledge from `deliveryBatches()` or `batches()`.
*/
events(): AsyncIterable<ChangeEnvelope<T>>;
}LiveDeliverySession@smart-byte/leani-sdk/backfill
export type LiveDeliverySession<T = unknown> = DeliverySession<
LiveStreamHello,
LiveStreamRecord<T>
>;MultiLaneSubscriptionRequest@smart-byte/leani-sdk/backfill
export interface MultiLaneSubscriptionRequest {
processor: string;
consumer: string;
credential?: string;
lanes: {
live?: boolean;
history?: Array<{ subscriptionId: string }>;
};
view?: "live_priority" | "lane_specific";
batching?: BackfillBatchingRequest;
signal?: AbortSignal;
}UnifiedDeliveryBatch@smart-byte/leani-sdk/backfill
export type UnifiedDeliveryBatch<T = unknown> =
| {
laneKind: "live";
laneId: "live";
streamId: string;
ackCursor: string;
events: ChangeEnvelope<T>[];
completion?: never;
record: LiveStreamBatch<T>;
}
| {
laneKind: "history";
laneId: string;
streamId: string;
ackCursor: string;
events: ChangeEnvelope<T>[];
completion?: BackfillStreamCompletion;
record: BackfillStreamBatch<T> | BackfillStreamCompletion;
};HistoryDeliveryBatch@smart-byte/leani-sdk/backfill
export type HistoryDeliveryBatch<T = unknown> = Extract<
UnifiedDeliveryBatch<T>,
{ laneKind: "history" }
>;MultiLaneDelivery@smart-byte/leani-sdk/backfill
export interface MultiLaneDelivery<T = unknown> {
batches(): AsyncIterable<UnifiedDeliveryBatch<T>>;
liveBatches(): AsyncIterable<UnifiedDeliveryBatch<T>>;
historyBatches(
subscriptionId: string,
): AsyncIterable<UnifiedDeliveryBatch<T>>;
acknowledge(
batch: UnifiedDeliveryBatch<T>,
options?: { signal?: AbortSignal },
): Promise<DurableConsumer>;
close(): Promise<void>;
}BackfillSubscriptionClientOptions@smart-byte/leani-sdk/backfill
export interface BackfillSubscriptionClientOptions {
baseUrl: string | URL;
token?: string;
fetch?: FetchLike;
/** Deadline for JSON requests; established delivery streams stay open. */
timeoutMs?: number;
}BackfillSubscriptionClient@smart-byte/leani-sdk/backfill
export interface BackfillSubscriptionClient {
readonly baseUrl: URL;
create(request: CreateBackfillSubscription): Promise<BackfillStatus>;
list(options?: { signal?: AbortSignal }): Promise<BackfillStatus[]>;
inspect(
subscription: string,
options?: { signal?: AbortSignal },
): Promise<BackfillStatus>;
cancel(
subscription: string,
options?: { signal?: AbortSignal },
): Promise<BackfillStatus>;
/** Re-queue a failed subscription to resume from its committed progress. */
retry(
subscription: string,
options?: { signal?: AbortSignal },
): Promise<BackfillStatus>;
/**
* Delete a terminal subscription. A failed or cancelled one is refused
* while its required consumer has unacknowledged records, unless
* `discardUnacknowledged` is set.
*/
delete(
subscription: string,
options?: { signal?: AbortSignal; discardUnacknowledged?: boolean },
): Promise<HistoricalWorkDeletion>;
changes<T = unknown>(
subscription: string,
consumer: string,
options?: {
credential?: string;
limit?: number;
signal?: AbortSignal;
},
): Promise<{
data: ChangeEnvelope<T>[];
nextCursor: string | null;
coverage: unknown;
}>;
stream<T = unknown>(
subscription: string,
consumer: string,
options?: {
credential?: string;
batching?: BackfillBatchingRequest;
signal?: AbortSignal;
},
): Promise<BackfillDeliverySession<T>>;
streamLive<T = unknown>(
processor: string,
consumer: string,
options?: { credential?: string; signal?: AbortSignal },
): Promise<LiveDeliverySession<T>>;
subscribe<T = unknown>(
request: MultiLaneSubscriptionRequest,
): Promise<MultiLaneDelivery<T>>;
}createBackfillSubscriptionClient@smart-byte/leani-sdk/backfill
export function createBackfillSubscriptionClient(
options: BackfillSubscriptionClientOptions,
): BackfillSubscriptionClient;BackfillFailurePolicy@smart-byte/leani-sdk/backfill
export type BackfillFailurePolicy = "retry" | "discard" | "throw";RunBackfillOptions@smart-byte/leani-sdk/backfill
export interface RunBackfillOptions<T = unknown> {
/** Apply one history batch. It is acknowledged after this resolves. */
onBatch(batch: HistoryDeliveryBatch<T>): void | Promise<void>;
/** What a failed subscription does: retry it (default), delete it, or throw. */
onFailure?: BackfillFailurePolicy;
/** Retries before "retry" gives up and throws. Default 3. */
maxRetries?: number;
/** The consumer's credential; `request.consumer.credential` by default. */
credential?: string;
batching?: BackfillBatchingRequest;
/**
* Stops the run, as `request.signal` does too. The run rejects with the
* abort reason and keeps the subscription.
*/
signal?: AbortSignal;
}RunBackfillResult@smart-byte/leani-sdk/backfill
export interface RunBackfillResult {
outcome: "completed" | "cancelled" | "failed";
/** The subscription as it ended, before its deletion. */
subscription: BackfillStatus;
/** The completion record this run received, if it streamed one. */
completion?: BackfillStreamCompletion;
deletion: HistoricalWorkDeletion;
}runBackfill@smart-byte/leani-sdk/backfill
export async function runBackfill<T = unknown>(
client: BackfillSubscriptionClient,
request: CreateBackfillSubscription,
options: RunBackfillOptions<T>,
): Promise<RunBackfillResult>;parseNdjson@smart-byte/leani-sdk/backfill
export async function* parseNdjson(
body: ReadableStream<Uint8Array>,
signal?: AbortSignal,
): AsyncGenerator<unknown>;LeaniErrorBody@smart-byte/leani-sdk
export interface LeaniErrorBody {
error: {
code: string;
message: string;
retryable: boolean;
details?: Record<string, unknown> | null;
requestId: string;
};
}Built by Smart-Byte · Legal notice (Impressum) · Privacy