@microsoft/agents-hosting-extensions-msteams 1.7.2

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 (143) hide show
  1. package/README.md +147 -0
  2. package/dist/package.json +46 -0
  3. package/dist/src/activity-extensions/index.d.ts +1 -0
  4. package/dist/src/activity-extensions/index.js +8 -0
  5. package/dist/src/activity-extensions/index.js.map +1 -0
  6. package/dist/src/activity-extensions/teamsChannelData.d.ts +12 -0
  7. package/dist/src/activity-extensions/teamsChannelData.js +29 -0
  8. package/dist/src/activity-extensions/teamsChannelData.js.map +1 -0
  9. package/dist/src/app/index.d.ts +1 -0
  10. package/dist/src/app/index.js +20 -0
  11. package/dist/src/app/index.js.map +1 -0
  12. package/dist/src/app/teamsAppExtensions.d.ts +145 -0
  13. package/dist/src/app/teamsAppExtensions.js +201 -0
  14. package/dist/src/app/teamsAppExtensions.js.map +1 -0
  15. package/dist/src/channels/index.d.ts +1 -0
  16. package/dist/src/channels/index.js +20 -0
  17. package/dist/src/channels/index.js.map +1 -0
  18. package/dist/src/channels/teamsChannel.d.ts +100 -0
  19. package/dist/src/channels/teamsChannel.js +210 -0
  20. package/dist/src/channels/teamsChannel.js.map +1 -0
  21. package/dist/src/config/config.d.ts +37 -0
  22. package/dist/src/config/config.js +71 -0
  23. package/dist/src/config/config.js.map +1 -0
  24. package/dist/src/config/index.d.ts +1 -0
  25. package/dist/src/config/index.js +20 -0
  26. package/dist/src/config/index.js.map +1 -0
  27. package/dist/src/errorHelper.d.ts +19 -0
  28. package/dist/src/errorHelper.js +96 -0
  29. package/dist/src/errorHelper.js.map +1 -0
  30. package/dist/src/fileConsents/fileConsent.d.ts +37 -0
  31. package/dist/src/fileConsents/fileConsent.js +79 -0
  32. package/dist/src/fileConsents/fileConsent.js.map +1 -0
  33. package/dist/src/fileConsents/index.d.ts +1 -0
  34. package/dist/src/fileConsents/index.js +20 -0
  35. package/dist/src/fileConsents/index.js.map +1 -0
  36. package/dist/src/graphClientFactory.d.ts +10 -0
  37. package/dist/src/graphClientFactory.js +98 -0
  38. package/dist/src/graphClientFactory.js.map +1 -0
  39. package/dist/src/index.d.ts +20 -0
  40. package/dist/src/index.js +39 -0
  41. package/dist/src/index.js.map +1 -0
  42. package/dist/src/meetings/index.d.ts +1 -0
  43. package/dist/src/meetings/index.js +20 -0
  44. package/dist/src/meetings/index.js.map +1 -0
  45. package/dist/src/meetings/meeting.d.ts +84 -0
  46. package/dist/src/meetings/meeting.js +107 -0
  47. package/dist/src/meetings/meeting.js.map +1 -0
  48. package/dist/src/messageExtensions/index.d.ts +2 -0
  49. package/dist/src/messageExtensions/index.js +24 -0
  50. package/dist/src/messageExtensions/index.js.map +1 -0
  51. package/dist/src/messageExtensions/messageExtension.d.ts +133 -0
  52. package/dist/src/messageExtensions/messageExtension.js +326 -0
  53. package/dist/src/messageExtensions/messageExtension.js.map +1 -0
  54. package/dist/src/messageExtensions/messagingExtensionQuery.d.ts +87 -0
  55. package/dist/src/messageExtensions/messagingExtensionQuery.js +35 -0
  56. package/dist/src/messageExtensions/messagingExtensionQuery.js.map +1 -0
  57. package/dist/src/messages/index.d.ts +1 -0
  58. package/dist/src/messages/index.js +20 -0
  59. package/dist/src/messages/index.js.map +1 -0
  60. package/dist/src/messages/message.d.ts +67 -0
  61. package/dist/src/messages/message.js +129 -0
  62. package/dist/src/messages/message.js.map +1 -0
  63. package/dist/src/models/index.d.ts +1 -0
  64. package/dist/src/models/index.js +20 -0
  65. package/dist/src/models/index.js.map +1 -0
  66. package/dist/src/models/readReceiptInfo.d.ts +27 -0
  67. package/dist/src/models/readReceiptInfo.js +44 -0
  68. package/dist/src/models/readReceiptInfo.js.map +1 -0
  69. package/dist/src/taskModules/index.d.ts +1 -0
  70. package/dist/src/taskModules/index.js +20 -0
  71. package/dist/src/taskModules/index.js.map +1 -0
  72. package/dist/src/taskModules/taskModule.d.ts +42 -0
  73. package/dist/src/taskModules/taskModule.js +102 -0
  74. package/dist/src/taskModules/taskModule.js.map +1 -0
  75. package/dist/src/teams/index.d.ts +1 -0
  76. package/dist/src/teams/index.js +20 -0
  77. package/dist/src/teams/index.js.map +1 -0
  78. package/dist/src/teams/teamsTeam.d.ts +82 -0
  79. package/dist/src/teams/teamsTeam.js +172 -0
  80. package/dist/src/teams/teamsTeam.js.map +1 -0
  81. package/dist/src/teamsActivity.d.ts +15 -0
  82. package/dist/src/teamsActivity.js +5 -0
  83. package/dist/src/teamsActivity.js.map +1 -0
  84. package/dist/src/teamsActivityExtensions.d.ts +53 -0
  85. package/dist/src/teamsActivityExtensions.js +101 -0
  86. package/dist/src/teamsActivityExtensions.js.map +1 -0
  87. package/dist/src/teamsAgentExtension.d.ts +105 -0
  88. package/dist/src/teamsAgentExtension.js +178 -0
  89. package/dist/src/teamsAgentExtension.js.map +1 -0
  90. package/dist/src/teamsApiClientExtensions.d.ts +13 -0
  91. package/dist/src/teamsApiClientExtensions.js +41 -0
  92. package/dist/src/teamsApiClientExtensions.js.map +1 -0
  93. package/dist/src/teamsHeaderPropagation.d.ts +14 -0
  94. package/dist/src/teamsHeaderPropagation.js +35 -0
  95. package/dist/src/teamsHeaderPropagation.js.map +1 -0
  96. package/dist/src/teamsModelExtensions.d.ts +19 -0
  97. package/dist/src/teamsModelExtensions.js +38 -0
  98. package/dist/src/teamsModelExtensions.js.map +1 -0
  99. package/dist/src/teamsProactiveServiceEndpoints.d.ts +15 -0
  100. package/dist/src/teamsProactiveServiceEndpoints.js +21 -0
  101. package/dist/src/teamsProactiveServiceEndpoints.js.map +1 -0
  102. package/dist/src/teamsRouteHandler.d.ts +13 -0
  103. package/dist/src/teamsRouteHandler.js +18 -0
  104. package/dist/src/teamsRouteHandler.js.map +1 -0
  105. package/dist/src/teamsTurnContext.d.ts +64 -0
  106. package/dist/src/teamsTurnContext.js +113 -0
  107. package/dist/src/teamsTurnContext.js.map +1 -0
  108. package/package.json +46 -0
  109. package/src/activity-extensions/index.ts +4 -0
  110. package/src/activity-extensions/teamsChannelData.ts +30 -0
  111. package/src/app/index.ts +4 -0
  112. package/src/app/teamsAppExtensions.ts +369 -0
  113. package/src/channels/index.ts +4 -0
  114. package/src/channels/teamsChannel.ts +229 -0
  115. package/src/config/config.ts +79 -0
  116. package/src/config/index.ts +4 -0
  117. package/src/errorHelper.ts +104 -0
  118. package/src/fileConsents/fileConsent.ts +85 -0
  119. package/src/fileConsents/index.ts +4 -0
  120. package/src/graphClientFactory.ts +127 -0
  121. package/src/index.ts +23 -0
  122. package/src/meetings/index.ts +4 -0
  123. package/src/meetings/meeting.ts +146 -0
  124. package/src/messageExtensions/index.ts +5 -0
  125. package/src/messageExtensions/messageExtension.ts +370 -0
  126. package/src/messageExtensions/messagingExtensionQuery.ts +34 -0
  127. package/src/messages/index.ts +4 -0
  128. package/src/messages/message.ts +148 -0
  129. package/src/models/index.ts +4 -0
  130. package/src/models/readReceiptInfo.ts +50 -0
  131. package/src/taskModules/index.ts +4 -0
  132. package/src/taskModules/taskModule.ts +113 -0
  133. package/src/teams/index.ts +4 -0
  134. package/src/teams/teamsTeam.ts +189 -0
  135. package/src/teamsActivity.ts +19 -0
  136. package/src/teamsActivityExtensions.ts +99 -0
  137. package/src/teamsAgentExtension.ts +205 -0
  138. package/src/teamsApiClientExtensions.ts +47 -0
  139. package/src/teamsHeaderPropagation.ts +32 -0
  140. package/src/teamsModelExtensions.ts +42 -0
  141. package/src/teamsProactiveServiceEndpoints.ts +18 -0
  142. package/src/teamsRouteHandler.ts +22 -0
  143. package/src/teamsTurnContext.ts +125 -0
@@ -0,0 +1,370 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { Activity, ActivityTypes } from '@microsoft/agents-activity'
5
+ import { AgentApplication, RouteHandler, RouteRank, RouteSelector, TurnContext, TurnState } from '@microsoft/agents-hosting'
6
+ import type { AppBasedLinkQuery, MessagingExtensionAction, MessagingExtensionActionResponse, MessagingExtensionQuery, MessagingExtensionResponse } from '@microsoft/teams.api'
7
+ import { z } from 'zod'
8
+ import { messagingExtensionQueryZodSchema } from './messagingExtensionQuery'
9
+ import { TeamsTurnContext } from '../teamsTurnContext'
10
+
11
+ const appBasedLinkQuerySchema = z.object({
12
+ url: z.string().optional(),
13
+ state: z.string().optional()
14
+ }).passthrough()
15
+
16
+ function parseAppBasedLinkQuery (value: unknown): AppBasedLinkQuery | undefined {
17
+ if (value == null) return undefined
18
+ return appBasedLinkQuerySchema.parse(value) as AppBasedLinkQuery
19
+ }
20
+
21
+ function matchesCommandId (context: TurnContext, commandId: string | RegExp): boolean {
22
+ const activityCommandId = (context.activity.value as any)?.commandId
23
+ if (activityCommandId == null) return false
24
+ return typeof commandId === 'string'
25
+ ? activityCommandId === commandId
26
+ : commandId.test(activityCommandId)
27
+ }
28
+
29
+ function matchesPreviewAction (context: TurnContext, previewAction: 'edit' | 'send'): boolean {
30
+ const activityPreviewAction = (context.activity.value as any)?.botMessagePreviewAction
31
+ return typeof activityPreviewAction !== 'string' ||
32
+ activityPreviewAction.length === 0 ||
33
+ activityPreviewAction.toLowerCase() === previewAction
34
+ }
35
+
36
+ function getActivityPreview (action: MessagingExtensionAction): Activity | undefined {
37
+ const activityPreview = action.botActivityPreview?.[0]
38
+ return activityPreview != null ? Activity.fromObject(activityPreview) : undefined
39
+ }
40
+
41
+ type RouteQueryHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, query: MessagingExtensionQuery) => Promise<MessagingExtensionResponse>
42
+ type SelectItemHandler<TState extends TurnState, TData = unknown> = (context: TeamsTurnContext, state: TState, item: TData) => Promise<MessagingExtensionResponse>
43
+ type QueryLinkHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, query: AppBasedLinkQuery | undefined) => Promise<MessagingExtensionResponse>
44
+ type FetchActionHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, action: MessagingExtensionAction) => Promise<MessagingExtensionActionResponse>
45
+ type SubmitActionHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, action: MessagingExtensionAction) => Promise<MessagingExtensionActionResponse>
46
+ type MessagePreviewEditHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, activity: Activity | undefined) => Promise<MessagingExtensionActionResponse>
47
+ type MessagePreviewSendHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, activity: Activity | undefined) => Promise<void>
48
+ type QuerySettingUrlHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState) => Promise<MessagingExtensionResponse>
49
+ type SettingHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, settings: MessagingExtensionQuery) => Promise<MessagingExtensionResponse>
50
+ type CardButtonClickedHandler<TState extends TurnState, TData = unknown> = (context: TeamsTurnContext, state: TState, cardData: TData) => Promise<void>
51
+
52
+ /**
53
+ * Registers handlers for Microsoft Teams message extension invokes.
54
+ *
55
+ * @typeParam TState - The turn state type used by the agent application.
56
+ */
57
+ export class MessageExtension<TState extends TurnState> {
58
+ _app: AgentApplication<TState>
59
+
60
+ /**
61
+ * Creates a Teams message extension route helper.
62
+ *
63
+ * @param app - The agent application that receives the registered routes.
64
+ */
65
+ constructor (app: AgentApplication<TState>) {
66
+ this._app = app
67
+ }
68
+
69
+ /**
70
+ * Registers a handler for compose extension query invokes.
71
+ *
72
+ * @param commandId - Command ID or regular expression used to match the query command.
73
+ * @param handler - Handler invoked with the parsed messaging extension query.
74
+ * @param rank - Optional route rank used for route ordering.
75
+ * @param authHandlers - Optional authorization handlers required by the route.
76
+ * @returns This message extension helper for chaining.
77
+ */
78
+ onQuery (commandId: string | RegExp, handler: RouteQueryHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
79
+ const routeSel: RouteSelector = (context: TurnContext) => {
80
+ return Promise.resolve(
81
+ context.activity.type === ActivityTypes.Invoke &&
82
+ context.activity.channelId === 'msteams' &&
83
+ context.activity.name === 'composeExtension/query' &&
84
+ matchesCommandId(context, commandId)
85
+ )
86
+ }
87
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
88
+ const messageExtensionQuery: MessagingExtensionQuery = messagingExtensionQueryZodSchema.parse(context.activity.value)
89
+ const response: MessagingExtensionResponse = await handler(new TeamsTurnContext(context), state, messageExtensionQuery)
90
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
91
+ invokeResponse.value = { status: 200, body: response }
92
+ await context.sendActivity(invokeResponse)
93
+ }
94
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
95
+ return this
96
+ }
97
+
98
+ /**
99
+ * Registers a handler for compose extension select item invokes.
100
+ *
101
+ * @param handler - Handler invoked with the selected item payload.
102
+ * @param rank - Optional route rank used for route ordering.
103
+ * @param authHandlers - Optional authorization handlers required by the route.
104
+ * @returns This message extension helper for chaining.
105
+ */
106
+ onSelectItem<TData = unknown> (handler: SelectItemHandler<TState, TData>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
107
+ const routeSel: RouteSelector = (context: TurnContext) => {
108
+ return Promise.resolve(
109
+ context.activity.type === ActivityTypes.Invoke &&
110
+ context.activity.channelId === 'msteams' &&
111
+ context.activity.name === 'composeExtension/selectItem'
112
+ )
113
+ }
114
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
115
+ const response: MessagingExtensionResponse = await handler(new TeamsTurnContext(context), state, context.activity.value as TData)
116
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
117
+ invokeResponse.value = { status: 200, body: response }
118
+ await context.sendActivity(invokeResponse)
119
+ }
120
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
121
+ return this
122
+ }
123
+
124
+ /**
125
+ * Registers a handler for app-based link query invokes.
126
+ *
127
+ * @param handler - Handler invoked with the app-based link query payload.
128
+ * @param rank - Optional route rank used for route ordering.
129
+ * @param authHandlers - Optional authorization handlers required by the route.
130
+ * @returns This message extension helper for chaining.
131
+ */
132
+ onQueryLink (handler: QueryLinkHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
133
+ const routeSel: RouteSelector = (context: TurnContext) => {
134
+ return Promise.resolve(
135
+ context.activity.type === ActivityTypes.Invoke &&
136
+ context.activity.channelId === 'msteams' &&
137
+ context.activity.name === 'composeExtension/queryLink'
138
+ )
139
+ }
140
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
141
+ const query = parseAppBasedLinkQuery(context.activity.value)
142
+ const response: MessagingExtensionResponse = await handler(new TeamsTurnContext(context), state, query)
143
+ const invokeResponse = Activity.fromObject({ type: ActivityTypes.InvokeResponse, value: { status: 200, body: response } })
144
+ await context.sendActivity(invokeResponse)
145
+ }
146
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
147
+ return this
148
+ }
149
+
150
+ /**
151
+ * Registers a handler for anonymous app-based link query invokes.
152
+ *
153
+ * @param handler - Handler invoked with the app-based link query payload, when present.
154
+ * @param rank - Optional route rank used for route ordering.
155
+ * @param authHandlers - Optional authorization handlers required by the route.
156
+ * @returns This message extension helper for chaining.
157
+ */
158
+ onAnonymousQueryLink (handler: QueryLinkHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
159
+ const routeSel: RouteSelector = (context: TurnContext) => {
160
+ return Promise.resolve(
161
+ context.activity.type === ActivityTypes.Invoke &&
162
+ context.activity.channelId === 'msteams' &&
163
+ context.activity.name === 'composeExtension/anonymousQueryLink'
164
+ )
165
+ }
166
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
167
+ const query = parseAppBasedLinkQuery(context.activity.value)
168
+ const response: MessagingExtensionResponse = await handler(new TeamsTurnContext(context), state, query)
169
+ const invokeResponse = Activity.fromObject({ type: ActivityTypes.InvokeResponse, value: { status: 200, body: response } })
170
+ await context.sendActivity(invokeResponse)
171
+ }
172
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
173
+ return this
174
+ }
175
+
176
+ /**
177
+ * Registers a handler for compose extension fetch task invokes.
178
+ *
179
+ * @param commandId - Command ID or regular expression used to match the action command.
180
+ * @param handler - Handler invoked with the messaging extension action payload.
181
+ * @param rank - Optional route rank used for route ordering.
182
+ * @param authHandlers - Optional authorization handlers required by the route.
183
+ * @returns This message extension helper for chaining.
184
+ */
185
+ onFetchAction (commandId: string | RegExp, handler: FetchActionHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
186
+ const routeSel: RouteSelector = (context: TurnContext) => {
187
+ return Promise.resolve(
188
+ context.activity.type === ActivityTypes.Invoke &&
189
+ context.activity.channelId === 'msteams' &&
190
+ context.activity.name === 'composeExtension/fetchTask' &&
191
+ matchesCommandId(context, commandId)
192
+ )
193
+ }
194
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
195
+ const actionResponse: MessagingExtensionActionResponse = await handler(new TeamsTurnContext(context), state, context.activity.value as MessagingExtensionAction)
196
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
197
+ invokeResponse.value = { status: 200, body: actionResponse }
198
+ await context.sendActivity(invokeResponse)
199
+ }
200
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
201
+ return this
202
+ }
203
+
204
+ /**
205
+ * Registers a handler for compose extension submit action invokes.
206
+ *
207
+ * @param commandId - Command ID or regular expression used to match the action command.
208
+ * @param handler - Handler invoked with the messaging extension action payload.
209
+ * @param rank - Optional route rank used for route ordering.
210
+ * @param authHandlers - Optional authorization handlers required by the route.
211
+ * @returns This message extension helper for chaining.
212
+ */
213
+ onSubmitAction (commandId: string | RegExp, handler: SubmitActionHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
214
+ const routeSel: RouteSelector = (context: TurnContext) => {
215
+ return Promise.resolve(
216
+ context.activity.type === ActivityTypes.Invoke &&
217
+ context.activity.channelId === 'msteams' &&
218
+ context.activity.name === 'composeExtension/submitAction' &&
219
+ matchesCommandId(context, commandId)
220
+ )
221
+ }
222
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
223
+ const response: MessagingExtensionActionResponse = await handler(new TeamsTurnContext(context), state, context.activity.value as MessagingExtensionAction)
224
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
225
+ invokeResponse.value = { status: 200, body: response }
226
+ await context.sendActivity(invokeResponse)
227
+ }
228
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
229
+ return this
230
+ }
231
+
232
+ /**
233
+ * Registers a handler for message preview edit submit action invokes.
234
+ *
235
+ * @param commandId - Command ID or regular expression used to match the action command.
236
+ * @param handler - Handler invoked with the preview activity, when present.
237
+ * @param rank - Optional route rank used for route ordering.
238
+ * @param authHandlers - Optional authorization handlers required by the route.
239
+ * @returns This message extension helper for chaining.
240
+ */
241
+ onMessagePreviewEdit (commandId: string | RegExp, handler: MessagePreviewEditHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
242
+ const routeSel: RouteSelector = (context: TurnContext) => {
243
+ return Promise.resolve(!!(
244
+ context.activity.type === ActivityTypes.Invoke &&
245
+ context.activity.channelId === 'msteams' &&
246
+ context.activity.name === 'composeExtension/submitAction' &&
247
+ matchesPreviewAction(context, 'edit') &&
248
+ matchesCommandId(context, commandId)
249
+ ))
250
+ }
251
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
252
+ const activity = getActivityPreview(context.activity.value as MessagingExtensionAction)
253
+ const response: MessagingExtensionActionResponse = await handler(new TeamsTurnContext(context), state, activity)
254
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
255
+ invokeResponse.value = { status: 200, body: response }
256
+ await context.sendActivity(invokeResponse)
257
+ }
258
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
259
+ return this
260
+ }
261
+
262
+ /**
263
+ * Registers a handler for message preview send submit action invokes.
264
+ *
265
+ * @param commandId - Command ID or regular expression used to match the action command.
266
+ * @param handler - Handler invoked with the preview activity, when present.
267
+ * @param rank - Optional route rank used for route ordering.
268
+ * @param authHandlers - Optional authorization handlers required by the route.
269
+ * @returns This message extension helper for chaining.
270
+ */
271
+ onMessagePreviewSend (commandId: string | RegExp, handler: MessagePreviewSendHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
272
+ const routeSel: RouteSelector = (context: TurnContext) => {
273
+ return Promise.resolve(!!(
274
+ context.activity.type === ActivityTypes.Invoke &&
275
+ context.activity.channelId === 'msteams' &&
276
+ context.activity.name === 'composeExtension/submitAction' &&
277
+ matchesPreviewAction(context, 'send') &&
278
+ matchesCommandId(context, commandId)
279
+ ))
280
+ }
281
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
282
+ const msgExtensionAction = context.activity.value as MessagingExtensionAction
283
+ const activityPreview = getActivityPreview(msgExtensionAction)
284
+ await handler(new TeamsTurnContext(context), state, activityPreview)
285
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
286
+ invokeResponse.value = { status: 200, body: {} }
287
+ await context.sendActivity(invokeResponse)
288
+ }
289
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
290
+ return this
291
+ }
292
+
293
+ /**
294
+ * Registers a handler for compose extension query setting URL invokes.
295
+ *
296
+ * @param handler - Handler invoked when Teams requests a settings URL.
297
+ * @param rank - Optional route rank used for route ordering.
298
+ * @param authHandlers - Optional authorization handlers required by the route.
299
+ * @returns This message extension helper for chaining.
300
+ */
301
+ onQuerySettingUrl (handler: QuerySettingUrlHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
302
+ const routeSel: RouteSelector = (context: TurnContext) => {
303
+ return Promise.resolve(
304
+ context.activity.type === ActivityTypes.Invoke &&
305
+ context.activity.channelId === 'msteams' &&
306
+ context.activity.name === 'composeExtension/querySettingUrl'
307
+ )
308
+ }
309
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
310
+ const response: MessagingExtensionResponse = await handler(new TeamsTurnContext(context), state)
311
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
312
+ invokeResponse.value = { status: 200, body: response }
313
+ await context.sendActivity(invokeResponse)
314
+ }
315
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
316
+ return this
317
+ }
318
+
319
+ /**
320
+ * Registers a handler for compose extension setting invokes.
321
+ *
322
+ * @param handler - Handler invoked with the messaging extension settings payload.
323
+ * @param rank - Optional route rank used for route ordering.
324
+ * @param authHandlers - Optional authorization handlers required by the route.
325
+ * @returns This message extension helper for chaining.
326
+ */
327
+ onSetting (handler: SettingHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
328
+ const routeSel: RouteSelector = (context: TurnContext) => {
329
+ return Promise.resolve(
330
+ context.activity.type === ActivityTypes.Invoke &&
331
+ context.activity.channelId === 'msteams' &&
332
+ context.activity.name === 'composeExtension/setting'
333
+ )
334
+ }
335
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
336
+ const response: MessagingExtensionResponse = await handler(new TeamsTurnContext(context), state, context.activity.value as MessagingExtensionQuery)
337
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
338
+ invokeResponse.value = { status: 200, body: response }
339
+ await context.sendActivity(invokeResponse)
340
+ }
341
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
342
+ return this
343
+ }
344
+
345
+ /**
346
+ * Registers a handler for card button clicked invokes from message extension cards.
347
+ *
348
+ * @param handler - Handler invoked with the card action payload.
349
+ * @param rank - Optional route rank used for route ordering.
350
+ * @param authHandlers - Optional authorization handlers required by the route.
351
+ * @returns This message extension helper for chaining.
352
+ */
353
+ onCardButtonClicked<TData = unknown> (handler: CardButtonClickedHandler<TState, TData>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
354
+ const routeSel: RouteSelector = (context: TurnContext) => {
355
+ return Promise.resolve(
356
+ context.activity.type === ActivityTypes.Invoke &&
357
+ context.activity.channelId === 'msteams' &&
358
+ context.activity.name === 'composeExtension/onCardButtonClicked'
359
+ )
360
+ }
361
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
362
+ await handler(new TeamsTurnContext(context), state, context.activity.value as TData)
363
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
364
+ invokeResponse.value = { status: 200 }
365
+ await context.sendActivity(invokeResponse)
366
+ }
367
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
368
+ return this
369
+ }
370
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright(c) Microsoft Corporation.All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { z } from 'zod'
7
+ import type { MessagingExtensionQuery } from '@microsoft/teams.api'
8
+
9
+ /**
10
+ * Zod schema for validating MessagingExtensionQuery.
11
+ * @ignore
12
+ */
13
+ export const messagingExtensionQueryZodSchema = z.object({
14
+ commandId: z.string().min(1).optional(),
15
+ parameters: z.array(z.object({
16
+ name: z.string().min(1).optional(),
17
+ value: z.any().optional()
18
+ })).optional(),
19
+ queryOptions: z.object({
20
+ skip: z.number().optional(),
21
+ count: z.number().optional()
22
+ }).optional(),
23
+ state: z.string().min(1).optional()
24
+ }).passthrough()
25
+
26
+ /**
27
+ * Parses the given value as a messaging extension query.
28
+ *
29
+ * @param {unknown} value - The value to parse.
30
+ * @returns {MessagingExtensionQuery} - The parsed messaging extension query.
31
+ */
32
+ export function parseValueMessagingExtensionQuery (value: unknown): MessagingExtensionQuery {
33
+ return messagingExtensionQueryZodSchema.parse(value) as MessagingExtensionQuery
34
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ export * from './message'
@@ -0,0 +1,148 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { Activity, ActivityTypes } from '@microsoft/agents-activity'
5
+ import { AgentApplication, RouteHandler, RouteRank, RouteSelector, TurnContext, TurnState } from '@microsoft/agents-hosting'
6
+ import { parseTeamsChannelData } from '../activity-extensions'
7
+ import type { O365ConnectorCardActionQuery } from '@microsoft/teams.api'
8
+ import { TeamsTurnContext } from '../teamsTurnContext'
9
+ import type { ReadReceiptInfo } from '../models/readReceiptInfo'
10
+ import { createTeamsRouteHandler, TeamsRouteHandler } from '../teamsRouteHandler'
11
+
12
+ type ExecuteActionRouteHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, query: O365ConnectorCardActionQuery) => Promise<void>
13
+ type ReadReceiptHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, data: ReadReceiptInfo) => Promise<void>
14
+
15
+ function equalsIgnoreCase (actual: unknown, expected: string): boolean {
16
+ return typeof actual === 'string' && actual.toLowerCase() === expected.toLowerCase()
17
+ }
18
+
19
+ /**
20
+ * Registers handlers for Microsoft Teams message lifecycle events.
21
+ *
22
+ * @typeParam TState - The turn state type used by the agent application.
23
+ */
24
+ export class Message<TState extends TurnState = TurnState> {
25
+ private _app: AgentApplication<TState>
26
+
27
+ /**
28
+ * Creates a Teams message route helper.
29
+ *
30
+ * @param app - The agent application that receives the registered routes.
31
+ */
32
+ constructor (app: AgentApplication<TState>) {
33
+ this._app = app
34
+ }
35
+
36
+ /**
37
+ * Registers a handler for Teams message edit events.
38
+ *
39
+ * @param handler - Handler invoked for matching message edit activities.
40
+ * @param rank - Optional route rank used for route ordering.
41
+ * @param authHandlers - Optional authorization handlers required by the route.
42
+ * @returns This message helper for chaining.
43
+ */
44
+ onMessageEdit (handler: TeamsRouteHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
45
+ const routeSel: RouteSelector = (context: TurnContext) => {
46
+ const channelData = parseTeamsChannelData(context.activity.channelData)
47
+ return Promise.resolve(
48
+ context.activity.type === ActivityTypes.MessageUpdate &&
49
+ context.activity.channelId === 'msteams' &&
50
+ equalsIgnoreCase(channelData?.eventType, 'editMessage')
51
+ )
52
+ }
53
+ this._app.addRoute(routeSel, createTeamsRouteHandler(handler), false, rank, authHandlers)
54
+ return this
55
+ }
56
+
57
+ /**
58
+ * Registers a handler for Teams soft-delete message events.
59
+ *
60
+ * @param handler - Handler invoked for matching message delete activities.
61
+ * @param rank - Optional route rank used for route ordering.
62
+ * @param authHandlers - Optional authorization handlers required by the route.
63
+ * @returns This message helper for chaining.
64
+ */
65
+ onMessageDelete (handler: TeamsRouteHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
66
+ const routeSel: RouteSelector = (context: TurnContext) => {
67
+ const channelData = parseTeamsChannelData(context.activity.channelData)
68
+ return Promise.resolve(
69
+ context.activity.type === ActivityTypes.MessageDelete &&
70
+ context.activity.channelId === 'msteams' &&
71
+ equalsIgnoreCase(channelData?.eventType, 'softDeleteMessage')
72
+ )
73
+ }
74
+ this._app.addRoute(routeSel, createTeamsRouteHandler(handler), false, rank, authHandlers)
75
+ return this
76
+ }
77
+
78
+ /**
79
+ * Registers a handler for Teams message undelete events.
80
+ *
81
+ * @param handler - Handler invoked for matching message update activities.
82
+ * @param rank - Optional route rank used for route ordering.
83
+ * @param authHandlers - Optional authorization handlers required by the route.
84
+ * @returns This message helper for chaining.
85
+ */
86
+ onMessageUndelete (handler: TeamsRouteHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
87
+ const routeSel: RouteSelector = (context: TurnContext) => {
88
+ const channelData = parseTeamsChannelData(context.activity.channelData)
89
+ return Promise.resolve(
90
+ context.activity.type === ActivityTypes.MessageUpdate &&
91
+ context.activity.channelId === 'msteams' &&
92
+ equalsIgnoreCase(channelData?.eventType, 'undeleteMessage')
93
+ )
94
+ }
95
+ this._app.addRoute(routeSel, createTeamsRouteHandler(handler), false, rank, authHandlers)
96
+ return this
97
+ }
98
+
99
+ /**
100
+ * Registers a handler for Teams read receipt events.
101
+ *
102
+ * @param handler - Handler invoked with read receipt information.
103
+ * @param rank - Optional route rank used for route ordering.
104
+ * @param authHandlers - Optional authorization handlers required by the route.
105
+ * @returns This message helper for chaining.
106
+ */
107
+ onReadReceipt (handler: ReadReceiptHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
108
+ const routeSel: RouteSelector = (context: TurnContext) => {
109
+ return Promise.resolve(
110
+ context.activity.type === ActivityTypes.Event &&
111
+ context.activity.channelId === 'msteams' &&
112
+ equalsIgnoreCase(context.activity.name, 'application/vnd.microsoft.readReceipt')
113
+ )
114
+ }
115
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
116
+ await handler(new TeamsTurnContext(context), state, context.activity.value as ReadReceiptInfo)
117
+ }
118
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
119
+ return this
120
+ }
121
+
122
+ /**
123
+ * Registers a handler for Office 365 connector card execute action invokes.
124
+ *
125
+ * @param handler - Handler invoked with the connector card action query.
126
+ * @param rank - Optional route rank used for route ordering.
127
+ * @param authHandlers - Optional authorization handlers required by the route.
128
+ * @returns This message helper for chaining.
129
+ */
130
+ onExecuteAction (handler: ExecuteActionRouteHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
131
+ const routeSel: RouteSelector = (context: TurnContext) => {
132
+ return Promise.resolve(
133
+ context.activity.type === ActivityTypes.Invoke &&
134
+ context.activity.channelId === 'msteams' &&
135
+ equalsIgnoreCase(context.activity.name, 'actionableMessage/executeAction')
136
+ )
137
+ }
138
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
139
+ const query = (context.activity.value ?? {}) as O365ConnectorCardActionQuery
140
+ await handler(new TeamsTurnContext(context), state, query)
141
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
142
+ invokeResponse.value = { status: 200 }
143
+ await context.sendActivity(invokeResponse)
144
+ }
145
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
146
+ return this
147
+ }
148
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ export * from './readReceiptInfo'
@@ -0,0 +1,50 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ /**
5
+ * Class representing read receipt information.
6
+ */
7
+ export class ReadReceiptInfo {
8
+ /**
9
+ * The ID of the last read message.
10
+ */
11
+ lastReadMessageId: string
12
+
13
+ /**
14
+ * Creates an instance of ReadReceiptInfo.
15
+ * @param {string} [lastReadMessageId=''] - The ID of the last read message.
16
+ */
17
+ constructor (lastReadMessageId: string = '') {
18
+ this.lastReadMessageId = lastReadMessageId
19
+ }
20
+
21
+ /**
22
+ * Checks if a message has been read.
23
+ * @param {string} compareMessageId - The ID of the message to compare.
24
+ * @param {string} lastReadMessageId - The ID of the last read message.
25
+ * @returns {boolean} True if the message has been read, false otherwise.
26
+ */
27
+ static isMessageRead (compareMessageId: string, lastReadMessageId: string): boolean {
28
+ if (compareMessageId.trim().length === 0 || lastReadMessageId.trim().length === 0) {
29
+ return false
30
+ }
31
+
32
+ const compareMessageIdNum = Number(compareMessageId)
33
+ const lastReadMessageIdNum = Number(lastReadMessageId)
34
+
35
+ if (!Number.isFinite(compareMessageIdNum) || !Number.isFinite(lastReadMessageIdNum)) {
36
+ return false
37
+ }
38
+
39
+ return compareMessageIdNum <= lastReadMessageIdNum
40
+ }
41
+
42
+ /**
43
+ * Checks if a message has been read using the instance's last read message ID.
44
+ * @param {string} compareMessageId - The ID of the message to compare.
45
+ * @returns {boolean} True if the message has been read, false otherwise.
46
+ */
47
+ isMessageRead (compareMessageId: string): boolean {
48
+ return ReadReceiptInfo.isMessageRead(compareMessageId, this.lastReadMessageId)
49
+ }
50
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ export * from './taskModule'