account-lookup-service 17.4.1-csi-1300.0 → 17.4.1-csi-1300.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.
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.0",
4
+ "version": "17.4.1-csi-1300.2",
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",
@@ -0,0 +1,49 @@
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 { proxies } = require('@mojaloop/central-services-shared').Util
29
+ const oracle = require('../../models/oracle/facade')
30
+ const participant = require('../../models/participantEndpoint/facade')
31
+ const config = require('../../lib/config')
32
+ const partiesUtils = require('./partiesUtils')
33
+
34
+ const createDeps = ({ cache, proxyCache, childSpan, log, stepState }) => Object.freeze({
35
+ cache,
36
+ proxyCache,
37
+ childSpan,
38
+ log,
39
+ stepState,
40
+ config,
41
+ oracle,
42
+ participant,
43
+ proxies,
44
+ partiesUtils
45
+ })
46
+
47
+ module.exports = {
48
+ createDeps
49
+ }
@@ -23,38 +23,11 @@
23
23
  --------------
24
24
  **********/
25
25
 
26
- const { Enum, Util } = require('@mojaloop/central-services-shared')
27
- // const ErrorHandler = require('@mojaloop/central-services-error-handling')
28
26
  const Metrics = require('@mojaloop/central-services-metrics')
29
-
30
- const oracle = require('../../models/oracle/facade')
31
- const participant = require('../../models/participantEndpoint/facade')
32
- const config = require('../../lib/config')
33
27
  const libUtil = require('../../lib/util')
34
28
  const { logger } = require('../../lib')
35
- // const { createCallbackHeaders } = require('../../lib/headers')
36
- // const { ERROR_MESSAGES } = require('../../constants')
37
29
  const { GetPartiesService } = require('./services')
38
- const partiesUtils = require('./partiesUtils')
39
-
40
- // const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
41
- // const { Headers, RestMethods } = Enum.Http
42
- const { Headers } = Enum.Http
43
-
44
- // const proxyCacheTtlSec = 40 // todo: make configurable
45
-
46
- const createDeps = ({ cache, proxyCache, childSpan, log, stepState }) => Object.freeze({
47
- cache,
48
- proxyCache,
49
- childSpan,
50
- log,
51
- stepState,
52
- config,
53
- oracle,
54
- participant,
55
- proxies: Util.proxies,
56
- partiesUtils
57
- })
30
+ const { createDeps } = require('./deps')
58
31
 
59
32
  /**
60
33
  * @function getPartiesByTypeAndID
@@ -76,261 +49,28 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
76
49
  'Get party by Type and Id',
77
50
  ['success']
78
51
  ).startTimer()
52
+ const childSpan = span ? span.getChild(component) : undefined
79
53
  const log = logger.child({ component, params })
80
54
  const stepState = libUtil.initStepState()
81
- const childSpan = span ? span.getChild(component) : undefined
82
55
 
83
- const service = new GetPartiesService(createDeps({
84
- cache, proxyCache, childSpan, log, stepState
85
- }))
86
-
87
- const proxyEnabled = !!(config.PROXY_CACHE_CONFIG.enabled && proxyCache)
88
- const source = headers[Headers.FSPIOP.SOURCE]
89
- const proxy = proxyEnabled && headers[Headers.FSPIOP.PROXY]
90
- const destination = headers[Headers.FSPIOP.DESTINATION]
91
- // see https://github.com/mojaloop/design-authority/issues/79
92
- // the requester has specified a destination routing header. We should respect that and forward the request directly to the destination
93
- // without consulting any oracles.
94
-
95
- log.info('parties::getPartiesByTypeAndID start', { source, destination, proxy })
96
-
97
- let requester
98
- let fspiopError
56
+ const deps = createDeps({ cache, proxyCache, childSpan, log, stepState })
57
+ const service = new GetPartiesService(deps)
58
+ const results = {}
99
59
 
100
60
  try {
101
- requester = await service.validateRequester({ source, proxy })
102
-
103
- if (destination) {
104
- await service.forwardRequestToDestination({ destination, headers, params })
105
- // await forwardRequestToDestination({
106
- // destination, headers, options, callbackEndpointType, childSpan, proxyEnabled, proxyCache, log, stepState
107
- // })
108
- histTimerEnd({ success: true })
109
- return
110
- }
111
-
112
- const response = await service.sendOracleDiscoveryRequest({ headers, params, query })
113
-
114
- if (Array.isArray(response?.data?.partyList) && response.data.partyList.length > 0) {
115
- const partyList = service.filterOraclePartyList({ response, params })
116
- await service.processOraclePartyList({ partyList, headers, params, destination })
117
- // const partyList = filterOraclePartyList({ response, params, log, stepState })
118
- // await processOraclePartyList({
119
- // partyList, headers, params, destination, childSpan, proxyEnabled, proxyCache, log, stepState
120
- // })
121
- } else {
122
- log.info('empty partyList form oracle, getting proxies list...', { proxyEnabled, params })
123
- const proxyNames = await service.getFilteredProxyList(proxy)
124
- // getFilteredProxyList({ config, proxy, proxyEnabled, stepState })
125
-
126
- if (!proxyNames.length) {
127
- fspiopError = await service.sendErrorCallback({ requester, headers, params })
128
- // sendErrorCallback({
129
- // headers, params, requester, childSpan, stepState
130
- // })
131
- } else {
132
- await service.triggerSendToProxiesFlow({ proxyNames, headers, params, source })
133
- // await triggerSendToProxiesFlow({
134
- // proxyNames, headers, params, source, childSpan, proxyCache, log, stepState
135
- // })
136
- }
137
- }
138
- log.info('parties::getPartiesByTypeAndID is done')
61
+ await service.handleRequest({ headers, params, query, results })
62
+ log.info('getPartiesByTypeAndID is done')
139
63
  histTimerEnd({ success: true })
140
- } catch (err) {
141
- fspiopError = await partiesUtils.createErrorHandlerOnSendingCallback(config, log)(err, headers, params, requester)
64
+ } catch (error) {
65
+ const { requester } = results
66
+ results.fspiopError = await service.handleError({ error, requester, headers, params })
142
67
  histTimerEnd({ success: false })
143
- if (fspiopError) {
144
- libUtil.countFspiopError(fspiopError, { operation: component, step: stepState.step })
68
+ if (results.fspiopError) {
69
+ libUtil.countFspiopError(results.fspiopError, { operation: component, step: stepState.step })
145
70
  }
146
71
  } finally {
147
- await libUtil.finishSpanWithError(childSpan, fspiopError)
72
+ await libUtil.finishSpanWithError(childSpan, results.fspiopError)
148
73
  }
149
74
  }
150
75
 
151
- // const validateRequester = async ({ source, proxy, proxyCache, stepState }) => {
152
- // stepState.inProgress('validateRequester-0')
153
- // const log = logger.child({ source, method: 'validateRequester' })
154
- // const sourceParticipant = await participant.validateParticipant(source)
155
- // if (sourceParticipant) {
156
- // log.debug('source is in scheme')
157
- // return source
158
- // }
159
- //
160
- // if (!proxy) {
161
- // const errMessage = ERROR_MESSAGES.sourceFspNotFound
162
- // log.warn(errMessage)
163
- // throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
164
- // }
165
- //
166
- // const proxyParticipant = await participant.validateParticipant(proxy)
167
- // if (!proxyParticipant) {
168
- // const errMessage = ERROR_MESSAGES.partyProxyNotFound
169
- // log.warn(errMessage, { proxy })
170
- // throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
171
- // }
172
- //
173
- // const isCached = await proxyCache.addDfspIdToProxyMapping(source, proxy)
174
- // // think, what if isCached !== true?
175
- // log.info('source is added to proxyMapping cache:', { proxy, isCached })
176
- // return proxy
177
- // }
178
-
179
- // const forwardRequestToDestination = async ({
180
- // destination, headers, options, callbackEndpointType, childSpan, proxyEnabled, proxyCache, log, stepState
181
- // }) => {
182
- // let sendTo = destination
183
- // stepState.inProgress('validateDestination-1')
184
- //
185
- // const destParticipantModel = await participant.validateParticipant(destination)
186
- // if (!destParticipantModel) {
187
- // stepState.inProgress('lookupProxyDestination-2')
188
- // const proxyId = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
189
- //
190
- // if (!proxyId) {
191
- // log.warn('no destination participant, and no dfsp-to-proxy mapping', { destination })
192
- // const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
193
- // throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
194
- // }
195
- // sendTo = proxyId
196
- // }
197
- // // all ok, go ahead and forward the request
198
- // stepState.inProgress('forwardRequest-3')
199
- // await participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
200
- // log.info('discovery getPartiesByTypeAndID request was sent', { sendTo })
201
- // }
202
-
203
- // const filterOraclePartyList = ({ response, params, log, stepState }) => {
204
- // // 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:
205
- // stepState.inProgress('filterOraclePartyList-5')
206
- // const callbackEndpointType = partiesUtils.getPartyCbType(params.SubId)
207
- // let filteredResponsePartyList
208
- //
209
- // switch (callbackEndpointType) {
210
- // case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_GET:
211
- // filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
212
- // break
213
- // case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET:
214
- // filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
215
- // break
216
- // default:
217
- // filteredResponsePartyList = response // Fallback to providing the standard list
218
- // }
219
- //
220
- // if (!Array.isArray(filteredResponsePartyList) || !filteredResponsePartyList.length) {
221
- // const errMessage = 'Requested FSP/Party not found'
222
- // log.warn(errMessage)
223
- // throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
224
- // }
225
- //
226
- // return filteredResponsePartyList
227
- // }
228
-
229
- // const processOraclePartyList = async ({
230
- // partyList, headers, params, destination, childSpan, proxyEnabled, proxyCache, log, stepState
231
- // }) => {
232
- // const callbackEndpointType = partiesUtils.getPartyCbType(params.SubId)
233
- // const options = partiesUtils.partiesRequestOptionsDto(params)
234
- //
235
- // let sentCount = 0 // if sentCount === 0 after sending, should we restart the whole process?
236
- // const sending = partyList.map(async party => {
237
- // const { fspId } = party
238
- // const clonedHeaders = { ...headers }
239
- // if (!destination) {
240
- // clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
241
- // }
242
- // stepState.inProgress('validateParticipant-6')
243
- // const schemeParticipant = await participant.validateParticipant(fspId)
244
- // if (schemeParticipant) {
245
- // sentCount++
246
- // log.info('participant is in scheme', { fspId })
247
- // return participant.sendRequest(clonedHeaders, fspId, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
248
- // }
249
- //
250
- // // If the participant is not in the scheme and proxy routing is enabled,
251
- // // we should check if there is a proxy for it and send the request to the proxy
252
- // if (proxyEnabled) {
253
- // stepState.inProgress('lookupProxyByDfspId-7')
254
- // const proxyName = await proxyCache.lookupProxyByDfspId(fspId)
255
- // if (!proxyName) {
256
- // log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
257
- // // todo: delete reference in oracle
258
- // } else {
259
- // sentCount++
260
- // log.info('participant is NOT in scheme, use proxy name', { fspId, proxyName })
261
- // return participant.sendRequest(clonedHeaders, proxyName, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
262
- // }
263
- // }
264
- // })
265
- // await Promise.all(sending)
266
- // log.verbose('processOraclePartyList is done', { sentCount })
267
- // // todo: think what if sentCount === 0 here
268
- // }
269
-
270
- // const getFilteredProxyList = async ({ config, proxy, proxyEnabled, stepState }) => {
271
- // stepState.inProgress('getAllProxies-8')
272
- // if (!proxyEnabled) return []
273
- //
274
- // const proxyNames = await Util.proxies.getAllProxiesNames(config.SWITCH_ENDPOINT)
275
- // return proxyNames.filter(name => name !== proxy)
276
- // }
277
-
278
- // const sendErrorCallback = async ({
279
- // headers, params, requester, childSpan, stepState
280
- // }) => {
281
- // stepState.inProgress('sendErrorToParticipant-9')
282
- // const callbackHeaders = createCallbackHeaders({
283
- // requestHeaders: headers,
284
- // partyIdType: params.Type,
285
- // partyIdentifier: params.ID,
286
- // endpointTemplate: params.SubId
287
- // ? FspEndpointTemplates.PARTIES_SUB_ID_PUT_ERROR
288
- // : FspEndpointTemplates.PARTIES_PUT_ERROR
289
- // })
290
- // const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
291
- //
292
- // await participant.sendErrorToParticipant(
293
- // requester,
294
- // partiesUtils.errorPartyCbType(params.SubId),
295
- // fspiopError.toApiErrorObject(config.ERROR_HANDLING),
296
- // callbackHeaders,
297
- // params,
298
- // childSpan
299
- // )
300
- // return fspiopError
301
- // }
302
-
303
- // const triggerSendToProxiesFlow = async ({
304
- // proxyNames, headers, params, source, childSpan, proxyCache, log, stepState
305
- // }) => {
306
- // stepState.inProgress('setSendToProxiesList-10')
307
- // const alsReq = partiesUtils.alsRequestDto(source, params)
308
- // log.info('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
309
- //
310
- // const isCached = await proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
311
- // if (!isCached) {
312
- // log.warn('failed to setSendToProxiesList')
313
- // throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
314
- // }
315
- //
316
- // const callbackEndpointType = partiesUtils.getPartyCbType(params.SubId)
317
- // const options = partiesUtils.partiesRequestOptionsDto(params)
318
- // stepState.inProgress('sendingProxyRequests-11')
319
- // const sending = proxyNames.map(
320
- // proxyName => participant.sendRequest(headers, proxyName, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
321
- // .then(({ status, data } = {}) => ({ status, data }))
322
- // )
323
- // const results = await Promise.allSettled(sending)
324
- // const isOk = results.some(result => result.status === 'fulfilled')
325
- // // If, at least, one request is sent to proxy, we treat the whole flow as successful.
326
- // // Failed requests should be handled by TTL expired/timeout handler
327
- // // todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
328
- // log.info('triggerSendToProxiesFlow is done:', { isOk, results, proxyNames, alsReq })
329
- // stepState.inProgress('allSent-12')
330
- // if (!isOk) {
331
- // log.warn('no successful requests sent to proxies')
332
- // throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
333
- // }
334
- // }
335
-
336
76
  module.exports = getPartiesByTypeAndID
@@ -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')
@@ -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
  }
@@ -31,7 +31,6 @@
31
31
 
32
32
  const { Headers, RestMethods } = require('@mojaloop/central-services-shared').Enum.Http
33
33
  const { decodePayload } = require('@mojaloop/central-services-shared').Util.StreamingProtocol
34
- const { MojaloopApiErrorCodes } = require('@mojaloop/sdk-standard-components').Errors
35
34
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
36
35
  const Metrics = require('@mojaloop/central-services-metrics')
37
36
 
@@ -43,7 +42,8 @@ const { logger } = require('../../lib')
43
42
  const { ERROR_MESSAGES } = require('../../constants')
44
43
 
45
44
  const partiesUtils = require('./partiesUtils')
46
- const getPartiesByTypeAndID = require('./getPartiesByTypeAndID')
45
+ const services = require('./services')
46
+ const { createDeps } = require('./deps')
47
47
 
48
48
  /**
49
49
  * @function putPartiesByTypeAndID
@@ -158,103 +158,57 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
158
158
  'Put parties error by type and id',
159
159
  ['success']
160
160
  ).startTimer()
161
- const log = logger.child({ params, component })
161
+ const childSpan = span ? span.getChild(component) : undefined
162
+ const log = logger.child({ component, params })
163
+ const stepState = libUtil.initStepState()
164
+
165
+ const deps = createDeps({ cache, proxyCache, childSpan, log, stepState })
166
+ const service = new services.PutPartiesErrorService(deps)
167
+ const results = {}
168
+
162
169
  const destination = headers[Headers.FSPIOP.DESTINATION]
163
170
  const proxyEnabled = !!(Config.PROXY_CACHE_CONFIG.enabled && proxyCache)
164
171
  const proxy = proxyEnabled && headers[Headers.FSPIOP.PROXY]
165
-
166
- const childSpan = span ? span.getChild(component) : undefined
167
- const stepState = libUtil.initStepState()
168
172
  log.info('parties::putPartiesErrorByTypeAndID start', { destination, proxy })
169
173
 
170
- let sendTo
171
- let fspiopError
172
-
173
174
  try {
174
175
  if (proxy) {
175
- const isDone = await processProxyErrorCallback({
176
- headers, params, payload, childSpan, cache, proxyCache, log, proxy, destination, stepState
177
- })
178
- if (isDone) {
176
+ const notValid = await service.checkPayee({ headers, params, payload, proxy })
177
+ if (notValid) {
178
+ const getPartiesService = new services.GetPartiesService(deps)
179
+ // todo: think, if we need to remove destination header before starting new discovery
180
+ await getPartiesService.handleRequest({ headers, params, results })
181
+ log.info('putPartiesErrorByTypeAndID triggered new discovery flow')
182
+ histTimerEnd({ success: true })
183
+ return
184
+ }
185
+
186
+ const isLast = await service.checkLastProxyCallback({ destination, proxy, params })
187
+ if (!isLast) {
179
188
  log.info('putPartiesErrorByTypeAndID proxy callback was processed', { proxy })
180
189
  histTimerEnd({ success: true })
181
190
  return
182
191
  }
183
192
  }
184
193
 
185
- sendTo = await identifyDestinationForErrorCallback({
186
- destination, proxyCache, proxyEnabled, log, stepState
187
- })
188
-
189
- await sendErrorCallbackToParticipant({
190
- sendTo, headers, params, dataUri, childSpan, stepState
191
- })
194
+ const sendTo = await service.identifyDestinationForErrorCallback(destination)
195
+ results.requester = sendTo
196
+ await service.sendErrorCallbackToParticipant({ sendTo, headers, params, dataUri })
192
197
 
193
198
  log.info('putPartiesErrorByTypeAndID callback was sent', { sendTo })
194
199
  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 })
200
+ } catch (error) {
201
+ const { requester } = results
202
+ results.fspiopError = await service.handleError({ error, requester, headers, params })
203
+ if (results.fspiopError) {
204
+ libUtil.countFspiopError(results.fspiopError, { operation: component, step: stepState.step })
199
205
  }
200
206
  histTimerEnd({ success: false })
201
207
  } finally {
202
- await libUtil.finishSpanWithError(childSpan, fspiopError)
208
+ await libUtil.finishSpanWithError(childSpan, results.fspiopError)
203
209
  }
204
210
  }
205
211
 
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
225
- }
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
- }
257
-
258
212
  module.exports = {
259
213
  putPartiesByTypeAndID,
260
214
  putPartiesErrorByTypeAndID
@@ -0,0 +1,88 @@
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 { Enum } = require('@mojaloop/central-services-shared')
30
+
31
+ const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
32
+ const { Headers, RestMethods } = Enum.Http
33
+
34
+ class BasePartiesService {
35
+ constructor (deps) {
36
+ this.deps = deps
37
+ this.log = this.deps.log.child({ component: this.constructor.name })
38
+ this.proxyEnabled = !!(deps.config.PROXY_CACHE_CONFIG?.enabled && deps.proxyCache)
39
+ }
40
+
41
+ async handleRequest () {
42
+ throw new Error('handleRequest must be implemented by subclass')
43
+ }
44
+
45
+ async handleError ({ error, requester, headers, params }) {
46
+ const log = this.log.child({ method: 'handleError' })
47
+ try {
48
+ log.error('error in processing parties request: ', error)
49
+ const sendTo = requester || headers[Headers.FSPIOP.SOURCE]
50
+ const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(error)
51
+ const errorInfo = await this.deps.partiesUtils.makePutPartiesErrorPayload(this.deps.config, fspiopError, headers, params)
52
+
53
+ await this.sendErrorCallback({ sendTo, errorInfo, headers, params })
54
+ log.info('handleError in done', { sendTo, errorInfo })
55
+ return fspiopError
56
+ } catch (exc) {
57
+ // We can't do anything else here- we _must_ handle all errors _within_ this function because
58
+ // we've already sent a sync response- we cannot throw.
59
+ log.error('failed to handleError. No further processing! ', exc)
60
+ }
61
+ }
62
+
63
+ async validateParticipant (participantId) {
64
+ return this.deps.participant.validateParticipant(participantId)
65
+ }
66
+
67
+ async sendErrorCallback ({ sendTo, errorInfo, headers, params, payload = undefined }) {
68
+ const endpointType = this.deps.partiesUtils.errorPartyCbType(params.SubId)
69
+ return this.deps.participant.sendErrorToParticipant(
70
+ sendTo, endpointType, errorInfo, headers, params, payload, this.deps.childSpan
71
+ )
72
+ }
73
+
74
+ async sendDeleteOracleRequest (headers, params) {
75
+ return this.deps.oracle.oracleRequest(headers, RestMethods.DELETE, params, null, null, this.deps.cache)
76
+ }
77
+
78
+ static enums () {
79
+ return {
80
+ FspEndpointTypes,
81
+ FspEndpointTemplates,
82
+ Headers,
83
+ RestMethods
84
+ }
85
+ }
86
+ }
87
+
88
+ module.exports = BasePartiesService
@@ -26,66 +26,91 @@
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
+ class GetPartiesService extends BasePartiesService {
41
+ async handleRequest ({ headers, params, query, results }) {
42
+ const source = headers[Headers.FSPIOP.SOURCE]
43
+ const proxy = headers[Headers.FSPIOP.PROXY]
44
+ const destination = headers[Headers.FSPIOP.DESTINATION]
45
+ // see https://github.com/mojaloop/design-authority/issues/79
46
+ // the requester has specified a destination routing header. We should respect that and forward the request directly to the destination
47
+ // without consulting any oracles.
48
+ this.log.info('handling getParties request', { source, destination, proxy })
49
+
50
+ const requester = await this.validateRequester({ source, proxy })
51
+ results.requester = requester
52
+
53
+ if (destination) {
54
+ await this.forwardRequestToDestination({ destination, headers, params })
55
+ return
56
+ }
57
+ const response = await this.sendOracleDiscoveryRequest({ headers, params, query })
40
58
 
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
- }
59
+ if (Array.isArray(response?.data?.partyList) && response.data.partyList.length > 0) {
60
+ const partyList = this.filterOraclePartyList({ response, params })
61
+ await this.processOraclePartyList({ partyList, headers, params, destination })
62
+ return
63
+ }
64
+
65
+ this.log.info('empty partyList form oracle, getting proxyList...', { params })
66
+ const proxyNames = await this.getFilteredProxyList(proxy)
67
+
68
+ if (proxyNames.length) {
69
+ await this.triggerSendToProxiesFlow({ proxyNames, headers, params, source })
70
+ return
71
+ }
46
72
 
47
- async handleRequest () {
48
- // todo: add logic
73
+ results.fspiopError = await this.sendPartyNotFoundErrorCallback({ requester, headers, params })
49
74
  }
50
75
 
51
76
  async validateRequester ({ source, proxy }) {
52
- this.#deps.stepState.inProgress('validateRequester-0')
77
+ this.deps.stepState.inProgress('validateRequester-0')
53
78
  const log = this.log.child({ source, method: 'validateRequester' })
54
79
 
55
- const sourceParticipant = await this.#validateParticipant(source)
80
+ const sourceParticipant = await this.validateParticipant(source)
56
81
  if (sourceParticipant) {
57
82
  log.debug('source is in scheme')
58
83
  return source
59
84
  }
60
85
 
61
- if (!proxy) {
86
+ if (!this.proxyEnabled || !proxy) {
62
87
  const errMessage = ERROR_MESSAGES.sourceFspNotFound
63
88
  log.warn(errMessage)
64
89
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
65
90
  }
66
91
 
67
- const proxyParticipant = await this.#validateParticipant(proxy)
92
+ const proxyParticipant = await this.validateParticipant(proxy)
68
93
  if (!proxyParticipant) {
69
94
  const errMessage = ERROR_MESSAGES.partyProxyNotFound
70
95
  log.warn(errMessage, { proxy })
71
96
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
72
97
  }
73
98
 
74
- const isCached = await this.#deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
99
+ const isCached = await this.deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
75
100
  // think, what if isCached !== true?
76
101
  log.info('source is added to proxyMapping cache:', { proxy, isCached })
77
102
  return proxy
78
103
  }
79
104
 
80
105
  async forwardRequestToDestination ({ destination, headers, params }) {
81
- this.#deps.stepState.inProgress('validateDestination-1')
106
+ this.deps.stepState.inProgress('validateDestination-1')
82
107
  const log = this.log.child({ method: 'forwardRequestToDestination' })
83
108
  let sendTo = destination
84
109
 
85
- const destParticipantModel = await this.#validateParticipant(destination)
110
+ const destParticipantModel = await this.validateParticipant(destination)
86
111
  if (!destParticipantModel) {
87
- this.#deps.stepState.inProgress('lookupProxyDestination-2')
88
- 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)
89
114
 
90
115
  if (!proxyId) {
91
116
  log.warn('no destination participant, and no dfsp-to-proxy mapping', { destination })
@@ -101,8 +126,8 @@ class GetPartiesService {
101
126
 
102
127
  filterOraclePartyList ({ response, params }) {
103
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:
104
- this.#deps.stepState.inProgress('filterOraclePartyList-5')
105
- const callbackEndpointType = this.#deps.partiesUtils.getPartyCbType(params.SubId)
129
+ this.deps.stepState.inProgress('filterOraclePartyList-5')
130
+ const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
106
131
  let filteredResponsePartyList
107
132
 
108
133
  switch (callbackEndpointType) {
@@ -118,7 +143,7 @@ class GetPartiesService {
118
143
 
119
144
  if (!Array.isArray(filteredResponsePartyList) || !filteredResponsePartyList.length) {
120
145
  const errMessage = 'Requested FSP/Party not found'
121
- this.#deps.log.warn(errMessage)
146
+ this.log.warn(errMessage)
122
147
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
123
148
  }
124
149
 
@@ -135,8 +160,8 @@ class GetPartiesService {
135
160
  if (!destination) {
136
161
  clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
137
162
  }
138
- this.#deps.stepState.inProgress('validateParticipant-6')
139
- const schemeParticipant = await this.#validateParticipant(fspId)
163
+ this.deps.stepState.inProgress('validateParticipant-6')
164
+ const schemeParticipant = await this.validateParticipant(fspId)
140
165
  if (schemeParticipant) {
141
166
  sentCount++
142
167
  log.info('participant is in scheme', { fspId })
@@ -150,8 +175,8 @@ class GetPartiesService {
150
175
  // If the participant is not in the scheme and proxy routing is enabled,
151
176
  // we should check if there is a proxy for it and send the request to the proxy
152
177
  if (this.proxyEnabled) {
153
- this.#deps.stepState.inProgress('lookupProxyByDfspId-7')
154
- const proxyName = await this.#deps.proxyCache.lookupProxyByDfspId(fspId)
178
+ this.deps.stepState.inProgress('lookupProxyByDfspId-7')
179
+ const proxyName = await this.deps.proxyCache.lookupProxyByDfspId(fspId)
155
180
  if (!proxyName) {
156
181
  log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
157
182
  // todo: delete reference in oracle
@@ -172,27 +197,30 @@ class GetPartiesService {
172
197
  }
173
198
 
174
199
  async getFilteredProxyList (proxy) {
175
- this.#deps.stepState.inProgress('getAllProxies-8')
176
- if (!this.proxyEnabled) return []
200
+ this.deps.stepState.inProgress('getAllProxies-8')
201
+ if (!this.proxyEnabled) {
202
+ this.log.warn('proxyCache is not enabled')
203
+ return []
204
+ }
177
205
 
178
- 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)
179
207
  this.log.debug('getAllProxiesNames is done', { proxyNames })
180
208
  return proxyNames.filter(name => name !== proxy)
181
209
  }
182
210
 
183
211
  async triggerSendToProxiesFlow ({ proxyNames, headers, params, source }) {
184
212
  const log = this.log.child({ method: 'triggerSendToProxiesFlow' })
185
- this.#deps.stepState.inProgress('setSendToProxiesList-10')
186
- const alsReq = this.#deps.partiesUtils.alsRequestDto(source, params)
213
+ this.deps.stepState.inProgress('setSendToProxiesList-10')
214
+ const alsReq = this.deps.partiesUtils.alsRequestDto(source, params)
187
215
  log.info('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
188
216
 
189
- const isCached = await this.#deps.proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
217
+ const isCached = await this.deps.proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
190
218
  if (!isCached) {
191
219
  log.warn('failed to setSendToProxiesList')
192
220
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
193
221
  }
194
222
 
195
- this.#deps.stepState.inProgress('sendingProxyRequests-11')
223
+ this.deps.stepState.inProgress('sendingProxyRequests-11')
196
224
  const sending = proxyNames.map(
197
225
  sendTo => this.#forwardGetPartiesRequest({ sendTo, headers, params })
198
226
  .then(({ status, data } = {}) => ({ status, data }))
@@ -203,31 +231,15 @@ class GetPartiesService {
203
231
  // Failed requests should be handled by TTL expired/timeout handler
204
232
  // todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
205
233
  log.info('triggerSendToProxiesFlow is done:', { isOk, results, proxyNames, alsReq })
206
- this.#deps.stepState.inProgress('allSent-12')
234
+ this.deps.stepState.inProgress('allSent-12')
207
235
  if (!isOk) {
208
236
  log.warn('no successful requests sent to proxies')
209
237
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
210
238
  }
211
239
  }
212
240
 
213
- async #validateParticipant (participantId) {
214
- return this.#deps.participant.validateParticipant(participantId)
215
- }
216
-
217
- async #forwardGetPartiesRequest ({ sendTo, headers, params }) {
218
- this.#deps.stepState.inProgress('forwardRequest-3')
219
- const callbackEndpointType = this.#deps.partiesUtils.getPartyCbType(params.SubId)
220
- const options = this.#deps.partiesUtils.partiesRequestOptionsDto(params)
221
-
222
- return this.#deps.participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, this.#deps.childSpan)
223
- }
224
-
225
- // async sendSuccessCallback ({ headers, sendTo }) {
226
- // return this.#deps.participant.sendRequest(headers, sendTo,)
227
- // }
228
-
229
- async sendErrorCallback ({ requester, headers, params }) {
230
- this.#deps.stepState.inProgress('sendErrorCallback-9')
241
+ async sendPartyNotFoundErrorCallback ({ requester, headers, params }) {
242
+ this.deps.stepState.inProgress('sendErrorCallback-9')
231
243
  const callbackHeaders = createCallbackHeaders({
232
244
  requestHeaders: headers,
233
245
  partyIdType: params.Type,
@@ -238,20 +250,26 @@ class GetPartiesService {
238
250
  })
239
251
  const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
240
252
 
241
- await this.#deps.participant.sendErrorToParticipant(
242
- requester,
243
- this.#deps.partiesUtils.errorPartyCbType(params.SubId),
244
- fspiopError.toApiErrorObject(this.#deps.config.ERROR_HANDLING),
245
- callbackHeaders,
246
- params,
247
- this.#deps.childSpan
248
- )
253
+ await this.sendErrorCallback({
254
+ sendTo: requester,
255
+ errorInfo: fspiopError.toApiErrorObject(this.deps.config.ERROR_HANDLING),
256
+ headers: callbackHeaders,
257
+ params
258
+ })
249
259
  return fspiopError
250
260
  }
251
261
 
252
262
  async sendOracleDiscoveryRequest ({ headers, params, query }) {
253
- this.#deps.stepState.inProgress('oracleRequest-4')
254
- 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)
255
273
  }
256
274
  }
257
275
 
@@ -0,0 +1,81 @@
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 { ERROR_MESSAGES } = require('../../../constants')
31
+ const BasePartiesService = require('./BasePartiesService')
32
+
33
+ class PutPartiesErrorService extends BasePartiesService {
34
+ async handleRequest () {
35
+ // todo: add impl.
36
+ }
37
+
38
+ async checkPayee ({ headers, params, payload, proxy }) {
39
+ const notValid = this.deps.partiesUtils.isNotValidPayeeCase(payload)
40
+ if (notValid) {
41
+ this.deps.stepState.inProgress('notValidPayeeCase-1')
42
+ this.log.warn('notValidPayee case - deleting Participants and run getPartiesByTypeAndID', { proxy, payload })
43
+ const swappedHeaders = this.deps.partiesUtils.swapSourceDestinationHeaders(headers)
44
+ await super.sendDeleteOracleRequest(swappedHeaders, params)
45
+ }
46
+ return notValid
47
+ }
48
+
49
+ async checkLastProxyCallback ({ destination, proxy, params }) {
50
+ this.deps.stepState.inProgress('checkLastProxyCallback-2')
51
+ const alsReq = this.deps.partiesUtils.alsRequestDto(destination, params) // or source?
52
+ const isLast = await this.deps.proxyCache.receivedErrorResponse(alsReq, proxy)
53
+ this.log.info(`got${isLast ? '' : 'NOT'} last error callback from proxy`, { proxy, alsReq, isLast })
54
+ return isLast
55
+ }
56
+
57
+ async identifyDestinationForErrorCallback (destination) {
58
+ this.deps.stepState.inProgress('validateParticipant-3')
59
+ const destinationParticipant = await super.validateParticipant(destination)
60
+ if (destinationParticipant) return destination
61
+
62
+ this.deps.stepState.inProgress('lookupProxyDestination-4')
63
+ const proxyName = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
64
+ if (proxyName) return proxyName
65
+
66
+ const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
67
+ this.log.warn(errMessage, { destination })
68
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
69
+ }
70
+
71
+ async sendErrorCallbackToParticipant ({ sendTo, headers, params, dataUri }) {
72
+ this.deps.stepState.inProgress('sendErrorToParticipant-5')
73
+ const decodedPayload = decodePayload(dataUri, { asParsed: false })
74
+ const errorInfo = decodedPayload.body.toString()
75
+ return super.sendErrorCallback({
76
+ sendTo, errorInfo, headers, params
77
+ })
78
+ }
79
+ }
80
+
81
+ module.exports = PutPartiesErrorService
@@ -26,7 +26,9 @@
26
26
  ******/
27
27
 
28
28
  const GetPartiesService = require('./GetPartiesService')
29
+ const PutPartiesErrorService = require('./PutPartiesErrorService')
29
30
 
30
31
  module.exports = {
31
- GetPartiesService
32
+ GetPartiesService,
33
+ PutPartiesErrorService
32
34
  }