@mojaloop/sdk-scheme-adapter 12.2.1 → 12.3.0

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.
Files changed (37) hide show
  1. package/.env.example +1 -1
  2. package/CHANGELOG.md +22 -0
  3. package/audit-resolve.json +71 -1
  4. package/package.json +4 -1
  5. package/src/ControlAgent/index.js +2 -3
  6. package/src/ControlServer/index.js +2 -2
  7. package/src/InboundServer/index.js +7 -7
  8. package/src/InboundServer/middlewares.js +2 -2
  9. package/src/OutboundServer/handlers.js +3 -0
  10. package/src/OutboundServer/index.js +10 -11
  11. package/src/config.js +31 -14
  12. package/src/index.js +198 -10
  13. package/src/lib/cache.js +110 -52
  14. package/src/lib/metrics.js +148 -0
  15. package/src/lib/model/AccountsModel.js +4 -1
  16. package/src/lib/model/Async2SyncModel.js +4 -1
  17. package/src/lib/model/InboundTransfersModel.js +4 -1
  18. package/src/lib/model/OutboundBulkQuotesModel.js +4 -1
  19. package/src/lib/model/OutboundBulkTransfersModel.js +4 -1
  20. package/src/lib/model/OutboundRequestToPayModel.js +4 -1
  21. package/src/lib/model/OutboundRequestToPayTransferModel.js +4 -1
  22. package/src/lib/model/OutboundTransfersModel.js +61 -1
  23. package/src/lib/model/ProxyModel/index.js +4 -2
  24. package/src/lib/validate.js +2 -2
  25. package/test/__mocks__/redis.js +4 -0
  26. package/test/config/integration.env +5 -0
  27. package/test/unit/ControlServer/index.js +3 -3
  28. package/test/unit/InboundServer.test.js +1 -1
  29. package/test/unit/api/utils.js +4 -1
  30. package/test/unit/config.test.js +3 -3
  31. package/test/unit/data/defaultConfig.json +23 -7
  32. package/test/unit/index.test.js +95 -4
  33. package/test/unit/lib/model/OutboundTransfersModel.test.js +37 -1
  34. package/test/unit/lib/model/data/defaultConfig.json +24 -9
  35. package/src/lib/api/index.js +0 -12
  36. package/src/lib/randomphrase/index.js +0 -21
  37. package/src/lib/randomphrase/words.json +0 -3397
package/.env.example CHANGED
@@ -141,7 +141,7 @@ ALLOW_TRANSFER_WITHOUT_QUOTE=false
141
141
  # To enable request for notification on fulfiled transfer
142
142
  RESERVE_NOTIFICATION=true
143
143
 
144
- # resources API versions should be string in format: "resouceOneName=1.0,resourceTwoName=1.1"
144
+ # resources API versions should be string in format: "resourceOneName=1.0,resourceTwoName=1.1"
145
145
  RESOURCE_VERSIONS="transfers=1.1,participants=1.1"
146
146
 
147
147
  # Management API websocket connection settings.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,26 @@
1
1
  # Changelog: [mojaloop/thirdparty-api-svc](https://github.com/mojaloop/thirdparty-api-svc)
2
+ ## [12.3.0](https://github.com/mojaloop/sdk-scheme-adapter/compare/v12.2.3...v12.3.0) (2022-05-04)
3
+
4
+
5
+ ### Features
6
+
7
+ * port over prom client metrics ([#312](https://github.com/mojaloop/sdk-scheme-adapter/issues/312)) ([8de66d5](https://github.com/mojaloop/sdk-scheme-adapter/commit/8de66d505b94cddb5e3b8e857ae491f85058d395))
8
+ * pull in live reconfiguration logic ([#313](https://github.com/mojaloop/sdk-scheme-adapter/issues/313)) ([ae5648a](https://github.com/mojaloop/sdk-scheme-adapter/commit/ae5648a500eaab80804db0298facc1e352482fb9))
9
+
10
+ ### [12.2.3](https://github.com/mojaloop/sdk-scheme-adapter/compare/v12.2.2...v12.2.3) (2022-04-26)
11
+
12
+
13
+ ### Refactors
14
+
15
+ * change config structure and remove unused code ([#311](https://github.com/mojaloop/sdk-scheme-adapter/issues/311)) ([c2e69e7](https://github.com/mojaloop/sdk-scheme-adapter/commit/c2e69e751daf7ad74ae213e8987946fdb84dd427))
16
+
17
+ ### [12.2.2](https://github.com/mojaloop/sdk-scheme-adapter/compare/v12.2.1...v12.2.2) (2022-04-22)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * make management url config option optional ([#310](https://github.com/mojaloop/sdk-scheme-adapter/issues/310)) ([93c4048](https://github.com/mojaloop/sdk-scheme-adapter/commit/93c4048d5a604be81ce90365ff3f9cd42b531fef))
23
+
2
24
  ### [12.2.1](https://github.com/mojaloop/sdk-scheme-adapter/compare/v12.2.0...v12.2.1) (2022-04-21)
3
25
 
4
26
 
@@ -434,8 +434,78 @@
434
434
  "decision": "ignore",
435
435
  "madeAt": 1650459475376,
436
436
  "expiresAt": 1653051469252
437
+ },
438
+ "1070245|@mojaloop/central-services-shared>@mojaloop/event-sdk>moment": {
439
+ "decision": "ignore",
440
+ "madeAt": 1651072086111,
441
+ "expiresAt": 1653664079920
442
+ },
443
+ "1070245|@mojaloop/event-sdk>moment": {
444
+ "decision": "ignore",
445
+ "madeAt": 1651072086111,
446
+ "expiresAt": 1653664079920
447
+ },
448
+ "1070030|@mojaloop/central-services-shared>@mojaloop/event-sdk>moment>shins>markdown-it": {
449
+ "decision": "ignore",
450
+ "madeAt": 1651072088351,
451
+ "expiresAt": 1653664079920
452
+ },
453
+ "1070030|widdershins>markdown-it": {
454
+ "decision": "ignore",
455
+ "madeAt": 1651072088351,
456
+ "expiresAt": 1653664079920
457
+ },
458
+ "1068154|@mojaloop/central-services-shared>@mojaloop/event-sdk>moment>shins>markdown-it>sanitize-html": {
459
+ "decision": "ignore",
460
+ "madeAt": 1651072089481,
461
+ "expiresAt": 1653664079920
462
+ },
463
+ "1068155|@mojaloop/central-services-shared>@mojaloop/event-sdk>moment>shins>markdown-it>sanitize-html": {
464
+ "decision": "ignore",
465
+ "madeAt": 1651072090420,
466
+ "expiresAt": 1653664079920
467
+ },
468
+ "1070250|ansi-regex": {
469
+ "decision": "ignore",
470
+ "madeAt": 1651072091389,
471
+ "expiresAt": 1653664079920
472
+ },
473
+ "1070252|ansi-regex": {
474
+ "decision": "ignore",
475
+ "madeAt": 1651072092335,
476
+ "expiresAt": 1653664079920
477
+ },
478
+ "1070256|ejs": {
479
+ "decision": "ignore",
480
+ "madeAt": 1651072093304,
481
+ "expiresAt": 1653664079920
482
+ },
483
+ "1067536|json-pointer": {
484
+ "decision": "ignore",
485
+ "madeAt": 1651072094695,
486
+ "expiresAt": 1653664079920
487
+ },
488
+ "1067553|swagger2openapi>better-ajv-errors>jsonpointer": {
489
+ "decision": "ignore",
490
+ "madeAt": 1651072095680,
491
+ "expiresAt": 1653664079920
492
+ },
493
+ "1067946|swagger2openapi>better-ajv-errors>jsonpointer>oas-validator>ajv": {
494
+ "decision": "ignore",
495
+ "madeAt": 1651072096735,
496
+ "expiresAt": 1653664079920
497
+ },
498
+ "1068310|widdershins>markdown-it>yargs>yargs-parser": {
499
+ "decision": "ignore",
500
+ "madeAt": 1651072098082,
501
+ "expiresAt": 1653664079920
502
+ },
503
+ "1070260|@mojaloop/central-services-shared>shins>sanitize-html": {
504
+ "decision": "ignore",
505
+ "madeAt": 1651249549067,
506
+ "expiresAt": 1653841542147
437
507
  }
438
508
  },
439
509
  "rules": {},
440
510
  "version": 1
441
- }
511
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mojaloop/sdk-scheme-adapter",
3
- "version": "12.2.1",
3
+ "version": "12.3.0",
4
4
  "description": "An adapter for connecting to Mojaloop API enabled switches.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -74,10 +74,13 @@
74
74
  "json-schema-ref-parser": "^9.0.9",
75
75
  "koa": "^2.13.1",
76
76
  "koa-body": "^4.2.0",
77
+ "lodash": "^4.17.21",
77
78
  "module-alias": "^2.2.2",
78
79
  "oauth2-server": "^4.0.0-dev.2",
79
80
  "openapi-jsonschema-parameters": "^9.3.0",
81
+ "prom-client": "^12.0.0",
80
82
  "promise-timeout": "^1.3.0",
83
+ "random-word-slugs": "^0.1.6",
81
84
  "redis": "^3.1.2",
82
85
  "uuidv4": "^6.2.12",
83
86
  "ws": "^7.5.5"
@@ -25,8 +25,7 @@
25
25
  const assert = require('assert').strict;
26
26
  const ws = require('ws');
27
27
  const jsonPatch = require('fast-json-patch');
28
- const randomPhrase = require('~/lib/randomphrase');
29
-
28
+ const { generateSlug } = require('random-word-slugs');
30
29
 
31
30
  /**************************************************************************
32
31
  * The message protocol messages, verbs, and errors
@@ -75,7 +74,7 @@ const deserialise = (msg) => {
75
74
  });
76
75
  };
77
76
 
78
- const buildMsg = (verb, msg, data, id = randomPhrase()) => serialise({
77
+ const buildMsg = (verb, msg, data, id = generateSlug(4)) => serialise({
79
78
  verb,
80
79
  msg,
81
80
  data,
@@ -26,8 +26,8 @@ const assert = require('assert').strict;
26
26
 
27
27
  const ws = require('ws');
28
28
  const jsonPatch = require('fast-json-patch');
29
+ const { generateSlug } = require('random-word-slugs');
29
30
 
30
- const randomPhrase = require('~/lib/randomphrase');
31
31
 
32
32
  /**************************************************************************
33
33
  * The message protocol messages, verbs, and errors
@@ -76,7 +76,7 @@ const deserialise = (msg) => {
76
76
  });
77
77
  };
78
78
 
79
- const buildMsg = (verb, msg, data, id = randomPhrase()) => serialise({
79
+ const buildMsg = (verb, msg, data, id = generateSlug(4)) => serialise({
80
80
  verb,
81
81
  msg,
82
82
  data,
@@ -35,7 +35,7 @@ class InboundApi extends EventEmitter {
35
35
  auth: new WSO2Auth({
36
36
  ...conf.wso2.auth,
37
37
  logger,
38
- tlsCreds: conf.mutualTLS.outboundRequests.enabled && conf.mutualTLS.outboundRequests.creds,
38
+ tlsCreds: conf.inbound.tls.mutualTLS.enabled && conf.inbound.tls.creds,
39
39
  }),
40
40
  retryWso2AuthFailureTimes: conf.wso2.requestAuthFailureRetryTimes,
41
41
  };
@@ -160,8 +160,8 @@ class InboundServer extends EventEmitter {
160
160
  this.emit('error', ...args);
161
161
  });
162
162
  this._server = this._createServer(
163
- conf.mutualTLS.inboundRequests.enabled,
164
- conf.mutualTLS.inboundRequests.creds,
163
+ conf.inbound.tls.mutualTLS.enabled,
164
+ conf.inbound.tls.creds,
165
165
  this._api.callback()
166
166
  );
167
167
  }
@@ -172,8 +172,8 @@ class InboundServer extends EventEmitter {
172
172
  const apiSpecs = yaml.load(fs.readFileSync(specPath));
173
173
  await this._validator.initialise(apiSpecs);
174
174
  await this._api.start();
175
- await new Promise((resolve) => this._server.listen(this._conf.inboundServerPort, resolve));
176
- this._logger.log(`Serving inbound API on port ${this._conf.inboundServerPort}`);
175
+ await new Promise((resolve) => this._server.listen(this._conf.inbound.port, resolve));
176
+ this._logger.log(`Serving outbound API on port ${this._conf.inbound.port}`);
177
177
  }
178
178
 
179
179
  async stop() {
@@ -194,7 +194,7 @@ class InboundServer extends EventEmitter {
194
194
  // are subclasses of net.Server. This wasn't considered as a requirement at the time of
195
195
  // writing.
196
196
  assert(
197
- this._conf.mutualTLS.inboundRequests.enabled === conf.mutualTLS.inboundRequests.enabled,
197
+ this._conf.inbound.tls.mutualTLS.enabled === conf.inbound.tls.mutualTLS.enabled,
198
198
  'Cannot live-restart an HTTPS server as HTTP or vice versa',
199
199
  );
200
200
  const newApi = new InboundApi(conf, logger, cache, this._validator);
@@ -207,7 +207,7 @@ class InboundServer extends EventEmitter {
207
207
  conf.inbound.tls.creds,
208
208
  this._conf.inbound.tls.creds
209
209
  );
210
- if (this._conf.mutualTLS.inboundRequests.enabled && tlsCredsChanged) {
210
+ if (this._conf.inbound.tls.mutualTLS.enabled && tlsCredsChanged) {
211
211
  this._server.setSecureContext(conf.inbound.tls.creds);
212
212
  }
213
213
  this._server.removeAllListeners('request');
@@ -10,7 +10,7 @@
10
10
 
11
11
  const coBody = require('co-body');
12
12
 
13
- const randomPhrase = require('../lib/randomphrase');
13
+ const { generateSlug } = require('random-word-slugs');
14
14
  const { Jws, Errors } = require('@mojaloop/sdk-standard-components');
15
15
  const {
16
16
  parseAcceptHeader,
@@ -157,7 +157,7 @@ const cacheRequest = (cache) => async (ctx, next) => {
157
157
  * @return {Function}
158
158
  */
159
159
  const createRequestIdGenerator = () => async (ctx, next) => {
160
- ctx.request.id = randomPhrase();
160
+ ctx.request.id = generateSlug(4);
161
161
  await next();
162
162
  };
163
163
 
@@ -112,6 +112,7 @@ const postTransfers = async (ctx) => {
112
112
  cache: ctx.state.cache,
113
113
  logger: ctx.state.logger,
114
114
  wso2: ctx.state.wso2,
115
+ metricsClient: ctx.state.metricsClient,
115
116
  });
116
117
 
117
118
  // initialize the transfer model and start it running
@@ -144,6 +145,7 @@ const getTransfers = async (ctx) => {
144
145
  cache: ctx.state.cache,
145
146
  logger: ctx.state.logger,
146
147
  wso2: ctx.state.wso2,
148
+ metricsClient: ctx.state.metricsClient,
147
149
  });
148
150
 
149
151
  // initialize the transfer model and start it running
@@ -172,6 +174,7 @@ const putTransfers = async (ctx) => {
172
174
  cache: ctx.state.cache,
173
175
  logger: ctx.state.logger,
174
176
  wso2: ctx.state.wso2,
177
+ metricsClient: ctx.state.metricsClient,
175
178
  });
176
179
 
177
180
  // TODO: check the incoming body to reject party or quote when requested to do so
@@ -28,18 +28,19 @@ const middlewares = require('./middlewares');
28
28
  const endpointRegex = /\/.*/g;
29
29
 
30
30
  class OutboundApi extends EventEmitter {
31
- constructor(conf, logger, cache, validator) {
31
+ constructor(conf, logger, cache, validator, metricsClient) {
32
32
  super({ captureExceptions: true });
33
33
  this._logger = logger;
34
34
  this._api = new Koa();
35
35
  this._conf = conf;
36
36
  this._cache = cache;
37
+ this._metricsClient = metricsClient;
37
38
 
38
39
  this._wso2 = {
39
40
  auth: new WSO2Auth({
40
41
  ...this._conf.wso2.auth,
41
42
  logger: this._logger,
42
- tlsCreds: this._conf.mutualTLS.outboundRequests.enabled && this._conf.mutualTLS.outboundRequests.creds,
43
+ tlsCreds: this._conf.outbound.tls.mutualTLS.enabled && this._conf.outbound.tls.creds,
43
44
  }),
44
45
  retryWso2AuthFailureTimes: conf.wso2.requestAuthFailureRetryTimes,
45
46
  };
@@ -54,7 +55,7 @@ class OutboundApi extends EventEmitter {
54
55
  this._api.use(middlewares.createErrorHandler(this._logger));
55
56
  this._api.use(middlewares.createRequestIdGenerator());
56
57
  this._api.use(koaBody()); // outbound always expects application/json
57
- this._api.use(middlewares.applyState({ cache, wso2: this._wso2, conf }));
58
+ this._api.use(middlewares.applyState({ cache, wso2: this._wso2, conf, metricsClient }));
58
59
  this._api.use(middlewares.createLogger(this._logger));
59
60
 
60
61
  //Note that we strip off any path on peerEndpoint config after the origin.
@@ -67,7 +68,7 @@ class OutboundApi extends EventEmitter {
67
68
  proxyConfig: conf.proxyConfig,
68
69
  logger: this._logger,
69
70
  wso2Auth: this._wso2.auth,
70
- tls: conf.mutualTLS.outboundRequests,
71
+ tls: conf.outbound.tls,
71
72
  }));
72
73
  }
73
74
 
@@ -91,7 +92,7 @@ class OutboundApi extends EventEmitter {
91
92
  }
92
93
 
93
94
  class OutboundServer extends EventEmitter {
94
- constructor(conf, logger, cache) {
95
+ constructor(conf, logger, cache, metricsClient) {
95
96
  super({ captureExceptions: true });
96
97
  this._validator = new Validate();
97
98
  this._conf = conf;
@@ -101,7 +102,8 @@ class OutboundServer extends EventEmitter {
101
102
  conf,
102
103
  this._logger.push({ component: 'api' }),
103
104
  cache,
104
- this._validator
105
+ this._validator,
106
+ metricsClient
105
107
  );
106
108
  this._api.on('error', (...args) => {
107
109
  this.emit('error', ...args);
@@ -111,14 +113,11 @@ class OutboundServer extends EventEmitter {
111
113
 
112
114
  async start() {
113
115
  await this._api.start();
114
-
115
116
  const specPath = path.join(__dirname, 'api.yaml');
116
117
  const apiSpecs = yaml.load(fs.readFileSync(specPath));
117
118
  await this._validator.initialise(apiSpecs);
118
-
119
- await new Promise((resolve) => this._server.listen(this._conf.outboundServerPort, resolve));
120
-
121
- this._logger.log(`Serving outbound API on port ${this._conf.outboundServerPort}`);
119
+ await new Promise((resolve) => this._server.listen(this._conf.outbound.port, resolve));
120
+ this._logger.log(`Serving outbound API on port ${this._conf.outbound.port}`);
122
121
  }
123
122
 
124
123
  async stop() {
package/src/config.js CHANGED
@@ -22,8 +22,8 @@ function getFileContent (path) {
22
22
  }
23
23
 
24
24
  /**
25
- * Gets Resources versions from enviromental variable RESOURCES_VERSIONS
26
- * should be string in format: "resouceOneName=1.0,resourceTwoName=1.1"
25
+ * Gets Resources versions from environmental variable RESOURCES_VERSIONS
26
+ * should be string in format: "resourceOneName=1.0,resourceTwoName=1.1"
27
27
  */
28
28
  function getVersionFromConfig (resourceString) {
29
29
  const resourceVersionMap = {};
@@ -44,7 +44,7 @@ function parseResourceVersions (resourceString) {
44
44
  const resourceFormatRegex = /(([A-Za-z])\w*)=([0-9]+).([0-9]+)([^;:|],*)/g;
45
45
  const noSpResources = resourceString.replace(/\s/g,'');
46
46
  if (!resourceFormatRegex.test(noSpResources)) {
47
- throw new Error('Resource versions format should be in format: "resouceOneName=1.0,resourceTwoName=1.1"');
47
+ throw new Error('Resource versions format should be in format: "resourceOneName=1.0,resourceTwoName=1.1"');
48
48
  }
49
49
  return getVersionFromConfig(noSpResources);
50
50
  }
@@ -59,20 +59,28 @@ const env = from(process.env, {
59
59
  module.exports = {
60
60
  __parseResourceVersion: parseResourceVersions,
61
61
  control: {
62
- mgmtAPIWsUrl: env.get('MGMT_API_WS_URL').required().asString(),
62
+ mgmtAPIWsUrl: env.get('MGMT_API_WS_URL').default('127.0.0.1').asString(),
63
63
  mgmtAPIWsPort: env.get('MGMT_API_WS_PORT').default('4005').asPortNumber()
64
64
  },
65
- mutualTLS: {
66
- inboundRequests: {
67
- enabled: env.get('INBOUND_MUTUAL_TLS_ENABLED').default('false').asBool(),
65
+ inbound: {
66
+ port: env.get('INBOUND_LISTEN_PORT').default('4000').asPortNumber(),
67
+ tls: {
68
+ mutualTLS: {
69
+ enabled: env.get('INBOUND_MUTUAL_TLS_ENABLED').default('false').asBool(),
70
+ },
68
71
  creds: {
69
72
  ca: env.get('IN_CA_CERT_PATH').asFileListContent(),
70
73
  cert: env.get('IN_SERVER_CERT_PATH').asFileContent(),
71
74
  key: env.get('IN_SERVER_KEY_PATH').asFileContent(),
72
75
  },
73
76
  },
74
- outboundRequests: {
75
- enabled: env.get('OUTBOUND_MUTUAL_TLS_ENABLED').default('false').asBool(),
77
+ },
78
+ outbound: {
79
+ port: env.get('OUTBOUND_LISTEN_PORT').default('4001').asPortNumber(),
80
+ tls: {
81
+ mutualTLS: {
82
+ enabled: env.get('OUTBOUND_MUTUAL_TLS_ENABLED').default('false').asBool(),
83
+ },
76
84
  creds: {
77
85
  ca: env.get('OUT_CA_CERT_PATH').asFileListContent(),
78
86
  cert: env.get('OUT_CLIENT_CERT_PATH').asFileContent(),
@@ -80,9 +88,9 @@ module.exports = {
80
88
  },
81
89
  },
82
90
  },
83
- inboundServerPort: env.get('INBOUND_LISTEN_PORT').default('4000').asPortNumber(),
84
- outboundServerPort: env.get('OUTBOUND_LISTEN_PORT').default('4001').asPortNumber(),
85
- testServerPort: env.get('TEST_LISTEN_PORT').default('4002').asPortNumber(),
91
+ test: {
92
+ port: env.get('TEST_LISTEN_PORT').default('4002').asPortNumber(),
93
+ },
86
94
  peerEndpoint: env.get('PEER_ENDPOINT').required().asString(),
87
95
  alsEndpoint: env.get('ALS_ENDPOINT').asString(),
88
96
  quotesEndpoint: env.get('QUOTES_ENDPOINT').asString(),
@@ -97,6 +105,9 @@ module.exports = {
97
105
  checkIlp: env.get('CHECK_ILP').default('true').asBool(),
98
106
  expirySeconds: env.get('EXPIRY_SECONDS').default('60').asIntPositive(),
99
107
 
108
+ multiplePartiesResponse: env.get('MULTIPLE_PARTIES_RESPONSE').default('false').asBool(),
109
+ multiplePartiesResponseSeconds: env.get('MULTIPLE_PARTIES_RESPONSE_SECONDS').default('30').asIntPositive(),
110
+
100
111
  autoAcceptQuotes: env.get('AUTO_ACCEPT_QUOTES').default('true').asBool(),
101
112
  autoAcceptParty: env.get('AUTO_ACCEPT_PARTY').default('true').asBool(),
102
113
  autoAcceptR2PBusinessQuotes: env.get('AUTO_ACCEPT_R2P_BUSINESS_QUOTES').default('false').asBool(),
@@ -157,13 +168,19 @@ module.exports = {
157
168
 
158
169
  proxyConfig: env.get('PROXY_CONFIG_PATH').asYamlConfig(),
159
170
  reserveNotification: env.get('RESERVE_NOTIFICATION').default('false').asBool(),
160
- // resourceVersions config should be string in format: "resouceOneName=1.0,resourceTwoName=1.1"
171
+ sendFinalNotificationIfRequested: env.get('SEND_FINAL_NOTIFICATION_IF_REQUESTED').default('false').asBool(),
172
+
173
+ // resourceVersions config should be string in format: "resourceOneName=1.0,resourceTwoName=1.1"
161
174
  resourceVersions: env.get('RESOURCE_VERSIONS').default('').asResourceVersions(),
162
175
 
176
+ metrics: {
177
+ port: env.get('METRICS_SERVER_LISTEN_PORT').default('4004').asPortNumber()
178
+ },
179
+
163
180
  // in 3PPI DFSP's generate their own `transferId` which is associated with
164
181
  // a transactionRequestId. this option decodes the ilp packet for
165
182
  // the `transactionId` to retrieve the quote from cache
166
183
  allowDifferentTransferTransactionId: env.get('ALLOW_DIFFERENT_TRANSFER_TRANSACTION_ID').default('false').asBool(),
167
184
 
168
- pm4mlEnabled: env.get('PM4ML_ENABLED').default('false').asBool(),
185
+ pm4mlEnabled: env.get('PM4ML_ENABLED').default('false').asBool()
169
186
  };