From 38d2312f6d2e3a9dfe40a69b8e0237a3a16775e8 Mon Sep 17 00:00:00 2001 From: Gavin Barron Date: Tue, 12 Dec 2023 23:32:05 +0000 Subject: [PATCH 1/3] feat: support multiple chat comoponents sharing a subscription using different sessionIds --- .../Caching/SubscriptionCache.ts | 22 ++++------- .../src/statefulClient/GraphConfig.ts | 8 +++- .../statefulClient/GraphNotificationClient.ts | 39 ++++++++----------- .../statefulClient/StatefulGraphChatClient.ts | 4 +- .../replaceOrAppendSessionId.tests.ts | 36 +++++++++++++++++ .../replaceOrAppendSessionId.ts | 11 ++++++ .../src/statefulClient/useGraphChatClient.ts | 2 +- 7 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts create mode 100644 packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts diff --git a/packages/mgt-chat/src/statefulClient/Caching/SubscriptionCache.ts b/packages/mgt-chat/src/statefulClient/Caching/SubscriptionCache.ts index 7065f8a77..3bbd8206f 100644 --- a/packages/mgt-chat/src/statefulClient/Caching/SubscriptionCache.ts +++ b/packages/mgt-chat/src/statefulClient/Caching/SubscriptionCache.ts @@ -12,28 +12,24 @@ import { IDBPObjectStore } from 'idb'; type CachedSubscriptionData = CacheItem & { chatId: string; - sessionId: string; subscriptions: Subscription[]; lastAccessDateTime: string; }; -const buildCacheKey = (chatId: string, sessionId: string): string => `${chatId}:${sessionId}`; - export class SubscriptionsCache { private get cache(): CacheStore { const conversation: CacheSchema = schemas.conversation; return CacheService.getCache(conversation, conversation.stores.subscriptions); } - public async loadSubscriptions(chatId: string, sessionId: string): Promise { + public async loadSubscriptions(chatId: string): Promise { if (isConversationCacheEnabled()) { - const cacheKey = buildCacheKey(chatId, sessionId); let data; await this.cache.transaction(async (store: IDBPObjectStore) => { - data = (await store.get(cacheKey)) as CachedSubscriptionData | undefined; + data = (await store.get(chatId)) as CachedSubscriptionData | undefined; if (data) { data.lastAccessDateTime = new Date().toISOString(); - await store.put(data, cacheKey); + await store.put(data, chatId); } }); return data || undefined; @@ -41,12 +37,11 @@ export class SubscriptionsCache { return undefined; } - public async cacheSubscription(chatId: string, sessionId: string, subscriptionRecord: Subscription): Promise { + public async cacheSubscription(chatId: string, subscriptionRecord: Subscription): Promise { await this.cache.transaction(async (store: IDBPObjectStore) => { log('cacheSubscription', subscriptionRecord); - const cacheKey = buildCacheKey(chatId, sessionId); - let cacheEntry = (await store.get(cacheKey)) as CachedSubscriptionData | undefined; + let cacheEntry = (await store.get(chatId)) as CachedSubscriptionData | undefined; if (cacheEntry && cacheEntry.chatId === chatId) { const subIndex = cacheEntry.subscriptions.findIndex(s => s.resource === subscriptionRecord.resource); if (subIndex !== -1) { @@ -57,7 +52,6 @@ export class SubscriptionsCache { } else { cacheEntry = { chatId, - sessionId, subscriptions: [subscriptionRecord], // we're cheating a bit here to ensure that we have a defined lastAccessDateTime // but we're updating the value for all cases before storing it. @@ -66,12 +60,12 @@ export class SubscriptionsCache { } cacheEntry.lastAccessDateTime = new Date().toISOString(); - await store.put(cacheEntry, cacheKey); + await store.put(cacheEntry, chatId); }); } - public deleteCachedSubscriptions(chatId: string, sessionId: string): Promise { - return this.cache.delete(buildCacheKey(chatId, sessionId)); + public deleteCachedSubscriptions(chatId: string): Promise { + return this.cache.delete(chatId); } public loadInactiveSubscriptions(inactivityThreshold: string): Promise { diff --git a/packages/mgt-chat/src/statefulClient/GraphConfig.ts b/packages/mgt-chat/src/statefulClient/GraphConfig.ts index 5c278ff23..b96dc3633 100644 --- a/packages/mgt-chat/src/statefulClient/GraphConfig.ts +++ b/packages/mgt-chat/src/statefulClient/GraphConfig.ts @@ -6,6 +6,7 @@ */ import { GraphEndpoint } from '@microsoft/mgt-element'; +import { replaceOrAppendSessionId } from './replaceOrAppendSessionId'; export class GraphConfig { public static ackAsString = false; @@ -30,11 +31,14 @@ export class GraphConfig { return GraphConfig.useCanary ? `${GraphConfig.baseCanaryUrl}/subscriptions` : '/subscriptions'; } - public static adjustNotificationUrl(url: string): string { + public static adjustNotificationUrl(url: string, sessionId = 'default'): string { if (GraphConfig.useCanary && url) { url = url.replace('https://graph.microsoft.com/1.0', GraphConfig.baseCanaryUrl); url = url.replace('https://graph.microsoft.com/beta', GraphConfig.baseCanaryUrl); } - return url.replace(GraphConfig.webSocketsPrefix, ''); + url = url.replace(GraphConfig.webSocketsPrefix, ''); + // update or append sessionid + url = replaceOrAppendSessionId(url, sessionId); + return url; } } diff --git a/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts b/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts index e27870989..5a943cc83 100644 --- a/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts +++ b/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts @@ -84,14 +84,12 @@ export class GraphNotificationClient { /** * Removes any active timers that may exist to prevent memory leaks and perf issues. * Call this method when the component that depends an instance of this class is being removed from the DOM - * i.e */ - public async tearDown() { + public tearDown() { log('cleaning up graph notification resources'); if (this.cleanupInterval) this.timer.clearInterval(this.cleanupInterval); if (this.renewalInterval) this.timer.clearInterval(this.renewalInterval); this.timer.close(); - await this.unsubscribeFromChatNotifications(this.chatId, this.sessionId); } private readonly getToken = async () => { @@ -177,7 +175,7 @@ export class GraphNotificationClient { private readonly cacheSubscription = async (subscriptionRecord: Subscription): Promise => { log(subscriptionRecord); - await this.subscriptionCache.cacheSubscription(this.chatId, this.sessionId, subscriptionRecord); + await this.subscriptionCache.cacheSubscription(this.chatId, subscriptionRecord); // only start timer once. -1 for renewalInterval is semaphore it has stopped. if (this.renewalInterval === undefined) this.startRenewalTimer(); @@ -190,7 +188,7 @@ export class GraphNotificationClient { ).toISOString(); const subscriptionDefinition: Subscription = { changeType: changeTypes.join(','), - notificationUrl: `${GraphConfig.webSocketsPrefix}?groupId=${this.chatId}&sessionId=${this.sessionId}`, + notificationUrl: `${GraphConfig.webSocketsPrefix}?groupId=${this.chatId}`, resource: resourcePath, expirationDateTime, includeResourceData: true, @@ -227,8 +225,7 @@ export class GraphNotificationClient { private readonly renewalTimer = async () => { log(`running subscription renewal timer for chatId: ${this.chatId} sessionId: ${this.sessionId}`); - const subscriptions = - (await this.subscriptionCache.loadSubscriptions(this.chatId, this.sessionId))?.subscriptions || []; + const subscriptions = (await this.subscriptionCache.loadSubscriptions(this.chatId))?.subscriptions || []; if (subscriptions.length === 0) { log(`No subscriptions found in session state. Stop renewal timer ${this.renewalInterval}.`); clearInterval(this.renewalInterval); @@ -261,7 +258,7 @@ export class GraphNotificationClient { new Date().getTime() + appSettings.defaultSubscriptionLifetimeInMinutes * 60 * 1000 ); - const subscriptionCache = await this.subscriptionCache.loadSubscriptions(this.chatId, this.sessionId); + const subscriptionCache = await this.subscriptionCache.loadSubscriptions(this.chatId); const awaits: Promise[] = []; for (const subscription of subscriptionCache?.subscriptions || []) { if (!subscription.id) continue; @@ -286,7 +283,7 @@ export class GraphNotificationClient { withCredentials: false }; const connection = new HubConnectionBuilder() - .withUrl(GraphConfig.adjustNotificationUrl(notificationUrl), connectionOptions) + .withUrl(GraphConfig.adjustNotificationUrl(notificationUrl, this.sessionId), connectionOptions) .withAutomaticReconnect() .configureLogging(LogLevel.Information) .build(); @@ -347,7 +344,7 @@ export class GraphNotificationClient { await Promise.all(tasks); tasks = []; for (const inactive of inactiveSubs) { - tasks.push(this.subscriptionCache.deleteCachedSubscriptions(inactive.chatId, inactive.sessionId)); + tasks.push(this.subscriptionCache.deleteCachedSubscriptions(inactive.chatId)); } }; @@ -357,26 +354,22 @@ export class GraphNotificationClient { this.connection = undefined; } - private async unsubscribeFromChatNotifications(chatId: string, sessionId: string) { + private async unsubscribeFromChatNotifications(chatId: string) { await this.closeSignalRConnection(); - const cacheData = await this.subscriptionCache.loadSubscriptions(chatId, sessionId); + const cacheData = await this.subscriptionCache.loadSubscriptions(chatId); if (cacheData) { await Promise.all([ this.removeSubscriptions(cacheData.subscriptions), - this.subscriptionCache.deleteCachedSubscriptions(chatId, sessionId) + this.subscriptionCache.deleteCachedSubscriptions(chatId) ]); } } public async subscribeToChatNotifications(chatId: string, sessionId: string) { - // if we have a "previous" chat state at present, unsubscribe for the previous chatId - if (this.chatId && this.sessionId && chatId !== this.chatId) { - await this.unsubscribeFromChatNotifications(this.chatId, this.sessionId); - } this.chatId = chatId; this.sessionId = sessionId; // MGT uses a per-user cache, so no concerns of loading the cached data for another user. - const cacheData = await this.subscriptionCache.loadSubscriptions(chatId, sessionId); + const cacheData = await this.subscriptionCache.loadSubscriptions(chatId); if (cacheData) { // check subscription validity & renew if all still valid otherwise recreate const someExpired = cacheData.subscriptions.some( @@ -384,14 +377,16 @@ export class GraphNotificationClient { ); // for a given user + app + chatId + sessionId they only get one websocket and receive all notifications via that websocket. const webSocketUrl = cacheData.subscriptions.find(s => s.notificationUrl)?.notificationUrl; - if (someExpired) { - await this.removeSubscriptions(cacheData.subscriptions); - } else if (webSocketUrl) { + if (!someExpired && webSocketUrl) { + // if we have a websocket url and all the subscriptions are valid, we can reuse the websocket and return before recreating subscriptions. await this.createSignalRConnection(webSocketUrl); await this.renewChatSubscriptions(); return; + } else if (someExpired) { + // if some are expired, remove them and continue to recreate the subscription + await this.removeSubscriptions(cacheData.subscriptions); } - await this.subscriptionCache.deleteCachedSubscriptions(chatId, sessionId); + await this.subscriptionCache.deleteCachedSubscriptions(chatId); } const promises: Promise[] = []; promises.push(this.subscribeToResource(`/chats/${chatId}/messages`, ['created', 'updated', 'deleted'])); diff --git a/packages/mgt-chat/src/statefulClient/StatefulGraphChatClient.ts b/packages/mgt-chat/src/statefulClient/StatefulGraphChatClient.ts index f154ca61c..f9c313922 100644 --- a/packages/mgt-chat/src/statefulClient/StatefulGraphChatClient.ts +++ b/packages/mgt-chat/src/statefulClient/StatefulGraphChatClient.ts @@ -219,8 +219,8 @@ class StatefulGraphChatClient implements StatefulClient { /** * Provides a method to clean up any resources being used internally when a consuming component is being removed from the DOM */ - public async tearDown() { - await this._notificationClient.tearDown(); + public tearDown() { + this._notificationClient.tearDown(); } /** diff --git a/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts new file mode 100644 index 000000000..c17497ce4 --- /dev/null +++ b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts @@ -0,0 +1,36 @@ +import { replaceOrAppendSessionId } from './replaceOrAppendSessionId'; +import { expect } from '@open-wc/testing'; + +describe('replaceOrAppendSessionId tests', () => { + it('should replace existing sessionid', async () => { + const result = replaceOrAppendSessionId('https://graph.microsoft.com/1.0/me?sessionid=default', '123'); + await expect(result).to.equal('https://graph.microsoft.com/1.0/me?sessionid=123'); + }); + it('should replace existing sessionid when there are query string params after sessionid', async () => { + const result = replaceOrAppendSessionId('https://graph.microsoft.com/1.0/me?sessionid=default&foo=bar', '123'); + await expect(result).to.equal('https://graph.microsoft.com/1.0/me?sessionid=123&foo=bar'); + }); + it('should replace existing sessionid when there are query string params before sessionid', async () => { + const result = replaceOrAppendSessionId('https://graph.microsoft.com/1.0/me?foo=bar&sessionid=default', '123'); + await expect(result).to.equal('https://graph.microsoft.com/1.0/me?foo=bar&sessionid=123'); + }); + it('should append sessionid there is a query string params with sessionid as a substring', async () => { + const result = replaceOrAppendSessionId('https://graph.microsoft.com/1.0/me?foosessionid=bar', '123'); + await expect(result).to.equal('https://graph.microsoft.com/1.0/me?foosessionid=bar&sessionid=123'); + }); + it('should replace sessionid there is also a query string params with sessionid as a substring', async () => { + const result = replaceOrAppendSessionId( + 'https://graph.microsoft.com/1.0/me?foosessionid=bar&sessionid=default&bar=too', + '123' + ); + await expect(result).to.equal('https://graph.microsoft.com/1.0/me?foosessionid=bar&sessionid=123&bar=too'); + }); + it('should append sessionid with ? when no query params present', async () => { + const result = replaceOrAppendSessionId('https://graph.microsoft.com/1.0/me', '123'); + await expect(result).to.equal('https://graph.microsoft.com/1.0/me?sessionid=123'); + }); + it('should append sessionid with & when query params are present', async () => { + const result = replaceOrAppendSessionId('https://graph.microsoft.com/1.0/me?foo=bar', '123'); + await expect(result).to.equal('https://graph.microsoft.com/1.0/me?foo=bar&sessionid=123'); + }); +}); diff --git a/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts new file mode 100644 index 000000000..1cd496edc --- /dev/null +++ b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts @@ -0,0 +1,11 @@ +export const replaceOrAppendSessionId = (url: string, sessionId: string) => { + // match on any whole query parameter of sessionid and include the value + const sessionIdRegex = /([?&]{1})sessionid=[^&]*/; + if (url.match(sessionIdRegex)) { + url = url.replace(sessionIdRegex, `$1sessionid=${sessionId}`); + } else { + const paramSeparator = url.indexOf('?') > -1 ? '&' : '?'; + url = `${url}${paramSeparator}sessionid=${sessionId}`; + } + return url; +}; diff --git a/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts b/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts index 98852ebc4..f81c4fa30 100644 --- a/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts +++ b/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts @@ -62,7 +62,7 @@ export const useGraphChatClient = (chatId: string): StatefulGraphChatClient => { useEffect(() => { return () => { log('invoked clean up effect'); - void chatClient.tearDown(); + chatClient.tearDown(); }; }, [chatClient]); From ffb5ce924f4b8541aa5eb98e878c36c92d421ce6 Mon Sep 17 00:00:00 2001 From: Gavin Barron Date: Wed, 13 Dec 2023 21:16:36 +0000 Subject: [PATCH 2/3] re-work sessionId to be unique per component --- .../src/statefulClient/useGraphChatClient.ts | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts b/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts index f81c4fa30..6db2a7376 100644 --- a/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts +++ b/packages/mgt-chat/src/statefulClient/useGraphChatClient.ts @@ -10,33 +10,12 @@ import { v4 as uuid } from 'uuid'; import { StatefulGraphChatClient } from './StatefulGraphChatClient'; import { log } from '@microsoft/mgt-element'; -/** - * The key name to use for storing the sessionId in session storage - */ -const keyName = 'mgt-chat-session-id'; - -/** - * reads a string from session storage, or if there is no string for the keyName, generate a new uuid and place in storage - */ -const getOrGenerateSessionId = () => { - const value = sessionStorage.getItem(keyName); - - if (value) { - return value; - } else { - const newValue = uuid(); - sessionStorage.setItem(keyName, newValue); - return newValue; - } -}; - /** * Provides a stable sessionId for the lifetime of the browser tab. * @returns a string that is either read from session storage or generated and placed in session storage */ const useSessionId = (): string => { - // when a function is passed to useState, it is only invoked on the first render - const [sessionId] = useState(getOrGenerateSessionId); + const [sessionId] = useState(() => uuid()); return sessionId; }; From fc348ac7261569ee8651dfe0c1757a9176eb9d20 Mon Sep 17 00:00:00 2001 From: Gavin Barron Date: Wed, 13 Dec 2023 21:31:18 +0000 Subject: [PATCH 3/3] make groupId unique for a given chatId per browser instance --- .../statefulClient/GraphNotificationClient.ts | 3 ++- .../chatOperationScopes.tests.ts | 7 +++++ .../statefulClient/getOrGenerateGroupId.ts | 26 +++++++++++++++++++ .../replaceOrAppendSessionId.tests.ts | 7 +++++ .../replaceOrAppendSessionId.ts | 7 +++++ packages/mgt-chat/src/utils/Timer.ts | 7 +++++ .../src/utils/rewriteEmojiContent.tests.ts | 7 +++++ .../mgt-chat/src/utils/rewriteEmojiContent.ts | 7 +++++ packages/mgt-chat/src/utils/timerWorker.ts | 7 +++++ .../mgt-person-card/MgtPersonCardConfig.ts | 7 +++++ .../getMgtPersonCardScopes.tests.ts | 7 +++++ .../mgt-person-card/getMgtPersonCardScopes.ts | 7 +++++ .../src/components/mgt-person-card/types.ts | 7 +++++ .../mgt-theme-toggle.tests.ts | 7 +++++ .../src/registerMgtComponents.ts | 7 +++++ .../src/utils/GraphHelpers.tests.ts | 7 +++++ .../mgt-element/src/utils/equals.tests.ts | 7 +++++ .../src/utils/registerComponent.ts | 7 +++++ .../mgt-msal2-provider/src/exports.ts | 7 +++++ .../mgt-proxy-provider/src/exports.ts | 7 +++++ 20 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 packages/mgt-chat/src/statefulClient/getOrGenerateGroupId.ts diff --git a/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts b/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts index 5a943cc83..8ef50b58c 100644 --- a/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts +++ b/packages/mgt-chat/src/statefulClient/GraphNotificationClient.ts @@ -18,6 +18,7 @@ import type { import { GraphConfig } from './GraphConfig'; import { SubscriptionsCache } from './Caching/SubscriptionCache'; import { Timer } from '../utils/Timer'; +import { getOrGenerateGroupId } from './getOrGenerateGroupId'; export const appSettings = { defaultSubscriptionLifetimeInMinutes: 10, @@ -188,7 +189,7 @@ export class GraphNotificationClient { ).toISOString(); const subscriptionDefinition: Subscription = { changeType: changeTypes.join(','), - notificationUrl: `${GraphConfig.webSocketsPrefix}?groupId=${this.chatId}`, + notificationUrl: `${GraphConfig.webSocketsPrefix}?groupId=${getOrGenerateGroupId(this.chatId)}`, resource: resourcePath, expirationDateTime, includeResourceData: true, diff --git a/packages/mgt-chat/src/statefulClient/chatOperationScopes.tests.ts b/packages/mgt-chat/src/statefulClient/chatOperationScopes.tests.ts index b4b87302d..9b49e05ca 100644 --- a/packages/mgt-chat/src/statefulClient/chatOperationScopes.tests.ts +++ b/packages/mgt-chat/src/statefulClient/chatOperationScopes.tests.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { expect } from '@open-wc/testing'; import { allChatScopes } from './chatOperationScopes'; diff --git a/packages/mgt-chat/src/statefulClient/getOrGenerateGroupId.ts b/packages/mgt-chat/src/statefulClient/getOrGenerateGroupId.ts new file mode 100644 index 000000000..889773a77 --- /dev/null +++ b/packages/mgt-chat/src/statefulClient/getOrGenerateGroupId.ts @@ -0,0 +1,26 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + +import { v4 as uuid } from 'uuid'; + +const keyPrefix = 'mgt-chat-group-id'; + +/** + * reads a string from session storage, or if there is no string for the keyName, generate a new uuid and place in storage + */ +export const getOrGenerateGroupId = (chatId: string) => { + const key = `${keyPrefix}::${chatId}`; + const value = localStorage.getItem(key); + + if (value) { + return value; + } else { + const newValue = uuid(); + localStorage.setItem(key, newValue); + return newValue; + } +}; diff --git a/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts index c17497ce4..1275427c5 100644 --- a/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts +++ b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.tests.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { replaceOrAppendSessionId } from './replaceOrAppendSessionId'; import { expect } from '@open-wc/testing'; diff --git a/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts index 1cd496edc..0e8ba91d4 100644 --- a/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts +++ b/packages/mgt-chat/src/statefulClient/replaceOrAppendSessionId.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + export const replaceOrAppendSessionId = (url: string, sessionId: string) => { // match on any whole query parameter of sessionid and include the value const sessionIdRegex = /([?&]{1})sessionid=[^&]*/; diff --git a/packages/mgt-chat/src/utils/Timer.ts b/packages/mgt-chat/src/utils/Timer.ts index 66339daf8..7c812c967 100644 --- a/packages/mgt-chat/src/utils/Timer.ts +++ b/packages/mgt-chat/src/utils/Timer.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { v4 as uuid } from 'uuid'; import { TimerWork } from './timerWorker'; diff --git a/packages/mgt-chat/src/utils/rewriteEmojiContent.tests.ts b/packages/mgt-chat/src/utils/rewriteEmojiContent.tests.ts index 4f6351fe5..2edb229b3 100644 --- a/packages/mgt-chat/src/utils/rewriteEmojiContent.tests.ts +++ b/packages/mgt-chat/src/utils/rewriteEmojiContent.tests.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { expect } from '@open-wc/testing'; import { rewriteEmojiContent } from './rewriteEmojiContent'; diff --git a/packages/mgt-chat/src/utils/rewriteEmojiContent.ts b/packages/mgt-chat/src/utils/rewriteEmojiContent.ts index 114982d37..472cbad48 100644 --- a/packages/mgt-chat/src/utils/rewriteEmojiContent.ts +++ b/packages/mgt-chat/src/utils/rewriteEmojiContent.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + /** * Regex to detect and extract emoji alt text * diff --git a/packages/mgt-chat/src/utils/timerWorker.ts b/packages/mgt-chat/src/utils/timerWorker.ts index 21bce3bd6..de3ca9cb4 100644 --- a/packages/mgt-chat/src/utils/timerWorker.ts +++ b/packages/mgt-chat/src/utils/timerWorker.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + export interface TimerWork { id: string; type: 'clearInterval' | 'setInterval' | 'runCallback'; diff --git a/packages/mgt-components/src/components/mgt-person-card/MgtPersonCardConfig.ts b/packages/mgt-components/src/components/mgt-person-card/MgtPersonCardConfig.ts index ac7bf9c3b..3f357a8a8 100644 --- a/packages/mgt-components/src/components/mgt-person-card/MgtPersonCardConfig.ts +++ b/packages/mgt-components/src/components/mgt-person-card/MgtPersonCardConfig.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + interface SectionsConfig { /** * Gets or sets whether the organization section is shown diff --git a/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.tests.ts b/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.tests.ts index 0b1a5fdd3..401124c3e 100644 --- a/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.tests.ts +++ b/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.tests.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { MgtPersonCardConfig } from './MgtPersonCardConfig'; import { expect } from '@open-wc/testing'; import { getMgtPersonCardScopes } from './getMgtPersonCardScopes'; diff --git a/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.ts b/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.ts index f30bf98e2..ac6c47f7d 100644 --- a/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.ts +++ b/packages/mgt-components/src/components/mgt-person-card/getMgtPersonCardScopes.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { MgtPersonCardConfig } from './MgtPersonCardConfig'; /** diff --git a/packages/mgt-components/src/components/mgt-person-card/types.ts b/packages/mgt-components/src/components/mgt-person-card/types.ts index 2d0ae5bc1..00041d999 100644 --- a/packages/mgt-components/src/components/mgt-person-card/types.ts +++ b/packages/mgt-components/src/components/mgt-person-card/types.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + export interface IExpandable { isExpanded: boolean; } diff --git a/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts b/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts index 9f09170b7..c4b709589 100644 --- a/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts +++ b/packages/mgt-components/src/components/mgt-theme-toggle/mgt-theme-toggle.tests.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + /* eslint-disable @typescript-eslint/no-unused-expressions */ /** * ------------------------------------------------------------------------------------------- diff --git a/packages/mgt-components/src/registerMgtComponents.ts b/packages/mgt-components/src/registerMgtComponents.ts index 24d264cc4..6409336af 100644 --- a/packages/mgt-components/src/registerMgtComponents.ts +++ b/packages/mgt-components/src/registerMgtComponents.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { registerMgtAgendaComponent, registerMgtFileComponent, diff --git a/packages/mgt-element/src/utils/GraphHelpers.tests.ts b/packages/mgt-element/src/utils/GraphHelpers.tests.ts index 014229c35..5fd627bfe 100644 --- a/packages/mgt-element/src/utils/GraphHelpers.tests.ts +++ b/packages/mgt-element/src/utils/GraphHelpers.tests.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + /* eslint-disable @typescript-eslint/no-unused-expressions */ /** * ------------------------------------------------------------------------------------------- diff --git a/packages/mgt-element/src/utils/equals.tests.ts b/packages/mgt-element/src/utils/equals.tests.ts index ce991ca4b..1c8c38120 100644 --- a/packages/mgt-element/src/utils/equals.tests.ts +++ b/packages/mgt-element/src/utils/equals.tests.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + /* eslint-disable @typescript-eslint/no-unused-expressions */ /** * ------------------------------------------------------------------------------------------- diff --git a/packages/mgt-element/src/utils/registerComponent.ts b/packages/mgt-element/src/utils/registerComponent.ts index f0327a25e..dd0b2a71b 100644 --- a/packages/mgt-element/src/utils/registerComponent.ts +++ b/packages/mgt-element/src/utils/registerComponent.ts @@ -1,3 +1,10 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + import { customElementHelper } from '../components/customElementHelper'; export const buildComponentName = (tagBase: string) => `${customElementHelper.prefix}-${tagBase}`; diff --git a/packages/providers/mgt-msal2-provider/src/exports.ts b/packages/providers/mgt-msal2-provider/src/exports.ts index 9bc3a2de1..eeae91892 100644 --- a/packages/providers/mgt-msal2-provider/src/exports.ts +++ b/packages/providers/mgt-msal2-provider/src/exports.ts @@ -1,2 +1,9 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + export * from './Msal2Provider'; export * from './mgt-msal2-provider'; diff --git a/packages/providers/mgt-proxy-provider/src/exports.ts b/packages/providers/mgt-proxy-provider/src/exports.ts index e597818a4..4d872a467 100644 --- a/packages/providers/mgt-proxy-provider/src/exports.ts +++ b/packages/providers/mgt-proxy-provider/src/exports.ts @@ -1,2 +1,9 @@ +/** + * ------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. + * See License in the project root for license information. + * ------------------------------------------------------------------------------------------- + */ + export * from './mgt-proxy-provider'; export * from './ProxyProvider';