@mojaloop/sdk-scheme-adapter 24.7.0 → 24.8.1-snapshot.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/.yarn/cache/{@mojaloop-central-services-shared-npm-18.23.2-5627dda2e3-5fb84a745d.zip → @mojaloop-central-services-shared-npm-18.24.0-34d9578f93-8c24dea9e4.zip} +0 -0
  2. package/.yarn/cache/@mojaloop-inter-scheme-proxy-cache-lib-npm-2.5.0-eeb80fe407-bf7e14ce33.zip +0 -0
  3. package/.yarn/cache/{@mojaloop-sdk-standard-components-npm-19.11.2-d6fd02bca7-0cbc9e56e2.zip → @mojaloop-sdk-standard-components-npm-19.14.0-snapshot.3-1229293931-a3faf5f3ac.zip} +0 -0
  4. package/.yarn/cache/{@types-node-npm-22.14.0-a09e354ed5-8bfae1d3c4.zip → @types-node-npm-22.14.1-ff7e0a29d7-e22363f40a.zip} +0 -0
  5. package/.yarn/cache/{@typescript-eslint-eslint-plugin-npm-8.29.0-9227710d0b-83475d3a47.zip → @typescript-eslint-eslint-plugin-npm-8.30.1-f4da10f397-dbdc516ad9.zip} +0 -0
  6. package/.yarn/cache/{@typescript-eslint-parser-npm-8.29.0-510bf7f523-96a1a8cc8a.zip → @typescript-eslint-parser-npm-8.30.1-bcee4d456e-cac3cfe1c1.zip} +0 -0
  7. package/.yarn/cache/{@typescript-eslint-scope-manager-npm-8.29.0-6046e43075-89a5999ba8.zip → @typescript-eslint-scope-manager-npm-8.30.1-4b479f2d73-cef9e70016.zip} +0 -0
  8. package/.yarn/cache/{@typescript-eslint-type-utils-npm-8.29.0-1674862818-553fde7826.zip → @typescript-eslint-type-utils-npm-8.30.1-0e1c22c03c-6283d4b4d0.zip} +0 -0
  9. package/.yarn/cache/@typescript-eslint-types-npm-8.30.1-8bfe1eac21-264c4d8e1b.zip +0 -0
  10. package/.yarn/cache/{@typescript-eslint-typescript-estree-npm-8.29.0-92fb2cc910-7275c61dc5.zip → @typescript-eslint-typescript-estree-npm-8.30.1-185919bfaf-f57a34e36d.zip} +0 -0
  11. package/.yarn/cache/{@typescript-eslint-utils-npm-8.29.0-ebf0886c15-81d1afc5de.zip → @typescript-eslint-utils-npm-8.30.1-e8c9d86e99-637b3b8b3d.zip} +0 -0
  12. package/.yarn/cache/{@typescript-eslint-visitor-keys-npm-8.29.0-e8a9b1561e-d306a7d96b.zip → @typescript-eslint-visitor-keys-npm-8.30.1-e4b2f0ebba-7878f1e3e2.zip} +0 -0
  13. package/.yarn/cache/dotenv-npm-16.5.0-67343a179e-6543fe87b5.zip +0 -0
  14. package/.yarn/cache/ioredis-npm-5.6.1-d69383b35a-89100a97b2.zip +0 -0
  15. package/.yarn/cache/{koa-npm-2.16.0-fccb365a23-01be3231d4.zip → koa-npm-2.16.1-7f26717794-4946d19efb.zip} +0 -0
  16. package/.yarn/cache/openapi-backend-npm-5.12.0-b2560843ff-0b13c6f128.zip +0 -0
  17. package/.yarn/cache/{ts-jest-npm-29.3.1-c9a9791a5c-7320bbfab2.zip → ts-jest-npm-29.3.2-cda1b1f7ad-aad8f81ba5.zip} +0 -0
  18. package/.yarn/cache/{type-fest-npm-4.39.1-227092867f-71ce0e2582.zip → type-fest-npm-4.40.0-18c72d1d94-af2863a707.zip} +0 -0
  19. package/.yarn/cache/{typescript-npm-5.8.2-b95d637f6a-7f9e3d7ac1.zip → typescript-npm-5.8.3-fbd7aef456-cb1d081c88.zip} +0 -0
  20. package/.yarn/cache/{typescript-patch-ef570fb450-a58d19ff98.zip → typescript-patch-9106e8a080-1b503525a8.zip} +0 -0
  21. package/.yarn/cache/yaml-npm-2.7.1-9e92f81b45-385f8115dd.zip +0 -0
  22. package/.yarn/install-state.gz +0 -0
  23. package/CHANGELOG.md +7 -0
  24. package/modules/api-svc/package.json +6 -6
  25. package/modules/api-svc/src/InboundServer/api.yaml +172 -133
  26. package/modules/api-svc/src/InboundServer/api_iso20022.yaml +39 -0
  27. package/modules/api-svc/src/InboundServer/api_template.yaml +170 -66
  28. package/modules/api-svc/src/InboundServer/handlers.js +26 -6
  29. package/modules/api-svc/src/InboundServer/index.js +2 -1
  30. package/modules/api-svc/src/InboundServer/middlewares.js +61 -21
  31. package/modules/api-svc/src/config.js +1 -0
  32. package/modules/api-svc/src/lib/model/InboundPingModel.js +100 -0
  33. package/modules/api-svc/src/lib/model/index.js +3 -2
  34. package/modules/api-svc/test/__mocks__/@mojaloop/sdk-standard-components.js +2 -0
  35. package/modules/api-svc/test/unit/lib/model/InboundPingModel.test.js +124 -0
  36. package/modules/outbound-command-event-handler/package.json +8 -8
  37. package/modules/outbound-domain-event-handler/package.json +7 -7
  38. package/modules/private-shared-lib/package.json +7 -7
  39. package/package.json +6 -6
  40. package/.yarn/cache/@mojaloop-api-snippets-npm-17.10.1-4e48158984-9a0f1d2fd2.zip +0 -0
  41. package/.yarn/cache/@mojaloop-central-services-logger-npm-11.7.0-bd1e0d14fc-386d668607.zip +0 -0
  42. package/.yarn/cache/@mojaloop-inter-scheme-proxy-cache-lib-npm-2.4.0-cc60317958-8e539f65c3.zip +0 -0
  43. package/.yarn/cache/@mojaloop-ml-schema-transformer-lib-npm-2.7.0-bc64d97e72-bad585bd7d.zip +0 -0
  44. package/.yarn/cache/@rollup-rollup-linux-x64-musl-npm-4.37.0-51462d4265-8.zip +0 -0
  45. package/.yarn/cache/@typescript-eslint-types-npm-8.29.0-be9f1bbfb7-30bf710e21.zip +0 -0
@@ -1,71 +1,175 @@
1
- openapi: 3.0.0
1
+ openapi: 3.0.2
2
2
  info:
3
- version: '1.1'
3
+ version: '2.0-draft'
4
4
  title: Open API for FSP Interoperability (FSPIOP)
5
5
  description: >-
6
- Based on API Definition.docx updated on 2020-05-19 Version 1.1.
7
- API supports a maximum size of 65536 bytes (64 Kilobytes) in the HTTP
8
- header.
6
+ Revision date: 2023-11-23
7
+ Based on [API Definition updated on 2020-05-19 Version
8
+ 1.1](https://github.com/mojaloop/mojaloop-specification/blob/main/documents/v1.1-document-set/API%20Definition_v1.1.pdf).
9
+
10
+ This is implementation friendly version of the API definition.
11
+
12
+ It includes the below definitions needed for third-party functionality.
13
+ - AuthenticationType
14
+ - U2F enum
15
+ - AuthenticationValue
16
+ - oneOf is changed to anyOf
17
+ - new element is added U2FPinValue
18
+ - New element U2FPIN
19
+
20
+ **Note:** The API supports a maximum size of 65536 bytes (64 Kilobytes) in
21
+ the HTTP header.
9
22
  license:
10
- name: Open API for FSP Interoperability (FSPIOP)
23
+ name: CC BY-ND 4.0
24
+ url: 'https://github.com/mojaloop/mojaloop-specification/blob/main/LICENSE.md'
25
+ contact:
26
+ name: Sam Kummary
27
+ url: 'https://github.com/mojaloop/mojaloop-specification/issues'
28
+ servers:
29
+ - url: 'protocol://hostname:<port>/switch/'
30
+ variables:
31
+ protocol:
32
+ enum:
33
+ - http
34
+ - https
35
+ default: https
11
36
  paths:
12
- '/participants/{ID}/error':
13
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/participants_ID_error.yaml'
14
- '/participants/{ID}':
15
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/participants_ID.yaml'
16
- '/participants/{Type}/{ID}/error':
17
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/participants_Type_ID_error.yaml'
18
- '/participants/{Type}/{ID}/{SubId}/error':
19
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/participants_Type_ID_SubId_error.yaml'
20
- '/participants/{Type}/{ID}/{SubId}':
21
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/participants_Type_ID_SubId.yaml'
22
- '/participants/{Type}/{ID}':
23
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/participants_Type_ID.yaml'
24
- '/participants':
25
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/participants.yaml'
26
- '/parties/{Type}/{ID}':
27
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/parties_Type_ID.yaml'
28
- '/parties/{Type}/{ID}/error':
29
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/parties_Type_ID_error.yaml'
30
- '/parties/{Type}/{ID}/{SubId}':
31
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/parties_Type_ID_SubId.yaml'
32
- '/parties/{Type}/{ID}/{SubId}/error':
33
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/parties_Type_ID_SubId_error.yaml'
34
- '/transactionRequests/{ID}/error':
35
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transactionRequests_ID_error.yaml'
36
- '/transactionRequests/{ID}':
37
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transactionRequests_ID.yaml'
38
- '/transactionRequests':
39
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transactionRequests.yaml'
40
- '/quotes/{ID}/error':
41
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/quotes_ID_error.yaml'
42
- '/quotes/{ID}':
43
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/quotes_ID.yaml'
44
- '/quotes':
45
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/quotes.yaml'
46
- '/authorizations/{ID}':
47
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/authorizations_ID.yaml'
48
- '/authorizations/{ID}/error':
49
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/authorizations_ID_error.yaml'
50
- '/transfers/{ID}/error':
51
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transfers_ID_error.yaml'
52
- '/transfers/{ID}':
53
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transfers_ID.yaml'
54
- '/transfers':
55
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transfers.yaml'
56
- '/transactions/{ID}':
57
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transactions_ID.yaml'
58
- '/transactions/{ID}/error':
59
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/transactions_ID_error.yaml'
60
- '/bulkQuotes/{ID}/error':
61
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/bulkQuotes_ID_error.yaml'
62
- '/bulkQuotes/{ID}':
63
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/bulkQuotes_ID.yaml'
64
- '/bulkQuotes':
65
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/bulkQuotes.yaml'
66
- '/bulkTransfers/{ID}':
67
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/bulkTransfers_ID.yaml'
68
- '/bulkTransfers':
69
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/bulkTransfers.yaml'
70
- '/bulkTransfers/{ID}/error':
71
- $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v1_1/openapi3/paths/bulkTransfers_ID_error.yaml'
37
+ /interface:
38
+ post:
39
+ description: >-
40
+ Essential path to include schema definitions that are not used so that
41
+ these definitions get included into the openapi-cli bundle api
42
+ definition so that they get converted into typescript definitions.
43
+ operationId: test
44
+ requestBody:
45
+ content:
46
+ application/json:
47
+ schema:
48
+ oneOf:
49
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/BinaryString.yaml'
50
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/BinaryString32.yaml'
51
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/Date.yaml'
52
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/Integer.yaml'
53
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/Name.yaml'
54
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/PersonalIdentifierType.yaml'
55
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/TokenCode.yaml'
56
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/Transaction.yaml'
57
+ - $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/UndefinedEnum.yaml'
58
+ responses:
59
+ 200:
60
+ description: Ok
61
+ /ping:
62
+ post:
63
+ description: The HTTP request `POST /ping` is used to validate mTLS and JWS
64
+ summary: For testing mTLS and JWS
65
+ tags:
66
+ - participants
67
+ - ping
68
+ operationId: handlePostPing
69
+ requestBody:
70
+ description: The object sent in the POST/PUT `/ping` requests with validation request ID.
71
+ required: true
72
+ content:
73
+ application/json:
74
+ schema:
75
+ type: object
76
+ properties:
77
+ requestId:
78
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/schemas/CorrelationId.yaml'
79
+ required:
80
+ - requestId
81
+ responses:
82
+ '202':
83
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/202.yaml'
84
+ '400':
85
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/400.yaml'
86
+ '401':
87
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/401.yaml'
88
+ '403':
89
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/403.yaml'
90
+ '404':
91
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/404.yaml'
92
+ '405':
93
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/405.yaml'
94
+ '406':
95
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/406.yaml'
96
+ '501':
97
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/501.yaml'
98
+ '503':
99
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/components/responses/503.yaml'
100
+ /participants:
101
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/participants.yaml'
102
+ /participants/{ID}:
103
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/participants_ID.yaml'
104
+ /participants/{ID}/error:
105
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/participants_ID_error.yaml'
106
+ /participants/{Type}/{ID}:
107
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/participants_Type_ID.yaml'
108
+ /participants/{Type}/{ID}/error:
109
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/participants_Type_ID_error.yaml'
110
+ /participants/{Type}/{ID}/{SubId}:
111
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/participants_Type_ID_SubId.yaml'
112
+ /participants/{Type}/{ID}/{SubId}/error:
113
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/participants_Type_ID_SubId_error.yaml'
114
+ /parties/{Type}/{ID}:
115
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/parties_Type_ID.yaml'
116
+ /parties/{Type}/{ID}/error:
117
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/parties_Type_ID_error.yaml'
118
+ /parties/{Type}/{ID}/{SubId}:
119
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/parties_Type_ID_SubId.yaml'
120
+ /parties/{Type}/{ID}/{SubId}/error:
121
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/parties_Type_ID_SubId_error.yaml'
122
+ /transactionRequests:
123
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transactionRequests.yaml'
124
+ /transactionRequests/{ID}:
125
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transactionRequests_ID.yaml'
126
+ /transactionRequests/{ID}/error:
127
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transactionRequests_ID_error.yaml'
128
+ /quotes:
129
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/quotes.yaml'
130
+ /quotes/{ID}:
131
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/quotes_ID.yaml'
132
+ /quotes/{ID}/error:
133
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/quotes_ID_error.yaml'
134
+ /authorizations/{ID}:
135
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/authorizations_ID.yaml'
136
+ /authorizations/{ID}/error:
137
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/authorizations_ID_error.yaml'
138
+ /transfers:
139
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transfers.yaml'
140
+ /transfers/{ID}:
141
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transfers_ID.yaml'
142
+ /transfers/{ID}/error:
143
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transfers_ID_error.yaml'
144
+ /transactions/{ID}:
145
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transactions_ID.yaml'
146
+ /transactions/{ID}/error:
147
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/transactions_ID_error.yaml'
148
+ /bulkQuotes:
149
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/bulkQuotes.yaml'
150
+ /bulkQuotes/{ID}:
151
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/bulkQuotes_ID.yaml'
152
+ /bulkQuotes/{ID}/error:
153
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/bulkQuotes_ID_error.yaml'
154
+ /bulkTransfers:
155
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/bulkTransfers.yaml'
156
+ /bulkTransfers/{ID}:
157
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/bulkTransfers_ID.yaml'
158
+ /bulkTransfers/{ID}/error:
159
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/bulkTransfers_ID_error.yaml'
160
+ /fxQuotes:
161
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/fxQuotes.yaml'
162
+ /fxQuotes/{ID}:
163
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/fxQuotes_ID.yaml'
164
+ /fxQuotes/{ID}/error:
165
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/fxQuotes_ID_error.yaml'
166
+ /fxTransfers:
167
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/fxTransfers.yaml'
168
+ /fxTransfers/{ID}:
169
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/fxTransfers_ID.yaml'
170
+ /fxTransfers/{ID}/error:
171
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/fxTransfers_ID_error.yaml'
172
+ /services/FXP:
173
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/services_FXP.yaml'
174
+ /services/FXP/{SourceCurrency}/{TargetCurrency}:
175
+ $ref: '../../../../node_modules/@mojaloop/api-snippets/fspiop/v2_0/openapi3/paths/services_FXP_SourceCurrency_TargetCurrency.yaml'
@@ -34,6 +34,7 @@
34
34
  const { Enum } = require('@mojaloop/central-services-shared');
35
35
  const {
36
36
  InboundTransfersModel,
37
+ InboundPingModel,
37
38
  PartiesModel,
38
39
  QuotesModel,
39
40
  TransfersModel,
@@ -411,8 +412,8 @@ const putParticipantsByTypeAndId = async (ctx) => {
411
412
  // publish an event onto the cache for subscribers to action
412
413
  let cacheId = `${idType}_${idValue}` + (idSubValue ? `_${idSubValue}` : '');
413
414
  const message = { data };
414
-
415
- // We need to determine if this callback is a response to either a GET/POST /participants
415
+
416
+ // We need to determine if this callback is a response to either a GET/POST /participants
416
417
  // or DELETE /participants/{Type}/{ID}/{SubId} request
417
418
  const adCacheId = `ad_${cacheId}`;
418
419
  if (ctx.state.cache._callbacks[adCacheId]) {
@@ -431,8 +432,8 @@ const putParticipantsByTypeAndId = async (ctx) => {
431
432
 
432
433
 
433
434
  /**
434
- * Handles a PUT /participants/{Type}/{ID}/{SubId}/error request.
435
- * This is an error response to a GET /participants/{Type}/{ID}/{SubId} or
435
+ * Handles a PUT /participants/{Type}/{ID}/{SubId}/error request.
436
+ * This is an error response to a GET /participants/{Type}/{ID}/{SubId} or
436
437
  * DELETE /participants/{Type}/{ID}/{SubId} request
437
438
  */
438
439
  const putParticipantsByTypeAndIdError = async(ctx) => {
@@ -450,7 +451,7 @@ const putParticipantsByTypeAndIdError = async(ctx) => {
450
451
  let cacheId = `${idType}_${idValue}` + (idSubValue ? `_${idSubValue}` : '');
451
452
  const message = { data };
452
453
 
453
- // We need to determine if this callback is a response to either a GET/POST /participants
454
+ // We need to determine if this callback is a response to either a GET/POST /participants
454
455
  // or DELETE /participants/{Type}/{ID}/{SubId} request
455
456
  const adCacheId = `ad_${cacheId}`;
456
457
  if (ctx.state.cache._callbacks[adCacheId]) {
@@ -1105,6 +1106,22 @@ const createPutFxTransfersHandler = (success) => async (ctx) => {
1105
1106
  ctx.response.status = ReturnCodes.OK.CODE;
1106
1107
  };
1107
1108
 
1109
+ const handlePostPing = (ctx) => {
1110
+ const { jwsPingValidationResult, conf, logger, wso2 } = ctx.state;
1111
+ const { sourceFspId, body, headers } = extractBodyHeadersSourceFspId(ctx);
1112
+
1113
+ const model = new InboundPingModel({
1114
+ ...conf,
1115
+ resourceVersions: ctx.resourceVersions,
1116
+ logger,
1117
+ wso2,
1118
+ });
1119
+ model.postPing({ jwsPingValidationResult, sourceFspId, body, headers })
1120
+ .catch(err => logger.error('error in handlePostPing:', err));
1121
+
1122
+ prepareResponse(ctx);
1123
+ };
1124
+
1108
1125
  module.exports = {
1109
1126
  '/': {
1110
1127
  get: healthCheck
@@ -1217,5 +1234,8 @@ module.exports = {
1217
1234
  },
1218
1235
  '/fxTransfers/{ID}/error': {
1219
1236
  put: createPutFxTransfersHandler(false)
1220
- }
1237
+ },
1238
+ '/ping': {
1239
+ post: handlePostPing
1240
+ },
1221
1241
  };
@@ -125,7 +125,8 @@ class InboundApi extends EventEmitter {
125
125
  api.use(middlewares.createJwsValidator(logger, jwsVerificationKeys, jwsExclusions));
126
126
  }
127
127
 
128
- api.use(middlewares.applyState({ cache, wso2, conf, logExcludePaths }));
128
+ api.use(middlewares.applyState({ conf, cache, wso2, logExcludePaths }));
129
+ api.use(middlewares.createPingMiddleware(conf, jwsVerificationKeys));
129
130
  api.use(middlewares.createRequestValidator(validator));
130
131
  api.use(middlewares.assignFspiopIdentifier());
131
132
  if (conf.enableTestFeatures) {
@@ -25,8 +25,8 @@
25
25
  --------------
26
26
  ******/
27
27
  const { env } = require('node:process');
28
- const coBody = require('co-body');
29
28
  const { generateSlug } = require('random-word-slugs');
29
+ const coBody = require('co-body');
30
30
 
31
31
  const { Jws, Errors, common } = require('@mojaloop/sdk-standard-components');
32
32
  const { ReturnCodes } = require('@mojaloop/central-services-shared').Enum.Http;
@@ -58,7 +58,7 @@ const createErrorHandler = (logger) => async (ctx, next) => {
58
58
  await next();
59
59
  } catch (err) {
60
60
  // TODO: return a 500 here if the response has not already been sent?
61
- logger.isErrorEnabled && logger.push({ err }).error('Error caught in catchall');
61
+ logger.error('Error caught in catchall: ', err);
62
62
  }
63
63
  };
64
64
 
@@ -261,7 +261,7 @@ const createHeaderValidator = (conf) => async (
261
261
 
262
262
  // Only validate requests for the requested resources
263
263
  if (!resources.includes(resource)) {
264
- logger.info(`skip validation for ${resource}`);
264
+ logger.info(`skipping header validation for ${resource}`);
265
265
  return await next();
266
266
  }
267
267
 
@@ -347,17 +347,9 @@ const createHeaderValidator = (conf) => async (
347
347
  return;
348
348
  }
349
349
 
350
- try {
351
- ctx.request.body = await coBody.json(ctx.req, { limit: conf.fspiopApiServerMaxRequestBytes });
352
- }
353
- catch(err) {
354
- // error parsing body
355
- logger.push({ err }).error('Error parsing body');
356
- ctx.response.status = Errors.MojaloopApiErrorCodes.MALFORMED_SYNTAX.httpStatusCode;
357
- ctx.response.body = new Errors.MojaloopFSPIOPError(err, err.message, null,
358
- Errors.MojaloopApiErrorCodes.MALFORMED_SYNTAX).toApiErrorObject();
359
- return;
360
- }
350
+ const isOk = await extractRequestBody(conf, ctx);
351
+ if (!isOk) return;
352
+
361
353
  await next();
362
354
  };
363
355
 
@@ -372,7 +364,7 @@ const createHeaderValidator = (conf) => async (
372
364
  const createJwsValidator = (logger, keys, exclusions) => {
373
365
  // todo: take logger from ctx
374
366
  const jwsValidator = new Jws.validator({
375
- logger: logger,
367
+ logger,
376
368
  validationKeys: keys,
377
369
  });
378
370
  // JWS validation for incoming requests
@@ -383,22 +375,23 @@ const createJwsValidator = (logger, keys, exclusions) => {
383
375
  if (exclusions.includes('putParties')
384
376
  && ctx.request.method === 'PUT'
385
377
  && ctx.request.path.startsWith('/parties/')) {
386
- logger.isInfoEnabled && logger.info('Skipping jws validation on put parties. config flag is set');
378
+ logger.info('skipping jws validation on put parties. config flag is set');
387
379
  return await next();
388
380
  }
389
381
 
382
+ if (isPingRoute(ctx)) return await next();
383
+
390
384
  // we dont check signatures on GET requests
391
385
  // todo: validate this requirement. No state is mutated by GETs but
392
386
  // there are potential security issues if message origin is used to
393
387
  // determine permission sets i.e. what is "readable"
394
388
  if (ctx.request.method !== 'GET') {
395
389
  logger.isDebugEnabled && logger.push({ request: ctx.request, body: ctx.request.body }).debug('Validating JWS');
396
- jwsValidator.validate(ctx.request, logger);
390
+ jwsValidator.validate(ctx.request);
397
391
  }
398
392
 
399
- }
400
- catch(err) {
401
- logger.push({ err }).error('Inbound request failed JWS validation');
393
+ } catch (err) {
394
+ logger.error('Inbound request failed JWS validation', err);
402
395
 
403
396
  ctx.response.status = ReturnCodes.BADREQUEST.CODE;
404
397
  ctx.response.body = new Errors.MojaloopFSPIOPError(
@@ -445,7 +438,6 @@ const createLogger = (logger) => async (ctx, next) => {
445
438
  await next();
446
439
  };
447
440
 
448
-
449
441
  /**
450
442
  * Add validation for each inbound request
451
443
  * @param validator
@@ -516,6 +508,53 @@ const createResponseLogging = () => async (ctx, next) => {
516
508
  return await next();
517
509
  };
518
510
 
511
+ const createPingMiddleware = (config, validationKeys) => async (ctx, next) => {
512
+ if (!isPingRoute(ctx)) return await next();
513
+
514
+ const { logger } = ctx.state;
515
+ const isOk = await extractRequestBody(config, ctx);
516
+ if (!isOk) {
517
+ logger.warn('failed to extract request body');
518
+ return;
519
+ }
520
+
521
+ let result;
522
+
523
+ if (validationKeys) {
524
+ const jwsValidator = new Jws.validator({
525
+ logger,
526
+ validationKeys,
527
+ });
528
+
529
+ try {
530
+ result = jwsValidator.validate(ctx.request);
531
+ } catch (err) {
532
+ result = err;
533
+ }
534
+ }
535
+
536
+ ctx.state.jwsPingValidationResult = result;
537
+ logger.verbose(`is jwsPingValidation passed: ${result === true}`);
538
+
539
+ await next();
540
+ };
541
+
542
+ const extractRequestBody = async (conf, ctx) => {
543
+ try {
544
+ ctx.request.body = await coBody.json(ctx.req, { limit: conf.fspiopApiServerMaxRequestBytes });
545
+ return true;
546
+ } catch (err) {
547
+ // error parsing body
548
+ ctx.state.logger.error('Error parsing body: ', err);
549
+ ctx.response.status = Errors.MojaloopApiErrorCodes.MALFORMED_SYNTAX.httpStatusCode;
550
+ ctx.response.body = new Errors.MojaloopFSPIOPError(err, err.message, null,
551
+ Errors.MojaloopApiErrorCodes.MALFORMED_SYNTAX).toApiErrorObject();
552
+
553
+ }
554
+ };
555
+
556
+ const isPingRoute = (ctx) => ctx.request?.path?.startsWith('/ping');
557
+
519
558
  module.exports = {
520
559
  applyState,
521
560
  assignFspiopIdentifier,
@@ -528,5 +567,6 @@ module.exports = {
528
567
  createRequestValidator,
529
568
  createResponseBodyHandler,
530
569
  createResponseLogging,
570
+ createPingMiddleware,
531
571
  logResponse,
532
572
  };
@@ -157,6 +157,7 @@ module.exports = {
157
157
  bulkTransfersEndpoint: env.get('BULK_TRANSFERS_ENDPOINT').asString(),
158
158
  fxQuotesEndpoint: env.get('FX_QUOTES_ENDPOINT').asString(),
159
159
  fxTransfersEndpoint: env.get('FX_TRANSFERS_ENDPOINT').asString(),
160
+ pingEndpoint: env.get('PING_ENDPOINT').asString(),
160
161
  backendEndpoint: env.get('BACKEND_ENDPOINT').required().asString(),
161
162
 
162
163
  getServicesFxpResponse: env.get('GET_SERVICES_FXP_RESPONSE').default('').asArray(),
@@ -0,0 +1,100 @@
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 { requests: { PingRequests }, Errors } = require('@mojaloop/sdk-standard-components');
29
+ const { Headers } = require('@mojaloop/central-services-shared').Enum.Http;
30
+
31
+ class InboundPingModel {
32
+ constructor(config) {
33
+ this.logger = config.logger.push({ component: this.constructor.name });
34
+ this.dfspId = config.dfspId;
35
+ this.pingRequests = new PingRequests({
36
+ logger: this.logger,
37
+ peerEndpoint: config.peerEndpoint,
38
+ pingEndpoint: config.pingEndpoint,
39
+ dfspId: config.dfspId,
40
+ tls: {
41
+ enabled: config.outbound.tls.mutualTLS.enabled,
42
+ creds: config.outbound.tls.creds,
43
+ },
44
+ jwsSign: config.jwsSign,
45
+ jwsSigningKey: config.jwsSigningKey,
46
+ // todo: think, if we need the rest
47
+ wso2: config.wso2,
48
+ resourceVersions: config.resourceVersions,
49
+ apiType: config.apiType,
50
+ });
51
+ }
52
+
53
+ async postPing({ jwsPingValidationResult, sourceFspId, body, headers }) {
54
+ const { requestId } = body;
55
+ const log = this.logger.child({ requestId, sourceFspId });
56
+ log.debug('postPing...', { jwsPingValidationResult, headers });
57
+
58
+ if (jwsPingValidationResult === true) {
59
+ log.verbose('ping JWS validation passed, sending PUT ping callback...');
60
+ return this.pingRequests.putPing({
61
+ requestId,
62
+ destination: sourceFspId,
63
+ headers: this.#createCallbackHeaders(headers),
64
+ });
65
+ }
66
+
67
+ const errInfo = this.#createPingError(jwsPingValidationResult);
68
+ log.info('ping JWS validation failed, sending PUT ping error callback...', { errInfo });
69
+ return this.pingRequests.putPingError({
70
+ requestId,
71
+ destination: sourceFspId,
72
+ headers: this.#createCallbackHeaders(headers),
73
+ errInfo
74
+ });
75
+ }
76
+
77
+ #createPingError(jwsPingValidationResult, destination) {
78
+ const cause = jwsPingValidationResult || new Error('JWS validationKeys are not provided');
79
+ const errMessage = 'error on JWS ping validation';
80
+ const fspiopError = new Errors.MojaloopFSPIOPError(
81
+ cause,
82
+ errMessage,
83
+ destination,
84
+ Errors.MojaloopApiErrorCodes.VALIDATION_ERROR
85
+ );
86
+ this.logger.warn(`${errMessage}: ${cause.message}`);
87
+
88
+ return fspiopError.toApiErrorObject();
89
+ }
90
+
91
+ #createCallbackHeaders(headers) {
92
+ return {
93
+ ...headers,
94
+ [Headers.FSPIOP.DESTINATION]: headers[Headers.FSPIOP.SOURCE],
95
+ [Headers.FSPIOP.SOURCE]: this.dfspId
96
+ };
97
+ }
98
+ }
99
+
100
+ module.exports = InboundPingModel;
@@ -26,8 +26,8 @@
26
26
  ******/
27
27
  'use strict';
28
28
 
29
-
30
29
  const InboundTransfersModel = require('./InboundTransfersModel');
30
+ const InboundPingModel = require('./InboundPingModel');
31
31
  const OutboundTransfersModel = require('./OutboundTransfersModel');
32
32
  const OutboundBulkQuotesModel = require('./OutboundBulkQuotesModel');
33
33
  const OutboundBulkTransfersModel = require('./OutboundBulkTransfersModel');
@@ -43,11 +43,12 @@ const TransfersModel = require('./TransfersModel');
43
43
  module.exports = {
44
44
  AccountsModel,
45
45
  BackendError,
46
+ InboundTransfersModel,
47
+ InboundPingModel,
46
48
  OutboundBulkQuotesModel,
47
49
  OutboundBulkTransfersModel,
48
50
  OutboundRequestToPayTransferModel,
49
51
  OutboundRequestToPayModel,
50
- InboundTransfersModel,
51
52
  OutboundTransfersModel,
52
53
  ProxyModel,
53
54
  PersistentStateMachine,
@@ -33,6 +33,7 @@ const {
33
33
  axios,
34
34
  MojaloopRequests, Errors, WSO2Auth, Jws, Logger, common,
35
35
  httpRequester,
36
+ requests: { PingRequests },
36
37
  Ilp: { ILP_VERSIONS }
37
38
  } = jest.requireActual('@mojaloop/sdk-standard-components');
38
39
 
@@ -200,6 +201,7 @@ module.exports = {
200
201
  axios,
201
202
  Ilp,
202
203
  httpRequester,
204
+ requests: { PingRequests },
203
205
  MojaloopRequests: MockMojaloopRequests,
204
206
  Jws: {
205
207
  validator: MockJwsValidator,