diff --git a/.circleci/config.yml b/.circleci/config.yml index 34ebad5f8..7fed86290 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,13 +1,19 @@ -# CircleCI v2 Config -version: 2 +# CircleCI v2.1 Config +version: 2.1 -defaults_working_directory: &defaults_working_directory - working_directory: /home/circleci/project - -defaults_docker_node: &defaults_docker_node - docker: - - image: node:10.15-alpine +## +# orbs +# +# Orbs used in this pipeline +## +orbs: + slack: circleci/slack@3.4.2 +## +# defaults +# +# YAML defaults templates, in alphabetical order +## defaults_Dependencies: &defaults_Dependencies name: Install default dependencies command: | @@ -15,14 +21,13 @@ defaults_Dependencies: &defaults_Dependencies apk --no-cache add ca-certificates apk --no-cache add curl apk --no-cache add openssh-client + # for node 10.15-alpine, need to install from edge repo + apk --no-cache add openjdk11 --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community + apk --no-cache add graphviz apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake npm config set unsafe-perm true npm install -g gitbook-cli -defaults_Environment: &defaults_environment - name: Set default environment - command: | - echo "Nothing to do here right now...move along!" defaults_slack_announcement: &defaults_slack_announcement name: Slack announcement for tag releases @@ -75,40 +80,53 @@ defaults_publish_to_gh_pages: &defaults_publish_to_gh_pages echo "Publishing $GITHUB_TAG release to $GITBOOK_TARGET_BRANCH on github..." git push -q $GITHUB_PROJECT_USERNAME $GITBOOK_TARGET_BRANCH &> git.log +## +# Executors +# +# CircleCI Executors +## +executors: + default-docker: + working_directory: /home/circleci/project + docker: + - image: node:10.15-alpine + + default-machine: + machine: + image: ubuntu-1604:201903-01 +## +# Jobs +# +# A map of CircleCI jobs +## jobs: setup: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: - checkout - run: <<: *defaults_Dependencies - - run: - <<: *defaults_environment - run: name: Access npm folder as root command: cd $(npm root -g)/npm - run: name: Update NPM install - command: npm install + command: npm ci - run: name: Delete build dependencies command: apk del build-dependencies - save_cache: - key: dependency-cache-{{ .Revision }} + key: dependency-cache-{{ checksum "package-lock.json" }} paths: - node_modules build: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: - checkout - run: <<: *defaults_Dependencies - - run: - <<: *defaults_environment - run: name: Installing build dependencies command: | @@ -123,25 +141,49 @@ jobs: curl -L https://sourceforge.net/projects/plantuml/files/plantuml.${PLANTUML_VERSION}.jar/download -o plantuml.jar - restore_cache: keys: - - dependency-cache-{{ .Revision }} + - dependency-cache-{{ checksum "package-lock.json" }} - run: name: Build Gitbooks command: | npm run gitbook:build - save_cache: - key: build-cache-{{ .Revision }} + key: dependency-cache-{{ checksum "package-lock.json" }} paths: - _book + + test-svg: + executor: default-machine + steps: + - checkout + - run: + name: Set up NVM + command: | + echo ${NVM_DIR} + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + nvm install v10.15.3 + nvm alias default v10.15.3 + node --version + npm ci + - run: + name: Check if plantuml has been updated correctly + command: | + set +o pipefail + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + npm run build:plantuml:all + FILE_COUNT=$(git diff --name-only | grep .svg | wc -l) + if [ ${FILE_COUNT} -ne "0" ]; then + echo "${FILE_COUNT} plantuml files are out of sync. Please run npm run build:plantuml and try again."; + exit 1; + else + echo 'Plantuml files are up to date'; + fi deploy: - <<: *defaults_working_directory - <<: *defaults_docker_node + executor: default-docker steps: - checkout - run: <<: *defaults_Dependencies - - run: - <<: *defaults_environment - run: name: setup environment vars command: | @@ -162,6 +204,11 @@ jobs: - run: <<: *defaults_slack_announcement +## +# Workflows +# +# CircleCI Workflow config +## workflows: version: 2 build_and_test: @@ -176,6 +223,17 @@ workflows: - /feature.*/ - /bugfix.*/ - gh-pages + - test-svg: + context: org-global + requires: + - setup + filters: + tags: + only: /.*/ + branches: + ignore: + - /feature*/ + - /bugfix*/ - build: context: org-global requires: diff --git a/NOTES.md b/NOTES.md new file mode 100644 index 000000000..b9f639960 --- /dev/null +++ b/NOTES.md @@ -0,0 +1,51 @@ +# Documentation Notes + +Helpers and notes for building and working on these docs. + + +## Building `.svg`s from plantuml sources + +We use a git commit hook to automatically rebuild `.svg` files from plantuml +sources. The magic of git hooks means that no extra work is required by you +after creating or editing a `.puml` file + +Behind the scenes, this hook spins up a docker container to run the PUML server +and calls `./scripts/_render_svg.js` for each file that has changed. We use the +docker version instead of the public puml server to (1) get around rate limits, and +(2) ensure deterministic SVG output that is git diffable. + +### Creating a new PUML + +1. Create a new `*.puml/plantuml` file +2. Add the file and generate the `.svg` + +```bash +git add . #(or the specific file you are working on) +npm run build:plantuml:diff +``` +3. Update your `.md` file to refer to the newly created `.svg` file +4. Git add/commit +### Updating an existing PUML + +1. Make changes to an existing `*.puml/plantuml` file +2. `git add` + `git commit` +3. The pre-commit hook rebuilds the changed SVG files, and adds them before the commit + +### Building all `.puml` sources manually + +You can also force a complete rebuild of all `.puml` and `.plantuml` sources like so: + +```bash +npm install +npm run build:plantuml:all +``` + +### `test-svg` CI/CD Step + +This is a ci/cd step that ensures that the `.svg` files have been updated +correctly, just in case something got out of sync on your branch before +merging a pull request. + +It runs `npm run build:plantuml:all` to build all of the plantuml sources +and if it detects file changes, it means something went wrong with the +commit hook (or you skipped it with `git commit -n`). diff --git a/contributors-guide/tools-and-technologies/assets/diagrams/automated-testing/QARegressionTestingMojaloop-Complete.svg b/contributors-guide/tools-and-technologies/assets/diagrams/automated-testing/QARegressionTestingMojaloop-Complete.svg new file mode 100644 index 000000000..c5a3bd917 --- /dev/null +++ b/contributors-guide/tools-and-technologies/assets/diagrams/automated-testing/QARegressionTestingMojaloop-Complete.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + Regression Test Life Cycle + + + (Self-contained Test Server on EC2) + + + + + + This could be a manual trigger, + + + scheduler timer or + + + an external action like a Pull Request + + + from the Source Control System + + + + Test is triggered + + + + Validate run parameters as expected? + + + yes + + + no + + + + + Set Timestamp + + + PostmanCollection to execute + + + List of email recipients + + + Environment Variables + + + Execution Timestamp + + + Output FileName + + + + Prepare environment for required run + + + + Abort run with Note stating incorrect Run Parameters + + + + + + Create Simulator Docker Container + + + + + This container has node + + + Newman\email SMTP Server + + + + Create Regression Test Docker Container + + + + + Set up any variables for + + + preparation of the request to follow + + + + Perform Pre-Request Script + + + + Execute Postman Request + + + + Perform Test + + + + + Inspect the response + + + against variables set previously during + + + the run to determine if expected results are obtained + + + + Log Results + + + + no + + + Run Parameter requested 'Abort at First Error'? + + + yes + + + + + + yes + + + Assertion Test Failed? + + + no + + + + Yes + + + More Postman Requests to run? + + + No + + + + + + Destroy Simulator Docker Container + + + + Finalise Report + + + + Prepare Notification(s) + + + + Attach Reports + + + + + The Attachment (Generated Report) + + + is sent as an attachment + + + to the different notification channels. + + + + Send out Notification(s) + + + + Destroy Regression Test Docker Container + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hackathon-materials/README.md b/hackathon-materials/README.md new file mode 100644 index 000000000..99e95c391 --- /dev/null +++ b/hackathon-materials/README.md @@ -0,0 +1,7 @@ +# Hackathon Materials + +A set of documentation from past hackathons. In the future, we may spin this folder off into it's own fully fledged "Mojaloop Hackathon Guide". For now, it's a place to put reference material. + +Most of this initial material comes from The Include Everyone Mojaloop Hackathon in Kampala, Uganda late 2019. + +If you have additional material you want to add, or changes you want to make, please go ahead and raise a pull request. \ No newline at end of file diff --git a/hackathon-materials/images/lab_onboarding_01.png b/hackathon-materials/images/lab_onboarding_01.png new file mode 100644 index 000000000..3ff3c9558 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_01.png differ diff --git a/hackathon-materials/images/lab_onboarding_02.png b/hackathon-materials/images/lab_onboarding_02.png new file mode 100644 index 000000000..9f587dd0b Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_02.png differ diff --git a/hackathon-materials/images/lab_onboarding_04.png b/hackathon-materials/images/lab_onboarding_04.png new file mode 100644 index 000000000..3a048003f Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_04.png differ diff --git a/hackathon-materials/images/lab_onboarding_05.png b/hackathon-materials/images/lab_onboarding_05.png new file mode 100644 index 000000000..7d2b805ff Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_05.png differ diff --git a/hackathon-materials/images/lab_onboarding_06.png b/hackathon-materials/images/lab_onboarding_06.png new file mode 100644 index 000000000..d690a7f36 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_06.png differ diff --git a/hackathon-materials/images/lab_onboarding_07.png b/hackathon-materials/images/lab_onboarding_07.png new file mode 100644 index 000000000..4446f55f1 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_07.png differ diff --git a/hackathon-materials/images/lab_onboarding_08.png b/hackathon-materials/images/lab_onboarding_08.png new file mode 100644 index 000000000..a15a27f21 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_08.png differ diff --git a/hackathon-materials/images/lab_onboarding_09.png b/hackathon-materials/images/lab_onboarding_09.png new file mode 100644 index 000000000..6a8e3e877 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_09.png differ diff --git a/hackathon-materials/images/lab_onboarding_10.png b/hackathon-materials/images/lab_onboarding_10.png new file mode 100644 index 000000000..b699f92fc Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_10.png differ diff --git a/hackathon-materials/images/lab_onboarding_11.png b/hackathon-materials/images/lab_onboarding_11.png new file mode 100644 index 000000000..40af4b86d Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_11.png differ diff --git a/hackathon-materials/images/lab_onboarding_12.png b/hackathon-materials/images/lab_onboarding_12.png new file mode 100644 index 000000000..71fb2e738 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_12.png differ diff --git a/hackathon-materials/images/lab_onboarding_13.png b/hackathon-materials/images/lab_onboarding_13.png new file mode 100644 index 000000000..3acbbd1f9 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_13.png differ diff --git a/hackathon-materials/images/lab_onboarding_14.png b/hackathon-materials/images/lab_onboarding_14.png new file mode 100644 index 000000000..e132b02f6 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_14.png differ diff --git a/hackathon-materials/images/lab_onboarding_15.png b/hackathon-materials/images/lab_onboarding_15.png new file mode 100644 index 000000000..d10967224 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_15.png differ diff --git a/hackathon-materials/images/lab_onboarding_16.png b/hackathon-materials/images/lab_onboarding_16.png new file mode 100644 index 000000000..0b2341a04 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_16.png differ diff --git a/hackathon-materials/images/lab_onboarding_17.png b/hackathon-materials/images/lab_onboarding_17.png new file mode 100644 index 000000000..3cbe498fe Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_17.png differ diff --git a/hackathon-materials/images/lab_onboarding_18.png b/hackathon-materials/images/lab_onboarding_18.png new file mode 100644 index 000000000..9f7f274f3 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_18.png differ diff --git a/hackathon-materials/images/lab_onboarding_19.png b/hackathon-materials/images/lab_onboarding_19.png new file mode 100644 index 000000000..eeaa8b422 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_19.png differ diff --git a/hackathon-materials/images/lab_onboarding_20.png b/hackathon-materials/images/lab_onboarding_20.png new file mode 100644 index 000000000..4848b3af4 Binary files /dev/null and b/hackathon-materials/images/lab_onboarding_20.png differ diff --git a/hackathon-materials/images/postman_01.png b/hackathon-materials/images/postman_01.png new file mode 100644 index 000000000..6164d22f3 Binary files /dev/null and b/hackathon-materials/images/postman_01.png differ diff --git a/hackathon-materials/images/postman_02.png b/hackathon-materials/images/postman_02.png new file mode 100644 index 000000000..ffcfa218f Binary files /dev/null and b/hackathon-materials/images/postman_02.png differ diff --git a/hackathon-materials/lab_onboarding.md b/hackathon-materials/lab_onboarding.md new file mode 100644 index 000000000..dd108d77c --- /dev/null +++ b/hackathon-materials/lab_onboarding.md @@ -0,0 +1,91 @@ +# ModusBox Mojaloop Lab +## Getting started with the Lab + +>***Note:** This document is specific to the ModusBox lab provided for the Include Everyone hackathon, but may generalize well in the future* + + +## 1.0 Obtaining an Access Token + +- 1.1 Go to the public gateway (the link has been removed as this environment is not public). + +- 1.2 Click “Sign Up”, and go through the steps to create a new account + + + + +- 1.3 Click “Sign Up” > follow the dialog box to the sign in page > Enter your details and “Sign In” + +
+ + + +- 1.4 In the top left, select “Applications” + + + + +- 1.5 Select “Default Application” from the list + + + +- 1.6 Navigate to “Production Keys” > set the validity of the key to “-1” > “Generate Keys” + +
+ + +- 1.7 Your access key along with a token will be created. Click “Show keys” + + + +- 1.8 Observe that your access token has been created. You can copy this for later reference + + + +- 1.9 Navigate to APIs in the top left menu + + + +- 1.10 From the list of APIs, select “CentralLedgerApi…” + + + + +- 1.11 You now need to subscribe the DefaultApplication to this api. You can do this in the top right > “Subscribe” + +
+ + + +- 1.12 Navigate to “Api Console”. Your access token should already be pre-filled for you. + + + +- 1.13 Now we can test out the `/health` endpoint of the central-ledger service. Browse down the list of endpoints > “Try it out” > “Execute” + +
+
+
+ + + +1.14 You should see a response similar to the following: + + +```json +{ + "status": "OK", + "uptime": 535767.333, + "startTime": "2019-09-17T15:11:37.794Z", + "versionNumber": "7.3.1", + "services": [ + { + "name": "datastore", + "status": "OK" + }, + { + "name": "broker", + "status": "OK" + } + ] +} +``` \ No newline at end of file diff --git a/hackathon-materials/preread.md b/hackathon-materials/preread.md new file mode 100644 index 000000000..97bf3d959 --- /dev/null +++ b/hackathon-materials/preread.md @@ -0,0 +1,67 @@ +# Hackathon Pre-Read: +> Goal: A simple reading and todo list for hackathon participants + +## Compulsory Reading +>Time to complete: 15-30 minutes + +- [Mojaloop Project Website](https://mojaloop.io/ ) + - Basic into the project + - Intro video +- [Mojaloop Documentation](https://mojaloop.io/documentation/) + - Overview + - Onboarding doc [todo: this needs work] + - Repo Details (get a lay of the land from the services) +- [Onboarding to the ModusBox Lab Environment](./lab_onboarding.md) + - Logging in and using the environment + - getting an access token and talking to the Lab from postman/curl + + +## Hackathon Onboarding Checklist +>Time to complete: 15-30 minutes + +### Slack: +> The Mojaloop OSS Community uses Slack for all of its communications and announcements. + + +1. Go to [mojaloop-slack.herokuapp.com](mojaloop-slack.herokuapp.com) > Enter your Email address and press "Join" +2. Follow the steps in the email to set up your Slack account +3. Go [here](https://slack.com/intl/en-gm/downloads/) to download slack for your computer +_Optional: You can also go to the Play Store or App Store and install Slack on your phone as well_ +4. Once Slack is installed, select "Channels" in the left bar and search for the `#this-hackathon-name` channel +_[todo: update this doc and replace `#this-hackathon-name` with a channel name specific for the hackathon]_ + + +### Postman +>Postman is a REST API testing and automation tool which we use to interact with the Lab environment and Mojaloop itself + +1. Go to [Postman Downloads](https://www.getpostman.com/downloads/) to download Postman for your machine +2. Clone or Download the [mojaloop/postman](https://github.com/mojaloop/postman) repository. This contains a number of postman 'Collections' which will help you to interact with Mojaloop and the Lab environment +3. Open Postman, and select "Import" from the top left and navigate to where you cloned the Postman repo + +![postman_01.png](./images/postman_01.png) + +4. Drag and drop all of the `collection.json` files into the dialog, and they will be imported into your environment +![postman_02.png](./images/postman_02.png) + +5. Do the same as above with the files in `./environment`. These files specify the environment variables for the collections +6. Now that the collections and environment are set up, we will use the Collection Runner to run one of the test collections. The Collection Runner will run through a list of HTTP requests inside of a collection, which we use to automate or test different processes. +7. Select "Runner" from the top left (next to import), and select the +_[todo: fill this section in after getting the Lab environment test runner]_ + + +## Extended Reading + +- Mojaloop API Specification + Use Cases. For a better understanding of the API and how the API can be used to implement various interoperable payment use cases + - [Mojaloop API Spec v1.0](https://github.com/mojaloop/mojaloop-specification/blob/master/API%20Definition%20v1.0.pdf) + - [Mojaloop Use Cases](https://github.com/mojaloop/mojaloop-specification/blob/master/Use%20Cases.pdf) + +- Getting a local Mojaloop Environment up and Running On Kubernetes. For running Mojaloop yourself, either on a local machine, or cloud server + - [Mojaloop Deployment Guide](https://mojaloop.io/documentation/deployment-guide/) + +- Getting started with contributing to Mojaloop: + - [Mojaloop Contributor's Guide](https://mojaloop.io/documentation/contributors-guide/) + - _[todo: Github + Zenhub setup]_ + +- Digging into the code: + - [central-ledger service](https://github.com/mojaloop/central-ledger) + - [ml-api-adpater service](https://github.com/mojaloop/ml-api-adapter) \ No newline at end of file diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-delete-oracle-7.3.4.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-delete-oracle-7.3.4.svg new file mode 100644 index 000000000..6cbc84f40 --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-delete-oracle-7.3.4.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + 7.3.4 Delete Oracle Endpoint + + + + Account Lookup Service + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Account Lookup Service Admin API + + + + + Account Lookup Service Admin API + + + + + DELETE Oracle Handler + + + + + DELETE Oracle Handler + + + + + ALS Store + + + + + ALS Store + + + + + + + + Get Oracle Endpoint + + + + + 1 + + + Request to Delete Oracle Endpoint - + + + DELETE /oracles/{ID} + + + + + 2 + + + Delete Oracle Endpoint + + + + + 3 + + + Update existing Oracle Endpoint By ID + + + + Update isActive = false + + + + + alt + + + [Delete existing Oracle Endpoint (success)] + + + + + 4 + + + Return Success + + + + + 5 + + + Return success response + + + + + 6 + + + Return + + + HTTP Status: + + + 204 + + + + + alt + + + [Delete existing Oracle Endpoint (failure)] + + + + + 7 + + + Throws Error (Not Found) + + + + + 8 + + + Throw Error + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 9 + + + Return + + + HTTP Status: + + + 502 + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-get-oracle-7.3.1.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-get-oracle-7.3.1.svg new file mode 100644 index 000000000..7447557a3 --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-get-oracle-7.3.1.svg @@ -0,0 +1,240 @@ + + + + + + + + + + + 7.3.1 Get All Oracle Endpoints + + + + Account Lookup Service + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Account Lookup Service Admin API + + + + + Account Lookup Service Admin API + + + + + Get Oracles Handler + + + + + Get Oracles Handler + + + + + ALS Store + + + + + ALS Store + + + + + + + + Get Oracle Endpoints + + + + + 1 + + + Request to GET all Oracle Endpoints - + + + GET /oracles?currency=USD&type=MSISDN + + + + + 2 + + + Get Oracle Endpoints + + + + + 3 + + + Get oracle endpoints + + + + + alt + + + [Get Oracle Endpoints (success)] + + + + + 4 + + + Return Oracle Endpoints + + + + + 5 + + + Return Oracle Endpoints + + + + + Message: + + + { + + + [ + + + { + + + "oracleId": <string>, + + + "oracleIdType": <PartyIdType>, + + + "endpoint": { + + + "value": <string>, + + + "endpointType": <EndpointType> + + + }, + + + "currency": <Currency>, + + + "isDefault": <boolean> + + + } + + + ] + + + } + + + + + 6 + + + Return + + + HTTP Status: + + + 200 + + + + + alt + + + [Get Oracle Endpoints (failure)] + + + + + 7 + + + Throw Error + + + + + 8 + + + Throw Error + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 9 + + + Return + + + HTTP Status: + + + 502 + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-post-oracle-7.3.2.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-post-oracle-7.3.2.svg new file mode 100644 index 000000000..0638bdb48 --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-post-oracle-7.3.2.svg @@ -0,0 +1,233 @@ + + + + + + + + + + + 7.3.2 Create Oracle Endpoints + + + + Account Lookup Service + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Account Lookup Service Admin API + + + + + Account Lookup Service Admin API + + + + + POST Oracle Handler + + + + + POST Oracle Handler + + + + + ALS Store + + + + + ALS Store + + + + + + + + Get Oracle Endpoint + + + + + 1 + + + Request to Create Oracle Endpoint - + + + POST /oracles + + + + + Message: + + + { + + + "oracleIdType": <PartyIdType>, + + + "endpoint": { + + + "value": <string>, + + + "endpointType": <EndpointType> + + + }, + + + "currency": <Currency>, + + + "isDefault": <boolean> + + + } + + + + + 2 + + + Create Oracle Endpoint + + + + + 3 + + + Build Oracle Endpoint Data Object + + + + + 4 + + + Insert Oracle Endpoint Data Object + + + + + alt + + + [Create Oracle Entry (success)] + + + + + 5 + + + Return success response + + + + + 6 + + + Return success response + + + + + 7 + + + Return + + + HTTP Status: + + + 201 + + + + + alt + + + [Create Oracle Entry (failure)] + + + + + 8 + + + Throw Error + + + + + 9 + + + Throw Error + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 10 + + + Return + + + HTTP Status: + + + 502 + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-put-oracle-7.3.3.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-put-oracle-7.3.3.svg new file mode 100644 index 000000000..98da55c5c --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-admin-put-oracle-7.3.3.svg @@ -0,0 +1,319 @@ + + + + + + + + + + + 7.3.3 Update Oracle Endpoint + + + + Account Lookup Service + + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Account Lookup Service Admin API + + + + + Account Lookup Service Admin API + + + + + PUT Oracle Handler + + + + + PUT Oracle Handler + + + + + ALS Store + + + + + ALS Store + + + + + + + + Get Oracle Endpoint + + + + + 1 + + + Request to Update Oracle Endpoint - + + + PUT /oracles/{ID} + + + + + Message: + + + { + + + "oracleIdType": <PartyIdType>, + + + "endpoint": { + + + "value": <string>, + + + "endpointType": <EndpointType> + + + }, + + + "currency": <Currency>, + + + "isDefault": <boolean> + + + } + + + + + 2 + + + Update Oracle Endpoint + + + + + 3 + + + Find existing Oracle Endpoint + + + + + alt + + + [Find existing Oracle Endpoint (success)] + + + + + 4 + + + Return Oracle Endpoint Result + + + + + 5 + + + Update Returned Oracle Data Object + + + + + 6 + + + Update Oracle Data Object + + + + + alt + + + [Update Oracle Entry (success)] + + + + + 7 + + + Return success response + + + + + 8 + + + Return success response + + + + + 9 + + + Return + + + HTTP Status: + + + 204 + + + + + alt + + + [Update Oracle Entry (failure)] + + + + + 10 + + + Throw Error + + + + + 11 + + + Throw Error + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 12 + + + Return + + + HTTP Status: + + + 502 + + + + + alt + + + [Find existing Oracle Endpoint (failure)] + + + + + 13 + + + Returns Empty Object + + + + + 14 + + + Throw Error + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 15 + + + Return + + + HTTP Status: + + + 502 + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-del-endpoint-cache-7.3.0.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-del-endpoint-cache-7.3.0.svg new file mode 100644 index 000000000..ab60d1d1b --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-del-endpoint-cache-7.3.0.svg @@ -0,0 +1,208 @@ + + + + + + + + + + + 7.3.0 Delete Endpoint Cache + + + + Account Lookup Service + + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Account Lookup Service API + + + + + Account Lookup Service API + + + + + Delete Endpoint Cache Handler + + + + + Delete Endpoint Cache Handler + + + + + Cache + + + + + Cache + + + + + + + + + Delete Endpoint Cache + + + + + 1 + + + Request to DELETE Endpoint Cache - DELETE /endpointcache + + + + + 2 + + + Delete Cache + + + + + 3 + + + Stop Cache + + + + + alt + + + [Stop Cache Status (success)] + + + + + 4 + + + Return status + + + + + 5 + + + Initialize Cache + + + + + 6 + + + Return Status + + + + + 7 + + + Return Status + + + + + 8 + + + Return + + + HTTP Status: + + + 202 + + + + + alt + + + [Validate Status (service failure)] + + + + + 9 + + + Throw Error + + + + + 10 + + + Throw Error + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 11 + + + Return + + + HTTP Status: + + + 502 + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-del-participants-7.1.2.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-del-participants-7.1.2.svg new file mode 100644 index 000000000..4612fee5f --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-del-participants-7.1.2.svg @@ -0,0 +1,632 @@ + + + + + + + + + + + 7.1.2. Delete Participant Details + + + + Financial Service Provider + + + + Account Lookup Service + + + + Central Services + + + + ALS Oracle Service/Adapter + + + + Financial Service Provider + + + + + + + + + Payer FSP + + + + + Payer FSP + + + + + Account Lookup + + + Service (ALS) + + + + + Account Lookup + + + Service (ALS) + + + + + ALS Participant + + + Handler + + + + + ALS Participant + + + Handler + + + + + ALS Participant Endpoint + + + Oracle DAO + + + + + ALS Participant Endpoint + + + Oracle DAO + + + + + ALS Database + + + + + ALS Database + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Participant DAO + + + + + ALS CentralService + + + Participant DAO + + + + + ALS Parties + + + FSP DAO + + + + + ALS Parties + + + FSP DAO + + + + + Central Service API + + + + + Central Service API + + + + + Oracle Service API + + + + + Oracle Service API + + + + + Payee FSP + + + + + Payee FSP + + + + + + + + Get Party Details + + + + 1 + + + Request to delete Participant details + + + DEL - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + Response code: + + + 202 + + + Error code: + + + 200x, 300x, 310x, 320x + + + + + Validate request against + + + Mojaloop Interface Specification. + + + Error code: + + + 300x, 310x + + + + + 2 + + + Request to delete Participant details + + + + + alt + + + [oracleEndpoint match found & parties information retrieved] + + + + + 3 + + + Get Oracle Routing Config + + + Error code: + + + 200x, 310x, 320x + + + + + ref + + + GET Participants - + + + + Get Oracle Routing Config Sequence + + + + + + + Validate FSPIOP-Source Participant + + + + + 4 + + + Request FSPIOP-Source participant information + + + Error code: + + + 200x + + + + + 5 + + + GET - /participants/{FSPIOP-Source} + + + Error code: + + + 200x, 310x, 320x + + + + + 6 + + + Return FSPIOP-Source participant information + + + + + 7 + + + Return FSPIOP-Source participant information + + + + + 8 + + + Validate FSPIOP-Source participant + + + Error code: + + + 320x + + + + + 9 + + + Validate that PARTICIPANT.fspId == FSPIOP-Source + + + Error code: + + + 3100 + + + + + 10 + + + Get Participant Information for PayerFSP + + + Error code: + + + 200x, 310x, 320x + + + + + ref + + + GET Participants - + + + + Request Participant Information from Oracle Sequence + + + + + + + Validate Participant Ownership + + + + + 11 + + + Validate that PARTICIPANT.fspId matches Participant Information retrieved from Oracle. + + + Error code: + + + 3100 + + + + + 12 + + + Request to delete Participant's FSP details DEL - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + Error code: + + + 200x, 310x, 320x + + + + + 13 + + + Request to delete Participant's FSP details DEL - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 14 + + + Return result + + + + + 15 + + + Return result + + + + + 16 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + Error code: + + + 200x + + + + + 17 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Error code: + + + 200x, 310x, 320x + + + + + 18 + + + List of PayerFSP Participant Callback Endpoints + + + + + 19 + + + List of PayerFSP Participant Callback Endpoints + + + + + 20 + + + Match PayerFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_PUT + + + + + 21 + + + Return delete request result + + + + 22 + + + Callback indiciating success: + + + PUT - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + + [Validation failure or Oracle was unable process delete request] + + + + + 23 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 24 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 25 + + + List of PayerFSP Participant Callback Endpoints + + + + + 26 + + + List of PayerFSP Participant Callback Endpoints + + + + + 27 + + + Match PayerFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR + + + + + 28 + + + Handle error + + + Error code: + + + 200x, 310x, 320x + + + + 29 + + + Callback: PUT - /participants/{TYPE}/{ID}/error + + + + [Empty list of switchEndpoint results returned] + + + + + 30 + + + Handle error + + + Error code: + + + 200x + + + + Error Handling Framework + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-get-participants-7.1.0.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-get-participants-7.1.0.svg new file mode 100644 index 000000000..74687dae8 --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-get-participants-7.1.0.svg @@ -0,0 +1,558 @@ + + + + + + + + + + + 7.1.0. Get Participant Details + + + + Financial Service Provider + + + + Account Lookup Service + + + + Central Services + + + + ALS Oracle Service/Adapter + + + + + + + + + + Payer FSP + + + + + Payer FSP + + + + + Account Lookup + + + Service (ALS) + + + + + Account Lookup + + + Service (ALS) + + + + + ALS Participant + + + Handler + + + + + ALS Participant + + + Handler + + + + + ALS Endpoint Type + + + Config DAO + + + + + ALS Endpoint Type + + + Config DAO + + + + + ALS Participant + + + Oracle DAO + + + + + ALS Participant + + + Oracle DAO + + + + + ALS Database + + + + + ALS Database + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Endpoint DAO + + + + + Central Service API + + + + + Central Service API + + + + + Oracle Service API + + + + + Oracle Service API + + + + + + + + Get Participant's FSP Details + + + + 1 + + + Request to get participant's FSP details + + + GET - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + Response code: + + + 202 + + + Error code: + + + 200x, 300x, 310x, 320x + + + + + Validate request against + + + Mojaloop Interface Specification. + + + Error code: + + + 300x, 310x + + + + + 2 + + + Request to get participant's FSP details + + + + + alt + + + [oracleEndpoint match found] + + + + + IMPLEMENTATION: Get Oracle Routing Config Sequence + + + [CACHED] + + + + + 3 + + + Fetch Oracle Routing information based on + + + {TYPE} and {CURRENCY} if provided + + + Error code: + + + 200x + + + + + 4 + + + Retrieve oracleEndpoint + + + Error code: + + + 200x + + + + oracleEndpoint + + + endpointType + + + partyIdType + + + currency (optional) + + + + + 5 + + + Return oracleEndpoint result set + + + + + 6 + + + List of + + + oracleEndpoint + + + for the Participant + + + + + opt + + + [oracleEndpoint IS NULL] + + + + + 7 + + + Error code: + + + 3200 + + + + + IMPLEMENTATION: Request Participant Information from Oracle Sequence + + + + + 8 + + + Request to get participant's FSP details + + + GET - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + Error code: + + + 200x, 310x, 320x + + + + + 9 + + + Request to get participant's FSP details + + + GET - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 10 + + + Return list of Participant information + + + + + 11 + + + Return list of Participant information + + + + + 12 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 13 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 14 + + + List of PayerFSP Participant Callback Endpoints + + + + + 15 + + + List of PayerFSP Participant Callback Endpoints + + + + + 16 + + + Match PayerFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_PUT + + + + + 17 + + + Return list of Participant information + + + + 18 + + + Callback: PUT - /participants/{TYPE}/{ID}?currency={CURRENCY} + + + + [oracleEndpoint IS NULL OR error occurred] + + + + + 19 + + + Retrieve the Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 20 + + + Retrieve the Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints. + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 21 + + + List of Participant Callback Endpoints + + + + + 22 + + + List of Participant Callback Endpoints + + + + + 23 + + + Match Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR + + + + + 24 + + + Handle error + + + Error code: + + + 200x, 310x, 320x + + + + 25 + + + Callback: PUT - /participants/{TYPE}/{ID}/error + + + + [switchEndpoint IS NULL] + + + + + 26 + + + Handle error + + + Error code: + + + 200x + + + + Error Handling Framework + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-get-parties-7.2.0.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-get-parties-7.2.0.svg new file mode 100644 index 000000000..7b3342d7b --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-get-parties-7.2.0.svg @@ -0,0 +1,699 @@ + + + + + + + + + + + 7.2.0. Get Party Details + + + + Financial Service Provider + + + + Account Lookup Service + + + + Central Services + + + + ALS Oracle Service/Adapter + + + + Financial Service Provider + + + + + + + + + Payer FSP + + + + + Payer FSP + + + + + Account Lookup + + + Service (ALS) + + + + + Account Lookup + + + Service (ALS) + + + + + ALS Participant + + + Handler + + + + + ALS Participant + + + Handler + + + + + ALS Database + + + + + ALS Database + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Participant DAO + + + + + ALS CentralService + + + Participant DAO + + + + + ALS Parties + + + FSP DAO + + + + + ALS Parties + + + FSP DAO + + + + + Central Service API + + + + + Central Service API + + + + + Oracle Service API + + + + + Oracle Service API + + + + + Payee FSP + + + + + Payee FSP + + + + + + + + Get Party Details + + + + 1 + + + Request to get parties's FSP details + + + GET - /parties/{TYPE}/{ID}?currency={CURRENCY} + + + Response code: + + + 202 + + + Error code: + + + 200x, 300x, 310x, 320x + + + + + Validate request against + + + Mojaloop Interface Specification. + + + Error code: + + + 300x, 310x + + + + + 2 + + + Request to get parties's FSP details + + + + + alt + + + [oracleEndpoint match found & parties information retrieved] + + + + + 3 + + + Get Oracle Routing Config + + + Error code: + + + 200x, 310x, 320x + + + + + ref + + + GET Participants - + + + + Get Oracle Routing Config Sequence + + + + + + + Validate FSPIOP-Source Participant + + + + + 4 + + + Request FSPIOP-Source participant information + + + Error code: + + + 200x + + + + + 5 + + + GET - /participants/{FSPIOP-Source} + + + Error code: + + + 200x, 310x, 320x + + + + + 6 + + + Return FSPIOP-Source participant information + + + + + 7 + + + Return FSPIOP-Source participant information + + + + + 8 + + + Validate FSPIOP-Source participant + + + Error code: + + + 320x + + + + + 9 + + + Get Participant Information for PayeeFSP + + + Error code: + + + 200x, 310x, 320x + + + + + ref + + + GET Participants - + + + + Request Participant Information from Oracle Sequence + + + + + + + 10 + + + Request Parties information from FSP. + + + Error code: + + + 200x + + + + 11 + + + Parties Callback to Destination: + + + GET - /parties/{TYPE}/{ID}?currency={CURRENCY} + + + Response code: + + + 202 + + + Error code: + + + 200x, 310x, 320x + + + + 12 + + + Callback with Participant Information: + + + PUT - /parties/{TYPE}/{ID}?currency={CURRENCY} + + + Error code: + + + 200x, 300x, 310x, 320x + + + + + 13 + + + Validate request against + + + Mojaloop Interface Specification + + + Error code: + + + 300x, 310x + + + + + 14 + + + Process Participant Callback Information for PUT + + + + + 15 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + Error code: + + + 200x + + + + + 16 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Error code: + + + 200x, 310x, 320x + + + + + 17 + + + List of PayerFSP Participant Callback Endpoints + + + + + 18 + + + List of PayerFSP Participant Callback Endpoints + + + + + 19 + + + Match PayerFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTIES_PUT + + + + + 20 + + + Return Participant Information to PayerFSP + + + + 21 + + + Callback with Parties Information: + + + PUT - /parties/{TYPE}/{ID}?currency={CURRENCY} + + + + [Empty list of End-Points returned for either (PayeeFSP or Oracle) config information or Error occurred for PayerFSP] + + + + + 22 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 23 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 24 + + + List of PayerFSP Participant Callback Endpoints + + + + + 25 + + + List of PayerFSP Participant Callback Endpoints + + + + + 26 + + + Match PayerFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR + + + + + 27 + + + Handle error + + + Error code: + + + 200x, 310x, 320x + + + + 28 + + + Callback: PUT - /participants/{TYPE}/{ID}/error + + + + [Empty list of End-Points returned for PayerFSP config information or Error occurred for PayeeFSP] + + + + + 29 + + + Retrieve the PayeeFSP Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 30 + + + Retrieve the PayeeFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 31 + + + List of PayeeFSP Participant Callback Endpoints + + + + + 32 + + + List of PayeeFSP Participant Callback Endpoints + + + + + 33 + + + Match PayeeFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR + + + + + 34 + + + Handle error + + + Error code: + + + 200x, 310x, 320x + + + + 35 + + + Callback: PUT - /participants/{TYPE}/{ID}/error + + + + [Empty list of switchEndpoint results returned] + + + + + 36 + + + Handle error + + + Error code: + + + 200x + + + + Error Handling Framework + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-post-participants-7.1.3.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-post-participants-7.1.3.svg new file mode 100644 index 000000000..07a5a256d --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-post-participants-7.1.3.svg @@ -0,0 +1,598 @@ + + + + + + + + + + + 7.1.3 Post Participant Details by Type and ID + + + + Financial Service Provider + + + + Account Lookup Service + + + + Central Services + + + + ALS Oracle Service/Adapter + + + + + + + + + Payer FSP + + + + + Payer FSP + + + + + Account Lookup + + + Service (ALS) + + + + + Account Lookup + + + Service (ALS) + + + + + ALS Participant + + + Handler + + + + + ALS Participant + + + Handler + + + + + ALS Participant + + + Oracle DAO + + + + + ALS Participant + + + Oracle DAO + + + + + ALS Database + + + + + ALS Database + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Participant DAO + + + + + ALS CentralService + + + Participant DAO + + + + + Central Service API + + + + + Central Service API + + + + + Oracle Service API + + + + + Oracle Service API + + + + + + + + Post Participant's FSP Details + + + + + Headers - postParticipantsByTypeIDHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - postParticipantsByTypeIDMessage: + + + { + + + "fspId": "string" + + + } + + + + 1 + + + Request to add participant's FSP details + + + POST - /participants/{Type}/{ID} + + + Response code: + + + 202 + + + Error code: + + + 200x, 300x, 310x, 320x + + + + + Validate request against + + + Mojaloop Interface Specification. + + + Error code: + + + 300x, 310x + + + + + 2 + + + Process create participant's FSP details + + + + + 3 + + + Validate that PARTICIPANT.fspId == FSPIOP-Source + + + Error code: + + + 3100 + + + + + alt + + + [Validation passed] + + + + + 4 + + + Get Oracle Routing Config based on Type (and optional Currency) + + + Error code: + + + 300x, 310x + + + + + ref + + + GET Participants - + + + + Get Oracle Routing Config Sequence + + + + + + + Validate Participant's FSP + + + + + 5 + + + Request participant (PARTICIPANT.fspId) information for {Type} + + + Error code: + + + 200x + + + + + 6 + + + GET - /participants/{PARTICIPANT.fspId} + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 7 + + + Return participant information + + + + + 8 + + + Return participant information + + + + + 9 + + + Validate participant + + + Error code: + + + 320x + + + + + 10 + + + Create participant's FSP details + + + POST - /participants + + + Error code: + + + 200x, 310x, 320x + + + + + 11 + + + Create participant's FSP details + + + POST - /participants + + + Response code: + + + 204 + + + Error code: + + + 200x, 310x, 320x + + + + + 12 + + + Return result of Participant Create request + + + + + 13 + + + Return result of Participant Create request + + + + + 14 + + + Retrieve the PayerFSP (FSPIOP-Source) Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 15 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 16 + + + List of PayerFSP Participant Callback Endpoints + + + + + 17 + + + List of PayerFSP Participant Callback Endpoints + + + + + 18 + + + Match PayerFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_PUT + + + + + 19 + + + Return list of Participant information from ParticipantResult + + + + 20 + + + Callback: PUT - /participants/{Type}/{ID} + + + + [Validation failure] + + + + + 21 + + + Retrieve the PayerFSP (FSPIOP-Source) Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 22 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 23 + + + List of PayerFSP Participant Callback Endpoints + + + + + 24 + + + List of PayerFSP Participant Callback Endpoints + + + + + 25 + + + Match Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR + + + + + 26 + + + Handle error + + + Error code: + + + 200x, 310x, 320x + + + + 27 + + + Callback: PUT - /participants/{Type}/{ID}/error + + diff --git a/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-post-participants-batch-7.1.1.svg b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-post-participants-batch-7.1.1.svg new file mode 100644 index 000000000..e3883aba0 --- /dev/null +++ b/mojaloop-technical-overview/account-lookup-service/assets/diagrams/sequence/seq-acct-lookup-post-participants-batch-7.1.1.svg @@ -0,0 +1,674 @@ + + + + + + + + + + + 7.1.1. Post Participant (Batch) Details + + + + Financial Service Provider + + + + Account Lookup Service + + + + Central Services + + + + ALS Oracle Service/Adapter + + + + + + + + + + Payer FSP + + + + + Payer FSP + + + + + Account Lookup + + + Service (ALS) + + + + + Account Lookup + + + Service (ALS) + + + + + ALS Participant + + + Handler + + + + + ALS Participant + + + Handler + + + + + ALS Participant + + + Oracle DAO + + + + + ALS Participant + + + Oracle DAO + + + + + ALS Database + + + + + ALS Database + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Endpoint DAO + + + + + ALS CentralService + + + Participant DAO + + + + + ALS CentralService + + + Participant DAO + + + + + Central Service API + + + + + Central Service API + + + + + Oracle Service API + + + + + Oracle Service API + + + + + + + + Post Participant's FSP Details + + + + + Headers - postParticipantsHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - postParticipantsMessage: + + + { + + + "requestId": "string", + + + "partyList": [ + + + { + + + "partyIdType": "string", + + + "partyIdentifier": "string", + + + "partySubIdOrType": "string", + + + "fspId": "string" + + + } + + + ], + + + "currency": "string" + + + } + + + + 1 + + + Request to add participant's FSP details + + + POST - /participants + + + Response code: + + + 202 + + + Error code: + + + 200x, 300x, 310x, 320x + + + + + Validate request against + + + Mojaloop Interface Specification. + + + Error code: + + + 300x, 310x + + + + + 2 + + + Process create participant's FSP details + + + + + loop + + + [for Participant in ParticipantList] + + + + + 3 + + + Validate that PARTICIPANT.fspId == FSPIOP-Source + + + Error code: + + + 3100 + + + + + 4 + + + Group Participant lists into a Map (ParticipantMap) based on {TYPE} + + + + + alt + + + [Validation passed and the ParticipantMap was created successfully] + + + + + loop + + + [for keys in ParticipantMap -> TypeKey] + + + + + 5 + + + Get Oracle Routing Config based on TypeKey (and optional Currency) + + + Error code: + + + 300x, 310x + + + + + ref + + + GET Participants - + + + + Get Oracle Routing Config Sequence + + + + + + + Validate Participant's FSP + + + + + 6 + + + Request participant (PARTICIPANT.fspId) information for {TypeKey} + + + Error code: + + + 200x + + + + + 7 + + + GET - /participants/{PARTICIPANT.fspId} + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 8 + + + Return participant information + + + + + 9 + + + Return participant information + + + + + 10 + + + Validate participant + + + Error code: + + + 320x + + + + + 11 + + + Create participant's FSP details + + + POST - /participants + + + Error code: + + + 200x, 310x, 320x + + + + + 12 + + + Create participant's FSP details + + + POST - /participants + + + Response code: + + + 204 + + + Error code: + + + 200x, 310x, 320x + + + + + 13 + + + Return result of Participant Create request + + + + + 14 + + + Return result of Participant Create request + + + + + 15 + + + Store results in ParticipantResultMap[TypeKey] + + + + + loop + + + [for keys in ParticipantResultMap -> TypeKey] + + + + + 16 + + + Combine ParticipantResultMap[TypeKey] results into ParticipantResult + + + + + 17 + + + Retrieve the PayerFSP (FSPIOP-Source) Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 18 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 19 + + + List of PayerFSP Participant Callback Endpoints + + + + + 20 + + + List of PayerFSP Participant Callback Endpoints + + + + + 21 + + + Match PayerFSP Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT + + + + + 22 + + + Return list of Participant information from ParticipantResult + + + + 23 + + + Callback: PUT - /participants/{requestId} + + + + [Validation failure and/or the ParticipantMap was not created successfully] + + + + + 24 + + + Retrieve the PayerFSP (FSPIOP-Source) Participant Callback Endpoint + + + Error code: + + + 200x, 310x, 320x + + + + + 25 + + + Retrieve the PayerFSP Participant Callback Endpoint + + + GET - /participants/{FSPIOP-Source}/endpoints + + + Response code: + + + 200 + + + Error code: + + + 200x, 310x, 320x + + + + + 26 + + + List of PayerFSP Participant Callback Endpoints + + + + + 27 + + + List of PayerFSP Participant Callback Endpoints + + + + + 28 + + + Match Participant Callback Endpoints for + + + FSPIOP_CALLBACK_URL_PARTICIPANT_BATCH_PUT_ERROR + + + + + 29 + + + Handle error + + + Error code: + + + 200x, 310x, 320x + + + + 30 + + + Callback: PUT - /participants/{requestId}/error + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.1.0-bulk-prepare-overview.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.1.0-bulk-prepare-overview.svg new file mode 100644 index 000000000..b24804c17 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.1.0-bulk-prepare-overview.svg @@ -0,0 +1,788 @@ + + + + + + + + + + + 1.1.0. DFSP1 sends a Bulk Prepare Transfer request to DFSP2 + + + + Financial Service Providers + + + + Bulk API Adapter Service + + + + Central Service + + + + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + Bulk API Adapter + + + + + Bulk API Adapter + + + + + Bulk API Notification + + + Handler + + + + + Bulk API Notification + + + Handler + + + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + Central Service API + + + + + Central Service API + + + + + + + topic- + + + bulk-prepare + + + + + topic- + + + bulk-prepare + + + Bulk Prepare + + + Handler + + + + + Bulk Prepare + + + Handler + + + + + + + topic- + + + transfer-prepare + + + + + topic- + + + transfer-prepare + + + Prepare Handler + + + + + Prepare Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + Position Handler + + + + + Position Handler + + + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + Bulk Processing + + + Handler + + + + + Bulk Processing + + + Handler + + + + + + + topic- + + + notifications + + + + + topic- + + + notifications + + + + + + DFSP1 sends a Bulk Prepare Transfer request to DFSP2 + + + + + Headers - transferHeaders: { + + + Content-Length: <int>, + + + Content-Type: <string>, + + + Date: <date>, + + + FSPIOP-Source: <string>, + + + FSPIOP-Destination: <string>, + + + FSPIOP-Encryption: <string>, + + + FSPIOP-Signature: <string>, + + + FSPIOP-URI: <uri>, + + + FSPIOP-HTTP-Method: <string> + + + } + + + Payload - bulkTransferMessage: + + + { + + + bulkTransferId: <uuid>, + + + bulkQuoteId: <uuid>, + + + payeeFsp: <string>, + + + payerFsp: <string>, + + + individualTransfers: [ + + + { + + + transferId: <uuid>, + + + transferAmount: + + + { + + + currency: <string>, + + + amount: <string> + + + }, + + + ilpPacket: <string>, + + + condition: <string>, + + + extensionList: { extension: [ + + + { key: <string>, value: <string> } + + + ] } + + + } + + + ], + + + extensionList: { extension: [ + + + { key: <string>, value: <string> } + + + ] }, + + + expiration: <string> + + + } + + + + 1 + + + POST - /bulkTransfers + + + + + 2 + + + Validate incoming message + + + Error codes: + + + 3000-3002, 3100-3107 + + + + + loop + + + + + 3 + + + Persist individual transfers in the bulk to + + + object store: + + + MLOS.individualTransfers + + + + + 4 + + + Return messageId reference to the stored object(s) + + + + + Message: + + + { + + + id: <messageId> + + + to: <payeeFspName>, + + + from: <payerFspName>, + + + type: "application/json" + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + bulkTransferId: <uuid>, + + + bulkQuoteId": <uuid>, + + + payerFsp: <string>, + + + payeeFsp: <string>, + + + expiration: <timestamp>, + + + hash: <string> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: "bulk-prepare", + + + action: "bulk-prepare", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 5 + + + Route & Publish Bulk Prepare event + + + for Payer + + + Error code: + + + 2003 + + + + + 6 + + + Ensure event is replicated + + + as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 7 + + + Respond replication acknowledgements + + + have been received + + + + + 8 + + + Respond HTTP - 202 (Accepted) + + + + + 9 + + + Consume message + + + + + ref + + + Bulk Prepare Handler Consume + + + + + alt + + + [Success] + + + + + 10 + + + Produce (stream) single transfer message + + + for each individual transfer [loop] + + + + [Failure] + + + + + 11 + + + Produce single message for the entire bulk + + + + + 12 + + + Consume message + + + + + ref + + + Prepare Handler Consume + + + + + alt + + + [Success] + + + + + 13 + + + Produce message + + + + [Failure] + + + + + 14 + + + Produce message + + + + + 15 + + + Consume message + + + + + ref + + + Position Handler Consume + + + + + 16 + + + Produce message + + + + + 17 + + + Consume message + + + + + ref + + + Bulk Processing Handler Consume + + + + + 18 + + + Persist bulk message by destination to the + + + object store: + + + MLOS.bulkTransferResults + + + + + 19 + + + Return the reference to the stored + + + notification object(s): + + + messageId + + + + + 20 + + + Send Bulk Prepare notification + + + + + 21 + + + Consume message + + + + + 22 + + + Retrieve bulk notification(s) by reference & destination: + + + MLOS.bulkTransferResults.messageId + destination + + + + + 23 + + + Return notification(s) payload + + + + + ref + + + Send notification to Participant (Payee) + + + + + 24 + + + Send Bulk Prepare notification to Payee + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.1.1-bulk-prepare-handler.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.1.1-bulk-prepare-handler.svg new file mode 100644 index 000000000..eb4b20b44 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.1.1-bulk-prepare-handler.svg @@ -0,0 +1,1009 @@ + + + + + + + + + + + 1.1.1. Bulk Prepare Handler Consume + + + + Central Service + + + + + + + + + + + + + + + + + + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + + + topic- + + + bulk-prepare + + + + + topic- + + + bulk-prepare + + + Bulk Prepare + + + Handler + + + + + Bulk Prepare + + + Handler + + + + + + + topic- + + + transfer-prepare + + + + + topic- + + + transfer-prepare + + + + + topic-event + + + + + topic-event + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + topic-bulk- + + + processing + + + + + topic-bulk- + + + processing + + + Bulk DAO + + + + + Bulk DAO + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Bulk Prepare Handler Consume + + + + + 1 + + + Consume Bulk Prepare message + + + + + Validate Bulk Prepare Transfer + + + + + Duplicate Check + + + + + The Specification doesn't touch on the duplicate handling + + + of bulk transfers, so the current design mostly follows the + + + strategy used for individual transfers, except in two places: + + + 1. For duplicate requests where hash matches, the current design + + + includes only the status of the bulk & timestamp (if completed), + + + but not the individual transfers (for which a GET should be used). + + + 2. For duplicate requests where hash matches, but are not in a + + + finalized state, only the state of the bulkTransfer is sent. + + + + + 2 + + + Request Duplicate Check + + + + + ref + + + Request Duplicate Check (using message.content.payload) + + + + + 3 + + + Return { hasDuplicateId: Boolean, hasDuplicateHash: Boolean } + + + + + alt + + + [hasDuplicateId == TRUE && hasDuplicateHash == TRUE] + + + + + break + + + [Return TRUE & Log ('Not implemented')] + + + + [hasDuplicateId == TRUE && hasDuplicateHash == FALSE] + + + + + { + + + id: <messageId>, + + + from: <ledgerName>, + + + to: <payerFspName>, + + + type: "application/json", + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + errorInformation: { + + + errorCode: "3106", + + + errorDescription: "Modified request", + + + extensionList: { + + + extension: [ + + + { + + + key: "_cause", + + + value: <FSPIOPError> + + + } + + + ] + + + } + + + }, + + + uriParams: { + + + id: <bulkTransferId> + + + } + + + } + + + }, + + + metadata: { + + + correlationId: <uuid>, + + + event: { + + + id: <uuid>, + + + type: "notification", + + + action: "bulk-prepare", + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: "3106", + + + description: "Modified request" + + + }, + + + responseTo: <uuid> + + + } + + + } + + + } + + + + + 4 + + + Publish Notification (failure) event for Payer + + + Error codes: + + + 3106 + + + + [hasDuplicateId == FALSE] + + + + + Validate Bulk Transfer Prepare Request + + + + + 5 + + + FSPIOP Source matches Payer + + + + + 6 + + + Check expiration + + + + + 7 + + + Payer and Payee FSP's are different + + + + + Validate Payer + + + + + 8 + + + Request to retrieve Payer Participant details (if it exists) + + + + + 9 + + + Request Participant details + + + + participant + + + participantCurrency + + + + + 10 + + + Return Participant details if it exists + + + + + 11 + + + Return Participant details if it exists + + + + + 12 + + + Validate Payer + + + Error codes: + + + 3202 + + + + + Validate Payee + + + + + 13 + + + Request to retrieve Payee Participant details (if it exists) + + + + + 14 + + + Request Participant details + + + + participant + + + participantCurrency + + + + + 15 + + + Return Participant details if it exists + + + + + 16 + + + Return Participant details if it exists + + + + + 17 + + + Validate Payee + + + Error codes: + + + 3203 + + + + + alt + + + [Validate Bulk Transfer Prepare Request (success)] + + + + + Persist Bulk Transfer State (with bulkTransferState='RECEIVED') + + + + + 18 + + + Request to persist bulk transfer + + + Error codes: + + + 2003 + + + + + 19 + + + Persist bulkTransfer + + + + bulkTransfer + + + bulkTransferExtension + + + bulkTransferStateChange + + + + + 20 + + + Return state + + + + [Validate Bulk Transfer Prepare Request (failure)] + + + + + Persist Bulk Transfer State (with bulkTransferState='INVALID') (Introducing a new status INVALID to mark these entries) + + + + + 21 + + + Request to persist bulk transfer + + + (when Payee/Payer/crypto-condition validation fails) + + + Error codes: + + + 2003 + + + + + 22 + + + Persist transfer + + + + bulkTransfer + + + bulkTransferExtension + + + bulkTransferStateChange + + + bulkTransferError + + + + + 23 + + + Return state + + + + + alt + + + [Validate Bulk Prepare Transfer (success)] + + + + + loop + + + [for each individual transfer in the bulk] + + + + + 24 + + + Retrieve individual transfers from the bulk using + + + reference: + + + MLOS.individualTransfers.messageId + + + + + Add elements such as Expiry time, Payer FSP, Payee FSP, etc. to each + + + transfer to make their format similar to a single transfer + + + + + 25 + + + Stream bulk's individual transfers + + + + + Insert Bulk Transfer Association (with bulkProcessingState='RECEIVED') + + + + + 26 + + + Request to persist bulk transfer association + + + Error codes: + + + 2003 + + + + + 27 + + + Insert bulkTransferAssociation + + + + bulkTransferAssociation + + + bulkTransferStateChange + + + + + 28 + + + Return state + + + + + Message: + + + { + + + id: <messageId> + + + from: <payerFspName>, + + + to: <payeeFspName>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "prepare", + + + action: "bulk-prepare", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0, + + + description:"action successful" + + + } + + + } + + + } + + + } + + + + + 29 + + + Route & Publish Prepare event to the Payee for the Individual Transfer + + + Error codes: + + + 2003 + + + + [Validate Bulk Prepare Transfer (failure)] + + + + + Message: + + + { + + + id: <messageId> + + + from: <ledgerName>, + + + to: <bulkTransferMessage.payerFsp>, + + + type: "application/json", + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": <possible codes: [2003, 3100, 3105, 3106, 3202, 3203, 3300, 3301]> + + + "errorDescription": "<refer to section 7.6 for description>", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "bulk-processing", + + + action: "bulk-abort", + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 30 + + + Publish Processing (failure) event for Payer + + + Error codes: + + + 2003 + + + + + Insert Bulk Transfer Association (with bulkProcessingState='INVALID') + + + + + 31 + + + Request to persist bulk transfer association + + + Error codes: + + + 2003 + + + + + 32 + + + Insert bulkTransferAssociation + + + + bulkTransferAssociation + + + bulkTransferStateChange + + + + + 33 + + + Return state + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.2.1-prepare-handler.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.2.1-prepare-handler.svg new file mode 100644 index 000000000..af0e4479c --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.2.1-prepare-handler.svg @@ -0,0 +1,975 @@ + + + + + + + + + + + 1.2.1. Prepare Handler Consume individual transfers from Bulk + + + + Central Service + + + + + + + + + + + + + + + + + + + + topic- + + + transfer-prepare + + + + + topic- + + + transfer-prepare + + + Prepare Handler + + + + + Prepare Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic- + + + event + + + + + topic- + + + event + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + Position DAO + + + + + Position DAO + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Prepare Handler Consume + + + + + 1 + + + Consume Prepare event message + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'prepare' && action == 'bulk-prepare' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate Prepare Transfer + + + + + 4 + + + Schema validation of the incoming message + + + + + 5 + + + Verify the message's signature (to be confirmed in future requirement) + + + + + Validate Duplicate Check + + + + + 6 + + + Request Duplicate Check + + + + + ref + + + Request Duplicate Check + + + + + 7 + + + Return { hasDuplicateId: Boolean, hasDuplicateHash: Boolean } + + + + + alt + + + [hasDuplicateId == TRUE && hasDuplicateHash == TRUE] + + + + + In the context of a bulk (when compared to regular transfers), duplicate + + + individual transfers are now considered and reported with Modified Request, + + + because they could have already been handled for another bulk. + + + + + break + + + + + { + + + id: <messageId> + + + from: <ledgerName>, + + + to: <payerFspName>, + + + type: "application/json", + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + errorInformation: { + + + errorCode: "3106", + + + errorDescription: "Modified request - Individual transfer prepare duplicate", + + + extensionList: { extension: [ { key: "_cause", value: <FSPIOPError> } ] } + + + } + + + }, + + + uriParams: { id: <transferId> } + + + }, + + + metadata: { + + + correlationId: <uuid>, + + + event: { + + + type: "bulk-processing", + + + action: "prepare-duplicate", + + + createdAt: <timestamp>, + + + state: { + + + code: "3106", + + + status: "error", + + + description: "Modified request - Individual transfer prepare duplicate" + + + }, + + + id: <uuid>, + + + responseTo: <uuid> + + + } + + + } + + + + + 8 + + + Publish Processing (failure) event for Payer + + + Error codes: + + + 2003 + + + + [hasDuplicateId == TRUE && hasDuplicateHash == FALSE] + + + + + break + + + + + { + + + id: <messageId> + + + from: <ledgerName>, + + + to: <payerFspName>, + + + type: "application/json", + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + errorInformation: { + + + errorCode: "3106", + + + errorDescription: "Modified request", + + + extensionList: { extension: [ { key: "_cause", value: <FSPIOPError> } ] } + + + } + + + }, + + + uriParams: { id: <transferId> } + + + }, + + + metadata: { + + + correlationId: <uuid>, + + + event: { + + + type: "bulk-processing", + + + action: "prepare-duplicate", + + + createdAt: <timestamp>, + + + state: { + + + code: "3106", + + + status: "error", + + + description: "Modified request" + + + }, + + + id: <uuid>, + + + responseTo: <uuid> + + + } + + + } + + + + + 9 + + + Publish Processing (failure) event for Payer + + + Error codes: + + + 2003 + + + + [hasDuplicateId == FALSE] + + + + + The validation of Payer, Payee can be skipped for individual transfers in Bulk + + + as they should've/would've been validated already in the bulk prepare part. + + + However, leaving it here for now, as in the future, this can be leveraged + + + when bulk transfers to multiple Payees are supported by the Specification. + + + + + Validate Payer + + + + + 10 + + + Request to retrieve Payer Participant details (if it exists) + + + + + 11 + + + Request Participant details + + + + participant + + + participantCurrency + + + + + 12 + + + Return Participant details if it exists + + + + + 13 + + + Return Participant details if it exists + + + + + 14 + + + Validate Payer + + + Error codes: + + + 3202 + + + + + Validate Payee + + + + + 15 + + + Request to retrieve Payee Participant details (if it exists) + + + + + 16 + + + Request Participant details + + + + participant + + + participantCurrency + + + + + 17 + + + Return Participant details if it exists + + + + + 18 + + + Return Participant details if it exists + + + + + 19 + + + Validate Payee + + + Error codes: + + + 3203 + + + + + alt + + + [Validate Prepare Transfer (success)] + + + + + Persist Transfer State (with transferState='RECEIVED-PREPARE') + + + + + 20 + + + Request to persist transfer + + + Error codes: + + + 2003 + + + + + 21 + + + Persist transfer + + + + transfer + + + transferParticipant + + + transferStateChange + + + transferExtension + + + ilpPacket + + + + + 22 + + + Return success + + + + [Validate Prepare Transfer (failure)] + + + + + Persist Transfer State (with transferState='INVALID') (Introducing a new status INVALID to mark these entries) + + + + + 23 + + + Request to persist transfer + + + (when Payee/Payer/crypto-condition validation fails) + + + Error codes: + + + 2003 + + + + + 24 + + + Persist transfer + + + + transfer + + + transferParticipant + + + transferStateChange + + + transferExtension + + + transferError + + + ilpPacket + + + + + 25 + + + Return success + + + + + alt + + + [Validate Prepare Transfer (success)] + + + + + Message: + + + { + + + id: <messageId> + + + from: <payerFspName>, + + + to: <payeeFspName>, + + + type: "application/json", + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "position", + + + action: "bulk-prepare", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0, + + + description:"action successful" + + + } + + + } + + + } + + + } + + + + + 26 + + + Route & Publish Position event for Payer + + + Error codes: + + + 2003 + + + + [Validate Prepare Transfer (failure)] + + + + + Message: + + + { + + + id: <messageId> + + + from: <ledgerName>, + + + to: <payerFspName>, + + + type: "application/json" + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": <possible codes: [2003, 3100, 3105, 3106, 3202, 3203, 3300, 3301]> + + + "errorDescription": "<refer to section 35.1.3 for description>", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "bulk-processing", + + + action: "prepare", + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 27 + + + Publish Prepare failure event to Bulk Processing Topic (for Payer) + + + Error codes: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.3.0-position-overview.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.3.0-position-overview.svg new file mode 100644 index 000000000..a6c1ce040 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.3.0-position-overview.svg @@ -0,0 +1,298 @@ + + + + + + + + + + + 1.3.0. Position Handler Consume individual transfers from Bulk + + + + Central Service + + + + + + + + + + + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Handler + + + + + Position Handler + + + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + Position Handler Consume + + + + + alt + + + [Consume Prepare message for Payer] + + + + + 1 + + + Consume Position event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'position' && action == 'bulk-prepare' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Prepare Position Handler Consume + + + + + 4 + + + Produce message + + + + [Consume Fulfil message for Payee] + + + + + 5 + + + Consume Position event message for Payee + + + + + break + + + + + Validate Event + + + + + 6 + + + Validate event - Rule: type == 'position' && action == 'bulk-commit' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 7 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Fulfil Position Handler Consume + + + + + 8 + + + Produce message + + + + [Consume Abort message] + + + + + 9 + + + Consume Position event message + + + + + break + + + + + Validate Event + + + + + 10 + + + Validate event - Rule: type == 'position' && action == 'timeout-reserved' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 11 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Abort Position Handler Consume + + + + + 12 + + + Produce message + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.3.1-position-prepare.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.3.1-position-prepare.svg new file mode 100644 index 000000000..1403dc6ab --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.3.1-position-prepare.svg @@ -0,0 +1,1092 @@ + + + + + + + + + + + 1.3.1. Prepare Position Handler Consume (single message, includes individual transfers from Bulk) + + + + Central Service + + + + + + + + + + + + + + Position Handler + + + + + Position Handler + + + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + Position + + + Management + + + Facade + + + + + Position + + + Management + + + Facade + + + + + Position DAO + + + + + Position DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Prepare Position Handler Consume + + + + + 1 + + + Request transfers to be processed + + + + + 2 + + + Check 1st transfer to select the Participant and Currency + + + + + DB TRANSACTION + + + + + 3 + + + Loop through batch and build list of transferIds and calculate sumTransfersInBatch, + + + checking all in Batch are for the correct Paricipant and Currency + + + Error code: + + + 2001, 3100 + + + + + 4 + + + Retrieve current state of all transfers in array from DB with select whereIn + + + (FYI: The two DB transaction model needs to add a mini-state step here (RECEIVED_PREPARE => RECEIVDED_PREPARE_PROCESSING) so that the transfers are left alone if processing has started) + + + + transferStateChange + + + transferParticipant + + + + + 5 + + + Return current state of all selected transfers from DB + + + + + 6 + + + Validate current state (transferStateChange.transferStateId == 'RECEIVED_PREPARE') + + + Error code: + + + 2001 + + + against failing transfers + + + Batch is not rejected as a whole. + + + + + List of transfers used during processing + + + reservedTransfers + + + is list of transfers to be processed in the batch + + + abortedTransfers + + + is the list of transfers in the incorrect state going into the process. Currently the transferStateChange is set to ABORTED - this should only be done if not already in a final state (idempotency) + + + processedTransfers + + + is the list of transfers that have gone through the position management algorithm. Both successful and failed trasnfers appear here as the order and "running position" against each is necessary for reconciliation + + + Scalar intermidate values used in the algorithm + + + transferAmount + + + = payload.amount.amount + + + sumTransfersInBatch + + + = SUM amount against each Transfer in batch + + + currentPosition + + + = participantPosition.value + + + reservedPosition + + + = participantPosition.{original}reservedValue + + + effectivePosition + + + = currentPosition + reservedPosition + + + heldPosition + + + = effectivePosition + sumTransfersInBatch + + + availablePosition + + + = participantLimit(NetDebitCap) - effectivePosition + + + sumReserved + + + = SUM of transfers that have met rule criteria and processed + + + + + Going to reserve the sum of the valid transfers in the batch against the Participants Positon in the Currency of this batch + + + and calculate the available position for the Participant to use + + + + + 7 + + + Select effectivePosition FOR UPDATE from DB for Payer + + + + participantPosition + + + + + 8 + + + Return effectivePosition (currentPosition and reservedPosition) from DB for Payer + + + + + 9 + + + Increment reservedValue to heldPosition + + + (reservedValue = reservedPosition + sumTransfersInBatch) + + + + + 10 + + + Persist reservedValue + + + + UPDATE + + + participantPosition + + + SET reservedValue += sumTransfersInBatch + + + + + 11 + + + Request position limits for Payer Participant + + + + FROM + + + participantLimit + + + WHERE participantLimit.limitTypeId = 'NET-DEBIT-CAP' + + + AND participantLimit.participantId = payload.payerFsp + + + AND participantLimit.currencyId = payload.amount.currency + + + + + 12 + + + Return position limits + + + + + 13 + + + availablePosition + + + = participantLimit(netDebitCap) - effectivePosition (same as = netDebitCap - currentPosition - reservedPosition) + + + + + For each transfer in the batch, validate the availablility of position to meet the transfer amount + + + this will be as per the position algorithm documented below + + + + + 14 + + + Validate availablePosition for each tranfser (see algorithm below) + + + Error code: + + + 4001 + + + + + 01: sumReserved = 0 // Record the sum of the transfers we allow to progress to RESERVED + + + 02: sumProcessed =0 // Record the sum of the transfers already processed in this batch + + + 03: processedTransfers = {} // The list of processed transfers - so that we can store the additional information around the decision. Most importantly the "running" position + + + 04: foreach transfer in reservedTransfers + + + 05: sumProcessed += transfer.amount // the total processed so far + + + (NEED TO UPDATE IN CODE) + + + 06: if availablePosition >= transfer.amount + + + 07: transfer.state = "RESERVED" + + + 08: availablePosition -= preparedTransfer.amount + + + 09: sumRESERVED += preparedTransfer.amount + + + 10: else + + + 11: preparedTransfer.state = "ABORTED" + + + 12: preparedTransfer.reason = "Net Debit Cap exceeded by this request at this time, please try again later" + + + 13: end if + + + 14: runningPosition = currentPosition + sumReserved // the initial value of the Participants position plus the total value that has been accepted in the batch so far + + + 15: runningReservedValue = sumTransfersInBatch - sumProcessed + reservedPosition + + + (NEED TO UPDATE IN CODE) + + + // the running down of the total reserved value at the begining of the batch. + + + 16: Add transfer to the processedTransfer list recording the transfer state and running position and reserved values { transferState, transfer, rawMessage, transferAmount, runningPosition, runningReservedValue } + + + 16: end foreach + + + + + Once the outcome for all transfers is known,update the Participant's position and remove the reserved amount associated with the batch + + + (If there are any alarm limits, process those returning limits in which the threshold has been breached) + + + Do a bulk insert of the trasnferStateChanges associated with processing, using the result to complete the participantPositionChange and bulk insert of these to persist the running position + + + + + 15 + + + Assess any limit thresholds on the final position + + + adding to alarm list if triggered + + + + + 16 + + + Persist latest position + + + value + + + and + + + reservedValue + + + to DB for Payer + + + + UPDATE + + + participantPosition + + + SET value += sumRESERVED, + + + reservedValue -= sumTransfersInBatch + + + + + 17 + + + Bulk persist transferStateChange for all processedTransfers + + + + batch INSERT + + + transferStateChange + + + select for update from transfer table where transferId in ([transferBatch.transferId,...]) + + + build list of transferStateChanges from transferBatch + + + + + 18 + + + Populate batchParticipantPositionChange from the resultant transferStateChange and the earlier processedTransfer list + + + + + Effectively: + + + SET transferStateChangeId = processedTransfer.transferStateChangeId, + + + participantPositionId = preparedTransfer.participantPositionId, + + + value = preparedTransfer.positionValue, + + + reservedValue = preparedTransfer.positionReservedValue + + + + + 19 + + + Bulk persist the participant position change for all processedTransfers + + + + batch INSERT + + + participantPositionChange + + + + + 20 + + + Return a map of transferIds and their transferStateChanges + + + + + alt + + + [Calculate & Validate Latest Position Prepare (success)] + + + + + 21 + + + Notifications for Position Validation Success + + + Reference: Position Validation Success case (Prepare) + + + + [Calculate & Validate Latest Position Prepare (failure)] + + + + + Validation failure! + + + + + Persist Transfer State (with transferState='ABORTED' on position check fail) + + + + + 22 + + + Request to persist transfer + + + Error code: + + + 2003 + + + + + transferStateChange.state = "ABORTED", + + + transferStateChange.reason = "Net Debit Cap exceeded by this request at this time, please try again later" + + + + + 23 + + + Persist transfer state + + + + transferStateChange + + + + + 24 + + + Return success + + + + + 25 + + + Notifications for failures + + + Reference: Failure in Position Validation (Prepare) + + + + + Reference: Failure in Position Validation (Prepare) + + + + + alt + + + [If action == 'bulk-prepare'] + + + + + Message: + + + { + + + id: "<messageId>" + + + from: <ledgerName>, + + + to: <transferMessage.payerFsp>, + + + type: "application/json" + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 4001, + + + "errorDescription": "Payer FSP insufficient liquidity", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "bulk-processing", + + + action: "bulk-prepare", + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 26 + + + Publish Position failure event (in Prepare) to Bulk Processing Topic (for Payer) + + + Error codes: + + + 2003 + + + + [If action == 'prepare'] + + + + + Message: + + + { + + + id: "<messageId>" + + + from: <ledgerName>, + + + to: <transferMessage.payerFsp>, + + + type: "application/json" + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 4001, + + + "errorDescription": "Payer FSP insufficient liquidity", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "notification", + + + action: "position", + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 27 + + + Publish Notification (failure) event for Payer + + + Error code: + + + 2003 + + + + + Reference: Position Validation Success case (Prepare) + + + + + alt + + + [If action == 'bulk-prepare'] + + + + + Message: + + + { + + + id: "<messageId>" + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: "application/json" + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "bulk-processing", + + + action: "bulk-prepare", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 28 + + + Publish Position Success event (in Prepare) to Bulk Processing Topic + + + Error codes: + + + 2003 + + + + [If action == 'prepare'] + + + + + Message: + + + { + + + id: "<messageId>" + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: "application/json" + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "notification", + + + action: "abort", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 29 + + + Publish Notification event + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.4.1-bulk-processing-handler.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.4.1-bulk-processing-handler.svg new file mode 100644 index 000000000..fa4186d7d --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-1.4.1-bulk-processing-handler.svg @@ -0,0 +1,860 @@ + + + + + + + + + + + 1.4.0. Bulk Processing Handler Consume + + + + Central Service + + + + + + + + + + + + + + + + + + + + + + + + + topic-bulk- + + + processing + + + + + topic-bulk- + + + processing + + + Bulk Processing + + + Handler + + + + + Bulk Processing + + + Handler + + + + + + + topic-event + + + + + topic-event + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + + + topic-notification + + + + + topic-notification + + + Bulk DAO + + + + + Bulk DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Bulk Processing Handler Consume + + + + + 1 + + + Consume message + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: + + + type == 'bulk-processing' && action IN + + + ['prepare-duplicate', 'bulk-prepare', + + + 'bulk-timeout-received', 'fulfil-duplicate', + + + 'bulk-commit', 'bulk-timeout-reserved'] + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Process Message + + + + + 4 + + + Retrieve current state of Bulk Transfer + + + + + 5 + + + Retrieve current state of Bulk Transfer + + + + bulkTransfer + + + bulkTransferStateChange + + + + + 6 + + + Return + + + bulkTransferInfo + + + + + 7 + + + Return + + + bulkTransferInfo + + + + + Validate Bulk Transfer State + + + + + Initialize variables + + + : + + + let criteriaState + + + let incompleteBulkState + + + let completedBulkState + + + let bulkTransferState + + + let processingState + + + let errorCode, errorMessage + + + let produceNotification = false + + + + + alt + + + [bulkTransferInfo.bulkTransferState IN ['RECEIVED', 'PENDING_PREPARE']] + + + + + criteriaState = 'RECEIVED' + + + incompleteBulkState = 'PENDING_PREPARE' + + + completedBulkState = 'ACCEPTED' + + + + + alt + + + [action == 'prepare-duplicate' AND state.status == 'error'] + + + + + processingState = 'RECEIVED_DUPLICATE' + + + errorCode = payload.errorInformation.errorCode + + + errorDescription = payload.errorInformation.errorDescription + + + + [action == 'bulk-prepare' AND state.status == 'error'] + + + + + processingState = 'RECEIVED_INVALID' + + + errorCode = payload.errorInformation.errorCode + + + errorDescription = payload.errorInformation.errorDescription + + + + [action == 'bulk-prepare' AND state.status == 'success'] + + + + + processingState = 'ACCEPTED' + + + + [action IN ['bulk-timeout-received', 'bulk-timeout-reserved']] + + + + + incompleteBulkState = 'EXPIRING' + + + completedBulkState = 'COMPLETED' + + + processingState = 'EXPIRED' + + + errorCode = payload.errorInformation.errorCode + + + errorDescription = payload.errorInformation.errorDescription + + + + [all other actions] + + + + + throw + + + ErrorHandler.Factory.createFSPIOPError(INTERNAL_SERVER_ERROR) + + + + [bulkTransferInfo.bulkTransferState IN ['ACCEPTED']] + + + + + alt + + + [action == 'bulk-timeout-reserved'] + + + + + criteriaState = 'ACCEPTED' + + + incompleteBulkState = 'EXPIRING' + + + completedBulkState = 'COMPLETED' + + + processingState = 'EXPIRED' + + + + [all other actions] + + + + + throw + + + ErrorHandler.Factory.createFSPIOPError(INTERNAL_SERVER_ERROR) + + + + [bulkTransferInfo.bulkTransferState IN ['PROCESSING', 'PENDING_FULFIL', 'EXPIRING']] + + + + + criteriaState = 'PROCESSING' + + + incompleteBulkState = 'PENDING_FULFIL' + + + completedBulkState = 'COMPLETED' + + + + + alt + + + [action == 'fulfil-duplicate'] + + + + + processingState = 'FULFIL_DUPLICATE' + + + + [action == 'bulk-commit' AND state.status == 'success'] + + + + + processingState = 'COMPLETED' + + + + [action == 'reject' AND state.status == 'success'] + + + + + processingState = 'REJECTED' + + + + [action IN ['commit', 'abort'] AND state.status == 'error'] + + + + + processingState = 'FULFIL_INVALID' + + + + [action == 'bulk-timeout-reserved'] + + + + + incompleteBulkState = 'EXPIRING' + + + completedBulkState = 'COMPLETED' + + + processingState = 'EXPIRED' + + + errorCode = payload.errorInformation.errorCode + + + errorDescription = payload.errorInformation.errorDescription + + + + [all other actions] + + + + + throw + + + ErrorHandler.Factory.createFSPIOPError(INTERNAL_SERVER_ERROR) + + + + [all other ['PENDING_INVALID', 'COMPLETED', 'REJECTED', 'INVALID']] + + + + + throw + + + ErrorHandler.Factory.createFSPIOPError(INTERNAL_SERVER_ERROR) + + + + + 8 + + + Persist individual transfer processing state + + + + + 9 + + + Persist individual transfer processing state + + + -- store errorCode/errorMessage when + + + state.status == 'error' + + + + bulkTransferAssociation + + + + + 10 + + + Return success + + + + + 11 + + + Check previously defined completion criteria + + + + + 12 + + + Select EXISTS (LIMIT 1) in criteriaState + + + + bulkTransferAssociation + + + + + 13 + + + Return + + + existingIndividualTransfer + + + + + 14 + + + Return + + + existingIndividualTransfer + + + + + alt + + + [individual transfer exists] + + + + + bulkTransferState = incompleteBulkState + + + + [no transfer in criteriaState exists] + + + + + bulkTransferState = completedBulkState + + + produceNotification = true + + + + + 15 + + + Persist bulkTransferState from previous step + + + + + 16 + + + Persist bulkTransferState + + + + bulkTransferStateChange + + + + + 17 + + + Return success + + + + + alt + + + [produceNotification == true] + + + + + 18 + + + Request to retrieve all bulk transfer and individual transfer results + + + + + 19 + + + Get bulkTransferResult + + + + bulkTransfer + + + bulkTransferStateChange + + + bulkTransferAssociation + + + + + 20 + + + Return + + + bulkTransferResult + + + + + 21 + + + Return + + + bulkTransferResult + + + + + Send Bulk Notification(s) + + + + + Depending on the action decide where to + + + send notification: payer, payee OR both + + + + + 22 + + + Generate & Persist bulk message to object store: + + + MLOS.bulkTransferResults + + + by destination + + + + + 23 + + + Return reference to the stored object(s) + + + MLOS.bulkTransferResults.messageId + + + + + Message: + + + { + + + id: <messageId> + + + from: <source>, + + + to: <destination>, + + + type: "application/json" + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + bulkTransferId: <uuid>, + + + bulkTransferState: <string> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "notification", + + + action: "bulk-[prepare | commit | abort | processing]", + + + createdAt: <timestamp>, + + + state: { + + + status: state.status, + + + code: state.code + + + } + + + } + + + } + + + } + + + + + 24 + + + Publish Notification event for Payer/Payee + + + Error codes: + + + 2003 + + + + [produceNotification == false] + + + + + Do nothing (awaitAllTransfers) + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.1.0-bulk-fulfil-overview.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.1.0-bulk-fulfil-overview.svg new file mode 100644 index 000000000..90d6889fc --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.1.0-bulk-fulfil-overview.svg @@ -0,0 +1,835 @@ + + + + + + + + + + + 2.1.0. DFSP2 sends a Bulk Fulfil Success Transfer request + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API + + + Notification Handler + + + + + ML API + + + Notification Handler + + + + + + + mongo- + + + object-store + + + + + mongo- + + + object-store + + + Central Service API + + + + + Central Service API + + + + + + + topic- + + + bulk-fulfil + + + + + topic- + + + bulk-fulfil + + + Bulk Fulfil + + + Handler + + + + + Bulk Fulfil + + + Handler + + + + + + + topic- + + + fulfil + + + + + topic- + + + fulfil + + + Fulfil + + + Handler + + + + + Fulfil + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + Position + + + Handler + + + + + Position + + + Handler + + + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + Bulk Processing + + + Handler + + + + + Bulk Processing + + + Handler + + + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + + DFSP2 sends a Bulk Fulfil Success Transfer request to DFSP1 + + + + + Headers - transferHeaders: { + + + Content-Length: <int>, + + + Content-Type: <string>, + + + Date: <date>, + + + FSPIOP-Source: <string>, + + + FSPIOP-Destination: <string>, + + + FSPIOP-Encryption: <string>, + + + FSPIOP-Signature: <string>, + + + FSPIOP-URI: <uri>, + + + FSPIOP-HTTP-Method: <string> + + + } + + + Payload - bulkTransferMessage: + + + { + + + bulkTransferState: <bulkTransferState>, + + + completedTimestamp: <completedTimeStamp>, + + + individualTransferResults: + + + [ + + + { + + + transferId: <uuid>, + + + fulfilment: <ilpCondition>, + + + extensionList: { extension: [ + + + { key: <string>, value: <string> } + + + ] } + + + } + + + ], + + + extensionList: { extension: [ + + + { key: <string>, value: <string> } + + + ] } + + + } + + + + 1 + + + PUT - /bulkTransfers/<ID> + + + + + 2 + + + Validate incoming message + + + Error codes: + + + 3000-3002, 3100-3107 + + + + + 3 + + + Persist incoming bulk message to + + + object store: + + + MLOS.individualTransferFulfils + + + + + 4 + + + Return messageId reference to the stored object(s) + + + + + Message: + + + { + + + id: <messageId>, + + + from: <payeeFspName>, + + + to: <payerFspName>, + + + type: "application/json", + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + bulkTransferId: <uuid>, + + + bulkTransferState: "COMPLETED", + + + completedTimestamp: <timestamp>, + + + extensionList: { extension: [ + + + { key: <string>, value: <string> } + + + ] }, + + + count: <int>, + + + hash: <string> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: "bulk-fulfil", + + + action: "bulk-commit", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 5 + + + Route & Publish Bulk Fulfil event for Payee + + + Error code: + + + 2003 + + + + + 6 + + + Ensure event is replicated + + + as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 7 + + + Respond replication acknowledgements + + + have been received + + + + + 8 + + + Respond HTTP - 200 (OK) + + + + + 9 + + + Consume message + + + + + 10 + + + Retrieve individual transfers by key: + + + MLOS.individualTransferFulfils.messageId + + + + + 11 + + + Stream bulk's individual transfers + + + + + ref + + + Bulk Prepare Handler Consume + + + + + alt + + + [Success] + + + + + 12 + + + Produce (stream) single transfer message + + + for each individual transfer [loop] + + + + [Failure] + + + + + 13 + + + Produce single message for the entire bulk + + + + + 14 + + + Consume message + + + + + ref + + + Fulfil Handler Consume (Success) + + + + + alt + + + [Success] + + + + + 15 + + + Produce message + + + + [Failure] + + + + + 16 + + + Produce message + + + + + 17 + + + Consume message + + + + + ref + + + Position Handler Consume (Success) + + + + + 18 + + + Produce message + + + + + 19 + + + Consume message + + + + + ref + + + Bulk Processing Handler Consume (Success) + + + + + 20 + + + Persist bulk message by destination to the + + + object store: + + + MLOS.bulkTransferResults + + + + + 21 + + + Return the reference to the stored + + + notification object(s): + + + messageId + + + + + 22 + + + Send Bulk Commit notification + + + + + 23 + + + Consume message + + + + + 24 + + + Retrieve bulk notification(s) by reference & destination: + + + MLOS.bulkTransferResults.messageId + destination + + + + + 25 + + + Return notification payload + + + + + opt + + + [action == 'bulk-commit'] + + + + + ref + + + Send notification to Participant (Payer) + + + + + 26 + + + Send callback notification + + + + + 27 + + + Consume message + + + + + 28 + + + Retrieve bulk notification(s) by reference & destination: + + + MLOS.bulkTransferResults.messageId + destination + + + + + 29 + + + Return notification payload + + + + + opt + + + [action == 'bulk-commit'] + + + + + ref + + + Send notification to Participant (Payee) + + + + + 30 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.1.1-bulk-fulfil-handler.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.1.1-bulk-fulfil-handler.svg new file mode 100644 index 000000000..bb328dce5 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.1.1-bulk-fulfil-handler.svg @@ -0,0 +1,954 @@ + + + + + + + + + + + 2.1.1. Bulk Fulfil Handler Consume + + + + Central Service + + + + + + + + + + + + + + + + + + + mongo- + + + object-store + + + + + mongo- + + + object-store + + + + + topic-bulk- + + + fulfil + + + + + topic-bulk- + + + fulfil + + + Bulk Fulfil + + + Handler + + + + + Bulk Fulfil + + + Handler + + + + + + + topic-transfer- + + + fulfil + + + + + topic-transfer- + + + fulfil + + + + + topic-bulk- + + + processing + + + + + topic-bulk- + + + processing + + + + + topic-event + + + + + topic-event + + + + + topic-notification + + + + + topic-notification + + + Bulk DAO + + + + + Bulk DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Bulk Fulfil Handler Consume + + + + + 1 + + + Consume message + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: + + + type == 'bulk-fulfil' && action == 'bulk-commit' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate FSPIOP-Signature + + + + + ref + + + Validate message.content.headers. + + + FSPIOP-Signature + + + Error codes: + + + 3105/3106 + + + + + Validate Bulk Fulfil Transfer + + + + + 4 + + + Schema validation of the incoming message + + + + + 5 + + + Verify the message's signature + + + (to be confirmed in future requirement) + + + + + The above validation steps are already handled by the + + + Bulk-API-Adapter for the open source implementation. + + + It may need to be added in future for custom adapters. + + + + + Validate Duplicate Check + + + + + 6 + + + Request Duplicate Check + + + + + ref + + + Request Duplicate Check + + + + + 7 + + + Return { hasDuplicateId: Boolean, hasDuplicateHash: Boolean } + + + + + alt + + + [hasDuplicateId == TRUE && hasDuplicateHash == TRUE] + + + + + break + + + + + 8 + + + Request to retrieve Bulk Transfer state & completedTimestamp + + + Error code: + + + 2003 + + + + + 9 + + + Query database + + + + bulkTransfer + + + bulkTransferFulfilment + + + bulkTransferStateChange + + + + + 10 + + + Return resultset + + + + + 11 + + + Return + + + bulkTransferStateId + + + & + + + completedTimestamp + + + (not null when completed) + + + + + Message: + + + { + + + id: <messageId> + + + from: <ledgerName>, + + + to: <payeeFspName>, + + + type: application/json + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + bulkTransferState: <string>, + + + completedTimestamp: <optional> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "notification", + + + action: "bulk-fulfil-duplicate", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 12 + + + Publish Notification event for Payee + + + + [hasDuplicateId == TRUE && hasDuplicateHash == FALSE] + + + + + { + + + id: <messageId>, + + + from: <ledgerName", + + + to: <payeeFspName>, + + + type: "application/json", + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + errorInformation: { + + + errorCode: "3106", + + + errorDescription: "Modified request", + + + extensionList: { + + + extension: [ + + + { + + + key: "_cause", + + + value: <FSPIOPError> + + + } + + + ] + + + } + + + }, + + + uriParams: { + + + id: <bulkTransferId> + + + } + + + } + + + }, + + + metadata: { + + + correlationId: <uuid>, + + + event: { + + + id: <uuid>, + + + type: "notification", + + + action: "bulk-commit", + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: "3106", + + + description: "Modified request" + + + }, + + + responseTo: <uuid> + + + } + + + } + + + } + + + + + 13 + + + Publish Notification (failure) event for Payer + + + Error codes: + + + 3106 + + + + [hasDuplicateId == FALSE] + + + + + alt + + + [Validate Bulk Transfer Fulfil (success)] + + + + + Persist Bulk Transfer State (with bulktransferState='PROCESSING') + + + + + 14 + + + Request to persist bulk transfer fulfil + + + Error codes: + + + 2003 + + + + + 15 + + + Persist bulkTransferFulfilment + + + + bulkTransferFulfilment + + + bulkTransferStateChange + + + bulkTransferExtension + + + + + 16 + + + Return success + + + + [Validate Bulk Transfer Fulfil (failure)] + + + + + Persist Bulk Transfer State (with bulkTransferState='INVALID/REJECTED') + + + + + 17 + + + Request to persist bulk + + + transfer fulfil failure + + + Error codes: + + + 2003 + + + + + 18 + + + Persist transfer + + + + bulkTransferFulfilment + + + bulkTransferStateChange + + + bulkTransferExtension + + + bulkTransferError + + + + + 19 + + + Return success + + + + + alt + + + [Validate Bulk Transfer Fulfil (success)] + + + + + loop + + + [for every individual transfer in the bulk fulfil list] + + + + + 20 + + + Retrieve individual transfers from the bulk using + + + reference: + + + MLOS.individualTransferFulfils.messageId + + + + + 21 + + + Stream bulk's individual transfer fulfils + + + + + Message: + + + { + + + id: <messageId> + + + from: <payeeFspName>, + + + to: <payerFspName>, + + + type: "application/json" + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "fulfil", + + + action: "bulk-commit", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 22 + + + Route & Publish Prepare event to the Payer for the Individual Transfer + + + Error codes: + + + 2003 + + + + [Validate Bulk Transfer Fulfil (failure)] + + + + + Message: + + + { + + + id: <messageId> + + + from: <ledgerName>, + + + to: <payerFspName>, + + + type: "application/json" + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": <possible codes: [2003, 3100, 3105, 3106, 3202, 3203, 3300, 3301]> + + + "errorDescription": "<refer to section 35.1.3 for description>", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "notification", + + + action: "bulk-abort", + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 23 + + + Publish Notification (failure) event for Payer + + + Error codes: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.2.1-fulfil-handler-commit.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.2.1-fulfil-handler-commit.svg new file mode 100644 index 000000000..b89824971 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.2.1-fulfil-handler-commit.svg @@ -0,0 +1,726 @@ + + + + + + + + + + + 2.2.1. Fulfil Handler Consume (Success) individual transfers from Bulk + + + + Central Service + + + + + + + + + + + + + + + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Fulfil Handler + + + + + Fulfil Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic- + + + event + + + + + topic- + + + event + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + + + topic- + + + notification + + + + + topic- + + + notification + + + Position DAO + + + + + Position DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Fulfil Handler Consume (Success) + + + + + 1 + + + Consume Fulfil event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'fulfil' && action == 'bulk-commit' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate FSPIOP-Signature + + + + + ref + + + Validate message.content.headers. + + + FSPIOP-Signature + + + Error codes: + + + 3105/3106 + + + + + Validate Duplicate Check + + + + + 4 + + + Request Duplicate Check + + + + + ref + + + Request Duplicate Check + + + + + 5 + + + Return { hasDuplicateId: Boolean, hasDuplicateHash: Boolean } + + + + + alt + + + [hasDuplicateId == TRUE && hasDuplicateHash == TRUE] + + + + + break + + + + + 6 + + + stateRecord = await getTransferState(transferId) + + + + + alt + + + [endStateList.includes(stateRecord.transferStateId)] + + + + + ref + + + getTransfer callback + + + + + 7 + + + Produce message + + + + + + Ignore - resend in progress + + + + [hasDuplicateId == TRUE && hasDuplicateHash == FALSE] + + + + + Validate Prepare Transfer (failure) - Modified Request + + + + [hasDuplicateId == FALSE] + + + + + Validate and persist Transfer Fulfilment + + + + + 8 + + + Request information for the validate checks + + + Error code: + + + 2003 + + + + + 9 + + + Fetch from database + + + + transfer + + + + + 10 + + + + + 11 + + + Return transfer + + + + + 12 + + + Validate that Transfer.ilpCondition = SHA-256 (content.payload.fulfilment) + + + Error code: + + + 2001 + + + + + 13 + + + Validate expirationDate + + + Error code: + + + 3303 + + + + + opt + + + [Transfer.ilpCondition validate successful] + + + + + Request current Settlement Window + + + + + 14 + + + Request to retrieve current/latest transfer settlement window + + + Error code: + + + 2003 + + + + + 15 + + + Fetch settlementWindowId + + + + settlementWindow + + + + + 16 + + + + + 17 + + + Return settlementWindowId to be appended during transferFulfilment insert + + + TODO + + + : During settlement design make sure transfers in 'RECEIVED-FULFIL' + + + state are updated to the next settlement window + + + + + Persist fulfilment + + + + + 18 + + + Persist fulfilment with the result of the above check (transferFulfilment.isValid) + + + Error code: + + + 2003 + + + + + 19 + + + Persist to database + + + + transferFulfilment + + + transferExtension + + + + + 20 + + + Return success + + + + + alt + + + [Transfer.ilpCondition validate successful] + + + + + Persist Transfer State (with transferState='RECEIVED-FULFIL') + + + + + 21 + + + Request to persist transfer state + + + Error code: + + + 2003 + + + + + 22 + + + Persist transfer state + + + + transferStateChange + + + + + 23 + + + Return success + + + + + Message: + + + { + + + id: <messageId>, + + + from: <payeeFspName>, + + + to: <payerFspName>, + + + type: "application/json", + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "position", + + + action: "bulk-commit", + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 24 + + + Route & Publish Position event for Payee + + + + [Validate Fulfil Transfer not successful] + + + + + break + + + + + 25 + + + Route & Publish Notification event for Payee + + + Reference: Failure in validation + + + + + Reference: Failure in validation + + + + + Message: + + + { + + + id: <messageId>, + + + from: <ledgerName>, + + + to: <payeeFspName>, + + + type: "application/json", + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: "bulk-processing", + + + action: "bulk-commit", + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 26 + + + Publish Notification event for Payee to Bulk Processing Topic + + + Error codes: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.2.2-fulfil-handler-abort.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.2.2-fulfil-handler-abort.svg new file mode 100644 index 000000000..1b64285dd --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.2.2-fulfil-handler-abort.svg @@ -0,0 +1,1975 @@ + + + + + + + + + + + 2.2.2. Fulfil Handler Consume (Reject/Abort) (single message, includes individual transfers from Bulk) + + + + Central Service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + topic- + + + fulfil + + + + + topic- + + + fulfil + + + Fulfil Handler + + + + + Fulfil Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic- + + + event + + + + + topic- + + + event + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + + + topic- + + + notification + + + + + topic- + + + notification + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + + Fulfil Handler Consume (Failure) + + + + + alt + + + [Consume Single Message] + + + + + 1 + + + Consume Fulfil event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type IN ['fulfil','bulk-fulfil'] && ( action IN ['reject','abort'] ) + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate FSPIOP-Signature + + + + + ref + + + Validate message.content.headers. + + + FSPIOP-Signature + + + Error codes: + + + 2001 + + + + + Validate Transfer Fulfil Duplicate Check + + + + + 4 + + + Generate transferFulfilmentId uuid + + + + + 5 + + + Request to retrieve transfer fulfilment hashes by transferId + + + Error code: + + + 2003 + + + + + 6 + + + Request Transfer fulfilment + + + duplicate message hashes + + + + SELET transferId, hash + + + FROM + + + transferFulfilmentDuplicateCheck + + + WHERE transferId = request.params.id + + + + + 7 + + + Return existing hashes + + + + + 8 + + + Return (list of) transfer fulfil messages hash(es) + + + + + 9 + + + Loop the list of returned hashes & compare + + + each entry with the calculated message hash + + + + + alt + + + [Hash matched] + + + + + 10 + + + Request to retrieve Transfer Fulfilment & Transfer state + + + Error code: + + + 2003 + + + + + 11 + + + Request to retrieve + + + transferFulfilment & transferState + + + + transferFulfilment + + + transferStateChange + + + + + 12 + + + Return transferFulfilment & + + + transferState + + + + + 13 + + + Return Transfer Fulfilment & Transfer state + + + + + alt + + + [transferFulfilment.isValid == 0] + + + + + break + + + + + alt + + + [If type == 'fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: fulfil-duplicate, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 14 + + + Publish Notification event for Payee - Modified Request + + + Error codes: + + + 3106 + + + + [If type == 'bulk-fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: fulfil-duplicate, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 15 + + + Publish Notification event for Payee - Modified Request + + + 3106 to Bulk Processing Topic + + + Error codes: + + + 3106 + + + + [transferState IN ['COMMITTED', 'ABORTED']] + + + + + break + + + + + alt + + + [If type == 'fulfil'] + + + + + ref + + + Send notification to Participant (Payee) + + + + [If type == 'bulk-fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: fulfil-duplicate, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 16 + + + Publish Notification event for Payee to Bulk Processing Topic + + + Error codes: + + + 2003 + + + + [transferState NOT 'RESERVED'] + + + + + break + + + + + 17 + + + Reference: Failure in validation + + + Error code: + + + 2001 + + + + + + break + + + + + alt + + + [If type == 'fulfil'] + + + + + 18 + + + Allow previous request to complete + + + + [If type == 'bulk-fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: fulfil-duplicate, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 19 + + + Publish Notification event for Payee to Bulk Processing Topic + + + Error codes: + + + 2003 + + + + [Hash not matched] + + + + + 20 + + + Request to persist transfer hash + + + Error codes: + + + 2003 + + + + + 21 + + + Persist hash + + + + transferFulfilmentDuplicateCheck + + + + + 22 + + + Return success + + + + + alt + + + [action=='reject' call made on PUT /transfers/{ID}] + + + + + 23 + + + Request information for the validate checks + + + Error code: + + + 2003 + + + + + 24 + + + Fetch from database + + + + transfer + + + + + 25 + + + + + 26 + + + Return transfer + + + + + alt + + + [Fulfilment present in the PUT /transfers/{ID} message] + + + + + 27 + + + Validate that Transfer.ilpCondition = SHA-256 (content.payload.fulfilment) + + + Error code: + + + 2001 + + + + + Persist fulfilment + + + + + 28 + + + Persist fulfilment with the result of the above check (transferFulfilment.isValid) + + + Error code: + + + 2003 + + + + + 29 + + + Persist to database + + + + transferFulfilment + + + transferExtension + + + + + 30 + + + Return success + + + + [Fulfilment NOT present in the PUT /transfers/{ID} message] + + + + + 31 + + + Validate that transfer fulfilment message to Abort is valid + + + Error code: + + + 2001 + + + + + Persist extensions + + + + + 32 + + + Persist extensionList elements + + + Error code: + + + 2003 + + + + + 33 + + + Persist to database + + + + transferExtension + + + + + 34 + + + Return success + + + + + alt + + + [Transfer.ilpCondition validate successful OR generic validation successful] + + + + + Persist Transfer State (with transferState='RECEIVED_REJECT') + + + + + 35 + + + Request to persist transfer state + + + Error code: + + + 2003 + + + + + 36 + + + Persist transfer state + + + + transferStateChange + + + + + 37 + + + Return success + + + + + 38 + + + Route & Publish Position event for Payer + + + Reference: Publish Position Reject event for Payer + + + + [Validate Fulfil Transfer not successful or Generic validation failed] + + + + + break + + + + + 39 + + + Publish event for Payee + + + Reference: Failure in validation + + + + [action=='abort' Error callback] + + + + + alt + + + [Validation successful] + + + + + Persist Transfer State (with transferState='RECEIVED_ERROR') + + + + + 40 + + + Request to persist transfer state & Error + + + Error code: + + + 2003 + + + + + 41 + + + Persist transfer state & Error + + + + transferStateChange + + + transferError + + + transferExtension + + + + + 42 + + + Return success + + + + + 43 + + + Error callback validated + + + Reference: Produce message for validated error callback + + + + [Validate Transfer Error Message not successful] + + + + + break + + + + + 44 + + + Notifications for failures + + + Reference: Validate Transfer Error Message not successful + + + + [Consume Batch Messages] + + + + + To be delivered by future story + + + + + Reference: Validate Transfer Error Message not successful + + + + + alt + + + [If type == 'bulk-fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 45 + + + Publish Processing event for Payee to Bulk Processing Topic + + + Error codes: + + + 2003 + + + + [If type == 'fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: fulfil, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 46 + + + Route & Publish Notification event for Payee + + + + + Reference: Produce message for validated error callback + + + + + alt + + + [If type == 'bulk-fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 47 + + + Route & Publish Position event for Payer + + + + [If type == 'fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 48 + + + Route & Publish Position event for Payer + + + + + Reference: Failure in validation + + + + + alt + + + [If type == 'bulk-fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 49 + + + Publish processing event to the Bulk Processing Topic + + + Error codes: + + + 2003 + + + + [If type == 'fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: fulfil, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 50 + + + Route & Publish Notification event for Payee + + + + + Reference: Publish Position Reject event for Payer + + + + + alt + + + [If type == 'bulk-fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-position, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 51 + + + Route & Publish Position event for Payer + + + + [If type == 'fulfil'] + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 52 + + + Route & Publish Position event for Payer + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.3.1-position-fulfil.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.3.1-position-fulfil.svg new file mode 100644 index 000000000..a50bd3d57 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.3.1-position-fulfil.svg @@ -0,0 +1,468 @@ + + + + + + + + + + + 2.3.1. Fulfil Position Handler Consume (single message, includes individual transfers from Bulk) + + + + Central Service + + + + + + + + + Position Handler + + + + + Position Handler + + + + + + + topic- + + + notifications + + + + + topic- + + + notifications + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + Position DAO + + + + + Position DAO + + + + + Position Facade + + + + + Position Facade + + + + + Central Store + + + + + Central Store + + + + + + + + Fulfil Position Handler Consume + + + + + 1 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 2 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + transferParticipant + + + + + 3 + + + Return current state of transfer from DB + + + + + 4 + + + Return current state of transfer from DB + + + + + 5 + + + Validate current state (transferState is 'RECEIVED-FULFIL') + + + Error code: + + + 2001 + + + + + Persist Position change and Transfer State (with transferState='COMMITTED' on position check pass) + + + + + 6 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + DB TRANSACTION + + + + + 7 + + + Select participantPosition.value FOR UPDATE from DB for Payee + + + + participantPosition + + + + + 8 + + + Return participantPosition.value from DB for Payee + + + + + 9 + + + latestPosition + + + = participantPosition.value - payload.amount.amount + + + + + 10 + + + Persist latestPosition to DB for Payee + + + + UPDATE + + + participantPosition + + + SET value = latestPosition + + + + + 11 + + + Persist transfer state and participant position change + + + + INSERT + + + transferStateChange + + + transferStateId = 'COMMITTED' + + + INSERT + + + participantPositionChange + + + SET participantPositionId = participantPosition.participantPositionId, + + + transferStateChangeId = transferStateChange.transferStateChangeId, + + + value = latestPosition, + + + reservedValue = participantPosition.reservedValue + + + createdDate = new Date() + + + + + 12 + + + Return success + + + + + alt + + + [If type == 'bulk-position'] + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: bulk-commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 13 + + + Publish Transfer event to Bulk Processing Topic + + + Error codes: + + + 2003 + + + + [If type == 'position'] + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 14 + + + Publish Transfer event + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.3.2-position-abort.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.3.2-position-abort.svg new file mode 100644 index 000000000..9ebfd3c26 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-2.3.2-position-abort.svg @@ -0,0 +1,1297 @@ + + + + + + + + + + + 2.3.2. Abort Position Handler Consume (single message, includes individual transfers from Bulk) + + + + Central Service + + + + + + + + + + + + + + + + + + + Position Handler + + + + + Position Handler + + + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + Position DAO + + + + + Position DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Abort Position Handler Consume + + + + + opt + + + [type IN ['position','bulk-position'] && action == 'timeout-reserved'] + + + + + 1 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 2 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + transferParticipant + + + + + 3 + + + Return current state of transfer from DB + + + + + 4 + + + Return current state of transfer from DB + + + + + 5 + + + Validate current state + + + (transferStateChange.transferStateId == 'RESERVED_TIMEOUT') + + + Error code: + + + 2001 + + + + + Persist Position change and Transfer state + + + + + 6 + + + transferStateId + + + = 'EXPIRED_RESERVED' + + + + + 7 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + DB TRANSACTION IMPLEMENTATION + + + + + 8 + + + Select participantPosition.value FOR UPDATE for payerCurrencyId + + + + participantPosition + + + + + 9 + + + Return participantPosition + + + + + 10 + + + latestPosition + + + = participantPosition - payload.amount.amount + + + + + 11 + + + Persist latestPosition to DB for Payer + + + + UPDATE + + + participantPosition + + + SET value = latestPosition + + + + + 12 + + + Persist participant position change and state change + + + + INSERT + + + transferStateChange + + + VALUES (transferStateId) + + + INSERT + + + participantPositionChange + + + SET participantPositionId = participantPosition.participantPositionId, + + + transferStateChangeId = transferStateChange.transferStateChangeId, + + + value = latestPosition, + + + reservedValue = participantPosition.reservedValue + + + createdDate = new Date() + + + + + 13 + + + Return success + + + + + alt + + + [If type == 'bulk-position'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3300, + + + "errorDescription": "Transfer expired", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 14 + + + Publish Transfer event to Bulk Processing Topic (for Payer) + + + Error codes: + + + 2003 + + + + [If type == 'position'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3300, + + + "errorDescription": "Transfer expired", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 15 + + + Publish Notification event + + + Error code: + + + 2003 + + + + + opt + + + [type IN ['position','bulk-position'] && (action IN ['reject', 'abort'])] + + + + + 16 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 17 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + + + 18 + + + Return current state of transfer from DB + + + + + 19 + + + Return current state of transfer from DB + + + + + 20 + + + Validate current state + + + (transferStateChange.transferStateId IN ['RECEIVED_REJECT', 'RECEIVED_ERROR']) + + + Error code: + + + 2001 + + + + + Persist Position change and Transfer state + + + + + 21 + + + transferStateId + + + = (action == 'reject' ? 'ABORTED_REJECTED' : 'ABORTED_ERROR' ) + + + + + 22 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + Refer to + + + DB TRANSACTION IMPLEMENTATION + + + above + + + + + 23 + + + Persist to database + + + + participantPosition + + + transferStateChange + + + participantPositionChange + + + + + 24 + + + Return success + + + + + alt + + + [If action == 'reject'] + + + + + alt + + + [If type == 'position'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0, + + + description: "action successful" + + + } + + + } + + + } + + + } + + + + + 25 + + + Publish Notification event + + + Error code: + + + 2003 + + + + [If type == 'bulk-position'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0, + + + description: "action successful" + + + } + + + } + + + } + + + } + + + + + 26 + + + Publish Notification event + + + Error code: + + + 2003 + + + + [action == 'abort'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <payload.errorInformation.errorCode || 5000> + + + description: <payload.errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 27 + + + Publish Notification event + + + Error code: + + + 2003 + + + + + opt + + + [type IN ['position','bulk-position'] && action == 'fail' (Unable to currently trigger this scenario)] + + + + + 28 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 29 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + + + 30 + + + Return current state of transfer from DB + + + + + 31 + + + Return current state of transfer from DB + + + + + 32 + + + Validate current state (transferStateChange.transferStateId == 'FAILED') + + + + + Persist Position change and Transfer state + + + + + 33 + + + transferStateId + + + = 'FAILED' + + + + + 34 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + Refer to + + + DB TRANSACTION IMPLEMENTATION + + + above + + + + + 35 + + + Persist to database + + + + participantPosition + + + transferStateChange + + + participantPositionChange + + + + + 36 + + + Return success + + + + + alt + + + [If type =='position'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3100, + + + "errorDescription": "Transfer failed", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 37 + + + Publish Notification event + + + Error code: + + + 2003 + + + + [If type =='bulk-position'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3100, + + + "errorDescription": "Transfer failed", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: bulk-processing, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 38 + + + Publish Notification event + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.svg new file mode 100644 index 000000000..20faf4b81 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.0-timeout-overview.svg @@ -0,0 +1,406 @@ + + + + + + + + + + + 3.1.0. Transfer Timeout (incl. Bulk Transfer) + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API + + + Adapter + + + + + ML API + + + Adapter + + + + + ML API Notification + + + Event Handler + + + + + ML API Notification + + + Event Handler + + + + + Transfer Timeout + + + Handler + + + + + Transfer Timeout + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic-event + + + + + topic-event + + + Position Event + + + Handler + + + + + Position Event + + + Handler + + + + + + + topic- + + + notification + + + + + topic- + + + notification + + + Bulk Processing + + + Handler + + + + + Bulk Processing + + + Handler + + + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + + + + Transfer Expiry + + + + + ref + + + Timeout Handler Consume + + + + + alt + + + [transferStateId == 'RECEIVED_PREPARE'] + + + + + alt + + + [Regular Transfer] + + + + + 1 + + + Produce message + + + + [Individual Transfer from a Bulk] + + + + + 2 + + + Produce message + + + + [transferStateId == 'RESERVED'] + + + + + 3 + + + Produce message + + + + + 4 + + + Consume message + + + + + ref + + + Position Hander Consume (Timeout) + + + + + alt + + + [Regular Transfer] + + + + + 5 + + + Produce message + + + + [Individual Transfer from a Bulk] + + + + + 6 + + + Produce message + + + + + opt + + + [action IN ['bulk-timeout-received', 'bulk-timeout-reserved']] + + + + + 7 + + + Consume message + + + + + ref + + + Bulk Processing Consume + + + + + 8 + + + Produce message + + + + + opt + + + [action IN ['timeout-received', 'timeout-reserved', 'bulk-timeout-received', 'bulk-timeout-reserved']] + + + + + 9 + + + Consume message + + + + + ref + + + Send notification to Participant (Payer) + + + + + 10 + + + Send callback notification + + + + + opt + + + [action IN ['timeout-reserved', 'bulk-timeout-reserved']] + + + + + 11 + + + Consume message + + + + + ref + + + Send notification to Participant (Payee) + + + + + 12 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.svg new file mode 100644 index 000000000..4f687da29 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-3.1.1-timeout-handler.svg @@ -0,0 +1,1340 @@ + + + + + + + + + + + 3.1.1. Timeout Handler Consume (incl. Bulk Transfer) + + + + Central Service + + + + + + + + + + + + + + Transfer Timeout + + + Handler + + + + + Transfer Timeout + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + topic-event + + + + + topic-event + + + + + topic- + + + bulk-processing + + + + + topic- + + + bulk-processing + + + Position DAO + + + + + Position DAO + + + + + Segment DAO + + + + + Segment DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Timeout Handler Consume + + + + + Persist Event Information + + + + + 1 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Get previous checkpoint of last record processed (Lower limit for inclusion) + + + + + 2 + + + Get last segment as @intervalMin + + + + + 3 + + + Get last segment as @intervalMin + + + + SELECT value INTO @intervalMin + + + FROM + + + segment + + + WHERE segmentType = 'timeout' + + + AND enumeration = 0 + + + AND tableName = 'transferStateChange' + + + + + 4 + + + Return @intervalMin + + + + + 5 + + + Return @intervalMin + + + + + opt + + + [@intervalMin IS NULL => segment record NOT FOUND] + + + + + 6 + + + Set @intervalMin = 0 + + + + + Do Cleanup + + + + + 7 + + + Clean up transferTimeout from finalised transfers + + + + + 8 + + + Clean up transferTimeout from finalised transfers + + + + DELETE tt + + + FROM + + + transferTimeout + + + AS tt + + + JOIN (SELECT tsc.transferId, MAX(tsc.transferStateChangeId) maxTransferStateChangeId + + + FROM + + + transferTimeout + + + tt1 + + + JOIN + + + transferStateChange + + + tsc + + + ON tsc.transferId = tt1.transferId + + + GROUP BY transferId) ts + + + ON ts.transferId = tt.transferId + + + JOIN + + + transferStateChange + + + tsc + + + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + + + WHERE tsc.transferStateId IN ('RECEIVED_FULFIL', 'COMMITTED', 'FAILED' + + + , 'EXPIRED', 'REJECTED', 'EXPIRED_PREPARED', 'EXPIRED_RESERVED', 'ABORTED') + + + + + 9 + + + Return success + + + + + Determine IntervalMax (Upper limit for inclusion) + + + + + 10 + + + Get last transferStateChangeId as @intervalMax + + + + + 11 + + + Get last transferStateChangeId as @intervalMax + + + + SELECT MAX(transferStateChangeId) INTO @intervalMax + + + FROM + + + transferStateChange + + + + + 12 + + + Return @intervalMax + + + + + 13 + + + Return @intervalMax + + + + + Prepare data and return the list for expiration + + + + + 14 + + + Prepare data and get transfers to be expired + + + + + DB TRANSACTION + + + + + 15 + + + transactionTimestamp + + + = now() + + + + + 16 + + + Insert all new transfers still in processing state + + + + INSERT INTO + + + transferTimeout + + + (transferId, expirationDate) + + + SELECT t.transferId, t.expirationDate + + + FROM + + + transfer + + + t + + + JOIN (SELECT transferId, MAX(transferStateChangeId) maxTransferStateChangeId + + + FROM + + + transferStateChange + + + WHERE transferStateChangeId > @intervalMin + + + AND transferStateChangeId <= @intervalMax + + + GROUP BY transferId) ts + + + ON ts.transferId = t.transferId + + + JOIN + + + transferStateChange + + + tsc + + + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + + + WHERE tsc.transferStateId IN ('RECEIVED_PREPARE', 'RESERVED') + + + + + 17 + + + Insert transfer state ABORTED for + + + expired RECEIVED_PREPARE transfers + + + + INSERT INTO + + + transferStateChange + + + SELECT tt.transferId, 'EXPIRED_PREPARED' AS transferStateId, 'Aborted by Timeout Handler' AS reason + + + FROM + + + transferTimeout + + + tt + + + JOIN ( + + + -- Following subquery is reused 3 times and may be optimized if needed + + + SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId + + + FROM + + + transferStateChange + + + tsc1 + + + JOIN + + + transferTimeout + + + tt1 + + + ON tt1.transferId = tsc1.transferId + + + GROUP BY tsc1.transferId) ts + + + ON ts.transferId = tt.transferId + + + JOIN + + + transferStateChange + + + tsc + + + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + + + WHERE tt.expirationDate < {transactionTimestamp} + + + AND tsc.transferStateId = 'RECEIVED_PREPARE' + + + + + 18 + + + Insert transfer state EXPIRED for + + + expired RESERVED transfers + + + + INSERT INTO + + + transferStateChange + + + SELECT tt.transferId, 'RESERVED_TIMEOUT' AS transferStateId, 'Expired by Timeout Handler' AS reason + + + FROM + + + transferTimeout + + + tt + + + JOIN (SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId + + + FROM + + + transferStateChange + + + tsc1 + + + JOIN + + + transferTimeout + + + tt1 + + + ON tt1.transferId = tsc1.transferId + + + GROUP BY tsc1.transferId) ts + + + ON ts.transferId = tt.transferId + + + JOIN + + + transferStateChange + + + tsc + + + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + + + WHERE tt.expirationDate < {transactionTimestamp} + + + AND tsc.transferStateId = 'RESERVED' + + + + + 19 + + + Update segment table to be used for the next run + + + + IF @intervalMin = 0 + + + INSERT + + + INTO + + + segment + + + (segmentType, enumeration, tableName, value) + + + VALUES ('timeout', 0, 'transferStateChange', @intervalMax) + + + ELSE + + + UPDATE + + + segment + + + SET value = @intervalMax + + + WHERE segmentType = 'timeout' + + + AND enumeration = 0 + + + AND tableName = 'transferStateChange' + + + + + 20 + + + Get list of transfers to be expired with current state + + + + SELECT tt.*, tsc.transferStateId, tp1.participantCurrencyId payerParticipantId, + + + tp2.participantCurrencyId payeeParticipantId, bta.bulkTransferId + + + FROM + + + transferTimeout + + + tt + + + JOIN (SELECT tsc1.transferId, MAX(tsc1.transferStateChangeId) maxTransferStateChangeId + + + FROM + + + transferStateChange + + + tsc1 + + + JOIN + + + transferTimeout + + + tt1 + + + ON tt1.transferId = tsc1.transferId + + + GROUP BY tsc1.transferId) ts + + + ON ts.transferId = tt.transferId + + + JOIN + + + transferStateChange + + + tsc + + + ON tsc.transferStateChangeId = ts.maxTransferStateChangeId + + + JOIN + + + transferParticipant + + + tp1 + + + ON tp1.transferId = tt.transferId + + + AND tp1.transferParticipantRoleTypeId = {PAYER_DFSP} + + + AND tp1.ledgerEntryTypeId = {PRINCIPLE_VALUE} + + + JOIN + + + transferParticipant + + + tp2 + + + ON tp2.transferId = tt.transferId + + + AND tp2.transferParticipantRoleTypeId = {PAYEE_DFSP} + + + AND tp2.ledgerEntryTypeId = {PRINCIPLE_VALUE} + + + LEFT JOIN + + + bulkTransferAssociation + + + bta + + + ON bta.transferId = tt.transferId + + + WHERE tt.expirationDate < {transactionTimestamp} + + + + + 21 + + + Return + + + transferTimeoutList + + + + + 22 + + + Return + + + transferTimeoutList + + + + + loop + + + [for each transfer in the list] + + + + + alt + + + [transferTimeoutList.bulkTransferId == NULL (Regular Transfer)] + + + + + alt + + + [transferStateId == 'RECEIVED_PREPARE'] + + + + + Message: + + + { + + + id: <transferId>, + + + from: <payerParticipantId>, + + + to: <payeeParticipantId>, + + + type: application/json, + + + content: { + + + headers: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + }, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3300, + + + "errorDescription": "Generic expired error", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: notification, + + + action: timeout-received, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 23 + + + Publish Notification event + + + + [transferStateId == 'RESERVED'] + + + + + Message: + + + { + + + id: <transferId>, + + + from: <payerParticipantId>, + + + to: <payeeParticipantId>, + + + type: application/json, + + + content: { + + + headers: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + }, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3300, + + + "errorDescription": "Generic expired error", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: position, + + + action: timeout-reserved, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 24 + + + Route & Publish Position event + + + + [Individual Transfer from a Bulk] + + + + + alt + + + [transferStateId == 'RECEIVED_PREPARE'] + + + + + Message: + + + { + + + id + + + : <transferTimeoutList.bulkTransferId>, + + + transferId + + + : <transferTimeoutList.transferId>, + + + from: <payerParticipantId>, + + + to: <payeeParticipantId>, + + + type: application/json, + + + content: { + + + headers: <bulkTransferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3300, + + + "errorDescription": "Generic expired error", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: bulk-processing, + + + action: bulk-timeout-received, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 25 + + + Publish to Bulk Processing topic + + + + [transferStateId == 'RESERVED'] + + + + + Message: + + + { + + + id + + + : <transferTimeoutList.bulkTransferId>, + + + transferId + + + : <transferTimeoutList.transferId>, + + + from: <payerParticipantId>, + + + to: <payeeParticipantId>, + + + type: application/json, + + + content: { + + + headers: <bulkTransferHeaders>,, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3300, + + + "errorDescription": "Generic expired error", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: position, + + + action: bulk-timeout-reserved, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 26 + + + Route & Publish Position event + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-4.1.0-abort-overview.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-4.1.0-abort-overview.svg new file mode 100644 index 000000000..65d6a65a7 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-4.1.0-abort-overview.svg @@ -0,0 +1,732 @@ + + + + + + + + + + + 4.1.0. Bulk Transfer Abort + + + + Financial Service Providers + + + + Bulk API Adapter Service + + + + Central Service + + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + Bulk API Adapter + + + + + Bulk API Adapter + + + + + Bulk API Notification Event Handler + + + + + Bulk API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + Bulk-Fulfil-Topic + + + + + Bulk-Fulfil-Topic + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Bulk Fulfil Event Handler + + + + + Bulk Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + + + Event-Topic + + + + + Event-Topic + + + Position Event Handler + + + + + Position Event Handler + + + + + + + topic-bulk-processing + + + + + topic-bulk-processing + + + Bulk Processing Event Handler + + + + + Bulk Processing Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + + + mojaloop- + + + object-store + + + ( + + + MLOS + + + ) + + + Central Services DB + + + + + Central Services DB + + + + + + + + + DFSP2 sends a Fulfil Abort Transfer request + + + + + Note + + + : In the payload for PUT /bulkTransfers/<ID>/error + + + only the + + + errorInformation + + + field is + + + required + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - errorMessage: + + + { + + + "errorInformation": { + + + "errorCode": <string>, + + + "errorDescription": <string>, + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + } + + + + 1 + + + PUT - /bulkTransfers/<ID>/error + + + + + 2 + + + Persist request payload with messageId in cache + + + + + Message: { + + + messageId: <string>, + + + bulkTransferId: <string>, + + + payload: <object> + + + } + + + + individualTransferFulfils + + + + + 3 + + + Response of save operation + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: fulfil, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 4 + + + Produce bulk-fulfil message + + + + + 5 + + + Respond HTTP - 200 (OK) + + + + + 6 + + + Consume bulk-fulfil message + + + + + 7 + + + Perform duplicate check + + + + + 8 + + + Validate request + + + + + loop + + + [n times, n = number of individual transfers] + + + + + Message: { + + + transferId: <string>, + + + bulkTransferId< <string>, + + + bulkTransferAssociationRecord: { + + + transferId: <string>, + + + bulkTransferId: <string>, + + + bulkProcessingStateId: <string>, + + + errorCode: <string>, + + + errorDescription: <string> + + + } + + + } + + + + + 9 + + + Update bulkTransferAssociation table + + + + bulkTransferAssociation + + + + + 10 + + + Produce fulfil message with action bulk-abort for each individual transfer + + + + + loop + + + [n times, n = number of individual transfers] + + + + + 11 + + + Consume message + + + + + ref + + + Fulfil Handler Consume (bulk-abort) + + + + + 12 + + + Produce message + + + + + loop + + + [n times, n = number of individual transfers] + + + + + 13 + + + Consume message + + + + + ref + + + Position Handler Consume (bulk-abort) + + + + + 14 + + + Produce message + + + + + loop + + + [n times, n = number of individual transfers] + + + + + 15 + + + Consume individual transfer message + + + + + ref + + + Bulk Processing Handler Consume (bulk-abort) + + + + + 16 + + + Produce message (Payer) + + + + + 17 + + + Produce message (Payee) + + + + + 18 + + + Consume message (Payer) + + + + + 19 + + + Consume message (Payee) + + + + + opt + + + [action == 'bulk-abort'] + + + + + ref + + + Notification Handler (Payer) + + + + + 20 + + + Send callback notification + + + + + opt + + + [action == 'bulk-abort'] + + + + + ref + + + Notification Handler (Payee) + + + + + 21 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-5.1.0-get-overview.svg b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-5.1.0-get-overview.svg new file mode 100644 index 000000000..0c0bb5959 --- /dev/null +++ b/mojaloop-technical-overview/central-bulk-transfers/assets/diagrams/sequence/seq-bulk-5.1.0-get-overview.svg @@ -0,0 +1,552 @@ + + + + + + + + + + + 5.1.0. Request Bulk Transfer Status + + + + Financial Service Provider + + + + Bulk API Adapter Service + + + + Central Ledger + + + + + + + + + DFSP(n) + + + Participant + + + + + DFSP(n) + + + Participant + + + + + Bulk API Adapter + + + + + Bulk API Adapter + + + + + Bulk API Notification Event Handler + + + + + Bulk API Notification Event Handler + + + + + + + Topic-Transfer-Get + + + + + Topic-Transfer-Get + + + GET Event Handler + + + + + GET Event Handler + + + + + Bulk Transfer DAO + + + + + Bulk Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Request Bulk transfer status + + + + + 1 + + + Request bulk transfer status - GET - /bulkTransfers/{ID} + + + + + 2 + + + Publish event information + + + + + 3 + + + Respond HTTP - 200 (OK) + + + + + 4 + + + Consume message + + + + + ref + + + GET Handler Consume + + + + + 5 + + + Request bulk transfer participants + + + + + 6 + + + Fetch bulk transfer participants + + + + bulkTransfer + + + participant + + + + + 7 + + + Return query result + + + + + 8 + + + Return bulk transfer participants + + + + + alt + + + [Is request not from bulk transfer Payer or Payee FSP?] + + + + + { + + + "errorInformation": { + + + "errorCode": 3210, + + + "errorDescription": "Bulk transfer ID not found" + + + } + + + } + + + + + 9 + + + Publish notification event (404) + + + + + 10 + + + callback PUT on /bulkTransfers/{ID}/error + + + + + 11 + + + Request bulk transfer status + + + + + 12 + + + Fetch bulk transfer status + + + + bulkTransferStateChange + + + bulkTransferState + + + bulkTransferError + + + bulkTransferExtension + + + transferStateChange + + + transferState + + + transferFulfilment + + + transferError + + + transferExtension + + + ilpPacket + + + + + 13 + + + Return query result + + + + + 14 + + + Return bulk transfer status + + + + + alt + + + [Is there a bulk transfer with the given ID recorded in the system?] + + + + + alt + + + [Bulk Transfer state is + + + "PROCESSING" + + + ] + + + + + { + + + "bulkTransferState": "PROCESSING" + + + } + + + + + 15 + + + Publish notification event + + + + + 16 + + + Send callback - PUT /bulkTransfers/{ID} + + + + + alt + + + [Request is from Payee FSP?] + + + + + 17 + + + Exclude transfers with + + + transferStateId + + + not in + + + [ + + + COMMITTED + + + , + + + ABORTED_REJECTED + + + , + + + EXPIRED_RESERVED + + + ] + + + + + { + + + "bulkTransferState": "<BulkTransferState>", + + + "individualTransferResults": [ + + + { + + + "transferId": "<TransferId>", + + + "fulfilment": "WLctttbu2HvTsa1XWvUoGRcQozHsqeu9Ahl2JW9Bsu8", + + + "errorInformation": <ErrorInformationObject>, + + + "extensionList": { + + + "extension": + + + [ + + + { + + + "key": "Description", + + + "value": "This is a more detailed description" + + + } + + + ] + + + } + + + } + + + ], + + + "completedTimestamp": "2018-09-24T08:38:08.699-04:00", + + + "extensionList": + + + { + + + "extension": + + + [ + + + { + + + "key": "Description", + + + "value": "This is a more detailed description" + + + } + + + ] + + + } + + + } + + + + + NOTE: If transfer is REJECTED, error information may be provided. + + + Either fulfilment or errorInformation should be set, not both. + + + + + 18 + + + Publish notification event + + + + + 19 + + + callback PUT on /bulkTransfers/{ID} + + + + + Log ERROR event + + + + [A bulk transfer with the given ID is not present in the System or this is an invalid request] + + + + + { + + + "errorInformation": { + + + "errorCode": 3210, + + + "errorDescription": "Bulk transfer ID not found" + + + } + + + } + + + + + 20 + + + Publish notification event (404) + + + + + 21 + + + callback PUT on /bulkTransfers/{ID}/error + + diff --git a/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-event-9.1.0.svg b/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-event-9.1.0.svg new file mode 100644 index 000000000..3f48ce80a --- /dev/null +++ b/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-event-9.1.0.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + 9.1.0. Event Handler Placeholder + + + + Event Handler Placeholder + + + + + + Event Handler Placeholder + + + + + Event Handler Placeholder + + + + + + + Event-Topic + + + + + Event-Topic + + + + + + Event Handler Placeholder + + + + + 1 + + + Consume Event message + + + Error code: + + + 2001 + + + + + Message: + + + { + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: INFO, + + + action: AUDIT, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + The type would be an ENUM with values: + + + [INFO, DEBUG, ERROR, WARN, FATAL, TRACE] + + + Possible values for "action" would be + + + [AUDIT, EXCEPTION] + + + The event messages can be handled based on the values of these two variables + + + (when the placeholder is extended). + + + + + 2 + + + Auto-commit + + + Error code: + + + 2001 + + + + + Currently events to only be published as part of the placeholder. + + + This can be evolved to add relevant functionality. + + diff --git a/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-notification-reject-5.1.1.svg b/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-notification-reject-5.1.1.svg new file mode 100644 index 000000000..6eb610b07 --- /dev/null +++ b/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-notification-reject-5.1.1.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + 5.1.1. Notification Handler for Rejections + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + DFSP Notified of Rejection + + + + + 1 + + + Consume Notification event message + + + Error code: + + + 2001 + + + + + Persist Event Information + + + + + 2 + + + Publish event information + + + Error code: + + + 3201 + + + + + ref + + + Event Handler + + + + + alt + + + [consume a single messages] + + + + + Validate Event + + + + + 3 + + + Validate event - Rule: type == 'notification' && [action IN ['reject', 'timeout-received', 'timeout-reserved']] + + + + + 4 + + + Request Participant Callback details + + + Error code: + + + 3201 + + + + + ref + + + Get Participant Callback Details + + + + + 5 + + + Return Participant Callback details + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + payload: <transferMessage> + + + }, + + + } + + + + + 6 + + + Send Callback Notification + + + Error code: + + + 1000, 1001, 3002 + + + + [Validate rule type != 'notification' / Error] + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <errorCode>, + + + "errorDescription": <ErrorMessage>, + + + } + + + } + + + + + 7 + + + Invalid messages retrieved from the Notification Topic + + + Error code: + + + 3201 + + + + + ref + + + Event Handler + + + + + Log ERROR Messages + + + Update Event log upon ERROR notification + + diff --git a/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-signature-validation.svg b/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-signature-validation.svg new file mode 100644 index 000000000..4e80c45ca --- /dev/null +++ b/mojaloop-technical-overview/central-event-processor/assets/diagrams/sequence/seq-signature-validation.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + Signature Validation + + + + + Alice + + + + Alice + + + + Bob + + + + Bob + + + + + Authentication Request + + + + + Authentication Response + + + + + Another authentication Request + + + + + another authentication Response + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-callback-3.1.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-callback-3.1.0.svg new file mode 100644 index 000000000..c7acd7bd0 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-callback-3.1.0.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + 3.1.0 Get Participant Callback Details + + + + ML API Adapter Service + + + + Central Services + + + + + + + + + ML-API-ADAPTER + + + + + ML-API-ADAPTER + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Get Callback Details + + + + + 1 + + + Request to get callback details - GET - /participants/{name}/endpoints?type={typeValue} + + + + + 2 + + + Fetch Callback details for Participant + + + + + 3 + + + Fetch Participant + + + Error code: + + + 3200 + + + + + 4 + + + Fetch Participant + + + + participant + + + + + 5 + + + Retrieved Participant + + + + + 6 + + + Return Participant + + + + + 7 + + + Validate DFSP + + + + + alt + + + [Validate participant (success)] + + + + + 8 + + + check if "type" parameter is sent + + + + + alt + + + [Check if "type" parameter is sent (Sent)] + + + + + 9 + + + Fetch Callback details for Participant and type + + + Error code: + + + 3000 + + + + + 10 + + + Fetch Callback details for Participant and type + + + + + Condition: + + + isActive = 1 + + + [endpointTypeId = <type>] + + + + participantEndpoint + + + + + 11 + + + Retrieved Callback details for Participant and type + + + + + 12 + + + Return Callback details for Participant and type + + + + + Message: + + + { + + + endpoints: {type: <type>, value: <value>} + + + } + + + + + 13 + + + Return Callback details for Participant + + + + + 14 + + + Return Callback details for Participant + + + + [Check if "type" parameter is sent (Not Sent)] + + + + + 15 + + + Fetch Callback details for Participant + + + Error code: + + + 3000 + + + + + 16 + + + Fetch Callback details for Participant + + + + + Condition: + + + isActive = 1 + + + + participantEndpoint + + + + + 17 + + + Retrieved Callback details for Participant + + + + + 18 + + + Return Callback details for Participant + + + + + Message: + + + { + + + endpoints: [ + + + {type: <type>, value: <value>}, + + + {type: <type>, value: <value>} + + + ] + + + } + + + + + 19 + + + Return Callback details for Participant + + + + + 20 + + + Return Callback details for Participant + + + + [Validate participant (failure)/ Error] + + + + + Validation failure/ Error! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <errorCode>, + + + "errorDescription": <ErrorMessage>, + + + } + + + } + + + + + 21 + + + Return + + + Error code: + + + 3000, 3200 + + + + + 22 + + + Return + + + Error code: + + + 3000, 3200 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-callback-add-3.1.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-callback-add-3.1.0.svg new file mode 100644 index 000000000..975978ddb --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-callback-add-3.1.0.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + 3.1.0 Add Participant Callback Details + + + + Central Services + + + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Add Callback Details + + + + + 1 + + + Request to add callback details - POST - /paticipants/{name}/endpoints + + + + + Message: + + + { + + + payload: { + + + endpoint: { + + + type: <typeValue>, + + + value: <endpointValue> + + + } + + + } + + + } + + + + + 2 + + + Add Callback details for Participant + + + + + 3 + + + Fetch Participant + + + Error code: + + + 3200 + + + + + 4 + + + Fetch Participant + + + + participant + + + + + 5 + + + Retrieved Participant + + + + + 6 + + + Return Participant + + + + + 7 + + + Validate DFSP + + + + + alt + + + [Validate participant (success)] + + + + + 8 + + + Add Callback details for Participant + + + Error code: + + + 2003/ + + + Msg: + + + Service unavailable + + + Error code: + + + 2001/ + + + Msg: + + + Internal Server Error + + + + + 9 + + + Persist Participant Endpoint + + + + participantEndpoint + + + + + If (endpoint exists && isActive = 1) + + + oldEndpoint.isActive = 0 + + + insert endpoint + + + Else + + + insert endpoint + + + End + + + + + 10 + + + Return status + + + + + 11 + + + Validate status + + + + + alt + + + [Validate status (success)] + + + + + 12 + + + Return Status Code 201 + + + + + 13 + + + Return Status Code 201 + + + + [Validate status (failure) / Error] + + + + + Error! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 14 + + + Return + + + Error code + + + + + 15 + + + Return + + + Error code + + + + [Validate participant (failure)] + + + + + Validation failure! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": 3200, + + + "errorDescription": "FSP id Not Found", + + + } + + + } + + + + + 16 + + + Return + + + Error code: + + + 3200 + + + + + 17 + + + Return + + + Error code: + + + 3200 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.0-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.0-v1.1.svg new file mode 100644 index 000000000..1a04bdb4a --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.0-v1.1.svg @@ -0,0 +1,665 @@ + + + + + + + + + + + 2.1.0. DFSP2 sends a Fulfil Success Transfer request v1.1 + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + topic-fulfil + + + + + topic-fulfil + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic- + + + settlement-model + + + + + topic- + + + settlement-model + + + Settlement Model + + + Handler + + + + + Settlement Model + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + Position Handler + + + + + Position Handler + + + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + + DFSP2 sends a request for notification after tranfer is being committed in the Switch + + + + + 1 + + + Retrieve fulfilment string generated during + + + the quoting process or regenerate it using + + + Local secret + + + and + + + ILP Packet + + + as inputs + + + + + alt + + + [Send back notification reserve request] + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - transferMessage: + + + { + + + "fulfilment": <IlpFulfilment>, + + + "transferState": "RESERVED" + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + + [Send back commit request] + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - transferMessage: + + + { + + + "fulfilment": <IlpFulfilment>, + + + "completedTimestamp": <DateTime>, + + + "transferState": "COMMITTED" + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + + 2 + + + PUT - /transfers/<ID> + + + + + 3 + + + Validate incoming token and originator matching Payee + + + Error codes: + + + 3000-3002, 3100-3107 + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: fulfil, + + + action: reserve || commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 4 + + + Route & Publish Fulfil event for Payee + + + Error code: + + + 2003 + + + + + 5 + + + Ensure event is replicated as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 6 + + + Respond replication acknowledgements have been received + + + + + 7 + + + Respond HTTP - 200 (OK) + + + + + 8 + + + Consume message + + + + + ref + + + Fulfil Handler Consume (Success) { + + + + 2.1.1-v1.1 + + + + } + + + + + 9 + + + Produce message + + + + + 10 + + + Produce message + + + + + 11 + + + Consume message + + + + + ref + + + Settlement Model Handler Consume (Success) + + + + + 12 + + + Consume message + + + + + ref + + + Position Handler Consume (Success) + + + + + 13 + + + Produce message + + + + + 14 + + + Consume message + + + + + opt + + + [action == 'commit'] + + + + + ref + + + Send notification to Participant (Payer) + + + + + 15 + + + Send callback notification + + + + + 16 + + + Consume message + + + + + opt + + + [action == 'reserve'] + + + + + ref + + + Send notification to Participant (Payee) + + + + + 17 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.0.svg new file mode 100644 index 000000000..052c40891 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.0.svg @@ -0,0 +1,574 @@ + + + + + + + + + + + 2.1.0. DFSP2 sends a Fulfil Success Transfer request + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + topic-fulfil + + + + + topic-fulfil + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic- + + + settlement-model + + + + + topic- + + + settlement-model + + + Settlement Model + + + Handler + + + + + Settlement Model + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + Position Handler + + + + + Position Handler + + + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + + DFSP2 sends a Fulfil Success Transfer request + + + + + 1 + + + Retrieve fulfilment string generated during + + + the quoting process or regenerate it using + + + Local secret + + + and + + + ILP Packet + + + as inputs + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - transferMessage: + + + { + + + "fulfilment": <IlpFulfilment>, + + + "completedTimestamp": <DateTime>, + + + "transferState": "COMMITTED", + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + + 2 + + + PUT - /transfers/<ID> + + + + + 3 + + + Validate incoming token and originator matching Payee + + + Error codes: + + + 3000-3002, 3100-3107 + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: fulfil, + + + action: commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 4 + + + Route & Publish Fulfil event for Payee + + + Error code: + + + 2003 + + + + + 5 + + + Ensure event is replicated as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 6 + + + Respond replication acknowledgements have been received + + + + + 7 + + + Respond HTTP - 200 (OK) + + + + + 8 + + + Consume message + + + + + ref + + + Fulfil Handler Consume (Success) { + + + + 2.1.1 + + + + } + + + + + 9 + + + Produce message + + + + + 10 + + + Produce message + + + + + 11 + + + Consume message + + + + + ref + + + Settlement Model Handler Consume (Success) + + + + + 12 + + + Consume message + + + + + ref + + + Position Handler Consume (Success) + + + + + 13 + + + Produce message + + + + + 14 + + + Consume message + + + + + opt + + + [action == 'commit'] + + + + + ref + + + Send notification to Participant (Payer) + + + + + 15 + + + Send callback notification + + + + + 16 + + + Consume message + + + + + opt + + + [action == 'commit'] + + + + + ref + + + Send notification to Participant (Payee) + + + + + 17 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.1-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.1-v1.1.svg new file mode 100644 index 000000000..9d931dc0c --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.1-v1.1.svg @@ -0,0 +1,821 @@ + + + + + + + + + + + 2.1.1. Fulfil Handler Consume (Success) v1.1 + + + + Central Service + + + + + + + + + + + + + + + + + + + + + + topic-fulfil + + + + + topic-fulfil + + + Fulfil Event + + + Handler + + + + + Fulfil Event + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic-event + + + + + topic-event + + + + + topic- + + + settlement-model + + + + + topic- + + + settlement-model + + + + + topic- + + + notification + + + + + topic- + + + notification + + + Position DAO + + + + + Position DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Fulfil Handler Consume (Success) + + + + + alt + + + [Consume Single Message] + + + + + 1 + + + Consume Fulfil event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'fulfil' && action IN ['commit', 'reserve'] + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate Duplicate Check + + + + + 4 + + + Request Duplicate Check + + + + + ref + + + Request Duplicate Check + + + + + 5 + + + Return { hasDuplicateId: Boolean, hasDuplicateHash: Boolean } + + + + + alt + + + [hasDuplicateId == TRUE && hasDuplicateHash == TRUE] + + + + + break + + + + + 6 + + + stateRecord = await getTransferState(transferId) + + + + + alt + + + [endStateList.includes(stateRecord.transferStateId)] + + + + + ref + + + getTransfer callback + + + + + 7 + + + Produce message + + + + + + Ignore - resend in progress + + + + [hasDuplicateId == TRUE && hasDuplicateHash == FALSE] + + + + + Validate Prepare Transfer (failure) - Modified Request + + + + [hasDuplicateId == FALSE] + + + + + Validate and persist Transfer Fulfilment + + + + + 8 + + + Request information for the validate checks + + + Error code: + + + 2003 + + + + + 9 + + + Fetch from database + + + + transfer + + + + + 10 + + + + + 11 + + + Return transfer + + + + + 12 + + + Validate that Transfer.ilpCondition = SHA-256 (content.payload.fulfilment) + + + Error code: + + + 2001 + + + + + 13 + + + Validate expirationDate + + + Error code: + + + 3303 + + + + + opt + + + [Transfer.ilpCondition validate successful] + + + + + Request current Settlement Window + + + + + 14 + + + Request to retrieve current/latest transfer settlement window + + + Error code: + + + 2003 + + + + + 15 + + + Fetch settlementWindowId + + + + settlementWindow + + + + + 16 + + + + + 17 + + + Return settlementWindowId to be appended during transferFulfilment insert + + + TODO + + + : During settlement design make sure transfers in 'RECEIVED-FULFIL' + + + state are updated to the next settlement window + + + + + Persist fulfilment + + + + + 18 + + + Persist fulfilment with the result of the above check (transferFulfilment.isValid) + + + Error code: + + + 2003 + + + + + 19 + + + Persist to database + + + + transferFulfilment + + + transferExtension + + + + + 20 + + + Return success + + + + + alt + + + [Transfer.ilpCondition validate successful] + + + + + Persist Transfer State (with transferState='RECEIVED-FULFIL') + + + + + 21 + + + Request to persist transfer state + + + Error code: + + + 2003 + + + + + 22 + + + Persist transfer state + + + + transferStateChange + + + + + 23 + + + Return success + + + + + Message: + + + { + + + id: <id>, + + + from: switch, + + + to: switch, + + + type: application/json + + + content: { + + + payload: { + + + transferId: {id} + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: setmodel, + + + action: commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 24 + + + Route & Publish settlement model event + + + + + Message: + + + { + + + id: <id>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: commit || reserve, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 25 + + + Route & Publish Position event for Payee + + + + [Validate Fulfil Transfer not successful] + + + + + Persist Transfer State (with transferState='ABORTED') + + + + + 26 + + + Request to persist transfer state + + + Error code: + + + 2003 + + + + + 27 + + + Persist transfer state + + + + transferStateChange + + + + + 28 + + + Return success + + + + + Message: + + + { + + + id: <id>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 29 + + + Route & Publish Position event for Payer + + + + [Consume Batch Messages] + + + + + To be delivered by future story + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.1.svg new file mode 100644 index 000000000..de1888f4f --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-fulfil-2.1.1.svg @@ -0,0 +1,821 @@ + + + + + + + + + + + 2.1.1. Fulfil Handler Consume (Success) + + + + Central Service + + + + + + + + + + + + + + + + + + + + + + topic-fulfil + + + + + topic-fulfil + + + Fulfil Event + + + Handler + + + + + Fulfil Event + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic-event + + + + + topic-event + + + + + topic- + + + settlement-model + + + + + topic- + + + settlement-model + + + + + topic- + + + notification + + + + + topic- + + + notification + + + Position DAO + + + + + Position DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Fulfil Handler Consume (Success) + + + + + alt + + + [Consume Single Message] + + + + + 1 + + + Consume Fulfil event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'fulfil' && action == 'commit' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate Duplicate Check + + + + + 4 + + + Request Duplicate Check + + + + + ref + + + Request Duplicate Check + + + + + 5 + + + Return { hasDuplicateId: Boolean, hasDuplicateHash: Boolean } + + + + + alt + + + [hasDuplicateId == TRUE && hasDuplicateHash == TRUE] + + + + + break + + + + + 6 + + + stateRecord = await getTransferState(transferId) + + + + + alt + + + [endStateList.includes(stateRecord.transferStateId)] + + + + + ref + + + getTransfer callback + + + + + 7 + + + Produce message + + + + + + Ignore - resend in progress + + + + [hasDuplicateId == TRUE && hasDuplicateHash == FALSE] + + + + + Validate Prepare Transfer (failure) - Modified Request + + + + [hasDuplicateId == FALSE] + + + + + Validate and persist Transfer Fulfilment + + + + + 8 + + + Request information for the validate checks + + + Error code: + + + 2003 + + + + + 9 + + + Fetch from database + + + + transfer + + + + + 10 + + + + + 11 + + + Return transfer + + + + + 12 + + + Validate that Transfer.ilpCondition = SHA-256 (content.payload.fulfilment) + + + Error code: + + + 2001 + + + + + 13 + + + Validate expirationDate + + + Error code: + + + 3303 + + + + + opt + + + [Transfer.ilpCondition validate successful] + + + + + Request current Settlement Window + + + + + 14 + + + Request to retrieve current/latest transfer settlement window + + + Error code: + + + 2003 + + + + + 15 + + + Fetch settlementWindowId + + + + settlementWindow + + + + + 16 + + + + + 17 + + + Return settlementWindowId to be appended during transferFulfilment insert + + + TODO + + + : During settlement design make sure transfers in 'RECEIVED-FULFIL' + + + state are updated to the next settlement window + + + + + Persist fulfilment + + + + + 18 + + + Persist fulfilment with the result of the above check (transferFulfilment.isValid) + + + Error code: + + + 2003 + + + + + 19 + + + Persist to database + + + + transferFulfilment + + + transferExtension + + + + + 20 + + + Return success + + + + + alt + + + [Transfer.ilpCondition validate successful] + + + + + Persist Transfer State (with transferState='RECEIVED-FULFIL') + + + + + 21 + + + Request to persist transfer state + + + Error code: + + + 2003 + + + + + 22 + + + Persist transfer state + + + + transferStateChange + + + + + 23 + + + Return success + + + + + Message: + + + { + + + id: <id>, + + + from: switch, + + + to: switch, + + + type: application/json + + + content: { + + + payload: { + + + transferId: {id} + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: setmodel, + + + action: commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 24 + + + Route & Publish settlement model event + + + + + Message: + + + { + + + id: <id>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 25 + + + Route & Publish Position event for Payee + + + + [Validate Fulfil Transfer not successful] + + + + + Persist Transfer State (with transferState='ABORTED') + + + + + 26 + + + Request to persist transfer state + + + Error code: + + + 2003 + + + + + 27 + + + Persist transfer state + + + + transferStateChange + + + + + 28 + + + Return success + + + + + Message: + + + { + + + id: <id>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 29 + + + Route & Publish Position event for Payer + + + + [Consume Batch Messages] + + + + + To be delivered by future story + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-all-participant-limit-1.0.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-all-participant-limit-1.0.0.svg new file mode 100644 index 000000000..3f24665cc --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-all-participant-limit-1.0.0.svg @@ -0,0 +1,241 @@ + + + + + + + + + + + 1.0.0 Get Participant Limit Details For All Participants + + + + Central Services + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant Facade + + + + + Participant Facade + + + + + Central Store + + + + + Central Store + + + + + + + + Get Limits for all Participants + + + + + 1 + + + Request to get Limits - GET - /participants/limits?type={typeValue}&currency={currencyType} + + + + + 2 + + + Fetch Limits for all Participants + + + + + 3 + + + Fetch Limits for all participants with currency and type + + + Error code: + + + 3000 + + + + + 4 + + + Fetch Limits for currencyId and type(if passed) + + + + + Condition: + + + participantCurrency.participantCurrencyId = participant.participantCurrencyId + + + participantLimit.isActive = 1 + + + participantLimit.participantCurrencyId = participantCurrency.participantCurrencyId + + + [ + + + participantLimit.participantLimitTypeId = participantLimitType.participantLimitTypeId + + + participantLimit.participantCurrencyId = <currencyId> + + + participantLimitType.name = <type> + + + ] + + + + participant + + + participantCurrency + + + participantLimit + + + participantLimitType + + + + + 5 + + + Retrieved Participant Limits for currencyId and type + + + + + 6 + + + Return Limits for all participants + + + + + Message: + + + [ + + + { + + + name: <fsp> + + + currency: <currencyId>, + + + limit: {type: <type>, value: <value>} + + + }, + + + { + + + name: <fsp> + + + currency: <currencyId>, + + + limit: {type: <type>, value: <value>} + + + } + + + ] + + + + + 7 + + + Return Limits for all participants + + + Error code: + + + 3000 + + + + + 8 + + + Return Limits for all participants + + + Error code: + + + 3000 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-health-1.0.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-health-1.0.0.svg new file mode 100644 index 000000000..aff440cd5 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-health-1.0.0.svg @@ -0,0 +1,324 @@ + + + + + + + + + + + 1.0.0 Get Health Check + + + + Central Services + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Central Service API + + + + + Central Service API + + + + + Metadata Handler + + + + + Metadata Handler + + + + + Central Store + + + + + Central Store + + + + + + + Kafka Store + + + + + Kafka Store + + + + + Logging Sidecar + + + + + Logging Sidecar + + + + + + Get Detailed Health Check + + + + + 1 + + + Request to getHealth - GET /health?detailed=true + + + + + 2 + + + Fetch health status for all sub services + + + + + 3 + + + Fetch Service Metadata + + + + + - versionNumber + + + - uptime + + + - time service started + + + + + 4 + + + Check connection status + + + + + 5 + + + Report connection status + + + + + 6 + + + Check connection status + + + + + 7 + + + Report connection status + + + + + 8 + + + Check connection status + + + + + 9 + + + Report connection status + + + + + alt + + + [Validate Status (success)] + + + + + 10 + + + Return status response + + + + + Example Message: + + + 200 Success + + + { + + + "status": "UP", + + + "uptime": 1234, + + + "started": "2019-05-31T05:09:25.409Z", + + + "versionNumber": "5.2.3", + + + "services": [ + + + { + + + "name": "kafka", + + + "status": "UP", + + + "latency": 10 + + + } + + + ] + + + } + + + + + 11 + + + Return + + + HTTP Status: + + + 200 + + + + + alt + + + [Validate Status (service failure)] + + + + + 12 + + + Return status response + + + + + Example Message: + + + 502 Bad Gateway + + + { + + + "status": "DOWN", + + + "uptime": 1234, + + + "started": "2019-05-31T05:09:25.409Z", + + + "versionNumber": "5.2.3", + + + "services": [ + + + { + + + "name": "kafka", + + + "status": "DOWN", + + + "latency": 1111111 + + + } + + + ] + + + } + + + + + 13 + + + Return + + + HTTP Status: + + + 502 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-participant-position-limit-1.1.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-participant-position-limit-1.1.0.svg new file mode 100644 index 000000000..e017a501e --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-participant-position-limit-1.1.0.svg @@ -0,0 +1,568 @@ + + + + + + + + + + + 1.1.0 Request Participant Position and Limit Details + + + + Central Services + + + + + + + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant Facade + + + + + Participant Facade + + + + + Central Store + + + + + Central Store + + + + + + + + + + Get Callback Details + + + + + 1 + + + Request to get Limits - GET - /participants/{name}/limits?type={typeValue}&currency={currencyValue} + + + + + 2 + + + Fetch Limits for Participant + + + + + 3 + + + check if "currency" parameter is sent + + + + + alt + + + [Check if "currency" parameter is sent (Sent)] + + + + + 4 + + + Fetch Participant/currency id + + + Error code: + + + 3200 + + + + + 5 + + + Fetch Participant/currency id + + + + participant + + + participantCurrency + + + + + 6 + + + Retrieved Participant + + + + + 7 + + + Return Participant/currency id + + + + + 8 + + + Validate DFSP + + + + + alt + + + [Validate participant (success)] + + + + + 9 + + + Fetch Participant Limits for currency and type + + + Error code: + + + 3000 + + + + + 10 + + + Fetch Participant Limit for currencyId and type(if passed) + + + + + Condition: + + + participantLimit.isActive = 1 + + + participantLimit.participantCurrencyId = <currencyId> + + + [ participantLimit.participantLimitTypeId = participantLimitType.participantLimitTypeId + + + participantLimitType.name = <type> + + + ] + + + + participantLimit + + + participantLimitType + + + + + 11 + + + Retrieved Participant Limits for currencyId and type + + + + + 12 + + + Return Participant Limits for currencyId and type + + + + + Message: + + + [ + + + { currency: <currencyId>, + + + limit: {type: <type>, value: <value>} + + + } + + + ] + + + + + 13 + + + Return Participant Limits + + + + + 14 + + + Return Participant Limits + + + + [Validate participant (failure)/ Error] + + + + + Validation failure/ Error! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <errorCode>, + + + "errorDescription": <ErrorMessage>, + + + } + + + } + + + + + 15 + + + Return + + + Error code: + + + 3000, 3200 + + + + + 16 + + + Return + + + Error code: + + + 3000, 3200 + + + + [Check if "currency" parameter is sent (Not Sent)] + + + + + 17 + + + Fetch Participant + + + Error code: + + + 3200 + + + + + 18 + + + Fetch Participant + + + + participant + + + + + 19 + + + Retrieved Participant + + + + + 20 + + + Return Participant + + + + + 21 + + + Validate DFSP + + + + + alt + + + [Validate participant (success)] + + + + + 22 + + + Fetch Participant Limits for all currencies and type + + + Error code: + + + 3000 + + + + + 23 + + + Fetch Participant Limit for all currencies and type(if passed) + + + + + Condition: + + + participantCurrency.participantId = <participantId> + + + participantLimit.participantCurrencyId = participantCurrency.participantCurrencyId + + + participantLimit.isActive = 1 + + + [ participantLimit.participantLimitTypeId = participantLimitType.participantLimitTypeId + + + participantLimitType.name = <type> + + + ] + + + + participantCurrency + + + participantLimit + + + participantLimitType + + + + + 24 + + + Retrieved Participant Limits for all currencies and type + + + + + 25 + + + Return Participant Limits for all currencies and type + + + + + Message: + + + [ + + + { currency: <currencyId>, + + + limit: {type: <type>, value: <value>} + + + } + + + ] + + + + + 26 + + + Return Participant Limits + + + + + 27 + + + Return Participant Limits + + + + [Validate participant (failure)/ Error] + + + + + Validation failure/ Error! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <errorCode>, + + + "errorDescription": <ErrorMessage>, + + + } + + + } + + + + + 28 + + + Return + + + Error code: + + + 3000, 3200 + + + + + 29 + + + Return + + + Error code: + + + 3000, 3200 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-transfer-1.1.5-phase2.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-transfer-1.1.5-phase2.svg new file mode 100644 index 000000000..8ad873bd3 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-get-transfer-1.1.5-phase2.svg @@ -0,0 +1,402 @@ + + + + + + + + + + + 1.1.5. Request transfer status (getTransferStatusById) - Phase2 version + + + + Financial Service Provider + + + + ML API Adapter Service + + + + Central Service + + + + + + + + + DFSP(n) + + + Participant + + + + + DFSP(n) + + + Participant + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + Event-Topic + + + + + Event-Topic + + + Transfer-DAO + + + + + Transfer-DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Request transfer status + + + + + 1 + + + Callback transfer status request URL - GET - /transfers/{ID} + + + + + Persist Event Information + + + + + 2 + + + Request transfer information - GET - /transfers/{ID} + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + 4 + + + Return success + + + + + 5 + + + Return success + + + + + 6 + + + Respond HTTP - 200 (OK) + + + + + 7 + + + Request details for Transfer - GET - /transfers/{ID} + + + Error code: + + + 2003 + + + + + 8 + + + Request transfer status + + + Error code: + + + 2003 + + + + + 9 + + + Fetch transfer status + + + + SELECT transferId, transferStateId + + + FROM + + + transferStateChange + + + WHERE transferId = {ID} + + + ORDER BY transferStateChangeId desc limit 1 + + + + + 10 + + + Return transfer status + + + + + 11 + + + Return transfer status + + + Error codes: + + + 3202, 3203 + + + + + alt + + + [Is there a transfer with the given ID recorded in the system?] + + + + + alt + + + [Yes AND transferState is COMMITTED + + + This implies that a succesful transfer with the given ID is recorded in the system] + + + + + { + + + "fulfilment": "WLctttbu2HvTsa1XWvUoGRcQozHsqeu9Ahl2JW9Bsu8", + + + "completedTimestamp": "2018-09-24T08:38:08.699-04:00", + + + "transferState": "COMMITTED", + + + extensionList: + + + { + + + extension: + + + [ + + + { + + + "key": "Description", + + + "value": "This is a more detailed description" + + + } + + + ] + + + } + + + } + + + + + 12 + + + callback PUT on /transfers/{ID} + + + + [transferState in [RECEIVED, RESERVED, ABORTED]] + + + + + { + + + "transferState": "RECEIVED", + + + extensionList: + + + { + + + extension: + + + [ + + + { + + + "key": "Description", + + + "value": "This is a more detailed description" + + + } + + + ] + + + } + + + } + + + + + 13 + + + callback PUT on /transfers/{ID} + + + + + Log ERROR event + + + + [A transfer with the given ID is not present in the System or this is an invalid request] + + + + + { + + + "errorInformation": { + + + "errorCode": <integer>, + + + "errorDescription": "Client error description" + + + } + + + } + + + + + 14 + + + callback PUT on /transfers/{ID}/error + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-manage-participant-limit-1.1.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-manage-participant-limit-1.1.0.svg new file mode 100644 index 000000000..a640cdb01 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-manage-participant-limit-1.1.0.svg @@ -0,0 +1,457 @@ + + + + + + + + + + + 1.1.0 Manage Participant Limits + + + + Central Services + + + + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Manage Net Debit Cap + + + + + 1 + + + Request to adjust Participant Limit for a certain Currency - POST - /participants/{name}/limits + + + + + Message: + + + { + + + payload: { + + + currency: <string>, + + + limit: { + + + type: <string>, + + + value: <Id> + + + } + + + } + + + } + + + + + 2 + + + Adjust Limit for Participant + + + + + 3 + + + Fetch Participant/currency + + + Error code: + + + 3200 + + + + + 4 + + + Fetch Participant/currency + + + + participant + + + participantCurrency + + + + + 5 + + + Retrieved Participant/currency + + + + + 6 + + + Return Participant/currency + + + + + 7 + + + Validate DFSP + + + + + alt + + + [Validate participant (success)] + + + + + 8 + + + (for ParticipantCurrency) Fetch ParticipantLimit + + + Error code: + + + 3200 + + + + + 9 + + + Fetch ParticipantLimit + + + + participantLimit + + + + + 10 + + + Retrieved ParticipantLimit + + + + + 11 + + + Return ParticipantLimit + + + + + 12 + + + Validate ParticipantLimit + + + + + alt + + + [Validate participantLimit (success)] + + + + + DB TRANSACTION IMPLEMENTATION - Lock on ParticipantLimit table with UPDATE + + + + + If (record exists && isActive = 1) + + + oldIsActive.isActive = 0 + + + insert Record + + + Else + + + insert Record + + + End + + + + + 13 + + + (for ParticipantLimit) Insert new ParticipantLimit + + + Error code: + + + 3200 + + + + + 14 + + + Insert ParticipantLimit + + + + participantLimit + + + + + 15 + + + Inserted ParticipantLimit + + + + + 16 + + + Return ParticipantLimit + + + + [Validate participantLimit (failure)] + + + + + Validation failure! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": 3200, + + + "errorDescription": "ParticipantLimit Not Found", + + + } + + + } + + + + + 17 + + + Return new Limit values and status 200 + + + + + Message: + + + { + + + "currency": "EUR", + + + "limit": { + + + "participantLimitId": <number>, + + + "participantLimitTypeId": <number>, + + + "type": <string>, + + + "value": <string>, + + + "isActive": 1 + + + } + + + } + + + + + 18 + + + Return new Limit values and status 200 + + + + [Validate participant (failure)] + + + + + Validation failure! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": 3200, + + + "errorDescription": "FSP id Not Found", + + + } + + + } + + + + + 19 + + + Return + + + Error code: + + + 3200 + + + + + 20 + + + Return + + + Error code: + + + 3200 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participant-position-limits-1.0.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participant-position-limits-1.0.0.svg new file mode 100644 index 000000000..fcfca97c7 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participant-position-limits-1.0.0.svg @@ -0,0 +1,527 @@ + + + + + + + + + + + 1.0.0 Create initial position and limits for Participant + + + + Central Services + + + + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant FACADE + + + + + Participant FACADE + + + + + Central Store + + + + + Central Store + + + + + + + + Create initial position and limits + + + + + 1 + + + Request to Create initial position and limits - POST - /paticipants/{name}/initialPositionAndLimits + + + + + Message: + + + { + + + currency: <currencyId>, + + + limit: { + + + type: <limitType>, + + + value: <limitValue> + + + }, + + + initialPosition: <positionValue> + + + } + + + + + 2 + + + Create initial position and limits for Participant + + + + + 3 + + + Fetch Participant/ Currency Id + + + Error code: + + + 3200 + + + + + 4 + + + Fetch Participant/Currency Id + + + + participant + + + participantCurrency + + + + + 5 + + + Retrieved Participant/Currency Id + + + + + 6 + + + Return Participant/Currency Id + + + + + 7 + + + Validate DFSP + + + + + alt + + + [Validate participant (success)] + + + + + 8 + + + Fetch limit for participantCurrencyId + + + + + 9 + + + Fetch limit for participantCurrencyId + + + + participantLimit + + + + + 10 + + + Retrieved participant limit + + + + + 11 + + + Return participant limit + + + + + 12 + + + Fetch position for participantCurrencyId + + + + + 13 + + + Fetch position for participantCurrencyId + + + + participantPosition + + + + + 14 + + + Retrieved participant position + + + + + 15 + + + Return participant position + + + + + 16 + + + Participant position or limit exists check + + + + + alt + + + [position or limit does not exist (success)] + + + + + 17 + + + create initial position and limits for Participantt + + + Error code: + + + 2003/ + + + Msg: + + + Service unavailable + + + Error code: + + + 2001/ + + + Msg: + + + Internal Server Error + + + + + 18 + + + Persist Participant limits/position + + + + participantPosition + + + participantLimit + + + + + 19 + + + Return status + + + + + alt + + + [Details persisted successfully] + + + + + 20 + + + Return Status Code 201 + + + + + 21 + + + Return Status Code 201 + + + + [Details not persisted/Error] + + + + + Error! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": <Error Code>, + + + "errorDescription": <Msg>, + + + } + + + } + + + + + 22 + + + Return + + + Error code + + + + + 23 + + + Return + + + Error code + + + + [position or limit exists (failure)] + + + + + Error! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": 3200, + + + "errorDescription": "Participant Limit or Initial Position already set", + + + } + + + } + + + + + 24 + + + Return + + + Error code: + + + 3200 + + + + + 25 + + + Return + + + Error code: + + + 3200 + + + + [Validate participant (failure)] + + + + + Validation failure! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": 3200, + + + "errorDescription": "FSP id Not Found", + + + } + + + } + + + + + 26 + + + Return + + + Error code: + + + 3200 + + + + + 27 + + + Return + + + Error code: + + + 3200 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participants-positions-query-4.1.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participants-positions-query-4.1.0.svg new file mode 100644 index 000000000..b623ef955 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participants-positions-query-4.1.0.svg @@ -0,0 +1,448 @@ + + + + + + + + + + + 4.1.0 Get Participant Position Details + + + + HUB Operator + + + + Central Service + + + + + + + + + HUB OPERATOR + + + + + HUB OPERATOR + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant DAO + + + + + Participant DAO + + + + + Position Facade + + + + + Position Facade + + + + + Central Store + + + + + Central Store + + + + + + + + Get Position Details + + + + + 1 + + + Request to get positions - GET - /participants/{name}/positions?currency={currencyId} + + + + + 2 + + + Fetch Positions for Participant + + + + + 3 + + + Fetch Participant + + + Error code: + + + 2003,3201 + + + + + 4 + + + Fetch Participant + + + + participant + + + + + 5 + + + Retrieved Participant + + + + + 6 + + + Return Participant + + + + + 7 + + + Validate DFSP + + + Error code: + + + 3201 + + + + + alt + + + [Validate participant (success)] + + + + + 8 + + + currency parameter passed ? + + + + + alt + + + [currency parameter passed] + + + + + 9 + + + Fetch Participant position for a currency id + + + Error code: + + + 2003 + + + + + 10 + + + Fetch Participant position for a currency id + + + + participantCurrency + + + participantPosition + + + + + 11 + + + Retrieved Participant position for a currency id + + + + + 12 + + + Return Positions for Participant + + + + + Message: + + + { + + + { + + + currency: <currencyId>, + + + value: <positionValue>, + + + updatedTime: <timeStamp1> + + + } + + + } + + + + + 13 + + + Return Participant position for a currency id + + + + + 14 + + + Return Participant position for a currency id + + + + [currency parameter not passed] + + + + + 15 + + + Fetch Participant Positions for all currencies + + + Error code: + + + 2003 + + + + + 16 + + + Fetch Participant Positions for all currencies + + + + participantCurrency + + + participantPosition + + + + + 17 + + + Retrieved Participant Positions for all currencies + + + + + 18 + + + Return Participant Positions for all currencies + + + + + Message: + + + { + + + [ + + + { + + + currency: <currencyId1>, + + + value: <positionValue1>, + + + updatedTime: <timeStamp1> + + + }, + + + { + + + currency: <currencyId2>, + + + value: <positionValue2>, + + + updatedTime: <timeStamp2> + + + } + + + ] + + + } + + + + + 19 + + + Return Participant Positions for all currencies + + + + + 20 + + + Return Participant Positions for all currencies + + + + [Validate participant (failure)] + + + + + Validation failure! + + + + + Message: + + + { + + + "errorInformation": { + + + "errorCode": 3201, + + + "errorDescription": "FSP id does not exist or not found", + + + } + + + } + + + + + 21 + + + Return + + + Error code: + + + 3201 + + + + + 22 + + + Return + + + Error code: + + + 3201 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participants-positions-query-all-4.2.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participants-positions-query-all-4.2.0.svg new file mode 100644 index 000000000..76b9e95a5 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-participants-positions-query-all-4.2.0.svg @@ -0,0 +1,321 @@ + + + + + + + + + + + 4.2.0 Get Positions of all Participants + + + + ML API Adapter Service + + + + Central Service + + + + + + ML-API-ADAPTER + + + + + ML-API-ADAPTER + + + + + Central Service API + + + + + Central Service API + + + + + Participant Handler + + + + + Participant Handler + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Get Position Details + + + + + 1 + + + Request to get positions - GET - /participants/positions + + + + + 2 + + + Fetch Positions for all Participants + + + + + 3 + + + Fetch Positions for all active Participants + + + Error code: + + + 2003,3200 + + + + + 4 + + + Fetch Positions for: + + + all active Participants + + + with all active Currencies for each Participant + + + + participant + + + participantPosition + + + participantCurrency + + + + + 5 + + + Retrieved Positions for Participants + + + + + 6 + + + Return Positions for Participants + + + + + Message: + + + { + + + snapshotAt: <timestamp0>, + + + positions: + + + [ + + + { + + + participantId: <dfsp1>, + + + participantPositions: + + + [ + + + { + + + currentPosition: { + + + currency: <currency1>, + + + value: <amount1>, + + + reservedValue: <amount2>, + + + lastUpdated: <timeStamp1> + + + } + + + }, + + + { + + + currentPosition: { + + + currency: <currency2>, + + + value: <amount3>, + + + reservedValue: <amount4>, + + + lastUpdated: <timeStamp2> + + + } + + + } + + + ] + + + }, + + + { + + + participantId: <dfsp2>, + + + participantPositions: + + + [ + + + { + + + currentPosition: { + + + currency: <currency1>, + + + value: <amount1>, + + + reservedValue: <amount2>, + + + lastUpdated: <timeStamp1> + + + } + + + }, + + + { + + + currentPosition: { + + + currency: <currency2>, + + + value: <amount3>, + + + reservedValue: <amount4>, + + + lastUpdated: <timeStamp2> + + + } + + + } + + + ] + + + } + + + ] + + + } + + + + + 7 + + + Return Positions for Participants + + + + + 8 + + + Return Positions for Participants + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.0-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.0-v1.1.svg new file mode 100644 index 000000000..6829d68ff --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.0-v1.1.svg @@ -0,0 +1,301 @@ + + + + + + + + + + + 1.3.0. Position Handler Consume (single message) v1.1 + + + + Central Service + + + + + + + + + + + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Handler + + + + + Position Handler + + + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + Position Handler Consume + + + + + alt + + + [Consume Prepare message for Payer] + + + + + 1 + + + Consume Position event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'position' && action == 'prepare' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Prepare Position Handler Consume + + + + + 4 + + + Produce message + + + + [Consume Fulfil message for Payee] + + + + + 5 + + + Consume Position event message for Payee + + + + + break + + + + + Validate Event + + + + + 6 + + + Validate event - Rule: type == 'position' && action IN ['commit', 'reserve'] + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 7 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Fulfil Position Handler Consume + + + + + 8 + + + Produce message + + + + [Consume Abort message] + + + + + 9 + + + Consume Position event message + + + + + break + + + + + Validate Event + + + + + 10 + + + Validate event - Rule: type == 'position' && + + + action IN ['timeout-reserved', 'reject', 'fail'] + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 11 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Abort Position Handler Consume + + + + + 12 + + + Produce message + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.0.svg new file mode 100644 index 000000000..f03e043a8 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.0.svg @@ -0,0 +1,301 @@ + + + + + + + + + + + 1.3.0. Position Handler Consume (single message) + + + + Central Service + + + + + + + + + + + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Handler + + + + + Position Handler + + + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + Position Handler Consume + + + + + alt + + + [Consume Prepare message for Payer] + + + + + 1 + + + Consume Position event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'position' && action == 'prepare' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Prepare Position Handler Consume + + + + + 4 + + + Produce message + + + + [Consume Fulfil message for Payee] + + + + + 5 + + + Consume Position event message for Payee + + + + + break + + + + + Validate Event + + + + + 6 + + + Validate event - Rule: type == 'position' && action == 'commit' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 7 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Fulfil Position Handler Consume + + + + + 8 + + + Produce message + + + + [Consume Abort message] + + + + + 9 + + + Consume Position event message + + + + + break + + + + + Validate Event + + + + + 10 + + + Validate event - Rule: type == 'position' && + + + action IN ['timeout-reserved', 'reject', 'fail'] + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 11 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + ref + + + Abort Position Handler Consume + + + + + 12 + + + Produce message + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.1-prepare.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.1-prepare.svg new file mode 100644 index 000000000..eb9405f37 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.1-prepare.svg @@ -0,0 +1,815 @@ + + + + + + + + + + + 1.3.1. Prepare Position Handler Consume + + + + Central Service + + + + + + + + + Position Handler + + + + + Position Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + Position + + + Management + + + Facade + + + + + Position + + + Management + + + Facade + + + + + Position DAO + + + + + Position DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Prepare Position Handler Consume + + + + + 1 + + + Request transfers to be processed + + + + + 2 + + + Check 1st transfer to select the Participant and Currency + + + + + DB TRANSACTION + + + + + 3 + + + Loop through batch and build list of transferIds and calculate sumTransfersInBatch, + + + checking all in Batch are for the correct Paricipant and Currency + + + Error code: + + + 2001, 3100 + + + + + 4 + + + Retrieve current state of all transfers in array from DB with select whereIn + + + (FYI: The two DB transaction model needs to add a mini-state step here (RECEIVED_PREPARE => RECEIVDED_PREPARE_PROCESSING) so that the transfers are left alone if processing has started) + + + + transferStateChange + + + transferParticipant + + + + + 5 + + + Return current state of all selected transfers from DB + + + + + 6 + + + Validate current state (transferStateChange.transferStateId == 'RECEIVED_PREPARE') + + + Error code: + + + 2001 + + + against failing transfers + + + Batch is not rejected as a whole. + + + + + List of transfers used during processing + + + reservedTransfers + + + is list of transfers to be processed in the batch + + + abortedTransfers + + + is the list of transfers in the incorrect state going into the process. Currently the transferStateChange is set to ABORTED - this should only be done if not already in a final state (idempotency) + + + processedTransfers + + + is the list of transfers that have gone through the position management algorithm. Both successful and failed trasnfers appear here as the order and "running position" against each is necessary for reconciliation + + + Scalar intermidate values used in the algorithm + + + transferAmount + + + = payload.amount.amount + + + sumTransfersInBatch + + + = SUM amount against each Transfer in batch + + + currentPosition + + + = participantPosition.value + + + reservedPosition + + + = participantPosition.{original}reservedValue + + + effectivePosition + + + = currentPosition + reservedPosition + + + heldPosition + + + = effectivePosition + sumTransfersInBatch + + + availablePosition + + + = participantLimit(NetDebitCap) - effectivePosition + + + sumReserved + + + = SUM of transfers that have met rule criteria and processed + + + + + Going to reserve the sum of the valid transfers in the batch against the Participants Positon in the Currency of this batch + + + and calculate the available position for the Participant to use + + + + + 7 + + + Select effectivePosition FOR UPDATE from DB for Payer + + + + participantPosition + + + + + 8 + + + Return effectivePosition (currentPosition and reservedPosition) from DB for Payer + + + + + 9 + + + Increment reservedValue to heldPosition + + + (reservedValue = reservedPosition + sumTransfersInBatch) + + + + + 10 + + + Persist reservedValue + + + + UPDATE + + + participantPosition + + + SET reservedValue += sumTransfersInBatch + + + + + 11 + + + Request position limits for Payer Participant + + + + FROM + + + participantLimit + + + WHERE participantLimit.limitTypeId = 'NET-DEBIT-CAP' + + + AND participantLimit.participantId = payload.payerFsp + + + AND participantLimit.currencyId = payload.amount.currency + + + + + 12 + + + Return position limits + + + + + 13 + + + availablePosition + + + = participantLimit(netDebitCap) - effectivePosition (same as = netDebitCap - currentPosition - reservedPosition) + + + + + For each transfer in the batch, validate the availablility of position to meet the transfer amount + + + this will be as per the position algorithm documented below + + + + + 14 + + + Validate availablePosition for each tranfser (see algorithm below) + + + Error code: + + + 4001 + + + + + 01: sumReserved = 0 // Record the sum of the transfers we allow to progress to RESERVED + + + 02: sumProcessed =0 // Record the sum of the transfers already processed in this batch + + + 03: processedTransfers = {} // The list of processed transfers - so that we can store the additional information around the decision. Most importantly the "running" position + + + 04: foreach transfer in reservedTransfers + + + 05: sumProcessed += transfer.amount // the total processed so far + + + (NEED TO UPDATE IN CODE) + + + 06: if availablePosition >= transfer.amount + + + 07: transfer.state = "RESERVED" + + + 08: availablePosition -= preparedTransfer.amount + + + 09: sumRESERVED += preparedTransfer.amount + + + 10: else + + + 11: preparedTransfer.state = "ABORTED" + + + 12: preparedTransfer.reason = "Net Debit Cap exceeded by this request at this time, please try again later" + + + 13: end if + + + 14: runningPosition = currentPosition + sumReserved // the initial value of the Participants position plus the total value that has been accepted in the batch so far + + + 15: runningReservedValue = sumTransfersInBatch - sumProcessed + reservedPosition + + + (NEED TO UPDATE IN CODE) + + + // the running down of the total reserved value at the begining of the batch. + + + 16: Add transfer to the processedTransfer list recording the transfer state and running position and reserved values { transferState, transfer, rawMessage, transferAmount, runningPosition, runningReservedValue } + + + 16: end foreach + + + + + Once the outcome for all transfers is known,update the Participant's position and remove the reserved amount associated with the batch + + + (If there are any alarm limits, process those returning limits in which the threshold has been breached) + + + Do a bulk insert of the trasnferStateChanges associated with processing, using the result to complete the participantPositionChange and bulk insert of these to persist the running position + + + + + 15 + + + Assess any limit thresholds on the final position + + + adding to alarm list if triggered + + + + + 16 + + + Persist latest position + + + value + + + and + + + reservedValue + + + to DB for Payer + + + + UPDATE + + + participantPosition + + + SET value += sumRESERVED, + + + reservedValue -= sumTransfersInBatch + + + + + 17 + + + Bulk persist transferStateChange for all processedTransfers + + + + batch INSERT + + + transferStateChange + + + select for update from transfer table where transferId in ([transferBatch.transferId,...]) + + + build list of transferStateChanges from transferBatch + + + + + 18 + + + Populate batchParticipantPositionChange from the resultant transferStateChange and the earlier processedTransfer list + + + + + Effectively: + + + SET transferStateChangeId = processedTransfer.transferStateChangeId, + + + participantPositionId = preparedTransfer.participantPositionId, + + + value = preparedTransfer.positionValue, + + + reservedValue = preparedTransfer.positionReservedValue + + + + + 19 + + + Bulk persist the participant position change for all processedTransfers + + + + batch INSERT + + + participantPositionChange + + + + + 20 + + + Return a map of transferIds and their transferStateChanges + + + + + alt + + + [Calculate & Validate Latest Position Prepare (success)] + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: transfer, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 21 + + + Publish Notification event + + + Error code: + + + 2003 + + + + [Calculate & Validate Latest Position Prepare (failure)] + + + + + Validation failure! + + + + + Persist Transfer State (with transferState='ABORTED' on position check fail) + + + + + 22 + + + Request to persist transfer + + + Error code: + + + 2003 + + + + + transferStateChange.state = "ABORTED", + + + transferStateChange.reason = "Net Debit Cap exceeded by this request at this time, please try again later" + + + + + 23 + + + Persist transfer state + + + + transferStateChange + + + + + 24 + + + Return success + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <ledgerName>, + + + to: <transferMessage.payerFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 4001, + + + "errorDescription": "Payer FSP insufficient liquidity", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 25 + + + Publish Notification (failure) event for Payer + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.2-fulfil-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.2-fulfil-v1.1.svg new file mode 100644 index 000000000..de29ad2c9 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.2-fulfil-v1.1.svg @@ -0,0 +1,345 @@ + + + + + + + + + + + 1.3.2. Fulfil Position Handler Consume v1.1 + + + + Central Service + + + + + + + + Position Handler + + + + + Position Handler + + + + + + + Notifications-Topic + + + + + Notifications-Topic + + + Position DAO + + + + + Position DAO + + + + + Position Facade + + + + + Position Facade + + + + + Central Store + + + + + Central Store + + + + + + + + Fulfil Position Handler Consume + + + + + 1 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 2 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + transferParticipant + + + + + 3 + + + Return current state of transfer from DB + + + + + 4 + + + Return current state of transfer from DB + + + + + 5 + + + Validate current state (transferState is 'RECEIVED-FULFIL') + + + Error code: + + + 2001 + + + + + Persist Position change and Transfer State (with transferState='COMMITTED' on position check pass) + + + + + 6 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + DB TRANSACTION + + + + + 7 + + + Select participantPosition.value FOR UPDATE from DB for Payee + + + + participantPosition + + + + + 8 + + + Return participantPosition.value from DB for Payee + + + + + 9 + + + latestPosition + + + = participantPosition.value - payload.amount.amount + + + + + 10 + + + Persist latestPosition to DB for Payee + + + + UPDATE + + + participantPosition + + + SET value = latestPosition + + + + + 11 + + + Persist transfer state and participant position change + + + + INSERT + + + transferStateChange + + + transferStateId = 'COMMITTED' + + + INSERT + + + participantPositionChange + + + SET participantPositionId = participantPosition.participantPositionId, + + + transferStateChangeId = transferStateChange.transferStateChangeId, + + + value = latestPosition, + + + reservedValue = participantPosition.reservedValue + + + createdDate = new Date() + + + + + 12 + + + Return success + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: transfer, + + + action: commit || reserve, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 13 + + + Publish Transfer event + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.2-fulfil.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.2-fulfil.svg new file mode 100644 index 000000000..89ddaffd3 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.2-fulfil.svg @@ -0,0 +1,345 @@ + + + + + + + + + + + 1.3.2. Fulfil Position Handler Consume + + + + Central Service + + + + + + + + Position Handler + + + + + Position Handler + + + + + + + Notifications-Topic + + + + + Notifications-Topic + + + Position DAO + + + + + Position DAO + + + + + Position Facade + + + + + Position Facade + + + + + Central Store + + + + + Central Store + + + + + + + + Fulfil Position Handler Consume + + + + + 1 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 2 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + transferParticipant + + + + + 3 + + + Return current state of transfer from DB + + + + + 4 + + + Return current state of transfer from DB + + + + + 5 + + + Validate current state (transferState is 'RECEIVED-FULFIL') + + + Error code: + + + 2001 + + + + + Persist Position change and Transfer State (with transferState='COMMITTED' on position check pass) + + + + + 6 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + DB TRANSACTION + + + + + 7 + + + Select participantPosition.value FOR UPDATE from DB for Payee + + + + participantPosition + + + + + 8 + + + Return participantPosition.value from DB for Payee + + + + + 9 + + + latestPosition + + + = participantPosition.value - payload.amount.amount + + + + + 10 + + + Persist latestPosition to DB for Payee + + + + UPDATE + + + participantPosition + + + SET value = latestPosition + + + + + 11 + + + Persist transfer state and participant position change + + + + INSERT + + + transferStateChange + + + transferStateId = 'COMMITTED' + + + INSERT + + + participantPositionChange + + + SET participantPositionId = participantPosition.participantPositionId, + + + transferStateChangeId = transferStateChange.transferStateChangeId, + + + value = latestPosition, + + + reservedValue = participantPosition.reservedValue + + + createdDate = new Date() + + + + + 12 + + + Return success + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: transfer, + + + action: commit, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 13 + + + Publish Transfer event + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.3-abort.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.3-abort.svg new file mode 100644 index 000000000..57c541a8c --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-position-1.3.3-abort.svg @@ -0,0 +1,915 @@ + + + + + + + + + + + 1.3.3. Abort Position Handler Consume + + + + Central Service + + + + + + + + + + + + + + + Position Handler + + + + + Position Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + Position DAO + + + + + Position DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Abort Position Handler Consume + + + + + opt + + + [type == 'position' && action == 'timeout-reserved'] + + + + + 1 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 2 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + transferParticipant + + + + + 3 + + + Return current state of transfer from DB + + + + + 4 + + + Return current state of transfer from DB + + + + + 5 + + + Validate current state (transferStateChange.transferStateId == 'RESERVED_TIMEOUT') + + + Error code: + + + 2001 + + + + + Persist Position change and Transfer state + + + + + 6 + + + transferStateId + + + = 'EXPIRED_RESERVED' + + + + + 7 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + DB TRANSACTION IMPLEMENTATION + + + + + 8 + + + Select participantPosition.value FOR UPDATE for payerCurrencyId + + + + participantPosition + + + + + 9 + + + Return participantPosition + + + + + 10 + + + latestPosition + + + = participantPosition - payload.amount.amount + + + + + 11 + + + Persist latestPosition to DB for Payer + + + + UPDATE + + + participantPosition + + + SET value = latestPosition + + + + + 12 + + + Persist participant position change and state change + + + + INSERT + + + transferStateChange + + + VALUES (transferStateId) + + + INSERT + + + participantPositionChange + + + SET participantPositionId = participantPosition.participantPositionId, + + + transferStateChangeId = transferStateChange.transferStateChangeId, + + + value = latestPosition, + + + reservedValue = participantPosition.reservedValue + + + createdDate = new Date() + + + + + 13 + + + Return success + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3300, + + + "errorDescription": "Transfer expired", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 14 + + + Publish Notification event + + + Error code: + + + 2003 + + + + + opt + + + [type == 'position' && (action IN ['reject', 'abort'])] + + + + + 15 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 16 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + + + 17 + + + Return current state of transfer from DB + + + + + 18 + + + Return current state of transfer from DB + + + + + 19 + + + Validate current state (transferStateChange.transferStateId IN ['RECEIVED_REJECT', 'RECEIVED_ERROR']) + + + Error code: + + + 2001 + + + + + Persist Position change and Transfer state + + + + + 20 + + + transferStateId + + + = (action == 'reject' ? 'ABORTED_REJECTED' : 'ABORTED_ERROR' ) + + + + + 21 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + Refer to + + + DB TRANSACTION IMPLEMENTATION + + + above + + + + + 22 + + + Persist to database + + + + participantPosition + + + transferStateChange + + + participantPositionChange + + + + + 23 + + + Return success + + + + + alt + + + [action == 'reject'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0, + + + description: "action successful" + + + } + + + } + + + } + + + } + + + + [action == 'abort'] + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <payload.errorInformation.errorCode || 5000> + + + description: <payload.errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 24 + + + Publish Notification event + + + Error code: + + + 2003 + + + + + opt + + + [type == 'position' && action == 'fail' (Unable to currently trigger this scenario)] + + + + + 25 + + + Request current state of transfer from DB + + + Error code: + + + 2003 + + + + + 26 + + + Retrieve current state of transfer from DB + + + + transferStateChange + + + + + 27 + + + Return current state of transfer from DB + + + + + 28 + + + Return current state of transfer from DB + + + + + 29 + + + Validate current state (transferStateChange.transferStateId == 'FAILED') + + + + + Persist Position change and Transfer state + + + + + 30 + + + transferStateId + + + = 'FAILED' + + + + + 31 + + + Request to persist latest position and state to DB + + + Error code: + + + 2003 + + + + + Refer to + + + DB TRANSACTION IMPLEMENTATION + + + above + + + + + 32 + + + Persist to database + + + + participantPosition + + + transferStateChange + + + participantPositionChange + + + + + 33 + + + Return success + + + + + Message: { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3100, + + + "errorDescription": "Transfer failed", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 34 + + + Publish Notification event + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.0.svg new file mode 100644 index 000000000..597c20f74 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.0.svg @@ -0,0 +1,455 @@ + + + + + + + + + + + 1.1.0. DFSP1 sends a Prepare Transfer request to DFSP2 + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + topic-transfer-prepare + + + + + topic-transfer-prepare + + + Prepare Event Handler + + + + + Prepare Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Event Handler + + + + + Position Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + DFSP1 sends a Prepare Transfer request to DFSP2 + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - transferMessage: + + + { + + + "transferId": <uuid>, + + + "payeeFsp": dfsp2, + + + "payerFsp": dfsp1, + + + "amount": { + + + "currency": "AED", + + + "amount": "string" + + + }, + + + "ilpPacket": "string", + + + "condition": "string", + + + "expiration": "string", + + + "extensionList": { + + + "extension": [ + + + { + + + "key": "string", + + + "value": "string" + + + } + + + ] + + + } + + + } + + + + 1 + + + POST - /transfers + + + + + 2 + + + Validate incoming token and originator matching Payer + + + Error codes: + + + 3000-3002, 3100-3107 + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: prepare, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 3 + + + Route & Publish Prepare event for Payer + + + Error code: + + + 2003 + + + + + 4 + + + Ensure event is replicated as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 5 + + + Respond replication acknowledgements have been received + + + + + 6 + + + Respond HTTP - 202 (Accepted) + + + + + 7 + + + Consume message + + + + + ref + + + Prepare Handler Consume + + + + + 8 + + + Produce message + + + + + 9 + + + Consume message + + + + + ref + + + Position Handler Consume + + + + + 10 + + + Produce message + + + + + 11 + + + Consume message + + + + + ref + + + Send notification to Participant (Payee) + + + + + 12 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.1.a.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.1.a.svg new file mode 100644 index 000000000..65895c97b --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.1.a.svg @@ -0,0 +1,738 @@ + + + + + + + + + + + 1.1.1.a. Prepare Handler Consume (single message) + + + + Central Service + + + + + + + + + + + + + + + + + + + + topic-transfer-prepare + + + + + topic-transfer-prepare + + + Prepare Event Handler + + + + + Prepare Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + Position DAO + + + + + Position DAO + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Prepare Handler Consume + + + + + 1 + + + Consume Prepare event message + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'prepare' && action == 'prepare' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate Prepare Transfer + + + + + 4 + + + Schema validation of the incoming message + + + + + 5 + + + Verify the message's signature (to be confirmed in future requirement) + + + + + The above validation steps are already handled by + + + the ML-Adapter for the open source implementation. + + + It may need to be added in future for custom adapters. + + + + + Validate Duplicate Check + + + + + 6 + + + Request Duplicate Check + + + + + ref + + + Request Duplicate Check + + + + + 7 + + + Return { hasDuplicateId: Boolean, hasDuplicateHash: Boolean } + + + + + alt + + + [hasDuplicateId == TRUE && hasDuplicateHash == TRUE] + + + + + break + + + + + 8 + + + stateRecord = await getTransferState(transferId) + + + + + alt + + + [endStateList.includes(stateRecord.transferStateId)] + + + + + ref + + + getTransfer callback + + + + + 9 + + + Produce message + + + + + + Ignore - resend in progress + + + + [hasDuplicateId == TRUE && hasDuplicateHash == FALSE] + + + + + Validate Prepare Transfer (failure) - Modified Request + + + + [hasDuplicateId == FALSE] + + + + + Validate Payer + + + + + 10 + + + Request to retrieve Payer Participant details (if it exists) + + + + + 11 + + + Request Participant details + + + + participant + + + participantCurrency + + + + + 12 + + + Return Participant details if it exists + + + + + 13 + + + Return Participant details if it exists + + + + + 14 + + + Validate Payer + + + Error codes: + + + 3202 + + + + + Validate Payee + + + + + 15 + + + Request to retrieve Payee Participant details (if it exists) + + + + + 16 + + + Request Participant details + + + + participant + + + participantCurrency + + + + + 17 + + + Return Participant details if it exists + + + + + 18 + + + Return Participant details if it exists + + + + + 19 + + + Validate Payee + + + Error codes: + + + 3203 + + + + + alt + + + [Validate Prepare Transfer (success)] + + + + + Persist Transfer State (with transferState='RECEIVED-PREPARE') + + + + + 20 + + + Request to persist transfer + + + Error codes: + + + 2003 + + + + + 21 + + + Persist transfer + + + + transfer + + + transferParticipant + + + transferStateChange + + + transferExtension + + + ilpPacket + + + + + 22 + + + Return success + + + + [Validate Prepare Transfer (failure)] + + + + + Persist Transfer State (with transferState='INVALID') (Introducing a new status INVALID to mark these entries) + + + + + 23 + + + Request to persist transfer + + + (when Payee/Payer/crypto-condition validation fails) + + + Error codes: + + + 2003 + + + + + 24 + + + Persist transfer + + + + transfer + + + transferParticipant + + + transferStateChange + + + transferExtension + + + transferError + + + ilpPacket + + + + + 25 + + + Return success + + + + + alt + + + [Validate Prepare Transfer (success)] + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 26 + + + Route & Publish Position event for Payer + + + Error codes: + + + 2003 + + + + [Validate Prepare Transfer (failure)] + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <ledgerName>, + + + to: <transferMessage.payerFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": <possible codes: [2003, 3100, 3105, 3106, 3202, 3203, 3300, 3301]> + + + "errorDescription": "<refer to section 35.1.3 for description>", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 27 + + + Publish Notification (failure) event for Payer + + + Error codes: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.1.b.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.1.b.svg new file mode 100644 index 000000000..d59177bec --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.1.b.svg @@ -0,0 +1,492 @@ + + + + + + + + + + + 1.1.1.b. Prepare Handler Consume (batch messages) + + + + Central Service + + + + + + + + + + + topic-transfer-prepare + + + + + topic-transfer-prepare + + + Prepare Event Handler + + + + + Prepare Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + Position DAO + + + + + Position DAO + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Prepare Handler Consume + + + + + 1 + + + Consume Prepare event batch of messages for Payer + + + + + Persist Event Information + + + + + 2 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Fetch batch Payer information + + + + + 3 + + + Request to retrieve batch of Payer Participant details (if it exists) + + + + + 4 + + + Request Participant details + + + + participant + + + + + 5 + + + Return Participant details if it exists + + + + + 6 + + + Return Participant details if it exists + + + + + 7 + + + Validate Payer + + + + + 8 + + + store result set in var: $LIST_PARTICIPANTS_DETAILS_PAYER + + + + + Fetch batch Payee information + + + + + 9 + + + Request to retrieve batch of Payee Participant details (if it exists) + + + + + 10 + + + Request Participant details + + + + participant + + + + + 11 + + + Return Participant details if it exists + + + + + 12 + + + Return Participant details if it exists + + + + + 13 + + + Validate Payee + + + + + 14 + + + store result set in var: $LIST_PARTICIPANTS_DETAILS_PAYEE + + + + + Fetch batch of transfers + + + + + 15 + + + Request to retrieve batch of Transfers (if it exists) + + + + + 16 + + + Request batch of Transfers + + + + transfer + + + + + 17 + + + Return batch of Transfers (if it exists) + + + + + 18 + + + Return batch of Transfer (if it exists) + + + + + 19 + + + store result set in var: $LIST_TRANSFERS + + + + + loop + + + [for each message in batch] + + + + + Validate Prepare Transfer + + + + + Validate Payer + + + + + 20 + + + Validate Payer against in-memory var $LIST_PARTICIPANTS_DETAILS_PAYER + + + + + Validate Payee + + + + + 21 + + + Validate Payee against in-memory var $LIST_PARTICIPANTS_DETAILS_PAYEE + + + + + Duplicate check + + + + + 22 + + + Validate duplicate Check against in-memory var $LIST_TRANSFERS + + + + + 23 + + + Validate amount + + + + + 24 + + + Validate crypto-condition + + + + + 25 + + + Validate message signature (to be confirmed in future requirement) + + + + + Persist Transfer State (with transferState='RECEIVED' on validation pass) + + + + + 26 + + + Request to persist transfer + + + + + 27 + + + Persist transfer + + + + transferStateChange + + + + + 28 + + + Return success + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 29 + + + Route & Publish Position event for Payer + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.2.a.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.2.a.svg new file mode 100644 index 000000000..2a0857acf --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.2.a.svg @@ -0,0 +1,633 @@ + + + + + + + + + + + 1.1.2.a. Position Handler Consume (single message) + + + + Central Service + + + + + + + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Event Handler + + + + + Position Event Handler + + + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + Position DAO + + + + + Position DAO + + + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Position Handler Consume + + + + + 1 + + + Consume Position event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'position' && action == 'prepare' + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + alt + + + [Calulate & Validate Latest Position (success)] + + + + + Calculate position and persist change + + + + + 4 + + + Request latest position from DB for Payer + + + + + 5 + + + Retrieve latest position from DB for Payer + + + + transferPosition + + + + + 6 + + + Retrieve latest position from DB for Payer + + + + + 7 + + + Return latest position + + + + + 8 + + + Request position limits for Payer Participant + + + + + 9 + + + Request position limits for Payer Participant + + + + participant + + + participantLimit + + + + + 10 + + + Return position limits + + + + + 11 + + + Return position limits + + + + + 12 + + + Calculate latest position (lpos) for prepare + + + + + 13 + + + Validate Calculated latest position against the net-debit cap (netcap) - Rule: lpos < netcap + + + + + 14 + + + Request to persist latest position for Payer + + + + + 15 + + + Persist latest position to DB for Payer + + + + transferPosition + + + + + 16 + + + Return success + + + + + Persist Transfer State (with transferState='RESERVED' on position check pass) + + + + + 17 + + + Request to persist transfer + + + + + 18 + + + Persist transfer state + + + + transferStateChange + + + + + 19 + + + Return success + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: transfer, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 20 + + + Publish Notification event to Payee + + + + [Calculate & Validate Latest Position (failure)] + + + + + Calculate position and persist change + + + + + 21 + + + Request latest position from DB for Payer + + + + + 22 + + + Retrieve latest position from DB for Payer + + + + transferPosition + + + + + 23 + + + Retrieve latest position from DB for Payer + + + + + 24 + + + Return latest position + + + + + 25 + + + Request position limits for Payer Participant + + + + + 26 + + + Request position limits for Payer Participant + + + + participant + + + participantLimit + + + + + 27 + + + Return position limits + + + + + 28 + + + Return position limits + + + + + 29 + + + Calculate latest position (lpos) for prepare + + + + + 30 + + + Validate Calculated latest position against the net-debit cap (netcap) - Rule: lpos < netcap + + + + + Validation failure! + + + + + Persist Transfer State (with transferState='ABORTED' on position check pass) + + + + + 31 + + + Request to persist transfer + + + + + 32 + + + Persist transfer state + + + + transferStateChange + + + + + 33 + + + Return success + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <ledgerName>, + + + to: <transferMessage.payerFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: { + + + "errorInformation": { + + + "errorCode": 4001, + + + "errorDescription": "Payer FSP insufficient liquidity", + + + "extensionList": <transferMessage.extensionList> + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: notification, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 34 + + + Publish Notification (failure) event for Payer + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.2.b.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.2.b.svg new file mode 100644 index 000000000..6bde7e864 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.2.b.svg @@ -0,0 +1,337 @@ + + + + + + + + + + + 1.1.2.b. Position Handler Consume (batch messages) + + + + Central Service + + + + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Event Handler + + + + + Position Event Handler + + + + + + + Transfer-Topic + + + + + Transfer-Topic + + + Event-Topic + + + + + Event-Topic + + + + + + + Notification-Topic + + + + + Notification-Topic + + + Position DAO + + + + + Position DAO + + + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Position Handler Consume + + + + + 1 + + + Consume Position event batch of messages for Payer + + + + + Persist Event Information + + + + + 2 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + loop + + + [for each message in batch] + + + + + Calculate position and persist change + + + + + 3 + + + Request latest position from DB for Payer + + + + + 4 + + + Retrieve latest position from DB for Payer + + + + transferPosition + + + + + 5 + + + Return latest position + + + + + 6 + + + Calculate latest position (lpos) by incrementing transfer for prepare + + + + + 7 + + + Validate Calculated latest position against the net-debit cap (netcap) - Rule: lpos < netcap + + + + + 8 + + + Request to persist latest position for Payer + + + + + 9 + + + Persist latest position to DB for Payer + + + + transferPosition + + + + + 10 + + + Return success + + + + + Persist Transfer State (with transferState='RESERVED' on position check pass) + + + + + 11 + + + Request to persist batch transfer + + + + + 12 + + + Persist batch transfer + + + + transferStateChange + + + + + 13 + + + Return success + + + + + Message: + + + { + + + id: <transferMessage.transferId> + + + from: <transferMessage.payerFsp>, + + + to: <transferMessage.payeeFsp>, + + + type: application/json + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: transfer, + + + action: prepare, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 14 + + + Publish Transfer event + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.a-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.a-v1.1.svg new file mode 100644 index 000000000..7461e0ab9 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.a-v1.1.svg @@ -0,0 +1,326 @@ + + + + + + + + + + + 1.1.4.a. Send notification to Participant (Payer/Payee) (single message) v1.1 + + + + Financial Service Provider (Payer) + + + + ML API Adapter Service + + + + Central Service + + + + Financial Service Provider (Payee) + + + + + + + + Payer DFSP + + + Participant + + + + + Payer DFSP + + + Participant + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + Central Service API + + + + + Central Service API + + + + + + + Event-Topic + + + + + Event-Topic + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + Payee DFSP + + + Participant + + + + + Payee DFSP + + + Participant + + + + + + + + Send notification to Participants + + + + + 1 + + + Consume Notification event + + + + + Persist Event Information + + + + + 2 + + + Request to persist event information - POST - /events + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + 4 + + + Return success + + + + + 5 + + + Return success + + + + + The endpoint details are cached, when the cache + + + expires, the details are fetched again + + + + + 6 + + + Request Endpoint details for Participant - GET - /participants/{{fsp}}/endpoints + + + Error code: + + + 2003 + + + + + 7 + + + Fetch Endpoint details for Participant + + + Error code: + + + 2003 + + + + + 8 + + + Fetch Endpoint details for Participant + + + + participantEndpoint + + + + + 9 + + + Retrieved Endpoint details for Participant + + + + + 10 + + + Return Endpoint details for Participant + + + + + 11 + + + Return Endpoint details for Participant + + + Error codes: + + + 3202, 3203 + + + + + 12 + + + Notification with Prepare/fulfil result/error to + + + Payer DFSP to specified Endpoint - PUT + + + Error code: + + + 1001 + + + + + 13 + + + HTTP 200 OK + + + + + alt + + + [event.action === 'reserve'] + + + + + alt + + + [event.status === 'success'] + + + + + 14 + + + Notification to with succesful fulfil result (committed) to Payee DFSP to specified Endpoint - PATCH + + + Error code: + + + 1001 + + + + + 15 + + + HTTP 200 OK + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.a.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.a.svg new file mode 100644 index 000000000..de654e47e --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.a.svg @@ -0,0 +1,317 @@ + + + + + + + + + + + 1.1.4.a. Send notification to Participant (Payer/Payee) (single message) + + + + Financial Service Provider (Payer) + + + + ML API Adapter Service + + + + Central Service + + + + Financial Service Provider (Payee) + + + + + + + Payer DFSP + + + Participant + + + + + Payer DFSP + + + Participant + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + Central Service API + + + + + Central Service API + + + + + + + Event-Topic + + + + + Event-Topic + + + Participant DAO + + + + + Participant DAO + + + + + Central Store + + + + + Central Store + + + + + Payee DFSP + + + Participant + + + + + Payee DFSP + + + Participant + + + + + + + + Send notification to Participants + + + + + 1 + + + Consume Notification event + + + + + Persist Event Information + + + + + 2 + + + Request to persist event information - POST - /events + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + 4 + + + Return success + + + + + 5 + + + Return success + + + + + The endpoint details are cached, when the cache + + + expires, the details are fetched again + + + + + 6 + + + Request Endpoint details for Participant - GET - /participants/{{fsp}}/endpoints + + + Error code: + + + 2003 + + + + + 7 + + + Fetch Endpoint details for Participant + + + Error code: + + + 2003 + + + + + 8 + + + Fetch Endpoint details for Participant + + + + participantEndpoint + + + + + 9 + + + Retrieved Endpoint details for Participant + + + + + 10 + + + Return Endpoint details for Participant + + + + + 11 + + + Return Endpoint details for Participant + + + Error codes: + + + 3202, 3203 + + + + + 12 + + + Notification with Prepare/fulfil result/error to + + + Payer DFSP to specified Endpoint - PUT + + + Error code: + + + 1001 + + + + + 13 + + + HTTP 200 OK + + + + + alt + + + [Config.SEND_TRANSFER_CONFIRMATION_TO_PAYEE === true] + + + + + 14 + + + Notification to with fulfil result (committed/aborted/rejected) to Payee DFSP to specified Endpoint - PUT + + + Error code: + + + 1001 + + + + + 15 + + + HTTP 200 OK + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.b.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.b.svg new file mode 100644 index 000000000..19bd4690a --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-prepare-1.1.4.b.svg @@ -0,0 +1,241 @@ + + + + + + + + + + + 1.1.4.b. Send notification to Participant (Payer/Payee) (batch messages) + + + + Financial Service Provider + + + + ML API Adapter Service + + + + Central Service + + + + + + + + DFSP(n) + + + Participant + + + + + DFSP(n) + + + Participant + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + Central Service API + + + + + Central Service API + + + + + + + Event-Topic + + + + + Event-Topic + + + + EVENT_DAO + + + + EVENT_DAO + + + Notification DAO + + + + + Notification DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Send notification to Participant + + + + + 1 + + + Consume Notifications event batch of messages for Participant + + + + + loop + + + [for each message in batch] + + + + + Persist Event Information + + + + + 2 + + + Request to persist event information - POST - /events + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + 4 + + + Return success + + + + + 5 + + + Return success + + + + + 6 + + + Request Notifications details for Participant - GET - /notifications/DFPS(n) + + + + + 7 + + + Fetch Notifications details for Participant + + + + + 8 + + + Fetch Notifications details for Participant + + + + transferPosition + + + + + 9 + + + Retrieved Notification details for Participant + + + + + 10 + + + Return Notifications details for Participant + + + + + 11 + + + Return Notifications details for Participant + + + + + 12 + + + Callback with Prepare result to Participant to specified URL - PUT - /<dfsp-host>>/transfers + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0-v1.1.svg new file mode 100644 index 000000000..d00bef23e --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0-v1.1.svg @@ -0,0 +1,341 @@ + + + + + + + + + + + 2.2.0. DFSP2 sends a Fulfil Reject Transfer request + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + + DFSP2 sends an error callback to reject a transfer with an errorCode and description + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - transferMessage: + + + { + + + "errorInformation": { + + + "errorCode": <errorCode>, + + + "errorDescription": <errorDescription>, + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + } + + + + 1 + + + PUT - /transfers/<ID>/error + + + + + 2 + + + Validate incoming token and originator matching Payee + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: fulfil, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 3 + + + Route & Publish Fulfil event for Payee + + + + + 4 + + + Ensure event is replicated as configured (ACKS=all) + + + + + 5 + + + Respond replication acknowledgements have been received + + + + + 6 + + + Respond HTTP - 200 (OK) + + + + + 7 + + + Consume message + + + + + 8 + + + Log error message + + + + + (corresponding to a Fulfil message with transferState='ABORTED') + + + action REJECT is not allowed into fulfil handler + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.a-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.a-v1.1.svg new file mode 100644 index 000000000..dd1fc3063 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.a-v1.1.svg @@ -0,0 +1,495 @@ + + + + + + + + + + + 2.2.0.a. DFSP2 sends a PUT call on /error end-point for a Transfer request + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Event Handler + + + + + Position Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + DFSP2 sends a Fulfil Success Transfer request + + + + + 1 + + + During processing of an incoming + + + POST /transfers request, some processing + + + error occurred and an Error callback is made + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - errorMessage: + + + { + + + errorInformation + + + { + + + "errorCode": <errorCode>, + + + "errorDescription": <errorDescription> + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + } + + + + 2 + + + PUT - /transfers/<ID>/error + + + + + 3 + + + Validate incoming originator matching Payee + + + Error codes: + + + 3000-3002, 3100-3107 + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <errorMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: fulfil, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 4 + + + Route & Publish Abort event for Payee + + + Error code: + + + 2003 + + + + + 5 + + + Ensure event is replicated as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 6 + + + Respond replication acknowledgements have been received + + + + + 7 + + + Respond HTTP - 200 (OK) + + + + + 8 + + + Consume message + + + + + ref + + + Fulfil Handler Consume (Abort) + + + + + 9 + + + Produce message + + + + + 10 + + + Consume message + + + + + ref + + + Position Handler Consume (Abort) + + + + + 11 + + + Produce message + + + + + 12 + + + Consume message + + + + + opt + + + [action == 'abort'] + + + + + ref + + + Send notification to Participant (Payer) + + + + + 13 + + + Send callback notification + + + + + 14 + + + Consume message + + + + + opt + + + [action == 'abort'] + + + + + ref + + + Send notification to Participant (Payee) + + + + + 15 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.a.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.a.svg new file mode 100644 index 000000000..7ac9606f1 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.a.svg @@ -0,0 +1,495 @@ + + + + + + + + + + + 2.2.0.a. DFSP2 sends a PUT call on /error end-point for a Transfer request + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + Position Event Handler + + + + + Position Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + DFSP2 sends a Fulfil Success Transfer request + + + + + 1 + + + During processing of an incoming + + + POST /transfers request, some processing + + + error occurred and an Error callback is made + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - errorMessage: + + + { + + + errorInformation + + + { + + + "errorCode": <errorCode>, + + + "errorDescription": <errorDescription> + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + } + + + + 2 + + + PUT - /transfers/<ID>/error + + + + + 3 + + + Validate incoming originator matching Payee + + + Error codes: + + + 3000-3002, 3100-3107 + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <errorMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: fulfil, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 4 + + + Route & Publish Abort/Reject event for Payee + + + Error code: + + + 2003 + + + + + 5 + + + Ensure event is replicated as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 6 + + + Respond replication acknowledgements have been received + + + + + 7 + + + Respond HTTP - 200 (OK) + + + + + 8 + + + Consume message + + + + + ref + + + Fulfil Handler Consume (Reject/Abort) + + + + + 9 + + + Produce message + + + + + 10 + + + Consume message + + + + + ref + + + Position Handler Consume (Abort) + + + + + 11 + + + Produce message + + + + + 12 + + + Consume message + + + + + opt + + + [action == 'abort'] + + + + + ref + + + Send notification to Participant (Payer) + + + + + 13 + + + Send callback notification + + + + + 14 + + + Consume message + + + + + opt + + + [action == 'abort'] + + + + + ref + + + Send notification to Participant (Payee) + + + + + 15 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.svg new file mode 100644 index 000000000..a2cbf7626 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.0.svg @@ -0,0 +1,489 @@ + + + + + + + + + + + 2.2.0. DFSP2 sends a Fulfil Reject Transfer request + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API Adapter + + + + + ML API Adapter + + + + + ML API Notification Event Handler + + + + + ML API Notification Event Handler + + + + + Central Service API + + + + + Central Service API + + + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + + + Event-Topic + + + + + Event-Topic + + + Position Event Handler + + + + + Position Event Handler + + + + + + + Notification-Topic + + + + + Notification-Topic + + + + + + DFSP2 sends a Fulfil Reject Transfer request + + + + + 1 + + + Retrieve fulfilment string generated during + + + the quoting process or regenerate it using + + + Local secret + + + and + + + ILP Packet + + + as inputs + + + + + Note + + + : In the payload for PUT /transfers/<ID> + + + only the + + + transferState + + + field is + + + required + + + + + Headers - transferHeaders: { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + } + + + Payload - transferMessage: + + + { + + + "fulfilment": <IlpFulfilment>, + + + "completedTimestamp": <DateTime>, + + + "transferState": "ABORTED", + + + "extensionList": { + + + "extension": [ + + + { + + + "key": <string>, + + + "value": <string> + + + } + + + ] + + + } + + + } + + + + + Note + + + : Payee rejection reason should be captured + + + in the extensionList within the payload. + + + + 2 + + + PUT - /transfers/<ID> + + + + + 3 + + + Validate incoming token and originator matching Payee + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: fulfil, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 4 + + + Route & Publish Fulfil event for Payee + + + + + 5 + + + Ensure event is replicated as configured (ACKS=all) + + + + + 6 + + + Respond replication acknowledgements have been received + + + + + 7 + + + Respond HTTP - 200 (OK) + + + + + 8 + + + Consume message + + + + + ref + + + Fulfil Handler Consume (Reject/Abort) + + + + + 9 + + + Produce message + + + + + 10 + + + Consume message + + + + + ref + + + Position Handler Consume (Reject) + + + + + 11 + + + Produce message + + + + + 12 + + + Consume message + + + + + opt + + + [action == 'reject'] + + + + + ref + + + Send notification to Participant (Payer) + + + + + 13 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.1-v1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.1-v1.1.svg new file mode 100644 index 000000000..7b61b6711 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.1-v1.1.svg @@ -0,0 +1,697 @@ + + + + + + + + + + + 2.2.1. Fulfil Handler Consume (Abort/Reject) + + + + Central Service + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Fulfil Handler Consume (Failure) + + + + + alt + + + [Consume Single Message] + + + + + 1 + + + Consume Fulfil event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'fulfil' && ( action IN ['reject','abort'] ) + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate FSPIOP-Signature + + + + + ref + + + Validate message.content.headers. + + + FSPIOP-Signature + + + Error codes: + + + 2001 + + + + + Validate Transfer Fulfil Duplicate Check + + + + + 4 + + + Generate transferFulfilmentId uuid + + + + + 5 + + + Request to retrieve transfer fulfilment hashes by transferId + + + Error code: + + + 2003 + + + + + 6 + + + Request Transfer fulfilment duplicate message hashes + + + + SELET transferId, hash + + + FROM + + + transferFulfilmentDuplicateCheck + + + WHERE transferId = request.params.id + + + + + 7 + + + Return existing hashes + + + + + 8 + + + Return (list of) transfer fulfil messages hash(es) + + + + + 9 + + + Loop the list of returned hashes and compare each entry with the calculated message hash + + + + + alt + + + [Hash matched] + + + + + 10 + + + Request to retrieve Transfer Fulfilment and Transfer state + + + Error code: + + + 2003 + + + + + 11 + + + Request to retrieve Transfer Fulfilment and Transfer state + + + + transferFulfilment + + + transferStateChange + + + + + 12 + + + Return Transfer Fulfilment and Transfer state + + + + + 13 + + + Return Transfer Fulfilment and Transfer state + + + + + alt + + + [transferFulfilment.isValid == 0] + + + + + break + + + + + 14 + + + Error handling: + + + 3105 + + + + [transferState IN ['COMMITTED', 'ABORTED']] + + + + + break + + + + + ref + + + Send notification to Participant (Payee) + + + + [transferState NOT 'RESERVED'] + + + + + break + + + + + 15 + + + Error code: + + + 2001 + + + + + + break + + + + + 16 + + + Allow previous request to complete + + + + [Hash not matched] + + + + + 17 + + + Request to persist transfer hash + + + Error codes: + + + 2003 + + + + + 18 + + + Persist hash + + + + transferFulfilmentDuplicateCheck + + + + + 19 + + + Return success + + + + + alt + + + [action=='reject' call made on PUT /transfers/{ID}] + + + + + 20 + + + Log error message + + + + + action REJECT is not allowed into fulfil handler + + + + [action=='abort' Error callback] + + + + + alt + + + [Validation successful] + + + + + Persist Transfer State (with transferState='RECEIVED_ERROR') + + + + + 21 + + + Request to persist transfer state and Error + + + Error code: + + + 2003 + + + + + 22 + + + Persist transfer state and error information + + + + transferStateChange + + + transferError + + + transferExtension + + + + + 23 + + + Return success + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 24 + + + Route & Publish Position event for Payer + + + + [Validate Transfer Error Message not successful] + + + + + break + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 25 + + + Route & Publish Notification event for Payee + + + + [Consume Batch Messages] + + + + + To be delivered by future story + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.1.svg new file mode 100644 index 000000000..ad8d40a03 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-reject-2.2.1.svg @@ -0,0 +1,1073 @@ + + + + + + + + + + + 2.2.1. Fulfil Handler Consume (Reject/Abort) + + + + Central Service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fulfil-Topic + + + + + Fulfil-Topic + + + Fulfil Event Handler + + + + + Fulfil Event Handler + + + + + + + topic-transfer-position + + + + + topic-transfer-position + + + + + Event-Topic + + + + + Event-Topic + + + + + Notification-Topic + + + + + Notification-Topic + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + + Fulfil Handler Consume (Failure) + + + + + alt + + + [Consume Single Message] + + + + + 1 + + + Consume Fulfil event message for Payer + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'fulfil' && ( action IN ['reject','abort'] ) + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Validate FSPIOP-Signature + + + + + ref + + + Validate message.content.headers. + + + FSPIOP-Signature + + + Error codes: + + + 2001 + + + + + Validate Transfer Fulfil Duplicate Check + + + + + 4 + + + Generate transferFulfilmentId uuid + + + + + 5 + + + Request to retrieve transfer fulfilment hashes by transferId + + + Error code: + + + 2003 + + + + + 6 + + + Request Transfer fulfilment duplicate message hashes + + + + SELET transferId, hash + + + FROM + + + transferFulfilmentDuplicateCheck + + + WHERE transferId = request.params.id + + + + + 7 + + + Return existing hashes + + + + + 8 + + + Return (list of) transfer fulfil messages hash(es) + + + + + 9 + + + Loop the list of returned hashes and compare each entry with the calculated message hash + + + + + alt + + + [Hash matched] + + + + + 10 + + + Request to retrieve Transfer Fulfilment and Transfer state + + + Error code: + + + 2003 + + + + + 11 + + + Request to retrieve Transfer Fulfilment and Transfer state + + + + transferFulfilment + + + transferStateChange + + + + + 12 + + + Return Transfer Fulfilment and Transfer state + + + + + 13 + + + Return Transfer Fulfilment and Transfer state + + + + + alt + + + [transferFulfilment.isValid == 0] + + + + + break + + + + + 14 + + + Error handling: + + + 3105 + + + + [transferState IN ['COMMITTED', 'ABORTED']] + + + + + break + + + + + ref + + + Send notification to Participant (Payee) + + + + [transferState NOT 'RESERVED'] + + + + + break + + + + + 15 + + + Error code: + + + 2001 + + + + + + break + + + + + 16 + + + Allow previous request to complete + + + + [Hash not matched] + + + + + 17 + + + Request to persist transfer hash + + + Error codes: + + + 2003 + + + + + 18 + + + Persist hash + + + + transferFulfilmentDuplicateCheck + + + + + 19 + + + Return success + + + + + alt + + + [action=='reject' call made on PUT /transfers/{ID}] + + + + + 20 + + + Request information for the validate checks + + + Error code: + + + 2003 + + + + + 21 + + + Fetch from database + + + + transfer + + + + + 22 + + + + + 23 + + + Return transfer + + + + + alt + + + [Fulfilment present in the PUT /transfers/{ID} message] + + + + + 24 + + + Validate that Transfer.ilpCondition = SHA-256 (content.payload.fulfilment) + + + Error code: + + + 2001 + + + + + Persist fulfilment + + + + + 25 + + + Persist fulfilment with the result of the above check (transferFulfilment.isValid) + + + Error code: + + + 2003 + + + + + 26 + + + Persist to database + + + + transferFulfilment + + + transferExtension + + + + + 27 + + + Return success + + + + [Fulfilment NOT present in the PUT /transfers/{ID} message] + + + + + 28 + + + Validate that transfer fulfilment message to Abort is valid + + + Error code: + + + 2001 + + + + + Persist extensions + + + + + 29 + + + Persist extensionList elements + + + Error code: + + + 2003 + + + + + 30 + + + Persist to database + + + + transferExtension + + + + + 31 + + + Return success + + + + + alt + + + [Transfer.ilpCondition validate successful OR generic validation successful] + + + + + Persist Transfer State (with transferState='RECEIVED_REJECT') + + + + + 32 + + + Request to persist transfer state + + + Error code: + + + 2003 + + + + + 33 + + + Persist transfer state + + + + transferStateChange + + + + + 34 + + + Return success + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 35 + + + Route & Publish Position event for Payer + + + + [Validate Fulfil Transfer not successful or Generic validation failed] + + + + + break + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: reject, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 36 + + + Route & Publish Notification event for Payee + + + + [action=='abort' Error callback] + + + + + alt + + + [Validation successful] + + + + + Persist Transfer State (with transferState='RECEIVED_ERROR') + + + + + 37 + + + Request to persist transfer state and Error + + + Error code: + + + 2003 + + + + + 38 + + + Persist transfer state and error information + + + + transferStateChange + + + transferError + + + transferExtension + + + + + 39 + + + Return success + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 40 + + + Route & Publish Position event for Payer + + + + [Validate Transfer Error Message not successful] + + + + + break + + + + + Message: + + + { + + + id: <ID>, + + + from: <transferHeaders.FSPIOP-Source>, + + + to: <transferHeaders.FSPIOP-Destination>, + + + type: application/json, + + + content: { + + + headers: <transferHeaders>, + + + payload: <transferMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: <previous.uuid>, + + + type: position, + + + action: abort, + + + createdAt: <timestamp>, + + + state: { + + + status: "error", + + + code: 1 + + + } + + + } + + + } + + + } + + + + + 41 + + + Route & Publish Notification event for Payee + + + + [Consume Batch Messages] + + + + + To be delivered by future story + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-request-dup-check-9.1.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-request-dup-check-9.1.1.svg new file mode 100644 index 000000000..988ffd39a --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-request-dup-check-9.1.1.svg @@ -0,0 +1,292 @@ + + + + + + + + + + + 9.1.1. Request Duplicate Check (incl. Transfers, Quotes, Bulk Transfers, Bulk Quotes) + + + + Central Service + + + + + + + + + + + + topic-source + + + + + topic-source + + + Processing + + + Handler + + + + + Processing + + + Handler + + + + + + + topic-event + + + + + topic-event + + + + + topic-notifcation + + + + + topic-notifcation + + + Request DAO + + + + + Request DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Request Duplicate Check + + + + + 1 + + + Consume message + + + + + 2 + + + Generate hash: + + + generatedHash + + + + + UUID Check (compareById) + + + + + 3 + + + Query hash using getDuplicateDataFuncOverride(id) + + + Error code: + + + 2003 + + + + + request + + + keyword to be replaced by + + + transfer + + + , + + + transferFulfilment + + + , + + + bulkTransfer + + + or other depending + + + on the override + + + + + 4 + + + getDuplicateDataFuncOverride + + + + request + + + DuplicateCheck + + + + + 5 + + + Return + + + duplicateHashRecord + + + + + 6 + + + Return + + + hasDuplicateId + + + + + alt + + + [hasDuplicateId == TRUE] + + + + + Hash Check (compareByHash) + + + + + generatedHash == duplicateHashRecord.hash + + + + + 7 + + + Return + + + hasDuplicateHash + + + + [hasDuplicateId == FALSE] + + + + + Store Message Hash + + + + + 8 + + + Persist hash using saveHashFuncOverride(id, generatedHash) + + + Error code: + + + 2003 + + + + + 9 + + + Persist + + + generatedHash + + + + request + + + DuplicateCheck + + + + + 10 + + + Return success + + + + + return { + + + hasDuplicateId: Boolean, + + + hasDuplicateHash: Boolean + + + } + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-setmodel-2.1.2.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-setmodel-2.1.2.svg new file mode 100644 index 000000000..50323963f --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-setmodel-2.1.2.svg @@ -0,0 +1,292 @@ + + + + + + + + + + + 2.1.2. Settlement Model Handler Consume + + + + Central Service + + + + + + + + + + + + + + topic- + + + settlement-model + + + + + topic- + + + settlement-model + + + Settlement Model + + + Handler + + + + + Settlement Model + + + Handler + + + + + + + topic-event + + + + + topic-event + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Settlement Model Handler Consume + + + + + alt + + + [Consume Single Message] + + + + + 1 + + + Consume settlement model + + + event message + + + + + break + + + + + Validate Event + + + + + 2 + + + Validate event - Rule: type == 'setmodel' && action == 'commit' + + + Error codes: + + + 2001 + + + + + Persist Event Information + + + + + 3 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + 4 + + + Assign transferParicipant state(s) + + + Error code: + + + 2003 + + + + + DB TRANSACTION + + + + + 5 + + + Fetch transfer participant entries + + + + transferParticipant + + + + + 6 + + + Return + + + transferParticipantRecords + + + + + loop + + + [for each transferParticipant] + + + + + Settlement models caching to be considered + + + + + 7 + + + Get settlement model by currency and ledger entry + + + + settlementModel + + + + + 8 + + + Return + + + settlementModel + + + + + opt + + + [settlementModel.delay == 'IMMEDIATE' && settlementModel.granularity == 'GROSS'] + + + + + 9 + + + Set states: CLOSED->PENDING_SETTLEMENT->SETTLED + + + + transferParticipantStateChange + + + transferParticipant + + + + + + 10 + + + Set state: OPEN + + + + transferParticipantStateChange + + + transferParticipant + + + + + 11 + + + Return success + + + + [Consume Batch Messages] + + + + + To be delivered by future story + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.0.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.0.svg new file mode 100644 index 000000000..b35a96686 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.0.svg @@ -0,0 +1,339 @@ + + + + + + + + + + + 2.3.0. Transfer Timeout + + + + Financial Service Providers + + + + ML API Adapter Service + + + + Central Service + + + + + + + + + DFSP1 + + + Payer + + + + + DFSP1 + + + Payer + + + + + DFSP2 + + + Payee + + + + + DFSP2 + + + Payee + + + + + ML API + + + Adapter + + + + + ML API + + + Adapter + + + + + Notification + + + Handler + + + + + Notification + + + Handler + + + + + Timeout Prepare + + + Handler + + + + + Timeout Prepare + + + Handler + + + + + + + topic- + + + transfer-timeout + + + + + topic- + + + transfer-timeout + + + Timeout + + + Handler + + + + + Timeout + + + Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + Position + + + Handler + + + + + Position + + + Handler + + + + + + + topic-notification + + + + + topic-notification + + + + + + Transfer Expiry + + + + + ref + + + Timeout Processing Handler Consume + + + + + 1 + + + Produce message + + + + + 2 + + + Consume message + + + + + ref + + + Timeout Processing Handler Consume + + + + + alt + + + [transferStateId == 'RECEIVED_PREPARE'] + + + + + 3 + + + Produce message + + + + [transferStateId == 'RESERVED'] + + + + + 4 + + + Produce message + + + + + 5 + + + Consume message + + + + + ref + + + Position Hander Consume (Timeout) + + + + + 6 + + + Produce message + + + + + opt + + + [action IN ['timeout-received', 'timeout-reserved']] + + + + + 7 + + + Consume message + + + + + ref + + + Send notification to Participant (Payer) + + + + + 8 + + + Send callback notification + + + + + 9 + + + Consume message + + + + + opt + + + [action == 'timeout-reserved'] + + + + + ref + + + Send notification to Participant (Payee) + + + + + 10 + + + Send callback notification + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.1.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.1.svg new file mode 100644 index 000000000..08083d7e3 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.1.svg @@ -0,0 +1,325 @@ + + + + + + + + + + + 2.3.1. Timeout Prepare Handler + + + + Central Service + + + + + + + Timeout Prepare + + + Handler + + + + + Timeout Prepare + + + Handler + + + + + + + topic- + + + transfer-timeout + + + + + topic- + + + transfer-timeout + + + + + topic-event + + + + + topic-event + + + Timeout DAO + + + + + Timeout DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Timeout Prepare Handler + + + + + Persist Event Information + + + + + 1 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Cleanup + + + + + 2 + + + Cleanup Fulfilled Transfers + + + Error code: + + + 2003 + + + + + 3 + + + Delete fuflfilled transfers records + + + + DELETE et + + + FROM + + + expiringTransfer + + + et + + + JOIN + + + transferFulfilment + + + tf + + + ON tf.transferId = et.transferId + + + + + 4 + + + Return success + + + + + List Expired + + + + + 5 + + + Retrieve Expired Transfers + + + Error code: + + + 2003 + + + + + 6 + + + Select using index + + + + SELECT * + + + FROM + + + expiringTransfer + + + WHERE expirationDate < currentTimestamp + + + + + 7 + + + Return expired transfers + + + + + 8 + + + Return + + + expiredTransfersList + + + + + loop + + + [for each transfer in the list] + + + + + Message: + + + { + + + id: <uuid> + + + from: <switch>, + + + to: <payerFsp>, + + + type: application/json + + + content: { + + + headers: null, + + + payload: <transfer> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: null, + + + type: transfer, + + + action: timeout, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 9 + + + Publish Timeout event + + + Error code: + + + 2003 + + diff --git a/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.2.svg b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.2.svg new file mode 100644 index 000000000..0103f7ba9 --- /dev/null +++ b/mojaloop-technical-overview/central-ledger/assets/diagrams/sequence/seq-timeout-2.3.2.svg @@ -0,0 +1,614 @@ + + + + + + + + + + + 2.3.2. Timeout Handler + + + + Central Service + + + + + + + + + + + topic- + + + transfer-timeout + + + + + topic- + + + transfer-timeout + + + Transfer Timeout Handler + + + + + Transfer Timeout Handler + + + + + + + topic- + + + transfer-position + + + + + topic- + + + transfer-position + + + + + topic- + + + notification + + + + + topic- + + + notification + + + + + topic-event + + + + + topic-event + + + Timeout DAO + + + + + Timeout DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Timeout Handler Consume + + + + + 1 + + + Consume message + + + + + Persist Event Information + + + + + 2 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + Get transfer info + + + + + 3 + + + Acquire transfer information + + + Error code: + + + 2003 + + + + + 4 + + + Get transfer data and state + + + + transfer + + + transferParticipant + + + participantCurrency + + + participant + + + transferStateChange + + + + + 5 + + + Return + + + transferInfo + + + + + 6 + + + Return + + + transferInfo + + + + + alt + + + [transferInfo.transferStateId == 'RECEIVED_PREPARE'] + + + + + 7 + + + Set EXPIRED_PREPARED state + + + Error code: + + + 2003 + + + + + 8 + + + Insert state change + + + + transferStateChange + + + + + 9 + + + Return success + + + + + Message: + + + { + + + id: <transferId>, + + + from: <payerParticipantId>, + + + to: <payeeParticipantId>, + + + type: application/json, + + + content: { + + + headers: + + + { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + }, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3303, + + + "errorDescription": "Transfer expired", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: notification, + + + action: timeout-received, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 10 + + + Publish Notification event + + + + [transferInfo.transferStateId == 'RESERVED'] + + + + + 11 + + + Set RESERVED_TIMEOUT state + + + Error code: + + + 2003 + + + + + 12 + + + Insert state change + + + + transferStateChange + + + + + 13 + + + Return success + + + + + Message: + + + { + + + id: <transferId>, + + + from: <payerParticipantId>, + + + to: <payeeParticipantId>, + + + type: application/json, + + + content: { + + + headers: + + + { + + + Content-Length: <Content-Length>, + + + Content-Type: <Content-Type>, + + + Date: <Date>, + + + X-Forwarded-For: <X-Forwarded-For>, + + + FSPIOP-Source: <FSPIOP-Source>, + + + FSPIOP-Destination: <FSPIOP-Destination>, + + + FSPIOP-Encryption: <FSPIOP-Encryption>, + + + FSPIOP-Signature: <FSPIOP-Signature>, + + + FSPIOP-URI: <FSPIOP-URI>, + + + FSPIOP-HTTP-Method: <FSPIOP-HTTP-Method> + + + }, + + + payload: { + + + "errorInformation": { + + + "errorCode": 3303, + + + "errorDescription": "Transfer expired", + + + "extensionList": <transferMessage.extensionList> + + + } + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + type: position, + + + action: timeout-reserved, + + + createdAt: <timestamp>, + + + state: { + + + status: 'error', + + + code: <errorInformation.errorCode> + + + description: <errorInformation.errorDescription> + + + } + + + } + + + } + + + } + + + + + 14 + + + Route & Publish Position event + + + Error code: + + + 2003 + + + + + + Any other state is ignored + + + + + Cleanup + + + + + 15 + + + Cleanup handled expiring transfer + + + Error code: + + + 2003 + + + + + 16 + + + Delete record + + + + expiringTransfer + + + + + 17 + + + Return success + + diff --git a/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.0.a-reconciliationTransferPrepare.svg b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.0.a-reconciliationTransferPrepare.svg new file mode 100644 index 000000000..56512040f --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.0.a-reconciliationTransferPrepare.svg @@ -0,0 +1,267 @@ + + + + + + + + + + + 5.1.0.a. Reconciliation transfer prepare (reconciliationTransferPrepare) + + + + Central Service + + + + + + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + reconciliationTransferPrepare (payload, trx) + + + + + 1 + + + Insert transferDuplicateCheck + + + + INSERT INTO + + + transferDuplicateCheck + + + (transferId, hash, createdDate) + + + VALUES ({payload.transferId}, hashCode({payload.transferId}), {transactionTimestamp}) + + + + + 2 + + + Insert transfer + + + + INSERT INTO + + + transfer + + + (transferId, amount, currencyId, + + + ilpCondition, expirationDate, createdDate) + + + VALUES ({payload.transferId}, {payload.amount.amount}, + + + {payload.amount.curency}, 0, + + + {new Date()+Config.INTERNAL_TRANSFER_VALIDITY_SECONDS}, + + + {transactionTimestamp}) + + + + + 3 + + + Retrieve hub reconciliation account + + + + SELECT participantCurrencyId AS reconciliationAccountId + + + FROM + + + participantCurrency + + + WHERE participantId = 1 + + + AND currencyId = {payload.amount.currency} + + + LIMIT 1 + + + + + 4 + + + Return + + + reconciliationAccountId + + + + + alt + + + [payload.action == 'RECORD_FUNDS_IN'] + + + + + ledgerEntryTypeId + + + = 'RECORD_FUNDS_IN' + + + amount + + + = + + + payload.amount.amount + + + + [payload.action == 'RECORD_FUNDS_OUT_PREPARE'] + + + + + ledgerEntryTypeId + + + = 'RECORD_FUNDS_OUT' + + + amount + + + = + + + -payload.amount.amount + + + + + 5 + + + Insert transferParticipant records + + + + INSERT INTO + + + transferParticipant + + + (transferId, participantCurrencyId, transferParticipantRoleTypeId, + + + ledgerEntryTypeId, amount, createdDate) + + + VALUES (payload.transferId, reconciliationAccountId, 'HUB', + + + {ledgerEntryTypeId}, {amount}, {transactionTimestamp}) + + + INSERT INTO + + + transferParticipant + + + (transferId, participantCurrencyId, transferParticipantRoleTypeId, + + + ledgerEntryTypeId, amount, createdDate) + + + VALUES ({payload.transferId}, {payload.participantCurrencyId}, 'DFSP_SETTLEMENT', + + + {ledgerEntryTypeId}, {-amount}, {transactionTimestamp}) + + + + + 6 + + + Insert transferStateChange record + + + + INSERT INTO + + + transferStateChange + + + (transferId, transferStateId, reason, createdDate) + + + VALUES ({payload.transferId}, 'RECEIVED_PREPARE', + + + {payload.reason}, {transactionTimestamp}) + + + + + 7 + + + Save externalReference and extensions + + + + transferExtension + + diff --git a/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.0.b-transferStateAndPositionChange.svg b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.0.b-transferStateAndPositionChange.svg new file mode 100644 index 000000000..57ab88b3f --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.0.b-transferStateAndPositionChange.svg @@ -0,0 +1,473 @@ + + + + + + + + + + + 5.1.0.b. Transfer state and position change (transferStateAndPositionChange) + + + + Central Service + + + + + + + + + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + transferStateAndPositionUpdate (param1, trx) + + + + + param1 + + + = { + + + transferId: {payload.transferId}, + + + transferStateId: "enum", + + + reason: {payload.reason}, + + + createdDate: {transactionTimestamp}, + + + drUpdated: "boolean", + + + crUpdated: "boolean" + + + } + + + + + 1 + + + Select all required info + + + + SELECT dr.participantCurrencyId AS drAccountId, + + + dr.amount AS drAmount, drp.participantPositionId AS drPositionId, + + + drp.value AS drPositionValue, drp.reservedValue AS drReservedValue, + + + cr.participantCurrencyId AS crAccountId, + + + cr.amount AS crAmount, crp.participantPositionId AS crPositionId, + + + crp.value AS crPositionValue, crp.reservedValue AS crReservedValue, + + + tsc.transferStateId + + + FROM + + + transfer + + + t + + + JOIN + + + transferParticipant + + + dr + + + ON dr.transferId = t.transferId + + + AND dr.amount > 0 + + + JOIN + + + participantCurrency + + + drpc + + + ON drpc.participantCurrencyId = dr.participantCurrencyId + + + JOIN + + + participantPosition + + + drp + + + ON drp.participantCurrencyId = dr.participantCurrencyId + + + JOIN + + + transferParticipant + + + cr + + + ON cr.transferId = t.transferId + + + AND cr.amount < 0 + + + JOIN + + + participantCurrency + + + crpc + + + ON crpc.participantCurrencyId = dr.participantCurrencyId + + + JOIN + + + participantPosition + + + crp + + + ON crp.participantCurrencyId = cr.participantCurrencyId + + + JOIN + + + transferStateChange + + + tsc + + + ON tsc.transferId = t.transferId + + + WHERE t.transferId = param1.tranferId + + + AND drpc.ledgerAccountTypeId IN('POSITION', 'SETTLEMENT', ' + + + HUB_RECONCILIATION', 'HUB_MULTILATERAL_SETTLEMENT') + + + AND crpc.ledgerAccountTypeId IN('POSITION', 'SETTLEMENT', ' + + + HUB_RECONCILIATION', 'HUB_MULTILATERAL_SETTLEMENT') + + + ORDER BY transferStateChangeId DESC + + + LIMIT 1 + + + + + 2 + + + Return + + + info + + + + + opt + + + [param1.transferStateId == 'COMMITTED'] + + + + + 3 + + + Change transfer state + + + + INSERT INTO + + + transferStateChange + + + (transferId, transferStateId, reason, createdDate) + + + VALUES ({param1.transferId, 'RECEIVED_FULFIL', {param1.reason}, {param1.createdDate}) + + + + [param1.transferStateId == 'ABORTED'] + + + + + 4 + + + Change transfer state + + + + INSERT INTO + + + transferStateChange + + + (transferId, transferStateId, reason, createdDate) + + + VALUES ({param1.transferId, 'REJECTED', {param1.reason}, {param1.createdDate}) + + + + + 5 + + + Change transfer state + + + + INSERT INTO + + + transferStateChange + + + (transferId, transferStateId, reason, createdDate) + + + VALUES ({param1.transferId, {param1.transferStateId}, {param1.reason}, {param1.createdDate}) + + + + + 6 + + + Return + + + transferStateChangeId + + + + + opt + + + [param1.drUpdated == true] + + + + + opt + + + [param1.transferStateId == 'ABORTED'] + + + + + info.drAmount = -info.drAmount + + + + + 7 + + + Change DR position + + + + UPDATE + + + participantPosition + + + SET value = {info.drPositionValue + info.drAmount} + + + WHERE participantPositionId = {info.drPositionId} + + + INSERT INTO + + + participantPositionChange + + + (participantPositionId, + + + transferStateChangeId, value, reservedValue, createdDate) + + + VALUES ({info.drPositionId}, {transferStateChangeId}, + + + {info.drPositionValue + info.drAmount}, {info.drReservedValue}, + + + {param1.createdDate}) + + + + + opt + + + [param1.crUpdated == true] + + + + + opt + + + [param1.transferStateId == 'ABORTED'] + + + + + info.crAmount = -info.crAmount + + + + + 8 + + + Change CR position + + + + UPDATE + + + participantPosition + + + SET value = {info.crPositionValue + info.crAmount} + + + WHERE participantPositionId = {info.crPositionId} + + + INSERT INTO + + + participantPositionChange + + + (participantPositionId, + + + transferStateChangeId, value, reservedValue, createdDate) + + + VALUES ({info.crPositionId}, {transferStateChangeId}, + + + {info.crPositionValue + info.crAmount}, {info.crReservedValue}, + + + {param1.createdDate}) + + + + + return + + + { + + + transferStateChangeId, + + + drPositionValue: {info.drPositionValue + info.drAmount} + + + crPositionValue: {info.crPositionValue + info.crAmount} + + + } + + diff --git a/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.1-in.svg b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.1-in.svg new file mode 100644 index 000000000..c83a1ab9b --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.1.1-in.svg @@ -0,0 +1,426 @@ + + + + + + + + + + + 5.1.1. Record Funds In (recordFundsIn) + + + + Central HUB + + + + Central Service + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Central Service + + + Admin API + + + + + Central Service + + + Admin API + + + + + + + Admin-Transfer-Topic + + + + + Admin-Transfer-Topic + + + Admin Event Handler + + + + + Admin Event Handler + + + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Record Funds In + + + + + { + + + "transferId": <uuid>, + + + "externalReference": "string", + + + "action": "recordFundsIn", + + + "amount": { + + + "amount": <decimal>, + + + "currency": "string" + + + }, + + + "reason": "string", + + + "extensionList": { + + + "extension": [ + + + { + + + "key": "string", + + + "value": "string" + + + } + + + ] + + + } + + + } + + + + + 1 + + + POST - /participants/{name}/accounts/{id} + + + + + Message: + + + { + + + id: <payload.transferId> + + + from: "dfspName", + + + to: "Hub", + + + type: "application/json" + + + content: { + + + headers: <payloadHeaders>, + + + payload: <payloadMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: "", + + + type: "transfer", + + + action: "recordFundsIn", + + + createdAt: <timestamp>, + + + state: "" + + + } + + + }, + + + pp: "" + + + } + + + + + 2 + + + Route & Publish Prepare event + + + Error code: + + + 2003 + + + + + 3 + + + Ensure event is replicated + + + as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 4 + + + Respond replication acks + + + have been received + + + + + 5 + + + Respond HTTP - 202 (Accepted) + + + + + 6 + + + Consume message + + + + + 7 + + + Prepare transfer + + + + + DB TRANSACTION + + + + + Reconciliation Transfer Prepare + + + + + ref + + + reconciliationTransferPrepare + + + (payload, trx) + + + + + Reconciliation Transfer Reserve + + + + + ref + + + transferStateAndPositionUpdate + + + ({ + + + transferId: {payload.transferId}, + + + transferStateId: "RESERVED", + + + reason: {payload.reason}, + + + createdDate: {transactionTimestamp}, + + + drUpdated: true, + + + crUpdated: false + + + }, trx) + + + + + Reconciliation Transfer Commit + + + + + 8 + + + Insert transferFulfilment record + + + + INSERT INTO + + + transferFulfilment + + + (transferFulfilmentId, transferId, ilpFulfilment, + + + completedDate, isValid, settlementWindowId, createdDate) + + + VALUES ({Uuid()}, {payload.transferId}, 0, {transactionTimestamp}, + + + 1, NULL, {transactionTimestamp}) + + + + + ref + + + transferStateAndPositionUpdate + + + ({ + + + transferId: {payload.transferId}, + + + transferStateId: "COMMITTED", + + + reason: {payload.reason}, + + + createdDate: {transactionTimestamp}, + + + drUpdated: false, + + + crUpdated: true + + + }, trx) + + + + + 9 + + + Finished await + + diff --git a/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.1-out-prepare-reserve.svg b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.1-out-prepare-reserve.svg new file mode 100644 index 000000000..a22743415 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.1-out-prepare-reserve.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + 5.2.1. Record Funds Out - Prepare & Reserve (recordFundsOutPrepareReserve) + + + + Central HUB + + + + Central Service + + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Central Service + + + Admin API + + + + + Central Service + + + Admin API + + + + + + + Admin-Transfer-Topic + + + + + Admin-Transfer-Topic + + + Admin Event Handler + + + + + Admin Event Handler + + + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Record Funds Out - Prepare & Reserve + + + + + { + + + "transferId": <uuid>, + + + "externalReference": "string", + + + "action": "recordFundsOutPrepareReserve", + + + "amount": { + + + "amount": <decimal>, + + + "currency": "string" + + + }, + + + "reason": "string", + + + "extensionList": { + + + "extension": [ + + + { + + + "key": "string", + + + "value": "string" + + + } + + + ] + + + } + + + } + + + + + 1 + + + POST - /participants/{name}/accounts/{id} + + + + + Message: + + + { + + + id: <payload.transferId> + + + from: "Hub", + + + to: "dfspName", + + + type: "application/json" + + + content: { + + + headers: <payloadHeaders>, + + + payload: <payloadMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: "", + + + type: "transfer", + + + action: "recordFundsOutPrepareReserve", + + + createdAt: <timestamp>, + + + state: "" + + + } + + + }, + + + pp: "" + + + } + + + + + 2 + + + Route & Publish Prepare event + + + Error code: + + + 2003 + + + + + 3 + + + Ensure event is replicated + + + as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 4 + + + Respond replication acks + + + have been received + + + + + 5 + + + Respond HTTP - 202 (Accepted) + + + + + 6 + + + Consume message + + + + + 7 + + + Prepare transfer + + + and reserve + + + + + DB TRANSACTION + + + + + Reconciliation Transfer Prepare + + + + + ref + + + reconciliationTransferPrepare + + + (payload, trx) + + + + + Reconciliation Transfer Reserve + + + + + ref + + + transferStateAndPositionUpdate + + + ({ + + + transferId: {payload.transferId}, + + + transferStateId: "RESERVED", + + + reason: {payload.reason}, + + + createdDate: {transactionTimestamp}, + + + drUpdated: true, + + + crUpdated: false + + + }, trx) + + + + + opt + + + [transferStateAndPositionUpdate.crPositionValue > 0] + + + + + payload.reason = 'Aborted due to insufficient funds' + + + + + Reconciliation Transfer Abort + + + + + 8 + + + Insert transferFulfilment record + + + + INSERT INTO + + + transferFulfilment + + + (transferFulfilmentId, transferId, ilpFulfilment, + + + completedDate, isValid, settlementWindowId, createdDate) + + + VALUES ({Uuid()}, {payload.transferId}, 0, {transactionTimestamp}, + + + 1, NULL, {transactionTimestamp}) + + + + + ref + + + transferStateAndPositionUpdate + + + ({ + + + transferId: {payload.transferId}, + + + transferStateId: "ABORTED", + + + reason: {payload.reason}, + + + createdDate: {transactionTimestamp}, + + + drUpdated: true, + + + crUpdated: false + + + }, trx) + + + + + 9 + + + Finished await + + diff --git a/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.2-out-commit.svg b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.2-out-commit.svg new file mode 100644 index 000000000..fd276ff59 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.2-out-commit.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + 5.2.2. Record Funds Out Commit (recordFundsOutCommit) + + + + Central HUB + + + + Central Service + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Central Service + + + Admin API + + + + + Central Service + + + Admin API + + + + + + + Admin-Transfer-Topic + + + + + Admin-Transfer-Topic + + + Admin Event Handler + + + + + Admin Event Handler + + + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Record Funds Out Commit + + + + + { + + + "action": "recordFundsOutCommit", + + + "reason": "string" + + + } + + + + + 1 + + + PUT - /participants/{name}/accounts/ + + + {id}/transfers/{transferId} + + + + + Message: + + + { + + + id: <payload.transferId> + + + from: "Hub", + + + to: "dfspName", + + + type: "application/json" + + + content: { + + + headers: <payloadHeaders>, + + + payload: <payloadMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: "", + + + type: "transfer", + + + action: "recordFundsOutCommit", + + + createdAt: <timestamp>, + + + state: "" + + + } + + + }, + + + pp: "" + + + } + + + + + 2 + + + Route & Publish Prepare event + + + Error code: + + + 2003 + + + + + 3 + + + Ensure event is replicated + + + as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 4 + + + Respond replication acks + + + have been received + + + + + 5 + + + Respond HTTP - 202 (Accepted) + + + + + 6 + + + Consume message + + + + + 7 + + + Commit transfer + + + + + DB TRANSACTION + + + + + Reconciliation Transfer Commit + + + + + 8 + + + Insert transferFulfilment record + + + + INSERT INTO + + + transferFulfilment + + + (transferFulfilmentId, transferId, ilpFulfilment, + + + completedDate, isValid, settlementWindowId, createdDate) + + + VALUES ({transferFulfilmentId}, {payload.transferId}, 0, {transactionTimestamp}, + + + 1, NULL, {transactionTimestamp}) + + + + + ref + + + transferStateAndPositionUpdate + + + ({ + + + transferId: {payload.transferId}, + + + transferStateId: "COMMITTED", + + + reason: {payload.reason}, + + + createdDate: {transactionTimestamp}, + + + drUpdated: false, + + + crUpdated: true + + + }, trx) + + + + + 9 + + + Finished await + + diff --git a/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.3-out-abort.svg b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.3-out-abort.svg new file mode 100644 index 000000000..8db2df0c4 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/funds-in-out/assets/diagrams/sequence/seq-recfunds-5.2.3-out-abort.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + 5.2.3. Record Funds Out Abort (recordFundsOutAbort) + + + + Central HUB + + + + Central Service + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Central Service + + + Admin API + + + + + Central Service + + + Admin API + + + + + + + Admin-Transfer-Topic + + + + + Admin-Transfer-Topic + + + Admin Event Handler + + + + + Admin Event Handler + + + + + Transfer DAO + + + + + Transfer DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Record Funds Out Abort + + + + + { + + + "action": "recordFundsOutAbort", + + + "reason": "string" + + + } + + + + + 1 + + + PUT - /participants/{name}/accounts/ + + + {id}/transfers/{transferId} + + + + + Message: + + + { + + + id: <payload.transferId> + + + from: "Hub", + + + to: "dfspName", + + + type: "application/json" + + + content: { + + + headers: <payloadHeaders>, + + + payload: <payloadMessage> + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: "", + + + type: "transfer", + + + action: "recordFundsOutAbort", + + + createdAt: <timestamp>, + + + state: "" + + + } + + + }, + + + pp: "" + + + } + + + + + 2 + + + Route & Publish Prepare event + + + Error code: + + + 2003 + + + + + 3 + + + Ensure event is replicated + + + as configured (ACKS=all) + + + Error code: + + + 2003 + + + + + 4 + + + Respond replication acks + + + have been received + + + + + 5 + + + Respond HTTP - 202 (Accepted) + + + + + 6 + + + Consume message + + + + + 7 + + + Abort transfer + + + + + DB TRANSACTION + + + + + Reconciliation Transfer Abort + + + + + 8 + + + Insert transferFulfilment record + + + + INSERT INTO + + + transferFulfilment + + + (transferFulfilmentId, transferId, ilpFulfilment, + + + completedDate, isValid, settlementWindowId, createdDate) + + + VALUES ({transferFulfilmentId}, {payload.transferId}, 0, {transactionTimestamp}, + + + 1, NULL, {transactionTimestamp}) + + + + + ref + + + transferStateAndPositionUpdate + + + ({ + + + transferId: {payload.transferId}, + + + transferStateId: "ABORTED", + + + reason: {payload.reason}, + + + createdDate: {transactionTimestamp}, + + + drUpdated: true, + + + crUpdated: false + + + }, trx) + + + + + 9 + + + Finished await + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.1.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.1.svg new file mode 100644 index 000000000..cdf3e22c5 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.1.svg @@ -0,0 +1,1033 @@ + + + + + + + + + + + 6.2.1. Trigger Settlement Event (createSettlement) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Trigger Settlement Event + + + + + { + + + "settlementModel": "string", + + + "reason": "string", + + + "settlementWindows": [ + + + { + + + "id": 1, + + + }, + + + { + + + "id": 2, + + + } + + + ] + + + } + + + + + 1 + + + POST - /settlements + + + + + 2 + + + Request settlementModel + + + Error code: + + + 2001 + + + + + 3 + + + Retrieve settlementModel + + + + SELECT sg.name settlementGranularity, si.name settlementInterchange, + + + sd.name settlementDelay, sm.ledgerAccountTypeId, + + + sm.currencyId, sm.requireLiquidityCheck + + + FROM + + + settlementModel + + + sm + + + JOIN + + + settlementGranularity + + + sg + + + ON sg.settlementGranularityId = sm.settlementGranularityId + + + JOIN + + + settlementInterchange + + + si + + + ON si.settlementInterchangeId = sm.settlementInterchangeId + + + JOIN + + + settlementDelay + + + sd + + + ON sd.settlementDelayId = sm.settlementDelayId + + + WHERE name = {settlementModelName} + + + AND isActive = 1 + + + + + 4 + + + Return data + + + + + 5 + + + Return + + + settlementModelData (smd) + + + + + break + + + [smd.settlementGranularity != 'NET' || + + + smd.settlementInterchange != 'MULTILATERAL' || + + + smd.settlementDelay != 'DEFERRED'] + + + + + Log ERROR event + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "Invalid settlement model" + + + } + + + } + + + + + 6 + + + Respond HTTP - 4xx (Client error) + + + + + 7 + + + Request settlementWindow(s) + + + Error code: + + + 2001 + + + + + 8 + + + Retrieve settlementWindow(s) + + + + SELECT DISTINCT sw.settlementWindowId, sw.currentStateChangeId, sw.createdDate + + + FROM + + + settlementWindow + + + sw + + + JOIN + + + settlementWindowStateChange + + + swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + JOIN + + + settlementWindowContent + + + swc + + + ON swc.settlementWindowId = sw.settlementWindowId + + + JOIN + + + settlementWindowContentStateChange + + + swcsc + + + ON swcsc.settlementWindowContentStateChangeId = sw.currentStateChangeId + + + WHERE sw.settlementWindowId IN {payload.settlementWindows.idList} + + + AND swc.ledgerAccountType = smd.ledgerAccountType + + + AND swc.currencyId = ISNULL(smd.currencyId, swc.currencyId) + + + AND swsc.settlementWindowStateId IN ('CLOSED', 'ABORTED', 'PENDING_SETTLEMENT') + + + AND swcsc.settlementWindowStateId IN ('CLOSED', 'ABORTED') + + + + + 9 + + + Return data + + + + + 10 + + + Return + + + windowsData + + + + + break + + + [payload.settlementWindows.length != windowsData.length] + + + + + Log ERROR event + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "Inapplicable windows found: ${windowId1}, ${windowId2}, ..." + + + } + + + } + + + + + 11 + + + Respond HTTP - 4xx (Client error) + + + + + All preliminary validations succeeded + + + + + Main processing + + + + + 12 + + + Create settlement + + + Error code: + + + 2001 + + + + + DB TRANSACTION + + + + + let + + + transactionTimestamp + + + = now() + + + + + 13 + + + Insert new settlement + + + + INSERT INTO + + + settlement + + + (reason, createdDate) + + + VALUES ({payload.reason}, {transactionTimestamp}) + + + + + 14 + + + Return + + + settlementId + + + + + 15 + + + Associate settlement windows with the settlement + + + + INSERT INTO + + + settlementSettlementWindow + + + (settlementId, settlementWindowId, createdDate) + + + VALUES ({settlementId}, {payload.settlementWindows.idList}, {transactionTimestamp}) + + + + + 16 + + + Bind to settlement + + + + settlementWindowContent + + + .settlementId + + + settlementContentAggregation + + + .settlementId + + + .currentStateId + + + + + 17 + + + Change state to 'PENDING_SETTLEMENT' + + + + transferParticipantStateChange + + + transferParticipant + + + settlementWindowContentStateChange + + + settlementWindowContent + + + + + 18 + + + Aggregate settlement net amounts + + + + INSERT INTO + + + settlementParticipantCurrency + + + (settlementId, participantCurrencyId, netAmount, createdDate) + + + SELECT settlementId, participantCurrencyId, SUM(amount), {transactionTimestamp} + + + JOIN + + + settlementContentAggregation + + + WHERE settlementId = {settlementId} + + + GROUP BY settlementId, participantCurrencyId + + + + + 19 + + + Return inserted + + + settlementParticipantCurrencyIdList + + + + + 20 + + + Insert initial settlement accounts state 'PENDING_SETTLEMENT' + + + + INSERT INTO + + + settlementParticipantCurrencyStateChange + + + (settlementParticipantCurrencyId, settlementStateId, reason, createdDate) + + + VALUES ({settlementParticipantCurrencyIdList}, 'PENDING_SETTLEMENT', + + + {payload.reason}, {transactionTimestamp}) + + + + + 21 + + + Return inserted + + + settlementParticipantCurrencyStateChangeIdList + + + + + 22 + + + Merge settlementParticipantCurrencyStateChangeIdList + + + to settlementParticipantCurrencyIdList in order to + + + issue the following update in one knex command + + + + + 23 + + + Update pointers to current state change ids + + + + UPDATE + + + settlementParticipantCurrency + + + SET currentStateChangeId = {settlementParticipantCurrencyStateChangeIdList} + + + WHERE settlementParticipantCurrencyId = {settlementParticipantCurrencyIdList} + + + + + loop + + + [foreach w in windowsData] + + + + + opt + + + [if w.currentStateChangeId IN ('CLOSED', 'ABORTED')] + + + + + 24 + + + Insert new state for settlementWindow 'PENDING_SETTLEMENT' + + + + INSERT INTO + + + settlementWindowStateChange + + + (settlementWindowId, settlementWindowStateId, reason, createdDate) + + + VALUES ({w.settlementWindowId}, 'PENDING_SETTLEMENT', + + + {payload.reason}, {transactionTimestamp}) + + + + + 25 + + + Return inserted + + + settlementWindowStateChangeId + + + + + 26 + + + Update pointers to current state change ids + + + + UPDATE + + + settlementWindow + + + SET currentStateChangeId = {settlementWindowStateChangeId} + + + WHERE settlementWindowId = {w.settlementWindowId} + + + + + 27 + + + Insert initial state for settlement 'PENDING_SETTLEMENT' + + + + INSERT INTO + + + settlementStateChange + + + (settlementId, settlementStateId, reason, createdDate) + + + VALUES ({settlementId}, ‘PENDING_SETTLEMENT’, + + + {payload.reason}, {transactionTimestamp}) + + + + + 28 + + + Return + + + settlementStateChangeId + + + + + 29 + + + Update pointer to current state change id + + + + UPDATE + + + settlement + + + SET currentStateChangeId = {settlementStateChangeId} + + + WHERE settlementId = {settlementId} + + + + + 30 + + + Retrieve all content + + + + settlementWindowContent + + + settlementWindowContentStateChange + + + ledgerAccountType + + + currency + + + settlementWindow + + + settlementWindowStateChange + + + + + 31 + + + Return + + + settlementWindowContentReport + + + + + 32 + + + Use previous result to produce settlementWindowsData ( + + + swd + + + ) array + + + + + 33 + + + Select account data for response + + + + SELECT pc.participantId, spc.participantCurrencyId, spc.netAmount, pc.currencyId + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE spc.settlementId = {settlementId} + + + + + 34 + + + Return + + + accountData + + + + + 35 + + + Construct and return result + + + + + { + + + "id": settlementId, + + + "state": "PENDING_SETTLEMENT", + + + "settlementWindows": [ + + + { + + + "id": swd[m].id, + + + "state": swd[m].state, + + + "reason": swd[m].reason, + + + "createdDate": swd[m].createdDate, + + + "changedDate": swd[m].changedDate, + + + "content": [ + + + { + + + "id": swd[m].content[n].settlementWindowContentId, + + + "state": swd[m].content[n].settlementWindowStateId, + + + "ledgerAccountType": swd[m].content[n].ledgerAccountType, + + + "currencyId": swd[m].content[n].currencyId, + + + "createdDate": swd[m].content[n].createdDate, + + + "changedDate": swd[m].content[n].changedDate + + + } + + + ] + + + } + + + ], + + + "participants": [ + + + { + + + "id": accountData.participantId, + + + "accounts": [ + + + { + + + "id": accountData.participantCurrencyId, + + + "state": "PENDING_SETTLEMENT", + + + "reason": payload.reason, + + + "netSettlementAmount": { + + + "amount": accountData.netAmount, + + + "currency": accountData.currencyId + + + } + + + } + + + ] + + + } + + + ] + + + } + + + + + 36 + + + Respond HTTP - 201 (Created) + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.2.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.2.svg new file mode 100644 index 000000000..f47d21e98 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.2.svg @@ -0,0 +1,609 @@ + + + + + + + + + + + 6.2.2. Query Settlements by Parameters (getSettlementsByParams) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Query Settlements by Parameters + + + + + Params: + + + ?[state={settlementStateId}] + + + [&fromDateTime={fromDateTime}] + + + [&toDateTime={toDateTime}] + + + [&currency={currencyId}] + + + [&settlementWindowId={settlementWindowId}] + + + [&fromSettlementWindowDateTime={fromSettlementWindowDateTime}] + + + [&toSettlementWindowDateTime={toSettlementWindowDateTime}] + + + [&participantId={participantId}] + + + [&accountId={participantCurrencyId}] + + + + + 1 + + + GET - /settlements + + + + + 2 + + + Retrieve settlements + + + Error code: + + + 2001 + + + + + 3 + + + Retrieve requested data + + + + SELECT + + + DISTINCT + + + s.settlementId, ssc.settlementStateId, + + + ssw.settlementWindowId, swsc.settlementWindowStateId, swsc.reason + + + settlementWindowReason, sw.createdDate, swsc.createdDate changedDate, + + + pc.participantId, spc.participantCurrencyId, spcsc.reason + + + accountReason, spcsc.settlementStateId accountState, spc.netAmount + + + accountAmount, pc.currencyId accountCurrency + + + FROM + + + settlement + + + s + + + JOIN + + + settlementStateChange + + + ssc + + + ON ssc.settlementStateChangeId = s.currentStateChangeId + + + JOIN + + + settlementSettlementWindow + + + ssw + + + ON ssw.settlementId = s.settlementId + + + JOIN + + + settlementWindow + + + sw + + + ON sw.settlementWindowId = ssw.settlementWindowId + + + JOIN + + + settlementWindowStateChange + + + swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + JOIN + + + settlementWindowContent + + + swc + + + ON swc.settlementWindowId = sw.settlementWindowId + + + JOIN + + + settlementWindowContentAggregation + + + swca + + + ON swca.settlementWindowContentId = swc.settlementWindowContentId + + + JOIN + + + settlementParticipantCurrency + + + spc + + + ON spc.settlementId = s.settlementId + + + AND spc.participantCurrencyId = swca.participantCurrencyId + + + JOIN + + + settlementParticipantCurrencyStateChange + + + spcsc + + + ON spcsc.settlementParticipantCurrencyStateChangeId = spc.currentStateChangeId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE [ssc.settlementStateId = {settlementStateId}] + + + [AND s.createdDate >= {fromDateTime}] + + + [AND s.createdDate <= {toDateTime}] + + + [AND pc.currencyId = {currencyId}] + + + [AND sw.settlementWindowId = + + + {settlementWindowId} + + + ] + + + [AND sw.createdDate >= {fromSettlementWindowDateTime}] + + + [AND sw.createdDate <= {toSettlementWindowDateTime}] + + + [AND pc.participantId = {participantId}] + + + [AND spc.participantCurrencyId = {participantCurrencyId}] + + + + + 4 + + + Return data + + + + + 5 + + + Return + + + settlementsData + + + + + alt + + + [Settlement(s) found] + + + + + let settlements = {} + + + let settlement + + + let participant + + + + + loop + + + [settlementsData] + + + + + if (!settlements[settlementsData.settlementId]) { + + + settlements[settlementsData.settlementId] = { + + + "id: settlementsData.settlementId, + + + "state": settlementsData.settlementStateId + + + } + + + } + + + settlement = settlements[settlementsData.settlementId] + + + if (!settlement.settlementWindows[settlementsData.settlementWindowId]) { + + + settlement.settlementWindows[settlementsData.settlementWindowId] = { + + + "id": settlementsData.settlementWindowId, + + + "state": settlementsData.settlementWindowStateId, + + + "reason": settlementsData.settlementWindowReason, + + + "createdDate": settlementsData.createdDate, + + + "changedDate": settlementsData.changedDate + + + } + + + } + + + if (!settlement.participants[settlementsData.participantId]) { + + + settlement.participants[settlementsData.participantId] = { + + + "id": settlementsData.participantId + + + } + + + } + + + participant = settlement.participants[settlementsData.participantId] + + + participant.accounts[settlementsData.accountId] = { + + + "id": settlementsData.participantCurrencyId, + + + "state": settlementsData.accountState, + + + "reason": settlementsData.accountReason, + + + "netSettlementAmount": { + + + "amount": settlementsData.accountAmount, + + + "currency": settlementsData.accountCurrency + + + } + + + } + + + + + 6 + + + Transform + + + settlements + + + map to array + + + + + [ + + + { + + + "id": settlementId, + + + "state": settlementStateId, + + + "settlementWindows": [ + + + { + + + "id": settlementWindowId, + + + "state": settlementWindowStateId, + + + "reason": settlementWindowReason, + + + "createdDate": createdDate, + + + "changedDate": changedDate + + + } + + + ], + + + "participants": [ + + + { + + + "id": participantId, + + + "accounts": [ + + + { + + + "id": participantCurrencyId, + + + "state": accountState, + + + "reason": accountReason, + + + "netSettlementAmount": { + + + "amount": accountAmount, + + + "currency": accountCurrency + + + } + + + } + + + ] + + + } + + + ] + + + } + + + ] + + + + + 7 + + + Respond HTTP - 200 (OK) + + + + + + Log ERROR event + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "Client error description" + + + } + + + } + + + + + 8 + + + Respond HTTP - 4xx (Client error) + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.3.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.3.svg new file mode 100644 index 000000000..47915f13b --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.3.svg @@ -0,0 +1,916 @@ + + + + + + + + + + + 6.2.3. Get Settlement By Settlement, Participant and Account (getSettlementBySPA) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Get Settlement By Settlement, Participant and Account + + + + + alt + + + + + 1 + + + GET - /settlements/{settlementId}/ + + + participants/{participantId} + + + + + + 2 + + + GET - /settlements/{settlementId}/ + + + participants/{participantId}/ + + + accounts/{accountId} + + + + + let settlementFound = false + + + let participantFoundInSettlement = false + + + let accountProvided = accountId > 0 + + + let participantAndAccountMatched = !accountProvided + + + let accountFoundInSettlement = !accountProvided + + + + + 3 + + + Request settlement state + + + Error code: + + + 2001 + + + + + 4 + + + Retrieve settlement + + + + SELECT s.settlementId, ssc.settlementStateId, s.reason, s.createdDate + + + FROM + + + settlement + + + s + + + JOIN + + + settlementStateChange + + + ssc + + + ON ssc.settlementStateChangeId = s.currentStateChangeId + + + WHERE s.settlementId = {id} + + + + + 5 + + + Return + + + settlement + + + + + if (settlement.settlementId) { + + + settlementFound + + + = true + + + } + + + + + opt + + + [settlementFound] + + + + + 6 + + + Check participant + + + Error code: + + + 2001 + + + + + 7 + + + Check exists + + + + SELECT settlementParticipantCurrencyId + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE spc.settlementId = {id} + + + AND pc.participantId = {participantId} + + + + + 8 + + + Return + + + settlementParticipantCurrencyIdList + + + + + if (settlementParticipantCurrencyIdList.length > 0) { + + + participantFoundInSettlement + + + = true + + + } + + + + + opt + + + [participantFoundInSettlement && accountProvided] + + + + + 9 + + + Check participant + + + Error code: + + + 2001 + + + + + 10 + + + Check exists + + + + SELECT participantCurrencyId + + + JOIN + + + participantCurrency + + + WHERE participantCurrencyId = {accountId} + + + AND participantId = {participantId} + + + + + 11 + + + Return + + + account + + + + + if (account) { + + + participantAndAccountMatched + + + = true + + + } + + + + + opt + + + [participantAndAccountMatched] + + + + + 12 + + + Check account in settlement + + + Error code: + + + 2001 + + + + + 13 + + + Check exists + + + + SELECT settlementParticipantCurrencyId + + + FROM + + + settlementParticipantCurrency + + + WHERE spc.settlementId = {id} + + + AND pc.participantCurrencyId = {accountId} + + + + + 14 + + + Return + + + settlementParticipantCurrencyId + + + + + if (settlementParticipantCurrencyId) { + + + accountFoundInSettlement + + + = true + + + } + + + + + alt + + + [settlementFound && participantFoundInSettlement && participantAndAccountMatched && accountFoundInSettlement] + + + + + 15 + + + Request settlement windows + + + Error code: + + + 2001 + + + + + 16 + + + Retrieve windows + + + + + alt + + + [accountProvided] + + + + SELECT + + + DISTINCT + + + sw.settlementWindowId, swsc.settlementWindowStateId, + + + swsc.reason, sw.createdDate, swsc.createdDate changedDate + + + FROM + + + settlementSettlementWindow + + + ssw + + + JOIN + + + settlementWindow + + + sw + + + ON sw.settlementWindowId = ssw.settlementWindowId + + + JOIN + + + settlementWindowStateChange + + + swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + JOIN + + + settlementWindowContent + + + swc + + + ON swc.settlementWindowId = sw.settlementWindowId + + + JOIN + + + settlementWindowContentAggregation + + + swca + + + ON swca.settlementWindowContentId = swc.settlementWindowContentId + + + AND swca.participantCurrencyId = + + + {accountId} + + + WHERE ssw.settlementId = {id} + + + + + SELECT DISTINCT sw.settlementWindowId, swsc.settlementWindowStateId, + + + swsc.reason, sw.createdDate, swsc.createdDate changedDate + + + FROM + + + settlementSettlementWindow + + + ssw + + + JOIN + + + settlementWindow + + + sw + + + ON sw.settlementWindowId = ssw.settlementWindowId + + + JOIN + + + settlementWindowStateChange + + + swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + JOIN + + + settlementWindowContent + + + swc + + + ON swc.settlementWindowId = sw.settlementWindowId + + + JOIN + + + settlementWindowContentAggregation + + + swca + + + ON swca.settlementWindowContentId = swc.settlementWindowContentId + + + AND swca.participantCurrencyId IN( + + + SELECT participantCurrencyId + + + FROM participantCurrency + + + WHERE participantId = + + + {participantId} + + + ) + + + WHERE ssw.settlementId = {id} + + + + + 17 + + + Return + + + windows + + + + + 18 + + + Request settlement accounts + + + Error code: + + + 2001 + + + + + 19 + + + Retrieve accounts + + + + + alt + + + [accountProvided] + + + + SELECT pc.participantId, spc.participantCurrencyId, spcsc.settlementStateId, + + + spcsc.reason, spc.netAmount, pc.currencyId + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + settlementParticipantCurrencyStateChange + + + spcsc + + + ON spcsc.settlementParticipantCurrencyStateChangeId = spc.currentStateChangeId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE spc.settlementParticipantCurrencyId = {settlementParticipantCurrencyId} + + + + + SELECT pc.participantId, spc.participantCurrencyId, spcsc.settlementStateId, + + + spcsc.reason, spc.netAmount, pc.currencyId + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + settlementParticipantCurrencyStateChange + + + spcsc + + + ON spcsc.settlementParticipantCurrencyStateChangeId = spc.currentStateChangeId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE spc.settlementParticipantCurrencyId IN {settlementParticipantCurrencyIdList} + + + + + 20 + + + Return + + + accounts + + + + + { + + + "id": settlement.settlementId, + + + "state": settlement.settlementStateId, + + + "settlementWindows": [ + + + [ + + + { + + + "id": window.settlementWindowId, + + + "reason": window.reason, + + + "state": window.settlementWindowStateId, + + + "createdDate": window.createdDate, + + + "changedDate": window.changedDate + + + } + + + ] + + + ], + + + "participants": [ + + + { + + + "id": account.participantId, + + + "accounts": [ + + + { + + + "id": account.participantCurrencyId, + + + "reason": account.reason, + + + "state": account.settlementStateId, + + + "netSettlementAmount": { + + + "amount": account.netAmount, + + + "currency": account.currencyId + + + } + + + } + + + ] + + + } + + + ] + + + } + + + + + 21 + + + Respond HTTP - 200 (OK) + + + + [!settlementFound || !participantFoundInSettlement || !participantAndAccountMatched || !accountFoundInSettlement] + + + + + Log ERROR event (based on the failure) + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "Client error description" + + + } + + + } + + + + + 22 + + + Respond HTTP - 4xx (Client error) + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.4.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.4.svg new file mode 100644 index 000000000..460c5a1ac --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.4.svg @@ -0,0 +1,442 @@ + + + + + + + + + + + 6.2.4. Get Settlement By Id (getSettlementById) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Get Settlement By Id + + + + + 1 + + + GET - /settlements/{id} + + + + + 2 + + + Request settlement state + + + Error code: + + + 2001 + + + + + 3 + + + Retrieve settlement + + + + SELECT s.settlementId, ssc.settlementStateId, s.reason, s.createdDate + + + FROM + + + settlement + + + s + + + JOIN + + + settlementStateChange + + + ssc + + + ON ssc.settlementStateChangeId = s.currentStateChangeId + + + WHERE s.settlementId = {id} + + + + + 4 + + + Return + + + settlement + + + + + alt + + + [settlement found] + + + + + 5 + + + Request settlement windows + + + Error code: + + + 2001 + + + + + 6 + + + Retrieve windows + + + + SELECT sw.settlementWindowId, swsc.settlementWindowStateId, + + + swsc.reason, sw.createdDate, swsc.createdDate changedDate + + + FROM + + + settlementSettlementWindow + + + ssw + + + JOIN + + + settlementWindow + + + sw + + + ON sw.settlementWindowId = ssw.settlementWindowId + + + JOIN + + + settlementWindowStateChange + + + swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + WHERE ssw.settlementId = {id} + + + + + 7 + + + Return + + + windows + + + + + 8 + + + Request settlement accounts + + + Error code: + + + 2001 + + + + + 9 + + + Retrieve accounts + + + + SELECT pc.participantId, spc.participantCurrencyId, spcsc.settlementStateId, + + + spcsc.reason, spc.netAmount, pc.currencyId + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + settlementParticipantCurrencyStateChange + + + spcsc + + + ON spcsc.settlementParticipantCurrencyStateChangeId = spc.currentStateChangeId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE spc.settlementId = {id} + + + + + 10 + + + Return + + + accounts + + + + + { + + + "id": settlement.settlementId, + + + "state": settlement.settlementStateId, + + + "settlementWindows": [ + + + [ + + + { + + + "id": window.settlementWindowId, + + + "reason": window.reason, + + + "state": window.settlementWindowStateId, + + + "createdDate": window.createdDate, + + + "changedDate": window.changedDate + + + } + + + ] + + + ], + + + "participants": [ + + + { + + + "id": account.participantId, + + + "accounts": [ + + + { + + + "id": account.participantCurrencyId, + + + "reason": account.reason, + + + "state": account.settlementStateId, + + + "netSettlementAmount": { + + + "amount": account.netAmount, + + + "currency": account.currencyId + + + } + + + } + + + ] + + + } + + + ] + + + } + + + + + 11 + + + Respond HTTP - 200 (OK) + + + + + + Log ERROR event + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "Client error description" + + + } + + + } + + + + + 12 + + + Respond HTTP - 4xx (Client error) + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.5.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.5.svg new file mode 100644 index 000000000..73611b591 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.5.svg @@ -0,0 +1,1754 @@ + + + + + + + + + + + 6.2.5. Acknowledgement of Settlement Transfer (updateSettlementById) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + + + + + + + + + + + + + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Acknowledgement of Settlement Transfer + + + + + { + + + "participants": [ + + + { + + + "id": 1 + + + "accounts" : [ + + + { "id": 1, "state": "PENDING_SETTLEMENT", "reason": <string> }, + + + { "id": 2, "state": "PS_TRANSFERS_RECORDED", "reason": <string>, "externalReference": <string> }, + + + { "id": 3, "state": "PS_TRANSFERS_RESERVED", "reason": <string> }, + + + { "id": 4, "state": "PS_TRANSFERS_COMMITTED", "reason": <string>, "externalReference": <string> }, + + + { "id": 5, "state": "SETTLED", "reason": <string> } + + + ] + + + }, + + + { + + + "id": 2 + + + "accounts" : [ + + + { "id": 6, "state": "SETTLED", "reason": <string> } + + + ] + + + } + + + ] + + + } + + + + + 1 + + + PUT - /settlement/{id} + + + + + 2 + + + updateSettlementById routine + + + Error code: + + + 2001 + + + + + DB TRANSACTION + + + + + 3 + + + Retrieve settlement information + + + + SELECT s.settlementId, ssc.settlementStateId, + + + ssc.reason, ssc.createdDate, sm.autoPositionReset + + + FROM + + + settlement + + + s + + + JOIN + + + settlementStateChange + + + ssc + + + ON ssc.settlementStateChangeId = s.currentStateChangeId + + + JOIN + + + settlementModel + + + sm + + + ON sm.settlementModelId = s.settlementModelId + + + WHERE s.settlementId = {id} + + + FOR UPDATE + + + + + 4 + + + Return + + + settlementData + + + + + 5 + + + Retrive settlement accounts information + + + + SELECT pc.participantId, spc.participantCurrencyId, + + + spcsc.settlementStateId, spcsc.reason, + + + spcsc.createdDate, spc.netAmount, pc.currencyId, + + + spc.settlementParticipantCurrencyId AS + + + key + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + settlementParticipantCurrencyStateChange + + + spcsc + + + ON spcsc.settlementParticipantCurrencyStateChangeId = + + + spc.currentStateChangeId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE spc.settlementId = {id} + + + FOR UPDATE + + + + + 6 + + + Return + + + settlementAccountsList + + + + + All objects below are for the purpose of the syncronous request. + + + If at some point, Node process memory limit is reached, we may decide to: + + + A. Limit the amount of transfers per window and windows per settlement or + + + B. Move to asyncronous processing where we don't need these objects + + + + + Available raw datasets from DB: + + + settlementData + + + contains information about settlement and its current state/reason + + + settlementAccountsList + + + holds information about all accounts and their current state/reason + + + Local variables and objects: + + + settlementAccounts + + + : { // (derived from + + + settlementAccountsList + + + ) + + + pendingSettlementCount: <integer>, // count of accounts in PENDING_SETTLEMENT state + + + psTransfersRecordedCount: <integer>, // count of accounts in PS_TRANSFERS_RECORDED state + + + psTransfersReservedCount: <integer>, // count of accounts in PS_TRANSFERS_RESERVED state + + + psTransfersCommittedCount: <integer>, // count of accounts in PS_TRANSFERS_COMMITTED state + + + settledCount: <integer>, // count of accounts in SETTLED state + + + abortedCount: <integer> // count of accounts in ABORTED state + + + unknownCount: <integer>, + + + settledIdList: <array>, + + + changedIdList: <array> + + + } + + + settlementAccountsInit + + + copy of previous object to be preserved for comparission at the end + + + allAccounts + + + : { // same as previous but accessed by account id (derived from + + + settlementAccountsList + + + ) + + + participantCurrencyId_key: { // number used to access the object in map-like style + + + id: participantCurrencyId, + + + state: settlementStateId, + + + reason: reason, + + + createdDate: createdDate, + + + netSettlementAmount: { + + + amount: netAmount, + + + currency: currencyId + + + }, + + + participantId: participantId, // could be used to reconstruct allParticipants + + + key: + + + key + + + // will be used to insert new state for settlementParticipantCurrency + + + } + + + } + + + let + + + transactionTimestamp + + + = now() + + + + + 7 + + + Declare and initialize variables + + + + + let settlementAccounts = { + + + pendingSettlementCount: 0, + + + psTransfersRecordedCount: 0, + + + psTransfersReservedCount: 0, + + + psTransfersCommittedCount: 0, + + + settledCount: 0, + + + abortedCount: 0, + + + unknownCount: 0 + + + } + + + let allAccounts = {} // declare map + + + let pid // participantId + + + let aid // accountId (participantCurrencyId) + + + let state + + + + + loop + + + [settlementAccountsList as account] + + + + + 8 + + + Populate + + + allAccounts + + + + + pid = account.participantId + + + aid = account.participantCurrencyId + + + state = account.settlementStateId + + + allAccounts[aid] = { + + + id: aid, + + + state, + + + reason: account.reason, + + + createDate: account.createdDate, + + + netSettlementAmount: { + + + amount: account.netAmount, + + + currency: account.currencyId + + + }, + + + participantId: pid, + + + key: account.key + + + } + + + + + 9 + + + Populate + + + settlementAccounts + + + + + alt + + + [state == 'PENDING_SETTLEMENT'] + + + + + settlementAccounts.pendingSettlementCount++ + + + + [state == 'PS_TRANSFERS_RECORDED'] + + + + + settlementAccounts.psTransfersRecordedCount++ + + + + [state == 'PS_TRANSFERS_RESERVED'] + + + + + settlementAccounts.psTransfersReservedCount++ + + + + [state == 'PS_TRANSFERS_COMMITTED'] + + + + + settlementAccounts.psTransfersCommittedCount++ + + + + [state == 'SETTLED'] + + + + + settlementAccounts.settledCount++ + + + + [state == 'ABORTED'] + + + + + settlementAccounts.abortedCount++ + + + + [default] + + + + + settlementAccounts.unknownCount++ + + + + + 10 + + + Make a copy of settlementAccounts into + + + settlementAccountsInit + + + + + settlementAccountsInit = Object.assign({}, settlementAccounts) + + + + + Available objects after the setup: + + + settlementAccounts + + + is used for tracing settlement state and state transition allowance + + + allAccounts + + + is helper object, same as previous, providing direct access to account by id + + + Now we are ready to process the + + + payload + + + : + + + participants + + + = [] // part of the response object that lists the affected participants and respective accounts + + + settlementParticipantCurrencyStateChange + + + = [] // array to collect inserts to the table + + + settlementParticipantCurrencySettledList + + + = [] // array to collect settled accounts + + + processedAccounts + + + = [] // array to log processed accounts and restrict subsequent processing + + + + + loop + + + [let participant IN payload.participants] + + + + + 11 + + + Loop payload for each + + + participantPayload + + + + + let participantPayload = payload.participants[participant] + + + participants.push({id: participantPayload.id, accounts: []}) + + + let pi = participants.length - 1 + + + participant = participants[pi] + + + + + loop + + + [let account IN participantPayload.accounts] + + + + + 12 + + + Loop payload for each + + + accountPayload + + + + + let accountPayload = participantPayload.accounts[account] + + + + + alt + + + [allAccounts[accountPayload.id] == undefined] + + + + + 13 + + + If the account doesn't match the settlement + + + + + participant.accounts.push({ + + + id: accountPayload.id, + + + errorInformation: { + + + errorCode: 3000, + + + errorDescription: 'Account not found' + + + } + + + }) + + + + [participantPayload.id != allAccounts[accountPayload.id].participantId] + + + + + 14 + + + If the account doesn't match the participant + + + + + participant.accounts.push({ + + + id: accountPayload.id, + + + errorInformation: { + + + errorCode: 3000, + + + errorDescription: 'Participant and account mismatch' + + + } + + + }) + + + + [processedAccounts.indexOf(accountPayload.id) > -1] + + + + + 15 + + + If the account has been previosly processed (duplicated in the payload) + + + + + participant.accounts.push({ + + + id: accountPayload.id, + + + state: allAccounts[accountPayload.id].state, + + + reason: allAccounts[accountPayload.id].reason, + + + createdDate: allAccounts[accountPayload.id].createdDate, + + + netSettlementAmount: allAccounts[accountPayload.id].netSettlementAmount + + + errorInformation: { + + + errorCode: 3000, + + + errorDescription: 'Account already processed once' + + + } + + + }) + + + + [allAccounts[account.id].state == accountPayload.state // allowed] + + + + + 16 + + + Same-state reason amendment is always allowed + + + + + processedAccounts.push(accountPayload.id) + + + participant.accounts.push({ + + + id: accountPayload.id, + + + state: accountPayload.state, + + + reason: accountPayload.reason, + + + externalReference: accountPayload.externalReference, + + + createdDate: transactionTimestamp, + + + netSettlementAmount: allAccounts[accountPayload.id].netSettlementAmount + + + }) + + + settlementParticipantCurrencyStateChange.push({ + + + settlementParticipantCurrencyId: allAccounts[accountPayload.id].key, + + + settlementStateId: accountPayload.state, + + + reason: accountPayload.reason, + + + externalReference: accountPayload.externalReference + + + }) + + + allAccounts[accountPayload.id].reason = accountPayload.reason + + + allAccounts[accountPayload.id].createdDate = currentTimestamp + + + + [settlementData.state == 'PENDING_SETTLEMENT' && accountPayload.state == 'PS_TRANSFERS_RECORDED'] + + + + [settlementData.state == 'PS_TRANSFERS_RECORDED' && accountPayload.state == 'PS_TRANSFERS_RESERVED'] + + + + [settlementData.state == 'PS_TRANSFERS_RESERVED' && accountPayload.state == 'PS_TRANSFERS_COMMITTED'] + + + + [settlementData.state == 'PS_TRANSFERS_COMMITTED' || settlementData.state == 'SETTLING' && accountPayload.state == 'SETTLED'] + + + + + Note + + + : Since we previously checked same-state, here we don't need to match + + + allAccounts[account.id].state == settlementData.state. + + + + + 17 + + + Settlement acknowledgement + + + + + processedAccounts.push(accountPayload.id) + + + participant.accounts.push({ + + + id: accountPayload.id, + + + state: accountPayload.state, + + + reason: accountPayload.reason, + + + externalReference: accountPayload.externalReference, + + + createdDate: transactionTimestamp, + + + netSettlementAmount: allAccounts[accountPayload.id].netSettlementAmount + + + }) + + + settlementParticipantCurrencyStateChange.push({ + + + settlementParticipantCurrencyId: allAccounts[accountPayload.id].key, + + + settlementStateId: accountPayload.state, + + + reason: accountPayload.reason, + + + externalReference: accountPayload.externalReference, + + + settlementTransferId: Uuid() -- only for PS_TRANSFERS_RECORDED + + + }) + + + if (accountPayload.state == 'PS_TRANSFERS_RECORDED') { + + + settlementAccounts.pendingSettlementCount-- + + + settlementAccounts.psTransfersRecordedCount++ + + + } else if (accountPayload.state == 'PS_TRANSFERS_RESERVED') { + + + settlementAccounts.psTransfersRecordedCount-- + + + settlementAccounts.psTransfersReservedCount++ + + + } else if (accountPayload.state == 'PS_TRANSFERS_COMMITTED') { + + + settlementAccounts.psTransfersReservedCount-- + + + settlementAccounts.psTransfersCommittedCount++ + + + } else if (accountPayload.state == 'SETTLED') { + + + settlementParticipantCurrencySettledIdList.push(allAccounts[accountPayload.id].key) + + + settlementAccounts.psTransfersCommittedCount-- + + + settlementAccounts.settledCount++ + + + settlementAccounts.settledIdList.push(accountPayload.id) + + + } + + + settlementAccounts.changedIdList.push(accountPayload.id) + + + allAccounts[accountPayload.id].state = accountPayload.state + + + allAccounts[accountPayload.id].reason = accountPayload.reason + + + allAccounts[accountPayload.id].externalReference = accountPayload.externalReference + + + allAccounts[accountPayload.id].createdDate = currentTimestamp + + + + + + 18 + + + All other state transitions are not permitted + + + + + participant.accounts.push({ + + + id: accountPayload.id, + + + state: allAccounts[accountPayload.id].state, + + + reason: allAccounts[accountPayload.id].reason, + + + createdDate: allAccounts[accountPayload.id].createdDate, + + + netSettlementAmount: allAccounts[accountPayload.id].netSettlementAmount + + + errorInformation: { + + + errorCode: <integer>, + + + errorDescription: 'State change not allowed' + + + } + + + }) + + + + + Bulk insert settlementParticipantCurrencyStateChange + + + + + 19 + + + Insert settlementParticipantCurrencyStateChange + + + + settlementParticipantCurrencyStateChange + + + + + 20 + + + Return + + + settlementParticipantCurrencyStateChangeIdList + + + + + 21 + + + Merge settlementParticipantCurrencyStateChangeIdList + + + to + + + settlementParticipantCurrencyIdList + + + in order to + + + issue the following update in one knex command + + + + + 22 + + + Update pointers to current state change ids + + + + UPDATE + + + settlementParticipantCurrency + + + SET currentStateChangeId = + + + {settlementParticipantCurrencyStateChangeIdList}, + + + settlementTransferId = + + + settlementParticipantCurrencyStateChange.settlementTransferId + + + -- only for PENDING_SETTLEMENT to PS_TRANSFERS_RECORDED + + + WHERE settlementParticipantCurrencyId = + + + {settlementParticipantCurrencyStateChange + + + .settlementParticipantCurrencyIdList} + + + + + opt + + + [autoPositionReset == true] + + + + + alt + + + [settlementData.state == 'PENDING_SETTLEMENT'] + + + + + ref + + + Settlement Transfer Prepare + + + Inputs + + + : settlementId, transactionTimestamp, enums, trx + + + + [settlementData.state == 'PS_TRANSFERS_RECORDED'] + + + + + ref + + + Settlement Transfer Reserve + + + Inputs + + + : settlementId, transactionTimestamp, enums, trx + + + + [settlementData.state == 'PS_TRANSFERS_RESERVED'] + + + + + ref + + + Settlement Transfer Commit + + + Inputs + + + : settlementId, transactionTimestamp, enums, trx + + + + + Update aggregations, contents & windows + + + + + opt + + + [settlementParticipantCurrencySettledIdList.length > 0] + + + + + 23 + + + Change settlementWindowState where applicable + + + + settlementContentAggregation + + + transferParticipantStateChange + + + transferParticipant + + + settlementWindowContentStateChange + + + settlementWindowContent + + + settlementWindowStateChange + + + settlementWindow + + + + + 24 + + + Retrieve all affected content (incl. when settled) + + + + settlementContentAggregation + + + settlementWindowContent + + + settlementWindowContentStateChange + + + ledgerAccountType + + + settlementWindow + + + settlementWindowStateChange + + + + + 25 + + + Return + + + affectedWindowsReport + + + + + 26 + + + Use previous result to produce settlementWindowsData ( + + + swd + + + ) array + + + + + Prepare and insert settlementStateChange + + + + + let settlementStateChanged = true + + + + + alt + + + [settlementData.state == 'PENDING_SETTLEMENT' + + + && settlementAccounts.pendingSettlementCount == 0] + + + + + settlementData.state = 'PS_TRANSFERS_RECORDED' + + + settlementData.reason = 'All settlement accounts are PS_TRANSFERS_RECORDED' + + + + [settlementData.state == 'PS_TRANSFERS_RECORDED' + + + && settlementAccounts.psTransfersRecordedCount == 0] + + + + + settlementData.state = 'PS_TRANSFERS_RESERVED' + + + settlementData.reason = 'All settlement accounts are PS_TRANSFERS_RESERVED' + + + + [settlementData.state == 'PS_TRANSFERS_RESERVED' + + + && settlementAccounts.psTransfersReservedCount == 0] + + + + + settlementData.state = 'PS_TRANSFERS_COMMITTED' + + + settlementData.reason = 'All settlement accounts are PS_TRANSFERS_COMMITTED' + + + + [settlementData.state == 'PS_TRANSFERS_COMMITTED' + + + && settlementAccounts.psTransfersCommittedCount > 0 + + + && settlementAccounts.settledCount > 0] + + + + + settlementData.state = 'SETTLING' + + + settlementData.reason = 'Some settlement accounts are SETTLED' + + + + [(settlementData.state == 'PS_TRANSFERS_COMMITTED' || settlementData.state == 'SETTLING') + + + && settlementAccounts.psTransfersCommittedCount == 0] + + + + + settlementData.state = 'SETTLED' + + + settlementData.reason = 'All settlement accounts are SETTLED' + + + + + + settlementStateChanged = false + + + + + opt + + + [settlementStateChanged == true] + + + + + settlementData.createdDate = currentTimestamp + + + settlementStateChange.push(settlementData) + + + + + 27 + + + Insert settlementStateChange + + + + settlementStateChange + + + + + 28 + + + Return + + + settlementStateChangeId + + + + + 29 + + + Update pointer to current state change id + + + + UPDATE + + + settlement + + + .currentStateChangeId + + + + + 30 + + + Return transaction result + + + + + { + + + "id": {id}, + + + "state": settlementData.state, + + + "createdDate": settlementData.createdDate, + + + "settlementWindows": [ + + + { + + + "id": swd[m].id, + + + "state": swd[m].state, + + + "reason": swd[m].reason, + + + "createdDate": swd[m].createdDate, + + + "changedDate": swd[m].changedDate, + + + "content": [ + + + { + + + "id": swd[m].content[n].settlementWindowContentId, + + + "state": swd[m].content[n].settlementWindowStateId, + + + "ledgerAccountType": swd[m].content[n].ledgerAccountType, + + + "currencyId": swd[m].content[n].currencyId, + + + "createdDate": swd[m].content[n].createdDate, + + + "changedDate": swd[m].content[n].changedDate + + + } + + + ] + + + } + + + ], + + + "participants": [ + + + { + + + "id": <integer>, + + + "accounts": [ + + + { + + + "id": <integer>, + + + "state": "<string>, + + + "reason": <string>, + + + "externalReference": <string>, + + + "createdDate": <date>, + + + "netSettlementAmount": { + + + "amount": <decimal>, + + + "currency": <enum> + + + } + + + }, + + + { + + + "id": <integer>, + + + "state": <string>, + + + "reason": <string>, + + + "createdDate": <date>, + + + "netSettlementAmount": { + + + "amount": <decimal>, + + + "currency": <enum> + + + }, + + + "errorInformation": { + + + "errorCode": <integer>, + + + "errorDescription": <string> + + + } + + + } + + + ] + + + } + + + ] + + + } + + + + + 31 + + + Return response + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.6.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.6.svg new file mode 100644 index 000000000..38256e7a0 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-settlement-6.2.6.svg @@ -0,0 +1,801 @@ + + + + + + + + + + + 6.2.6. Settlement Abort (abortSettlementById) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Settlement Abort + + + + + { + + + "state": "ABORTED", + + + "reason": {abortReasonString} + + + } + + + + + 1 + + + PUT - /settlement/{id} + + + + + 2 + + + abortSettlementById facade method + + + Error code: + + + 2001 + + + + + 3 + + + Retrieve settlement information + + + + SELECT s.settlementId, ssc.settlementStateId, + + + ssc.reason, ssc.createdDate + + + FROM + + + settlement + + + s + + + JOIN + + + settlementStateChange + + + ssc + + + ON ssc.settlementStateChangeId = s.currentStateChangeId + + + WHERE s.settlementId = {id} + + + + + 4 + + + Return + + + settlementData + + + + + alt + + + [settlementData.settlementStateId == 'PS_TRANSFERS_COMMITTED'|| + + + settlementData.settlementStateId == 'SETTLING'|| + + + settlementData.settlementStateId == 'SETTLED'] + + + + + break + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "State change is not allowed" + + + } + + + } + + + + [settlementData.settlementStateId == 'ABORTED'] + + + + + break + + + + + 5 + + + Append additional info at settlement level + + + + INSERT INTO + + + settlementStateChange + + + (settlementId, settlementStateId, reason) + + + VALUES ({id}, 'ABORTED', {abortReasonString}) + + + + + { + + + "id": {id}, + + + "state": 'ABORTED', + + + "reason": {abortReasonString} + + + } + + + + [settlementData.settlementStateId == 'PS_TRANSFERS_RESERVED'] + + + + + 6 + + + Find account in PS_TRANSFERS_COMMITTED + + + + SELECT spc.participantCurrencyId + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + settlementParticipantCurrencyStateChange + + + spcsc + + + ON spcsc.settlementParticipantCurrencyStateChangeId = spc.currentStateChangeId + + + WHERE spc.settlementId = {id} + + + AND spcsc.settlementStateId = 'PS_TRANSFERS_COMMITTED' + + + LIMIT 1 + + + + + 7 + + + Return + + + transferCommittedAccount + + + + + break + + + [transferCommittedAccount != undefined] + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "At least one settlement transfer is committed" + + + } + + + } + + + + + DB TRANSACTION + + + + + 8 + + + Retrive settlement accounts information + + + + SELECT pc.participantId, spc.participantCurrencyId, + + + spcsc.settlementStateId, spcsc.reason, + + + spcsc.createdDate, spc.netAmount, pc.currencyId, + + + spc.settlementParticipantCurrencyId AS + + + key + + + FROM + + + settlementParticipantCurrency + + + spc + + + JOIN + + + settlementParticipantCurrencyStateChange + + + spcsc + + + ON spcsc.settlementParticipantCurrencyStateChangeId = + + + spc.currentStateChangeId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = spc.participantCurrencyId + + + WHERE spc.settlementId = {id} + + + FOR UPDATE + + + + + 9 + + + Return + + + settlementAccountsList + + + + + 10 + + + Retrive settlement windows information + + + + SELECT ssw.settlementWindowId, swsc.settlementWindowStateId, + + + swsc.reason, swsc.createdDate + + + FROM + + + settlementSettlementWindow + + + ssw + + + JOIN + + + settlementWindow + + + sw + + + ON sw.settlementWindow = ssw.settlementWindowId + + + JOIN + + + settlementWindowStateChange + + + swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + WHERE ssw.settlementId = {id} + + + FOR UPDATE + + + + + 11 + + + Return + + + windowsList + + + + + Bulk insert settlementParticipantCurrencyStateChange + + + + + 12 + + + Insert settlementParticipantCurrencyStateChange + + + + settlementParticipantCurrencyStateChange + + + + + 13 + + + Return + + + spcscIdList + + + + + 14 + + + Merge spcscIdList into settlementAccountsList + + + + + 15 + + + Update all pointers to current state change ids + + + + UPDATE + + + settlementParticipantCurrency + + + .currentStateChangeIds + + + + + ref + + + Settlement Transfer Abort + + + Inputs + + + : settlementId, transactionTimestamp, enums, trx + + + + + Bulk insert and reset contents & aggregations + + + + + 16 + + + Bulk insert aborted state + + + + settlementWindowContentStateChange + + + + + 17 + + + Return + + + swcscIdList + + + + + 18 + + + Merge swcscIdList + + + + + 19 + + + Update current state references and reset settlementId + + + + settlementWindowContent + + + .currentStateChangeIds + + + .settlementId + + + settlementContentAggregation + + + .settlementId + + + + + Bulk insert settlementWindowStateChange + + + + + 20 + + + Insert settlementWindowStateChange + + + + settlementWindowStateChange + + + + + 21 + + + Return + + + swscIdList + + + + + 22 + + + Merge swscIdList into windowList + + + + + 23 + + + Update all pointers to current state change ids + + + + UPDATE + + + settlementWindow + + + .currentStateChangeIds + + + + + Insert settlementStateChange + + + + + 24 + + + Insert settlementStateChange + + + + INSERT INTO + + + settlementStateChange + + + (settlementId, settlementStateId, reason) + + + VALUES ({id}, 'ABORTED', {abortReasonString}) + + + + + 25 + + + Return + + + settlementStateChangeId + + + + + 26 + + + Update pointer to current state change id + + + + UPDATE + + + settlement + + + .currentStateChangeId + + + + + 27 + + + Return facade method result + + + + + alt + + + [success] + + + + + { + + + "id": {id}, + + + "state": 'ABORTED', + + + "reason": {abortReasonString} + + + } + + + + + 28 + + + Respond HTTP - 200 (OK) + + + + + + Log ERROR event + + + + + { + + + errorInformation: { + + + "errorCode": <integer>, + + + "errorDescription": "Client/Server error description" + + + } + + + } + + + + + 29 + + + Respond HTTP 4xx or 5xx + + + (Client/Server error) + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.1.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.1.svg new file mode 100644 index 000000000..7ce3f9839 --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.1.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + 6.1.1. Request Settlement Window By Id (getSettlementWindowById) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Request Settlement Window + + + + + 1 + + + GET - /settlementWindows/{id} + + + + + 2 + + + Request settlementWindow by id + + + Error code: + + + 2001 + + + + + 3 + + + Select from DB + + + + SELECT sw.settlementWindowId, swsc.settlementWindowStateId, + + + swsc.reason, sw.createdDate, swsc.createdDate changedDate + + + FROM + + + settlementWindow + + + AS sw + + + JOIN + + + settlementWindowStateChange + + + AS swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + WHERE sw.settlementWindowId = {id} + + + + + 4 + + + Return + + + data + + + + + alt + + + [settlementWindow found] + + + + + 5 + + + Request settlementWindowContent(s) + + + Error code: + + + 2001 + + + + + 6 + + + Select from DB + + + + settlementWindowContent + + + settlementWindowContentStateChange + + + ledgerAccountType + + + + + 7 + + + Return + + + contentList + + + + + { + + + "id": data.settlementWindowId, + + + "state": data.settlementWindowStateId, + + + "reason": data.reason, + + + "createdDate": data.createdDate, + + + "changedDate": data.changedDate, + + + "content": [ + + + { + + + "id": contentList.settlementWindowContentId, + + + "state": contentList.settlementWindowStateId, + + + "ledgerAccountType": contentList.ledgerAccountType, + + + "currencyId": contentList.currencyId, + + + "createdDate": contentList.createdDate, + + + "changedDate": contentList.changedDate, + + + "settlementId": contentList.settlementId + + + } + + + ] + + + } + + + + + 8 + + + Respond HTTP - 200 (OK) + + + + + + Log ERROR event + + + + + { + + + "errorInformation": { + + + "errorCode": <integer>, + + + "errorDescription": <string> + + + } + + + } + + + + + 9 + + + Respond HTTP - 4xx (Client error) + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.2.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.2.svg new file mode 100644 index 000000000..6e7e3ea3f --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.2.svg @@ -0,0 +1,1073 @@ + + + + + + + + + + + 6.1.2. Close Settlement Window (closeSettlementWindow) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + + + topic- + + + settlement-window + + + + + topic- + + + settlement-window + + + Settlement Window + + + Handler + + + + + Settlement Window + + + Handler + + + + + + + topic-event + + + + + topic-event + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Close Settlement Window + + + + + { + + + "state": "CLOSED", + + + "reason": <string> + + + } + + + + + 1 + + + POST - /settlementWindows/{id} + + + + + 2 + + + Validate payload, existing window, + + + state, assigned transfers, etc. + + + + + break + + + + + { + + + "errorInformation": { + + + "errorCode": <integer>, + + + "errorDescription": "FSPIOP Error Description" + + + } + + + } + + + + + 3 + + + Respond HTTP - 400 (Bad Request) + + + + + 4 + + + Get requested settlementWindow and state + + + Error code: + + + 2001 + + + + + 5 + + + Get settlementWindow state + + + + SELECT sw.settlementWindowId, swsc.settlementWindowStateId, + + + swsc.reason, sw.createdDate, swsc.createdDate changedDate + + + FROM + + + settlementWindow + + + AS sw + + + JOIN + + + settlementWindowStateChange + + + AS swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + WHERE sw.settlementWindowId = {id} + + + + + 6 + + + Return result + + + + + alt + + + [settlementWindow found && settlementWindowStateId == 'OPEN'] + + + + + Process settlement window + + + + + 7 + + + Terminate current window and open a new one + + + Error code: + + + 2001 + + + + + DB TRANSACTION: Terminate window usage and initate next + + + + + let + + + transactionTimestamp + + + = now() + + + + + 8 + + + Terminate requested window + + + + INSERT INTO + + + settlementWindowStateChange + + + (settlementWindowId, settlementWindowStateId, reason, createdDate) + + + VALUES ({id}, 'PROCESSING', {payload.reason}, {transactionTimestamp}) + + + + + 9 + + + Return + + + settlementWindowStateChangeId + + + + + 10 + + + Update pointer to current state change id + + + + UPDATE + + + settlementWindow + + + SET currentStateChangeId = {settlementWindowStateChangeId} + + + WHERE settlementWindowId = {id} + + + + + 11 + + + Create new settlementWindow + + + + INSERT INTO + + + settlementWindow + + + (reason, createdDate) + + + VALUES ({payload.reason}, {transactionTimestamp}) + + + + + 12 + + + Return + + + settlementWindowId + + + + + 13 + + + Insert intial state for the created window + + + + INSERT INTO + + + settlementWindowStateChange + + + (settlementWindowId, settlementWindowStateId, reason, createdDate) + + + VALUES ({settlementWindowId}, 'OPEN', {payload.reason}, {transactionTimestamp}) + + + + + 14 + + + Return + + + newSettlementWindowStateChangeId + + + + + 15 + + + Update pointer to current state change id + + + + UPDATE + + + settlementWindow + + + SET currentStateChangeId = {newSettlementWindowStateChangeId} + + + WHERE settlementWindowId = {settlementWindowId} + + + + + 16 + + + Return success + + + + + Message: + + + { + + + id: <uuid> + + + from: switch, + + + to: switch, + + + type: application/json + + + content: { + + + payload: { + + + settlementWindowId: {id} + + + } + + + }, + + + metadata: { + + + event: { + + + id: <uuid>, + + + responseTo: null, + + + type: setwin, + + + action: close, + + + createdAt: <timestamp>, + + + state: { + + + status: "success", + + + code: 0 + + + } + + + } + + + } + + + } + + + + + 17 + + + Produce Settlement Window + + + event message + + + Error codes: + + + 2003 + + + + + { + + + "id": settlementWindowId, + + + "state": 'OPEN', + + + "reason": payload.reason, + + + "createdDate": transactionTimestamp, + + + "changedDate": transactionTimestamp + + + } + + + + + 18 + + + Respond HTTP - 201 (Created) + + + + + Close settlement window (SettlementWindowHandler) + + + + + 19 + + + Consume Settlement Window + + + event message + + + + + Persist Event Information + + + + + 20 + + + Publish event information + + + + + ref + + + Event Handler Consume + + + + + let + + + id + + + = message.content.payload.settlementWindowId + + + let + + + windowContentReady + + + = false + + + let + + + iter + + + = 0 + + + + + loop + + + [iter < Config.WIN_AGGREGATION_RETRY_COUNT && !windowContentReady] + + + + + iter++ + + + + + 21 + + + Check if all transferParticipant records + + + for the requested window have been set + + + (currentStateChangeId is NOT NULL). + + + Error code: + + + 2001 + + + + + 22 + + + Use EXISTS query to find NULL currentStateChangeId records + + + + transferFulfilment + + + transferParticipant + + + + + 23 + + + Return result (success / failure) + + + + + opt + + + [transferParticipant records have been processed by central-ledger SettlementModelHandler] + + + + + 24 + + + Generate window content and aggregations + + + Error code: + + + 2001 + + + + + DB TRANSACTION: Generate window content and aggregations + + + + + let + + + transactionTimestamp + + + = now() + + + + + 25 + + + Change all applicable entries to CLOSED state + + + + transferParticipantStateChange + + + transferParticipant + + + + + 26 + + + Determine window content and insert + + + + INSERT INTO + + + settlementWindowContent + + + (settlementWindowId, ledgerAccountTypeId, + + + currencyId, createdDate) + + + SELECT DISTINCT {id} settlementWindowId, pc.ledgerAccountTypeId, + + + pc.currencyId, transactionTimestamp + + + FROM + + + transferFulfilment + + + tf + + + JOIN + + + transferParticipant + + + tp + + + ON tp.transferId = tf.transferId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = tp.participantCurrencyId + + + WHERE tf.settlementWindowId = {id} + + + + + 27 + + + Aggregate window data and insert + + + + INSERT INTO + + + settlementContentAggregation + + + (settlementWindowContentId, participantCurrencyId, + + + transferParticipantRoleTypeId, ledgerEntryTypeId, currentStateId, createdDate, amount) + + + SELECT swc.settlementWindowContentId, pc.participantCurrencyId, tp.transferParticipantRoleTypeId, + + + tp.ledgerEntryTypeId, 'CLOSED', transactionTimestamp, SUM(tp.amount) + + + FROM + + + transferFulfilment + + + tf + + + JOIN + + + transferParticipant + + + tp + + + ON tf.transferId = tp.transferId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = tp.participantCurrencyId + + + JOIN + + + settlementWindowContent + + + swc + + + ON swc.settlementWindowId = tf.settlementWindowId + + + AND swc.ledgerAccountTypeId = pc.ledgerAccountTypeId + + + AND swc.currencyId = pc.currencyId + + + WHERE ttf.settlementWindowId = {id} + + + GROUP BY swc.settlementWindowContentId, pc.participantCurrencyId, + + + tp.transferParticipantRoleTypeId, tp.ledgerEntryTypeId + + + + + 28 + + + Insert initial window content state change + + + + INSERT INTO + + + settlementWindowContentStateChange + + + (settlementWindowContentId, settlementWindowStateId) + + + SELECT swc.settlementWindowContentId, 'CLOSED' + + + FROM + + + settlementWindowContent + + + swc + + + WHERE swc.settlementWindowId = {id} + + + + + 29 + + + Update pointers to current state change ids + + + + settlementWindowContent + + + + + 30 + + + Return result (success / failure) + + + + + alt + + + [success] + + + + + windowContentReady = true + + + + + 31 + + + Close requested window + + + Error code: + + + 2001 + + + + + 32 + + + Change window state to 'CLOSED' + + + + settlementWindowStateChange + + + settlementWindow.currentStateChangeId + + + + [failure && iter < Config.WIN_AGGREGATION_RETRY_COUNT] + + + + + sleep + + + Config.WIN_AGGREGATION_RETRY_INTERVAL seconds + + + + [failure] + + + + + 33 + + + Fail requested window + + + Error code: + + + 2001 + + + + + 34 + + + Change window state to 'FAILED' + + + + settlementWindowStateChange + + + settlementWindow.currentStateChangeId + + + + 35 + + + Log ERROR event + + + + + 36 + + + Log ERROR event + + + + + { + + + "errorInformation": { + + + "errorCode": <integer>, + + + "errorDescription": "Client error description" + + + } + + + } + + + + + 37 + + + Respond HTTP - 4xx (Client error) + + diff --git a/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.3.svg b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.3.svg new file mode 100644 index 000000000..090e598ac --- /dev/null +++ b/mojaloop-technical-overview/central-settlements/settlement-process/assets/diagrams/sequence/seq-setwindow-6.1.3.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + 6.1.3. Get Settlement Windows By Parameters (getSettlementWindowsByParams) + + + + Central HUB + + + + Settlement Service + + + + Central Services + + + + + + + + Hub Employee + + + + + Hub Employee + + + + + Settlement Service API + + + + + Settlement Service API + + + + + Settlement DAO + + + + + Settlement DAO + + + + + Central Store + + + + + Central Store + + + + + + + + Get Settlement Windows By Parameters + + + + + Params: + + + ?participantId={participantId} + + + &state={state} + + + &fromDateTime={fromDateTime} + + + &toDateTime={toDateTime} + + + + + 1 + + + GET - /settlementWindows/{params} + + + + + 2 + + + Request settlementWindow + + + Error code: + + + 2001 + + + + + 3 + + + Request settlementWindows + + + + SELECT DISTINCT sw.settlementId, swsc.settlementWindowStateId, + + + swsc.reason, sw.createdDate, swsc.createdDate changedDate + + + FROM + + + settlementWindow + + + sw + + + JOIN + + + settlementWindowStateChange + + + swsc + + + ON swsc.settlementWindowStateChangeId = sw.currentStateChangeId + + + JOIN + + + transferFulfilment + + + tf + + + ON tf.settlementWindowId = sw.settlementWindowId + + + JOIN + + + transferParticipant + + + tp + + + ON tp.transferId = tf.transferId + + + JOIN + + + participantCurrency + + + pc + + + ON pc.participantCurrencyId = tp.participantCurrencyId + + + [WHERE pc.participantId = {participantId}] + + + [AND swsc.settlementWindowStateId = {state}] + + + [AND sw.createdDate >= {fromDateTime}] + + + [AND sw.createdDate <= {toDateTime}] + + + + + 4 + + + Return data + + + + + 5 + + + Return + + + settlementWindows + + + + + alt + + + [One or more records found] + + + + + [ + + + { + + + "id": settlementWindow.settlementId, + + + "state": settlementWindow.settlementWindowStateId, + + + "reason": settlementWindow.reason, + + + "createdDate": settlementWindow.createdDate, + + + "changedDate": settlementWindow.changedDate + + + } + + + ] + + + + + 6 + + + Respond HTTP - 200 (OK) + + + + + + Log ERROR event + + + + + { + + + "errorInformation": { + + + "errorCode": <integer>, + + + "errorDescription": "Client error description" + + + } + + + } + + + + + 7 + + + Respond HTTP - 4xx (Client error) + + diff --git a/mojaloop-technical-overview/event-stream-processor/assets/diagrams/sequence/process-flow.svg b/mojaloop-technical-overview/event-stream-processor/assets/diagrams/sequence/process-flow.svg new file mode 100644 index 000000000..0919b3c48 --- /dev/null +++ b/mojaloop-technical-overview/event-stream-processor/assets/diagrams/sequence/process-flow.svg @@ -0,0 +1,1028 @@ + + + + + + + + + + + Event Streaming Processor flow + + + + Central Services + + + + Event Stream Processor + + + + Cache + + + + Elasticsearch + + + + + + + + + + + + + + + + + + + + + + + + Notification topic + + + + + Notification topic + + + Topic Observable + + + + + Topic Observable + + + + + Tracing Observable + + + + + Tracing Observable + + + + + Caching Observable + + + + + Caching Observable + + + + + Check For Last Span Observable + + + + + Check For Last Span Observable + + + + + Create Trace Observable + + + + + Create Trace Observable + + + + + Send Trace Handler + + + + + Send Trace Handler + + + + + Send Span Handler + + + + + Send Span Handler + + + + + Cache Handler + + + + + Cache Handler + + + + + Cache Storage + + + + + Cache Storage + + + + + APM + + + + + APM + + + + + Elasticsearch API + + + + + Elasticsearch API + + + + + + + + New Event Message Received + + + + + 1 + + + Consume Event Message + + + + + Message: + + + { + + + "from": "payeefsp", + + + "to": "payerfsp", + + + "id": "659ee338-c8f8-4c06-8aff-944e6c5cd694", + + + "content": { + + + "headers": { + + + "content-type": "applicationvnd.interoperability.transfers+json;version=1.0", + + + "date": "2019-05-28T16:34:41.000Z", + + + "fspiop-source": "payeefsp", + + + "fspiop-destination": "payerfsp" + + + }, + + + "payload": <payload> + + + }, + + + "type": "application/json", + + + "metadata": { + + + "event": { + + + "id": "3920382d-f78c-4023-adf9-0d7a4a2a3a2f", + + + "type": "trace", + + + "action": "span", + + + "createdAt": "2019-05-29T23:18:32.935Z", + + + "state": { + + + "status": "success", + + + "code": 0, + + + "description": "action successful" + + + }, + + + "responseTo": "1a396c07-47ab-4d68-a7a0-7a1ea36f0012" + + + }, + + + "trace": { + + + "service": "central-ledger-prepare-handler", + + + "traceId": "bbd7b2c7bbd7b2c7", + + + "parentSpanId": "44ba9bbc5840", + + + "spanId": "2aa9cd0a7e87", + + + "startTimestamp": "2015-08-29T11:22:09.815479Z", + + + "finishTimestamp": "2015-08-29T11:22:09.815479Z", + + + "tags": { + + + "transctionId": "659ee338-c8f8-4c06-8aff-944e6c5cd694", + + + "transctionType": "transfer", + + + "parentEventType": "bulk-prepare", + + + "parentEventAction": "prepare" + + + } + + + } + + + } + + + } + + + + + 2 + + + Send message for log purposes to custom index + + + + + 3 + + + Verify its tracing event Message + + + + + 4 + + + Send Message to Tracing Observable + + + + + Cache Span + + + + + 5 + + + Send Span Context, + + + metadata.State and Content + + + from Message + + + + + { + + + spanContext: { + + + service: "central-ledger-prepare-handler", + + + traceId: "bbd7b2c7bbd7b2c7", + + + parentSpanId: "44ba9bbc5840", + + + spanId: "2aa9cd0a7e87", + + + startTimestamp: "2015-08-29T11:22:09.815479Z", + + + finishTimestamp: "2015-08-29T11:22:09.815479Z", + + + tags: { + + + transctionId: "659ee338-c8f8-4c06-8aff-944e6c5cd694", + + + transctionType: "transfer", + + + parentEventType: "bulk-prepare", + + + parentEventAction: "prepare" + + + }, + + + state: metadata.state, + + + content + + + } + + + + + 6 + + + Get cachedTrace by traceId + + + + + alt + + + [the span should not be cached] + + + + + 7 + + + currentSpan + + + + + 8 + + + store to APM + + + + + 9 + + + Complete + + + + + + 10 + + + Validate transactionType, TransactionAction and service to match Config.START_CRITERIA && !parentSpandId + + + + + alt + + + [!cachedTrace] + + + + + 11 + + + Create new cachedTrace + + + + + { + + + spans: {}, + + + masterSpan: null, + + + lastSpan: null + + + } + + + + + alt + + + [!parentSpan] + + + + + 12 + + + Generate MasterSpanId + + + + + 13 + + + Make received span child of masterSpan + + + merge({ parentSpanId: MasterSpanId }, { ...spanContext }) + + + + + 14 + + + Create MasterSpanContext merge({ tags: { ...tags, masterSpan: MasterSpanId } }, + + + { ...spanContext }, + + + { spanId: MasterSpanId, service: `master-${tags.transactionType}` }) + + + + + 15 + + + Add masterSpan to cachedTrace + + + + + 16 + + + Add span to cachedTrace + + + + + { + + + spans: { + + + 2aa9cd0a7e87: { + + + state, + + + content + + + spanContext: { + + + "service": "central-ledger-prepare-handler", + + + "traceId": "bbd7b2c7bbd7b2c7", + + + "parentSpanId": + + + MasterSpanId + + + , + + + "spanId": "2aa9cd0a7e87", + + + "startTimestamp": "2015-08-29T11:22:09.815479Z", + + + "finishTimestamp": "2015-08-29T11:22:09.815479Z", + + + "tags": { + + + "transctionId": "659ee338-c8f8-4c06-8aff-944e6c5cd694", + + + "transctionType": "transfer", + + + "parentEventType": "bulk-prepare", + + + "parentEventAction": "prepare" + + + } + + + } + + + }, + + + MasterSpanId: + + + { + + + state, + + + content, + + + MasterSpanContext + + + } + + + }, + + + masterSpan: + + + MasterSpanContext + + + , + + + lastSpan: null + + + } + + + + + 17 + + + Update cachedTrace to Cache + + + + + alt + + + [cachedTrace not staled or expired] + + + + + 18 + + + unsubscribe from Scheduler + + + + + 19 + + + record cachedTrace + + + + + 20 + + + Reschedule scheduler for handling stale traces + + + + + 21 + + + Send traceId to check if last span has been received + + + and cached + + + + + Check for last span + + + + + 22 + + + Get cachedTrace by traceId + + + + + 23 + + + Sort spans by startTimestamp + + + + + loop + + + [for currentSpan of SortedSpans] + + + + + alt + + + [parentSpan] + + + + + 24 + + + isError = (errorCode in parentSpan + + + OR parentSpan status === failed + + + OR status === failed) + + + + + 25 + + + apply masterSpan and error tags from parent to current span in cachedTrace + + + + + alt + + + [!isLastSpan] + + + + + 26 + + + Update cachedTrace to Cache + + + + + alt + + + [cachedTrace not staled or expired] + + + + + 27 + + + unsubscribe from Scheduler + + + + + 28 + + + record cachedTrace + + + + + 29 + + + Reschedule scheduler for handling stale traces + + + + + + 30 + + + Validate transactionType, TransactionAction, service and isError + + + to match Config.START_CRITERIA && !parentSpandId + + + + + 31 + + + cachedTrace.lastSpan = currentSpan.spanContext + + + + + 32 + + + Update cachedTrace to Cache + + + + + alt + + + [cachedTrace not staled or expired] + + + + + 33 + + + unsubscribe from Scheduler + + + + + 34 + + + record cachedTrace + + + + + 35 + + + Reschedule scheduler for handling stale traces + + + + + 36 + + + Send traceId + + + + + Recreate Trace from Cached Trace + + + + + 37 + + + get cachedTrace by TraceId + + + + + alt + + + [cachedTrace.lastSpan AND cachedTrace.masterSpan] + + + + + 38 + + + currentSpan = lastSpan + + + + + 39 + + + resultTrace = [lastSpan] + + + + + loop + + + [for i = 0; i < cachedTrace.spans.length; i++] + + + + + 40 + + + get parentSpan of currentSpan + + + + + alt + + + [parentSpan] + + + + + 41 + + + insert parent span in resultTrace in front + + + + + + 42 + + + break loop + + + + + alt + + + [cachedTrace.masterSpan === currentSpan.spanId] + + + + + 43 + + + masterSpan.finishTimestamp = resultTrace[resultTrace.length - 1].finishTimestamp + + + + + 44 + + + send resultTrace + + + + + send Trace + + + + + loop + + + [trace elements] + + + + + 45 + + + send each span + + + + + 46 + + + send span to APM + + + + + 47 + + + unsubscribe scheduler for traceId + + + + + 48 + + + drop cachedTrace + + diff --git a/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-get-bulk-quotes-2.1.0.svg b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-get-bulk-quotes-2.1.0.svg new file mode 100644 index 000000000..9cab870cb --- /dev/null +++ b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-get-bulk-quotes-2.1.0.svg @@ -0,0 +1,369 @@ + + + + + + + + + + + Retrieve Bulk Quote Information + + + + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + [Quoting Service] + + + + Switch + + + [Quoting Service] + + + + Payee FSP + + + + Payee FSP + + + + + Payer FSP sends request to get bulk quote details + + + to Payee FSP via the Switch + + + + + 1 + + + GET /bulkQuotes/{ID} + + + + + Validate request against + + + Mojaloop interface specification + + + Error code: 300x, 310x + + + HTTP error response code: 4xx + + + + + 2 + + + Schema validation + + + + + 3 + + + 202 Accepted + + + + + 4 + + + Retrieve bulk quotes endpoint for Payee FSP + + + + + alt + + + [Payee FSP quotes endpoint is found] + + + + + Switch forwards request to Payee FSP (pass-through mode) + + + + + 5 + + + GET /bulkQuotes/{ID} + + + + + 6 + + + 202 Accepted + + + + + 7 + + + Payee FSP retireves bulk quote + + + + + alt + + + [Payee FSP successfully retieves quote] + + + + + Payee FSP responds to quote request + + + + + 8 + + + PUT /quotes/{ID} + + + + + Validate request against + + + Mojaloop interface specification + + + Error code: 300x, 310x + + + HTTP error response code: 4xx + + + + + 9 + + + 200 Ok + + + + + alt + + + [Response is ok] + + + + + 10 + + + Retrieve bulk quotes endpoint for the Payer FSP + + + + + alt + + + [Bulk Quotes callback endpoint found] + + + + + Switch forwards bulk quote response to Payer FSP + + + + + 11 + + + PUT /bulkQuotes/{ID} + + + + + 12 + + + 200 Ok + + + + [Bulk Quotes callback endpoint not found] + + + + + Switch returns error to Payee FSP + + + + + 13 + + + PUT /bulkQuotes/{ID}/error + + + + + 14 + + + 200 Ok + + + + [Response is invalid] + + + + + Switch returns error to Payee FSP + + + + + 15 + + + PUT /bulkQuotes/{ID}/error + + + + + 16 + + + 200 Ok + + + + + Note that under this + + + scenario the Payer FSP + + + may not receive a response + + + + [bulkQuote not found] + + + + + Payee FSP returns error to Switch + + + Error code: 3205 + + + + + 17 + + + PUT /bulkQuotes/{ID}/error + + + + + 18 + + + 200 OK + + + + + Switch returns error to Payer FSP + + + Error code: 3205 + + + + + 19 + + + PUT /bulkQuotes/{ID}/error + + + + + 20 + + + 200 OK + + + + [Payee FSP Bulk quotes endpoint is not found] + + + + + Switch returns error to Payer FSP + + + Error code: 3201 + + + + + 21 + + + PUT /bulkQuotes/{ID}error + + + + + 22 + + + 200 OK + + diff --git a/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-get-quotes-1.1.0.svg b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-get-quotes-1.1.0.svg new file mode 100644 index 000000000..679d20f98 --- /dev/null +++ b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-get-quotes-1.1.0.svg @@ -0,0 +1,496 @@ + + + + + + + + + + + Retrieve Quote Information + + + + + + + + + + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + [Quoting + + + Service] + + + + Switch + + + [Quoting + + + Service] + + + Central Store + + + + + Central Store + + + + + + Payee FSP + + + + Payee FSP + + + + + + Payer FSP sends request to get quote details + + + to Payee FSP via the Switch + + + + + 1 + + + GET /quotes/{ID} + + + + + Validate request against + + + Mojaloop interface specification + + + Error code: 300x, 310x + + + HTTP error response code: 4xx + + + + + 2 + + + Schema validation + + + + + 3 + + + 202 Accepted + + + + + 4 + + + Retrieve quotes endpoint for Payee FSP + + + + + alt + + + [Payee FSP quotes endpoint is found] + + + + + Switch forwards request to Payee FSP (pass-through mode) + + + <Payer based Rules> + + + + + 5 + + + GET /quotes/{ID} + + + + + 6 + + + 202 Accepted + + + + + 7 + + + Payee FSP retireves quote + + + + + alt + + + [Payee FSP successfully retieves quote] + + + + + Payee FSP responds to quote request + + + + + 8 + + + PUT /quotes/{ID} + + + + + 9 + + + 200 Ok + + + + + 10 + + + Validate response (schema, headers ( + + + Error code: 3100 + + + )) + + + + + alt + + + [Response is ok] + + + + + alt + + + [SimpleRoutingMode is FALSE] + + + + + 11 + + + Validate response (duplicate response check, handle resend scenario ( + + + Error code: 3106 + + + )) + + + + + alt + + + [Validation passed] + + + + + 12 + + + Persist quote response + + + + quoteResponse + + + quoteResponseDuplicateCheck + + + quoteResponseIlpPacket + + + quoteExtensions + + + geoCode + + + + + 13 + + + Quote response saved + + + + + alt + + + [SimpleRoutingMode is TRUE] + + + + + 14 + + + Retrieve quotes endpoint for the Payer FSP + + + + [SimpleRoutingMode is FALSE] + + + + + 15 + + + Retrieve quote party endpoint (PAYER) + + + + + alt + + + [Quotes callback endpoint found] + + + + + Switch forwards quote response to Payer FSP + + + <Payee whole request Rule> + + + + + 16 + + + PUT /quotes/{ID} + + + + + 17 + + + 200 Ok + + + + [Quotes callback endpoint not found] + + + + + Switch returns error to Payee FSP + + + + + 18 + + + PUT /quotes/{ID}/error + + + + + 19 + + + 200 Ok + + + + [Response is invalid] + + + + + Switch returns error to Payee FSP + + + + + 20 + + + PUT /quotes/{ID}/error + + + + + 21 + + + 200 Ok + + + + + Note that under this + + + scenario the Payer FSP + + + may not receive a response + + + + [Quote not found] + + + + + Payee FSP returns error to Switch + + + Error code: 3205 + + + + + 22 + + + PUT quotes/{ID}/error + + + + + 23 + + + 200 OK + + + + + alt + + + [SimpleRoutingMode is FALSE] + + + + + 24 + + + Persist error data + + + + + Switch returns error to Payer FSP + + + Error code: 3205 + + + + + 25 + + + PUT quotes/{ID}/error + + + + + 26 + + + 200 OK + + + + [Payee FSP quotes endpoint is not found] + + + + + Switch returns error to Payer FSP + + + Error code: 3201 + + + + + 27 + + + PUT quotes/{ID}error + + + + + 28 + + + 200 OK + + diff --git a/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-post-bulk-quotes-2.2.0.svg b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-post-bulk-quotes-2.2.0.svg new file mode 100644 index 000000000..4b3363dd6 --- /dev/null +++ b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-post-bulk-quotes-2.2.0.svg @@ -0,0 +1,387 @@ + + + + + + + + + + + Request Bulk Quote Creation + + + + + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + [Quoting Service] + + + + Switch + + + [Quoting Service] + + + + Payee FSP + + + + Payee FSP + + + + + Payer FSP sends bulk quote request + + + to Payee FSP via the Switch + + + + + 1 + + + POST /bulkQuotes + + + + + Validate request against + + + Mojaloop interface specification + + + Error code: 300x, 310x + + + HTTP error response code: 4xx + + + + + 2 + + + Schema validation + + + + + 3 + + + 202 Accepted + + + + + 4 + + + Bulk Quote request validation (rules engine etc.) + + + + + 5 + + + Duplicate check + + + + + alt + + + [Request is a duplicate but not a resend] + + + + + Switch returns error back to Payer FSP + + + Error code: 3106 + + + + + 6 + + + PUT /bulkQuotes/{ID}/error + + + + + 7 + + + 200 OK + + + + [Request is a duplicate and a resend] + + + + + 8 + + + Switch handles resend scenario + + + + + 9 + + + Use fspiop-destination header to retrieve + + + bulk quotes endpoint for Payee DFSP + + + + + alt + + + [Payee bulk quotes endpoint found] + + + + + Switch forwards bulk quote request to Payee FSP + + + + + 10 + + + POST /bulkQuotes + + + + + 11 + + + 202 OK + + + + + 12 + + + Payee FSP calculates individual quotes + + + and responds with a bulk quote result + + + + + alt + + + [Payee bulkQuotes processing successful] + + + + + Payee FSP sends bulk quote response back to Payer FSP via the Switch + + + + + 13 + + + PUT /bulkQuotes/{ID} + + + + + 14 + + + 200 OK + + + + + 15 + + + Validate bulk quote response + + + + + 16 + + + Duplicate check + + + + + alt + + + [Response is duplicate but not a resend] + + + + + 17 + + + PUT /bulkQuotes/{ID}/error + + + + + 18 + + + 200 OK + + + + + alt + + + [Response is a duplicate and a resend] + + + + + 19 + + + Switch handles resend scenario + + + + + Switch forwards quote response to Payer FSP + + + + + 20 + + + PUT /bulkQuotes/{ID} + + + + + 21 + + + 200 OK + + + + [Payee rejects bulk quote or encounters an error] + + + + + Payee FSP sends error callback to Payer FSP via the Switch + + + + + 22 + + + PUT /bulkQuotes/{ID}/error + + + + + 23 + + + 200 OK + + + + + Switch forwards error callback to Payer FSP + + + + + 24 + + + PUT /bulkQuotes/{ID}/error + + + + + 25 + + + 200 OK + + + + [Payee FSP quotes endpoint not found] + + + + + Switch sends an error callback to Payer FSP + + + Error code: 3201 + + + + + 26 + + + PUT /bulkQuotes/{ID}/error + + + + + 27 + + + 200 OK + + diff --git a/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-post-quotes-1.2.0.svg b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-post-quotes-1.2.0.svg new file mode 100644 index 000000000..6250d6e02 --- /dev/null +++ b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-post-quotes-1.2.0.svg @@ -0,0 +1,536 @@ + + + + + + + + + + + Request Quote Creation + + + + + + + + + + + + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + [Quoting + + + Service] + + + + Switch + + + [Quoting + + + Service] + + + Central Store + + + + + Central Store + + + + + + Payee FSP + + + + Payee FSP + + + + + + Payer FSP sends request for quote + + + to Payee FSP via the Switch + + + + + 1 + + + POST /quotes + + + + + Validate request against + + + Mojaloop interface specification + + + Error code: 300x, 310x + + + HTTP error response code: 4xx + + + + + 2 + + + Schema validation + + + + + 3 + + + 202 Accepted + + + + + 4 + + + Quote request validation (rules engine etc.) + + + + + alt + + + [SimpleRoutingMode === FALSE] + + + + + 5 + + + Duplicate check + + + + + alt + + + [Request is a duplicate but not a resend] + + + + + Switch returns error back to Payer FSP + + + Error code: 3106 + + + + + 6 + + + PUT /quotes/{ID}/error + + + + + 7 + + + 200 OK + + + + [Request is a duplicate and a resend] + + + + + 8 + + + Switch handles resend scenario + + + + + 9 + + + Persist quote request + + + + quoteDuplicateCheck + + + transactionReference + + + quote + + + quoteParty + + + quoteExtension + + + geoCode + + + + + 10 + + + Quote request saved + + + + + alt + + + [SimpleRoutingMode === TRUE] + + + + + 11 + + + Use fspiop-destination header to retrieve quotes endpoint for Payee FSP + + + + [SimpleRoutingMode === FALSE] + + + + + 12 + + + Retireve Payee FSP endpoint using quote party information + + + + + alt + + + [Payee quotes endpoint found] + + + + + Switch forwards quote request to Payee FSP + + + + + 13 + + + POST /quotes + + + + + 14 + + + 202 OK + + + + + 15 + + + Payee FSP presists and calculates quote + + + + + alt + + + [Payee quotes processing successful] + + + + + Payee FSP sends quote response back to Payer FSP via the Switch + + + + + 16 + + + PUT /quotes/{ID} + + + + + 17 + + + 200 OK + + + + + 18 + + + Validate quote response + + + + + alt + + + [SimpleRoutingMode === FALSE] + + + + + 19 + + + Duplicate check + + + + + alt + + + [Response is duplicate but not a resend] + + + + + 20 + + + PUT /quotes/{ID}/error + + + + + 21 + + + 200 OK + + + + + alt + + + [Response is a duplicate and a resend] + + + + + 22 + + + Switch handles resend scenario + + + + + 23 + + + Persist quote response + + + + quoteResponse + + + quoteDuplicateCheck + + + quoteResponseIlpPacket + + + geoCode + + + quoteExtension + + + + + 24 + + + Quote response saved + + + + + Switch forwards quote response to Payer FSP + + + + + 25 + + + PUT /quotes/{ID} + + + + + 26 + + + 200 OK + + + + [Payee rejects quotes or encounters and error] + + + + + Payee FSP sends error callback to Payer FSP via the Switch + + + + + 27 + + + PUT /quotes/{ID}/error + + + + + 28 + + + 200 OK + + + + + alt + + + [SimpleRoutingMode === FALSE] + + + + + 29 + + + Store quote error + + + + quoteError + + + + + 30 + + + Quote error saved + + + + + Switch forwards error callback to Payer FSP + + + + + 31 + + + PUT /quotes/{ID}/error + + + + + 32 + + + 200 OK + + + + [Payee FSP quotes endpoint not found] + + + + + Switch sends an error callback to Payer FSP + + + Error code: 3201 + + + + + 33 + + + PUT /quotes/{ID}/error + + + + + 34 + + + 200 OK + + diff --git a/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-quotes-1.0.0.svg b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-quotes-1.0.0.svg new file mode 100644 index 000000000..b79aecb9d --- /dev/null +++ b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-quotes-1.0.0.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + Quoting Service Sequences + + + + + + + + + Payer DFSP + + + + Payer DFSP + + + + Switch + + + Quoting + + + Service + + + + Switch + + + Quoting + + + Service + + + + Payee DFSP + + + + Payee DFSP + + + + + Payer DFSP requests quote from Payee DFSP + + + + + 1 + + + POST /quotes + + + + + 2 + + + 202 Accepted + + + + + 3 + + + Validate Quote Request + + + + + alt + + + [quote is valid] + + + + + 4 + + + Persist Quote Data + + + + + Switch forwards quote request to Payee DFSP + + + <Payer based Rules> + + + + + 5 + + + POST /quotes + + + + + 6 + + + 202 Accepted + + + + + 7 + + + Calculate Fees/Charges + + + + + alt + + + [Payee DFSP successfully calculates quote] + + + + + Payee DFSP responds to quote request + + + + + 8 + + + PUT /quotes/{ID} + + + + + 9 + + + 200 Ok + + + + + 10 + + + Validate Quote Response + + + + + alt + + + [response is ok] + + + + + 11 + + + Persist Response Data + + + + + Switch forwards quote response to Payer DFSP + + + <Payee whole request Rule> + + + + + 12 + + + PUT /quotes/{ID} + + + + + 13 + + + 200 Ok + + + + + Payer DFSP continues + + + with transfer if quote + + + is acceptable... + + + + [response invalid] + + + + + Switch returns error to Payee DFSP + + + + + 14 + + + PUT /quotes/{ID}/error + + + + + 15 + + + 200 Ok + + + + + Note that under this + + + scenario the Payer DFSP + + + may not receive a response + + + + [Payee DFSP calculation fails or rejects the request] + + + + + Payee DFSP returns error to Switch + + + + + 16 + + + PUT quotes/{ID}/error + + + + + 17 + + + 200 OK + + + + + 18 + + + Persist error data + + + + + Switch returns error to Payer DFSP + + + + + 19 + + + PUT quotes/{ID}/error + + + + + 20 + + + 200 OK + + + + [quote invalid] + + + + + Switch returns error to Payer DFSP + + + + + 21 + + + PUT quotes/{ID}/error + + + + + 22 + + + 200 OK + + diff --git a/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-quotes-overview-1.0.0.svg b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-quotes-overview-1.0.0.svg new file mode 100644 index 000000000..69b7fb6d4 --- /dev/null +++ b/mojaloop-technical-overview/quoting-service/assets/diagrams/sequence/seq-quotes-overview-1.0.0.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + Quoting Service Sequences + + + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + Quoting + + + Service + + + + Switch + + + Quoting + + + Service + + + + Payee FSP + + + + Payee FSP + + + + + Payer FSP requests quote from Payee FSP + + + + + 1 + + + POST /quotes + + + + + 2 + + + 202 Accepted + + + + + 3 + + + Validate Quote Request + + + + + alt + + + [quote is valid] + + + + + 4 + + + Persist Quote Data + + + + + Switch forwards quote request to Payee FSP + + + <Payer based Rules> + + + + + 5 + + + POST /quotes + + + + + 6 + + + 202 Accepted + + + + + 7 + + + Calculate Fees/Charges + + + + + alt + + + [Payee FSP successfully calculates quote] + + + + + Payee FSP responds to quote request + + + + + 8 + + + PUT /quotes/{ID} + + + + + 9 + + + 200 Ok + + + + + 10 + + + Validate Quote Response + + + + + alt + + + [response is ok] + + + + + 11 + + + Persist Response Data + + + + + Switch forwards quote response to Payer FSP + + + <Payee whole request Rule> + + + + + 12 + + + PUT /quotes/{ID} + + + + + 13 + + + 200 Ok + + + + + Payer FSP continues + + + with transfer if quote + + + is acceptable... + + + + [response invalid] + + + + + Switch returns error to Payee FSP + + + + + 14 + + + PUT /quotes/{ID}/error + + + + + 15 + + + 200 Ok + + + + + Note that under this + + + scenario the Payer FSP + + + may not receive a response + + + + [Payee FSP calculation fails or rejects the request] + + + + + Payee FSP returns error to Switch + + + + + 16 + + + PUT quotes/{ID}/error + + + + + 17 + + + 200 OK + + + + + 18 + + + Persist error data + + + + + Switch returns error to Payer FSP + + + + + 19 + + + PUT quotes/{ID}/error + + + + + 20 + + + 200 OK + + + + [quote invalid] + + + + + Switch returns error to Payer FSP + + + + + 21 + + + PUT quotes/{ID}/error + + + + + 22 + + + 200 OK + + diff --git a/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-authorizations-3.0.0.svg b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-authorizations-3.0.0.svg new file mode 100644 index 000000000..20f251063 --- /dev/null +++ b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-authorizations-3.0.0.svg @@ -0,0 +1,231 @@ + + + + + + + + + + + Transaction Requests Service - Authorizations + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + transaction-requests-service + + + + Switch + + + transaction-requests-service + + + + Payee FSP + + + + Payee FSP + + + + + 1 + + + Lookup, Transaction request, + + + processing not shown here + + + + + Payee FSP generates a transaction-request to the Payer FSP + + + + + 2 + + + Do quote, generate OTP + + + notify user (not shown here) + + + + + 3 + + + GET /authorizations/{TransactionRequestID} + + + + + 4 + + + 202 Accepted + + + + + alt + + + [authorization request is valid] + + + + + 5 + + + Validate GET /authorizations/{TransactionRequestID} (internal validation) + + + + + 6 + + + Retrieve corresponding end-points for Payee FSP + + + + + Switch forwards GET /authorizations request to Payee FSP + + + + + 7 + + + GET /authorizations/{TransactionRequestID} + + + + + 8 + + + 202 Accepted + + + + + 9 + + + Process authorization request + + + (Payer approves/rejects transaction + + + using OTP) + + + + + Payee FSP responds with PUT /authorizations//{TransactionRequestID} + + + + + 10 + + + PUT /authorizations//{TransactionRequestID} + + + + + 11 + + + 200 Ok + + + + + Switch forwards PUT /authorizations//{TransactionRequestID} to Payer FSP + + + + + 12 + + + Retrieve corresponding end-points for Payer FSP + + + + + 13 + + + PUT /authorizations//{TransactionRequestID} + + + + + 14 + + + 200 Ok + + + + [authorization request is invalid] + + + + + Switch returns error callback to Payer FSP + + + + + 15 + + + PUT /authorizations/{TransactionRequestID}/error + + + + + 16 + + + 200 OK + + + + + 17 + + + Validate OTP sent by Payee FSP + + diff --git a/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-service-1.0.0.svg b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-service-1.0.0.svg new file mode 100644 index 000000000..b5a1c7313 --- /dev/null +++ b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-service-1.0.0.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + Transaction Requests Service - Create + + + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + transaction-requests-service + + + + Switch + + + transaction-requests-service + + + + Payee FSP + + + + Payee FSP + + + + + 1 + + + Lookup process + + + (not shown here) + + + + + Payee FSP generates a transaction-request to the Payer FSP + + + + + 2 + + + POST /transactionRequests + + + + + 3 + + + Validate POST /transactionRequests schema + + + + + 4 + + + 202 Accepted + + + + + alt + + + [transaction-request is valid] + + + + + 5 + + + Validate POST /transactionRequests (internal validation) + + + + + 6 + + + Retrieve corresponding end-points for Payer FSP + + + + + Switch forwards POST /transactionRequests request to Payer FSP + + + + + 7 + + + POST /transactionRequests + + + + + 8 + + + 202 Accepted + + + + + 9 + + + Process transaction-request + + + + + alt + + + [Payer FSP successfully processes transaction-request] + + + + + Payer FSP responds to POST /transactionRequests + + + + + 10 + + + PUT /transactionRequests/{ID} + + + + + 11 + + + 200 Ok + + + + + 12 + + + Validate PUT /transactionRequests/{ID} + + + + + alt + + + [response is ok] + + + + + Switch forwards transaction-request response to Payee FSP + + + + + 13 + + + Retrieve corresponding end-points for Payee FSP + + + + + 14 + + + PUT /transactionRequests/{ID} + + + + + 15 + + + 200 Ok + + + + + Wait for a quote, transfer by Payer FSP + + + or a rejected transaction-request + + + + [response invalid] + + + + + Switch returns error to Payer FSP + + + + + 16 + + + PUT /transactionRequests/{ID}/error + + + + + 17 + + + 200 Ok + + + + + Note that under this + + + scenario the Payee FSP + + + may not receive a response + + + + [Payer FSP calculation fails or rejects the request] + + + + + Payer FSP returns error to Switch + + + + + 18 + + + PUT /transactionRequests/{ID}/error + + + + + 19 + + + 200 OK + + + + + Switch returns error to Payee FSP + + + + + 20 + + + PUT /transactionRequests/{ID}/error + + + + + 21 + + + 200 OK + + + + [transaction-request is invalid] + + + + + Switch returns error to Payee FSP + + + + + 22 + + + PUT /transactionRequests/{ID}/error + + + + + 23 + + + 200 OK + + diff --git a/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-service-get-2.0.0.svg b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-service-get-2.0.0.svg new file mode 100644 index 000000000..bbc20538b --- /dev/null +++ b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/seq-trx-req-service-get-2.0.0.svg @@ -0,0 +1,309 @@ + + + + + + + + + + + Transaction Requests Service - Query + + + + + + + + + Payer FSP + + + + Payer FSP + + + + Switch + + + transaction-requests-service + + + + Switch + + + transaction-requests-service + + + + Payee FSP + + + + Payee FSP + + + + + Payee FSP requests the status of a transaction-request at the Payer FSP. + + + ID here is the ID of prevoiusly created transaction-request + + + + + 1 + + + GET /transactionRequests/{ID} + + + + + 2 + + + Validate GET /transactionRequests/{ID} + + + + + 3 + + + 202 Accepted + + + + + alt + + + [transaction-request query is valid] + + + + + 4 + + + Retrieve corresponding end-points for Payer FSP + + + + + Switch forwards GET /transactionRequests/{ID} request to Payer FSP + + + + + 5 + + + GET /transactionRequests/{ID} + + + + + 6 + + + 202 Accepted + + + + + 7 + + + Retrieve transaction-request + + + + + alt + + + [Payer FSP successfully retrieves transaction-request] + + + + + Payer FSP responds with the + + + PUT /transactionRequests/{ID} callback + + + + + 8 + + + PUT /transactionRequests/{ID} + + + + + 9 + + + 200 Ok + + + + + 10 + + + Validate PUT /transactionRequests/{ID} + + + + + alt + + + [response is ok] + + + + + Switch forwards transaction-request response to Payee FSP + + + + + 11 + + + Retrieve corresponding end-points for Payee FSP + + + + + 12 + + + PUT /transactionRequests/{ID} + + + + + 13 + + + 200 Ok + + + + [response invalid] + + + + + Switch returns error to Payer FSP + + + + + 14 + + + PUT /transactionRequests/{ID}/error + + + + + 15 + + + 200 Ok + + + + + Note that under this + + + scenario the Payee FSP + + + may not receive a response + + + + [Payer FSP is unable to retrieve the transaction-request] + + + + + Payer FSP returns error to Switch + + + + + 16 + + + PUT /transactionRequests/{ID}/error + + + + + 17 + + + 200 OK + + + + + Switch returns error to Payee FSP + + + + + 18 + + + PUT /transactionRequests/{ID}/error + + + + + 19 + + + 200 OK + + + + [transaction-request is invalid] + + + + + Switch returns error to Payee FSP + + + + + 20 + + + PUT /transactionRequests/{ID}/error + + + + + 21 + + + 200 OK + + diff --git a/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/trx-service-overview-spec.svg b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/trx-service-overview-spec.svg new file mode 100644 index 000000000..e54569705 --- /dev/null +++ b/mojaloop-technical-overview/transaction-requests-service/assets/diagrams/sequence/trx-service-overview-spec.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + Payer + + + FSP + + + + Optional + + + Switch + + + + Payee + + + FSP + + + + Payee + + + + + + + I would like to receive + + + funds from +123456789 + + + + Lookup +123456789 + + + (process not shown here) + + + + POST /transactionRequest/ + + + (Payee information, + + + transaction details) + + + + + HTTP 202 + + + (Accepted) + + + + POST /transactionRequests/ + + + (Payee information, + + + transaction details) + + + + + HTTP 202 + + + (Accepted) + + + + Perform optional validation + + + + PUT /transactionRequests/ + + + <ID> + + + (Received status) + + + + + HTTP 200 + + + (OK) + + + + PUT /transactionRequests/ + + + <ID> + + + (Received status) + + + + + HTTP 200 + + + (OK) + + + + Wait for either quote and + + + transfer, or rejected + + + transaction request by Payer + + diff --git a/package-lock.json b/package-lock.json index 75ccdc441..32283ec92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,35 @@ { "name": "documentation", - "version": "11.2.0", + "version": "11.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, "@korzio/djv-draft-04": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@korzio/djv-draft-04/-/djv-draft-04-2.0.1.tgz", @@ -122,18 +148,18 @@ } }, "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.0.tgz", + "integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==", "dev": true }, "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", "dev": true, "requires": { - "defer-to-connect": "^1.0.1" + "defer-to-connect": "^2.0.0" } }, "@tootallnate/once": { @@ -142,17 +168,64 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", + "dev": true + }, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/node": { "version": "13.13.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz", - "integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==", - "optional": true + "integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } }, "@types/yauzl": { "version": "2.9.1", @@ -186,7 +259,8 @@ "acorn": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", - "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", + "optional": true }, "acorn-globals": { "version": "1.0.9", @@ -976,36 +1050,35 @@ } } }, + "cacheable-lookup": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz", + "integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w==", + "dev": true + }, "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", "dev": true, "requires": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", + "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } + "responselike": "^2.0.0" + } + }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" } }, "call-me-maybe": { @@ -1013,6 +1086,12 @@ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", @@ -1191,6 +1270,17 @@ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1238,6 +1328,12 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" }, + "compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -1344,6 +1440,19 @@ "vary": "^1" } }, + "cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", @@ -1374,15 +1483,73 @@ "nth-check": "~1.0.0" } }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "css-what": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", "integrity": "sha1-18wt9FGAZm+Z0rFEYmOUaeAPc2w=" }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", + "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha1-nxJ29bK0Y/IRTT8sdSUK+MGjb0o=" + "integrity": "sha1-nxJ29bK0Y/IRTT8sdSUK+MGjb0o=", + "optional": true }, "cssstyle": { "version": "0.2.37", @@ -1540,12 +1707,20 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, "requires": { - "mimic-response": "^1.0.0" + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } } }, "deep-aplus": { @@ -1574,11 +1749,20 @@ "dev": true }, "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", + "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -1656,6 +1840,12 @@ "wrappy": "1" } }, + "directory-tree": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-2.2.5.tgz", + "integrity": "sha512-qmeuql8N7hQB5b+cnlvbcHSjKBNpRjLY5KcvyFd9CTC5uTN7sJshEQ/ExZidAcEUEYcC/76i8ikLtbBMG81YRg==", + "dev": true + }, "djv": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/djv/-/djv-2.1.2.tgz", @@ -1802,6 +1992,46 @@ "prr": "~1.0.1" } }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -2392,6 +2622,15 @@ "locate-path": "^3.0.0" } }, + "find-versions": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "dev": true, + "requires": { + "semver-regex": "^2.0.0" + } + }, "flat": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", @@ -2539,6 +2778,12 @@ "rimraf": "2" } }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -2609,6 +2854,17 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-promise": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/get-promise/-/get-promise-1.4.0.tgz", @@ -2632,9 +2888,9 @@ "dev": true }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { "pump": "^3.0.0" @@ -2840,6 +3096,17 @@ "requires": { "graceful-fs": "^4.1.6" } + }, + "node-plantuml": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/node-plantuml/-/node-plantuml-0.6.2.tgz", + "integrity": "sha512-4/nf/gBvKVm4+EbBgFQZf0n8N3jfAA7mRExs3NfgujSsaouktZwYkUzBUqUR8nRzIWDmJ4hA1QiWOjpEArTiZQ==", + "requires": { + "commander": "^2.8.1", + "node-nailgun-client": "^0.1.0", + "node-nailgun-server": "^0.1.3", + "plantuml-encoder": "^1.2.5" + } } } }, @@ -2925,22 +3192,22 @@ } }, "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "version": "11.8.0", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.0.tgz", + "integrity": "sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ==", "dev": true, "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.1", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" } }, "graceful-fs": { @@ -2972,12 +3239,27 @@ "har-schema": "^2.0.0" } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -3200,6 +3482,16 @@ "sshpk": "^1.7.0" } }, + "http2-wrapper": { + "version": "1.0.0-beta.5.2", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz", + "integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, "https-proxy-agent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", @@ -3232,6 +3524,75 @@ "ms": "^2.0.0" } }, + "husky": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz", + "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.6.0", + "cosmiconfig": "^7.0.0", + "find-versions": "^3.2.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3265,6 +3626,16 @@ "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", "optional": true }, + "import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -3325,6 +3696,12 @@ "kind-of": "^3.0.2" } }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -3338,6 +3715,12 @@ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=" }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -3355,6 +3738,12 @@ "kind-of": "^3.0.2" } }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -3441,6 +3830,12 @@ "xtend": "^4.0.0" } }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, "is-npm": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", @@ -3503,6 +3898,24 @@ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3568,6 +3981,12 @@ "resolved": "https://registry.npmjs.org/js-quantities/-/js-quantities-1.7.5.tgz", "integrity": "sha512-4rnv5eKQSDyRPREOkzw6OG/IY7/zfAlTgjvUcfA2eQ76/sYND3eo0fMl5q5uQEjdAnfDmZNJZrJvlOJzgqV6AA==" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -3606,9 +4025,9 @@ } }, "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, "json-parse-better-errors": { @@ -3639,7 +4058,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify": { "version": "1.0.1", @@ -3738,12 +4157,12 @@ } }, "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz", + "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==", "dev": true, "requires": { - "json-buffer": "3.0.0" + "json-buffer": "3.0.1" } }, "kind-of": { @@ -3982,6 +4401,12 @@ } } }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, "live-server": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/live-server/-/live-server-1.2.1.tgz", @@ -4514,9 +4939,9 @@ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" }, "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "dev": true }, "lru-cache": { @@ -4660,6 +5085,12 @@ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", "integrity": "sha1-XdaUPJOFSCZwFtTjTwV1gwgMUUw=" }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -5083,14 +5514,15 @@ } }, "node-plantuml": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/node-plantuml/-/node-plantuml-0.6.2.tgz", - "integrity": "sha512-4/nf/gBvKVm4+EbBgFQZf0n8N3jfAA7mRExs3NfgujSsaouktZwYkUzBUqUR8nRzIWDmJ4hA1QiWOjpEArTiZQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/node-plantuml/-/node-plantuml-0.5.0.tgz", + "integrity": "sha1-A8LthW5rJyxxShVoRTp0fCZv3B8=", + "dev": true, "requires": { "commander": "^2.8.1", "node-nailgun-client": "^0.1.0", "node-nailgun-server": "^0.1.3", - "plantuml-encoder": "^1.2.5" + "plantuml-encoder": "^1.2.4" } }, "nopt": { @@ -5234,7 +5666,7 @@ "dependencies": { "JSONStream": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=", "requires": { "jsonparse": "^1.2.0", @@ -5243,19 +5675,19 @@ "dependencies": { "jsonparse": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" }, "through": { "version": "2.3.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" } } }, "abbrev": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" }, "agent-base": { @@ -5276,37 +5708,37 @@ }, "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "ansicolors": { "version": "0.3.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" }, "ansistyles": { "version": "0.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=" }, "aproba": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", "integrity": "sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw==" }, "archy": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" }, "bluebird": { "version": "3.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" }, "cacache": { "version": "9.2.9", - "resolved": false, + "resolved": "https://registry.npmjs.org/cacache/-/cacache-9.2.9.tgz", "integrity": "sha512-ghg1j5OyTJ6qsrqU++dN23QiTDxb5AZCFGsF3oB+v9v/gY+F4X8L/0gdQMEjd+8Ot3D29M2etX5PKozHRn2JQw==", "requires": { "bluebird": "^3.5.0", @@ -5326,17 +5758,17 @@ }, "call-limit": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.0.tgz", "integrity": "sha1-b9YbA/PaQqLNDsK2DwK9DnGZH+o=" }, "chownr": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" }, "cmd-shim": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz", "integrity": "sha1-b8vamUg6j9FdfTChlspp1oii79s=", "requires": { "graceful-fs": "^4.1.2", @@ -5345,7 +5777,7 @@ }, "columnify": { "version": "1.5.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", "requires": { "strip-ansi": "^3.0.0", @@ -5354,7 +5786,7 @@ "dependencies": { "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -5362,14 +5794,14 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" } } }, "wcwidth": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", "requires": { "defaults": "^1.0.3" @@ -5377,7 +5809,7 @@ "dependencies": { "defaults": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "requires": { "clone": "^1.0.2" @@ -5385,7 +5817,7 @@ "dependencies": { "clone": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=" } } @@ -5396,7 +5828,7 @@ }, "config-chain": { "version": "1.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", "requires": { "ini": "^1.3.4", @@ -5405,7 +5837,7 @@ "dependencies": { "proto-list": { "version": "1.2.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" } } @@ -5420,17 +5852,17 @@ }, "debuglog": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" }, "detect-indent": { "version": "5.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" }, "dezalgo": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", "requires": { "asap": "^2.0.0", @@ -5439,19 +5871,19 @@ "dependencies": { "asap": { "version": "2.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz", "integrity": "sha1-UidltQw1EEkOUtfc/ghe+bqWlY8=" } } }, "editor": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" }, "fs-vacuum": { "version": "1.2.10", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz", "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=", "requires": { "graceful-fs": "^4.1.2", @@ -5461,7 +5893,7 @@ }, "fs-write-stream-atomic": { "version": "1.0.10", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "requires": { "graceful-fs": "^4.1.2", @@ -5472,7 +5904,7 @@ }, "fstream-npm": { "version": "1.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/fstream-npm/-/fstream-npm-1.2.1.tgz", "integrity": "sha512-iBHpm/LmD1qw0TlHMAqVd9rwdU6M+EHRUnPkXpRi5G/Hf0FIFH+oZFryodAU2MFNfGRh/CzhUFlMKV3pdeOTDw==", "requires": { "fstream-ignore": "^1.0.0", @@ -5481,7 +5913,7 @@ "dependencies": { "fstream-ignore": { "version": "1.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", "requires": { "fstream": "^1.0.0", @@ -5491,7 +5923,7 @@ "dependencies": { "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" @@ -5499,7 +5931,7 @@ "dependencies": { "brace-expansion": { "version": "1.1.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { "balanced-match": "^1.0.0", @@ -5508,12 +5940,12 @@ "dependencies": { "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" } } @@ -5526,7 +5958,7 @@ }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "requires": { "fs.realpath": "^1.0.0", @@ -5539,12 +5971,12 @@ "dependencies": { "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" @@ -5552,7 +5984,7 @@ "dependencies": { "brace-expansion": { "version": "1.1.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { "balanced-match": "^1.0.0", @@ -5561,12 +5993,12 @@ "dependencies": { "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" } } @@ -5575,24 +6007,24 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" } } }, "graceful-fs": { "version": "4.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "hosted-git-info": { "version": "2.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" }, "http-cache-semantics": { @@ -5620,17 +6052,17 @@ }, "iferr": { "version": "0.1.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" }, "imurmurhash": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "^1.3.0", @@ -5639,17 +6071,17 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" }, "init-package-json": { "version": "1.10.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.1.tgz", "integrity": "sha1-zYc6FneWvvuZYSsodioLY5P9j2o=", "requires": { "glob": "^7.1.1", @@ -5664,7 +6096,7 @@ "dependencies": { "promzard": { "version": "0.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", "requires": { "read": "1" @@ -5674,22 +6106,22 @@ }, "lazy-property": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz", "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=" }, "lockfile": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.3.tgz", "integrity": "sha1-Jjj8OaAzHpysGgS3F5mTHJxQ33k=" }, "lodash._baseindexof": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=" }, "lodash._baseuniq": { "version": "4.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", "requires": { "lodash._createset": "~4.0.0", @@ -5698,29 +6130,29 @@ "dependencies": { "lodash._createset": { "version": "4.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=" }, "lodash._root": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" } } }, "lodash._bindcallback": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" }, "lodash._cacheindexof": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=" }, "lodash._createcache": { "version": "3.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", "requires": { "lodash._getnative": "^3.0.0" @@ -5728,37 +6160,37 @@ }, "lodash._getnative": { "version": "3.9.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" }, "lodash.clonedeep": { "version": "4.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, "lodash.restparam": { "version": "3.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" }, "lodash.union": { "version": "4.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" }, "lodash.uniq": { "version": "4.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "lodash.without": { "version": "4.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz", "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=" }, "lru-cache": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "requires": { "pseudomap": "^1.0.2", @@ -5767,12 +6199,12 @@ "dependencies": { "pseudomap": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "yallist": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" } } @@ -5884,7 +6316,7 @@ }, "mississippi": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-1.3.0.tgz", "integrity": "sha1-0gFYPrEjJ+PFwWQqQEqcrPlONPU=", "requires": { "concat-stream": "^1.5.0", @@ -5901,7 +6333,7 @@ "dependencies": { "concat-stream": { "version": "1.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "requires": { "inherits": "^2.0.3", @@ -5911,14 +6343,14 @@ "dependencies": { "typedarray": { "version": "0.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" } } }, "duplexify": { "version": "3.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz", "integrity": "sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=", "requires": { "end-of-stream": "1.0.0", @@ -5929,7 +6361,7 @@ "dependencies": { "end-of-stream": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", "integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=", "requires": { "once": "~1.3.0" @@ -5937,7 +6369,7 @@ "dependencies": { "once": { "version": "1.3.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "requires": { "wrappy": "1" @@ -5947,14 +6379,14 @@ }, "stream-shift": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" } } }, "end-of-stream": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", "requires": { "once": "^1.4.0" @@ -5962,7 +6394,7 @@ }, "flush-write-stream": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz", "integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=", "requires": { "inherits": "^2.0.1", @@ -5971,7 +6403,7 @@ }, "from2": { "version": "2.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "requires": { "inherits": "^2.0.1", @@ -5980,7 +6412,7 @@ }, "parallel-transform": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", "requires": { "cyclist": "~0.2.2", @@ -5990,14 +6422,14 @@ "dependencies": { "cyclist": { "version": "0.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" } } }, "pump": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz", "integrity": "sha1-Oz7mUS+U8OV1U4wXmV+fFpkKXVE=", "requires": { "end-of-stream": "^1.1.0", @@ -6006,7 +6438,7 @@ }, "pumpify": { "version": "1.3.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.3.5.tgz", "integrity": "sha1-G2ccYZlAq8rqwK0OOjwWS+dgmTs=", "requires": { "duplexify": "^3.1.2", @@ -6016,7 +6448,7 @@ }, "stream-each": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.0.tgz", "integrity": "sha1-HpXUdXP1gNgU3A/4zQ9m8c5TyZE=", "requires": { "end-of-stream": "^1.1.0", @@ -6025,14 +6457,14 @@ "dependencies": { "stream-shift": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" } } }, "through2": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "requires": { "readable-stream": "^2.1.5", @@ -6041,7 +6473,7 @@ "dependencies": { "xtend": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } @@ -6058,7 +6490,7 @@ }, "move-concurrently": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "requires": { "aproba": "^1.1.1", @@ -6071,7 +6503,7 @@ "dependencies": { "run-queue": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "requires": { "aproba": "^1.1.1" @@ -6111,7 +6543,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "requires": { "abbrev": "1", @@ -6120,7 +6552,7 @@ }, "normalize-package-data": { "version": "2.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "requires": { "hosted-git-info": "^2.1.4", @@ -6131,7 +6563,7 @@ "dependencies": { "is-builtin-module": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { "builtin-modules": "^1.0.0" @@ -6139,7 +6571,7 @@ "dependencies": { "builtin-modules": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" } } @@ -6148,12 +6580,12 @@ }, "npm-cache-filename": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=" }, "npm-install-checks": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.0.tgz", "integrity": "sha1-1K7N/VGlPjcjt7L5Oy7ijjB7wNc=", "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" @@ -6161,7 +6593,7 @@ }, "npm-package-arg": { "version": "5.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz", "integrity": "sha512-wJBsrf0qpypPT7A0LART18hCdyhpCMxeTtcb0X4IZO2jsP6Om7EHN1d9KSKiqD+KVH030RVNpWS9thk+pb7wzA==", "requires": { "hosted-git-info": "^2.4.2", @@ -6172,7 +6604,7 @@ }, "npm-registry-client": { "version": "8.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.4.0.tgz", "integrity": "sha512-PVNfqq0lyRdFnE//nDmn3CC9uqTsr8Bya9KPLIevlXMfkP0m4RpCVyFFk0W1Gfx436kKwyhLA6J+lV+rgR81gQ==", "requires": { "concat-stream": "^1.5.2", @@ -6190,7 +6622,7 @@ "dependencies": { "concat-stream": { "version": "1.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "requires": { "inherits": "^2.0.3", @@ -6200,7 +6632,7 @@ "dependencies": { "typedarray": { "version": "0.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" } } @@ -6209,12 +6641,12 @@ }, "npm-user-validate": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.0.tgz", "integrity": "sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=" }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { "are-we-there-yet": "~1.1.2", @@ -6225,7 +6657,7 @@ "dependencies": { "are-we-there-yet": { "version": "1.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "requires": { "delegates": "^1.0.0", @@ -6234,19 +6666,19 @@ "dependencies": { "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" } } }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { "aproba": "^1.0.3", @@ -6261,17 +6693,17 @@ "dependencies": { "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -6281,12 +6713,12 @@ "dependencies": { "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" @@ -6294,7 +6726,7 @@ "dependencies": { "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" } } @@ -6303,7 +6735,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -6311,14 +6743,14 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" } } }, "wide-align": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "requires": { "string-width": "^1.0.2" @@ -6328,14 +6760,14 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" } } }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" @@ -6343,12 +6775,12 @@ }, "opener": { "version": "1.4.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=" }, "osenv": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", "requires": { "os-homedir": "^1.0.0", @@ -6357,19 +6789,19 @@ "dependencies": { "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" } } }, "pacote": { "version": "2.7.38", - "resolved": false, + "resolved": "https://registry.npmjs.org/pacote/-/pacote-2.7.38.tgz", "integrity": "sha512-XxHUyHQB7QCVBxoXeVu0yKxT+2PvJucsc0+1E+6f95lMUxEAYERgSAc71ckYXrYr35Ew3xFU/LrhdIK21GQFFA==", "requires": { "bluebird": "^3.5.0", @@ -6397,7 +6829,7 @@ "dependencies": { "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" @@ -6405,7 +6837,7 @@ "dependencies": { "brace-expansion": { "version": "1.1.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "requires": { "balanced-match": "^1.0.0", @@ -6414,12 +6846,12 @@ "dependencies": { "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" } } @@ -6428,7 +6860,7 @@ }, "npm-pick-manifest": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-1.0.4.tgz", "integrity": "sha512-MKxNdeyOZysPRTTbHtW0M5Fw38Jo/3ARsoGw5qjCfS+XGjvNB/Gb4qtAZUFmKPM2mVum+eX559eHvKywU856BQ==", "requires": { "npm-package-arg": "^5.1.2", @@ -6437,7 +6869,7 @@ }, "promise-retry": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", "requires": { "err-code": "^1.0.0", @@ -6446,14 +6878,14 @@ "dependencies": { "err-code": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" } } }, "protoduck": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-4.0.0.tgz", "integrity": "sha1-/kh02MeRM2bP2erRJFOiLNNlf44=", "requires": { "genfun": "^4.0.1" @@ -6461,14 +6893,14 @@ "dependencies": { "genfun": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/genfun/-/genfun-4.0.1.tgz", "integrity": "sha1-7RAEHy5KfxsKOEZtF6XD4n3x38E=" } } }, "tar-stream": { "version": "1.5.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz", "integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=", "requires": { "bl": "^1.0.0", @@ -6479,7 +6911,7 @@ "dependencies": { "bl": { "version": "1.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", "requires": { "readable-stream": "^2.0.5" @@ -6487,7 +6919,7 @@ }, "end-of-stream": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", "requires": { "once": "^1.4.0" @@ -6495,7 +6927,7 @@ }, "xtend": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } @@ -6504,12 +6936,12 @@ }, "path-is-inside": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, "promise-inflight": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" }, "pump": { @@ -6523,7 +6955,7 @@ }, "read": { "version": "1.0.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", "requires": { "mute-stream": "~0.0.4" @@ -6531,14 +6963,14 @@ "dependencies": { "mute-stream": { "version": "0.0.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" } } }, "read-cmd-shim": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz", "integrity": "sha1-LV0Vd4ajfAVdIgd8MsU/gynpHHs=", "requires": { "graceful-fs": "^4.1.2" @@ -6546,7 +6978,7 @@ }, "read-installed": { "version": "4.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", "requires": { "debuglog": "^1.0.1", @@ -6560,14 +6992,14 @@ "dependencies": { "util-extend": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" } } }, "read-package-json": { "version": "2.0.9", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.9.tgz", "integrity": "sha512-vuV8p921IgyelL4UOKv3FsRuRZSaRn30HanLAOKargsr8TbBEq+I3MgloSRXYuKhNdYP1wlEGilMWAIayA2RFg==", "requires": { "glob": "^7.1.1", @@ -6578,7 +7010,7 @@ "dependencies": { "json-parse-helpfulerror": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", "integrity": "sha1-E/FM4C7tTpgSl7ZOueO5MuLdE9w=", "requires": { "jju": "^1.1.0" @@ -6586,7 +7018,7 @@ "dependencies": { "jju": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/jju/-/jju-1.3.0.tgz", "integrity": "sha1-2t2e8BkkvHKLA/L3l5vb1i96Kqo=" } } @@ -6595,7 +7027,7 @@ }, "read-package-tree": { "version": "5.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.6.tgz", "integrity": "sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg==", "requires": { "debuglog": "^1.0.1", @@ -6607,7 +7039,7 @@ }, "readable-stream": { "version": "2.3.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", "requires": { "core-util-is": "~1.0.0", @@ -6621,22 +7053,22 @@ "dependencies": { "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "process-nextick-args": { "version": "1.0.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" }, "string_decoder": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "requires": { "safe-buffer": "~5.1.0" @@ -6644,14 +7076,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" } } }, "readdir-scoped-modules": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz", "integrity": "sha1-n6+jfShr5dksuuve4DDcm19AZ0c=", "requires": { "debuglog": "^1.0.1", @@ -6671,7 +7103,7 @@ }, "request": { "version": "2.81.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", "requires": { "aws-sign2": "~0.6.0", @@ -6700,22 +7132,22 @@ "dependencies": { "aws-sign2": { "version": "0.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" }, "aws4": { "version": "1.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" }, "caseless": { "version": "0.12.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "combined-stream": { "version": "1.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "requires": { "delayed-stream": "~1.0.0" @@ -6723,24 +7155,24 @@ "dependencies": { "delayed-stream": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" } } }, "extend": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" }, "forever-agent": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { "version": "2.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", "requires": { "asynckit": "^0.4.0", @@ -6750,14 +7182,14 @@ "dependencies": { "asynckit": { "version": "0.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" } } }, "har-validator": { "version": "4.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", "requires": { "ajv": "^4.9.1", @@ -6766,7 +7198,7 @@ "dependencies": { "ajv": { "version": "4.11.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "requires": { "co": "^4.6.0", @@ -6775,12 +7207,12 @@ "dependencies": { "co": { "version": "4.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "json-stable-stringify": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "requires": { "jsonify": "~0.0.0" @@ -6788,7 +7220,7 @@ "dependencies": { "jsonify": { "version": "0.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" } } @@ -6797,14 +7229,14 @@ }, "har-schema": { "version": "1.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" } } }, "hawk": { "version": "3.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", "requires": { "boom": "2.x.x", @@ -6815,7 +7247,7 @@ "dependencies": { "boom": { "version": "2.10.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "requires": { "hoek": "2.x.x" @@ -6823,7 +7255,7 @@ }, "cryptiles": { "version": "2.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "requires": { "boom": "2.x.x" @@ -6831,12 +7263,12 @@ }, "hoek": { "version": "2.16.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" }, "sntp": { "version": "1.0.9", - "resolved": false, + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", "requires": { "hoek": "2.x.x" @@ -6846,7 +7278,7 @@ }, "http-signature": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "requires": { "assert-plus": "^0.2.0", @@ -6856,12 +7288,12 @@ "dependencies": { "assert-plus": { "version": "0.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" }, "jsprim": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", "requires": { "assert-plus": "1.0.0", @@ -6872,22 +7304,22 @@ "dependencies": { "assert-plus": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "extsprintf": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" }, "json-schema": { "version": "0.2.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "verror": { "version": "1.3.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", "requires": { "extsprintf": "1.0.2" @@ -6899,22 +7331,22 @@ }, "is-typedarray": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "isstream": { "version": "0.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "json-stringify-safe": { "version": "5.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "mime-types": { "version": "2.1.15", - "resolved": false, + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", "requires": { "mime-db": "~1.27.0" @@ -6922,34 +7354,34 @@ "dependencies": { "mime-db": { "version": "1.27.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" } } }, "oauth-sign": { "version": "0.8.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" }, "performance-now": { "version": "0.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" }, "qs": { "version": "6.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" }, "stringstream": { "version": "0.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" }, "tough-cookie": { "version": "2.3.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", "requires": { "punycode": "^1.4.1" @@ -6957,14 +7389,14 @@ "dependencies": { "punycode": { "version": "1.4.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" } } }, "tunnel-agent": { "version": "0.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { "safe-buffer": "^5.0.1" @@ -6974,12 +7406,12 @@ }, "retry": { "version": "0.10.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" }, "rimraf": { "version": "2.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", "requires": { "glob": "^7.0.5" @@ -6987,17 +7419,17 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "semver": { "version": "5.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, "sha": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz", "integrity": "sha1-YDCCL70smCOUn49y7WQR7lzyWq4=", "requires": { "graceful-fs": "^4.1.2", @@ -7006,7 +7438,7 @@ }, "slide": { "version": "1.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" }, "smart-buffer": { @@ -7034,12 +7466,12 @@ }, "sorted-object": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz", "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=" }, "sorted-union-stream": { "version": "2.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz", "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=", "requires": { "from2": "^1.3.0", @@ -7048,7 +7480,7 @@ "dependencies": { "from2": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz", "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=", "requires": { "inherits": "~2.0.1", @@ -7057,7 +7489,7 @@ "dependencies": { "readable-stream": { "version": "1.1.14", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -7068,17 +7500,17 @@ "dependencies": { "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "isarray": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "string_decoder": { "version": "0.10.31", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" } } @@ -7087,7 +7519,7 @@ }, "stream-iterate": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz", "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=", "requires": { "readable-stream": "^2.1.5", @@ -7096,7 +7528,7 @@ "dependencies": { "stream-shift": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" } } @@ -7121,7 +7553,7 @@ }, "ssri": { "version": "4.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/ssri/-/ssri-4.1.6.tgz", "integrity": "sha512-WUbCdgSAMQjTFZRWvSPpauryvREEA+Krn19rx67UlJEJx/M192ZHxMmJXjZ4tkdFm+Sb0SXGlENeQVlA5wY7kA==", "requires": { "safe-buffer": "^5.1.0" @@ -7129,7 +7561,7 @@ }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { "ansi-regex": "^3.0.0" @@ -7137,7 +7569,7 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" } } @@ -7154,22 +7586,22 @@ }, "text-table": { "version": "0.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, "uid-number": { "version": "0.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" }, "umask": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=" }, "unique-filename": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", "requires": { "unique-slug": "^2.0.0" @@ -7177,7 +7609,7 @@ "dependencies": { "unique-slug": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", "requires": { "imurmurhash": "^0.1.4" @@ -7187,12 +7619,12 @@ }, "unpipe": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "update-notifier": { "version": "2.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.2.0.tgz", "integrity": "sha1-G1g3z5DAc22IYncytmHBOPht5y8=", "requires": { "boxen": "^1.0.0", @@ -7207,7 +7639,7 @@ "dependencies": { "boxen": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.1.0.tgz", "integrity": "sha1-sbad1SIwXoB6md7ud329blFnsQI=", "requires": { "ansi-align": "^2.0.0", @@ -7221,7 +7653,7 @@ "dependencies": { "ansi-align": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "requires": { "string-width": "^2.0.0" @@ -7229,17 +7661,17 @@ }, "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" }, "cli-boxes": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" }, "string-width": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -7248,12 +7680,12 @@ "dependencies": { "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { "ansi-regex": "^3.0.0" @@ -7263,7 +7695,7 @@ }, "term-size": { "version": "0.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/term-size/-/term-size-0.1.1.tgz", "integrity": "sha1-hzYLljlsq1dgljcUzaDQy+7K2co=", "requires": { "execa": "^0.4.0" @@ -7271,7 +7703,7 @@ "dependencies": { "execa": { "version": "0.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/execa/-/execa-0.4.0.tgz", "integrity": "sha1-TrZGejaglfq7KXD/nV4/t7zm68M=", "requires": { "cross-spawn-async": "^2.1.1", @@ -7284,7 +7716,7 @@ "dependencies": { "cross-spawn-async": { "version": "2.2.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz", "integrity": "sha1-hF/wwINKPe2dFg2sptOQkGuyiMw=", "requires": { "lru-cache": "^4.0.0", @@ -7293,12 +7725,12 @@ }, "is-stream": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "npm-run-path": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz", "integrity": "sha1-9cMr9ZX+ga6Sfa7FLoL4sACsPI8=", "requires": { "path-key": "^1.0.0" @@ -7306,17 +7738,17 @@ }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "path-key": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz", "integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68=" }, "strip-eof": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" } } @@ -7325,7 +7757,7 @@ }, "widest-line": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-1.0.0.tgz", "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=", "requires": { "string-width": "^1.0.1" @@ -7333,7 +7765,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -7343,12 +7775,12 @@ "dependencies": { "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" @@ -7356,14 +7788,14 @@ "dependencies": { "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" } } }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -7371,7 +7803,7 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" } } @@ -7384,7 +7816,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -7396,17 +7828,17 @@ "dependencies": { "ansi-styles": { "version": "2.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, "escape-string-regexp": { "version": "1.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "has-ansi": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { "ansi-regex": "^2.0.0" @@ -7414,14 +7846,14 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" } } }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -7429,21 +7861,21 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" } } }, "supports-color": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" } } }, "configstore": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.0.tgz", "integrity": "sha1-Rd+QcHPibfoc9LLVL1tgVF6qEdE=", "requires": { "dot-prop": "^4.1.0", @@ -7456,7 +7888,7 @@ "dependencies": { "dot-prop": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.1.1.tgz", "integrity": "sha1-qEk/C3te7sglJbXHWH+n3nyoWcE=", "requires": { "is-obj": "^1.0.0" @@ -7464,14 +7896,14 @@ "dependencies": { "is-obj": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" } } }, "make-dir": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", "integrity": "sha1-l6ARdR6R3YfPre9Ygy67BJNt6Xg=", "requires": { "pify": "^2.3.0" @@ -7479,14 +7911,14 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, "unique-string": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "requires": { "crypto-random-string": "^1.0.0" @@ -7494,7 +7926,7 @@ "dependencies": { "crypto-random-string": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" } } @@ -7503,17 +7935,17 @@ }, "import-lazy": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" }, "is-npm": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" }, "latest-version": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "requires": { "package-json": "^4.0.0" @@ -7521,7 +7953,7 @@ "dependencies": { "package-json": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "requires": { "got": "^6.7.1", @@ -7532,7 +7964,7 @@ "dependencies": { "got": { "version": "6.7.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "requires": { "create-error-class": "^3.0.0", @@ -7550,7 +7982,7 @@ "dependencies": { "create-error-class": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "requires": { "capture-stack-trace": "^1.0.0" @@ -7558,54 +7990,54 @@ "dependencies": { "capture-stack-trace": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" } } }, "duplexer3": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, "get-stream": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, "is-redirect": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, "is-retry-allowed": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" }, "is-stream": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "lowercase-keys": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" }, "timed-out": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, "unzip-response": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" }, "url-parse-lax": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "requires": { "prepend-http": "^1.0.1" @@ -7613,7 +8045,7 @@ "dependencies": { "prepend-http": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" } } @@ -7622,7 +8054,7 @@ }, "registry-url": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "requires": { "rc": "^1.0.1" @@ -7645,7 +8077,7 @@ }, "semver-diff": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "requires": { "semver": "^5.0.3" @@ -7653,19 +8085,19 @@ }, "xdg-basedir": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" } } }, "uuid": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" }, "validate-npm-package-license": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "requires": { "spdx-correct": "~1.0.0", @@ -7674,7 +8106,7 @@ "dependencies": { "spdx-correct": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "requires": { "spdx-license-ids": "^1.0.2" @@ -7682,21 +8114,21 @@ "dependencies": { "spdx-license-ids": { "version": "1.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" } } }, "spdx-expression-parse": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" } } }, "validate-npm-package-name": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", "requires": { "builtins": "^1.0.3" @@ -7704,14 +8136,14 @@ "dependencies": { "builtins": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" } } }, "which": { "version": "1.2.14", - "resolved": false, + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", "requires": { "isexe": "^2.0.0" @@ -7719,14 +8151,14 @@ "dependencies": { "isexe": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" } } }, "worker-farm": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.3.1.tgz", "integrity": "sha1-QzMRK7SbF6oFC4eJXKayys9A5f8=", "requires": { "errno": ">=0.1.1 <0.2.0-0", @@ -7735,7 +8167,7 @@ "dependencies": { "errno": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", "requires": { "prr": "~0.0.0" @@ -7743,26 +8175,26 @@ "dependencies": { "prr": { "version": "0.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=" } } }, "xtend": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.1.0.tgz", "integrity": "sha512-0TZ20a+xcIl4u0+Mj5xDH2yOWdmQiXlKf9Hm+TgDXjTMsEYb+gDrmb8e8UNAzMCitX8NBqG4Z/FUQIyzv/R1JQ==", "requires": { "graceful-fs": "^4.1.11", @@ -8286,7 +8718,6 @@ }, "async-some": { "version": "1.0.2", - "resolved": false, "integrity": "sha1-TYqBYg1ZWHkbW5j4AtMgd3bpVQk=", "requires": { "dezalgo": "^1.0.2" @@ -8378,7 +8809,6 @@ }, "dezalgo": { "version": "1.0.3", - "resolved": false, "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", "requires": { "asap": "^2.0.0", @@ -8453,7 +8883,6 @@ }, "github-url-from-username-repo": { "version": "1.0.2", - "resolved": false, "integrity": "sha1-fdeTMNKr5pwQws73lxTJchV5Hfo=" }, "glob": { @@ -8595,7 +9024,6 @@ }, "nopt": { "version": "3.0.6", - "resolved": false, "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "requires": { "abbrev": "1" @@ -8886,7 +9314,6 @@ }, "read-installed": { "version": "4.0.3", - "resolved": false, "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", "requires": { "debuglog": "^1.0.1", @@ -8905,7 +9332,6 @@ }, "readdir-scoped-modules": { "version": "1.0.2", - "resolved": false, "integrity": "sha1-n6+jfShr5dksuuve4DDcm19AZ0c=", "requires": { "debuglog": "^1.0.1", @@ -9544,7 +9970,6 @@ }, "validate-npm-package-name": { "version": "2.2.2", - "resolved": false, "integrity": "sha1-9laVsi9zJEQgGaPH+jmm5/0pkIU=", "requires": { "builtins": "0.0.7" @@ -9572,7 +9997,6 @@ }, "write-file-atomic": { "version": "1.1.4", - "resolved": false, "integrity": "sha1-sfUtwujcDjywTRh6JfdYo4qQyjs=", "requires": { "graceful-fs": "^4.1.2", @@ -9716,6 +10140,18 @@ } } }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -9731,6 +10167,29 @@ } } }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", + "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", @@ -9755,6 +10214,18 @@ } } }, + "object.values": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", + "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -9776,6 +10247,12 @@ "wrappy": "1" } }, + "opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "dev": true + }, "opn": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/opn/-/opn-6.0.0.tgz", @@ -9827,9 +10304,9 @@ } }, "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", "dev": true }, "p-limit": { @@ -9877,6 +10354,132 @@ "semver": "^6.2.0" }, "dependencies": { + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -9939,6 +10542,15 @@ "readable-stream": "^2.1.5" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", @@ -9950,6 +10562,26 @@ "is-glob": "^2.0.0" } }, + "parse-json": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "dependencies": { + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + } + } + }, "parse5": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", @@ -10004,6 +10636,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "pause-stream": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", @@ -10022,11 +10660,65 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, "plantuml-encoder": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/plantuml-encoder/-/plantuml-encoder-1.4.0.tgz", "integrity": "sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==" }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -10035,7 +10727,8 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "optional": true }, "prepend-http": { "version": "2.0.0", @@ -10302,6 +10995,12 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, "randomatic": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", @@ -10879,18 +11578,30 @@ "path-parse": "^1.0.6" } }, + "resolve-alpn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz", + "integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", "dev": true, "requires": { - "lowercase-keys": "^1.0.0" + "lowercase-keys": "^2.0.0" } }, "ret": { @@ -10948,14 +11659,19 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", - "optional": true + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, "semver-diff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", @@ -10973,6 +11689,12 @@ } } }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true + }, "semver-utils": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/semver-utils/-/semver-utils-1.1.4.tgz", @@ -11091,6 +11813,12 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", @@ -11408,6 +12136,12 @@ "minipass": "^3.1.1" } }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, "stack-chain": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-2.0.0.tgz", @@ -11482,6 +12216,26 @@ "strip-ansi": "^4.0.0" } }, + "string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -11503,6 +12257,12 @@ "ansi-regex": "^3.0.0" } }, + "strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -11526,6 +12286,57 @@ "puppeteer": "^3.0.2" } }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + } + } + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -11690,7 +12501,7 @@ "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tough-cookie": { "version": "2.5.0", @@ -11748,6 +12559,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "optional": true, "requires": { "prelude-ls": "~1.1.2" } @@ -11854,7 +12666,7 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=" + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "unix-crypt-td-js": { "version": "1.1.4", @@ -11866,6 +12678,12 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -11988,7 +12806,7 @@ "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" } @@ -12031,6 +12849,39 @@ "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", "dev": true }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -12119,6 +12970,12 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", + "dev": true + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", @@ -12282,6 +13139,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "dev": true + }, "yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", diff --git a/package.json b/package.json index 4dccf0c38..4df0bc57d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "documentation", - "version": "11.2.0", + "version": "11.2.1", "description": "Mojaloop Documentation GitBook Project", "dependencies": { "express": "4.17.1", @@ -21,28 +21,43 @@ "svgexport": "0.4.1" }, "devDependencies": { + "directory-tree": "^2.2.5", + "got": "^11.8.0", + "husky": "^4.2.5", "license-checker": "25.0.1", + "node-plantuml": "^0.5.0", "npm-audit-resolver": "2.2.1", - "npm-check-updates": "7.0.2" + "npm-check-updates": "7.0.2", + "plantuml-encoder": "^1.4.0", + "strip-comments": "^2.0.1", + "svgo": "^1.3.2" }, "scripts": { - "run": "npm run gitbook:serve", - "start": "npm run gitbook:serveNoReload", - "gitbook:install": "gitbook install", - "gitbook:build": "gitbook build", - "gitbook:serve": "gitbook serve --port 8989", - "gitbook:serveNoReload": "gitbook serve --no-live --port 8989", - "gitbook:export:pdf": "gitbook pdf ./", + "audit:check": "SHELL=sh check-audit", + "audit:resolve": "SHELL=sh resolve-audit", + "build:plantuml:all": "./scripts/_build_plantuml_all.sh", + "build:plantuml:diff": "./scripts/_build_plantuml_diff.sh", + "dep:check": "npx ncu -e 2", + "dep:update": "npx ncu -u", "docker:build": "docker build --no-cache -t mojaloop/documentation .", "docker:push": "docker push mojaloop/documentation", "docker:run": "docker run --rm -it --name mojadoc -p 8989:8989 mojaloop/documentation", "express:run": "node index.js", - "audit:resolve": "SHELL=sh resolve-audit", - "audit:check": "SHELL=sh check-audit", - "license:list": "license-checker . --excludePackages `cat .licenseignore | grep '^[^#;]' | awk 'BEGIN { ORS=\"\" } { print p$0\";\"; } END { print \n }'` --production --csv", + "gitbook:build": "gitbook build", + "gitbook:export:pdf": "gitbook pdf ./", + "gitbook:install": "gitbook install", + "gitbook:serve": "gitbook serve --port 8989", + "gitbook:serveNoReload": "gitbook serve --no-live --port 8989", "license:check": "npm run license:list -- --failOn `cat .licensebanned | grep '^[^#;]' | awk 'BEGIN { ORS=\"\" } { print p$0\";\"; } END { print \n }'`", - "dep:check": "npx ncu -e 2", - "dep:update": "npx ncu -u" + "license:list": "license-checker . --excludePackages `cat .licenseignore | grep '^[^#;]' | awk 'BEGIN { ORS=\"\" } { print p$0\";\"; } END { print \n }'` --production --csv", + "run": "npm run gitbook:serve", + "start": "npm run gitbook:serveNoReload" + }, + "husky": { + "hooks": { + "pre-commit": "npm run build:plantuml:diff", + "post-commit": "git update-index --again" + } }, "repository": { "type": "git", diff --git a/scripts/_build_plantuml_all.sh b/scripts/_build_plantuml_all.sh new file mode 100755 index 000000000..408cad363 --- /dev/null +++ b/scripts/_build_plantuml_all.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PUML_PORT=9999 +export PUML_BASE_URL=http://localhost:${PUML_PORT} + +## +# searches through repo for plantuml sources +# and exports them using `node-plantuml` +## + +trap ctrl_c INT +function ctrl_c() { + echo "exit early - stopping docker" + docker stop puml-local + exit 1 +} + +# run the docker puml server +docker run -d --rm \ + --name puml-local \ + -p ${PUML_PORT}:8080 \ + plantuml/plantuml-server:jetty-v1.2020.21 + +# note: this `find` is not optimal, but both BSD and GNU compatible +for i in $(find ${DIR}/.. -name '*.p*uml' | grep -v node_modules); do + echo "rendering .puml -> .svg for diagram diagram: $i" + + ${DIR}/_render_svg.js $i +done + + +docker stop puml-local \ No newline at end of file diff --git a/scripts/_build_plantuml_diff.sh b/scripts/_build_plantuml_diff.sh new file mode 100755 index 000000000..99a0a7529 --- /dev/null +++ b/scripts/_build_plantuml_diff.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PUML_PORT=9999 +export PUML_BASE_URL=http://localhost:${PUML_PORT} + +## +# searches through staged files for .puml/.plantuml sources +# and updates svgs them using `node-plantuml` +## + +trap ctrl_c INT +function ctrl_c() { + echo "exit early - stopping docker" + docker stop puml-local + exit 1 +} + +# run the docker puml server +docker run -d --rm \ + --name puml-local \ + -p ${PUML_PORT}:8080 \ + plantuml/plantuml-server:jetty-v1.2020.21 + +for i in $(git diff --staged --name-only `find ${DIR}/.. -name '*.p*uml'`); do + echo "rendering .puml -> .svg for diagram diagram: $i" + ${DIR}/_render_svg.js $1 +done + +docker stop puml-local + +git add ./**/*.svg diff --git a/scripts/_render_svg.js b/scripts/_render_svg.js new file mode 100755 index 000000000..6a7d5d0ce --- /dev/null +++ b/scripts/_render_svg.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node + + +/** + * Uses plantuml server to render a puml to svg + */ + +const fs = require('fs') +const path = require('path') +const util = require('util') +const got = require('got') +const SVGO = require('svgo') +const plantumlEncoder = require('plantuml-encoder') + +const rendererBaseUrl = process.env.PUML_BASE_URL || 'http://www.plantuml.com/plantuml' + +svgo = new SVGO({ + js2svg: { pretty: true, indent: 2 }, + plugins: [ + { removeComments: true }, + ] +}); + +async function main() { + let [_, _script, inputPath, outputPath] = process.argv + + if (!inputPath) { + console.log("usage: ./_render_svg.js []") + process.exit(1) + } + + // If not specified, replace .puml or .plantuml with `.svg` + if (!outputPath) { + outputPath = inputPath.replace('.puml', '.svg') + .replace('.plantuml', '.svg') + } + + const rawPumlContents = fs.readFileSync(inputPath) + const encoded = plantumlEncoder.encode(rawPumlContents.toString()) + const url = path.join(rendererBaseUrl, 'svg', encoded) + let result + try { + result = await got.get(url) + } catch (err) { + console.log('http request failed to render puml with error', err.message) + if (err.message.indexOf('Response code 403') > -1) { + console.log('Note: sometimes the public puml renderer fails when the input diagrams are too large. Try running your own renderer server with docker.') + } + process.exit(1) + } + + // Strip comments and prettify svg + // This makes sure that our .svg files are deterministic and diffable + const formatted = await svgo.optimize(result.body) + fs.writeFileSync(outputPath, formatted.data) +} + +main() \ No newline at end of file