@mojaloop/sdk-scheme-adapter 11.18.8
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/.env.example +140 -0
- package/.eslintignore +2 -0
- package/.eslintrc.json +30 -0
- package/.nvmrc +1 -0
- package/.versionrc +15 -0
- package/CHANGELOG.md +118 -0
- package/InboundServer/api.yaml +3594 -0
- package/InboundServer/api_template.yaml +69 -0
- package/InboundServer/handlers.js +940 -0
- package/InboundServer/index.js +205 -0
- package/InboundServer/middlewares.js +426 -0
- package/OAuthTestServer/index.js +66 -0
- package/OAuthTestServer/model.js +70 -0
- package/OutboundServer/api.yaml +2732 -0
- package/OutboundServer/api_interfaces/index.d.ts +117 -0
- package/OutboundServer/api_interfaces/openapi.d.ts +1475 -0
- package/OutboundServer/api_template/components/parameters/bulkQuoteId.yaml +9 -0
- package/OutboundServer/api_template/components/parameters/bulkTransferId.yaml +9 -0
- package/OutboundServer/api_template/components/parameters/requestToPayTransactionId.yaml +9 -0
- package/OutboundServer/api_template/components/parameters/transferId.yaml +9 -0
- package/OutboundServer/api_template/components/responses/accountsCreationCompleted.yaml +5 -0
- package/OutboundServer/api_template/components/responses/accountsCreationError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/accountsCreationTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/responses/authorizationPostSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/authorizationsServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkQuoteTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/bulkTransferTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/responses/partiesByIdError404.yaml +9 -0
- package/OutboundServer/api_template/components/responses/partiesByIdSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/quotesPostSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/quotesServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/requestToPaySuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/requestToPayTransferBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/requestToPayTransferSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/simpleTransfersPostSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/simpleTransfersServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferBadRequest.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferServerError.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferSuccess.yaml +5 -0
- package/OutboundServer/api_template/components/responses/transferTimeout.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/accountCreationStatus.yaml +18 -0
- package/OutboundServer/api_template/components/schemas/accountsCreationState.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/accountsRequest.yaml +20 -0
- package/OutboundServer/api_template/components/schemas/accountsResponse.yaml +15 -0
- package/OutboundServer/api_template/components/schemas/async2SyncCurrentState.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/authorizationsPostRequest.yaml +15 -0
- package/OutboundServer/api_template/components/schemas/authorizationsPostResponse.yaml +19 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteErrorResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteRequest.yaml +26 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteResponse.yaml +21 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteStatus.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/bulkQuoteStatusResponse.yaml +17 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferErrorResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferRequest.yaml +26 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferResponse.yaml +16 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferStatus.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/bulkTransferStatusResponse.yaml +17 -0
- package/OutboundServer/api_template/components/schemas/errorAccountsResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/errorAuthorizationsResponse.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/errorQuotesResponse.yaml +9 -0
- package/OutboundServer/api_template/components/schemas/errorResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/errorSimpleTransfersResponse.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/errorTransferResponse.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/extensionListEmptiable.yaml +6 -0
- package/OutboundServer/api_template/components/schemas/individualQuote.yaml +32 -0
- package/OutboundServer/api_template/components/schemas/individualQuoteResult.yaml +28 -0
- package/OutboundServer/api_template/components/schemas/individualTransfer.yaml +32 -0
- package/OutboundServer/api_template/components/schemas/individualTransferFulfilment.yaml +13 -0
- package/OutboundServer/api_template/components/schemas/individualTransferResult.yaml +41 -0
- package/OutboundServer/api_template/components/schemas/mojaloopError.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/mojaloopTransactionRequestState.yaml +2 -0
- package/OutboundServer/api_template/components/schemas/partiesByIdResponse.yaml +13 -0
- package/OutboundServer/api_template/components/schemas/quote.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/quoteError.yaml +16 -0
- package/OutboundServer/api_template/components/schemas/quotesPostRequest.yaml +13 -0
- package/OutboundServer/api_template/components/schemas/quotesPostResponse.yaml +48 -0
- package/OutboundServer/api_template/components/schemas/requestToPayRequest.yaml +39 -0
- package/OutboundServer/api_template/components/schemas/requestToPayResponse.yaml +41 -0
- package/OutboundServer/api_template/components/schemas/requestToPayTransferRequest.yaml +42 -0
- package/OutboundServer/api_template/components/schemas/requestToPayTransferResponse.yaml +58 -0
- package/OutboundServer/api_template/components/schemas/simpleTransferServerError.yaml +5 -0
- package/OutboundServer/api_template/components/schemas/simpleTransfersPostRequest.yaml +12 -0
- package/OutboundServer/api_template/components/schemas/simpleTransfersPostResponse.yaml +11 -0
- package/OutboundServer/api_template/components/schemas/transactionType.yaml +4 -0
- package/OutboundServer/api_template/components/schemas/transferContinuationAcceptOTP.yaml +9 -0
- package/OutboundServer/api_template/components/schemas/transferContinuationAcceptParty.yaml +8 -0
- package/OutboundServer/api_template/components/schemas/transferContinuationAcceptQuote.yaml +9 -0
- package/OutboundServer/api_template/components/schemas/transferError.yaml +16 -0
- package/OutboundServer/api_template/components/schemas/transferFulfilment.yaml +3 -0
- package/OutboundServer/api_template/components/schemas/transferParty.yaml +40 -0
- package/OutboundServer/api_template/components/schemas/transferRequest.yaml +37 -0
- package/OutboundServer/api_template/components/schemas/transferResponse.yaml +58 -0
- package/OutboundServer/api_template/components/schemas/transferStatus.yaml +6 -0
- package/OutboundServer/api_template/components/schemas/transferStatusResponse.yaml +13 -0
- package/OutboundServer/api_template/health.yaml +12 -0
- package/OutboundServer/api_template/openapi.yaml +55 -0
- package/OutboundServer/api_template/paths/accounts.yaml +26 -0
- package/OutboundServer/api_template/paths/authorizations.yaml +19 -0
- package/OutboundServer/api_template/paths/bulkQuotes.yaml +23 -0
- package/OutboundServer/api_template/paths/bulkQuotes_bulkQuoteId.yaml +24 -0
- package/OutboundServer/api_template/paths/bulkTransfers.yaml +23 -0
- package/OutboundServer/api_template/paths/bulkTransfers_bulkTransferId.yaml +24 -0
- package/OutboundServer/api_template/paths/parties_Type_ID.yaml +20 -0
- package/OutboundServer/api_template/paths/parties_Type_ID_SubId.yaml +22 -0
- package/OutboundServer/api_template/paths/quotes.yaml +20 -0
- package/OutboundServer/api_template/paths/requestToPay.yaml +22 -0
- package/OutboundServer/api_template/paths/requestToPayTransfer.yaml +57 -0
- package/OutboundServer/api_template/paths/requestToPayTransfer_requestToPayTransactionId.yaml +34 -0
- package/OutboundServer/api_template/paths/simpleTransfers.yaml +19 -0
- package/OutboundServer/api_template/paths/transfers.yaml +55 -0
- package/OutboundServer/api_template/paths/transfers_transferId.yaml +58 -0
- package/OutboundServer/handlers.js +622 -0
- package/OutboundServer/index.js +137 -0
- package/OutboundServer/middlewares.js +67 -0
- package/TestServer/api.yaml +62 -0
- package/TestServer/handlers.js +63 -0
- package/TestServer/index.js +215 -0
- package/audit-resolve.json +65 -0
- package/babel.config.js +3 -0
- package/config.js +158 -0
- package/index.d.ts +1 -0
- package/index.js +149 -0
- package/jest.config.js +15 -0
- package/lib/api/index.js +12 -0
- package/lib/cache.js +352 -0
- package/lib/check.js +25 -0
- package/lib/model/AccountsModel.js +396 -0
- package/lib/model/Async2SyncModel.js +283 -0
- package/lib/model/AuthorizationsModel.js +86 -0
- package/lib/model/InboundTransfersModel.js +730 -0
- package/lib/model/OutboundBulkQuotesModel.js +485 -0
- package/lib/model/OutboundBulkTransfersModel.js +479 -0
- package/lib/model/OutboundRequestToPayModel.js +517 -0
- package/lib/model/OutboundRequestToPayTransferModel.js +893 -0
- package/lib/model/OutboundTransfersModel.js +823 -0
- package/lib/model/PartiesModel.js +70 -0
- package/lib/model/ProxyModel/MatchRules/Expression.js +48 -0
- package/lib/model/ProxyModel/MatchRules/Headers.js +65 -0
- package/lib/model/ProxyModel/MatchRules/MatchRule.js +27 -0
- package/lib/model/ProxyModel/MatchRules/Path.js +36 -0
- package/lib/model/ProxyModel/MatchRules/Query.js +65 -0
- package/lib/model/ProxyModel/MatchRules/index.js +19 -0
- package/lib/model/ProxyModel/Route.js +82 -0
- package/lib/model/ProxyModel/configSchema.json +118 -0
- package/lib/model/ProxyModel/index.js +138 -0
- package/lib/model/QuotesModel.js +94 -0
- package/lib/model/TransfersModel.js +81 -0
- package/lib/model/common/BackendError.js +26 -0
- package/lib/model/common/PersistentStateMachine.js +93 -0
- package/lib/model/common/index.js +18 -0
- package/lib/model/index.js +43 -0
- package/lib/model/lib/deferredJob.js +113 -0
- package/lib/model/lib/index.js +9 -0
- package/lib/model/lib/requests/backendRequests.js +227 -0
- package/lib/model/lib/requests/common.js +76 -0
- package/lib/model/lib/requests/index.js +19 -0
- package/lib/model/lib/shared.js +468 -0
- package/lib/randomphrase/index.js +21 -0
- package/lib/randomphrase/words.json +3397 -0
- package/lib/router.js +28 -0
- package/lib/validate.js +205 -0
- package/package.json +102 -0
- package/test/__mocks__/@mojaloop/sdk-standard-components.js +152 -0
- package/test/__mocks__/javascript-state-machine.js +21 -0
- package/test/__mocks__/redis.js +49 -0
- package/test/__mocks__/uuidv4.js +16 -0
- package/test/config/integration.env +136 -0
- package/test/integration/lib/Outbound/authorizations.test.js +58 -0
- package/test/integration/lib/Outbound/data/authorizationsPostRequest.json +43 -0
- package/test/integration/lib/Outbound/data/quotesPostRequest.json +52 -0
- package/test/integration/lib/Outbound/data/transfersPostRequest.json +24 -0
- package/test/integration/lib/Outbound/parties.test.js +28 -0
- package/test/integration/lib/Outbound/quotes.test.js +58 -0
- package/test/integration/lib/Outbound/simpleTransfers.test.js +67 -0
- package/test/integration/lib/cache.test.js +80 -0
- package/test/integration/testEnv.js +7 -0
- package/test/unit/InboundServer.test.js +443 -0
- package/test/unit/TestServer.test.js +394 -0
- package/test/unit/api/accounts/accounts.test.js +128 -0
- package/test/unit/api/accounts/data/postAccountsBody.json +7 -0
- package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +25 -0
- package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +19 -0
- package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +17 -0
- package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +21 -0
- package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +21 -0
- package/test/unit/api/accounts/utils.js +65 -0
- package/test/unit/api/proxy/data/proxyConfig.yaml +82 -0
- package/test/unit/api/proxy/data/requestBody.json +22 -0
- package/test/unit/api/proxy/data/requestHeaders.json +5 -0
- package/test/unit/api/proxy/data/requestQuery.json +6 -0
- package/test/unit/api/proxy/data/responseBody.json +21 -0
- package/test/unit/api/proxy/data/responseHeaders.json +5 -0
- package/test/unit/api/proxy/proxy.test.js +220 -0
- package/test/unit/api/proxy/utils.js +79 -0
- package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +21 -0
- package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +17 -0
- package/test/unit/api/transfers/data/postQuotesBody.json +52 -0
- package/test/unit/api/transfers/data/postTransfersBadBody.json +17 -0
- package/test/unit/api/transfers/data/postTransfersBody.json +24 -0
- package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +53 -0
- package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +47 -0
- package/test/unit/api/transfers/data/postTransfersSimpleBody.json +26 -0
- package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +101 -0
- package/test/unit/api/transfers/data/putPartiesBody.json +20 -0
- package/test/unit/api/transfers/data/putQuotesBody.json +37 -0
- package/test/unit/api/transfers/data/putTransfersBody.json +17 -0
- package/test/unit/api/transfers/transfers.test.js +191 -0
- package/test/unit/api/transfers/utils.js +183 -0
- package/test/unit/api/utils.js +75 -0
- package/test/unit/config.test.js +119 -0
- package/test/unit/data/commonHttpHeaders.json +6 -0
- package/test/unit/data/defaultConfig.json +58 -0
- package/test/unit/data/postQuotesBody.json +52 -0
- package/test/unit/data/putParticipantsBody.json +12 -0
- package/test/unit/data/putPartiesBody.json +20 -0
- package/test/unit/data/testFile.json +29 -0
- package/test/unit/data/testFile.yaml +14 -0
- package/test/unit/inboundApi/data/mockArguments.json +117 -0
- package/test/unit/inboundApi/data/mockTransactionRequest.json +42 -0
- package/test/unit/inboundApi/handlers.test.js +799 -0
- package/test/unit/index.test.js +55 -0
- package/test/unit/lib/cache.test.js +146 -0
- package/test/unit/lib/model/AccountsModel.test.js +121 -0
- package/test/unit/lib/model/AuthorizationsModel.test.js +460 -0
- package/test/unit/lib/model/InboundTransfersModel.test.js +628 -0
- package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +249 -0
- package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +244 -0
- package/test/unit/lib/model/OutboundRequestToPayModel.test.js +166 -0
- package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +245 -0
- package/test/unit/lib/model/OutboundTransfersModel.test.js +836 -0
- package/test/unit/lib/model/PartiesModel.test.js +468 -0
- package/test/unit/lib/model/QuotesModel.test.js +470 -0
- package/test/unit/lib/model/TransfersModel.test.js +474 -0
- package/test/unit/lib/model/common/PersistentStateMachine.test.js +179 -0
- package/test/unit/lib/model/data/authorizationsResponse.json +13 -0
- package/test/unit/lib/model/data/bulkQuoteRequest.json +27 -0
- package/test/unit/lib/model/data/bulkQuoteResponse.json +35 -0
- package/test/unit/lib/model/data/bulkTransferFulfil.json +13 -0
- package/test/unit/lib/model/data/bulkTransferRequest.json +29 -0
- package/test/unit/lib/model/data/defaultConfig.json +47 -0
- package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +42 -0
- package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +22 -0
- package/test/unit/lib/model/data/getTransfersBackendResponse.json +34 -0
- package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +17 -0
- package/test/unit/lib/model/data/mockArguments.json +131 -0
- package/test/unit/lib/model/data/mockTxnRequestsArguments.json +63 -0
- package/test/unit/lib/model/data/notificationToPayee.json +10 -0
- package/test/unit/lib/model/data/payeeParty.json +16 -0
- package/test/unit/lib/model/data/putAuthorizationsResponse.json +10 -0
- package/test/unit/lib/model/data/putQuotesResponse.json +33 -0
- package/test/unit/lib/model/data/putTransfersResponse.json +5 -0
- package/test/unit/lib/model/data/quoteResponse.json +31 -0
- package/test/unit/lib/model/data/requestToPayRequest.json +20 -0
- package/test/unit/lib/model/data/requestToPayTransferRequest.json +27 -0
- package/test/unit/lib/model/data/transactionRequestResponse.json +18 -0
- package/test/unit/lib/model/data/transferFulfil.json +8 -0
- package/test/unit/lib/model/data/transferRequest.json +26 -0
- package/test/unit/lib/model/mockedLibRequests.js +74 -0
- package/test/unit/mockLogger.js +39 -0
- package/test/unit/outboundApi/data/bulkQuoteRequest.json +28 -0
- package/test/unit/outboundApi/data/bulkTransferRequest.json +28 -0
- package/test/unit/outboundApi/data/mockBulkQuoteError.json +45 -0
- package/test/unit/outboundApi/data/mockBulkTransferError.json +48 -0
- package/test/unit/outboundApi/data/mockError.json +41 -0
- package/test/unit/outboundApi/data/mockGetPartiesError.json +4 -0
- package/test/unit/outboundApi/data/mockRequestToPayError.json +32 -0
- package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +39 -0
- package/test/unit/outboundApi/data/requestToPay.json +21 -0
- package/test/unit/outboundApi/data/requestToPayTransferRequest.json +20 -0
- package/test/unit/outboundApi/data/transferRequest.json +21 -0
- package/test/unit/outboundApi/handlers.test.js +986 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
/**************************************************************************
|
|
2
|
+
* (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
|
|
3
|
+
* *
|
|
4
|
+
* This file is made available under the terms of the license agreement *
|
|
5
|
+
* specified in the corresponding source code repository. *
|
|
6
|
+
* *
|
|
7
|
+
* ORIGINAL AUTHOR: *
|
|
8
|
+
* Steven Oderayi - steven.oderayi@modusbox.com *
|
|
9
|
+
**************************************************************************/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const util = require('util');
|
|
14
|
+
const { uuid } = require('uuidv4');
|
|
15
|
+
const StateMachine = require('javascript-state-machine');
|
|
16
|
+
const { MojaloopRequests } = require('@mojaloop/sdk-standard-components');
|
|
17
|
+
const { BackendError } = require('./common');
|
|
18
|
+
|
|
19
|
+
const stateEnum = {
|
|
20
|
+
'ERROR_OCCURRED': 'ERROR_OCCURRED',
|
|
21
|
+
'COMPLETED': 'COMPLETED',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Models the state machine and operations required for performing an outbound bulk transfer
|
|
26
|
+
*/
|
|
27
|
+
class OutboundBulkTransfersModel {
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this._cache = config.cache;
|
|
30
|
+
this._logger = config.logger;
|
|
31
|
+
this._requestProcessingTimeoutSeconds = config.requestProcessingTimeoutSeconds;
|
|
32
|
+
this._dfspId = config.dfspId;
|
|
33
|
+
this._expirySeconds = config.expirySeconds;
|
|
34
|
+
this._rejectExpiredTransferFulfils = config.rejectExpiredTransferFulfils;
|
|
35
|
+
|
|
36
|
+
this._requests = new MojaloopRequests({
|
|
37
|
+
logger: this._logger,
|
|
38
|
+
peerEndpoint: config.peerEndpoint,
|
|
39
|
+
bulkTransfersEndpoint: config.bulkTransfersEndpoint,
|
|
40
|
+
dfspId: config.dfspId,
|
|
41
|
+
tls: config.tls,
|
|
42
|
+
jwsSign: config.jwsSign,
|
|
43
|
+
jwsSignPutParties: config.jwsSignPutParties,
|
|
44
|
+
jwsSigningKey: config.jwsSigningKey,
|
|
45
|
+
wso2: config.wso2,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Initializes the internal state machine object
|
|
51
|
+
*/
|
|
52
|
+
_initStateMachine (initState) {
|
|
53
|
+
this.stateMachine = new StateMachine({
|
|
54
|
+
init: initState,
|
|
55
|
+
transitions: [
|
|
56
|
+
{ name: 'executeBulkTransfer', from: 'start', to: 'succeeded' },
|
|
57
|
+
{ name: 'getBulkTransfer', to: 'succeeded' },
|
|
58
|
+
{ name: 'error', from: '*', to: 'errored' },
|
|
59
|
+
],
|
|
60
|
+
methods: {
|
|
61
|
+
onTransition: this._handleTransition.bind(this),
|
|
62
|
+
onAfterTransition: this._afterTransition.bind(this),
|
|
63
|
+
onPendingTransition: (transition, from, to) => {
|
|
64
|
+
// allow transitions to 'error' state while other transitions are in progress
|
|
65
|
+
if(transition !== 'error') {
|
|
66
|
+
throw new Error(`Transition requested while another transition is in progress: ${transition} from: ${from} to: ${to}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return this.stateMachine[initState];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Updates the internal state representation to reflect that of the state machine itself
|
|
77
|
+
*/
|
|
78
|
+
_afterTransition() {
|
|
79
|
+
this._logger.log(`State machine transitioned: ${this.data.currentState} -> ${this.stateMachine.state}`);
|
|
80
|
+
this.data.currentState = this.stateMachine.state;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initializes the bulk transfer model
|
|
85
|
+
*
|
|
86
|
+
* @param data {object} - The inbound API POST /bulkTransfers request body
|
|
87
|
+
*/
|
|
88
|
+
async initialize(data) {
|
|
89
|
+
this.data = data;
|
|
90
|
+
|
|
91
|
+
// add a bulkTransferId if one is not present e.g. on first submission
|
|
92
|
+
if(!this.data.hasOwnProperty('bulkTransferId')) {
|
|
93
|
+
this.data.bulkTransferId = uuid();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// initialize the bulk transfer state machine to its starting state
|
|
97
|
+
if(!this.data.hasOwnProperty('currentState')) {
|
|
98
|
+
this.data.currentState = 'start';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this._initStateMachine(this.data.currentState);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Handles state machine transitions
|
|
106
|
+
*/
|
|
107
|
+
async _handleTransition(lifecycle, ...args) {
|
|
108
|
+
this._logger.log(`Bulk transfer ${this.data.bulkTransferId} is transitioning from ${lifecycle.from} to ${lifecycle.to} in response to ${lifecycle.transition}`);
|
|
109
|
+
|
|
110
|
+
switch(lifecycle.transition) {
|
|
111
|
+
case 'init':
|
|
112
|
+
return;
|
|
113
|
+
|
|
114
|
+
case 'executeBulkTransfer':
|
|
115
|
+
return this._executeBulkTransfer();
|
|
116
|
+
|
|
117
|
+
case 'getBulkTransfer':
|
|
118
|
+
return this._getBulkTransfer(this.data.bulkTransferId);
|
|
119
|
+
|
|
120
|
+
case 'error':
|
|
121
|
+
this._logger.log(`State machine is erroring with error: ${util.inspect(args)}`);
|
|
122
|
+
this.data.lastError = args[0] || new Error('unspecified error');
|
|
123
|
+
break;
|
|
124
|
+
|
|
125
|
+
default:
|
|
126
|
+
throw new Error(`Unhandled state transition for bulk transfer ${this.data.bulkTransferId}: ${util.inspect(args)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Executes a bulk transfer
|
|
132
|
+
* Starts the transfer process by sending a POST /bulkTransfers (prepare) request to the switch;
|
|
133
|
+
* then waits for a notification from the cache that the transfer has been fulfilled
|
|
134
|
+
*/
|
|
135
|
+
async _executeBulkTransfer() {
|
|
136
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
137
|
+
return new Promise(async (resolve, reject) => {
|
|
138
|
+
// create a bulk transfer request
|
|
139
|
+
const bulkTransferPrepare = this._buildBulkTransferPrepareRequest();
|
|
140
|
+
|
|
141
|
+
// listen for events on the bulkTransferId
|
|
142
|
+
const bulkTransferKey = `bulkTransfer_${this.data.bulkTransferId}`;
|
|
143
|
+
|
|
144
|
+
// hook up a subscriber to handle response messages
|
|
145
|
+
const subId = await this._cache.subscribe(bulkTransferKey, (cn, msg, subId) => {
|
|
146
|
+
try {
|
|
147
|
+
let error;
|
|
148
|
+
let message = JSON.parse(msg);
|
|
149
|
+
|
|
150
|
+
if (message.type === 'bulkTransferFulfil') {
|
|
151
|
+
if (this._rejectExpiredTransferFulfils) {
|
|
152
|
+
const now = new Date().toISOString();
|
|
153
|
+
if (now > bulkTransferPrepare.expiration) {
|
|
154
|
+
const msg = 'Bulk transfer fulfils missed expiry deadline';
|
|
155
|
+
error = new BackendError(msg, 504);
|
|
156
|
+
this._logger.error(`${msg}: system time=${now} > expiration time=${bulkTransferPrepare.expiration}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} else if (message.type === 'bulkTransferError') {
|
|
160
|
+
error = new BackendError(`Got an error response preparing bulk transfer: ${util.inspect(message.data, { depth: Infinity })}`, 500);
|
|
161
|
+
error.mojaloopError = message.data;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this._logger.push({ message }).log(`Ignoring cache notification for bulk transfer ${bulkTransferKey}. Unknown message type ${message.type}.`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// cancel the timeout handler
|
|
169
|
+
clearTimeout(timeout);
|
|
170
|
+
|
|
171
|
+
// stop listening for bulk transfer resolution messages
|
|
172
|
+
// no need to await for the unsubscribe to complete.
|
|
173
|
+
// we dont really care if the unsubscribe fails but we should log it regardless
|
|
174
|
+
this._cache.unsubscribe(bulkTransferKey, subId).catch(e => {
|
|
175
|
+
this._logger.log(`Error unsubscribing (in callback) ${bulkTransferKey} ${subId}: ${e.stack || util.inspect(e)}`);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
if (error) {
|
|
179
|
+
return reject(error);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const bulkTransferFulfil = message.data;
|
|
183
|
+
this._logger.push({ bulkTransferFulfil }).log('Bulk transfer fulfils received');
|
|
184
|
+
|
|
185
|
+
return resolve(bulkTransferFulfil);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
return reject(err);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// set up a timeout for the request
|
|
193
|
+
const timeout = setTimeout(() => {
|
|
194
|
+
const err = new BackendError(`Timeout waiting for fulfil for bulk transfer ${this.data.bulkTransferId}`, 504);
|
|
195
|
+
|
|
196
|
+
// we dont really care if the unsubscribe fails but we should log it regardless
|
|
197
|
+
this._cache.unsubscribe(bulkTransferKey, subId).catch(e => {
|
|
198
|
+
this._logger.log(`Error unsubscribing (in timeout handler) ${bulkTransferKey} ${subId}: ${e.stack || util.inspect(e)}`);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
return reject(err);
|
|
202
|
+
}, this._requestProcessingTimeoutSeconds * 1000);
|
|
203
|
+
|
|
204
|
+
// now we have a timeout handler and a cache subscriber hooked up we can fire off
|
|
205
|
+
// a POST /bulkTransfers request to the switch
|
|
206
|
+
try {
|
|
207
|
+
const res = await this._requests.postBulkTransfers(bulkTransferPrepare, this.data.from.fspId);
|
|
208
|
+
this._logger.push({ res }).log('Bulk transfer request sent to peer');
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
// cancel the timout and unsubscribe before rejecting the promise
|
|
212
|
+
clearTimeout(timeout);
|
|
213
|
+
|
|
214
|
+
// we dont really care if the unsubscribe fails but we should log it regardless
|
|
215
|
+
this._cache.unsubscribe(bulkTransferKey, subId).catch(e => {
|
|
216
|
+
this._logger.log(`Error unsubscribing (in error handler) ${bulkTransferKey} ${subId}: ${e.stack || util.inspect(e)}`);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
return reject(err);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Constructs a bulk transfer request payload
|
|
226
|
+
*
|
|
227
|
+
* @returns {object} - the bulk transfer request object
|
|
228
|
+
*/
|
|
229
|
+
_buildBulkTransferPrepareRequest() {
|
|
230
|
+
const bulkTransferRequest = {
|
|
231
|
+
bulkTransferId: this.data.bulkTransferId,
|
|
232
|
+
bulkQuoteId: this.data.bulkQuoteId,
|
|
233
|
+
payerFsp: this._dfspId,
|
|
234
|
+
payeeFsp: this.data.individualTransfers[0].to.fspId,
|
|
235
|
+
expiration: this._getExpirationTimestamp()
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// add extensionList if provided
|
|
239
|
+
if (this.data.extensions && this.data.extensions.length > 0) {
|
|
240
|
+
bulkTransferRequest.extensionList = {
|
|
241
|
+
extension: this.data.extensions
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
bulkTransferRequest.individualTransfers = this.data.individualTransfers.map((individualTransfer) => {
|
|
246
|
+
if (bulkTransferRequest.payeeFsp !== individualTransfer.to.fspId) throw new BackendError('payee fsps are not the same into the whole bulk', 500);
|
|
247
|
+
|
|
248
|
+
const transferId = individualTransfer.transferId || uuid();
|
|
249
|
+
|
|
250
|
+
const transferPrepare = {
|
|
251
|
+
transferId: transferId,
|
|
252
|
+
transferAmount: {
|
|
253
|
+
currency: individualTransfer.currency,
|
|
254
|
+
amount: individualTransfer.amount
|
|
255
|
+
},
|
|
256
|
+
ilpPacket: individualTransfer.ilpPacket,
|
|
257
|
+
condition: individualTransfer.condition,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
if (individualTransfer.extensions && individualTransfer.extensions.length > 0) {
|
|
261
|
+
bulkTransferRequest.extensionList = {
|
|
262
|
+
extension: individualTransfer.extensions
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
return transferPrepare;
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
return bulkTransferRequest;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Get bulk transfer details by sending GET /bulkTransfers/{ID} request to the switch
|
|
275
|
+
*/
|
|
276
|
+
async _getBulkTransfer(bulkTransferId) {
|
|
277
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
278
|
+
return new Promise(async (resolve, reject) => {
|
|
279
|
+
const bulkTransferKey = `bulkTransfer_${bulkTransferId}`;
|
|
280
|
+
|
|
281
|
+
// hook up a subscriber to handle response messages
|
|
282
|
+
const subId = await this._cache.subscribe(bulkTransferKey, (cn, msg, subId) => {
|
|
283
|
+
try {
|
|
284
|
+
let error;
|
|
285
|
+
let message = JSON.parse(msg);
|
|
286
|
+
|
|
287
|
+
if (message.type === 'bulkTransferError') {
|
|
288
|
+
error = new BackendError(`Got an error response retrieving bulk transfer: ${util.inspect(message.data, { depth: Infinity })}`, 500);
|
|
289
|
+
error.mojaloopError = message.data;
|
|
290
|
+
} else if (message.type !== 'bulkTransferFulfil') {
|
|
291
|
+
this._logger.push({ message }).log(`Ignoring cache notification for bulk transfer ${bulkTransferKey}. Uknokwn message type ${message.type}.`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// cancel the timeout handler
|
|
296
|
+
clearTimeout(timeout);
|
|
297
|
+
|
|
298
|
+
// stop listening for bulk transfer fulfil messages
|
|
299
|
+
this._cache.unsubscribe(bulkTransferKey, subId).catch(e => {
|
|
300
|
+
this._logger.log(`Error unsubscribing (in callback) ${bulkTransferKey} ${subId}: ${e.stack || util.inspect(e)}`);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if (error) {
|
|
304
|
+
return reject(error);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const fulfils = message.data;
|
|
308
|
+
this._logger.push({ fulfils }).log('Bulk transfer fulfils received');
|
|
309
|
+
|
|
310
|
+
return resolve(fulfils);
|
|
311
|
+
}
|
|
312
|
+
catch(err) {
|
|
313
|
+
return reject(err);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// set up a timeout for the resolution
|
|
318
|
+
const timeout = setTimeout(() => {
|
|
319
|
+
const err = new BackendError(`Timeout getting bulk transfer ${bulkTransferId}`, 504);
|
|
320
|
+
|
|
321
|
+
// we dont really care if the unsubscribe fails but we should log it regardless
|
|
322
|
+
this._cache.unsubscribe(bulkTransferKey, subId).catch(e => {
|
|
323
|
+
this._logger.log(`Error unsubscribing (in timeout handler) ${bulkTransferKey} ${subId}: ${e.stack || util.inspect(e)}`);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
return reject(err);
|
|
327
|
+
}, this._requestProcessingTimeoutSeconds * 1000);
|
|
328
|
+
|
|
329
|
+
// now we have a timeout handler and a cache subscriber hooked up we can fire off
|
|
330
|
+
// a GET /bulkTransfers/{ID} request to the switch
|
|
331
|
+
try {
|
|
332
|
+
const res = await this._requests.getBulkTransfers(bulkTransferId);
|
|
333
|
+
this._logger.push({ peer: res }).log('Bulk transfer lookup sent to peer');
|
|
334
|
+
}
|
|
335
|
+
catch(err) {
|
|
336
|
+
// cancel the timout and unsubscribe before rejecting the promise
|
|
337
|
+
clearTimeout(timeout);
|
|
338
|
+
|
|
339
|
+
// we dont really care if the unsubscribe fails but we should log it regardless
|
|
340
|
+
this._cache.unsubscribe(bulkTransferKey, subId).catch(e => {
|
|
341
|
+
this._logger.log(`Error unsubscribing ${bulkTransferKey} ${subId}: ${e.stack || util.inspect(e)}`);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
return reject(err);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Returns an ISO-8601 format timestamp n-seconds in the future for expiration of a bulk quote API object,
|
|
351
|
+
* where n is equal to our config setting "expirySeconds"
|
|
352
|
+
*
|
|
353
|
+
* @returns {string} - ISO-8601 format future expiration timestamp
|
|
354
|
+
*/
|
|
355
|
+
_getExpirationTimestamp() {
|
|
356
|
+
let now = new Date();
|
|
357
|
+
return new Date(now.getTime() + (this._expirySeconds * 1000)).toISOString();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Returns an object representing the final state of the bulk transfer suitable for the outbound API
|
|
362
|
+
*
|
|
363
|
+
* @returns {object} - Response representing the result of the bulk transfer process
|
|
364
|
+
*/
|
|
365
|
+
getResponse() {
|
|
366
|
+
// we want to project some of our internal state into a more useful
|
|
367
|
+
// representation to return to the SDK API consumer
|
|
368
|
+
let resp = { ...this.data };
|
|
369
|
+
|
|
370
|
+
switch(this.data.currentState) {
|
|
371
|
+
case 'succeeded':
|
|
372
|
+
resp.currentState = stateEnum.COMPLETED;
|
|
373
|
+
break;
|
|
374
|
+
|
|
375
|
+
case 'errored':
|
|
376
|
+
resp.currentState = stateEnum.ERROR_OCCURRED;
|
|
377
|
+
break;
|
|
378
|
+
|
|
379
|
+
default:
|
|
380
|
+
this._logger.log(`Bulk transfer model response being returned from an unexpected state: ${this.data.currentState}. Returning ERROR_OCCURRED state`);
|
|
381
|
+
resp.currentState = stateEnum.ERROR_OCCURRED;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return resp;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Persists the model state to cache for reinstantiation at a later point
|
|
390
|
+
*/
|
|
391
|
+
async _save() {
|
|
392
|
+
try {
|
|
393
|
+
this.data.currentState = this.stateMachine.state;
|
|
394
|
+
const res = await this._cache.set(`bulkTransferModel_${this.data.bulkTransferId}`, this.data);
|
|
395
|
+
this._logger.push({ res }).log('Persisted bulk transfer model in cache');
|
|
396
|
+
}
|
|
397
|
+
catch(err) {
|
|
398
|
+
this._logger.push({ err }).log('Error saving bulk transfer model');
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Loads a bulk transfer model from cache for resumption of the bulk transfer process
|
|
406
|
+
*
|
|
407
|
+
* @param bulkTransferId {string} - UUID bulkTransferId of the model to load from cache
|
|
408
|
+
*/
|
|
409
|
+
async load(bulkTransferId) {
|
|
410
|
+
try {
|
|
411
|
+
const data = await this._cache.get(`bulkTransferModel_${bulkTransferId}`);
|
|
412
|
+
if(!data) {
|
|
413
|
+
throw new Error(`No cached data found for bulkTransferId: ${bulkTransferId}`);
|
|
414
|
+
}
|
|
415
|
+
await this.initialize(data);
|
|
416
|
+
this._logger.push({ cache: this.data }).log('Bulk transfer model loaded from cached state');
|
|
417
|
+
}
|
|
418
|
+
catch(err) {
|
|
419
|
+
this._logger.push({ err }).log('Error loading bulk transfer model');
|
|
420
|
+
throw err;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Returns a promise that resolves when the state machine has reached a terminal state
|
|
426
|
+
*/
|
|
427
|
+
async run() {
|
|
428
|
+
try {
|
|
429
|
+
// run transitions based on incoming state
|
|
430
|
+
switch(this.data.currentState) {
|
|
431
|
+
case 'start':
|
|
432
|
+
await this.stateMachine.executeBulkTransfer();
|
|
433
|
+
this._logger.log(`Bulk transfer ${this.data.bulkTransferId} has been completed`);
|
|
434
|
+
break;
|
|
435
|
+
|
|
436
|
+
case 'getBulkTransfer':
|
|
437
|
+
await this.stateMachine.getBulkTransfer();
|
|
438
|
+
this._logger.log(`Get bulk transfer ${this.data.bulkTransferId} has been completed`);
|
|
439
|
+
break;
|
|
440
|
+
|
|
441
|
+
case 'succeeded':
|
|
442
|
+
// all steps complete so return
|
|
443
|
+
this._logger.log('Bulk transfer completed successfully');
|
|
444
|
+
await this._save();
|
|
445
|
+
return this.getResponse();
|
|
446
|
+
|
|
447
|
+
case 'errored':
|
|
448
|
+
// stopped in errored state
|
|
449
|
+
this._logger.log('State machine in errored state');
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// now call ourselves recursively to deal with the next transition
|
|
454
|
+
this._logger.log(`Bulk transfer model state machine transition completed in state: ${this.stateMachine.state}. Recursing to handle next transition.`);
|
|
455
|
+
return this.run();
|
|
456
|
+
}
|
|
457
|
+
catch(err) {
|
|
458
|
+
this._logger.log(`Error running transfer model: ${util.inspect(err)}`);
|
|
459
|
+
|
|
460
|
+
// as this function is recursive, we dont want to error the state machine multiple times
|
|
461
|
+
if(this.data.currentState !== 'errored') {
|
|
462
|
+
// err should not have a bulkTransferState property here!
|
|
463
|
+
if(err.bulkTransferState) {
|
|
464
|
+
this._logger.log(`State machine is broken: ${util.inspect(err)}`);
|
|
465
|
+
}
|
|
466
|
+
// transition to errored state
|
|
467
|
+
await this.stateMachine.error(err);
|
|
468
|
+
|
|
469
|
+
// avoid circular ref between bulkTransferState.lastError and err
|
|
470
|
+
err.bulkTransferState = JSON.parse(JSON.stringify(this.getResponse()));
|
|
471
|
+
}
|
|
472
|
+
throw err;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
module.exports = OutboundBulkTransfersModel;
|