@microsoft/agents-hosting-extensions-msteams 1.7.0-beta.10.g0c6864b626

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,113 @@
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 { TaskModuleRequest, TaskModuleResponse } from '@microsoft/teams.api'
7
+ import { TeamsTurnContext } from '../teamsTurnContext'
8
+
9
+ const DEFAULT_TASK_DATA_KEY = 'task'
10
+
11
+ function matchesTaskKeyValue (context: TurnContext, value: string | RegExp, key: string): boolean {
12
+ const taskData = (context.activity.value as any)?.data
13
+ if (!taskData || typeof taskData !== 'object') return false
14
+ const dataValue = taskData[normalizeTaskDataKey(key)]
15
+ if (typeof dataValue !== 'string') return false
16
+ return typeof value === 'string' ? dataValue === value : value.test(dataValue)
17
+ }
18
+
19
+ function isTaskInvoke (context: TurnContext, name: string): boolean {
20
+ return (
21
+ context.activity.type === ActivityTypes.Invoke &&
22
+ context.activity.channelId === 'msteams' &&
23
+ context.activity.name === name &&
24
+ context.activity.value != null
25
+ )
26
+ }
27
+
28
+ function normalizeTaskDataKey (key: string): string {
29
+ return key.trim() || DEFAULT_TASK_DATA_KEY
30
+ }
31
+
32
+ function matchesTaskInvoke (context: TurnContext, name: string, value: string | RegExp | null, key: string): boolean {
33
+ if (!isTaskInvoke(context, name)) {
34
+ return false
35
+ }
36
+
37
+ if (value == null || (typeof value === 'string' && value.trim() === '')) {
38
+ return true
39
+ }
40
+
41
+ return matchesTaskKeyValue(context, value, key)
42
+ }
43
+
44
+ type FetchHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, request: TaskModuleRequest) => Promise<TaskModuleResponse>
45
+ type SubmitHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, request: TaskModuleRequest) => Promise<TaskModuleResponse>
46
+
47
+ /**
48
+ * Registers handlers for Microsoft Teams task module invoke activities.
49
+ *
50
+ * @typeParam TState - The turn state type used by the agent application.
51
+ */
52
+ export class TaskModule<TState extends TurnState> {
53
+ _app: AgentApplication<TState>
54
+
55
+ /**
56
+ * Creates a Teams task module route helper.
57
+ *
58
+ * @param app - The agent application that receives the registered routes.
59
+ */
60
+ constructor (app: AgentApplication<TState>) {
61
+ this._app = app
62
+ }
63
+
64
+ /**
65
+ * Registers a handler for Teams task/fetch invokes.
66
+ *
67
+ * @param value - Optional task data value or regular expression used to match the invoke.
68
+ * @param handler - Handler invoked with the task module request.
69
+ * @param key - Task data key to inspect when matching `value`. Defaults to `task`.
70
+ * @param rank - Optional route rank used for route ordering.
71
+ * @param authHandlers - Optional authorization handlers required by the route.
72
+ * @returns This task module helper for chaining.
73
+ */
74
+ onFetch (value: string | RegExp | null, handler: FetchHandler<TState>, key: string = DEFAULT_TASK_DATA_KEY, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
75
+ const routeSel: RouteSelector = (context: TurnContext) => {
76
+ return Promise.resolve(matchesTaskInvoke(context, 'task/fetch', value, key))
77
+ }
78
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
79
+ const request = context.activity.value as TaskModuleRequest
80
+ const response: TaskModuleResponse = await handler(new TeamsTurnContext(context), state, request)
81
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
82
+ invokeResponse.value = { status: 200, body: response }
83
+ await context.sendActivity(invokeResponse)
84
+ }
85
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
86
+ return this
87
+ }
88
+
89
+ /**
90
+ * Registers a handler for Teams task/submit invokes.
91
+ *
92
+ * @param value - Optional task data value or regular expression used to match the invoke.
93
+ * @param handler - Handler invoked with the task module request.
94
+ * @param key - Task data key to inspect when matching `value`. Defaults to `task`.
95
+ * @param rank - Optional route rank used for route ordering.
96
+ * @param authHandlers - Optional authorization handlers required by the route.
97
+ * @returns This task module helper for chaining.
98
+ */
99
+ onSubmit (value: string | RegExp | null, handler: SubmitHandler<TState>, key: string = DEFAULT_TASK_DATA_KEY, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
100
+ const routeSel: RouteSelector = (context: TurnContext) => {
101
+ return Promise.resolve(matchesTaskInvoke(context, 'task/submit', value, key))
102
+ }
103
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
104
+ const request = context.activity.value as TaskModuleRequest
105
+ const response: TaskModuleResponse = await handler(new TeamsTurnContext(context), state, request)
106
+ const invokeResponse = new Activity(ActivityTypes.InvokeResponse)
107
+ invokeResponse.value = { status: 200, body: response }
108
+ await context.sendActivity(invokeResponse)
109
+ }
110
+ this._app.addRoute(routeSel, routeHandler, true, rank, authHandlers)
111
+ return this
112
+ }
113
+ }
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ export * from './teamsTeam'
@@ -0,0 +1,189 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { 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 { TeamInfo } from '@microsoft/teams.api'
8
+ import { TeamsTurnContext } from '../teamsTurnContext'
9
+
10
+ const TEAM_ARCHIVED_EVENT = 'teamArchived'
11
+ const TEAM_UNARCHIVED_EVENT = 'teamUnarchived'
12
+ const TEAM_RENAMED_EVENT = 'teamRenamed'
13
+ const TEAM_RESTORED_EVENT = 'teamRestored'
14
+ const TEAM_DELETED_EVENT = 'teamDeleted'
15
+ const TEAM_HARD_DELETED_EVENT = 'teamHardDeleted'
16
+
17
+ type TeamUpdateHandler<TState extends TurnState> = (context: TeamsTurnContext, state: TState, data: TeamInfo) => Promise<void>
18
+
19
+ function isTeamUpdateEvent (context: TurnContext, eventType?: string): boolean {
20
+ const channelData = parseTeamsChannelData(context.activity.channelData)
21
+ const actualEventType = typeof channelData?.eventType === 'string' ? channelData.eventType.toLowerCase() : undefined
22
+ const expectedEventType = eventType?.toLowerCase()
23
+
24
+ return (
25
+ context.activity.type === ActivityTypes.ConversationUpdate &&
26
+ context.activity.channelId === 'msteams' &&
27
+ channelData?.team != null &&
28
+ (
29
+ expectedEventType != null
30
+ ? actualEventType === expectedEventType
31
+ : actualEventType?.startsWith('team') === true
32
+ )
33
+ )
34
+ }
35
+
36
+ function getTeamInfo (context: TurnContext): TeamInfo {
37
+ return parseTeamsChannelData(context.activity.channelData).team as TeamInfo
38
+ }
39
+
40
+ /**
41
+ * Registers handlers for Microsoft Teams team lifecycle events.
42
+ *
43
+ * @typeParam TState - The turn state type used by the agent application.
44
+ */
45
+ export class TeamsTeam<TState extends TurnState = TurnState> {
46
+ private _app: AgentApplication<TState>
47
+
48
+ /**
49
+ * Creates a Teams team route helper.
50
+ *
51
+ * @param app - The agent application that receives the registered routes.
52
+ */
53
+ constructor (app: AgentApplication<TState>) {
54
+ this._app = app
55
+ }
56
+
57
+ /**
58
+ * Registers a handler for any Teams team update event.
59
+ *
60
+ * @param handler - Handler invoked with the Teams turn context, turn state, and team information.
61
+ * @param rank - Optional route rank used for route ordering.
62
+ * @param authHandlers - Optional authorization handlers required by the route.
63
+ * @returns This team helper for chaining.
64
+ */
65
+ onTeamEventReceived (handler: TeamUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
66
+ const routeSel: RouteSelector = (context: TurnContext) => {
67
+ return Promise.resolve(isTeamUpdateEvent(context))
68
+ }
69
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
70
+ await handler(new TeamsTurnContext(context), state, getTeamInfo(context))
71
+ }
72
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
73
+ return this
74
+ }
75
+
76
+ /**
77
+ * Registers a handler for Teams team archived events.
78
+ *
79
+ * @param handler - Handler invoked with the archived team information.
80
+ * @param rank - Optional route rank used for route ordering.
81
+ * @param authHandlers - Optional authorization handlers required by the route.
82
+ * @returns This team helper for chaining.
83
+ */
84
+ onArchived (handler: TeamUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
85
+ const routeSel: RouteSelector = (context: TurnContext) => {
86
+ return Promise.resolve(isTeamUpdateEvent(context, TEAM_ARCHIVED_EVENT))
87
+ }
88
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
89
+ await handler(new TeamsTurnContext(context), state, getTeamInfo(context))
90
+ }
91
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
92
+ return this
93
+ }
94
+
95
+ /**
96
+ * Registers a handler for Teams team unarchived events.
97
+ *
98
+ * @param handler - Handler invoked with the unarchived team information.
99
+ * @param rank - Optional route rank used for route ordering.
100
+ * @param authHandlers - Optional authorization handlers required by the route.
101
+ * @returns This team helper for chaining.
102
+ */
103
+ onUnarchived (handler: TeamUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
104
+ const routeSel: RouteSelector = (context: TurnContext) => {
105
+ return Promise.resolve(isTeamUpdateEvent(context, TEAM_UNARCHIVED_EVENT))
106
+ }
107
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
108
+ await handler(new TeamsTurnContext(context), state, getTeamInfo(context))
109
+ }
110
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
111
+ return this
112
+ }
113
+
114
+ /**
115
+ * Registers a handler for Teams team renamed events.
116
+ *
117
+ * @param handler - Handler invoked with the renamed team information.
118
+ * @param rank - Optional route rank used for route ordering.
119
+ * @param authHandlers - Optional authorization handlers required by the route.
120
+ * @returns This team helper for chaining.
121
+ */
122
+ onRenamed (handler: TeamUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
123
+ const routeSel: RouteSelector = (context: TurnContext) => {
124
+ return Promise.resolve(isTeamUpdateEvent(context, TEAM_RENAMED_EVENT))
125
+ }
126
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
127
+ await handler(new TeamsTurnContext(context), state, getTeamInfo(context))
128
+ }
129
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
130
+ return this
131
+ }
132
+
133
+ /**
134
+ * Registers a handler for Teams team restored events.
135
+ *
136
+ * @param handler - Handler invoked with the restored team information.
137
+ * @param rank - Optional route rank used for route ordering.
138
+ * @param authHandlers - Optional authorization handlers required by the route.
139
+ * @returns This team helper for chaining.
140
+ */
141
+ onRestored (handler: TeamUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
142
+ const routeSel: RouteSelector = (context: TurnContext) => {
143
+ return Promise.resolve(isTeamUpdateEvent(context, TEAM_RESTORED_EVENT))
144
+ }
145
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
146
+ await handler(new TeamsTurnContext(context), state, getTeamInfo(context))
147
+ }
148
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
149
+ return this
150
+ }
151
+
152
+ /**
153
+ * Registers a handler for Teams team deleted events.
154
+ *
155
+ * @param handler - Handler invoked with the deleted team information.
156
+ * @param rank - Optional route rank used for route ordering.
157
+ * @param authHandlers - Optional authorization handlers required by the route.
158
+ * @returns This team helper for chaining.
159
+ */
160
+ onDeleted (handler: TeamUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
161
+ const routeSel: RouteSelector = (context: TurnContext) => {
162
+ return Promise.resolve(isTeamUpdateEvent(context, TEAM_DELETED_EVENT))
163
+ }
164
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
165
+ await handler(new TeamsTurnContext(context), state, getTeamInfo(context))
166
+ }
167
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
168
+ return this
169
+ }
170
+
171
+ /**
172
+ * Registers a handler for Teams team hard-deleted events.
173
+ *
174
+ * @param handler - Handler invoked with the hard-deleted team information.
175
+ * @param rank - Optional route rank used for route ordering.
176
+ * @param authHandlers - Optional authorization handlers required by the route.
177
+ * @returns This team helper for chaining.
178
+ */
179
+ onHardDeleted (handler: TeamUpdateHandler<TState>, rank: number = RouteRank.Unspecified, authHandlers: string[] = []) {
180
+ const routeSel: RouteSelector = (context: TurnContext) => {
181
+ return Promise.resolve(isTeamUpdateEvent(context, TEAM_HARD_DELETED_EVENT))
182
+ }
183
+ const routeHandler: RouteHandler<TState> = async (context: TurnContext, state: TState) => {
184
+ await handler(new TeamsTurnContext(context), state, getTeamInfo(context))
185
+ }
186
+ this._app.addRoute(routeSel, routeHandler, false, rank, authHandlers)
187
+ return this
188
+ }
189
+ }
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import type { Activity } from '@microsoft/agents-activity'
5
+ import type { ChannelData } from '@microsoft/teams.api'
6
+
7
+ /**
8
+ * A Teams activity whose channel-specific payload uses the Microsoft Teams API model.
9
+ *
10
+ * @remarks
11
+ * This is a type-only specialization of {@link Activity}. Teams activities keep
12
+ * their original runtime identity; no activity conversion or cloning occurs.
13
+ */
14
+ export interface TeamsActivity extends Activity {
15
+ /**
16
+ * Channel-specific data for the Teams activity.
17
+ */
18
+ channelData?: ChannelData
19
+ }
@@ -0,0 +1,99 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { Activity } from '@microsoft/agents-activity'
5
+ import type { ChannelData, OnBehalfOf } from '@microsoft/teams.api'
6
+ import { parseTeamsChannelData } from './activity-extensions'
7
+
8
+ /**
9
+ * Gets the Teams selected channel ID from the activity's channel data settings.
10
+ *
11
+ * @param activity - Activity containing Teams channel data.
12
+ * @returns The selected channel ID, if present.
13
+ */
14
+ export function teamsGetSelectedChannelId (activity: Activity): string | undefined {
15
+ const channelData = parseTeamsChannelData(activity.channelData)
16
+ return (channelData as any)?.settings?.selectedChannel?.id
17
+ }
18
+
19
+ /**
20
+ * Gets the Teams channel ID from the activity's channel data.
21
+ *
22
+ * @param activity - Activity containing Teams channel data.
23
+ * @returns The Teams channel ID, if present.
24
+ */
25
+ export function teamsGetChannelId (activity: Activity): string | undefined {
26
+ const channelData = parseTeamsChannelData(activity.channelData)
27
+ return (channelData as any)?.channel?.id
28
+ }
29
+
30
+ /**
31
+ * Gets the Teams meeting info from the activity's channel data.
32
+ *
33
+ * @param activity - Activity containing Teams channel data.
34
+ * @returns Teams meeting information, if present.
35
+ */
36
+ export function teamsGetMeetingInfo (activity: Activity): ChannelData['meeting'] | undefined {
37
+ const channelData = parseTeamsChannelData(activity.channelData)
38
+ return channelData?.meeting
39
+ }
40
+
41
+ /**
42
+ * Gets the Teams team info from the activity's channel data.
43
+ *
44
+ * @param activity - Activity containing Teams channel data.
45
+ * @returns Teams team information, if present.
46
+ */
47
+ export function teamsGetTeamInfo (activity: Activity): ChannelData['team'] | undefined {
48
+ const channelData = parseTeamsChannelData(activity.channelData)
49
+ return channelData?.team
50
+ }
51
+
52
+ /**
53
+ * Configures the activity to generate a notification within Teams.
54
+ * @param activity - The activity to configure.
55
+ * @param alertInMeeting - If true, renders a popup in meeting chat as well as the chat thread.
56
+ * @param externalResourceUrl - URL to external resource (must be in manifest's valid domains).
57
+ */
58
+ export function teamsNotifyUser (activity: Activity, alertInMeeting: boolean = false, externalResourceUrl?: string): void {
59
+ if (!activity.channelData || typeof activity.channelData !== 'object') {
60
+ activity.channelData = {}
61
+ }
62
+ const channelData = activity.channelData as Record<string, unknown>
63
+ channelData.notification = {
64
+ alert: !alertInMeeting,
65
+ alertInMeeting,
66
+ ...(externalResourceUrl != null && { externalResourceUrl })
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Gets the Teams OnBehalfOf list from the activity's channel data.
72
+ *
73
+ * @param activity - Activity containing Teams channel data.
74
+ * @returns The Teams on-behalf-of entries, if present.
75
+ */
76
+ export function teamsGetTeamOnBehalfOf (activity: Activity): OnBehalfOf[] | undefined {
77
+ const channelData = parseTeamsChannelData(activity.channelData)
78
+ return (channelData as any)?.onBehalfOf
79
+ }
80
+
81
+ /**
82
+ * Adds the Teams feedback loop flag to the activity's channel data.
83
+ * Returns false if channel data is already set.
84
+ *
85
+ * @param activity - The activity to configure.
86
+ * @param feedbackLoopType - The feedback loop type value. Defaults to "default".
87
+ * @returns True when feedback loop channel data was added; otherwise false.
88
+ */
89
+ export function teamsEnableFeedbackLoop (activity: Activity, feedbackLoopType: string = 'default'): boolean {
90
+ if (activity.channelData != null) {
91
+ return false
92
+ }
93
+ activity.channelData = {
94
+ feedbackLoop: {
95
+ type: feedbackLoopType
96
+ }
97
+ }
98
+ return true
99
+ }
@@ -0,0 +1,205 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { ExceptionHelper } from '@microsoft/agents-activity'
5
+ import { Client as GraphClient } from '@microsoft/microsoft-graph-client'
6
+ import { AgentApplication, AgentExtension, type Connections, TurnContext, TurnState } from '@microsoft/agents-hosting'
7
+ import { Client as TeamsClient } from '@microsoft/teams.api'
8
+ import { parseTeamsChannelData } from './activity-extensions'
9
+ import { TeamsConfig } from './config/config'
10
+ import { FileConsent } from './fileConsents/fileConsent'
11
+ import { Meeting } from './meetings/meeting'
12
+ import { Message } from './messages/message'
13
+ import { MessageExtension } from './messageExtensions/messageExtension'
14
+ import { TaskModule } from './taskModules/taskModule'
15
+ import { TeamsChannel } from './channels/teamsChannel'
16
+ import { TeamsTeam } from './teams/teamsTeam'
17
+ import { setTeamsApiClient } from './teamsApiClientExtensions'
18
+ import { applyTeamsHeaderPropagation } from './teamsHeaderPropagation'
19
+ import { TeamsTurnContext } from './teamsTurnContext'
20
+ import { createAppGraphClient, createUserGraphClient } from './graphClientFactory'
21
+ import { Errors } from './errorHelper'
22
+
23
+ const DEFAULT_GRAPH_BASE_URL = 'https://graph.microsoft.com/v1.0'
24
+
25
+ /**
26
+ * Adds Microsoft Teams-specific routing, context helpers, and API clients to an agent application.
27
+ *
28
+ * Register an instance with `AgentApplication.registerExtension` to configure handlers for Teams
29
+ * events, message extensions, task modules, file consent flows, and related Teams capabilities.
30
+ *
31
+ * @typeParam TState - The turn state type used by the agent application.
32
+ */
33
+ export class TeamsAgentExtension<TState extends TurnState = TurnState> extends AgentExtension<TState> {
34
+ private _app: AgentApplication<TState>
35
+ private _meetings: Meeting<TState>
36
+ private _messageExtensions: MessageExtension<TState>
37
+ private _taskModules: TaskModule<TState>
38
+ private _channels: TeamsChannel<TState>
39
+ private _teams: TeamsTeam<TState>
40
+ private _messages: Message<TState>
41
+ private _fileConsent: FileConsent<TState>
42
+ private _config: TeamsConfig<TState>
43
+
44
+ /**
45
+ * Creates a new Teams extension for the provided agent application.
46
+ *
47
+ * The extension configures Teams header propagation and prepares a Teams API client for each
48
+ * incoming Teams turn.
49
+ *
50
+ * @param app - The agent application to extend with Teams capabilities.
51
+ */
52
+ constructor (app: AgentApplication<TState>) {
53
+ super('msteams')
54
+ this._app = app
55
+ this._meetings = new Meeting(app)
56
+ this._messageExtensions = new MessageExtension(app)
57
+ this._taskModules = new TaskModule(app)
58
+ this._channels = new TeamsChannel(app)
59
+ this._teams = new TeamsTeam(app)
60
+ this._messages = new Message(app)
61
+ this._fileConsent = new FileConsent(app)
62
+ this._config = new TeamsConfig(app)
63
+
64
+ const headerPropagation = this._app.options.headerPropagation
65
+ this._app.options.headerPropagation = (headers) => {
66
+ headerPropagation?.(headers)
67
+ applyTeamsHeaderPropagation(headers)
68
+ }
69
+
70
+ this._app.onTurn('beforeTurn', async (context) => {
71
+ if (context.activity.channelId === this.channelId) {
72
+ setTeamsApiClient(context, this.channelId)
73
+ try {
74
+ context.activity.channelData = parseTeamsChannelData(context.activity.channelData)
75
+ } catch {
76
+ // ignore parse errors for unexpected channelData payloads
77
+ }
78
+ }
79
+ return true
80
+ })
81
+ }
82
+
83
+ /**
84
+ * Gets the route registration helper for Teams meeting events.
85
+ */
86
+ public get meetings (): Meeting<TState> {
87
+ return this._meetings
88
+ }
89
+
90
+ /**
91
+ * Gets the route registration helper for Teams message extension activities.
92
+ */
93
+ public get messageExtensions (): MessageExtension<TState> {
94
+ return this._messageExtensions
95
+ }
96
+
97
+ /**
98
+ * Gets the route registration helper for Teams task module invoke activities.
99
+ */
100
+ public get taskModules (): TaskModule<TState> {
101
+ return this._taskModules
102
+ }
103
+
104
+ /**
105
+ * Gets the route registration helper for Teams channel events.
106
+ */
107
+ public get channels (): TeamsChannel<TState> {
108
+ return this._channels
109
+ }
110
+
111
+ /**
112
+ * Gets the route registration helper for Teams team events.
113
+ */
114
+ public get teams (): TeamsTeam<TState> {
115
+ return this._teams
116
+ }
117
+
118
+ /**
119
+ * Gets the route registration helper for Teams message lifecycle events.
120
+ */
121
+ public get messages (): Message<TState> {
122
+ return this._messages
123
+ }
124
+
125
+ /**
126
+ * Gets the route registration helper for Teams file consent card actions.
127
+ */
128
+ public get fileConsent (): FileConsent<TState> {
129
+ return this._fileConsent
130
+ }
131
+
132
+ /**
133
+ * Gets the route registration helper for Teams app configuration invokes.
134
+ */
135
+ public get config (): TeamsConfig<TState> {
136
+ return this._config
137
+ }
138
+
139
+ /**
140
+ * Gets the Teams API client associated with the current turn.
141
+ *
142
+ * @param context - The turn context for the current Teams activity.
143
+ * @returns The Teams API client stored on the turn.
144
+ * @throws If the current turn has not been initialized with a Teams API client.
145
+ */
146
+ public getTeamsClient (context: TurnContext): TeamsClient {
147
+ return new TeamsTurnContext(context).client
148
+ }
149
+
150
+ /**
151
+ * Creates a Microsoft Graph client that obtains access tokens through the agent authorization system.
152
+ *
153
+ * @param context - The turn context used to acquire the user token.
154
+ * @param handlerName - Optional authorization handler name. Required when multiple handlers are configured.
155
+ * @param graphBaseUrl - Optional Graph base URL. Defaults to Microsoft Graph v1.0.
156
+ * @returns A Microsoft Graph client configured with the resolved authentication provider.
157
+ */
158
+ public getGraphClient (context: TurnContext, handlerName?: string, graphBaseUrl: string = DEFAULT_GRAPH_BASE_URL): GraphClient {
159
+ if (!context) {
160
+ throw ExceptionHelper.generateException(Error, Errors.TeamsGraphParameterRequired, undefined, { parameterName: 'context' })
161
+ }
162
+
163
+ return createUserGraphClient(this._app.authorization, context, handlerName, graphBaseUrl)
164
+ }
165
+
166
+ /**
167
+ * Creates a Microsoft Graph client that obtains an app-only token from the connection resolved for the current turn.
168
+ *
169
+ * @param context - The turn context used to resolve the token connection.
170
+ * @param graphBaseUrl - Optional Graph base URL. Defaults to Microsoft Graph v1.0.
171
+ * @returns A Microsoft Graph client configured with application permissions.
172
+ */
173
+ public getAppGraphClient (context: TurnContext, graphBaseUrl: string = DEFAULT_GRAPH_BASE_URL): GraphClient {
174
+ if (!context) {
175
+ throw ExceptionHelper.generateException(Error, Errors.TeamsGraphParameterRequired, undefined, { parameterName: 'context' })
176
+ }
177
+
178
+ const tokenProvider = this.getConnections().getTokenProviderFromActivity(context.identity, context.activity)
179
+ return createAppGraphClient(tokenProvider, graphBaseUrl)
180
+ }
181
+
182
+ /**
183
+ * Creates a Microsoft Graph client that obtains an app-only token from a named connection.
184
+ *
185
+ * @param connectionName - The configured token connection name.
186
+ * @param graphBaseUrl - Optional Graph base URL. Defaults to Microsoft Graph v1.0.
187
+ * @returns A Microsoft Graph client configured with application permissions.
188
+ */
189
+ public getAppGraphClientForConnection (connectionName: string, graphBaseUrl: string = DEFAULT_GRAPH_BASE_URL): GraphClient {
190
+ if (!connectionName) {
191
+ throw ExceptionHelper.generateException(Error, Errors.TeamsGraphParameterRequired, undefined, { parameterName: 'connectionName' })
192
+ }
193
+
194
+ return createAppGraphClient(this.getConnections().getConnection(connectionName), graphBaseUrl)
195
+ }
196
+
197
+ private getConnections (): Connections {
198
+ const connections = this._app.options.connections ?? this._app.adapter.connectionManager
199
+ if (!connections) {
200
+ throw ExceptionHelper.generateException(Error, Errors.TeamsGraphConnectionsNotConfigured)
201
+ }
202
+
203
+ return connections
204
+ }
205
+ }
@@ -0,0 +1,47 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { ExceptionHelper } from '@microsoft/agents-activity'
5
+ import { ConnectorClient, TurnContext } from '@microsoft/agents-hosting'
6
+ import { Client as TeamsClient } from '@microsoft/teams.api'
7
+ import { Errors } from './errorHelper'
8
+
9
+ /**
10
+ * Turn state key used to store the Teams API client for the current turn.
11
+ */
12
+ export const TeamsClientKey = Symbol('TeamsClient')
13
+
14
+ /**
15
+ * Creates and stores a Teams API client for the current Teams turn.
16
+ *
17
+ * @param context - Turn context whose turn state should receive the Teams client.
18
+ * @param channelId - Teams channel ID to match before creating the client. Defaults to `msteams`.
19
+ * @throws If the connector client or service URL required to create the Teams client is missing.
20
+ */
21
+ export function setTeamsApiClient (context: TurnContext, channelId: string = 'msteams'): void {
22
+ if (context.activity.channelId !== channelId || context.turnState.has(TeamsClientKey)) {
23
+ return
24
+ }
25
+
26
+ const connectorClient = context.turnState.get<ConnectorClient>(context.adapter.ConnectorClientKey)
27
+ const serviceUrl = context.activity.serviceUrl ?? connectorClient?.httpClient.baseURL
28
+
29
+ if (!connectorClient) {
30
+ throw ExceptionHelper.generateException(Error, Errors.TeamsApiClientSetupFailed, undefined, { missing: 'ConnectorClient in turnState' })
31
+ }
32
+
33
+ if (!serviceUrl) {
34
+ throw ExceptionHelper.generateException(Error, Errors.TeamsApiClientSetupFailed, undefined, { missing: 'activity.serviceUrl and ConnectorClient baseURL' })
35
+ }
36
+
37
+ context.turnState.set(
38
+ TeamsClientKey,
39
+ new TeamsClient(serviceUrl, {
40
+ headers: getClientHeaders(connectorClient)
41
+ })
42
+ )
43
+ }
44
+
45
+ function getClientHeaders (connectorClient: ConnectorClient): Record<string, string> {
46
+ return { ...connectorClient.httpClient.defaultHeaders }
47
+ }