Create DirectLine Adapter (#159)
* Add CreateACSAdapter scenario markers * Add urlResolvers util & Refactor * Refactor * Update test * Add support on DirectLine version & CDN URL config properties & Update tests * Add telemetry event * Add DirectLine chat adapter optional params * Add DirectLine property on CDNPackagesInfo * Add ability to create DirectLine * Throw Error on adapter load failure * Clean up * Add ChatSDKErrors enum * Refactor & Add test * Update CHANGELOG.md * Refactor * Add chatAdapterCreators util & Refactor creationg of DirectLine * Refactor * Refactor creation of ACSAdapter * Clean up * Refactor creation of IC3Adapter * Fix lint
This commit is contained in:
Родитель
2a7572c4fc
Коммит
5f9a9ded5d
|
@ -2,6 +2,9 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Add ability to use `ChatSDK.createChatAdapter()` for `DirectLine` protocol
|
||||
- Add `CreateACSAdapter` telemetry event
|
||||
|
||||
## [1.2.0] - 2022-11-11
|
||||
### Added
|
||||
|
|
|
@ -197,6 +197,58 @@ describe('Omnichannel Chat SDK', () => {
|
|||
expect(url).toBe(libraries.getACSAdapterCDNUrl());
|
||||
});
|
||||
|
||||
it('ChatSDK should be able to pick custom webChatDirectLineVersion if set', async () => {
|
||||
const omnichannelConfig = {
|
||||
orgUrl: '',
|
||||
orgId: '',
|
||||
widgetId: ''
|
||||
};
|
||||
|
||||
const chatSDKConfig = {
|
||||
chatAdapterConfig: {
|
||||
webChatDirectLineVersion: 'version'
|
||||
}
|
||||
};
|
||||
|
||||
const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
||||
const url = chatSDK.resolveChatAdapterUrl(ChatAdapterProtocols.DirectLine);
|
||||
|
||||
expect(url).toBe(libraries.getDirectLineCDNUrl(chatSDKConfig.chatAdapterConfig.webChatDirectLineVersion));
|
||||
});
|
||||
|
||||
it('ChatSDK should be able to pick custom webChatDirectLineCDNUrl if set', async () => {
|
||||
const omnichannelConfig = {
|
||||
orgUrl: '',
|
||||
orgId: '',
|
||||
widgetId: ''
|
||||
};
|
||||
|
||||
const chatSDKConfig = {
|
||||
chatAdapterConfig: {
|
||||
webChatDirectLineVersion: 'version',
|
||||
webChatDirectLineCDNUrl: 'cdn'
|
||||
}
|
||||
};
|
||||
|
||||
const chatSDK = new OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
||||
const url = chatSDK.resolveChatAdapterUrl(ChatAdapterProtocols.DirectLine);
|
||||
|
||||
expect(url).toBe(chatSDKConfig.chatAdapterConfig.webChatDirectLineCDNUrl);
|
||||
});
|
||||
|
||||
it('ChatSDK should pick the default webChatDirectLineCDNUrl if no chatAdapterConfig is set', async () => {
|
||||
const omnichannelConfig = {
|
||||
orgUrl: '',
|
||||
orgId: '',
|
||||
widgetId: ''
|
||||
};
|
||||
|
||||
const chatSDK = new OmnichannelChatSDK(omnichannelConfig);
|
||||
const url = chatSDK.resolveChatAdapterUrl(ChatAdapterProtocols.DirectLine);
|
||||
|
||||
expect(url).toBe(libraries.getDirectLineCDNUrl());
|
||||
});
|
||||
|
||||
it('ChatSDK should throw an error if ChatSDK.resolveChatAdapterUrl() is called with other protocol than supported protocols', async () => {
|
||||
const omnichannelConfig = {
|
||||
orgUrl: '',
|
||||
|
@ -206,9 +258,10 @@ describe('Omnichannel Chat SDK', () => {
|
|||
|
||||
const chatSDK = new OmnichannelChatSDK(omnichannelConfig);
|
||||
|
||||
const protocol = ChatAdapterProtocols.DirectLine;
|
||||
const protocol = "UnsupportedProtocol";
|
||||
try {
|
||||
chatSDK.resolveChatAdapterUrl(protocol);
|
||||
fail();
|
||||
} catch (error) {
|
||||
expect(error.toString()).toContain(`ChatAdapter for protocol ${protocol} currently not supported`);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import CallingOptionsOptionSetNumber from "../src/core/CallingOptionsOptionSetNu
|
|||
import AriaTelemetry from "../src/telemetry/AriaTelemetry";
|
||||
import * as settings from '../src/config/settings';
|
||||
import { AWTLogManager } from "../src/external/aria/webjs/AriaSDK";
|
||||
import ChatSDKErrors from "../src/core/ChatSDKErrors";
|
||||
|
||||
describe('Omnichannel Chat SDK (Web)', () => {
|
||||
(settings as any).ariaTelemetryKey = '';
|
||||
|
@ -67,6 +68,40 @@ describe('Omnichannel Chat SDK (Web)', () => {
|
|||
expect(chatSDK.OCClient.sessionInit.mock.calls[0][1]).toMatchObject(sessionInitOptionalParams);
|
||||
});
|
||||
|
||||
it('ChatSDK.startChat() with sendDefaultInitContext should throw an error if not used on Web Platform', async () => {
|
||||
const chatSDK = new OmnichannelChatSDK(omnichannelConfig);
|
||||
chatSDK.getChatConfig = jest.fn();
|
||||
|
||||
await chatSDK.initialize();
|
||||
|
||||
chatSDK.IC3Client = {
|
||||
initialize: jest.fn(),
|
||||
joinConversation: jest.fn()
|
||||
}
|
||||
|
||||
const optionalParams = {
|
||||
sendDefaultInitContext: true
|
||||
}
|
||||
|
||||
jest.spyOn(chatSDK.OCClient, 'getChatToken').mockResolvedValue(Promise.resolve({
|
||||
ChatId: '',
|
||||
Token: '',
|
||||
RegionGtms: '{}'
|
||||
}));
|
||||
|
||||
jest.spyOn(chatSDK.OCClient, 'sessionInit').mockResolvedValue(Promise.resolve());
|
||||
|
||||
jest.spyOn(platform, 'isNode').mockReturnValue(true);
|
||||
jest.spyOn(platform, 'isReactNative').mockReturnValue(false);
|
||||
jest.spyOn(platform, 'isBrowser').mockReturnValue(false);
|
||||
|
||||
try {
|
||||
await chatSDK.startChat(optionalParams);
|
||||
} catch (error) {
|
||||
expect(error.message).toEqual(ChatSDKErrors.UnsupportedPlatform);
|
||||
}
|
||||
});
|
||||
|
||||
it('ChatSDK.createChatAdapter() should be returned succesfully on Web platform', async () => {
|
||||
const chatSDK = new OmnichannelChatSDK(omnichannelConfig);
|
||||
chatSDK.getChatConfig = jest.fn();
|
||||
|
@ -109,7 +144,7 @@ describe('Omnichannel Chat SDK (Web)', () => {
|
|||
jest.spyOn(platform, 'isReactNative').mockReturnValue(false);
|
||||
jest.spyOn(platform, 'isBrowser').mockReturnValue(true);
|
||||
|
||||
const protocol = 'DirectLine';
|
||||
const protocol = 'UnsupportedProtocol';
|
||||
const optionalParams = {
|
||||
protocol
|
||||
}
|
||||
|
|
|
@ -15,13 +15,16 @@ import AuthSettings from "./core/AuthSettings";
|
|||
import CallingOptionsOptionSetNumber from "./core/CallingOptionsOptionSetNumber";
|
||||
import ChatAdapterOptionalParams from "./core/messaging/ChatAdapterOptionalParams";
|
||||
import ChatAdapterProtocols from "./core/messaging/ChatAdapterProtocols";
|
||||
import { ChatClient } from "@azure/communication-chat";
|
||||
import ChatConfig from "./core/ChatConfig";
|
||||
import ChatReconnectContext from "./core/ChatReconnectContext";
|
||||
import ChatReconnectOptionalParams from "./core/ChatReconnectOptionalParams";
|
||||
import ChatSDKConfig from "./core/ChatSDKConfig";
|
||||
import ChatSDKErrors from "./core/ChatSDKErrors";
|
||||
import ChatSDKExceptionDetails from "./core/ChatSDKExceptionDetails";
|
||||
import ChatSDKMessage from "./core/messaging/ChatSDKMessage";
|
||||
import ChatTranscriptBody from "./core/ChatTranscriptBody";
|
||||
import { createACSAdapter, createDirectLine, createIC3Adapter } from "./utils/chatAdapterCreators";
|
||||
import ConversationMode from "./core/ConversationMode";
|
||||
import DeliveryMode from "@microsoft/omnichannel-ic3core/lib/model/DeliveryMode";
|
||||
import FileMetadata from "@microsoft/omnichannel-amsclient/lib/FileMetadata";
|
||||
|
@ -39,7 +42,6 @@ import IFileMetadata from "@microsoft/omnichannel-ic3core/lib/model/IFileMetadat
|
|||
import IGetChatTokenOptionalParams from "@microsoft/ocsdk/lib/Interfaces/IGetChatTokenOptionalParams";
|
||||
import IGetChatTranscriptsOptionalParams from "@microsoft/ocsdk/lib/Interfaces/IGetChatTranscriptsOptionalParams";
|
||||
import IGetLWIDetailsOptionalParams from "@microsoft/ocsdk/lib/Interfaces/IGetLWIDetailsOptionalParams";
|
||||
import IIC3AdapterOptions from "./external/IC3Adapter/IIC3AdapterOptions";
|
||||
import IInitializationInfo from "@microsoft/omnichannel-ic3core/lib/model/IInitializationInfo";
|
||||
import IMessage from "@microsoft/omnichannel-ic3core/lib/model/IMessage";
|
||||
import InitializeOptionalParams from "./core/InitializeOptionalParams";
|
||||
|
@ -71,15 +73,12 @@ import ScenarioMarker from "./telemetry/ScenarioMarker";
|
|||
import StartChatOptionalParams from "./core/StartChatOptionalParams";
|
||||
import TelemetryEvent from "./telemetry/TelemetryEvent";
|
||||
import createAMSClient from "@microsoft/omnichannel-amsclient";
|
||||
import createChannelDataEgressMiddleware from "./external/ACSAdapter/createChannelDataEgressMiddleware";
|
||||
import createFormatEgressTagsMiddleware from "./external/ACSAdapter/createFormatEgressTagsMiddleware";
|
||||
import createFormatIngressTagsMiddleware from "./external/ACSAdapter/createFormatIngressTagsMiddleware";
|
||||
import createOmnichannelMessage from "./utils/createOmnichannelMessage";
|
||||
import createTelemetry from "./utils/createTelemetry";
|
||||
import createVoiceVideoCalling from "./api/createVoiceVideoCalling";
|
||||
import { defaultMessageTags } from "./core/messaging/MessageTags";
|
||||
import {isCustomerMessage} from "./utils/utilities";
|
||||
import libraries from "./utils/libraries";
|
||||
import urlResolvers from "./utils/urlResolvers";
|
||||
import validateOmnichannelConfig from "./validators/OmnichannelConfigValidator";
|
||||
|
||||
class OmnichannelChatSDK {
|
||||
|
@ -452,7 +451,7 @@ class OmnichannelChatSDK {
|
|||
if (optionalParams.sendDefaultInitContext) {
|
||||
if (platform.isNode() || platform.isReactNative()) {
|
||||
const exceptionDetails: ChatSDKExceptionDetails = {
|
||||
response: "UnsupportedPlatform",
|
||||
response: ChatSDKErrors.UnsupportedPlatform,
|
||||
message: "sendDefaultInitContext is only supported on browser"
|
||||
};
|
||||
|
||||
|
@ -1447,7 +1446,6 @@ class OmnichannelChatSDK {
|
|||
});
|
||||
|
||||
try {
|
||||
|
||||
if (this.authenticatedUserToken) {
|
||||
emailTranscriptOptionalParams.authenticatedUserToken = this.authenticatedUserToken;
|
||||
}
|
||||
|
@ -1519,94 +1517,18 @@ class OmnichannelChatSDK {
|
|||
}
|
||||
|
||||
const {protocol} = optionalParams;
|
||||
const supportedChatAdapterProtocols = [ChatAdapterProtocols.ACS, ChatAdapterProtocols.IC3];
|
||||
const supportedChatAdapterProtocols = [ChatAdapterProtocols.ACS, ChatAdapterProtocols.IC3, ChatAdapterProtocols.DirectLine];
|
||||
if (protocol && !supportedChatAdapterProtocols.includes(protocol as string)) {
|
||||
return Promise.reject(`ChatAdapter for protocol ${protocol} currently not supported`);
|
||||
}
|
||||
|
||||
if (protocol === ChatAdapterProtocols.ACS || this.liveChatVersion === LiveChatVersion.V2) {
|
||||
return new Promise (async (resolve, reject) => { // eslint-disable-line no-async-promise-executor
|
||||
const options = optionalParams.ACSAdapter? optionalParams.ACSAdapter.options: {};
|
||||
|
||||
// Tags formatting middlewares are required to be the last in the pipeline to ensure tags are converted to the right format
|
||||
const defaultEgressMiddlewares = [createChannelDataEgressMiddleware({widgetId: this.omnichannelConfig.widgetId}), createFormatEgressTagsMiddleware()];
|
||||
const defaultIngressMiddlewares = [createFormatIngressTagsMiddleware()];
|
||||
const egressMiddleware = options?.egressMiddleware? [...options.egressMiddleware, ...defaultEgressMiddlewares]: [...defaultEgressMiddlewares];
|
||||
const ingressMiddleware = options?.ingressMiddleware? [...options.egressMiddleware, ...defaultIngressMiddlewares]: [...defaultIngressMiddlewares];
|
||||
const featuresOption = {
|
||||
enableAdaptiveCards: true, // Whether to enable adaptive card payload in adapter (payload in JSON string)
|
||||
enableThreadMemberUpdateNotification: true, // Whether to enable chat thread member join/leave notification
|
||||
enableLeaveThreadOnWindowClosed: false, // Whether to remove user on browser close event
|
||||
...options, // overrides
|
||||
ingressMiddleware,
|
||||
egressMiddleware
|
||||
};
|
||||
|
||||
const acsAdapterCDNUrl = this.resolveChatAdapterUrl(protocol || ChatAdapterProtocols.ACS);
|
||||
this.telemetry?.setCDNPackages({
|
||||
ACSAdapter: acsAdapterCDNUrl
|
||||
});
|
||||
|
||||
await loadScript(acsAdapterCDNUrl, () => {
|
||||
/* istanbul ignore next */
|
||||
this.debug && console.debug('ACSAdapter loaded!');
|
||||
try {
|
||||
const { ChatAdapter } = window as any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
const fileManager = new AMSFileManager(this.AMSClient as FramedClient, this.acsAdapterLogger);
|
||||
const adapter = ChatAdapter.createACSAdapter(
|
||||
this.chatToken.token as string,
|
||||
this.chatToken.visitorId || 'teamsvisitor',
|
||||
this.chatToken.chatId as string,
|
||||
this.chatToken.acsEndpoint as string,
|
||||
fileManager,
|
||||
30000,
|
||||
ACSParticipantDisplayName.Customer,
|
||||
this.ACSClient?.getChatClient(),
|
||||
this.acsAdapterLogger, // logger
|
||||
featuresOption,
|
||||
);
|
||||
|
||||
resolve(adapter);
|
||||
} catch {
|
||||
throw new Error('Failed to load ACSAdapter');
|
||||
}
|
||||
}, () => {
|
||||
reject('Failed to load ACSADapter');
|
||||
});
|
||||
});
|
||||
if (protocol === ChatAdapterProtocols.DirectLine) {
|
||||
return createDirectLine(optionalParams, this.chatSDKConfig, this.liveChatVersion, ChatAdapterProtocols.DirectLine, this.telemetry as typeof AriaTelemetry, this.scenarioMarker);
|
||||
} else if (protocol === ChatAdapterProtocols.ACS || this.liveChatVersion === LiveChatVersion.V2) {
|
||||
const fileManager = new AMSFileManager(this.AMSClient as FramedClient, this.acsAdapterLogger);
|
||||
return createACSAdapter(optionalParams, this.chatSDKConfig, this.liveChatVersion, ChatAdapterProtocols.ACS, this.telemetry as typeof AriaTelemetry, this.scenarioMarker, this.omnichannelConfig, this.chatToken, fileManager, this.ACSClient?.getChatClient() as ChatClient, this.acsAdapterLogger as ACSAdapterLogger);
|
||||
} else if (protocol === ChatAdapterProtocols.IC3 || this.liveChatVersion === LiveChatVersion.V1) {
|
||||
return new Promise (async (resolve, reject) => { // eslint-disable-line no-async-promise-executor
|
||||
const options = optionalParams.IC3Adapter? optionalParams.IC3Adapter.options: {};
|
||||
const ic3AdapterCDNUrl = this.resolveChatAdapterUrl(protocol || ChatAdapterProtocols.IC3);
|
||||
this.telemetry?.setCDNPackages({
|
||||
IC3Adapter: ic3AdapterCDNUrl
|
||||
});
|
||||
|
||||
this.scenarioMarker.startScenario(TelemetryEvent.CreateIC3Adapter);
|
||||
|
||||
await loadScript(ic3AdapterCDNUrl, () => {
|
||||
/* istanbul ignore next */
|
||||
this.debug && console.debug('IC3Adapter loaded!');
|
||||
const adapterConfig: IIC3AdapterOptions = {
|
||||
chatToken: this.chatToken,
|
||||
userDisplayName: 'Customer',
|
||||
userId: this.chatToken.visitorId || 'teamsvisitor',
|
||||
sdkURL: this.resolveIC3ClientUrl(),
|
||||
sdk: this.IC3Client,
|
||||
...options // overrides
|
||||
};
|
||||
|
||||
const adapter = new window.Microsoft.BotFramework.WebChat.IC3Adapter(adapterConfig);
|
||||
adapter.logger = this.ic3ClientLogger;
|
||||
|
||||
this.scenarioMarker.completeScenario(TelemetryEvent.CreateIC3Adapter);
|
||||
|
||||
resolve(adapter);
|
||||
}, () => {
|
||||
this.scenarioMarker.failScenario(TelemetryEvent.CreateIC3Adapter);
|
||||
reject('Failed to load IC3Adapter');
|
||||
});
|
||||
});
|
||||
return createIC3Adapter(optionalParams, this.chatSDKConfig, this.liveChatVersion, ChatAdapterProtocols.IC3, this.telemetry as typeof AriaTelemetry, this.scenarioMarker, this.chatToken, this.IC3Client, this.ic3ClientLogger as IC3ClientLogger);
|
||||
}
|
||||
|
||||
return Promise.reject(`ChatAdapter for protocol ${protocol} currently not supported`);
|
||||
|
@ -1912,46 +1834,11 @@ class OmnichannelChatSDK {
|
|||
}
|
||||
|
||||
private resolveIC3ClientUrl(): string {
|
||||
if (this.chatSDKConfig.ic3Config && 'ic3ClientCDNUrl' in this.chatSDKConfig.ic3Config) {
|
||||
return this.chatSDKConfig.ic3Config.ic3ClientCDNUrl as string;
|
||||
}
|
||||
|
||||
if (this.chatSDKConfig.ic3Config && 'ic3ClientVersion' in this.chatSDKConfig.ic3Config) {
|
||||
return libraries.getIC3ClientCDNUrl(this.chatSDKConfig.ic3Config.ic3ClientVersion);
|
||||
}
|
||||
|
||||
return libraries.getIC3ClientCDNUrl();
|
||||
return urlResolvers.resolveIC3ClientUrl(this.chatSDKConfig);
|
||||
}
|
||||
|
||||
private resolveChatAdapterUrl(protocol: string): string {
|
||||
const supportedChatAdapterProtocols = [ChatAdapterProtocols.ACS, ChatAdapterProtocols.IC3];
|
||||
if (protocol && !supportedChatAdapterProtocols.includes(protocol as string)) {
|
||||
throw new Error(`ChatAdapter for protocol ${protocol} currently not supported`);
|
||||
}
|
||||
|
||||
if (protocol === ChatAdapterProtocols.ACS || this.liveChatVersion === LiveChatVersion.V2) {
|
||||
if (this.chatSDKConfig.chatAdapterConfig && 'webChatACSAdapterCDNUrl' in this.chatSDKConfig.chatAdapterConfig) {
|
||||
return this.chatSDKConfig.chatAdapterConfig.webChatACSAdapterCDNUrl as string;
|
||||
}
|
||||
|
||||
if (this.chatSDKConfig.chatAdapterConfig && 'webChatACSAdapterVersion' in this.chatSDKConfig.chatAdapterConfig) {
|
||||
return libraries.getACSAdapterCDNUrl(this.chatSDKConfig.chatAdapterConfig.webChatACSAdapterVersion);
|
||||
}
|
||||
|
||||
return libraries.getACSAdapterCDNUrl();
|
||||
} else if (protocol === ChatAdapterProtocols.IC3 || this.liveChatVersion === LiveChatVersion.V1) {
|
||||
if (this.chatSDKConfig.chatAdapterConfig && 'webChatIC3AdapterCDNUrl' in this.chatSDKConfig.chatAdapterConfig) {
|
||||
return this.chatSDKConfig.chatAdapterConfig.webChatIC3AdapterCDNUrl as string;
|
||||
}
|
||||
|
||||
if (this.chatSDKConfig.chatAdapterConfig && 'webChatIC3AdapterVersion' in this.chatSDKConfig.chatAdapterConfig) {
|
||||
return libraries.getIC3AdapterCDNUrl(this.chatSDKConfig.chatAdapterConfig.webChatIC3AdapterVersion);
|
||||
}
|
||||
|
||||
return libraries.getIC3AdapterCDNUrl();
|
||||
}
|
||||
|
||||
return '';
|
||||
return urlResolvers.resolveChatAdapterUrl(this.chatSDKConfig, this.liveChatVersion, protocol);
|
||||
}
|
||||
|
||||
private async updateChatToken(newToken: string, newRegionGTMS: IRegionGtms): Promise<void> {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
const ic3ClientVersion = '2021.08.14.1';
|
||||
const webChatIC3AdapterVersion = '0.1.0-master.2dba07b';
|
||||
const webChatACSAdapterVersion = '0.0.35-beta.12';
|
||||
const webChatDirectLineVersion = '0.15.1';
|
||||
const ariaTelemetryKey = 'c7655518acf1403f93ff6b9f77942f0a-d01a02fd-6b50-4de3-a566-62eda11f93bc-7083';
|
||||
|
||||
export {
|
||||
ic3ClientVersion,
|
||||
webChatIC3AdapterVersion,
|
||||
webChatACSAdapterVersion,
|
||||
webChatDirectLineVersion,
|
||||
ariaTelemetryKey
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
enum ChatSDKErrors {
|
||||
UnsupportedPlatform = "UnsupportedPlatform"
|
||||
}
|
||||
|
||||
export default ChatSDKErrors;
|
|
@ -3,4 +3,6 @@ export default interface ChatAdapterConfig {
|
|||
webChatIC3AdapterCDNUrl?: string;
|
||||
webChatACSAdapterVersion?: string;
|
||||
webChatACSAdapterCDNUrl?: string;
|
||||
webChatDirectLineVersion?: string;
|
||||
webChatDirectLineCDNUrl?: string;
|
||||
}
|
|
@ -4,12 +4,17 @@ interface ChatAdapterOptionalParams {
|
|||
options?: {
|
||||
[key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
}
|
||||
};
|
||||
ACSAdapter?: {
|
||||
options?: {
|
||||
[key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
}
|
||||
};
|
||||
DirectLine?: {
|
||||
options?: {
|
||||
[key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default ChatAdapterOptionalParams;
|
|
@ -35,6 +35,7 @@ interface CDNPackagesInfo {
|
|||
IC3Client?: string;
|
||||
IC3Adapter?: string;
|
||||
ACSAdapter?: string;
|
||||
DirectLine?: string;
|
||||
SpoolSDK?: string;
|
||||
VoiceVideoCalling?: string;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ enum TelemetryEvent {
|
|||
GetLiveChatTranscript = "GetLiveChatTranscript",
|
||||
CreateIC3Adapter = "CreateChatAdapter",
|
||||
CreateACSAdapter = "CreateACSAdapter",
|
||||
CreateDirectLine = "CreateDirectLine",
|
||||
GetVoiceVideoCalling = "GetVoiceVideoCalling",
|
||||
GetIC3Client = "GetIC3Client",
|
||||
InitializeVoiceVideoCallingSDK = "InitializeVoiceVideoCallingSDK",
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
import { ACSAdapterLogger, IC3ClientLogger } from "./loggers";
|
||||
import ACSParticipantDisplayName from "../core/messaging/ACSParticipantDisplayName";
|
||||
import AMSFileManager from "../external/ACSAdapter/AMSFileManager";
|
||||
import AriaTelemetry from "../telemetry/AriaTelemetry";
|
||||
import ChatAdapterOptionalParams from "../core/messaging/ChatAdapterOptionalParams";
|
||||
import { ChatClient } from "@azure/communication-chat";
|
||||
import ChatSDKConfig from "../core/ChatSDKConfig";
|
||||
import createChannelDataEgressMiddleware from "../external/ACSAdapter/createChannelDataEgressMiddleware";
|
||||
import createFormatEgressTagsMiddleware from "../external/ACSAdapter/createFormatEgressTagsMiddleware";
|
||||
import createFormatIngressTagsMiddleware from "../external/ACSAdapter/createFormatIngressTagsMiddleware";
|
||||
import IChatToken from "../external/IC3Adapter/IChatToken";
|
||||
import IIC3AdapterOptions from "../external/IC3Adapter/IIC3AdapterOptions";
|
||||
import LiveChatVersion from "../core/LiveChatVersion";
|
||||
import { loadScript } from "./WebUtils";
|
||||
import OmnichannelConfig from "../core/OmnichannelConfig";
|
||||
import ScenarioMarker from "../telemetry/ScenarioMarker";
|
||||
import TelemetryEvent from "../telemetry/TelemetryEvent";
|
||||
import urlResolvers from "./urlResolvers";
|
||||
|
||||
const createDirectLine = async (optionalParams: ChatAdapterOptionalParams, chatSDKConfig: ChatSDKConfig, liveChatVersion: LiveChatVersion, protocol: string, telemetry: typeof AriaTelemetry, scenarioMarker: ScenarioMarker): Promise<unknown> => {
|
||||
const options = optionalParams.DirectLine? optionalParams.DirectLine.options: {};
|
||||
const directLineCDNUrl = urlResolvers.resolveChatAdapterUrl(chatSDKConfig, liveChatVersion, protocol);
|
||||
|
||||
telemetry?.setCDNPackages({
|
||||
DirectLine: directLineCDNUrl
|
||||
});
|
||||
|
||||
scenarioMarker.startScenario(TelemetryEvent.CreateDirectLine);
|
||||
|
||||
try {
|
||||
await loadScript(directLineCDNUrl);
|
||||
} catch {
|
||||
scenarioMarker.failScenario(TelemetryEvent.CreateDirectLine);
|
||||
throw new Error('Failed to load DirectLine');
|
||||
}
|
||||
|
||||
try {
|
||||
const {DirectLine} = window as any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
const adapter = new DirectLine.DirectLine({...options});
|
||||
scenarioMarker.completeScenario(TelemetryEvent.CreateDirectLine);
|
||||
return adapter;
|
||||
} catch {
|
||||
scenarioMarker.failScenario(TelemetryEvent.CreateDirectLine);
|
||||
throw new Error('Failed to create DirectLine');
|
||||
}
|
||||
};
|
||||
|
||||
const createACSAdapter = async (optionalParams: ChatAdapterOptionalParams, chatSDKConfig: ChatSDKConfig, liveChatVersion: LiveChatVersion, protocol: string, telemetry: typeof AriaTelemetry, scenarioMarker: ScenarioMarker, omnichannelConfig: OmnichannelConfig, chatToken: IChatToken, fileManager: AMSFileManager, chatClient: ChatClient, logger: ACSAdapterLogger): Promise<unknown> => {
|
||||
const options = optionalParams.ACSAdapter? optionalParams.ACSAdapter.options: {};
|
||||
const acsAdapterCDNUrl = urlResolvers.resolveChatAdapterUrl(chatSDKConfig, liveChatVersion, protocol);
|
||||
|
||||
telemetry?.setCDNPackages({
|
||||
ACSAdapter: acsAdapterCDNUrl
|
||||
});
|
||||
|
||||
// Tags formatting middlewares are required to be the last in the pipeline to ensure tags are converted to the right format
|
||||
const defaultEgressMiddlewares = [createChannelDataEgressMiddleware({widgetId: omnichannelConfig.widgetId}), createFormatEgressTagsMiddleware()];
|
||||
const defaultIngressMiddlewares = [createFormatIngressTagsMiddleware()];
|
||||
const egressMiddleware = options?.egressMiddleware? [...options.egressMiddleware, ...defaultEgressMiddlewares]: [...defaultEgressMiddlewares];
|
||||
const ingressMiddleware = options?.ingressMiddleware? [...options.egressMiddleware, ...defaultIngressMiddlewares]: [...defaultIngressMiddlewares];
|
||||
const featuresOption = {
|
||||
enableAdaptiveCards: true, // Whether to enable adaptive card payload in adapter (payload in JSON string)
|
||||
enableThreadMemberUpdateNotification: true, // Whether to enable chat thread member join/leave notification
|
||||
enableLeaveThreadOnWindowClosed: false, // Whether to remove user on browser close event
|
||||
...options, // overrides
|
||||
ingressMiddleware,
|
||||
egressMiddleware
|
||||
};
|
||||
|
||||
scenarioMarker.startScenario(TelemetryEvent.CreateACSAdapter);
|
||||
|
||||
try {
|
||||
await loadScript(acsAdapterCDNUrl);
|
||||
} catch {
|
||||
scenarioMarker.failScenario(TelemetryEvent.CreateACSAdapter);
|
||||
throw new Error('Failed to load ACSAdapter');
|
||||
}
|
||||
|
||||
try {
|
||||
const { ChatAdapter } = window as any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
const adapter = ChatAdapter.createACSAdapter(
|
||||
chatToken.token as string,
|
||||
chatToken.visitorId || 'teamsvisitor',
|
||||
chatToken.chatId as string,
|
||||
chatToken.acsEndpoint as string,
|
||||
fileManager,
|
||||
30000,
|
||||
ACSParticipantDisplayName.Customer,
|
||||
chatClient,
|
||||
logger,
|
||||
featuresOption,
|
||||
);
|
||||
|
||||
scenarioMarker.completeScenario(TelemetryEvent.CreateACSAdapter);
|
||||
return adapter;
|
||||
} catch {
|
||||
scenarioMarker.failScenario(TelemetryEvent.CreateACSAdapter);
|
||||
throw new Error('Failed to create ACSAdapter');
|
||||
}
|
||||
};
|
||||
|
||||
const createIC3Adapter = async (optionalParams: ChatAdapterOptionalParams, chatSDKConfig: ChatSDKConfig, liveChatVersion: LiveChatVersion, protocol: string, telemetry: typeof AriaTelemetry, scenarioMarker: ScenarioMarker, chatToken: IChatToken, ic3Client: any, logger: IC3ClientLogger): Promise<unknown> => { // eslint-disable-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
||||
const options = optionalParams.IC3Adapter? optionalParams.IC3Adapter.options: {};
|
||||
const ic3AdapterCDNUrl = urlResolvers.resolveChatAdapterUrl(chatSDKConfig, liveChatVersion, protocol);
|
||||
|
||||
telemetry?.setCDNPackages({
|
||||
IC3Adapter: ic3AdapterCDNUrl
|
||||
});
|
||||
|
||||
scenarioMarker.startScenario(TelemetryEvent.CreateIC3Adapter);
|
||||
|
||||
try {
|
||||
await loadScript(ic3AdapterCDNUrl);
|
||||
} catch {
|
||||
scenarioMarker.failScenario(TelemetryEvent.CreateIC3Adapter);
|
||||
throw new Error('Failed to load IC3Adapter');
|
||||
}
|
||||
|
||||
const adapterConfig: IIC3AdapterOptions = {
|
||||
chatToken: chatToken,
|
||||
userDisplayName: 'Customer',
|
||||
userId: chatToken.visitorId || 'teamsvisitor',
|
||||
sdkURL: urlResolvers.resolveIC3ClientUrl(chatSDKConfig),
|
||||
sdk: ic3Client,
|
||||
...options // overrides
|
||||
};
|
||||
|
||||
try {
|
||||
const adapter = new window.Microsoft.BotFramework.WebChat.IC3Adapter(adapterConfig);
|
||||
adapter.logger = logger;
|
||||
scenarioMarker.completeScenario(TelemetryEvent.CreateIC3Adapter);
|
||||
return adapter;
|
||||
} catch {
|
||||
scenarioMarker.failScenario(TelemetryEvent.CreateIC3Adapter);
|
||||
throw new Error('Failed to create IC3Adapter');
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
createDirectLine,
|
||||
createACSAdapter,
|
||||
createIC3Adapter
|
||||
};
|
||||
|
||||
export {
|
||||
createDirectLine,
|
||||
createACSAdapter,
|
||||
createIC3Adapter
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
import { ic3ClientVersion, webChatACSAdapterVersion, webChatIC3AdapterVersion } from "../config/settings";
|
||||
import { ic3ClientVersion, webChatACSAdapterVersion, webChatDirectLineVersion, webChatIC3AdapterVersion } from "../config/settings";
|
||||
|
||||
const getIC3ClientCDNUrl = (version = ic3ClientVersion): string => {
|
||||
const IC3ClientCDNUrl = `https://comms.omnichannelengagementhub.com/release/${version}/Scripts/SDK/SDK.min.js`;
|
||||
|
@ -15,14 +15,21 @@ const getACSAdapterCDNUrl = (version = webChatACSAdapterVersion): string => {
|
|||
return ACSAdapterCDNUrl;
|
||||
}
|
||||
|
||||
const getDirectLineCDNUrl = (version = webChatDirectLineVersion): string => {
|
||||
const DirectLineCDNUrl = `https://unpkg.com/botframework-directlinejs@${version}/dist/directline.js`;
|
||||
return DirectLineCDNUrl;
|
||||
}
|
||||
|
||||
export default {
|
||||
getIC3ClientCDNUrl,
|
||||
getIC3AdapterCDNUrl,
|
||||
getACSAdapterCDNUrl
|
||||
getACSAdapterCDNUrl,
|
||||
getDirectLineCDNUrl
|
||||
}
|
||||
|
||||
export {
|
||||
getIC3ClientCDNUrl,
|
||||
getIC3AdapterCDNUrl,
|
||||
getACSAdapterCDNUrl
|
||||
getACSAdapterCDNUrl,
|
||||
getDirectLineCDNUrl
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
import ChatSDKConfig from "../core/ChatSDKConfig";
|
||||
import LiveChatVersion from "../core/LiveChatVersion";
|
||||
import ChatAdapterProtocols from "../core/messaging/ChatAdapterProtocols";
|
||||
import libraries from "./libraries";
|
||||
|
||||
const resolveIC3ClientUrl = (chatSDKConfig: ChatSDKConfig): string => {
|
||||
if (chatSDKConfig.ic3Config && 'ic3ClientCDNUrl' in chatSDKConfig.ic3Config) {
|
||||
return chatSDKConfig.ic3Config.ic3ClientCDNUrl as string;
|
||||
}
|
||||
|
||||
if (chatSDKConfig.ic3Config && 'ic3ClientVersion' in chatSDKConfig.ic3Config) {
|
||||
return libraries.getIC3ClientCDNUrl(chatSDKConfig.ic3Config.ic3ClientVersion);
|
||||
}
|
||||
|
||||
return libraries.getIC3ClientCDNUrl();
|
||||
};
|
||||
|
||||
const resolveDirectLineCDNUrl = (chatSDKConfig: ChatSDKConfig) => {
|
||||
if (chatSDKConfig.chatAdapterConfig && 'webChatDirectLineCDNUrl' in chatSDKConfig.chatAdapterConfig) {
|
||||
return chatSDKConfig.chatAdapterConfig.webChatDirectLineCDNUrl as string;
|
||||
}
|
||||
|
||||
if (chatSDKConfig.chatAdapterConfig && 'webChatDirectLineVersion' in chatSDKConfig.chatAdapterConfig) {
|
||||
return libraries.getDirectLineCDNUrl(chatSDKConfig.chatAdapterConfig.webChatDirectLineVersion);
|
||||
}
|
||||
|
||||
return libraries.getDirectLineCDNUrl();
|
||||
}
|
||||
|
||||
const resolveACSAdapterCDNUrl = (chatSDKConfig: ChatSDKConfig) => {
|
||||
if (chatSDKConfig.chatAdapterConfig && 'webChatACSAdapterCDNUrl' in chatSDKConfig.chatAdapterConfig) {
|
||||
return chatSDKConfig.chatAdapterConfig.webChatACSAdapterCDNUrl as string;
|
||||
}
|
||||
|
||||
if (chatSDKConfig.chatAdapterConfig && 'webChatACSAdapterVersion' in chatSDKConfig.chatAdapterConfig) {
|
||||
return libraries.getACSAdapterCDNUrl(chatSDKConfig.chatAdapterConfig.webChatACSAdapterVersion);
|
||||
}
|
||||
|
||||
return libraries.getACSAdapterCDNUrl();
|
||||
};
|
||||
|
||||
const resolveIC3AdapterCDNUrl = (chatSDKConfig: ChatSDKConfig) => {
|
||||
if (chatSDKConfig.chatAdapterConfig && 'webChatIC3AdapterCDNUrl' in chatSDKConfig.chatAdapterConfig) {
|
||||
return chatSDKConfig.chatAdapterConfig.webChatIC3AdapterCDNUrl as string;
|
||||
}
|
||||
|
||||
if (chatSDKConfig.chatAdapterConfig && 'webChatIC3AdapterVersion' in chatSDKConfig.chatAdapterConfig) {
|
||||
return libraries.getIC3AdapterCDNUrl(chatSDKConfig.chatAdapterConfig.webChatIC3AdapterVersion);
|
||||
}
|
||||
|
||||
return libraries.getIC3AdapterCDNUrl();
|
||||
};
|
||||
|
||||
const resolveChatAdapterUrl = (chatSDKConfig: ChatSDKConfig, liveChatVersion: LiveChatVersion, protocol: string): string => {
|
||||
const supportedChatAdapterProtocols = [ChatAdapterProtocols.ACS, ChatAdapterProtocols.IC3, ChatAdapterProtocols.DirectLine];
|
||||
if (protocol && !supportedChatAdapterProtocols.includes(protocol as string)) {
|
||||
throw new Error(`ChatAdapter for protocol ${protocol} currently not supported`);
|
||||
}
|
||||
|
||||
if (protocol === ChatAdapterProtocols.DirectLine) {
|
||||
return resolveDirectLineCDNUrl(chatSDKConfig);
|
||||
} else if (protocol === ChatAdapterProtocols.ACS || liveChatVersion === LiveChatVersion.V2) {
|
||||
return resolveACSAdapterCDNUrl(chatSDKConfig);
|
||||
} else if (protocol === ChatAdapterProtocols.IC3 || liveChatVersion === LiveChatVersion.V1) {
|
||||
return resolveIC3AdapterCDNUrl(chatSDKConfig);
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
export default {
|
||||
resolveIC3ClientUrl,
|
||||
resolveChatAdapterUrl
|
||||
}
|
||||
|
||||
export {
|
||||
resolveIC3ClientUrl,
|
||||
resolveChatAdapterUrl
|
||||
}
|
Загрузка…
Ссылка в новой задаче