@chat-adapter/teams 4.17.0 → 4.19.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.
- package/README.md +288 -7
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@chat-adapter/teams)
|
|
4
4
|
[](https://www.npmjs.com/package/@chat-adapter/teams)
|
|
5
5
|
|
|
6
|
-
Microsoft Teams adapter for [Chat SDK](https://chat-sdk.dev
|
|
6
|
+
Microsoft Teams adapter for [Chat SDK](https://chat-sdk.dev). Configure with Azure Bot Service.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
|
|
11
|
+
pnpm add @chat-adapter/teams
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
## Usage
|
|
15
15
|
|
|
16
|
+
The adapter auto-detects `TEAMS_APP_ID`, `TEAMS_APP_PASSWORD`, and `TEAMS_APP_TENANT_ID` from environment variables:
|
|
17
|
+
|
|
16
18
|
```typescript
|
|
17
19
|
import { Chat } from "chat";
|
|
18
20
|
import { createTeamsAdapter } from "@chat-adapter/teams";
|
|
@@ -21,10 +23,7 @@ const bot = new Chat({
|
|
|
21
23
|
userName: "mybot",
|
|
22
24
|
adapters: {
|
|
23
25
|
teams: createTeamsAdapter({
|
|
24
|
-
appId: process.env.TEAMS_APP_ID!,
|
|
25
|
-
appPassword: process.env.TEAMS_APP_PASSWORD!,
|
|
26
26
|
appType: "SingleTenant",
|
|
27
|
-
appTenantId: process.env.TEAMS_APP_TENANT_ID!,
|
|
28
27
|
}),
|
|
29
28
|
},
|
|
30
29
|
});
|
|
@@ -34,9 +33,291 @@ bot.onNewMention(async (thread, message) => {
|
|
|
34
33
|
});
|
|
35
34
|
```
|
|
36
35
|
|
|
37
|
-
##
|
|
36
|
+
## Azure Bot setup
|
|
37
|
+
|
|
38
|
+
### 1. Create Azure Bot resource
|
|
39
|
+
|
|
40
|
+
1. Go to [portal.azure.com](https://portal.azure.com)
|
|
41
|
+
2. Click **Create a resource**
|
|
42
|
+
3. Search for **Azure Bot** and select it
|
|
43
|
+
4. Click **Create** and fill in:
|
|
44
|
+
- **Bot handle**: Unique identifier for your bot
|
|
45
|
+
- **Subscription**: Your Azure subscription
|
|
46
|
+
- **Resource group**: Create new or use existing
|
|
47
|
+
- **Pricing tier**: F0 (free) for testing
|
|
48
|
+
- **Type of App**: **Single Tenant** (recommended for enterprise)
|
|
49
|
+
- **Creation type**: **Create new Microsoft App ID**
|
|
50
|
+
5. Click **Review + create** then **Create**
|
|
51
|
+
|
|
52
|
+
### 2. Get app credentials
|
|
53
|
+
|
|
54
|
+
1. Go to your Bot resource then **Configuration**
|
|
55
|
+
2. Copy **Microsoft App ID** as `TEAMS_APP_ID`
|
|
56
|
+
3. Click **Manage Password** (next to Microsoft App ID)
|
|
57
|
+
4. In the App Registration page, go to **Certificates & secrets**
|
|
58
|
+
5. Click **New client secret**, add description, select expiry, click **Add**
|
|
59
|
+
6. Copy the **Value** immediately (shown only once) as `TEAMS_APP_PASSWORD`
|
|
60
|
+
7. Go to **Overview** and copy **Directory (tenant) ID** as `TEAMS_APP_TENANT_ID`
|
|
61
|
+
|
|
62
|
+
### 3. Configure messaging endpoint
|
|
63
|
+
|
|
64
|
+
1. In your Azure Bot resource, go to **Configuration**
|
|
65
|
+
2. Set **Messaging endpoint** to `https://your-domain.com/api/webhooks/teams`
|
|
66
|
+
3. Click **Apply**
|
|
67
|
+
|
|
68
|
+
### 4. Enable Teams channel
|
|
69
|
+
|
|
70
|
+
1. In your Azure Bot resource, go to **Channels**
|
|
71
|
+
2. Click **Microsoft Teams**
|
|
72
|
+
3. Accept the terms of service
|
|
73
|
+
4. Click **Apply**
|
|
74
|
+
|
|
75
|
+
### 5. Create Teams app package
|
|
76
|
+
|
|
77
|
+
Create a `manifest.json` file:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
|
|
82
|
+
"manifestVersion": "1.16",
|
|
83
|
+
"version": "1.0.0",
|
|
84
|
+
"id": "your_app_id_here",
|
|
85
|
+
"packageName": "com.yourcompany.chatbot",
|
|
86
|
+
"developer": {
|
|
87
|
+
"name": "Your Company",
|
|
88
|
+
"websiteUrl": "https://your-domain.com",
|
|
89
|
+
"privacyUrl": "https://your-domain.com/privacy",
|
|
90
|
+
"termsOfUseUrl": "https://your-domain.com/terms"
|
|
91
|
+
},
|
|
92
|
+
"name": {
|
|
93
|
+
"short": "Chat Bot",
|
|
94
|
+
"full": "Chat SDK Demo Bot"
|
|
95
|
+
},
|
|
96
|
+
"description": {
|
|
97
|
+
"short": "A chat bot powered by Chat SDK",
|
|
98
|
+
"full": "A chat bot powered by Chat SDK that responds to messages and commands."
|
|
99
|
+
},
|
|
100
|
+
"icons": {
|
|
101
|
+
"outline": "outline.png",
|
|
102
|
+
"color": "color.png"
|
|
103
|
+
},
|
|
104
|
+
"accentColor": "#FFFFFF",
|
|
105
|
+
"bots": [
|
|
106
|
+
{
|
|
107
|
+
"botId": "your_app_id_here",
|
|
108
|
+
"scopes": ["personal", "team", "groupchat"],
|
|
109
|
+
"supportsFiles": false,
|
|
110
|
+
"isNotificationOnly": false
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"permissions": ["identity", "messageTeamMembers"],
|
|
114
|
+
"validDomains": ["your-domain.com"]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Create icon files (32x32 `outline.png` and 192x192 `color.png`), then zip all three files together.
|
|
119
|
+
|
|
120
|
+
### 6. Upload app to Teams
|
|
121
|
+
|
|
122
|
+
**For testing (sideloading):**
|
|
123
|
+
|
|
124
|
+
1. In Teams, click **Apps** in the sidebar
|
|
125
|
+
2. Click **Manage your apps** then **Upload an app**
|
|
126
|
+
3. Click **Upload a custom app** and select your zip file
|
|
127
|
+
|
|
128
|
+
**For organization-wide deployment:**
|
|
129
|
+
|
|
130
|
+
1. Go to [Teams Admin Center](https://admin.teams.microsoft.com)
|
|
131
|
+
2. Go to **Teams apps** then **Manage apps**
|
|
132
|
+
3. Click **Upload new app** and select your zip file
|
|
133
|
+
4. Go to **Setup policies** to control who can use the app
|
|
134
|
+
|
|
135
|
+
## Configuration
|
|
136
|
+
|
|
137
|
+
All options are auto-detected from environment variables when not provided.
|
|
138
|
+
|
|
139
|
+
| Option | Required | Description |
|
|
140
|
+
|--------|----------|-------------|
|
|
141
|
+
| `appId` | No* | Azure Bot App ID. Auto-detected from `TEAMS_APP_ID` |
|
|
142
|
+
| `appPassword` | No** | Azure Bot App Password. Auto-detected from `TEAMS_APP_PASSWORD` |
|
|
143
|
+
| `certificate` | No** | Certificate-based authentication config |
|
|
144
|
+
| `federated` | No** | Federated (workload identity) authentication config |
|
|
145
|
+
| `appType` | No | `"MultiTenant"` or `"SingleTenant"` (default: `"MultiTenant"`) |
|
|
146
|
+
| `appTenantId` | For SingleTenant | Azure AD Tenant ID. Auto-detected from `TEAMS_APP_TENANT_ID` |
|
|
147
|
+
| `logger` | No | Logger instance (defaults to `ConsoleLogger("info")`) |
|
|
148
|
+
|
|
149
|
+
\*`appId` is required — either via config or `TEAMS_APP_ID` env var.
|
|
150
|
+
|
|
151
|
+
\*\*Exactly one authentication method is required: `appPassword`, `certificate`, or `federated`.
|
|
152
|
+
|
|
153
|
+
### Authentication methods
|
|
154
|
+
|
|
155
|
+
The adapter supports three mutually exclusive authentication methods. When no explicit auth is provided, `TEAMS_APP_PASSWORD` is auto-detected from environment variables.
|
|
156
|
+
|
|
157
|
+
#### Client secret (default)
|
|
158
|
+
|
|
159
|
+
The simplest option — provide `appPassword` directly or set `TEAMS_APP_PASSWORD`:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
createTeamsAdapter({
|
|
163
|
+
appPassword: "your_app_password_here",
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### Certificate
|
|
168
|
+
|
|
169
|
+
Authenticate with a PEM certificate. Provide either `certificateThumbprint` or `x5c` (public certificate for subject-name validation):
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
createTeamsAdapter({
|
|
173
|
+
certificate: {
|
|
174
|
+
certificatePrivateKey: "-----BEGIN RSA PRIVATE KEY-----\n...",
|
|
175
|
+
certificateThumbprint: "AB1234...", // hex-encoded thumbprint
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Or with subject-name validation:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
createTeamsAdapter({
|
|
184
|
+
certificate: {
|
|
185
|
+
certificatePrivateKey: "-----BEGIN RSA PRIVATE KEY-----\n...",
|
|
186
|
+
x5c: "-----BEGIN CERTIFICATE-----\n...",
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
#### Federated (workload identity)
|
|
192
|
+
|
|
193
|
+
For environments with managed identities (e.g. Azure Kubernetes Service, GitHub Actions):
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
createTeamsAdapter({
|
|
197
|
+
federated: {
|
|
198
|
+
clientId: "your_managed_identity_client_id_here",
|
|
199
|
+
clientAudience: "api://AzureADTokenExchange", // optional, this is the default
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Environment variables
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
TEAMS_APP_ID=...
|
|
208
|
+
TEAMS_APP_PASSWORD=...
|
|
209
|
+
TEAMS_APP_TENANT_ID=... # Required for SingleTenant
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Features
|
|
213
|
+
|
|
214
|
+
### Messaging
|
|
215
|
+
|
|
216
|
+
| Feature | Supported |
|
|
217
|
+
|---------|-----------|
|
|
218
|
+
| Post message | Yes |
|
|
219
|
+
| Edit message | Yes |
|
|
220
|
+
| Delete message | Yes |
|
|
221
|
+
| File uploads | Yes |
|
|
222
|
+
| Streaming | Post+Edit fallback |
|
|
223
|
+
|
|
224
|
+
### Rich content
|
|
225
|
+
|
|
226
|
+
| Feature | Supported |
|
|
227
|
+
|---------|-----------|
|
|
228
|
+
| Card format | Adaptive Cards |
|
|
229
|
+
| Buttons | Yes |
|
|
230
|
+
| Link buttons | Yes |
|
|
231
|
+
| Select menus | No |
|
|
232
|
+
| Tables | GFM |
|
|
233
|
+
| Fields | Yes |
|
|
234
|
+
| Images in cards | Yes |
|
|
235
|
+
| Modals | No |
|
|
236
|
+
|
|
237
|
+
### Conversations
|
|
238
|
+
|
|
239
|
+
| Feature | Supported |
|
|
240
|
+
|---------|-----------|
|
|
241
|
+
| Slash commands | No |
|
|
242
|
+
| Mentions | Yes |
|
|
243
|
+
| Add reactions | No |
|
|
244
|
+
| Remove reactions | No |
|
|
245
|
+
| Typing indicator | No |
|
|
246
|
+
| DMs | Yes |
|
|
247
|
+
| Ephemeral messages | No (DM fallback) |
|
|
248
|
+
|
|
249
|
+
### Message history
|
|
250
|
+
|
|
251
|
+
| Feature | Supported |
|
|
252
|
+
|---------|-----------|
|
|
253
|
+
| Fetch messages | Yes |
|
|
254
|
+
| Fetch single message | No |
|
|
255
|
+
| Fetch thread info | Yes |
|
|
256
|
+
| Fetch channel messages | Yes |
|
|
257
|
+
| List threads | Yes |
|
|
258
|
+
| Fetch channel info | Yes |
|
|
259
|
+
| Post channel message | Yes |
|
|
260
|
+
|
|
261
|
+
## Limitations
|
|
262
|
+
|
|
263
|
+
- **Adding reactions**: Teams Bot Framework doesn't support bots adding reactions. Calling `addReaction()` or `removeReaction()` throws a `NotImplementedError`. The bot can still receive reaction events via `onReaction()`.
|
|
264
|
+
- **Typing indicators**: Not available via Bot Framework. `startTyping()` is a no-op.
|
|
265
|
+
|
|
266
|
+
### Message history (`fetchMessages`)
|
|
267
|
+
|
|
268
|
+
Fetching message history requires the Microsoft Graph API with client credentials flow. To enable it:
|
|
269
|
+
|
|
270
|
+
1. Set `appTenantId` in the adapter config
|
|
271
|
+
2. Grant one of these Azure AD app permissions:
|
|
272
|
+
- `ChatMessage.Read.Chat`
|
|
273
|
+
- `Chat.Read.All`
|
|
274
|
+
- `Chat.Read.WhereInstalled`
|
|
275
|
+
|
|
276
|
+
Without these permissions, `fetchMessages` will not be able to retrieve channel history.
|
|
277
|
+
|
|
278
|
+
### Receiving all messages
|
|
279
|
+
|
|
280
|
+
By default, Teams bots only receive messages when directly @-mentioned. To receive all messages in a channel or group chat, add Resource-Specific Consent (RSC) permissions to your Teams app manifest:
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"authorization": {
|
|
285
|
+
"permissions": {
|
|
286
|
+
"resourceSpecific": [
|
|
287
|
+
{
|
|
288
|
+
"name": "ChannelMessage.Read.Group",
|
|
289
|
+
"type": "Application"
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Alternatively, configure the bot in Azure to receive all messages.
|
|
298
|
+
|
|
299
|
+
## Troubleshooting
|
|
300
|
+
|
|
301
|
+
### "Unauthorized" error
|
|
302
|
+
|
|
303
|
+
- Verify `TEAMS_APP_ID` and your chosen auth credential are correct
|
|
304
|
+
- For client secret auth, check that `TEAMS_APP_PASSWORD` is valid
|
|
305
|
+
- For certificate auth, ensure the private key and thumbprint/x5c match what's registered in Azure AD
|
|
306
|
+
- For federated auth, verify the managed identity client ID and audience are correct
|
|
307
|
+
- For SingleTenant apps, ensure `TEAMS_APP_TENANT_ID` is set
|
|
308
|
+
- Check that the messaging endpoint URL is correct in Azure
|
|
309
|
+
|
|
310
|
+
### Bot not appearing in Teams
|
|
311
|
+
|
|
312
|
+
- Verify the Teams channel is enabled in Azure Bot
|
|
313
|
+
- Check that the app manifest is correctly configured
|
|
314
|
+
- Ensure the app is installed in the workspace/team
|
|
315
|
+
|
|
316
|
+
### Messages not received
|
|
38
317
|
|
|
39
|
-
|
|
318
|
+
- Verify the messaging endpoint URL is correct
|
|
319
|
+
- Check that your server is accessible from the internet
|
|
320
|
+
- Review Azure Bot logs for errors
|
|
40
321
|
|
|
41
322
|
## License
|
|
42
323
|
|
package/dist/index.js
CHANGED
|
@@ -3890,8 +3890,22 @@ var TeamsFormatConverter = class extends BaseFormatConverter {
|
|
|
3890
3890
|
);
|
|
3891
3891
|
markdown = markdown.replace(/<code>([^<]+)<\/code>/gi, "`$1`");
|
|
3892
3892
|
markdown = markdown.replace(/<pre>([^<]+)<\/pre>/gi, "```\n$1\n```");
|
|
3893
|
-
|
|
3894
|
-
|
|
3893
|
+
let prev;
|
|
3894
|
+
do {
|
|
3895
|
+
prev = markdown;
|
|
3896
|
+
markdown = markdown.replace(/<[^>]+>/g, "");
|
|
3897
|
+
} while (markdown !== prev);
|
|
3898
|
+
const entityMap = {
|
|
3899
|
+
"<": "<",
|
|
3900
|
+
">": ">",
|
|
3901
|
+
"&": "&",
|
|
3902
|
+
""": '"',
|
|
3903
|
+
"'": "'"
|
|
3904
|
+
};
|
|
3905
|
+
markdown = markdown.replace(
|
|
3906
|
+
/&(?:lt|gt|amp|quot|#39);/g,
|
|
3907
|
+
(match) => entityMap[match] ?? match
|
|
3908
|
+
);
|
|
3895
3909
|
return parseMarkdown(markdown);
|
|
3896
3910
|
}
|
|
3897
3911
|
nodeToTeams(node) {
|
|
@@ -5087,7 +5101,13 @@ var TeamsAdapter = class {
|
|
|
5087
5101
|
}
|
|
5088
5102
|
let text = "";
|
|
5089
5103
|
if (msg.body?.content) {
|
|
5090
|
-
|
|
5104
|
+
let stripped = msg.body.content;
|
|
5105
|
+
let prev;
|
|
5106
|
+
do {
|
|
5107
|
+
prev = stripped;
|
|
5108
|
+
stripped = stripped.replace(/<[^>]*>/g, "");
|
|
5109
|
+
} while (stripped !== prev);
|
|
5110
|
+
text = stripped.trim();
|
|
5091
5111
|
}
|
|
5092
5112
|
if (!text && msg.attachments?.length) {
|
|
5093
5113
|
for (const att of msg.attachments) {
|