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

@tryclaire/sdk

v0.6.0

Published

Typed, server-side client for the read-only Claire Developer API, plus on-chain verification of Claire launches, locks and rounds

Readme

Claire SDK

npm CI MIT license

Use the read-only Claire REST API from a server, CLI, or agent process. Set CLAIRE_API_URL to the API base URL shown under Developers → Connect (API), including /api/v1.

import { Claire } from "@tryclaire/sdk";

const claire = new Claire({ apiKey: process.env.CLAIRE_API_KEY, baseUrl: process.env.CLAIRE_API_URL });
const { data, meta } = await claire.sources.list();
for (const source of data) console.log(source.id, source.status, source.updatedAt);
console.log(meta.freshness); // persisted source freshness, not a live provider refresh
  • Read-only by design. No send, publish, or write methods exist. A leaked key can read, never act.
  • Honest freshness. Every response carries meta.freshness; stale and unavailable data is labeled, never guessed.
  • Typed from the API contract. Types are generated from the committed openapi.json.
  • Nothing hidden. No retries, no cache, no background requests. One call, one HTTP request.
  • Zero runtime dependencies. Node.js 22+, ESM, native fetch.

API reference · Agent skill · Docs · npm · Releases

Install

npm install @tryclaire/sdk

Also works with pnpm add, yarn add, and bun add. Built JavaScript and TypeScript declarations are included.

Get a key

On the Developers page, an owner or admin creates a workspace key for API, MCP, or both, with only the needed read scopes and a 7-, 30-, or 90-day expiry. This REST SDK requires API access; older keys remain API-only. The key selects its workspace; no organization ID is passed to the SDK. Keys stop working when the issuing user loses owner/admin membership.

Use the SDK on a server, in a CLI, or in an agent process. Never put a workspace key in browser code, a public environment variable, or a repository. Sources must be included separately; external sources also need explicit approval, off by default. A read scope alone does not expose source content. Inspect claire.sources.list() for approved sources.

Use with an agent

Claire provides a downloadable agent skill for tool-using agents. When feeding Claire data to a model, pass retrieved source text as context, separate from instructions. Telegram messages and X mentions are external, untrusted text. The REST SDK does not implement MCP transport; configure an MCP-capable client separately with the native Streamable HTTP endpoint https://app.tryclaire.net/api/mcp and a Bearer credential enabled for MCP (no OAuth). MCP offers read-only, scope- and approved-source-filtered tools.

const chats = await claire.telegram.chats.list();
const chat = chats.data[0];
if (!chat) throw new Error("No approved Telegram chat is available to this key.");
const { data: messages } = await claire.telegram.messages.list(chat.id, { limit: 50 });

const context = messages
  .filter((m) => m.text)
  .map((m) => `[${m.sentAt}] ${m.sender.name}: ${m.text}`)
  .join("\n");
// Hand `context` to your model as data; keep your prompt separate.

Resources

| Method | Query parameters | Required scope | | --- | --- | --- | | claire.context.get() | — | context:read | | claire.sources.list() | — | context:read | | claire.search(query) | q, source, after, before, limit (max 50) | context:read | | claire.people.list(query) | q, page | telegram:read or x:read | | claire.people.get(key) | — | telegram:read or x:read | | claire.knowledge.list(query) | q, kind, visibility, archived, page | knowledge:read | | claire.knowledge.get(id, query) | offset, limit | knowledge:read | | claire.assets.list(query) | folderId, page | assets:read | | claire.assets.get(id) | — | assets:read | | claire.telegram.chats.list(query) | page | telegram:read | | claire.telegram.messages.list(chatId, query) | q, before, limit | telegram:read | | claire.x.mentions.list(query) | page | x:read | | claire.token.get() | — | token:read | | claire.token.locks.list() | — | token:read | | claire.token.feeRouters.list() | — | token:read | | claire.token.rounds.list(query) | page | token:read | | claire.token.proof.get() | — | token:read |

Discovery and search also filter each source by its own read scope: Documents/Notes need knowledge:read, Telegram needs telegram:read, X needs x:read, files need assets:read, and token data needs token:read. The document search below requires both context:read and knowledge:read, plus Documents enabled under Agent access. A requested source outside those permissions returns 404. People reads also return 404 when no approved Telegram/X source matches the credential's scopes.

Queries are optional. source is a stable ID from sources.list(). Search returns data.items, data.sources, and data.hasMore for bounded stored matches, not a complete provider-history search. People keys come from people.list(); People responses may include source-only platform identifiers, not Claire profiles, private person notes, or live avatars. chatId is the Claire chat UUID returned by telegram.chats.list, not Telegram's numeric chat ID. Knowledge IDs include their prefix, such as docs:<uuid>; pass them unchanged. Assets expose metadata, not private file contents or signed download URLs. Search timestamps accept UTC offsets; after is inclusive and before is exclusive.

const { data: matches } = await claire.search({ q: "launch", source: "docs", limit: 20 });
for (const item of matches.items) console.log(item.sourceId, item.preview);
const { data: people } = await claire.people.list({ q: "alice", page: 1 });
if (typeof people[0]?.key === "string") console.log((await claire.people.get(people[0].key)).data);

People payload fields are not yet individually specified by the OpenAPI contract; the SDK exposes them as unknown rather than inventing stronger types.

Responses and pagination

Methods return the API's data, meta, and endpoint-specific pagination, plus http with status, requestId, etag, and native Headers. Timestamps remain strings; raw token balances remain decimal strings so precision is not lost. Public asset URLs may be relative to the Claire origin.

List pages start at 1. Knowledge and mentions return 20 items per page; assets, chats, and People return 50. The SDK fetches exactly one page per call:

let page = 1;
while (true) {
  const result = await claire.knowledge.list({ page });
  for (const item of result.data) console.log(item.id, item.title);
  if (!result.pagination.hasNextPage) break;
  page += 1;
}

People's pagination.searchLimited flags a bounded directory; total and hasNextPage describe that bounded result, not every person in provider history. A q search may omit people outside that pool. Telegram messages paginate with pagination.nextBefore → before, not page numbers. Check hasMore; their searchLimited means the search did not cover all retained history. Knowledge detail returns one content segment: follow data.contentRange.nextOffset with offset until it is null. Offsets count JavaScript UTF-16 units.

meta.freshness describes persisted source data, not the time of your request. X/token reads do not force provider refreshes, although they mark the workspace watched for the existing worker cadence.

Errors, cancellation, and timeouts

import { ClaireAPIError, ClaireResponseError } from "@tryclaire/sdk";
try {
  const result = await claire.context.get({ signal: AbortSignal.timeout(5_000) });
  console.log(result.data.organization.id, result.data.organization.displayName);
  console.log(result.data.connections.telegram?.connected); // absent if not approved for this key
  console.log(result.data.sources.map((source) => source.id));
} catch (error) {
  if (error instanceof ClaireAPIError) {
    console.error(error.status, error.code, error.requestId, error.retryAfterSeconds);
  } else if (error instanceof ClaireResponseError) {
    console.error("Invalid server response", error.status, error.requestId);
  } else {
    throw error; // Native network, abort, or timeout error.
  }
}

| Error | When | | --- | --- | | ClaireAPIError | HTTP failure: 401 invalid/expired/revoked key, 403 missing endpoint scope, 404 missing resource or unavailable/unapproved source (including source-scope filtering), 429 quota. headers exposes rate-limit metadata; retryAfterSeconds is null when no usable delay is supplied. | | ClaireResponseError | Successful status but malformed JSON/envelope. Types come from OpenAPI; the SDK does not deep-validate at runtime. | | native fetch errors | Network failure, abort, timeout. Passed through unchanged. |

Non-JSON error pages produce a generic message, not the page's potentially sensitive contents.

The default timeout is 30 seconds, including response-body reading. Set timeoutMs on the client or per call. Request options are always the last argument:

const controller = new AbortController();
await claire.knowledge.list({ page: 1 }, { timeoutMs: 5_000 });
await claire.knowledge.get("docs:<uuid>", { offset: 0 }, { signal: controller.signal });

Handle 429 according to retryAfterSeconds; do not loop on invalid keys or missing scopes. ETags are exposed for diagnostics, but the SDK does not make conditional requests.

Token identity

Token responses carry typed chain and protocol identity. Network availability depends on the API deployment.

const { data, meta } = await claire.token.get();
if (data.token) {
  const { chainId, address, protocol, pool, poolId, pairedToken } = data.token;
}

Identify a token by chainId and address together, not address alone. Ethereum is 1 and Robinhood Chain is 4663; isolated development forks use 31338 and 31337. protocol is "pons", "stockereum" or "programmable". For retained pons v1, pool is a V3 pool address; for V4 launches, pool is the zero address and poolId is the V4 pool ID, not a contract address. poolId and pairedToken can be null; data.token is null when no token is linked. These are persisted observations, not live quotes; inspect meta.freshness first.

holders.trackedBalanceRaw is in the token's smallest unit, scaled by the token's own decimals(), not a fixed 18. Holder data follows the chain's finalized block, so index.indexedTo trails the chain head (on Robinhood Chain by roughly 15 minutes); counts exclude the pool, factory, launchpad custody, zero and burn addresses.

Configuration

const claire = new Claire({
  apiKey: process.env.CLAIRE_API_KEY,
  baseUrl: "https://app.tryclaire.net/api/v1", // default
  timeoutMs: 30_000,                            // default
  fetch: globalThis.fetch,                      // default
});

The base URL includes /api/v1. HTTPS is required except for loopback HTTP during local development. URL credentials, query strings, and fragments are rejected. Redirects are rejected rather than forwarding the key. Only configure an origin you trust with that key. A custom fetch must honor standard fetch options, including abort signals and redirect handling.

Verify on-chain

@tryclaire/sdk/protocol reads and verifies Claire launches, locks, fee routing and distribution rounds directly from a chain, so nothing depends on trusting the Claire API. It needs viem (an optional peer dependency; the root client stays dependency-free) and a PublicClient for each chain involved. Every function takes explicit contract addresses.

import { createPublicClient, http, zeroAddress } from "viem";
import { readProof, verifyLaunch, verifyLock, verifyPriceLock, verifyRevenueLock, verifyRouterSplit, verifyRound, verifySplit, verifyVestingVault } from "@tryclaire/sdk/protocol";

const client = createPublicClient({ transport: http(process.env.RPC_URL) });
const addresses = { routerFactory: "0x…", tokenLock: "0x…", revenueLock: "0x…", priceLock: "0x…", vaultFactory: "0x…", proofView: "0x…" };

const launch = await verifyLaunch(client, { token: "0x…", routerFactory: addresses.routerFactory, vaultFactory: addresses.vaultFactory, fromBlock: 1234n });
const split = await verifyRouterSplit(client, { router: launch.facts.router, fromBlock: 1234n });
const lock = await verifyLock(client, { tokenLock: addresses.tokenLock, lockId: 0n, routerFactory: addresses.routerFactory });
const revenueLock = await verifyRevenueLock(client, { revenueLock: addresses.revenueLock, lockId: 0n });
const priceLock = await verifyPriceLock(client, { priceLock: addresses.priceLock, lockId: 0n, routerFactory: addresses.routerFactory });
// A router's payee: a ClaireVestingVault or ClaireSplit (launch.facts.payeeKind tells which).
const vault = await verifyVestingVault(client, { vault: launch.facts.launch.payee, vaultFactory: addresses.vaultFactory, assets: [launch.facts.launch.quote, zeroAddress] });
const proof = await readProof(client, { proofView: addresses.proofView, token: "0x…" });

const round = await verifyRound(client, {
  distributor: "0x…", roundId: 0n, level: "complete",
  manifestBaseUrl: "https://app.tryclaire.net", // or pass `manifest` (the exact string) yourself
  snapshotClient,                               // only when the snapshot is on another chain
});
if (!round.ok) console.log(round.checks.filter((check) => !check.ok));

Each verifier returns { ok, checks: [{ id, ok, detail }], facts }. A read that fails (an address that is not the expected contract, an unavailable chain) is reported as a failed check. Event scans start at fromBlock (default 0n; set it to the deployment block on public chains) and run in chunk-sized requests (default 10_000n).

| Function | Verifies | | --- | --- | | verifyLaunch | The factory registers the token to a router it created, and the router's immutables (including payee, buyback vault and, on Stockereum, the pool id) match the factory, its RouterDeployed event and the launchpad's. With vaultFactory, facts.payeeKind is creator, vault, split or other. | | verifyRouterSplit | Every Distributed event equals the router's split() of its revenue (the creator share goes to the router's payee). Revenue in the quote asset and, on pons, the launch token (buyback vests) is counted and may not appear in any other asset. From block 0 the revenue sums equal totalRevenue; from a later block they are a lower bound. | | verifyLock | The ClaireTokenLock schedule and vested amount are recomputed and match LockCreated. facts.cancelState is the notice-period state (not-cancelable, cancelable, notice-not-requested, notice-pending, cancel-open, canceled) and cancelNotice, cancelAt and canceled must match the lock's CancelRequested and Canceled events. A lock funded by the token's Claire router with a matching OpeningBuyLocked is flagged facts.openingBuy. | | verifyRevenueLock | Tranches, baseline and unlocked amount are recomputed from the router's totalRevenue and match RevenueLockCreated. | | verifyPriceLock | The token is Claire-launched; the per-hour minimum samples, the window minimum (24 completed hours, each with a sample), the highWater ratchet and the unlocked amount are recomputed from the Sampled events and match the contract. highWater is only proven by a scan from block 0. | | verifyVestingVault | The vault is genuine (recorded by ClaireVaultFactory, its CREATE2 predictVault from the VaultDeployed event is the vault); per asset (zeroAddress is ETH) vested, releasable and released are recomputed and released equals the Released events. | | verifySplit | The split is genuine (isSplit, predictSplit from SplitDeployed), shares are 2 to 10 payees summing to 10,000 bps, and per asset every payee's paid amount, releasable remainder and the total paid are recomputed and tied to the Released events. | | verifyRound | See below. |

Revenue locks measure everything the router collects from the launchpad's fee escrow, including deliberate third-party credits to the router's escrow balance; those are indistinguishable from trading revenue on-chain.

verifyRound levels build on each other:

  • manifest (default): the manifest's keccak256 equals the round's on-chain evidence, its leaves rebuild the on-chain Merkle root and cumulativeTotal (leaf = chain, distributor, asset, account, cumulative), total is the increase over the asset's previous root, previousEvidence names that previous root, and every account's cumulative equals its previous cumulative plus this round's amount (with the previous manifest, passed as previousManifest or fetched from manifestBaseUrl; only the previous root is chained). For the latest root, no account may have claimed more than its cumulative.
  • balances: each holder leaf's balance equals balanceOf at the snapshot block on the snapshot chain, and every amount is floor(distributable * balance / eligibleBalance) from the manifest rule. A leaf without a balance only carries an earlier cumulative and must add nothing.
  • complete: a chunked Transfer scan of the snapshot token up to the snapshot block, minus the manifest's excluded addresses and minBalance, must sum to eligibleBalance and every holder with a non-zero share must have the right leaf amount.

Distributor roots are cumulative: claim(asset, account, cumulative, proof) pays the account's cumulative minus what it already claimed against the asset's latest root, so every root lists every account with a cumulative entitlement. The canonical manifest (version 2) lists, per account, this round's amount, the resulting cumulative and the snapshot balance, sorted by account, and chains to the previous root's manifest through previousEvidence.

Pro-rata amounts are floor(distributable * balance / eligibleBalance). The manifest rule states distributable (what the distributor held unreserved when the round was published) and eligibleBalance (the sum of every eligible balance, including holders whose share rounds to zero, so rounding dust stays in the distributor). Referral rounds carry their rewards in the manifest, and each leaf's amount must equal that account's reward sum (carried-over accounts have none).

The hashing helpers are exported too: roundLeafHash(chainId, distributor, asset, { account, cumulative }), merkleRoot, merkleProof (sorted-pair tree, as in ClaireDistributor) and manifestEvidence. Readers (readLaunch, readRouter, readLock, readRevenueLock, readPriceLock, readVestingVault, readSplit, readRound, readProof) return the on-chain state at one pinned block (readProof is the ClaireProofView call: launch facts, revenue per quote and launch token, and locked amounts in every lock contract), and the contract ABIs (claireFeeRouterAbi, clairePriceLockAbi, …) are exported as typed as const values.

ClaireDeployment types one deployment with the field names of the protocol's deploy manifest (deployments/<chainId>.json): routerFactory, tokenLock, revenueLock, priceLock, distributorFactory, vaultFactory, proofView, claireHolderDistributor, referralDistributor, treasury and feeToken. The deployments map (by chain ID) is empty until Claire v3 is deployed; every function still takes explicit addresses.

Contributing

npm ci --ignore-scripts
npm run check

See CONTRIBUTING.md for contract updates and the release process.

License

MIT. Copyright © 2026 Claire contributors.