@microsoft/agents-hosting 0.2.14 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +17 -1
  2. package/dist/src/app/agentApplication.d.ts +27 -15
  3. package/dist/src/app/agentApplication.js +36 -31
  4. package/dist/src/app/agentApplication.js.map +1 -1
  5. package/dist/src/app/agentApplicationBuilder.d.ts +3 -4
  6. package/dist/src/app/agentApplicationBuilder.js +7 -7
  7. package/dist/src/app/agentApplicationBuilder.js.map +1 -1
  8. package/dist/src/app/agentApplicationOptions.d.ts +26 -2
  9. package/dist/src/app/appRoute.d.ts +6 -0
  10. package/dist/src/app/attachmentDownloader.d.ts +18 -0
  11. package/dist/src/app/attachmentDownloader.js +18 -0
  12. package/dist/src/app/attachmentDownloader.js.map +1 -1
  13. package/dist/src/app/conversationUpdateEvents.d.ts +6 -0
  14. package/dist/src/app/index.d.ts +1 -1
  15. package/dist/src/app/index.js +1 -1
  16. package/dist/src/app/index.js.map +1 -1
  17. package/dist/src/app/inputFileDownloader.d.ts +22 -0
  18. package/dist/src/app/oauth/authorization.d.ts +87 -0
  19. package/dist/src/app/oauth/authorization.js +135 -0
  20. package/dist/src/app/oauth/authorization.js.map +1 -0
  21. package/dist/src/app/routeHandler.d.ts +8 -0
  22. package/dist/src/app/routeSelector.d.ts +9 -0
  23. package/dist/src/app/turnState.d.ts +128 -15
  24. package/dist/src/app/turnState.js +114 -16
  25. package/dist/src/app/turnState.js.map +1 -1
  26. package/dist/src/auth/authConfiguration.d.ts +24 -0
  27. package/dist/src/auth/authConfiguration.js.map +1 -1
  28. package/dist/src/auth/request.d.ts +12 -0
  29. package/dist/src/baseAdapter.d.ts +17 -0
  30. package/dist/src/baseAdapter.js +17 -0
  31. package/dist/src/baseAdapter.js.map +1 -1
  32. package/dist/src/cards/cardFactory.d.ts +3 -0
  33. package/dist/src/cards/cardFactory.js +3 -0
  34. package/dist/src/cards/cardFactory.js.map +1 -1
  35. package/dist/src/cards/o365ConnectorCardActionBase.d.ts +8 -0
  36. package/dist/src/oauth/oAuthFlow.d.ts +32 -3
  37. package/dist/src/oauth/oAuthFlow.js +38 -14
  38. package/dist/src/oauth/oAuthFlow.js.map +1 -1
  39. package/dist/src/oauth/userTokenClient.d.ts +2 -2
  40. package/dist/src/oauth/userTokenClient.js +3 -3
  41. package/dist/src/oauth/userTokenClient.js.map +1 -1
  42. package/dist/src/state/agentStatePropertyAccesor.d.ts +1 -1
  43. package/dist/src/state/agentStatePropertyAccesor.js +1 -1
  44. package/dist/src/statusCodes.d.ts +39 -0
  45. package/dist/src/statusCodes.js +39 -0
  46. package/dist/src/statusCodes.js.map +1 -1
  47. package/dist/src/storage/fileStorage.d.ts +9 -0
  48. package/dist/src/storage/fileStorage.js +62 -0
  49. package/dist/src/storage/fileStorage.js.map +1 -0
  50. package/dist/src/storage/index.d.ts +1 -0
  51. package/dist/src/storage/index.js +1 -0
  52. package/dist/src/storage/index.js.map +1 -1
  53. package/dist/src/tokenResponseEventName.d.ts +3 -0
  54. package/dist/src/tokenResponseEventName.js +3 -0
  55. package/dist/src/tokenResponseEventName.js.map +1 -1
  56. package/package.json +4 -4
  57. package/src/app/agentApplication.ts +36 -32
  58. package/src/app/agentApplicationBuilder.ts +8 -8
  59. package/src/app/agentApplicationOptions.ts +33 -2
  60. package/src/app/appRoute.ts +7 -0
  61. package/src/app/attachmentDownloader.ts +18 -0
  62. package/src/app/conversationUpdateEvents.ts +6 -0
  63. package/src/app/index.ts +1 -1
  64. package/src/app/inputFileDownloader.ts +24 -0
  65. package/src/app/oauth/authorization.ts +162 -0
  66. package/src/app/routeHandler.ts +8 -0
  67. package/src/app/routeSelector.ts +9 -0
  68. package/src/app/turnState.ts +129 -33
  69. package/src/auth/authConfiguration.ts +32 -1
  70. package/src/auth/request.ts +15 -0
  71. package/src/baseAdapter.ts +18 -0
  72. package/src/cards/cardFactory.ts +3 -0
  73. package/src/cards/o365ConnectorCardActionBase.ts +8 -0
  74. package/src/oauth/oAuthFlow.ts +59 -18
  75. package/src/oauth/userTokenClient.ts +4 -4
  76. package/src/state/agentStatePropertyAccesor.ts +1 -1
  77. package/src/statusCodes.ts +51 -0
  78. package/src/storage/fileStorage.ts +59 -0
  79. package/src/storage/index.ts +1 -0
  80. package/src/tokenResponseEventName.ts +3 -0
  81. package/dist/src/app/oauth/userIdentity.d.ts +0 -43
  82. package/dist/src/app/oauth/userIdentity.js +0 -54
  83. package/dist/src/app/oauth/userIdentity.js.map +0 -1
  84. package/src/app/oauth/userIdentity.ts +0 -78
@@ -15,8 +15,7 @@ import { AppRoute } from './appRoute'
15
15
  import { TurnContext } from '../turnContext'
16
16
  import { ResourceResponse } from '../connector-client'
17
17
  import { debug } from '../logger'
18
- import { UserIdentity } from './oauth/userIdentity'
19
- import { MemoryStorage } from '../storage'
18
+ import { Authorization } from './oauth/authorization'
20
19
 
21
20
  const logger = debug('agents:agent-application')
22
21
 
@@ -46,14 +45,14 @@ export class AgentApplication<TState extends TurnState> {
46
45
  protected readonly _beforeTurn: ApplicationEventHandler<TState>[] = []
47
46
  protected readonly _afterTurn: ApplicationEventHandler<TState>[] = []
48
47
  private readonly _adapter?: BaseAdapter
48
+ private readonly _authorization?: Authorization
49
49
  private _typingTimer: any
50
- private readonly _userIdentity?: UserIdentity
51
50
 
52
51
  public constructor (options?: Partial<AgentApplicationOptions<TState>>) {
53
52
  this._options = {
54
53
  ...options,
55
54
  turnStateFactory: options?.turnStateFactory || (() => new TurnState() as TState),
56
- startTypingTimer: options?.startTypingTimer !== undefined ? options.startTypingTimer : true,
55
+ startTypingTimer: options?.startTypingTimer !== undefined ? options.startTypingTimer : false,
57
56
  longRunningMessages: options?.longRunningMessages !== undefined ? options.longRunningMessages : false
58
57
  }
59
58
 
@@ -61,8 +60,8 @@ export class AgentApplication<TState extends TurnState> {
61
60
  this._adapter = this._options.adapter
62
61
  }
63
62
 
64
- if (this._options.authentication && this._options.authentication.enableSSO && this._options.authentication.ssoConnectionName) {
65
- this._userIdentity = new UserIdentity(this._options.storage ?? new MemoryStorage(), this._options.authentication.ssoConnectionName)
63
+ if (this._options.authorization) {
64
+ this._authorization = new Authorization(this._options.storage!, this._options.authorization)
66
65
  }
67
66
 
68
67
  if (this._options.longRunningMessages && !this._adapter && !this._options.agentAppId) {
@@ -72,6 +71,10 @@ export class AgentApplication<TState extends TurnState> {
72
71
  }
73
72
  }
74
73
 
74
+ /**
75
+ * Gets the adapter associated with the application.
76
+ * @throws Error if the adapter is not configured.
77
+ */
75
78
  public get adapter (): BaseAdapter {
76
79
  if (!this._adapter) {
77
80
  throw new Error(
@@ -82,16 +85,24 @@ export class AgentApplication<TState extends TurnState> {
82
85
  return this._adapter
83
86
  }
84
87
 
85
- public get userIdentity (): UserIdentity {
86
- if (!this._userIdentity) {
88
+ /**
89
+ * Gets the authorization instance for the application.
90
+ * @throws Error if no authentication options were configured.
91
+ */
92
+ public get authorization (): Authorization {
93
+ if (!this._authorization) {
87
94
  throw new Error(
88
- 'The Application.authentication property is unavailable because no authentication options were configured.'
95
+ 'The Application.authorization property is unavailable because no authentication options were configured.'
89
96
  )
90
97
  }
91
98
 
92
- return this._userIdentity
99
+ return this._authorization
93
100
  }
94
101
 
102
+ /**
103
+ * Gets the options used to configure the application.
104
+ * @returns The application options.
105
+ */
95
106
  public get options (): AgentApplicationOptions<TState> {
96
107
  return this._options
97
108
  }
@@ -108,13 +119,13 @@ export class AgentApplication<TState extends TurnState> {
108
119
  *
109
120
  * Example usage:
110
121
  * ```typescript
111
- * app.error(async (context, error) => {
122
+ * app.onError(async (context, error) => {
112
123
  * console.error(`An error occurred: ${error.message}`);
113
124
  * await context.sendActivity('Sorry, something went wrong!');
114
125
  * });
115
126
  * ```
116
127
  */
117
- public error (handler: (context: TurnContext, error: Error) => Promise<void>): this {
128
+ public onError (handler: (context: TurnContext, error: Error) => Promise<void>): this {
118
129
  if (this._adapter) {
119
130
  this._adapter.onTurnError = handler
120
131
  }
@@ -160,12 +171,12 @@ export class AgentApplication<TState extends TurnState> {
160
171
  *
161
172
  * Example usage:
162
173
  * ```typescript
163
- * app.activity(ActivityTypes.Message, async (context, state) => {
174
+ * app.onActivity(ActivityTypes.Message, async (context, state) => {
164
175
  * await context.sendActivity('I received your message');
165
176
  * });
166
177
  * ```
167
178
  */
168
- public activity (
179
+ public onActivity (
169
180
  type: string | RegExp | RouteSelector | (string | RegExp | RouteSelector)[],
170
181
  handler: (context: TurnContext, state: TState) => Promise<void>
171
182
  ): this {
@@ -189,7 +200,7 @@ export class AgentApplication<TState extends TurnState> {
189
200
  *
190
201
  * Example usage:
191
202
  * ```typescript
192
- * app.conversationUpdate('membersAdded', async (context, state) => {
203
+ * app.onConversationUpdate('membersAdded', async (context, state) => {
193
204
  * const membersAdded = context.activity.membersAdded;
194
205
  * for (const member of membersAdded) {
195
206
  * if (member.id !== context.activity.recipient.id) {
@@ -199,7 +210,7 @@ export class AgentApplication<TState extends TurnState> {
199
210
  * });
200
211
  * ```
201
212
  */
202
- public conversationUpdate (
213
+ public onConversationUpdate (
203
214
  event: ConversationUpdateEvents,
204
215
  handler: (context: TurnContext, state: TState) => Promise<void>
205
216
  ): this {
@@ -262,16 +273,16 @@ export class AgentApplication<TState extends TurnState> {
262
273
  *
263
274
  * Example usage:
264
275
  * ```typescript
265
- * app.message('hello', async (context, state) => {
276
+ * app.onMessage('hello', async (context, state) => {
266
277
  * await context.sendActivity('Hello there!');
267
278
  * });
268
279
  *
269
- * app.message(/help., async (context, state) => {
280
+ * app.onMessage(/help., async (context, state) => {
270
281
  * await context.sendActivity('How can I help you?');
271
282
  * });
272
283
  * ```
273
284
  */
274
- public message (
285
+ public onMessage (
275
286
  keyword: string | RegExp | RouteSelector | (string | RegExp | RouteSelector)[],
276
287
  handler: (context: TurnContext, state: TState) => Promise<void>
277
288
  ): this {
@@ -300,9 +311,9 @@ export class AgentApplication<TState extends TurnState> {
300
311
  * });
301
312
  * ```
302
313
  */
303
- public onSignInSuccess (handler: (context: TurnContext, state: TurnState) => void): this {
304
- if (this._userIdentity) {
305
- this._userIdentity.onSignInSuccess(handler)
314
+ public onSignInSuccess (handler: (context: TurnContext, state: TurnState, id?: string) => void): this {
315
+ if (this.options.authorization) {
316
+ this.authorization.onSignInSuccess(handler)
306
317
  } else {
307
318
  throw new Error(
308
319
  'The Application.authentication property is unavailable because no authentication options were configured.'
@@ -355,10 +366,6 @@ export class AgentApplication<TState extends TurnState> {
355
366
  return false
356
367
  }
357
368
 
358
- if (typeof state.temp.input !== 'string') {
359
- state.temp.input = context.activity.text ?? ''
360
- }
361
-
362
369
  if (Array.isArray(this._options.fileDownloaders) && this._options.fileDownloaders.length > 0) {
363
370
  const inputFiles = state.temp.inputFiles ?? []
364
371
  for (let i = 0; i < this._options.fileDownloaders.length; i++) {
@@ -368,10 +375,6 @@ export class AgentApplication<TState extends TurnState> {
368
375
  state.temp.inputFiles = inputFiles
369
376
  }
370
377
 
371
- if (state.temp.actionOutputs === undefined) {
372
- state.temp.actionOutputs = {}
373
- }
374
-
375
378
  for (let i = 0; i < this._routes.length; i++) {
376
379
  const route = this._routes[i]
377
380
  if (await route.selector(context)) {
@@ -532,19 +535,20 @@ export class AgentApplication<TState extends TurnState> {
532
535
  *
533
536
  * Example usage:
534
537
  * ```typescript
535
- * app.turn('beforeTurn', async (context, state) => {
538
+ * app.onTurn('beforeTurn', async (context, state) => {
536
539
  * console.log('Processing before turn');
537
540
  * return true; // Continue execution
538
541
  * });
539
542
  * ```
540
543
  */
541
- public turn (
544
+ public onTurn (
542
545
  event: TurnEvents | TurnEvents[],
543
546
  handler: (context: TurnContext, state: TState) => Promise<boolean>
544
547
  ): this {
545
548
  (Array.isArray(event) ? event : [event]).forEach((e) => {
546
549
  switch (e) {
547
550
  case 'beforeTurn':
551
+ this._beforeTurn.push(handler)
548
552
  break
549
553
  case 'afterTurn':
550
554
  this._afterTurn.push(handler)
@@ -7,7 +7,7 @@ import { AgentApplication } from './agentApplication'
7
7
  import { AgentApplicationOptions } from './agentApplicationOptions'
8
8
  import { TurnState } from './turnState'
9
9
  import { Storage } from '../storage'
10
- import { UserIdentityOptions } from './oauth/userIdentity'
10
+ import { AuthorizationHandlers } from './oauth/authorization'
11
11
 
12
12
  /**
13
13
  * Builder class for creating and configuring AgentApplication instances.
@@ -49,18 +49,18 @@ export class AgentApplicationBuilder<TState extends TurnState = TurnState> {
49
49
  * @param startTypingTimer Whether to show typing indicators
50
50
  * @returns This builder instance for chaining
51
51
  */
52
- public setStartTypingTimer (startTypingTimer: boolean): this {
53
- this._options.startTypingTimer = startTypingTimer
54
- return this
55
- }
52
+ // public setStartTypingTimer (startTypingTimer: boolean): this {
53
+ // this._options.startTypingTimer = startTypingTimer
54
+ // return this
55
+ // }
56
56
 
57
57
  /**
58
58
  * Sets authentication options for the AgentApplication.
59
- * @param authenticationOptions The user identity authentication options
59
+ * @param authHandlers The user identity authentication options
60
60
  * @returns This builder instance for chaining
61
61
  */
62
- public withAuthentication (authenticationOptions: UserIdentityOptions): this {
63
- this._options.authentication = authenticationOptions
62
+ public withAuthorization (authHandlers: AuthorizationHandlers): this {
63
+ this._options.authorization = authHandlers
64
64
  return this
65
65
  }
66
66
 
@@ -7,15 +7,46 @@ import { CloudAdapter } from '../cloudAdapter'
7
7
  import { InputFileDownloader } from './inputFileDownloader'
8
8
  import { TurnState } from './turnState'
9
9
  import { Storage } from '../storage'
10
- import { UserIdentityOptions } from './oauth/userIdentity'
10
+ import { AuthorizationHandlers } from './oauth/authorization'
11
11
 
12
12
  export interface AgentApplicationOptions<TState extends TurnState> {
13
+ /**
14
+ * The adapter used for handling bot interactions.
15
+ */
13
16
  adapter?: CloudAdapter;
17
+
18
+ /**
19
+ * The application ID of the agent.
20
+ */
14
21
  agentAppId?: string;
22
+
23
+ /**
24
+ * The storage mechanism for persisting state.
25
+ */
15
26
  storage?: Storage;
27
+
28
+ /**
29
+ * Whether to start a typing timer for the bot.
30
+ */
16
31
  startTypingTimer: boolean;
32
+
33
+ /**
34
+ * Whether to enable long-running messages.
35
+ */
17
36
  longRunningMessages: boolean;
37
+
38
+ /**
39
+ * A factory function to create the turn state.
40
+ */
18
41
  turnStateFactory: () => TState;
42
+
43
+ /**
44
+ * An array of file downloaders for handling input files.
45
+ */
19
46
  fileDownloaders?: InputFileDownloader<TState>[];
20
- authentication?: UserIdentityOptions;
47
+
48
+ /**
49
+ * Handlers for managing authorization.
50
+ */
51
+ authorization?: AuthorizationHandlers;
21
52
  }
@@ -8,6 +8,13 @@ import { RouteSelector } from './routeSelector'
8
8
  import { TurnState } from './turnState'
9
9
 
10
10
  export interface AppRoute<TState extends TurnState> {
11
+ /**
12
+ * The selector function used to determine if this route should handle the current activity.
13
+ */
11
14
  selector: RouteSelector;
15
+
16
+ /**
17
+ * The handler function that processes the activity if the selector matches.
18
+ */
12
19
  handler: RouteHandler<TState>;
13
20
  }
@@ -14,13 +14,31 @@ import { loadAuthConfigFromEnv, MsalTokenProvider } from '../auth'
14
14
 
15
15
  const logger = debug('agents:attachmentDownloader')
16
16
 
17
+ /**
18
+ * A utility class for downloading input files from activity attachments.
19
+ *
20
+ * This class provides functionality to filter and download attachments from a turn context,
21
+ * supporting various content types and handling authentication for secure URLs.
22
+ *
23
+ * @typeParam TState - The type of the turn state used in the application.
24
+ */
17
25
  export class AttachmentDownloader<TState extends TurnState = TurnState> implements InputFileDownloader<TState> {
18
26
  private _httpClient: AxiosInstance
19
27
 
28
+ /**
29
+ * Creates an instance of AttachmentDownloader.
30
+ * This class is responsible for downloading input files from attachments.
31
+ */
20
32
  public constructor () {
21
33
  this._httpClient = axios.create()
22
34
  }
23
35
 
36
+ /**
37
+ * Downloads files from the attachments in the current turn context.
38
+ * @param context The turn context containing the activity with attachments.
39
+ * @param state The turn state for the current conversation.
40
+ * @returns A promise that resolves to an array of downloaded input files.
41
+ */
24
42
  public async downloadFiles (context: TurnContext, state: TState): Promise<InputFile[]> {
25
43
  const attachments = context.activity.attachments?.filter((a) => !a.contentType.startsWith('text/html'))
26
44
  if (!attachments || attachments.length === 0) {
@@ -3,6 +3,12 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
+ /**
7
+ * Represents the types of conversation update events that can occur.
8
+ *
9
+ * - `membersAdded`: Triggered when new members are added to the conversation.
10
+ * - `membersRemoved`: Triggered when members are removed from the conversation.
11
+ */
6
12
  export type ConversationUpdateEvents =
7
13
  | 'membersAdded'
8
14
  | 'membersRemoved'
package/src/app/index.ts CHANGED
@@ -3,7 +3,7 @@ export * from './agentApplicationBuilder'
3
3
  export * from './agentApplicationOptions'
4
4
  export * from './appRoute'
5
5
  export * from './attachmentDownloader'
6
- export * from './oauth/userIdentity'
6
+ export * from './oauth/authorization'
7
7
  export * from './conversationUpdateEvents'
8
8
  export * from './routeHandler'
9
9
  export * from './routeSelector'
@@ -6,12 +6,36 @@
6
6
  import { TurnContext } from '../turnContext'
7
7
  import { TurnState } from './turnState'
8
8
 
9
+ /**
10
+ * Represents a file input with its content, type, and optional URL.
11
+ */
9
12
  export interface InputFile {
13
+ /**
14
+ * The content of the file as a Buffer.
15
+ */
10
16
  content: Buffer;
17
+
18
+ /**
19
+ * The MIME type of the file content.
20
+ */
11
21
  contentType: string;
22
+
23
+ /**
24
+ * An optional URL pointing to the file content.
25
+ */
12
26
  contentUrl?: string;
13
27
  }
14
28
 
29
+ /**
30
+ * Interface for downloading input files in a specific turn context and state.
31
+ */
15
32
  export interface InputFileDownloader<TState extends TurnState = TurnState> {
33
+ /**
34
+ * Downloads files based on the provided turn context and state.
35
+ *
36
+ * @param context - The turn context for the current operation.
37
+ * @param state - The state associated with the current turn.
38
+ * @returns A promise that resolves to an array of input files.
39
+ */
16
40
  downloadFiles(context: TurnContext, state: TState): Promise<InputFile[]>;
17
41
  }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { TurnContext } from '../../turnContext'
7
+ import { debug } from '../../logger'
8
+ import { TurnState } from '../turnState'
9
+ import { Storage } from '../../storage'
10
+ import { OAuthFlow, TokenRequestStatus, TokenResponse } from '../../oauth'
11
+ import { UserState } from '../../state'
12
+
13
+ const logger = debug('agents:authorization')
14
+
15
+ /**
16
+ * Interface defining an authorization handler for OAuth flows
17
+ * @interface AuthHandler
18
+ */
19
+ export interface AuthHandler {
20
+ /** Connection name for the auth provider */
21
+ name?: string,
22
+ /** Whether authorization should be triggered automatically */
23
+ auto?: boolean,
24
+ /** The OAuth flow implementation */
25
+ flow?: OAuthFlow,
26
+ /** Title to display on auth cards/UI */
27
+ title?: string,
28
+ /** Text to display on auth cards/UI */
29
+ text?: string,
30
+ }
31
+
32
+ /**
33
+ * Options for configuring user authorization.
34
+ * Contains settings to configure OAuth connections.
35
+ */
36
+ export interface AuthorizationHandlers extends Record<string, AuthHandler> {}
37
+
38
+ /**
39
+ * Class responsible for managing authorization and OAuth flows
40
+ * @class Authorization
41
+ */
42
+ export class Authorization {
43
+ _authHandlers: AuthorizationHandlers
44
+
45
+ /**
46
+ * Creates a new instance of UserAuthorization.
47
+ * @param {Storage} storage - The storage system to use for state management.
48
+ * @param {AuthorizationHandlers} authHandlers - Configuration for OAuth providers
49
+ * @throws {Error} If storage is null/undefined or no auth handlers are provided
50
+ */
51
+ constructor (storage: Storage, authHandlers: AuthorizationHandlers) {
52
+ if (storage === undefined || storage === null) {
53
+ throw new Error('Storage is required for UserAuthorization')
54
+ }
55
+ const userState = new UserState(storage)
56
+ if (authHandlers === undefined || Object.keys(authHandlers).length === 0) {
57
+ throw new Error('The authorization does not have any auth handlers')
58
+ }
59
+ this._authHandlers = authHandlers
60
+ for (const ah in this._authHandlers) {
61
+ if (this._authHandlers![ah].name === undefined && process.env[ah + '_connectionName'] === undefined) {
62
+ throw new Error(`AuthHandler name ${ah}_connectionName not set in autorization and not found in env vars.`)
63
+ }
64
+ const currentAuthHandler = this._authHandlers![ah]
65
+ currentAuthHandler.name = currentAuthHandler.name ?? process.env[ah + '_connectionName'] as string
66
+ currentAuthHandler.title = currentAuthHandler.title ?? process.env[ah + '_connectionTitle'] as string
67
+ currentAuthHandler.text = currentAuthHandler.text ?? process.env[ah + '_connectionText'] as string
68
+ currentAuthHandler.auto = currentAuthHandler.auto ?? process.env[ah + '_connectionAuto'] === 'true'
69
+ currentAuthHandler.flow = new OAuthFlow(userState, currentAuthHandler.name, null!, currentAuthHandler.title, currentAuthHandler.text)
70
+ }
71
+ logger.info('Authorization handlers configured with', this._authHandlers.length, 'handlers')
72
+ }
73
+
74
+ /**
75
+ * Gets the token for a specific auth handler
76
+ * @param {TurnContext} context - The context object for the current turn
77
+ * @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
78
+ * @returns {Promise<TokenResponse>} The token response from the OAuth provider
79
+ */
80
+ public async getToken (context: TurnContext, authHandlerId?: string): Promise<TokenResponse> {
81
+ logger.info('getToken from user token service for authHandlerId:', authHandlerId)
82
+ const authHandler = this.resolverHandler(authHandlerId)
83
+ return await authHandler.flow?.getUserToken(context)!
84
+ }
85
+
86
+ /**
87
+ * Begins or continues an OAuth flow
88
+ * @param {TurnContext} context - The context object for the current turn
89
+ * @param {TurnState} state - The state object for the current turn
90
+ * @param {string} [authHandlerId] - Optional ID of the auth handler to use, defaults to first handler
91
+ * @returns {Promise<TokenResponse>} The token response from the OAuth provider
92
+ */
93
+ public async beginOrContinueFlow (context: TurnContext, state: TurnState, authHandlerId?: string) : Promise<TokenResponse> {
94
+ logger.info('beginOrContinueFlow for authHandlerId:', authHandlerId)
95
+ const flow = this.resolverHandler(authHandlerId).flow!
96
+ let tokenResponse: TokenResponse
97
+ if (flow.state!.flowStarted === false) {
98
+ tokenResponse = await flow.beginFlow(context)
99
+ } else {
100
+ tokenResponse = await flow.continueFlow(context)
101
+ if (tokenResponse.status === TokenRequestStatus.Success) {
102
+ if (this._signInHandler) {
103
+ await this._signInHandler(context, state, authHandlerId)
104
+ }
105
+ }
106
+ }
107
+ return tokenResponse
108
+ }
109
+
110
+ /**
111
+ * Gets the current state of the OAuth flow
112
+ * @param {string} [authHandlerId] - Optional ID of the auth handler to check, defaults to first handler
113
+ * @returns {boolean} Whether the flow has started
114
+ */
115
+ public getFlowState (authHandlerId?: string) : boolean {
116
+ const flow = this.resolverHandler(authHandlerId).flow!
117
+ return flow.state?.flowStarted!
118
+ }
119
+
120
+ /**
121
+ * Resolves the auth handler to use based on the provided ID
122
+ * @param {string} [authHandlerId] - Optional ID of the auth handler to resolve, defaults to first handler
123
+ * @returns {AuthHandler} The resolved auth handler
124
+ */
125
+ resolverHandler = (authHandlerId?: string) : AuthHandler => {
126
+ if (authHandlerId) {
127
+ return this._authHandlers![authHandlerId]
128
+ }
129
+ return this._authHandlers![Object.keys(this._authHandlers)[0]]
130
+ }
131
+
132
+ /**
133
+ * Signs out the current user.
134
+ * This method clears the user's token and resets the SSO state.
135
+ *
136
+ * @param {TurnContext} context - The context object for the current turn.
137
+ * @param {TurnState} state - The state object for the current turn.
138
+ * @param {string} [authHandlerId] - Optional ID of the auth handler to use for sign out
139
+ * @returns {Promise<void>}
140
+ */
141
+ async signOut (context: TurnContext, state: TurnState, authHandlerId?: string) : Promise<void> {
142
+ logger.info('signOut for authHandlerId:', authHandlerId)
143
+ if (authHandlerId === undefined) { // aw
144
+ for (const ah in this._authHandlers) {
145
+ const flow = this._authHandlers[ah].flow
146
+ await flow?.signOut(context)
147
+ }
148
+ } else {
149
+ await this.resolverHandler(authHandlerId).flow?.signOut(context)
150
+ }
151
+ }
152
+
153
+ _signInHandler: ((context: TurnContext, state: TurnState, authHandlerId?: string) => void) | null = null
154
+
155
+ /**
156
+ * Sets a handler to be called when sign-in is successfully completed
157
+ * @param {Function} handler - The handler function to call on successful sign-in
158
+ */
159
+ public onSignInSuccess (handler: (context: TurnContext, state: TurnState, authHandlerId?: string) => void) {
160
+ this._signInHandler = handler
161
+ }
162
+ }
@@ -6,4 +6,12 @@
6
6
  import { TurnContext } from '../turnContext'
7
7
  import { TurnState } from './turnState'
8
8
 
9
+ /**
10
+ * A handler function for routing operations in a specific turn context and state.
11
+ *
12
+ * @typeParam TState - The type of the turn state.
13
+ * @param context - The turn context for the current operation.
14
+ * @param state - The state associated with the current turn.
15
+ * @returns A promise that resolves when the routing operation is complete.
16
+ */
9
17
  export type RouteHandler<TState extends TurnState> = (context: TurnContext, state: TState) => Promise<void>
@@ -5,6 +5,15 @@
5
5
 
6
6
  import { TurnContext } from '../turnContext'
7
7
 
8
+ /**
9
+ * A function that determines whether a specific condition is met in the given turn context.
10
+ *
11
+ * @param context - The turn context for the current operation.
12
+ * @returns A promise that resolves to a boolean indicating whether the condition is met.
13
+ */
8
14
  export type Selector = (context: TurnContext) => Promise<boolean>
9
15
 
16
+ /**
17
+ * A specialized selector for routing operations.
18
+ */
10
19
  export type RouteSelector = Selector