Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

quiq-chat

Package Overview
Dependencies
Maintainers
1
Versions
152
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

quiq-chat - npm Package Compare versions

Comparing version 1.8.2 to 1.8.3

.idea/misc.xml

166

build/quiq-chat.js

@@ -141,8 +141,9 @@ 'use strict';

var bypassUrls = ['/session/web', '/agents-available'];
var bypassUrls = ['/session/web', '/agents-available', '/chat'];
var retryCount = 0;
var timedOut = false;
var timerId = void 0;
var stubbornFetch = (function (url, fetchRequest) {
var retryCount = 0;
var timedOut = false;
var timerId = void 0;
var delayIfNeeded = function delayIfNeeded() {

@@ -260,3 +261,3 @@ return new Promise(function (resolve) {

var version = "1.8.2";
var version = "1.8.3";

@@ -315,2 +316,8 @@ //

//
var _onNewSession = void 0;
var registerNewSessionCallback = function registerNewSessionCallback(callback) {
_onNewSession = callback;
};
var joinChat$1 = function joinChat() {

@@ -368,4 +375,16 @@ quiqFetch(getUrlForContactPoint() + '/join', { method: 'POST', credentials: 'include' });

/**
* Creates a new session and tracking ID
* @param host - Host against which to call /generate
* @param sessionChange - Indicates whether this is being called to replace old session. Results in newSession callback being fired.
*/
var login = function login(host) {
return quiqFetch(getSessionApiUrl(host) + '/generate', { credentials: 'include', method: 'POST' });
return quiqFetch(getSessionApiUrl(host) + '/generate', {
credentials: 'include',
method: 'POST'
}, {
responseType: 'JSON'
}).then(function (res) {
if (_onNewSession) _onNewSession(res.tokenId);
});
};

@@ -614,2 +633,7 @@

this.onNewSession = function (callback) {
_this2.callbacks.onNewSession = callback;
return _this2;
};
this.onBurn = function (callback) {

@@ -656,11 +680,3 @@ _this2.callbacks.onBurn = callback;

connectSocket({
socketUrl: wsInfo.url,
callbacks: {
onConnectionLoss: _this2._handleConnectionLoss,
onConnectionEstablish: _this2._handleConnectionEstablish,
onMessage: _this2._handleWebsocketMessage,
onBurn: _this2._handleBurnItDown
}
});
_this2._connectSocket(wsInfo);

@@ -823,2 +839,63 @@ if (_this2.callbacks.onConnectionStatusChange) {

this._connectSocket = function (wsInfo) {
connectSocket({
socketUrl: wsInfo.url,
callbacks: {
onConnectionLoss: _this2._handleConnectionLoss,
onConnectionEstablish: _this2._handleConnectionEstablish,
onMessage: _this2._handleWebsocketMessage,
onBurn: _this2._handleBurnItDown
}
});
};
this._handleNewSession = function () {
var _ref8 = _asyncToGenerator$1(regeneratorRuntime.mark(function _callee5(newTrackingId) {
var wsInfo;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
if (!(_this2.trackingId && newTrackingId !== _this2.trackingId)) {
_context5.next = 10;
break;
}
// Clear message and events caches (tracking ID is different now, so we essentially have a new Conversation)
_this2.textMessages = [];
_this2.events = [];
_this2.userIsRegistered = false;
if (_this2.callbacks.onNewSession) {
_this2.callbacks.onNewSession();
}
// Disconnect/reconnect websocket
// (Connection establishment handler will refresh messages)
disconnectSocket(); // Ensure we only have one websocket connection open
_context5.next = 8;
return fetchWebsocketInfo();
case 8:
wsInfo = _context5.sent;
_this2._connectSocket(wsInfo);
case 10:
_this2.trackingId = newTrackingId;
case 11:
case 'end':
return _context5.stop();
}
}
}, _callee5, _this2);
}));
return function (_x3) {
return _ref8.apply(this, arguments);
};
}();
this._handleWebsocketMessage = function (message) {

@@ -832,10 +909,5 @@ if (message.messageType === MessageTypes.CHAT_MESSAGE) {

case MessageTypes.LEAVE:
case MessageTypes.REGISTER:
_this2._processNewMessagesAndEvents([], [message.data]);
break;
case MessageTypes.REGISTER:
if (_this2.callbacks.onRegistration) {
_this2.callbacks.onRegistration();
}
_this2.userIsRegistered = true;
break;
case MessageTypes.AGENT_TYPING:

@@ -871,16 +943,16 @@ if (_this2.callbacks.onAgentTyping) {

this._handleConnectionEstablish = _asyncToGenerator$1(regeneratorRuntime.mark(function _callee5() {
var _ref9, messages, events;
this._handleConnectionEstablish = _asyncToGenerator$1(regeneratorRuntime.mark(function _callee6() {
var _ref10, messages, events;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
return regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context5.prev = _context5.next) {
switch (_context6.prev = _context6.next) {
case 0:
_context5.next = 2;
_context6.next = 2;
return getConversation();
case 2:
_ref9 = _context5.sent;
messages = _ref9.messages;
events = _ref9.events;
_ref10 = _context6.sent;
messages = _ref10.messages;
events = _ref10.events;

@@ -898,6 +970,6 @@

case 'end':
return _context5.stop();
return _context6.stop();
}
}
}, _callee5, _this2);
}, _callee6, _this2);
}));

@@ -912,11 +984,27 @@

var sortedMessages = sortByTimestamp(_this2.textMessages.concat(newMessages));
var sortedEvents = sortByTimestamp(_this2.events.concat(newEvents));
// Apparently, it's possible (though not common) to receive duplicate messages in transcript response.
// We need to take union of new and current messages to account for this
_this2.textMessages = sortedMessages;
_this2.events = sortedEvents;
// If we found new messages, sort them, update cached textMessages, and send callback
if (newMessages.length) {
_this2.textMessages = sortByTimestamp(lodash.unionBy(_this2.textMessages, newMessages, 'id'));
if (newMessages.length && _this2.callbacks.onNewMessages && sendNewMessageCallback) {
_this2.callbacks.onNewMessages(_this2.textMessages);
if (_this2.callbacks.onNewMessages && sendNewMessageCallback) {
_this2.callbacks.onNewMessages(_this2.textMessages);
}
}
// If we found new events, sort them, update cached events, and check if a new registration event was received. Fire callback if so.
if (newEvents.length) {
_this2.events = sortByTimestamp(lodash.unionBy(_this2.events, newEvents, 'id'));
if (newEvents.find(function (e) {
return e.type === MessageTypes.REGISTER;
})) {
if (_this2.callbacks.onRegistration) {
_this2.callbacks.onRegistration();
}
_this2.userIsRegistered = true;
}
}
};

@@ -931,2 +1019,3 @@

this.connected = false;
this.trackingId = null;

@@ -951,2 +1040,5 @@ setGlobals({

});
// Register with apiCalls for new session events
registerNewSessionCallback(this._handleNewSession);
};

@@ -953,0 +1045,0 @@

{
"name": "quiq-chat",
"version": "1.8.2",
"version": "1.8.3",
"description": "Library to help with network requests to create a webchat client for Quiq Messaging",

@@ -5,0 +5,0 @@ "main": "build/quiq-chat.js",

@@ -33,2 +33,4 @@ // @flow

const testTrackingId = 'dsafdsafaweufh';
describe('QuiqChatClient', () => {

@@ -39,2 +41,3 @@ const onNewMessages = jest.fn();

const onErrorResolved = jest.fn();
const onNewSession = jest.fn();
const onConnectionStatusChange = jest.fn();

@@ -62,2 +65,3 @@ const onBurn = jest.fn();

.onRegistration(onRegistration)
.onNewSession(onNewSession)
.onBurn(onBurn);

@@ -177,2 +181,80 @@

describe('handling new session', () => {
describe('when no trackingId is defined, i.e., this is first session', () => {
it('updates cached trackingId', () => {
if (!client) {
throw new Error('Client should be defined');
}
client._handleNewSession(testTrackingId);
expect(client.trackingId).toBe(testTrackingId);
});
it('does NOT fire new session callback', () => {
if (!client) {
throw new Error('Client should be defined');
}
client._handleNewSession(testTrackingId);
expect(client.callbacks.onNewSession).not.toHaveBeenCalled();
});
});
describe('when trackingId has not changed, i.e. session was refreshed', () => {
beforeEach(() => {
if (!client) {
throw new Error('Client should be defined');
}
client.trackingId = testTrackingId;
});
it('updates cached trackingId', () => {
if (!client) {
throw new Error('Client should be defined');
}
client._handleNewSession(testTrackingId);
expect(client.trackingId).toBe(testTrackingId);
});
it('does NOT fire new session callback', () => {
if (!client) {
throw new Error('Client should be defined');
}
client._handleNewSession(testTrackingId);
expect(client.callbacks.onNewSession).not.toHaveBeenCalled();
});
});
describe('when trackingId has changed, i.e. new conversation', () => {
beforeEach(() => {
if (!client) {
throw new Error('Client should be defined');
}
client.trackingId = 'oldId';
});
it('updates cached trackingId', async () => {
if (!client) {
throw new Error('Client should be defined');
}
await client._handleNewSession(testTrackingId);
expect(client.trackingId).toBe(testTrackingId);
});
it('does fire new session callback', () => {
if (!client) {
throw new Error('Client should be defined');
}
client._handleNewSession(testTrackingId);
expect(client.callbacks.onNewSession).toHaveBeenCalled();
});
});
});
describe('getting new Register event', () => {

@@ -179,0 +261,0 @@ const newEvent = {type: 'Register', id: 'reg1', timestamp: 3};

@@ -7,2 +7,8 @@ // @flow

let _onNewSession: (newTrackingId: string) => any;
export const registerNewSessionCallback = (callback: (newTrackingId: string) => any) => {
_onNewSession = callback;
};
export const joinChat = () => {

@@ -62,4 +68,20 @@ quiqFetch(`${getUrlForContactPoint()}/join`, {method: 'POST', credentials: 'include'});

/**
* Creates a new session and tracking ID
* @param host - Host against which to call /generate
* @param sessionChange - Indicates whether this is being called to replace old session. Results in newSession callback being fired.
*/
export const login = (host?: string) =>
quiqFetch(`${getSessionApiUrl(host)}/generate`, {credentials: 'include', method: 'POST'});
quiqFetch(
`${getSessionApiUrl(host)}/generate`,
{
credentials: 'include',
method: 'POST',
},
{
responseType: 'JSON',
},
).then(res => {
if (_onNewSession) _onNewSession(res.tokenId);
});

@@ -66,0 +88,0 @@ export const validateSession = () => quiqFetch(getSessionApiUrl(), {credentials: 'include'});

@@ -8,3 +8,3 @@ // @flow

import {registerCallbacks, onInit} from './stubbornFetch';
import {differenceBy, last, partition} from 'lodash';
import {differenceBy, unionBy, last, partition} from 'lodash';
import {sortByTimestamp} from './utils';

@@ -30,2 +30,3 @@ import type {QuiqChatCallbacks} from 'types';

userIsRegistered: boolean;
trackingId: ?string;

@@ -40,2 +41,3 @@ constructor(host: string, contactPoint: string) {

this.connected = false;
this.trackingId = null;

@@ -60,2 +62,5 @@ setGlobals({

});
// Register with apiCalls for new session events
API.registerNewSessionCallback(this._handleNewSession);
}

@@ -103,2 +108,7 @@

onNewSession = (callback: () => void): QuiqChatClient => {
this.callbacks.onNewSession = callback;
return this;
};
onBurn = (callback: () => void): QuiqChatClient => {

@@ -127,11 +137,3 @@ this.callbacks.onBurn = callback;

const wsInfo: {url: string} = await API.fetchWebsocketInfo();
connectSocket({
socketUrl: wsInfo.url,
callbacks: {
onConnectionLoss: this._handleConnectionLoss,
onConnectionEstablish: this._handleConnectionEstablish,
onMessage: this._handleWebsocketMessage,
onBurn: this._handleBurnItDown,
},
});
this._connectSocket(wsInfo);

@@ -216,3 +218,35 @@ if (this.callbacks.onConnectionStatusChange) {

/** Private Members **/
_connectSocket = (wsInfo: {url: string}) => {
connectSocket({
socketUrl: wsInfo.url,
callbacks: {
onConnectionLoss: this._handleConnectionLoss,
onConnectionEstablish: this._handleConnectionEstablish,
onMessage: this._handleWebsocketMessage,
onBurn: this._handleBurnItDown,
},
});
};
_handleNewSession = async (newTrackingId: string) => {
if (this.trackingId && newTrackingId !== this.trackingId) {
// Clear message and events caches (tracking ID is different now, so we essentially have a new Conversation)
this.textMessages = [];
this.events = [];
this.userIsRegistered = false;
if (this.callbacks.onNewSession) {
this.callbacks.onNewSession();
}
// Disconnect/reconnect websocket
// (Connection establishment handler will refresh messages)
disconnectSocket(); // Ensure we only have one websocket connection open
const wsInfo: {url: string} = await API.fetchWebsocketInfo();
this._connectSocket(wsInfo);
}
this.trackingId = newTrackingId;
};
_handleWebsocketMessage = (message: AtmosphereMessage) => {

@@ -226,10 +260,5 @@ if (message.messageType === MessageTypes.CHAT_MESSAGE) {

case MessageTypes.LEAVE:
case MessageTypes.REGISTER:
this._processNewMessagesAndEvents([], [message.data]);
break;
case MessageTypes.REGISTER:
if (this.callbacks.onRegistration) {
this.callbacks.onRegistration();
}
this.userIsRegistered = true;
break;
case MessageTypes.AGENT_TYPING:

@@ -282,14 +311,28 @@ if (this.callbacks.onAgentTyping) {

): void => {
const newMessages = differenceBy(messages, this.textMessages, 'id');
const newEvents = differenceBy(events, this.events, 'id');
const newMessages: Array<TextMessage> = differenceBy(messages, this.textMessages, 'id');
const newEvents: Array<Event> = differenceBy(events, this.events, 'id');
const sortedMessages = sortByTimestamp(this.textMessages.concat(newMessages));
const sortedEvents = sortByTimestamp(this.events.concat(newEvents));
// Apparently, it's possible (though not common) to receive duplicate messages in transcript response.
// We need to take union of new and current messages to account for this
this.textMessages = sortedMessages;
this.events = sortedEvents;
// If we found new messages, sort them, update cached textMessages, and send callback
if (newMessages.length) {
this.textMessages = sortByTimestamp(unionBy(this.textMessages, newMessages, 'id'));
if (newMessages.length && this.callbacks.onNewMessages && sendNewMessageCallback) {
this.callbacks.onNewMessages(this.textMessages);
if (this.callbacks.onNewMessages && sendNewMessageCallback) {
this.callbacks.onNewMessages(this.textMessages);
}
}
// If we found new events, sort them, update cached events, and check if a new registration event was received. Fire callback if so.
if (newEvents.length) {
this.events = sortByTimestamp(unionBy(this.events, newEvents, 'id'));
if (newEvents.find(e => e.type === MessageTypes.REGISTER)) {
if (this.callbacks.onRegistration) {
this.callbacks.onRegistration();
}
this.userIsRegistered = true;
}
}
};

@@ -296,0 +339,0 @@ }

@@ -25,8 +25,9 @@ // @flow

const bypassUrls = ['/session/web', '/agents-available'];
const bypassUrls = ['/session/web', '/agents-available', '/chat'];
let retryCount = 0;
let timedOut = false;
let timerId;
export default (url: string, fetchRequest: RequestOptions) => {
let retryCount = 0;
let timedOut = false;
let timerId;
const delayIfNeeded = () =>

@@ -33,0 +34,0 @@ new Promise(resolve => {

@@ -54,2 +54,3 @@ // @flow

onBurn?: () => void,
onNewSession?: () => void,
};

@@ -56,0 +57,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc