@jambonz/speech-utils 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs/promises');
2
2
  const {noopLogger, makeSynthKey} = require('./utils');
3
- const EXPIRES = (process.env.JAMBONES_TTS_CACHE_DURATION_MINS || 4 * 60) * 60; // cache tts for 4 hours
3
+ const {JAMBONES_TTS_CACHE_DURATION_MINS} = require('./config');
4
+ const EXPIRES = JAMBONES_TTS_CACHE_DURATION_MINS;
4
5
 
5
6
  async function addFileToCache(client, logger, path,
6
7
  {account_sid, vendor, language, voice, deploymentId, engine, text}) {
package/lib/config.js ADDED
@@ -0,0 +1,20 @@
1
+ const JAMBONES_TTS_TRIM_SILENCE = process.env.JAMBONES_TTS_TRIM_SILENCE;
2
+ const JAMBONES_DISABLE_TTS_STREAMING = process.env.JAMBONES_DISABLE_TTS_STREAMING;
3
+
4
+ const JAMBONES_HTTP_PROXY_IP = process.env.JAMBONES_HTTP_PROXY_IP;
5
+ const JAMBONES_HTTP_PROXY_PORT = process.env.JAMBONES_HTTP_PROXY_PORT;
6
+ const JAMBONES_TTS_CACHE_DURATION_MINS = (parseInt(process.env.JAMBONES_TTS_CACHE_DURATION_MINS) || 4 * 60) * 60; // cache tts for 4 hours
7
+
8
+ const TMP_FOLDER = '/tmp';
9
+
10
+ const HTTP_TIMEOUT = 5000;
11
+
12
+ module.exports = {
13
+ JAMBONES_TTS_TRIM_SILENCE,
14
+ JAMBONES_DISABLE_TTS_STREAMING,
15
+ JAMBONES_HTTP_PROXY_IP,
16
+ JAMBONES_HTTP_PROXY_PORT,
17
+ JAMBONES_TTS_CACHE_DURATION_MINS,
18
+ TMP_FOLDER,
19
+ HTTP_TIMEOUT
20
+ };
@@ -2,7 +2,7 @@ const formurlencoded = require('form-urlencoded');
2
2
  const {Pool} = require('undici');
3
3
  const pool = new Pool('https://iam.cloud.ibm.com');
4
4
  const {makeIbmKey, noopLogger} = require('./utils');
5
- const { HTTP_TIMEOUT } = require('./constants');
5
+ const { HTTP_TIMEOUT } = require('./config');
6
6
  const debug = require('debug')('jambonz:realtimedb-helpers');
7
7
 
8
8
  async function getIbmAccessToken(client, logger, apiKey) {
@@ -2,7 +2,7 @@ const formurlencoded = require('form-urlencoded');
2
2
  const {Pool} = require('undici');
3
3
  const pool = new Pool('https://auth.crt.nuance.com');
4
4
  const {makeNuanceKey, makeBasicAuthHeader, noopLogger} = require('./utils');
5
- const { HTTP_TIMEOUT } = require('./constants');
5
+ const { HTTP_TIMEOUT } = require('./config');
6
6
  const debug = require('debug')('jambonz:realtimedb-helpers');
7
7
 
8
8
  async function getNuanceAccessToken(client, logger, clientId, secret, scope) {
@@ -9,7 +9,7 @@ const ttsGoogle = require('@google-cloud/text-to-speech');
9
9
  const { PollyClient, DescribeVoicesCommand } = require('@aws-sdk/client-polly');
10
10
  const getAwsAuthToken = require('./get-aws-sts-token');
11
11
  const {Pool} = require('undici');
12
- const { HTTP_TIMEOUT } = require('./constants');
12
+ const { HTTP_TIMEOUT } = require('./config');
13
13
  const verbioVoicePool = new Pool('https://us.rest.speechcenter.verbio.com');
14
14
 
15
15
  const getIbmVoices = async(client, logger, credentials) => {
@@ -1,6 +1,6 @@
1
1
  const {Pool} = require('undici');
2
2
  const { noopLogger, makeVerbioKey } = require('./utils');
3
- const { HTTP_TIMEOUT } = require('./constants');
3
+ const { HTTP_TIMEOUT } = require('./config');
4
4
  const pool = new Pool('https://auth.speechcenter.verbio.com:444');
5
5
  const debug = require('debug')('jambonz:realtimedb-helpers');
6
6
 
@@ -19,7 +19,8 @@ const {
19
19
  createNuanceClient,
20
20
  createKryptonClient,
21
21
  createRivaClient,
22
- noopLogger
22
+ noopLogger,
23
+ makeFilePath
23
24
  } = require('./utils');
24
25
  const getNuanceAccessToken = require('./get-nuance-access-token');
25
26
  const getVerbioAccessToken = require('./get-verbio-token');
@@ -37,8 +38,13 @@ const {
37
38
  const {SynthesizeSpeechRequest} = require('../stubs/riva/proto/riva_tts_pb');
38
39
  const {AudioEncoding} = require('../stubs/riva/proto/riva_audio_pb');
39
40
  const debug = require('debug')('jambonz:realtimedb-helpers');
40
- const EXPIRES = (process.env.JAMBONES_TTS_CACHE_DURATION_MINS || 4 * 60) * 60; // cache tts for 4 hours
41
- const TMP_FOLDER = '/tmp';
41
+ const {
42
+ JAMBONES_DISABLE_TTS_STREAMING,
43
+ JAMBONES_HTTP_PROXY_IP,
44
+ JAMBONES_HTTP_PROXY_PORT,
45
+ JAMBONES_TTS_CACHE_DURATION_MINS,
46
+ } = require('./config');
47
+ const EXPIRES = JAMBONES_TTS_CACHE_DURATION_MINS;
42
48
  const OpenAI = require('openai');
43
49
  const getAwsAuthToken = require('./get-aws-sts-token');
44
50
 
@@ -154,19 +160,7 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
154
160
  text
155
161
  });
156
162
  let filePath;
157
- if (['nuance', 'nvidia', 'verbio'].includes(vendor) ||
158
- (
159
- (process.env.JAMBONES_TTS_TRIM_SILENCE || !process.env.JAMBONES_DISABLE_TTS_STREAMING) &&
160
- ['microsoft', 'azure'].includes(vendor)
161
- ) ||
162
- (
163
- !process.env.JAMBONES_DISABLE_TTS_STREAMING &&
164
- ['elevenlabs', 'deepgram', 'rimelabs'].includes(vendor)
165
- )
166
- ) {
167
- filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.r8`;
168
- }
169
- else filePath = `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt || ''}`)}.mp3`;
163
+ filePath = makeFilePath(vendor, key, salt);
170
164
  debug(`synth key is ${key}`);
171
165
  let cached;
172
166
  if (!disableTtsCache) {
@@ -200,8 +194,7 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
200
194
  case 'microsoft':
201
195
  vendorLabel = 'microsoft';
202
196
  audioBuffer = await synthMicrosoft(logger, {credentials, stats, language, voice, text, deploymentId,
203
- filePath, renderForCaching, disableTtsStreaming});
204
- if (audioBuffer?.filePath) return audioBuffer;
197
+ filePath, renderForCaching, disableTtsStreaming});
205
198
  break;
206
199
  case 'nuance':
207
200
  model = model || 'enhanced';
@@ -219,25 +212,21 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
219
212
  case 'elevenlabs':
220
213
  audioBuffer = await synthElevenlabs(logger, {
221
214
  credentials, options, stats, language, voice, text, renderForCaching, disableTtsStreaming, filePath
222
- });
223
- if (audioBuffer?.filePath) return audioBuffer;
215
+ });
224
216
  break;
225
217
  case 'playht':
226
218
  audioBuffer = await synthPlayHT(logger, {
227
219
  credentials, options, stats, language, voice, text, renderForCaching, disableTtsStreaming, filePath
228
- });
229
- if (audioBuffer?.filePath) return audioBuffer;
220
+ });
230
221
  break;
231
222
  case 'rimelabs':
232
223
  audioBuffer = await synthRimelabs(logger, {
233
224
  credentials, options, stats, language, voice, text, renderForCaching, disableTtsStreaming, filePath
234
- });
235
- if (audioBuffer?.filePath) return audioBuffer;
225
+ });
236
226
  break;
237
227
  case 'whisper':
238
228
  audioBuffer = await synthWhisper(logger, {
239
- credentials, stats, voice, text, renderForCaching, disableTtsStreaming});
240
- if (audioBuffer?.filePath) return audioBuffer;
229
+ credentials, stats, voice, text, renderForCaching, disableTtsStreaming});
241
230
  break;
242
231
  case 'verbio':
243
232
  audioBuffer = await synthVerbio(client, logger, {
@@ -246,8 +235,7 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
246
235
  break;
247
236
  case 'deepgram':
248
237
  audioBuffer = await synthDeepgram(logger, {credentials, stats, model, text,
249
- renderForCaching, disableTtsStreaming});
250
- if (audioBuffer?.filePath) return audioBuffer;
238
+ renderForCaching, disableTtsStreaming});
251
239
  break;
252
240
  case vendor.startsWith('custom') ? vendor : 'cant_match_value':
253
241
  ({ audioBuffer, filePath } = await synthCustomVendor(logger,
@@ -256,6 +244,7 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
256
244
  default:
257
245
  assert(`synthAudio: unsupported speech vendor ${vendor}`);
258
246
  }
247
+ if('filePath' in audioBuffer) return audioBuffer;
259
248
  const diff = process.hrtime(startAt);
260
249
  const time = diff[0] * 1e3 + diff[1] * 1e-6;
261
250
  rtt = time.toFixed(0);
@@ -454,7 +443,7 @@ const synthMicrosoft = async(logger, {
454
443
  content = `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="${language}"><voice name="${voice}">${words}</voice></speak>`;
455
444
  logger.info({content}, 'synthMicrosoft');
456
445
  }
457
- if (!process.env.JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
446
+ if (!JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
458
447
  let params = '';
459
448
  params += `{api_key=${apiKey}`;
460
449
  params += `,language=${language}`;
@@ -464,8 +453,8 @@ const synthMicrosoft = async(logger, {
464
453
  if (region) params += `,region=${region}`;
465
454
  if (custom_tts_endpoint) params += `,endpointId=${custom_tts_endpoint}`;
466
455
  if (custom_tts_endpoint_url) params += `,endpoint=${custom_tts_endpoint_url}`;
467
- if (process.env.JAMBONES_HTTP_PROXY_IP) params += `,http_proxy_ip=${process.env.JAMBONES_HTTP_PROXY_IP}`;
468
- if (process.env.JAMBONES_HTTP_PROXY_PORT) params += `,http_proxy_port=${process.env.JAMBONES_HTTP_PROXY_PORT}`;
456
+ if (JAMBONES_HTTP_PROXY_IP) params += `,http_proxy_ip=${JAMBONES_HTTP_PROXY_IP}`;
457
+ if (JAMBONES_HTTP_PROXY_PORT) params += `,http_proxy_port=${JAMBONES_HTTP_PROXY_PORT}`;
469
458
  params += '}';
470
459
  return {
471
460
  filePath: `say:${params}${content.replace(/\n/g, ' ')}`,
@@ -494,10 +483,10 @@ const synthMicrosoft = async(logger, {
494
483
  SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm :
495
484
  SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
496
485
 
497
- if (process.env.JAMBONES_HTTP_PROXY_IP && process.env.JAMBONES_HTTP_PROXY_PORT) {
486
+ if (JAMBONES_HTTP_PROXY_IP && JAMBONES_HTTP_PROXY_PORT) {
498
487
  logger.debug(
499
- `synthMicrosoft: using proxy ${process.env.JAMBONES_HTTP_PROXY_IP}:${process.env.JAMBONES_HTTP_PROXY_PORT}`);
500
- speechConfig.setProxy(process.env.JAMBONES_HTTP_PROXY_IP, process.env.JAMBONES_HTTP_PROXY_PORT);
488
+ `synthMicrosoft: using proxy ${JAMBONES_HTTP_PROXY_IP}:${JAMBONES_HTTP_PROXY_PORT}`);
489
+ speechConfig.setProxy(JAMBONES_HTTP_PROXY_IP, JAMBONES_HTTP_PROXY_PORT);
501
490
  }
502
491
  const synthesizer = new SpeechSynthesizer(speechConfig);
503
492
 
@@ -683,7 +672,7 @@ const synthElevenlabs = async(logger, {
683
672
  const opts = !!options && Object.keys(options).length !== 0 ? options : JSON.parse(credOpts || '{}');
684
673
 
685
674
  /* default to using the streaming interface, unless disabled by env var OR we want just a cache file */
686
- if (!process.env.JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
675
+ if (!JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
687
676
  let params = '';
688
677
  params += `{api_key=${api_key}`;
689
678
  params += ',vendor=elevenlabs';
@@ -736,7 +725,7 @@ const synthPlayHT = async(logger, {
736
725
  const opts = !!options && Object.keys(options).length !== 0 ? options : JSON.parse(credOpts || '{}');
737
726
 
738
727
  /* default to using the streaming interface, unless disabled by env var OR we want just a cache file */
739
- if (!process.env.JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
728
+ if (!JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
740
729
  let params = '';
741
730
  params += `{api_key=${api_key}`;
742
731
  params += `,user_id=${user_id}`;
@@ -791,7 +780,7 @@ const synthRimelabs = async(logger, {
791
780
  const opts = !!options && Object.keys(options).length !== 0 ? options : JSON.parse(credOpts || '{}');
792
781
 
793
782
  /* default to using the streaming interface, unless disabled by env var OR we want just a cache file */
794
- if (!process.env.JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
783
+ if (!JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
795
784
  let params = '';
796
785
  params += `{api_key=${api_key}`;
797
786
  params += `,model_id=${model_id}`;
@@ -873,7 +862,7 @@ const synthVerbio = async(client, logger, {credentials, stats, voice, text, rend
873
862
  const synthWhisper = async(logger, {credentials, stats, voice, text, renderForCaching, disableTtsStreaming}) => {
874
863
  const {api_key, model_id, baseURL, timeout, speed} = credentials;
875
864
  /* if the env is set to stream then bag out, unless we are specifically rendering to generate a cache file */
876
- if (!process.env.JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
865
+ if (!JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
877
866
  let params = '';
878
867
  params += `{api_key=${api_key}`;
879
868
  params += `,model_id=${model_id}`;
@@ -912,7 +901,7 @@ const synthWhisper = async(logger, {credentials, stats, voice, text, renderForCa
912
901
 
913
902
  const synthDeepgram = async(logger, {credentials, stats, model, text, renderForCaching, disableTtsStreaming}) => {
914
903
  const {api_key} = credentials;
915
- if (!process.env.JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
904
+ if (!JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
916
905
  let params = '';
917
906
  params += `{api_key=${api_key}`;
918
907
  params += ',vendor=deepgram';
package/lib/utils.js CHANGED
@@ -6,7 +6,7 @@ const pool = new Pool('https://auth.crt.nuance.com');
6
6
  const NUANCE_AUTH_ENDPOINT = 'tts.api.nuance.com:443';
7
7
  const grpc = require('@grpc/grpc-js');
8
8
  const formurlencoded = require('form-urlencoded');
9
- const { HTTP_TIMEOUT } = require('./constants');
9
+ const { JAMBONES_DISABLE_TTS_STREAMING, JAMBONES_TTS_TRIM_SILENCE, TMP_FOLDER, HTTP_TIMEOUT } = require('./config');
10
10
 
11
11
  const debug = require('debug')('jambonz:realtimedb-helpers');
12
12
  /**
@@ -19,7 +19,44 @@ const debug = require('debug')('jambonz:realtimedb-helpers');
19
19
  function makeSynthKey({account_sid = '', vendor, language, voice, engine = '', text}) {
20
20
  const hash = crypto.createHash('sha1');
21
21
  hash.update(`${language}:${vendor}:${voice}:${engine}:${text}`);
22
- return `tts${account_sid ? (':' + account_sid) : ''}:${hash.digest('hex')}`;
22
+ const hexHashKey = hash.digest('hex');
23
+ const accountKey = account_sid ? `:${account_sid}` : '';
24
+ const namespace = vendor.startsWith('custom') ? vendor : getFileExtension(vendor);
25
+ const key = `tts${accountKey}:${namespace}:${hexHashKey}`;
26
+ return key;
27
+ }
28
+
29
+ function makeFilePath(vendor, key, salt = '') {
30
+ const extension = getFileExtension(vendor);
31
+ return `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt}`)}.${extension}`;
32
+ }
33
+
34
+ function getFileExtension(vendor) {
35
+ const mp3Extension = 'mp3';
36
+ const r8Extension = 'r8';
37
+
38
+ switch (vendor) {
39
+ case 'azure':
40
+ case 'microsoft':
41
+ if (!JAMBONES_DISABLE_TTS_STREAMING || JAMBONES_TTS_TRIM_SILENCE) {
42
+ return r8Extension;
43
+ } else {
44
+ return mp3Extension;
45
+ }
46
+ case 'deepgram':
47
+ case 'elevenlabs':
48
+ case 'rimlabs':
49
+ if (!JAMBONES_DISABLE_TTS_STREAMING) {
50
+ return r8Extension;
51
+ } else {
52
+ return mp3Extension;
53
+ }
54
+ case 'nuance':
55
+ case 'nvidia':
56
+ return r8Extension;
57
+ default:
58
+ return mp3Extension;
59
+ }
23
60
  }
24
61
 
25
62
  const noopLogger = {
@@ -130,5 +167,6 @@ module.exports = {
130
167
  createRivaClient,
131
168
  makeBasicAuthHeader,
132
169
  NUANCE_AUTH_ENDPOINT,
133
- noopLogger
170
+ noopLogger,
171
+ makeFilePath
134
172
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/speech-utils",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "TTS-related speech utilities for jambonz",
5
5
  "main": "index.js",
6
6
  "author": "Dave Horton",
@@ -12,6 +12,7 @@
12
12
  "test": "NODE_ENV=test node test/ ",
13
13
  "coverage": "nyc --reporter html --report-dir ./coverage npm run test",
14
14
  "jslint": "eslint index.js lib",
15
+ "jslint:fix": "eslint --fix '**/*.js'",
15
16
  "build": "./build_stubs.sh"
16
17
  },
17
18
  "repository": {
@@ -62,9 +62,9 @@ function deserialize_nuance_tts_v1_UnarySynthesisResponse(buffer_arg) {
62
62
 
63
63
  //
64
64
  // The Synthesizer service offers these functionalities:
65
- // - GetVoices: Queries the list of available voices, with filters to reduce the search space.
66
- // - Synthesize: Synthesizes audio from input text and parameters, and returns an audio stream.
67
- // - UnarySynthesize: Synthesizes audio from input text and parameters, and returns a single audio response.
65
+ // - GetVoices: Queries the list of available voices, with filters to reduce the search space.
66
+ // - Synthesize: Synthesizes audio from input text and parameters, and returns an audio stream.
67
+ // - UnarySynthesize: Synthesizes audio from input text and parameters, and returns a single audio response.
68
68
  var SynthesizerService = exports.SynthesizerService = {
69
69
  getVoices: {
70
70
  path: '/nuance.tts.v1.Synthesizer/GetVoices',
@@ -1 +1 @@
1
- // GENERATED CODE -- NO SERVICES IN PROTO
1
+ // GENERATED CODE -- NO SERVICES IN PROTO
@@ -57,7 +57,7 @@ function deserialize_nvidia_riva_tts_SynthesizeSpeechResponse(buffer_arg) {
57
57
  var RivaSpeechSynthesisService = exports.RivaSpeechSynthesisService = {
58
58
  // Used to request text-to-speech from the service. Submit a request containing the
59
59
  // desired text and configuration, and receive audio bytes in the requested format.
60
- synthesize: {
60
+ synthesize: {
61
61
  path: '/nvidia.riva.tts.RivaSpeechSynthesis/Synthesize',
62
62
  requestStream: false,
63
63
  responseStream: false,
@@ -69,9 +69,9 @@ synthesize: {
69
69
  responseDeserialize: deserialize_nvidia_riva_tts_SynthesizeSpeechResponse,
70
70
  },
71
71
  // Used to request text-to-speech returned via stream as it becomes available.
72
- // Submit a SynthesizeSpeechRequest with desired text and configuration,
73
- // and receive stream of bytes in the requested format.
74
- synthesizeOnline: {
72
+ // Submit a SynthesizeSpeechRequest with desired text and configuration,
73
+ // and receive stream of bytes in the requested format.
74
+ synthesizeOnline: {
75
75
  path: '/nvidia.riva.tts.RivaSpeechSynthesis/SynthesizeOnline',
76
76
  requestStream: false,
77
77
  responseStream: true,
@@ -83,7 +83,7 @@ synthesizeOnline: {
83
83
  responseDeserialize: deserialize_nvidia_riva_tts_SynthesizeSpeechResponse,
84
84
  },
85
85
  // Enables clients to request the configuration of the current Synthesize service, or a specific model within the service.
86
- getRivaSynthesisConfig: {
86
+ getRivaSynthesisConfig: {
87
87
  path: '/nvidia.riva.tts.RivaSpeechSynthesis/GetRivaSynthesisConfig',
88
88
  requestStream: false,
89
89
  responseStream: false,
package/test/synth.js CHANGED
@@ -789,8 +789,19 @@ test('TTS Cache tests', async(t) => {
789
789
  t.ok(error, `error returned when specified key was not found`);
790
790
 
791
791
  // make sure other tts keys are still there
792
- const cached = (await client.keys('tts:*')).length;
793
- t.ok(cached >= 1, `successfully kept all non-specified tts records in cache`);
792
+ const cached = await client.keys('tts:*')
793
+ t.ok(cached.length >= 1, `successfully kept all non-specified tts records in cache`);
794
+
795
+ // retrieve keys from cache and check the key contains the file extension
796
+ let key = cached[0];
797
+ t.ok(key.includes('mp3'), `tts cache extension shoult be part of the key and equal mp3`);
798
+
799
+ process.env.VG_TRIM_TTS_SILENCE = 'true';
800
+ await client.set(makeSynthKey({ vendor: 'azure' }), 'value');
801
+
802
+ const r8Keys = await client.keys('tts:r8*');
803
+ key = r8Keys[0];
804
+ t.ok(key.includes('r8'), `tts cache extension shoult be part of the key and equal r8`);
794
805
 
795
806
  } catch (err) {
796
807
  console.error(JSON.stringify(err));
package/lib/constants.js DELETED
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- HTTP_TIMEOUT: 5000
3
- };