account-lookup-service 17.4.1-csi-1300.1 → 17.4.1-csi-1300.3

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "account-lookup-service",
3
3
  "description": "Account Lookup Service is used to validate Party and Participant lookups.",
4
- "version": "17.4.1-csi-1300.1",
4
+ "version": "17.4.1-csi-1300.3",
5
5
  "license": "Apache-2.0",
6
6
  "author": "ModusBox",
7
7
  "contributors": [
@@ -97,7 +97,7 @@
97
97
  "@mojaloop/central-services-metrics": "12.4.5",
98
98
  "@mojaloop/central-services-shared": "18.22.4-snapshot.0",
99
99
  "@mojaloop/central-services-stream": "11.5.1",
100
- "@mojaloop/database-lib": "11.1.3",
100
+ "@mojaloop/database-lib": "11.1.4",
101
101
  "@mojaloop/event-sdk": "14.3.2",
102
102
  "@mojaloop/inter-scheme-proxy-cache-lib": "2.3.7",
103
103
  "@mojaloop/ml-schema-transformer-lib": "2.5.8",
@@ -61,8 +61,9 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
61
61
  await service.handleRequest({ headers, params, query, results })
62
62
  log.info('getPartiesByTypeAndID is done')
63
63
  histTimerEnd({ success: true })
64
- } catch (err) {
65
- results.fspiopError = await deps.partiesUtils.createErrorHandlerOnSendingCallback(deps.config, log)(err, headers, params, results.requester)
64
+ } catch (error) {
65
+ const { requester } = results
66
+ results.fspiopError = await service.handleError({ error, requester, headers, params })
66
67
  histTimerEnd({ success: false })
67
68
  if (results.fspiopError) {
68
69
  libUtil.countFspiopError(results.fspiopError, { operation: component, step: stepState.step })
@@ -26,6 +26,8 @@
26
26
  ******/
27
27
 
28
28
  const { Enum, Util: { Hapi } } = require('@mojaloop/central-services-shared')
29
+ const { MojaloopApiErrorCodes } = require('@mojaloop/sdk-standard-components').Errors
30
+ // todo: check why do we need sdk-standard-components deps here !!!
29
31
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
30
32
 
31
33
  const participant = require('../../models/participantEndpoint/facade')
@@ -79,7 +81,7 @@ const swapSourceDestinationHeaders = (headers) => {
79
81
  }
80
82
  }
81
83
 
82
- // change signature to accept object
84
+ // todo: check if we need this function
83
85
  const createErrorHandlerOnSendingCallback = (config, logger) => async (err, headers, params, requester) => {
84
86
  try {
85
87
  logger.error('error in sending parties callback: ', err)
@@ -99,6 +101,10 @@ const createErrorHandlerOnSendingCallback = (config, logger) => async (err, head
99
101
  }
100
102
  }
101
103
 
104
+ function isNotValidPayeeCase (payload) {
105
+ return payload?.errorInformation?.errorCode === MojaloopApiErrorCodes.PAYEE_IDENTIFIER_NOT_VALID.code
106
+ }
107
+
102
108
  module.exports = {
103
109
  getPartyCbType,
104
110
  putPartyCbType,
@@ -107,5 +113,6 @@ module.exports = {
107
113
  createErrorHandlerOnSendingCallback,
108
114
  alsRequestDto,
109
115
  partiesRequestOptionsDto,
110
- swapSourceDestinationHeaders
116
+ swapSourceDestinationHeaders,
117
+ isNotValidPayeeCase
111
118
  }
@@ -29,21 +29,15 @@
29
29
 
30
30
  'use strict'
31
31
 
32
- const { Headers, RestMethods } = require('@mojaloop/central-services-shared').Enum.Http
33
- const { decodePayload } = require('@mojaloop/central-services-shared').Util.StreamingProtocol
34
- const { MojaloopApiErrorCodes } = require('@mojaloop/sdk-standard-components').Errors
35
- const ErrorHandler = require('@mojaloop/central-services-error-handling')
32
+ const { Headers } = require('@mojaloop/central-services-shared').Enum.Http
36
33
  const Metrics = require('@mojaloop/central-services-metrics')
37
34
 
38
- const oracle = require('../../models/oracle/facade')
39
- const participant = require('../../models/participantEndpoint/facade')
40
35
  const libUtil = require('../../lib/util')
41
36
  const Config = require('../../lib/config')
42
37
  const { logger } = require('../../lib')
43
- const { ERROR_MESSAGES } = require('../../constants')
44
38
 
45
- const partiesUtils = require('./partiesUtils')
46
- const getPartiesByTypeAndID = require('./getPartiesByTypeAndID')
39
+ const services = require('./services')
40
+ const { createDeps } = require('./deps')
47
41
 
48
42
  /**
49
43
  * @function putPartiesByTypeAndID
@@ -59,80 +53,44 @@ const getPartiesByTypeAndID = require('./getPartiesByTypeAndID')
59
53
  * @param {IProxyCache} [proxyCache] - IProxyCache instance
60
54
  */
61
55
  const putPartiesByTypeAndID = async (headers, params, method, payload, dataUri, cache, proxyCache = undefined) => {
62
- const components = putPartiesByTypeAndID.name
56
+ // todo: think, if we need to pass span here
57
+ const component = putPartiesByTypeAndID.name
63
58
  const histTimerEnd = Metrics.getHistogram(
64
- components,
59
+ component,
65
60
  'Put parties by type and id',
66
61
  ['success']
67
62
  ).startTimer()
68
- const log = logger.child({ params, components })
63
+ // const childSpan = span ? span.getChild(component) : undefined
64
+ const log = logger.child({ component, params })
65
+ const stepState = libUtil.initStepState()
66
+
67
+ const deps = createDeps({ cache, proxyCache, log, stepState })
68
+ const service = new services.PutPartiesService(deps)
69
+ const results = {}
70
+
69
71
  const source = headers[Headers.FSPIOP.SOURCE]
70
72
  const destination = headers[Headers.FSPIOP.DESTINATION]
71
73
  const proxy = headers[Headers.FSPIOP.PROXY]
72
- const proxyEnabled = !!(Config.PROXY_CACHE_CONFIG.enabled && proxyCache)
73
74
  log.info('parties::putPartiesByTypeAndID start', { source, destination, proxy })
74
75
 
75
- let sendTo
76
- let step
77
-
78
76
  try {
79
- step = 'validateParticipant-1'
80
- const requesterParticipant = await participant.validateParticipant(source)
81
- if (!requesterParticipant) {
82
- if (!proxyEnabled || !proxy) {
83
- const errMessage = ERROR_MESSAGES.sourceFspNotFound
84
- log.warn(`${errMessage} and no proxy`)
85
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
86
- }
87
- step = 'addDfspIdToProxyMapping-1'
88
- const isCached = await proxyCache.addDfspIdToProxyMapping(source, proxy)
89
- // think,if we should throw error if isCached === false?
90
- log.info('addDfspIdToProxyMapping is done', { source, proxy, isCached })
91
- }
77
+ await service.validateSourceParticipant({ source, proxy })
92
78
 
93
- if (proxyEnabled && proxy) {
94
- const alsReq = partiesUtils.alsRequestDto(destination, params)
95
- step = 'receivedSuccessResponse-2'
96
- const isExists = await proxyCache.receivedSuccessResponse(alsReq)
97
- if (!isExists) {
98
- log.warn('destination is NOT in scheme, and no cached sendToProxiesList', { destination, alsReq })
99
- // todo: think, if we need to throw an error here
100
- } else {
101
- const mappingPayload = {
102
- fspId: source
103
- }
104
- step = 'oracleRequest-3'
105
- await oracle.oracleRequest(headers, RestMethods.POST, params, null, mappingPayload, cache)
106
- log.info('oracle was updated with mappingPayload', { mappingPayload })
107
- }
108
- }
109
- step = 'validateParticipant-4'
110
- const destinationParticipant = await participant.validateParticipant(destination)
111
- if (!destinationParticipant) {
112
- step = 'lookupProxyByDfspId-5'
113
- const proxyName = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
114
- if (!proxyName) {
115
- const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
116
- log.warn(errMessage)
117
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
118
- }
119
- sendTo = proxyName
120
- } else {
121
- sendTo = destinationParticipant.name
79
+ if (proxy) {
80
+ await service.checkProxySuccessResponse({ destination, source, headers, params })
122
81
  }
123
82
 
124
- const decodedPayload = decodePayload(dataUri, { asParsed: false })
125
- const callbackEndpointType = partiesUtils.putPartyCbType(params.SubId)
126
- const options = partiesUtils.partiesRequestOptionsDto(params)
127
- step = 'sendRequest-6'
128
- await participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.PUT, decodedPayload.body.toString(), options)
83
+ const sendTo = await service.identifyDestinationForSuccessCallback(destination)
84
+ results.requester = sendTo
85
+ await service.sendSuccessCallback({ sendTo, headers, params, dataUri })
129
86
 
130
- log.info('parties::putPartiesByTypeAndID::callback was sent', { sendTo })
87
+ log.info('putPartiesByTypeAndID callback was sent', { sendTo })
131
88
  histTimerEnd({ success: true })
132
- } catch (err) {
133
- const fspiopError = await partiesUtils.createErrorHandlerOnSendingCallback(Config, log)(err, headers, params, sendTo)
134
- if (fspiopError) {
135
- libUtil.countFspiopError(fspiopError, { operation: components, step })
89
+ } catch (error) {
90
+ const { requester } = results
91
+ results.fspiopError = await service.handleError({ error, requester, headers, params })
92
+ if (results.fspiopError) {
93
+ libUtil.countFspiopError(results.fspiopError, { operation: component, step: stepState.step })
136
94
  }
137
95
  histTimerEnd({ success: false })
138
96
  }
@@ -158,101 +116,55 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
158
116
  'Put parties error by type and id',
159
117
  ['success']
160
118
  ).startTimer()
161
- const log = logger.child({ params, component })
119
+ const childSpan = span ? span.getChild(component) : undefined
120
+ const log = logger.child({ component, params })
121
+ const stepState = libUtil.initStepState()
122
+
123
+ const deps = createDeps({ cache, proxyCache, childSpan, log, stepState })
124
+ const service = new services.PutPartiesErrorService(deps)
125
+ const results = {}
126
+
162
127
  const destination = headers[Headers.FSPIOP.DESTINATION]
163
128
  const proxyEnabled = !!(Config.PROXY_CACHE_CONFIG.enabled && proxyCache)
164
129
  const proxy = proxyEnabled && headers[Headers.FSPIOP.PROXY]
165
-
166
- const childSpan = span ? span.getChild(component) : undefined
167
- const stepState = libUtil.initStepState()
168
130
  log.info('parties::putPartiesErrorByTypeAndID start', { destination, proxy })
169
131
 
170
- let sendTo
171
- let fspiopError
172
-
173
132
  try {
174
133
  if (proxy) {
175
- const isDone = await processProxyErrorCallback({
176
- headers, params, payload, childSpan, cache, proxyCache, log, proxy, destination, stepState
177
- })
178
- if (isDone) {
134
+ const notValid = await service.checkPayee({ headers, params, payload, proxy })
135
+ if (notValid) {
136
+ const getPartiesService = new services.GetPartiesService(deps)
137
+ // todo: think, if we need to remove destination header before starting new discovery
138
+ await getPartiesService.handleRequest({ headers, params, results })
139
+ log.info('putPartiesErrorByTypeAndID triggered new discovery flow')
140
+ histTimerEnd({ success: true })
141
+ return
142
+ }
143
+
144
+ const isLast = await service.checkLastProxyCallback({ destination, proxy, params })
145
+ if (!isLast) {
179
146
  log.info('putPartiesErrorByTypeAndID proxy callback was processed', { proxy })
180
147
  histTimerEnd({ success: true })
181
148
  return
182
149
  }
183
150
  }
184
151
 
185
- sendTo = await identifyDestinationForErrorCallback({
186
- destination, proxyCache, proxyEnabled, log, stepState
187
- })
188
-
189
- await sendErrorCallbackToParticipant({
190
- sendTo, headers, params, dataUri, childSpan, stepState
191
- })
152
+ const sendTo = await service.identifyDestinationForErrorCallback(destination)
153
+ results.requester = sendTo
154
+ await service.sendErrorCallbackToParticipant({ sendTo, headers, params, dataUri })
192
155
 
193
156
  log.info('putPartiesErrorByTypeAndID callback was sent', { sendTo })
194
157
  histTimerEnd({ success: true })
195
- } catch (err) {
196
- fspiopError = await partiesUtils.createErrorHandlerOnSendingCallback(Config, log)(err, headers, params, sendTo)
197
- if (fspiopError) {
198
- libUtil.countFspiopError(fspiopError, { operation: component, step: stepState.step })
158
+ } catch (error) {
159
+ const { requester } = results
160
+ results.fspiopError = await service.handleError({ error, requester, headers, params })
161
+ if (results.fspiopError) {
162
+ libUtil.countFspiopError(results.fspiopError, { operation: component, step: stepState.step })
199
163
  }
200
164
  histTimerEnd({ success: false })
201
165
  } finally {
202
- await libUtil.finishSpanWithError(childSpan, fspiopError)
203
- }
204
- }
205
-
206
- const processProxyErrorCallback = async ({
207
- headers, params, payload, childSpan, cache, proxyCache, log, proxy, destination, stepState
208
- }) => {
209
- log.verbose('processProxyErrorCallback...')
210
- let isDone // whether or not to continue putPartiesErrorByTypeAndID
211
-
212
- if (isNotValidPayeeCase(payload)) {
213
- stepState.inProgress('notValidPayeeCase-1')
214
- log.info('notValidPayee case - deleted Participants and run getPartiesByTypeAndID', { proxy, payload })
215
- const swappedHeaders = partiesUtils.swapSourceDestinationHeaders(headers)
216
- await oracle.oracleRequest(swappedHeaders, RestMethods.DELETE, params, null, null, cache)
217
- getPartiesByTypeAndID(swappedHeaders, params, RestMethods.GET, {}, childSpan, cache, proxyCache)
218
- isDone = true
219
- } else {
220
- stepState.inProgress('receivedErrorResponse-2')
221
- const alsReq = partiesUtils.alsRequestDto(destination, params) // or source?
222
- const isLast = await proxyCache.receivedErrorResponse(alsReq, proxy)
223
- log.info(`got${isLast ? '' : 'NOT'} last error callback from proxy`, { proxy, alsReq, isLast })
224
- isDone = !isLast
166
+ await libUtil.finishSpanWithError(childSpan, results.fspiopError)
225
167
  }
226
- return isDone
227
- }
228
-
229
- const identifyDestinationForErrorCallback = async ({
230
- destination, proxyCache, proxyEnabled, log, stepState
231
- }) => {
232
- stepState.inProgress('validateParticipant-3')
233
- const destinationParticipant = await participant.validateParticipant(destination)
234
- if (destinationParticipant) return destination
235
-
236
- stepState.inProgress('lookupProxyDestination-4')
237
- const proxyName = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
238
- if (proxyName) return proxyName
239
-
240
- const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
241
- log.warn(errMessage)
242
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
243
- }
244
-
245
- const sendErrorCallbackToParticipant = async ({
246
- sendTo, headers, params, dataUri, childSpan, stepState
247
- }) => {
248
- stepState.inProgress('sendErrorToParticipant-5')
249
- const decodedPayload = decodePayload(dataUri, { asParsed: false })
250
- const callbackEndpointType = partiesUtils.errorPartyCbType(params.SubId)
251
- await participant.sendErrorToParticipant(sendTo, callbackEndpointType, decodedPayload.body.toString(), headers, params, childSpan)
252
- }
253
-
254
- function isNotValidPayeeCase (payload) {
255
- return payload?.errorInformation?.errorCode === MojaloopApiErrorCodes.PAYEE_IDENTIFIER_NOT_VALID.code
256
168
  }
257
169
 
258
170
  module.exports = {
@@ -0,0 +1,94 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ * Eugen Klymniuk <eugen.klymniuk@infitx.com>
24
+
25
+ --------------
26
+ ******/
27
+
28
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
+ const { decodePayload } = require('@mojaloop/central-services-shared').Util.StreamingProtocol
30
+ const { Enum } = require('@mojaloop/central-services-shared')
31
+
32
+ const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
33
+ const { Headers, RestMethods } = Enum.Http
34
+
35
+ class BasePartiesService {
36
+ constructor (deps) {
37
+ this.deps = deps
38
+ this.log = this.deps.log.child({ component: this.constructor.name })
39
+ this.proxyEnabled = !!(deps.config.PROXY_CACHE_CONFIG?.enabled && deps.proxyCache)
40
+ }
41
+
42
+ async handleRequest () {
43
+ throw new Error('handleRequest must be implemented by subclass')
44
+ }
45
+
46
+ async handleError ({ error, requester, headers, params }) {
47
+ const log = this.log.child({ method: 'handleError' })
48
+ try {
49
+ log.error('error in processing parties request: ', error)
50
+ const sendTo = requester || headers[Headers.FSPIOP.SOURCE]
51
+ const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(error)
52
+ const errorInfo = await this.deps.partiesUtils.makePutPartiesErrorPayload(this.deps.config, fspiopError, headers, params)
53
+
54
+ await this.sendErrorCallback({ sendTo, errorInfo, headers, params })
55
+ log.info('handleError in done', { sendTo, errorInfo })
56
+ return fspiopError
57
+ } catch (exc) {
58
+ // We can't do anything else here- we _must_ handle all errors _within_ this function because
59
+ // we've already sent a sync response- we cannot throw.
60
+ log.error('failed to handleError. No further processing! ', exc)
61
+ }
62
+ }
63
+
64
+ async validateParticipant (participantId) {
65
+ return this.deps.participant.validateParticipant(participantId)
66
+ }
67
+
68
+ async sendErrorCallback ({ sendTo, errorInfo, headers, params, payload = undefined }) {
69
+ const endpointType = this.deps.partiesUtils.errorPartyCbType(params.SubId)
70
+ return this.deps.participant.sendErrorToParticipant(
71
+ sendTo, endpointType, errorInfo, headers, params, payload, this.deps.childSpan
72
+ )
73
+ }
74
+
75
+ async sendDeleteOracleRequest (headers, params) {
76
+ return this.deps.oracle.oracleRequest(headers, RestMethods.DELETE, params, null, null, this.deps.cache)
77
+ }
78
+
79
+ static decodeDataUriPayload (dataUri) {
80
+ const decoded = decodePayload(dataUri, { asParsed: false })
81
+ return decoded.body.toString()
82
+ }
83
+
84
+ static enums () {
85
+ return {
86
+ FspEndpointTypes,
87
+ FspEndpointTemplates,
88
+ Headers,
89
+ RestMethods
90
+ }
91
+ }
92
+ }
93
+
94
+ module.exports = BasePartiesService
@@ -26,24 +26,18 @@
26
26
  ******/
27
27
 
28
28
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
- const { Enum } = require('@mojaloop/central-services-shared')
30
29
  const { ERROR_MESSAGES } = require('../../../constants')
31
30
  const { createCallbackHeaders } = require('../../../lib/headers')
31
+ const BasePartiesService = require('./BasePartiesService')
32
32
 
33
- const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
34
- const { Headers, RestMethods } = Enum.Http
33
+ const {
34
+ FspEndpointTypes, FspEndpointTemplates,
35
+ Headers, RestMethods
36
+ } = BasePartiesService.enums()
35
37
 
36
38
  const proxyCacheTtlSec = 40 // todo: make configurable
37
39
 
38
- class GetPartiesService {
39
- #deps
40
-
41
- constructor (deps) {
42
- this.#deps = deps
43
- this.log = this.#deps.log.child({ component: this.constructor.name })
44
- this.proxyEnabled = !!(deps.config.PROXY_CACHE_CONFIG?.enabled && deps.proxyCache)
45
- }
46
-
40
+ class GetPartiesService extends BasePartiesService {
47
41
  async handleRequest ({ headers, params, query, results }) {
48
42
  const source = headers[Headers.FSPIOP.SOURCE]
49
43
  const proxy = headers[Headers.FSPIOP.PROXY]
@@ -72,17 +66,18 @@ class GetPartiesService {
72
66
  const proxyNames = await this.getFilteredProxyList(proxy)
73
67
 
74
68
  if (proxyNames.length) {
75
- return this.triggerSendToProxiesFlow({ proxyNames, headers, params, source })
69
+ await this.triggerSendToProxiesFlow({ proxyNames, headers, params, source })
70
+ return
76
71
  }
77
72
 
78
- results.fspiopError = await this.sendErrorCallback({ requester, headers, params })
73
+ results.fspiopError = await this.sendPartyNotFoundErrorCallback({ requester, headers, params })
79
74
  }
80
75
 
81
76
  async validateRequester ({ source, proxy }) {
82
- this.#deps.stepState.inProgress('validateRequester-0')
77
+ this.deps.stepState.inProgress('validateRequester-0')
83
78
  const log = this.log.child({ source, method: 'validateRequester' })
84
79
 
85
- const sourceParticipant = await this.#validateParticipant(source)
80
+ const sourceParticipant = await this.validateParticipant(source)
86
81
  if (sourceParticipant) {
87
82
  log.debug('source is in scheme')
88
83
  return source
@@ -94,28 +89,28 @@ class GetPartiesService {
94
89
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
95
90
  }
96
91
 
97
- const proxyParticipant = await this.#validateParticipant(proxy)
92
+ const proxyParticipant = await this.validateParticipant(proxy)
98
93
  if (!proxyParticipant) {
99
94
  const errMessage = ERROR_MESSAGES.partyProxyNotFound
100
95
  log.warn(errMessage, { proxy })
101
96
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
102
97
  }
103
98
 
104
- const isCached = await this.#deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
99
+ const isCached = await this.deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
105
100
  // think, what if isCached !== true?
106
101
  log.info('source is added to proxyMapping cache:', { proxy, isCached })
107
102
  return proxy
108
103
  }
109
104
 
110
105
  async forwardRequestToDestination ({ destination, headers, params }) {
111
- this.#deps.stepState.inProgress('validateDestination-1')
106
+ this.deps.stepState.inProgress('validateDestination-1')
112
107
  const log = this.log.child({ method: 'forwardRequestToDestination' })
113
108
  let sendTo = destination
114
109
 
115
- const destParticipantModel = await this.#validateParticipant(destination)
110
+ const destParticipantModel = await this.validateParticipant(destination)
116
111
  if (!destParticipantModel) {
117
- this.#deps.stepState.inProgress('lookupProxyDestination-2')
118
- const proxyId = this.proxyEnabled && await this.#deps.proxyCache.lookupProxyByDfspId(destination)
112
+ this.deps.stepState.inProgress('lookupProxyDestination-2')
113
+ const proxyId = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
119
114
 
120
115
  if (!proxyId) {
121
116
  log.warn('no destination participant, and no dfsp-to-proxy mapping', { destination })
@@ -131,8 +126,8 @@ class GetPartiesService {
131
126
 
132
127
  filterOraclePartyList ({ response, params }) {
133
128
  // Oracle's API is a standard rest-style end-point Thus a GET /party on the oracle will return all participant-party records. We must filter the results based on the callbackEndpointType to make sure we remove records containing partySubIdOrType when we are in FSPIOP_CALLBACK_URL_PARTIES_GET mode:
134
- this.#deps.stepState.inProgress('filterOraclePartyList-5')
135
- const callbackEndpointType = this.#deps.partiesUtils.getPartyCbType(params.SubId)
129
+ this.deps.stepState.inProgress('filterOraclePartyList-5')
130
+ const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
136
131
  let filteredResponsePartyList
137
132
 
138
133
  switch (callbackEndpointType) {
@@ -148,7 +143,7 @@ class GetPartiesService {
148
143
 
149
144
  if (!Array.isArray(filteredResponsePartyList) || !filteredResponsePartyList.length) {
150
145
  const errMessage = 'Requested FSP/Party not found'
151
- this.#deps.log.warn(errMessage)
146
+ this.log.warn(errMessage)
152
147
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
153
148
  }
154
149
 
@@ -165,8 +160,8 @@ class GetPartiesService {
165
160
  if (!destination) {
166
161
  clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
167
162
  }
168
- this.#deps.stepState.inProgress('validateParticipant-6')
169
- const schemeParticipant = await this.#validateParticipant(fspId)
163
+ this.deps.stepState.inProgress('validateParticipant-6')
164
+ const schemeParticipant = await this.validateParticipant(fspId)
170
165
  if (schemeParticipant) {
171
166
  sentCount++
172
167
  log.info('participant is in scheme', { fspId })
@@ -180,8 +175,8 @@ class GetPartiesService {
180
175
  // If the participant is not in the scheme and proxy routing is enabled,
181
176
  // we should check if there is a proxy for it and send the request to the proxy
182
177
  if (this.proxyEnabled) {
183
- this.#deps.stepState.inProgress('lookupProxyByDfspId-7')
184
- const proxyName = await this.#deps.proxyCache.lookupProxyByDfspId(fspId)
178
+ this.deps.stepState.inProgress('lookupProxyByDfspId-7')
179
+ const proxyName = await this.deps.proxyCache.lookupProxyByDfspId(fspId)
185
180
  if (!proxyName) {
186
181
  log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
187
182
  // todo: delete reference in oracle
@@ -202,30 +197,30 @@ class GetPartiesService {
202
197
  }
203
198
 
204
199
  async getFilteredProxyList (proxy) {
205
- this.#deps.stepState.inProgress('getAllProxies-8')
200
+ this.deps.stepState.inProgress('getAllProxies-8')
206
201
  if (!this.proxyEnabled) {
207
202
  this.log.warn('proxyCache is not enabled')
208
203
  return []
209
204
  }
210
205
 
211
- const proxyNames = await this.#deps.proxies.getAllProxiesNames(this.#deps.config.SWITCH_ENDPOINT)
206
+ const proxyNames = await this.deps.proxies.getAllProxiesNames(this.deps.config.SWITCH_ENDPOINT)
212
207
  this.log.debug('getAllProxiesNames is done', { proxyNames })
213
208
  return proxyNames.filter(name => name !== proxy)
214
209
  }
215
210
 
216
211
  async triggerSendToProxiesFlow ({ proxyNames, headers, params, source }) {
217
212
  const log = this.log.child({ method: 'triggerSendToProxiesFlow' })
218
- this.#deps.stepState.inProgress('setSendToProxiesList-10')
219
- const alsReq = this.#deps.partiesUtils.alsRequestDto(source, params)
213
+ this.deps.stepState.inProgress('setSendToProxiesList-10')
214
+ const alsReq = this.deps.partiesUtils.alsRequestDto(source, params)
220
215
  log.info('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
221
216
 
222
- const isCached = await this.#deps.proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
217
+ const isCached = await this.deps.proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
223
218
  if (!isCached) {
224
219
  log.warn('failed to setSendToProxiesList')
225
220
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
226
221
  }
227
222
 
228
- this.#deps.stepState.inProgress('sendingProxyRequests-11')
223
+ this.deps.stepState.inProgress('sendingProxyRequests-11')
229
224
  const sending = proxyNames.map(
230
225
  sendTo => this.#forwardGetPartiesRequest({ sendTo, headers, params })
231
226
  .then(({ status, data } = {}) => ({ status, data }))
@@ -236,31 +231,15 @@ class GetPartiesService {
236
231
  // Failed requests should be handled by TTL expired/timeout handler
237
232
  // todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
238
233
  log.info('triggerSendToProxiesFlow is done:', { isOk, results, proxyNames, alsReq })
239
- this.#deps.stepState.inProgress('allSent-12')
234
+ this.deps.stepState.inProgress('allSent-12')
240
235
  if (!isOk) {
241
236
  log.warn('no successful requests sent to proxies')
242
237
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
243
238
  }
244
239
  }
245
240
 
246
- async #validateParticipant (participantId) {
247
- return this.#deps.participant.validateParticipant(participantId)
248
- }
249
-
250
- async #forwardGetPartiesRequest ({ sendTo, headers, params }) {
251
- this.#deps.stepState.inProgress('forwardRequest-3')
252
- const callbackEndpointType = this.#deps.partiesUtils.getPartyCbType(params.SubId)
253
- const options = this.#deps.partiesUtils.partiesRequestOptionsDto(params)
254
-
255
- return this.#deps.participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, this.#deps.childSpan)
256
- }
257
-
258
- // async sendSuccessCallback ({ headers, sendTo }) {
259
- // return this.#deps.participant.sendRequest(headers, sendTo,)
260
- // }
261
-
262
- async sendErrorCallback ({ requester, headers, params }) {
263
- this.#deps.stepState.inProgress('sendErrorCallback-9')
241
+ async sendPartyNotFoundErrorCallback ({ requester, headers, params }) {
242
+ this.deps.stepState.inProgress('sendErrorCallback-9')
264
243
  const callbackHeaders = createCallbackHeaders({
265
244
  requestHeaders: headers,
266
245
  partyIdType: params.Type,
@@ -271,20 +250,26 @@ class GetPartiesService {
271
250
  })
272
251
  const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
273
252
 
274
- await this.#deps.participant.sendErrorToParticipant(
275
- requester,
276
- this.#deps.partiesUtils.errorPartyCbType(params.SubId),
277
- fspiopError.toApiErrorObject(this.#deps.config.ERROR_HANDLING),
278
- callbackHeaders,
279
- params,
280
- this.#deps.childSpan
281
- )
253
+ await this.sendErrorCallback({
254
+ sendTo: requester,
255
+ errorInfo: fspiopError.toApiErrorObject(this.deps.config.ERROR_HANDLING),
256
+ headers: callbackHeaders,
257
+ params
258
+ })
282
259
  return fspiopError
283
260
  }
284
261
 
285
262
  async sendOracleDiscoveryRequest ({ headers, params, query }) {
286
- this.#deps.stepState.inProgress('oracleRequest-4')
287
- return this.#deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.#deps.cache)
263
+ this.deps.stepState.inProgress('oracleRequest-4')
264
+ return this.deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.deps.cache)
265
+ }
266
+
267
+ async #forwardGetPartiesRequest ({ sendTo, headers, params }) {
268
+ this.deps.stepState.inProgress('forwardRequest-3')
269
+ const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
270
+ const options = this.deps.partiesUtils.partiesRequestOptionsDto(params)
271
+
272
+ return this.deps.participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, this.deps.childSpan)
288
273
  }
289
274
  }
290
275
 
@@ -0,0 +1,80 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ * Eugen Klymniuk <eugen.klymniuk@infitx.com>
24
+
25
+ --------------
26
+ ******/
27
+
28
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
+ const { ERROR_MESSAGES } = require('../../../constants')
30
+ const BasePartiesService = require('./BasePartiesService')
31
+
32
+ class PutPartiesErrorService extends BasePartiesService {
33
+ async handleRequest () {
34
+ // todo: add impl.
35
+ }
36
+
37
+ async checkPayee ({ headers, params, payload, proxy }) {
38
+ const notValid = this.deps.partiesUtils.isNotValidPayeeCase(payload)
39
+ if (notValid) {
40
+ this.deps.stepState.inProgress('notValidPayeeCase-1')
41
+ this.log.warn('notValidPayee case - deleting Participants and run getPartiesByTypeAndID', { proxy, payload })
42
+ const swappedHeaders = this.deps.partiesUtils.swapSourceDestinationHeaders(headers)
43
+ await super.sendDeleteOracleRequest(swappedHeaders, params)
44
+ }
45
+ return notValid
46
+ }
47
+
48
+ async checkLastProxyCallback ({ destination, proxy, params }) {
49
+ this.deps.stepState.inProgress('checkLastProxyCallback-2')
50
+ const alsReq = this.deps.partiesUtils.alsRequestDto(destination, params) // or source?
51
+ const isLast = await this.deps.proxyCache.receivedErrorResponse(alsReq, proxy)
52
+ this.log.info(`got${isLast ? '' : 'NOT'} last error callback from proxy`, { proxy, alsReq, isLast })
53
+ return isLast
54
+ }
55
+
56
+ async identifyDestinationForErrorCallback (destination) {
57
+ this.deps.stepState.inProgress('validateParticipant-3')
58
+ const destinationParticipant = await super.validateParticipant(destination)
59
+ if (destinationParticipant) return destination
60
+
61
+ this.deps.stepState.inProgress('lookupProxyDestination-4')
62
+ const proxyName = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
63
+ if (proxyName) return proxyName
64
+
65
+ const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
66
+ this.log.warn(errMessage, { destination })
67
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
68
+ }
69
+
70
+ async sendErrorCallbackToParticipant ({ sendTo, headers, params, dataUri }) {
71
+ this.deps.stepState.inProgress('sendErrorToParticipant-5')
72
+ const errorInfo = PutPartiesErrorService.decodeDataUriPayload(dataUri)
73
+ await super.sendErrorCallback({
74
+ sendTo, errorInfo, headers, params
75
+ })
76
+ this.log.verbose('sendErrorCallbackToParticipant is done', { sendTo, errorInfo })
77
+ }
78
+ }
79
+
80
+ module.exports = PutPartiesErrorService
@@ -0,0 +1,108 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ * Eugen Klymniuk <eugen.klymniuk@infitx.com>
24
+
25
+ --------------
26
+ ******/
27
+
28
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
+ const { ERROR_MESSAGES } = require('../../../constants')
30
+ const BasePartiesService = require('./BasePartiesService')
31
+
32
+ const { RestMethods } = BasePartiesService.enums()
33
+
34
+ class PutPartiesService extends BasePartiesService {
35
+ async handleRequest () {
36
+ // todo: add impl.
37
+ }
38
+
39
+ async validateSourceParticipant ({ source, proxy }) {
40
+ this.deps.stepState.inProgress('validateSourceParticipant-1')
41
+ const requesterParticipant = await super.validateParticipant(source)
42
+
43
+ if (!requesterParticipant) {
44
+ if (!this.proxyEnabled || !proxy) {
45
+ const errMessage = ERROR_MESSAGES.sourceFspNotFound
46
+ this.log.warn(`${errMessage} and no proxy`, { source })
47
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
48
+ }
49
+ const isCached = await this.deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
50
+ // todo: think,if we should throw error if isCached === false?
51
+ this.log.info('addDfspIdToProxyMapping is done', { source, proxy, isCached })
52
+ }
53
+ }
54
+
55
+ async checkProxySuccessResponse ({ destination, source, headers, params }) {
56
+ if (this.proxyEnabled) {
57
+ this.deps.stepState.inProgress('checkProxySuccessResponse-2')
58
+ const alsReq = this.deps.partiesUtils.alsRequestDto(destination, params)
59
+
60
+ const isExists = await this.deps.proxyCache.receivedSuccessResponse(alsReq)
61
+ if (isExists) {
62
+ await this.#updateOracleWithParticipantMapping({ source, headers, params })
63
+ return
64
+ }
65
+ this.log.warn('destination is NOT in scheme, and no cached sendToProxiesList', { destination, alsReq })
66
+ // todo: think, if we need to throw an error here
67
+ }
68
+ }
69
+
70
+ async identifyDestinationForSuccessCallback (destination) {
71
+ this.deps.stepState.inProgress('validateDestinationParticipant-4')
72
+ const destinationParticipant = await super.validateParticipant(destination)
73
+ if (destinationParticipant) {
74
+ return destinationParticipant.name
75
+ }
76
+
77
+ const proxyName = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
78
+ if (!proxyName) {
79
+ const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
80
+ this.log.warn(`${errMessage} and no proxy`, { destination })
81
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
82
+ }
83
+ return proxyName
84
+ }
85
+
86
+ async sendSuccessCallback ({ sendTo, headers, params, dataUri }) {
87
+ this.deps.stepState.inProgress('#sendSuccessCallback-6')
88
+ const payload = PutPartiesService.decodeDataUriPayload(dataUri)
89
+ const callbackEndpointType = this.deps.partiesUtils.putPartyCbType(params.SubId)
90
+ const options = this.deps.partiesUtils.partiesRequestOptionsDto(params)
91
+
92
+ await this.deps.participant.sendRequest(
93
+ headers, sendTo, callbackEndpointType, RestMethods.PUT, payload, options
94
+ )
95
+ this.log.verbose('sendSuccessCallback is done', { sendTo, payload })
96
+ }
97
+
98
+ async #updateOracleWithParticipantMapping ({ source, headers, params }) {
99
+ this.deps.stepState.inProgress('#updateOracleWithParticipantMapping-3')
100
+ const mappingPayload = {
101
+ fspId: source
102
+ }
103
+ await this.deps.oracle.oracleRequest(headers, RestMethods.POST, params, null, mappingPayload, this.deps.cache)
104
+ this.log.info('oracle was updated with mappingPayload', { mappingPayload })
105
+ }
106
+ }
107
+
108
+ module.exports = PutPartiesService
@@ -26,7 +26,11 @@
26
26
  ******/
27
27
 
28
28
  const GetPartiesService = require('./GetPartiesService')
29
+ const PutPartiesService = require('./PutPartiesService')
30
+ const PutPartiesErrorService = require('./PutPartiesErrorService')
29
31
 
30
32
  module.exports = {
31
- GetPartiesService
33
+ GetPartiesService,
34
+ PutPartiesService,
35
+ PutPartiesErrorService
32
36
  }