
Product
Introducing Socket Firewall Enterprise: Flexible, Configurable Protection for Modern Package Ecosystems
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.
acs_webchat-chat-adapter
Advanced tools
An adapter for connecting WebChat with Azure Communication Services
ACS Webchat Adapter is a project for connecting Webchat UX to ACS chat.
createACSAdapter = (
token: string,
id: string,
threadId: string,
environmentUrl: string,
fileManager: IFileManager,
pollingInterval: number,
eventSubscriber: IErrorEventSubscriber,
displayName?: string,
chatClient?: ChatClient,
logger?: ILogger,
adapterOptions?: AdapterOptions
): SealedAdapter<IDirectLineActivity, ACSAdapterState>
token An ACS user access token
id The ACS user's id
threadId Id of the chat thread to join
environmentUrl ACS resource endpoint
fileManager IFileManager instance for filesharing
pollingInterval Interval in milliseconds that the adapter will poll for messages, polling is only done when notifications are not enabled. The minimum value is 5 seconds. Default value is 30 seconds.
eventSubscriber IErrorEventSubscriber instance to send error events to the caller.
displayName User's displayname
chatClient Chat Client
logger Logger instance
adapterOptions Adapter options, see Feature Options for more detail
ACS Webchat Adapter requires CommunicationUserToken and EnvironmentUrl. You can either directly use ConnectionString of ACS service or can host token management service project.
Get the connection string from ACS Communication Service In local.settings.json replace [CONNECTION_STRING] with connection string
{
"ConnectionString": "endpoint=https://********;accesskey=******"
}
If the token management project is running, paste the service URL to:
In webpack.dev.config.js, replace hosted_function_url with your own connection string
{
search: 'TOKEN_MANAGEMENT_SERVICE_URL',
replace: '' // URL of token management service
}
npm installnpm run startsrc
βββ egress
β βββ createEgress[ActivityType]ActivityMiddleware.ts
βββ ingress
β βββ subsribe[Event].ts
βββ sdk
βββ index.html
ingress contains all the event subscribe middleware which listens to ACS event and dispatchs activity to Webchat
egress contains all the middles which applied to WebChat and listen to different actions and call sdks
sdk contains api wrappers for sdk including authentication
index.html is a demo html running by npm run start, which could be used as sample code
Install VSCode mermaid extension to view this diagram in VSCode
There are 2 token types:
sequenceDiagram
participant ACS Token Service
participant App Web Server
participant Web App
participant WebChat
participant ACS Adapter
participant ACS Chat SDK
participant Azure Communication Service
Web App-->>App Web Server: Send User Token for authentication and ask for an ACS token
App Web Server -->> App Web Server: Validate the user using User Token
App Web Server -->> ACS Token Service: Create an ACS token
ACS Token Service -->> App Web Server: Return an ACS token
App Web Server -->> App Web Server: Bind User Identity with ACS token
App Web Server -->> Web App: Return an ACS token
Web App -->> ACS Adapter: Use ACS token to create adapter
Web App -->> WebChat: Render Webchat and bind with adapter
ACS Adapter -->> ACS Chat SDK: Create ChatClient using ACS token
ACS Chat SDK -->> Azure Communication Service: Network request to service
Notes:
ACS doesn't provide a login service, all authentications depends on the original app authentication, and App Server is responsible for assign an ACS token after user validation(then bind ACS token with user info)
Every time when ACS Token Service is asked for creating a new User Token, a new ACS user is created, token binding should happen again
Thread Creation logic could happen either in App Web Server or in Adapter, it is just a preference of whether developers want it to be a heavy server depending or light server depending app
sequenceDiagram
participant WebChat
participant ACS Adapter
participant ACS Chat SDK
participant Azure Communication Service
WebChat -->> WebChat: User sends messages
WebChat -->> ACS Adapter: Pass message as an Activity to ACS Adapter
ACS Adapter -->> ACS Chat SDK: Call chatClient.sendMessage(message)
ACS Chat SDK -->> Azure Communication Service: Send post message network request
Azure Communication Service -->> ACS Chat SDK: Receive message from network
ACS Chat SDK -->> ACS Adapter: Trigger receive message event
ACS Adapter -->> WebChat: Dispatch IncomingActivity
sequenceDiagram
participant ACS Adapter
participant ChatWidget
participant Edge Server
participant Azure Communication Service
Edge Server -->> Azure Communication Service: Join Conversation (using ACS Chat SDK)
Edge Server -->> Azure Communication Service: Create token and add customer into thread
Edge Server -->> ChatWidget: token & threadId
ChatWidget -->> ACS Adapter: token & threadId
Edge Server -->> Azure Communication Service: Send queue information (using chatClient.sendMessage)
Azure Communication Service -->> ACS Adapter: Dispatch queue messgae
ACS Adapter -->> ChatWidget: Dispatch Activity with ChannelData
Edge Server -->> Azure Communication Service: Agent ready, create token and join agent to thread
Edge Server -->> Azure Communication Service: Agent ready, create token and join the agent to the thread
Azure Communication Service -->> ACS Adapter: trigger threadUpdate
sequenceDiagram
participant ACS Adapter
participant ChatWidget
participant Edge Server
participant Azure Communication Service
ACS Adapter -->> Edge Server: Send heartbeat
ACS Adapter -->> Edge Server: Stop heartbeat
Edge Server -->> Edge Server: no heartbeat received for 90s
Edge Server -->> Azure Communication Service: kick user out of the thread
Azure Communication Service -->> ACS Adapter: Notify thread update
ACS Adapter -->> ChatWidget: User left the chat
Dev Test js file can work without real server logic - check before you start in readme for more details
npm run build:dev<script> tag in html, and call window.ChatAdapter.initializeThread()npm run build<script> tag in html, and call window.ChatAdapter.createACSAdapter (check sample code in index.html)To use telemetry for adapter, you will need to implement Logger api for adapter
interface ILogger {
logEvent(loglevel: LogLevel, event: ACSLogData): void;
}
To use the error event notifier, you will need to implement the following method
interface IErrorEventSubscriber {
notifyErrorEvent(adapterErrorEvent: AdapterErrorEvent): void;
}
And pass it when you call window.ChatAdapter.createACSAdapter (put it in the 6th parameter), check our demo index.html for reference
The following features can be enabled by injecting AdapterOptions interface.
export interface AdapterOptions {
enableAdaptiveCards: boolean; // to enable adaptive card payload in adapter (which will convert content payload into a json string)
enableThreadMemberUpdateNotification: boolean; // to enable chat thread member join/leave notification
enableLeaveThreadOnWindowClosed: boolean; // to remove user on browser close event
enableSenderDisplayNameInTypingNotification?: boolean; // Whether to send sender display name in typing notification,
historyPageSizeLimit?: number; // If requested paged responses of messages otherwise undefined
serverPageSizeLimit?: number; // Number of messages to fetch from the server at once
shouldFileAttachmentDownloadTimeout?: boolean; // Whether file attachment download be timed out.
fileAttachmentDownloadTimeout?: number; // If shouldFileAttachmentDownloadTimeout is set then timeout value in milliseconds when attachment download should be timed out. Default value 90s.
messagePollingHandle?: IMessagePollingHandle; // Provides more control over polling calls made to Chat Gateway service.
}
Adapter options are injected to directline while creating ACS adapter.
const featuresOption = {
enableAdaptiveCards: true,
enableThreadMemberUpdateNotification: true,
enableLeaveThreadOnWindowClosed: true,
enableSenderDisplayNameInTypingNotification: true,
historyPageSizeLimit: 5,
serverPageSizeLimit: 60,
shouldFileAttachmentDownloadTimeout: true,
fileAttachmentDownloadTimeout: 120000
};
const directLine = createACSAdapter(token, userId, threadId, environmentUrl, fileManager, displayName, logger, featuresOption);
| Option | Type | Default | Description |
|---|---|---|---|
| enableThreadMemberUpdateNotification | boolean | false | Send chat thread member update notification activities to WebChat when a new user joins thread or a user leave the thread. |
| enableAdaptiveCards | boolean | false | The Adaptive Cards are sent as attachments in activity. The format is followd as per guidelines. Development Panel has adaptive card implementation.The example code can be found at location src/development/react-componets/.adaptiveCard.tsx |
| enableLeaveThreadOnWindowClosed | boolean | false | On browser close, whether users will remove themselves from the chat thread. |
| enableSenderDisplayNameInTypingNotification | boolean | false | Whether send user display name when sending typing indicator. |
| historyPageSizeLimit | number | undefined | History message pagination can be turned on via setting a valid historyPageSizeLimit. To send a pagination event: window.dispatchEvent(new Event('acs-adapter-loadnextpage')); |
| serverPageSizeLimit | number | undefined | Number of messages to fetch from the server at once. Putting a high value like 60 will result in a fewer calls to the server to fetch all the messages on a thread. |
| shouldFileAttachmentDownloadTimeout | boolean | undefined | Whether file attachment download be timed out. |
| fileAttachmentDownloadTimeout | number | undefined | If the shouldFileAttachmentDownloadTimeout is set then the value of timeout when file download should be timed out. Default will be 90000ms enforced only when shouldFileAttachmentDownloadTimeout is true, otherwise will wait for browser timeout. |
| messagePollingHandle | Interface IMessagePollingHandle | undefined | Provides methods to control polling. |
IMessagePollingHandle has been added to provide more control over polling calls that Adapter invokes to fetch messages in the background. In some cases clients might want to stop these calls from their end either completely or temporarily when a user is removed as a participant. Interface provides two methods whose description is below that client could implement and provide a reference to in AdapterOptions.
| Method | Description | Return value | Default |
|---|---|---|---|
getIsPollingEnabled: () => boolean; | Get client polling setting during each polling cycle. This only disables the call to the service but the scheduler is still on going | Return true to execute message fetching call for current cycle. Return false to skip message fetching call for current cycle. | true |
stopPolling: () => boolean; | This stops the scheduler from scheduling any further message fetching calls. | Return true to stop scheduling any next message fetching calls. Return false to continue scheduling next message fetching calls | false |
Instead of leaving the thread in Server side, we also allow user to leave thread using our adapter. To leave chat raise a 'acs-adapter-leavechat' event. The sample code is written in file 'src\development\react-component\leavechat.tsx'. Development Panel has leave chat button implemented.
window.dispatchEvent(new Event('acs-adapter-leavechat'));
When egress ACS backend throws an exception, an activity with channel data of type error will be triggered.
To display message to user, you can detect activity of type error like below. The message and stack of the Error object is saved in the activity text property.
if (
action.payload &&
action.payload.activity?.channelData &&
action.payload.activity?.channelData.type == 'Error'
) {
dispatch({
type: 'WEB_CHAT/SET_NOTIFICATION',
payload: {
level: 'info',
message: message: JSON.parse(action.payload.activity.text).payload.details.Message
}
});
Development Panel is integrated inside of dev mode js file, if you import dev mode in html(Check index.html for Reference):
const {
renderDebugPanel
} = window.ChatAdapter;
/*
Create adapter and store...
*/
window.WebChat.renderWebChat(
{
directLine,
store,
},
document.getElementById('root')
);
renderDebugPanel(document.getElementById('devPannel'), store);
Development panel has Adaptive Card UI panel and Leave Chat button implementation.
To launch development panel in dev mode:
npm run startAll the unit test files are under /test/unit folder, run npm run test:unit to test
To run a single test file for instance, run npm run test:unit -- test/unit/ingress/subscribeNewMessageAndThreadUpdate.test.ts
When you are writing test and wanna debug it:
npm run test:debug to testAll the integration test files are under /test/integration folder
To test:
npm run install:chromedriver to install chrome drivernpm run execute:integrationtest to testTo enable filesharing implement the IFileManager interface and provide an instance of this when creating the adapter. See index.html for an example using the OneDriveFileManager implementation.
activity.attachments Contains the attachment data. Each attachment contains the following properties:
contentType The MIME-type
contentUrl The file contents URL
name The filename
thumbnailUrl Applicable to images and videos only, the image thumbnail URL
When sending attachments ensure the attachments property is populated on the Message activity that is sent to the adapter, this is done by Webchat component.
When receiving messages the adapter will populate this property if the ChatMessage contains attachments.
Note since filesharing is supported through metadata activity.channelData.metadata will contain the property returned by IFileManager's createChatMessageMetadata()method. You do NOT need to explicitly set this in the metadata yourself.
Example of an activity with attachments that Webchat component sends to adapter:
const activity: ACSDirectLineActivity = {
...
attachments: [
{
filename: "<YOUR_FILENAME>",
contentType: "<YOUR_FILETYPE>"
contentURL: "<YOUR_URL>"
thumbnailURL: "<YOUR_THUMBNAIL_URL>"
}
]
...
}
Note that when using Webchat components built-in file attachment capabilities, you should not need to construct this activity yourself.
attachments are passed directly to IFileManager uploadFiles() method, if you require additional data for file upload you can modify the attachments in the activity.
For example in the attachments below, myAdditionalData will be passed inside attachments to uploadFile():
attachments: {
filename: "<YOUR_FILENAME>",
contentType: "<YOUR_FILETYPE>"
contentURL: "<YOUR_URL>"
thumbnailURL: "<YOUR_THUMBNAIL_URL>"
myAdditionalData: "<YOUR_ADDITIONAL_DATA>"
}
Adapter supports message tagging. Tags are sent as ChatMessage metadata.
activity.channelData.tags: string
To send tags to the adapter, populate this property inside the activity. When receiving activities from the adapter, this property will be populated if the ChatMessage contains tags.
Note since tags are sent as metadata activity.channelData.metadata.tags will also contain the tags. You do NOT need to explicitly set this in the metadata yourself.
Exampe of sending tags in an Activity:
const activity: ACSDirectLineActivity = {
...
channelData: {
tags: "tag1"
}
...
}
And the resulting metadata on the ChatMessage object from ACS:
const message: ChatMessage = {
...
metadata: {
tags: "tag1"
}
...
}
ChatMessages may contain metadata, which is a property bag of string key-value pairs.
Message tagging and filesharing are supported through ChatMessage metadata, you do NOT need to explicitly set these in the metadata yourself, the adapter will do that for you. You can however send additional metadata if needed.
You can send additional ChatMessage metadata by populating the activity.channelData.metadata property which is of type Record<string, string>. When receiving ChatMessages, the adapter will populate this property if the message contains metadata.
Example Activity showing metadata format:
const activity: ACSDirectLineActivity = {
...
channelData: {
metadata: {
"<YOUR_KEY>" : "<YOUR_VALUE>"
}
}
...
}
Note: Webchat component does not support message edits. Note: If adaptive cards are enabled, the adapter expects the message content to be a JSON object with text property. For example, valid content for an adaptive card:
JSON.stringify({
text: "Hello world!"
})
The adapter listens for ChatMessageEditedEvents and will dispatch an MessageEdit activity when incoming events are received.
Since message edits are unsupported by Webchat, MessageEdit Activities are custom activity types that you must handle yourself.
MessageEdit activities contain the edited content (which may be the message content or metadata) as well as the timestamp when the message was edited. The MessageEdit Activity will have the same messageid as the original ChatMessage.
Below shows the format of a MessageEdit Activity, see the ACSDirectLineActivity for more type information:
const activity: IDirectLineActivity = {
attachment?s: any[],
channelId: string,
channelData?: {
attachmentSizes: number[],
tags: string,
metadata: Record<string, string>;
},
conversation: { id: string },
from: {
id: string,
name: string,
role: string
},
messageid: string,
text: string,
timestamp: string,
type: ActivityType.Message
}
The following properties contain information about the message edit:
text is the edited message's content
timestamp is the timestamp when the message was edited, in ISO 8601 format
messageid is the id of the edited message
type is ActivityType.Message which is equal to "message"
If the edited message contains metadata the following properties will be present:
attachments is an array of objects containing file attachment data, see Filesharing for more detail.
channelData.tags contains the message tags (this is an optional metadata property)
channelData.metadata contains the message metadata
Enable Adaptive Cards by setting enableAdaptiveCards inside AdapterOptions to true. When enabled, the adapter will determine if the received message is an adaptive card & format the activity appropriately. If adaptive cards are not enabled then Webchat will render messages as is.
ACS Adapter expects the ChatMessage for an adaptive card to contain:
microsoft.azure.communication.chat.bot.contenttype with a value of azurebotservice.adaptivecardNOTE Webchat currently supports activityMiddleware and createStore middleware, these can also be utilized for similar effect.
You can provide your own custom egress and ingress middlewares when initializing the adapter.
Inside AdapterOptions, provde ingressMiddleware and/or egressMiddleware.
ingressMiddleware: An array of middlewares that are invoked on incoming messages from ACS. The middlewares will be applied in the order they are provided. Ingress middleware can be used to intercept messages received from ACS.
egressMiddleware: An array of middlewares that are invoked on outgoing messages to ACS. The middlewares will be applied in the order they are provided. Egress middleware can be used to intercept messages before sending them to ACS.
Example:
const myEgressMiddleware = ({ getState }) => (next) => (activity) => {
if (activity.type === ActivityType.Message) {
// Do something with the message before sending it to ACS
}
return next(activity);
}
const options: AdapterOptions = {
enableAdaptiveCards: false,
enableThreadMemberUpdateNotification: true,
enableLeaveThreadOnWindowClosed: true,
historyPageSizeLimit: 5,
egressMiddleware: [myEgressMiddleware]
};
const adapter = createACSAdapter(
token,
userId,
threadId,
environmentUrl,
fileManager,
pollingInterval,
displayName,
logger,
options
);
TODO: Explain how other users and developers can contribute to make your code better.
If you want to learn more about creating good readme files then refer the following guidelines. You can also seek inspiration from the below readme files:
FAQs
An adapter for connecting WebChat with Azure Communication Services
The npm package acs_webchat-chat-adapter receives a total of 859 weekly downloads. As such, acs_webchat-chat-adapter popularity was classified as not popular.
We found that acs_webchat-chat-adapter demonstrated a not healthy version release cadence and project activity because the last version was released a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.

Security News
Open source dashboard CNAPulse tracks CVE Numbering Authoritiesβ publishing activity, highlighting trends and transparency across the CVE ecosystem.

Product
Detect malware, unsafe data flows, and license issues in GitHub Actions with Socketβs new workflow scanning support.