@microsoft/teams.client 2.0.10 → 2.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.d.mts CHANGED
@@ -1,7 +1,6 @@
1
- import * as msal from '@azure/msal-browser';
2
- import * as http from '@microsoft/teams.common/http';
3
- import { ILogger } from '@microsoft/teams.common/logging';
4
- import * as graph from '@microsoft/teams.graph';
1
+ import { IPublicClientApplication, Configuration, SilentRequest } from '@azure/msal-browser';
2
+ import { ILogger, Client } from '@microsoft/teams.common';
3
+ import { Client as Client$1 } from '@microsoft/teams.graph';
5
4
 
6
5
  /**
7
6
  * Options to control how MSAL is initialized and used.
@@ -12,14 +11,14 @@ type MsalOptions = ({
12
11
  * This is useful if you want to use a custom MSAL instance or if you want to share the
13
12
  * same MSAL instance across multiple apps.
14
13
  */
15
- readonly msalInstance?: msal.IPublicClientApplication;
14
+ readonly msalInstance?: IPublicClientApplication;
16
15
  readonly configuration?: never;
17
16
  } | {
18
17
  readonly msalInstance?: never;
19
18
  /**
20
19
  * MSAL configuration to use when constructing an MSAL instance used
21
20
  * to make authenticated function calls to remote endpoints. */
22
- readonly configuration?: msal.Configuration;
21
+ readonly configuration?: Configuration;
23
22
  }) & {
24
23
  /**
25
24
  * Options to control scope consent pre-warming. If explicitly set to false, no pre-warming is performed.
@@ -64,13 +63,13 @@ type AppState = {
64
63
  } | {
65
64
  phase: 'started';
66
65
  startedAt: Date;
67
- msalInstance: msal.IPublicClientApplication;
66
+ msalInstance: IPublicClientApplication;
68
67
  };
69
68
  /**
70
69
  * ExecOptions is used to specify options for the exec method.
71
70
  */
72
71
  type ExecOptions = ({
73
- readonly msalTokenRequest?: msal.SilentRequest;
72
+ readonly msalTokenRequest?: SilentRequest;
74
73
  readonly permission?: never;
75
74
  } | {
76
75
  readonly msalTokenRequest?: never;
@@ -85,8 +84,8 @@ type ExecOptions = ({
85
84
  */
86
85
  declare class App {
87
86
  readonly options: AppOptions;
88
- readonly http: http.Client;
89
- readonly graph: graph.Client;
87
+ readonly http: Client;
88
+ readonly graph: Client$1;
90
89
  readonly clientId: string;
91
90
  protected _state: AppState;
92
91
  /**
@@ -99,7 +98,7 @@ declare class App {
99
98
  */
100
99
  get startedAt(): Date | undefined;
101
100
  /** The msal instance used in this app. undefined until the app is started. */
102
- get msalInstance(): msal.IPublicClientApplication | undefined;
101
+ get msalInstance(): IPublicClientApplication | undefined;
103
102
  constructor(clientId: string, options?: AppOptions);
104
103
  /**
105
104
  * Starts the library and initializes the dependent teams-js and MSAL libraries.
package/dist/app.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import * as msal from '@azure/msal-browser';
2
- import * as http from '@microsoft/teams.common/http';
3
- import { ILogger } from '@microsoft/teams.common/logging';
4
- import * as graph from '@microsoft/teams.graph';
1
+ import { IPublicClientApplication, Configuration, SilentRequest } from '@azure/msal-browser';
2
+ import { ILogger, Client } from '@microsoft/teams.common';
3
+ import { Client as Client$1 } from '@microsoft/teams.graph';
5
4
 
6
5
  /**
7
6
  * Options to control how MSAL is initialized and used.
@@ -12,14 +11,14 @@ type MsalOptions = ({
12
11
  * This is useful if you want to use a custom MSAL instance or if you want to share the
13
12
  * same MSAL instance across multiple apps.
14
13
  */
15
- readonly msalInstance?: msal.IPublicClientApplication;
14
+ readonly msalInstance?: IPublicClientApplication;
16
15
  readonly configuration?: never;
17
16
  } | {
18
17
  readonly msalInstance?: never;
19
18
  /**
20
19
  * MSAL configuration to use when constructing an MSAL instance used
21
20
  * to make authenticated function calls to remote endpoints. */
22
- readonly configuration?: msal.Configuration;
21
+ readonly configuration?: Configuration;
23
22
  }) & {
24
23
  /**
25
24
  * Options to control scope consent pre-warming. If explicitly set to false, no pre-warming is performed.
@@ -64,13 +63,13 @@ type AppState = {
64
63
  } | {
65
64
  phase: 'started';
66
65
  startedAt: Date;
67
- msalInstance: msal.IPublicClientApplication;
66
+ msalInstance: IPublicClientApplication;
68
67
  };
69
68
  /**
70
69
  * ExecOptions is used to specify options for the exec method.
71
70
  */
72
71
  type ExecOptions = ({
73
- readonly msalTokenRequest?: msal.SilentRequest;
72
+ readonly msalTokenRequest?: SilentRequest;
74
73
  readonly permission?: never;
75
74
  } | {
76
75
  readonly msalTokenRequest?: never;
@@ -85,8 +84,8 @@ type ExecOptions = ({
85
84
  */
86
85
  declare class App {
87
86
  readonly options: AppOptions;
88
- readonly http: http.Client;
89
- readonly graph: graph.Client;
87
+ readonly http: Client;
88
+ readonly graph: Client$1;
90
89
  readonly clientId: string;
91
90
  protected _state: AppState;
92
91
  /**
@@ -99,7 +98,7 @@ declare class App {
99
98
  */
100
99
  get startedAt(): Date | undefined;
101
100
  /** The msal instance used in this app. undefined until the app is started. */
102
- get msalInstance(): msal.IPublicClientApplication | undefined;
101
+ get msalInstance(): IPublicClientApplication | undefined;
103
102
  constructor(clientId: string, options?: AppOptions);
104
103
  /**
105
104
  * Starts the library and initializes the dependent teams-js and MSAL libraries.
package/dist/app.js CHANGED
@@ -1,34 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var msal = require('@azure/msal-browser');
3
+ var msalBrowser = require('@azure/msal-browser');
4
4
  var teamsJs = require('@microsoft/teams-js');
5
- var http = require('@microsoft/teams.common/http');
6
- var logging = require('@microsoft/teams.common/logging');
5
+ var teams_common = require('@microsoft/teams.common');
7
6
  var graphUtils = require('./graph-utils');
8
7
  var msalUtils = require('./msal-utils');
9
8
 
10
- function _interopNamespace(e) {
11
- if (e && e.__esModule) return e;
12
- var n = Object.create(null);
13
- if (e) {
14
- Object.keys(e).forEach(function (k) {
15
- if (k !== 'default') {
16
- var d = Object.getOwnPropertyDescriptor(e, k);
17
- Object.defineProperty(n, k, d.get ? d : {
18
- enumerable: true,
19
- get: function () { return e[k]; }
20
- });
21
- }
22
- });
23
- }
24
- n.default = e;
25
- return Object.freeze(n);
26
- }
27
-
28
- var msal__namespace = /*#__PURE__*/_interopNamespace(msal);
29
- var teamsJs__namespace = /*#__PURE__*/_interopNamespace(teamsJs);
30
- var http__namespace = /*#__PURE__*/_interopNamespace(http);
31
-
32
9
  class App {
33
10
  options;
34
11
  http;
@@ -58,8 +35,8 @@ class App {
58
35
  }
59
36
  this.clientId = clientId;
60
37
  this.options = options;
61
- this._log = options?.logger || new logging.ConsoleLogger("@teams/client");
62
- this.http = new http__namespace.Client({
38
+ this._log = options?.logger || new teams_common.ConsoleLogger("@teams/client");
39
+ this.http = new teams_common.Client({
63
40
  baseUrl: options?.remoteApiOptions?.baseUrl
64
41
  });
65
42
  this.graph = graphUtils.buildGraphClient(() => this.appStateGuard(), this._log);
@@ -76,11 +53,11 @@ class App {
76
53
  }
77
54
  this._log.debug("app starting");
78
55
  this._state = { phase: "starting" };
79
- await teamsJs__namespace.app.initialize();
56
+ await teamsJs.app.initialize();
80
57
  let msalInstance = this.options.msalOptions?.msalInstance;
81
58
  if (!msalInstance) {
82
59
  const msalConfig = this.options.msalOptions?.configuration ?? msalUtils.buildMsalConfig(this.clientId, this._log);
83
- msalInstance = await msal__namespace.createNestablePublicClientApplication(
60
+ msalInstance = await msalBrowser.createNestablePublicClientApplication(
84
61
  msalConfig
85
62
  );
86
63
  }
@@ -104,7 +81,7 @@ class App {
104
81
  */
105
82
  async exec(name, data, options) {
106
83
  const { msalInstance } = this.appStateGuard();
107
- const context = await teamsJs__namespace.app.getContext();
84
+ const context = await teamsJs.app.getContext();
108
85
  const remoteAppResource = this.options.remoteApiOptions?.remoteAppResource ?? `api://${this.clientId}`;
109
86
  const accessToken = await msalUtils.acquireMsalAccessToken(
110
87
  msalInstance,
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":"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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\n/**\n * Options to control how MSAL is initialized and used.\n */\nexport type MsalOptions = (\n | {\n /**\n * MSAL instance to use when making authenticated function calls to remote endpoints.\n * This is useful if you want to use a custom MSAL instance or if you want to share the\n * same MSAL instance across multiple apps.\n */\n readonly msalInstance?: msal.IPublicClientApplication;\n readonly configuration?: never;\n }\n | {\n readonly msalInstance?: never;\n /**\n * MSAL configuration to use when constructing an MSAL instance used\n * to make authenticated function calls to remote endpoints. */\n readonly configuration?: msal.Configuration;\n }\n) & {\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 RemoteApiOptions = {\n /**\n * The remote API base URL. If omitted, it's assumed that the remote API is hosted in the same domain as the app.\n */\n readonly baseUrl?: string;\n\n /**\n * The default resource name when building a token request for the Entra token to include when invoking\n * a remote function. This is useful when the API is hosted in an different AAD app from\n * the caller and is typically in the format 'api://<remoteAppClientId>'.\n * When invoking @see exec with default options or a permission name,\n * this value is used to build a token request in the format of '<remoteAppResource>/<permission>'.\n * If omitted, it's assumed that the API is hosted in the same AAD app as the caller, and the\n * token request is made for 'api://<clientId>/permission'.\n */\n readonly remoteAppResource?: string;\n};\n\nexport type AppOptions = {\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 /** Options to control how remote APIs are invoked. */\n readonly remoteApiOptions?: RemoteApiOptions;\n};\n\ntype AppState =\n | {\n phase: 'stopped' | 'starting';\n startedAt?: never;\n msalInstance?: never;\n }\n | {\n phase: 'started';\n startedAt: Date;\n msalInstance: msal.IPublicClientApplication;\n };\n\n/**\n * ExecOptions is used to specify options for the exec method.\n */\nexport type ExecOptions = (\n | {\n readonly msalTokenRequest?: msal.SilentRequest;\n readonly permission?: never;\n }\n | { readonly msalTokenRequest?: never; readonly permission?: string }\n) & {\n readonly requestHeaders?: Record<string, string>;\n};\n\n/**\n * The main entry point for this library. This class streamlines Microsoft Teams app development\n * by simplifying the process of managing authentication, interacting with Microsoft Graph APIs,\n * and executing server-side functions.\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({\n baseUrl: options?.remoteApiOptions?.baseUrl,\n });\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\n let msalInstance = this.options.msalOptions?.msalInstance;\n if (!msalInstance) {\n const msalConfig =\n this.options.msalOptions?.configuration ??\n buildMsalConfig(this.clientId, this._log);\n msalInstance = await msal.createNestablePublicClientApplication(\n msalConfig\n );\n }\n\n this._state = { phase: 'started', msalInstance, 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>(\n name: string,\n data?: unknown,\n options?: ExecOptions\n ): Promise<T> {\n const { msalInstance } = this.appStateGuard();\n const context = await teamsJs.app.getContext();\n\n const remoteAppResource =\n this.options.remoteApiOptions?.remoteAppResource ??\n `api://${this.clientId}`;\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n options?.msalTokenRequest ??\n getStandardExecSilentRequest(remoteAppResource, 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 || undefined,\n 'x-teams-page-id': context.page.id || undefined,\n 'x-teams-sub-page-id': context.page.subPageId || undefined,\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(\n msalInstance,\n { scopes },\n this.log\n );\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
+ {"version":3,"sources":["../src/app.ts"],"names":["ConsoleLogger","HttpClient","buildGraphClient","app","buildMsalConfig","createNestablePublicClientApplication","acquireMsalAccessToken","getStandardExecSilentRequest","hasConsentForScopes"],"mappings":"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","file":"app.js","sourcesContent":["import {\n createNestablePublicClientApplication,\n type Configuration,\n type IPublicClientApplication,\n type SilentRequest,\n} from '@azure/msal-browser';\n\nimport { app } from '@microsoft/teams-js';\nimport { ConsoleLogger, Client as HttpClient, ILogger } from '@microsoft/teams.common';\nimport { Client as GraphClient } from '@microsoft/teams.graph';\n\nimport { buildGraphClient } from './graph-utils';\nimport {\n acquireMsalAccessToken,\n buildMsalConfig,\n getStandardExecSilentRequest,\n hasConsentForScopes,\n} from './msal-utils';\n\n/**\n * Options to control how MSAL is initialized and used.\n */\nexport type MsalOptions = (\n | {\n /**\n * MSAL instance to use when making authenticated function calls to remote endpoints.\n * This is useful if you want to use a custom MSAL instance or if you want to share the\n * same MSAL instance across multiple apps.\n */\n readonly msalInstance?: IPublicClientApplication;\n readonly configuration?: never;\n }\n | {\n readonly msalInstance?: never;\n /**\n * MSAL configuration to use when constructing an MSAL instance used\n * to make authenticated function calls to remote endpoints. */\n readonly configuration?: Configuration;\n }\n) & {\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 RemoteApiOptions = {\n /**\n * The remote API base URL. If omitted, it's assumed that the remote API is hosted in the same domain as the app.\n */\n readonly baseUrl?: string;\n\n /**\n * The default resource name when building a token request for the Entra token to include when invoking\n * a remote function. This is useful when the API is hosted in an different AAD app from\n * the caller and is typically in the format 'api://<remoteAppClientId>'.\n * When invoking @see exec with default options or a permission name,\n * this value is used to build a token request in the format of '<remoteAppResource>/<permission>'.\n * If omitted, it's assumed that the API is hosted in the same AAD app as the caller, and the\n * token request is made for 'api://<clientId>/permission'.\n */\n readonly remoteAppResource?: string;\n};\n\nexport type AppOptions = {\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 /** Options to control how remote APIs are invoked. */\n readonly remoteApiOptions?: RemoteApiOptions;\n};\n\ntype AppState =\n | {\n phase: 'stopped' | 'starting';\n startedAt?: never;\n msalInstance?: never;\n }\n | {\n phase: 'started';\n startedAt: Date;\n msalInstance: IPublicClientApplication;\n };\n\n/**\n * ExecOptions is used to specify options for the exec method.\n */\nexport type ExecOptions = (\n | {\n readonly msalTokenRequest?: SilentRequest;\n readonly permission?: never;\n }\n | { readonly msalTokenRequest?: never; readonly permission?: string }\n) & {\n readonly requestHeaders?: Record<string, string>;\n};\n\n/**\n * The main entry point for this library. This class streamlines Microsoft Teams app development\n * by simplifying the process of managing authentication, interacting with Microsoft Graph APIs,\n * and executing server-side functions.\n */\nexport class App {\n readonly options: AppOptions;\n readonly http: HttpClient;\n readonly graph: GraphClient;\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 HttpClient({\n baseUrl: options?.remoteApiOptions?.baseUrl,\n });\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 app.initialize();\n\n let msalInstance = this.options.msalOptions?.msalInstance;\n if (!msalInstance) {\n const msalConfig =\n this.options.msalOptions?.configuration ??\n buildMsalConfig(this.clientId, this._log);\n msalInstance = await createNestablePublicClientApplication(\n msalConfig\n );\n }\n\n this._state = { phase: 'started', msalInstance, 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>(\n name: string,\n data?: unknown,\n options?: ExecOptions\n ): Promise<T> {\n const { msalInstance } = this.appStateGuard();\n const context = await app.getContext();\n\n const remoteAppResource =\n this.options.remoteApiOptions?.remoteAppResource ??\n `api://${this.clientId}`;\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n options?.msalTokenRequest ??\n getStandardExecSilentRequest(remoteAppResource, 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 || undefined,\n 'x-teams-page-id': context.page.id || undefined,\n 'x-teams-sub-page-id': context.page.subPageId || undefined,\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(\n msalInstance,\n { scopes },\n this.log\n );\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 CHANGED
@@ -1,9 +1,8 @@
1
- import * as msal from '@azure/msal-browser';
2
- import * as teamsJs from '@microsoft/teams-js';
3
- import * as http from '@microsoft/teams.common/http';
4
- import { ConsoleLogger } from '@microsoft/teams.common/logging';
5
- import { buildGraphClient } from './graph-utils';
6
- import { buildMsalConfig, acquireMsalAccessToken, getStandardExecSilentRequest, hasConsentForScopes } from './msal-utils';
1
+ import { createNestablePublicClientApplication } from '@azure/msal-browser';
2
+ import { app } from '@microsoft/teams-js';
3
+ import { ConsoleLogger, Client } from '@microsoft/teams.common';
4
+ import { buildGraphClient } from './graph-utils.mjs';
5
+ import { buildMsalConfig, acquireMsalAccessToken, getStandardExecSilentRequest, hasConsentForScopes } from './msal-utils.mjs';
7
6
 
8
7
  class App {
9
8
  options;
@@ -35,7 +34,7 @@ class App {
35
34
  this.clientId = clientId;
36
35
  this.options = options;
37
36
  this._log = options?.logger || new ConsoleLogger("@teams/client");
38
- this.http = new http.Client({
37
+ this.http = new Client({
39
38
  baseUrl: options?.remoteApiOptions?.baseUrl
40
39
  });
41
40
  this.graph = buildGraphClient(() => this.appStateGuard(), this._log);
@@ -52,11 +51,11 @@ class App {
52
51
  }
53
52
  this._log.debug("app starting");
54
53
  this._state = { phase: "starting" };
55
- await teamsJs.app.initialize();
54
+ await app.initialize();
56
55
  let msalInstance = this.options.msalOptions?.msalInstance;
57
56
  if (!msalInstance) {
58
57
  const msalConfig = this.options.msalOptions?.configuration ?? buildMsalConfig(this.clientId, this._log);
59
- msalInstance = await msal.createNestablePublicClientApplication(
58
+ msalInstance = await createNestablePublicClientApplication(
60
59
  msalConfig
61
60
  );
62
61
  }
@@ -80,7 +79,7 @@ class App {
80
79
  */
81
80
  async exec(name, data, options) {
82
81
  const { msalInstance } = this.appStateGuard();
83
- const context = await teamsJs.app.getContext();
82
+ const context = await app.getContext();
84
83
  const remoteAppResource = this.options.remoteApiOptions?.remoteAppResource ?? `api://${this.clientId}`;
85
84
  const accessToken = await acquireMsalAccessToken(
86
85
  msalInstance,
package/dist/app.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/app.ts"],"names":[],"mappings":";;;;;;;AA4GO,MAAM,GAAA,CAAI;AAAA,EACN,OAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACC,MAAA,GAAmB,EAAE,KAAA,EAAO,SAAA,EAAU;AAAA;AAAA;AAAA;AAAA,EAKhD,IAAI,GAAA,GAAM;AACR,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EACd;AAAA,EACU,IAAA;AAAA;AAAA;AAAA;AAAA,EAKV,IAAI,SAAA,GAAY;AACd,IAAA,OAAO,KAAK,MAAA,EAAQ,SAAA;AAAA,EACtB;AAAA;AAAA,EAGA,IAAI,YAAA,GAAe;AACjB,IAAA,OAAO,KAAK,MAAA,CAAO,YAAA;AAAA,EACrB;AAAA,EAEA,WAAA,CAAY,QAAA,EAAkB,OAAA,GAAsB,EAAC,EAAG;AACtD,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,MAAM,oBAAoB,CAAA;AAAA,IACtC;AAEA,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,IAAA,GAAO,OAAA,EAAS,MAAA,IAAU,IAAI,cAAc,eAAe,CAAA;AAChE,IAAA,IAAA,CAAK,IAAA,GAAO,IAAI,IAAA,CAAK,MAAA,CAAO;AAAA,MAC1B,OAAA,EAAS,SAAS,gBAAA,EAAkB;AAAA,KACrC,CAAA;AACD,IAAA,IAAA,CAAK,QAAQ,gBAAA,CAAiB,MAAM,KAAK,aAAA,EAAc,EAAG,KAAK,IAAI,CAAA;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAA,GAAuB;AAC3B,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,KAAA,KAAU,SAAA,EAAW;AACnC,MAAA,IAAA,CAAK,KAAK,KAAA,CAAM,CAAA,YAAA,EAAe,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAClD,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,IAAA,CAAK,MAAM,cAAc,CAAA;AAC9B,IAAA,IAAA,CAAK,MAAA,GAAS,EAAE,KAAA,EAAO,UAAA,EAAW;AAElC,IAAA,MAAM,OAAA,CAAQ,IAAI,UAAA,EAAW;AAE7B,IAAA,IAAI,YAAA,GAAe,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAa,YAAA;AAC7C,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,MAAM,UAAA,GACJ,KAAK,OAAA,CAAQ,WAAA,EAAa,iBAC1B,eAAA,CAAgB,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA;AAC1C,MAAA,YAAA,GAAe,MAAM,IAAA,CAAK,qCAAA;AAAA,QACxB;AAAA,OACF;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,EAAE,KAAA,EAAO,SAAA,EAAW,cAAc,SAAA,kBAAW,IAAI,MAAK,EAAE;AAGtE,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAa,aAAA,KAAkB,KAAA,EAAO;AACrD,MAAA,MAAM,SAAS,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAa,aAAA,IAAiB,CAAC,UAAU,CAAA;AACrE,MAAA,IAAA,CAAK,KAAK,KAAA,CAAM,CAAA,+BAAA,EAAkC,OAAO,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACrE,MAAA,MAAM,IAAA,CAAK,uBAAuB,MAAM,CAAA;AAAA,IAC1C;AAEA,IAAA,IAAA,CAAK,IAAA,CAAK,MAAM,aAAa,CAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,IAAA,CACJ,IAAA,EACA,IAAA,EACA,OAAA,EACY;AACZ,IAAA,MAAM,EAAE,YAAA,EAAa,GAAI,IAAA,CAAK,aAAA,EAAc;AAC5C,IAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA,CAAI,UAAA,EAAW;AAE7C,IAAA,MAAM,oBACJ,IAAA,CAAK,OAAA,CAAQ,kBAAkB,iBAAA,IAC/B,CAAA,MAAA,EAAS,KAAK,QAAQ,CAAA,CAAA;AACxB,IAAA,MAAM,cAAc,MAAM,sBAAA;AAAA,MACxB,YAAA;AAAA,MACA,OAAA,EAAS,gBAAA,IACP,4BAAA,CAA6B,iBAAA,EAAmB,SAAS,UAAU,CAAA;AAAA,MACrE,IAAA,CAAK;AAAA,KACP;AAEA,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,IAAA,CAAK,KAAQ,CAAA,eAAA,EAAkB,IAAI,IAAI,IAAA,EAAM;AAAA,MAClE,OAAA,EAAS;AAAA,QACP,aAAA,EAAe,UAAU,WAAW,CAAA,CAAA;AAAA,QACpC,wBAAA,EAA0B,QAAQ,GAAA,CAAI,SAAA;AAAA,QACtC,oBAAA,EAAsB,QAAQ,OAAA,EAAS,EAAA;AAAA,QACvC,iBAAA,EAAmB,QAAQ,IAAA,EAAM,EAAA;AAAA,QACjC,oBAAA,EAAsB,QAAQ,OAAA,EAAS,EAAA;AAAA,QACvC,oBAAA,EAAsB,OAAA,CAAQ,GAAA,CAAI,eAAA,IAAmB,MAAA;AAAA,QACrD,iBAAA,EAAmB,OAAA,CAAQ,IAAA,CAAK,EAAA,IAAM,MAAA;AAAA,QACtC,qBAAA,EAAuB,OAAA,CAAQ,IAAA,CAAK,SAAA,IAAa,MAAA;AAAA,QACjD,iBAAA,EAAmB,QAAQ,IAAA,EAAM,UAAA;AAAA,QACjC,GAAI,OAAA,EAAS,cAAA,IAAkB;AAAC;AAClC,KACD,CAAA;AAED,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,oBAAoB,MAAA,EAAoC;AAC5D,IAAA,MAAM,EAAE,YAAA,EAAa,GAAI,IAAA,CAAK,aAAA,EAAc;AAE5C,IAAA,OAAO,MAAM,mBAAA,CAAoB,YAAA,EAAc,MAAA,EAAQ,KAAK,GAAG,CAAA;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,uBAAuB,MAAA,EAAoC;AAC/D,IAAA,MAAM,EAAE,YAAA,EAAa,GAAI,IAAA,CAAK,aAAA,EAAc;AAE5C,IAAA,IAAI;AACF,MAAA,MAAM,QAAQ,MAAM,sBAAA;AAAA,QAClB,YAAA;AAAA,QACA,EAAE,MAAA,EAAO;AAAA,QACT,IAAA,CAAK;AAAA,OACP;AACA,MAAA,OAAO,CAAC,CAAC,KAAA;AAAA,IACX,SAAS,EAAA,EAAI;AACX,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,aAAA,GAAiD;AACvD,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,KAAA,KAAU,SAAA,EAAW;AACnC,MAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AAAA,IACnC;AACA,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AACF","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\n/**\n * Options to control how MSAL is initialized and used.\n */\nexport type MsalOptions = (\n | {\n /**\n * MSAL instance to use when making authenticated function calls to remote endpoints.\n * This is useful if you want to use a custom MSAL instance or if you want to share the\n * same MSAL instance across multiple apps.\n */\n readonly msalInstance?: msal.IPublicClientApplication;\n readonly configuration?: never;\n }\n | {\n readonly msalInstance?: never;\n /**\n * MSAL configuration to use when constructing an MSAL instance used\n * to make authenticated function calls to remote endpoints. */\n readonly configuration?: msal.Configuration;\n }\n) & {\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 RemoteApiOptions = {\n /**\n * The remote API base URL. If omitted, it's assumed that the remote API is hosted in the same domain as the app.\n */\n readonly baseUrl?: string;\n\n /**\n * The default resource name when building a token request for the Entra token to include when invoking\n * a remote function. This is useful when the API is hosted in an different AAD app from\n * the caller and is typically in the format 'api://<remoteAppClientId>'.\n * When invoking @see exec with default options or a permission name,\n * this value is used to build a token request in the format of '<remoteAppResource>/<permission>'.\n * If omitted, it's assumed that the API is hosted in the same AAD app as the caller, and the\n * token request is made for 'api://<clientId>/permission'.\n */\n readonly remoteAppResource?: string;\n};\n\nexport type AppOptions = {\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 /** Options to control how remote APIs are invoked. */\n readonly remoteApiOptions?: RemoteApiOptions;\n};\n\ntype AppState =\n | {\n phase: 'stopped' | 'starting';\n startedAt?: never;\n msalInstance?: never;\n }\n | {\n phase: 'started';\n startedAt: Date;\n msalInstance: msal.IPublicClientApplication;\n };\n\n/**\n * ExecOptions is used to specify options for the exec method.\n */\nexport type ExecOptions = (\n | {\n readonly msalTokenRequest?: msal.SilentRequest;\n readonly permission?: never;\n }\n | { readonly msalTokenRequest?: never; readonly permission?: string }\n) & {\n readonly requestHeaders?: Record<string, string>;\n};\n\n/**\n * The main entry point for this library. This class streamlines Microsoft Teams app development\n * by simplifying the process of managing authentication, interacting with Microsoft Graph APIs,\n * and executing server-side functions.\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({\n baseUrl: options?.remoteApiOptions?.baseUrl,\n });\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\n let msalInstance = this.options.msalOptions?.msalInstance;\n if (!msalInstance) {\n const msalConfig =\n this.options.msalOptions?.configuration ??\n buildMsalConfig(this.clientId, this._log);\n msalInstance = await msal.createNestablePublicClientApplication(\n msalConfig\n );\n }\n\n this._state = { phase: 'started', msalInstance, 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>(\n name: string,\n data?: unknown,\n options?: ExecOptions\n ): Promise<T> {\n const { msalInstance } = this.appStateGuard();\n const context = await teamsJs.app.getContext();\n\n const remoteAppResource =\n this.options.remoteApiOptions?.remoteAppResource ??\n `api://${this.clientId}`;\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n options?.msalTokenRequest ??\n getStandardExecSilentRequest(remoteAppResource, 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 || undefined,\n 'x-teams-page-id': context.page.id || undefined,\n 'x-teams-sub-page-id': context.page.subPageId || undefined,\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(\n msalInstance,\n { scopes },\n this.log\n );\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
+ {"version":3,"sources":["../src/app.ts"],"names":["HttpClient"],"mappings":"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","file":"app.mjs","sourcesContent":["import {\n createNestablePublicClientApplication,\n type Configuration,\n type IPublicClientApplication,\n type SilentRequest,\n} from '@azure/msal-browser';\n\nimport { app } from '@microsoft/teams-js';\nimport { ConsoleLogger, Client as HttpClient, ILogger } from '@microsoft/teams.common';\nimport { Client as GraphClient } from '@microsoft/teams.graph';\n\nimport { buildGraphClient } from './graph-utils';\nimport {\n acquireMsalAccessToken,\n buildMsalConfig,\n getStandardExecSilentRequest,\n hasConsentForScopes,\n} from './msal-utils';\n\n/**\n * Options to control how MSAL is initialized and used.\n */\nexport type MsalOptions = (\n | {\n /**\n * MSAL instance to use when making authenticated function calls to remote endpoints.\n * This is useful if you want to use a custom MSAL instance or if you want to share the\n * same MSAL instance across multiple apps.\n */\n readonly msalInstance?: IPublicClientApplication;\n readonly configuration?: never;\n }\n | {\n readonly msalInstance?: never;\n /**\n * MSAL configuration to use when constructing an MSAL instance used\n * to make authenticated function calls to remote endpoints. */\n readonly configuration?: Configuration;\n }\n) & {\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 RemoteApiOptions = {\n /**\n * The remote API base URL. If omitted, it's assumed that the remote API is hosted in the same domain as the app.\n */\n readonly baseUrl?: string;\n\n /**\n * The default resource name when building a token request for the Entra token to include when invoking\n * a remote function. This is useful when the API is hosted in an different AAD app from\n * the caller and is typically in the format 'api://<remoteAppClientId>'.\n * When invoking @see exec with default options or a permission name,\n * this value is used to build a token request in the format of '<remoteAppResource>/<permission>'.\n * If omitted, it's assumed that the API is hosted in the same AAD app as the caller, and the\n * token request is made for 'api://<clientId>/permission'.\n */\n readonly remoteAppResource?: string;\n};\n\nexport type AppOptions = {\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 /** Options to control how remote APIs are invoked. */\n readonly remoteApiOptions?: RemoteApiOptions;\n};\n\ntype AppState =\n | {\n phase: 'stopped' | 'starting';\n startedAt?: never;\n msalInstance?: never;\n }\n | {\n phase: 'started';\n startedAt: Date;\n msalInstance: IPublicClientApplication;\n };\n\n/**\n * ExecOptions is used to specify options for the exec method.\n */\nexport type ExecOptions = (\n | {\n readonly msalTokenRequest?: SilentRequest;\n readonly permission?: never;\n }\n | { readonly msalTokenRequest?: never; readonly permission?: string }\n) & {\n readonly requestHeaders?: Record<string, string>;\n};\n\n/**\n * The main entry point for this library. This class streamlines Microsoft Teams app development\n * by simplifying the process of managing authentication, interacting with Microsoft Graph APIs,\n * and executing server-side functions.\n */\nexport class App {\n readonly options: AppOptions;\n readonly http: HttpClient;\n readonly graph: GraphClient;\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 HttpClient({\n baseUrl: options?.remoteApiOptions?.baseUrl,\n });\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 app.initialize();\n\n let msalInstance = this.options.msalOptions?.msalInstance;\n if (!msalInstance) {\n const msalConfig =\n this.options.msalOptions?.configuration ??\n buildMsalConfig(this.clientId, this._log);\n msalInstance = await createNestablePublicClientApplication(\n msalConfig\n );\n }\n\n this._state = { phase: 'started', msalInstance, 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>(\n name: string,\n data?: unknown,\n options?: ExecOptions\n ): Promise<T> {\n const { msalInstance } = this.appStateGuard();\n const context = await app.getContext();\n\n const remoteAppResource =\n this.options.remoteApiOptions?.remoteAppResource ??\n `api://${this.clientId}`;\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n options?.msalTokenRequest ??\n getStandardExecSilentRequest(remoteAppResource, 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 || undefined,\n 'x-teams-page-id': context.page.id || undefined,\n 'x-teams-sub-page-id': context.page.subPageId || undefined,\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(\n msalInstance,\n { scopes },\n this.log\n );\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,10 +1,10 @@
1
- import { ILogger } from '@microsoft/teams.common/logging';
2
- import * as graph from '@microsoft/teams.graph';
1
+ import { ILogger } from '@microsoft/teams.common';
2
+ import { Client } from '@microsoft/teams.graph';
3
3
  import { acquireMsalAccessToken } from './msal-utils.mjs';
4
4
  import '@azure/msal-browser';
5
5
 
6
6
  declare function buildGraphClient(getMsalInstance: () => {
7
7
  msalInstance: Parameters<typeof acquireMsalAccessToken>[0];
8
- }, logger: ILogger): graph.Client;
8
+ }, logger: ILogger): Client;
9
9
 
10
10
  export { buildGraphClient };
@@ -1,10 +1,10 @@
1
- import { ILogger } from '@microsoft/teams.common/logging';
2
- import * as graph from '@microsoft/teams.graph';
1
+ import { ILogger } from '@microsoft/teams.common';
2
+ import { Client } from '@microsoft/teams.graph';
3
3
  import { acquireMsalAccessToken } from './msal-utils.js';
4
4
  import '@azure/msal-browser';
5
5
 
6
6
  declare function buildGraphClient(getMsalInstance: () => {
7
7
  msalInstance: Parameters<typeof acquireMsalAccessToken>[0];
8
- }, logger: ILogger): graph.Client;
8
+ }, logger: ILogger): Client;
9
9
 
10
10
  export { buildGraphClient };
@@ -1,30 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var http = require('@microsoft/teams.common/http');
4
- var graph = require('@microsoft/teams.graph');
3
+ var teams_common = require('@microsoft/teams.common');
4
+ var teams_graph = require('@microsoft/teams.graph');
5
5
  var msalUtils = require('./msal-utils');
6
6
 
7
- function _interopNamespace(e) {
8
- if (e && e.__esModule) return e;
9
- var n = Object.create(null);
10
- if (e) {
11
- Object.keys(e).forEach(function (k) {
12
- if (k !== 'default') {
13
- var d = Object.getOwnPropertyDescriptor(e, k);
14
- Object.defineProperty(n, k, d.get ? d : {
15
- enumerable: true,
16
- get: function () { return e[k]; }
17
- });
18
- }
19
- });
20
- }
21
- n.default = e;
22
- return Object.freeze(n);
23
- }
24
-
25
- var http__namespace = /*#__PURE__*/_interopNamespace(http);
26
- var graph__namespace = /*#__PURE__*/_interopNamespace(graph);
27
-
28
7
  function buildGraphClient(getMsalInstance, logger) {
29
8
  {
30
9
  const graphRequestAccessTokenInterceptor = async (ctx) => {
@@ -37,8 +16,8 @@ function buildGraphClient(getMsalInstance, logger) {
37
16
  ctx.config.headers.set("Authorization", `Bearer ${accessToken}`);
38
17
  return ctx.config;
39
18
  };
40
- return new graph__namespace.Client(
41
- new http__namespace.Client({
19
+ return new teams_graph.Client(
20
+ new teams_common.Client({
42
21
  interceptors: [{ request: graphRequestAccessTokenInterceptor }]
43
22
  })
44
23
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/graph-utils.ts"],"names":["acquireMsalAccessToken","graph","http"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAMO,SAAS,gBAAA,CACd,iBACA,MAAA,EACc;AACd,EAAA;AACE,IAAA,MAAM,kCAAA,GAAqC,OAAO,GAAA,KAA6B;AAC7E,MAAA,MAAM,EAAE,YAAA,EAAa,GAAI,eAAA,EAAgB;AAIzC,MAAA,MAAM,cAAc,MAAMA,gCAAA;AAAA,QACxB,YAAA;AAAA,QACA,EAAE,MAAA,EAAQ,CAAC,UAAU,CAAA,EAAE;AAAA,QACvB;AAAA,OACF;AAEA,MAAA,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,WAAW,CAAA,CAAE,CAAA;AAC/D,MAAA,OAAO,GAAA,CAAI,MAAA;AAAA,IACb,CAAA;AAEA,IAAA,OAAO,IAAIC,gBAAA,CAAM,MAAA;AAAA,MACf,IAAIC,gBAAK,MAAA,CAAO;AAAA,QACd,YAAA,EAAc,CAAC,EAAE,OAAA,EAAS,oCAAoC;AAAA,OAC/D;AAAA,KACH;AAAA,EACF;AACF","file":"graph-utils.js","sourcesContent":["import * as http from '@microsoft/teams.common/http';\nimport { ILogger } from '@microsoft/teams.common/logging';\nimport * as graph from '@microsoft/teams.graph';\n\nimport { acquireMsalAccessToken } from './msal-utils';\n\nexport function buildGraphClient(\n getMsalInstance: () => { msalInstance: Parameters<typeof acquireMsalAccessToken>[0] },\n logger: ILogger\n): graph.Client {\n {\n const graphRequestAccessTokenInterceptor = async (ctx: http.RequestContext) => {\n const { msalInstance } = getMsalInstance();\n\n // The developer should already have made sure that the user has consented to the scope\n // needed for the graph API they're calling, so requesting '.default' should be sufficient.\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n { scopes: ['.default'] },\n logger\n );\n\n ctx.config.headers.set('Authorization', `Bearer ${accessToken}`);\n return ctx.config;\n };\n\n return new graph.Client(\n new http.Client({\n interceptors: [{ request: graphRequestAccessTokenInterceptor }],\n })\n );\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/graph-utils.ts"],"names":["acquireMsalAccessToken","GraphClient","HttpClient"],"mappings":";;;;;;AAKO,SAAS,gBAAA,CACd,iBACA,MAAA,EACa;AACb,EAAA;AACE,IAAA,MAAM,kCAAA,GAAqC,OAAO,GAAA,KAAwB;AACxE,MAAA,MAAM,EAAE,YAAA,EAAa,GAAI,eAAA,EAAgB;AAIzC,MAAA,MAAM,cAAc,MAAMA,gCAAA;AAAA,QACxB,YAAA;AAAA,QACA,EAAE,MAAA,EAAQ,CAAC,UAAU,CAAA,EAAE;AAAA,QACvB;AAAA,OACF;AAEA,MAAA,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,WAAW,CAAA,CAAE,CAAA;AAC/D,MAAA,OAAO,GAAA,CAAI,MAAA;AAAA,IACb,CAAA;AAEA,IAAA,OAAO,IAAIC,kBAAA;AAAA,MACT,IAAIC,mBAAA,CAAW;AAAA,QACb,YAAA,EAAc,CAAC,EAAE,OAAA,EAAS,oCAAoC;AAAA,OAC/D;AAAA,KACH;AAAA,EACF;AACF","file":"graph-utils.js","sourcesContent":["import { Client as HttpClient, ILogger, type RequestContext } from '@microsoft/teams.common';\nimport { Client as GraphClient } from '@microsoft/teams.graph';\n\nimport { acquireMsalAccessToken } from './msal-utils';\n\nexport function buildGraphClient(\n getMsalInstance: () => { msalInstance: Parameters<typeof acquireMsalAccessToken>[0] },\n logger: ILogger\n): GraphClient {\n {\n const graphRequestAccessTokenInterceptor = async (ctx: RequestContext) => {\n const { msalInstance } = getMsalInstance();\n\n // The developer should already have made sure that the user has consented to the scope\n // needed for the graph API they're calling, so requesting '.default' should be sufficient.\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n { scopes: ['.default'] },\n logger\n );\n\n ctx.config.headers.set('Authorization', `Bearer ${accessToken}`);\n return ctx.config;\n };\n\n return new GraphClient(\n new HttpClient({\n interceptors: [{ request: graphRequestAccessTokenInterceptor }],\n })\n );\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
- import * as http from '@microsoft/teams.common/http';
2
- import * as graph from '@microsoft/teams.graph';
3
- import { acquireMsalAccessToken } from './msal-utils';
1
+ import { Client as Client$1 } from '@microsoft/teams.common';
2
+ import { Client } from '@microsoft/teams.graph';
3
+ import { acquireMsalAccessToken } from './msal-utils.mjs';
4
4
 
5
5
  function buildGraphClient(getMsalInstance, logger) {
6
6
  {
@@ -14,8 +14,8 @@ function buildGraphClient(getMsalInstance, logger) {
14
14
  ctx.config.headers.set("Authorization", `Bearer ${accessToken}`);
15
15
  return ctx.config;
16
16
  };
17
- return new graph.Client(
18
- new http.Client({
17
+ return new Client(
18
+ new Client$1({
19
19
  interceptors: [{ request: graphRequestAccessTokenInterceptor }]
20
20
  })
21
21
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/graph-utils.ts"],"names":[],"mappings":";;;;AAMO,SAAS,gBAAA,CACd,iBACA,MAAA,EACc;AACd,EAAA;AACE,IAAA,MAAM,kCAAA,GAAqC,OAAO,GAAA,KAA6B;AAC7E,MAAA,MAAM,EAAE,YAAA,EAAa,GAAI,eAAA,EAAgB;AAIzC,MAAA,MAAM,cAAc,MAAM,sBAAA;AAAA,QACxB,YAAA;AAAA,QACA,EAAE,MAAA,EAAQ,CAAC,UAAU,CAAA,EAAE;AAAA,QACvB;AAAA,OACF;AAEA,MAAA,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,WAAW,CAAA,CAAE,CAAA;AAC/D,MAAA,OAAO,GAAA,CAAI,MAAA;AAAA,IACb,CAAA;AAEA,IAAA,OAAO,IAAI,KAAA,CAAM,MAAA;AAAA,MACf,IAAI,KAAK,MAAA,CAAO;AAAA,QACd,YAAA,EAAc,CAAC,EAAE,OAAA,EAAS,oCAAoC;AAAA,OAC/D;AAAA,KACH;AAAA,EACF;AACF","file":"graph-utils.mjs","sourcesContent":["import * as http from '@microsoft/teams.common/http';\nimport { ILogger } from '@microsoft/teams.common/logging';\nimport * as graph from '@microsoft/teams.graph';\n\nimport { acquireMsalAccessToken } from './msal-utils';\n\nexport function buildGraphClient(\n getMsalInstance: () => { msalInstance: Parameters<typeof acquireMsalAccessToken>[0] },\n logger: ILogger\n): graph.Client {\n {\n const graphRequestAccessTokenInterceptor = async (ctx: http.RequestContext) => {\n const { msalInstance } = getMsalInstance();\n\n // The developer should already have made sure that the user has consented to the scope\n // needed for the graph API they're calling, so requesting '.default' should be sufficient.\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n { scopes: ['.default'] },\n logger\n );\n\n ctx.config.headers.set('Authorization', `Bearer ${accessToken}`);\n return ctx.config;\n };\n\n return new graph.Client(\n new http.Client({\n interceptors: [{ request: graphRequestAccessTokenInterceptor }],\n })\n );\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/graph-utils.ts"],"names":["GraphClient","HttpClient"],"mappings":";;;;AAKO,SAAS,gBAAA,CACd,iBACA,MAAA,EACa;AACb,EAAA;AACE,IAAA,MAAM,kCAAA,GAAqC,OAAO,GAAA,KAAwB;AACxE,MAAA,MAAM,EAAE,YAAA,EAAa,GAAI,eAAA,EAAgB;AAIzC,MAAA,MAAM,cAAc,MAAM,sBAAA;AAAA,QACxB,YAAA;AAAA,QACA,EAAE,MAAA,EAAQ,CAAC,UAAU,CAAA,EAAE;AAAA,QACvB;AAAA,OACF;AAEA,MAAA,GAAA,CAAI,OAAO,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,WAAW,CAAA,CAAE,CAAA;AAC/D,MAAA,OAAO,GAAA,CAAI,MAAA;AAAA,IACb,CAAA;AAEA,IAAA,OAAO,IAAIA,MAAA;AAAA,MACT,IAAIC,QAAA,CAAW;AAAA,QACb,YAAA,EAAc,CAAC,EAAE,OAAA,EAAS,oCAAoC;AAAA,OAC/D;AAAA,KACH;AAAA,EACF;AACF","file":"graph-utils.mjs","sourcesContent":["import { Client as HttpClient, ILogger, type RequestContext } from '@microsoft/teams.common';\nimport { Client as GraphClient } from '@microsoft/teams.graph';\n\nimport { acquireMsalAccessToken } from './msal-utils';\n\nexport function buildGraphClient(\n getMsalInstance: () => { msalInstance: Parameters<typeof acquireMsalAccessToken>[0] },\n logger: ILogger\n): GraphClient {\n {\n const graphRequestAccessTokenInterceptor = async (ctx: RequestContext) => {\n const { msalInstance } = getMsalInstance();\n\n // The developer should already have made sure that the user has consented to the scope\n // needed for the graph API they're calling, so requesting '.default' should be sufficient.\n const accessToken = await acquireMsalAccessToken(\n msalInstance,\n { scopes: ['.default'] },\n logger\n );\n\n ctx.config.headers.set('Authorization', `Bearer ${accessToken}`);\n return ctx.config;\n };\n\n return new GraphClient(\n new HttpClient({\n interceptors: [{ request: graphRequestAccessTokenInterceptor }],\n })\n );\n }\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  export { App, AppOptions, ExecOptions, MsalOptions } from './app.mjs';
2
2
  import '@azure/msal-browser';
3
- import '@microsoft/teams.common/http';
4
- import '@microsoft/teams.common/logging';
3
+ import '@microsoft/teams.common';
5
4
  import '@microsoft/teams.graph';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export { App, AppOptions, ExecOptions, MsalOptions } from './app.js';
2
2
  import '@azure/msal-browser';
3
- import '@microsoft/teams.common/http';
4
- import '@microsoft/teams.common/logging';
3
+ import '@microsoft/teams.common';
5
4
  import '@microsoft/teams.graph';
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- export { App } from './app';
1
+ export { App } from './app.mjs';
2
2
  //# sourceMappingURL=index.mjs.map
3
3
  //# sourceMappingURL=index.mjs.map
@@ -1,5 +1,5 @@
1
- import * as msal from '@azure/msal-browser';
2
- import { ILogger } from '@microsoft/teams.common/logging';
1
+ import { IPublicClientApplication, SilentRequest, Configuration } from '@azure/msal-browser';
2
+ import { ILogger } from '@microsoft/teams.common';
3
3
 
4
4
  /**
5
5
  * Gets a silent request used to acquire an Entra access token for invoking remote functions on behalf of a user.
@@ -7,7 +7,7 @@ import { ILogger } from '@microsoft/teams.common/logging';
7
7
  * @param permission The permission to request. Defaults to 'access_as_user'.
8
8
  * @returns
9
9
  */
10
- declare const getStandardExecSilentRequest: (resource: string, permission?: string) => msal.SilentRequest;
10
+ declare const getStandardExecSilentRequest: (resource: string, permission?: string) => SilentRequest;
11
11
  /**
12
12
  * Builds a default MSAL configuration for the specified client ID.
13
13
  * @param clientId The application client ID.
@@ -15,7 +15,7 @@ declare const getStandardExecSilentRequest: (resource: string, permission?: stri
15
15
  * @returns A default MSAL configuration object suitable for creating a
16
16
  * @see{IPublicClientApplication} instance for a multi-tenant application.
17
17
  */
18
- declare const buildMsalConfig: (clientId: string, logger: ILogger) => msal.Configuration;
18
+ declare const buildMsalConfig: (clientId: string, logger: ILogger) => Configuration;
19
19
  /**
20
20
  * Acquires an access token using MSAL. It first attempts to acquire the token silently,
21
21
  * and if that fails with an InteractionRequiredAuthError, it falls back to acquiring the
@@ -25,7 +25,7 @@ declare const buildMsalConfig: (clientId: string, logger: ILogger) => msal.Confi
25
25
  * @param logger The logger instance to use for logging errors.
26
26
  * @returns A promise that resolves to the acquired access token.
27
27
  */
28
- declare const acquireMsalAccessToken: (msalInstance: Pick<msal.IPublicClientApplication, "acquireTokenSilent" | "acquireTokenPopup">, request: msal.SilentRequest, logger: ILogger) => Promise<string>;
28
+ declare const acquireMsalAccessToken: (msalInstance: Pick<IPublicClientApplication, "acquireTokenSilent" | "acquireTokenPopup">, request: SilentRequest, logger: ILogger) => Promise<string>;
29
29
  /**
30
30
  * Tests whether the user has consented to the specified scopes by attempting to acquire a token silently.
31
31
  * If the token acquisition is successful, it indicates that the user has consented to the scopes.
@@ -35,6 +35,6 @@ declare const acquireMsalAccessToken: (msalInstance: Pick<msal.IPublicClientAppl
35
35
  * @param logger The logger instance to use.
36
36
  * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.
37
37
  */
38
- declare const hasConsentForScopes: (msalInstance: Pick<msal.IPublicClientApplication, "acquireTokenSilent">, scopes: string[], logger: ILogger) => Promise<boolean>;
38
+ declare const hasConsentForScopes: (msalInstance: Pick<IPublicClientApplication, "acquireTokenSilent">, scopes: string[], logger: ILogger) => Promise<boolean>;
39
39
 
40
40
  export { acquireMsalAccessToken, buildMsalConfig, getStandardExecSilentRequest, hasConsentForScopes };
@@ -1,5 +1,5 @@
1
- import * as msal from '@azure/msal-browser';
2
- import { ILogger } from '@microsoft/teams.common/logging';
1
+ import { IPublicClientApplication, SilentRequest, Configuration } from '@azure/msal-browser';
2
+ import { ILogger } from '@microsoft/teams.common';
3
3
 
4
4
  /**
5
5
  * Gets a silent request used to acquire an Entra access token for invoking remote functions on behalf of a user.
@@ -7,7 +7,7 @@ import { ILogger } from '@microsoft/teams.common/logging';
7
7
  * @param permission The permission to request. Defaults to 'access_as_user'.
8
8
  * @returns
9
9
  */
10
- declare const getStandardExecSilentRequest: (resource: string, permission?: string) => msal.SilentRequest;
10
+ declare const getStandardExecSilentRequest: (resource: string, permission?: string) => SilentRequest;
11
11
  /**
12
12
  * Builds a default MSAL configuration for the specified client ID.
13
13
  * @param clientId The application client ID.
@@ -15,7 +15,7 @@ declare const getStandardExecSilentRequest: (resource: string, permission?: stri
15
15
  * @returns A default MSAL configuration object suitable for creating a
16
16
  * @see{IPublicClientApplication} instance for a multi-tenant application.
17
17
  */
18
- declare const buildMsalConfig: (clientId: string, logger: ILogger) => msal.Configuration;
18
+ declare const buildMsalConfig: (clientId: string, logger: ILogger) => Configuration;
19
19
  /**
20
20
  * Acquires an access token using MSAL. It first attempts to acquire the token silently,
21
21
  * and if that fails with an InteractionRequiredAuthError, it falls back to acquiring the
@@ -25,7 +25,7 @@ declare const buildMsalConfig: (clientId: string, logger: ILogger) => msal.Confi
25
25
  * @param logger The logger instance to use for logging errors.
26
26
  * @returns A promise that resolves to the acquired access token.
27
27
  */
28
- declare const acquireMsalAccessToken: (msalInstance: Pick<msal.IPublicClientApplication, "acquireTokenSilent" | "acquireTokenPopup">, request: msal.SilentRequest, logger: ILogger) => Promise<string>;
28
+ declare const acquireMsalAccessToken: (msalInstance: Pick<IPublicClientApplication, "acquireTokenSilent" | "acquireTokenPopup">, request: SilentRequest, logger: ILogger) => Promise<string>;
29
29
  /**
30
30
  * Tests whether the user has consented to the specified scopes by attempting to acquire a token silently.
31
31
  * If the token acquisition is successful, it indicates that the user has consented to the scopes.
@@ -35,6 +35,6 @@ declare const acquireMsalAccessToken: (msalInstance: Pick<msal.IPublicClientAppl
35
35
  * @param logger The logger instance to use.
36
36
  * @returns A promise that resolves to a boolean indicating whether the user has consented to the scopes.
37
37
  */
38
- declare const hasConsentForScopes: (msalInstance: Pick<msal.IPublicClientApplication, "acquireTokenSilent">, scopes: string[], logger: ILogger) => Promise<boolean>;
38
+ declare const hasConsentForScopes: (msalInstance: Pick<IPublicClientApplication, "acquireTokenSilent">, scopes: string[], logger: ILogger) => Promise<boolean>;
39
39
 
40
40
  export { acquireMsalAccessToken, buildMsalConfig, getStandardExecSilentRequest, hasConsentForScopes };
@@ -1,26 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var msal = require('@azure/msal-browser');
4
-
5
- function _interopNamespace(e) {
6
- if (e && e.__esModule) return e;
7
- var n = Object.create(null);
8
- if (e) {
9
- Object.keys(e).forEach(function (k) {
10
- if (k !== 'default') {
11
- var d = Object.getOwnPropertyDescriptor(e, k);
12
- Object.defineProperty(n, k, d.get ? d : {
13
- enumerable: true,
14
- get: function () { return e[k]; }
15
- });
16
- }
17
- });
18
- }
19
- n.default = e;
20
- return Object.freeze(n);
21
- }
22
-
23
- var msal__namespace = /*#__PURE__*/_interopNamespace(msal);
3
+ var msalBrowser = require('@azure/msal-browser');
24
4
 
25
5
  const getStandardExecSilentRequest = (resource, permission = "access_as_user") => ({
26
6
  scopes: [`${resource}/${permission}`]
@@ -38,16 +18,16 @@ const buildMsalConfig = (clientId, logger) => {
38
18
  piiLoggingEnabled: false,
39
19
  loggerCallback: (level, message) => {
40
20
  switch (level) {
41
- case msal__namespace.LogLevel.Error:
21
+ case msalBrowser.LogLevel.Error:
42
22
  logger.error(message);
43
23
  return;
44
- case msal__namespace.LogLevel.Info:
24
+ case msalBrowser.LogLevel.Info:
45
25
  logger.info(message);
46
26
  return;
47
- case msal__namespace.LogLevel.Verbose:
27
+ case msalBrowser.LogLevel.Verbose:
48
28
  logger.debug(message);
49
29
  return;
50
- case msal__namespace.LogLevel.Warning:
30
+ case msalBrowser.LogLevel.Warning:
51
31
  logger.warn(message);
52
32
  return;
53
33
  default:
@@ -63,7 +43,7 @@ const acquireMsalAccessToken = async (msalInstance, request, logger) => {
63
43
  const response = await msalInstance.acquireTokenSilent(request);
64
44
  return response.accessToken;
65
45
  } catch (ex) {
66
- const tryAcquireTokenPopup = ex instanceof msal__namespace.InteractionRequiredAuthError;
46
+ const tryAcquireTokenPopup = ex instanceof msalBrowser.InteractionRequiredAuthError;
67
47
  if (!tryAcquireTokenPopup) {
68
48
  logger.error("acquireTokenSilent failed", ex);
69
49
  throw ex;
@@ -85,7 +65,7 @@ const hasConsentForScopes = async (msalInstance, scopes, logger) => {
85
65
  });
86
66
  return true;
87
67
  } catch (ex) {
88
- const acquireTokenPopupNeeded = ex instanceof msal__namespace.InteractionRequiredAuthError;
68
+ const acquireTokenPopupNeeded = ex instanceof msalBrowser.InteractionRequiredAuthError;
89
69
  const logLevel = acquireTokenPopupNeeded ? "debug" : "error";
90
70
  logger.log(logLevel, "hasConsentForScopes failed", ex);
91
71
  return false;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/msal-utils.ts"],"names":["msal"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAUO,MAAM,4BAAA,GAA+B,CAC1C,QAAA,EACA,UAAA,GAAa,gBAAA,MACW;AAAA,EACxB,QAAQ,CAAC,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,UAAU,CAAA,CAAE;AACtC,CAAA;AASO,MAAM,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAA,KAAwC;AACxF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,QAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,MACX,WAAA,EAAa,GAAA;AAAA,MACb,qBAAA,EAAuB;AAAA,KACzB;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,aAAA,EAAe;AAAA,QACb,iBAAA,EAAmB,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAA,KAAY;AAClC,UAAA,QAAQ,KAAA;AAAO,YACb,KAAKA,gBAAK,QAAA,CAAS,KAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAA,CAAS,IAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAA,CAAS,OAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,gBAAK,QAAA,CAAS,OAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ,QACF;AAAA;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAA,GAAyB,OACpC,YAAA,EACA,OAAA,EACA,MAAA,KACoB;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,oBAAA,GAAuB,cAAcA,eAAA,CAAK,4BAAA;AAChD,IAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,MAAA,MAAA,CAAO,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAA,MAAM,EAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AACX,IAAA,MAAA,CAAO,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAA,MAAM,EAAA;AAAA,EACR;AACF;AAWO,MAAM,mBAAA,GAAsB,OACjC,YAAA,EACA,MAAA,EACA,MAAA,KACqB;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,aAAa,kBAAA,CAAmB;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,uBAAA,GAA0B,cAAcA,eAAA,CAAK,4BAAA;AACnD,IAAA,MAAM,QAAA,GAAW,0BAA0B,OAAA,GAAU,OAAA;AACrD,IAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAA,OAAO,KAAA;AAAA,EACT;AACF","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 resource The resource to use, e.g 'api://<clientId>'.\n * @param permission The permission to request. Defaults to 'access_as_user'.\n * @returns\n */\nexport const getStandardExecSilentRequest = (\n resource: string,\n permission = 'access_as_user'\n): msal.SilentRequest => ({\n scopes: [`${resource}/${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
+ {"version":3,"sources":["../src/msal-utils.ts"],"names":["LogLevel","InteractionRequiredAuthError"],"mappings":";;;;AAgBO,MAAM,4BAAA,GAA+B,CAC1C,QAAA,EACA,UAAA,GAAa,gBAAA,MACM;AAAA,EACnB,QAAQ,CAAC,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,UAAU,CAAA,CAAE;AACtC,CAAA;AASO,MAAM,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAA,KAAmC;AACnF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,QAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,MACX,WAAA,EAAa,GAAA;AAAA,MACb,qBAAA,EAAuB;AAAA,KACzB;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,aAAA,EAAe;AAAA,QACb,iBAAA,EAAmB,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAA,KAAY;AAClC,UAAA,QAAQ,KAAA;AAAO,YACb,KAAKA,oBAAA,CAAS,KAAA;AACZ,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,oBAAA,CAAS,IAAA;AACZ,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAKA,oBAAA,CAAS,OAAA;AACZ,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAKA,oBAAA,CAAS,OAAA;AACZ,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ,QACF;AAAA;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAA,GAAyB,OACpC,YAAA,EACA,OAAA,EACA,MAAA,KACoB;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,uBAAuB,EAAA,YAAcC,wCAAA;AAC3C,IAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,MAAA,MAAA,CAAO,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAA,MAAM,EAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AACX,IAAA,MAAA,CAAO,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAA,MAAM,EAAA;AAAA,EACR;AACF;AAWO,MAAM,mBAAA,GAAsB,OACjC,YAAA,EACA,MAAA,EACA,MAAA,KACqB;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,aAAa,kBAAA,CAAmB;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,0BAA0B,EAAA,YAAcA,wCAAA;AAC9C,IAAA,MAAM,QAAA,GAAW,0BAA0B,OAAA,GAAU,OAAA;AACrD,IAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAA,OAAO,KAAA;AAAA,EACT;AACF","file":"msal-utils.js","sourcesContent":["import {\n type Configuration,\n type IPublicClientApplication,\n InteractionRequiredAuthError,\n LogLevel,\n type SilentRequest,\n} from '@azure/msal-browser';\n\nimport { ILogger } from '@microsoft/teams.common';\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 resource The resource to use, e.g 'api://<clientId>'.\n * @param permission The permission to request. Defaults to 'access_as_user'.\n * @returns\n */\nexport const getStandardExecSilentRequest = (\n resource: string,\n permission = 'access_as_user'\n): SilentRequest => ({\n scopes: [`${resource}/${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): 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 LogLevel.Error:\n logger.error(message);\n return;\n case LogLevel.Info:\n logger.info(message);\n return;\n case LogLevel.Verbose:\n logger.debug(message);\n return;\n case 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<IPublicClientApplication, 'acquireTokenSilent' | 'acquireTokenPopup'>,\n request: 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 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<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 InteractionRequiredAuthError;\n const logLevel = acquireTokenPopupNeeded ? 'debug' : 'error';\n logger.log(logLevel, 'hasConsentForScopes failed', ex);\n return false;\n }\n};\n"]}
@@ -1,4 +1,4 @@
1
- import * as msal from '@azure/msal-browser';
1
+ import { LogLevel, InteractionRequiredAuthError } from '@azure/msal-browser';
2
2
 
3
3
  const getStandardExecSilentRequest = (resource, permission = "access_as_user") => ({
4
4
  scopes: [`${resource}/${permission}`]
@@ -16,16 +16,16 @@ const buildMsalConfig = (clientId, logger) => {
16
16
  piiLoggingEnabled: false,
17
17
  loggerCallback: (level, message) => {
18
18
  switch (level) {
19
- case msal.LogLevel.Error:
19
+ case LogLevel.Error:
20
20
  logger.error(message);
21
21
  return;
22
- case msal.LogLevel.Info:
22
+ case LogLevel.Info:
23
23
  logger.info(message);
24
24
  return;
25
- case msal.LogLevel.Verbose:
25
+ case LogLevel.Verbose:
26
26
  logger.debug(message);
27
27
  return;
28
- case msal.LogLevel.Warning:
28
+ case LogLevel.Warning:
29
29
  logger.warn(message);
30
30
  return;
31
31
  default:
@@ -41,7 +41,7 @@ const acquireMsalAccessToken = async (msalInstance, request, logger) => {
41
41
  const response = await msalInstance.acquireTokenSilent(request);
42
42
  return response.accessToken;
43
43
  } catch (ex) {
44
- const tryAcquireTokenPopup = ex instanceof msal.InteractionRequiredAuthError;
44
+ const tryAcquireTokenPopup = ex instanceof InteractionRequiredAuthError;
45
45
  if (!tryAcquireTokenPopup) {
46
46
  logger.error("acquireTokenSilent failed", ex);
47
47
  throw ex;
@@ -63,7 +63,7 @@ const hasConsentForScopes = async (msalInstance, scopes, logger) => {
63
63
  });
64
64
  return true;
65
65
  } catch (ex) {
66
- const acquireTokenPopupNeeded = ex instanceof msal.InteractionRequiredAuthError;
66
+ const acquireTokenPopupNeeded = ex instanceof InteractionRequiredAuthError;
67
67
  const logLevel = acquireTokenPopupNeeded ? "debug" : "error";
68
68
  logger.log(logLevel, "hasConsentForScopes failed", ex);
69
69
  return false;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/msal-utils.ts"],"names":[],"mappings":";;AAUO,MAAM,4BAAA,GAA+B,CAC1C,QAAA,EACA,UAAA,GAAa,gBAAA,MACW;AAAA,EACxB,QAAQ,CAAC,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,UAAU,CAAA,CAAE;AACtC,CAAA;AASO,MAAM,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAA,KAAwC;AACxF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,QAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,MACX,WAAA,EAAa,GAAA;AAAA,MACb,qBAAA,EAAuB;AAAA,KACzB;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,aAAA,EAAe;AAAA,QACb,iBAAA,EAAmB,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAA,KAAY;AAClC,UAAA,QAAQ,KAAA;AAAO,YACb,KAAK,KAAK,QAAA,CAAS,KAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,KAAK,QAAA,CAAS,IAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAK,KAAK,QAAA,CAAS,OAAA;AACjB,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,KAAK,QAAA,CAAS,OAAA;AACjB,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ,QACF;AAAA;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAA,GAAyB,OACpC,YAAA,EACA,OAAA,EACA,MAAA,KACoB;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,oBAAA,GAAuB,cAAc,IAAA,CAAK,4BAAA;AAChD,IAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,MAAA,MAAA,CAAO,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAA,MAAM,EAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AACX,IAAA,MAAA,CAAO,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAA,MAAM,EAAA;AAAA,EACR;AACF;AAWO,MAAM,mBAAA,GAAsB,OACjC,YAAA,EACA,MAAA,EACA,MAAA,KACqB;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,aAAa,kBAAA,CAAmB;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,uBAAA,GAA0B,cAAc,IAAA,CAAK,4BAAA;AACnD,IAAA,MAAM,QAAA,GAAW,0BAA0B,OAAA,GAAU,OAAA;AACrD,IAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAA,OAAO,KAAA;AAAA,EACT;AACF","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 resource The resource to use, e.g 'api://<clientId>'.\n * @param permission The permission to request. Defaults to 'access_as_user'.\n * @returns\n */\nexport const getStandardExecSilentRequest = (\n resource: string,\n permission = 'access_as_user'\n): msal.SilentRequest => ({\n scopes: [`${resource}/${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
+ {"version":3,"sources":["../src/msal-utils.ts"],"names":[],"mappings":";;AAgBO,MAAM,4BAAA,GAA+B,CAC1C,QAAA,EACA,UAAA,GAAa,gBAAA,MACM;AAAA,EACnB,QAAQ,CAAC,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,UAAU,CAAA,CAAE;AACtC,CAAA;AASO,MAAM,eAAA,GAAkB,CAAC,QAAA,EAAkB,MAAA,KAAmC;AACnF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,QAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,MACX,WAAA,EAAa,GAAA;AAAA,MACb,qBAAA,EAAuB;AAAA,KACzB;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,aAAA,EAAe;AAAA,QACb,iBAAA,EAAmB,KAAA;AAAA,QACnB,cAAA,EAAgB,CAAC,KAAA,EAAO,OAAA,KAAY;AAClC,UAAA,QAAQ,KAAA;AAAO,YACb,KAAK,QAAA,CAAS,KAAA;AACZ,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,QAAA,CAAS,IAAA;AACZ,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF,KAAK,QAAA,CAAS,OAAA;AACZ,cAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AACpB,cAAA;AAAA,YACF,KAAK,QAAA,CAAS,OAAA;AACZ,cAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,cAAA;AAAA,YACF;AACE,cAAA;AAAA;AACJ,QACF;AAAA;AACF;AACF,GACF;AACF;AAWO,MAAM,sBAAA,GAAyB,OACpC,YAAA,EACA,OAAA,EACA,MAAA,KACoB;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,kBAAA,CAAmB,OAAO,CAAA;AAC9D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,uBAAuB,EAAA,YAAc,4BAAA;AAC3C,IAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,MAAA,MAAA,CAAO,KAAA,CAAM,6BAA6B,EAAE,CAAA;AAC5C,MAAA,MAAM,EAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,MAAM,qDAAqD,CAAA;AAClE,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,iBAAA,CAAkB,OAAO,CAAA;AAC7D,IAAA,OAAO,QAAA,CAAS,WAAA;AAAA,EAClB,SAAS,EAAA,EAAI;AACX,IAAA,MAAA,CAAO,KAAA,CAAM,4BAA4B,EAAE,CAAA;AAC3C,IAAA,MAAM,EAAA;AAAA,EACR;AACF;AAWO,MAAM,mBAAA,GAAsB,OACjC,YAAA,EACA,MAAA,EACA,MAAA,KACqB;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,aAAa,kBAAA,CAAmB;AAAA,MACpC;AAAA,KACD,CAAA;AAED,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,EAAA,EAAI;AAGX,IAAA,MAAM,0BAA0B,EAAA,YAAc,4BAAA;AAC9C,IAAA,MAAM,QAAA,GAAW,0BAA0B,OAAA,GAAU,OAAA;AACrD,IAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,4BAAA,EAA8B,EAAE,CAAA;AACrD,IAAA,OAAO,KAAA;AAAA,EACT;AACF","file":"msal-utils.mjs","sourcesContent":["import {\n type Configuration,\n type IPublicClientApplication,\n InteractionRequiredAuthError,\n LogLevel,\n type SilentRequest,\n} from '@azure/msal-browser';\n\nimport { ILogger } from '@microsoft/teams.common';\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 resource The resource to use, e.g 'api://<clientId>'.\n * @param permission The permission to request. Defaults to 'access_as_user'.\n * @returns\n */\nexport const getStandardExecSilentRequest = (\n resource: string,\n permission = 'access_as_user'\n): SilentRequest => ({\n scopes: [`${resource}/${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): 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 LogLevel.Error:\n logger.error(message);\n return;\n case LogLevel.Info:\n logger.info(message);\n return;\n case LogLevel.Verbose:\n logger.debug(message);\n return;\n case 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<IPublicClientApplication, 'acquireTokenSilent' | 'acquireTokenPopup'>,\n request: 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 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<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 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": "2.0.10",
3
+ "version": "2.0.11",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -38,15 +38,15 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@azure/msal-browser": "^4.9.1",
41
- "@microsoft/teams.api": "2.0.10",
42
- "@microsoft/teams.common": "2.0.10",
43
- "@microsoft/teams.graph": "2.0.10"
41
+ "@microsoft/teams.api": "2.0.11",
42
+ "@microsoft/teams.common": "2.0.11",
43
+ "@microsoft/teams.graph": "2.0.11"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@microsoft/teams-js": "^2.35.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@microsoft/teams.config": "2.0.10",
49
+ "@microsoft/teams.config": "2.0.11",
50
50
  "@types/jest": "^29.5.12",
51
51
  "jest": "^29.7.0",
52
52
  "rimraf": "^6.0.1",