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.53.0 to 1.54.0

coverage/lcov-report/block-navigation.js

3

package.json
{
"name": "quiq-chat",
"version": "1.53.0",
"version": "1.54.0",
"descri1tion":

@@ -42,2 +42,3 @@ "Library to help with network requests to create a webchat client for Quiq Messaging",

"store": "2.0.12",
"stubborn-fetch": "^0.0.4",
"ua-parser-js": "0.7.12"

@@ -44,0 +45,0 @@ },

@@ -43,5 +43,3 @@ # quiq-chat [![Build Status](https://travis-ci.org/Quiq/quiq-chat.svg?branch=master)](https://travis-ci.org/Quiq/quiq-chat) [![npm version](https://badge.fury.io/js/quiq-chat.svg)](https://badge.fury.io/js/quiq-chat) [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)

});
QuiqChatClient.onRetryableError(error => {
// Show some error message
}).QuiqChatClient.onErrorResolved(() => {
QuiqChatClient.onErrorResolved(() => {
// Remove the error message

@@ -86,6 +84,2 @@ });

#### onRetryableError(error: ?ApiError) => [QuiqChatClient](#quiqchatclient)
Called whenever there is a retryable error from the API
#### onErrorResolved() => [QuiqChatClient](#quiqchatclient)

@@ -120,6 +114,2 @@

#### onClientInactiveTimeout() => [QuiqChatClient](#quiqchatclient)
Called when quiq-chat disconnects the websocket due to the chat client being inactive for a set amount of time
#### getMessages(cache?: boolean = true) => Promise<Array<[ConversationMessage](#ConversationMessage)>>

@@ -126,0 +116,0 @@

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

import {set} from 'store';
import * as stubbornFetch from '../stubbornFetch';
import * as Utils from '../Utils/utils';

@@ -54,3 +53,2 @@ import log from 'loglevel';

const onRegistration = jest.fn();
const onClientInactiveTimeout = jest.fn();
const host = 'https://test.goquiq.fake';

@@ -60,3 +58,2 @@ const contactPoint = 'test';

const mockStore = (storage: any);
const setClientInactive = jest.spyOn(stubbornFetch, 'setClientInactive');

@@ -84,3 +81,2 @@ beforeEach(() => {

QuiqChatClient.onBurn(onBurn);
QuiqChatClient.onClientInactiveTimeout(onClientInactiveTimeout);

@@ -120,6 +116,2 @@ QuiqChatClient.start();

});
it('calls setClientInactive with false', () => {
expect(setClientInactive).toBeCalledWith(false);
});
});

@@ -165,6 +157,2 @@

});
it('does not call setClientInactive', () => {
expect(setClientInactive).not.toBeCalled();
});
});

@@ -306,3 +294,2 @@

QuiqChatClient.onBurn(onBurn);
QuiqChatClient.onClientInactiveTimeout(onClientInactiveTimeout);

@@ -398,3 +385,2 @@ if (!QuiqChatClient) {

QuiqChatClient.onBurn(onBurn);
QuiqChatClient.onClientInactiveTimeout(onClientInactiveTimeout);

@@ -543,3 +529,2 @@ QuiqChatClient.events = [];

QuiqChatClient.onBurn(onBurn);
QuiqChatClient.onClientInactiveTimeout(onClientInactiveTimeout);

@@ -546,0 +531,0 @@ if (!QuiqChatClient) {

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

} from './types';
import {setFetchMode} from 'quiqFetch';
import * as storage from './storage';

@@ -145,8 +146,2 @@ import logger from './logging';

onRetryableError = (callback: (error: ?ApiError) => void): QuiqChatClient => {
this.callbacks.onRetryableError = callback;
StubbornFetch.registerCallbacks({onRetryableError: callback});
return this;
};
onErrorResolved = (callback: () => void): QuiqChatClient => {

@@ -173,8 +168,2 @@ this.callbacks.onErrorResolved = callback;

onClientInactiveTimeout = (callback: () => void): QuiqChatClient => {
this.callbacks.onClientInactiveTimeout = callback;
return this;
};
onPersistentDataChange = (callback: (data: PersistentData) => void): QuiqChatClient => {

@@ -192,3 +181,2 @@ storage.registerCallbacks({onPersistentDataChange: callback});

this.initialized = true;
StubbornFetch.setClientInactive(false);

@@ -400,2 +388,4 @@ // Order Matters here. Ensure we successfully complete this fetchConversation request before connecting to

_setFetchMode = setFetchMode;
/**

@@ -402,0 +392,0 @@ * Returns an object of state information, useful for logging errors.

// @flow
import stubbornFetch from './stubbornFetch';
import {checkRequiredSettings} from './globals';
import {isStorageEnabled, getTrackingId} from './storage';
import oldStubbornFetch from './stubbornFetch';
import StubbornFetch, {StubbornFetchError} from 'stubborn-fetch';
import {checkRequiredSettings, getSessionApiUrl, getGenerateUrl, getBurned} from './globals';
import {isStorageEnabled, getTrackingId, getAccessToken} from './storage';
import {login} from './apiCalls';
import merge from 'lodash/merge';
import {formatQueryParams, createGuid} from './Utils/utils';
import {burnItDown, formatQueryParams, createGuid} from './Utils/utils';
import {version} from '../package.json';
import logger from './logging';
import logging from './logging';
const log = logger('QuiqFetch');
const messages = {
burned: 'Client in bad state. Aborting call.',
burnedFromServer: 'Received 466 response code from server. Blocking any further API Calls.',
storageDisabled: 'Storage is not enabled, aborting call',
trackingIdChanged: 'Tracking ID changed, not retrying after login.',
cannotParseResponse: (url: string) => `Couldn't parse API response from ${url}`,
unknownError: (url: string) => `Unknown error while parsing ${url}`,
};
const quiqFetchLog = logging('QuiqFetch');
const logger = {
log: quiqFetchLog.log,
info: quiqFetchLog.info,
warn: quiqFetchLog.warn,
error: (msg: string, e: StubbornFetchError) =>
quiqFetchLog.error(
msg,
e,
e &&
e.error &&
e.error.data &&
e.error.data.response &&
e.error.data.response.status &&
e.error.data.response.status >= 400 &&
e.error.data.response.status < 500,
),
};
let fetchMode;
export const setFetchMode = (mode?: 'edge' | 'legacy') => {
fetchMode = mode;
};
const quiqFetch = (

@@ -28,5 +61,9 @@ url: string,

if (!isStorageEnabled()) {
return Promise.reject('Storage is not enabled, aborting call');
return Promise.reject(new Error(messages.storageDisabled));
}
if (getBurned()) {
return Promise.reject(new Error(messages.burned));
}
if (options.checkRequiredSettings) checkRequiredSettings();

@@ -49,3 +86,9 @@

mode: 'cors',
headers: {
correlationId,
};
request.method = request.method || 'GET';
request.headers = Object.assign(
{},
{
'X-Quiq-Line': '2',

@@ -55,21 +98,71 @@ 'X-Quiq-Client-Id': 'Quiq-Chat-Client',

'x-centricient-correlation-id': correlationId,
'X-Quiq-Access-Token': getAccessToken(),
},
correlationId,
};
options.requestType === 'JSON'
? {
Accept: 'application/json',
'Content-Type': 'application/json',
}
: {},
);
let headers = {};
if (options.requestType === 'JSON' && request.headers) {
headers = {
Accept: 'application/json',
'Content-Type': 'application/json',
};
}
if (overrides) {
request.headers = merge(request.headers, headers);
request = merge(request, overrides);
}
request.method = request.method || 'GET';
return stubbornFetch(parsedUrl, request)
if (!fetchMode || fetchMode === 'legacy') {
return oldStubbornFetch(parsedUrl, request)
.then((res: Promise<Response> | Response): any => {
if (options.responseType === 'JSON' && res && res.json) {
return ((res: any): Response)
.json()
.then(result => result)
.catch(err => {
logger.warn(messages.cannotParseResponse(parsedUrl), {exception: err});
return err;
});
} else if (options.responseType === 'NONE') {
return;
}
return res;
})
.catch(err => {
return Promise.reject(err);
});
}
const onError = (e: StubbornFetchError) => {
if (e.data && e.data.response && e.data.response.status) {
const {status} = e.data.response;
if (
status === 466 ||
(status === 401 && (url === getGenerateUrl() || url === getSessionApiUrl()))
) {
burnItDown();
return true;
}
}
switch (e.type) {
case StubbornFetchError.types.MAX_ERRORS_EXCEEDED:
case StubbornFetchError.types.RATE_LIMITED:
burnItDown();
return true;
}
return false;
};
return new StubbornFetch(parsedUrl, request, {
retries: -1,
maxErrors: 100,
retryOnNetworkFailure: true,
totalRequestTimeLimit: 30000,
onError,
logger,
minimumStatusCodeForRetry: 402,
})
.send()
.then((res: Promise<Response> | Response): any => {

@@ -81,3 +174,3 @@ if (options.responseType === 'JSON' && res && res.json) {

.catch(err => {
log.warn(`Couldn't parse API response from ${parsedUrl}`, {exception: err});
logger.warn(messages.cannotParseResponse(parsedUrl), {exception: err});
return err;

@@ -91,4 +184,30 @@ });

})
.catch(err => {
return Promise.reject(err);
.catch(error => {
if (!error) return Promise.reject(new Error(messages.unknownError(parsedUrl)));
if (onError(error)) {
return Promise.reject(new Error(messages.burned));
}
if (
error.type === StubbornFetchError.types.HTTP_ERROR &&
error.data &&
error.data.response &&
error.data.response.status &&
error.data.response.status === 401
) {
return login()
.then(({trackingId, oldTrackingId}) => {
// Do NOT retry if tid changed--this is a new session, and any call we might be making was intended for old session
if (oldTrackingId && trackingId !== oldTrackingId) {
logger.warn(messages.trackingIdChanged);
return Promise.reject(new Error(error));
}
return quiqFetch(url, overrides, options);
})
.catch(err => Promise.reject(err));
}
return Promise.reject(error);
});

@@ -95,0 +214,0 @@ };

@@ -10,3 +10,3 @@ import Raven from 'raven-js';

autoBreadcrumbs: {
xhr: false, // XMLHttpRequest
xhr: true, // XMLHttpRequest
console: true, // console logging

@@ -13,0 +13,0 @@ dom: true, // DOM interactions, i.e. clicks/typing

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

'Client has exceeded maximum number of errors for a single session. Aborting session.',
clientInactive: 'The client has been inactive for 30 minutes. Blocking any further API Calls.',
};

@@ -28,3 +27,2 @@

onError?: (error: ?ApiError) => void,
onRetryableError?: (error: ?ApiError) => void,
onErrorResolved?: () => void,

@@ -36,3 +34,2 @@ };

let initialized = false;
let clientInactive = false;
let errorCount = 0;

@@ -48,6 +45,2 @@

export const setClientInactive = (isInactive: boolean) => {
clientInactive = isInactive;
};
const logRequest = (logData: Object) => {

@@ -115,8 +108,2 @@ if (logData._logged) return;

if (clientInactive) {
logData.statusCode = -1;
logData.reason = 'Request blocked because client is inactive';
logRequest(logData);
return reject(new Error(messages.clientInactive));
}
if (!bypassUrls.find(u => url.includes(u)) && !initialized) {

@@ -175,3 +162,2 @@ log.warn(`Request to ${url} blocked because client is not yet initialized`, {

if (callbacks.onRetryableError) callbacks.onRetryableError();
errorCount++;

@@ -193,3 +179,2 @@ return login().then(({trackingId, oldTrackingId}) => {

if (!timedOut && response.status >= 402 && response.status !== 422 && retryCount < 4) {
if (callbacks.onRetryableError) callbacks.onRetryableError();
errorCount++;

@@ -226,3 +211,2 @@ retryCount++;

if (!timedOut && retryCount < 4) {
if (callbacks.onRetryableError) callbacks.onRetryableError();
errorCount++;

@@ -229,0 +213,0 @@ retryCount++;

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

onError?: (error: ?ApiError) => void,
onRetryableError?: (error: ?ApiError) => void,
onErrorResolved?: () => void,

@@ -73,3 +72,2 @@ onConnectionStatusChange?: (connected: boolean) => void,

onNewSession?: () => void,
onClientInactiveTimeout?: () => void,
onPersistentDataChange?: (data: PersistentData) => void,

@@ -76,0 +74,0 @@ sentryMetadata?: () => Object,

@@ -33,16 +33,19 @@ // @flow

{data = {}, exception = null} = {},
shouldCapture = true,
) => {
const extra = Object.assign({}, QuiqChatClient && QuiqChatClient._getState(), data);
if (exception) {
Raven.captureException(exception, {
level,
logger: loggerName,
extra,
});
} else {
Raven.captureMessage(message, {
level,
logger: loggerName,
extra,
});
if (shouldCapture) {
if (exception) {
Raven.captureException(exception, {
level,
logger: loggerName,
extra,
});
} else {
Raven.captureMessage(message, {
level,
logger: loggerName,
extra,
});
}
}

@@ -49,0 +52,0 @@ rawMethod(message);

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 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

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

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

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

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