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

caspian-sdk

v1.0.1

Published

Caspian TypeScript SDK — one bot program across channels

Readme

caspian-sdk (TypeScript)

Rewrite of the Caspian TypeScript SDK. You write a Chat SDK-shaped API. It desugars into a small Effect kernel. This package is not the legacy CommClient.

import { Caspian } from "caspian-sdk"

const cx = new Caspian()

cx.onMessage(
  { channel: "telegram", kind: "dm", overlap: "queue" },
  async (thread, msg) => {
    await thread.typing()
    await thread.post(`echo:${msg.text}`)
  },
)

kind here is the chat kind (dm / group / channel). The method name already means “message events.”

thread.post enqueues a Post command. It does not call Telegram.

Telegram lives in caspian-sdk/telegram: parseTelegramUpdate turns an Update into Events; planTurn turns Commands into Bot API method bodies.

The other channels are the same shape — import the pack, not the facade:

import { discord, discordHttpLayer } from "caspian-sdk/discord"
import { slack, slackHttpLayer } from "caspian-sdk/slack"

Also: caspian/voice, caspian/email, caspian/sms, caspian/whatsapp, caspian/messenger, caspian/imessage, caspian/x, caspian/linear. Each pack parses platform bytes into kernel Events, plans Commands into platform calls, and owns overlap keys / thread ids. Unsupported kernel commands fail as AdapterError. WhatsApp delivery receipts are not kernel Events (no Receipt constructor) — parse returns [].

Self-host inbound: await cx.listen({ adapter: telegramHttpLayer(), ... }) then POST → cx.webhooks.telegram(req). The platform is ACKed 200 before the model; a wrong secret is 401. Tests inject a recording Layer — no live network in CI.

Hosted inbound: await cx.run({ adapter: hostedHttpLayer(), webhookSecret, ... }) then POST → cx.webhooks.caspian(req). The body is a kernel Event envelope, signed with HMAC-SHA256 (X-Caspian-Signature). Execute goes to the Caspian outbox, not api.telegram.org.

via is required on channels.add. There is no omit-means-hosted:

await cx.channels.add("telegram", { via: "hosted" })
await cx.channels.add("telegram", {
  via: "self-host",
  botToken: token,
  webhookUrl: "https://myapp.example.com/api/webhooks/telegram",
})

"hosted" | "self-host" only. Not oauth, not credentials. Self-host inbound without webhookUrl is an error; inbound: false is send-only. This mints a Connection. It does not call a live gateway yet.

cx.tools(thread) / cx.tools({ preset: "outbound" }) is the same Command surface as thread.post for models. Parameters come from Command schemas. Thread ids only — never a platform chat id. Host and Call are not tools.

thread.recent(n) and thread.state are runner memory. Handlers ask; Memory (and Process/Hosted on top of it) stores inbound Events and SetState. A thread with no store returns [] / undefined.

bun install
bun run ci