account-lookup-service 15.6.0-iso.2 → 15.6.0-iso.20

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 (43) hide show
  1. package/.circleci/config.yml +1 -1
  2. package/.ncurc.yaml +1 -2
  3. package/audit-ci.jsonc +3 -1
  4. package/jest.config.js +2 -0
  5. package/package.json +14 -16
  6. package/src/constants.js +2 -1
  7. package/src/domain/participants/participants.js +173 -130
  8. package/src/domain/parties/getPartiesByTypeAndID.js +15 -14
  9. package/src/domain/parties/parties.js +13 -12
  10. package/src/domain/parties/utils.js +13 -6
  11. package/src/domain/timeout/dto.js +4 -10
  12. package/src/handlers/index.js +4 -4
  13. package/src/handlers/monitoring/index.js +1 -1
  14. package/src/interface/api-swagger-iso20022-parties.yaml +7 -6
  15. package/src/interface/api-swagger.yaml +7 -6
  16. package/src/interface/fspiop-rest-v2.0-ISO20022_parties.yaml +2043 -1583
  17. package/src/lib/config.js +1 -1
  18. package/src/lib/index.js +1 -2
  19. package/src/models/participantEndpoint/facade.js +21 -19
  20. package/src/plugins.js +20 -9
  21. package/src/server.js +3 -19
  22. package/test/fixtures/index.js +30 -6
  23. package/test/fixtures/iso.js +1 -1
  24. package/test/unit/api/health.test.js +3 -0
  25. package/test/unit/api/participants/participants.test.js +5 -7
  26. package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +0 -3
  27. package/test/unit/api/participants/{Type}/{ID}.test.js +0 -3
  28. package/test/unit/api/participants.test.js +36 -3
  29. package/test/unit/domain/participants/participants.test.js +76 -48
  30. package/test/unit/domain/parties/parties.test.js +3 -3
  31. package/test/unit/domain/parties/utils.test.js +60 -0
  32. package/test/unit/domain/timeout/dto.test.js +1 -2
  33. package/test/unit/lib/TransformFacades.test.js +2 -1
  34. package/test/unit/lib/config.test.js +7 -0
  35. package/test/unit/models/participantEndpoint/facade.test.js +25 -8
  36. package/test/unit/plugins.test.js +4 -2
  37. package/test/util/apiClients/BasicApiClient.js +2 -2
  38. package/src/handlers/monitoring/plugins/metrics.js +0 -48
  39. package/src/lib/requestLogger.js +0 -54
  40. package/src/metrics/handler.js +0 -33
  41. package/src/metrics/plugin.js +0 -52
  42. package/src/metrics/routes.js +0 -43
  43. package/test/unit/lib/requestLogger.test.js +0 -115
@@ -32,21 +32,22 @@ const oracle = require('../../models/oracle/facade')
32
32
  const participant = require('../../models/participantEndpoint/facade')
33
33
  const { createCallbackHeaders } = require('../../lib/headers')
34
34
  const { ERROR_MESSAGES } = require('../../constants')
35
- const { loggerFactory } = require('../../lib')
35
+ const { logger } = require('../../lib')
36
36
  const Config = require('../../lib/config')
37
37
  const utils = require('./utils')
38
38
 
39
39
  const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
40
40
  const { Headers, RestMethods } = Enum.Http
41
41
 
42
- const logger = loggerFactory('domain:get-parties')
42
+ const log = logger.child('domain:get-parties')
43
+ const handleErrorOnSendingCallback = utils.createErrorHandlerOnSendingCallback(Config, log)
43
44
 
44
45
  const proxyCacheTtlSec = 40 // todo: make configurable
45
46
 
46
47
  const validateRequester = async ({ source, proxy, proxyCache }) => {
47
48
  const sourceParticipant = await participant.validateParticipant(source)
48
49
  if (sourceParticipant) {
49
- logger.debug('source is in scheme', { source })
50
+ log.debug('source is in scheme', { source })
50
51
  return source
51
52
  }
52
53
 
@@ -63,7 +64,7 @@ const validateRequester = async ({ source, proxy, proxyCache }) => {
63
64
 
64
65
  const isCached = await proxyCache.addDfspIdToProxyMapping(source, proxy)
65
66
  // think, what if isCached !== true?
66
- logger.info('source is added to proxyMapping cache:', { source, proxy, isCached })
67
+ log.info('source is added to proxyMapping cache:', { source, proxy, isCached })
67
68
  return proxy
68
69
  }
69
70
 
@@ -94,7 +95,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
94
95
  const callbackEndpointType = utils.getPartyCbType(partySubId)
95
96
 
96
97
  const childSpan = span ? span.getChild('getPartiesByTypeAndID') : undefined
97
- logger.info('parties::getPartiesByTypeAndID::begin', { source, proxy, params })
98
+ log.info('parties::getPartiesByTypeAndID::begin', { source, proxy, params })
98
99
 
99
100
  let requester
100
101
  let fspiopError
@@ -127,7 +128,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
127
128
  await participant.sendRequest(headers, destination, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
128
129
 
129
130
  histTimerEnd({ success: true })
130
- logger.info('discovery getPartiesByTypeAndID request was sent to destination', { destination })
131
+ log.info('discovery getPartiesByTypeAndID request was sent to destination', { destination })
131
132
  return
132
133
  }
133
134
 
@@ -161,7 +162,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
161
162
  const schemeParticipant = await participant.validateParticipant(fspId)
162
163
  if (schemeParticipant) {
163
164
  sentCount++
164
- logger.debug('participant is in scheme', { fspId })
165
+ log.debug('participant is in scheme', { fspId })
165
166
  return participant.sendRequest(clonedHeaders, party.fspId, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
166
167
  }
167
168
 
@@ -170,20 +171,20 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
170
171
  if (proxyEnabled) {
171
172
  const proxyName = await proxyCache.lookupProxyByDfspId(fspId)
172
173
  if (!proxyName) {
173
- logger.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
174
+ log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
174
175
  // todo: delete reference in oracle
175
176
  } else {
176
177
  sentCount++
177
- logger.debug('participant NOT is in scheme, use proxy name', { fspId, proxyName })
178
+ log.debug('participant NOT is in scheme, use proxy name', { fspId, proxyName })
178
179
  return participant.sendRequest(clonedHeaders, proxyName, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
179
180
  }
180
181
  }
181
182
  })
182
183
  await Promise.all(sending)
183
- logger.info('participant.sendRequests to filtered oracle partyList are done', { sentCount })
184
+ log.info('participant.sendRequests to filtered oracle partyList are done', { sentCount })
184
185
  // todo: think what if sentCount === 0 here
185
186
  } else {
186
- logger.info('empty partyList form oracle, getting proxies list...', { proxyEnabled, params })
187
+ log.info('empty partyList form oracle, getting proxies list...', { proxyEnabled, params })
187
188
  let filteredProxyNames = []
188
189
 
189
190
  if (proxyEnabled) {
@@ -206,7 +207,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
206
207
  fspiopError.toApiErrorObject(config.ERROR_HANDLING), callbackHeaders, params, childSpan)
207
208
  } else {
208
209
  const alsReq = utils.alsRequestDto(source, params)
209
- logger.info('starting setSendToProxiesList flow: ', { filteredProxyNames, alsReq, proxyCacheTtlSec })
210
+ log.info('starting setSendToProxiesList flow: ', { filteredProxyNames, alsReq, proxyCacheTtlSec })
210
211
  const isCached = await proxyCache.setSendToProxiesList(alsReq, filteredProxyNames, proxyCacheTtlSec)
211
212
  if (!isCached) {
212
213
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
@@ -221,7 +222,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
221
222
  // If, at least, one request is sent to proxy, we treat the whole flow as successful.
222
223
  // Failed requests should be handled by TTL expired/timeout handler
223
224
  // todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
224
- logger.info('setSendToProxiesList flow is done:', { isOk, results, filteredProxyNames, alsReq })
225
+ log.info('setSendToProxiesList flow is done:', { isOk, results, filteredProxyNames, alsReq })
225
226
  if (!isOk) {
226
227
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
227
228
  }
@@ -229,7 +230,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
229
230
  }
230
231
  histTimerEnd({ success: true })
231
232
  } catch (err) {
232
- fspiopError = await utils.handleErrorOnSendingCallback(err, headers, params, requester)
233
+ fspiopError = await handleErrorOnSendingCallback(err, headers, params, requester)
233
234
  histTimerEnd({ success: false })
234
235
  } finally {
235
236
  await utils.finishSpanWithError(childSpan, fspiopError)
@@ -38,12 +38,13 @@ const Metrics = require('@mojaloop/central-services-metrics')
38
38
  const oracle = require('../../models/oracle/facade')
39
39
  const participant = require('../../models/participantEndpoint/facade')
40
40
  const { ERROR_MESSAGES } = require('../../constants')
41
- const { loggerFactory } = require('../../lib')
41
+ const { logger } = require('../../lib')
42
42
  const Config = require('../../lib/config')
43
43
  const utils = require('./utils')
44
44
  const getPartiesByTypeAndID = require('./getPartiesByTypeAndID')
45
45
 
46
- const logger = loggerFactory('domain:put-parties')
46
+ const log = logger.child('domain:put-parties')
47
+ const handleErrorOnSendingCallback = utils.createErrorHandlerOnSendingCallback(Config, log)
47
48
 
48
49
  /**
49
50
  * @function putPartiesByTypeAndID
@@ -70,7 +71,7 @@ const putPartiesByTypeAndID = async (headers, params, method, payload, dataUri,
70
71
  const destination = headers[Headers.FSPIOP.DESTINATION]
71
72
  const proxy = headers[Headers.FSPIOP.PROXY]
72
73
  const proxyEnabled = !!(Config.PROXY_CACHE_CONFIG.enabled && proxyCache)
73
- logger.info('parties::putPartiesByTypeAndID::begin', { source, destination, proxy, params })
74
+ log.info('parties::putPartiesByTypeAndID::begin', { source, destination, proxy, params })
74
75
 
75
76
  let sendTo
76
77
  try {
@@ -82,21 +83,21 @@ const putPartiesByTypeAndID = async (headers, params, method, payload, dataUri,
82
83
  }
83
84
  const isCached = await proxyCache.addDfspIdToProxyMapping(source, proxy)
84
85
  // think,if we should throw error if isCached === false?
85
- logger.info('addDfspIdToProxyMapping is done', { source, proxy, isCached })
86
+ log.info('addDfspIdToProxyMapping is done', { source, proxy, isCached })
86
87
  }
87
88
 
88
89
  if (proxyEnabled && proxy) {
89
90
  const alsReq = utils.alsRequestDto(destination, params) // or source?
90
91
  const isExists = await proxyCache.receivedSuccessResponse(alsReq)
91
92
  if (!isExists) {
92
- logger.warn('destination is NOT in scheme, and no cached sendToProxiesList', { destination, alsReq })
93
+ log.warn('destination is NOT in scheme, and no cached sendToProxiesList', { destination, alsReq })
93
94
  // think, if we need to throw an error here
94
95
  } else {
95
96
  const mappingPayload = {
96
97
  fspId: source
97
98
  }
98
99
  await oracle.oracleRequest(headers, RestMethods.POST, params, null, mappingPayload, cache)
99
- logger.info('oracle was updated with mappingPayload', { mappingPayload, params })
100
+ log.info('oracle was updated with mappingPayload', { mappingPayload, params })
100
101
  }
101
102
  }
102
103
 
@@ -121,10 +122,10 @@ const putPartiesByTypeAndID = async (headers, params, method, payload, dataUri,
121
122
  }
122
123
  await participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.PUT, decodedPayload.body.toString(), options)
123
124
 
124
- logger.info('parties::putPartiesByTypeAndID::callback was sent', { sendTo, options })
125
+ log.info('parties::putPartiesByTypeAndID::callback was sent', { sendTo, options })
125
126
  histTimerEnd({ success: true })
126
127
  } catch (err) {
127
- await utils.handleErrorOnSendingCallback(err, headers, params, sendTo)
128
+ await handleErrorOnSendingCallback(err, headers, params, sendTo)
128
129
  histTimerEnd({ success: false })
129
130
  }
130
131
  }
@@ -167,14 +168,14 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
167
168
  getPartiesByTypeAndID(swappedHeaders, params, RestMethods.GET, {}, span, cache, proxyCache)
168
169
  // todo: - think if we need to send errorCallback?
169
170
  // - or sentCallback after getPartiesByTypeAndID is done
170
- logger.info('notValidPayee case - deleted Participants and run getPartiesByTypeAndID:', { proxy, params, payload })
171
+ log.info('notValidPayee case - deleted Participants and run getPartiesByTypeAndID:', { proxy, params, payload })
171
172
  return
172
173
  }
173
174
 
174
175
  const alsReq = utils.alsRequestDto(destination, params) // or source?
175
176
  const isLast = await proxyCache.receivedErrorResponse(alsReq, proxy)
176
177
  if (!isLast) {
177
- logger.info('got NOT last error callback from proxy:', { proxy, alsReq })
178
+ log.info('got NOT last error callback from proxy:', { proxy, alsReq })
178
179
  return
179
180
  }
180
181
  }
@@ -194,10 +195,10 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
194
195
  const decodedPayload = decodePayload(dataUri, { asParsed: false })
195
196
  await participant.sendErrorToParticipant(sendTo, callbackEndpointType, decodedPayload.body.toString(), headers, params, childSpan)
196
197
 
197
- logger.info('putPartiesErrorByTypeAndID callback was sent', { sendTo })
198
+ log.info('putPartiesErrorByTypeAndID callback was sent', { sendTo })
198
199
  histTimerEnd({ success: true })
199
200
  } catch (err) {
200
- fspiopError = await utils.handleErrorOnSendingCallback(err, headers, params, sendTo)
201
+ fspiopError = await handleErrorOnSendingCallback(err, headers, params, sendTo)
201
202
  histTimerEnd({ success: false })
202
203
  } finally {
203
204
  await utils.finishSpanWithError(childSpan, fspiopError)
@@ -1,10 +1,9 @@
1
- const { Enum } = require('@mojaloop/central-services-shared')
1
+ const { Enum, Util: { Hapi } } = require('@mojaloop/central-services-shared')
2
2
  const EventSdk = require('@mojaloop/event-sdk')
3
3
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
4
4
 
5
5
  const participant = require('../../models/participantEndpoint/facade')
6
- const Config = require('../../lib/config')
7
- const { logger } = require('../../lib')
6
+ const { TransformFacades } = require('../../lib')
8
7
 
9
8
  const { FspEndpointTypes } = Enum.EndPoints
10
9
  const { Headers } = Enum.Http
@@ -33,6 +32,13 @@ const finishSpanWithError = async (childSpan, fspiopError) => {
33
32
  }
34
33
  }
35
34
 
35
+ const makePutPartiesErrorPayload = async (config, fspiopError, headers, params) => {
36
+ const body = fspiopError.toApiErrorObject(config.ERROR_HANDLING)
37
+ return config.API_TYPE === Hapi.API_TYPES.iso20022
38
+ ? (await TransformFacades.FSPIOP.parties.putError({ body, headers, params })).body
39
+ : body
40
+ }
41
+
36
42
  const alsRequestDto = (sourceId, params) => ({
37
43
  sourceId,
38
44
  type: params.Type,
@@ -54,13 +60,13 @@ const swapSourceDestinationHeaders = (headers) => {
54
60
  }
55
61
 
56
62
  // change signature to accept object
57
- const handleErrorOnSendingCallback = async (err, headers, params, requester) => {
63
+ const createErrorHandlerOnSendingCallback = (config, logger) => async (err, headers, params, requester) => {
58
64
  try {
59
65
  logger.error('error in sending parties callback', err)
60
66
  const sendTo = requester || headers[Headers.FSPIOP.SOURCE]
61
67
  const errorCallbackEndpointType = errorPartyCbType(params.SubId)
62
68
  const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err)
63
- const errInfo = fspiopError.toApiErrorObject(Config.ERROR_HANDLING)
69
+ const errInfo = await makePutPartiesErrorPayload(config, fspiopError, headers, params)
64
70
 
65
71
  await participant.sendErrorToParticipant(sendTo, errorCallbackEndpointType, errInfo, headers, params)
66
72
 
@@ -77,8 +83,9 @@ module.exports = {
77
83
  getPartyCbType,
78
84
  putPartyCbType,
79
85
  errorPartyCbType,
86
+ makePutPartiesErrorPayload,
80
87
  finishSpanWithError,
81
- handleErrorOnSendingCallback,
88
+ createErrorHandlerOnSendingCallback,
82
89
  alsRequestDto,
83
90
  swapSourceDestinationHeaders
84
91
  }
@@ -8,18 +8,10 @@ const {
8
8
  EndPoints: { FspEndpointTypes }
9
9
  } = require('@mojaloop/central-services-shared').Enum
10
10
  const { Tracer } = require('@mojaloop/event-sdk')
11
- const { API_TYPES } = require('@mojaloop/central-services-shared').Util.Hapi
12
11
 
13
- const { TransformFacades } = require('../../lib')
14
12
  const LibUtil = require('../../lib/util')
15
13
  const Config = require('../../lib/config')
16
-
17
- const makeErrorPayload = async (headers, params) => {
18
- const body = createFSPIOPError(FSPIOPErrorCodes.EXPIRED_ERROR).toApiErrorObject(Config.ERROR_HANDLING)
19
- return Config.API_TYPE === API_TYPES.iso20022
20
- ? (await TransformFacades.FSPIOP.parties.putError({ body, headers, params })).body
21
- : body
22
- }
14
+ const partiesUtils = require('../parties/utils')
23
15
 
24
16
  const timeoutCallbackDto = async ({ destination, partyId, partyType }) => {
25
17
  const headers = {
@@ -30,8 +22,10 @@ const timeoutCallbackDto = async ({ destination, partyId, partyType }) => {
30
22
  ID: partyId,
31
23
  Type: partyType
32
24
  }
25
+ const error = createFSPIOPError(FSPIOPErrorCodes.EXPIRED_ERROR)
26
+
33
27
  const dto = {
34
- errorInformation: await makeErrorPayload(headers, params),
28
+ errorInformation: await partiesUtils.makePutPartiesErrorPayload(Config, error, headers, params),
35
29
  headers,
36
30
  params,
37
31
  endpointType: FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR
@@ -35,7 +35,7 @@ const Package = require('../../package.json')
35
35
  const Server = require('../server')
36
36
  const { HANDLER_TYPES } = require('../constants')
37
37
  const Config = require('../lib/config')
38
- const logger = require('../lib').loggerFactory('ALS-timeout-handler')
38
+ const log = require('../lib').logger.child('ALS-timeout-handler')
39
39
 
40
40
  const Program = new Command()
41
41
 
@@ -51,16 +51,16 @@ Program.command('handlers')
51
51
  const handlers = []
52
52
 
53
53
  if (args.timeout) {
54
- logger.debug('CLI: Executing --timeout')
54
+ log.debug('CLI: Executing --timeout')
55
55
  handlers.push(HANDLER_TYPES.TIMEOUT)
56
56
  }
57
57
 
58
58
  if (handlers.length === 0) {
59
- logger.debug('CLI: No handlers specified')
59
+ log.debug('CLI: No handlers specified')
60
60
  return
61
61
  }
62
62
 
63
- module.exports = await Server.initializeHandlers(handlers, Config, logger)
63
+ module.exports = await Server.initializeHandlers(handlers, Config, log)
64
64
  })
65
65
 
66
66
  if (Array.isArray(process.argv) && process.argv.length > 2) {
@@ -18,7 +18,7 @@
18
18
  const Hapi = require('@hapi/hapi')
19
19
  const Metrics = require('@mojaloop/central-services-metrics')
20
20
  const { plugin: HealthPlugin } = require('./plugins/health')
21
- const { plugin: MetricsPlugin } = require('./plugins/metrics')
21
+ const MetricsPlugin = require('@mojaloop/central-services-metrics').plugin
22
22
  const { logger } = require('../../lib')
23
23
 
24
24
  let server
@@ -890,13 +890,14 @@ components:
890
890
  schemas:
891
891
  CorrelationId:
892
892
  title: CorrelationId
893
- pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
894
893
  type: string
895
- description: Identifier that correlates all messages of the same sequence. The
896
- API data type UUID (Universally Unique Identifier) is a JSON String in canonical
897
- format, conforming to RFC 4122, that is restricted by a regular expression
898
- for interoperability reasons. An UUID is always 36 characters long, 32 hexadecimal
899
- symbols and 4 dashes (‘-‘).
894
+ pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$|^[0-9A-HJKMNP-TV-Z]{26}$
895
+ description: >-
896
+ Identifier that correlates all messages of the same sequence.
897
+ The supported identifiers formats are for
898
+ lowercase [UUID](https://datatracker.ietf.org/doc/html/rfc9562) and
899
+ uppercase [ULID](https://github.com/ulid/spec)
900
+ example: 'b51ec534-ee48-4575-b6a9-ead2955b8069'
900
901
  Currency:
901
902
  title: CurrencyEnum
902
903
  maxLength: 3
@@ -889,13 +889,14 @@ components:
889
889
  schemas:
890
890
  CorrelationId:
891
891
  title: CorrelationId
892
- pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
893
892
  type: string
894
- description: Identifier that correlates all messages of the same sequence. The
895
- API data type UUID (Universally Unique Identifier) is a JSON String in canonical
896
- format, conforming to RFC 4122, that is restricted by a regular expression
897
- for interoperability reasons. An UUID is always 36 characters long, 32 hexadecimal
898
- symbols and 4 dashes (‘-‘).
893
+ pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$|^[0-9A-HJKMNP-TV-Z]{26}$
894
+ description: >-
895
+ Identifier that correlates all messages of the same sequence.
896
+ The supported identifiers formats are for
897
+ lowercase [UUID](https://datatracker.ietf.org/doc/html/rfc9562) and
898
+ uppercase [ULID](https://github.com/ulid/spec)
899
+ example: 'b51ec534-ee48-4575-b6a9-ead2955b8069'
899
900
  Currency:
900
901
  title: CurrencyEnum
901
902
  maxLength: 3