@microsoft/teams.client 0.2.13 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,37 +1,37 @@
1
- # Teams: Client
2
-
3
- <p>
4
- <a href="https://www.npmjs.com/package/@microsoft/teams.client" target="_blank">
5
- <img src="https://img.shields.io/npm/v/@microsoft/teams.client" />
6
- </a>
7
- <a href="https://www.npmjs.com/package/@microsoft/teams.client?activeTab=code" target="_blank">
8
- <img src="https://img.shields.io/bundlephobia/min/@microsoft/teams.client" />
9
- </a>
10
- <a href="https://www.npmjs.com/package/@microsoft/teams.client?activeTab=dependencies" target="_blank">
11
- <img src="https://img.shields.io/librariesio/release/npm/@microsoft/teams.client" />
12
- </a>
13
- <a href="https://www.npmjs.com/package/@microsoft/teams.client" target="_blank">
14
- <img src="https://img.shields.io/npm/dw/@microsoft/teams.client" />
15
- </a>
16
- <a href="https://microsoft.github.io/teams-ai" target="_blank">
17
- <img src="https://img.shields.io/badge/📖 docs-open-blue" />
18
- </a>
19
- </p>
20
-
21
- A client used to create app/bot surfaces such as tabs.
22
-
23
- <a href="https://microsoft.github.io/teams-ai" target="_blank">
24
- <img src="https://img.shields.io/badge/📖 Getting Started-blue?style=for-the-badge" />
25
- </a>
26
-
27
- ## Install
28
-
29
- ```bash
30
- $: npm install @microsoft/teams.client
31
- ```
32
-
33
- ## Dependencies
34
-
35
- ## Links
36
-
37
- - https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/what-are-tabs?tabs=personal
1
+ # Teams: Client
2
+
3
+ <p>
4
+ <a href="https://www.npmjs.com/package/@microsoft/teams.client" target="_blank">
5
+ <img src="https://img.shields.io/npm/v/@microsoft/teams.client" />
6
+ </a>
7
+ <a href="https://www.npmjs.com/package/@microsoft/teams.client?activeTab=code" target="_blank">
8
+ <img src="https://img.shields.io/bundlephobia/min/@microsoft/teams.client" />
9
+ </a>
10
+ <a href="https://www.npmjs.com/package/@microsoft/teams.client?activeTab=dependencies" target="_blank">
11
+ <img src="https://img.shields.io/librariesio/release/npm/@microsoft/teams.client" />
12
+ </a>
13
+ <a href="https://www.npmjs.com/package/@microsoft/teams.client" target="_blank">
14
+ <img src="https://img.shields.io/npm/dw/@microsoft/teams.client" />
15
+ </a>
16
+ <a href="https://microsoft.github.io/teams-ai" target="_blank">
17
+ <img src="https://img.shields.io/badge/📖 docs-open-blue" />
18
+ </a>
19
+ </p>
20
+
21
+ A client used to create app/bot surfaces such as tabs.
22
+
23
+ <a href="https://microsoft.github.io/teams-ai" target="_blank">
24
+ <img src="https://img.shields.io/badge/📖 Getting Started-blue?style=for-the-badge" />
25
+ </a>
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ $: npm install @microsoft/teams.client
31
+ ```
32
+
33
+ ## Dependencies
34
+
35
+ ## Links
36
+
37
+ - https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/what-are-tabs?tabs=personal
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/app.ts"],"names":["ConsoleLogger","http","buildGraphClient","teamsJs","buildMsalConfig","msal","acquireMsalAccessToken","getStandardExecSilentRequest","hasConsentForScopes"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEO,MAAM,GAAI,CAAA;AAAA,EACN,OAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACC,MAAA,GAAmB,EAAE,KAAA,EAAO,SAAU,EAAA;AAAA;AAAA;AAAA;AAAA,EAKhD,IAAI,GAAM,GAAA;AACR,IAAA,OAAO,IAAK,CAAA,IAAA;AAAA;AACd,EACU,IAAA;AAAA;AAAA;AAAA;AAAA,EAKV,IAAI,SAAY,GAAA;AACd,IAAA,OAAO,KAAK,MAAQ,EAAA,SAAA;AAAA;AACtB;AAAA,EAGA,IAAI,YAAe,GAAA;AACjB,IAAA,OAAO,KAAK,MAAO,CAAA,YAAA;AAAA;AACrB,EAEA,WAAY,CAAA,QAAA,EAAkB,OAAsB,GAAA,EAAI,EAAA;AACtD,IAAA,IAAI,CAAC,QAAU,EAAA;AACb,MAAM,MAAA,IAAI,MAAM,oBAAoB,CAAA;AAAA;AAGtC,IAAA,IAAA,CAAK,QAAW,GAAA,QAAA;AAChB,IAAA,IAAA,CAAK,OAAU,GAAA,OAAA;AACf,IAAA,IAAA,CAAK,IAAO,GAAA,OAAA,EAAS,MAAU,IAAA,IAAIA,sBAAc,eAAe,CAAA;AAChE,IAAK,IAAA,CAAA,IAAA,GAAO,IAAIC,eAAK,CAAA,MAAA,CAAO,EAAE,OAAS,EAAA,OAAA,EAAS,SAAS,CAAA;AACzD,IAAA,IAAA,CAAK,QAAQC,2BAAiB,CAAA,MAAM,KAAK,aAAc,EAAA,EAAG,KAAK,IAAI,CAAA;AAAA;AACrE;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAuB,GAAA;AAC3B,IAAI,IAAA,IAAA,CAAK,MAAO,CAAA,KAAA,KAAU,SAAW,EAAA;AACnC,MAAA,IAAA,CAAK,KAAK,KAAM,CAAA,CAAA,YAAA,EAAe,IAAK,CAAA,MAAA,CAAO,KAAK,CAAE,CAAA,CAAA;AAClD,MAAA;AAAA;AAGF,IAAK,IAAA,CAAA,IAAA,CAAK,MAAM,cAAc,CAAA;AAC9B,IAAK,IAAA,CAAA,MAAA,GAAS,EAAE,KAAA,EAAO,UAAW,EAAA;AAElC,IAAM,MAAAC,kBAAA,CAAQ,IAAI,UAAW,EAAA;AAC7B,IAAA,MAAM,OAAU,GAAA,MAAMA,kBAAQ,CAAA,GAAA,CAAI,UAAW,EAAA;AAE7C,IAAM,MAAA,UAAA,GACJ,KAAK,OAAQ,CAAA,WAAA,EAAa,iBAAiBC,yBAAgB,CAAA,IAAA,CAAK,QAAU,EAAA,IAAA,CAAK,IAAI,CAAA;AACrF,IAAA,MAAM,YAAe,GAAA,MAAMC,eAAK,CAAA,qCAAA,CAAsC,UAAU,CAAA;AAChF,IAAA,MAAM,aAAa,UAAW,EAAA;AAE9B,IAAK,IAAA,CAAA,MAAA,GAAS,EAAE,KAAO,EAAA,SAAA,EAAW,cAAc,OAAS,EAAA,SAAA,kBAAe,IAAA,IAAA,EAAO,EAAA;AAG/E,IAAA,IAAI,IAAK,CAAA,OAAA,CAAQ,WAAa,EAAA,aAAA,KAAkB,KAAO,EAAA;AACrD,MAAA,MAAM,SAAS,IAAK,CAAA,OAAA,CAAQ,WAAa,EAAA,aAAA,IAAiB,CAAC,UAAU,CAAA;AACrE,MAAA,IAAA,CAAK,KAAK,KAAM,CAAA,CAAA,+BAAA,EAAkC,OAAO,IAAK,CAAA,IAAI,CAAC,CAAE,CAAA,CAAA;AACrE,MAAM,MAAA,IAAA,CAAK,uBAAuB,MAAM,CAAA;AAAA;AAG1C,IAAK,IAAA,CAAA,IAAA,CAAK,MAAM,aAAa,CAAA;AAAA;AAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,IAAA,CAAkB,IAAc,EAAA,IAAA,EAAgB,OAAmC,EAAA;AACvF,IAAA,MAAM,EAAE,YAAA,EAAc,OAAQ,EAAA,GAAI,KAAK,aAAc,EAAA;AAErD,IAAA,MAAM,cAAc,MAAMC,gCAAA;AAAA,MACxB,YAAA;AAAA,MACA,SAAS,gBAAoB,IAAAC,sCAAA,CAA6B,IAAK,CAAA,QAAA,EAAU,SAAS,UAAU,CAAA;AAAA,MAC5F,IAAK,CAAA;AAAA,KACP;AAEA,IAAM,MAAA,GAAA,GAAM,MAAM,IAAK,CAAA,IAAA,CAAK,KAAQ,CAAkB,eAAA,EAAA,IAAI,IAAI,IAAM,EAAA;AAAA,MAClE,OAAS,EAAA;AAAA,QACP,aAAA,EAAe,UAAU,WAAW,CAAA,CAAA;AAAA,QACpC,wBAAA,EAA0B,QAAQ,GAAI,CAAA,SAAA;AAAA,QACtC,oBAAA,EAAsB,QAAQ,OAAS,EAAA,EAAA;AAAA,QACvC,iBAAA,EAAmB,QAAQ,IAAM,EAAA,EAAA;AAAA,QACjC,oBAAA,EAAsB,QAAQ,OAAS,EAAA,EAAA;AAAA,QACvC,oBAAA,EAAsB,QAAQ,GAAI,CAAA,eAAA;AAAA,QAClC,iBAAA,EAAmB,QAAQ,IAAK,CAAA,EAAA;AAAA,QAChC,qBAAA,EAAuB,QAAQ,IAAK,CAAA,SAAA;AAAA,QACpC,iBAAA,EAAmB,QAAQ,IAAM,EAAA,UAAA;AAAA,QACjC,GAAI,OAAS,EAAA,cAAA,IAAkB;AAAC;AAClC,KACD,CAAA;AAED,IAAA,OAAO,GAAI,CAAA,IAAA;AAAA;AACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,oBAAoB,MAAoC,EAAA;AAC5D,IAAA,MAAM,EAAE,YAAA,EAAiB,GAAA,IAAA,CAAK,aAAc,EAAA;AAE5C,IAAA,OAAO,MAAMC,6BAAA,CAAoB,YAAc,EAAA,MAAA,EAAQ,KAAK,GAAG,CAAA;AAAA;AACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,uBAAuB,MAAoC,EAAA;AAC/D,IAAA,MAAM,EAAE,YAAA,EAAiB,GAAA,IAAA,CAAK,aAAc,EAAA;AAE5C,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAQ,MAAMF,gCAAuB,CAAA,YAAA,EAAc,EAAE,MAAO,EAAA,EAAG,KAAK,GAAG,CAAA;AAC7E,MAAA,OAAO,CAAC,CAAC,KAAA;AAAA,aACF,EAAI,EAAA;AACX,MAAO,OAAA,KAAA;AAAA;AACT;AACF,EAEQ,aAAiD,GAAA;AACvD,IAAI,IAAA,IAAA,CAAK,MAAO,CAAA,KAAA,KAAU,SAAW,EAAA;AACnC,MAAM,MAAA,IAAI,MAAM,iBAAiB,CAAA;AAAA;AAEnC,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AAEhB","file":"app.js","sourcesContent":["import * as msal from '@azure/msal-browser';\r\n\r\nimport * as teamsJs from '@microsoft/teams-js';\r\nimport * as http from '@microsoft/teams.common/http';\r\nimport { ILogger, ConsoleLogger } from '@microsoft/teams.common/logging';\r\nimport * as graph from '@microsoft/teams.graph';\r\n\r\nimport { buildGraphClient } from './graph-utils';\r\nimport {\r\n acquireMsalAccessToken,\r\n buildMsalConfig,\r\n getStandardExecSilentRequest,\r\n hasConsentForScopes,\r\n} from './msal-utils';\r\n\r\nexport type MsalOptions = {\r\n /**\r\n * Optional MSAL configuration. This parameter is used to construct an MSAL instance in order\r\n * to make authenticated function calls. If omitted, a default configuration is created.\r\n */\r\n readonly configuration?: msal.Configuration;\r\n /**\r\n * Options to control scope consent pre-warming. If explicitly set to false, no pre-warming is performed.\r\n * If no value is provided, the default scope (i.e. \".default\") is pre-warmed. If a set of scopes is\r\n * provided, the specified scopes are pre-warmed. The scopes should be for a single resource, and they\r\n * should not mix the .default scope with named scopes.\r\n */\r\n readonly prewarmScopes?: false | string[];\r\n};\r\n\r\nexport type AppOptions = {\r\n /**\r\n * The app base url.\r\n */\r\n readonly baseUrl?: string;\r\n\r\n /** App tenant ID */\r\n readonly tenantId?: string;\r\n\r\n /**\r\n * Logger instance to use.\r\n */\r\n readonly logger?: ILogger;\r\n\r\n /**\r\n * Options to control how MSAL is initialized and used.\r\n */\r\n readonly msalOptions?: MsalOptions;\r\n};\r\n\r\ntype AppState =\r\n | {\r\n phase: 'stopped' | 'starting';\r\n startedAt?: never;\r\n msalInstance?: never;\r\n context?: never;\r\n }\r\n | {\r\n phase: 'started';\r\n startedAt: Date;\r\n msalInstance: msal.IPublicClientApplication;\r\n context: teamsJs.app.Context;\r\n };\r\n\r\nexport type ExecOptions = (\r\n | { msalTokenRequest: msal.SilentRequest; permission?: never }\r\n | { msalTokenRequest?: never; permission: string }\r\n | { msalTokenRequest?: never; permission?: never }\r\n) & {\r\n requestHeaders?: Record<string, string>;\r\n};\r\n\r\nexport class App {\r\n readonly options: AppOptions;\r\n readonly http: http.Client;\r\n readonly graph: graph.Client;\r\n readonly clientId: string;\r\n protected _state: AppState = { phase: 'stopped' };\r\n\r\n /**\r\n * the apps logger\r\n */\r\n get log() {\r\n return this._log;\r\n }\r\n protected _log: ILogger;\r\n\r\n /**\r\n * the date/time when the app was successfully started.\r\n */\r\n get startedAt() {\r\n return this._state?.startedAt;\r\n }\r\n\r\n /** the msal instance used in this app. undefined until the app is started. */\r\n get msalInstance() {\r\n return this._state.msalInstance;\r\n }\r\n\r\n constructor(clientId: string, options: AppOptions = {}) {\r\n if (!clientId) {\r\n throw new Error('Invalid client ID.');\r\n }\r\n\r\n this.clientId = clientId;\r\n this.options = options;\r\n this._log = options?.logger || new ConsoleLogger('@teams/client');\r\n this.http = new http.Client({ baseUrl: options?.baseUrl });\r\n this.graph = buildGraphClient(() => this.appStateGuard(), this._log);\r\n }\r\n\r\n /**\r\n * Starts the library and initializes the dependent teams-js and MSAL libraries.\r\n * @returns A promise that will be fulfilled when the app has started, or\r\n * rejected if the initialization fails or times out.\r\n */\r\n async start(): Promise<void> {\r\n if (this._state.phase !== 'stopped') {\r\n this._log.debug(`app already ${this._state.phase}`);\r\n return;\r\n }\r\n\r\n this._log.debug('app starting');\r\n this._state = { phase: 'starting' };\r\n\r\n await teamsJs.app.initialize();\r\n const context = await teamsJs.app.getContext();\r\n\r\n const msalConfig =\r\n this.options.msalOptions?.configuration ?? buildMsalConfig(this.clientId, this._log);\r\n const msalInstance = await msal.createNestablePublicClientApplication(msalConfig);\r\n await msalInstance.initialize();\r\n\r\n this._state = { phase: 'started', msalInstance, context, startedAt: new Date() };\r\n\r\n // pre-warm consent for the specified scopes\r\n if (this.options.msalOptions?.prewarmScopes !== false) {\r\n const scopes = this.options.msalOptions?.prewarmScopes ?? ['.default'];\r\n this._log.debug(`prewarming consent for scopes: ${scopes.join(', ')}`);\r\n await this.ensureConsentForScopes(scopes);\r\n }\r\n\r\n this._log.debug('app started');\r\n }\r\n\r\n /**\r\n * Execute a server-side function\r\n * @param name The unique function name\r\n * @param data The data to send\r\n * @param options Options\r\n * @param options.msalTokenRequest Optional MSAL token request.\r\n * If omitted, a default token request is used.\r\n * @param options.requestHeaders Optional additional request headers.\r\n * @returns The function response\r\n */\r\n async exec<T = unknown>(name: string, data?: unknown, options?: ExecOptions): Promise<T> {\r\n const { msalInstance, context } = this.appStateGuard();\r\n\r\n const accessToken = await acquireMsalAccessToken(\r\n msalInstance,\r\n options?.msalTokenRequest ?? getStandardExecSilentRequest(this.clientId, options?.permission),\r\n this._log\r\n );\r\n\r\n const res = await this.http.post<T>(`/api/functions/${name}`, data, {\r\n headers: {\r\n authorization: `Bearer ${accessToken}`,\r\n 'x-teams-app-session-id': context.app.sessionId,\r\n 'x-teams-channel-id': context.channel?.id,\r\n 'x-teams-chat-id': context.chat?.id,\r\n 'x-teams-meeting-id': context.meeting?.id,\r\n 'x-teams-message-id': context.app.parentMessageId,\r\n 'x-teams-page-id': context.page.id,\r\n 'x-teams-sub-page-id': context.page.subPageId,\r\n 'x-teams-team-id': context.team?.internalId,\r\n ...(options?.requestHeaders ?? {}),\r\n },\r\n });\r\n\r\n return res.data;\r\n }\r\n\r\n /**\r\n * Tests whether the user has consented to the specified scopes without prompting the user for consent.\r\n * @param scopes The scopes to check consent for.The scopes should be for a single resource, and they\r\n * should not mix the .default scope with named scopes.\r\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\r\n */\r\n async hasConsentForScopes(scopes: string[]): Promise<boolean> {\r\n const { msalInstance } = this.appStateGuard();\r\n\r\n return await hasConsentForScopes(msalInstance, scopes, this.log);\r\n }\r\n\r\n /**\r\n * Tests whether the user has consented to the specified scopes, and prompts them if not. This is useful for ensuring\r\n * that the user has consented to the required scopes before calling a graph API or other resource.\r\n * @param scopes - The scopes to prewarm consent for. The scopes should be for a single resource, and they\r\n * should not mix the .default scope with named scopes.\r\n * @returns A value indicating whether consent has been acquired for the specified scopes.\r\n */\r\n async ensureConsentForScopes(scopes: string[]): Promise<boolean> {\r\n const { msalInstance } = this.appStateGuard();\r\n\r\n try {\r\n const token = await acquireMsalAccessToken(msalInstance, { scopes }, this.log);\r\n return !!token;\r\n } catch (ex) {\r\n return false;\r\n }\r\n }\r\n\r\n private appStateGuard(): AppState & { phase: 'started' } {\r\n if (this._state.phase !== 'started') {\r\n throw new Error('App not started');\r\n }\r\n return this._state;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/app.ts"],"names":["ConsoleLogger","http","buildGraphClient","teamsJs","buildMsalConfig","msal","acquireMsalAccessToken","getStandardExecSilentRequest","hasConsentForScopes"],"mappings":"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","file":"app.js","sourcesContent":["import * as msal from '@azure/msal-browser';\n\nimport * as teamsJs from '@microsoft/teams-js';\nimport * as http from '@microsoft/teams.common/http';\nimport { ILogger, ConsoleLogger } from '@microsoft/teams.common/logging';\nimport * as graph from '@microsoft/teams.graph';\n\nimport { buildGraphClient } from './graph-utils';\nimport {\n acquireMsalAccessToken,\n buildMsalConfig,\n getStandardExecSilentRequest,\n hasConsentForScopes,\n} from './msal-utils';\n\nexport type MsalOptions = {\n /**\n * Optional MSAL configuration. This parameter is used to construct an MSAL instance in order\n * to make authenticated function calls. If omitted, a default configuration is created.\n */\n readonly configuration?: msal.Configuration;\n /**\n * Options to control scope consent pre-warming. If explicitly set to false, no pre-warming is performed.\n * If no value is provided, the default scope (i.e. \".default\") is pre-warmed. If a set of scopes is\n * provided, the specified scopes are pre-warmed. The scopes should be for a single resource, and they\n * should not mix the .default scope with named scopes.\n */\n readonly prewarmScopes?: false | string[];\n};\n\nexport type AppOptions = {\n /**\n * The app base url.\n */\n readonly baseUrl?: string;\n\n /** App tenant ID */\n readonly tenantId?: string;\n\n /**\n * Logger instance to use.\n */\n readonly logger?: ILogger;\n\n /**\n * Options to control how MSAL is initialized and used.\n */\n readonly msalOptions?: MsalOptions;\n};\n\ntype AppState =\n | {\n phase: 'stopped' | 'starting';\n startedAt?: never;\n msalInstance?: never;\n context?: never;\n }\n | {\n phase: 'started';\n startedAt: Date;\n msalInstance: msal.IPublicClientApplication;\n context: teamsJs.app.Context;\n };\n\nexport type ExecOptions = (\n | { msalTokenRequest: msal.SilentRequest; permission?: never }\n | { msalTokenRequest?: never; permission: string }\n | { msalTokenRequest?: never; permission?: never }\n) & {\n requestHeaders?: Record<string, string>;\n};\n\nexport class App {\n readonly options: AppOptions;\n readonly http: http.Client;\n readonly graph: graph.Client;\n readonly clientId: string;\n protected _state: AppState = { phase: 'stopped' };\n\n /**\n * the apps logger\n */\n get log() {\n return this._log;\n }\n protected _log: ILogger;\n\n /**\n * the date/time when the app was successfully started.\n */\n get startedAt() {\n return this._state?.startedAt;\n }\n\n /** the msal instance used in this app. undefined until the app is started. */\n get msalInstance() {\n return this._state.msalInstance;\n }\n\n constructor(clientId: string, options: AppOptions = {}) {\n if (!clientId) {\n throw new Error('Invalid client ID.');\n }\n\n this.clientId = clientId;\n this.options = options;\n this._log = options?.logger || new ConsoleLogger('@teams/client');\n this.http = new http.Client({ baseUrl: options?.baseUrl });\n this.graph = buildGraphClient(() => this.appStateGuard(), this._log);\n }\n\n /**\n * Starts the library and initializes the dependent teams-js and MSAL libraries.\n * @returns A promise that will be fulfilled when the app has started, or\n * rejected if the initialization fails or times out.\n */\n async start(): Promise<void> {\n if (this._state.phase !== 'stopped') {\n this._log.debug(`app already ${this._state.phase}`);\n return;\n }\n\n this._log.debug('app starting');\n this._state = { phase: 'starting' };\n\n await teamsJs.app.initialize();\n const context = await teamsJs.app.getContext();\n\n const msalConfig =\n this.options.msalOptions?.configuration ?? buildMsalConfig(this.clientId, this._log);\n const msalInstance = await msal.createNestablePublicClientApplication(msalConfig);\n await msalInstance.initialize();\n\n this._state = { phase: 'started', msalInstance, context, startedAt: new Date() };\n\n // pre-warm consent for the specified scopes\n if (this.options.msalOptions?.prewarmScopes !== false) {\n const scopes = this.options.msalOptions?.prewarmScopes ?? ['.default'];\n this._log.debug(`prewarming consent for scopes: ${scopes.join(', ')}`);\n await this.ensureConsentForScopes(scopes);\n }\n\n this._log.debug('app started');\n }\n\n /**\n * Execute a server-side function\n * @param name The unique function name\n * @param data The data to send\n * @param options Options\n * @param options.msalTokenRequest Optional MSAL token request.\n * If omitted, a default token request is used.\n * @param options.requestHeaders Optional additional request headers.\n * @returns The function response\n */\n async exec<T = unknown>(name: string, data?: unknown, options?: ExecOptions): Promise<T> {\n const { msalInstance, context } = this.appStateGuard();\n\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n options?.msalTokenRequest ?? getStandardExecSilentRequest(this.clientId, options?.permission),\n this._log\n );\n\n const res = await this.http.post<T>(`/api/functions/${name}`, data, {\n headers: {\n authorization: `Bearer ${accessToken}`,\n 'x-teams-app-session-id': context.app.sessionId,\n 'x-teams-channel-id': context.channel?.id,\n 'x-teams-chat-id': context.chat?.id,\n 'x-teams-meeting-id': context.meeting?.id,\n 'x-teams-message-id': context.app.parentMessageId,\n 'x-teams-page-id': context.page.id,\n 'x-teams-sub-page-id': context.page.subPageId,\n 'x-teams-team-id': context.team?.internalId,\n ...(options?.requestHeaders ?? {}),\n },\n });\n\n return res.data;\n }\n\n /**\n * Tests whether the user has consented to the specified scopes without prompting the user for consent.\n * @param scopes The scopes to check consent for.The scopes should be for a single resource, and they\n * should not mix the .default scope with named scopes.\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\n */\n async hasConsentForScopes(scopes: string[]): Promise<boolean> {\n const { msalInstance } = this.appStateGuard();\n\n return await hasConsentForScopes(msalInstance, scopes, this.log);\n }\n\n /**\n * Tests whether the user has consented to the specified scopes, and prompts them if not. This is useful for ensuring\n * that the user has consented to the required scopes before calling a graph API or other resource.\n * @param scopes - The scopes to prewarm consent for. The scopes should be for a single resource, and they\n * should not mix the .default scope with named scopes.\n * @returns A value indicating whether consent has been acquired for the specified scopes.\n */\n async ensureConsentForScopes(scopes: string[]): Promise<boolean> {\n const { msalInstance } = this.appStateGuard();\n\n try {\n const token = await acquireMsalAccessToken(msalInstance, { scopes }, this.log);\n return !!token;\n } catch (ex) {\n return false;\n }\n }\n\n private appStateGuard(): AppState & { phase: 'started' } {\n if (this._state.phase !== 'started') {\n throw new Error('App not started');\n }\n return this._state;\n }\n}\n"]}
package/dist/app.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/app.ts"],"names":[],"mappings":";;;;;;;AAwEO,MAAM,GAAI,CAAA;AAAA,EACN,OAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACC,MAAA,GAAmB,EAAE,KAAA,EAAO,SAAU,EAAA;AAAA;AAAA;AAAA;AAAA,EAKhD,IAAI,GAAM,GAAA;AACR,IAAA,OAAO,IAAK,CAAA,IAAA;AAAA;AACd,EACU,IAAA;AAAA;AAAA;AAAA;AAAA,EAKV,IAAI,SAAY,GAAA;AACd,IAAA,OAAO,KAAK,MAAQ,EAAA,SAAA;AAAA;AACtB;AAAA,EAGA,IAAI,YAAe,GAAA;AACjB,IAAA,OAAO,KAAK,MAAO,CAAA,YAAA;AAAA;AACrB,EAEA,WAAY,CAAA,QAAA,EAAkB,OAAsB,GAAA,EAAI,EAAA;AACtD,IAAA,IAAI,CAAC,QAAU,EAAA;AACb,MAAM,MAAA,IAAI,MAAM,oBAAoB,CAAA;AAAA;AAGtC,IAAA,IAAA,CAAK,QAAW,GAAA,QAAA;AAChB,IAAA,IAAA,CAAK,OAAU,GAAA,OAAA;AACf,IAAA,IAAA,CAAK,IAAO,GAAA,OAAA,EAAS,MAAU,IAAA,IAAI,cAAc,eAAe,CAAA;AAChE,IAAK,IAAA,CAAA,IAAA,GAAO,IAAI,IAAK,CAAA,MAAA,CAAO,EAAE,OAAS,EAAA,OAAA,EAAS,SAAS,CAAA;AACzD,IAAA,IAAA,CAAK,QAAQ,gBAAiB,CAAA,MAAM,KAAK,aAAc,EAAA,EAAG,KAAK,IAAI,CAAA;AAAA;AACrE;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAuB,GAAA;AAC3B,IAAI,IAAA,IAAA,CAAK,MAAO,CAAA,KAAA,KAAU,SAAW,EAAA;AACnC,MAAA,IAAA,CAAK,KAAK,KAAM,CAAA,CAAA,YAAA,EAAe,IAAK,CAAA,MAAA,CAAO,KAAK,CAAE,CAAA,CAAA;AAClD,MAAA;AAAA;AAGF,IAAK,IAAA,CAAA,IAAA,CAAK,MAAM,cAAc,CAAA;AAC9B,IAAK,IAAA,CAAA,MAAA,GAAS,EAAE,KAAA,EAAO,UAAW,EAAA;AAElC,IAAM,MAAA,OAAA,CAAQ,IAAI,UAAW,EAAA;AAC7B,IAAA,MAAM,OAAU,GAAA,MAAM,OAAQ,CAAA,GAAA,CAAI,UAAW,EAAA;AAE7C,IAAM,MAAA,UAAA,GACJ,KAAK,OAAQ,CAAA,WAAA,EAAa,iBAAiB,eAAgB,CAAA,IAAA,CAAK,QAAU,EAAA,IAAA,CAAK,IAAI,CAAA;AACrF,IAAA,MAAM,YAAe,GAAA,MAAM,IAAK,CAAA,qCAAA,CAAsC,UAAU,CAAA;AAChF,IAAA,MAAM,aAAa,UAAW,EAAA;AAE9B,IAAK,IAAA,CAAA,MAAA,GAAS,EAAE,KAAO,EAAA,SAAA,EAAW,cAAc,OAAS,EAAA,SAAA,kBAAe,IAAA,IAAA,EAAO,EAAA;AAG/E,IAAA,IAAI,IAAK,CAAA,OAAA,CAAQ,WAAa,EAAA,aAAA,KAAkB,KAAO,EAAA;AACrD,MAAA,MAAM,SAAS,IAAK,CAAA,OAAA,CAAQ,WAAa,EAAA,aAAA,IAAiB,CAAC,UAAU,CAAA;AACrE,MAAA,IAAA,CAAK,KAAK,KAAM,CAAA,CAAA,+BAAA,EAAkC,OAAO,IAAK,CAAA,IAAI,CAAC,CAAE,CAAA,CAAA;AACrE,MAAM,MAAA,IAAA,CAAK,uBAAuB,MAAM,CAAA;AAAA;AAG1C,IAAK,IAAA,CAAA,IAAA,CAAK,MAAM,aAAa,CAAA;AAAA;AAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,IAAA,CAAkB,IAAc,EAAA,IAAA,EAAgB,OAAmC,EAAA;AACvF,IAAA,MAAM,EAAE,YAAA,EAAc,OAAQ,EAAA,GAAI,KAAK,aAAc,EAAA;AAErD,IAAA,MAAM,cAAc,MAAM,sBAAA;AAAA,MACxB,YAAA;AAAA,MACA,SAAS,gBAAoB,IAAA,4BAAA,CAA6B,IAAK,CAAA,QAAA,EAAU,SAAS,UAAU,CAAA;AAAA,MAC5F,IAAK,CAAA;AAAA,KACP;AAEA,IAAM,MAAA,GAAA,GAAM,MAAM,IAAK,CAAA,IAAA,CAAK,KAAQ,CAAkB,eAAA,EAAA,IAAI,IAAI,IAAM,EAAA;AAAA,MAClE,OAAS,EAAA;AAAA,QACP,aAAA,EAAe,UAAU,WAAW,CAAA,CAAA;AAAA,QACpC,wBAAA,EAA0B,QAAQ,GAAI,CAAA,SAAA;AAAA,QACtC,oBAAA,EAAsB,QAAQ,OAAS,EAAA,EAAA;AAAA,QACvC,iBAAA,EAAmB,QAAQ,IAAM,EAAA,EAAA;AAAA,QACjC,oBAAA,EAAsB,QAAQ,OAAS,EAAA,EAAA;AAAA,QACvC,oBAAA,EAAsB,QAAQ,GAAI,CAAA,eAAA;AAAA,QAClC,iBAAA,EAAmB,QAAQ,IAAK,CAAA,EAAA;AAAA,QAChC,qBAAA,EAAuB,QAAQ,IAAK,CAAA,SAAA;AAAA,QACpC,iBAAA,EAAmB,QAAQ,IAAM,EAAA,UAAA;AAAA,QACjC,GAAI,OAAS,EAAA,cAAA,IAAkB;AAAC;AAClC,KACD,CAAA;AAED,IAAA,OAAO,GAAI,CAAA,IAAA;AAAA;AACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,oBAAoB,MAAoC,EAAA;AAC5D,IAAA,MAAM,EAAE,YAAA,EAAiB,GAAA,IAAA,CAAK,aAAc,EAAA;AAE5C,IAAA,OAAO,MAAM,mBAAA,CAAoB,YAAc,EAAA,MAAA,EAAQ,KAAK,GAAG,CAAA;AAAA;AACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,uBAAuB,MAAoC,EAAA;AAC/D,IAAA,MAAM,EAAE,YAAA,EAAiB,GAAA,IAAA,CAAK,aAAc,EAAA;AAE5C,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAQ,MAAM,sBAAuB,CAAA,YAAA,EAAc,EAAE,MAAO,EAAA,EAAG,KAAK,GAAG,CAAA;AAC7E,MAAA,OAAO,CAAC,CAAC,KAAA;AAAA,aACF,EAAI,EAAA;AACX,MAAO,OAAA,KAAA;AAAA;AACT;AACF,EAEQ,aAAiD,GAAA;AACvD,IAAI,IAAA,IAAA,CAAK,MAAO,CAAA,KAAA,KAAU,SAAW,EAAA;AACnC,MAAM,MAAA,IAAI,MAAM,iBAAiB,CAAA;AAAA;AAEnC,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AAEhB","file":"app.mjs","sourcesContent":["import * as msal from '@azure/msal-browser';\r\n\r\nimport * as teamsJs from '@microsoft/teams-js';\r\nimport * as http from '@microsoft/teams.common/http';\r\nimport { ILogger, ConsoleLogger } from '@microsoft/teams.common/logging';\r\nimport * as graph from '@microsoft/teams.graph';\r\n\r\nimport { buildGraphClient } from './graph-utils';\r\nimport {\r\n acquireMsalAccessToken,\r\n buildMsalConfig,\r\n getStandardExecSilentRequest,\r\n hasConsentForScopes,\r\n} from './msal-utils';\r\n\r\nexport type MsalOptions = {\r\n /**\r\n * Optional MSAL configuration. This parameter is used to construct an MSAL instance in order\r\n * to make authenticated function calls. If omitted, a default configuration is created.\r\n */\r\n readonly configuration?: msal.Configuration;\r\n /**\r\n * Options to control scope consent pre-warming. If explicitly set to false, no pre-warming is performed.\r\n * If no value is provided, the default scope (i.e. \".default\") is pre-warmed. If a set of scopes is\r\n * provided, the specified scopes are pre-warmed. The scopes should be for a single resource, and they\r\n * should not mix the .default scope with named scopes.\r\n */\r\n readonly prewarmScopes?: false | string[];\r\n};\r\n\r\nexport type AppOptions = {\r\n /**\r\n * The app base url.\r\n */\r\n readonly baseUrl?: string;\r\n\r\n /** App tenant ID */\r\n readonly tenantId?: string;\r\n\r\n /**\r\n * Logger instance to use.\r\n */\r\n readonly logger?: ILogger;\r\n\r\n /**\r\n * Options to control how MSAL is initialized and used.\r\n */\r\n readonly msalOptions?: MsalOptions;\r\n};\r\n\r\ntype AppState =\r\n | {\r\n phase: 'stopped' | 'starting';\r\n startedAt?: never;\r\n msalInstance?: never;\r\n context?: never;\r\n }\r\n | {\r\n phase: 'started';\r\n startedAt: Date;\r\n msalInstance: msal.IPublicClientApplication;\r\n context: teamsJs.app.Context;\r\n };\r\n\r\nexport type ExecOptions = (\r\n | { msalTokenRequest: msal.SilentRequest; permission?: never }\r\n | { msalTokenRequest?: never; permission: string }\r\n | { msalTokenRequest?: never; permission?: never }\r\n) & {\r\n requestHeaders?: Record<string, string>;\r\n};\r\n\r\nexport class App {\r\n readonly options: AppOptions;\r\n readonly http: http.Client;\r\n readonly graph: graph.Client;\r\n readonly clientId: string;\r\n protected _state: AppState = { phase: 'stopped' };\r\n\r\n /**\r\n * the apps logger\r\n */\r\n get log() {\r\n return this._log;\r\n }\r\n protected _log: ILogger;\r\n\r\n /**\r\n * the date/time when the app was successfully started.\r\n */\r\n get startedAt() {\r\n return this._state?.startedAt;\r\n }\r\n\r\n /** the msal instance used in this app. undefined until the app is started. */\r\n get msalInstance() {\r\n return this._state.msalInstance;\r\n }\r\n\r\n constructor(clientId: string, options: AppOptions = {}) {\r\n if (!clientId) {\r\n throw new Error('Invalid client ID.');\r\n }\r\n\r\n this.clientId = clientId;\r\n this.options = options;\r\n this._log = options?.logger || new ConsoleLogger('@teams/client');\r\n this.http = new http.Client({ baseUrl: options?.baseUrl });\r\n this.graph = buildGraphClient(() => this.appStateGuard(), this._log);\r\n }\r\n\r\n /**\r\n * Starts the library and initializes the dependent teams-js and MSAL libraries.\r\n * @returns A promise that will be fulfilled when the app has started, or\r\n * rejected if the initialization fails or times out.\r\n */\r\n async start(): Promise<void> {\r\n if (this._state.phase !== 'stopped') {\r\n this._log.debug(`app already ${this._state.phase}`);\r\n return;\r\n }\r\n\r\n this._log.debug('app starting');\r\n this._state = { phase: 'starting' };\r\n\r\n await teamsJs.app.initialize();\r\n const context = await teamsJs.app.getContext();\r\n\r\n const msalConfig =\r\n this.options.msalOptions?.configuration ?? buildMsalConfig(this.clientId, this._log);\r\n const msalInstance = await msal.createNestablePublicClientApplication(msalConfig);\r\n await msalInstance.initialize();\r\n\r\n this._state = { phase: 'started', msalInstance, context, startedAt: new Date() };\r\n\r\n // pre-warm consent for the specified scopes\r\n if (this.options.msalOptions?.prewarmScopes !== false) {\r\n const scopes = this.options.msalOptions?.prewarmScopes ?? ['.default'];\r\n this._log.debug(`prewarming consent for scopes: ${scopes.join(', ')}`);\r\n await this.ensureConsentForScopes(scopes);\r\n }\r\n\r\n this._log.debug('app started');\r\n }\r\n\r\n /**\r\n * Execute a server-side function\r\n * @param name The unique function name\r\n * @param data The data to send\r\n * @param options Options\r\n * @param options.msalTokenRequest Optional MSAL token request.\r\n * If omitted, a default token request is used.\r\n * @param options.requestHeaders Optional additional request headers.\r\n * @returns The function response\r\n */\r\n async exec<T = unknown>(name: string, data?: unknown, options?: ExecOptions): Promise<T> {\r\n const { msalInstance, context } = this.appStateGuard();\r\n\r\n const accessToken = await acquireMsalAccessToken(\r\n msalInstance,\r\n options?.msalTokenRequest ?? getStandardExecSilentRequest(this.clientId, options?.permission),\r\n this._log\r\n );\r\n\r\n const res = await this.http.post<T>(`/api/functions/${name}`, data, {\r\n headers: {\r\n authorization: `Bearer ${accessToken}`,\r\n 'x-teams-app-session-id': context.app.sessionId,\r\n 'x-teams-channel-id': context.channel?.id,\r\n 'x-teams-chat-id': context.chat?.id,\r\n 'x-teams-meeting-id': context.meeting?.id,\r\n 'x-teams-message-id': context.app.parentMessageId,\r\n 'x-teams-page-id': context.page.id,\r\n 'x-teams-sub-page-id': context.page.subPageId,\r\n 'x-teams-team-id': context.team?.internalId,\r\n ...(options?.requestHeaders ?? {}),\r\n },\r\n });\r\n\r\n return res.data;\r\n }\r\n\r\n /**\r\n * Tests whether the user has consented to the specified scopes without prompting the user for consent.\r\n * @param scopes The scopes to check consent for.The scopes should be for a single resource, and they\r\n * should not mix the .default scope with named scopes.\r\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\r\n */\r\n async hasConsentForScopes(scopes: string[]): Promise<boolean> {\r\n const { msalInstance } = this.appStateGuard();\r\n\r\n return await hasConsentForScopes(msalInstance, scopes, this.log);\r\n }\r\n\r\n /**\r\n * Tests whether the user has consented to the specified scopes, and prompts them if not. This is useful for ensuring\r\n * that the user has consented to the required scopes before calling a graph API or other resource.\r\n * @param scopes - The scopes to prewarm consent for. The scopes should be for a single resource, and they\r\n * should not mix the .default scope with named scopes.\r\n * @returns A value indicating whether consent has been acquired for the specified scopes.\r\n */\r\n async ensureConsentForScopes(scopes: string[]): Promise<boolean> {\r\n const { msalInstance } = this.appStateGuard();\r\n\r\n try {\r\n const token = await acquireMsalAccessToken(msalInstance, { scopes }, this.log);\r\n return !!token;\r\n } catch (ex) {\r\n return false;\r\n }\r\n }\r\n\r\n private appStateGuard(): AppState & { phase: 'started' } {\r\n if (this._state.phase !== 'started') {\r\n throw new Error('App not started');\r\n }\r\n return this._state;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/app.ts"],"names":[],"mappings":"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","file":"app.mjs","sourcesContent":["import * as msal from '@azure/msal-browser';\n\nimport * as teamsJs from '@microsoft/teams-js';\nimport * as http from '@microsoft/teams.common/http';\nimport { ILogger, ConsoleLogger } from '@microsoft/teams.common/logging';\nimport * as graph from '@microsoft/teams.graph';\n\nimport { buildGraphClient } from './graph-utils';\nimport {\n acquireMsalAccessToken,\n buildMsalConfig,\n getStandardExecSilentRequest,\n hasConsentForScopes,\n} from './msal-utils';\n\nexport type MsalOptions = {\n /**\n * Optional MSAL configuration. This parameter is used to construct an MSAL instance in order\n * to make authenticated function calls. If omitted, a default configuration is created.\n */\n readonly configuration?: msal.Configuration;\n /**\n * Options to control scope consent pre-warming. If explicitly set to false, no pre-warming is performed.\n * If no value is provided, the default scope (i.e. \".default\") is pre-warmed. If a set of scopes is\n * provided, the specified scopes are pre-warmed. The scopes should be for a single resource, and they\n * should not mix the .default scope with named scopes.\n */\n readonly prewarmScopes?: false | string[];\n};\n\nexport type AppOptions = {\n /**\n * The app base url.\n */\n readonly baseUrl?: string;\n\n /** App tenant ID */\n readonly tenantId?: string;\n\n /**\n * Logger instance to use.\n */\n readonly logger?: ILogger;\n\n /**\n * Options to control how MSAL is initialized and used.\n */\n readonly msalOptions?: MsalOptions;\n};\n\ntype AppState =\n | {\n phase: 'stopped' | 'starting';\n startedAt?: never;\n msalInstance?: never;\n context?: never;\n }\n | {\n phase: 'started';\n startedAt: Date;\n msalInstance: msal.IPublicClientApplication;\n context: teamsJs.app.Context;\n };\n\nexport type ExecOptions = (\n | { msalTokenRequest: msal.SilentRequest; permission?: never }\n | { msalTokenRequest?: never; permission: string }\n | { msalTokenRequest?: never; permission?: never }\n) & {\n requestHeaders?: Record<string, string>;\n};\n\nexport class App {\n readonly options: AppOptions;\n readonly http: http.Client;\n readonly graph: graph.Client;\n readonly clientId: string;\n protected _state: AppState = { phase: 'stopped' };\n\n /**\n * the apps logger\n */\n get log() {\n return this._log;\n }\n protected _log: ILogger;\n\n /**\n * the date/time when the app was successfully started.\n */\n get startedAt() {\n return this._state?.startedAt;\n }\n\n /** the msal instance used in this app. undefined until the app is started. */\n get msalInstance() {\n return this._state.msalInstance;\n }\n\n constructor(clientId: string, options: AppOptions = {}) {\n if (!clientId) {\n throw new Error('Invalid client ID.');\n }\n\n this.clientId = clientId;\n this.options = options;\n this._log = options?.logger || new ConsoleLogger('@teams/client');\n this.http = new http.Client({ baseUrl: options?.baseUrl });\n this.graph = buildGraphClient(() => this.appStateGuard(), this._log);\n }\n\n /**\n * Starts the library and initializes the dependent teams-js and MSAL libraries.\n * @returns A promise that will be fulfilled when the app has started, or\n * rejected if the initialization fails or times out.\n */\n async start(): Promise<void> {\n if (this._state.phase !== 'stopped') {\n this._log.debug(`app already ${this._state.phase}`);\n return;\n }\n\n this._log.debug('app starting');\n this._state = { phase: 'starting' };\n\n await teamsJs.app.initialize();\n const context = await teamsJs.app.getContext();\n\n const msalConfig =\n this.options.msalOptions?.configuration ?? buildMsalConfig(this.clientId, this._log);\n const msalInstance = await msal.createNestablePublicClientApplication(msalConfig);\n await msalInstance.initialize();\n\n this._state = { phase: 'started', msalInstance, context, startedAt: new Date() };\n\n // pre-warm consent for the specified scopes\n if (this.options.msalOptions?.prewarmScopes !== false) {\n const scopes = this.options.msalOptions?.prewarmScopes ?? ['.default'];\n this._log.debug(`prewarming consent for scopes: ${scopes.join(', ')}`);\n await this.ensureConsentForScopes(scopes);\n }\n\n this._log.debug('app started');\n }\n\n /**\n * Execute a server-side function\n * @param name The unique function name\n * @param data The data to send\n * @param options Options\n * @param options.msalTokenRequest Optional MSAL token request.\n * If omitted, a default token request is used.\n * @param options.requestHeaders Optional additional request headers.\n * @returns The function response\n */\n async exec<T = unknown>(name: string, data?: unknown, options?: ExecOptions): Promise<T> {\n const { msalInstance, context } = this.appStateGuard();\n\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n options?.msalTokenRequest ?? getStandardExecSilentRequest(this.clientId, options?.permission),\n this._log\n );\n\n const res = await this.http.post<T>(`/api/functions/${name}`, data, {\n headers: {\n authorization: `Bearer ${accessToken}`,\n 'x-teams-app-session-id': context.app.sessionId,\n 'x-teams-channel-id': context.channel?.id,\n 'x-teams-chat-id': context.chat?.id,\n 'x-teams-meeting-id': context.meeting?.id,\n 'x-teams-message-id': context.app.parentMessageId,\n 'x-teams-page-id': context.page.id,\n 'x-teams-sub-page-id': context.page.subPageId,\n 'x-teams-team-id': context.team?.internalId,\n ...(options?.requestHeaders ?? {}),\n },\n });\n\n return res.data;\n }\n\n /**\n * Tests whether the user has consented to the specified scopes without prompting the user for consent.\n * @param scopes The scopes to check consent for.The scopes should be for a single resource, and they\n * should not mix the .default scope with named scopes.\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\n */\n async hasConsentForScopes(scopes: string[]): Promise<boolean> {\n const { msalInstance } = this.appStateGuard();\n\n return await hasConsentForScopes(msalInstance, scopes, this.log);\n }\n\n /**\n * Tests whether the user has consented to the specified scopes, and prompts them if not. This is useful for ensuring\n * that the user has consented to the required scopes before calling a graph API or other resource.\n * @param scopes - The scopes to prewarm consent for. The scopes should be for a single resource, and they\n * should not mix the .default scope with named scopes.\n * @returns A value indicating whether consent has been acquired for the specified scopes.\n */\n async ensureConsentForScopes(scopes: string[]): Promise<boolean> {\n const { msalInstance } = this.appStateGuard();\n\n try {\n const token = await acquireMsalAccessToken(msalInstance, { scopes }, this.log);\n return !!token;\n } catch (ex) {\n return false;\n }\n }\n\n private appStateGuard(): AppState & { phase: 'started' } {\n if (this._state.phase !== 'started') {\n throw new Error('App not started');\n }\n return this._state;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/msal-utils.ts"],"names":["msal"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAUO,MAAM,4BAA+B,GAAA,CAC1C,cACA,EAAA,UAAA,GAAa,gBACW,MAAA;AAAA,EACxB,QAAQ,CAAC,CAAA,MAAA,EAAS,cAAc,CAAA,CAAA,EAAI,UAAU,CAAE,CAAA;AAClD,CAAA;AASa,MAAA,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAwC,KAAA;AACxF,EAAO,OAAA;AAAA,IACL,IAAM,EAAA;AAAA,MACJ,QAAA;AAAA,MACA,SAAW,EAAA,EAAA;AAAA,MACX,WAAa,EAAA,GAAA;AAAA,MACb,qBAAuB,EAAA;AAAA,KACzB;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,aAAe,EAAA;AAAA,QACb,iBAAmB,EAAA,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAY,KAAA;AAClC,UAAA,QAAQ,KAAO;AAAA,YACb,KAAKA,gBAAK,QAAS,CAAA,KAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAS,CAAA,IAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ;AACF;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAyB,GAAA,OACpC,YACA,EAAA,OAAA,EACA,MACoB,KAAA;AACpB,EAAI,IAAA;AACF,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AAGX,IAAM,MAAA,oBAAA,GAAuB,cAAcA,eAAK,CAAA,4BAAA;AAChD,IAAA,IAAI,CAAC,oBAAsB,EAAA;AACzB,MAAO,MAAA,CAAA,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAM,MAAA,EAAA;AAAA;AACR;AAGF,EAAI,IAAA;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AACX,IAAO,MAAA,CAAA,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAM,MAAA,EAAA;AAAA;AAEV;AAWO,MAAM,mBAAsB,GAAA,OACjC,YACA,EAAA,MAAA,EACA,MACqB,KAAA;AACrB,EAAI,IAAA;AACF,IAAA,MAAM,aAAa,kBAAmB,CAAA;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAO,OAAA,IAAA;AAAA,WACA,EAAI,EAAA;AAGX,IAAM,MAAA,uBAAA,GAA0B,cAAcA,eAAK,CAAA,4BAAA;AACnD,IAAM,MAAA,QAAA,GAAW,0BAA0B,OAAU,GAAA,OAAA;AACrD,IAAO,MAAA,CAAA,GAAA,CAAI,QAAU,EAAA,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAO,OAAA,KAAA;AAAA;AAEX","file":"msal-utils.js","sourcesContent":["import * as msal from '@azure/msal-browser';\r\n\r\nimport { ILogger } from '@microsoft/teams.common/logging';\r\n\r\n/**\r\n * Gets a silent request used to acquire an Entra access token for invoking remote functions on behalf of a user.\r\n * @param remoteClientId The client ID of the remote application.\r\n * @param permission The permission to request. Defaults to 'access_as_user'.\r\n * @returns\r\n */\r\nexport const getStandardExecSilentRequest = (\r\n remoteClientId: string,\r\n permission = 'access_as_user'\r\n): msal.SilentRequest => ({\r\n scopes: [`api://${remoteClientId}/${permission}`],\r\n});\r\n\r\n/**\r\n * Builds a default MSAL configuration for the specified client ID.\r\n * @param clientId The application client ID.\r\n * @param logger The logger instance to use for logging MSAL events.\r\n * @returns A default MSAL configuration object suitable for creating a\r\n * @see{IPublicClientApplication} instance for a multi-tenant application.\r\n */\r\nexport const buildMsalConfig = (clientId: string, logger: ILogger): msal.Configuration => {\r\n return {\r\n auth: {\r\n clientId,\r\n authority: '',\r\n redirectUri: '/',\r\n postLogoutRedirectUri: '/',\r\n },\r\n system: {\r\n loggerOptions: {\r\n piiLoggingEnabled: false,\r\n loggerCallback: (level, message) => {\r\n switch (level) {\r\n case msal.LogLevel.Error:\r\n logger.error(message);\r\n return;\r\n case msal.LogLevel.Info:\r\n logger.info(message);\r\n return;\r\n case msal.LogLevel.Verbose:\r\n logger.debug(message);\r\n return;\r\n case msal.LogLevel.Warning:\r\n logger.warn(message);\r\n return;\r\n default:\r\n return;\r\n }\r\n },\r\n },\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Acquires an access token using MSAL. It first attempts to acquire the token silently,\r\n * and if that fails with an InteractionRequiredAuthError, it falls back to acquiring the\r\n * token via a popup.\r\n * @param msalInstance The MSAL instance to use for acquiring the token.\r\n * @param request The token request object.\r\n * @param logger The logger instance to use for logging errors.\r\n * @returns A promise that resolves to the acquired access token.\r\n */\r\nexport const acquireMsalAccessToken = async (\r\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent' | 'acquireTokenPopup'>,\r\n request: msal.SilentRequest,\r\n logger: ILogger\r\n): Promise<string> => {\r\n try {\r\n const response = await msalInstance.acquireTokenSilent(request);\r\n return response.accessToken;\r\n } catch (ex) {\r\n // InteractionRequiredAuthError indicates that the user may not have consented to the requested\r\n // scope yet -- for this, we can fall back on acquireTokenPopup instead.\r\n const tryAcquireTokenPopup = ex instanceof msal.InteractionRequiredAuthError;\r\n if (!tryAcquireTokenPopup) {\r\n logger.error('acquireTokenSilent failed', ex);\r\n throw ex;\r\n }\r\n }\r\n\r\n try {\r\n logger.debug('acquireTokenSilent failed; trying acquireTokenPopup');\r\n const response = await msalInstance.acquireTokenPopup(request);\r\n return response.accessToken;\r\n } catch (ex) {\r\n logger.error('acquireTokenPopup failed', ex);\r\n throw ex;\r\n }\r\n};\r\n\r\n/**\r\n * Tests whether the user has consented to the specified scopes by attempting to acquire a token silently.\r\n * If the token acquisition is successful, it indicates that the user has consented to the scopes.\r\n * If it fails, it indicates that the user has not consented to the scopes.\r\n * @param msalInstance The MSAL instance to use.\r\n * @param scopes The scopes to check consent for. The scopes should not mix resources, or mix default scope with non-default scopes.\r\n * @param logger The logger instance to use.\r\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\r\n */\r\nexport const hasConsentForScopes = async (\r\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent'>,\r\n scopes: string[],\r\n logger: ILogger\r\n): Promise<boolean> => {\r\n try {\r\n await msalInstance.acquireTokenSilent({\r\n scopes,\r\n });\r\n\r\n return true;\r\n } catch (ex) {\r\n // InteractionRequiredAuthError indicates that the user has not consented to the requested scope yet.\r\n // This is not an error, but may be interesting when trouble shooting.\r\n const acquireTokenPopupNeeded = ex instanceof msal.InteractionRequiredAuthError;\r\n const logLevel = acquireTokenPopupNeeded ? 'debug' : 'error';\r\n logger.log(logLevel, 'hasConsentForScopes failed', ex);\r\n return false;\r\n }\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/msal-utils.ts"],"names":["msal"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAUO,MAAM,4BAA+B,GAAA,CAC1C,cACA,EAAA,UAAA,GAAa,gBACW,MAAA;AAAA,EACxB,QAAQ,CAAC,CAAA,MAAA,EAAS,cAAc,CAAA,CAAA,EAAI,UAAU,CAAE,CAAA;AAClD,CAAA;AASa,MAAA,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAwC,KAAA;AACxF,EAAO,OAAA;AAAA,IACL,IAAM,EAAA;AAAA,MACJ,QAAA;AAAA,MACA,SAAW,EAAA,EAAA;AAAA,MACX,WAAa,EAAA,GAAA;AAAA,MACb,qBAAuB,EAAA;AAAA,KACzB;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,aAAe,EAAA;AAAA,QACb,iBAAmB,EAAA,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAY,KAAA;AAClC,UAAA,QAAQ,KAAO;AAAA,YACb,KAAKA,gBAAK,QAAS,CAAA,KAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAS,CAAA,IAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ;AACF;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAyB,GAAA,OACpC,YACA,EAAA,OAAA,EACA,MACoB,KAAA;AACpB,EAAI,IAAA;AACF,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AAGX,IAAM,MAAA,oBAAA,GAAuB,cAAcA,eAAK,CAAA,4BAAA;AAChD,IAAA,IAAI,CAAC,oBAAsB,EAAA;AACzB,MAAO,MAAA,CAAA,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAM,MAAA,EAAA;AAAA;AACR;AAGF,EAAI,IAAA;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AACX,IAAO,MAAA,CAAA,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAM,MAAA,EAAA;AAAA;AAEV;AAWO,MAAM,mBAAsB,GAAA,OACjC,YACA,EAAA,MAAA,EACA,MACqB,KAAA;AACrB,EAAI,IAAA;AACF,IAAA,MAAM,aAAa,kBAAmB,CAAA;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAO,OAAA,IAAA;AAAA,WACA,EAAI,EAAA;AAGX,IAAM,MAAA,uBAAA,GAA0B,cAAcA,eAAK,CAAA,4BAAA;AACnD,IAAM,MAAA,QAAA,GAAW,0BAA0B,OAAU,GAAA,OAAA;AACrD,IAAO,MAAA,CAAA,GAAA,CAAI,QAAU,EAAA,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAO,OAAA,KAAA;AAAA;AAEX","file":"msal-utils.js","sourcesContent":["import * as msal from '@azure/msal-browser';\n\nimport { ILogger } from '@microsoft/teams.common/logging';\n\n/**\n * Gets a silent request used to acquire an Entra access token for invoking remote functions on behalf of a user.\n * @param remoteClientId The client ID of the remote application.\n * @param permission The permission to request. Defaults to 'access_as_user'.\n * @returns\n */\nexport const getStandardExecSilentRequest = (\n remoteClientId: string,\n permission = 'access_as_user'\n): msal.SilentRequest => ({\n scopes: [`api://${remoteClientId}/${permission}`],\n});\n\n/**\n * Builds a default MSAL configuration for the specified client ID.\n * @param clientId The application client ID.\n * @param logger The logger instance to use for logging MSAL events.\n * @returns A default MSAL configuration object suitable for creating a\n * @see{IPublicClientApplication} instance for a multi-tenant application.\n */\nexport const buildMsalConfig = (clientId: string, logger: ILogger): msal.Configuration => {\n return {\n auth: {\n clientId,\n authority: '',\n redirectUri: '/',\n postLogoutRedirectUri: '/',\n },\n system: {\n loggerOptions: {\n piiLoggingEnabled: false,\n loggerCallback: (level, message) => {\n switch (level) {\n case msal.LogLevel.Error:\n logger.error(message);\n return;\n case msal.LogLevel.Info:\n logger.info(message);\n return;\n case msal.LogLevel.Verbose:\n logger.debug(message);\n return;\n case msal.LogLevel.Warning:\n logger.warn(message);\n return;\n default:\n return;\n }\n },\n },\n },\n };\n};\n\n/**\n * Acquires an access token using MSAL. It first attempts to acquire the token silently,\n * and if that fails with an InteractionRequiredAuthError, it falls back to acquiring the\n * token via a popup.\n * @param msalInstance The MSAL instance to use for acquiring the token.\n * @param request The token request object.\n * @param logger The logger instance to use for logging errors.\n * @returns A promise that resolves to the acquired access token.\n */\nexport const acquireMsalAccessToken = async (\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent' | 'acquireTokenPopup'>,\n request: msal.SilentRequest,\n logger: ILogger\n): Promise<string> => {\n try {\n const response = await msalInstance.acquireTokenSilent(request);\n return response.accessToken;\n } catch (ex) {\n // InteractionRequiredAuthError indicates that the user may not have consented to the requested\n // scope yet -- for this, we can fall back on acquireTokenPopup instead.\n const tryAcquireTokenPopup = ex instanceof msal.InteractionRequiredAuthError;\n if (!tryAcquireTokenPopup) {\n logger.error('acquireTokenSilent failed', ex);\n throw ex;\n }\n }\n\n try {\n logger.debug('acquireTokenSilent failed; trying acquireTokenPopup');\n const response = await msalInstance.acquireTokenPopup(request);\n return response.accessToken;\n } catch (ex) {\n logger.error('acquireTokenPopup failed', ex);\n throw ex;\n }\n};\n\n/**\n * Tests whether the user has consented to the specified scopes by attempting to acquire a token silently.\n * If the token acquisition is successful, it indicates that the user has consented to the scopes.\n * If it fails, it indicates that the user has not consented to the scopes.\n * @param msalInstance The MSAL instance to use.\n * @param scopes The scopes to check consent for. The scopes should not mix resources, or mix default scope with non-default scopes.\n * @param logger The logger instance to use.\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\n */\nexport const hasConsentForScopes = async (\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent'>,\n scopes: string[],\n logger: ILogger\n): Promise<boolean> => {\n try {\n await msalInstance.acquireTokenSilent({\n scopes,\n });\n\n return true;\n } catch (ex) {\n // InteractionRequiredAuthError indicates that the user has not consented to the requested scope yet.\n // This is not an error, but may be interesting when trouble shooting.\n const acquireTokenPopupNeeded = ex instanceof msal.InteractionRequiredAuthError;\n const logLevel = acquireTokenPopupNeeded ? 'debug' : 'error';\n logger.log(logLevel, 'hasConsentForScopes failed', ex);\n return false;\n }\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/msal-utils.ts"],"names":[],"mappings":";;AAUO,MAAM,4BAA+B,GAAA,CAC1C,cACA,EAAA,UAAA,GAAa,gBACW,MAAA;AAAA,EACxB,QAAQ,CAAC,CAAA,MAAA,EAAS,cAAc,CAAA,CAAA,EAAI,UAAU,CAAE,CAAA;AAClD,CAAA;AASa,MAAA,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAwC,KAAA;AACxF,EAAO,OAAA;AAAA,IACL,IAAM,EAAA;AAAA,MACJ,QAAA;AAAA,MACA,SAAW,EAAA,EAAA;AAAA,MACX,WAAa,EAAA,GAAA;AAAA,MACb,qBAAuB,EAAA;AAAA,KACzB;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,aAAe,EAAA;AAAA,QACb,iBAAmB,EAAA,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAY,KAAA;AAClC,UAAA,QAAQ,KAAO;AAAA,YACb,KAAK,KAAK,QAAS,CAAA,KAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,KAAK,QAAS,CAAA,IAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAK,KAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,KAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ;AACF;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAyB,GAAA,OACpC,YACA,EAAA,OAAA,EACA,MACoB,KAAA;AACpB,EAAI,IAAA;AACF,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AAGX,IAAM,MAAA,oBAAA,GAAuB,cAAc,IAAK,CAAA,4BAAA;AAChD,IAAA,IAAI,CAAC,oBAAsB,EAAA;AACzB,MAAO,MAAA,CAAA,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAM,MAAA,EAAA;AAAA;AACR;AAGF,EAAI,IAAA;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AACX,IAAO,MAAA,CAAA,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAM,MAAA,EAAA;AAAA;AAEV;AAWO,MAAM,mBAAsB,GAAA,OACjC,YACA,EAAA,MAAA,EACA,MACqB,KAAA;AACrB,EAAI,IAAA;AACF,IAAA,MAAM,aAAa,kBAAmB,CAAA;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAO,OAAA,IAAA;AAAA,WACA,EAAI,EAAA;AAGX,IAAM,MAAA,uBAAA,GAA0B,cAAc,IAAK,CAAA,4BAAA;AACnD,IAAM,MAAA,QAAA,GAAW,0BAA0B,OAAU,GAAA,OAAA;AACrD,IAAO,MAAA,CAAA,GAAA,CAAI,QAAU,EAAA,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAO,OAAA,KAAA;AAAA;AAEX","file":"msal-utils.mjs","sourcesContent":["import * as msal from '@azure/msal-browser';\r\n\r\nimport { ILogger } from '@microsoft/teams.common/logging';\r\n\r\n/**\r\n * Gets a silent request used to acquire an Entra access token for invoking remote functions on behalf of a user.\r\n * @param remoteClientId The client ID of the remote application.\r\n * @param permission The permission to request. Defaults to 'access_as_user'.\r\n * @returns\r\n */\r\nexport const getStandardExecSilentRequest = (\r\n remoteClientId: string,\r\n permission = 'access_as_user'\r\n): msal.SilentRequest => ({\r\n scopes: [`api://${remoteClientId}/${permission}`],\r\n});\r\n\r\n/**\r\n * Builds a default MSAL configuration for the specified client ID.\r\n * @param clientId The application client ID.\r\n * @param logger The logger instance to use for logging MSAL events.\r\n * @returns A default MSAL configuration object suitable for creating a\r\n * @see{IPublicClientApplication} instance for a multi-tenant application.\r\n */\r\nexport const buildMsalConfig = (clientId: string, logger: ILogger): msal.Configuration => {\r\n return {\r\n auth: {\r\n clientId,\r\n authority: '',\r\n redirectUri: '/',\r\n postLogoutRedirectUri: '/',\r\n },\r\n system: {\r\n loggerOptions: {\r\n piiLoggingEnabled: false,\r\n loggerCallback: (level, message) => {\r\n switch (level) {\r\n case msal.LogLevel.Error:\r\n logger.error(message);\r\n return;\r\n case msal.LogLevel.Info:\r\n logger.info(message);\r\n return;\r\n case msal.LogLevel.Verbose:\r\n logger.debug(message);\r\n return;\r\n case msal.LogLevel.Warning:\r\n logger.warn(message);\r\n return;\r\n default:\r\n return;\r\n }\r\n },\r\n },\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Acquires an access token using MSAL. It first attempts to acquire the token silently,\r\n * and if that fails with an InteractionRequiredAuthError, it falls back to acquiring the\r\n * token via a popup.\r\n * @param msalInstance The MSAL instance to use for acquiring the token.\r\n * @param request The token request object.\r\n * @param logger The logger instance to use for logging errors.\r\n * @returns A promise that resolves to the acquired access token.\r\n */\r\nexport const acquireMsalAccessToken = async (\r\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent' | 'acquireTokenPopup'>,\r\n request: msal.SilentRequest,\r\n logger: ILogger\r\n): Promise<string> => {\r\n try {\r\n const response = await msalInstance.acquireTokenSilent(request);\r\n return response.accessToken;\r\n } catch (ex) {\r\n // InteractionRequiredAuthError indicates that the user may not have consented to the requested\r\n // scope yet -- for this, we can fall back on acquireTokenPopup instead.\r\n const tryAcquireTokenPopup = ex instanceof msal.InteractionRequiredAuthError;\r\n if (!tryAcquireTokenPopup) {\r\n logger.error('acquireTokenSilent failed', ex);\r\n throw ex;\r\n }\r\n }\r\n\r\n try {\r\n logger.debug('acquireTokenSilent failed; trying acquireTokenPopup');\r\n const response = await msalInstance.acquireTokenPopup(request);\r\n return response.accessToken;\r\n } catch (ex) {\r\n logger.error('acquireTokenPopup failed', ex);\r\n throw ex;\r\n }\r\n};\r\n\r\n/**\r\n * Tests whether the user has consented to the specified scopes by attempting to acquire a token silently.\r\n * If the token acquisition is successful, it indicates that the user has consented to the scopes.\r\n * If it fails, it indicates that the user has not consented to the scopes.\r\n * @param msalInstance The MSAL instance to use.\r\n * @param scopes The scopes to check consent for. The scopes should not mix resources, or mix default scope with non-default scopes.\r\n * @param logger The logger instance to use.\r\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\r\n */\r\nexport const hasConsentForScopes = async (\r\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent'>,\r\n scopes: string[],\r\n logger: ILogger\r\n): Promise<boolean> => {\r\n try {\r\n await msalInstance.acquireTokenSilent({\r\n scopes,\r\n });\r\n\r\n return true;\r\n } catch (ex) {\r\n // InteractionRequiredAuthError indicates that the user has not consented to the requested scope yet.\r\n // This is not an error, but may be interesting when trouble shooting.\r\n const acquireTokenPopupNeeded = ex instanceof msal.InteractionRequiredAuthError;\r\n const logLevel = acquireTokenPopupNeeded ? 'debug' : 'error';\r\n logger.log(logLevel, 'hasConsentForScopes failed', ex);\r\n return false;\r\n }\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/msal-utils.ts"],"names":[],"mappings":";;AAUO,MAAM,4BAA+B,GAAA,CAC1C,cACA,EAAA,UAAA,GAAa,gBACW,MAAA;AAAA,EACxB,QAAQ,CAAC,CAAA,MAAA,EAAS,cAAc,CAAA,CAAA,EAAI,UAAU,CAAE,CAAA;AAClD,CAAA;AASa,MAAA,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAwC,KAAA;AACxF,EAAO,OAAA;AAAA,IACL,IAAM,EAAA;AAAA,MACJ,QAAA;AAAA,MACA,SAAW,EAAA,EAAA;AAAA,MACX,WAAa,EAAA,GAAA;AAAA,MACb,qBAAuB,EAAA;AAAA,KACzB;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,aAAe,EAAA;AAAA,QACb,iBAAmB,EAAA,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAY,KAAA;AAClC,UAAA,QAAQ,KAAO;AAAA,YACb,KAAK,KAAK,QAAS,CAAA,KAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,KAAK,QAAS,CAAA,IAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAK,KAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,KAAK,QAAS,CAAA,OAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ;AACF;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAyB,GAAA,OACpC,YACA,EAAA,OAAA,EACA,MACoB,KAAA;AACpB,EAAI,IAAA;AACF,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AAGX,IAAM,MAAA,oBAAA,GAAuB,cAAc,IAAK,CAAA,4BAAA;AAChD,IAAA,IAAI,CAAC,oBAAsB,EAAA;AACzB,MAAO,MAAA,CAAA,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAM,MAAA,EAAA;AAAA;AACR;AAGF,EAAI,IAAA;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAW,GAAA,MAAM,YAAa,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAS,CAAA,WAAA;AAAA,WACT,EAAI,EAAA;AACX,IAAO,MAAA,CAAA,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAM,MAAA,EAAA;AAAA;AAEV;AAWO,MAAM,mBAAsB,GAAA,OACjC,YACA,EAAA,MAAA,EACA,MACqB,KAAA;AACrB,EAAI,IAAA;AACF,IAAA,MAAM,aAAa,kBAAmB,CAAA;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAO,OAAA,IAAA;AAAA,WACA,EAAI,EAAA;AAGX,IAAM,MAAA,uBAAA,GAA0B,cAAc,IAAK,CAAA,4BAAA;AACnD,IAAM,MAAA,QAAA,GAAW,0BAA0B,OAAU,GAAA,OAAA;AACrD,IAAO,MAAA,CAAA,GAAA,CAAI,QAAU,EAAA,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAO,OAAA,KAAA;AAAA;AAEX","file":"msal-utils.mjs","sourcesContent":["import * as msal from '@azure/msal-browser';\n\nimport { ILogger } from '@microsoft/teams.common/logging';\n\n/**\n * Gets a silent request used to acquire an Entra access token for invoking remote functions on behalf of a user.\n * @param remoteClientId The client ID of the remote application.\n * @param permission The permission to request. Defaults to 'access_as_user'.\n * @returns\n */\nexport const getStandardExecSilentRequest = (\n remoteClientId: string,\n permission = 'access_as_user'\n): msal.SilentRequest => ({\n scopes: [`api://${remoteClientId}/${permission}`],\n});\n\n/**\n * Builds a default MSAL configuration for the specified client ID.\n * @param clientId The application client ID.\n * @param logger The logger instance to use for logging MSAL events.\n * @returns A default MSAL configuration object suitable for creating a\n * @see{IPublicClientApplication} instance for a multi-tenant application.\n */\nexport const buildMsalConfig = (clientId: string, logger: ILogger): msal.Configuration => {\n return {\n auth: {\n clientId,\n authority: '',\n redirectUri: '/',\n postLogoutRedirectUri: '/',\n },\n system: {\n loggerOptions: {\n piiLoggingEnabled: false,\n loggerCallback: (level, message) => {\n switch (level) {\n case msal.LogLevel.Error:\n logger.error(message);\n return;\n case msal.LogLevel.Info:\n logger.info(message);\n return;\n case msal.LogLevel.Verbose:\n logger.debug(message);\n return;\n case msal.LogLevel.Warning:\n logger.warn(message);\n return;\n default:\n return;\n }\n },\n },\n },\n };\n};\n\n/**\n * Acquires an access token using MSAL. It first attempts to acquire the token silently,\n * and if that fails with an InteractionRequiredAuthError, it falls back to acquiring the\n * token via a popup.\n * @param msalInstance The MSAL instance to use for acquiring the token.\n * @param request The token request object.\n * @param logger The logger instance to use for logging errors.\n * @returns A promise that resolves to the acquired access token.\n */\nexport const acquireMsalAccessToken = async (\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent' | 'acquireTokenPopup'>,\n request: msal.SilentRequest,\n logger: ILogger\n): Promise<string> => {\n try {\n const response = await msalInstance.acquireTokenSilent(request);\n return response.accessToken;\n } catch (ex) {\n // InteractionRequiredAuthError indicates that the user may not have consented to the requested\n // scope yet -- for this, we can fall back on acquireTokenPopup instead.\n const tryAcquireTokenPopup = ex instanceof msal.InteractionRequiredAuthError;\n if (!tryAcquireTokenPopup) {\n logger.error('acquireTokenSilent failed', ex);\n throw ex;\n }\n }\n\n try {\n logger.debug('acquireTokenSilent failed; trying acquireTokenPopup');\n const response = await msalInstance.acquireTokenPopup(request);\n return response.accessToken;\n } catch (ex) {\n logger.error('acquireTokenPopup failed', ex);\n throw ex;\n }\n};\n\n/**\n * Tests whether the user has consented to the specified scopes by attempting to acquire a token silently.\n * If the token acquisition is successful, it indicates that the user has consented to the scopes.\n * If it fails, it indicates that the user has not consented to the scopes.\n * @param msalInstance The MSAL instance to use.\n * @param scopes The scopes to check consent for. The scopes should not mix resources, or mix default scope with non-default scopes.\n * @param logger The logger instance to use.\n * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.\n */\nexport const hasConsentForScopes = async (\n msalInstance: Pick<msal.IPublicClientApplication, 'acquireTokenSilent'>,\n scopes: string[],\n logger: ILogger\n): Promise<boolean> => {\n try {\n await msalInstance.acquireTokenSilent({\n scopes,\n });\n\n return true;\n } catch (ex) {\n // InteractionRequiredAuthError indicates that the user has not consented to the requested scope yet.\n // This is not an error, but may be interesting when trouble shooting.\n const acquireTokenPopupNeeded = ex instanceof msal.InteractionRequiredAuthError;\n const logLevel = acquireTokenPopupNeeded ? 'debug' : 'error';\n logger.log(logLevel, 'hasConsentForScopes failed', ex);\n return false;\n }\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/teams.client",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -34,8 +34,7 @@
34
34
  "lint": "npx eslint",
35
35
  "lint:fix": "npx eslint --fix",
36
36
  "build": "npx tsup",
37
- "test": "npx jest",
38
- "fmt": "npx prettier --write \"**/*.{js,ts,tsx,md,json}\""
37
+ "test": "npx jest"
39
38
  },
40
39
  "dependencies": {
41
40
  "@azure/msal-browser": "^4.9.1",