@microsoft/teamsfx 0.6.2 → 0.6.3-alpha.42a29d71b.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,9 +3,13 @@ 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 } from 'botbuilder';
6
+ import { ActivityTypes, Channels, TeamsInfo, CardFactory, ActionTypes, MessageFactory, StatusCodes, verifyStateOperationName, tokenExchangeOperationName, TurnContext, BotFrameworkAdapter } from 'botbuilder';
7
7
  import { Dialog } from 'botbuilder-dialogs';
8
8
  import { v4 } from 'uuid';
9
+ import axios from 'axios';
10
+ import { Agent } from 'https';
11
+ import * as path from 'path';
12
+ import * as fs from 'fs';
9
13
 
10
14
  // Copyright (c) Microsoft Corporation.
11
15
  // Licensed under the MIT license.
@@ -67,6 +71,10 @@ var ErrorCode;
67
71
  * Identity type error.
68
72
  */
69
73
  ErrorCode["IdentityTypeNotSupported"] = "IdentityTypeNotSupported";
74
+ /**
75
+ * Authentication info already exists error.
76
+ */
77
+ ErrorCode["AuthorizationInfoAlreadyExists"] = "AuthorizationInfoAlreadyExists";
70
78
  })(ErrorCode || (ErrorCode = {}));
71
79
  /**
72
80
  * @internal
@@ -88,6 +96,14 @@ ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token
88
96
  ErrorMessage.OnlyMSTeamsChannelSupported = "{0} is only supported in MS Teams Channel";
89
97
  // IdentityTypeNotSupported Error
90
98
  ErrorMessage.IdentityTypeNotSupported = "{0} identity is not supported in {1}";
99
+ // AuthorizationInfoError
100
+ ErrorMessage.AuthorizationHeaderAlreadyExists = "Authorization header already exists!";
101
+ ErrorMessage.BasicCredentialAlreadyExists = "Basic credential already exists!";
102
+ // InvalidParameter Error
103
+ ErrorMessage.EmptyParameter = "Parameter {0} is empty";
104
+ ErrorMessage.DuplicateHttpsOptionProperty = "Axios HTTPS agent already defined value for property {0}";
105
+ ErrorMessage.DuplicateApiKeyInHeader = "The request already defined api key in request header with name {0}.";
106
+ ErrorMessage.DuplicateApiKeyInQueryParam = "The request already defined api key in query parameter with name {0}.";
91
107
  /**
92
108
  * Error class with code and message thrown by the SDK.
93
109
  *
@@ -1386,6 +1402,325 @@ class TeamsBotSsoPrompt extends Dialog {
1386
1402
  }
1387
1403
 
1388
1404
  // Copyright (c) Microsoft Corporation.
1405
+ /**
1406
+ * Initializes new Axios instance with specific auth provider
1407
+ *
1408
+ * @param apiEndpoint - Base url of the API
1409
+ * @param authProvider - Auth provider that injects authentication info to each request
1410
+ * @returns axios instance configured with specfic auth provider
1411
+ *
1412
+ * @example
1413
+ * ```typescript
1414
+ * const client = createApiClient("https://my-api-endpoint-base-url", new BasicAuthProvider("xxx","xxx"));
1415
+ * ```
1416
+ *
1417
+ * @beta
1418
+ */
1419
+ function createApiClient(apiEndpoint, authProvider) {
1420
+ // Add a request interceptor
1421
+ const instance = axios.create({
1422
+ baseURL: apiEndpoint,
1423
+ });
1424
+ instance.interceptors.request.use(async function (config) {
1425
+ return await authProvider.AddAuthenticationInfo(config);
1426
+ });
1427
+ return instance;
1428
+ }
1429
+
1430
+ // Copyright (c) Microsoft Corporation.
1431
+ /**
1432
+ * Provider that handles Bearer Token authentication
1433
+ *
1434
+ * @beta
1435
+ */
1436
+ class BearerTokenAuthProvider {
1437
+ /**
1438
+ * @param { () => Promise<string> } getToken - Function that returns the content of bearer token used in http request
1439
+ *
1440
+ * @beta
1441
+ */
1442
+ constructor(getToken) {
1443
+ this.getToken = getToken;
1444
+ }
1445
+ /**
1446
+ * Adds authentication info to http requests
1447
+ *
1448
+ * @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
1449
+ * Refer https://axios-http.com/docs/req_config for detailed document.
1450
+ *
1451
+ * @returns Updated axios request config.
1452
+ *
1453
+ * @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header already exists in request configuration.
1454
+ *
1455
+ * @beta
1456
+ */
1457
+ async AddAuthenticationInfo(config) {
1458
+ const token = await this.getToken();
1459
+ if (!config.headers) {
1460
+ config.headers = {};
1461
+ }
1462
+ if (config.headers["Authorization"]) {
1463
+ throw new ErrorWithCode(ErrorMessage.AuthorizationHeaderAlreadyExists, ErrorCode.AuthorizationInfoAlreadyExists);
1464
+ }
1465
+ config.headers["Authorization"] = `Bearer ${token}`;
1466
+ return config;
1467
+ }
1468
+ }
1469
+
1470
+ // Copyright (c) Microsoft Corporation.
1471
+ /**
1472
+ * Provider that handles Basic authentication
1473
+ *
1474
+ * @beta
1475
+ */
1476
+ class BasicAuthProvider {
1477
+ /**
1478
+ *
1479
+ * @param { string } userName - Username used in basic auth
1480
+ * @param { string } password - Password used in basic auth
1481
+ *
1482
+ * @throws {@link ErrorCode|InvalidParameter} - when username or password is empty.
1483
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1484
+ *
1485
+ * @beta
1486
+ */
1487
+ constructor(userName, password) {
1488
+ if (!userName) {
1489
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "username"), ErrorCode.InvalidParameter);
1490
+ }
1491
+ if (!password) {
1492
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "password"), ErrorCode.InvalidParameter);
1493
+ }
1494
+ this.userName = userName;
1495
+ this.password = password;
1496
+ }
1497
+ /**
1498
+ * Adds authentication info to http requests
1499
+ *
1500
+ * @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
1501
+ * Refer https://axios-http.com/docs/req_config for detailed document.
1502
+ *
1503
+ * @returns Updated axios request config.
1504
+ *
1505
+ * @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header or auth property already exists in request configuration.
1506
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1507
+ *
1508
+ * @beta
1509
+ */
1510
+ async AddAuthenticationInfo(config) {
1511
+ if (config.headers && config.headers["Authorization"]) {
1512
+ throw new ErrorWithCode(ErrorMessage.AuthorizationHeaderAlreadyExists, ErrorCode.AuthorizationInfoAlreadyExists);
1513
+ }
1514
+ if (config.auth) {
1515
+ throw new ErrorWithCode(ErrorMessage.BasicCredentialAlreadyExists, ErrorCode.AuthorizationInfoAlreadyExists);
1516
+ }
1517
+ config.auth = {
1518
+ username: this.userName,
1519
+ password: this.password,
1520
+ };
1521
+ return config;
1522
+ }
1523
+ }
1524
+
1525
+ // Copyright (c) Microsoft Corporation.
1526
+ /**
1527
+ * Provider that handles API Key authentication
1528
+ *
1529
+ * @beta
1530
+ */
1531
+ class ApiKeyProvider {
1532
+ /**
1533
+ *
1534
+ * @param { string } keyName - The name of request header or query parameter that specifies API Key
1535
+ * @param { string } keyValue - The value of API Key
1536
+ * @param { ApiKeyLocation } keyLocation - The location of API Key: request header or query parameter.
1537
+ *
1538
+ * @throws {@link ErrorCode|InvalidParameter} - when key name or key value is empty.
1539
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1540
+ *
1541
+ * @beta
1542
+ */
1543
+ constructor(keyName, keyValue, keyLocation) {
1544
+ if (!keyName) {
1545
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "keyName"), ErrorCode.InvalidParameter);
1546
+ }
1547
+ if (!keyValue) {
1548
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "keyVaule"), ErrorCode.InvalidParameter);
1549
+ }
1550
+ this.keyName = keyName;
1551
+ this.keyValue = keyValue;
1552
+ this.keyLocation = keyLocation;
1553
+ }
1554
+ /**
1555
+ * Adds authentication info to http requests
1556
+ *
1557
+ * @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
1558
+ * Refer https://axios-http.com/docs/req_config for detailed document.
1559
+ *
1560
+ * @returns Updated axios request config.
1561
+ *
1562
+ * @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when API key already exists in request header or url query parameter.
1563
+ * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1564
+ *
1565
+ * @beta
1566
+ */
1567
+ async AddAuthenticationInfo(config) {
1568
+ switch (this.keyLocation) {
1569
+ case ApiKeyLocation.Header:
1570
+ if (!config.headers) {
1571
+ config.headers = {};
1572
+ }
1573
+ if (config.headers[this.keyName]) {
1574
+ throw new ErrorWithCode(formatString(ErrorMessage.DuplicateApiKeyInHeader, this.keyName), ErrorCode.AuthorizationInfoAlreadyExists);
1575
+ }
1576
+ config.headers[this.keyName] = this.keyValue;
1577
+ break;
1578
+ case ApiKeyLocation.QueryParams:
1579
+ if (!config.params) {
1580
+ config.params = {};
1581
+ }
1582
+ const url = new URL(config.url, config.baseURL);
1583
+ if (config.params[this.keyName] || url.searchParams.has(this.keyName)) {
1584
+ throw new ErrorWithCode(formatString(ErrorMessage.DuplicateApiKeyInQueryParam, this.keyName), ErrorCode.AuthorizationInfoAlreadyExists);
1585
+ }
1586
+ config.params[this.keyName] = this.keyValue;
1587
+ break;
1588
+ }
1589
+ return config;
1590
+ }
1591
+ }
1592
+ /**
1593
+ * Define available location for API Key location
1594
+ *
1595
+ * @beta
1596
+ */
1597
+ var ApiKeyLocation;
1598
+ (function (ApiKeyLocation) {
1599
+ /**
1600
+ * The API Key is placed in request header
1601
+ */
1602
+ ApiKeyLocation[ApiKeyLocation["Header"] = 0] = "Header";
1603
+ /**
1604
+ * The API Key is placed in query parameter
1605
+ */
1606
+ ApiKeyLocation[ApiKeyLocation["QueryParams"] = 1] = "QueryParams";
1607
+ })(ApiKeyLocation || (ApiKeyLocation = {}));
1608
+
1609
+ // Copyright (c) Microsoft Corporation.
1610
+ /**
1611
+ * Provider that handles Certificate authentication
1612
+ *
1613
+ * @beta
1614
+ */
1615
+ class CertificateAuthProvider {
1616
+ /**
1617
+ *
1618
+ * @param { SecureContextOptions } certOption - information about the cert used in http requests
1619
+ *
1620
+ * @throws {@link ErrorCode|InvalidParameter} - when cert option is empty.
1621
+ *
1622
+ * @beta
1623
+ */
1624
+ constructor(certOption) {
1625
+ if (certOption && Object.keys(certOption).length !== 0) {
1626
+ this.certOption = certOption;
1627
+ }
1628
+ else {
1629
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "certOption"), ErrorCode.InvalidParameter);
1630
+ }
1631
+ }
1632
+ /**
1633
+ * Adds authentication info to http requests.
1634
+ *
1635
+ * @param { AxiosRequestConfig } config - Contains all the request information and can be updated to include extra authentication info.
1636
+ * Refer https://axios-http.com/docs/req_config for detailed document.
1637
+ *
1638
+ * @returns Updated axios request config.
1639
+ *
1640
+ * @throws {@link ErrorCode|InvalidParameter} - when custom httpsAgent in the request has duplicate properties with certOption provided in constructor.
1641
+ *
1642
+ * @beta
1643
+ */
1644
+ async AddAuthenticationInfo(config) {
1645
+ if (!config.httpsAgent) {
1646
+ config.httpsAgent = new Agent(this.certOption);
1647
+ }
1648
+ else {
1649
+ const existingProperties = new Set(Object.keys(config.httpsAgent.options));
1650
+ for (const property of Object.keys(this.certOption)) {
1651
+ if (existingProperties.has(property)) {
1652
+ throw new ErrorWithCode(formatString(ErrorMessage.DuplicateHttpsOptionProperty, property), ErrorCode.InvalidParameter);
1653
+ }
1654
+ }
1655
+ Object.assign(config.httpsAgent.options, this.certOption);
1656
+ }
1657
+ return config;
1658
+ }
1659
+ }
1660
+ /**
1661
+ * Helper to create SecureContextOptions from PEM format cert
1662
+ *
1663
+ * @param { string | Buffer } cert - The cert chain in PEM format
1664
+ * @param { string | Buffer } key - The private key for the cert chain
1665
+ * @param { {passphrase?: string; ca?: string | Buffer} } options - Optional settings when create the cert options.
1666
+ *
1667
+ * @returns Instance of SecureContextOptions
1668
+ *
1669
+ * @throws {@link ErrorCode|InvalidParameter} - when any parameter is empty
1670
+ *
1671
+ */
1672
+ function createPemCertOption(cert, key, options) {
1673
+ if (cert.length === 0) {
1674
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "cert"), ErrorCode.InvalidParameter);
1675
+ }
1676
+ if (key.length === 0) {
1677
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "key"), ErrorCode.InvalidParameter);
1678
+ }
1679
+ return {
1680
+ cert,
1681
+ key,
1682
+ passphrase: options === null || options === void 0 ? void 0 : options.passphrase,
1683
+ ca: options === null || options === void 0 ? void 0 : options.ca,
1684
+ };
1685
+ }
1686
+ /**
1687
+ * Helper to create SecureContextOptions from PFX format cert
1688
+ *
1689
+ * @param { string | Buffer } pfx - The content of .pfx file
1690
+ * @param { {passphrase?: string} } options - Optional settings when create the cert options.
1691
+ *
1692
+ * @returns Instance of SecureContextOptions
1693
+ *
1694
+ * @throws {@link ErrorCode|InvalidParameter} - when any parameter is empty
1695
+ *
1696
+ */
1697
+ function createPfxCertOption(pfx, options) {
1698
+ if (pfx.length === 0) {
1699
+ throw new ErrorWithCode(formatString(ErrorMessage.EmptyParameter, "pfx"), ErrorCode.InvalidParameter);
1700
+ }
1701
+ return {
1702
+ pfx,
1703
+ passphrase: options === null || options === void 0 ? void 0 : options.passphrase,
1704
+ };
1705
+ }
1706
+
1707
+ // Copyright (c) Microsoft Corporation.
1708
+ // Following keys are used by SDK internally
1709
+ const ReservedKey = new Set([
1710
+ "authorityHost",
1711
+ "tenantId",
1712
+ "clientId",
1713
+ "clientSecret",
1714
+ "initiateLoginEndpoint",
1715
+ "applicationIdUri",
1716
+ "apiEndpoint",
1717
+ "apiName",
1718
+ "sqlServerEndpoint",
1719
+ "sqlUsername",
1720
+ "sqlPassword",
1721
+ "sqlDatabaseName",
1722
+ "sqlIdentityId",
1723
+ ]);
1389
1724
  /**
1390
1725
  * A class providing credential and configuration.
1391
1726
  * @beta
@@ -1559,13 +1894,979 @@ class TeamsFx {
1559
1894
  this.configuration.set("sqlDatabaseName", env.SQL_DATABASE_NAME);
1560
1895
  this.configuration.set("sqlIdentityId", env.IDENTITY_ID);
1561
1896
  Object.keys(env).forEach((key) => {
1562
- const value = env[key];
1563
- if (key.startsWith("TEAMSFX_") && value) {
1564
- this.configuration.set(key.substring(8), value);
1897
+ if (ReservedKey.has(key)) {
1898
+ internalLogger.warn(`The name of environment variable ${key} is preserved. Will not load it as configuration.`);
1899
+ }
1900
+ this.configuration.set(key, env[key]);
1901
+ });
1902
+ }
1903
+ }
1904
+
1905
+ // Copyright (c) Microsoft Corporation.
1906
+ /**
1907
+ * @internal
1908
+ */
1909
+ var ActivityType;
1910
+ (function (ActivityType) {
1911
+ ActivityType[ActivityType["CurrentBotInstalled"] = 0] = "CurrentBotInstalled";
1912
+ ActivityType[ActivityType["CurrentBotMessaged"] = 1] = "CurrentBotMessaged";
1913
+ ActivityType[ActivityType["CurrentBotUninstalled"] = 2] = "CurrentBotUninstalled";
1914
+ ActivityType[ActivityType["TeamDeleted"] = 3] = "TeamDeleted";
1915
+ ActivityType[ActivityType["TeamRestored"] = 4] = "TeamRestored";
1916
+ ActivityType[ActivityType["Unknown"] = 5] = "Unknown";
1917
+ })(ActivityType || (ActivityType = {}));
1918
+ /**
1919
+ * @internal
1920
+ */
1921
+ class NotificationMiddleware {
1922
+ constructor(options) {
1923
+ this.conversationReferenceStore = options.conversationReferenceStore;
1924
+ }
1925
+ async onTurn(context, next) {
1926
+ const type = this.classifyActivity(context.activity);
1927
+ switch (type) {
1928
+ case ActivityType.CurrentBotInstalled:
1929
+ case ActivityType.TeamRestored: {
1930
+ const reference = TurnContext.getConversationReference(context.activity);
1931
+ await this.conversationReferenceStore.set(reference);
1932
+ break;
1933
+ }
1934
+ case ActivityType.CurrentBotUninstalled:
1935
+ case ActivityType.TeamDeleted: {
1936
+ const reference = TurnContext.getConversationReference(context.activity);
1937
+ await this.conversationReferenceStore.delete(reference);
1938
+ break;
1939
+ }
1940
+ }
1941
+ await next();
1942
+ }
1943
+ classifyActivity(activity) {
1944
+ var _a, _b;
1945
+ const activityType = activity.type;
1946
+ if (activityType === "installationUpdate") {
1947
+ const action = (_a = activity.action) === null || _a === void 0 ? void 0 : _a.toLowerCase();
1948
+ if (action === "add") {
1949
+ return ActivityType.CurrentBotInstalled;
1950
+ }
1951
+ else {
1952
+ return ActivityType.CurrentBotUninstalled;
1953
+ }
1954
+ }
1955
+ else if (activityType === "conversationUpdate") {
1956
+ const eventType = (_b = activity.channelData) === null || _b === void 0 ? void 0 : _b.eventType;
1957
+ if (eventType === "teamDeleted") {
1958
+ return ActivityType.TeamDeleted;
1959
+ }
1960
+ else if (eventType === "teamRestored") {
1961
+ return ActivityType.TeamRestored;
1962
+ }
1963
+ }
1964
+ return ActivityType.Unknown;
1965
+ }
1966
+ }
1967
+ class CommandResponseMiddleware {
1968
+ constructor(handlers) {
1969
+ this.commandHandlers = [];
1970
+ if (handlers && handlers.length > 0) {
1971
+ this.commandHandlers.push(...handlers);
1972
+ }
1973
+ }
1974
+ async onTurn(context, next) {
1975
+ const type = this.classifyActivity(context.activity);
1976
+ switch (type) {
1977
+ case ActivityType.CurrentBotMessaged:
1978
+ // Invoke corresponding command handler for the command response
1979
+ const commandText = this.getActivityText(context.activity);
1980
+ const message = {
1981
+ text: commandText,
1982
+ };
1983
+ for (const handler of this.commandHandlers) {
1984
+ const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
1985
+ // It is important to note that the command bot will stop processing handlers
1986
+ // when the first command handler is matched.
1987
+ if (!!matchResult) {
1988
+ message.matches = Array.isArray(matchResult) ? matchResult : void 0;
1989
+ const response = await handler.handleCommandReceived(context, message);
1990
+ await context.sendActivity(response);
1991
+ break;
1992
+ }
1993
+ }
1994
+ break;
1995
+ }
1996
+ await next();
1997
+ }
1998
+ classifyActivity(activity) {
1999
+ if (activity.type === ActivityTypes.Message) {
2000
+ return ActivityType.CurrentBotMessaged;
2001
+ }
2002
+ return ActivityType.Unknown;
2003
+ }
2004
+ matchPattern(pattern, text) {
2005
+ if (text) {
2006
+ if (typeof pattern === "string") {
2007
+ const regExp = new RegExp(pattern, "i");
2008
+ return regExp.test(text);
2009
+ }
2010
+ if (pattern instanceof RegExp) {
2011
+ const matches = text.match(pattern);
2012
+ return matches !== null && matches !== void 0 ? matches : false;
2013
+ }
2014
+ }
2015
+ return false;
2016
+ }
2017
+ shouldTrigger(patterns, text) {
2018
+ const expressions = Array.isArray(patterns) ? patterns : [patterns];
2019
+ for (const ex of expressions) {
2020
+ const arg = this.matchPattern(ex, text);
2021
+ if (arg)
2022
+ return arg;
2023
+ }
2024
+ return false;
2025
+ }
2026
+ getActivityText(activity) {
2027
+ let text = activity.text;
2028
+ const removedMentionText = TurnContext.removeRecipientMention(activity);
2029
+ if (removedMentionText) {
2030
+ text = removedMentionText
2031
+ .toLowerCase()
2032
+ .replace(/\n|\r\n/g, "")
2033
+ .trim();
2034
+ }
2035
+ return text;
2036
+ }
2037
+ }
2038
+
2039
+ // Copyright (c) Microsoft Corporation.
2040
+ /**
2041
+ * A command bot for receiving commands and sending responses in Teams.
2042
+ *
2043
+ * @remarks
2044
+ * 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.
2045
+ *
2046
+ * @beta
2047
+ */
2048
+ class CommandBot {
2049
+ /**
2050
+ * Creates a new instance of the `CommandBot`.
2051
+ *
2052
+ * @param adapter The bound `BotFrameworkAdapter`.
2053
+ * @param options - initialize options
2054
+ *
2055
+ * @beta
2056
+ */
2057
+ constructor(adapter, options) {
2058
+ this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands);
2059
+ this.adapter = adapter.use(this.middleware);
2060
+ }
2061
+ /**
2062
+ * Registers a command into the command bot.
2063
+ *
2064
+ * @param command The command to registered.
2065
+ *
2066
+ * @beta
2067
+ */
2068
+ registerCommand(command) {
2069
+ if (command) {
2070
+ this.middleware.commandHandlers.push(command);
2071
+ }
2072
+ }
2073
+ /**
2074
+ * Registers commands into the command bot.
2075
+ *
2076
+ * @param commands The command to registered.
2077
+ *
2078
+ * @beta
2079
+ */
2080
+ registerCommands(commands) {
2081
+ if (commands) {
2082
+ this.middleware.commandHandlers.push(...commands);
2083
+ }
2084
+ }
2085
+ }
2086
+
2087
+ // Copyright (c) Microsoft Corporation.
2088
+ /**
2089
+ * @internal
2090
+ */
2091
+ class LocalFileStorage {
2092
+ constructor(fileDir) {
2093
+ this.localFileName = ".notification.localstore.json";
2094
+ this.filePath = path.resolve(fileDir, this.localFileName);
2095
+ }
2096
+ async read(key) {
2097
+ if (!(await this.storeFileExists())) {
2098
+ return undefined;
2099
+ }
2100
+ const data = await this.readFromFile();
2101
+ return data[key];
2102
+ }
2103
+ async list() {
2104
+ if (!(await this.storeFileExists())) {
2105
+ return [];
2106
+ }
2107
+ const data = await this.readFromFile();
2108
+ return Object.entries(data).map((entry) => entry[1]);
2109
+ }
2110
+ async write(key, object) {
2111
+ if (!(await this.storeFileExists())) {
2112
+ await this.writeToFile({ [key]: object });
2113
+ return;
2114
+ }
2115
+ const data = await this.readFromFile();
2116
+ await this.writeToFile(Object.assign(data, { [key]: object }));
2117
+ }
2118
+ async delete(key) {
2119
+ if (await this.storeFileExists()) {
2120
+ const data = await this.readFromFile();
2121
+ if (data[key] !== undefined) {
2122
+ delete data[key];
2123
+ await this.writeToFile(data);
2124
+ }
2125
+ }
2126
+ }
2127
+ storeFileExists() {
2128
+ return new Promise((resolve) => {
2129
+ try {
2130
+ fs.access(this.filePath, (err) => {
2131
+ if (err) {
2132
+ resolve(false);
2133
+ }
2134
+ else {
2135
+ resolve(true);
2136
+ }
2137
+ });
2138
+ }
2139
+ catch (error) {
2140
+ resolve(false);
1565
2141
  }
1566
2142
  });
1567
2143
  }
2144
+ readFromFile() {
2145
+ return new Promise((resolve, reject) => {
2146
+ try {
2147
+ fs.readFile(this.filePath, { encoding: "utf-8" }, (err, rawData) => {
2148
+ if (err) {
2149
+ reject(err);
2150
+ }
2151
+ else {
2152
+ resolve(JSON.parse(rawData));
2153
+ }
2154
+ });
2155
+ }
2156
+ catch (error) {
2157
+ reject(error);
2158
+ }
2159
+ });
2160
+ }
2161
+ async writeToFile(data) {
2162
+ return new Promise((resolve, reject) => {
2163
+ try {
2164
+ const rawData = JSON.stringify(data, undefined, 2);
2165
+ fs.writeFile(this.filePath, rawData, { encoding: "utf-8" }, (err) => {
2166
+ if (err) {
2167
+ reject(err);
2168
+ }
2169
+ else {
2170
+ resolve();
2171
+ }
2172
+ });
2173
+ }
2174
+ catch (error) {
2175
+ reject(error);
2176
+ }
2177
+ });
2178
+ }
2179
+ }
2180
+ /**
2181
+ * @internal
2182
+ */
2183
+ class ConversationReferenceStore {
2184
+ constructor(storage) {
2185
+ this.storage = storage;
2186
+ }
2187
+ async check(reference) {
2188
+ const ref = await this.storage.read(this.getKey(reference));
2189
+ return ref !== undefined;
2190
+ }
2191
+ getAll() {
2192
+ return this.storage.list();
2193
+ }
2194
+ set(reference) {
2195
+ return this.storage.write(this.getKey(reference), reference);
2196
+ }
2197
+ delete(reference) {
2198
+ return this.storage.delete(this.getKey(reference));
2199
+ }
2200
+ getKey(reference) {
2201
+ var _a, _b;
2202
+ return `_${(_a = reference.conversation) === null || _a === void 0 ? void 0 : _a.tenantId}_${(_b = reference.conversation) === null || _b === void 0 ? void 0 : _b.id}`;
2203
+ }
2204
+ }
2205
+
2206
+ // Copyright (c) Microsoft Corporation.
2207
+ // Licensed under the MIT license.
2208
+ /**
2209
+ * @internal
2210
+ */
2211
+ function cloneConversation(conversation) {
2212
+ return Object.assign({}, conversation);
2213
+ }
2214
+ /**
2215
+ * @internal
2216
+ */
2217
+ function getTargetType(conversationReference) {
2218
+ var _a;
2219
+ const conversationType = (_a = conversationReference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
2220
+ if (conversationType === "personal") {
2221
+ return "Person";
2222
+ }
2223
+ else if (conversationType === "groupChat") {
2224
+ return "Group";
2225
+ }
2226
+ else if (conversationType === "channel") {
2227
+ return "Channel";
2228
+ }
2229
+ else {
2230
+ return undefined;
2231
+ }
2232
+ }
2233
+ /**
2234
+ * @internal
2235
+ */
2236
+ function getTeamsBotInstallationId(context) {
2237
+ var _a, _b, _c, _d;
2238
+ 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;
2239
+ }
2240
+
2241
+ // Copyright (c) Microsoft Corporation.
2242
+ /**
2243
+ * Send a plain text message to a notification target.
2244
+ *
2245
+ * @param target - the notification target.
2246
+ * @param text - the plain text message.
2247
+ * @returns A `Promise` representing the asynchronous operation.
2248
+ *
2249
+ * @beta
2250
+ */
2251
+ function sendMessage(target, text) {
2252
+ return target.sendMessage(text);
2253
+ }
2254
+ /**
2255
+ * Send an adaptive card message to a notification target.
2256
+ *
2257
+ * @param target - the notification target.
2258
+ * @param card - the adaptive card raw JSON.
2259
+ * @returns A `Promise` representing the asynchronous operation.
2260
+ *
2261
+ * @beta
2262
+ */
2263
+ function sendAdaptiveCard(target, card) {
2264
+ return target.sendAdaptiveCard(card);
2265
+ }
2266
+ /**
2267
+ * A {@link NotificationTarget} that represents a team channel.
2268
+ *
2269
+ * @remarks
2270
+ * It's recommended to get channels from {@link TeamsBotInstallation.channels()}.
2271
+ *
2272
+ * @beta
2273
+ */
2274
+ class Channel {
2275
+ /**
2276
+ * Constuctor.
2277
+ *
2278
+ * @remarks
2279
+ * It's recommended to get channels from {@link TeamsBotInstallation.channels()}, instead of using this constructor.
2280
+ *
2281
+ * @param parent - The parent {@link TeamsBotInstallation} where this channel is created from.
2282
+ * @param info - Detailed channel information.
2283
+ *
2284
+ * @beta
2285
+ */
2286
+ constructor(parent, info) {
2287
+ /**
2288
+ * Notification target type. For channel it's always "Channel".
2289
+ *
2290
+ * @beta
2291
+ */
2292
+ this.type = "Channel";
2293
+ this.parent = parent;
2294
+ this.info = info;
2295
+ }
2296
+ /**
2297
+ * Send a plain text message.
2298
+ *
2299
+ * @param text - the plain text message.
2300
+ * @returns A `Promise` representing the asynchronous operation.
2301
+ *
2302
+ * @beta
2303
+ */
2304
+ sendMessage(text) {
2305
+ return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2306
+ const conversation = await this.newConversation(context);
2307
+ await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2308
+ await ctx.sendActivity(text);
2309
+ });
2310
+ });
2311
+ }
2312
+ /**
2313
+ * Send an adaptive card message.
2314
+ *
2315
+ * @param card - the adaptive card raw JSON.
2316
+ * @returns A `Promise` representing the asynchronous operation.
2317
+ *
2318
+ * @beta
2319
+ */
2320
+ async sendAdaptiveCard(card) {
2321
+ return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2322
+ const conversation = await this.newConversation(context);
2323
+ await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2324
+ await ctx.sendActivity({
2325
+ attachments: [CardFactory.adaptiveCard(card)],
2326
+ });
2327
+ });
2328
+ });
2329
+ }
2330
+ /**
2331
+ * @internal
2332
+ */
2333
+ async newConversation(context) {
2334
+ const reference = TurnContext.getConversationReference(context.activity);
2335
+ const channelConversation = cloneConversation(reference);
2336
+ channelConversation.conversation.id = this.info.id || "";
2337
+ return channelConversation;
2338
+ }
2339
+ }
2340
+ /**
2341
+ * A {@link NotificationTarget} that represents a team member.
2342
+ *
2343
+ * @remarks
2344
+ * It's recommended to get members from {@link TeamsBotInstallation.members()}.
2345
+ *
2346
+ * @beta
2347
+ */
2348
+ class Member {
2349
+ /**
2350
+ * Constuctor.
2351
+ *
2352
+ * @remarks
2353
+ * It's recommended to get members from {@link TeamsBotInstallation.members()}, instead of using this constructor.
2354
+ *
2355
+ * @param parent - The parent {@link TeamsBotInstallation} where this member is created from.
2356
+ * @param account - Detailed member account information.
2357
+ *
2358
+ * @beta
2359
+ */
2360
+ constructor(parent, account) {
2361
+ /**
2362
+ * Notification target type. For member it's always "Person".
2363
+ *
2364
+ * @beta
2365
+ */
2366
+ this.type = "Person";
2367
+ this.parent = parent;
2368
+ this.account = account;
2369
+ }
2370
+ /**
2371
+ * Send a plain text message.
2372
+ *
2373
+ * @param text - the plain text message.
2374
+ * @returns A `Promise` representing the asynchronous operation.
2375
+ *
2376
+ * @beta
2377
+ */
2378
+ sendMessage(text) {
2379
+ return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2380
+ const conversation = await this.newConversation(context);
2381
+ await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2382
+ await ctx.sendActivity(text);
2383
+ });
2384
+ });
2385
+ }
2386
+ /**
2387
+ * Send an adaptive card message.
2388
+ *
2389
+ * @param card - the adaptive card raw JSON.
2390
+ * @returns A `Promise` representing the asynchronous operation.
2391
+ *
2392
+ * @beta
2393
+ */
2394
+ async sendAdaptiveCard(card) {
2395
+ return this.parent.adapter.continueConversation(this.parent.conversationReference, async (context) => {
2396
+ const conversation = await this.newConversation(context);
2397
+ await this.parent.adapter.continueConversation(conversation, async (ctx) => {
2398
+ await ctx.sendActivity({
2399
+ attachments: [CardFactory.adaptiveCard(card)],
2400
+ });
2401
+ });
2402
+ });
2403
+ }
2404
+ /**
2405
+ * @internal
2406
+ */
2407
+ async newConversation(context) {
2408
+ const reference = TurnContext.getConversationReference(context.activity);
2409
+ const personalConversation = cloneConversation(reference);
2410
+ const connectorClient = context.turnState.get(this.parent.adapter.ConnectorClientKey);
2411
+ const conversation = await connectorClient.conversations.createConversation({
2412
+ isGroup: false,
2413
+ tenantId: context.activity.conversation.tenantId,
2414
+ bot: context.activity.recipient,
2415
+ members: [this.account],
2416
+ channelData: {},
2417
+ });
2418
+ personalConversation.conversation.id = conversation.id;
2419
+ return personalConversation;
2420
+ }
2421
+ }
2422
+ /**
2423
+ * A {@link NotificationTarget} that represents a bot installation. Teams Bot could be installed into
2424
+ * - Personal chat
2425
+ * - Group chat
2426
+ * - Team (by default the `General` channel)
2427
+ *
2428
+ * @remarks
2429
+ * It's recommended to get bot installations from {@link ConversationBot.installations()}.
2430
+ *
2431
+ * @beta
2432
+ */
2433
+ class TeamsBotInstallation {
2434
+ /**
2435
+ * Constructor
2436
+ *
2437
+ * @remarks
2438
+ * It's recommended to get bot installations from {@link ConversationBot.installations()}, instead of using this constructor.
2439
+ *
2440
+ * @param adapter - the bound `BotFrameworkAdapter`.
2441
+ * @param conversationReference - the bound `ConversationReference`.
2442
+ *
2443
+ * @beta
2444
+ */
2445
+ constructor(adapter, conversationReference) {
2446
+ this.adapter = adapter;
2447
+ this.conversationReference = conversationReference;
2448
+ this.type = getTargetType(conversationReference);
2449
+ }
2450
+ /**
2451
+ * Send a plain text message.
2452
+ *
2453
+ * @param text - the plain text message.
2454
+ * @returns A `Promise` representing the asynchronous operation.
2455
+ *
2456
+ * @beta
2457
+ */
2458
+ sendMessage(text) {
2459
+ return this.adapter.continueConversation(this.conversationReference, async (context) => {
2460
+ await context.sendActivity(text);
2461
+ });
2462
+ }
2463
+ /**
2464
+ * Send an adaptive card message.
2465
+ *
2466
+ * @param card - the adaptive card raw JSON.
2467
+ * @returns A `Promise` representing the asynchronous operation.
2468
+ *
2469
+ * @beta
2470
+ */
2471
+ sendAdaptiveCard(card) {
2472
+ return this.adapter.continueConversation(this.conversationReference, async (context) => {
2473
+ await context.sendActivity({
2474
+ attachments: [CardFactory.adaptiveCard(card)],
2475
+ });
2476
+ });
2477
+ }
2478
+ /**
2479
+ * Get channels from this bot installation.
2480
+ *
2481
+ * @returns an array of channels if bot is installed into a team, otherwise returns an empty array.
2482
+ *
2483
+ * @beta
2484
+ */
2485
+ async channels() {
2486
+ let teamsChannels = [];
2487
+ await this.adapter.continueConversation(this.conversationReference, async (context) => {
2488
+ const teamId = getTeamsBotInstallationId(context);
2489
+ if (teamId !== undefined) {
2490
+ teamsChannels = await TeamsInfo.getTeamChannels(context, teamId);
2491
+ }
2492
+ });
2493
+ const channels = [];
2494
+ for (const channel of teamsChannels) {
2495
+ channels.push(new Channel(this, channel));
2496
+ }
2497
+ return channels;
2498
+ }
2499
+ /**
2500
+ * Get members from this bot installation.
2501
+ *
2502
+ * @returns an array of members from where the bot is installed.
2503
+ *
2504
+ * @beta
2505
+ */
2506
+ async members() {
2507
+ const members = [];
2508
+ await this.adapter.continueConversation(this.conversationReference, async (context) => {
2509
+ let continuationToken;
2510
+ do {
2511
+ const pagedMembers = await TeamsInfo.getPagedMembers(context, undefined, continuationToken);
2512
+ continuationToken = pagedMembers.continuationToken;
2513
+ for (const member of pagedMembers.members) {
2514
+ members.push(new Member(this, member));
2515
+ }
2516
+ } while (continuationToken !== undefined);
2517
+ });
2518
+ return members;
2519
+ }
2520
+ }
2521
+ /**
2522
+ * Provide utilities to send notification to varies targets (e.g., member, group, channel).
2523
+ *
2524
+ * @beta
2525
+ */
2526
+ class NotificationBot {
2527
+ /**
2528
+ * constructor of the notification bot.
2529
+ *
2530
+ * @remarks
2531
+ * To ensure accuracy, it's recommended to initialize before handling any message.
2532
+ *
2533
+ * @param adapter - the bound `BotFrameworkAdapter`
2534
+ * @param options - initialize options
2535
+ *
2536
+ * @beta
2537
+ */
2538
+ constructor(adapter, options) {
2539
+ var _a, _b;
2540
+ const storage = (_a = options === null || options === void 0 ? void 0 : options.storage) !== null && _a !== void 0 ? _a : new LocalFileStorage(path.resolve(process.env.RUNNING_ON_AZURE === "1" ? (_b = process.env.TEMP) !== null && _b !== void 0 ? _b : "./" : "./"));
2541
+ this.conversationReferenceStore = new ConversationReferenceStore(storage);
2542
+ this.adapter = adapter.use(new NotificationMiddleware({
2543
+ conversationReferenceStore: this.conversationReferenceStore,
2544
+ }));
2545
+ }
2546
+ /**
2547
+ * Get all targets where the bot is installed.
2548
+ *
2549
+ * @remarks
2550
+ * The result is retrieving from the persisted storage.
2551
+ *
2552
+ * @returns - an array of {@link TeamsBotInstallation}.
2553
+ *
2554
+ * @beta
2555
+ */
2556
+ async installations() {
2557
+ if (this.conversationReferenceStore === undefined || this.adapter === undefined) {
2558
+ throw new Error("NotificationBot has not been initialized.");
2559
+ }
2560
+ const references = (await this.conversationReferenceStore.getAll()).values();
2561
+ const targets = [];
2562
+ for (const reference of references) {
2563
+ // validate connection
2564
+ let valid = true;
2565
+ this.adapter.continueConversation(reference, async (context) => {
2566
+ try {
2567
+ // try get member to see if the installation is still valid
2568
+ await TeamsInfo.getPagedMembers(context, 1);
2569
+ }
2570
+ catch (error) {
2571
+ if (error.code === "BotNotInConversationRoster") {
2572
+ valid = false;
2573
+ }
2574
+ }
2575
+ });
2576
+ if (valid) {
2577
+ targets.push(new TeamsBotInstallation(this.adapter, reference));
2578
+ }
2579
+ else {
2580
+ this.conversationReferenceStore.delete(reference);
2581
+ }
2582
+ }
2583
+ return targets;
2584
+ }
2585
+ }
2586
+
2587
+ // Copyright (c) Microsoft Corporation.
2588
+ /**
2589
+ * Provide utilities for bot conversation, including:
2590
+ * - handle command and response.
2591
+ * - send notification to varies targets (e.g., member, group, channel).
2592
+ *
2593
+ * @example
2594
+ * For command and response, you can register your commands through the constructor, or use the `registerCommand` and `registerCommands` API to add commands later.
2595
+ *
2596
+ * ```typescript
2597
+ * // register through constructor
2598
+ * const conversationBot = new ConversationBot({
2599
+ * command: {
2600
+ * enabled: true,
2601
+ * commands: [ new HelloWorldCommandHandler() ],
2602
+ * },
2603
+ * });
2604
+ *
2605
+ * // register through `register*` API
2606
+ * conversationBot.command.registerCommand(new HelpCommandHandler());
2607
+ * ```
2608
+ *
2609
+ * For notification, you can enable notification at initialization, then send notifications at any time.
2610
+ *
2611
+ * ```typescript
2612
+ * // enable through constructor
2613
+ * const conversationBot = new ConversationBot({
2614
+ * notification: {
2615
+ * enabled: true,
2616
+ * },
2617
+ * });
2618
+ *
2619
+ * // get all bot installations and send message
2620
+ * for (const target of await conversationBot.notification.installations()) {
2621
+ * await target.sendMessage("Hello Notification");
2622
+ * }
2623
+ *
2624
+ * // alternative - send message to all members
2625
+ * for (const target of await conversationBot.notification.installations()) {
2626
+ * for (const member of await target.members()) {
2627
+ * await member.sendMessage("Hello Notification");
2628
+ * }
2629
+ * }
2630
+ * ```
2631
+ *
2632
+ * @remarks
2633
+ * Set `adapter` in {@link ConversationOptions} to use your own bot adapter.
2634
+ *
2635
+ * 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.
2636
+ *
2637
+ * For notification, set `notification.storage` in {@link ConversationOptions} to use your own storage implementation.
2638
+ *
2639
+ * @beta
2640
+ */
2641
+ class ConversationBot {
2642
+ /**
2643
+ * Creates new instance of the `ConversationBot`.
2644
+ *
2645
+ * @remarks
2646
+ * It's recommended to create your own adapter and storage for production environment instead of the default one.
2647
+ *
2648
+ * @param options - initialize options
2649
+ *
2650
+ * @beta
2651
+ */
2652
+ constructor(options) {
2653
+ var _a, _b;
2654
+ if (options.adapter) {
2655
+ this.adapter = options.adapter;
2656
+ }
2657
+ else {
2658
+ this.adapter = this.createDefaultAdapter(options.adapterConfig);
2659
+ }
2660
+ if ((_a = options.command) === null || _a === void 0 ? void 0 : _a.enabled) {
2661
+ this.command = new CommandBot(this.adapter, options.command);
2662
+ }
2663
+ if ((_b = options.notification) === null || _b === void 0 ? void 0 : _b.enabled) {
2664
+ this.notification = new NotificationBot(this.adapter, options.notification);
2665
+ }
2666
+ }
2667
+ createDefaultAdapter(adapterConfig) {
2668
+ const adapter = adapterConfig === undefined
2669
+ ? new BotFrameworkAdapter({
2670
+ appId: process.env.BOT_ID,
2671
+ appPassword: process.env.BOT_PASSWORD,
2672
+ })
2673
+ : new BotFrameworkAdapter(adapterConfig);
2674
+ // the default error handler
2675
+ adapter.onTurnError = async (context, error) => {
2676
+ // This check writes out errors to console.
2677
+ console.error(`[onTurnError] unhandled error: ${error}`);
2678
+ // Send a trace activity, which will be displayed in Bot Framework Emulator
2679
+ await context.sendTraceActivity("OnTurnError Trace", `${error}`, "https://www.botframework.com/schemas/error", "TurnError");
2680
+ // Send a message to the user
2681
+ await context.sendActivity(`The bot encountered unhandled error: ${error.message}`);
2682
+ await context.sendActivity("To continue to run this bot, please fix the bot source code.");
2683
+ };
2684
+ return adapter;
2685
+ }
2686
+ /**
2687
+ * The request handler to integrate with web request.
2688
+ *
2689
+ * @param req - an Express or Restify style request object.
2690
+ * @param res - an Express or Restify style response object.
2691
+ * @param logic - the additional function to handle bot context.
2692
+ *
2693
+ * @example
2694
+ * For example, to use with Restify:
2695
+ * ``` typescript
2696
+ * // The default/empty behavior
2697
+ * server.post("api/messages", conversationBot.requestHandler);
2698
+ *
2699
+ * // Or, add your own logic
2700
+ * server.post("api/messages", async (req, res) => {
2701
+ * await conversationBot.requestHandler(req, res, async (context) => {
2702
+ * // your-own-context-logic
2703
+ * });
2704
+ * });
2705
+ * ```
2706
+ *
2707
+ * @beta
2708
+ */
2709
+ async requestHandler(req, res, logic) {
2710
+ if (logic === undefined) {
2711
+ // create empty logic
2712
+ logic = async () => { };
2713
+ }
2714
+ await this.adapter.processActivity(req, res, logic);
2715
+ }
2716
+ }
2717
+
2718
+ // Copyright (c) Microsoft Corporation.
2719
+ const { AdaptiveCards } = require("@microsoft/adaptivecards-tools");
2720
+ /**
2721
+ * Provides utility method to build bot message with cards that supported in Teams.
2722
+ */
2723
+ class MessageBuilder {
2724
+ /**
2725
+ * Build a bot message activity attached with adaptive card.
2726
+ *
2727
+ * @param cardTemplate The adaptive card template.
2728
+ * @param data card data used to render the template.
2729
+ * @returns A bot message activity attached with an adaptive card.
2730
+ *
2731
+ * @example
2732
+ * ```javascript
2733
+ * const cardTemplate = {
2734
+ * type: "AdaptiveCard",
2735
+ * body: [
2736
+ * {
2737
+ * "type": "TextBlock",
2738
+ * "text": "${title}",
2739
+ * "size": "Large"
2740
+ * },
2741
+ * {
2742
+ * "type": "TextBlock",
2743
+ * "text": "${description}"
2744
+ * }],
2745
+ * $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
2746
+ * version: "1.4"
2747
+ * };
2748
+ *
2749
+ * type CardData = {
2750
+ * title: string,
2751
+ * description: string
2752
+ * };
2753
+ * const card = MessageBuilder.attachAdaptiveCard<CardData>(
2754
+ * cardTemplate, {
2755
+ * title: "sample card title",
2756
+ * description: "sample card description"
2757
+ * });
2758
+ * ```
2759
+ *
2760
+ * @beta
2761
+ */
2762
+ static attachAdaptiveCard(cardTemplate, data) {
2763
+ return {
2764
+ attachments: [CardFactory.adaptiveCard(AdaptiveCards.declare(cardTemplate).render(data))],
2765
+ };
2766
+ }
2767
+ /**
2768
+ * Build a bot message activity attached with an adaptive card.
2769
+ *
2770
+ * @param card The adaptive card content.
2771
+ * @returns A bot message activity attached with an adaptive card.
2772
+ *
2773
+ * @beta
2774
+ */
2775
+ static attachAdaptiveCardWithoutData(card) {
2776
+ return {
2777
+ attachments: [CardFactory.adaptiveCard(AdaptiveCards.declareWithoutData(card).render())],
2778
+ };
2779
+ }
2780
+ /**
2781
+ * Build a bot message activity attached with an hero card.
2782
+ *
2783
+ * @param title The card title.
2784
+ * @param images Optional. The array of images to include on the card.
2785
+ * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array
2786
+ * is converted to an `imBack` button with a title and value set to the value of the string.
2787
+ * @param other Optional. Any additional properties to include on the card.
2788
+ *
2789
+ * @returns A bot message activity attached with a hero card.
2790
+ *
2791
+ * @example
2792
+ * ```javascript
2793
+ * const message = MessageBuilder.attachHeroCard(
2794
+ * 'sample title',
2795
+ * ['https://example.com/sample.jpg'],
2796
+ * ['action']
2797
+ * );
2798
+ * ```
2799
+ *
2800
+ * @beta
2801
+ */
2802
+ static attachHeroCard(title, images, buttons, other) {
2803
+ return MessageBuilder.attachContent(CardFactory.heroCard(title, images, buttons, other));
2804
+ }
2805
+ /**
2806
+ * Returns an attachment for a sign-in card.
2807
+ *
2808
+ * @param title The title for the card's sign-in button.
2809
+ * @param url The URL of the sign-in page to use.
2810
+ * @param text Optional. Additional text to include on the card.
2811
+ *
2812
+ * @returns A bot message activity attached with a sign-in card.
2813
+ *
2814
+ * @remarks
2815
+ * For channels that don't natively support sign-in cards, an alternative message is rendered.
2816
+ *
2817
+ * @beta
2818
+ */
2819
+ static attachSigninCard(title, url, text) {
2820
+ return MessageBuilder.attachContent(CardFactory.signinCard(title, url, text));
2821
+ }
2822
+ /**
2823
+ * Build a bot message activity attached with an Office 365 connector card.
2824
+ *
2825
+ * @param card A description of the Office 365 connector card.
2826
+ * @returns A bot message activity attached with an Office 365 connector card.
2827
+ *
2828
+ * @beta
2829
+ */
2830
+ static attachO365ConnectorCard(card) {
2831
+ return MessageBuilder.attachContent(CardFactory.o365ConnectorCard(card));
2832
+ }
2833
+ /**
2834
+ * Build a message activity attached with a receipt card.
2835
+ * @param card A description of the receipt card.
2836
+ * @returns A message activity attached with a receipt card.
2837
+ *
2838
+ * @beta
2839
+ */
2840
+ static AttachReceiptCard(card) {
2841
+ return MessageBuilder.attachContent(CardFactory.receiptCard(card));
2842
+ }
2843
+ /**
2844
+ *
2845
+ * @param title The card title.
2846
+ * @param images Optional. The array of images to include on the card.
2847
+ * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array
2848
+ * is converted to an `imBack` button with a title and value set to the value of the string.
2849
+ * @param other Optional. Any additional properties to include on the card.
2850
+ * @returns A message activity attached with a thumbnail card
2851
+ *
2852
+ * @beta
2853
+ */
2854
+ static attachThumbnailCard(title, images, buttons, other) {
2855
+ return MessageBuilder.attachContent(CardFactory.thumbnailCard(title, images, buttons, other));
2856
+ }
2857
+ /**
2858
+ * Add an attachement to a bot activity.
2859
+ * @param attachement The attachment object to attach.
2860
+ * @returns A message activity with an attachment.
2861
+ *
2862
+ * @beta
2863
+ */
2864
+ static attachContent(attachement) {
2865
+ return {
2866
+ attachments: [attachement],
2867
+ };
2868
+ }
1568
2869
  }
1569
2870
 
1570
- export { AppCredential, ErrorCode, ErrorWithCode, IdentityType, LogLevel, MsGraphAuthProvider, OnBehalfOfUserCredential, TeamsBotSsoPrompt, TeamsFx, TeamsUserCredential, createMicrosoftGraphClient, getLogLevel, getTediousConnectionConfig, setLogFunction, setLogLevel, setLogger };
2871
+ 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 };
1571
2872
  //# sourceMappingURL=index.esm2017.mjs.map