Skip to content

Commit e8c4b1a

Browse files
authored
docs: update adapter docs (#412)
* docs: update adapter docs * docs: update adapter docs * docs: update adapter docs --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
1 parent a179b29 commit e8c4b1a

14 files changed

Lines changed: 213 additions & 887 deletions

File tree

README.md

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,9 @@ bot.onSubscribedMessage(async (thread, message) => {
4545

4646
See the [Getting Started guide](https://chat-sdk.dev/docs/getting-started) for a full walkthrough.
4747

48-
## Supported platforms
49-
50-
| Platform | Package | Mentions | Reactions | Cards | Modals | Streaming | DMs |
51-
|----------|---------|----------|-----------|-------|--------|-----------|-----|
52-
| Slack | `@chat-adapter/slack` | Yes | Yes | Yes | Yes | Native | Yes |
53-
| Microsoft Teams | `@chat-adapter/teams` | Yes | Read-only | Yes | No | Post+Edit | Yes |
54-
| Google Chat | `@chat-adapter/gchat` | Yes | Yes | Yes | No | Post+Edit | Yes |
55-
| Discord | `@chat-adapter/discord` | Yes | Yes | Yes | No | Post+Edit | Yes |
56-
| Telegram | `@chat-adapter/telegram` | Yes | Yes | Partial | No | Post+Edit | Yes |
57-
| GitHub | `@chat-adapter/github` | Yes | Yes | No | No | No | No |
58-
| Linear | `@chat-adapter/linear` | Yes | Yes | No | No | No | No |
59-
| WhatsApp | `@chat-adapter/whatsapp` | N/A | Yes | Partial | No | No | Yes |
48+
## Adapters
49+
50+
Browse official, vendor-official, and community adapters on [chat-sdk.dev/adapters](https://chat-sdk.dev/adapters). A cross-platform feature matrix is available at [chat-sdk.dev/docs/adapters](https://chat-sdk.dev/docs/adapters).
6051

6152
## Features
6253

@@ -70,24 +61,7 @@ See the [Getting Started guide](https://chat-sdk.dev/docs/getting-started) for a
7061
- [**File uploads**](https://chat-sdk.dev/docs/files) — send and receive file attachments
7162
- [**Direct messages**](https://chat-sdk.dev/docs/direct-messages) — initiate DMs programmatically
7263
- [**Ephemeral messages**](https://chat-sdk.dev/docs/ephemeral-messages) — user-only visible messages with DM fallback
73-
74-
## Packages
75-
76-
| Package | Description |
77-
|---------|-------------|
78-
| `chat` | Core SDK with `Chat` class, types, JSX runtime, and utilities |
79-
| `@chat-adapter/slack` | [Slack adapter](https://chat-sdk.dev/adapters/slack) |
80-
| `@chat-adapter/teams` | [Teams adapter](https://chat-sdk.dev/adapters/teams) |
81-
| `@chat-adapter/gchat` | [Google Chat adapter](https://chat-sdk.dev/adapters/gchat) |
82-
| `@chat-adapter/discord` | [Discord adapter](https://chat-sdk.dev/adapters/discord) |
83-
| `@chat-adapter/telegram` | [Telegram adapter](https://chat-sdk.dev/adapters/telegram) |
84-
| `@chat-adapter/github` | [GitHub adapter](https://chat-sdk.dev/adapters/github) |
85-
| `@chat-adapter/linear` | [Linear adapter](https://chat-sdk.dev/adapters/linear) |
86-
| `@chat-adapter/whatsapp` | [WhatsApp adapter](https://chat-sdk.dev/adapters/whatsapp) |
87-
| `@chat-adapter/state-redis` | [Redis state adapter](https://chat-sdk.dev/docs/state/redis) (production) |
88-
| `@chat-adapter/state-ioredis` | [ioredis state adapter](https://chat-sdk.dev/docs/state/ioredis) (alternative) |
89-
| `@chat-adapter/state-pg` | [PostgreSQL state adapter](https://chat-sdk.dev/docs/state/postgres) (production) |
90-
| `@chat-adapter/state-memory` | [In-memory state adapter](https://chat-sdk.dev/docs/state/memory) (development) |
64+
- [**Overlapping messages**](https://chat-sdk.dev/docs/concurrency) — queue, debounce, drop, or process concurrent messages on the same thread
9165

9266
## AI coding agent support
9367

apps/docs/adapters.json

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
"description": "Cloudflare Durable Objects state adapter with SQLite-backed persistence, distributed locking, and caching.",
128128
"packageName": "chat-state-cloudflare-do",
129129
"author": "dcartertwo",
130-
"readme": "https://github.com/dcartertwo/chat-state-cloudflare-do"
130+
"readme": "https://github.com/dcartertwo/chat-state-cloudflare-do/tree/13ebf545b302b7c8fdabf7de9c5de678e047ce5e"
131131
},
132132
{
133133
"name": "Beeper Matrix",
@@ -137,7 +137,7 @@
137137
"description": "Matrix adapter for Chat SDK, built and maintained by Beeper.",
138138
"packageName": "@beeper/chat-adapter-matrix",
139139
"author": "Beeper",
140-
"readme": "https://github.com/beeper/chat-adapter-matrix",
140+
"readme": "https://github.com/beeper/chat-adapter-matrix/tree/632fb141b07d7243f2a09ee12ec55854c628217d",
141141
"vendorOfficial": true
142142
},
143143
{
@@ -148,7 +148,7 @@
148148
"description": "iMessage adapter for Chat SDK. Supports both local (on-device) and Photon iMessage integration.",
149149
"packageName": "chat-adapter-imessage",
150150
"author": "Photon",
151-
"readme": "https://github.com/photon-hq/vercel-chat-adapter-imessage",
151+
"readme": "https://github.com/photon-hq/vercel-chat-adapter-imessage/tree/8e6ae8f1b824db798664c98be91138f083e02262",
152152
"vendorOfficial": true
153153
},
154154
{
@@ -159,7 +159,7 @@
159159
"description": "Community Webex adapter for Chat SDK with support for spaces, threads, and adaptive cards.",
160160
"packageName": "@bitbasti/chat-adapter-webex",
161161
"author": "SebastianBodza",
162-
"readme": "https://github.com/SebastianBodza/chat-adapter-webex"
162+
"readme": "https://github.com/SebastianBodza/chat-adapter-webex/tree/982d76b24217dfe2e248ec13a17d16c2df32e09e"
163163
},
164164
{
165165
"name": "Resend",
@@ -169,7 +169,7 @@
169169
"description": "Bidirectional email adapter for Chat SDK with threading, rich HTML emails, and attachment support via Resend.",
170170
"packageName": "@resend/chat-sdk-adapter",
171171
"author": "Resend",
172-
"readme": "https://github.com/resend/resend-chat-sdk",
172+
"readme": "https://github.com/resend/resend-chat-sdk/tree/6b66fc12eabdf2529422fc0c0cf946392f1b5a76",
173173
"vendorOfficial": true
174174
},
175175
{
@@ -180,7 +180,7 @@
180180
"description": "Unified social media DM adapter covering Instagram, Facebook, Telegram, WhatsApp, X/Twitter, Bluesky, and Reddit through a single integration.",
181181
"packageName": "@zernio/chat-sdk-adapter",
182182
"author": "Zernio",
183-
"readme": "https://github.com/zernio-dev/chat-sdk-adapter",
183+
"readme": "https://github.com/zernio-dev/chat-sdk-adapter/tree/0a51a1d224536ae5d117a3afb6ab992fab167214",
184184
"vendorOfficial": true
185185
},
186186
{
@@ -191,7 +191,7 @@
191191
"description": "Chat SDK adapter for Baileys (Unofficial WhatsApp API).",
192192
"packageName": "chat-adapter-baileys",
193193
"author": "rama-adi",
194-
"readme": "https://github.com/rama-adi/chat-adapter-baileys"
194+
"readme": "https://github.com/rama-adi/chat-adapter-baileys/tree/b5454e7c04c75d91b06213f16a4af82ddb4a120f"
195195
},
196196
{
197197
"name": "Liveblocks",
@@ -201,7 +201,7 @@
201201
"description": "Liveblocks Comments adapter for building conversational bots on top of Liveblocks rooms, threads, and comments.",
202202
"packageName": "@liveblocks/chat-sdk-adapter",
203203
"author": "Liveblocks",
204-
"readme": "https://github.com/liveblocks/liveblocks/tree/main/packages/liveblocks-chat-sdk-adapter",
204+
"readme": "https://github.com/liveblocks/liveblocks/tree/a939486c73819ea78a96443d54cb5557881d80b6/packages/liveblocks-chat-sdk-adapter",
205205
"vendorOfficial": true
206206
},
207207
{
@@ -212,7 +212,7 @@
212212
"description": "iMessage adapter for Chat SDK using Sendblue for building your own iMessage bots.",
213213
"packageName": "chat-adapter-sendblue",
214214
"author": "midday-ai",
215-
"readme": "https://github.com/midday-ai/chat-adapter-sendblue"
215+
"readme": "https://github.com/midday-ai/chat-adapter-sendblue/tree/5125a9d018f5d05dca063cd4d7e554fdb92ecce8"
216216
},
217217
{
218218
"name": "Zalo",
@@ -222,7 +222,7 @@
222222
"description": "Zalo adapter for Chat SDK using Zalo for building your own Zalo bots.",
223223
"packageName": "chat-adapter-zalo",
224224
"author": "buiducnhat",
225-
"readme": "https://github.com/buiducnhat/chat-adapter-zalo"
225+
"readme": "https://github.com/buiducnhat/chat-adapter-zalo/tree/a11acb91efa9752c6d15c0a00c759b92c479e6fa"
226226
},
227227
{
228228
"name": "Mattermost",
@@ -232,40 +232,6 @@
232232
"description": "Mattermost adapter for Chat SDK with support for posts, reactions, and slash commands.",
233233
"packageName": "chat-adapter-mattermost",
234234
"author": "thiagoferolla",
235-
"readme": "https://github.com/thiagoferolla/chat-adapter-mattermost"
236-
},
237-
{
238-
"name": "Instagram",
239-
"slug": "instagram",
240-
"type": "platform",
241-
"icon": "instagram",
242-
"description": "Build bots for Instagram direct messages and automated customer interactions.",
243-
"comingSoon": true
244-
},
245-
{
246-
"name": "Signal",
247-
"slug": "signal",
248-
"type": "platform",
249-
"icon": "signal",
250-
"description": "Integrate with Signal for private, encrypted bot messaging.",
251-
"comingSoon": true,
252-
"prs": ["https://github.com/vercel/chat/pull/169"]
253-
},
254-
{
255-
"name": "X",
256-
"slug": "x",
257-
"type": "platform",
258-
"icon": "x",
259-
"description": "Build bots for X direct messages and automated interactions.",
260-
"comingSoon": true
261-
},
262-
{
263-
"name": "Messenger",
264-
"slug": "messenger",
265-
"type": "platform",
266-
"icon": "messenger",
267-
"description": "Build bots for Facebook Messenger with rich messages and automated customer interactions.",
268-
"comingSoon": true,
269-
"prs": ["https://github.com/vercel/chat/pull/156"]
235+
"readme": "https://github.com/thiagoferolla/chat-adapter-mattermost/tree/70eb85321cba65d511f6e158b9a2f5aac2aa922c"
270236
}
271237
]

apps/docs/app/[lang]/(home)/adapters/[slug]/page.tsx

Lines changed: 124 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,76 @@ import { ReadmeContent } from "../components/readme-content";
1111
const LOCAL_PACKAGE_PATTERN = /github\.com\/vercel\/chat\/tree\/[^/]+\/(.+)/;
1212
const GITHUB_SUBPATH_PATTERN =
1313
/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)/;
14+
const GITHUB_REPO_REF_PATTERN =
15+
/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/?$/;
1416
const GITHUB_REPO_PATTERN = /github\.com\/([^/]+)\/([^/]+)/;
17+
const GITHUB_REPO_ROOT_PATTERN = /^(https:\/\/github\.com\/[^/]+\/[^/]+)/;
18+
19+
const UNPINNED_REF_PATTERN = /^(main|master|head|dev|develop|trunk|default)$/i;
20+
21+
const MAX_README_BYTES = 500_000;
22+
23+
type Adapter = (typeof adapters)[number];
1524

1625
const getAdapter = (slug: string) => adapters.find((a) => a.slug === slug);
1726

18-
const getReadme = async (repoUrl: string): Promise<string | undefined> => {
27+
const isCommunity = (adapter: Adapter): boolean =>
28+
"community" in adapter && adapter.community === true;
29+
30+
const isVendorOfficial = (adapter: Adapter): boolean =>
31+
"vendorOfficial" in adapter && adapter.vendorOfficial === true;
32+
33+
const getAuthor = (adapter: Adapter): string | undefined =>
34+
"author" in adapter ? adapter.author : undefined;
35+
36+
const getIssuesUrl = (readmeUrl: string | undefined): string | undefined => {
37+
if (!readmeUrl) {
38+
return undefined;
39+
}
40+
const match = readmeUrl.match(GITHUB_REPO_ROOT_PATTERN);
41+
return match ? `${match[1]}/issues` : undefined;
42+
};
43+
44+
const warnUnpinned = (adapter: Adapter, ref: string | undefined) => {
45+
if (!isCommunity(adapter)) {
46+
return;
47+
}
48+
if (ref && !UNPINNED_REF_PATTERN.test(ref)) {
49+
return;
50+
}
51+
console.warn(
52+
`[adapters] Community adapter "${adapter.name}" uses an unpinned README ref "${ref ?? "<default branch>"}". Pin to a commit SHA or tag in adapters.json to freeze content at review time.`
53+
);
54+
};
55+
56+
const truncate = (content: string): string =>
57+
content.length <= MAX_README_BYTES
58+
? content
59+
: `${content.slice(0, MAX_README_BYTES)}\n\n> _README truncated — view the full version on GitHub._`;
60+
61+
const fetchGitHubReadme = async (url: string): Promise<string | undefined> => {
62+
const response = await fetch(url, {
63+
headers: { Accept: "application/vnd.github.raw+json" },
64+
next: { revalidate: 3600 },
65+
});
66+
if (response.ok) {
67+
return response.text();
68+
}
69+
return undefined;
70+
};
71+
72+
const getReadme = async (adapter: Adapter): Promise<string | undefined> => {
73+
if (!adapter.readme) {
74+
return undefined;
75+
}
76+
const repoUrl = adapter.readme;
77+
1978
const localMatch = repoUrl.match(LOCAL_PACKAGE_PATTERN);
2079
if (localMatch) {
2180
const [, pkgPath] = localMatch;
2281
const filePath = join(process.cwd(), "..", "..", pkgPath, "README.md");
2382
try {
24-
return await readFile(filePath, "utf-8");
83+
return truncate(await readFile(filePath, "utf-8"));
2584
} catch {
2685
return undefined;
2786
}
@@ -30,32 +89,76 @@ const getReadme = async (repoUrl: string): Promise<string | undefined> => {
3089
const subpathMatch = repoUrl.match(GITHUB_SUBPATH_PATTERN);
3190
if (subpathMatch) {
3291
const [, owner, repo, ref, path] = subpathMatch;
33-
const url = `https://api.github.com/repos/${owner}/${repo}/readme/${path}?ref=${ref}`;
34-
const response = await fetch(url, {
35-
headers: { Accept: "application/vnd.github.raw+json" },
36-
next: { revalidate: 3600 },
37-
});
38-
if (response.ok) {
39-
return response.text();
40-
}
92+
warnUnpinned(adapter, ref);
93+
const content = await fetchGitHubReadme(
94+
`https://api.github.com/repos/${owner}/${repo}/readme/${path}?ref=${ref}`
95+
);
96+
return content ? truncate(content) : undefined;
97+
}
98+
99+
const repoRefMatch = repoUrl.match(GITHUB_REPO_REF_PATTERN);
100+
if (repoRefMatch) {
101+
const [, owner, repo, ref] = repoRefMatch;
102+
warnUnpinned(adapter, ref);
103+
const content = await fetchGitHubReadme(
104+
`https://api.github.com/repos/${owner}/${repo}/readme?ref=${ref}`
105+
);
106+
return content ? truncate(content) : undefined;
41107
}
42108

43109
const repoMatch = repoUrl.match(GITHUB_REPO_PATTERN);
44110
if (repoMatch) {
45111
const [, owner, repo] = repoMatch;
46-
const url = `https://api.github.com/repos/${owner}/${repo}/readme`;
47-
const response = await fetch(url, {
48-
headers: { Accept: "application/vnd.github.raw+json" },
49-
next: { revalidate: 3600 },
50-
});
51-
if (response.ok) {
52-
return response.text();
53-
}
112+
warnUnpinned(adapter, undefined);
113+
const content = await fetchGitHubReadme(
114+
`https://api.github.com/repos/${owner}/${repo}/readme`
115+
);
116+
return content ? truncate(content) : undefined;
54117
}
55118

56119
return undefined;
57120
};
58121

122+
const CommunityNotice = ({ adapter }: { adapter: Adapter }) => {
123+
if (!isCommunity(adapter)) {
124+
return null;
125+
}
126+
const issuesUrl = getIssuesUrl(adapter.readme);
127+
const author = getAuthor(adapter);
128+
const vendorOfficial = isVendorOfficial(adapter) && author;
129+
130+
return (
131+
<div className="mb-8 rounded-md border bg-muted/40 px-4 py-3 text-muted-foreground text-sm">
132+
{vendorOfficial ? (
133+
<>
134+
<strong className="text-foreground">Vendor-official adapter</strong>{" "}
135+
maintained by {author}, not Vercel or Chat SDK contributors. For
136+
feature requests, bug reports, and support,{" "}
137+
</>
138+
) : (
139+
<>
140+
<strong className="text-foreground">Community adapter.</strong> Not
141+
maintained by Vercel or Chat SDK contributors. For feature requests,
142+
bug reports, and support,{" "}
143+
</>
144+
)}
145+
{issuesUrl ? (
146+
<a
147+
className="text-primary underline hover:no-underline"
148+
href={issuesUrl}
149+
rel="noopener noreferrer"
150+
target="_blank"
151+
>
152+
file an issue on the adapter&apos;s repo
153+
</a>
154+
) : (
155+
<span>file an issue on the adapter&apos;s repo</span>
156+
)}
157+
.
158+
</div>
159+
);
160+
};
161+
59162
const AdapterPage = async ({
60163
params,
61164
}: PageProps<"/[lang]/adapters/[slug]">) => {
@@ -66,7 +169,7 @@ const AdapterPage = async ({
66169
notFound();
67170
}
68171

69-
const readme = await getReadme(adapter.readme);
172+
const readme = await getReadme(adapter);
70173

71174
return (
72175
<div className="container mx-auto max-w-3xl">
@@ -90,6 +193,7 @@ const AdapterPage = async ({
90193
<SiGithub className="size-6" />
91194
</a>
92195
</div>
196+
<CommunityNotice adapter={adapter} />
93197
<ReadmeContent>{readme}</ReadmeContent>
94198
</article>
95199
) : (
@@ -102,6 +206,7 @@ const AdapterPage = async ({
102206
All Adapters
103207
</Link>
104208
<h1 className="mb-4 font-bold text-2xl">{adapter.name}</h1>
209+
<CommunityNotice adapter={adapter} />
105210
<p className="text-muted-foreground">
106211
README not available. Visit the{" "}
107212
<a

0 commit comments

Comments
 (0)