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

chat-adapter-notion

v0.1.0

Published

ChatSDK adapter for [Notion](https://notion.so). Uses Notion page comments as a chat channel — each page is a thread, each comment is a message, and discussion threads map to sub-threads.

Readme

chat-adapter-notion

ChatSDK adapter for Notion. Uses Notion page comments as a chat channel — each page is a thread, each comment is a message, and discussion threads map to sub-threads.

Install

npm install chat-adapter-notion
# or
pnpm add chat-adapter-notion

Quick start

import { createChat } from "chat";
import { createNotionAdapter } from "chat-adapter-notion";

const adapter = createNotionAdapter({
  token: "ntn_...", // Notion integration token
  webhookSecret: "whsec_...", // Webhook signing secret
});

const chat = createChat({ adapters: [adapter] });
await chat.start();

Environment variables

Instead of passing config directly, you can set environment variables:

| Variable | Description | | ----------------------- | ---------------------------------------- | | NOTION_TOKEN | Notion internal integration token | | NOTION_WEBHOOK_SECRET | Secret used to verify webhook signatures |

// Reads from NOTION_TOKEN and NOTION_WEBHOOK_SECRET
const adapter = createNotionAdapter();

Webhook setup

1. Create a Notion integration

Go to notion.so/profile/integrations and create a new internal integration. Copy the integration token — this is your token / NOTION_TOKEN.

2. Deploy your webhook endpoint

Your server needs a publicly accessible HTTPS URL. Route POST requests to the adapter:

app.post("/webhooks/notion", async (req) => {
  return adapter.handleWebhook(req);
});

3. Create a webhook subscription

In your integration settings, go to the Webhooks tab:

  1. Click + Create a subscription
  2. Enter your public endpoint URL (e.g. https://your-app.com/webhooks/notion)
  3. Select comment.created as the event type

4. Complete the verification handshake

When you save, Notion sends a POST with a verification_token to your endpoint. The adapter responds to this automatically — it echoes the payload back with a 200.

Back in the Notion UI, click Verify, paste the token from the request body, and confirm.

After verification, Notion uses the verification token as the HMAC-SHA256 signing key for all future webhook events. Use it as your webhookSecret / NOTION_WEBHOOK_SECRET.

5. Grant page access

The integration needs access to each page you want to monitor. In a Notion page, click ...Connections → add your integration. Without this, the bot won't receive comment events or be able to read/post comments.

How the webhook handler works

Once configured, the adapter's handleWebhook method:

  1. Verifies the X-Notion-Signature HMAC-SHA256 signature
  2. Responds to Notion's verification handshake automatically
  3. Fetches the full comment via the API (webhook payloads are sparse)
  4. Converts Notion rich text to markdown and processes the message

Thread IDs

Thread IDs encode the Notion page and optional discussion thread:

notion:{base64url(pageId)}
notion:{base64url(pageId)}:{base64url(discussionId)}

Use encodeThreadId / decodeThreadId to work with them:

const threadId = adapter.encodeThreadId({ pageId: "abc-123" });
const { pageId, discussionId } = adapter.decodeThreadId(threadId);

Sending messages

Post messages as markdown, an AST, or raw text:

await adapter.postMessage(threadId, "Hello **world**");
await adapter.postMessage(threadId, { markdown: "# Title\nBody text" });
await adapter.postMessage(threadId, { ast: someAstRoot });

Markdown is automatically converted to Notion rich text with support for bold, italic, strikethrough, inline code, code blocks, and links. Text longer than 2000 characters is automatically chunked to stay within Notion's API limits.

Format conversion utilities

The package also exports lower-level conversion functions:

import {
  markdownToRichText,
  richTextToMarkdown,
  richTextToAst,
  astToRichText,
} from "chat-adapter-notion";

// Markdown string → Notion rich text request items
const richText = markdownToRichText("**bold** and *italic*");

// Notion rich text response items → Markdown string
const markdown = richTextToMarkdown(notionRichTextItems);

// Notion rich text → mdast tree (and back)
const ast = richTextToAst(notionRichTextItems);
const items = astToRichText(ast);

Limitations

The Notion API does not support editing or deleting comments, reactions, or typing indicators. These methods are implemented as graceful no-ops:

  • editMessage — posts a new comment instead of editing
  • deleteMessage — no-op
  • addReaction / removeReaction — no-op
  • startTyping — no-op

Development

pnpm install
pnpm test       # run tests
pnpm lint       # lint + format + typecheck
pnpm lint:fix   # auto-fix lint/format issues
pnpm build      # build to dist/