@opuscapita/service-client
Advanced tools
Comparing version 1.6.1 to 1.6.4
248
index.js
@@ -1,2 +0,2 @@ | ||
'use strict' | ||
'use strict'; | ||
@@ -14,4 +14,4 @@ const extend = require('extend'); | ||
// const { Console } = require('console'); | ||
const correlator = require("correlation-id"); | ||
const { v4: uuidv4 } = require('uuid'); | ||
const correlator = require('correlation-id'); | ||
const {v4: uuidv4} = require('uuid'); | ||
@@ -38,3 +38,3 @@ const JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/; | ||
this.config = this.config = extend(true, { }, ServiceClient.DefaultConfig, config); | ||
this.config.logger = this.config.logger || new Logger({ context: { name: '@opuscapita/service-client' } }); | ||
this.config.logger = this.config.logger || new Logger({context: {name: '@opuscapita/service-client'}}); | ||
this.config.parserContentType = this.config.parserContentType && this.config.parserContentType.toLowerCase(); | ||
@@ -53,11 +53,15 @@ this.token = null; | ||
ServiceClient.prototype._getServiceAccess = function(username = null, password = null) { | ||
/** | ||
* @param {string|null|undefined} username | ||
* @param {string|null|undefined} password | ||
*/ | ||
ServiceClient.prototype._getServiceAccess = function (username = null, password = null) { | ||
const config = this.config; | ||
let cacheKey; // = config.originService.authService.name + 'serviceToken'; | ||
const ECONNREFUSED = 'ECONNREFUSED'; | ||
const AUTH_TOKEN_FETCH_TRIES = +process.env.SERVICE_CLIENT_AUTH_TOKEN_FETCH_TRIES || 5; | ||
const AUTH_TOKEN_FETCH_DELAY = +process.env.SERVICE_CLIENT_AUTH_TOKEN_FETCH_DELAY || 0; | ||
const AUTH_TOKEN_FETCH_TRIES = parseInt(process.env.SERVICE_CLIENT_AUTH_TOKEN_FETCH_TRIES || '') || 5; | ||
const AUTH_TOKEN_FETCH_DELAY = parseInt(process.env.SERVICE_CLIENT_AUTH_TOKEN_FETCH_DELAY || '') || 0; | ||
const getOriginConfig = () => { | ||
const osc = config.originService | ||
const osc = config.originService; | ||
@@ -81,3 +85,3 @@ const mapObject = (props) => { | ||
if (!this.consul) { | ||
this.consul = configService.init({ host: config.consul.host }); | ||
this.consul = configService.init({host: config.consul.host}); | ||
} | ||
@@ -91,3 +95,3 @@ | ||
} | ||
} | ||
}; | ||
@@ -104,8 +108,21 @@ const queryAuthService = (originConfig, tryCounter = 0) => { | ||
if (!username) {return reject(new Error('Auth service could not be called: Empty field "username".'));} | ||
if (!password) {return reject(new Error('Auth service could not be called: Empty field "password".'));} | ||
if (!scope) {return reject(new Error('Auth service could not be called: Empty field "scope".'));} | ||
if (!clientKey) {return reject(new Error('Auth service could not be called: Empty field "clientKey".'));} | ||
if (!clientSecret) {return reject(new Error('Auth service could not be called: Empty field "clientSecret".'));} | ||
if (!username) { | ||
return reject(new Error('Auth service could not be called: Empty field "username".')); | ||
} | ||
if (!password) { | ||
return reject(new Error('Auth service could not be called: Empty field "password".')); | ||
} | ||
if (!scope) { | ||
return reject(new Error('Auth service could not be called: Empty field "scope".')); | ||
} | ||
if (!clientKey) { | ||
return reject(new Error('Auth service could not be called: Empty field "clientKey".')); | ||
} | ||
if (!clientSecret) { | ||
return reject(new Error('Auth service could not be called: Empty field "clientSecret".')); | ||
} | ||
/** | ||
* @type {any} | ||
*/ | ||
let data = | ||
@@ -115,16 +132,17 @@ { | ||
password: password, | ||
// eslint-disable-next-line camelcase | ||
grant_type: 'password', | ||
scope: scope | ||
} | ||
}; | ||
data = querystring.stringify(data); | ||
const auth = clientKey + ':' + clientSecret; | ||
const auth = `${clientKey}:${clientSecret}`; | ||
const headers = | ||
{ | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
// "Authorization": 'Basic ' + new Buffer(clientKey + ':' + clientSecret).toString('base64'), | ||
"Authorization": 'Basic ' + Buffer.alloc(auth.length, auth).toString('base64'), | ||
"Content-Length": Buffer.byteLength(data) | ||
} | ||
'Authorization': `Basic ${Buffer.alloc(auth.length, auth).toString('base64')}`, | ||
'Content-Length': Buffer.byteLength(data) | ||
}; | ||
@@ -144,4 +162,11 @@ return this._discover(originConfig.authServiceName).then((service) => { | ||
const request = http.request(options, (response) => { | ||
const statusCode = parseInt(response.statusCode, 10); | ||
if (!response.statusCode) { | ||
const error = new Error('No status code received from auth service'); | ||
// @ts-ignore | ||
error.response = response; | ||
throw error; | ||
} | ||
const statusCode = response.statusCode; | ||
response.on('data', (chunk) => tokenDetails.push(chunk)); | ||
@@ -156,3 +181,3 @@ response.on('end', () => { | ||
result: resultData | ||
} | ||
}; | ||
@@ -172,2 +197,3 @@ if (statusCode >= 100 && statusCode < 400) { | ||
const error = new Error(resultData); | ||
// @ts-ignore | ||
error.response = responseObject; | ||
@@ -179,2 +205,3 @@ | ||
const error = new Error(resultData); | ||
// @ts-ignore | ||
error.response = responseObject; | ||
@@ -185,4 +212,4 @@ | ||
} catch (error) { | ||
error.stack += '\n ' + stack.join('\n '); | ||
reject(error) | ||
error.stack += `\n ${stack.join('\n ')}`; | ||
reject(error); | ||
} | ||
@@ -193,14 +220,16 @@ }); | ||
request.on('error', error => { | ||
// @ts-ignore | ||
if (error && error.code) { | ||
// @ts-ignore | ||
if (error.code === ECONNREFUSED && tryCounter < AUTH_TOKEN_FETCH_TRIES) { | ||
config.logger.info(`${ECONNREFUSED} received from auth service, trying again`, { tryCounter }) | ||
config.logger.info(`${ECONNREFUSED} received from auth service, trying again`, {tryCounter}); | ||
setTimeout( | ||
() => resolve(queryAuthService(originConfig, tryCounter + 1)), | ||
AUTH_TOKEN_FETCH_DELAY | ||
) | ||
); | ||
} else { | ||
reject(error) | ||
reject(error); | ||
} | ||
} else { | ||
reject(error) | ||
reject(error); | ||
} | ||
@@ -213,3 +242,3 @@ }); | ||
}); | ||
} | ||
}; | ||
@@ -222,3 +251,3 @@ return getOriginConfig(). | ||
if (tokenDetails.id_token && !JWS_REGEX.test(tokenDetails.id_token)) { | ||
this.config.logger.warn('Malformed id_token fetched from cache', { idToken: tokenDetails.id_token }); | ||
this.config.logger.warn('Malformed id_token fetched from cache', {idToken: tokenDetails.id_token}); | ||
} | ||
@@ -231,6 +260,6 @@ return tokenDetails; | ||
catch(error => { | ||
config.logger.error('Could not query auth service', { error }); | ||
config.logger.error('Could not query auth service', {error}); | ||
throw error; | ||
}); | ||
} | ||
}; | ||
@@ -245,9 +274,9 @@ /** | ||
*/ | ||
ServiceClient.prototype._discover = function(serviceName) { | ||
ServiceClient.prototype._discover = function (serviceName) { | ||
if (!this.consul) { | ||
this.consul = configService.init({ host: this.config.consul.host }); | ||
this.consul = configService.init({host: this.config.consul.host}); | ||
} | ||
if (process.env.KUBER_DISCOVERY === 'true') { | ||
return configService.getProperty('service-client/discovery/' + serviceName). | ||
return configService.getProperty(`service-client/discovery/${serviceName}`). | ||
then( | ||
@@ -277,13 +306,13 @@ (resolvedOverride) => { | ||
} | ||
} | ||
}; | ||
ServiceClient.prototype._callWithToken = function(serviceName, verb, uri, data, additionalHeaders, correlationId) { | ||
ServiceClient.prototype._callWithToken = function (serviceName, verb, uri, data, additionalHeaders, correlationId) { | ||
const corrId = correlationId || correlator.getId(); | ||
if (!corrId) { | ||
this.config.logger.debug('Forcing NEW service token for service request.'); | ||
return this._callWithToken(serviceName, verb, uri, data, additionalHeaders, uuidv4()) | ||
return this._callWithToken(serviceName, verb, uri, data, additionalHeaders, uuidv4()); | ||
} | ||
return this._getServiceAccess().then((tokenDetails) => { | ||
const tokenHeader = { [this.config.originService.tokenKey]: tokenDetails.id_token }; | ||
const tokenHeader = {[this.config.originService.tokenKey]: tokenDetails.id_token}; | ||
const _additionalHeaders = extend(true, { }, additionalHeaders, tokenHeader); | ||
@@ -297,5 +326,5 @@ | ||
}); | ||
} | ||
}; | ||
ServiceClient.prototype._call = function(serviceName, verb, uri, data, additionalHeaders, startTime, tryCounter = 0) { | ||
ServiceClient.prototype._call = function (serviceName, verb, uri, data, additionalHeaders, startTime, tryCounter = 0) { | ||
let _data = data; | ||
@@ -310,3 +339,3 @@ | ||
const config = this.config; | ||
const cacheKey = serviceName + '/' + verb + '/' + _uri; | ||
const cacheKey = `${serviceName}/${verb}/${_uri}`; | ||
const headers = (config.context && config.context.headers) || { }; | ||
@@ -316,4 +345,5 @@ | ||
const tokenHeader = this.token && { [this.config.originService.tokenKey]: this.token.id_token }; | ||
const tokenHeader = this.token && {[this.config.originService.tokenKey]: this.token.id_token}; | ||
const localHeaders = extend(false, { }, headers, config.additionalHeaders, additionalHeaders, tokenHeader); | ||
/** @type {import('http').OutgoingHttpHeaders} */ | ||
const lowerHeaders = { }; | ||
@@ -327,3 +357,3 @@ | ||
if (!lowerHeaders['correlation-id']) { | ||
lowerHeaders['correlation-id'] = correlator.getId() || 'uuidv4:' + uuidv4(); | ||
lowerHeaders['correlation-id'] = correlator.getId() || `uuidv4:${uuidv4()}`; | ||
} | ||
@@ -339,3 +369,3 @@ | ||
config.logger.info('Calling service', { destService: serviceName, verb: _verb, uri: _uri, retry: tryCounter }); | ||
config.logger.info('Calling service', {destService: serviceName, verb: _verb, uri: _uri, retry: tryCounter}); | ||
@@ -345,3 +375,3 @@ if (_verb === 'POST' || _verb === 'PUT' || _verb === 'PATCH') { | ||
const dataIsBuffer = hasData && _data.constructor && typeof _data.constructor.isBuffer === 'function'; | ||
const serializeData = hasData && !dataIsBuffer && lowerHeaders['content-type'] === config.serializerContentType | ||
const serializeData = hasData && !dataIsBuffer && lowerHeaders['content-type'] === config.serializerContentType; | ||
@@ -367,6 +397,9 @@ if (serializeData) { | ||
if (cachedResult) { | ||
return cachedResult | ||
return cachedResult; | ||
} else { | ||
return this._discover(serviceName).then((service) => { | ||
return new Promise((resolve, reject) => { | ||
/** | ||
* @type {import('http').RequestOptions} | ||
*/ | ||
const options = { | ||
@@ -381,3 +414,3 @@ host: service.host, | ||
this.config.logger.trace('Call options', options); | ||
if (lowerHeaders['x-user-id-token'] && !JWS_REGEX.test(lowerHeaders['x-user-id-token'])) { | ||
if (lowerHeaders['x-user-id-token'] && !JWS_REGEX.test(lowerHeaders['x-user-id-token'].toString())) { | ||
this.config.logger.warn('Malformed x-user-id-token will be passed', { | ||
@@ -392,3 +425,10 @@ idToken: lowerHeaders['x-user-id-token'], | ||
const statusCode = parseInt(response.statusCode, 10); | ||
if (!response.statusCode) { | ||
const error = new Error('No status code received from service'); | ||
// @ts-ignore | ||
error.response = response; | ||
throw error; | ||
} | ||
const statusCode = response.statusCode; | ||
let contentType = response.headers['content-type']; | ||
@@ -401,3 +441,5 @@ const parserContentType = config.parserContentType; | ||
if (delimiterIndex > -1) {contentType = contentType.substr(0, delimiterIndex);} | ||
if (delimiterIndex > -1) { | ||
contentType = contentType.substr(0, delimiterIndex); | ||
} | ||
} | ||
@@ -415,3 +457,5 @@ | ||
resultData = buffer.toString('utf8'); | ||
} else {resultData = buffer;} | ||
} else { | ||
resultData = buffer; | ||
} | ||
} | ||
@@ -426,9 +470,10 @@ | ||
timeTaken: (timerRun[0] * 1000) + (timerRun[1] / 1e6) | ||
} | ||
config.logger.trace('Service call finished.', | ||
{ destService: serviceName, | ||
verb: _verb, | ||
uri: _uri, | ||
statusCode, | ||
timeTaken: responseObject.timeTaken }); | ||
}; | ||
config.logger.trace('Service call finished.', { | ||
destService: serviceName, | ||
verb: _verb, | ||
uri: _uri, | ||
statusCode, | ||
timeTaken: responseObject.timeTaken | ||
}); | ||
@@ -439,2 +484,3 @@ if (config.alwaysResolveResponses || (statusCode >= 100 && statusCode < 400)) { | ||
const error = new Error(JSON.stringify(resultData)); | ||
// @ts-ignore | ||
error.response = responseObject; | ||
@@ -445,3 +491,3 @@ | ||
} catch (error) { | ||
error.stack += '\n ' + stack.join('\n '); | ||
error.stack += `\n ${stack.join('\n ')}`; | ||
reject(error); | ||
@@ -462,2 +508,3 @@ } | ||
if (e.message === 'socket hang up' && tryCounter < 3) { | ||
/** @type {any} */ | ||
let timerRun = process.hrtime(timerStart); | ||
@@ -470,7 +517,9 @@ timerRun = ((timerRun[0] * 1000) + (timerRun[1] / 1e6)); | ||
`Retrying service ${serviceName} with ${_verb} ${_uri}`); | ||
resolve(this._call(serviceName, _verb, _uri, data, additionalHeaders, startTime, tryCounter + 1)) | ||
resolve(this._call(serviceName, _verb, _uri, data, additionalHeaders, startTime, tryCounter + 1)); | ||
} else { | ||
reject(new Error(e.message)); | ||
} | ||
} else {reject(new Error('The request failed with an unknown error.'));} | ||
} else { | ||
reject(new Error('The request failed with an unknown error.')); | ||
} | ||
}); | ||
@@ -487,3 +536,3 @@ | ||
}); | ||
} | ||
}; | ||
@@ -496,3 +545,3 @@ /** | ||
*/ | ||
ServiceClient.prototype.login = function(username, password) { | ||
ServiceClient.prototype.login = function (username, password) { | ||
return this._getServiceAccess(username, password).then(token => { | ||
@@ -504,3 +553,3 @@ const serviceClient = this.clone(); | ||
}); | ||
} | ||
}; | ||
@@ -521,3 +570,3 @@ /** | ||
*/ | ||
ServiceClient.prototype.get = function(serviceName, uri, forceServiceToken) { | ||
ServiceClient.prototype.get = function (serviceName, uri, forceServiceToken) { | ||
if (forceServiceToken) { | ||
@@ -528,3 +577,3 @@ return this._callWithToken(serviceName, 'GET', uri); | ||
return this._call(serviceName, 'GET', uri); | ||
} | ||
}; | ||
@@ -545,3 +594,3 @@ /** | ||
*/ | ||
ServiceClient.prototype.head = function(serviceName, uri, forceServiceToken) { | ||
ServiceClient.prototype.head = function (serviceName, uri, forceServiceToken) { | ||
if (forceServiceToken) { | ||
@@ -552,3 +601,3 @@ return this._callWithToken(serviceName, 'HEAD', uri).spread((result, response) => [response.headers, response]); | ||
return this._call(serviceName, 'HEAD', uri).spread((result, response) => [response.headers, response]); | ||
} | ||
}; | ||
@@ -572,7 +621,9 @@ /** | ||
*/ | ||
ServiceClient.prototype.post = function(serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) {return this._callWithToken(serviceName, 'POST', uri, data);} | ||
ServiceClient.prototype.post = function (serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) { | ||
return this._callWithToken(serviceName, 'POST', uri, data); | ||
} | ||
return this._call(serviceName, 'POST', uri, data); | ||
} | ||
}; | ||
@@ -596,7 +647,9 @@ /** | ||
*/ | ||
ServiceClient.prototype.put = function(serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) {return this._callWithToken(serviceName, 'PUT', uri, data);} | ||
ServiceClient.prototype.put = function (serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) { | ||
return this._callWithToken(serviceName, 'PUT', uri, data); | ||
} | ||
return this._call(serviceName, 'PUT', uri, data); | ||
} | ||
}; | ||
@@ -620,7 +673,9 @@ /** | ||
*/ | ||
ServiceClient.prototype.patch = function(serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) {return this._callWithToken(serviceName, 'PATCH', uri, data);} | ||
ServiceClient.prototype.patch = function (serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) { | ||
return this._callWithToken(serviceName, 'PATCH', uri, data); | ||
} | ||
return this._call(serviceName, 'PATCH', uri, data); | ||
} | ||
}; | ||
@@ -644,7 +699,9 @@ /** | ||
*/ | ||
ServiceClient.prototype.delete = function(serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) {return this._callWithToken(serviceName, 'DELETE', uri, data);} | ||
ServiceClient.prototype.delete = function (serviceName, uri, data, forceServiceToken) { | ||
if (forceServiceToken) { | ||
return this._callWithToken(serviceName, 'DELETE', uri, data); | ||
} | ||
return this._call(serviceName, 'DELETE', uri, data); | ||
} | ||
}; | ||
@@ -658,6 +715,6 @@ /** | ||
*/ | ||
ServiceClient.prototype.contextify = function(context) { | ||
ServiceClient.prototype.contextify = function (context) { | ||
extend(true, this.config.context, context); | ||
return this; | ||
} | ||
}; | ||
@@ -669,5 +726,5 @@ /** | ||
*/ | ||
ServiceClient.prototype.dispose = function() { | ||
ServiceClient.prototype.dispose = function () { | ||
return this.consul.then(consul => consul.dispose()).then(() => (this.consul = null)).catch(e => null); | ||
} | ||
}; | ||
@@ -684,12 +741,12 @@ /** | ||
*/ | ||
ServiceClient.prototype.set = function(key, value) { | ||
const config = extend(true, {}, this.config, { additionalHeaders: { [key]: value } }); | ||
ServiceClient.prototype.set = function (key, value) { | ||
const config = extend(true, {}, this.config, {additionalHeaders: {[key]: value}}); | ||
return new ServiceClient(config); | ||
} | ||
}; | ||
ServiceClient.prototype.setHeader = function(field, value) { | ||
ServiceClient.prototype.setHeader = function (field, value) { | ||
this.config.additionalHeaders[field.toLowerCase()] = value; | ||
// Object.defineProperty(this.config.additionalHeaders, key, value); | ||
return this; | ||
} | ||
}; | ||
@@ -701,5 +758,5 @@ /** | ||
*/ | ||
ServiceClient.prototype.clone = function(context) { | ||
ServiceClient.prototype.clone = function (context) { | ||
return (new ServiceClient(this.config)).contextify(context); | ||
} | ||
}; | ||
@@ -711,6 +768,5 @@ /** | ||
* @deprecated since 1.4.0 | ||
* @readonly | ||
* @enum {number} | ||
*/ | ||
ServiceClient.Mode = { | ||
ServiceClient.Mode = /** @readonly */ { | ||
/** Mode is invalid. */ | ||
@@ -724,3 +780,3 @@ None: 0, | ||
Debug: 3 | ||
} | ||
}; | ||
@@ -801,4 +857,4 @@ /** | ||
} | ||
} | ||
}; | ||
module.exports = ServiceClient; |
{ | ||
"name": "@opuscapita/service-client", | ||
"version": "1.6.1", | ||
"version": "1.6.4", | ||
"description": "Module for http based inter-service-communication for OpusCapitaBusinessNetwork.", | ||
@@ -34,5 +34,5 @@ "main": "index.js", | ||
"dependencies": { | ||
"@opuscapita/cache": "^1.2.0", | ||
"@opuscapita/config": "^3.1.12", | ||
"@opuscapita/logger": "^2.0.2", | ||
"@opuscapita/cache": "^1.3.0", | ||
"@opuscapita/config": "^3.1.13", | ||
"@opuscapita/logger": "^2.1.3", | ||
"bluebird": "^3.7.2", | ||
@@ -46,17 +46,17 @@ "bluebird-retry": "~0.11.0", | ||
"devDependencies": { | ||
"allure-commandline": "^2.13.8", | ||
"@opuscapita/eslint-config-opuscapita-bnapp": "^2.3.0", | ||
"allure-commandline": "^2.24.1", | ||
"babel-eslint": "10.1.0", | ||
"chai": "^4.3.4", | ||
"chai": "^4.3.10", | ||
"chai-as-promised": "^7.1.1", | ||
"chai-nock": "^1.3.0", | ||
"eslint": "^8.3.0", | ||
"eslint-config-opuscapita": "2.0.10", | ||
"eslint-plugin-react": "^7.27.1", | ||
"express": "^4.17.1", | ||
"mocha": "^9.1.3", | ||
"eslint": "^8.52.0", | ||
"eslint-plugin-react": "^7.33.2", | ||
"express": "^4.18.2", | ||
"mocha": "^9.2.2", | ||
"mocha-allure-reporter": "^1.4.0", | ||
"mocha-junit-reporter": "^2.0.2", | ||
"mocha-junit-reporter": "^2.2.1", | ||
"mocha-multi-reporters": "^1.5.1", | ||
"mock-require": "^3.0.3", | ||
"nock": "^13.2.1", | ||
"nock": "^13.3.6", | ||
"nyc": "^15.1.0", | ||
@@ -63,0 +63,0 @@ "sinon": "^12.0.1" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
41266
719
1
Updated@opuscapita/cache@^1.3.0
Updated@opuscapita/config@^3.1.13
Updated@opuscapita/logger@^2.1.3