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

@lumifyai/sdk

v0.1.0

Published

Official TypeScript/JavaScript SDK for the Lumify agent-ready sports intelligence API (schedules, live scores, odds, betting splits, and AI bet intelligence).

Readme

@lumifyai/sdk

Official TypeScript/JavaScript client for Lumify, the agent-ready sports intelligence API — schedules, live scores, odds, line movement, public betting splits, and AI bet intelligence across MLB, NFL, NCAAF, NBA, NHL, tennis, and soccer.

Status: v0.1.0 — the data-plane slice (sports/seasons/events/teams/players, SSE streaming, webhooks, agent onboarding). Same data as the REST API and the MCP server — this SDK is the typed REST path, not a third implementation.

Install

npm install @lumifyai/sdk

Requires Node.js 18+ (uses native fetch and Web Crypto — zero runtime dependencies) or any modern browser/edge runtime.

Quick start

import { Lumify } from "@lumifyai/sdk";

const client = new Lumify({ apiKey: process.env.LUMIFY_API_KEY! });

const { sports } = await client.sports.list();

const event = await client.events.get(12345, {
  includeOdds: true,
  includeIntelligence: true,
});
console.log(event.status, event.intelligence?.bets);

Create a key at https://lumify.ai/api-keys or programmatically via client.agent.keys.create().

Resources

client.sports.list() / client.seasons.list()
client.events.list(filters) / .get(id, { includeOdds?, includeIntelligence?, bookmaker? })
client.events.odds(id) / .oddsHistory(id) / .score(id) / .intelligence(id) / .splits(id)
client.events.stream(id)          // SSE async iterator of live score updates
client.events.paginate(filters) / .iterate(filters)   // cursor pagination helpers
client.teams.list(filters) / .get(id)
client.players.list(filters) / .get(id) / .events(id, filters)
client.webhooks.create() / .list() / .delete(id) / .verify(secret, header, rawBody)
client.agent.keys.create() / .list() / .revoke(id)
client.agent.credits.get() / .listPacks() / .topup(packId)

Every method maps 1:1 to a REST endpoint and returns the same JSON shape you'd get from curl — see https://lumify.ai/docs/reference for full field docs.

Pagination

List endpoints are cursor-paginated (after_id/limit, max 100). Use the iterator helpers instead of tracking cursors by hand:

for await (const event of client.events.iterate({ sport: "nfl", status: "scheduled" })) {
  console.log(event.id, event.starts_at);
}

// Or page-by-page (events pages use `events`, not `data`):
for await (const page of client.events.paginate({ sport: "nfl" }, { limit: 50 })) {
  console.log(page.events?.length, "events, next cursor:", page.next_after_id);
}

Live score streaming (SSE)

for await (const evt of client.events.stream(eventId)) {
  if (evt.event === "score") console.log(evt.data.status, evt.data.clock);
  if (evt.event === "done") break;
}

Cheaper than polling client.events.score(id) — the server only emits on change, plus periodic keep-alives, and closes when the event finishes.

Webhooks

const sub = await client.webhooks.create({ url: "https://you.example.com/hooks/lumify" });
// sub.signing_secret ("whsec_...") is returned once — store it.

// In your webhook handler, verify against the *raw* request body:
await client.webhooks.verify(signingSecret, req.header("Lumify-Signature")!, rawBody);

verify() throws WebhookSignatureError (bad format, signature mismatch, or a stale/replayed timestamp) — treat that as "reject with 4xx", not a crash.

Errors

Every non-2xx response throws a typed subclass of LumifyError — switch on err.code (the stable machine-readable slug), not err.message:

import { NotFoundError, RateLimitError, ValidationError } from "@lumifyai/sdk";

try {
  await client.events.get(999999999);
} catch (err) {
  if (err instanceof NotFoundError) { /* ... */ }
  if (err instanceof RateLimitError) console.log("retry after", err.retryAfter, "s");
  if (err instanceof ValidationError) console.log(err.fieldErrors);
}

AuthenticationError (401), PaymentError (402), PermissionError (403, has .upgradeUrl on sport-scope denials), NotFoundError (404), ValidationError (422, has .fieldErrors), RateLimitError (429, has .retryAfter from the envelope or Retry-After header), APIError (5xx), and ConnectionError (network/timeout, never reached the server) all extend LumifyError (.code, .status, .docUrl, .requestId).

GET requests are automatically retried (default: 2 attempts) with exponential backoff on 429/5xx/network failures, honoring Retry-After. Non-idempotent requests (POST/webhook & key creation) are never auto-retried. Configure with maxRetries / timeoutMs on the Lumify constructor.

Credits and rate limits

Every successful response carries X-Credits-Used, X-Credits-Remaining, and X-RateLimit-* headers. Read them via getMeta() (attached as hidden metadata on the returned object, so it never pollutes JSON.stringify or your own types):

import { getMeta } from "@lumifyai/sdk";

const odds = await client.events.odds(eventId);
const meta = getMeta(odds);
console.log(meta?.creditsUsed, meta?.rateLimitRemaining);

Queries for data that isn't available yet (e.g. odds not yet posted) return creditsUsed: 0 — you're never charged for a "not available" read.

Sync with REST, MCP, and the OpenAPI contract

This SDK's response types (src/generated/models.ts) are generated from Lumify's live OpenAPI schema, not hand-maintained — see scripts/export_openapi_sdk.py (repo root) and scripts/gen-models.mjs (this package). CI fails if either is stale, so the SDK can't silently drift from what the API actually returns. The client ergonomics (this README's resource shape, pagination/SSE/webhook helpers) are hand-written on top.

python scripts/export_openapi_sdk.py            # regenerate the schema slice
node clients/lumify-sdk/scripts/gen-models.mjs   # regenerate the TS models

Development

npm install
npm run build   # tsc -> dist/
npm test        # build + node --test

License

MIT © 2026 Lumify AI

Related