npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@viz-cx/api

v0.1.5

Published

Type-safe TypeScript SDK for the VIZ site API (api.viz.cx): blocks, profiles, richlist, signed webhooks, and the live op WebSocket.

Readme

@viz-cx/api

Type-safe TypeScript SDK for the VIZ site API (api.viz.cx): blocks, profiles, richlist, signed webhooks, and the live op WebSocket stream.

Relationship to @viz-cx/core

@viz-cx/api is the site API SDK — it talks to the api.viz.cx REST/WebSocket service built on top of the VIZ node. @viz-cx/core is the node RPC SDK — it talks directly to a VIZ node via JSON-RPC. Use @viz-cx/api for frontend/app integrations; use @viz-cx/core when you need raw chain access, transaction signing, or broadcasts. The two packages are independent; @viz-cx/core becomes relevant here only as the optional signer backend.

Install

pnpm add @viz-cx/api
# Optional: install @viz-cx/core if you want the batteries-included signer
pnpm add @viz-cx/core

Quickstart

import { createApiClient } from '@viz-cx/api';

const client = createApiClient();

const info = await client.getChainInfo();
console.log(info?.head_block_number);

const profile = await client.getProfile('alice');
console.log(profile?.balance);

const richlist = await client.getRichlist();
console.log(richlist?.accounts.length); // full snapshot (~14k accounts)

const block = await client.getBlock(81_000_000);
console.log(block?.block.length);

Auth

Signed requests use a nonce-based challenge flow. You provide a Signer — any object with { account: string, sign(nonceBytes: Uint8Array): string | Promise<string> }.

Custom SignFn

import { createApiClient } from '@viz-cx/api';
import type { SignFn } from '@viz-cx/api';

const mySign: SignFn = (nonceBytes) => {
  // Return a hex-encoded 65-byte recoverable ECDSA signature over sha256(nonceBytes).
  return myHardwareWallet.sign(nonceBytes);
};

const client = createApiClient({
  auth: { account: 'alice', sign: mySign },
});

withCoreSigner (batteries-included)

If @viz-cx/core is installed, use withCoreSigner from the @viz-cx/api/core-signer subpath:

import { createApiClient } from '@viz-cx/api';
import { withCoreSigner } from '@viz-cx/api/core-signer';

const client = createApiClient({
  auth: withCoreSigner('alice', '5J...privateKey'),
});

withCoreSigner wraps keys.sign from @viz-cx/core, which produces a 65-byte recoverable ECDSA signature (hex) over sha256(nonceBytes) — the format api.viz.cx expects.

Webhooks CRUD

Webhooks require auth. Pass an auth signer in client options or per-call.

import { createApiClient } from '@viz-cx/api';
import { withCoreSigner } from '@viz-cx/api/core-signer';

const client = createApiClient({
  auth: withCoreSigner('alice', '5J...privateKey'),
});

// Create a webhook (filter is optional)
const created = await client.webhooks.create({
  url: 'https://example.com/hook',
  filter: { opType: 'award', account: 'alice' },
});
console.log(created.id, created.secret);

// List webhooks for this account
const rows = await client.webhooks.list();
rows.forEach((r) => console.log(r.id, r.url, r.active));

// Delete a webhook
await client.webhooks.delete(created.id);

Live op stream (WebSocket)

client.streamOps(filter?) returns an OpStream — a reconnecting WebSocket client that is also an AsyncIterable.

Callback style

const stream = client.streamOps({ opType: 'award' });

const unsub = stream.on((msg) => {
  console.log(msg.opType, msg.body);
});

stream.onStatus((s) => console.log('status:', s)); // 'open' | 'reconnecting' | 'closed'

// Later:
unsub();
stream.close();

Async iterator style

const stream = client.streamOps();
for await (const msg of stream) {
  console.log(msg.opType, msg.body);
  if (someCondition) break; // break calls stream.close() automatically
}

Node.js WebSocket injection

The browser WebSocket global is used by default. In Node.js (< 22), inject one explicitly:

import { createApiClient } from '@viz-cx/api';
import { WebSocket } from 'ws';

const client = createApiClient({ WebSocket });
const stream = client.streamOps();

API reference

interface ApiClient {
  getChainInfo(): Promise<ChainInfo | null>;
  getLatestBlock(): Promise<BlockDoc | null>;
  getBlock(id: number): Promise<BlockDoc | null>;
  getProfile(user: string): Promise<Profile | null>;
  getRichlist(): Promise<Richlist | null>;
  avatarUrl(user: string): string;
  webhooks: {
    create(input: { url: string; filter?: WebhookFilter }, signer?: Signer): Promise<WebhookCreated>;
    list(signer?: Signer): Promise<WebhookRow[]>;
    delete(id: string, signer?: Signer): Promise<{ ok: true }>;
  };
  streamOps(filter?: WebhookFilter): OpStream;
  fetchNonce(): Promise<string>;
  authedFetch(path: string, init: RequestInit, signer?: Signer): Promise<Response>;
}

Options

createApiClient({
  baseUrl?: string;        // default: 'https://api.viz.cx'
  wsUrl?: string;          // default: 'wss://api.viz.cx/ws/ops'
  auth?: Signer;           // default signer for authed calls
  WebSocket?: WebSocketCtor; // WebSocket constructor (Node.js injection)
  fetch?: typeof fetch;    // custom fetch implementation
})

License

MIT