@microsoft/teamsfx 2.0.0-experimental.0 → 2.0.1-alpha.0d47bc042.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,20 +3,20 @@ import { ConfidentialClientApplication } from '@azure/msal-node';
3
3
  import { createHash } from 'crypto';
4
4
  import { Client } from '@microsoft/microsoft-graph-client';
5
5
  import { ManagedIdentityCredential } from '@azure/identity';
6
- import { ActivityTypes, Channels, TeamsInfo, CardFactory, ActionTypes, MessageFactory, StatusCodes, verifyStateOperationName, tokenExchangeOperationName, TurnContext, BotFrameworkAdapter } from 'botbuilder';
7
- import { Dialog } from 'botbuilder-dialogs';
6
+ import { ActivityTypes, Channels, TeamsInfo, CardFactory, ActionTypes, MessageFactory, StatusCodes, verifyStateOperationName, tokenExchangeOperationName, TurnContext, TeamsActivityHandler, MemoryStorage, UserState, ConversationState, BotFrameworkAdapter } from 'botbuilder';
7
+ import { Dialog, ComponentDialog, WaterfallDialog, DialogSet, DialogTurnStatus } from 'botbuilder-dialogs';
8
8
  import { v4 } from 'uuid';
9
9
  import axios from 'axios';
10
10
  import { Agent } from 'https';
11
11
  import * as path from 'path';
12
12
  import * as fs from 'fs';
13
+ import { __rest } from 'tslib';
13
14
  import { AdaptiveCards } from '@microsoft/adaptivecards-tools';
14
15
 
15
16
  // Copyright (c) Microsoft Corporation.
16
17
  // Licensed under the MIT license.
17
18
  /**
18
19
  * Error code to trace the error types.
19
- * @beta
20
20
  */
21
21
  var ErrorCode;
22
22
  (function (ErrorCode) {
@@ -40,6 +40,30 @@ var ErrorCode;
40
40
  * Channel is not supported error.
41
41
  */
42
42
  ErrorCode["ChannelNotSupported"] = "ChannelNotSupported";
43
+ /**
44
+ * Failed to retrieve sso token
45
+ */
46
+ ErrorCode["FailedToRetrieveSsoToken"] = "FailedToRetrieveSsoToken";
47
+ /**
48
+ * Failed to process sso handler
49
+ */
50
+ ErrorCode["FailedToProcessSsoHandler"] = "FailedToProcessSsoHandler";
51
+ /**
52
+ * Cannot find command
53
+ */
54
+ ErrorCode["CannotFindCommand"] = "CannotFindCommand";
55
+ /**
56
+ * Failed to run sso step
57
+ */
58
+ ErrorCode["FailedToRunSsoStep"] = "FailedToRunSsoStep";
59
+ /**
60
+ * Failed to run dedup step
61
+ */
62
+ ErrorCode["FailedToRunDedupStep"] = "FailedToRunDedupStep";
63
+ /**
64
+ * Sso activity handler is undefined
65
+ */
66
+ ErrorCode["SsoActivityHandlerIsUndefined"] = "SsoActivityHandlerIsUndefined";
43
67
  /**
44
68
  * Runtime is not supported error.
45
69
  */
@@ -95,6 +119,15 @@ ErrorMessage.NodejsRuntimeNotSupported = "{0} is not supported in Node.";
95
119
  ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token on behalf of user: {0}";
96
120
  // ChannelNotSupported Error
97
121
  ErrorMessage.OnlyMSTeamsChannelSupported = "{0} is only supported in MS Teams Channel";
122
+ ErrorMessage.FailedToProcessSsoHandler = "Failed to process sso handler: {0}";
123
+ // FailedToRetrieveSsoToken Error
124
+ ErrorMessage.FailedToRetrieveSsoToken = "Failed to retrieve sso token, user failed to finish the AAD consent flow.";
125
+ // CannotFindCommand Error
126
+ ErrorMessage.CannotFindCommand = "Cannot find command: {0}";
127
+ ErrorMessage.FailedToRunSsoStep = "Failed to run dialog to retrieve sso token: {0}";
128
+ ErrorMessage.FailedToRunDedupStep = "Failed to run dialog to remove duplicated messages: {0}";
129
+ // SsoActivityHandlerIsUndefined Error
130
+ ErrorMessage.SsoActivityHandlerIsNull = "Sso command can only be used or added when sso activity handler is not undefined";
98
131
  // IdentityTypeNotSupported Error
99
132
  ErrorMessage.IdentityTypeNotSupported = "{0} identity is not supported in {1}";
100
133
  // AuthorizationInfoError
@@ -105,10 +138,9 @@ ErrorMessage.EmptyParameter = "Parameter {0} is empty";
105
138
  ErrorMessage.DuplicateHttpsOptionProperty = "Axios HTTPS agent already defined value for property {0}";
106
139
  ErrorMessage.DuplicateApiKeyInHeader = "The request already defined api key in request header with name {0}.";
107
140
  ErrorMessage.DuplicateApiKeyInQueryParam = "The request already defined api key in query parameter with name {0}.";
141
+ ErrorMessage.OnlySupportInQueryActivity = "The handleMessageExtensionQueryWithToken only support in handleTeamsMessagingExtensionQuery with composeExtension/query type.";
108
142
  /**
109
143
  * Error class with code and message thrown by the SDK.
110
- *
111
- * @beta
112
144
  */
113
145
  class ErrorWithCode extends Error {
114
146
  /**
@@ -116,8 +148,6 @@ class ErrorWithCode extends Error {
116
148
  *
117
149
  * @param {string} message - error message.
118
150
  * @param {ErrorCode} code - error code.
119
- *
120
- * @beta
121
151
  */
122
152
  constructor(message, code) {
123
153
  if (!code) {
@@ -135,8 +165,6 @@ class ErrorWithCode extends Error {
135
165
  // Licensed under the MIT license.
136
166
  /**
137
167
  * Log level.
138
- *
139
- * @beta
140
168
  */
141
169
  var LogLevel;
142
170
  (function (LogLevel) {
@@ -161,8 +189,6 @@ var LogLevel;
161
189
  * Update log level helper.
162
190
  *
163
191
  * @param { LogLevel } level - log level in configuration
164
- *
165
- * @beta
166
192
  */
167
193
  function setLogLevel(level) {
168
194
  internalLogger.level = level;
@@ -171,8 +197,6 @@ function setLogLevel(level) {
171
197
  * Get log level.
172
198
  *
173
199
  * @returns Log level
174
- *
175
- * @beta
176
200
  */
177
201
  function getLogLevel() {
178
202
  return internalLogger.level;
@@ -247,8 +271,6 @@ const internalLogger = new InternalLogger();
247
271
  * error: console.error,
248
272
  * });
249
273
  * ```
250
- *
251
- * @beta
252
274
  */
253
275
  function setLogger(logger) {
254
276
  internalLogger.customLogger = logger;
@@ -266,8 +288,6 @@ function setLogger(logger) {
266
288
  * }
267
289
  * });
268
290
  * ```
269
- *
270
- * @beta
271
291
  */
272
292
  function setLogFunction(logFunction) {
273
293
  internalLogger.customLogFunction = logFunction;
@@ -310,6 +330,7 @@ function getUserInfoFromSsoToken(ssoToken) {
310
330
  const userInfo = {
311
331
  displayName: tokenObject.name,
312
332
  objectId: tokenObject.oid,
333
+ tenantId: tokenObject.tid,
313
334
  preferredUserName: "",
314
335
  };
315
336
  if (tokenObject.ver === "2.0") {
@@ -431,8 +452,6 @@ function parseCertificate(certificateContent) {
431
452
  *
432
453
  * @remarks
433
454
  * Only works in in server side.
434
- *
435
- * @beta
436
455
  */
437
456
  class AppCredential {
438
457
  /**
@@ -445,8 +464,6 @@ class AppCredential {
445
464
  *
446
465
  * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config.
447
466
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
448
- *
449
- * @beta
450
467
  */
451
468
  constructor(authConfig) {
452
469
  internalLogger.info("Create M365 tenant credential");
@@ -476,8 +493,6 @@ class AppCredential {
476
493
  *
477
494
  * @returns Access token with expected scopes.
478
495
  * Throw error if get access token failed.
479
- *
480
- * @beta
481
496
  */
482
497
  async getToken(scopes, options) {
483
498
  let accessToken;
@@ -517,7 +532,10 @@ class AppCredential {
517
532
  */
518
533
  loadAndValidateConfig(config) {
519
534
  internalLogger.verbose("Validate authentication configuration");
520
- if (config.clientId && (config.clientSecret || config.certificateContent) && config.tenantId) {
535
+ if (config.clientId &&
536
+ (config.clientSecret || config.certificateContent) &&
537
+ config.tenantId &&
538
+ config.authorityHost) {
521
539
  return config;
522
540
  }
523
541
  const missingValues = [];
@@ -530,6 +548,9 @@ class AppCredential {
530
548
  if (!config.tenantId) {
531
549
  missingValues.push("tenantId");
532
550
  }
551
+ if (!config.authorityHost) {
552
+ missingValues.push("authorityHost");
553
+ }
533
554
  const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingValues.join(", "), "undefined");
534
555
  internalLogger.error(errorMsg);
535
556
  throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);
@@ -547,8 +568,6 @@ class AppCredential {
547
568
  *
548
569
  * @remarks
549
570
  * Can only be used in server side.
550
- *
551
- * @beta
552
571
  */
553
572
  class OnBehalfOfUserCredential {
554
573
  /**
@@ -563,8 +582,6 @@ class OnBehalfOfUserCredential {
563
582
  * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config.
564
583
  * @throws {@link ErrorCode|InternalError} when SSO token is not valid.
565
584
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
566
- *
567
- * @beta
568
585
  */
569
586
  constructor(ssoToken, config) {
570
587
  internalLogger.info("Get on behalf of user credential");
@@ -625,8 +642,6 @@ class OnBehalfOfUserCredential {
625
642
  * @remarks
626
643
  * If scopes is empty string or array, it returns SSO token.
627
644
  * If scopes is non-empty, it returns access token for target scope.
628
- *
629
- * @beta
630
645
  */
631
646
  async getToken(scopes, options) {
632
647
  validateScopesType(scopes);
@@ -677,8 +692,6 @@ class OnBehalfOfUserCredential {
677
692
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
678
693
  *
679
694
  * @returns Basic user info with user displayName, objectId and preferredUserName.
680
- *
681
- * @beta
682
695
  */
683
696
  getUserInfo() {
684
697
  internalLogger.info("Get basic user info from SSO token");
@@ -710,44 +723,44 @@ class OnBehalfOfUserCredential {
710
723
  *
711
724
  * @remarks
712
725
  * Can only be used within Teams.
713
- *
714
- * @beta
715
726
  */
716
727
  class TeamsUserCredential {
717
728
  /**
718
729
  * Constructor of TeamsUserCredential.
719
730
  * @remarks
720
731
  * Can only be used within Teams.
721
- * @beta
722
732
  */
723
733
  constructor(authConfig) {
724
734
  throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), ErrorCode.RuntimeNotSupported);
725
735
  }
726
736
  /**
727
737
  * Popup login page to get user's access token with specific scopes.
738
+ *
739
+ * @param {string[]} resources - The optional list of resources for full trust Teams apps.
740
+ *
728
741
  * @remarks
729
742
  * Can only be used within Teams.
730
- * @beta
731
743
  */
732
- async login(scopes) {
744
+ async login(scopes, resources) {
733
745
  throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), ErrorCode.RuntimeNotSupported);
734
746
  }
735
747
  /**
736
748
  * Get access token from credential.
737
749
  * @remarks
738
750
  * Can only be used within Teams.
739
- * @beta
740
751
  */
741
752
  async getToken(scopes, options) {
742
753
  throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), ErrorCode.RuntimeNotSupported);
743
754
  }
744
755
  /**
745
756
  * Get basic user info from SSO token
757
+ *
758
+ * @param {string[]} resources - The optional list of resources for full trust Teams apps.
759
+ *
746
760
  * @remarks
747
761
  * Can only be used within Teams.
748
- * @beta
749
762
  */
750
- getUserInfo() {
763
+ getUserInfo(resources) {
751
764
  throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), ErrorCode.RuntimeNotSupported);
752
765
  }
753
766
  }
@@ -756,8 +769,6 @@ class TeamsUserCredential {
756
769
  const defaultScope = "https://graph.microsoft.com/.default";
757
770
  /**
758
771
  * Microsoft Graph auth provider for Teams Framework
759
- *
760
- * @beta
761
772
  */
762
773
  class MsGraphAuthProvider {
763
774
  /**
@@ -769,8 +780,6 @@ class MsGraphAuthProvider {
769
780
  * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
770
781
  *
771
782
  * @returns An instance of MsGraphAuthProvider.
772
- *
773
- * @beta
774
783
  */
775
784
  constructor(teamsfx, scopes) {
776
785
  this.teamsfx = teamsfx;
@@ -862,8 +871,6 @@ class MsGraphAuthProvider {
862
871
  * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
863
872
  *
864
873
  * @returns Graph client with specified scopes.
865
- *
866
- * @beta
867
874
  */
868
875
  function createMicrosoftGraphClient(teamsfx, scopes) {
869
876
  internalLogger.info("Create Microsoft Graph Client");
@@ -891,8 +898,6 @@ const defaultSQLScope = "https://database.windows.net/";
891
898
  * @throws {@link ErrorCode|InvalidConfiguration} when SQL config resource configuration is invalid.
892
899
  * @throws {@link ErrorCode|InternalError} when get user MSI token failed or MSI token is invalid.
893
900
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
894
- *
895
- * @beta
896
901
  */
897
902
  async function getTediousConnectionConfig(teamsfx, databaseName) {
898
903
  internalLogger.info("Get SQL configuration");
@@ -1047,8 +1052,6 @@ var TediousAuthenticationType;
1047
1052
  // Licensed under the MIT license.
1048
1053
  /**
1049
1054
  * Identity type to use in authentication.
1050
- *
1051
- * @beta
1052
1055
  */
1053
1056
  var IdentityType;
1054
1057
  (function (IdentityType) {
@@ -1066,8 +1069,6 @@ var IdentityType;
1066
1069
  const invokeResponseType = "invokeResponse";
1067
1070
  /**
1068
1071
  * Response body returned for a token exchange invoke activity.
1069
- *
1070
- * @beta
1071
1072
  */
1072
1073
  class TokenExchangeInvokeResponse {
1073
1074
  constructor(id, failureDetail) {
@@ -1122,8 +1123,6 @@ class TokenExchangeInvokeResponse {
1122
1123
  * }
1123
1124
  * ]));
1124
1125
  * ```
1125
- *
1126
- * @beta
1127
1126
  */
1128
1127
  class TeamsBotSsoPrompt extends Dialog {
1129
1128
  /**
@@ -1135,8 +1134,6 @@ class TeamsBotSsoPrompt extends Dialog {
1135
1134
  *
1136
1135
  * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
1137
1136
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1138
- *
1139
- * @beta
1140
1137
  */
1141
1138
  constructor(teamsfx, dialogId, settings) {
1142
1139
  super(dialogId);
@@ -1159,8 +1156,6 @@ class TeamsBotSsoPrompt extends Dialog {
1159
1156
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1160
1157
  *
1161
1158
  * @returns A `Promise` representing the asynchronous operation.
1162
- *
1163
- * @beta
1164
1159
  */
1165
1160
  async beginDialog(dc) {
1166
1161
  var _a;
@@ -1208,8 +1203,6 @@ class TeamsBotSsoPrompt extends Dialog {
1208
1203
  *
1209
1204
  * @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.
1210
1205
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1211
- *
1212
- * @beta
1213
1206
  */
1214
1207
  async continueDialog(dc) {
1215
1208
  var _a;
@@ -1260,9 +1253,6 @@ class TeamsBotSsoPrompt extends Dialog {
1260
1253
  if (!this.teamsfx.hasConfig("tenantId")) {
1261
1254
  missingConfigurations.push("tenantId");
1262
1255
  }
1263
- if (!this.teamsfx.hasConfig("applicationIdUri")) {
1264
- missingConfigurations.push("applicationIdUri");
1265
- }
1266
1256
  if (missingConfigurations.length != 0) {
1267
1257
  const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingConfigurations.join(", "), "undefined");
1268
1258
  internalLogger.error(errorMsg);
@@ -1313,9 +1303,7 @@ class TeamsBotSsoPrompt extends Dialog {
1313
1303
  internalLogger.verbose("Sign in link: " + signInLink);
1314
1304
  const tokenExchangeResource = {
1315
1305
  id: v4(),
1316
- uri: this.teamsfx.getConfig("applicationIdUri").replace(/\/$/, "") + "/access_as_user",
1317
1306
  };
1318
- internalLogger.verbose("Token exchange resource uri: " + tokenExchangeResource.uri);
1319
1307
  return {
1320
1308
  signInLink: signInLink,
1321
1309
  tokenExchangeResource: tokenExchangeResource,
@@ -1414,8 +1402,6 @@ class TeamsBotSsoPrompt extends Dialog {
1414
1402
  * ```typescript
1415
1403
  * const client = createApiClient("https://my-api-endpoint-base-url", new BasicAuthProvider("xxx","xxx"));
1416
1404
  * ```
1417
- *
1418
- * @beta
1419
1405
  */
1420
1406
  function createApiClient(apiEndpoint, authProvider) {
1421
1407
  // Add a request interceptor
@@ -1431,14 +1417,10 @@ function createApiClient(apiEndpoint, authProvider) {
1431
1417
  // Copyright (c) Microsoft Corporation.
1432
1418
  /**
1433
1419
  * Provider that handles Bearer Token authentication
1434
- *
1435
- * @beta
1436
1420
  */
1437
1421
  class BearerTokenAuthProvider {
1438
1422
  /**
1439
1423
  * @param { () => Promise<string> } getToken - Function that returns the content of bearer token used in http request
1440
- *
1441
- * @beta
1442
1424
  */
1443
1425
  constructor(getToken) {
1444
1426
  this.getToken = getToken;
@@ -1452,8 +1434,6 @@ class BearerTokenAuthProvider {
1452
1434
  * @returns Updated axios request config.
1453
1435
  *
1454
1436
  * @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header already exists in request configuration.
1455
- *
1456
- * @beta
1457
1437
  */
1458
1438
  async AddAuthenticationInfo(config) {
1459
1439
  const token = await this.getToken();
@@ -1471,8 +1451,6 @@ class BearerTokenAuthProvider {
1471
1451
  // Copyright (c) Microsoft Corporation.
1472
1452
  /**
1473
1453
  * Provider that handles Basic authentication
1474
- *
1475
- * @beta
1476
1454
  */
1477
1455
  class BasicAuthProvider {
1478
1456
  /**
@@ -1482,8 +1460,6 @@ class BasicAuthProvider {
1482
1460
  *
1483
1461
  * @throws {@link ErrorCode|InvalidParameter} - when username or password is empty.
1484
1462
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1485
- *
1486
- * @beta
1487
1463
  */
1488
1464
  constructor(userName, password) {
1489
1465
  if (!userName) {
@@ -1505,8 +1481,6 @@ class BasicAuthProvider {
1505
1481
  *
1506
1482
  * @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header or auth property already exists in request configuration.
1507
1483
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1508
- *
1509
- * @beta
1510
1484
  */
1511
1485
  async AddAuthenticationInfo(config) {
1512
1486
  if (config.headers && config.headers["Authorization"]) {
@@ -1526,8 +1500,6 @@ class BasicAuthProvider {
1526
1500
  // Copyright (c) Microsoft Corporation.
1527
1501
  /**
1528
1502
  * Provider that handles API Key authentication
1529
- *
1530
- * @beta
1531
1503
  */
1532
1504
  class ApiKeyProvider {
1533
1505
  /**
@@ -1538,8 +1510,6 @@ class ApiKeyProvider {
1538
1510
  *
1539
1511
  * @throws {@link ErrorCode|InvalidParameter} - when key name or key value is empty.
1540
1512
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1541
- *
1542
- * @beta
1543
1513
  */
1544
1514
  constructor(keyName, keyValue, keyLocation) {
1545
1515
  if (!keyName) {
@@ -1562,8 +1532,6 @@ class ApiKeyProvider {
1562
1532
  *
1563
1533
  * @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when API key already exists in request header or url query parameter.
1564
1534
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1565
- *
1566
- * @beta
1567
1535
  */
1568
1536
  async AddAuthenticationInfo(config) {
1569
1537
  switch (this.keyLocation) {
@@ -1580,8 +1548,12 @@ class ApiKeyProvider {
1580
1548
  if (!config.params) {
1581
1549
  config.params = {};
1582
1550
  }
1583
- const url = new URL(config.url, config.baseURL);
1584
- if (config.params[this.keyName] || url.searchParams.has(this.keyName)) {
1551
+ let urlHasDefinedApiKey = false;
1552
+ if (config.url) {
1553
+ const url = new URL(config.url, config.baseURL);
1554
+ urlHasDefinedApiKey = url.searchParams.has(this.keyName);
1555
+ }
1556
+ if (config.params[this.keyName] || urlHasDefinedApiKey) {
1585
1557
  throw new ErrorWithCode(formatString(ErrorMessage.DuplicateApiKeyInQueryParam, this.keyName), ErrorCode.AuthorizationInfoAlreadyExists);
1586
1558
  }
1587
1559
  config.params[this.keyName] = this.keyValue;
@@ -1592,8 +1564,6 @@ class ApiKeyProvider {
1592
1564
  }
1593
1565
  /**
1594
1566
  * Define available location for API Key location
1595
- *
1596
- * @beta
1597
1567
  */
1598
1568
  var ApiKeyLocation;
1599
1569
  (function (ApiKeyLocation) {
@@ -1610,8 +1580,6 @@ var ApiKeyLocation;
1610
1580
  // Copyright (c) Microsoft Corporation.
1611
1581
  /**
1612
1582
  * Provider that handles Certificate authentication
1613
- *
1614
- * @beta
1615
1583
  */
1616
1584
  class CertificateAuthProvider {
1617
1585
  /**
@@ -1619,8 +1587,6 @@ class CertificateAuthProvider {
1619
1587
  * @param { SecureContextOptions } certOption - information about the cert used in http requests
1620
1588
  *
1621
1589
  * @throws {@link ErrorCode|InvalidParameter} - when cert option is empty.
1622
- *
1623
- * @beta
1624
1590
  */
1625
1591
  constructor(certOption) {
1626
1592
  if (certOption && Object.keys(certOption).length !== 0) {
@@ -1639,8 +1605,6 @@ class CertificateAuthProvider {
1639
1605
  * @returns Updated axios request config.
1640
1606
  *
1641
1607
  * @throws {@link ErrorCode|InvalidParameter} - when custom httpsAgent in the request has duplicate properties with certOption provided in constructor.
1642
- *
1643
- * @beta
1644
1608
  */
1645
1609
  async AddAuthenticationInfo(config) {
1646
1610
  if (!config.httpsAgent) {
@@ -1724,7 +1688,6 @@ const ReservedKey = new Set([
1724
1688
  ]);
1725
1689
  /**
1726
1690
  * A class providing credential and configuration.
1727
- * @beta
1728
1691
  */
1729
1692
  class TeamsFx {
1730
1693
  /**
@@ -1734,16 +1697,15 @@ class TeamsFx {
1734
1697
  * @param customConfig - key/value pairs of customized configuration that overrides default ones.
1735
1698
  *
1736
1699
  * @throws {@link ErrorCode|IdentityTypeNotSupported} when setting app identity in browser.
1737
- *
1738
- * @beta
1739
1700
  */
1740
1701
  constructor(identityType, customConfig) {
1741
1702
  this.identityType = identityType !== null && identityType !== void 0 ? identityType : IdentityType.User;
1742
1703
  this.configuration = new Map();
1743
1704
  this.loadFromEnv();
1744
1705
  if (customConfig) {
1745
- for (const key of Object.keys(customConfig)) {
1746
- const value = customConfig[key];
1706
+ const myConfig = Object.assign({}, customConfig);
1707
+ for (const key of Object.keys(myConfig)) {
1708
+ const value = myConfig[key];
1747
1709
  if (value) {
1748
1710
  this.configuration.set(key, value);
1749
1711
  }
@@ -1754,7 +1716,6 @@ class TeamsFx {
1754
1716
  * Identity type set by user.
1755
1717
  *
1756
1718
  * @returns identity type.
1757
- * @beta
1758
1719
  */
1759
1720
  getIdentityType() {
1760
1721
  return this.identityType;
@@ -1767,7 +1728,6 @@ class TeamsFx {
1767
1728
  * identity is chose, will return {@link AppCredential}.
1768
1729
  *
1769
1730
  * @returns instance implements TokenCredential interface.
1770
- * @beta
1771
1731
  */
1772
1732
  getCredential() {
1773
1733
  if (this.identityType === IdentityType.User) {
@@ -1787,10 +1747,10 @@ class TeamsFx {
1787
1747
  }
1788
1748
  /**
1789
1749
  * Get user information.
1750
+ * @param {string[]} resources - The optional list of resources for full trust Teams apps.
1790
1751
  * @returns UserInfo object.
1791
- * @beta
1792
1752
  */
1793
- async getUserInfo() {
1753
+ async getUserInfo(resources) {
1794
1754
  if (this.identityType !== IdentityType.User) {
1795
1755
  const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported, this.identityType.toString(), "TeamsFx");
1796
1756
  internalLogger.error(errorMsg);
@@ -1812,22 +1772,20 @@ class TeamsFx {
1812
1772
  * await teamsfx.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string
1813
1773
  * ```
1814
1774
  * @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.
1775
+ * @param {string[]} resources - The optional list of resources for full trust Teams apps.
1815
1776
  *
1816
1777
  * @throws {@link ErrorCode|InternalError} when failed to login with unknown error.
1817
1778
  * @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.
1818
1779
  * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
1819
1780
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
1820
- *
1821
- * @beta
1822
1781
  */
1823
- async login(scopes) {
1782
+ async login(scopes, resources) {
1824
1783
  throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "login"), ErrorCode.RuntimeNotSupported);
1825
1784
  }
1826
1785
  /**
1827
1786
  * Set SSO token when using user identity in NodeJS.
1828
1787
  * @param {string} ssoToken - used for on behalf of user flow.
1829
1788
  * @returns self instance.
1830
- * @beta
1831
1789
  */
1832
1790
  setSsoToken(ssoToken) {
1833
1791
  if (this.identityType !== IdentityType.User) {
@@ -1840,7 +1798,6 @@ class TeamsFx {
1840
1798
  * Usually used by service plugins to retrieve specific config
1841
1799
  * @param {string} key - configuration key.
1842
1800
  * @returns value in configuration.
1843
- * @beta
1844
1801
  */
1845
1802
  getConfig(key) {
1846
1803
  const value = this.configuration.get(key);
@@ -1855,7 +1812,6 @@ class TeamsFx {
1855
1812
  * Check the value of specific key.
1856
1813
  * @param {string} key - configuration key.
1857
1814
  * @returns true if corresponding value is not empty string.
1858
- * @beta
1859
1815
  */
1860
1816
  hasConfig(key) {
1861
1817
  const value = this.configuration.get(key);
@@ -1864,7 +1820,6 @@ class TeamsFx {
1864
1820
  /**
1865
1821
  * Get all configurations.
1866
1822
  * @returns key value mappings.
1867
- * @beta
1868
1823
  */
1869
1824
  getConfigs() {
1870
1825
  const config = {};
@@ -1906,171 +1861,388 @@ class TeamsFx {
1906
1861
  // Copyright (c) Microsoft Corporation.
1907
1862
  // Licensed under the MIT license.
1908
1863
  /**
1909
- * @internal
1864
+ * The target type where the notification will be sent to.
1865
+ *
1866
+ * @remarks
1867
+ * - "Channel" means to a team channel. (By default, notification to a team will be sent to its "General" channel.)
1868
+ * - "Group" means to a group chat.
1869
+ * - "Person" means to a personal chat.
1910
1870
  */
1911
- function cloneConversation(conversation) {
1912
- return JSON.parse(JSON.stringify(conversation));
1913
- }
1871
+ var NotificationTargetType;
1872
+ (function (NotificationTargetType) {
1873
+ /**
1874
+ * The notification will be sent to a team channel.
1875
+ * (By default, notification to a team will be sent to its "General" channel.)
1876
+ */
1877
+ NotificationTargetType["Channel"] = "Channel";
1878
+ /**
1879
+ * The notification will be sent to a group chat.
1880
+ */
1881
+ NotificationTargetType["Group"] = "Group";
1882
+ /**
1883
+ * The notification will be sent to a personal chat.
1884
+ */
1885
+ NotificationTargetType["Person"] = "Person";
1886
+ })(NotificationTargetType || (NotificationTargetType = {}));
1887
+ /**
1888
+ * Options used to control how the response card will be sent to users.
1889
+ */
1890
+ var AdaptiveCardResponse;
1891
+ (function (AdaptiveCardResponse) {
1892
+ /**
1893
+ * The response card will be replaced the current one for the interactor who trigger the action.
1894
+ */
1895
+ AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForInteractor"] = 0] = "ReplaceForInteractor";
1896
+ /**
1897
+ * The response card will be replaced the current one for all users in the chat.
1898
+ */
1899
+ AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForAll"] = 1] = "ReplaceForAll";
1900
+ /**
1901
+ * The response card will be sent as a new message for all users in the chat.
1902
+ */
1903
+ AdaptiveCardResponse[AdaptiveCardResponse["NewForAll"] = 2] = "NewForAll";
1904
+ })(AdaptiveCardResponse || (AdaptiveCardResponse = {}));
1905
+ /**
1906
+ * Status code for an `application/vnd.microsoft.error` invoke response.
1907
+ */
1908
+ var InvokeResponseErrorCode;
1909
+ (function (InvokeResponseErrorCode) {
1910
+ /**
1911
+ * Invalid request.
1912
+ */
1913
+ InvokeResponseErrorCode[InvokeResponseErrorCode["BadRequest"] = 400] = "BadRequest";
1914
+ /**
1915
+ * Internal server error.
1916
+ */
1917
+ InvokeResponseErrorCode[InvokeResponseErrorCode["InternalServerError"] = 500] = "InternalServerError";
1918
+ })(InvokeResponseErrorCode || (InvokeResponseErrorCode = {}));
1919
+
1914
1920
  /**
1921
+ * Available response type for an adaptive card invoke response.
1915
1922
  * @internal
1916
1923
  */
1917
- function getTargetType(conversationReference) {
1918
- var _a;
1919
- const conversationType = (_a = conversationReference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
1920
- if (conversationType === "personal") {
1921
- return "Person";
1924
+ var InvokeResponseType;
1925
+ (function (InvokeResponseType) {
1926
+ InvokeResponseType["AdaptiveCard"] = "application/vnd.microsoft.card.adaptive";
1927
+ InvokeResponseType["Message"] = "application/vnd.microsoft.activity.message";
1928
+ InvokeResponseType["Error"] = "application/vnd.microsoft.error";
1929
+ })(InvokeResponseType || (InvokeResponseType = {}));
1930
+ /**
1931
+ * Provides methods for formatting various invoke responses a bot can send to respond to an invoke request.
1932
+ *
1933
+ * @remarks
1934
+ * All of these functions return an {@link InvokeResponse} object, which can be
1935
+ * passed as input to generate a new `invokeResponse` activity.
1936
+ *
1937
+ * This example sends an invoke response that contains an adaptive card.
1938
+ *
1939
+ * ```typescript
1940
+ *
1941
+ * const myCard = {
1942
+ * type: "AdaptiveCard",
1943
+ * body: [
1944
+ * {
1945
+ * "type": "TextBlock",
1946
+ * "text": "This is a sample card"
1947
+ * }],
1948
+ * $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
1949
+ * version: "1.4"
1950
+ * };
1951
+ *
1952
+ * const invokeResponse = InvokeResponseFactory.adaptiveCard(myCard);
1953
+ * await context.sendActivity({
1954
+ * type: ActivityTypes.InvokeResponse,
1955
+ * value: invokeResponse,
1956
+ * });
1957
+ * ```
1958
+ */
1959
+ class InvokeResponseFactory {
1960
+ /**
1961
+ * Create an invoke response from a text message.
1962
+ * The type of the invoke response is `application/vnd.microsoft.activity.message`
1963
+ * indicates the request was successfully processed.
1964
+ *
1965
+ * @param message A text message included in a invoke response.
1966
+ *
1967
+ * @returns {InvokeResponse} An InvokeResponse object.
1968
+ */
1969
+ static textMessage(message) {
1970
+ if (!message) {
1971
+ throw new Error("The text message cannot be null or empty");
1972
+ }
1973
+ return {
1974
+ status: StatusCodes.OK,
1975
+ body: {
1976
+ statusCode: StatusCodes.OK,
1977
+ type: InvokeResponseType.Message,
1978
+ value: message,
1979
+ },
1980
+ };
1922
1981
  }
1923
- else if (conversationType === "groupChat") {
1924
- return "Group";
1982
+ /**
1983
+ * Create an invoke response from an adaptive card.
1984
+ *
1985
+ * The type of the invoke response is `application/vnd.microsoft.card.adaptive` indicates
1986
+ * the request was successfully processed, and the response includes an adaptive card
1987
+ * that the client should display in place of the current one.
1988
+ *
1989
+ * @param card The adaptive card JSON payload.
1990
+ *
1991
+ * @returns {InvokeResponse} An InvokeResponse object.
1992
+ */
1993
+ static adaptiveCard(card) {
1994
+ if (!card) {
1995
+ throw new Error("The adaptive card content cannot be null or undefined");
1996
+ }
1997
+ return {
1998
+ status: StatusCodes.OK,
1999
+ body: {
2000
+ statusCode: StatusCodes.OK,
2001
+ type: InvokeResponseType.AdaptiveCard,
2002
+ value: card,
2003
+ },
2004
+ };
1925
2005
  }
1926
- else if (conversationType === "channel") {
1927
- return "Channel";
2006
+ /**
2007
+ * Create an invoke response with error code and message.
2008
+ *
2009
+ * The type of the invoke response is `application/vnd.microsoft.error` indicates
2010
+ * the request was failed to processed.
2011
+ *
2012
+ * @param errorCode The status code indicates error, available values:
2013
+ * - 400 (BadRequest): indicate the incoming request was invalid.
2014
+ * - 500 (InternalServerError): indicate an unexpected error occurred.
2015
+ * @param errorMessage The error message.
2016
+ *
2017
+ * @returns {InvokeResponse} An InvokeResponse object.
2018
+ */
2019
+ static errorResponse(errorCode, errorMessage) {
2020
+ return {
2021
+ status: StatusCodes.OK,
2022
+ body: {
2023
+ statusCode: errorCode,
2024
+ type: InvokeResponseType.Error,
2025
+ value: {
2026
+ code: errorCode.toString(),
2027
+ message: errorMessage,
2028
+ },
2029
+ },
2030
+ };
1928
2031
  }
1929
- else {
1930
- return undefined;
2032
+ /**
2033
+ * Create an invoke response with status code and response value.
2034
+ * @param statusCode The status code.
2035
+ * @param body The value of the response body.
2036
+ *
2037
+ * @returns {InvokeResponse} An InvokeResponse object.
2038
+ */
2039
+ static createInvokeResponse(statusCode, body) {
2040
+ return {
2041
+ status: statusCode,
2042
+ body: body,
2043
+ };
1931
2044
  }
1932
- }
2045
+ }
2046
+
1933
2047
  /**
1934
2048
  * @internal
1935
2049
  */
1936
- function getTeamsBotInstallationId(context) {
1937
- var _a, _b, _c, _d;
1938
- return (_d = (_c = (_b = (_a = context.activity) === null || _a === void 0 ? void 0 : _a.channelData) === null || _b === void 0 ? void 0 : _b.team) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : context.activity.conversation.id;
2050
+ class CardActionMiddleware {
2051
+ constructor(handlers) {
2052
+ this.actionHandlers = [];
2053
+ this.defaultMessage = "Your response was sent to the app";
2054
+ if (handlers && handlers.length > 0) {
2055
+ this.actionHandlers.push(...handlers);
2056
+ }
2057
+ }
2058
+ async onTurn(context, next) {
2059
+ var _a, _b, _c;
2060
+ if (context.activity.name === "adaptiveCard/action") {
2061
+ const action = context.activity.value.action;
2062
+ const actionVerb = action.verb;
2063
+ for (const handler of this.actionHandlers) {
2064
+ if (((_a = handler.triggerVerb) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (actionVerb === null || actionVerb === void 0 ? void 0 : actionVerb.toLowerCase())) {
2065
+ let response;
2066
+ try {
2067
+ response = await handler.handleActionInvoked(context, action.data);
2068
+ }
2069
+ catch (error) {
2070
+ const errorResponse = InvokeResponseFactory.errorResponse(InvokeResponseErrorCode.InternalServerError, error.message);
2071
+ await this.sendInvokeResponse(context, errorResponse);
2072
+ throw error;
2073
+ }
2074
+ const responseType = (_b = response.body) === null || _b === void 0 ? void 0 : _b.type;
2075
+ switch (responseType) {
2076
+ case InvokeResponseType.AdaptiveCard:
2077
+ const card = (_c = response.body) === null || _c === void 0 ? void 0 : _c.value;
2078
+ if (!card) {
2079
+ const errorMessage = "Adaptive card content cannot be found in the response body";
2080
+ await this.sendInvokeResponse(context, InvokeResponseFactory.errorResponse(InvokeResponseErrorCode.InternalServerError, errorMessage));
2081
+ throw new Error(errorMessage);
2082
+ }
2083
+ if (card.refresh && handler.adaptiveCardResponse !== AdaptiveCardResponse.NewForAll) {
2084
+ // Card won't be refreshed with AdaptiveCardResponse.ReplaceForInteractor.
2085
+ // So set to AdaptiveCardResponse.ReplaceForAll here.
2086
+ handler.adaptiveCardResponse = AdaptiveCardResponse.ReplaceForAll;
2087
+ }
2088
+ const activity = MessageFactory.attachment(CardFactory.adaptiveCard(card));
2089
+ if (handler.adaptiveCardResponse === AdaptiveCardResponse.NewForAll) {
2090
+ await this.sendInvokeResponse(context, InvokeResponseFactory.textMessage(this.defaultMessage));
2091
+ await context.sendActivity(activity);
2092
+ }
2093
+ else if (handler.adaptiveCardResponse === AdaptiveCardResponse.ReplaceForAll) {
2094
+ activity.id = context.activity.replyToId;
2095
+ await context.updateActivity(activity);
2096
+ await this.sendInvokeResponse(context, response);
2097
+ }
2098
+ else {
2099
+ await this.sendInvokeResponse(context, response);
2100
+ }
2101
+ break;
2102
+ case InvokeResponseType.Message:
2103
+ case InvokeResponseType.Error:
2104
+ default:
2105
+ await this.sendInvokeResponse(context, response);
2106
+ break;
2107
+ }
2108
+ break;
2109
+ }
2110
+ }
2111
+ }
2112
+ await next();
2113
+ }
2114
+ async sendInvokeResponse(context, response) {
2115
+ await context.sendActivity({
2116
+ type: ActivityTypes.InvokeResponse,
2117
+ value: response,
2118
+ });
2119
+ }
1939
2120
  }
1940
2121
 
1941
- // Copyright (c) Microsoft Corporation.
1942
2122
  /**
1943
- * @internal
2123
+ * A card action bot to respond to adaptive card universal actions.
1944
2124
  */
1945
- var ActivityType;
1946
- (function (ActivityType) {
1947
- ActivityType[ActivityType["CurrentBotInstalled"] = 0] = "CurrentBotInstalled";
1948
- ActivityType[ActivityType["CurrentBotMessaged"] = 1] = "CurrentBotMessaged";
1949
- ActivityType[ActivityType["CurrentBotUninstalled"] = 2] = "CurrentBotUninstalled";
1950
- ActivityType[ActivityType["TeamDeleted"] = 3] = "TeamDeleted";
1951
- ActivityType[ActivityType["TeamRestored"] = 4] = "TeamRestored";
1952
- ActivityType[ActivityType["Unknown"] = 5] = "Unknown";
1953
- })(ActivityType || (ActivityType = {}));
2125
+ class CardActionBot {
2126
+ /**
2127
+ * Creates a new instance of the `CardActionBot`.
2128
+ *
2129
+ * @param adapter The bound `BotFrameworkAdapter`.
2130
+ * @param options - initialize options
2131
+ */
2132
+ constructor(adapter, options) {
2133
+ this.middleware = new CardActionMiddleware(options === null || options === void 0 ? void 0 : options.actions);
2134
+ this.adapter = adapter.use(this.middleware);
2135
+ }
2136
+ /**
2137
+ * Registers a card action handler to the bot.
2138
+ * @param actionHandler A card action handler to be registered.
2139
+ */
2140
+ registerHandler(actionHandler) {
2141
+ if (actionHandler) {
2142
+ this.middleware.actionHandlers.push(actionHandler);
2143
+ }
2144
+ }
2145
+ /**
2146
+ * Registers card action handlers to the bot.
2147
+ * @param actionHandlers A set of card action handlers to be registered.
2148
+ */
2149
+ registerHandlers(actionHandlers) {
2150
+ if (actionHandlers) {
2151
+ this.middleware.actionHandlers.push(...actionHandlers);
2152
+ }
2153
+ }
2154
+ }
2155
+
2156
+ // Copyright (c) Microsoft Corporation.
1954
2157
  /**
1955
2158
  * @internal
1956
2159
  */
1957
- class NotificationMiddleware {
1958
- constructor(options) {
1959
- this.conversationReferenceStore = options.conversationReferenceStore;
2160
+ class CommandResponseMiddleware {
2161
+ constructor(handlers, ssoHandlers, activityHandler) {
2162
+ this.commandHandlers = [];
2163
+ this.ssoCommandHandlers = [];
2164
+ handlers = handlers !== null && handlers !== void 0 ? handlers : [];
2165
+ ssoHandlers = ssoHandlers !== null && ssoHandlers !== void 0 ? ssoHandlers : [];
2166
+ this.hasSsoCommand = ssoHandlers.length > 0;
2167
+ this.ssoActivityHandler = activityHandler;
2168
+ if (this.hasSsoCommand && !this.ssoActivityHandler) {
2169
+ internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
2170
+ throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, ErrorCode.SsoActivityHandlerIsUndefined);
2171
+ }
2172
+ this.commandHandlers.push(...handlers);
2173
+ for (const ssoHandler of ssoHandlers) {
2174
+ this.addSsoCommand(ssoHandler);
2175
+ }
2176
+ }
2177
+ addSsoCommand(ssoHandler) {
2178
+ var _a;
2179
+ (_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.addCommand(async (context, tokenResponse, message) => {
2180
+ const matchResult = this.shouldTrigger(ssoHandler.triggerPatterns, message.text);
2181
+ message.matches = Array.isArray(matchResult) ? matchResult : void 0;
2182
+ const response = await ssoHandler.handleCommandReceived(context, message, tokenResponse);
2183
+ await this.processResponse(context, response);
2184
+ }, ssoHandler.triggerPatterns);
2185
+ this.ssoCommandHandlers.push(ssoHandler);
2186
+ this.hasSsoCommand = true;
1960
2187
  }
1961
2188
  async onTurn(context, next) {
1962
- const type = this.classifyActivity(context.activity);
1963
- switch (type) {
1964
- case ActivityType.CurrentBotInstalled:
1965
- case ActivityType.TeamRestored: {
1966
- const reference = TurnContext.getConversationReference(context.activity);
1967
- await this.conversationReferenceStore.set(reference);
1968
- break;
2189
+ var _a, _b;
2190
+ if (context.activity.type === ActivityTypes.Message) {
2191
+ // Invoke corresponding command handler for the command response
2192
+ const commandText = this.getActivityText(context.activity);
2193
+ let alreadyProcessed = false;
2194
+ for (const handler of this.commandHandlers) {
2195
+ const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
2196
+ // It is important to note that the command bot will stop processing handlers
2197
+ // when the first command handler is matched.
2198
+ if (!!matchResult) {
2199
+ const message = {
2200
+ text: commandText,
2201
+ };
2202
+ message.matches = Array.isArray(matchResult) ? matchResult : void 0;
2203
+ const response = await handler.handleCommandReceived(context, message);
2204
+ await this.processResponse(context, response);
2205
+ alreadyProcessed = true;
2206
+ break;
2207
+ }
1969
2208
  }
1970
- case ActivityType.CurrentBotMessaged: {
1971
- await this.tryAddMessagedReference(context);
1972
- break;
2209
+ if (!alreadyProcessed) {
2210
+ for (const handler of this.ssoCommandHandlers) {
2211
+ const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
2212
+ if (!!matchResult) {
2213
+ await ((_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.run(context));
2214
+ break;
2215
+ }
2216
+ }
1973
2217
  }
1974
- case ActivityType.CurrentBotUninstalled:
1975
- case ActivityType.TeamDeleted: {
1976
- const reference = TurnContext.getConversationReference(context.activity);
1977
- await this.conversationReferenceStore.delete(reference);
1978
- break;
2218
+ }
2219
+ else {
2220
+ if (this.hasSsoCommand) {
2221
+ await ((_b = this.ssoActivityHandler) === null || _b === void 0 ? void 0 : _b.run(context));
1979
2222
  }
1980
2223
  }
1981
2224
  await next();
1982
2225
  }
1983
- classifyActivity(activity) {
1984
- var _a, _b;
1985
- const activityType = activity.type;
1986
- if (activityType === "installationUpdate") {
1987
- const action = (_a = activity.action) === null || _a === void 0 ? void 0 : _a.toLowerCase();
1988
- if (action === "add") {
1989
- return ActivityType.CurrentBotInstalled;
1990
- }
1991
- else {
1992
- return ActivityType.CurrentBotUninstalled;
2226
+ async processResponse(context, response) {
2227
+ if (typeof response === "string") {
2228
+ await context.sendActivity(response);
2229
+ }
2230
+ else {
2231
+ const replyActivity = response;
2232
+ if (replyActivity) {
2233
+ await context.sendActivity(replyActivity);
1993
2234
  }
1994
2235
  }
1995
- else if (activityType === "conversationUpdate") {
1996
- const eventType = (_b = activity.channelData) === null || _b === void 0 ? void 0 : _b.eventType;
1997
- if (eventType === "teamDeleted") {
1998
- return ActivityType.TeamDeleted;
2236
+ }
2237
+ matchPattern(pattern, text) {
2238
+ if (text) {
2239
+ if (typeof pattern === "string") {
2240
+ const regExp = new RegExp(pattern, "i");
2241
+ return regExp.test(text);
1999
2242
  }
2000
- else if (eventType === "teamRestored") {
2001
- return ActivityType.TeamRestored;
2002
- }
2003
- }
2004
- else if (activityType === "message") {
2005
- return ActivityType.CurrentBotMessaged;
2006
- }
2007
- return ActivityType.Unknown;
2008
- }
2009
- async tryAddMessagedReference(context) {
2010
- var _a, _b, _c, _d;
2011
- const reference = TurnContext.getConversationReference(context.activity);
2012
- const conversationType = (_a = reference === null || reference === void 0 ? void 0 : reference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
2013
- if (conversationType === "personal" || conversationType === "groupChat") {
2014
- if (!(await this.conversationReferenceStore.check(reference))) {
2015
- await this.conversationReferenceStore.set(reference);
2016
- }
2017
- }
2018
- else if (conversationType === "channel") {
2019
- const teamId = (_d = (_c = (_b = context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.team) === null || _d === void 0 ? void 0 : _d.id;
2020
- if (teamId !== undefined) {
2021
- const teamReference = cloneConversation(reference);
2022
- teamReference.conversation.id = teamId;
2023
- if (!(await this.conversationReferenceStore.check(teamReference))) {
2024
- await this.conversationReferenceStore.set(teamReference);
2025
- }
2026
- }
2027
- }
2028
- }
2029
- }
2030
- class CommandResponseMiddleware {
2031
- constructor(handlers) {
2032
- this.commandHandlers = [];
2033
- if (handlers && handlers.length > 0) {
2034
- this.commandHandlers.push(...handlers);
2035
- }
2036
- }
2037
- async onTurn(context, next) {
2038
- if (context.activity.type === ActivityTypes.Message) {
2039
- // Invoke corresponding command handler for the command response
2040
- const commandText = this.getActivityText(context.activity);
2041
- const message = {
2042
- text: commandText,
2043
- };
2044
- for (const handler of this.commandHandlers) {
2045
- const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
2046
- // It is important to note that the command bot will stop processing handlers
2047
- // when the first command handler is matched.
2048
- if (!!matchResult) {
2049
- message.matches = Array.isArray(matchResult) ? matchResult : void 0;
2050
- const response = await handler.handleCommandReceived(context, message);
2051
- if (typeof response === "string") {
2052
- await context.sendActivity(response);
2053
- }
2054
- else {
2055
- const replyActivity = response;
2056
- if (replyActivity) {
2057
- await context.sendActivity(replyActivity);
2058
- }
2059
- }
2060
- }
2061
- }
2062
- }
2063
- await next();
2064
- }
2065
- matchPattern(pattern, text) {
2066
- if (text) {
2067
- if (typeof pattern === "string") {
2068
- const regExp = new RegExp(pattern, "i");
2069
- return regExp.test(text);
2070
- }
2071
- if (pattern instanceof RegExp) {
2072
- const matches = text.match(pattern);
2073
- return matches !== null && matches !== void 0 ? matches : false;
2243
+ if (pattern instanceof RegExp) {
2244
+ const matches = text.match(pattern);
2245
+ return matches !== null && matches !== void 0 ? matches : false;
2074
2246
  }
2075
2247
  }
2076
2248
  return false;
@@ -2103,8 +2275,6 @@ class CommandResponseMiddleware {
2103
2275
  *
2104
2276
  * @remarks
2105
2277
  * Ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once.
2106
- *
2107
- * @beta
2108
2278
  */
2109
2279
  class CommandBot {
2110
2280
  /**
@@ -2112,19 +2282,16 @@ class CommandBot {
2112
2282
  *
2113
2283
  * @param adapter The bound `BotFrameworkAdapter`.
2114
2284
  * @param options - initialize options
2115
- *
2116
- * @beta
2117
2285
  */
2118
- constructor(adapter, options) {
2119
- this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands);
2286
+ constructor(adapter, options, ssoCommandActivityHandler, ssoConfig) {
2287
+ this.ssoConfig = ssoConfig;
2288
+ this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands, options === null || options === void 0 ? void 0 : options.ssoCommands, ssoCommandActivityHandler);
2120
2289
  this.adapter = adapter.use(this.middleware);
2121
2290
  }
2122
2291
  /**
2123
2292
  * Registers a command into the command bot.
2124
2293
  *
2125
- * @param command The command to registered.
2126
- *
2127
- * @beta
2294
+ * @param command The command to register.
2128
2295
  */
2129
2296
  registerCommand(command) {
2130
2297
  if (command) {
@@ -2134,15 +2301,165 @@ class CommandBot {
2134
2301
  /**
2135
2302
  * Registers commands into the command bot.
2136
2303
  *
2137
- * @param commands The command to registered.
2138
- *
2139
- * @beta
2304
+ * @param commands The commands to register.
2140
2305
  */
2141
2306
  registerCommands(commands) {
2142
2307
  if (commands) {
2143
2308
  this.middleware.commandHandlers.push(...commands);
2144
2309
  }
2145
2310
  }
2311
+ /**
2312
+ * Registers a sso command into the command bot.
2313
+ *
2314
+ * @param command The command to register.
2315
+ */
2316
+ registerSsoCommand(ssoCommand) {
2317
+ this.validateSsoActivityHandler();
2318
+ this.middleware.addSsoCommand(ssoCommand);
2319
+ }
2320
+ /**
2321
+ * Registers commands into the command bot.
2322
+ *
2323
+ * @param commands The commands to register.
2324
+ */
2325
+ registerSsoCommands(ssoCommands) {
2326
+ if (ssoCommands.length > 0) {
2327
+ this.validateSsoActivityHandler();
2328
+ for (const ssoCommand of ssoCommands) {
2329
+ this.middleware.addSsoCommand(ssoCommand);
2330
+ }
2331
+ }
2332
+ }
2333
+ validateSsoActivityHandler() {
2334
+ if (!this.middleware.ssoActivityHandler) {
2335
+ internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
2336
+ throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, ErrorCode.SsoActivityHandlerIsUndefined);
2337
+ }
2338
+ }
2339
+ }
2340
+
2341
+ // Copyright (c) Microsoft Corporation.
2342
+ /**
2343
+ * @internal
2344
+ */
2345
+ function cloneConversation(conversation) {
2346
+ return JSON.parse(JSON.stringify(conversation));
2347
+ }
2348
+ /**
2349
+ * @internal
2350
+ */
2351
+ function getTargetType(conversationReference) {
2352
+ var _a;
2353
+ const conversationType = (_a = conversationReference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
2354
+ if (conversationType === "personal") {
2355
+ return NotificationTargetType.Person;
2356
+ }
2357
+ else if (conversationType === "groupChat") {
2358
+ return NotificationTargetType.Group;
2359
+ }
2360
+ else if (conversationType === "channel") {
2361
+ return NotificationTargetType.Channel;
2362
+ }
2363
+ else {
2364
+ return undefined;
2365
+ }
2366
+ }
2367
+ /**
2368
+ * @internal
2369
+ */
2370
+ function getTeamsBotInstallationId(context) {
2371
+ var _a, _b, _c, _d;
2372
+ return (_d = (_c = (_b = (_a = context.activity) === null || _a === void 0 ? void 0 : _a.channelData) === null || _b === void 0 ? void 0 : _b.team) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : context.activity.conversation.id;
2373
+ }
2374
+
2375
+ // Copyright (c) Microsoft Corporation.
2376
+ /**
2377
+ * @internal
2378
+ */
2379
+ var ActivityType;
2380
+ (function (ActivityType) {
2381
+ ActivityType[ActivityType["CurrentBotInstalled"] = 0] = "CurrentBotInstalled";
2382
+ ActivityType[ActivityType["CurrentBotMessaged"] = 1] = "CurrentBotMessaged";
2383
+ ActivityType[ActivityType["CurrentBotUninstalled"] = 2] = "CurrentBotUninstalled";
2384
+ ActivityType[ActivityType["TeamDeleted"] = 3] = "TeamDeleted";
2385
+ ActivityType[ActivityType["TeamRestored"] = 4] = "TeamRestored";
2386
+ ActivityType[ActivityType["Unknown"] = 5] = "Unknown";
2387
+ })(ActivityType || (ActivityType = {}));
2388
+ /**
2389
+ * @internal
2390
+ */
2391
+ class NotificationMiddleware {
2392
+ constructor(options) {
2393
+ this.conversationReferenceStore = options.conversationReferenceStore;
2394
+ }
2395
+ async onTurn(context, next) {
2396
+ const type = this.classifyActivity(context.activity);
2397
+ switch (type) {
2398
+ case ActivityType.CurrentBotInstalled:
2399
+ case ActivityType.TeamRestored: {
2400
+ const reference = TurnContext.getConversationReference(context.activity);
2401
+ await this.conversationReferenceStore.set(reference);
2402
+ break;
2403
+ }
2404
+ case ActivityType.CurrentBotMessaged: {
2405
+ await this.tryAddMessagedReference(context);
2406
+ break;
2407
+ }
2408
+ case ActivityType.CurrentBotUninstalled:
2409
+ case ActivityType.TeamDeleted: {
2410
+ const reference = TurnContext.getConversationReference(context.activity);
2411
+ await this.conversationReferenceStore.delete(reference);
2412
+ break;
2413
+ }
2414
+ }
2415
+ await next();
2416
+ }
2417
+ classifyActivity(activity) {
2418
+ var _a, _b;
2419
+ const activityType = activity.type;
2420
+ if (activityType === "installationUpdate") {
2421
+ const action = (_a = activity.action) === null || _a === void 0 ? void 0 : _a.toLowerCase();
2422
+ if (action === "add") {
2423
+ return ActivityType.CurrentBotInstalled;
2424
+ }
2425
+ else {
2426
+ return ActivityType.CurrentBotUninstalled;
2427
+ }
2428
+ }
2429
+ else if (activityType === "conversationUpdate") {
2430
+ const eventType = (_b = activity.channelData) === null || _b === void 0 ? void 0 : _b.eventType;
2431
+ if (eventType === "teamDeleted") {
2432
+ return ActivityType.TeamDeleted;
2433
+ }
2434
+ else if (eventType === "teamRestored") {
2435
+ return ActivityType.TeamRestored;
2436
+ }
2437
+ }
2438
+ else if (activityType === "message") {
2439
+ return ActivityType.CurrentBotMessaged;
2440
+ }
2441
+ return ActivityType.Unknown;
2442
+ }
2443
+ async tryAddMessagedReference(context) {
2444
+ var _a, _b, _c, _d;
2445
+ const reference = TurnContext.getConversationReference(context.activity);
2446
+ const conversationType = (_a = reference === null || reference === void 0 ? void 0 : reference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
2447
+ if (conversationType === "personal" || conversationType === "groupChat") {
2448
+ if (!(await this.conversationReferenceStore.check(reference))) {
2449
+ await this.conversationReferenceStore.set(reference);
2450
+ }
2451
+ }
2452
+ else if (conversationType === "channel") {
2453
+ const teamId = (_d = (_c = (_b = context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.team) === null || _d === void 0 ? void 0 : _d.id;
2454
+ if (teamId !== undefined) {
2455
+ const teamReference = cloneConversation(reference);
2456
+ teamReference.conversation.id = teamId;
2457
+ if (!(await this.conversationReferenceStore.check(teamReference))) {
2458
+ await this.conversationReferenceStore.set(teamReference);
2459
+ }
2460
+ }
2461
+ }
2462
+ }
2146
2463
  }
2147
2464
 
2148
2465
  // Copyright (c) Microsoft Corporation.
@@ -2270,32 +2587,30 @@ class ConversationReferenceStore {
2270
2587
  *
2271
2588
  * @param target - the notification target.
2272
2589
  * @param text - the plain text message.
2273
- * @returns A `Promise` representing the asynchronous operation.
2274
- *
2275
- * @beta
2590
+ * @param onError - an optional error handler that can catch exceptions during message sending.
2591
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2592
+ * @returns the response of sending message.
2276
2593
  */
2277
- function sendMessage(target, text) {
2278
- return target.sendMessage(text);
2594
+ function sendMessage(target, text, onError) {
2595
+ return target.sendMessage(text, onError);
2279
2596
  }
2280
2597
  /**
2281
2598
  * Send an adaptive card message to a notification target.
2282
2599
  *
2283
2600
  * @param target - the notification target.
2284
2601
  * @param card - the adaptive card raw JSON.
2285
- * @returns A `Promise` representing the asynchronous operation.
2286
- *
2287
- * @beta
2602
+ * @param onError - an optional error handler that can catch exceptions during adaptive card sending.
2603
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2604
+ * @returns the response of sending adaptive card message.
2288
2605
  */
2289
- function sendAdaptiveCard(target, card) {
2290
- return target.sendAdaptiveCard(card);
2606
+ function sendAdaptiveCard(target, card, onError) {
2607
+ return target.sendAdaptiveCard(card, onError);
2291
2608
  }
2292
2609
  /**
2293
2610
  * A {@link NotificationTarget} that represents a team channel.
2294
2611
  *
2295
2612
  * @remarks
2296
2613
  * It's recommended to get channels from {@link TeamsBotInstallation.channels()}.
2297
- *
2298
- * @beta
2299
2614
  */
2300
2615
  class Channel {
2301
2616
  /**
@@ -2306,16 +2621,12 @@ class Channel {
2306
2621
  *
2307
2622
  * @param parent - The parent {@link TeamsBotInstallation} where this channel is created from.
2308
2623
  * @param info - Detailed channel information.
2309
- *
2310
- * @beta
2311
2624
  */
2312
2625
  constructor(parent, info) {
2313
2626
  /**
2314
2627
  * Notification target type. For channel it's always "Channel".
2315
- *
2316
- * @beta
2317
2628
  */
2318
- this.type = "Channel";
2629
+ this.type = NotificationTargetType.Channel;
2319
2630
  this.parent = parent;
2320
2631
  this.info = info;
2321
2632
  }
@@ -2323,35 +2634,61 @@ class Channel {
2323
2634
  * Send a plain text message.
2324
2635
  *
2325
2636
  * @param text - the plain text message.
2326
- * @returns A `Promise` representing the asynchronous operation.
2327
- *
2328
- * @beta
2637
+ * @param onError - an optional error handler that can catch exceptions during message sending.
2638
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2639
+ * @returns the response of sending message.
2329
2640
  */
2330
- sendMessage(text) {
2331
- return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2641
+ async sendMessage(text, onError) {
2642
+ const response = {};
2643
+ await this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2332
2644
  const conversation = await this.newConversation(context);
2333
2645
  await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2334
- await ctx.sendActivity(text);
2646
+ try {
2647
+ const res = await ctx.sendActivity(text);
2648
+ response.id = res === null || res === void 0 ? void 0 : res.id;
2649
+ }
2650
+ catch (error) {
2651
+ if (onError) {
2652
+ await onError(ctx, error);
2653
+ }
2654
+ else {
2655
+ throw error;
2656
+ }
2657
+ }
2335
2658
  });
2336
2659
  });
2660
+ return response;
2337
2661
  }
2338
2662
  /**
2339
2663
  * Send an adaptive card message.
2340
2664
  *
2341
2665
  * @param card - the adaptive card raw JSON.
2342
- * @returns A `Promise` representing the asynchronous operation.
2343
- *
2344
- * @beta
2666
+ * @param onError - an optional error handler that can catch exceptions during adaptive card sending.
2667
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2668
+ * @returns the response of sending adaptive card message.
2345
2669
  */
2346
- async sendAdaptiveCard(card) {
2347
- return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2670
+ async sendAdaptiveCard(card, onError) {
2671
+ const response = {};
2672
+ await this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2348
2673
  const conversation = await this.newConversation(context);
2349
2674
  await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2350
- await ctx.sendActivity({
2351
- attachments: [CardFactory.adaptiveCard(card)],
2352
- });
2675
+ try {
2676
+ const res = await ctx.sendActivity({
2677
+ attachments: [CardFactory.adaptiveCard(card)],
2678
+ });
2679
+ response.id = res === null || res === void 0 ? void 0 : res.id;
2680
+ }
2681
+ catch (error) {
2682
+ if (onError) {
2683
+ await onError(ctx, error);
2684
+ }
2685
+ else {
2686
+ throw error;
2687
+ }
2688
+ }
2353
2689
  });
2354
2690
  });
2691
+ return response;
2355
2692
  }
2356
2693
  /**
2357
2694
  * @internal
@@ -2368,8 +2705,6 @@ class Channel {
2368
2705
  *
2369
2706
  * @remarks
2370
2707
  * It's recommended to get members from {@link TeamsBotInstallation.members()}.
2371
- *
2372
- * @beta
2373
2708
  */
2374
2709
  class Member {
2375
2710
  /**
@@ -2380,16 +2715,12 @@ class Member {
2380
2715
  *
2381
2716
  * @param parent - The parent {@link TeamsBotInstallation} where this member is created from.
2382
2717
  * @param account - Detailed member account information.
2383
- *
2384
- * @beta
2385
2718
  */
2386
2719
  constructor(parent, account) {
2387
2720
  /**
2388
2721
  * Notification target type. For member it's always "Person".
2389
- *
2390
- * @beta
2391
2722
  */
2392
- this.type = "Person";
2723
+ this.type = NotificationTargetType.Person;
2393
2724
  this.parent = parent;
2394
2725
  this.account = account;
2395
2726
  }
@@ -2397,35 +2728,61 @@ class Member {
2397
2728
  * Send a plain text message.
2398
2729
  *
2399
2730
  * @param text - the plain text message.
2400
- * @returns A `Promise` representing the asynchronous operation.
2401
- *
2402
- * @beta
2731
+ * @param onError - an optional error handler that can catch exceptions during message sending.
2732
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2733
+ * @returns the response of sending message.
2403
2734
  */
2404
- sendMessage(text) {
2405
- return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2735
+ async sendMessage(text, onError) {
2736
+ const response = {};
2737
+ await this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2406
2738
  const conversation = await this.newConversation(context);
2407
2739
  await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2408
- await ctx.sendActivity(text);
2740
+ try {
2741
+ const res = await ctx.sendActivity(text);
2742
+ response.id = res === null || res === void 0 ? void 0 : res.id;
2743
+ }
2744
+ catch (error) {
2745
+ if (onError) {
2746
+ await onError(ctx, error);
2747
+ }
2748
+ else {
2749
+ throw error;
2750
+ }
2751
+ }
2409
2752
  });
2410
2753
  });
2754
+ return response;
2411
2755
  }
2412
2756
  /**
2413
2757
  * Send an adaptive card message.
2414
2758
  *
2415
2759
  * @param card - the adaptive card raw JSON.
2416
- * @returns A `Promise` representing the asynchronous operation.
2417
- *
2418
- * @beta
2760
+ * @param onError - an optional error handler that can catch exceptions during adaptive card sending.
2761
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2762
+ * @returns the response of sending adaptive card message.
2419
2763
  */
2420
- async sendAdaptiveCard(card) {
2421
- return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2764
+ async sendAdaptiveCard(card, onError) {
2765
+ const response = {};
2766
+ await this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2422
2767
  const conversation = await this.newConversation(context);
2423
2768
  await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2424
- await ctx.sendActivity({
2425
- attachments: [CardFactory.adaptiveCard(card)],
2426
- });
2769
+ try {
2770
+ const res = await ctx.sendActivity({
2771
+ attachments: [CardFactory.adaptiveCard(card)],
2772
+ });
2773
+ response.id = res === null || res === void 0 ? void 0 : res.id;
2774
+ }
2775
+ catch (error) {
2776
+ if (onError) {
2777
+ await onError(ctx, error);
2778
+ }
2779
+ else {
2780
+ throw error;
2781
+ }
2782
+ }
2427
2783
  });
2428
2784
  });
2785
+ return response;
2429
2786
  }
2430
2787
  /**
2431
2788
  * @internal
@@ -2453,8 +2810,6 @@ class Member {
2453
2810
  *
2454
2811
  * @remarks
2455
2812
  * It's recommended to get bot installations from {@link ConversationBot.installations()}.
2456
- *
2457
- * @beta
2458
2813
  */
2459
2814
  class TeamsBotInstallation {
2460
2815
  /**
@@ -2465,8 +2820,6 @@ class TeamsBotInstallation {
2465
2820
  *
2466
2821
  * @param adapter - the bound `BotFrameworkAdapter`.
2467
2822
  * @param conversationReference - the bound `ConversationReference`.
2468
- *
2469
- * @beta
2470
2823
  */
2471
2824
  constructor(adapter, conversationReference) {
2472
2825
  this.adapter = adapter;
@@ -2477,38 +2830,66 @@ class TeamsBotInstallation {
2477
2830
  * Send a plain text message.
2478
2831
  *
2479
2832
  * @param text - the plain text message.
2480
- * @returns A `Promise` representing the asynchronous operation.
2481
- *
2482
- * @beta
2833
+ * @param onError - an optional error handler that can catch exceptions during message sending.
2834
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2835
+ * @returns the response of sending message.
2483
2836
  */
2484
- sendMessage(text) {
2485
- return this.adapter.continueConversation(this.conversationReference, async (context) => {
2486
- await context.sendActivity(text);
2837
+ async sendMessage(text, onError) {
2838
+ const response = {};
2839
+ await this.adapter.continueConversation(this.conversationReference, async (context) => {
2840
+ try {
2841
+ const res = await context.sendActivity(text);
2842
+ response.id = res === null || res === void 0 ? void 0 : res.id;
2843
+ }
2844
+ catch (error) {
2845
+ if (onError) {
2846
+ await onError(context, error);
2847
+ }
2848
+ else {
2849
+ throw error;
2850
+ }
2851
+ }
2487
2852
  });
2853
+ return response;
2488
2854
  }
2489
2855
  /**
2490
2856
  * Send an adaptive card message.
2491
2857
  *
2492
2858
  * @param card - the adaptive card raw JSON.
2493
- * @returns A `Promise` representing the asynchronous operation.
2494
- *
2495
- * @beta
2859
+ * @param onError - an optional error handler that can catch exceptions during adaptive card sending.
2860
+ * If not defined, error will be handled by `BotAdapter.onTurnError`.
2861
+ * @returns the response of sending adaptive card message.
2496
2862
  */
2497
- sendAdaptiveCard(card) {
2498
- return this.adapter.continueConversation(this.conversationReference, async (context) => {
2499
- await context.sendActivity({
2500
- attachments: [CardFactory.adaptiveCard(card)],
2501
- });
2863
+ async sendAdaptiveCard(card, onError) {
2864
+ const response = {};
2865
+ await this.adapter.continueConversation(this.conversationReference, async (context) => {
2866
+ try {
2867
+ const res = await context.sendActivity({
2868
+ attachments: [CardFactory.adaptiveCard(card)],
2869
+ });
2870
+ response.id = res === null || res === void 0 ? void 0 : res.id;
2871
+ }
2872
+ catch (error) {
2873
+ if (onError) {
2874
+ await onError(context, error);
2875
+ }
2876
+ else {
2877
+ throw error;
2878
+ }
2879
+ }
2502
2880
  });
2881
+ return response;
2503
2882
  }
2504
2883
  /**
2505
2884
  * Get channels from this bot installation.
2506
2885
  *
2507
2886
  * @returns an array of channels if bot is installed into a team, otherwise returns an empty array.
2508
- *
2509
- * @beta
2510
2887
  */
2511
2888
  async channels() {
2889
+ const channels = [];
2890
+ if (this.type !== NotificationTargetType.Channel) {
2891
+ return channels;
2892
+ }
2512
2893
  let teamsChannels = [];
2513
2894
  await this.adapter.continueConversation(this.conversationReference, async (context) => {
2514
2895
  const teamId = getTeamsBotInstallationId(context);
@@ -2516,7 +2897,6 @@ class TeamsBotInstallation {
2516
2897
  teamsChannels = await TeamsInfo.getTeamChannels(context, teamId);
2517
2898
  }
2518
2899
  });
2519
- const channels = [];
2520
2900
  for (const channel of teamsChannels) {
2521
2901
  channels.push(new Channel(this, channel));
2522
2902
  }
@@ -2526,8 +2906,6 @@ class TeamsBotInstallation {
2526
2906
  * Get members from this bot installation.
2527
2907
  *
2528
2908
  * @returns an array of members from where the bot is installed.
2529
- *
2530
- * @beta
2531
2909
  */
2532
2910
  async members() {
2533
2911
  const members = [];
@@ -2543,11 +2921,27 @@ class TeamsBotInstallation {
2543
2921
  });
2544
2922
  return members;
2545
2923
  }
2924
+ /**
2925
+ * Get team details from this bot installation
2926
+ *
2927
+ * @returns the team details if bot is installed into a team, otherwise returns undefined.
2928
+ */
2929
+ async getTeamDetails() {
2930
+ if (this.type !== NotificationTargetType.Channel) {
2931
+ return undefined;
2932
+ }
2933
+ let teamDetails;
2934
+ await this.adapter.continueConversation(this.conversationReference, async (context) => {
2935
+ const teamId = getTeamsBotInstallationId(context);
2936
+ if (teamId !== undefined) {
2937
+ teamDetails = await TeamsInfo.getTeamDetails(context, teamId);
2938
+ }
2939
+ });
2940
+ return teamDetails;
2941
+ }
2546
2942
  }
2547
2943
  /**
2548
2944
  * Provide utilities to send notification to varies targets (e.g., member, group, channel).
2549
- *
2550
- * @beta
2551
2945
  */
2552
2946
  class NotificationBot {
2553
2947
  /**
@@ -2558,8 +2952,6 @@ class NotificationBot {
2558
2952
  *
2559
2953
  * @param adapter - the bound `BotFrameworkAdapter`
2560
2954
  * @param options - initialize options
2561
- *
2562
- * @beta
2563
2955
  */
2564
2956
  constructor(adapter, options) {
2565
2957
  var _a, _b;
@@ -2576,8 +2968,6 @@ class NotificationBot {
2576
2968
  * The result is retrieving from the persisted storage.
2577
2969
  *
2578
2970
  * @returns - an array of {@link TeamsBotInstallation}.
2579
- *
2580
- * @beta
2581
2971
  */
2582
2972
  async installations() {
2583
2973
  if (this.conversationReferenceStore === undefined || this.adapter === undefined) {
@@ -2608,6 +2998,459 @@ class NotificationBot {
2608
2998
  }
2609
2999
  return targets;
2610
3000
  }
3001
+ /**
3002
+ * Returns the first {@link Member} where predicate is true, and undefined otherwise.
3003
+ *
3004
+ * @param predicate find calls predicate once for each member of the installation,
3005
+ * until it finds one where predicate returns true. If such a member is found, find
3006
+ * immediately returns that member. Otherwise, find returns undefined.
3007
+ * @param scope the scope to find members from the installations
3008
+ * (personal chat, group chat, Teams channel).
3009
+ * @returns the first {@link Member} where predicate is true, and undefined otherwise.
3010
+ */
3011
+ async findMember(predicate, scope) {
3012
+ for (const target of await this.installations()) {
3013
+ if (this.matchSearchScope(target, scope)) {
3014
+ for (const member of await target.members()) {
3015
+ if (await predicate(member)) {
3016
+ return member;
3017
+ }
3018
+ }
3019
+ }
3020
+ }
3021
+ return;
3022
+ }
3023
+ /**
3024
+ * Returns the first {@link Channel} where predicate is true, and undefined otherwise.
3025
+ *
3026
+ * @param predicate find calls predicate once for each channel of the installation,
3027
+ * until it finds one where predicate returns true. If such a channel is found, find
3028
+ * immediately returns that channel. Otherwise, find returns undefined.
3029
+ * @returns the first {@link Channel} where predicate is true, and undefined otherwise.
3030
+ */
3031
+ async findChannel(predicate) {
3032
+ for (const target of await this.installations()) {
3033
+ if (target.type === NotificationTargetType.Channel) {
3034
+ const teamDetails = await target.getTeamDetails();
3035
+ for (const channel of await target.channels()) {
3036
+ if (await predicate(channel, teamDetails)) {
3037
+ return channel;
3038
+ }
3039
+ }
3040
+ }
3041
+ }
3042
+ return;
3043
+ }
3044
+ /**
3045
+ * Returns all {@link Member} where predicate is true, and empty array otherwise.
3046
+ *
3047
+ * @param predicate find calls predicate for each member of the installation.
3048
+ * @param scope the scope to find members from the installations
3049
+ * (personal chat, group chat, Teams channel).
3050
+ * @returns an array of {@link Member} where predicate is true, and empty array otherwise.
3051
+ */
3052
+ async findAllMembers(predicate, scope) {
3053
+ const members = [];
3054
+ for (const target of await this.installations()) {
3055
+ if (this.matchSearchScope(target, scope)) {
3056
+ for (const member of await target.members()) {
3057
+ if (await predicate(member)) {
3058
+ members.push(member);
3059
+ }
3060
+ }
3061
+ }
3062
+ }
3063
+ return members;
3064
+ }
3065
+ /**
3066
+ * Returns all {@link Channel} where predicate is true, and empty array otherwise.
3067
+ *
3068
+ * @param predicate find calls predicate for each channel of the installation.
3069
+ * @returns an array of {@link Channel} where predicate is true, and empty array otherwise.
3070
+ */
3071
+ async findAllChannels(predicate) {
3072
+ const channels = [];
3073
+ for (const target of await this.installations()) {
3074
+ if (target.type === NotificationTargetType.Channel) {
3075
+ const teamDetails = await target.getTeamDetails();
3076
+ for (const channel of await target.channels()) {
3077
+ if (await predicate(channel, teamDetails)) {
3078
+ channels.push(channel);
3079
+ }
3080
+ }
3081
+ }
3082
+ }
3083
+ return channels;
3084
+ }
3085
+ matchSearchScope(target, scope) {
3086
+ scope = scope !== null && scope !== void 0 ? scope : SearchScope.All;
3087
+ return ((target.type === NotificationTargetType.Channel && (scope & SearchScope.Channel) !== 0) ||
3088
+ (target.type === NotificationTargetType.Group && (scope & SearchScope.Group) !== 0) ||
3089
+ (target.type === NotificationTargetType.Person && (scope & SearchScope.Person) !== 0));
3090
+ }
3091
+ }
3092
+ /**
3093
+ * The search scope when calling {@link NotificationBot.findMember} and {@link NotificationBot.findAllMembers}.
3094
+ * The search scope is a flagged enum and it can be combined with `|`.
3095
+ * For example, to search from personal chat and group chat, use `SearchScope.Person | SearchScope.Group`.
3096
+ */
3097
+ var SearchScope;
3098
+ (function (SearchScope) {
3099
+ /**
3100
+ * Search members from the installations in personal chat only.
3101
+ */
3102
+ SearchScope[SearchScope["Person"] = 1] = "Person";
3103
+ /**
3104
+ * Search members from the installations in group chat only.
3105
+ */
3106
+ SearchScope[SearchScope["Group"] = 2] = "Group";
3107
+ /**
3108
+ * Search members from the installations in Teams channel only.
3109
+ */
3110
+ SearchScope[SearchScope["Channel"] = 4] = "Channel";
3111
+ /**
3112
+ * Search members from all installations including personal chat, group chat and Teams channel.
3113
+ */
3114
+ SearchScope[SearchScope["All"] = 7] = "All";
3115
+ })(SearchScope || (SearchScope = {}));
3116
+
3117
+ // Copyright (c) Microsoft Corporation.
3118
+ let DIALOG_NAME = "BotSsoExecutionDialog";
3119
+ let TEAMS_SSO_PROMPT_ID = "TeamsFxSsoPrompt";
3120
+ let COMMAND_ROUTE_DIALOG = "CommandRouteDialog";
3121
+ /**
3122
+ * Sso execution dialog, use to handle sso command
3123
+ */
3124
+ class BotSsoExecutionDialog extends ComponentDialog {
3125
+ /**
3126
+ * Creates a new instance of the BotSsoExecutionDialog.
3127
+ * @param dedupStorage Helper storage to remove duplicated messages
3128
+ * @param settings The list of scopes for which the token will have access
3129
+ * @param teamsfx {@link TeamsFx} instance for authentication
3130
+ */
3131
+ constructor(dedupStorage, ssoPromptSettings, teamsfx, dialogName) {
3132
+ super(dialogName !== null && dialogName !== void 0 ? dialogName : DIALOG_NAME);
3133
+ this.dedupStorageKeys = [];
3134
+ // Map to store the commandId and triggerPatterns, key: commandId, value: triggerPatterns
3135
+ this.commandMapping = new Map();
3136
+ if (dialogName) {
3137
+ DIALOG_NAME = dialogName;
3138
+ TEAMS_SSO_PROMPT_ID = dialogName + TEAMS_SSO_PROMPT_ID;
3139
+ COMMAND_ROUTE_DIALOG = dialogName + COMMAND_ROUTE_DIALOG;
3140
+ }
3141
+ this.initialDialogId = COMMAND_ROUTE_DIALOG;
3142
+ this.dedupStorage = dedupStorage;
3143
+ this.dedupStorageKeys = [];
3144
+ const ssoDialog = new TeamsBotSsoPrompt(teamsfx, TEAMS_SSO_PROMPT_ID, ssoPromptSettings);
3145
+ this.addDialog(ssoDialog);
3146
+ const commandRouteDialog = new WaterfallDialog(COMMAND_ROUTE_DIALOG, [
3147
+ this.commandRouteStep.bind(this),
3148
+ ]);
3149
+ this.addDialog(commandRouteDialog);
3150
+ }
3151
+ /**
3152
+ * Add TeamsFxBotSsoCommandHandler instance
3153
+ * @param handler {@link BotSsoExecutionDialogHandler} callback function
3154
+ * @param triggerPatterns The trigger pattern
3155
+ */
3156
+ addCommand(handler, triggerPatterns) {
3157
+ const commandId = this.getCommandHash(triggerPatterns);
3158
+ const dialog = new WaterfallDialog(commandId, [
3159
+ this.ssoStep.bind(this),
3160
+ this.dedupStep.bind(this),
3161
+ async (stepContext) => {
3162
+ const tokenResponse = stepContext.result.tokenResponse;
3163
+ const context = stepContext.context;
3164
+ const message = stepContext.result.message;
3165
+ try {
3166
+ if (tokenResponse) {
3167
+ await handler(context, tokenResponse, message);
3168
+ }
3169
+ else {
3170
+ throw new Error(ErrorMessage.FailedToRetrieveSsoToken);
3171
+ }
3172
+ return await stepContext.endDialog();
3173
+ }
3174
+ catch (error) {
3175
+ const errorMsg = formatString(ErrorMessage.FailedToProcessSsoHandler, error.message);
3176
+ internalLogger.error(errorMsg);
3177
+ return await stepContext.endDialog(new ErrorWithCode(errorMsg, ErrorCode.FailedToProcessSsoHandler));
3178
+ }
3179
+ },
3180
+ ]);
3181
+ this.commandMapping.set(commandId, triggerPatterns);
3182
+ this.addDialog(dialog);
3183
+ }
3184
+ getCommandHash(patterns) {
3185
+ const expressions = Array.isArray(patterns) ? patterns : [patterns];
3186
+ const patternStr = expressions.join();
3187
+ const patternStrWithoutSpecialChar = patternStr.replace(/[^a-zA-Z0-9]/g, "");
3188
+ const hash = createHash("sha256").update(patternStr).digest("hex").toLowerCase();
3189
+ return patternStrWithoutSpecialChar + hash;
3190
+ }
3191
+ /**
3192
+ * The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
3193
+ *
3194
+ * @param context The context object for the current turn.
3195
+ * @param accessor The instance of StatePropertyAccessor for dialog system.
3196
+ */
3197
+ async run(context, accessor) {
3198
+ const dialogSet = new DialogSet(accessor);
3199
+ dialogSet.add(this);
3200
+ const dialogContext = await dialogSet.createContext(context);
3201
+ this.ensureMsTeamsChannel(dialogContext);
3202
+ const results = await dialogContext.continueDialog();
3203
+ if (results && results.status === DialogTurnStatus.empty) {
3204
+ await dialogContext.beginDialog(this.id);
3205
+ }
3206
+ else if (results &&
3207
+ results.status === DialogTurnStatus.complete &&
3208
+ results.result instanceof Error) {
3209
+ throw results.result;
3210
+ }
3211
+ }
3212
+ getActivityText(activity) {
3213
+ let text = activity.text;
3214
+ const removedMentionText = TurnContext.removeRecipientMention(activity);
3215
+ if (removedMentionText) {
3216
+ text = removedMentionText
3217
+ .toLowerCase()
3218
+ .replace(/\n|\r\n/g, "")
3219
+ .trim();
3220
+ }
3221
+ return text;
3222
+ }
3223
+ async commandRouteStep(stepContext) {
3224
+ const turnContext = stepContext.context;
3225
+ const text = this.getActivityText(turnContext.activity);
3226
+ const commandId = this.getMatchesCommandId(text);
3227
+ if (commandId) {
3228
+ return await stepContext.beginDialog(commandId);
3229
+ }
3230
+ const errorMsg = formatString(ErrorMessage.CannotFindCommand, turnContext.activity.text);
3231
+ internalLogger.error(errorMsg);
3232
+ throw new ErrorWithCode(errorMsg, ErrorCode.CannotFindCommand);
3233
+ }
3234
+ async ssoStep(stepContext) {
3235
+ try {
3236
+ const turnContext = stepContext.context;
3237
+ const text = this.getActivityText(turnContext.activity);
3238
+ const message = {
3239
+ text,
3240
+ };
3241
+ stepContext.options.commandMessage = message;
3242
+ return await stepContext.beginDialog(TEAMS_SSO_PROMPT_ID);
3243
+ }
3244
+ catch (error) {
3245
+ const errorMsg = formatString(ErrorMessage.FailedToRunSsoStep, error.message);
3246
+ internalLogger.error(errorMsg);
3247
+ return await stepContext.endDialog(new ErrorWithCode(errorMsg, ErrorCode.FailedToRunSsoStep));
3248
+ }
3249
+ }
3250
+ async dedupStep(stepContext) {
3251
+ const tokenResponse = stepContext.result;
3252
+ if (!tokenResponse) {
3253
+ internalLogger.error(ErrorMessage.FailedToRetrieveSsoToken);
3254
+ return await stepContext.endDialog(new ErrorWithCode(ErrorMessage.FailedToRetrieveSsoToken, ErrorCode.FailedToRunSsoStep));
3255
+ }
3256
+ try {
3257
+ // Only dedup after ssoStep to make sure that all Teams client would receive the login request
3258
+ if (tokenResponse && (await this.shouldDedup(stepContext.context))) {
3259
+ return Dialog.EndOfTurn;
3260
+ }
3261
+ return await stepContext.next({
3262
+ tokenResponse,
3263
+ message: stepContext.options.commandMessage,
3264
+ });
3265
+ }
3266
+ catch (error) {
3267
+ const errorMsg = formatString(ErrorMessage.FailedToRunDedupStep, error.message);
3268
+ internalLogger.error(errorMsg);
3269
+ return await stepContext.endDialog(new ErrorWithCode(errorMsg, ErrorCode.FailedToRunDedupStep));
3270
+ }
3271
+ }
3272
+ /**
3273
+ * Called when the component is ending.
3274
+ *
3275
+ * @param context Context for the current turn of conversation.
3276
+ */
3277
+ async onEndDialog(context) {
3278
+ const conversationId = context.activity.conversation.id;
3279
+ const currentDedupKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) > 0);
3280
+ await this.dedupStorage.delete(currentDedupKeys);
3281
+ this.dedupStorageKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) < 0);
3282
+ }
3283
+ /**
3284
+ * If a user is signed into multiple Teams clients, the Bot might receive a "signin/tokenExchange" from each client.
3285
+ * Each token exchange request for a specific user login will have an identical activity.value.Id.
3286
+ * Only one of these token exchange requests should be processed by the bot. For a distributed bot in production,
3287
+ * this requires a distributed storage to ensure only one token exchange is processed.
3288
+ * @param context Context for the current turn of conversation.
3289
+ * @returns boolean value indicate whether the message should be removed
3290
+ */
3291
+ async shouldDedup(context) {
3292
+ const storeItem = {
3293
+ eTag: context.activity.value.id,
3294
+ };
3295
+ const key = this.getStorageKey(context);
3296
+ const storeItems = { [key]: storeItem };
3297
+ try {
3298
+ await this.dedupStorage.write(storeItems);
3299
+ this.dedupStorageKeys.push(key);
3300
+ }
3301
+ catch (err) {
3302
+ if (err instanceof Error && err.message.indexOf("eTag conflict")) {
3303
+ return true;
3304
+ }
3305
+ throw err;
3306
+ }
3307
+ return false;
3308
+ }
3309
+ getStorageKey(context) {
3310
+ if (!context || !context.activity || !context.activity.conversation) {
3311
+ throw new Error("Invalid context, can not get storage key!");
3312
+ }
3313
+ const activity = context.activity;
3314
+ const channelId = activity.channelId;
3315
+ const conversationId = activity.conversation.id;
3316
+ if (activity.type !== ActivityTypes.Invoke || activity.name !== tokenExchangeOperationName) {
3317
+ throw new Error("TokenExchangeState can only be used with Invokes of signin/tokenExchange.");
3318
+ }
3319
+ const value = activity.value;
3320
+ if (!value || !value.id) {
3321
+ throw new Error("Invalid signin/tokenExchange. Missing activity.value.id.");
3322
+ }
3323
+ return `${channelId}/${conversationId}/${value.id}`;
3324
+ }
3325
+ matchPattern(pattern, text) {
3326
+ if (text) {
3327
+ if (typeof pattern === "string") {
3328
+ const regExp = new RegExp(pattern, "i");
3329
+ return regExp.test(text);
3330
+ }
3331
+ if (pattern instanceof RegExp) {
3332
+ const matches = text.match(pattern);
3333
+ return matches !== null && matches !== void 0 ? matches : false;
3334
+ }
3335
+ }
3336
+ return false;
3337
+ }
3338
+ isPatternMatched(patterns, text) {
3339
+ const expressions = Array.isArray(patterns) ? patterns : [patterns];
3340
+ for (const ex of expressions) {
3341
+ const matches = this.matchPattern(ex, text);
3342
+ return !!matches;
3343
+ }
3344
+ return false;
3345
+ }
3346
+ getMatchesCommandId(text) {
3347
+ for (const command of this.commandMapping) {
3348
+ const pattern = command[1];
3349
+ if (this.isPatternMatched(pattern, text)) {
3350
+ return command[0];
3351
+ }
3352
+ }
3353
+ return undefined;
3354
+ }
3355
+ /**
3356
+ * Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
3357
+ * @param dc dialog context
3358
+ * @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams
3359
+ * @internal
3360
+ */
3361
+ ensureMsTeamsChannel(dc) {
3362
+ if (dc.context.activity.channelId != Channels.Msteams) {
3363
+ const errorMsg = formatString(ErrorMessage.OnlyMSTeamsChannelSupported, "SSO execution dialog");
3364
+ internalLogger.error(errorMsg);
3365
+ throw new ErrorWithCode(errorMsg, ErrorCode.ChannelNotSupported);
3366
+ }
3367
+ }
3368
+ }
3369
+
3370
+ // Copyright (c) Microsoft Corporation.
3371
+ /**
3372
+ * Default SSO execution activity handler
3373
+ */
3374
+ class DefaultBotSsoExecutionActivityHandler extends TeamsActivityHandler {
3375
+ /**
3376
+ * Creates a new instance of the DefaultBotSsoExecutionActivityHandler.
3377
+ * @param ssoConfig configuration for SSO command bot
3378
+ *
3379
+ * @remarks
3380
+ * In the constructor, it uses BotSsoConfig parameter which from {@link ConversationBot} options to initialize {@link BotSsoExecutionDialog}.
3381
+ * It also need to register an event handler for the message event which trigger {@link BotSsoExecutionDialog} instance.
3382
+ */
3383
+ constructor(ssoConfig) {
3384
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
3385
+ super();
3386
+ const memoryStorage = new MemoryStorage();
3387
+ const userState = (_b = (_a = ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.userState) !== null && _b !== void 0 ? _b : new UserState(memoryStorage);
3388
+ const conversationState = (_d = (_c = ssoConfig.dialog) === null || _c === void 0 ? void 0 : _c.conversationState) !== null && _d !== void 0 ? _d : new ConversationState(memoryStorage);
3389
+ const dedupStorage = (_f = (_e = ssoConfig.dialog) === null || _e === void 0 ? void 0 : _e.dedupStorage) !== null && _f !== void 0 ? _f : memoryStorage;
3390
+ const _l = ssoConfig.aad, { scopes } = _l, customConfig = __rest(_l, ["scopes"]);
3391
+ const settings = {
3392
+ scopes: scopes,
3393
+ timeout: (_h = (_g = ssoConfig.dialog) === null || _g === void 0 ? void 0 : _g.ssoPromptConfig) === null || _h === void 0 ? void 0 : _h.timeout,
3394
+ endOnInvalidMessage: (_k = (_j = ssoConfig.dialog) === null || _j === void 0 ? void 0 : _j.ssoPromptConfig) === null || _k === void 0 ? void 0 : _k.endOnInvalidMessage,
3395
+ };
3396
+ const teamsfx = new TeamsFx(IdentityType.User, Object.assign({}, customConfig));
3397
+ this.ssoExecutionDialog = new BotSsoExecutionDialog(dedupStorage, settings, teamsfx);
3398
+ this.conversationState = conversationState;
3399
+ this.dialogState = conversationState.createProperty("DialogState");
3400
+ this.userState = userState;
3401
+ this.onMessage(async (context, next) => {
3402
+ await this.ssoExecutionDialog.run(context, this.dialogState);
3403
+ await next();
3404
+ });
3405
+ }
3406
+ /**
3407
+ * Add TeamsFxBotSsoCommandHandler instance to SSO execution dialog
3408
+ * @param handler {@link BotSsoExecutionDialogHandler} callback function
3409
+ * @param triggerPatterns The trigger pattern
3410
+ *
3411
+ * @remarks
3412
+ * This function is used to add SSO command to {@link BotSsoExecutionDialog} instance.
3413
+ */
3414
+ addCommand(handler, triggerPatterns) {
3415
+ this.ssoExecutionDialog.addCommand(handler, triggerPatterns);
3416
+ }
3417
+ /**
3418
+ * Called to initiate the event emission process.
3419
+ * @param context The context object for the current turn.
3420
+ */
3421
+ async run(context) {
3422
+ try {
3423
+ await super.run(context);
3424
+ }
3425
+ finally {
3426
+ await this.conversationState.saveChanges(context, false);
3427
+ await this.userState.saveChanges(context, false);
3428
+ }
3429
+ }
3430
+ /**
3431
+ * Receives invoke activities with Activity name of 'signin/verifyState'.
3432
+ * @param context A context object for this turn.
3433
+ * @param query Signin state (part of signin action auth flow) verification invoke query.
3434
+ * @returns A promise that represents the work queued.
3435
+ *
3436
+ * @remarks
3437
+ * It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
3438
+ */
3439
+ async handleTeamsSigninVerifyState(context, query) {
3440
+ await this.ssoExecutionDialog.run(context, this.dialogState);
3441
+ }
3442
+ /**
3443
+ * Receives invoke activities with Activity name of 'signin/tokenExchange'
3444
+ * @param context A context object for this turn.
3445
+ * @param query Signin state (part of signin action auth flow) verification invoke query
3446
+ * @returns A promise that represents the work queued.
3447
+ *
3448
+ * @remark
3449
+ * It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
3450
+ */
3451
+ async handleTeamsSigninTokenExchange(context, query) {
3452
+ await this.ssoExecutionDialog.run(context, this.dialogState);
3453
+ }
2611
3454
  }
2612
3455
 
2613
3456
  // Copyright (c) Microsoft Corporation.
@@ -2661,8 +3504,6 @@ class NotificationBot {
2661
3504
  * For command and response, ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once.
2662
3505
  *
2663
3506
  * For notification, set `notification.storage` in {@link ConversationOptions} to use your own storage implementation.
2664
- *
2665
- * @beta
2666
3507
  */
2667
3508
  class ConversationBot {
2668
3509
  /**
@@ -2672,23 +3513,34 @@ class ConversationBot {
2672
3513
  * It's recommended to create your own adapter and storage for production environment instead of the default one.
2673
3514
  *
2674
3515
  * @param options - initialize options
2675
- *
2676
- * @beta
2677
3516
  */
2678
3517
  constructor(options) {
2679
- var _a, _b;
3518
+ var _a, _b, _c, _d;
2680
3519
  if (options.adapter) {
2681
3520
  this.adapter = options.adapter;
2682
3521
  }
2683
3522
  else {
2684
3523
  this.adapter = this.createDefaultAdapter(options.adapterConfig);
2685
3524
  }
2686
- if ((_a = options.command) === null || _a === void 0 ? void 0 : _a.enabled) {
2687
- this.command = new CommandBot(this.adapter, options.command);
3525
+ let ssoCommandActivityHandler;
3526
+ if (options === null || options === void 0 ? void 0 : options.ssoConfig) {
3527
+ if ((_a = options.ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.CustomBotSsoExecutionActivityHandler) {
3528
+ ssoCommandActivityHandler =
3529
+ new options.ssoConfig.dialog.CustomBotSsoExecutionActivityHandler(options.ssoConfig);
3530
+ }
3531
+ else {
3532
+ ssoCommandActivityHandler = new DefaultBotSsoExecutionActivityHandler(options.ssoConfig);
3533
+ }
3534
+ }
3535
+ if ((_b = options.command) === null || _b === void 0 ? void 0 : _b.enabled) {
3536
+ this.command = new CommandBot(this.adapter, options.command, ssoCommandActivityHandler, options.ssoConfig);
2688
3537
  }
2689
- if ((_b = options.notification) === null || _b === void 0 ? void 0 : _b.enabled) {
3538
+ if ((_c = options.notification) === null || _c === void 0 ? void 0 : _c.enabled) {
2690
3539
  this.notification = new NotificationBot(this.adapter, options.notification);
2691
3540
  }
3541
+ if ((_d = options.cardAction) === null || _d === void 0 ? void 0 : _d.enabled) {
3542
+ this.cardAction = new CardActionBot(this.adapter, options.cardAction);
3543
+ }
2692
3544
  }
2693
3545
  createDefaultAdapter(adapterConfig) {
2694
3546
  const adapter = adapterConfig === undefined
@@ -2729,8 +3581,6 @@ class ConversationBot {
2729
3581
  * });
2730
3582
  * });
2731
3583
  * ```
2732
- *
2733
- * @beta
2734
3584
  */
2735
3585
  async requestHandler(req, res, logic) {
2736
3586
  if (logic === undefined) {
@@ -2781,8 +3631,6 @@ class MessageBuilder {
2781
3631
  * description: "sample card description"
2782
3632
  * });
2783
3633
  * ```
2784
- *
2785
- * @beta
2786
3634
  */
2787
3635
  static attachAdaptiveCard(cardTemplate, data) {
2788
3636
  return {
@@ -2794,8 +3642,6 @@ class MessageBuilder {
2794
3642
  *
2795
3643
  * @param card The adaptive card content.
2796
3644
  * @returns A bot message activity attached with an adaptive card.
2797
- *
2798
- * @beta
2799
3645
  */
2800
3646
  static attachAdaptiveCardWithoutData(card) {
2801
3647
  return {
@@ -2821,8 +3667,6 @@ class MessageBuilder {
2821
3667
  * ['action']
2822
3668
  * );
2823
3669
  * ```
2824
- *
2825
- * @beta
2826
3670
  */
2827
3671
  static attachHeroCard(title, images, buttons, other) {
2828
3672
  return MessageBuilder.attachContent(CardFactory.heroCard(title, images, buttons, other));
@@ -2838,8 +3682,6 @@ class MessageBuilder {
2838
3682
  *
2839
3683
  * @remarks
2840
3684
  * For channels that don't natively support sign-in cards, an alternative message is rendered.
2841
- *
2842
- * @beta
2843
3685
  */
2844
3686
  static attachSigninCard(title, url, text) {
2845
3687
  return MessageBuilder.attachContent(CardFactory.signinCard(title, url, text));
@@ -2849,8 +3691,6 @@ class MessageBuilder {
2849
3691
  *
2850
3692
  * @param card A description of the Office 365 connector card.
2851
3693
  * @returns A bot message activity attached with an Office 365 connector card.
2852
- *
2853
- * @beta
2854
3694
  */
2855
3695
  static attachO365ConnectorCard(card) {
2856
3696
  return MessageBuilder.attachContent(CardFactory.o365ConnectorCard(card));
@@ -2859,8 +3699,6 @@ class MessageBuilder {
2859
3699
  * Build a message activity attached with a receipt card.
2860
3700
  * @param card A description of the receipt card.
2861
3701
  * @returns A message activity attached with a receipt card.
2862
- *
2863
- * @beta
2864
3702
  */
2865
3703
  static AttachReceiptCard(card) {
2866
3704
  return MessageBuilder.attachContent(CardFactory.receiptCard(card));
@@ -2873,8 +3711,6 @@ class MessageBuilder {
2873
3711
  * is converted to an `imBack` button with a title and value set to the value of the string.
2874
3712
  * @param other Optional. Any additional properties to include on the card.
2875
3713
  * @returns A message activity attached with a thumbnail card
2876
- *
2877
- * @beta
2878
3714
  */
2879
3715
  static attachThumbnailCard(title, images, buttons, other) {
2880
3716
  return MessageBuilder.attachContent(CardFactory.thumbnailCard(title, images, buttons, other));
@@ -2883,8 +3719,6 @@ class MessageBuilder {
2883
3719
  * Add an attachement to a bot activity.
2884
3720
  * @param attachement The attachment object to attach.
2885
3721
  * @returns A message activity with an attachment.
2886
- *
2887
- * @beta
2888
3722
  */
2889
3723
  static attachContent(attachement) {
2890
3724
  return {
@@ -2893,5 +3727,105 @@ class MessageBuilder {
2893
3727
  }
2894
3728
  }
2895
3729
 
2896
- export { ApiKeyLocation, ApiKeyProvider, AppCredential, BasicAuthProvider, BearerTokenAuthProvider, CertificateAuthProvider, Channel, CommandBot, ConversationBot, ErrorCode, ErrorWithCode, IdentityType, LogLevel, Member, MessageBuilder, MsGraphAuthProvider, NotificationBot, OnBehalfOfUserCredential, TeamsBotInstallation, TeamsBotSsoPrompt, TeamsFx, TeamsUserCredential, createApiClient, createMicrosoftGraphClient, createPemCertOption, createPfxCertOption, getLogLevel, getTediousConnectionConfig, sendAdaptiveCard, sendMessage, setLogFunction, setLogLevel, setLogger };
3730
+ // Copyright (c) Microsoft Corporation.
3731
+ /**
3732
+ * Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions.
3733
+ * This method only work on MessageExtension with Query now.
3734
+ *
3735
+ * @param {TeamsFx} teamsfx - Used to provide configuration and auth.
3736
+ * @param {string | string[]} scopes - The list of scopes for which the token will have access.
3737
+ *
3738
+ * @returns SignIn link CardAction with 200 status code.
3739
+ */
3740
+ function getSignInResponseForMessageExtension(teamsfx, scopes) {
3741
+ const scopesArray = getScopesArray(scopes);
3742
+ const signInLink = `${teamsfx.getConfig("initiateLoginEndpoint")}?scope=${encodeURI(scopesArray.join(" "))}&clientId=${teamsfx.getConfig("clientId")}&tenantId=${teamsfx.getConfig("tenantId")}`;
3743
+ return {
3744
+ composeExtension: {
3745
+ type: "silentAuth",
3746
+ suggestedActions: {
3747
+ actions: [
3748
+ {
3749
+ type: "openUrl",
3750
+ value: signInLink,
3751
+ title: "Message Extension OAuth",
3752
+ },
3753
+ ],
3754
+ },
3755
+ },
3756
+ };
3757
+ }
3758
+ /**
3759
+ * execution in message extension with SSO token.
3760
+ *
3761
+ * @param {TurnContext} context - The context object for the current turn.
3762
+ * @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration.
3763
+ * @param {string[]} scopes - The list of scopes for which the token will have access.
3764
+ * @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
3765
+ *
3766
+ * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
3767
+ * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
3768
+ * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
3769
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
3770
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
3771
+ *
3772
+ * @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
3773
+ */
3774
+ async function executionWithToken(context, config, scopes, logic) {
3775
+ const valueObj = context.activity.value;
3776
+ if (!valueObj.authentication || !valueObj.authentication.token) {
3777
+ internalLogger.verbose("No AccessToken in request, return silentAuth for AccessToken");
3778
+ return getSignInResponseForMessageExtension(new TeamsFx(IdentityType.User, config), scopes);
3779
+ }
3780
+ try {
3781
+ const teamsfx = new TeamsFx(IdentityType.User, config).setSsoToken(valueObj.authentication.token);
3782
+ const token = await teamsfx.getCredential().getToken(scopes);
3783
+ const ssoTokenExpiration = parseJwt(valueObj.authentication.token).exp;
3784
+ const tokenRes = {
3785
+ ssoToken: valueObj.authentication.token,
3786
+ ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),
3787
+ token: token.token,
3788
+ expiration: token.expiresOnTimestamp.toString(),
3789
+ connectionName: "",
3790
+ };
3791
+ if (logic) {
3792
+ return await logic(tokenRes);
3793
+ }
3794
+ }
3795
+ catch (err) {
3796
+ if (err instanceof ErrorWithCode && err.code === ErrorCode.UiRequiredError) {
3797
+ internalLogger.verbose("User not consent yet, return 412 to user consent first.");
3798
+ const response = { status: 412 };
3799
+ await context.sendActivity({ value: response, type: ActivityTypes.InvokeResponse });
3800
+ return;
3801
+ }
3802
+ throw err;
3803
+ }
3804
+ }
3805
+ /**
3806
+ * Users execute query in message extension with SSO or access token.
3807
+ *
3808
+ * @param {TurnContext} context - The context object for the current turn.
3809
+ * @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration.
3810
+ * @param {string| string[]} scopes - The list of scopes for which the token will have access.
3811
+ * @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
3812
+ *
3813
+ * @throws {@link ErrorCode|InternalError} when User invoke not response to message extension query.
3814
+ * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
3815
+ * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
3816
+ * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
3817
+ * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
3818
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
3819
+ *
3820
+ * @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
3821
+ */
3822
+ async function handleMessageExtensionQueryWithToken(context, config, scopes, logic) {
3823
+ if (context.activity.name != "composeExtension/query") {
3824
+ internalLogger.error(ErrorMessage.OnlySupportInQueryActivity);
3825
+ throw new ErrorWithCode(formatString(ErrorMessage.OnlySupportInQueryActivity), ErrorCode.FailedOperation);
3826
+ }
3827
+ return await executionWithToken(context, config !== null && config !== void 0 ? config : {}, scopes, logic);
3828
+ }
3829
+
3830
+ export { AdaptiveCardResponse, ApiKeyLocation, ApiKeyProvider, AppCredential, BasicAuthProvider, BearerTokenAuthProvider, BotSsoExecutionDialog, CardActionBot, CertificateAuthProvider, Channel, CommandBot, ConversationBot, ErrorCode, ErrorWithCode, IdentityType, InvokeResponseErrorCode, InvokeResponseFactory, LogLevel, Member, MessageBuilder, MsGraphAuthProvider, NotificationBot, NotificationTargetType, OnBehalfOfUserCredential, SearchScope, TeamsBotInstallation, TeamsBotSsoPrompt, TeamsFx, TeamsUserCredential, createApiClient, createMicrosoftGraphClient, createPemCertOption, createPfxCertOption, getLogLevel, getTediousConnectionConfig, handleMessageExtensionQueryWithToken, sendAdaptiveCard, sendMessage, setLogFunction, setLogLevel, setLogger };
2897
3831
  //# sourceMappingURL=index.esm2017.mjs.map