-
Notifications
You must be signed in to change notification settings - Fork 68
Description
Steps to reproduce:
import "amazon-connect-chatjs"; // v1.3.1
import {
ConnectClient,
StartChatContactCommand,
} from "@aws-sdk/client-connect"; // v3.254.0
// start a chat contact
const client = new ConnectClient({
region: "us-east-1",
credentials: {
accessKeyId: "...",
secretAccessKey: "...",
sessionToken: "...",
},
});
const { ContactId, ParticipantId, ParticipantToken } = await client.send(
new StartChatContactCommand({
InstanceId: "...",
ContactFlowId: "...",
ParticipantDetails: { DisplayName: "Customer" },
})
);
// set global config (enable delivery/read receipts)
connect.ChatSession.setGlobalConfig({});
// create chat session
const session = connect.ChatSession.create({
chatDetails: {
contactId: ContactId,
participantId: ParticipantId,
participantToken: ParticipantToken,
},
options: { region: "us-east-1" },
type: connect.ChatSession.SessionTypes.CUSTOMER,
});
// setup a message handler that will execute once for a message
let once = true;
session.onMessage(async (event) => {
if (event.data.Type === "MESSAGE" && once) {
once = false;
// attempt to send a read receipt
const { Id: messageId } = event.data;
console.log("Sending read receipt for message:", messageId);
try {
await session.sendEvent({
contentType: "application/vnd.amazonaws.connect.event.message.read",
// notice there's no JSON.stringify(...) wrapping
content: { messageId },
});
console.log("Sent read receipt for message:", messageId);
} catch (e) {
console.error(
`Failed to send read receipt for message '${messageId}':`,
e
);
}
}
});
// connect to the chat
await session.connect();Expected result:
The read receipt is sent successfully.
Actual result:
The read receipt fails to be sent:
Sending read receipt for message: (...some message id...)
Failed to send read receipt for message '(...some message id...)': {
"type": "InvalidParameterType",
"message": "Expected params.Content to be a string",
"stack": [
"InvalidParameterType: Expected params.Content to be a string",
...
],
"metadata": null
}
Analysis:
Even though ChatController.sendEvent() and MessageReceiptsUtil.prioritizeAndSendMessageReceipt() support content to be an Object instead of a String:
| var parsedContent = typeof content === "string" ? JSON.parse(content) : content; |
amazon-connect-chatjs/src/core/MessageReceiptsUtil.js
Lines 75 to 76 in d85c517
| var content = typeof args[2] === "string" ? JSON.parse(args[2]) : args[2]; | |
| var messageId = typeof content === "object" ? content.messageId : ""; |
| var content = typeof args[2] === "string" ? JSON.parse(args[2]) : args[2]; |
| var contentVal = typeof this.lastReadArgs[2] === "string" ? JSON.parse(this.lastReadArgs[2]) : this.lastReadArgs[2]; |
When the connectparticipant:SendEvent operation is invoked through the client, the original content value is sent:
| return resolve(callback.call(ChatClientContext, ...args)); |
| var sendEventPromise = callback.call(ChatClientContext, ...args); |
| var PromiseArr = [callback.call(ChatClientContext, ...args)]; |
| PromiseArr.push(callback.call(ChatClientContext, ...this.lastReadArgs)); |
Thus, when AWSChatClient.prototype.sendEvent() is ultimately invoked, the content value in its Object form is used, instead of its JSON String form (which is what the client expects):
amazon-connect-chatjs/src/client/client.js
Lines 233 to 239 in d85c517
| sendEvent(connectionToken, contentType, content) { | |
| let self = this; | |
| if(contentType === CONTENT_TYPE.typing) { | |
| return self.throttleEvent(connectionToken, contentType, content) | |
| } | |
| return self._submitEvent(connectionToken, contentType, content); | |
| } |
amazon-connect-chatjs/src/client/client.js
Lines 245 to 261 in d85c517
| async _submitEvent(connectionToken, contentType, content) { | |
| let self = this; | |
| var params = { | |
| ConnectionToken: connectionToken, | |
| ContentType: contentType, | |
| Content: content | |
| }; | |
| var sendEventRequest = self.chatClient.sendEvent(params); | |
| const logContent = {contentType}; | |
| try { | |
| const res = await self._sendRequest(sendEventRequest); | |
| this.logger.debug("Successfully send event", { ...logContent, id: res.data?.Id, }); | |
| return res; | |
| } catch (err) { | |
| return await Promise.reject(err); | |
| } | |
| } |
Proposed fix:
One of the following:
- Modify
ChatController.prototype.sendEvent()to validate thatcontentmust be a JSONString. - Modify
MessageReceiptsUtilto invokeAWSChatClient.prototype.sendEvent()withcontentbeing a JSONStringvalue. - Modify
AWSChatClient.prototype.sendEvent()so that it invokesJSON.stringify()ifcontentis anObject.