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

@getdial/chat-sdk-adapter

v0.2.0

Published

Wire a Dial phone number into a Chat SDK bot — the same handler answers SMS, MMS, iMessage, and inbound voice.

Readme

@getdial/chat-sdk-adapter

Wire a real phone number into your Chat SDK bot. The same onNewMention handler that answers Slack, Teams, or Discord now answers SMS, MMS, iMessage, and inbound voice calls too — with replies sent back over the phone through Dial.

npm install @getdial/chat-sdk-adapter chat
import { Chat } from "chat";
import { createDialAdapter } from "@getdial/chat-sdk-adapter";

const chat = new Chat({
  adapter: createDialAdapter(),  // reads DIAL_* env vars; overridable — see Options
  onNewMention: async ({ message, reply }) => {
    await reply(`heard you: ${message.text}`);
  },
});

// Bind to whatever HTTP framework you use:
app.post("/webhook/dial", (req) => chat.webhooks.dial(req));

Get a Dial API key and a phone number ID from https://getdial.ai. Point that number's webhook subscription at the endpoint above.

What the adapter carries

| Direction | Channel | Text | Media | |-----------|--------------|------|-------| | Inbound | SMS | ✅ | — | | Inbound | MMS | ✅ | ✅ (image / video / audio / file) | | Inbound | iMessage | ✅ | ✅ | | Inbound | Voice call | ✅ (as transcript) | — | | Outbound | SMS / MMS / iMessage | ✅ | ✅ (via attachment URLs) |

Configuration

createDialAdapter(config?) reads the environment when a field is omitted. Explicit values always win.

| Field | Env var | Required | What it is | |-----------------|------------------------|:--------:|------------| | apiKey | DIAL_API_KEY | ✅ | Dial API key (sk_live_…) minted from the dashboard. | | fromNumberId | DIAL_FROM_NUMBER_ID | ✅ | Dial's ID of the phone number the bot should send from. | | webhookSecret | DIAL_WEBHOOK_SECRET | ✅ in prod | Signing secret Dial issued when the webhook subscription was created. When set, incoming requests are verified against X-Dial-Signature; when unset, verification is skipped (dev only). | | apiBaseUrl | DIAL_API_URL | | Overrides the Dial API host. Defaults to https://api.getdial.ai. | | botName | BOT_USERNAME | | Display name Chat SDK uses for the bot. Defaults to "bot". | | logger | — | | Chat SDK Logger instance. Defaults to ConsoleLogger("info").child("dial"). |

Webhook events

Point the Dial webhook subscription at the endpoint you handed to chat.webhooks.dial. Four event types are recognized (envelope shape mirrors Dial's own emitter):

| Event | Response | |----------------------|----------| | message.received | Forwarded to the bot as a chat message. Media items become Chat SDK attachments (image / video / audio / file, keyed off contentType). | | call.ended (inbound) | Swallowed — 200 OK, not forwarded. Bots only see voice as the transcript delivered by the subsequent call.transcribed; a "call ended" placeholder here would hold the Chat SDK per-thread lock and starve the real transcript event. Very short calls that never get a transcript therefore don't surface to the bot at all. | | call.ended (outbound) | Dropped — 200 OK, not forwarded. Adapter surface is inbound-only. | | call.transcribed | Fetches the call via @getdial/sdk.getCall(). Forwarded as a voice message only when direction === "inbound". | | webhook.ping | 200 OK. Not forwarded — this is Dial's dashboard "test delivery" button. |

Anything else is answered 200 OK and ignored, so a future Dial event type doesn't break integrations before they upgrade.

Signature verification

When webhookSecret is set, every request must carry:

X-Dial-Signature: t=<unix_seconds>,v1=<hex-hmac-sha256(secret, `${t}.${rawBody}`)>

Rejection cases (all 401):

| Verdict | When | |-------------|------| | missing | No X-Dial-Signature header on the request. | | malformed | Header lacks t= or v1=, or t= is not a number. | | stale | abs(now - t) exceeds 5 minutes. Replay protection. | | mismatch | Recomputed HMAC doesn't equal v1, or lengths differ. Constant-time compare. |

Structurally invalid JSON, or an envelope with no type, returns 400.

Threads

A thread here is a pair of phone numbers — your Dial-owned number and the peer's:

dial:{yourDialNumber}:{peerNumber}

Every distinct pair is a distinct thread. Chat SDK's per-thread state (conversation history, context) is scoped per-pair, so simultaneous conversations don't leak into each other.

Design notes

  • @getdial/sdk under the hood. Outbound sends and transcript fetches go through the official Node SDK; no hand-rolled HTTP.
  • Node's crypto for signing. createHmac + timingSafeEqual, matching the exact primitive Dial's server signs with.
  • Package is ESM-only, TypeScript-first. Requires Node 18+.
  • No business logic in the adapter. It's a transport shim — your bot logic lives entirely in the Chat SDK handlers.

Links