chat 4.29.0 → 4.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +31 -5
  2. package/dist/adapters/index.d.ts +594 -0
  3. package/dist/adapters/index.js +751 -0
  4. package/dist/ai/index.d.ts +3 -3
  5. package/dist/{chat-D9UYaaNO.d.ts → chat-BjhJs_sP.d.ts} +10 -8
  6. package/dist/{chunk-V25FKIIL.js → chunk-LNXHNIFE.js} +2 -0
  7. package/dist/index.d.ts +4 -4
  8. package/dist/index.js +15 -10
  9. package/dist/{jsx-runtime-CFq1K_Ve.d.ts → jsx-runtime-CzthIo1o.d.ts} +6 -1
  10. package/dist/jsx-runtime.d.ts +1 -1
  11. package/dist/jsx-runtime.js +1 -1
  12. package/docs/adapters.mdx +140 -127
  13. package/docs/ai/index.mdx +6 -0
  14. package/docs/api/cards.mdx +8 -1
  15. package/docs/api/message.mdx +5 -1
  16. package/docs/cards.mdx +9 -1
  17. package/docs/concurrency.mdx +1 -1
  18. package/docs/contributing/building.mdx +6 -0
  19. package/docs/conversation-history.mdx +1 -1
  20. package/docs/create-chat-sdk.mdx +143 -0
  21. package/docs/error-handling.mdx +1 -1
  22. package/docs/getting-started.mdx +7 -3
  23. package/docs/index.mdx +3 -1
  24. package/docs/meta.json +5 -1
  25. package/docs/platform-adapters.mdx +148 -0
  26. package/docs/slack-primitives.mdx +320 -0
  27. package/docs/slash-commands.mdx +6 -1
  28. package/docs/streaming.mdx +1 -1
  29. package/docs/teams-primitives.mdx +255 -0
  30. package/docs/testing.mdx +1 -1
  31. package/docs/threads-messages-channels.mdx +2 -2
  32. package/docs/usage.mdx +3 -3
  33. package/package.json +24 -5
  34. package/resources/guides/create-a-discord-support-bot-with-nuxt-and-redis.md +5 -1
  35. package/resources/guides/how-to-build-a-slack-bot-with-next-js-and-redis.md +5 -1
  36. package/resources/guides/human-in-the-loop-with-chat-sdk-and-workflow-sdk.md +176 -0
  37. package/resources/guides/liveblocks-chat-sdk-ai-sdk.md +165 -0
  38. package/resources/guides/run-and-track-deploys-from-slack.md +7 -5
  39. package/resources/guides/ship-a-github-code-review-bot-with-hono-and-redis.md +5 -1
  40. package/resources/guides/slack-bot-vercel-blob.md +254 -0
  41. package/resources/guides/triage-form-submissions-with-chat-sdk.md +3 -1
  42. package/resources/templates.json +5 -0
  43. /package/docs/{state.mdx → state-adapters.mdx} +0 -0
@@ -0,0 +1,320 @@
1
+ ---
2
+ title: Slack Low-Level APIs
3
+ description: Use Slack request verification, formatting, Web API, and Block Kit helpers without the full Chat runtime.
4
+ type: guide
5
+ prerequisites:
6
+ - /adapters/official/slack
7
+ related:
8
+ - /docs/handling-events
9
+ - /docs/cards
10
+ - /docs/slash-commands
11
+ ---
12
+
13
+ The Slack adapter is the right default for most bots. It verifies requests, resolves tokens, parses Slack payloads, stores thread state, and routes events through `Chat`.
14
+
15
+ Use the low-level Slack subpaths when your app already owns routing, state, sessions, or workflow execution and only needs the Slack-specific primitives.
16
+
17
+ | Subpath | Use for |
18
+ |---------|---------|
19
+ | `@chat-adapter/slack/webhook` | Request verification, body parsing, Events API payloads, slash commands, interactions, and continuation data |
20
+ | `@chat-adapter/slack/format` | Slack mrkdwn tokens, text objects, dates, links, mentions, and simple mrkdwn to Markdown conversion |
21
+ | `@chat-adapter/slack/api` | Fetch-based Slack Web API calls, thread replies, views, and files without `@slack/web-api` |
22
+ | `@chat-adapter/slack/blocks` | Runtime-free conversion from simple card objects and input requests to Slack Block Kit |
23
+
24
+ <Callout type="info">
25
+ These subpaths are for custom runtimes. If you want Chat SDK to handle webhook routing, state, subscriptions, and platform normalization, use `createSlackAdapter` from `@chat-adapter/slack`.
26
+ </Callout>
27
+
28
+ ## Webhooks
29
+
30
+ [Slack signs incoming HTTP requests](https://docs.slack.dev/authentication/verifying-requests-from-slack/) with `x-slack-signature` and `x-slack-request-timestamp`. `verifySlackRequest` reads the request body, verifies the signature with your signing secret, and returns the raw body so you can parse it once.
31
+
32
+ ```typescript title="app/api/slack/route.ts" lineNumbers
33
+ import {
34
+ parseSlackWebhookBody,
35
+ verifySlackRequest,
36
+ } from "@chat-adapter/slack/webhook";
37
+ import { postSlackMessage } from "@chat-adapter/slack/api";
38
+
39
+ export async function POST(request: Request) {
40
+ const body = await verifySlackRequest(request, {
41
+ signingSecret: process.env.SLACK_SIGNING_SECRET!,
42
+ });
43
+
44
+ const payload = parseSlackWebhookBody(body, {
45
+ contentType: request.headers.get("content-type"),
46
+ headers: request.headers,
47
+ });
48
+
49
+ if (payload.kind === "url_verification") {
50
+ return Response.json({ challenge: payload.challenge });
51
+ }
52
+
53
+ if (payload.kind === "app_mention") {
54
+ await postSlackMessage({
55
+ channel: payload.continuation.channelId,
56
+ markdownText: `received: ${payload.text}`,
57
+ threadTs: payload.continuation.threadTs,
58
+ token: process.env.SLACK_BOT_TOKEN!,
59
+ });
60
+ }
61
+
62
+ return new Response(null, { status: 200 });
63
+ }
64
+ ```
65
+
66
+ [Slack slash commands](https://docs.slack.dev/interactivity/implementing-slash-commands/) and interactions should be acknowledged quickly. Slack documents a 3000 ms acknowledgement window for slash commands, so do slow work in your queue or workflow runtime after returning a 2xx response.
67
+
68
+ If you do not need direct access to the verified raw body, `readSlackWebhook` combines verification and parsing:
69
+
70
+ ```typescript
71
+ import { readSlackWebhook } from "@chat-adapter/slack/webhook";
72
+
73
+ const payload = await readSlackWebhook(request, {
74
+ signingSecret: process.env.SLACK_SIGNING_SECRET!,
75
+ });
76
+ ```
77
+
78
+ If your framework already buffered the request body, use `verifySlackSignature` with the raw body and headers, then pass that same body to `parseSlackWebhookBody`.
79
+
80
+ ### Payloads
81
+
82
+ `parseSlackWebhookBody` returns typed payloads:
83
+
84
+ | Kind | Slack surface |
85
+ |------|---------------|
86
+ | `url_verification` | Events API URL verification |
87
+ | `app_mention` | App mention events |
88
+ | `direct_message` | Direct message events |
89
+ | `slash_command` | Slash command form posts |
90
+ | `block_actions` | Button, select, and Block Kit action payloads |
91
+ | `block_suggestion` | External select suggestion payloads |
92
+ | `view_submission` | Modal submissions |
93
+ | `view_closed` | Modal close events |
94
+ | `unsupported` | Valid Slack payloads not normalized by this helper yet |
95
+
96
+ Message-like payloads include `continuation`, which contains provider-native reply context:
97
+
98
+ ```typescript
99
+ type SlackContinuation = {
100
+ channelId: string;
101
+ enterpriseId?: string;
102
+ teamId?: string;
103
+ threadTs: string;
104
+ };
105
+ ```
106
+
107
+ This is not a Chat SDK `Thread`. It is the durable Slack data you need to reply later with `@chat-adapter/slack/api`.
108
+
109
+ App mention and direct message payloads also include typed `files` parsed from Slack file objects. Each file keeps the raw Slack object plus common fields like `id`, `name`, `mimeType`, `size`, `url`, and `downloadUrl`.
110
+
111
+ Interaction payloads expose convenience fields from Slack's raw payload:
112
+
113
+ - `block_actions` includes `actions`, `messageBlocks`, `messagePromptBlock`, `messagePromptText`, `messageTs`, `triggerId`, `responseUrl`, `user`, and `continuation`
114
+ - `view_submission` includes `callbackId`, `privateMetadata`, `values`, `responseUrls`, and `user`
115
+
116
+ ## Formatting
117
+
118
+ Slack uses mrkdwn and special tokens for mentions, channels, dates, and links. The format subpath gives you small helpers for those strings.
119
+
120
+ The helper surface includes `escapeSlackText`, `unescapeSlackText`, `createSlackPlainText`, `createSlackMrkdwn`, `formatSlackUser`, `formatSlackChannel`, `formatSlackUserGroup`, `formatSlackSpecialMention`, `formatSlackLink`, `formatSlackDate`, and simple mrkdwn to Markdown normalization.
121
+
122
+ ```typescript title="format.ts" lineNumbers
123
+ import {
124
+ createSlackMrkdwn,
125
+ formatSlackDate,
126
+ formatSlackLink,
127
+ formatSlackUser,
128
+ slackMrkdwnToMarkdown,
129
+ } from "@chat-adapter/slack/format";
130
+
131
+ const text = createSlackMrkdwn(
132
+ `${formatSlackUser("U123")} approved ${formatSlackLink("https://example.com", "the deploy")}`
133
+ );
134
+
135
+ const when = formatSlackDate(
136
+ new Date("2026-05-27T12:00:00Z"),
137
+ "{date_short_pretty} at {time}",
138
+ "May 27 at 12:00"
139
+ );
140
+
141
+ const markdown = slackMrkdwnToMarkdown("hello <@U123|jane>, see <https://example.com|this>");
142
+ ```
143
+
144
+ `linkBareSlackMentions` only links Slack user IDs like `@U123`. It does not resolve display names, because Slack mentions are ID-based.
145
+
146
+ ## Web API
147
+
148
+ The API subpath calls [Slack Web API](https://docs.slack.dev/apis/web-api/) methods with `fetch`. It does not import `@slack/web-api`.
149
+
150
+ ```typescript title="slack.ts" lineNumbers
151
+ import {
152
+ postSlackMessage,
153
+ sendSlackResponseUrl,
154
+ updateSlackMessage,
155
+ } from "@chat-adapter/slack/api";
156
+
157
+ const posted = await postSlackMessage({
158
+ channel: "C123",
159
+ markdownText: "**hello**",
160
+ token: process.env.SLACK_BOT_TOKEN!,
161
+ });
162
+
163
+ await updateSlackMessage({
164
+ channel: "C123",
165
+ text: "updated",
166
+ token: process.env.SLACK_BOT_TOKEN!,
167
+ ts: posted.id,
168
+ });
169
+
170
+ await sendSlackResponseUrl("https://hooks.slack.com/actions/T/1/abc", {
171
+ replaceOriginal: true,
172
+ text: "done",
173
+ });
174
+ ```
175
+
176
+ Use `callSlackApi` when you need a Slack method that does not have a helper yet:
177
+
178
+ ```typescript
179
+ import { callSlackApi } from "@chat-adapter/slack/api";
180
+
181
+ const result = await callSlackApi(
182
+ "reactions.add",
183
+ { channel: "C123", name: "white_check_mark", timestamp: "1710000000.000001" },
184
+ { token: process.env.SLACK_BOT_TOKEN! }
185
+ );
186
+ ```
187
+
188
+ `markdownText` maps to the `markdown_text` field on [`chat.postMessage`](https://docs.slack.dev/reference/methods/chat.postMessage/) and cannot be combined with `text` or `blocks`. Use `text` with `blocks` when you need fallback text.
189
+
190
+ The subpath also includes `postSlackEphemeral`, `deleteSlackMessage`, `resolveSlackBotToken`, `encodeSlackApiBody`, and `assertSlackOk`.
191
+
192
+ Use `fetchSlackThreadReplies` when a custom runtime needs to refresh a thread with [`conversations.replies`](https://docs.slack.dev/reference/methods/conversations.replies/):
193
+
194
+ ```typescript
195
+ import { fetchSlackThreadReplies } from "@chat-adapter/slack/api";
196
+
197
+ const replies = await fetchSlackThreadReplies({
198
+ channel: payload.continuation.channelId,
199
+ limit: 50,
200
+ token: process.env.SLACK_BOT_TOKEN!,
201
+ ts: payload.continuation.threadTs,
202
+ });
203
+ ```
204
+
205
+ Use `openSlackView` to open a modal from an interaction `trigger_id`:
206
+
207
+ ```typescript
208
+ import { openSlackView } from "@chat-adapter/slack/api";
209
+
210
+ await openSlackView({
211
+ token: process.env.SLACK_BOT_TOKEN!,
212
+ triggerId: payload.triggerId,
213
+ view: {
214
+ type: "modal",
215
+ title: { type: "plain_text", text: "Answer" },
216
+ blocks: [],
217
+ },
218
+ });
219
+ ```
220
+
221
+ ### Files
222
+
223
+ [Slack's current external upload flow](https://docs.slack.dev/changelog/2024-04-a-better-way-to-upload-files-is-here-to-stay) uses `files.getUploadURLExternal`, then uploads bytes to the returned URL, then calls `files.completeUploadExternal`.
224
+
225
+ ```typescript
226
+ import { uploadSlackFiles } from "@chat-adapter/slack/api";
227
+
228
+ await uploadSlackFiles(
229
+ [{ data: new Uint8Array([1, 2, 3]), filename: "report.txt" }],
230
+ {
231
+ channelId: "C123",
232
+ initialComment: "report attached",
233
+ token: process.env.SLACK_BOT_TOKEN!,
234
+ }
235
+ );
236
+ ```
237
+
238
+ Use `fetchSlackFile` for private Slack file URLs that require bearer token authorization.
239
+
240
+ ## Blocks
241
+
242
+ The blocks subpath converts simple card objects into Slack Block Kit without importing the full `chat` JSX runtime.
243
+
244
+ It exports `cardToSlackBlocks`, `cardToBlockKit`, `cardToSlackFallbackText`, `cardToFallbackText`, and `convertSlackEmojiPlaceholders`.
245
+
246
+ ```typescript title="blocks.ts" lineNumbers
247
+ import {
248
+ cardToSlackBlocks,
249
+ cardToSlackFallbackText,
250
+ } from "@chat-adapter/slack/blocks";
251
+ import { postSlackMessage } from "@chat-adapter/slack/api";
252
+
253
+ const card = {
254
+ children: [
255
+ { content: "deploy v2.4.1?", type: "text" },
256
+ {
257
+ children: [
258
+ { id: "approve", label: "Approve", style: "primary", type: "button" },
259
+ { id: "deny", label: "Deny", style: "danger", type: "button" },
260
+ ],
261
+ type: "actions",
262
+ },
263
+ ],
264
+ title: "Deployment",
265
+ type: "card",
266
+ } as const;
267
+
268
+ await postSlackMessage({
269
+ blocks: cardToSlackBlocks(card),
270
+ channel: "C123",
271
+ text: cardToSlackFallbackText(card),
272
+ token: process.env.SLACK_BOT_TOKEN!,
273
+ });
274
+ ```
275
+
276
+ Use the full Chat SDK card JSX when you want cross-platform rendering. Use `@chat-adapter/slack/blocks` when you are building a Slack-only runtime and want Block Kit output directly.
277
+
278
+ The blocks subpath also includes small input request helpers for Slack-only runtimes:
279
+
280
+ ```typescript
281
+ import {
282
+ inputRequestToSlackBlocks,
283
+ parseSlackInputResponse,
284
+ } from "@chat-adapter/slack/blocks";
285
+ import { postSlackMessage } from "@chat-adapter/slack/api";
286
+
287
+ await postSlackMessage({
288
+ blocks: inputRequestToSlackBlocks({
289
+ options: [
290
+ { id: "approve", label: "Approve", style: "primary" },
291
+ { id: "deny", label: "Deny", style: "danger" },
292
+ ],
293
+ prompt: "Approve deploy?",
294
+ requestId: "deploy-1",
295
+ }),
296
+ channel: "C123",
297
+ text: "Approve deploy?",
298
+ token: process.env.SLACK_BOT_TOKEN!,
299
+ });
300
+
301
+ if (payload.kind === "block_actions") {
302
+ const action = payload.actions[0];
303
+ const response = action ? parseSlackInputResponse(action) : null;
304
+ }
305
+ ```
306
+
307
+ Set `display: "radio"` for radio buttons, or `display: "select"` for a static select menu. Set `allowFreeform: true` to add a "Type your answer" button next to the provided options.
308
+
309
+ For freeform answers, use `buildSlackFreeformView` with `openSlackView`, then read the submitted value from `payload.values` with `parseSlackFreeformValue`.
310
+
311
+ ## Import boundaries
312
+
313
+ The low-level Slack subpaths are designed to avoid the full runtime import graph:
314
+
315
+ - no `chat` import
316
+ - no `@chat-adapter/shared` import
317
+ - no `@slack/web-api` import
318
+ - no `@slack/socket-mode` import
319
+
320
+ The package still installs the full Slack adapter dependencies. The subpaths keep your source and bundle imports clean, but they are not a package-size split.
@@ -8,11 +8,12 @@ related:
8
8
  - /docs/modals
9
9
  - /adapters/official/slack
10
10
  - /adapters/official/discord
11
+ - /adapters/official/telegram
11
12
  ---
12
13
 
13
14
  Slash commands let users invoke your bot with `/command` syntax. Register handlers with `onSlashCommand` to respond.
14
15
 
15
- Slash commands are supported on [Slack](/adapters/official/slack) and [Discord](/adapters/official/discord).
16
+ Slash commands are supported on [Slack](/adapters/official/slack), [Discord](/adapters/official/discord), and [Telegram](/adapters/official/telegram).
16
17
 
17
18
  ## Handle a specific command
18
19
 
@@ -112,6 +113,10 @@ bot.onModalSubmit("feedback_form", async (event) => {
112
113
  });
113
114
  ```
114
115
 
116
+ ## Telegram
117
+
118
+ Telegram supports bot commands such as `/status` and `/status@mybot`. Register handlers with `onSlashCommand`; commands addressed to another bot are ignored as slash commands and continue through the normal message path.
119
+
115
120
  ## Discord
116
121
 
117
122
  Discord slash commands are received via [HTTP Interactions](/adapters/official/discord#http-interactions-vs-gateway) — no Gateway connection is needed. The adapter automatically sends a deferred response to Discord, then resolves it when your handler calls `event.channel.post()`.
@@ -59,10 +59,10 @@ await thread.post(stream);
59
59
  | Platform | Method | Description |
60
60
  |----------|--------|-------------|
61
61
  | Slack | Native streaming API | Uses Slack's `chatStream` for smooth, real-time updates |
62
+ | Telegram | Private chat rich draft previews | Uses Telegram's `sendRichMessageDraft` in private chats, persists the final response with `sendRichMessage`, and falls back to post + edit elsewhere |
62
63
  | Teams | Native (DMs) / Buffered (group chats) | Uses the Teams SDK's native `stream.emit()` for direct messages; accumulates chunks and posts one final message when no native streamer is active |
63
64
  | Google Chat | Post + Edit | Posts a message then edits it as chunks arrive |
64
65
  | Discord | Post + Edit | Posts a message then edits it as chunks arrive |
65
- | Telegram | Post + Edit | Posts a message then edits it as chunks arrive |
66
66
  | GitHub | Buffered | Accumulates chunks and posts one final comment |
67
67
  | Linear | Agent sessions / Post + Edit | Uses agent session activities in agent-session threads; falls back to post+edit comments in issue threads |
68
68
  | WhatsApp | Buffered | Accumulates chunks and sends one final message |
@@ -0,0 +1,255 @@
1
+ ---
2
+ title: Teams Low-Level APIs
3
+ description: Use Teams Activity parsing, Bot Connector calls, Graph reads, formatting, Adaptive Cards, and Task Module helpers without the full Chat runtime.
4
+ type: guide
5
+ prerequisites:
6
+ - /adapters/official/teams
7
+ related:
8
+ - /docs/handling-events
9
+ - /docs/cards
10
+ - /docs/modals
11
+ ---
12
+
13
+ The Teams adapter is the right default for most bots. It validates Bot Framework requests through the Microsoft Teams SDK, parses Activities, stores conversation context, renders Adaptive Cards, reads Graph history, and routes events through `Chat`.
14
+
15
+ Use the low-level Teams subpaths when your app already owns routing, state, sessions, or workflow execution and only needs Teams-specific primitives.
16
+
17
+ | Subpath | Use for |
18
+ |---------|---------|
19
+ | `@chat-adapter/teams/webhook` | Parse Bot Framework Activity JSON, classify common payloads, and extract continuation data |
20
+ | `@chat-adapter/teams/api` | Fetch-based Bot Connector calls for messages, updates, deletes, typing, and conversations |
21
+ | `@chat-adapter/teams/graph` | Fetch-based Microsoft Graph reads for chats, channels, channel messages, and replies |
22
+ | `@chat-adapter/teams/format` | Teams HTML, mention, Markdown-ish, and emoji string helpers |
23
+ | `@chat-adapter/teams/cards` | Runtime-free conversion from simple card objects and input requests to Adaptive Cards |
24
+ | `@chat-adapter/teams/modals` | Runtime-free Task Module Adaptive Card helpers and submit parsing |
25
+
26
+ <Callout type="warning">
27
+ The webhook subpath parses Activities only. It does not verify Microsoft Bot Framework JWTs. For production request validation, use `createTeamsAdapter` or the Microsoft Teams SDK request pipeline before handing the Activity to these helpers.
28
+ </Callout>
29
+
30
+ ## Webhooks
31
+
32
+ Teams sends Bot Framework Activity JSON. `readTeamsWebhook` reads the request body and classifies the Activity, but it intentionally does not perform JWT validation.
33
+
34
+ ```typescript title="app/api/teams/route.ts" lineNumbers
35
+ import { postTeamsMessage } from "@chat-adapter/teams/api";
36
+ import { readTeamsWebhook } from "@chat-adapter/teams/webhook";
37
+
38
+ export async function POST(request: Request) {
39
+ const payload = await readTeamsWebhook(request, {
40
+ botAppId: process.env.TEAMS_APP_ID,
41
+ });
42
+
43
+ if (payload.kind === "message") {
44
+ await postTeamsMessage({
45
+ conversationId: payload.continuation.conversationId,
46
+ credentials: {
47
+ appId: process.env.TEAMS_APP_ID!,
48
+ appPassword: process.env.TEAMS_APP_PASSWORD!,
49
+ tenantId: payload.continuation.tenantId,
50
+ },
51
+ markdownText: `received: ${payload.text}`,
52
+ serviceUrl: payload.continuation.serviceUrl,
53
+ });
54
+ }
55
+
56
+ return new Response(null, { status: 200 });
57
+ }
58
+ ```
59
+
60
+ `parseTeamsWebhookBody` returns typed payloads:
61
+
62
+ | Kind | Teams surface |
63
+ |------|---------------|
64
+ | `message` | Message activities |
65
+ | `message_reaction` | Reaction activities |
66
+ | `card_action` | Adaptive Card actions and `Action.Submit` message activities |
67
+ | `dialog_open` | Task Module `task/fetch` invokes |
68
+ | `dialog_submit` | Task Module `task/submit` invokes |
69
+ | `conversation_update` | Conversation membership and install context updates |
70
+ | `installation_update` | App installation updates |
71
+ | `unsupported` | Valid Activities not normalized by this helper yet |
72
+
73
+ Message-like payloads include `continuation`, which contains provider-native reply context:
74
+
75
+ ```typescript
76
+ type TeamsContinuation = {
77
+ activityId?: string;
78
+ channelId?: string;
79
+ conversationId: string;
80
+ replyToId?: string;
81
+ serviceUrl: string;
82
+ teamId?: string;
83
+ tenantId?: string;
84
+ };
85
+ ```
86
+
87
+ This is not a Chat SDK `Thread`. It is the durable Teams data you need to reply later with `@chat-adapter/teams/api`.
88
+
89
+ ## Bot Connector API
90
+
91
+ The API subpath calls the Bot Framework Connector REST API with `fetch`. It does not import `@microsoft/teams.apps`.
92
+
93
+ ```typescript title="teams.ts" lineNumbers
94
+ import {
95
+ deleteTeamsMessage,
96
+ postTeamsMessage,
97
+ sendTeamsTyping,
98
+ updateTeamsMessage,
99
+ } from "@chat-adapter/teams/api";
100
+
101
+ const credentials = {
102
+ appId: process.env.TEAMS_APP_ID!,
103
+ appPassword: process.env.TEAMS_APP_PASSWORD!,
104
+ tenantId: process.env.TEAMS_APP_TENANT_ID!,
105
+ };
106
+
107
+ const posted = await postTeamsMessage({
108
+ conversationId: "19:abc@thread.tacv2",
109
+ credentials,
110
+ markdownText: "**hello**",
111
+ serviceUrl: "https://smba.trafficmanager.net/teams/",
112
+ });
113
+
114
+ await updateTeamsMessage({
115
+ conversationId: "19:abc@thread.tacv2",
116
+ credentials,
117
+ messageId: posted.id,
118
+ serviceUrl: "https://smba.trafficmanager.net/teams/",
119
+ text: "updated",
120
+ });
121
+
122
+ await sendTeamsTyping({
123
+ conversationId: "19:abc@thread.tacv2",
124
+ credentials,
125
+ serviceUrl: "https://smba.trafficmanager.net/teams/",
126
+ });
127
+
128
+ await deleteTeamsMessage({
129
+ conversationId: "19:abc@thread.tacv2",
130
+ credentials,
131
+ messageId: posted.id,
132
+ serviceUrl: "https://smba.trafficmanager.net/teams/",
133
+ });
134
+ ```
135
+
136
+ Use `accessToken` in `credentials` when your runtime already owns Microsoft token acquisition. A direct `accessToken` must be scoped for the API you call it against — the Bot Connector subpath (`/api`) needs a `https://api.botframework.com/.default` token, while the Graph subpath (`/graph`) needs a `https://graph.microsoft.com/.default` token. Passing the same token to both will fail against one of them. When you supply `appId`/`appPassword` instead, each subpath requests the correct scope for you.
137
+
138
+ ## Graph
139
+
140
+ The Graph subpath reads Teams history with explicit Graph IDs. Unlike `TeamsAdapter`, it does not use the adapter state cache to infer `teamId`, `channelId`, or `chatId`.
141
+
142
+ ```typescript
143
+ import { listTeamsChannelMessages } from "@chat-adapter/teams/graph";
144
+
145
+ const messages = await listTeamsChannelMessages({
146
+ channelId: "19:channel@thread.tacv2",
147
+ credentials: {
148
+ appId: process.env.TEAMS_APP_ID!,
149
+ appPassword: process.env.TEAMS_APP_PASSWORD!,
150
+ tenantId: process.env.TEAMS_APP_TENANT_ID!,
151
+ },
152
+ limit: 25,
153
+ teamId: "19:team@thread.tacv2",
154
+ });
155
+
156
+ const latestText = messages.items[0]?.text;
157
+ ```
158
+
159
+ Graph reads require the same Microsoft Graph permissions as the full adapter. Channel and group-chat reads can use RSC permissions; DM reads require Azure AD application permissions such as `Chat.Read.All`.
160
+
161
+ ## Formatting
162
+
163
+ Teams renders message text as HTML. The format subpath provides small helpers for custom runtimes:
164
+
165
+ ```typescript
166
+ import {
167
+ formatTeamsMention,
168
+ markdownToTeamsHtml,
169
+ teamsHtmlToMarkdown,
170
+ } from "@chat-adapter/teams/format";
171
+
172
+ const html = markdownToTeamsHtml(
173
+ `${formatTeamsMention("Ada")} approved **deploy v2.4.1**`
174
+ );
175
+ const markdown = teamsHtmlToMarkdown("<p>Hello <strong>world</strong></p>");
176
+ ```
177
+
178
+ Use the full `TeamsFormatConverter` from `@chat-adapter/teams` when you need mdast conversion inside Chat SDK.
179
+
180
+ ## Cards
181
+
182
+ The cards subpath converts simple card objects into Adaptive Card JSON without importing the full `chat` JSX runtime.
183
+
184
+ ```typescript title="cards.ts" lineNumbers
185
+ import {
186
+ cardToAdaptiveCard,
187
+ cardToTeamsFallbackText,
188
+ } from "@chat-adapter/teams/cards";
189
+ import { postTeamsMessage } from "@chat-adapter/teams/api";
190
+
191
+ const card = {
192
+ children: [
193
+ { content: "deploy v2.4.1?", type: "text" },
194
+ {
195
+ children: [
196
+ { id: "approve", label: "Approve", style: "primary", type: "button" },
197
+ { id: "deny", label: "Deny", style: "danger", type: "button" },
198
+ ],
199
+ type: "actions",
200
+ },
201
+ ],
202
+ title: "Deployment",
203
+ type: "card",
204
+ } as const;
205
+
206
+ await postTeamsMessage({
207
+ adaptiveCard: cardToAdaptiveCard(card),
208
+ conversationId: payload.continuation.conversationId,
209
+ credentials,
210
+ serviceUrl: payload.continuation.serviceUrl,
211
+ text: cardToTeamsFallbackText(card),
212
+ });
213
+ ```
214
+
215
+ Use the full Chat SDK card JSX when you want cross-platform rendering. Use `@chat-adapter/teams/cards` when you are building a Teams-only runtime and want Adaptive Card output directly.
216
+
217
+ ## Modals
218
+
219
+ Teams Task Modules are invoke-based dialogs backed by Adaptive Cards. The modals subpath builds those cards and parses submit data.
220
+
221
+ ```typescript
222
+ import {
223
+ modalToAdaptiveCard,
224
+ parseTeamsDialogSubmitValues,
225
+ toTeamsTaskModuleResponse,
226
+ } from "@chat-adapter/teams/modals";
227
+
228
+ const modal = {
229
+ callbackId: "deploy",
230
+ children: [
231
+ { content: "Why deploy now?", type: "text" },
232
+ { id: "reason", label: "Reason", type: "text_input" },
233
+ ],
234
+ title: "Deploy",
235
+ type: "modal",
236
+ } as const;
237
+
238
+ const card = modalToAdaptiveCard(modal, { contextId: "deploy-1" });
239
+ const values = parseTeamsDialogSubmitValues(payload.value);
240
+
241
+ return Response.json(
242
+ toTeamsTaskModuleResponse({ action: "update", modal }, { contextId: "deploy-1" })
243
+ );
244
+ ```
245
+
246
+ ## Import Boundaries
247
+
248
+ The low-level Teams subpaths are designed to avoid the full runtime import graph:
249
+
250
+ - no `chat` import
251
+ - no `@chat-adapter/shared` import
252
+ - no `@microsoft/teams.apps` import
253
+ - no full adapter import
254
+
255
+ The package still installs the full Teams adapter dependencies. The subpaths keep your source and bundle imports clean, but they are not a package-size split.
package/docs/testing.mdx CHANGED
@@ -5,7 +5,7 @@ type: guide
5
5
  prerequisites:
6
6
  - /docs/getting-started
7
7
  related:
8
- - /docs/state
8
+ - /docs/state-adapters
9
9
  - /docs/handling-events
10
10
  - /docs/contributing/testing
11
11
  ---
@@ -83,7 +83,7 @@ await thread.startTyping();
83
83
  ```
84
84
 
85
85
  <Callout type="info">
86
- Not all platforms support typing indicators. The call is a no-op on unsupported platforms. See the [adapter feature matrix](/docs/adapters) for details.
86
+ Not all platforms support typing indicators. The call is a no-op on unsupported platforms. See the [adapter feature matrix](/docs/platform-adapters) for details.
87
87
  </Callout>
88
88
 
89
89
  ### Message history
@@ -149,7 +149,7 @@ await scheduled.cancel();
149
149
  ```
150
150
 
151
151
  <Callout type="info">
152
- Scheduled messages are currently only supported by the Slack adapter. Other adapters throw `NotImplementedError`. See the [feature matrix](/docs/adapters) for details.
152
+ Scheduled messages are currently only supported by the Slack adapter. Other adapters throw `NotImplementedError`. See the [feature matrix](/docs/platform-adapters) for details.
153
153
  </Callout>
154
154
 
155
155
  ## Messages
package/docs/usage.mdx CHANGED
@@ -7,7 +7,7 @@ prerequisites:
7
7
  related:
8
8
  - /docs/handling-events
9
9
  - /docs/adapters
10
- - /docs/state
10
+ - /docs/state-adapters
11
11
  ---
12
12
 
13
13
  The `Chat` class is the main entry point for your bot. It coordinates adapters, routes events to your handlers, and manages thread state.
@@ -34,10 +34,10 @@ bot.onNewMention(async (thread) => {
34
34
  ```
35
35
 
36
36
  <Callout type="info">
37
- This example uses Redis. Chat SDK also supports [PostgreSQL](/adapters/official/postgres) and [ioredis](/adapters/official/ioredis) as production state adapters. See [State Adapters](/docs/state) for all options.
37
+ This example uses Redis. Chat SDK also supports [PostgreSQL](/adapters/official/postgres) and [ioredis](/adapters/official/ioredis) as production state adapters. See [State Adapters](/docs/state-adapters) for all options.
38
38
  </Callout>
39
39
 
40
- Each adapter factory auto-detects credentials from environment variables (`SLACK_BOT_TOKEN`, `SLACK_SIGNING_SECRET`, `REDIS_URL`, etc.), so you can get started with zero config. Pass explicit values to override.
40
+ Each adapter factory auto-detects credentials from environment variables (`SLACK_BOT_TOKEN`, `SLACK_SIGNING_SECRET`, `REDIS_URL`, etc.), so you can get started with zero config. Pass explicit values to override. For setup UIs and build scripts, the [`chat/adapters` catalog](/docs/adapters#adapter-catalog-chatadapters) lists official and vendor-official adapter env specs without importing adapter packages.
41
41
 
42
42
  ## Multiple adapters
43
43