@memberjunction/messaging-adapters 0.0.1 → 5.17.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 (58) hide show
  1. package/README.md +231 -43
  2. package/dist/base/BaseMessagingAdapter.d.ts +428 -0
  3. package/dist/base/BaseMessagingAdapter.d.ts.map +1 -0
  4. package/dist/base/BaseMessagingAdapter.js +934 -0
  5. package/dist/base/BaseMessagingAdapter.js.map +1 -0
  6. package/dist/base/message-formatter.d.ts +70 -0
  7. package/dist/base/message-formatter.d.ts.map +1 -0
  8. package/dist/base/message-formatter.js +201 -0
  9. package/dist/base/message-formatter.js.map +1 -0
  10. package/dist/base/types.d.ts +211 -0
  11. package/dist/base/types.d.ts.map +1 -0
  12. package/dist/base/types.js +6 -0
  13. package/dist/base/types.js.map +1 -0
  14. package/dist/index.d.ts +72 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +76 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/slack/SlackAdapter.d.ts +141 -0
  19. package/dist/slack/SlackAdapter.d.ts.map +1 -0
  20. package/dist/slack/SlackAdapter.js +291 -0
  21. package/dist/slack/SlackAdapter.js.map +1 -0
  22. package/dist/slack/SlackMessagingExtension.d.ts +148 -0
  23. package/dist/slack/SlackMessagingExtension.d.ts.map +1 -0
  24. package/dist/slack/SlackMessagingExtension.js +433 -0
  25. package/dist/slack/SlackMessagingExtension.js.map +1 -0
  26. package/dist/slack/slack-block-builder.d.ts +133 -0
  27. package/dist/slack/slack-block-builder.d.ts.map +1 -0
  28. package/dist/slack/slack-block-builder.js +748 -0
  29. package/dist/slack/slack-block-builder.js.map +1 -0
  30. package/dist/slack/slack-formatter.d.ts +37 -0
  31. package/dist/slack/slack-formatter.d.ts.map +1 -0
  32. package/dist/slack/slack-formatter.js +116 -0
  33. package/dist/slack/slack-formatter.js.map +1 -0
  34. package/dist/slack/slack-interactivity.d.ts +38 -0
  35. package/dist/slack/slack-interactivity.d.ts.map +1 -0
  36. package/dist/slack/slack-interactivity.js +414 -0
  37. package/dist/slack/slack-interactivity.js.map +1 -0
  38. package/dist/slack/slack-routes.d.ts +35 -0
  39. package/dist/slack/slack-routes.d.ts.map +1 -0
  40. package/dist/slack/slack-routes.js +98 -0
  41. package/dist/slack/slack-routes.js.map +1 -0
  42. package/dist/teams/TeamsAdapter.d.ts +155 -0
  43. package/dist/teams/TeamsAdapter.d.ts.map +1 -0
  44. package/dist/teams/TeamsAdapter.js +383 -0
  45. package/dist/teams/TeamsAdapter.js.map +1 -0
  46. package/dist/teams/TeamsMessagingExtension.d.ts +75 -0
  47. package/dist/teams/TeamsMessagingExtension.d.ts.map +1 -0
  48. package/dist/teams/TeamsMessagingExtension.js +176 -0
  49. package/dist/teams/TeamsMessagingExtension.js.map +1 -0
  50. package/dist/teams/teams-card-builder.d.ts +94 -0
  51. package/dist/teams/teams-card-builder.d.ts.map +1 -0
  52. package/dist/teams/teams-card-builder.js +648 -0
  53. package/dist/teams/teams-card-builder.js.map +1 -0
  54. package/dist/teams/teams-formatter.d.ts +39 -0
  55. package/dist/teams/teams-formatter.d.ts.map +1 -0
  56. package/dist/teams/teams-formatter.js +107 -0
  57. package/dist/teams/teams-formatter.js.map +1 -0
  58. package/package.json +40 -7
@@ -0,0 +1,383 @@
1
+ /**
2
+ * @module @memberjunction/messaging-adapters
3
+ * @description Microsoft Teams-specific messaging adapter implementation.
4
+ *
5
+ * Extends `BaseMessagingAdapter` with Bot Framework operations for:
6
+ * - Sending and updating messages via `TurnContext`
7
+ * - Showing typing indicators via `ActivityTypes.Typing`
8
+ * - Formatting responses as Adaptive Cards
9
+ * - Stripping bot `<at>` mentions from message text
10
+ */
11
+ import { TurnContext, ActivityTypes } from 'botbuilder';
12
+ import { LogError, LogStatus } from '@memberjunction/core';
13
+ import { BaseMessagingAdapter } from '../base/BaseMessagingAdapter.js';
14
+ import { markdownToAdaptiveCard } from './teams-formatter.js';
15
+ import { buildRichAdaptiveCard } from './teams-card-builder.js';
16
+ /**
17
+ * Microsoft Teams-specific adapter that implements all platform operations
18
+ * using the Bot Framework SDK (`botbuilder`).
19
+ *
20
+ * ## Features
21
+ * - Native typing indicators via `ActivityTypes.Typing`
22
+ * - Adaptive Card rich formatting for responses
23
+ * - Bot mention stripping (`<at>BotName</at>`) for clean agent input
24
+ * - User email extraction from Bot Framework activities
25
+ *
26
+ * ## Authentication
27
+ * Requires a Microsoft App ID and Password registered in Azure Bot Service.
28
+ * The Bot Framework SDK handles JWT token validation automatically.
29
+ *
30
+ * ## Thread History
31
+ * Teams thread history fetching via Microsoft Graph API is not yet implemented.
32
+ * This means conversations are currently single-turn. Multi-turn support
33
+ * requires Graph API access with `ChannelMessage.Read.All` permission.
34
+ */
35
+ export class TeamsAdapter extends BaseMessagingAdapter {
36
+ static { this.CONV_REF_TTL_MS = 24 * 60 * 60 * 1000; }
37
+ static { this.CONV_REF_MAX_SIZE = 10_000; }
38
+ get PlatformName() { return 'Teams'; }
39
+ constructor(settings) {
40
+ super(settings);
41
+ /** The bot's Microsoft App ID (also used as the bot's user ID). */
42
+ this.botID = '';
43
+ /**
44
+ * Stored conversation references for proactive messaging.
45
+ * Maps conversation ID to the reference needed to send proactive messages.
46
+ * Entries are evicted after 24 hours to prevent unbounded growth.
47
+ */
48
+ this.conversationReferences = new Map();
49
+ /**
50
+ * Recently processed form activity IDs — prevents double-processing when
51
+ * Web Chat sends both an invoke and a message for the same Action.Submit.
52
+ * Uses timestamps instead of setTimeout for cleanup (avoids timer leaks).
53
+ */
54
+ this.recentFormActivityIds = new Map();
55
+ }
56
+ /**
57
+ * Convert a Bot Framework `TurnContext` into a normalized `IncomingMessage`.
58
+ *
59
+ * Called by `TeamsMessagingExtension` when a message activity is received.
60
+ *
61
+ * @param turnContext - Bot Framework turn context for the current activity.
62
+ * @returns Normalized incoming message.
63
+ */
64
+ MapTeamsActivity(turnContext) {
65
+ const activity = turnContext.activity;
66
+ // Store conversation reference for potential proactive messaging
67
+ const conversationRef = TurnContext.getConversationReference(activity);
68
+ this.storeConversationRef(activity.conversation?.id ?? '', conversationRef);
69
+ // Extract sender email from activity (available in Teams)
70
+ const senderEmail = activity.from?.['email'];
71
+ return {
72
+ MessageID: activity.id ?? '',
73
+ Text: activity.text ?? '',
74
+ SenderID: activity.from?.id ?? '',
75
+ SenderName: activity.from?.name ?? '',
76
+ SenderEmail: senderEmail,
77
+ ChannelID: activity.channelId ?? '',
78
+ ThreadID: activity.conversation?.id ?? null,
79
+ IsDirectMessage: activity.conversation?.conversationType === 'personal',
80
+ IsBotMention: this.hasBotMention(activity),
81
+ Timestamp: activity.timestamp ? new Date(activity.timestamp) : new Date(),
82
+ RawEvent: { activity, turnContext }
83
+ };
84
+ }
85
+ /**
86
+ * Initialize: set the bot ID from config or environment.
87
+ */
88
+ async onInitialize() {
89
+ const settings = this.settings;
90
+ this.botID = settings.MicrosoftAppId ?? process.env.MICROSOFT_APP_ID ?? '';
91
+ }
92
+ getBotUserId() {
93
+ return this.botID;
94
+ }
95
+ /**
96
+ * Send a typing indicator to the Teams conversation.
97
+ * Teams natively supports typing indicators via the Bot Framework.
98
+ */
99
+ async showTypingIndicator(message, _agent) {
100
+ const turnContext = message.RawEvent['turnContext'];
101
+ if (turnContext) {
102
+ await turnContext.sendActivity({ type: ActivityTypes.Typing });
103
+ }
104
+ }
105
+ /**
106
+ * Fetch thread history from Teams.
107
+ *
108
+ * NOTE: Not yet implemented. Requires Microsoft Graph API access with
109
+ * `ChannelMessage.Read.All` permission. Currently returns empty array,
110
+ * meaning conversations are single-turn.
111
+ *
112
+ * Future implementation would use:
113
+ * `GET /teams/{id}/channels/{id}/messages/{id}/replies`
114
+ */
115
+ async fetchThreadHistory(_channelId, _threadId) {
116
+ // TODO: Implement via Microsoft Graph API
117
+ // GET /teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies
118
+ // Requires Graph API client and ChannelMessage.Read.All permission
119
+ return [];
120
+ }
121
+ /**
122
+ * Post a new streaming message or update an existing one.
123
+ * Falls back to sending a new message if the channel doesn't support updates.
124
+ *
125
+ * Instead of caching update support on the singleton, we detect per-turn
126
+ * by checking `channelId`. Web Chat (`'webchat'`) doesn't support updates;
127
+ * real Teams (`'msteams'`) does. For unknown channels we try/catch.
128
+ */
129
+ async sendOrUpdateStreamingMessage(originalMessage, currentContent, existingMessageId, _agent) {
130
+ const turnContext = originalMessage.RawEvent['turnContext'];
131
+ const channelSupportsUpdate = this.channelSupportsUpdate(turnContext);
132
+ // Channels that don't support updates (Web Chat, emulator): skip ALL
133
+ // streaming messages. The typing indicator is already shown via
134
+ // showTypingIndicator(), and we'll send only the final Adaptive Card.
135
+ // Without this, the "thinking..." message stays permanently and the
136
+ // final card becomes a second message.
137
+ if (!channelSupportsUpdate) {
138
+ return '';
139
+ }
140
+ if (existingMessageId) {
141
+ try {
142
+ await turnContext.updateActivity({
143
+ id: existingMessageId,
144
+ type: ActivityTypes.Message,
145
+ text: currentContent + ' ...'
146
+ });
147
+ return existingMessageId;
148
+ }
149
+ catch {
150
+ // Individual update failed — fall through to send new message
151
+ }
152
+ }
153
+ const response = await turnContext.sendActivity(currentContent + ' ...');
154
+ return response?.id ?? '';
155
+ }
156
+ /**
157
+ * Send the final formatted response as an Adaptive Card.
158
+ */
159
+ async sendFinalMessage(originalMessage, response) {
160
+ const turnContext = originalMessage.RawEvent['turnContext'];
161
+ await turnContext.sendActivity({
162
+ type: ActivityTypes.Message,
163
+ // Omit `text` when an Adaptive Card is attached — Web Chat and Teams
164
+ // render both the text AND the card, causing duplicate content.
165
+ // The card itself contains all the content; `text` is only a fallback
166
+ // for clients that can't render cards (none of our targets).
167
+ attachments: [{
168
+ contentType: 'application/vnd.microsoft.card.adaptive',
169
+ content: response.RichPayload
170
+ }]
171
+ });
172
+ }
173
+ /**
174
+ * Update the streaming progress message with the final Adaptive Card.
175
+ * Falls back to sending a new message if the channel doesn't support updates.
176
+ */
177
+ async updateFinalMessage(originalMessage, messageId, response) {
178
+ const turnContext = originalMessage.RawEvent['turnContext'];
179
+ const channelSupportsUpdate = this.channelSupportsUpdate(turnContext);
180
+ if (channelSupportsUpdate) {
181
+ try {
182
+ await turnContext.updateActivity({
183
+ id: messageId,
184
+ type: ActivityTypes.Message,
185
+ attachments: [{
186
+ contentType: 'application/vnd.microsoft.card.adaptive',
187
+ content: response.RichPayload
188
+ }]
189
+ });
190
+ return;
191
+ }
192
+ catch {
193
+ // Fall through to send as new message
194
+ }
195
+ }
196
+ // Fallback: send as new message
197
+ await this.sendFinalMessage(originalMessage, response);
198
+ }
199
+ /**
200
+ * Format agent response as a rich Teams Adaptive Card.
201
+ *
202
+ * When a full `ExecuteAgentResult` is available, builds a rich card with
203
+ * agent header, action buttons, explorer links, and metadata footer.
204
+ * Falls back to basic markdown-to-TextBlock conversion otherwise.
205
+ */
206
+ async formatResponse(result, agent, responseText, metadata) {
207
+ const richPayload = result
208
+ ? buildRichAdaptiveCard(result, agent, responseText, {
209
+ explorerBaseURL: this.settings.ExplorerBaseURL,
210
+ artifactId: metadata?.ArtifactId,
211
+ conversationId: metadata?.ConversationId,
212
+ })
213
+ : markdownToAdaptiveCard(responseText);
214
+ return {
215
+ PlainText: responseText,
216
+ RichPayload: richPayload,
217
+ };
218
+ }
219
+ /**
220
+ * Strip the bot's `<at>` mention from the message text.
221
+ * Teams @mentions use the format `<at>BotName</at>`.
222
+ */
223
+ stripBotMention(text) {
224
+ return text.replace(/<at>[^<]+<\/at>/g, '').trim();
225
+ }
226
+ /**
227
+ * Look up the email for a Teams user.
228
+ * In Teams, the email is often available directly on the activity's `from` property.
229
+ *
230
+ * @param platformUserId - Teams user ID.
231
+ * @returns Email address, or `null` if not available.
232
+ */
233
+ async lookupUserEmail(platformUserId) {
234
+ // Teams provides email in the activity `from` field for most message types
235
+ // The caller already extracted SenderEmail from the activity
236
+ // For additional lookups, Graph API would be needed
237
+ return null;
238
+ }
239
+ /**
240
+ * Detect whether the current channel supports `updateActivity`.
241
+ * Real Teams (`msteams`) supports updates; Web Chat (`webchat`) does not.
242
+ * Unknown channels are assumed to support updates (try/catch guards the call).
243
+ */
244
+ channelSupportsUpdate(turnContext) {
245
+ const channelId = turnContext.activity?.channelId;
246
+ if (channelId === 'webchat' || channelId === 'emulator') {
247
+ return false;
248
+ }
249
+ return true;
250
+ }
251
+ static { this.FORM_DEDUP_TTL_MS = 30_000; }
252
+ /**
253
+ * Handle an Adaptive Card Action.Submit from a form rendered in Teams.
254
+ *
255
+ * Extracts field values from `activity.value`, builds the same
256
+ * `@{_mode:"form",...}` payload that Slack uses for modal submissions,
257
+ * and routes through `HandleMessage()` as a synthetic IncomingMessage.
258
+ *
259
+ * Does NOT send a bot acknowledgement message — the agent's own response
260
+ * serves as the acknowledgement, and a bot-authored echo of the form values
261
+ * would pollute the conversation history the agent sees.
262
+ */
263
+ async HandleFormSubmit(turnContext) {
264
+ try {
265
+ const activity = turnContext.activity;
266
+ // Dedup: Web Chat may fire both invoke + message for the same submit
267
+ const activityId = activity.id ?? '';
268
+ if (activityId && this.isRecentFormActivity(activityId)) {
269
+ LogStatus(`Teams form submit: duplicate activity '${activityId}', skipping`);
270
+ return;
271
+ }
272
+ if (activityId) {
273
+ this.recentFormActivityIds.set(activityId, Date.now());
274
+ }
275
+ const formValues = activity.value;
276
+ if (!formValues || formValues['action'] !== 'mj:form_submit') {
277
+ return;
278
+ }
279
+ LogStatus(`Teams form submit: user='${activity.from?.name}', conversation='${activity.conversation?.id}'`);
280
+ // Extract form fields: keys starting with "mj_form_" are input field IDs
281
+ const fields = this.extractFormFields(formValues);
282
+ if (fields.length === 0) {
283
+ LogStatus('Teams form submit: no fields extracted, ignoring');
284
+ return;
285
+ }
286
+ // Build the @{_mode:"form"} message matching Explorer/Slack format
287
+ const formResponse = JSON.stringify({
288
+ _mode: 'form',
289
+ action: 'formSubmit',
290
+ fields,
291
+ });
292
+ const messageText = `@${formResponse}`;
293
+ // Build a synthetic IncomingMessage and route through the adapter
294
+ const senderEmail = activity.from?.['email'];
295
+ // Store conversation reference for proactive messaging
296
+ const conversationRef = TurnContext.getConversationReference(activity);
297
+ this.storeConversationRef(activity.conversation?.id ?? '', conversationRef);
298
+ const incomingMessage = {
299
+ MessageID: activityId,
300
+ Text: messageText,
301
+ SenderID: activity.from?.id ?? '',
302
+ SenderName: activity.from?.name ?? '',
303
+ SenderEmail: senderEmail,
304
+ ChannelID: activity.channelId ?? '',
305
+ ThreadID: activity.conversation?.id ?? null,
306
+ IsDirectMessage: activity.conversation?.conversationType === 'personal',
307
+ IsBotMention: true,
308
+ Timestamp: activity.timestamp ? new Date(activity.timestamp) : new Date(),
309
+ RawEvent: { activity, turnContext },
310
+ };
311
+ await this.HandleMessage(incomingMessage);
312
+ }
313
+ catch (error) {
314
+ LogError('Failed to handle Teams form submission:', undefined, error);
315
+ }
316
+ }
317
+ /**
318
+ * Extract form field values from an Action.Submit activity.value object.
319
+ * Keys starting with "mj_form_" are input field IDs set by the card builder.
320
+ */
321
+ extractFormFields(formValues) {
322
+ const fields = [];
323
+ for (const [key, val] of Object.entries(formValues)) {
324
+ if (key.startsWith('mj_form_') && val != null && val !== '') {
325
+ const questionId = key.replace('mj_form_', '');
326
+ const strValue = String(val);
327
+ fields.push({
328
+ name: questionId,
329
+ value: strValue,
330
+ label: questionId,
331
+ displayValue: strValue,
332
+ });
333
+ }
334
+ }
335
+ return fields;
336
+ }
337
+ /**
338
+ * Check if the bot was @mentioned in a Teams activity.
339
+ */
340
+ hasBotMention(activity) {
341
+ const entities = activity.entities ?? [];
342
+ return entities.some(e => e.type === 'mention' &&
343
+ e.mentioned != null &&
344
+ e.mentioned?.id === this.botID);
345
+ }
346
+ // ─── TTL helpers ──────────────────────────────────────────────────
347
+ /** Store a conversation reference with TTL-based eviction. */
348
+ storeConversationRef(conversationId, ref) {
349
+ this.conversationReferences.set(conversationId, { ref, timestamp: Date.now() });
350
+ // Evict expired entries
351
+ const now = Date.now();
352
+ for (const [key, entry] of this.conversationReferences) {
353
+ if (now - entry.timestamp > TeamsAdapter.CONV_REF_TTL_MS) {
354
+ this.conversationReferences.delete(key);
355
+ }
356
+ }
357
+ if (this.conversationReferences.size > TeamsAdapter.CONV_REF_MAX_SIZE) {
358
+ const oldest = [...this.conversationReferences.entries()]
359
+ .sort((a, b) => a[1].timestamp - b[1].timestamp);
360
+ for (const [key] of oldest.slice(0, oldest.length - TeamsAdapter.CONV_REF_MAX_SIZE)) {
361
+ this.conversationReferences.delete(key);
362
+ }
363
+ }
364
+ }
365
+ /** Check if a form activity was recently processed (dedup). */
366
+ isRecentFormActivity(activityId) {
367
+ const timestamp = this.recentFormActivityIds.get(activityId);
368
+ if (timestamp == null)
369
+ return false;
370
+ if (Date.now() - timestamp > TeamsAdapter.FORM_DEDUP_TTL_MS) {
371
+ this.recentFormActivityIds.delete(activityId);
372
+ return false;
373
+ }
374
+ // Clean up expired entries opportunistically
375
+ for (const [key, ts] of this.recentFormActivityIds) {
376
+ if (Date.now() - ts > TeamsAdapter.FORM_DEDUP_TTL_MS) {
377
+ this.recentFormActivityIds.delete(key);
378
+ }
379
+ }
380
+ return true;
381
+ }
382
+ }
383
+ //# sourceMappingURL=TeamsAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamsAdapter.js","sourceRoot":"","sources":["../../src/teams/TeamsAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @module @memberjunction/messaging-adapters
3
+ * @description Microsoft Teams Server Extension — registers Bot Framework webhook
4
+ * route and delegates to TeamsAdapter.
5
+ *
6
+ * This is the entry point for Teams integration. It extends `BaseServerExtension`
7
+ * to plug into MJServer's extension framework, registering a POST webhook endpoint
8
+ * that receives Bot Framework activities.
9
+ *
10
+ * ## Azure Bot Setup
11
+ *
12
+ * 1. Register a bot in the Azure Bot Service
13
+ * 2. Set the messaging endpoint to `{your-server}/webhook/teams`
14
+ * 3. Note the Microsoft App ID and Password
15
+ * 4. Create a Teams app manifest pointing to the bot registration
16
+ * 5. Install the app in your Teams organization
17
+ * 6. Configure the App ID and Password in `mj.config.cjs`
18
+ *
19
+ * ## Configuration
20
+ *
21
+ * ```javascript
22
+ * // mj.config.cjs
23
+ * serverExtensions: [{
24
+ * Enabled: true,
25
+ * DriverClass: 'TeamsMessagingExtension',
26
+ * RootPath: '/webhook/teams',
27
+ * Settings: {
28
+ * DefaultAgentName: 'Sage',
29
+ * ContextUserEmail: 'bot@company.com',
30
+ * MicrosoftAppId: process.env.MICROSOFT_APP_ID,
31
+ * MicrosoftAppPassword: process.env.MICROSOFT_APP_PASSWORD,
32
+ * MaxThreadMessages: 50,
33
+ * StreamingUpdateIntervalMs: 2000,
34
+ * }
35
+ * }]
36
+ * ```
37
+ */
38
+ import { Application } from 'express';
39
+ import { BaseServerExtension, ServerExtensionConfig, ExtensionInitResult, ExtensionHealthResult } from '@memberjunction/server-extensions-core';
40
+ /**
41
+ * Server Extension that registers the Bot Framework webhook route and delegates
42
+ * message handling to the `TeamsAdapter`.
43
+ *
44
+ * Uses the Bot Framework SDK's `CloudAdapter` for authentication and activity
45
+ * processing, which handles JWT token validation automatically.
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // Auto-discovered by MJServer when package is imported and config is present
50
+ * // No manual instantiation needed — just add to mj.config.cjs
51
+ * ```
52
+ */
53
+ export declare class TeamsMessagingExtension extends BaseServerExtension {
54
+ /** The Teams adapter handling message processing. */
55
+ private adapter;
56
+ /** The Bot Framework cloud adapter for JWT validation and activity processing. */
57
+ private cloudAdapterInstance;
58
+ /**
59
+ * Initialize the Teams extension.
60
+ *
61
+ * Creates the Bot Framework `CloudAdapter` for authentication,
62
+ * initializes the `TeamsAdapter`, and registers the webhook route.
63
+ */
64
+ Initialize(app: Application, config: ServerExtensionConfig): Promise<ExtensionInitResult>;
65
+ /**
66
+ * Shut down the Teams extension. Releases the adapter and cloud adapter.
67
+ */
68
+ Shutdown(): Promise<void>;
69
+ /**
70
+ * Health check for the Teams extension.
71
+ * Reports whether the adapter and cloud adapter are initialized.
72
+ */
73
+ HealthCheck(): Promise<ExtensionHealthResult>;
74
+ }
75
+ //# sourceMappingURL=TeamsMessagingExtension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamsMessagingExtension.d.ts","sourceRoot":"","sources":["../../src/teams/TeamsMessagingExtension.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAS/C,OAAO,EACH,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACxB,MAAM,wCAAwC,CAAC;AAIhD;;;;;;;;;;;;GAYG;AACH,qBACa,uBAAwB,SAAQ,mBAAmB;IAC5D,qDAAqD;IACrD,OAAO,CAAC,OAAO,CAA6B;IAE5C,kFAAkF;IAClF,OAAO,CAAC,oBAAoB,CAA6B;IAEzD;;;;;OAKG;IACG,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA+E/F;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,qBAAqB,CAAC;CAUtD"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @module @memberjunction/messaging-adapters
3
+ * @description Microsoft Teams Server Extension — registers Bot Framework webhook
4
+ * route and delegates to TeamsAdapter.
5
+ *
6
+ * This is the entry point for Teams integration. It extends `BaseServerExtension`
7
+ * to plug into MJServer's extension framework, registering a POST webhook endpoint
8
+ * that receives Bot Framework activities.
9
+ *
10
+ * ## Azure Bot Setup
11
+ *
12
+ * 1. Register a bot in the Azure Bot Service
13
+ * 2. Set the messaging endpoint to `{your-server}/webhook/teams`
14
+ * 3. Note the Microsoft App ID and Password
15
+ * 4. Create a Teams app manifest pointing to the bot registration
16
+ * 5. Install the app in your Teams organization
17
+ * 6. Configure the App ID and Password in `mj.config.cjs`
18
+ *
19
+ * ## Configuration
20
+ *
21
+ * ```javascript
22
+ * // mj.config.cjs
23
+ * serverExtensions: [{
24
+ * Enabled: true,
25
+ * DriverClass: 'TeamsMessagingExtension',
26
+ * RootPath: '/webhook/teams',
27
+ * Settings: {
28
+ * DefaultAgentName: 'Sage',
29
+ * ContextUserEmail: 'bot@company.com',
30
+ * MicrosoftAppId: process.env.MICROSOFT_APP_ID,
31
+ * MicrosoftAppPassword: process.env.MICROSOFT_APP_PASSWORD,
32
+ * MaxThreadMessages: 50,
33
+ * StreamingUpdateIntervalMs: 2000,
34
+ * }
35
+ * }]
36
+ * ```
37
+ */
38
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
39
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
40
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
41
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
42
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
43
+ };
44
+ import express from 'express';
45
+ import { RegisterClass } from '@memberjunction/global';
46
+ import { LogError, LogStatus } from '@memberjunction/core';
47
+ import { CloudAdapter, ConfigurationBotFrameworkAuthentication, ActivityTypes, } from 'botbuilder';
48
+ import { BaseServerExtension } from '@memberjunction/server-extensions-core';
49
+ import { TeamsAdapter } from './TeamsAdapter.js';
50
+ /**
51
+ * Server Extension that registers the Bot Framework webhook route and delegates
52
+ * message handling to the `TeamsAdapter`.
53
+ *
54
+ * Uses the Bot Framework SDK's `CloudAdapter` for authentication and activity
55
+ * processing, which handles JWT token validation automatically.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // Auto-discovered by MJServer when package is imported and config is present
60
+ * // No manual instantiation needed — just add to mj.config.cjs
61
+ * ```
62
+ */
63
+ let TeamsMessagingExtension = class TeamsMessagingExtension extends BaseServerExtension {
64
+ constructor() {
65
+ super(...arguments);
66
+ /** The Teams adapter handling message processing. */
67
+ this.adapter = null;
68
+ /** The Bot Framework cloud adapter for JWT validation and activity processing. */
69
+ this.cloudAdapterInstance = null;
70
+ }
71
+ /**
72
+ * Initialize the Teams extension.
73
+ *
74
+ * Creates the Bot Framework `CloudAdapter` for authentication,
75
+ * initializes the `TeamsAdapter`, and registers the webhook route.
76
+ */
77
+ async Initialize(app, config) {
78
+ try {
79
+ const settings = config.Settings;
80
+ const appId = settings.MicrosoftAppId ?? process.env.MICROSOFT_APP_ID ?? '';
81
+ const appPassword = settings.MicrosoftAppPassword ?? process.env.MICROSOFT_APP_PASSWORD ?? '';
82
+ const appTenantId = settings.MicrosoftAppTenantId ?? process.env.MICROSOFT_APP_TENANT_ID ?? '';
83
+ const appType = settings.MicrosoftAppType ?? process.env.MICROSOFT_APP_TYPE ?? (appTenantId ? 'SingleTenant' : 'MultiTenant');
84
+ // Create Bot Framework authentication
85
+ const botFrameworkAuth = new ConfigurationBotFrameworkAuthentication({
86
+ MicrosoftAppId: appId,
87
+ MicrosoftAppPassword: appPassword,
88
+ MicrosoftAppType: appType,
89
+ MicrosoftAppTenantId: appTenantId,
90
+ });
91
+ this.cloudAdapterInstance = new CloudAdapter(botFrameworkAuth);
92
+ // Set up error handler for the cloud adapter
93
+ this.cloudAdapterInstance.onTurnError = async (context, error) => {
94
+ LogError(`Teams Bot Framework error: ${error.message}`, undefined, error);
95
+ await context.sendActivity('Sorry, an error occurred processing your message.');
96
+ };
97
+ // Create and initialize the Teams adapter
98
+ this.adapter = new TeamsAdapter(settings);
99
+ await this.adapter.Initialize();
100
+ // Register the Bot Framework webhook route
101
+ const adapter = this.adapter;
102
+ const cloudAdapter = this.cloudAdapterInstance;
103
+ app.post(config.RootPath, express.json(), async (req, res) => {
104
+ try {
105
+ await cloudAdapter.process(req, res, async (turnContext) => {
106
+ const activityValue = turnContext.activity.value;
107
+ const isFormSubmit = activityValue != null &&
108
+ activityValue['action'] === 'mj:form_submit';
109
+ if (isFormSubmit) {
110
+ // Action.Submit from an Adaptive Card form.
111
+ // Web Chat sends this as a Message; real Teams sends
112
+ // an Invoke. Handle both here, then send InvokeResponse
113
+ // if this was an invoke activity.
114
+ await adapter.HandleFormSubmit(turnContext);
115
+ if (turnContext.activity.type === ActivityTypes.Invoke) {
116
+ await turnContext.sendActivity({
117
+ type: ActivityTypes.InvokeResponse,
118
+ value: { status: 200 },
119
+ });
120
+ }
121
+ }
122
+ else if (turnContext.activity.type === ActivityTypes.Message) {
123
+ const incomingMessage = adapter.MapTeamsActivity(turnContext);
124
+ await adapter.HandleMessage(incomingMessage);
125
+ }
126
+ });
127
+ }
128
+ catch (error) {
129
+ LogError('Error processing Teams webhook:', undefined, error);
130
+ if (!res.headersSent) {
131
+ res.status(500).send('Internal Server Error');
132
+ }
133
+ }
134
+ });
135
+ return {
136
+ Success: true,
137
+ Message: `Teams messaging extension loaded for agent ${settings.DefaultAgentName}`,
138
+ RegisteredRoutes: [`POST ${config.RootPath}`]
139
+ };
140
+ }
141
+ catch (error) {
142
+ const message = error instanceof Error ? error.message : String(error);
143
+ return {
144
+ Success: false,
145
+ Message: `Failed to initialize Teams extension: ${message}`
146
+ };
147
+ }
148
+ }
149
+ /**
150
+ * Shut down the Teams extension. Releases the adapter and cloud adapter.
151
+ */
152
+ async Shutdown() {
153
+ LogStatus('Shutting down Teams messaging extension');
154
+ this.adapter = null;
155
+ this.cloudAdapterInstance = null;
156
+ }
157
+ /**
158
+ * Health check for the Teams extension.
159
+ * Reports whether the adapter and cloud adapter are initialized.
160
+ */
161
+ async HealthCheck() {
162
+ return {
163
+ Healthy: this.adapter !== null && this.cloudAdapterInstance !== null,
164
+ Name: 'TeamsMessagingExtension',
165
+ Details: {
166
+ adapterInitialized: this.adapter !== null,
167
+ cloudAdapterInitialized: this.cloudAdapterInstance !== null
168
+ }
169
+ };
170
+ }
171
+ };
172
+ TeamsMessagingExtension = __decorate([
173
+ RegisterClass(BaseServerExtension, 'TeamsMessagingExtension')
174
+ ], TeamsMessagingExtension);
175
+ export { TeamsMessagingExtension };
176
+ //# sourceMappingURL=TeamsMessagingExtension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamsMessagingExtension.js","sourceRoot":"","sources":["../../src/teams/TeamsMessagingExtension.ts"],"names":[],"mappings":"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"}