chat 4.27.0 → 4.28.1
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.
- package/dist/{chunk-AN7MRAVW.js → chunk-V25FKIIL.js} +5 -1
- package/dist/index.d.ts +269 -31
- package/dist/index.js +544 -88
- package/dist/{jsx-runtime-Co9uV6l7.d.ts → jsx-runtime-DxGwoLu2.d.ts} +10 -0
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/docs/actions.mdx +52 -1
- package/docs/adapters.mdx +42 -36
- package/docs/api/cards.mdx +4 -0
- package/docs/api/chat.mdx +91 -9
- package/docs/api/index.mdx +2 -0
- package/docs/api/markdown.mdx +28 -5
- package/docs/api/message.mdx +53 -0
- package/docs/api/meta.json +2 -0
- package/docs/api/modals.mdx +50 -0
- package/docs/api/postable-message.mdx +55 -1
- package/docs/api/thread.mdx +10 -2
- package/docs/api/transcripts.mdx +220 -0
- package/docs/cards.mdx +6 -0
- package/docs/concurrency.mdx +4 -0
- package/docs/contributing/building.mdx +73 -1
- package/docs/conversation-history.mdx +137 -0
- package/docs/direct-messages.mdx +13 -4
- package/docs/ephemeral-messages.mdx +1 -1
- package/docs/error-handling.mdx +15 -3
- package/docs/files.mdx +1 -1
- package/docs/index.mdx +7 -5
- package/docs/meta.json +14 -3
- package/docs/modals.mdx +24 -0
- package/docs/posting-messages.mdx +7 -3
- package/docs/streaming.mdx +72 -24
- package/docs/subject.mdx +53 -0
- package/docs/threads-messages-channels.mdx +9 -0
- package/docs/usage.mdx +11 -2
- package/package.json +1 -1
|
@@ -52,6 +52,8 @@ type TextStyle = "plain" | "bold" | "muted";
|
|
|
52
52
|
interface ButtonElement {
|
|
53
53
|
/** Whether this button triggers a regular action or opens a modal dialog. Default: "action" */
|
|
54
54
|
actionType?: "action" | "modal";
|
|
55
|
+
/** URL to POST action data to when this button is clicked */
|
|
56
|
+
callbackUrl?: string;
|
|
55
57
|
/** If true, the button is displayed in an inactive state and doesn't respond to user actions */
|
|
56
58
|
disabled?: boolean;
|
|
57
59
|
/** Unique action ID for callback routing */
|
|
@@ -241,6 +243,8 @@ declare function Actions(children: (ButtonElement | LinkButtonElement | SelectEl
|
|
|
241
243
|
interface ButtonOptions {
|
|
242
244
|
/** Whether this button triggers a regular action or opens a modal dialog. Default: "action" */
|
|
243
245
|
actionType?: "action" | "modal";
|
|
246
|
+
/** URL to POST action data to when this button is clicked */
|
|
247
|
+
callbackUrl?: string;
|
|
244
248
|
/** If true, the button is displayed in an inactive state and doesn't respond to user actions */
|
|
245
249
|
disabled?: boolean;
|
|
246
250
|
/** Unique action ID for callback routing */
|
|
@@ -374,6 +378,8 @@ declare function cardChildToFallbackText(child: CardChild): string | null;
|
|
|
374
378
|
type ModalChild = TextInputElement | SelectElement | ExternalSelectElement | RadioSelectElement | TextElement | FieldsElement;
|
|
375
379
|
interface ModalElement {
|
|
376
380
|
callbackId: string;
|
|
381
|
+
/** URL to POST form values to when this modal is submitted */
|
|
382
|
+
callbackUrl?: string;
|
|
377
383
|
children: ModalChild[];
|
|
378
384
|
closeLabel?: string;
|
|
379
385
|
notifyOnClose?: boolean;
|
|
@@ -427,6 +433,8 @@ interface RadioSelectElement {
|
|
|
427
433
|
declare function isModalElement(value: unknown): value is ModalElement;
|
|
428
434
|
interface ModalOptions {
|
|
429
435
|
callbackId: string;
|
|
436
|
+
/** URL to POST form values to when this modal is submitted */
|
|
437
|
+
callbackUrl?: string;
|
|
430
438
|
children?: ModalChild[];
|
|
431
439
|
closeLabel?: string;
|
|
432
440
|
notifyOnClose?: boolean;
|
|
@@ -527,6 +535,7 @@ interface TextProps {
|
|
|
527
535
|
/** Props for Button component in JSX */
|
|
528
536
|
interface ButtonProps {
|
|
529
537
|
actionType?: "action" | "modal";
|
|
538
|
+
callbackUrl?: string;
|
|
530
539
|
children?: string | number | (string | number | undefined)[];
|
|
531
540
|
disabled?: boolean;
|
|
532
541
|
id: string;
|
|
@@ -566,6 +575,7 @@ type DividerProps = Record<string, never>;
|
|
|
566
575
|
/** Props for Modal component in JSX */
|
|
567
576
|
interface ModalProps {
|
|
568
577
|
callbackId: string;
|
|
578
|
+
callbackUrl?: string;
|
|
569
579
|
children?: unknown;
|
|
570
580
|
closeLabel?: string;
|
|
571
581
|
notifyOnClose?: boolean;
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { A as ActionsComponent, B as ButtonComponent, X as ButtonProps, c as CardComponent, Y as CardJSXElement, Z as CardJSXProps, e as CardLinkComponent, _ as CardLinkProps, $ as CardProps, C as ChatElement, a0 as ContainerProps, D as DividerComponent, a1 as DividerProps, E as ExternalSelectComponent, a2 as ExternalSelectProps, F as FieldComponent, a3 as FieldProps, f as FieldsComponent, ar as Fragment, I as ImageComponent, a4 as ImageProps, as as JSX, L as LinkButtonComponent, a5 as LinkButtonProps, o as ModalComponent, a6 as ModalProps, R as RadioSelectComponent, j as SectionComponent, p as SelectComponent, q as SelectOptionComponent, a7 as SelectOptionProps, a8 as SelectProps, am as TableComponent, al as TableProps, T as TextComponent, r as TextInputComponent, a9 as TextInputProps, aa as TextProps, an as isCardLinkProps, h as isJSX, ao as jsx, aq as jsxDEV, ap as jsxs, t as toCardElement, l as toModalElement } from './jsx-runtime-
|
|
1
|
+
export { A as ActionsComponent, B as ButtonComponent, X as ButtonProps, c as CardComponent, Y as CardJSXElement, Z as CardJSXProps, e as CardLinkComponent, _ as CardLinkProps, $ as CardProps, C as ChatElement, a0 as ContainerProps, D as DividerComponent, a1 as DividerProps, E as ExternalSelectComponent, a2 as ExternalSelectProps, F as FieldComponent, a3 as FieldProps, f as FieldsComponent, ar as Fragment, I as ImageComponent, a4 as ImageProps, as as JSX, L as LinkButtonComponent, a5 as LinkButtonProps, o as ModalComponent, a6 as ModalProps, R as RadioSelectComponent, j as SectionComponent, p as SelectComponent, q as SelectOptionComponent, a7 as SelectOptionProps, a8 as SelectProps, am as TableComponent, al as TableProps, T as TextComponent, r as TextInputComponent, a9 as TextInputProps, aa as TextProps, an as isCardLinkProps, h as isJSX, ao as jsx, aq as jsxDEV, ap as jsxs, t as toCardElement, l as toModalElement } from './jsx-runtime-DxGwoLu2.js';
|
package/dist/jsx-runtime.js
CHANGED
package/docs/actions.mdx
CHANGED
|
@@ -94,5 +94,56 @@ bot.onAction("feedback", async (event) => {
|
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
<Callout type="info">
|
|
97
|
-
Modals are currently supported on Slack. Other platforms will receive a no-op
|
|
97
|
+
Modals are currently supported on Slack and Teams. Other platforms will receive a no-op
|
|
98
|
+
or fallback behavior.
|
|
98
99
|
</Callout>
|
|
100
|
+
|
|
101
|
+
## Callback URLs
|
|
102
|
+
|
|
103
|
+
Buttons accept a `callbackUrl` prop. When clicked, the action data is POSTed to that URL in addition to firing any `onAction` handler. This pairs naturally with webhook-based workflow engines to build approval flows without any `onAction` handler at all:
|
|
104
|
+
|
|
105
|
+
```tsx title="lib/bot.tsx" lineNumbers
|
|
106
|
+
bot.onNewMention(async (thread) => {
|
|
107
|
+
const approveUrl = "https://example.com/webhook/approve";
|
|
108
|
+
const denyUrl = "https://example.com/webhook/deny";
|
|
109
|
+
|
|
110
|
+
await thread.post(
|
|
111
|
+
<Card title="Deploy v2.4.1?">
|
|
112
|
+
<Actions>
|
|
113
|
+
<Button callbackUrl={approveUrl} id="approve" style="primary">
|
|
114
|
+
Approve
|
|
115
|
+
</Button>
|
|
116
|
+
<Button callbackUrl={denyUrl} id="deny" style="danger">
|
|
117
|
+
Deny
|
|
118
|
+
</Button>
|
|
119
|
+
</Actions>
|
|
120
|
+
</Card>
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Callback payload
|
|
126
|
+
|
|
127
|
+
The POST body sent to the `callbackUrl`:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"type": "action",
|
|
132
|
+
"actionId": "approve",
|
|
133
|
+
"user": { "id": "U123", "name": "alice" },
|
|
134
|
+
"threadId": "slack:C123:1234567890.123",
|
|
135
|
+
"messageId": "1234567890.456"
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
If the button also has a `value` prop, it is included in the payload as `"value"`.
|
|
140
|
+
|
|
141
|
+
<Callout type="info">
|
|
142
|
+
Platform limits apply to encoded button data. Discord's `custom_id` has a 100
|
|
143
|
+
character limit - if the action ID plus callback token exceed this, posting
|
|
144
|
+
the card throws a `ValidationError`. Telegram's `callback_data` has a 64 byte
|
|
145
|
+
limit - buttons that exceed this will throw a `ValidationError`. Keep action
|
|
146
|
+
IDs short when using `callbackUrl` on these platforms.
|
|
147
|
+
</Callout>
|
|
148
|
+
|
|
149
|
+
For modals, see [callbackUrl on modals](/docs/modals#callback-urls).
|
package/docs/adapters.mdx
CHANGED
|
@@ -8,57 +8,63 @@ prerequisites:
|
|
|
8
8
|
|
|
9
9
|
Adapters handle webhook verification, message parsing, and API calls for each platform. Install only the adapters you need. Browse all available adapters — including community-built ones — on the [Adapters](/adapters) page.
|
|
10
10
|
|
|
11
|
+
Need a browser chat UI? See the [Web adapter](/adapters/web) — it speaks the AI SDK `useChat` protocol so the same bot serves Slack, Teams, **and** a `<Conversation>` from `ai-elements` out of the box.
|
|
12
|
+
|
|
11
13
|
Ready to build your own? Follow the [building](/docs/contributing/building) guide.
|
|
12
14
|
|
|
13
15
|
## Feature matrix
|
|
14
16
|
|
|
15
17
|
### Messaging
|
|
16
18
|
|
|
17
|
-
| Feature | [Slack](/adapters/slack) | [Teams](/adapters/teams) | [Google Chat](/adapters/google-chat) | [Discord](/adapters/discord) | [Telegram](/adapters/telegram) | [GitHub](/adapters/github) | [Linear](/adapters/linear) | [WhatsApp](/adapters/whatsapp) |
|
|
18
|
-
|
|
19
|
-
| Post message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
20
|
-
| Edit message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <
|
|
21
|
-
| Delete message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <
|
|
22
|
-
| File uploads | <Check /> | <Check /> | <Cross /> | <Check /> | <Warn /> Single file | <Cross /> | <Cross /> | <Check /> Images, audio, docs |
|
|
23
|
-
| Streaming | <Check /> Native | <Warn />
|
|
24
|
-
| Scheduled messages | <Check /> Native | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
19
|
+
| Feature | [Slack](/adapters/slack) | [Teams](/adapters/teams) | [Google Chat](/adapters/google-chat) | [Discord](/adapters/discord) | [Telegram](/adapters/telegram) | [GitHub](/adapters/github) | [Linear](/adapters/linear) | [WhatsApp](/adapters/whatsapp) | [Messenger](/adapters/messenger) |
|
|
20
|
+
|---------|-------|-------|-------------|---------|---------|--------|--------|-----------|-----------|
|
|
21
|
+
| Post message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
22
|
+
| Edit message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Partial | <Cross /> | <Cross /> |
|
|
23
|
+
| Delete message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Partial | <Cross /> | <Cross /> |
|
|
24
|
+
| File uploads | <Check /> | <Check /> | <Cross /> | <Check /> | <Warn /> Single file | <Cross /> | <Cross /> | <Check /> Images, audio, docs | <Cross /> |
|
|
25
|
+
| Streaming | <Check /> Native | <Warn /> Native (DMs) / Buffered | <Warn /> Post+Edit | <Warn /> Post+Edit | <Warn /> Post+Edit | <Warn /> Buffered | <Warn /> Agent sessions / Post+Edit | <Warn /> Buffered | <Warn /> Buffered |
|
|
26
|
+
| Scheduled messages | <Check /> Native | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
25
27
|
|
|
26
28
|
### Rich content
|
|
27
29
|
|
|
28
|
-
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp |
|
|
29
|
-
|
|
30
|
-
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Embeds | Markdown + inline keyboard buttons | GFM Markdown | Markdown | WhatsApp templates |
|
|
31
|
-
| Buttons | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Inline keyboard callbacks | <Cross /> | <Cross /> | <Check /> Interactive replies |
|
|
32
|
-
| Link buttons | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Inline keyboard URLs | <Cross /> | <Cross /> | <Cross /> |
|
|
33
|
-
| Select menus | <Check /> | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
34
|
-
| Tables | <Check /> Block Kit | <Check /> GFM | <Warn /> ASCII | <Check /> GFM | <Warn /> ASCII | <Check /> GFM | <Check /> GFM | <Cross /> |
|
|
35
|
-
| Fields | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Template variables |
|
|
36
|
-
| Images in cards | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Check /> | <Cross /> | <Check /> |
|
|
37
|
-
| Modals | <Check /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
30
|
+
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp | Messenger |
|
|
31
|
+
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|-----------|
|
|
32
|
+
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Embeds | Markdown + inline keyboard buttons | GFM Markdown | Markdown | WhatsApp templates | Generic/Button Templates |
|
|
33
|
+
| Buttons | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Inline keyboard callbacks | <Cross /> | <Cross /> | <Check /> Interactive replies | <Warn /> Max 3, postback |
|
|
34
|
+
| Link buttons | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Inline keyboard URLs | <Cross /> | <Cross /> | <Cross /> | <Check /> |
|
|
35
|
+
| Select menus | <Check /> | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
36
|
+
| Tables | <Check /> Block Kit | <Check /> GFM | <Warn /> ASCII | <Check /> GFM | <Warn /> ASCII | <Check /> GFM | <Check /> GFM | <Cross /> | <Warn /> ASCII |
|
|
37
|
+
| Fields | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Template variables | <Warn /> ASCII |
|
|
38
|
+
| Images in cards | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Check /> | <Cross /> | <Check /> | <Check /> |
|
|
39
|
+
| Modals | <Check /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
38
40
|
|
|
39
41
|
### Conversations
|
|
40
42
|
|
|
41
|
-
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp |
|
|
42
|
-
|
|
43
|
-
| Slash commands | <Check /> | <Cross /> | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
44
|
-
| Mentions | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
45
|
-
| Add reactions | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
46
|
-
| Remove reactions | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> | <Warn /> | <Warn /> | <Cross /> |
|
|
47
|
-
| Typing indicator | <
|
|
48
|
-
| DMs | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> |
|
|
49
|
-
| Ephemeral messages | <Check /> Native | <Cross /> | <Check /> Native | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
43
|
+
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp | Messenger |
|
|
44
|
+
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|-----------|
|
|
45
|
+
| Slash commands | <Check /> | <Cross /> | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
46
|
+
| Mentions | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Check /> |
|
|
47
|
+
| Add reactions | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
48
|
+
| Remove reactions | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> | <Warn /> | <Warn /> | <Check /> | <Cross /> |
|
|
49
|
+
| Typing indicator | <Check /> | <Check /> | <Cross /> | <Check /> | <Check /> | <Cross /> | <Warn /> Agent sessions | <Cross /> | <Check /> |
|
|
50
|
+
| DMs | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> | <Check /> |
|
|
51
|
+
| Ephemeral messages | <Check /> Native | <Cross /> | <Check /> Native | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
52
|
+
| User lookup ([`getUser`](/docs/api/chat#getuser)) | <Check /> | <Warn /> Cached | <Warn /> Cached | <Check /> | <Warn /> Seen users | <Check /> | <Check /> | <Cross /> | <Cross /> |
|
|
53
|
+
| Parent subject ([`message.subject`](/docs/subject)) | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
|
|
54
|
+
| Native client ([`.client`](/docs/api/chat#getadapter)) | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
|
|
55
|
+
| Custom API endpoint (`apiUrl`) | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
50
56
|
|
|
51
57
|
### Message history
|
|
52
58
|
|
|
53
|
-
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp |
|
|
54
|
-
|
|
55
|
-
| Fetch messages | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Cached | <Check /> | <Check /> | <Warn /> Cached sent messages only |
|
|
56
|
-
| Fetch single message | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Warn /> Cached | <Cross /> | <Cross /> | <
|
|
57
|
-
| Fetch thread info | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <
|
|
58
|
-
| Fetch channel messages | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Cached | <Check /> | <Cross /> | <
|
|
59
|
-
| List threads | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Check /> | <Cross /> | <Cross /> |
|
|
60
|
-
| Fetch channel info | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
|
|
61
|
-
| Post channel message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> |
|
|
59
|
+
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp | Messenger |
|
|
60
|
+
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|-----------|
|
|
61
|
+
| Fetch messages | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Cached | <Check /> | <Check /> | <Warn /> Cached sent messages only | <Warn /> Cached sent messages only |
|
|
62
|
+
| Fetch single message | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Warn /> Cached | <Cross /> | <Cross /> | <Cross /> | <Warn /> Cached |
|
|
63
|
+
| Fetch thread info | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
64
|
+
| Fetch channel messages | <Check /> | <Check /> | <Check /> | <Check /> | <Warn /> Cached | <Check /> | <Cross /> | <Cross /> | <Warn /> Cached |
|
|
65
|
+
| List threads | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> |
|
|
66
|
+
| Fetch channel info | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> |
|
|
67
|
+
| Post channel message | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> | <Check /> |
|
|
62
68
|
|
|
63
69
|
<Callout type="info">
|
|
64
70
|
<Warn /> indicates partial support — the feature works with limitations. See individual adapter pages for details.
|
package/docs/api/cards.mdx
CHANGED
|
@@ -100,6 +100,10 @@ Button({ id: "delete", label: "Delete", style: "danger", value: "item-123" })
|
|
|
100
100
|
type: '"action" | "modal"',
|
|
101
101
|
default: '"action"',
|
|
102
102
|
},
|
|
103
|
+
callbackUrl: {
|
|
104
|
+
description: 'URL to POST action data to when this button is clicked.',
|
|
105
|
+
type: 'string',
|
|
106
|
+
},
|
|
103
107
|
}}
|
|
104
108
|
/>
|
|
105
109
|
|
package/docs/api/chat.mdx
CHANGED
|
@@ -168,7 +168,9 @@ Fires when a user clicks a button or selects an option in a card.
|
|
|
168
168
|
```typescript
|
|
169
169
|
// Single action
|
|
170
170
|
bot.onAction("approve", async (event) => {
|
|
171
|
-
|
|
171
|
+
if (event.thread) {
|
|
172
|
+
await event.thread.post("Approved!");
|
|
173
|
+
}
|
|
172
174
|
});
|
|
173
175
|
|
|
174
176
|
// Multiple actions
|
|
@@ -193,8 +195,8 @@ bot.onAction(async (event) => { /* ... */ });
|
|
|
193
195
|
type: 'Author',
|
|
194
196
|
},
|
|
195
197
|
'event.thread': {
|
|
196
|
-
description: 'The thread containing the card.',
|
|
197
|
-
type: 'Thread',
|
|
198
|
+
description: 'The thread containing the card, or null for view-based actions.',
|
|
199
|
+
type: 'Thread | null',
|
|
198
200
|
},
|
|
199
201
|
'event.triggerId': {
|
|
200
202
|
description: 'Trigger ID for opening modals (platform-specific, may expire quickly).',
|
|
@@ -261,9 +263,47 @@ Returns `ModalResponse | undefined` to control the modal after submission:
|
|
|
261
263
|
- `{ action: "update", modal: ModalElement }` — replace the modal content
|
|
262
264
|
- `{ action: "push", modal: ModalElement }` — push a new modal view onto the stack
|
|
263
265
|
|
|
266
|
+
### onOptionsLoad
|
|
267
|
+
|
|
268
|
+
Fires when an `ExternalSelect` requests options dynamically. The handler is keyed on the select's `id` and must return options synchronously enough for Slack's 3-second budget (the adapter caps the loader at ~2.5s and substitutes an empty result on timeout). Slack-only.
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
bot.onOptionsLoad("assignee", async (event) => {
|
|
272
|
+
const people = await peopleService.search(event.query);
|
|
273
|
+
return people.map((p) => ({ label: p.fullName, value: p.id }));
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Return an array of `OptionsLoadGroup` (`{ label, options }[]`) instead of a flat array to render grouped headers (e.g. "Recent" / "All"). Slack limits: max 100 groups, max 100 options per group.
|
|
278
|
+
|
|
279
|
+
<TypeTable
|
|
280
|
+
type={{
|
|
281
|
+
'event.actionId': {
|
|
282
|
+
description: 'The id of the select requesting options (matches the id passed to bot.onOptionsLoad).',
|
|
283
|
+
type: 'string',
|
|
284
|
+
},
|
|
285
|
+
'event.query': {
|
|
286
|
+
description: 'The text the user has typed so far.',
|
|
287
|
+
type: 'string',
|
|
288
|
+
},
|
|
289
|
+
'event.user': {
|
|
290
|
+
description: 'The user requesting options.',
|
|
291
|
+
type: 'Author',
|
|
292
|
+
},
|
|
293
|
+
'event.adapter': {
|
|
294
|
+
description: 'The adapter that received this event.',
|
|
295
|
+
type: 'Adapter',
|
|
296
|
+
},
|
|
297
|
+
'event.raw': {
|
|
298
|
+
description: 'Raw platform-specific payload.',
|
|
299
|
+
type: 'unknown',
|
|
300
|
+
},
|
|
301
|
+
}}
|
|
302
|
+
/>
|
|
303
|
+
|
|
264
304
|
### onSlashCommand
|
|
265
305
|
|
|
266
|
-
Fires when a user invokes a `/command` in the message composer. Currently supported on Slack.
|
|
306
|
+
Fires when a user invokes a `/command` in the message composer. Currently supported on Slack and Discord.
|
|
267
307
|
|
|
268
308
|
```typescript
|
|
269
309
|
// Specific command
|
|
@@ -426,12 +466,42 @@ bot.webhooks.teams(request, { waitUntil });
|
|
|
426
466
|
|
|
427
467
|
### getAdapter
|
|
428
468
|
|
|
429
|
-
Get
|
|
469
|
+
Get a typed adapter instance by name.
|
|
430
470
|
|
|
431
471
|
```typescript
|
|
432
472
|
const slack = bot.getAdapter("slack");
|
|
433
473
|
```
|
|
434
474
|
|
|
475
|
+
#### Direct client access
|
|
476
|
+
|
|
477
|
+
Use `.client` to access the platform's typed native API client directly — available on Linear and GitHub:
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
// Linear - full LinearClient from @linear/sdk
|
|
481
|
+
const linear = bot.getAdapter("linear").client;
|
|
482
|
+
const issue = await linear.issue("ENG-123");
|
|
483
|
+
const project = await issue.project;
|
|
484
|
+
|
|
485
|
+
// GitHub - full Octokit from @octokit/rest
|
|
486
|
+
const github = bot.getAdapter("github").client;
|
|
487
|
+
const { data: pulls } = await github.rest.pulls.list({
|
|
488
|
+
owner: "vercel",
|
|
489
|
+
repo: "chat",
|
|
490
|
+
state: "open",
|
|
491
|
+
});
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
The client uses the credentials from your adapter config. For multi-tenant adapters (Linear, GitHub), it returns the client for the current webhook request context.
|
|
495
|
+
|
|
496
|
+
<Callout type="warn">
|
|
497
|
+
For multi-tenant adapters (GitHub App without a fixed installation ID, Linear with per-org OAuth), `client` requires webhook handler context to resolve credentials. Calling it outside a handler throws. Single-tenant adapters (PAT, API key) work anywhere.
|
|
498
|
+
</Callout>
|
|
499
|
+
|
|
500
|
+
| Adapter | `client` type |
|
|
501
|
+
|---------|---------------|
|
|
502
|
+
| Linear | `LinearClient` from `@linear/sdk` |
|
|
503
|
+
| GitHub | `Octokit` from `@octokit/rest` |
|
|
504
|
+
|
|
435
505
|
### openDM
|
|
436
506
|
|
|
437
507
|
Open a direct message thread with a user.
|
|
@@ -498,10 +568,16 @@ const user = await bot.getUser(message.author);
|
|
|
498
568
|
- **GitHub** — `email` is `null` unless the user made it public, or you authenticated with the `user:email` scope.
|
|
499
569
|
- **Linear** — full profile (incl. email + avatar) for any active workspace member.
|
|
500
570
|
|
|
501
|
-
Fields that aren't available return `undefined`. Numeric user IDs (Discord/Telegram/GitHub) can be ambiguous when multiple of those adapters are registered — call the
|
|
571
|
+
Fields that aren't available return `undefined`. Numeric user IDs (Discord/Telegram/GitHub) can be ambiguous when multiple of those adapters are registered — `bot.getUser` throws a `ChatError` with code `AMBIGUOUS_USER_ID` in that case. Pass an `Author` from a message handler (which already carries the adapter), or call the adapter directly (`adapter.getUser(userId)`).
|
|
502
572
|
</Callout>
|
|
503
573
|
|
|
504
|
-
|
|
574
|
+
`bot.getUser` throws a `ChatError` in three cases. Handle them if your bot runs on multiple platforms:
|
|
575
|
+
|
|
576
|
+
| Code | When |
|
|
577
|
+
|------|------|
|
|
578
|
+
| `NOT_SUPPORTED` | The resolved adapter doesn't implement `getUser` (e.g. WhatsApp) |
|
|
579
|
+
| `AMBIGUOUS_USER_ID` | A numeric user ID could belong to more than one registered adapter (Discord/Telegram/GitHub) |
|
|
580
|
+
| `UNKNOWN_USER_ID_FORMAT` | The `userId` string doesn't match any registered platform's ID format |
|
|
505
581
|
|
|
506
582
|
```typescript
|
|
507
583
|
import { ChatError } from "chat";
|
|
@@ -512,8 +588,14 @@ try {
|
|
|
512
588
|
// User not found on this platform
|
|
513
589
|
}
|
|
514
590
|
} catch (error) {
|
|
515
|
-
if (error instanceof ChatError
|
|
516
|
-
|
|
591
|
+
if (error instanceof ChatError) {
|
|
592
|
+
if (error.code === "NOT_SUPPORTED") {
|
|
593
|
+
// This adapter doesn't support user lookups
|
|
594
|
+
} else if (error.code === "AMBIGUOUS_USER_ID") {
|
|
595
|
+
// Pass message.author or call adapter.getUser(userId) directly
|
|
596
|
+
} else if (error.code === "UNKNOWN_USER_ID_FORMAT") {
|
|
597
|
+
// userId doesn't match any known platform format
|
|
598
|
+
}
|
|
517
599
|
}
|
|
518
600
|
}
|
|
519
601
|
```
|
package/docs/api/index.mdx
CHANGED
|
@@ -31,6 +31,8 @@ import { Chat, root, paragraph, text, Card, Button, emoji } from "chat";
|
|
|
31
31
|
| Export | Description |
|
|
32
32
|
|--------|-------------|
|
|
33
33
|
| [`PostableMessage`](/docs/api/postable-message) | Union type accepted by `thread.post()` |
|
|
34
|
+
| [`Plan`](/docs/api/postable-message#plan) | Step-by-step task list that mutates after posting |
|
|
35
|
+
| [`StreamingPlan`](/docs/api/postable-message#streamingplan) | Wraps an async iterable with platform-specific streaming options |
|
|
34
36
|
| [`Cards`](/docs/api/cards) | Rich card components — `Card`, `Text`, `Button`, `Actions`, etc. |
|
|
35
37
|
| [`Markdown`](/docs/api/markdown) | AST builder functions — `root`, `paragraph`, `text`, `strong`, etc. |
|
|
36
38
|
| [`Modals`](/docs/api/modals) | Modal form components — `Modal`, `TextInput`, `Select`, etc. |
|
package/docs/api/markdown.mdx
CHANGED
|
@@ -15,6 +15,25 @@ import {
|
|
|
15
15
|
} from "chat";
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## Type re-exports
|
|
19
|
+
|
|
20
|
+
The chat package re-exports mdast's union and content types so adapters and downstream code can build exhaustively-typed AST walkers without depending on `mdast` directly:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import type { Nodes, Root, Content } from "chat";
|
|
24
|
+
|
|
25
|
+
function render(node: Nodes): string {
|
|
26
|
+
switch (node.type) {
|
|
27
|
+
case "text": return node.value;
|
|
28
|
+
case "strong": return node.children.map(render).join("");
|
|
29
|
+
// ...
|
|
30
|
+
default: throw new Error(`Unhandled: ${node satisfies never}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Adapters use this pattern to make the type checker reject the build when a new mdast node type is introduced upstream.
|
|
36
|
+
|
|
18
37
|
## Node builders
|
|
19
38
|
|
|
20
39
|
### root
|
|
@@ -222,7 +241,7 @@ const value = getNodeValue(node); // string | undefined
|
|
|
222
241
|
|
|
223
242
|
### tableToAscii
|
|
224
243
|
|
|
225
|
-
Render an mdast `Table` node as a padded ASCII table string. Used by adapters that lack native table support (
|
|
244
|
+
Render an mdast `Table` node as a padded ASCII table string. Used by adapters that lack native table support (Google Chat, Discord, Telegram).
|
|
226
245
|
|
|
227
246
|
```typescript
|
|
228
247
|
import { parseMarkdown, tableToAscii, isTableNode } from "chat";
|
|
@@ -261,17 +280,21 @@ The SDK uses mdast as the canonical format and each adapter converts it to the p
|
|
|
261
280
|
|
|
262
281
|
| Feature | Slack | Teams | Google Chat |
|
|
263
282
|
|---------|-------|-------|-------------|
|
|
264
|
-
| Bold |
|
|
283
|
+
| Bold | `**text**` | `**text**` | `*text*` |
|
|
265
284
|
| Italic | `_text_` | `_text_` | `_text_` |
|
|
266
|
-
| Strikethrough |
|
|
285
|
+
| Strikethrough | `~~text~~` | `~~text~~` | `~text~` |
|
|
267
286
|
| Code | `` `code` `` | `` `code` `` | `` `code` `` |
|
|
268
287
|
| Code blocks | ```` ``` ```` | ```` ``` ```` | ```` ``` ```` |
|
|
269
|
-
| Links |
|
|
288
|
+
| Links | `[text](url)` | `[text](url)` | `[text](url)` |
|
|
270
289
|
| Lists | Supported | Supported | Supported |
|
|
271
290
|
| Blockquotes | `>` | `>` | Simulated with `>` prefix |
|
|
272
|
-
| Tables |
|
|
291
|
+
| Tables | Native (markdown_text) | Native GFM | ASCII fallback |
|
|
273
292
|
| Mentions | `<@USER>` | `<at>name</at>` | `<users/{id}>` |
|
|
274
293
|
|
|
294
|
+
<Callout type="info">
|
|
295
|
+
Slack accepts standard markdown via the `markdown_text` field on `chat.postMessage` and friends, so the SDK passes markdown through directly. Incoming Slack messages still arrive as legacy mrkdwn (`*bold*`, `<url|text>`) and are parsed transparently. If you need to send mrkdwn yourself, use `{ raw: "..." }`.
|
|
296
|
+
</Callout>
|
|
297
|
+
|
|
275
298
|
<Callout type="info">
|
|
276
299
|
You don't need to worry about these differences when using the SDK — the AST builders and `parseMarkdown` handle conversion automatically. This table is useful if you're working with `raw` platform payloads or debugging formatting issues.
|
|
277
300
|
</Callout>
|
package/docs/api/message.mdx
CHANGED
|
@@ -54,6 +54,10 @@ import { Message } from "chat";
|
|
|
54
54
|
description: 'Whether the bot was @-mentioned in this message.',
|
|
55
55
|
type: 'boolean | undefined',
|
|
56
56
|
},
|
|
57
|
+
subject: {
|
|
58
|
+
description: 'Resolves the parent resource (issue, PR) this message is about. Returns null on chat platforms. See [Message Subject](/docs/subject).',
|
|
59
|
+
type: 'Promise<MessageSubject | null>',
|
|
60
|
+
},
|
|
57
61
|
}}
|
|
58
62
|
/>
|
|
59
63
|
|
|
@@ -200,6 +204,55 @@ When using [`toAiMessages()`](/docs/api/to-ai-messages), link metadata is automa
|
|
|
200
204
|
| Slack | URLs from `rich_text` blocks or `<url>` text patterns | Slack message links (`*.slack.com/archives/...`) |
|
|
201
205
|
| Others | Not yet — `links` is always `[]` | — |
|
|
202
206
|
|
|
207
|
+
## MessageSubject
|
|
208
|
+
|
|
209
|
+
Returned by `message.subject` on platforms with parent resources. See [Message Subject](/docs/subject) for usage.
|
|
210
|
+
|
|
211
|
+
<TypeTable
|
|
212
|
+
type={{
|
|
213
|
+
type: {
|
|
214
|
+
description: 'Resource kind, e.g. "issue" or "pull_request".',
|
|
215
|
+
type: 'string',
|
|
216
|
+
},
|
|
217
|
+
id: {
|
|
218
|
+
description: 'Resource identifier (e.g. "ENG-123" or "42").',
|
|
219
|
+
type: 'string',
|
|
220
|
+
},
|
|
221
|
+
title: {
|
|
222
|
+
description: 'Resource title.',
|
|
223
|
+
type: 'string | undefined',
|
|
224
|
+
},
|
|
225
|
+
description: {
|
|
226
|
+
description: 'Full description/body in markdown.',
|
|
227
|
+
type: 'string | undefined',
|
|
228
|
+
},
|
|
229
|
+
status: {
|
|
230
|
+
description: 'Current status (e.g. "In Progress", "open").',
|
|
231
|
+
type: 'string | undefined',
|
|
232
|
+
},
|
|
233
|
+
url: {
|
|
234
|
+
description: 'Web URL to the resource.',
|
|
235
|
+
type: 'string | undefined',
|
|
236
|
+
},
|
|
237
|
+
author: {
|
|
238
|
+
description: 'Resource creator.',
|
|
239
|
+
type: '{ id: string; name: string } | undefined',
|
|
240
|
+
},
|
|
241
|
+
assignee: {
|
|
242
|
+
description: 'Current assignee.',
|
|
243
|
+
type: '{ id: string; name: string } | undefined',
|
|
244
|
+
},
|
|
245
|
+
labels: {
|
|
246
|
+
description: 'Labels/tags.',
|
|
247
|
+
type: 'string[] | undefined',
|
|
248
|
+
},
|
|
249
|
+
raw: {
|
|
250
|
+
description: 'Full platform API response.',
|
|
251
|
+
type: 'unknown',
|
|
252
|
+
},
|
|
253
|
+
}}
|
|
254
|
+
/>
|
|
255
|
+
|
|
203
256
|
## Serialization
|
|
204
257
|
|
|
205
258
|
Messages can be serialized for workflow engines and external systems.
|
package/docs/api/meta.json
CHANGED
package/docs/api/modals.mdx
CHANGED
|
@@ -54,6 +54,10 @@ bot.onAction("open-form", async (event) => {
|
|
|
54
54
|
type: 'boolean',
|
|
55
55
|
default: 'false',
|
|
56
56
|
},
|
|
57
|
+
callbackUrl: {
|
|
58
|
+
description: 'URL to POST form values to when the modal is submitted.',
|
|
59
|
+
type: 'string',
|
|
60
|
+
},
|
|
57
61
|
privateMetadata: {
|
|
58
62
|
description: 'Arbitrary string passed through the modal lifecycle (e.g., JSON context).',
|
|
59
63
|
type: 'string',
|
|
@@ -167,6 +171,52 @@ Select({
|
|
|
167
171
|
}}
|
|
168
172
|
/>
|
|
169
173
|
|
|
174
|
+
## ExternalSelect
|
|
175
|
+
|
|
176
|
+
Dropdown that loads options dynamically from a handler as the user types. Slack-only. Pair with [`bot.onOptionsLoad`](/docs/api/chat#onoptionsload) to supply options. See [Modals → ExternalSelect](/docs/modals#externalselect) for a full example, grouped-options support, and Slack setup notes.
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
ExternalSelect({
|
|
180
|
+
id: "assignee",
|
|
181
|
+
label: "Assignee",
|
|
182
|
+
placeholder: "Search people",
|
|
183
|
+
minQueryLength: 1,
|
|
184
|
+
initialOption: { label: "Alice", value: "U123" },
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
<TypeTable
|
|
189
|
+
type={{
|
|
190
|
+
id: {
|
|
191
|
+
description: 'Input ID — used as the key in event.values.',
|
|
192
|
+
type: 'string',
|
|
193
|
+
},
|
|
194
|
+
label: {
|
|
195
|
+
description: 'Label displayed above the select.',
|
|
196
|
+
type: 'string',
|
|
197
|
+
},
|
|
198
|
+
placeholder: {
|
|
199
|
+
description: 'Placeholder text.',
|
|
200
|
+
type: 'string',
|
|
201
|
+
},
|
|
202
|
+
minQueryLength: {
|
|
203
|
+
description: 'Minimum characters before the loader fires (Slack default: 3).',
|
|
204
|
+
type: 'number',
|
|
205
|
+
},
|
|
206
|
+
initialOption: {
|
|
207
|
+
description: 'Pre-selected option when the modal opens. Unlike static Select where initialOption is a value string, ExternalSelect needs the full label/value object since the loader has not run yet.',
|
|
208
|
+
type: '{ label: string, value: string }',
|
|
209
|
+
},
|
|
210
|
+
optional: {
|
|
211
|
+
description: 'Whether the field can be left empty.',
|
|
212
|
+
type: 'boolean',
|
|
213
|
+
default: 'false',
|
|
214
|
+
},
|
|
215
|
+
}}
|
|
216
|
+
/>
|
|
217
|
+
|
|
218
|
+
The loader registered via `bot.onOptionsLoad("assignee", handler)` returns either a flat `SelectOptionElement[]` or `OptionsLoadGroup[]` (`{ label, options }[]`) for grouped options.
|
|
219
|
+
|
|
170
220
|
## RadioSelect
|
|
171
221
|
|
|
172
222
|
Radio button group for mutually exclusive choices.
|