espo-ts
v1.0.0
Published
Typescript SDK for Espo - the modular alkanes indexer
Readme
espo-ts SDK
A TypeScript client for the ESPO RPC API. Every call returns a BoxedResponse (via the bxrs package) so that success and failure states are explicit and exhaustively typed. If you have used Rust’s Result, you will feel right at home.
Installation
npm install espo-ts
# or
yarn add espo-ts
# or
pnpm add espo-tsQuick Start
import { Espo } from "espo-ts";
const client = new Espo("https://api.alkanode.com/rpc");
const holders = await client.getHolders("2:0", { limit: 5 });
if (holders.isErr()) {
console.error("Failed:", holders.errorType, holders.message);
process.exit(1);
}
console.log("First holder", holders.data.items.at(0));bxrs Error Handling
This SDK intentionally reuses bxrs primitives so you can chain, unwrap, or retry the same way you would with a Rust Result. If you have not used bxrs before, read their primitives (mirrored below) and the official docs.
import {
BoxedResponse,
Err,
Ok,
isErr,
retryOnBoxedError,
consumeOrThrow,
} from "bxrs";bxrs gives you:
Ok(data)/Err(message?, errorType?)factories- Gradual transforms with
.map(),.mapErr(),.andThen() - Guards (
isErr,isOk) and helpers (consumeOrThrow,consumeOrNull,retryOnBoxedError) - Long-form docs covering motivation, core types, and best practices
Essentials Module
const espo = new Espo("https://api.alkanode.com/rpc");
const tip = await espo.getTipHeight();
const holders = await espo.getHolders("2:68479", { limit: 10, page: 1 });
const balances = await espo.getAddressBalances(
"bc1pzysd2zc06t2j8wv3tqpsc2sj49kseerqmfn5g4zzz5nq23a4g36qwq24rw",
{ includeOutpoints: true }
);
const outpoints = await espo.getAddressOutpoints(
"bc1pzysd2zc06t2j8wv3tqpsc2sj49kseerqmfn5g4zzz5nq23a4g36qwq24rw"
);
const keys = await espo.getKeys("2:68479", { tryDecodeUtf8: true, limit: 5 });All returned payloads have already been normalized:
- Amount strings are converted to
number(8-decimal precision) orbigint - Optional curse-case parameters accept both snake and camel variants
value_u128fields fromgetKeysbecomebigint | null
AMM Data Example
const pool = "2:69744";
const base = "2:68479";
const quote = "2:0";
const pools = await espo.getPools({ limit: 5 });
const trades = await espo.getTrades(pool, { limit: 10, direction: "desc" });
const path = await espo.findBestSwapPath(base, quote, {
mode: "exact_in",
amountIn: 1_000_000n,
});
if (path.isOk()) {
console.log("Amount out", path.data.amount_out.toString());
console.log("Hops", path.data.hops);
}Every AMM response preserves full precision: pool reserves, swap amounts, and profits arrive as bigints, and swap hops are pre-normalized for convenience.
Handling Errors with bxrs
const holders = await espo.getHolders("2:0");
const response = holders
.map((payload) => payload.items.slice(0, 3))
.mapErr((err) => ({
errorType: "EspoClientError",
message: `failed at ${new Date().toISOString()}: ${err.message}`,
}));
if (response.isErr()) {
console.error(response.errorType, response.message);
return;
}
console.table(response.data);If you prefer to throw on failure:
import { consumeOrThrow } from "bxrs";
const retry = retryOnBoxedError({ timeoutMs: 10_000 });
const bestSwap = await retry(() => espo.getBestMevSwap("2:68479"));
const payload = consumeOrThrow(bestSwap);
console.log(payload.amount_out.toString());Testing Script
This repo includes npm run test which hits the public RPC using the provided address/outpoint/pool. Review test.ts for a real-world example of calling every method in sequence.
