@microsoft/agents-hosting 0.1.49 → 0.2.8-g3bf5832077
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/activityWireCompat.d.ts +19 -0
- package/dist/src/activityWireCompat.js +49 -0
- package/dist/src/activityWireCompat.js.map +1 -0
- package/dist/src/agent-client/agentClient.d.ts +8 -2
- package/dist/src/agent-client/agentClient.js +7 -10
- package/dist/src/agent-client/agentClient.js.map +1 -1
- package/dist/src/agent-client/{expressApi.d.ts → agentResponseHandler.d.ts} +2 -1
- package/dist/src/agent-client/{expressApi.js → agentResponseHandler.js} +16 -12
- package/dist/src/agent-client/agentResponseHandler.js.map +1 -0
- package/dist/src/agent-client/index.d.ts +1 -1
- package/dist/src/agent-client/index.js +1 -1
- package/dist/src/agent-client/index.js.map +1 -1
- package/dist/src/app/agentApplication.d.ts +9 -8
- package/dist/src/app/agentApplication.js +17 -8
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/{applicationBuilder.d.ts → agentApplicationBuilder.d.ts} +6 -6
- package/dist/src/app/{applicationBuilder.js → agentApplicationBuilder.js} +4 -4
- package/dist/src/app/agentApplicationBuilder.js.map +1 -0
- package/dist/src/app/{applicationOptions.d.ts → agentApplicationOptions.d.ts} +3 -3
- package/dist/src/app/{applicationOptions.js → agentApplicationOptions.js} +1 -1
- package/dist/src/app/agentApplicationOptions.js.map +1 -0
- package/dist/src/app/index.d.ts +4 -3
- package/dist/src/app/index.js +4 -3
- package/dist/src/app/index.js.map +1 -1
- package/dist/src/app/oauth/userIdentity.d.ts +43 -0
- package/dist/src/app/oauth/userIdentity.js +54 -0
- package/dist/src/app/oauth/userIdentity.js.map +1 -0
- package/dist/src/app/turnState.d.ts +1 -1
- package/dist/src/app/turnState.js +2 -2
- package/dist/src/app/turnState.js.map +1 -1
- package/dist/src/app/turnStateProperty.d.ts +40 -0
- package/dist/src/app/turnStateProperty.js +57 -0
- package/dist/src/app/turnStateProperty.js.map +1 -0
- package/dist/src/auth/authConfiguration.d.ts +21 -2
- package/dist/src/auth/authConfiguration.js +23 -4
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/jwt-middleware.js +2 -1
- package/dist/src/auth/jwt-middleware.js.map +1 -1
- package/dist/src/auth/msalTokenProvider.js +1 -1
- package/dist/src/auth/msalTokenProvider.js.map +1 -1
- package/dist/src/cards/cardFactory.d.ts +8 -0
- package/dist/src/cards/cardFactory.js +22 -1
- package/dist/src/cards/cardFactory.js.map +1 -1
- package/dist/src/cloudAdapter.d.ts +1 -2
- package/dist/src/cloudAdapter.js +7 -2
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/connector-client/connectorClient.d.ts +3 -2
- package/dist/src/connector-client/connectorClient.js +15 -3
- package/dist/src/connector-client/connectorClient.js.map +1 -1
- package/dist/src/connector-client/index.d.ts +0 -1
- package/dist/src/connector-client/index.js +0 -1
- package/dist/src/connector-client/index.js.map +1 -1
- package/dist/src/getProductInfo.d.ts +1 -0
- package/dist/src/getProductInfo.js +11 -0
- package/dist/src/getProductInfo.js.map +1 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/oauth/index.d.ts +3 -4
- package/dist/src/oauth/index.js +3 -4
- package/dist/src/oauth/index.js.map +1 -1
- package/dist/src/oauth/{oauthCard.d.ts → oAuthCard.d.ts} +1 -2
- package/dist/src/oauth/{oauthCard.js → oAuthCard.js} +1 -1
- package/dist/src/oauth/oAuthCard.js.map +1 -0
- package/dist/src/oauth/oAuthFlow.d.ts +47 -0
- package/dist/src/oauth/oAuthFlow.js +158 -0
- package/dist/src/oauth/oAuthFlow.js.map +1 -0
- package/dist/src/oauth/signingResource.d.ts +27 -3
- package/dist/src/oauth/tokenResponse.d.ts +29 -0
- package/dist/src/oauth/tokenResponse.js +25 -0
- package/dist/src/oauth/tokenResponse.js.map +1 -0
- package/dist/src/oauth/userTokenClient.d.ts +4 -3
- package/dist/src/oauth/userTokenClient.js +23 -13
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/state/agentState.d.ts +8 -3
- package/dist/src/state/agentState.js +17 -6
- package/dist/src/state/agentState.js.map +1 -1
- package/dist/src/state/agentStatePropertyAccesor.d.ts +58 -5
- package/dist/src/state/agentStatePropertyAccesor.js +6 -6
- package/dist/src/state/agentStatePropertyAccesor.js.map +1 -1
- package/package.json +3 -6
- package/src/activityWireCompat.ts +45 -0
- package/src/agent-client/agentClient.ts +21 -13
- package/src/agent-client/{expressApi.ts → agentResponseHandler.ts} +20 -12
- package/src/agent-client/index.ts +1 -1
- package/src/app/agentApplication.ts +24 -15
- package/src/app/{applicationBuilder.ts → agentApplicationBuilder.ts} +5 -5
- package/src/app/{applicationOptions.ts → agentApplicationOptions.ts} +3 -3
- package/src/app/index.ts +4 -3
- package/src/app/oauth/userIdentity.ts +78 -0
- package/src/app/turnState.ts +2 -2
- package/src/app/turnStateProperty.ts +72 -0
- package/src/auth/authConfiguration.ts +23 -4
- package/src/auth/jwt-middleware.ts +2 -1
- package/src/auth/msalTokenProvider.ts +1 -1
- package/src/cards/cardFactory.ts +26 -2
- package/src/cloudAdapter.ts +8 -4
- package/src/connector-client/connectorClient.ts +15 -5
- package/src/connector-client/index.ts +0 -1
- package/src/getProductInfo.ts +3 -0
- package/src/index.ts +2 -2
- package/src/oauth/index.ts +3 -4
- package/src/oauth/{oauthCard.ts → oAuthCard.ts} +1 -3
- package/src/oauth/oAuthFlow.ts +175 -0
- package/src/oauth/signingResource.ts +28 -3
- package/src/oauth/tokenResponse.ts +43 -0
- package/src/oauth/userTokenClient.ts +26 -16
- package/src/state/agentState.ts +25 -6
- package/src/state/agentStatePropertyAccesor.ts +65 -8
- package/dist/src/agent-client/expressApi.js.map +0 -1
- package/dist/src/app/applicationBuilder.js.map +0 -1
- package/dist/src/app/applicationOptions.js.map +0 -1
- package/dist/src/app/oauth/authenticationOptions.d.ts +0 -7
- package/dist/src/app/oauth/authenticationOptions.js +0 -7
- package/dist/src/app/oauth/authenticationOptions.js.map +0 -1
- package/dist/src/app/oauth/webChatOAuthFlowAppStyle.d.ts +0 -11
- package/dist/src/app/oauth/webChatOAuthFlowAppStyle.js +0 -85
- package/dist/src/app/oauth/webChatOAuthFlowAppStyle.js.map +0 -1
- package/dist/src/connector-client/conversationParameters.d.ts +0 -38
- package/dist/src/connector-client/conversationParameters.js +0 -7
- package/dist/src/connector-client/conversationParameters.js.map +0 -1
- package/dist/src/oauth/oauthCard.js.map +0 -1
- package/dist/src/oauth/tokenExchangeResource.d.ts +0 -17
- package/dist/src/oauth/tokenExchangeResource.js +0 -5
- package/dist/src/oauth/tokenExchangeResource.js.map +0 -1
- package/dist/src/oauth/tokenPostResource.d.ts +0 -9
- package/dist/src/oauth/tokenPostResource.js +0 -5
- package/dist/src/oauth/tokenPostResource.js.map +0 -1
- package/dist/src/oauth/webChatOAuthFlow.d.ts +0 -41
- package/dist/src/oauth/webChatOAuthFlow.js +0 -117
- package/dist/src/oauth/webChatOAuthFlow.js.map +0 -1
- package/src/app/oauth/authenticationOptions.ts +0 -8
- package/src/app/oauth/webChatOAuthFlowAppStyle.ts +0 -90
- package/src/connector-client/conversationParameters.ts +0 -40
- package/src/oauth/tokenExchangeResource.ts +0 -20
- package/src/oauth/tokenPostResource.ts +0 -12
- package/src/oauth/webChatOAuthFlow.ts +0 -123
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
import { debug } from './../logger'
|
|
4
|
+
import { Activity, ActivityTypes, Attachment } from '@microsoft/agents-activity'
|
|
5
|
+
import {
|
|
6
|
+
CardFactory,
|
|
7
|
+
AgentStatePropertyAccessor,
|
|
8
|
+
UserState,
|
|
9
|
+
TurnContext,
|
|
10
|
+
MessageFactory,
|
|
11
|
+
SigningResource,
|
|
12
|
+
TokenExchangeRequest,
|
|
13
|
+
UserTokenClient
|
|
14
|
+
} from '../'
|
|
15
|
+
import { TokenRequestStatus, TokenResponse } from './tokenResponse'
|
|
16
|
+
|
|
17
|
+
const logger = debug('agents:oauth-flow')
|
|
18
|
+
|
|
19
|
+
export class FlowState {
|
|
20
|
+
public flowStarted: boolean = false
|
|
21
|
+
public flowExpires: number = 0
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TokenVerifyState {
|
|
25
|
+
state: string
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Manages the OAuth flow for Teams.
|
|
29
|
+
*/
|
|
30
|
+
export class OAuthFlow {
|
|
31
|
+
userTokenClient?: UserTokenClient
|
|
32
|
+
state: FlowState | null
|
|
33
|
+
flowStateAccessor: AgentStatePropertyAccessor<FlowState | null>
|
|
34
|
+
tokenExchangeId: string | null = null
|
|
35
|
+
absOauthConnectionName: string
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new instance of OAuthFlow.
|
|
38
|
+
* @param userState The user state.
|
|
39
|
+
*/
|
|
40
|
+
constructor (userState: UserState, absOauthConnectionName: string, tokenClient?: UserTokenClient) {
|
|
41
|
+
this.state = null
|
|
42
|
+
this.flowStateAccessor = userState.createProperty('flowState')
|
|
43
|
+
this.absOauthConnectionName = absOauthConnectionName
|
|
44
|
+
this.userTokenClient = tokenClient
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public async getUserToken (context: TurnContext): Promise<TokenResponse> {
|
|
48
|
+
await this.initializeTokenClient(context)
|
|
49
|
+
return await this.userTokenClient?.getUserToken(this.absOauthConnectionName, context.activity.channelId!, context.activity.from?.id!)!
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Begins the OAuth flow.
|
|
54
|
+
* @param context The turn context.
|
|
55
|
+
* @returns A promise that resolves to the user token.
|
|
56
|
+
*/
|
|
57
|
+
public async beginFlow (context: TurnContext): Promise<TokenResponse> {
|
|
58
|
+
logger.info('Starting OAuth flow')
|
|
59
|
+
this.state = await this.getUserState(context)
|
|
60
|
+
|
|
61
|
+
const authConfig = context.adapter.authConfig
|
|
62
|
+
if (this.absOauthConnectionName === '') {
|
|
63
|
+
throw new Error('connectionName is not set in the auth config, review your environment variables')
|
|
64
|
+
}
|
|
65
|
+
await this.initializeTokenClient(context)
|
|
66
|
+
|
|
67
|
+
const tokenResponse = await this.userTokenClient!.getUserToken(this.absOauthConnectionName, context.activity.channelId!, context.activity.from?.id!)
|
|
68
|
+
if (tokenResponse?.status === TokenRequestStatus.Success) {
|
|
69
|
+
this.state.flowStarted = false
|
|
70
|
+
this.state.flowExpires = 0
|
|
71
|
+
await this.flowStateAccessor.set(context, this.state)
|
|
72
|
+
logger.info('User token retrieved successfully from service')
|
|
73
|
+
return tokenResponse
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const signingResource: SigningResource = await this.userTokenClient!.getSignInResource(authConfig.clientId!, this.absOauthConnectionName, context.activity)
|
|
77
|
+
const oCard: Attachment = CardFactory.oauthCard(this.absOauthConnectionName, 'Sign in', 'login', signingResource)
|
|
78
|
+
const cardActivity : Activity = MessageFactory.attachment(oCard)
|
|
79
|
+
await context.sendActivity(cardActivity)
|
|
80
|
+
this.state.flowStarted = true
|
|
81
|
+
this.state.flowExpires = Date.now() + 30000
|
|
82
|
+
await this.flowStateAccessor.set(context, this.state)
|
|
83
|
+
logger.info('OAuth begin flow completed, waiting for user to sign in')
|
|
84
|
+
return {
|
|
85
|
+
token: undefined,
|
|
86
|
+
status: TokenRequestStatus.InProgress
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Continues the OAuth flow.
|
|
92
|
+
* @param context The turn context.
|
|
93
|
+
* @returns A promise that resolves to the user token.
|
|
94
|
+
*/
|
|
95
|
+
public async continueFlow (context: TurnContext): Promise<TokenResponse> {
|
|
96
|
+
this.state = await this.getUserState(context)
|
|
97
|
+
await this.initializeTokenClient(context)
|
|
98
|
+
if (this.state?.flowExpires !== 0 && Date.now() > this.state!.flowExpires) {
|
|
99
|
+
logger.warn('Flow expired')
|
|
100
|
+
this.state!.flowStarted = false
|
|
101
|
+
await context.sendActivity(MessageFactory.text('Sign-in session expired. Please try again.'))
|
|
102
|
+
return { status: TokenRequestStatus.Expired, token: undefined }
|
|
103
|
+
}
|
|
104
|
+
const contFlowActivity = context.activity
|
|
105
|
+
if (contFlowActivity.type === ActivityTypes.Message) {
|
|
106
|
+
const magicCode = contFlowActivity.text as string
|
|
107
|
+
const result = await this.userTokenClient?.getUserToken(this.absOauthConnectionName, contFlowActivity.channelId!, contFlowActivity.from?.id!, magicCode)!
|
|
108
|
+
return result
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (contFlowActivity.type === ActivityTypes.Invoke && contFlowActivity.name === 'signin/verifyState') {
|
|
112
|
+
logger.info('Continuing OAuth flow with verifyState')
|
|
113
|
+
const tokenVerifyState = contFlowActivity.value as TokenVerifyState
|
|
114
|
+
const magicCode = tokenVerifyState.state
|
|
115
|
+
const result = await this.userTokenClient?.getUserToken(this.absOauthConnectionName, contFlowActivity.channelId!, contFlowActivity.from?.id!, magicCode)!
|
|
116
|
+
return result
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (contFlowActivity.type === ActivityTypes.Invoke && contFlowActivity.name === 'signin/tokenExchange') {
|
|
120
|
+
logger.info('Continuing OAuth flow with tokenExchange')
|
|
121
|
+
const tokenExchangeRequest = contFlowActivity.value as TokenExchangeRequest
|
|
122
|
+
if (this.tokenExchangeId === tokenExchangeRequest.id) { // dedupe
|
|
123
|
+
return { status: TokenRequestStatus.InProgress, token: undefined }
|
|
124
|
+
}
|
|
125
|
+
this.tokenExchangeId = tokenExchangeRequest.id!
|
|
126
|
+
const userTokenResp = await this.userTokenClient?.exchangeTokenAsync(contFlowActivity.from?.id!, this.absOauthConnectionName, contFlowActivity.channelId!, tokenExchangeRequest)
|
|
127
|
+
if (userTokenResp?.status === TokenRequestStatus.Success) {
|
|
128
|
+
logger.info('Token exchanged')
|
|
129
|
+
this.state!.flowStarted = false
|
|
130
|
+
await this.flowStateAccessor.set(context, this.state)
|
|
131
|
+
return userTokenResp
|
|
132
|
+
} else {
|
|
133
|
+
logger.warn('Token exchange failed')
|
|
134
|
+
this.state!.flowStarted = true
|
|
135
|
+
return { status: TokenRequestStatus.Failed, token: undefined }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { status: TokenRequestStatus.Failed, token: undefined }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Signs the user out.
|
|
143
|
+
* @param context The turn context.
|
|
144
|
+
* @returns A promise that resolves when the sign-out operation is complete.
|
|
145
|
+
*/
|
|
146
|
+
public async signOut (context: TurnContext): Promise<void> {
|
|
147
|
+
this.state = await this.getUserState(context)
|
|
148
|
+
await this.initializeTokenClient(context)
|
|
149
|
+
await this.userTokenClient?.signOut(context.activity.from?.id as string, this.absOauthConnectionName, context.activity.channelId as string)
|
|
150
|
+
this.state!.flowExpires = 0
|
|
151
|
+
await this.flowStateAccessor.set(context, this.state)
|
|
152
|
+
logger.info('User signed out successfully')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Gets the user state.
|
|
157
|
+
* @param context The turn context.
|
|
158
|
+
* @returns A promise that resolves to the user state.
|
|
159
|
+
*/
|
|
160
|
+
private async getUserState (context: TurnContext) {
|
|
161
|
+
let userProfile: FlowState | null = await this.flowStateAccessor.get(context, null)
|
|
162
|
+
if (userProfile === null) {
|
|
163
|
+
userProfile = new FlowState()
|
|
164
|
+
}
|
|
165
|
+
return userProfile
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private async initializeTokenClient (context: TurnContext) {
|
|
169
|
+
if (this.userTokenClient === undefined) {
|
|
170
|
+
const scope = 'https://api.botframework.com'
|
|
171
|
+
const accessToken = await context.adapter.authProvider.getAccessToken(context.adapter.authConfig, scope)
|
|
172
|
+
this.userTokenClient = new UserTokenClient(accessToken)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Represents a resource for exchanging tokens.
|
|
6
|
+
*/
|
|
7
|
+
export interface TokenExchangeResource {
|
|
8
|
+
/**
|
|
9
|
+
* The ID of the token exchange resource.
|
|
10
|
+
*/
|
|
11
|
+
id?: string
|
|
12
|
+
/**
|
|
13
|
+
* The URI of the token exchange resource.
|
|
14
|
+
*/
|
|
15
|
+
uri?: string
|
|
16
|
+
/**
|
|
17
|
+
* The provider ID for the token exchange resource.
|
|
18
|
+
*/
|
|
19
|
+
providerId?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Represents a resource for posting tokens.
|
|
24
|
+
*/
|
|
25
|
+
export interface TokenPostResource {
|
|
26
|
+
/**
|
|
27
|
+
* The SAS URL for the token post resource.
|
|
28
|
+
*/
|
|
29
|
+
sasUrl?: string
|
|
30
|
+
}
|
|
6
31
|
|
|
7
32
|
/**
|
|
8
33
|
* Represents a resource for signing in.
|
|
@@ -11,7 +36,7 @@ export interface SigningResource {
|
|
|
11
36
|
/**
|
|
12
37
|
* The link for signing in.
|
|
13
38
|
*/
|
|
14
|
-
|
|
39
|
+
signInLink: string,
|
|
15
40
|
/**
|
|
16
41
|
* The resource for token exchange.
|
|
17
42
|
*/
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents the status of an OAuth token request.
|
|
6
|
+
*/
|
|
7
|
+
export enum TokenRequestStatus {
|
|
8
|
+
/**
|
|
9
|
+
* Indicates that the token request was successful.
|
|
10
|
+
*/
|
|
11
|
+
Success = 'Success',
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Indicates that the token request failed.
|
|
15
|
+
*/
|
|
16
|
+
Failed = 'Failed',
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Indicates that the token request is pending.
|
|
20
|
+
*/
|
|
21
|
+
InProgress = 'InProgress',
|
|
22
|
+
|
|
23
|
+
Expired = 'Expired',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Represents the response containing OAuth token information.
|
|
28
|
+
* This interface encapsulates all data related to an OAuth token response.
|
|
29
|
+
*/
|
|
30
|
+
export interface TokenResponse {
|
|
31
|
+
|
|
32
|
+
status: TokenRequestStatus
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The OAuth token string, or null if no token is available.
|
|
36
|
+
*/
|
|
37
|
+
token: string | undefined
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The expiration time of the token, represented as a numeric timestamp.
|
|
41
|
+
*/
|
|
42
|
+
// expires: number
|
|
43
|
+
}
|
|
@@ -6,8 +6,11 @@ import { SigningResource } from './signingResource'
|
|
|
6
6
|
import { Activity } from '@microsoft/agents-activity'
|
|
7
7
|
import { debug } from '../logger'
|
|
8
8
|
import { TokenExchangeRequest } from './tokenExchangeRequest'
|
|
9
|
+
import { normalizeTokenExchangeState } from '../activityWireCompat'
|
|
10
|
+
import { TokenRequestStatus, TokenResponse } from './tokenResponse'
|
|
11
|
+
import { getProductInfo } from '../getProductInfo'
|
|
9
12
|
|
|
10
|
-
const logger = debug('agents:
|
|
13
|
+
const logger = debug('agents:user-token-client')
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* Client for managing user tokens.
|
|
@@ -24,7 +27,8 @@ export class UserTokenClient {
|
|
|
24
27
|
const axiosInstance = axios.create({
|
|
25
28
|
baseURL,
|
|
26
29
|
headers: {
|
|
27
|
-
Accept: 'application/json'
|
|
30
|
+
Accept: 'application/json',
|
|
31
|
+
'User-Agent': getProductInfo(),
|
|
28
32
|
}
|
|
29
33
|
})
|
|
30
34
|
axiosInstance.defaults.headers.common.Authorization = `Bearer ${token}`
|
|
@@ -39,16 +43,19 @@ export class UserTokenClient {
|
|
|
39
43
|
* @param code The optional code.
|
|
40
44
|
* @returns A promise that resolves to the user token.
|
|
41
45
|
*/
|
|
42
|
-
async getUserToken (connectionName: string, channelId: string, userId: string, code?: string) {
|
|
46
|
+
async getUserToken (connectionName: string, channelId: string, userId: string, code?: string) : Promise<TokenResponse> {
|
|
43
47
|
try {
|
|
44
48
|
const params = { connectionName, channelId, userId, code }
|
|
45
49
|
const response = await this.client.get('/api/usertoken/GetToken', { params })
|
|
46
|
-
return response.data
|
|
50
|
+
return { ...response.data, status: TokenRequestStatus.Success }
|
|
47
51
|
} catch (error: any) {
|
|
48
52
|
if (error.response?.status !== 404) {
|
|
49
53
|
logger.error(error)
|
|
50
54
|
}
|
|
51
|
-
return
|
|
55
|
+
return {
|
|
56
|
+
status: TokenRequestStatus.Failed,
|
|
57
|
+
token: undefined
|
|
58
|
+
}
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
|
|
@@ -59,14 +66,16 @@ export class UserTokenClient {
|
|
|
59
66
|
* @param channelId The channel ID.
|
|
60
67
|
* @returns A promise that resolves when the sign-out operation is complete.
|
|
61
68
|
*/
|
|
62
|
-
async signOut (userId: string, connectionName: string, channelId: string) {
|
|
69
|
+
async signOut (userId: string, connectionName: string, channelId: string) : Promise<void> {
|
|
63
70
|
try {
|
|
64
71
|
const params = { userId, connectionName, channelId }
|
|
65
72
|
const response = await this.client.delete('/api/usertoken/SignOut', { params })
|
|
66
|
-
|
|
73
|
+
if (response.status !== 200) {
|
|
74
|
+
throw new Error('Failed to sign out')
|
|
75
|
+
}
|
|
67
76
|
} catch (error: any) {
|
|
68
77
|
logger.error(error)
|
|
69
|
-
|
|
78
|
+
throw new Error('Failed to sign out')
|
|
70
79
|
}
|
|
71
80
|
}
|
|
72
81
|
|
|
@@ -80,12 +89,13 @@ export class UserTokenClient {
|
|
|
80
89
|
async getSignInResource (appId: string, cnxName: string, activity: Activity) : Promise<SigningResource> {
|
|
81
90
|
try {
|
|
82
91
|
const tokenExchangeState = {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
connectionName: cnxName,
|
|
93
|
+
conversation: activity.getConversationReference(),
|
|
94
|
+
relatesTo: activity.RelatesTo,
|
|
95
|
+
msAppId: appId
|
|
87
96
|
}
|
|
88
|
-
const
|
|
97
|
+
const tokenExchangeStateNormalized = normalizeTokenExchangeState(tokenExchangeState)
|
|
98
|
+
const state = Buffer.from(JSON.stringify(tokenExchangeStateNormalized)).toString('base64')
|
|
89
99
|
const params = { state }
|
|
90
100
|
const response = await this.client.get('/api/botsignin/GetSignInResource', { params })
|
|
91
101
|
return response.data as SigningResource
|
|
@@ -103,14 +113,14 @@ export class UserTokenClient {
|
|
|
103
113
|
* @param tokenExchangeRequest The token exchange request.
|
|
104
114
|
* @returns A promise that resolves to the exchanged token.
|
|
105
115
|
*/
|
|
106
|
-
async exchangeTokenAsync (userId: string, connectionName: string, channelId: string, tokenExchangeRequest: TokenExchangeRequest) {
|
|
116
|
+
async exchangeTokenAsync (userId: string, connectionName: string, channelId: string, tokenExchangeRequest: TokenExchangeRequest) : Promise<TokenResponse> {
|
|
107
117
|
try {
|
|
108
118
|
const params = { userId, connectionName, channelId }
|
|
109
119
|
const response = await this.client.post('/api/usertoken/exchange', tokenExchangeRequest, { params })
|
|
110
|
-
return response.data
|
|
120
|
+
return { ...response.data, status: TokenRequestStatus.Success }
|
|
111
121
|
} catch (error: any) {
|
|
112
122
|
logger.error(error)
|
|
113
|
-
return
|
|
123
|
+
return { status: TokenRequestStatus.Failed, token: undefined }
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
126
|
}
|
package/src/state/agentState.ts
CHANGED
|
@@ -16,6 +16,12 @@ export interface CachedAgentState {
|
|
|
16
16
|
hash: string
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export interface CustomKey {
|
|
20
|
+
channelId: string;
|
|
21
|
+
conversationId: string;
|
|
22
|
+
// TODO: namespace needs to be added
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
/**
|
|
20
26
|
* Manages the state of an Agent.
|
|
21
27
|
*/
|
|
@@ -45,11 +51,11 @@ export class AgentState {
|
|
|
45
51
|
* @param force Whether to force loading the state.
|
|
46
52
|
* @returns A promise that resolves to the loaded state.
|
|
47
53
|
*/
|
|
48
|
-
public async load (context: TurnContext, force = false): Promise<any> {
|
|
54
|
+
public async load (context: TurnContext, force = false, customKey?: CustomKey): Promise<any> {
|
|
49
55
|
const cached: CachedAgentState = context.turnState.get(this.stateKey)
|
|
50
56
|
|
|
51
57
|
if (force || !cached || !cached.state) {
|
|
52
|
-
const key = await this.
|
|
58
|
+
const key: string = await this.getStorageOrCustomKey(customKey, context)
|
|
53
59
|
logger.info(`Reading storage with key ${key}`)
|
|
54
60
|
const storedItem = await this.storage.read([key])
|
|
55
61
|
|
|
@@ -69,7 +75,7 @@ export class AgentState {
|
|
|
69
75
|
* @param force Whether to force saving the state.
|
|
70
76
|
* @returns A promise that resolves when the save operation is complete.
|
|
71
77
|
*/
|
|
72
|
-
public async saveChanges (context: TurnContext, force = false): Promise<void> {
|
|
78
|
+
public async saveChanges (context: TurnContext, force = false, customKey?: CustomKey): Promise<void> {
|
|
73
79
|
let cached: CachedAgentState = context.turnState.get(this.stateKey)
|
|
74
80
|
if (force || (cached && cached.hash !== this.calculateChangeHash(cached?.state))) {
|
|
75
81
|
if (!cached) {
|
|
@@ -78,7 +84,8 @@ export class AgentState {
|
|
|
78
84
|
cached.state.eTag = '*'
|
|
79
85
|
const changes: StoreItem = {} as StoreItem
|
|
80
86
|
|
|
81
|
-
const key = await this.
|
|
87
|
+
const key: string = await this.getStorageOrCustomKey(customKey, context)
|
|
88
|
+
|
|
82
89
|
changes[key] = cached.state
|
|
83
90
|
|
|
84
91
|
logger.info(`Writing storage with key ${key}`)
|
|
@@ -88,6 +95,17 @@ export class AgentState {
|
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
97
|
|
|
98
|
+
private async getStorageOrCustomKey (customKey: CustomKey | undefined, context: TurnContext) {
|
|
99
|
+
let key: string | undefined
|
|
100
|
+
if (customKey && customKey.channelId && customKey.conversationId) {
|
|
101
|
+
// TODO check ConversationState.ts line 40. This line below should follow the same pattern
|
|
102
|
+
key = `${customKey!.channelId}/conversations/${customKey!.conversationId}`
|
|
103
|
+
} else {
|
|
104
|
+
key = await this.storageKey(context)
|
|
105
|
+
}
|
|
106
|
+
return key
|
|
107
|
+
}
|
|
108
|
+
|
|
91
109
|
/**
|
|
92
110
|
* Clears the state from the turn context.
|
|
93
111
|
* @param context The turn context.
|
|
@@ -95,6 +113,7 @@ export class AgentState {
|
|
|
95
113
|
*/
|
|
96
114
|
public async clear (context: TurnContext): Promise<void> {
|
|
97
115
|
const emptyObjectToForceSave = { state: {}, hash: '' }
|
|
116
|
+
|
|
98
117
|
context.turnState.set(this.stateKey, emptyObjectToForceSave)
|
|
99
118
|
}
|
|
100
119
|
|
|
@@ -103,11 +122,11 @@ export class AgentState {
|
|
|
103
122
|
* @param context The turn context.
|
|
104
123
|
* @returns A promise that resolves when the delete operation is complete.
|
|
105
124
|
*/
|
|
106
|
-
public async delete (context: TurnContext): Promise<void> {
|
|
125
|
+
public async delete (context: TurnContext, customKey?: CustomKey): Promise<void> {
|
|
107
126
|
if (context.turnState.has(this.stateKey)) {
|
|
108
127
|
context.turnState.delete(this.stateKey)
|
|
109
128
|
}
|
|
110
|
-
const key = await this.
|
|
129
|
+
const key = await this.getStorageOrCustomKey(customKey, context)
|
|
111
130
|
logger.info(`Deleting storage with key ${key}`)
|
|
112
131
|
await this.storage.delete([key])
|
|
113
132
|
}
|
|
@@ -4,12 +4,69 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { TurnContext } from '../turnContext'
|
|
7
|
-
import { AgentState } from './agentState'
|
|
7
|
+
import { AgentState, CustomKey } from './agentState'
|
|
8
|
+
|
|
9
|
+
export interface StatePropertyAccessor<T = any> {
|
|
10
|
+
/**
|
|
11
|
+
* Deletes the persisted property from its backing storage object.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* The properties backing storage object SHOULD be loaded into memory on first access.
|
|
15
|
+
*
|
|
16
|
+
* ```JavaScript
|
|
17
|
+
* await myProperty.delete(context);
|
|
18
|
+
* ```
|
|
19
|
+
* @param context Context for the current turn of conversation with the user.
|
|
20
|
+
*/
|
|
21
|
+
delete(context: TurnContext): Promise<void>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Reads a persisted property from its backing storage object.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* The properties backing storage object SHOULD be loaded into memory on first access.
|
|
28
|
+
*
|
|
29
|
+
* If the property does not currently exist on the storage object and a `defaultValue` has been
|
|
30
|
+
* specified, a clone of the `defaultValue` SHOULD be copied to the storage object. If a
|
|
31
|
+
* `defaultValue` has not been specified then a value of `undefined` SHOULD be returned.
|
|
32
|
+
*
|
|
33
|
+
* ```JavaScript
|
|
34
|
+
* const value = await myProperty.get(context, { count: 0 });
|
|
35
|
+
* ```
|
|
36
|
+
* @param context Context for the current turn of conversation with the user.
|
|
37
|
+
*/
|
|
38
|
+
get(context: TurnContext): Promise<T | undefined>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Reads a persisted property from its backing storage object.
|
|
42
|
+
*
|
|
43
|
+
* @param context Context for the current turn of conversation with the user.
|
|
44
|
+
* @param defaultValue (Optional) default value to copy to the backing storage object if the property isn't found.
|
|
45
|
+
*/
|
|
46
|
+
get(context: TurnContext, defaultValue: T): Promise<T>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Assigns a new value to the properties backing storage object.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* The properties backing storage object SHOULD be loaded into memory on first access.
|
|
53
|
+
*
|
|
54
|
+
* Depending on the state systems implementation, an additional step may be required to
|
|
55
|
+
* persist the actual changes to disk.
|
|
56
|
+
*
|
|
57
|
+
* ```JavaScript
|
|
58
|
+
* await myProperty.set(context, value);
|
|
59
|
+
* ```
|
|
60
|
+
* @param context Context for the current turn of conversation with the user.
|
|
61
|
+
* @param value Value to assign.
|
|
62
|
+
*/
|
|
63
|
+
set(context: TurnContext, value: T): Promise<void>;
|
|
64
|
+
}
|
|
8
65
|
|
|
9
66
|
/**
|
|
10
67
|
* Provides access to an Agent state property.
|
|
11
68
|
*/
|
|
12
|
-
export class AgentStatePropertyAccessor<T = any> {
|
|
69
|
+
export class AgentStatePropertyAccessor<T = any> implements StatePropertyAccessor<T> {
|
|
13
70
|
/**
|
|
14
71
|
* Creates a new instance of AgentStatePropertyAccessor.
|
|
15
72
|
* @param state The agent state.
|
|
@@ -22,8 +79,8 @@ export class AgentStatePropertyAccessor<T = any> {
|
|
|
22
79
|
* @param context The turn context.
|
|
23
80
|
* @returns A promise that resolves when the delete operation is complete.
|
|
24
81
|
*/
|
|
25
|
-
async delete (context: TurnContext): Promise<void> {
|
|
26
|
-
const obj: any = await this.state.load(context)
|
|
82
|
+
async delete (context: TurnContext, customKey?: CustomKey): Promise<void> {
|
|
83
|
+
const obj: any = await this.state.load(context, false, customKey)
|
|
27
84
|
if (Object.prototype.hasOwnProperty.call(obj, this.name)) {
|
|
28
85
|
delete obj[this.name]
|
|
29
86
|
}
|
|
@@ -35,8 +92,8 @@ export class AgentStatePropertyAccessor<T = any> {
|
|
|
35
92
|
* @param defaultValue The default value to return if the property is not found.
|
|
36
93
|
* @returns A promise that resolves to the value of the property.
|
|
37
94
|
*/
|
|
38
|
-
async get (context: TurnContext, defaultValue?: T): Promise<T> {
|
|
39
|
-
const obj: any = await this.state.load(context)
|
|
95
|
+
async get (context: TurnContext, defaultValue?: T, customKey?: CustomKey): Promise<T> {
|
|
96
|
+
const obj: any = await this.state.load(context, false, customKey)
|
|
40
97
|
if (!Object.prototype.hasOwnProperty.call(obj, this.name) && defaultValue !== undefined) {
|
|
41
98
|
const clone: any =
|
|
42
99
|
typeof defaultValue === 'object' || Array.isArray(defaultValue)
|
|
@@ -54,8 +111,8 @@ export class AgentStatePropertyAccessor<T = any> {
|
|
|
54
111
|
* @param value The value to set.
|
|
55
112
|
* @returns A promise that resolves when the set operation is complete.
|
|
56
113
|
*/
|
|
57
|
-
async set (context: TurnContext, value: T): Promise<void> {
|
|
58
|
-
const obj: any = await this.state.load(context)
|
|
114
|
+
async set (context: TurnContext, value: T, customKey?: CustomKey): Promise<void> {
|
|
115
|
+
const obj: any = await this.state.load(context, false, customKey)
|
|
59
116
|
obj[this.name] = value
|
|
60
117
|
}
|
|
61
118
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"expressApi.js","sourceRoot":"","sources":["../../../src/agent-client/expressApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"applicationBuilder.js","sourceRoot":"","sources":["../../../src/app/applicationBuilder.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,yDAAqD;AAMrD,MAAa,kBAAkB;IAA/B;QACY,aAAQ,GAAwC,EAAE,CAAA;IA6B9D,CAAC;IA3BC,IAAc,OAAO;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAEM,WAAW,CAAE,OAAgB;QAClC,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;IAEM,oBAAoB,CAAE,gBAA8B;QACzD,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG,gBAAgB,CAAA;QACjD,OAAO,IAAI,CAAA;IACb,CAAC;IAEM,mBAAmB,CAAE,gBAAyB;QACnD,IAAI,CAAC,QAAQ,CAAC,gBAAgB,GAAG,gBAAgB,CAAA;QACjD,OAAO,IAAI,CAAA;IACb,CAAC;IAEM,kBAAkB,CAAE,qBAA4C;QACrE,IAAI,CAAC,QAAQ,CAAC,cAAc,GAAG,qBAAqB,CAAA;QACpD,OAAO,IAAI,CAAA;IACb,CAAC;IAEM,KAAK;QACV,OAAO,IAAI,mCAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC5C,CAAC;CACF;AA9BD,gDA8BC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"applicationOptions.js","sourceRoot":"","sources":["../../../src/app/applicationOptions.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authenticationOptions.js","sourceRoot":"","sources":["../../../../src/app/oauth/authenticationOptions.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { UserTokenClient } from '../../oauth/userTokenClient';
|
|
2
|
-
import { TurnContext } from '../../turnContext';
|
|
3
|
-
import { TurnState } from '../turnState';
|
|
4
|
-
import { Storage } from '../../storage';
|
|
5
|
-
export declare class WebChatOAuthFlowAppStyle {
|
|
6
|
-
userTokenClient?: UserTokenClient;
|
|
7
|
-
storage: Storage;
|
|
8
|
-
constructor(storage: Storage);
|
|
9
|
-
getOAuthToken(context: TurnContext, state: TurnState): Promise<string>;
|
|
10
|
-
signOut(context: TurnContext, state: TurnState): Promise<void>;
|
|
11
|
-
}
|