From d2027f7203dbb0d91e603a777a63e6f78a8831e2 Mon Sep 17 00:00:00 2001 From: Steven Oderayi Date: Wed, 10 Jun 2020 12:13:45 +0100 Subject: [PATCH 01/30] #1325: Bulk transfers and bulk quotes support (#49) * Add support for bulk transfers * Add bulkTransfers call from backend to outbound API * Add bulk quotes support * WIP: Add bulk transfer model and handler * Fix audit issues * Make sim, report, and test ports configuraable * Restore default ports in docker-compose * Port config update * Updates for bulk quotes and bulk transfers * Add POST /bulkQuotes, remove PUT /bulkTransfers/{bulkTransferId}. Fix API spec bugs * Update unit test for config.js * Add tests for bulkQuotes model * Fix audit issues * Add tests for bulk quotes * Update unit tests for simulator handler * Format code * Update contributors list * Fix bug with POST bulkQuotes and tests * Update contributors list * Update api spec * Add getBulkQuoteById and getBulkTransferById * Add unit tests for bulk quotes and bulk transfers handlers * Resolve audit issues * Cleanup * Update package.json * Update src/package.json Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> * Fix audit issues Co-authored-by: Sam <10507686+elnyry-sam-k@users.noreply.github.com> --- .gitignore | 5 +- src/audit-resolve.json | 40 ++-- src/config.js | 8 + src/index.js | 9 +- src/models/bulkQuote.js | 123 ++++++++++++ src/models/bulkTransfer.js | 100 ++++++++++ src/models/constants.js | 31 +++- src/models/model.js | 12 +- src/package-lock.json | 2 +- src/package.json | 3 +- src/sim-backend.env | 5 + src/simulator/api.yaml | 351 ++++++++++++++++++++++++++++++++++- src/simulator/handlers.js | 75 ++++++++ src/test-api/api.yaml | 37 ++-- src/test-api/client.js | 40 +++- src/test-api/handlers.js | 22 ++- src/test/constants.js | 176 +++++++++++++++--- src/test/model.js | 113 ++++++++++- src/test/simulator.js | 95 +++++++++- src/test/test-api.js | 119 +++++++++--- src/test/unit/TestUtils.js | 13 ++ src/test/unit/config.test.js | 8 + 22 files changed, 1296 insertions(+), 91 deletions(-) create mode 100644 src/models/bulkQuote.js create mode 100644 src/models/bulkTransfer.js diff --git a/.gitignore b/.gitignore index e47ab085..93d2e811 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,7 @@ simulator.log # environments docker-compose.local.yml goldenpayerfsp -goldenpayeefsp \ No newline at end of file +goldenpayeefsp + +#vscode configs +.vscode/ \ No newline at end of file diff --git a/src/audit-resolve.json b/src/audit-resolve.json index 902945d6..6e030d9c 100644 --- a/src/audit-resolve.json +++ b/src/audit-resolve.json @@ -1,14 +1,32 @@ { - "1300|nyc>istanbul-reports>handlebars": { - "fix": 1 + "decisions": { + "1300|nyc>istanbul-reports>handlebars": { + "madeAt": 0, + "decision": "fix" + }, + "1316|nyc>istanbul-reports>handlebars": { + "madeAt": 0, + "decision": "fix" + }, + "1324|nyc>istanbul-reports>handlebars": { + "madeAt": 0, + "decision": "fix" + }, + "1325|nyc>istanbul-reports>handlebars": { + "madeAt": 0, + "decision": "fix" + }, + "1500|npm-audit-resolver>yargs-unparser>yargs>yargs-parser": { + "decision": "ignore", + "madeAt": 1591787086979, + "expiresAt": 1592391879076 + }, + "1500|npm-audit-resolver>audit-resolve-core>yargs-parser": { + "decision": "ignore", + "madeAt": 1591787090589, + "expiresAt": 1592391879076 + } }, - "1316|nyc>istanbul-reports>handlebars": { - "fix": 1 - }, - "1324|nyc>istanbul-reports>handlebars": { - "fix": 1 - }, - "1325|nyc>istanbul-reports>handlebars": { - "fix": 1 - } + "rules": {}, + "version": 1 } \ No newline at end of file diff --git a/src/config.js b/src/config.js index 1e809764..92887f64 100644 --- a/src/config.js +++ b/src/config.js @@ -52,6 +52,11 @@ const config = { key: null, }, }, + ports: { + simulatorApi: 3000, + reportApi: 3002, + testApi: 3003, + }, }; @@ -70,6 +75,9 @@ const setConfig = async (cfg) => { readFile(cfg.SERVER_KEY_PATH), ]); } + config.ports.simulatorApi = cfg.SIMULATOR_API_LISTEN_PORT || config.ports.simulatorApi; + config.ports.reportApi = cfg.REPORT_API_LISTEN_PORT || config.ports.reportApi; + config.ports.testApi = cfg.TEST_API_LISTEN_PORT || config.ports.testApi; }; diff --git a/src/index.js b/src/index.js index c3c25b5d..7d64be6b 100644 --- a/src/index.js +++ b/src/index.js @@ -19,6 +19,9 @@ - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; @@ -255,9 +258,9 @@ const testApi = new Koa(); // If config specifies TLS, start an HTTPS server; otherwise HTTP let simServer; const conf = getConfig(); - const simulatorPort = 3000; - const reportPort = 3002; - const testApiPort = 3003; + const simulatorPort = conf.ports.simulatorApi; + const reportPort = conf.ports.reportApi; + const testApiPort = conf.ports.testApi; if (conf.tls.mutualTLS.enabled || conf.tls.enabled) { if (!(conf.tls.creds.ca && conf.tls.creds.cert && conf.tls.creds.key)) { diff --git a/src/models/bulkQuote.js b/src/models/bulkQuote.js new file mode 100644 index 00000000..c76c3132 --- /dev/null +++ b/src/models/bulkQuote.js @@ -0,0 +1,123 @@ +/***** + License + -------------- + Copyright © 2020 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + * ModusBox + - Steven Oderayi + -------------- + ******/ +'use strict'; + +/** + * @file Simulator resources BulkQuote model + * @description Defines the bulk quote model structure and operations within the simulator. + */ +const { bulkQuoteTable } = require('./constants'); + +// eslint-disable-next-line import/no-unresolved +require('dotenv').config(); + +/** + * @typedef {Object} BulkQuote + * + * Data model for bulk quotes. + */ +module.exports = class BulkQuote { + constructor(db) { + this.db = db; + } + + /** + * Gets a BulkQuote with the provided bulkQuoteId + * + * @async + * @param {String} bulkQuoteId The bulk quote Id. + * @returns {Promise} BulkQuote object. + */ + async get(bulkQuoteId) { + const res = await this.db.get(`SELECT * FROM ${bulkQuoteTable} WHERE id = ?`, [bulkQuoteId]); + return res; + } + + /** + * Creates a bulk quote. + * + * @async + * @param {Object} bulkQuoteRequest The bulk quote request object. + * @returns {Promise} The BulkQuote response. + */ + async create(bulkQuoteRequest) { + const { bulkQuoteId } = bulkQuoteRequest; + const individualQuoteResults = bulkQuoteRequest.individualQuotes.map((quote) => { + const fee = Math + .floor(Number(quote.amount) * Number(process.env.FEE_MULTIPLIER)) + .toString(); + return { + quoteId: quote.quoteId, + transactionId: quote.transactionId, + transferAmount: quote.amount, + transferAmountCurrency: quote.currency, + payeeFspFeeAmount: fee, + payeeFspFeeAmountCurrency: quote.currency, + payeeFspCommissionAmount: fee, + payeeFspCommissionAmountCurrency: quote.currency, + }; + }); + const response = { + bulkQuoteId, + individualQuoteResults, + }; + const reqStr = JSON.stringify(bulkQuoteRequest); + const resStr = JSON.stringify(response); + const created = new Date().toISOString().slice(0, 19); + + await this.db.get(`INSERT INTO ${bulkQuoteTable} (id, request, response, created) VALUES (?, ?, ?, ?)`, + [bulkQuoteId, reqStr, resStr, created]); + + return response; + } + + /** + * Updates a bulk quote + * + * @param {String} currentBulkOuoteId The bulk quote id to update. + * @param {Object} newBulkQuoteRequest The new BulkQuote object. + */ + async update(currentBulkOuoteId, newBulkQuoteRequest) { + const response = newBulkQuoteRequest.individualQuotes.map( + (quote) => ({ transferAmount: quote.amount, transferAmountCurrency: quote.currency }), + ); + const reqStr = JSON.stringify(newBulkQuoteRequest); + const resStr = JSON.stringify(response); + + await this.db.run(` + UPDATE ${bulkQuoteTable} + SET id = ?, request = ?, response = ? + WHERE id = ?`, [newBulkQuoteRequest.bulkQuoteId, reqStr, resStr, currentBulkOuoteId]); + } + + /** + * Deletes a BulkQuote. + * + * @async + * @param {String} bulkQuoteId The bulk quote id. + */ + async delete(bulkQuoteId) { + await this.db.run(`DELETE FROM ${bulkQuoteTable} WHERE id = ?`, [bulkQuoteId]); + } +}; diff --git a/src/models/bulkTransfer.js b/src/models/bulkTransfer.js new file mode 100644 index 00000000..9749af6c --- /dev/null +++ b/src/models/bulkTransfer.js @@ -0,0 +1,100 @@ +/***** + License + -------------- + Copyright © 2020 Bill & Melinda Gates Foundation + The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Gates Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Gates Foundation + - Name Surname + * ModusBox + - Steven Oderayi + -------------- + ******/ +'use strict'; + +/** + * @file Simulator resources BulkTransfer model + * @description Defines the bulk transfer model structure and operations within the simulator. + */ +const { bulkTransferTable } = require('./constants'); +require('dotenv').config(); + +/** + * @typedef {Object} BulkTransfer + * + * Data model for bulk transfer. + */ +module.exports = class BulkTransfer { + constructor(db) { + this.db = db; + } + + /** + * Retrieves a bulk transfer + * + * @async + * @param {String} bulkTransferId The bulk transfer id. + * @returns {Promise} BulkTransfer object. + */ + async get(bulkTransferId) { + const res = await this.db.get(`SELECT * FROM ${bulkTransferTable} WHERE id = ?`, [bulkTransferId]); + return res; + } + + /** + * Creates a bulk transfer. + * + * @async + * @param {Object} bulkTransferRequest The bulk transfer request object. + * @returns {Promise} BulkTransfer response. + */ + async create(bulkTransferRequest) { + const { bulkTransferId } = bulkTransferRequest; + const response = { bulkTransferId }; + const reqStr = JSON.stringify(bulkTransferRequest); + const resStr = JSON.stringify(response); + + await this.db.get(`INSERT INTO ${bulkTransferTable} (id, request, response) VALUES (?, ?, ?)`, [bulkTransferId, reqStr, resStr]); + + return response; + } + + /** + * Updates a bulk transfer + * + * @param {String} bulkTransferId The current bulk transfer id. + * @param {Object} BulkTansferRequest The new BulkTransfer object. + */ + async update(currentBulkTransferId, bulkTransferRequest) { + const { homeTransactionId: newBulkTransferId } = bulkTransferRequest; + const response = { newBulkTransferId }; + const reqStr = JSON.stringify(bulkTransferRequest); + const resStr = JSON.stringify(response); + + await this.db.run(` + UPDATE ${bulkTransferTable} + SET id = ?, request = ?, response = ? + WHERE id = ?`, [newBulkTransferId, reqStr, resStr, currentBulkTransferId]); + } + + /** + * Deletes a bulk transfer. + * + * @async + * @param {String} bulkTransferId The bulk transfer id. + */ + async delete(bulkTransferId) { + await this.db.run(`DELETE FROM ${bulkTransferTable} WHERE id = ?`, [bulkTransferId]); + } +}; diff --git a/src/models/constants.js b/src/models/constants.js index 0d8929ad..ef7f1bf2 100644 --- a/src/models/constants.js +++ b/src/models/constants.js @@ -26,6 +26,8 @@ const partyTable = 'party'; const quoteTable = 'quote'; const transactionRequestTable = 'transactionRequest'; const transferTable = 'transfer'; +const bulkQuoteTable = 'bulkQuote'; +const bulkTransferTable = 'bulkTransfer'; const partyExtensionTable = 'partyExtension'; const createPartyTable = ` @@ -59,6 +61,16 @@ CREATE TABLE IF NOT EXISTS ${quoteTable} ( ) `; +const createBulkQuoteTable = ` +CREATE TABLE IF NOT EXISTS ${bulkQuoteTable} ( + id TEXT NOT NULL PRIMARY KEY, + request TEXT, + response TEXT, + created TIMESTAMP + CHECK(id <> '') +) +`; + const createTransactionRequestTable = ` CREATE TABLE IF NOT EXISTS ${transactionRequestTable} ( id TEXT NOT NULL PRIMARY KEY, @@ -78,15 +90,28 @@ CREATE TABLE IF NOT EXISTS ${transferTable} ( ) `; +const createBulkTransferTable = ` +CREATE TABLE IF NOT EXISTS ${bulkTransferTable} ( + id TEXT NOT NULL PRIMARY KEY, + request TEXT, + response TEXT, + CHECK(id <> '') +) +`; + module.exports = { partyTable, quoteTable, + bulkQuoteTable, + transferTable, + bulkTransferTable, transactionRequestTable, + partyExtensionTable, createPartyTable, createQuoteTable, - createTransactionRequestTable, + createBulkQuoteTable, + createBulkTransferTable, createTransferTable, - transferTable, - partyExtensionTable, + createTransactionRequestTable, createPartyExtensionTable, }; diff --git a/src/models/model.js b/src/models/model.js index ea655476..7b5133f3 100644 --- a/src/models/model.js +++ b/src/models/model.js @@ -31,13 +31,17 @@ const sqlite = require('sqlite'); const Party = require('./party'); const Quote = require('./quote'); +const BulkQuote = require('./bulkQuote'); const TransactionRequest = require('./transactionrequest'); const Transfer = require('./transfer'); +const BulkTransfer = require('./bulkTransfer'); const { createPartyTable, - createTransferTable, createQuoteTable, + createBulkQuoteTable, + createTransferTable, + createBulkTransferTable, createTransactionRequestTable, createPartyExtensionTable, } = require('./constants'); @@ -54,8 +58,10 @@ module.exports = class Model { this.db = null; this.party = null; this.quote = null; + this.bulkQuote = null; this.transactionrequest = null; this.transfer = null; + this.bulkTransfer = null; } /** @@ -89,11 +95,15 @@ module.exports = class Model { await this.db.run(createTransactionRequestTable); await this.db.run(createTransferTable); await this.db.run(createPartyExtensionTable); + await this.db.run(createBulkQuoteTable); + await this.db.run(createBulkTransferTable); this.party = new Party(this.db); this.quote = new Quote(this.db); + this.bulkQuote = new BulkQuote(this.db); this.transactionrequest = new TransactionRequest(this.db); this.transfer = new Transfer(this.db); + this.bulkTransfer = new BulkTransfer(this.db); } catch (err) { throw new Error(err); } diff --git a/src/package-lock.json b/src/package-lock.json index fbc978a6..ef1b6d17 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "9.4.1", + "version": "10.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index aa259586..c2ab62e3 100644 --- a/src/package.json +++ b/src/package.json @@ -1,12 +1,13 @@ { "name": "mojaloop-simulator", - "version": "9.4.1", + "version": "10.4.0", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", "author": "Matt Kingston, ModusBox Inc.", "contributors": [ "Matt Kingston ", + "Steven Oderayi ", "ModusBox", "Mowali" ], diff --git a/src/sim-backend.env b/src/sim-backend.env index e8b2074d..c2aa3c04 100644 --- a/src/sim-backend.env +++ b/src/sim-backend.env @@ -42,3 +42,8 @@ FEE_MULTIPLIER=0.05 # e.g. a rule can be used to trigger NDC errors given transfers between certain limits. RULES_FILE=./rules.json + +# Ports for simulator, report, and test APIs +SIMULATOR_API_LISTEN_PORT=3000 +REPORT_API_LISTEN_PORT=3002 +TEST_API_LISTEN_PORT=3003 diff --git a/src/simulator/api.yaml b/src/simulator/api.yaml index a232cd33..40a56508 100644 --- a/src/simulator/api.yaml +++ b/src/simulator/api.yaml @@ -215,10 +215,137 @@ paths: application/json: schema: $ref: '#/components/schemas/errorResponse' + + /bulkQuotes: + post: + summary: Requests a bulk quote + tags: + - BulkQuotes + requestBody: + description: Incoming request for a bulk quotation + content: + application/json: + schema: + $ref: '#/components/schemas/bulkQuoteRequest' + responses: + 200: + description: A response to the bulk quote request + content: + application/json: + schema: + $ref: '#/components/schemas/bulkQuoteResponse' + 400: + description: Malformed or missing required headers or parameters + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + 500: + description: An error occured processing the request + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + + /bulkQuotes/{idValue}: + get: + summary: Requests information relating to a bulk quote identified by the specified identifier value + tags: + - BulkQuotes + parameters: + - name: idValue + in: path + required: true + schema: + $ref: '#/components/schemas/idValue' + responses: + 200: + description: Response containing details of the requested bulk quote + content: + application/json: + schema: + $ref: '#/components/schemas/bulkQuoteResponse' + 404: + description: The bulk quote specified by the provided identifier value is not known to the server + 400: + description: Malformed or missing required headers or parameters + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + 500: + description: An error occured processing the request + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + + /bulkTransfers: + post: + summary: Execute bulk transfer of funds from an external account to internal accounts + tags: + - BulkTransfers + requestBody: + description: An incoming bulk transfer request + content: + application/json: + schema: + $ref: '#/components/schemas/bulkTransferRequest' + responses: + 200: + description: The bulk transfer was accepted + content: + application/json: + schema: + $ref: '#/components/schemas/bulkTransferResponse' + 400: + description: Malformed or missing required headers or parameters + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + 500: + description: An error occured processing the request + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + + /bulkTransfers/{idValue}: + get: + summary: Requests information relating to a bulk transfer identified by the specified identifier value + tags: + - BulkTransfers + parameters: + - name: idValue + in: path + required: true + schema: + $ref: '#/components/schemas/idValue' + responses: + 200: + description: Response containing details of the requested bulk transfer + content: + application/json: + schema: + $ref: '#/components/schemas/bulkTransferResponse' + 404: + description: The bulk transfer specified by the provided identifier value is not known to the server + 400: + description: Malformed or missing required headers or parameters + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + 500: + description: An error occured processing the request + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' components: schemas: - quoteRequest: type: object description: A request for a quote for transfer from the DFSP backend @@ -580,6 +707,227 @@ components: merchantClassificationCode: type: string description: Up to 4 digits specifying the senders merchant classification, if known and applicable + + bulkQuoteRequest: + type: object + description: A request for a bulk quote + required: + - bulkQuoteId + - from + - individualQuotes + properties: + bulkQuoteId: + $ref: '#/components/schemas/bulkQuoteId' + from: + $ref: '#/components/schemas/transferParty' + description: Information about the Payer in the proposed financial transaction. + geoCode: + $ref: '#/components/schemas/geoCode' + description: Longitude and Latitude of the initiating Party. Can be used to detect fraud. + expiration: + $ref: '#/components/schemas/timestamp' + description: An optional deadline for responding to the quote request + individualQuotes: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: '#/components/schemas/IndividualQuote' + + bulkQuoteResponse: + type: object + description: A response to a request for a bulk quote + required: + - bulkQuoteId + - individualQuoteResults + properties: + bulkQuoteId: + $ref: '#/components/schemas/bulkQuoteId' + description: Id of the bulk quote this response relates to + expiration: + $ref: '#/components/schemas/timestamp' + description: Timestamp specifying the validity period of the bulk quotation + individualQuoteResults: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: '#/components/schemas/IndividualQuoteResult' + description: Fees for each individual transaction, if any of them are charged per + transaction. + + IndividualQuote: + type: object + description: Data model for individual quote in a bulk quote request + required: + - quoteId + - transactionId + - to + - amountType + - amount + - currency + - transactionType + - initiator + - initiatorType + properties: + quoteId: + $ref: '#/components/schemas/quoteId' + transactionId: + $ref: '#/components/schemas/transactionId' + description: Identifier for the transaction, decided by the Payer FSP during the creation of the quote + to: + $ref: '#/components/schemas/transferParty' + description: Information about the Payee in the proposed financial transaction. + amountType: + $ref: '#/components/schemas/amountType' + description: 'SEND for send amount, RECEIVE for receive amount.' + amount: + $ref: '#/components/schemas/money' + description: Depending on amountType. If SEND - The amount the Payer would like to send, that is, the amount that should be withdrawn from the Payer account including any fees. The amount is updated by each participating entity in the transaction. If RECEIVE - The amount the Payee should receive, that is, the amount that should be sent to the receiver exclusive any fees. The amount is not updated by any of the participating entities. + currency: + $ref: '#/components/schemas/currency' + feesAmount: + $ref: '#/components/schemas/money' + description: The fees in the transaction. The fees element should be empty if fees should be non-disclosed. The fees element should be non-empty if fees should be disclosed. + feesCurrency: + $ref: '#/components/schemas/currency' + transactionType: + $ref: '#/components/schemas/transactionType' + description: Type of transaction for which the quote is requested. + initiator: + $ref: '#/components/schemas/initiator' + description: Specifies if the initiator of the transfer is the payer or payee + initiatorType: + $ref: '#/components/schemas/initiatorType' + description: Specifies the type of the transaction initiator + note: + type: string + minLength: 1 + maxLength: 128 + description: An optional note associated with the quote + + IndividualQuoteResult: + type: object + description: Data model for individual quote in a bulk quote response + properties: + quoteId: + $ref: '#/components/schemas/quoteId' + description: Identifies quote message. + transferAmount: + $ref: '#/components/schemas/money' + description: The amount of money that the Payer FSP should transfer to the Payee FSP + transferAmountCurrency: + $ref: '#/components/schemas/currency' + description: The currency of the transferAmount + payeeReceiveAmount: + $ref: '#/components/schemas/money' + description: The amount that the Payee should receive in the end-to-end transaction. Optional as the Payee FSP might not want to disclose any optional Payee fees + payeeReceiveAmountCurrency: + $ref: '#/components/schemas/currency' + description: The currency of the payeeReceiveAmount + payeeFspFeeAmount: + $ref: '#/components/schemas/money' + description: Payee FSP’s part of the transaction fee + payeeFspFeeAmountCurrency: + $ref: '#/components/schemas/currency' + description: The currency of the payeeFspFeeAmount + payeeFspCommissionAmount: + $ref: '#/components/schemas/money' + description: Transaction commission from the Payee FSP + payeeFspCommissionAmountCurrency: + $ref: '#/components/schemas/currency' + description: Currency of the payeeFspCommissionAmount + + bulkQuoteId: + pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ + type: string + description: A Mojaloop API bulk quote identifier (UUID) + + bulkTransferRequest: + type: object + required: + - bulkTransferId + - from + - individualTransfers + properties: + bulkTransferId: + $ref: '#/components/schemas/bulkTransferId' + bulkQuote: + $ref: '#/components/schemas/bulkQuoteResponse' + from: + $ref: '#/components/schemas/transferParty' + individualTransfers: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: '#/components/schemas/IndividualTransfer' + + IndividualTransfer: + type: object + description: Data model for individual transfer in a bulk transfer request + required: + - transferId + - to + - amount + - currency + properties: + transferId: + $ref: '#/components/schemas/transferId' + to: + $ref: '#/components/schemas/transferParty' + description: Information about the Payee in the proposed financial transaction. + amountType: + $ref: '#/components/schemas/amountType' + description: 'SEND for send amount, RECEIVE for receive amount.' + amount: + $ref: '#/components/schemas/money' + description: Depending on amountType. If SEND - The amount the Payer would like to send, that is, the amount that should be withdrawn from the Payer account including any fees. The amount is updated by each participating entity in the transaction. If RECEIVE - The amount the Payee should receive, that is, the amount that should be sent to the receiver exclusive any fees. The amount is not updated by any of the participating entities. + currency: + $ref: '#/components/schemas/currency' + feesAmount: + $ref: '#/components/schemas/money' + description: The fees in the transaction. The fees element should be empty if fees should be non-disclosed. The fees element should be non-empty if fees should be disclosed. + feesCurrency: + $ref: '#/components/schemas/currency' + transactionType: + $ref: '#/components/schemas/transactionType' + description: Type of transaction for which the quote is requested. + initiator: + $ref: '#/components/schemas/initiator' + description: Specifies if the initiator of the transfer is the payer or payee + initiatorType: + $ref: '#/components/schemas/initiatorType' + description: Specifies the type of the transaction initiator + note: + type: string + minLength: 1 + maxLength: 128 + description: An optional note associated with the quote + + bulkTransferResponse: + type: object + required: + - homeTransactionId + properties: + bulkTransferId: + $ref: '#/components/schemas/bulkTransferId' + homeTransactionId: + type: string + description: Transaction ID from the DFSP backend, used to reconcile transactions between the switch and DFSP backend systems + from: + $ref: '#/components/schemas/transferParty' + individualTransfers: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: '#/components/schemas/IndividualTransfer' + + bulkTransferId: + pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ + type: string + description: A Mojaloop API transfer identifier (UUID) geoCode: type: object @@ -597,6 +945,7 @@ components: type: string pattern: ^(\+|-)?(?:90(?:(?:\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\.[0-9]{1,6})?))$ description: The API data type Latitude is a JSON String in a lexical format that is restricted by a regular expression for interoperability reasons. + longitude: type: string pattern: ^(\+|-)?(?:180(?:(?:\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\.[0-9]{1,6})?))$ diff --git a/src/simulator/handlers.js b/src/simulator/handlers.js index 4e57f773..d501ea71 100644 --- a/src/simulator/handlers.js +++ b/src/simulator/handlers.js @@ -18,6 +18,9 @@ * Gates Foundation - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; @@ -105,6 +108,37 @@ const postQuotes = async (ctx) => { } }; +const postBulkQuotes = async (ctx) => { + try { + const res = await ctx.state.model.bulkQuote.create(ctx.request.body); + ctx.state.logger.log(`postBulkQuotes is returning body: ${util.inspect(res)}`); + ctx.response.body = res; + ctx.response.status = 200; + } catch (err) { + ctx.state.logger.log(`Error in postBulkQuotes: ${getStackOrInspect(err)}`); + ctx.response.body = ApiErrorCodes.SERVER_ERROR; + ctx.response.status = 500; + } +}; + + +const getBulkQuoteById = async (ctx) => { + try { + const { idValue } = ctx.state.path.params; + const res = await ctx.state.model.bulkQuote.get(idValue); + if (!res) { + ctx.response.body = ApiErrorCodes.ID_NOT_FOUND; + ctx.response.status = 404; + return; + } + ctx.response.body = res; + ctx.response.status = 200; + } catch (err) { + ctx.response.body = ApiErrorCodes.SERVER_ERROR; + ctx.response.status = 500; + } +}; + const postTransactionRequests = async (ctx) => { try { const res = await ctx.state.model.transactionrequest.create(ctx.request.body); @@ -118,6 +152,35 @@ const postTransactionRequests = async (ctx) => { } }; +const postBulkTransfers = async (ctx) => { + try { + const res = await ctx.state.model.bulkTransfer.create(ctx.request.body); + ctx.state.logger.log(`postBulkTransfers is returning body: ${util.inspect(res)}`); + ctx.response.body = res; + ctx.response.status = 200; + } catch (err) { + ctx.state.logger.log(`Error in postBulkTransfers: ${getStackOrInspect(err)}`); + ctx.response.body = ApiErrorCodes.SERVER_ERROR; + ctx.response.status = 500; + } +}; + +const getBulkTransferById = async (ctx) => { + try { + const { idValue } = ctx.state.path.params; + const res = await ctx.state.model.bulkTransfer.get(idValue); + if (!res) { + ctx.response.body = ApiErrorCodes.ID_NOT_FOUND; + ctx.response.status = 404; + return; + } + ctx.response.body = res; + ctx.response.status = 200; + } catch (err) { + ctx.response.body = ApiErrorCodes.SERVER_ERROR; + ctx.response.status = 500; + } +}; const healthCheck = async (ctx) => { ctx.response.status = 200; @@ -138,12 +201,24 @@ const map = { '/quoterequests': { post: postQuotes, }, + '/bulkQuotes': { + post: postBulkQuotes, + }, + '/bulkQuotes/{idValue}': { + get: getBulkQuoteById, + }, '/transactionrequests': { post: postTransactionRequests, }, '/transfers': { post: postTransfers, }, + '/bulkTransfers': { + post: postBulkTransfers, + }, + '/bulkTransfers/{idValue}': { + get: getBulkTransferById, + }, '/otp/{requestToPayId}': { get: getOTPById, }, diff --git a/src/test-api/api.yaml b/src/test-api/api.yaml index cb2c1053..c09ef749 100644 --- a/src/test-api/api.yaml +++ b/src/test-api/api.yaml @@ -98,7 +98,7 @@ components: Scenario: title: Scenario type: object - description: An outbound transfer scenario + description: An outbound transfer, bulk transfer or bulk quote scenario required: - name - operation @@ -111,7 +111,7 @@ components: body: type: object description: >- - This object should be either a POST /transfers or PUT /transfers + This object should be either a POST /transfers, PUT /transfers, POST /bulkTransfers or POST /bulkQuotes request body as per the SDK outbound API specification params: $ref: '#/components/schemas/ScenarioOperationParameters' @@ -122,17 +122,32 @@ components: enum: - postTransfers - putTransfers + - postBulkTransfers + - postBulkQuotes ScenarioOperationParameters: - type: object description: Parameters to pass into the scenario operation - required: - - transferId - properties: - transferId: - type: string - description: >- - Transfer ID e.g. in the case of putTransfers operation this is the - ID of the transfer to complete + type: object + oneOf: + - properties: + transferId: + type: string + description: >- + Transfer ID e.g. in the case of putTransfers operation this is the + ID of the transfer to complete + required: + - transferId + - properties: + bulkTransferId: + type: string + description: Bulk transfer ID + required: + - bulkTransferId + - properties: + bulkQuoteId: + type: string + description: Bulk quote ID + required: + - bulkQuoteId Party: title: Party type: object diff --git a/src/test-api/client.js b/src/test-api/client.js index a0abf93a..5def0c6f 100644 --- a/src/test-api/client.js +++ b/src/test-api/client.js @@ -61,4 +61,42 @@ const putTransfers = async (transferId, body) => { return res.json(); }; -module.exports = { postTransfers, putTransfers }; +/** + * Endpoint call to outbound bulk transfer request initiation + * + * @param {Object} body bulk transfer body + * @returns {Promise.} response + */ +const postBulkTransfers = async (body) => { + const res = await fetch(`${OUTBOUND_ENDPOINT}/bulkTransfers`, { + method: 'POST', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + + return res.json(); +}; + +/** + * Endpoint call to outbound bulk quote request initiation + * + * @param {Object} body bulk quote body + * @returns {Promise.} response + */ +const postBulkQuotes = async (body) => { + const res = await fetch(`${OUTBOUND_ENDPOINT}/bulkQuotes`, { + method: 'POST', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + + return res.json(); +}; + + +module.exports = { + postTransfers, + putTransfers, + postBulkTransfers, + postBulkQuotes, +}; diff --git a/src/test-api/handlers.js b/src/test-api/handlers.js index 0ed70538..497b58bf 100644 --- a/src/test-api/handlers.js +++ b/src/test-api/handlers.js @@ -24,13 +24,19 @@ const util = require('util'); const Mustache = require('mustache'); - -const { postTransfers, putTransfers } = require('./client'); +const { + postTransfers, + putTransfers, + postBulkTransfers, + postBulkQuotes, +} = require('./client'); const { ApiErrorCodes } = require('../models/errors'); const supportedOperations = { POST_TRANSFERS: 'postTransfers', PUT_TRANSFERS: 'putTransfers', + POST_BULK_TRANSFERS: 'postBulkTransfers', + POST_BULK_QUOTES: 'postBulkQuotes', }; @@ -173,6 +179,16 @@ const handleOps = async (logger, model, ops) => { const response = await model.putTransfers(renderedParams.transferId, renderedBody); acc[op.name] = { result: response }; } + + if (op.operation === supportedOperations.POST_BULK_TRANSFERS) { + const response = await model.postBulkTransfers(renderedBody); + acc[op.name] = { result: response }; + } + + if (op.operation === supportedOperations.POST_BULK_QUOTES) { + const response = await model.postBulkQuotes(renderedBody); + acc[op.name] = { result: response }; + } } catch (error) { acc[op.name] = { error }; } @@ -190,6 +206,8 @@ const handleScenarios = async (ctx) => { const res = await handleOps(ctx.state.logger, { postTransfers, putTransfers, + postBulkTransfers, + postBulkQuotes, }, ctx.request.body); ctx.state.logger.log(`Scenario operations returned: ${util.inspect(res)}`); diff --git a/src/test/constants.js b/src/test/constants.js index 92e86f86..d346b72d 100644 --- a/src/test/constants.js +++ b/src/test/constants.js @@ -18,6 +18,9 @@ * Gates Foundation - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; @@ -29,6 +32,7 @@ const uuid = require('uuid/v1'); const chance = new Chance(); const randName = chance.name({ suffix: true, middle: true }); const transferId = uuid(); +const bulkTransferId = uuid(); const transactionRequestId = uuid(); const idType = 'msisdn'; const idValue = uuid(); @@ -46,6 +50,7 @@ const party = { idType, idValue, }; + const partyCreate = { displayName: randName, firstName: randName.split(' ')[0] || '', @@ -88,6 +93,79 @@ const quote = { initiatorType: 'CONSUMER', }; +const newQuote = { + quoteId: uuid(), + transactionId: uuid(), + to: { + idType: 'MSISDN', + idValue: '0012345', + }, + from: { + idType: 'MSISDN', + idValue: '0067890', + }, + amountType: 'SEND', + amount: '100', + currency: 'USD', + feesAmount: '0.5', + feesCurrency: 'USD', + transactionType: 'TRANSFER', + initiator: 'PAYER', + initiatorType: 'CONSUMER', +}; + +const bulkQuote = { + bulkQuoteId: idValue, + from: { + idType: 'MSISDN', + idValue: '0067890', + }, + individualQuotes: [ + { + quoteId: idValue, + transactionId: uuid(), + to: { + idType: 'MSISDN', + idValue: '0012345', + }, + amountType: 'SEND', + amount: '100', + currency: 'USD', + feesAmount: '0.5', + feesCurrency: 'USD', + transactionType: 'TRANSFER', + initiator: 'PAYER', + initiatorType: 'CONSUMER', + }, + ], +}; + +const newBulkQuote = { + bulkQuoteId: uuid(), + from: { + idType: 'MSISDN', + idValue: '0067890', + }, + individualQuotes: [ + { + quoteId: uuid(), + transactionId: uuid(), + to: { + idType: 'MSISDN', + idValue: '0012345', + }, + amountType: 'SEND', + amount: '100', + currency: 'USD', + feesAmount: '0.5', + feesCurrency: 'USD', + transactionType: 'TRANSFER', + initiator: 'PAYER', + initiatorType: 'CONSUMER', + }, + ], +}; + const transactionrequest = { transactionRequestId, to: { @@ -130,27 +208,6 @@ const transfer = { transactionType, }; -const newQuote = { - quoteId: uuid(), - transactionId: uuid(), - to: { - idType: 'MSISDN', - idValue: '0012345', - }, - from: { - idType: 'MSISDN', - idValue: '0067890', - }, - amountType: 'SEND', - amount: '100', - currency: 'USD', - feesAmount: '0.5', - feesCurrency: 'USD', - transactionType: 'TRANSFER', - initiator: 'PAYER', - initiatorType: 'CONSUMER', -}; - const newTransfer = { transferId: uuid(), quote: { @@ -173,6 +230,70 @@ const newTransfer = { transactionType, }; +const bulkTransfer = { + bulkTransferId, + from: { + idType, + idValue, + }, + bulkQuote: { + bulkQuoteId: idValue, + individualQuotes: [ + { + quoteId: uuid(), + transactionId: randName, + transferAmount: amount, + transferAmountCurrency: currency, + }, + ], + }, + individualTransfers: [ + { + transferId: uuid(), + to: { + idType, + idValue: '67890', + }, + amountType, + currency, + amount, + transactionType, + }, + ], +}; + +const newBulkTransfer = { + bulkTransferId: uuid(), + from: { + idType, + idValue, + }, + bulkQuote: { + bulkQuoteId: uuid(), + individualQuotes: [ + { + quoteId: uuid(), + transactionId: randName, + transferAmount: amount, + transferAmountCurrency: currency, + }, + ], + }, + individualTransfers: [ + { + transferId: uuid(), + to: { + idType, + idValue: '67890', + }, + amountType, + currency, + amount, + transactionType, + }, + ], +}; + const transferWithoutQuote = { transferId, currency, @@ -187,15 +308,20 @@ test('constants', async (t) => { module.exports = { transfer, + newTransfer, + transferWithoutQuote, + bulkTransfer, + newBulkTransfer, + bulkTransferId, quote, + newQuote, + bulkQuote, + newBulkQuote, transactionrequest, + transactionRequestId, party, partyCreate, - newQuote, - newTransfer, - transferWithoutQuote, idType, idValue, transferId, - transactionRequestId, }; diff --git a/src/test/model.js b/src/test/model.js index aba1ac27..5569c28d 100644 --- a/src/test/model.js +++ b/src/test/model.js @@ -18,6 +18,9 @@ * Gates Foundation - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; @@ -25,9 +28,13 @@ const test = require('ava'); const Model = require('../models/model'); + +const { cloneDeep } = require('./unit/TestUtils'); + const { - transfer, quote, transactionrequest, party, newQuote, newTransfer, idType, idValue, partyCreate, - transferId, transactionRequestId, + transfer, quote, newQuote, bulkQuote, newBulkQuote, transactionrequest, party, newTransfer, + bulkTransfer, newBulkTransfer, bulkTransferId, idType, idValue, partyCreate, transferId, + transactionRequestId, } = require('./constants'); test.beforeEach(async (t) => { @@ -61,6 +68,7 @@ test('create and retrieve all parties', async (t) => { } t.pass(); }); + test('create and retrieve all parties duplicates', async (t) => { const { model } = t.context; await model.party.create(partyCreate); @@ -214,6 +222,77 @@ test('create and delete a quote', async (t) => { t.is(deleted, undefined); }); +test('create a bulk quote', async (t) => { + await t.context.model.bulkQuote.create(cloneDeep(bulkQuote)); + t.pass(); +}); + +test('create and retrieve a bulk quote', async (t) => { + const { model } = t.context; + + await model.bulkQuote.create(cloneDeep(bulkQuote)); + const res = await model.bulkQuote.get(idValue); + + if (!res) { + t.fail('Result not found'); + } + + t.pass(); +}); + +test('created bulk quote has correct fees', async (t) => { + const { model } = t.context; + + const bq = await model.bulkQuote.create(cloneDeep(bulkQuote)); + const q = bq.individualQuoteResults[0]; + + if (q.payeeFspFeeAmount !== '5') { + return t.fail(`Fee is ${q.payeeFspFeeAmount}`); + } + if (q.payeeFspCommissionAmount !== '5') { + return t.fail(`Fee is ${q.payeeFspCommissionAmount}`); + } + + return t.pass(); +}); + +test('created bulk quote has correct fees when transfer amounts is small', async (t) => { + const { model } = t.context; + + const smq = cloneDeep(bulkQuote); + smq.individualQuotes[0].amount = 1; + const bq = await model.bulkQuote.create(smq); + const q = bq.individualQuoteResults[0]; + + if (q.payeeFspFeeAmount !== '0') { + return t.fail(`Fee is ${q.payeeFspFeeAmount}`); + } + if (q.payeeFspCommissionAmount !== '0') { + return t.fail(`Fee is ${q.payeeFspCommissionAmount}`); + } + + return t.pass(); +}); + +test('create and update a bulk quote', async (t) => { + const { model } = t.context; + + await model.bulkQuote.create(cloneDeep(bulkQuote)); + const orig = await model.bulkQuote.get(idValue); + await model.bulkQuote.update(idValue, cloneDeep(newBulkQuote)); + const changed = await model.bulkQuote.get(idValue); + t.notDeepEqual({ orig }, { changed }); +}); + +test('create and delete a bulk quote', async (t) => { + const { model } = t.context; + await model.bulkQuote.create(cloneDeep(bulkQuote)); + await model.bulkQuote.get(idValue); + await model.bulkQuote.delete(idValue); + const deleted = await model.bulkQuote.get(idValue); + t.is(deleted, undefined); +}); + test('create a transfer', async (t) => { await t.context.model.transfer.create(transfer); t.pass(); @@ -249,6 +328,36 @@ test('create and delete a transfer', async (t) => { t.is(deleted, undefined); }); +test('create and retrieve a bulk transfer', async (t) => { + const { model } = t.context; + + await model.bulkTransfer.create(cloneDeep(bulkTransfer)); + const res = await model.bulkTransfer.get(bulkTransferId); + if (!res) { + t.fail('Result not found'); + } + t.pass(); +}); + +test('create and update a bulk transfer', async (t) => { + const { model } = t.context; + + await model.bulkTransfer.create(cloneDeep(bulkTransfer)); + const orig = await model.bulkTransfer.get(idValue); + await model.bulkTransfer.update(idValue, cloneDeep(newBulkTransfer)); + const changed = await model.bulkTransfer.get(idValue); + t.notDeepEqual({ orig }, { changed }); +}); + +test('create and delete a bulkTransfer', async (t) => { + const { model } = t.context; + await model.bulkTransfer.create(cloneDeep(bulkTransfer)); + await model.bulkTransfer.get(bulkTransferId); + await model.bulkTransfer.delete(bulkTransferId); + const deleted = await model.bulkTransfer.get(bulkTransferId); + t.is(deleted, undefined); +}); + test('create a transactionrequest', async (t) => { await t.context.model.transactionrequest.create(transactionrequest); t.pass(); diff --git a/src/test/simulator.js b/src/test/simulator.js index b46e531f..4a369186 100644 --- a/src/test/simulator.js +++ b/src/test/simulator.js @@ -18,17 +18,20 @@ * Gates Foundation - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; const test = require('ava'); - +const { cloneDeep } = require('./unit/TestUtils'); const Model = require('../models/model'); const { map } = require('../simulator/handlers'); const { transfer, transferWithoutQuote, quote, transactionrequest, party, idType, idValue, - transactionRequestId, + transactionRequestId, bulkQuote, bulkTransfer, bulkTransferId, } = require('./constants'); const { ApiErrorCodes } = require('../models/errors'); @@ -71,6 +74,23 @@ test('create a quote', async (t) => { t.is(t.context.response.status, 200); }); +test('create a bulk quote', async (t) => { + // eslint-disable-next-line no-param-reassign + t.context.request = { body: cloneDeep(bulkQuote) }; + await map['/bulkQuotes'].post(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 200); +}); + +test('get a bulk quote', async (t) => { + await t.context.state.model.bulkQuote.create(bulkQuote); + // eslint-disable-next-line no-param-reassign + t.context.state.path = { params: { idValue } }; + await map['/bulkQuotes/{idValue}'].get(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 200); +}); + test('create a transfer', async (t) => { // eslint-disable-next-line no-param-reassign t.context.request = { body: transfer }; @@ -79,6 +99,23 @@ test('create a transfer', async (t) => { t.is(t.context.response.status, 200); }); +test('create a bulk transfer', async (t) => { + // eslint-disable-next-line no-param-reassign + t.context.request = { body: cloneDeep(bulkTransfer) }; + await map['/bulkTransfers'].post(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 200); +}); + +test('get a bulk transfer', async (t) => { + await t.context.state.model.bulkTransfer.create(bulkTransfer); + // eslint-disable-next-line no-param-reassign + t.context.state.path = { params: { idValue: bulkTransferId } }; + await map['/bulkTransfers/{idValue}'].get(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 200); +}); + test('create a transactionrequest', async (t) => { // eslint-disable-next-line no-param-reassign t.context.request = { body: transactionrequest }; @@ -130,6 +167,22 @@ test('should return 500 while posting a non valid transfer object', async (t) => t.is(t.context.response.status, 500); }); +test('should return 500 while posting a non valid bulk quote object', async (t) => { + // eslint-disable-next-line no-param-reassign + t.context.request = { body: { hello: 'world' } }; + await map['/bulkQuotes'].post(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 500); +}); + +test('should return 500 while posting a non valid bulk transfer object', async (t) => { + // eslint-disable-next-line no-param-reassign + t.context.request = { body: { hello: 'world' } }; + await map['/bulkTransfers'].post(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 500); +}); + test('should return 404 while getting a non existing participant', async (t) => { // eslint-disable-next-line no-param-reassign t.context.state.path = { params: { idValue: 'invalidID0001', idType: 'invalidType' } }; @@ -138,6 +191,23 @@ test('should return 404 while getting a non existing participant', async (t) => t.is(t.context.response.status, 404); }); +test('should return 404 while getting a non existent bulk quote', async (t) => { + // eslint-disable-next-line no-param-reassign + t.context.state.path = { params: { idValue: 'invalidID0001' } }; + await map['/bulkQuotes/{idValue}'].get(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 404); +}); + + +test('should return 404 while getting a non existent bulk transfer', async (t) => { + // eslint-disable-next-line no-param-reassign + t.context.state.path = { params: { idValue: 'invalidID0001' } }; + await map['/bulkTransfers/{idValue}'].get(t.context); + t.truthy(t.context.response.body); + t.is(t.context.response.status, 404); +}); + test('should return a valid health check', async (t) => { // Arrange // eslint-disable-next-line no-param-reassign @@ -175,3 +245,24 @@ test('postQuotes should handle 500 errors', async (t) => { t.deepEqual(t.context.response, expected, 'Response did not match expected'); t.pass(); }); + +test('postBulkQuotes should handle 500 errors', async (t) => { + // Arrange + // eslint-disable-next-line no-param-reassign + t.context.state.path = { params: { idValue, idType } }; + // eslint-disable-next-line no-throw-literal, no-param-reassign + t.context.state.model.bulkQuote.create = () => { throw 'Bad error!'; }; + // eslint-disable-next-line no-param-reassign + t.context.request = { body: cloneDeep(bulkQuote) }; + + const expected = { + body: ApiErrorCodes.SERVER_ERROR, + status: 500, + }; + + // Act + await map['/bulkQuotes'].post(t.context); + // Assert + t.deepEqual(t.context.response, expected, 'Response did not match expected'); + t.pass(); +}); diff --git a/src/test/test-api.js b/src/test/test-api.js index eb79232c..52ef235c 100644 --- a/src/test/test-api.js +++ b/src/test/test-api.js @@ -18,6 +18,9 @@ * Gates Foundation - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; @@ -27,36 +30,89 @@ const Model = require('../../src/models/model'); const handlers = require('../test-api/handlers'); const { ops, party, partyCreate } = require('./constants'); -const testOps = [{ - name: 'scenario1', - operation: 'postTransfers', - body: { - from: { - displayName: 'James Bush', - idType: 'MSISDN', - idValue: '447710066017', +const testOps = [ + { + name: 'scenario1', + operation: 'postTransfers', + body: { + from: { + displayName: 'James Bush', + idType: 'MSISDN', + idValue: '447710066017', + }, + to: { + idType: 'MSISDN', + idValue: '447710066018', + }, + amountType: 'SEND', + currency: 'USD', + amount: '100', + transactionType: 'TRANSFER', + note: 'test payment', + homeTransactionId: '123ABC', + }, + }, + { + name: 'scenario2', + operation: 'putTransfers', + params: { + transferId: '{{scenario1.result.transferId}}', }, - to: { - idType: 'MSISDN', - idValue: '447710066018', + body: { + acceptQuote: true, }, - amountType: 'SEND', - currency: 'USD', - amount: '100', - transactionType: 'TRANSFER', - note: 'test payment', - homeTransactionId: '123ABC', }, -}, { - name: 'scenario2', - operation: 'putTransfers', - params: { - transferId: '{{scenario1.result.transferId}}', + { + name: 'scenario3', + operation: 'postBulkTransfers', + body: { + from: { + displayName: 'Steven Oderayi', + idType: 'MSISDN', + idValue: '447710066028', + }, + individualTransfers: [ + { + to: { + idType: 'MSISDN', + idValue: '447710066018', + }, + amountType: 'SEND', + currency: 'USD', + amount: '100', + transactionType: 'TRANSFER', + note: 'test payment', + homeTransactionId: '123ABC', + }, + ], + }, }, - body: { - acceptQuote: true, + { + name: 'scenario4', + operation: 'postBulkQuotes', + body: { + from: { + displayName: 'Steven Oderayi', + idType: 'MSISDN', + idValue: '447710066028', + }, + individualQuotes: [ + { + quoteId: '8746736546', + transactionId: '5678390498', + to: { + idType: 'MSISDN', + idValue: '447710066018', + }, + currency: 'USD', + amount: '100', + note: 'test payment', + }, + ], + }, }, -}]; + +]; test.beforeEach(async (t) => { const model = new Model(); @@ -121,20 +177,31 @@ test('should call outbound transfers model and pass on results to next operation putTransfers: async (transferId) => Promise.resolve({ transferId, }), + postBulkTransfers: async () => Promise.resolve({ + bulkTransferId: '1234567890', + }), + postBulkQuotes: async () => Promise.resolve({ + bulkQuoteId: '1234567890', + }), }; const result = await handlers.handleOps(console, model, testOps); t.truthy(result.scenario1); t.truthy(result.scenario2); + t.truthy(result.scenario3); + t.truthy(result.scenario4); t.truthy(result.scenario1.result); t.truthy(result.scenario2.result); + t.truthy(result.scenario3.result); + t.truthy(result.scenario4.result); t.is(result.scenario1.result.transferId, '12345ABCDEF'); t.is(result.scenario2.result.transferId, '12345ABCDEF'); + t.is(result.scenario3.result.bulkTransferId, '1234567890'); + t.is(result.scenario4.result.bulkQuoteId, '1234567890'); }); - test('should return 500 when sending a non valid ops', async (t) => { // eslint-disable-next-line no-param-reassign t.context.request = { body: { hello: 'world' } }; diff --git a/src/test/unit/TestUtils.js b/src/test/unit/TestUtils.js index a8b5e8e8..9b2b6921 100644 --- a/src/test/unit/TestUtils.js +++ b/src/test/unit/TestUtils.js @@ -4,6 +4,19 @@ const testLogger = (t) => ({ push: () => ({ log: (message) => t.log(message) }), }); +/** + * Makes a deep clone of an object or array. + * + * Note that this will only copy JSON-compatible properties, + * things like function etc. will be lost. + * This function should only be used to clone simple objects with + * some depth which cannot be successfully cloned using other means. + * + * @returns {Object} clone of argument. + */ +const cloneDeep = (o) => JSON.parse(JSON.stringify(o)); + module.exports = { testLogger, + cloneDeep, }; diff --git a/src/test/unit/config.test.js b/src/test/unit/config.test.js index aa945afa..5042e42e 100644 --- a/src/test/unit/config.test.js +++ b/src/test/unit/config.test.js @@ -19,6 +19,9 @@ - Name Surname * Vessels Tech - Lewis Daly + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; @@ -44,6 +47,11 @@ test('Sets the basic config', async (t) => { mutualTLS: { enabled: false }, creds: { ca: null, cert: null, key: null }, }, + ports: { + simulatorApi: 3000, + reportApi: 3002, + testApi: 3003, + }, }; // Act From ce9227b951f8ed05c690e954f051d0abbb4dd283 Mon Sep 17 00:00:00 2001 From: Steven Oderayi Date: Wed, 10 Jun 2020 15:06:35 +0100 Subject: [PATCH 02/30] Hotfix: Fix python dependencies in CI (#53) * Upgrade python for CI build * Update ci config * Bump version --- .circleci/config.yml | 7 +++---- src/package-lock.json | 2 +- src/package.json | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 79487703..9985f2fa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,13 +19,12 @@ defaults_Dependencies: &defaults_Dependencies | defaults_awsCliDependencies: &defaults_awsCliDependencies | apk --no-cache add \ - python \ - py-pip \ + python3 \ + py3-pip \ groff \ less \ mailcap - pip install --upgrade awscli==1.14.5 s3cmd==2.0.1 python-magic - apk -v --purge del py-pip + pip3 install --upgrade pip awscli==1.14.5 s3cmd==2.0.1 python-magic defaults_build_docker_build: &defaults_build_docker_build name: Build Docker image diff --git a/src/package-lock.json b/src/package-lock.json index ef1b6d17..1e0f8b65 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.2.0", + "version": "10.4.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index c2ab62e3..110502fb 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.4.0", + "version": "10.4.1", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 8da29c5418d44506211b7e19a674166f15c53251 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Thu, 18 Jun 2020 11:54:51 +0100 Subject: [PATCH 03/30] Update pipeline (#54) * Add orbs * Update dependencies to Python@3 * Simplify defaults * Update to Python@3 * Remove comments * Remove unecessary executor * Update config * Use pip3 * Remove unused step * Update * Test * Test * Remove anchor for working directory * Update node * Test * Fix YAML syntax * Use anchor * Fix directory issue * Fix path * Add path to restore_cache * Test * Test * Update key * Update dependencies * Fix path * Add submodule dependencies to cache * Version dependency cache * Fix path * Test * Change directory to src * Allow build-local to run in parallel from the start --- .circleci/config.yml | 434 +++++++++++++++--------------------------- src/package-lock.json | 252 +++++++----------------- 2 files changed, 227 insertions(+), 459 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9985f2fa..2d6a33ec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,14 @@ # CircleCI v2.1 Config version: 2.1 + +## +# orbs +# +# Orbs used in this pipeline +## orbs: anchore: anchore/anchore-engine@1.6.0 + deploy-kube: mojaloop/deployment@0.1.6 ## # defaults @@ -9,105 +16,23 @@ orbs: # YAML defaults templates, in alphabetical order ## defaults_Dependencies: &defaults_Dependencies | - apk --no-cache add git - apk --no-cache add ca-certificates - apk --no-cache add curl - apk --no-cache add openssh-client - apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake - npm config set unsafe-perm true - npm install -g node-gyp + apk --update --no-cache add \ + git \ + ca-certificates \ + curl \ + openssh-client \ + -t build-dependencies make gcc g++ python3 libtool autoconf automake + npm config set unsafe-perm true + npm install -g node-gyp defaults_awsCliDependencies: &defaults_awsCliDependencies | - apk --no-cache add \ - python3 \ - py3-pip \ - groff \ - less \ - mailcap - pip3 install --upgrade pip awscli==1.14.5 s3cmd==2.0.1 python-magic - -defaults_build_docker_build: &defaults_build_docker_build - name: Build Docker image - command: | - docker build -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG . - -defaults_build_docker_login: &defaults_build_docker_login - name: Login to Docker Hub - command: | - docker login -u $DOCKER_USER -p $DOCKER_PASS - -defaults_build_docker_publish: &defaults_build_docker_publish - name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub - command: | - echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG" - docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG - echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG" - docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG - -defaults_deploy_config_kubernetes_cluster: &defaults_deploy_config_kubernetes_cluster - name: Configure Kubernetes cluster - command: | - echo "Configure Kubernetes cluster ${K8_CLUSTER_NAME}" - kubectl config set-cluster $K8_CLUSTER_NAME --server=$K8_CLUSTER_SERVER --insecure-skip-tls-verify=true - -defaults_deploy_config_kubernetes_context: &defaults_deploy_config_kubernetes_context - name: Confi gure Kubernetes context - command: | - echo "Configure Kubernetes context ${K8_CLUSTER_NAME}" - kubectl config set-context $K8_CLUSTER_NAME --cluster=$K8_CLUSTER_NAME --user=$K8_USER_NAME --namespace=$K8_NAMESPACE - -defaults_deploy_config_kubernetes_credentials: &defaults_deploy_config_kubernetes_credentials - name: Configure Kubernetes credentails - command: | - echo "Configure Kubernetes credentials ${K8_USER_NAME}" - if [ ! -z "$K8_USER_TOKEN" ]; - then - echo "Configure Kubernetes credentials ${K8_USER_NAME} using Token" - kubectl config set-credentials $K8_USER_NAME --token=$K8_USER_TOKEN - else - echo "Configure Kubernetes credentials ${K8_USER_NAME} using Certs" - kubectl config set-credentials $K8_USER_NAME --client-certificate=$CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_CERT_FILENAME --client-key=$CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_KEY_FILENAME - fi - -defaults_deploy_configure_helm: &defaults_deploy_configure_helm - name: Configure Helm - command: | - helm init --client-only - -defaults_deploy_install_or_upgrade_helm_chart: &defaults_deploy_install_or_upgrade_helm_chart - name: Install or Upgrade Helm Chart - command: | - echo "Install or Upgrade Chart ${K8_RELEASE_NAME} for Docker Image ${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_TAG}" - if [ -z "$(helm list -q | grep -E "^${K8_RELEASE_NAME}$")" ] && [ "$(helm list -q | grep -E "^${K8_RELEASE_NAME}$")" != "Error: Unauthorized" ]; - then - echo "Installing ${K8_RELEASE_NAME} new release" - helm install --namespace=$K8_NAMESPACE --name=$K8_RELEASE_NAME --repo=$K8_HELM_REPO $HELM_VALUE_SET_VALUES -f $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/$HELM_VALUE_FILENAME $K8_HELM_CHART_NAME - else - echo "Upgrading ${K8_RELEASE_NAME} release" - helm upgrade $K8_RELEASE_NAME --repo=$K8_HELM_REPO --reuse-values $HELM_VALUE_SET_VALUES -f $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/$HELM_VALUE_FILENAME $K8_HELM_CHART_NAME - fi - -defaults_deploy_prequisites: &defaults_deploy_prequisites - name: Copy deployment pre-requisites from S3 bucket - command: | - if [ -z "$K8_USER_TOKEN" ]; - then - echo "Copying K8 keys into $AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS folder" - mkdir $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS - aws s3 cp $AWS_S3_URI_DEVOPS_DEPLOYMENT_CONFIG/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_KEY_FILENAME $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/ - aws s3 cp $AWS_S3_URI_DEVOPS_DEPLOYMENT_CONFIG/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_CERT_FILENAME $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/ - else - echo "Skipping K8 keys into $AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS folder" - fi - echo "Copying Helm value file into $AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM folder for $K8_RELEASE_NAME release" - mkdir $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM - aws s3 cp $AWS_S3_URI_DEVOPS_DEPLOYMENT_CONFIG/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/$HELM_VALUE_FILENAME $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/ - -defaults_deploy_set_kubernetes_context: &defaults_deploy_set_kubernetes_context - name: Set Kubernetes context - command: | - echo "Configure Kubernetes context ${K8_CLUSTER_NAME}" - kubectl config use-context $K8_CLUSTER_NAME + apk --update --no-cache add \ + python3 \ + py3-pip \ + groff \ + less \ + mailcap + pip3 install --upgrade awscli==1.14.5 s3cmd==2.0.1 python-magic defaults_license_scanner: &defaults_license_scanner name: Install and set up license-scanner @@ -115,26 +40,10 @@ defaults_license_scanner: &defaults_license_scanner git clone https://github.com/mojaloop/license-scanner /tmp/license-scanner cd /tmp/license-scanner && make build default-files set-up - -# defaults_working_directory: &defaults_working_directory -# # The working directory for this project (place where package.json is) is /src, -# # as opposed to the project root -# working_directory: /home/circleci/project/git - -defaults_slack_announcement: &defaults_slack_announcement - name: Slack announcement for tag releases - command: | - curl -X POST \ - $SLACK_WEBHOOK_ANNOUNCEMENT \ - -H 'Content-type: application/json' \ - -H 'cache-control: no-cache' \ - -d "{\"text\": \"*${CIRCLE_PROJECT_REPONAME}* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" - src_working_directory: &src_working_directory - # The working directory for this project (place where package.json is) is /src, + # The working directory for this project (place where package.json is) is /src, # as opposed to the project root - working_directory: /home/circleci/project/git/src - + working_directory: ~/git/src ## # Executors @@ -144,19 +53,14 @@ src_working_directory: &src_working_directory executors: default-docker: working_directory: /home/circleci/project/git - docker: - - image: node:12.16.0-alpine + docker: + - image: node:12.18.0-alpine default-machine: working_directory: /home/circleci/project/git machine: image: ubuntu-1604:201903-01 - helm-kube: - working_directory: /home/circleci/project - docker: - - image: hypnoglow/kubernetes-helm - ## # Jobs # @@ -170,76 +74,63 @@ jobs: - run: name: Install general dependencies command: *defaults_Dependencies - # - run: - # name: Build dependencies - # command: apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake - - run: - name: Access npm folder as root - command: cd $(npm root -g)/npm - run: - name: Install node-gyp globally - command: npm install -g node-gyp + name: Update NPM install (using `npm ci`) + command: cd src && npm ci - run: - name: Update NPM install - command: npm install - <<: *src_working_directory + name: Delete build dependencies + command: apk del build-dependencies - save_cache: - key: dependency-cache-{{ checksum "./src/package.json" }} + key: dependency-cache-v1-{{ checksum "src/package-lock.json" }} paths: - - ./src/node_modules + - src/node_modules + - src/lib/log/node_modules + - src/lib/validate/node_modules test-unit: executor: default-docker steps: - checkout - - run: - name: Install general dependencies - command: *defaults_Dependencies - restore_cache: - key: dependency-cache-{{ checksum "./src/package.json" }} + key: dependency-cache-v1-{{ checksum "src/package-lock.json" }} + paths: + - src/node_modules + - src/lib/log/node_modules + - src/lib/validate/node_modules - run: - name: Install tape and tap-xunit - command: npm install tape tap-xunit - <<: *src_working_directory + name: Execute linting pass + command: cd src && npm run lint - run: name: Create dir for test results command: mkdir -p ./test/results - <<: *src_working_directory - - run: - name: Install tapes - command: npm install -g tapes - <<: *src_working_directory - run: name: Execute unit tests - command: npm -s run test:xunit > ./test/results/tape.xml - <<: *src_working_directory + command: cd src && npm run test > ../test/results/results.txt - store_artifacts: - path: ./src/test/results + path: ./test/results prefix: test - store_test_results: - path: ./src/test/results + path: ./test/results test-coverage: executor: default-docker steps: - checkout + - restore_cache: + key: dependency-cache-v1-{{ checksum "src/package-lock.json" }} + paths: + - src/node_modules + - src/lib/log/node_modules + - src/lib/validate/node_modules - run: name: Install general dependencies command: *defaults_Dependencies - run: name: Install AWS CLI dependencies command: *defaults_awsCliDependencies - - restore_cache: - keys: - - dependency-cache-{{ checksum "./src/package.json" }} - - run: - name: Run install again for nested package.json files - command: npm install - <<: *src_working_directory - run: name: Execute code coverage check - command: npm -s run test:coverage-check - <<: *src_working_directory + command: cd src && npm -s run test:coverage-check - store_artifacts: path: ./src/coverage prefix: test @@ -255,106 +146,93 @@ jobs: else echo "Not a release (env CIRCLE_BRANCH != 'master'), skipping sending lcov.info to SonarQube." fi - <<: *src_working_directory vulnerability-check: executor: default-docker steps: - checkout + - restore_cache: + key: dependency-cache-v1-{{ checksum "src/package-lock.json" }} + paths: + - src/node_modules + - src/lib/log/node_modules + - src/lib/validate/node_modules - run: name: Install general dependencies command: *defaults_Dependencies - - restore_cache: - key: dependency-cache-{{ checksum "./src/package.json" }} - run: name: Create dir for test results command: mkdir -p ./audit/results - <<: *src_working_directory - run: name: Check for new npm vulnerabilities - command: npm run audit:check --silent -- --json > ./audit/results/auditResults.json - <<: *src_working_directory + command: cd src && npm run audit:check --silent -- --json > ../audit/results/auditResults.json - store_artifacts: - path: ./src/audit/results + path: ./audit/results prefix: audit audit-licenses: executor: default-docker steps: - checkout + - restore_cache: + key: dependency-cache-v1-{{ checksum "src/package-lock.json" }} + paths: + - src/node_modules + - src/lib/log/node_modules + - src/lib/validate/node_modules - run: name: Install general dependencies command: *defaults_Dependencies - run: <<: *defaults_license_scanner - - restore_cache: - key: dependency-cache-{{ checksum "./src/package.json" }} - run: name: Run the license-scanner command: cd /tmp/license-scanner && pathToRepo=$CIRCLE_WORKING_DIRECTORY make run - <<: *src_working_directory - store_artifacts: path: /tmp/license-scanner/results prefix: licenses - test-integration: + build: executor: default-machine steps: - checkout - - restore_cache: - key: dependency-cache-{{ checksum "./src/package.json" }} - - run: - name: Create dir for test results - command: mkdir -p ./test/results - <<: *src_working_directory - run: - name: Execute integration tests - command: npm -s run test:integration - <<: *src_working_directory - - store_artifacts: - path: ./src/test/results - prefix: test - - store_test_results: - path: ./src/test/results + name: Build Docker $CIRCLE_TAG image + command: > + echo "Building Docker image: $CIRCLE_TAG" - test-functional: - executor: default-machine - steps: - - checkout + docker build + --build-arg=BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg=VERSION="$RELEASE_TAG" + --build-arg=VCS_URL="$CIRCLE_REPOSITORY_URL" + --build-arg=VCS_REF="$CIRCLE_SHA1" + -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG . - run: - name: Add the Postgres 9.6 binaries to the path. - command: echo ‘/usr/lib/postgresql/9.6/bin/:$PATH’ >> $BASH_ENV - - run: - name: Install Docker Compose - command: | - curl -L https://github.com/docker/compose/releases/download/1.11.2/docker-compose-`uname -s`-`uname -m` > ~/docker-compose - chmod +x ~/docker-compose - mv ~/docker-compose /usr/local/bin/docker-compose - - restore_cache: - key: dependency-cache-{{ checksum "./src/package.json" }} - - run: - name: Create dir for test results - command: mkdir -p ./test/results - <<: *src_working_directory - - run: - name: Execute functional tests - command: npm -s run test:functional - <<: *src_working_directory - - store_artifacts: - path: ./src/test/results - prefix: test - - store_test_results: - path: ./src/test/results + name: Save docker image to workspace + command: docker save -o /tmp/docker-image.tar $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG + - persist_to_workspace: + root: /tmp + paths: + - ./docker-image.tar - build: + build-local: executor: default-machine steps: - checkout - run: - <<: *defaults_build_docker_build + name: Build Docker local image for testing + command: > + echo "Building Docker image: local" + + docker build + --build-arg=BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg=VERSION="local" + --build-arg=VCS_URL="$CIRCLE_REPOSITORY_URL" + --build-arg=VCS_REF="$CIRCLE_SHA1" + -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local . - run: name: Save docker image to workspace - command: docker save -o /tmp/docker-image.tar $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG + command: docker save -o /tmp/docker-image.tar $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local - persist_to_workspace: root: /tmp paths: @@ -363,6 +241,7 @@ jobs: license-scan: executor: default-machine steps: + - checkout - attach_workspace: at: /tmp - run: @@ -372,7 +251,7 @@ jobs: <<: *defaults_license_scanner - run: name: Run the license-scanner - command: cd /tmp/license-scanner && mode=docker dockerImage=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG make run + command: cd /tmp/license-scanner && mode=docker dockerImages=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local make run - store_artifacts: path: /tmp/license-scanner/results prefix: licenses @@ -392,7 +271,7 @@ jobs: command: docker load -i /tmp/docker-image.tar - anchore/analyze_local_image: dockerfile_path: ./Dockerfile - image_name: ${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_TAG} + image_name: ${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:local # Anchore bug: if policy_failure is `true`, reports don't get written - we manually check for failures below policy_failure: false timeout: '500' @@ -410,21 +289,20 @@ jobs: printf "\n%s\n" "The following vulnerabilities were found:" jq '[.vulnerabilities | group_by(.package) | .[] | {package: .[0].package, vuln: [.[].vuln]}]' anchore-reports/*vuln*.json fi - - run: name: Upload Anchore reports to s3 command: | aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/${CIRCLE_PROJECT_REPONAME}/ --recursive aws s3 rm ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive --exclude "*" --include "${CIRCLE_PROJECT_REPONAME}*" aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive - + # TODO: Enable this when we want to increase the strictness of our security policies # failCount=$(cat anchore-reports/*policy*.json | grep 'fail' | wc -l) + # echo "FailCount is: ${failCount}" # if [ $failCount -gt 0 ]; then # printf "Failed with a policy failure count of: ${failCount}" # exit 1 # fi - - store_artifacts: path: anchore-reports @@ -438,45 +316,37 @@ jobs: name: Load the pre-built docker image from workspace command: docker load -i /tmp/docker-image.tar - run: - <<: *defaults_build_docker_login - - run: - name: setup environment vars for release/snapshot - command: ./.circleci/_set_up_deploy_envs.sh + name: Login to Docker Hub + command: docker login -u $DOCKER_USER -p $DOCKER_PASS - run: name: Re-tag pre built image command: | docker tag $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG - run: - <<: *defaults_build_docker_publish - - run: - <<: *defaults_slack_announcement - - # deploy: - # executor: helm-kube - # steps: - # - checkout - # - run: - # name: Install AWS CLI dependencies - # command: *defaults_awsCliDependencies - # - run: - # name: setup environment vars for release/snapshot - # command: ./.circleci/_set_up_deploy_envs.sh - # - run: - # <<: *defaults_deploy_prequisites - # - run: - # <<: *defaults_deploy_config_kubernetes_cluster - # - run: - # <<: *defaults_deploy_config_kubernetes_credentials - # - run: - # <<: *defaults_deploy_config_kubernetes_context - # - run: - # <<: *defaults_deploy_set_kubernetes_context - # - run: - # <<: *defaults_deploy_configure_helm - # - run: - # <<: *defaults_deploy_install_or_upgrade_helm_chart + name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub + command: | + echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG" + docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG + echo "Publishing $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG" + docker push $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$RELEASE_TAG + - run: + name: Slack announcement for tag releases + command: | + curl -X POST \ + $SLACK_WEBHOOK_ANNOUNCEMENT \ + -H 'Content-type: application/json' \ + -H 'cache-control: no-cache' \ + -d "{\"text\": \"*${CIRCLE_PROJECT_REPONAME}* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" + + deploy: + executor: deploy-kube/helm-kube + steps: + - checkout + - deploy-kube/setup_and_run: + helm_set_values: | + --set finance-portal.frontend.image.repository=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME \ + --set finance-portal.frontend.image.tag=$CIRCLE_TAG - ## # Workflows # @@ -495,75 +365,84 @@ workflows: ignore: - /feature*/ - /bugfix*/ + - /hotfix*/ - test-unit: context: org-global requires: - setup filters: - tags: - only: /.*/ branches: ignore: - /feature*/ - /bugfix*/ + - /hotfix*/ - test-coverage: context: org-global requires: - setup filters: - tags: - only: /.*/ branches: ignore: - /feature*/ - /bugfix*/ + - /hotfix*/ - vulnerability-check: context: org-global requires: - setup filters: - tags: - only: /.*/ branches: ignore: - /feature*/ - /bugfix*/ + - /hotfix*/ - audit-licenses: context: org-global requires: - setup filters: - tags: - only: /.*/ branches: ignore: - /feature*/ - /bugfix*/ - - build: + - /hotfix*/ + - build-local: context: org-global - requires: - - setup - - test-unit - - test-coverage - - vulnerability-check - - audit-licenses filters: - tags: - only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ branches: ignore: - - /.*/ + - /feature*/ + - /bugfix*/ + - /hotfix*/ - license-scan: context: org-global requires: - - build + - build-local + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ + - image-scan: + context: org-global + requires: + - build-local + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ + - build: + context: org-global filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ branches: ignore: - /.*/ - - image-scan: + - publish: context: org-global requires: - build @@ -573,14 +452,13 @@ workflows: branches: ignore: - /.*/ - - publish: + - deploy: context: org-global requires: - - license-scan - - image-scan + - publish filters: tags: - only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?/ branches: ignore: - - /.*/ \ No newline at end of file + - /.*/ diff --git a/src/package-lock.json b/src/package-lock.json index 1e0f8b65..3af2b134 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -2323,21 +2323,6 @@ "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", "dev": true }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3050,12 +3035,6 @@ } } }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, "irregular-plurals": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", @@ -3214,12 +3193,6 @@ "has": "^1.0.3" } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", @@ -3649,15 +3622,6 @@ "package-json": "^6.3.0" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -3815,15 +3779,6 @@ } } }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, "matcher": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz", @@ -3861,17 +3816,6 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, "merge-options": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-1.0.1.tgz", @@ -4409,17 +4353,6 @@ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -4440,24 +4373,6 @@ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "p-limit": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", @@ -5449,12 +5364,6 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -6187,33 +6096,63 @@ } }, "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", "dev": true, "requires": { "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" + "lodash": "^4.17.15", + "yargs": "^13.3.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -6223,12 +6162,6 @@ "locate-path": "^3.0.0" } }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -6260,102 +6193,59 @@ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" } }, "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", + "cliui": "^5.0.0", "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", + "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", From b708224bceaa239ad2a4e251383c30dac784d777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aar=C3=B3n=20Reynoza?= Date: Thu, 9 Jul 2020 04:12:20 -0700 Subject: [PATCH 04/30] Add Init Container To Onboard MSISDN's (#55) * Add init container to onboard with central-ledger * Remove environment var processing script * Switch RUN to CMD * Add OCI labels * Add contributor * Update init/central-ledger/Dockerfile Co-Authored-By: Matt Kingston * Clear whitespace and unused comments * Add build and publish to CI for init-central-ledger * Fix indentation * created insert msisnd script * complete docker container and MSISDN onboarding script * change MSISDN_LIST name * change script to handle MSISDN data * ignore dependency vulneravility * update dockerfile * rename * change pathfinder url name * modify scripts * fix script and docker container * add CI pipeline and remove unused files * fix docker command * fix indentation * fix tag implementation * yaml is fun * resolve vulnerabilities and fix docker save * fix docker build * fix docker image naming and add Matt suggestion * log current images * idk why but it works now * Clean up naming and pipeline * Bump version Co-authored-by: Kamuela Franco Co-authored-by: Matt Kingston --- .circleci/config.yml | 124 +++++++++++++++++-- init/onboard-msisdn-oracle/Dockerfile | 22 ++++ init/onboard-msisdn-oracle/insert_msisdns.sh | 16 +++ src/audit-resolve.json | 25 +--- src/package-lock.json | 9 +- src/package.json | 4 +- 6 files changed, 163 insertions(+), 37 deletions(-) create mode 100644 init/onboard-msisdn-oracle/Dockerfile create mode 100755 init/onboard-msisdn-oracle/insert_msisdns.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 2d6a33ec..22243825 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -202,10 +202,10 @@ jobs: echo "Building Docker image: $CIRCLE_TAG" docker build - --build-arg=BUILD_DATE="$(date -u --iso-8601=seconds)" - --build-arg=VERSION="$RELEASE_TAG" - --build-arg=VCS_URL="$CIRCLE_REPOSITORY_URL" - --build-arg=VCS_REF="$CIRCLE_SHA1" + --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg VERSION="$RELEASE_TAG" + --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" + --build-arg VCS_REF="$CIRCLE_SHA1" -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG . - run: name: Save docker image to workspace @@ -215,6 +215,29 @@ jobs: paths: - ./docker-image.tar + build-onboard-msisdn-oracle: + executor: default-machine + steps: + - checkout + - run: + name: Build Docker onboard-msisdn-oracle $CIRCLE_TAG image + command: > + echo "Building Docker image: onboard-msisdn-oracle $CIRCLE_TAG" + + docker build + --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg VERSION="$RELEASE_TAG" + --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" + --build-arg VCS_REF="$CIRCLE_SHA1" + -t $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG . + - run: + name: Save docker image to workspace + command: docker save -o /tmp/docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG + - persist_to_workspace: + root: /tmp + paths: + - ./docker-onboard-msisdn-oracle.tar + build-local: executor: default-machine steps: @@ -225,10 +248,10 @@ jobs: echo "Building Docker image: local" docker build - --build-arg=BUILD_DATE="$(date -u --iso-8601=seconds)" - --build-arg=VERSION="local" - --build-arg=VCS_URL="$CIRCLE_REPOSITORY_URL" - --build-arg=VCS_REF="$CIRCLE_SHA1" + --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg VERSION="local" + --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" + --build-arg VCS_REF="$CIRCLE_SHA1" -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local . - run: name: Save docker image to workspace @@ -238,6 +261,29 @@ jobs: paths: - ./docker-image.tar + build-local-onboard-msisdn-oracle: + executor: default-machine + steps: + - checkout + - run: + name: Build Docker onboard-msisdn-oracle local image for testing + command: > + echo "Building Docker image: onboard-msisdn-oracle local" + + docker build + --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg VERSION="local" + --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" + --build-arg VCS_REF="$CIRCLE_SHA1" + -t $DOCKER_ORG/onboard-msisdn-oracle:local ./init/onboard-msisdn-oracle/ + - run: + name: Save docker image to workspace + command: docker save -o /tmp/docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-msisdn-oracle:local + - persist_to_workspace: + root: /tmp + paths: + - ./docker-onboard-msisdn-oracle.tar + license-scan: executor: default-machine steps: @@ -338,6 +384,39 @@ jobs: -H 'cache-control: no-cache' \ -d "{\"text\": \"*${CIRCLE_PROJECT_REPONAME}* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" + publish-onboard-msisdn-oracle: + executor: default-machine + steps: + - checkout + - attach_workspace: + at: /tmp + - run: + name: Load the pre-built docker image for onboard-msisdn-oracle from workspace + command: docker load -i /tmp/docker-onboard-msisdn-oracle.tar + - run: + name: Login to Docker Hub + command: docker login -u $DOCKER_USER -p $DOCKER_PASS + - run: + name: Setup environment vars for release/snapshot + command: ./.circleci/_set_up_deploy_envs.sh + - run: + name: Re-tag pre built image + command: | + docker tag docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-msisdn-oracle:$RELEASE_TAG + - run: + name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub for onboard-msisdn-oracle + command: | + echo "Publishing $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG" + docker push $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG + - run: + name: Slack announcement for tag releases + command: | + curl -X POST \ + $SLACK_WEBHOOK_ANNOUNCEMENT \ + -H 'Content-type: application/json' \ + -H 'cache-control: no-cache' \ + -d "{\"text\": \"*onboard-msisdn-oracle* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" + deploy: executor: deploy-kube/helm-kube steps: @@ -414,6 +493,14 @@ workflows: - /feature*/ - /bugfix*/ - /hotfix*/ + - build-local-onboard-msisdn-oracle: + context: org-global + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ - license-scan: context: org-global requires: @@ -442,10 +529,30 @@ workflows: branches: ignore: - /.*/ + - build-onboard-msisdn-oracle: + context: org-global + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ + branches: + ignore: + - /.*/ - publish: context: org-global requires: - build + - build-onboard-msisdn-oracle + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ + branches: + ignore: + - /.*/ + - publish-onboard-msisdn-oracle: + context: org-global + requires: + - build + - build-onboard-msisdn-oracle filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ @@ -456,6 +563,7 @@ workflows: context: org-global requires: - publish + - publish-onboard-msisdn-oracle filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?/ diff --git a/init/onboard-msisdn-oracle/Dockerfile b/init/onboard-msisdn-oracle/Dockerfile new file mode 100644 index 00000000..e29026a6 --- /dev/null +++ b/init/onboard-msisdn-oracle/Dockerfile @@ -0,0 +1,22 @@ +FROM alpine + +ARG CREATED +ARG SOURCE +ARG REVISION +ARG VERSION + +# See https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys and https://github.com/opencontainers/image-spec/blob/master/spec.md for info +LABEL org.opencontainers.image.created=${CREATED} +LABEL org.opencontainers.image.url="https://mojaloop.io/" +LABEL org.opencontainers.image.source=${SOURCE} +LABEL org.opencontainers.image.version=${VERSION} +LABEL org.opencontainers.image.revision=${REVISION} +LABEL org.opencontainers.image.title="onboard-msisdn-oracle" +LABEL org.opencontainers.image.authors="aaron.reynoza@modusbox.com" +LABEL org.opencontainers.image.licenses="Apache-2.0" + +RUN apk add --no-cache --upgrade bash curl jq + +COPY insert_msisdns.sh /insert_msisdns.sh + +CMD ["sh", "/insert_msisdns.sh"] diff --git a/init/onboard-msisdn-oracle/insert_msisdns.sh b/init/onboard-msisdn-oracle/insert_msisdns.sh new file mode 100755 index 00000000..bc23e536 --- /dev/null +++ b/init/onboard-msisdn-oracle/insert_msisdns.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +CURRENT_DATE=$(date) +for participantMSISDN in $(echo "${MSISDN_LIST}" | jq -c '.[]'); do + MSISDN=$(echo "${participantMSISDN}" | jq -r '.MSISDN'); + CURRENCY=$(echo "${participantMSISDN}" | jq -r '.currency'); + DATA="{\"currency\": \"${CURRENCY}\", \"fspId\": \"${DFSP_NAME}\"}" + + curl -v --location --request PUT "${HOST_PATHFINDER_ORACLE}/participants/MSISDN/${MSISDN}" \ + --header 'Content-Type: application/json' \ + --header "date: ${CURRENT_DATE}" \ + --header "fspiop-source: ${DFSP_NAME}" \ + --data-raw "${DATA}"; +done + +echo "MSISDN's have been onboarded" diff --git a/src/audit-resolve.json b/src/audit-resolve.json index 6e030d9c..c1cad85d 100644 --- a/src/audit-resolve.json +++ b/src/audit-resolve.json @@ -1,30 +1,9 @@ { "decisions": { - "1300|nyc>istanbul-reports>handlebars": { - "madeAt": 0, - "decision": "fix" - }, - "1316|nyc>istanbul-reports>handlebars": { - "madeAt": 0, - "decision": "fix" - }, - "1324|nyc>istanbul-reports>handlebars": { - "madeAt": 0, - "decision": "fix" - }, - "1325|nyc>istanbul-reports>handlebars": { - "madeAt": 0, - "decision": "fix" - }, - "1500|npm-audit-resolver>yargs-unparser>yargs>yargs-parser": { - "decision": "ignore", - "madeAt": 1591787086979, - "expiresAt": 1592391879076 - }, "1500|npm-audit-resolver>audit-resolve-core>yargs-parser": { "decision": "ignore", - "madeAt": 1591787090589, - "expiresAt": 1592391879076 + "madeAt": 1594258444388, + "expiresAt": 1594863234907 } }, "rules": {}, diff --git a/src/package-lock.json b/src/package-lock.json index 3af2b134..028b92bf 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.4.1", + "version": "10.6.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3661,10 +3661,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, "lodash.clonedeep": { "version": "4.5.0", diff --git a/src/package.json b/src/package.json index 110502fb..88d426ae 100644 --- a/src/package.json +++ b/src/package.json @@ -1,13 +1,15 @@ { "name": "mojaloop-simulator", - "version": "10.4.1", + "version": "10.6.0", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", "author": "Matt Kingston, ModusBox Inc.", "contributors": [ + "Kamuela Franco ", "Matt Kingston ", "Steven Oderayi ", + "Aaron Reynoza ", "ModusBox", "Mowali" ], From 16ead3f9385c44b79b2d0f2cc11330afaf686e0b Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Thu, 9 Jul 2020 13:24:35 +0100 Subject: [PATCH 05/30] Fix publish for onboard-msisdn-oracle in pipeline (#58) * Fix publish for onboard-msisdn-oracle in pipeline * Bump version --- .circleci/config.yml | 6 +++++- src/package-lock.json | 2 +- src/package.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 22243825..87da64e9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -402,7 +402,7 @@ jobs: - run: name: Re-tag pre built image command: | - docker tag docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-msisdn-oracle:$RELEASE_TAG + docker tag $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG $DOCKER_ORG/onboard-msisdn-oracle:$RELEASE_TAG - run: name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub for onboard-msisdn-oracle command: | @@ -523,6 +523,8 @@ workflows: - /hotfix*/ - build: context: org-global + requires: + - setup filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ @@ -531,6 +533,8 @@ workflows: - /.*/ - build-onboard-msisdn-oracle: context: org-global + requires: + - setup filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ diff --git a/src/package-lock.json b/src/package-lock.json index 028b92bf..2338474a 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.0", + "version": "10.6.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index 88d426ae..d9f7c510 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.0", + "version": "10.6.1", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 52ee4073a1776c85e91828d6497095649d6337f1 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Thu, 9 Jul 2020 22:32:12 +0100 Subject: [PATCH 06/30] Add init container to onboard with central-ledger (#48) * Add init container to onboard with central-ledger * Remove environment var processing script * Switch RUN to CMD * Add OCI labels * Add contributor * Update init/central-ledger/Dockerfile Co-Authored-By: Matt Kingston * Clear whitespace and unused comments * Add build and publish to CI for init-central-ledger * Fix indentation * Update .circleci/config.yml Co-authored-by: Matt Kingston * Add ESLint and node-fetch * Update config to master branch * Add onboarding steps * Update finance-portal-lib dependency * Add logging * Update Dockerfile * Add items to .gitignore * Align output * Graceful exit on failure * Add log output * Add detailed logging on error * Update finance-portal-lib dependency * Add more detailed logging * Allow re-registration of same DFSP name and currency * Fix bug * Fix output by calling script directly * Fix logging and request edge cases * Add onboard-central-ledger to pipeline * Bump version * Add comments * Fix build argument references * Require setup for local builds * Update init/onboard-central-ledger/onboard-dfsp.js Co-authored-by: Matt Kingston * Log script commands and exit on error * Exit when required variable is not present Co-authored-by: Matt Kingston --- .circleci/config.yml | 141 +- .dockerignore | 3 + .gitignore | 4 +- init/onboard-central-ledger/.eslintrc.json | 6 + init/onboard-central-ledger/.gitignore | 1 + init/onboard-central-ledger/Dockerfile | 28 + init/onboard-central-ledger/onboard-dfsp.js | 502 +++++ init/onboard-central-ledger/package-lock.json | 1737 +++++++++++++++++ init/onboard-central-ledger/package.json | 24 + init/onboard-msisdn-oracle/insert_msisdns.sh | 2 + src/package-lock.json | 2 +- src/package.json | 2 +- 12 files changed, 2437 insertions(+), 15 deletions(-) create mode 100644 init/onboard-central-ledger/.eslintrc.json create mode 100644 init/onboard-central-ledger/.gitignore create mode 100644 init/onboard-central-ledger/Dockerfile create mode 100644 init/onboard-central-ledger/onboard-dfsp.js create mode 100644 init/onboard-central-ledger/package-lock.json create mode 100644 init/onboard-central-ledger/package.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 87da64e9..46df0aa7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -202,10 +202,10 @@ jobs: echo "Building Docker image: $CIRCLE_TAG" docker build - --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg CREATED="$(date -u --iso-8601=seconds)" --build-arg VERSION="$RELEASE_TAG" - --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" - --build-arg VCS_REF="$CIRCLE_SHA1" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:$CIRCLE_TAG . - run: name: Save docker image to workspace @@ -215,6 +215,29 @@ jobs: paths: - ./docker-image.tar + build-onboard-central-ledger: + executor: default-machine + steps: + - checkout + - run: + name: Build Docker onboard-central-ledger $CIRCLE_TAG image + command: > + echo "Building Docker image: onboard-central-ledger $CIRCLE_TAG" + + docker build + --build-arg CREATED="$(date -u --iso-8601=seconds)" + --build-arg VERSION="$RELEASE_TAG" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" + -t $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG . + - run: + name: Save docker image to workspace + command: docker save -o /tmp/docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG + - persist_to_workspace: + root: /tmp + paths: + - ./docker-onboard-central-ledger.tar + build-onboard-msisdn-oracle: executor: default-machine steps: @@ -225,10 +248,10 @@ jobs: echo "Building Docker image: onboard-msisdn-oracle $CIRCLE_TAG" docker build - --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg CREATED="$(date -u --iso-8601=seconds)" --build-arg VERSION="$RELEASE_TAG" - --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" - --build-arg VCS_REF="$CIRCLE_SHA1" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" -t $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG . - run: name: Save docker image to workspace @@ -248,10 +271,10 @@ jobs: echo "Building Docker image: local" docker build - --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg CREATED="$(date -u --iso-8601=seconds)" --build-arg VERSION="local" - --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" - --build-arg VCS_REF="$CIRCLE_SHA1" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local . - run: name: Save docker image to workspace @@ -261,6 +284,29 @@ jobs: paths: - ./docker-image.tar + build-local-onboard-central-ledger: + executor: default-machine + steps: + - checkout + - run: + name: Build Docker onboard-central-ledger local image for testing + command: > + echo "Building Docker image: onboard-central-ledger local" + + docker build + --build-arg CREATED="$(date -u --iso-8601=seconds)" + --build-arg VERSION="local" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" + -t $DOCKER_ORG/onboard-central-ledger:local ./init/onboard-central-ledger/ + - run: + name: Save docker image to workspace + command: docker save -o /tmp/docker-onboard-central-ledger.tar $DOCKER_ORG/onboard-central-ledger:local + - persist_to_workspace: + root: /tmp + paths: + - ./docker-onboard-central-ledger.tar + build-local-onboard-msisdn-oracle: executor: default-machine steps: @@ -271,10 +317,10 @@ jobs: echo "Building Docker image: onboard-msisdn-oracle local" docker build - --build-arg BUILD_DATE="$(date -u --iso-8601=seconds)" + --build-arg CREATED="$(date -u --iso-8601=seconds)" --build-arg VERSION="local" - --build-arg VCS_URL="$CIRCLE_REPOSITORY_URL" - --build-arg VCS_REF="$CIRCLE_SHA1" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" -t $DOCKER_ORG/onboard-msisdn-oracle:local ./init/onboard-msisdn-oracle/ - run: name: Save docker image to workspace @@ -384,6 +430,39 @@ jobs: -H 'cache-control: no-cache' \ -d "{\"text\": \"*${CIRCLE_PROJECT_REPONAME}* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" + publish-onboard-central-ledger: + executor: default-machine + steps: + - checkout + - attach_workspace: + at: /tmp + - run: + name: Load the pre-built docker image for onboard-central-ledger from workspace + command: docker load -i /tmp/docker-onboard-central-ledger.tar + - run: + name: Login to Docker Hub + command: docker login -u $DOCKER_USER -p $DOCKER_PASS + - run: + name: Setup environment vars for release/snapshot + command: ./.circleci/_set_up_deploy_envs.sh + - run: + name: Re-tag pre built image + command: | + docker tag $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG $DOCKER_ORG/onboard-central-ledger:$RELEASE_TAG + - run: + name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub for onboard-central-ledger + command: | + echo "Publishing $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG" + docker push $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG + - run: + name: Slack announcement for tag releases + command: | + curl -X POST \ + $SLACK_WEBHOOK_ANNOUNCEMENT \ + -H 'Content-type: application/json' \ + -H 'cache-control: no-cache' \ + -d "{\"text\": \"*onboard-central-ledger* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" + publish-onboard-msisdn-oracle: executor: default-machine steps: @@ -487,6 +566,18 @@ workflows: - /hotfix*/ - build-local: context: org-global + requires: + - setup + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ + - build-local-onboard-central-ledger: + context: org-global + requires: + - setup filters: branches: ignore: @@ -495,6 +586,8 @@ workflows: - /hotfix*/ - build-local-onboard-msisdn-oracle: context: org-global + requires: + - setup filters: branches: ignore: @@ -531,6 +624,16 @@ workflows: branches: ignore: - /.*/ + - build-onboard-central-ledger: + context: org-global + requires: + - setup + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ + branches: + ignore: + - /.*/ - build-onboard-msisdn-oracle: context: org-global requires: @@ -552,10 +655,23 @@ workflows: branches: ignore: - /.*/ + - publish-onboard-central-ledger: + context: org-global + requires: + - build + - build-onboard-central-ledger + - build-onboard-msisdn-oracle + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ + branches: + ignore: + - /.*/ - publish-onboard-msisdn-oracle: context: org-global requires: - build + - build-onboard-central-ledger - build-onboard-msisdn-oracle filters: tags: @@ -567,6 +683,7 @@ workflows: context: org-global requires: - publish + - publish-onboard-central-ledger - publish-onboard-msisdn-oracle filters: tags: diff --git a/.dockerignore b/.dockerignore index 04a8318e..c6e0e219 100644 --- a/.dockerignore +++ b/.dockerignore @@ -45,6 +45,9 @@ typings/ # Optional eslint cache .eslintcache +# ESlint config +.eslintrc.json + # Optional REPL history .node_repl_history diff --git a/.gitignore b/.gitignore index 93d2e811..951bbeda 100644 --- a/.gitignore +++ b/.gitignore @@ -68,4 +68,6 @@ goldenpayerfsp goldenpayeefsp #vscode configs -.vscode/ \ No newline at end of file +.vscode/ +/init/.DS_Store +/.DS_Store diff --git a/init/onboard-central-ledger/.eslintrc.json b/init/onboard-central-ledger/.eslintrc.json new file mode 100644 index 00000000..2ad15fd8 --- /dev/null +++ b/init/onboard-central-ledger/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "airbnb-base", + "env": { + "node": true + } +} diff --git a/init/onboard-central-ledger/.gitignore b/init/onboard-central-ledger/.gitignore new file mode 100644 index 00000000..4c49bd78 --- /dev/null +++ b/init/onboard-central-ledger/.gitignore @@ -0,0 +1 @@ +.env diff --git a/init/onboard-central-ledger/Dockerfile b/init/onboard-central-ledger/Dockerfile new file mode 100644 index 00000000..c6db93b7 --- /dev/null +++ b/init/onboard-central-ledger/Dockerfile @@ -0,0 +1,28 @@ +FROM node:12.18.2-alpine as builder + +ARG CREATED +ARG SOURCE +ARG REVISION +ARG VERSION + +# See https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys and https://github.com/opencontainers/image-spec/blob/master/spec.md for info +LABEL org.opencontainers.image.created=${CREATED} +LABEL org.opencontainers.image.url="https://mojaloop.io/" +LABEL org.opencontainers.image.source=${SOURCE} +LABEL org.opencontainers.image.version=${VERSION} +LABEL org.opencontainers.image.revision=${REVISION} +LABEL org.opencontainers.image.title="onboard-central-ledger" +LABEL org.opencontainers.image.authors="kamuela.franco@modusbox.com" +LABEL org.opencontainers.image.licenses="Apache-2.0" + +WORKDIR /opt/onboard-central-ledger +COPY package* *.js /opt/onboard-central-ledger/ + +RUN ["npm", "ci", "--production"] + +FROM node:12.18.2-alpine +WORKDIR /opt/onboard-central-ledger + +COPY --from=builder /opt/onboard-central-ledger . + +CMD ["node", "onboard-dfsp.js"] diff --git a/init/onboard-central-ledger/onboard-dfsp.js b/init/onboard-central-ledger/onboard-dfsp.js new file mode 100644 index 00000000..785f24ac --- /dev/null +++ b/init/onboard-central-ledger/onboard-dfsp.js @@ -0,0 +1,502 @@ +const uuid = require('uuid'); +const { + onboarding: { + sendRequest, + settlementIdFromHubAccounts, + getDfspAccounts, + addDfsp, + addInitialPositionAndLimits, + depositFunds, + addCallbackParticipantPut, + addCallbackParticipantPutError, + addCallbackParticipantPutBatch, + addCallbackParticipantPutBatchError, + addCallbackPartiesGet, + addCallbackPartiesPut, + addCallbackPartiesPutError, + addCallbackQuotes, + addCallbackTransferPost, + addCallbackTransferPut, + addCallbackTransferError, + setEmailNetDebitCapAdjustment, + setEmailSettlementTransferPositionChange, + setEmailNetDebitCapThresholdBreach, + }, +} = require('@mojaloop/finance-portal-lib'); + +function log(message) { + const timestamp = (new Date()).toISOString(); + // eslint-disable-next-line no-console + console.log(`[${timestamp}] ${message}`); +} + +log(`ENV: AUTH_BEARER_TOKEN:\t\t\t\t${process.env.AUTH_BEARER_TOKEN}`); +log(`ENV: BASE_CENTRAL_LEDGER_ADMIN:\t\t\t${process.env.BASE_CENTRAL_LEDGER_ADMIN}`); +log(`ENV: DFSP_CALLBACK_URL:\t\t\t\t${process.env.DFSP_CALLBACK_URL}`); +log(`ENV: DFSP_CURRENCY:\t\t\t\t\t${process.env.DFSP_CURRENCY}`); +log(`ENV: DFSP_NAME:\t\t\t\t\t${process.env.DFSP_NAME}`); +log(`ENV: DFSP_PARTY_ID:\t\t\t\t\t${process.env.DFSP_PARTY_ID}`); +log(`ENV: DFSP_PARTY_ID_TYPE:\t\t\t\t${process.env.DFSP_PARTY_ID_TYPE}`); +log(`ENV: FUNDS_IN_PREPARE_AMOUNT:\t\t\t${process.env.FUNDS_IN_PREPARE_AMOUNT}`); +log(`ENV: HOST_CENTRAL_LEDGER:\t\t\t\t${process.env.HOST_CENTRAL_LEDGER}`); +log(`ENV: HUB_OPERATOR_NAME:\t\t\t\t${process.env.HUB_OPERATOR_NAME}`); +log(`ENV: INITIAL_POSITION:\t\t\t\t${process.env.INITIAL_POSITION}`); +log(`ENV: NDC_ADJUSTMENT_EMAIL:\t\t\t\t${process.env.NDC_ADJUSTMENT_EMAIL}`); +log(`ENV: NDC_THRESHOLD_BREACH_EMAIL:\t\t\t${process.env.NDC_THRESHOLD_BREACH_EMAIL}`); +log(`ENV: NET_DEBIT_CAP:\t\t\t\t\t${process.env.NET_DEBIT_CAP}`); +log(`ENV: SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL:\t${process.env.SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL}`); + +const amount = process.env.FUNDS_IN_PREPARE_AMOUNT; +const authToken = process.env.AUTH_BEARER_TOKEN; +const baseCentralLedgerAdmin = process.env.BASE_CENTRAL_LEDGER_ADMIN; +const dfspCallbackUrl = process.env.DFSP_CALLBACK_URL; +const dfspCurrency = process.env.DFSP_CURRENCY; +const dfspPartyIdType = process.env.DFSP_PARTY_ID_TYPE; +const dfspPartyId = process.env.DFSP_PARTY_ID; +const dfspName = process.env.DFSP_NAME; +const fspiopSource = process.env.HUB_OPERATOR_NAME; +const hostCentralLedger = process.env.HOST_CENTRAL_LEDGER; +const initialPosition = parseInt(process.env.INITIAL_POSITION, 10); +log(`LOC: initialPosition:\t\t\t\t${initialPosition}`); +const netDebitCap = parseInt(process.env.NET_DEBIT_CAP, 10); +log(`LOC: netDebitCap:\t\t\t\t\t${netDebitCap}`); +const ndcAdjustmentEmail = process.env.NDC_ADJUSTMENT_EMAIL; +const ndcThresholdBreachEmail = process.env.NDC_THRESHOLD_BREACH_EMAIL; +const settlementTransferPositionChangeEmail = process.env.SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL; + +async function onboardDfsp() { + try { + log('EXE: INIT: sendRequest->addDfsp'); + const response = await sendRequest(addDfsp({ + dfspName, + dfspCurrency, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addDfsp'); + } else { + const error = await response.json(); + // Allow re-registering of the same DFSP name and currency + if (response.status === 400 && error.errorInformation.errorCode === '3000' + && /already/.test(error.errorInformation.errorDescription)) { + log(`EXE: FAIL: sendRequest->addDfsp:\t\t\t${JSON.stringify(error)}`); + log('EXE: INFO: Allowed failure:\t\t\t\tProceeding with next request'); + } else { + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addDfsp:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addInitialPositionAndLimits'); + const response = await sendRequest(addInitialPositionAndLimits({ + dfspName, + dfspCurrency, + netDebitCap, + initialPosition, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addInitialPositionAndLimits'); + } else { + const error = await response.json(); + // Allow re-registering + if (response.status === 500 && error.errorInformation.errorCode === '2001' + && /already/.test(error.errorInformation.errorDescription)) { + log(`EXE: FAIL: sendRequest->addInitialPositionAndLimits:\t${JSON.stringify(error)}`); + log('EXE: INFO: Allowed failure:\t\t\t\tProceeding with next request'); + } else { + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addInitialPositionAndLimits:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->getDfspAccounts'); + const response = await sendRequest(getDfspAccounts({ + dfspName, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + const dfspAccounts = await response.json(); + log('EXE: SUCC: sendRequest->getDfspAccounts'); + log(`LOC: dfspAccounts:\t\t\t\t\t${JSON.stringify(dfspAccounts)}`); + log('EXE: INIT: settlementAccountIdFromHubAccounts'); + const settlementAccountId = settlementIdFromHubAccounts(dfspAccounts, dfspCurrency); + log('EXE: SUCC: settlementAccountIdFromHubAccounts'); + log(`LOC: settlementAccountId:\t\t\t\t${settlementAccountId}`); + log('EXE: INIT: sendRequest->depositFunds'); + const innerResponse = await sendRequest(depositFunds({ + dfspName, + dfspCurrency, + amount, + transferId: uuid.v4(), + settlementAccountId, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (innerResponse.ok) { + log('EXE: SUCC: sendRequest->depositFunds'); + } else { + const innerError = await innerResponse.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(innerError)}`); + } + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + // Testing indicates this regex will match a settlementAccountIdFromHubAccounts error, but not a + // depositFunds error + if (/property/.test(message)) { + // So that a more specific failure can be logged + log(`EXE: FAIL: settlementAccountIdFromHubAccounts:\t${message}`); + } else { + log(`EXE: FAIL: sendRequest->depositFunds:\t\t${message}`); + } + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackParticipantPut'); + const response = await sendRequest(addCallbackParticipantPut({ + dfspName, + dfspCallbackUrl, + dfspPartyId, + dfspPartyIdType, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackParticipantPut'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackParticipantPut:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackParticipantPutError'); + const response = await sendRequest(addCallbackParticipantPutError({ + dfspName, + dfspCallbackUrl, + dfspPartyId, + dfspPartyIdType, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackParticipantPutError'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackParticipantPutError:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackParticipantPutBatch'); + const response = await sendRequest(addCallbackParticipantPutBatch({ + dfspName, + dfspCallbackUrl, + requestId: uuid.v4(), + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackParticipantPutBatch'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackParticipantPutBatch:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackParticipantPutBatchError'); + const response = await sendRequest(addCallbackParticipantPutBatchError({ + dfspName, + dfspCallbackUrl, + requestId: uuid.v4(), + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackParticipantPutBatchError'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackParticipantPutBatchError:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackPartiesGet'); + const response = await sendRequest(addCallbackPartiesGet({ + dfspName, + dfspCallbackUrl, + dfspPartyId, + dfspPartyIdType, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackPartiesGet'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackPartiesGet:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackPartiesPut'); + const response = await sendRequest(addCallbackPartiesPut({ + dfspName, + dfspCallbackUrl, + dfspPartyId, + dfspPartyIdType, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackPartiesPut'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackPartiesPut:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackPartiesPutError'); + const response = await sendRequest(addCallbackPartiesPutError({ + dfspName, + dfspCallbackUrl, + dfspPartyId, + dfspPartyIdType, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackPartiesPutError'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackPartiesPutError:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackQuotes'); + const response = await sendRequest(addCallbackQuotes({ + dfspName, + dfspCallbackUrl, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackQuotes'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackQuotes:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackTransferPost'); + const response = await sendRequest(addCallbackTransferPost({ + dfspName, + dfspCallbackUrl, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackTransferPost'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackTransferPost:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackTransferPut'); + const response = await sendRequest(addCallbackTransferPut({ + dfspName, + dfspCallbackUrl, + transferId: uuid.v4(), + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackTransferPut'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackTransferPut:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->addCallbackTransferError'); + const response = await sendRequest(addCallbackTransferError({ + dfspName, + dfspCallbackUrl, + transferId: uuid.v4(), + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->addCallbackTransferError'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->addCallbackTransferError:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->setEmailNetDebitCapAdjustment'); + const response = await sendRequest(setEmailNetDebitCapAdjustment({ + dfspName, + email: ndcAdjustmentEmail, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->setEmailNetDebitCapAdjustment'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->setEmailNetDebitCapAdjustment:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->setEmailSettlementTransferPositionChange'); + const response = await sendRequest(setEmailSettlementTransferPositionChange({ + dfspName, + email: settlementTransferPositionChangeEmail, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->setEmailSettlementTransferPositionChange'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->setEmailSettlementTransferPositionChange:\t${message}`); + process.exitCode = 1; + return; + } + + try { + log('EXE: INIT: sendRequest->setEmailNetDebitCapThresholdBreach'); + const response = await sendRequest(setEmailNetDebitCapThresholdBreach({ + dfspName, + email: ndcThresholdBreachEmail, + authToken, + hostCentralLedger, + baseCentralLedgerAdmin, + fspiopSource, + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->setEmailNetDebitCapThresholdBreach'); + } else { + const error = await response.json(); + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->setEmailNetDebitCapThresholdBreach:\t${message}`); + process.exitCode = 1; + } +} + +onboardDfsp(); diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json new file mode 100644 index 00000000..616bc46e --- /dev/null +++ b/init/onboard-central-ledger/package-lock.json @@ -0,0 +1,1737 @@ +{ + "name": "onboard-central-ledger", + "version": "10.6.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.1" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@mojaloop/finance-portal-lib": { + "version": "0.0.16-snapshot", + "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.16-snapshot.tgz", + "integrity": "sha512-dPB/xrbGtzg7w5o78Xhg/HXXuttSyxi6ELXyE4xXMhal5qXKEiwfX5Yeuu3MDZuCqmCi2XcY+VQhFiMQAw/oJQ==", + "requires": { + "big.js": "5.2.2", + "node-fetch": "2.3.0", + "uuid": "3.3.2", + "xml-js": "1.6.8" + }, + "dependencies": { + "node-fetch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", + "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, + "@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/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "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" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "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" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "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.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "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.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "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" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.2.0.tgz", + "integrity": "sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.0.0", + "eslint-visitor-keys": "^1.2.0", + "espree": "^7.1.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", + "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.9", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.21.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.21.2.tgz", + "integrity": "sha512-FEmxeGI6yaz+SnEB6YgNHlQK1Bs2DKLM+YF+vuTk5H8J9CLbJLtlPvRFgZZ2+sXiKAlN5dpdlrWOjK8ZoZJpQA==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz", + "integrity": "sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==", + "dev": true + }, + "espree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz", + "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==", + "dev": true, + "requires": { + "acorn": "^7.2.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.2.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "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 + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "inquirer": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.2.0.tgz", + "integrity": "sha512-E0c4rPwr9ByePfNlTIB8z51kK1s2n6jrHuJeEHENl/sbq2G/S1auvibgEwNR4uSyiU+PiYHqSwsgGiXjG8p5ZQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "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.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "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-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "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" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "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.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "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.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "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-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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 + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xml-js": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.8.tgz", + "integrity": "sha512-kUv/geyN80d+s1T68uBfjoz+PjNUjwwf5AWWRwKRqqQaGozpMVsFsKYnenPsxlbN/VL7f0ia8NfLLPCDwX+95Q==", + "requires": { + "sax": "^1.2.4" + } + } + } +} diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json new file mode 100644 index 00000000..4c667cbe --- /dev/null +++ b/init/onboard-central-ledger/package.json @@ -0,0 +1,24 @@ +{ + "name": "onboard-central-ledger", + "version": "10.6.2", + "description": "", + "main": "onboard-dfsp.js", + "dependencies": { + "@mojaloop/finance-portal-lib": "0.0.16-snapshot", + "node-fetch": "^2.6.0", + "uuid": "^8.2.0" + }, + "devDependencies": { + "eslint": "^7.2.0", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-plugin-import": "^2.21.2" + }, + "scripts": { + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "start": "node onboard-dfsp.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Kamuela Franco ", + "license": "Apache-2.0" +} diff --git a/init/onboard-msisdn-oracle/insert_msisdns.sh b/init/onboard-msisdn-oracle/insert_msisdns.sh index bc23e536..2daf8a1e 100755 --- a/init/onboard-msisdn-oracle/insert_msisdns.sh +++ b/init/onboard-msisdn-oracle/insert_msisdns.sh @@ -1,5 +1,7 @@ #!/usr/bin/env sh +set -eux + CURRENT_DATE=$(date) for participantMSISDN in $(echo "${MSISDN_LIST}" | jq -c '.[]'); do MSISDN=$(echo "${participantMSISDN}" | jq -r '.MSISDN'); diff --git a/src/package-lock.json b/src/package-lock.json index 2338474a..2a2349f0 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.1", + "version": "10.6.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index d9f7c510..c9546951 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.1", + "version": "10.6.2", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 7f29b3c8298421612a3470df51a404640a27a2d2 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Thu, 9 Jul 2020 22:47:42 +0100 Subject: [PATCH 07/30] Fix erroneous file name in pipeline (#59) * Fix file name * Bump version --- .circleci/config.yml | 2 +- init/onboard-central-ledger/package-lock.json | 2 +- init/onboard-central-ledger/package.json | 2 +- src/package-lock.json | 2 +- src/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 46df0aa7..110515bd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -232,7 +232,7 @@ jobs: -t $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG . - run: name: Save docker image to workspace - command: docker save -o /tmp/docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG + command: docker save -o /tmp/docker-onboard-central-ledger.tar $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG - persist_to_workspace: root: /tmp paths: diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index 616bc46e..7e94f62d 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "10.6.2", + "version": "10.6.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index 4c667cbe..405b83d9 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "10.6.2", + "version": "10.6.3", "description": "", "main": "onboard-dfsp.js", "dependencies": { diff --git a/src/package-lock.json b/src/package-lock.json index 2a2349f0..f8afc33c 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.2", + "version": "10.6.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index c9546951..bfdf7255 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.2", + "version": "10.6.3", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From c64b7f8e5382d830ea7d2b7bd2033fb870819fd5 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Mon, 13 Jul 2020 19:17:55 +0100 Subject: [PATCH 08/30] Remove dependency on org secret for build pipeline (#61) * Remove dependency on org secret for build pipeline * Update config.yml --- .circleci/config.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 110515bd..405e7806 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -275,10 +275,10 @@ jobs: --build-arg VERSION="local" --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" --build-arg REVISION="$CIRCLE_SHA1" - -t $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local . + -t mojaloop/$CIRCLE_PROJECT_REPONAME:local . - run: name: Save docker image to workspace - command: docker save -o /tmp/docker-image.tar $DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local + command: docker save -o /tmp/docker-image.tar mojaloop/$CIRCLE_PROJECT_REPONAME:local - persist_to_workspace: root: /tmp paths: @@ -298,10 +298,10 @@ jobs: --build-arg VERSION="local" --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" --build-arg REVISION="$CIRCLE_SHA1" - -t $DOCKER_ORG/onboard-central-ledger:local ./init/onboard-central-ledger/ + -t mojaloop/onboard-central-ledger:local ./init/onboard-central-ledger/ - run: name: Save docker image to workspace - command: docker save -o /tmp/docker-onboard-central-ledger.tar $DOCKER_ORG/onboard-central-ledger:local + command: docker save -o /tmp/docker-onboard-central-ledger.tar mojaloop/onboard-central-ledger:local - persist_to_workspace: root: /tmp paths: @@ -321,10 +321,10 @@ jobs: --build-arg VERSION="local" --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" --build-arg REVISION="$CIRCLE_SHA1" - -t $DOCKER_ORG/onboard-msisdn-oracle:local ./init/onboard-msisdn-oracle/ + -t mojaloop/onboard-msisdn-oracle:local ./init/onboard-msisdn-oracle/ - run: name: Save docker image to workspace - command: docker save -o /tmp/docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-msisdn-oracle:local + command: docker save -o /tmp/docker-onboard-msisdn-oracle.tar mojaloop/onboard-msisdn-oracle:local - persist_to_workspace: root: /tmp paths: @@ -343,7 +343,7 @@ jobs: <<: *defaults_license_scanner - run: name: Run the license-scanner - command: cd /tmp/license-scanner && mode=docker dockerImages=$DOCKER_ORG/$CIRCLE_PROJECT_REPONAME:local make run + command: cd /tmp/license-scanner && mode=docker dockerImages=mojaloop/$CIRCLE_PROJECT_REPONAME:local make run - store_artifacts: path: /tmp/license-scanner/results prefix: licenses @@ -363,7 +363,7 @@ jobs: command: docker load -i /tmp/docker-image.tar - anchore/analyze_local_image: dockerfile_path: ./Dockerfile - image_name: ${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:local + image_name: mojaloop/${CIRCLE_PROJECT_REPONAME}:local # Anchore bug: if policy_failure is `true`, reports don't get written - we manually check for failures below policy_failure: false timeout: '500' @@ -381,12 +381,12 @@ jobs: printf "\n%s\n" "The following vulnerabilities were found:" jq '[.vulnerabilities | group_by(.package) | .[] | {package: .[0].package, vuln: [.[].vuln]}]' anchore-reports/*vuln*.json fi - - run: - name: Upload Anchore reports to s3 - command: | - aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/${CIRCLE_PROJECT_REPONAME}/ --recursive - aws s3 rm ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive --exclude "*" --include "${CIRCLE_PROJECT_REPONAME}*" - aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive +# - run: +# name: Upload Anchore reports to s3 +# command: | +# aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/${CIRCLE_PROJECT_REPONAME}/ --recursive +# aws s3 rm ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive --exclude "*" --include "${CIRCLE_PROJECT_REPONAME}*" +# aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive # TODO: Enable this when we want to increase the strictness of our security policies # failCount=$(cat anchore-reports/*policy*.json | grep 'fail' | wc -l) From 32e9e822511015afbadc7e83a7aea70dadf85e06 Mon Sep 17 00:00:00 2001 From: Steven Oderayi Date: Tue, 14 Jul 2020 13:50:11 +0100 Subject: [PATCH 09/30] Fix bugs with API spec and model for bulk transfers (#62) --- src/models/bulkTransfer.js | 3 +++ src/package-lock.json | 5 +++-- src/package.json | 2 +- src/simulator/api.yaml | 2 -- src/test/test-api.js | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/models/bulkTransfer.js b/src/models/bulkTransfer.js index 9749af6c..7e3e64d5 100644 --- a/src/models/bulkTransfer.js +++ b/src/models/bulkTransfer.js @@ -62,6 +62,9 @@ module.exports = class BulkTransfer { async create(bulkTransferRequest) { const { bulkTransferId } = bulkTransferRequest; const response = { bulkTransferId }; + response.individualTransferResults = bulkTransferRequest.individualTransfers.map( + (transfer) => ({ transferId: transfer.transferId }), + ); const reqStr = JSON.stringify(bulkTransferRequest); const resStr = JSON.stringify(response); diff --git a/src/package-lock.json b/src/package-lock.json index f8afc33c..6d55eb53 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.3", + "version": "10.6.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3663,7 +3663,8 @@ "lodash": { "version": "4.17.19", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true }, "lodash.clonedeep": { "version": "4.5.0", diff --git a/src/package.json b/src/package.json index bfdf7255..2bc33d47 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.3", + "version": "10.6.4", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", diff --git a/src/simulator/api.yaml b/src/simulator/api.yaml index 40a56508..faadb54b 100644 --- a/src/simulator/api.yaml +++ b/src/simulator/api.yaml @@ -847,7 +847,6 @@ components: type: object required: - bulkTransferId - - from - individualTransfers properties: bulkTransferId: @@ -868,7 +867,6 @@ components: description: Data model for individual transfer in a bulk transfer request required: - transferId - - to - amount - currency properties: diff --git a/src/test/test-api.js b/src/test/test-api.js index 52ef235c..3432b311 100644 --- a/src/test/test-api.js +++ b/src/test/test-api.js @@ -26,7 +26,7 @@ 'use strict'; const test = require('ava'); -const Model = require('../../src/models/model'); +const Model = require('../models/model'); const handlers = require('../test-api/handlers'); const { ops, party, partyCreate } = require('./constants'); From e465845dea5c3da6f2649b732420613f878d5c94 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Tue, 14 Jul 2020 16:30:36 +0100 Subject: [PATCH 10/30] Fix erroneous use of environment variables for onboarding (#63) * Fix erroneous use of PARTY_ID and PARTY_ID_TYPE * Bump version --- init/onboard-central-ledger/onboard-dfsp.js | 18 ------------------ init/onboard-central-ledger/package-lock.json | 14 +++++++------- init/onboard-central-ledger/package.json | 4 ++-- src/package-lock.json | 2 +- src/package.json | 2 +- 5 files changed, 11 insertions(+), 29 deletions(-) diff --git a/init/onboard-central-ledger/onboard-dfsp.js b/init/onboard-central-ledger/onboard-dfsp.js index 785f24ac..7229d70c 100644 --- a/init/onboard-central-ledger/onboard-dfsp.js +++ b/init/onboard-central-ledger/onboard-dfsp.js @@ -35,8 +35,6 @@ log(`ENV: BASE_CENTRAL_LEDGER_ADMIN:\t\t\t${process.env.BASE_CENTRAL_LEDGER_ADMI log(`ENV: DFSP_CALLBACK_URL:\t\t\t\t${process.env.DFSP_CALLBACK_URL}`); log(`ENV: DFSP_CURRENCY:\t\t\t\t\t${process.env.DFSP_CURRENCY}`); log(`ENV: DFSP_NAME:\t\t\t\t\t${process.env.DFSP_NAME}`); -log(`ENV: DFSP_PARTY_ID:\t\t\t\t\t${process.env.DFSP_PARTY_ID}`); -log(`ENV: DFSP_PARTY_ID_TYPE:\t\t\t\t${process.env.DFSP_PARTY_ID_TYPE}`); log(`ENV: FUNDS_IN_PREPARE_AMOUNT:\t\t\t${process.env.FUNDS_IN_PREPARE_AMOUNT}`); log(`ENV: HOST_CENTRAL_LEDGER:\t\t\t\t${process.env.HOST_CENTRAL_LEDGER}`); log(`ENV: HUB_OPERATOR_NAME:\t\t\t\t${process.env.HUB_OPERATOR_NAME}`); @@ -51,8 +49,6 @@ const authToken = process.env.AUTH_BEARER_TOKEN; const baseCentralLedgerAdmin = process.env.BASE_CENTRAL_LEDGER_ADMIN; const dfspCallbackUrl = process.env.DFSP_CALLBACK_URL; const dfspCurrency = process.env.DFSP_CURRENCY; -const dfspPartyIdType = process.env.DFSP_PARTY_ID_TYPE; -const dfspPartyId = process.env.DFSP_PARTY_ID; const dfspName = process.env.DFSP_NAME; const fspiopSource = process.env.HUB_OPERATOR_NAME; const hostCentralLedger = process.env.HOST_CENTRAL_LEDGER; @@ -182,8 +178,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackParticipantPut({ dfspName, dfspCallbackUrl, - dfspPartyId, - dfspPartyIdType, authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -206,8 +200,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackParticipantPutError({ dfspName, dfspCallbackUrl, - dfspPartyId, - dfspPartyIdType, authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -230,7 +222,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackParticipantPutBatch({ dfspName, dfspCallbackUrl, - requestId: uuid.v4(), authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -253,7 +244,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackParticipantPutBatchError({ dfspName, dfspCallbackUrl, - requestId: uuid.v4(), authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -276,8 +266,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackPartiesGet({ dfspName, dfspCallbackUrl, - dfspPartyId, - dfspPartyIdType, authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -300,8 +288,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackPartiesPut({ dfspName, dfspCallbackUrl, - dfspPartyId, - dfspPartyIdType, authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -324,8 +310,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackPartiesPutError({ dfspName, dfspCallbackUrl, - dfspPartyId, - dfspPartyIdType, authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -392,7 +376,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackTransferPut({ dfspName, dfspCallbackUrl, - transferId: uuid.v4(), authToken, hostCentralLedger, baseCentralLedgerAdmin, @@ -415,7 +398,6 @@ async function onboardDfsp() { const response = await sendRequest(addCallbackTransferError({ dfspName, dfspCallbackUrl, - transferId: uuid.v4(), authToken, hostCentralLedger, baseCentralLedgerAdmin, diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index 7e94f62d..4a8e3af4 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "10.6.3", + "version": "10.6.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -44,9 +44,9 @@ } }, "@mojaloop/finance-portal-lib": { - "version": "0.0.16-snapshot", - "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.16-snapshot.tgz", - "integrity": "sha512-dPB/xrbGtzg7w5o78Xhg/HXXuttSyxi6ELXyE4xXMhal5qXKEiwfX5Yeuu3MDZuCqmCi2XcY+VQhFiMQAw/oJQ==", + "version": "0.0.17-snapshot", + "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.17-snapshot.tgz", + "integrity": "sha512-kT6HUKi3sa8hNckFCmNBbPeI9B8O2f2fUtrpTA6gVTkz300YZPr4nVP+Gk2iQ+UHfkertsNdSaZsFUUBob9LdA==", "requires": { "big.js": "5.2.2", "node-fetch": "2.3.0", @@ -1056,9 +1056,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "mimic-fn": { diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index 405b83d9..114320bd 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -1,10 +1,10 @@ { "name": "onboard-central-ledger", - "version": "10.6.3", + "version": "10.6.5", "description": "", "main": "onboard-dfsp.js", "dependencies": { - "@mojaloop/finance-portal-lib": "0.0.16-snapshot", + "@mojaloop/finance-portal-lib": "0.0.17-snapshot", "node-fetch": "^2.6.0", "uuid": "^8.2.0" }, diff --git a/src/package-lock.json b/src/package-lock.json index 6d55eb53..22d49ec7 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.4", + "version": "10.6.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index 2bc33d47..4aee8ae7 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.4", + "version": "10.6.5", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 3823d9ab042526b01a52719cf4f730274199cefa Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Thu, 23 Jul 2020 15:02:47 +0100 Subject: [PATCH 11/30] Fix build artifacts (#65) * Fix build artifacts * Bump version * Fix security issues --- .circleci/config.yml | 4 +-- init/onboard-central-ledger/package-lock.json | 2 +- init/onboard-central-ledger/package.json | 2 +- src/package-lock.json | 25 ++++++++----------- src/package.json | 2 +- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 405e7806..32dcbf21 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -229,7 +229,7 @@ jobs: --build-arg VERSION="$RELEASE_TAG" --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" --build-arg REVISION="$CIRCLE_SHA1" - -t $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG . + -t $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG ./init/onboard-central-ledger/ - run: name: Save docker image to workspace command: docker save -o /tmp/docker-onboard-central-ledger.tar $DOCKER_ORG/onboard-central-ledger:$CIRCLE_TAG @@ -252,7 +252,7 @@ jobs: --build-arg VERSION="$RELEASE_TAG" --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" --build-arg REVISION="$CIRCLE_SHA1" - -t $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG . + -t $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG ./init/onboard-msisdn-oracle/ - run: name: Save docker image to workspace command: docker save -o /tmp/docker-onboard-msisdn-oracle.tar $DOCKER_ORG/onboard-msisdn-oracle:$CIRCLE_TAG diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index 4a8e3af4..5d0eb13d 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "10.6.5", + "version": "10.6.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index 114320bd..4fa4db8d 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "10.6.5", + "version": "10.6.6", "description": "", "main": "onboard-dfsp.js", "dependencies": { diff --git a/src/package-lock.json b/src/package-lock.json index 22d49ec7..2043f032 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.5", + "version": "10.6.6", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -787,24 +787,18 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "audit-resolve-core": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/audit-resolve-core/-/audit-resolve-core-1.1.7.tgz", - "integrity": "sha512-9nLm9SgyMbMv86X5a/E6spcu3V+suceHF6Pg4BwjPqfxWBKDvISagJH9Ji592KihqBev4guKFO3BiNEVNnqh3A==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/audit-resolve-core/-/audit-resolve-core-1.1.8.tgz", + "integrity": "sha512-F3IWaxu1Xw4OokmtG9hkmsKoJt8DQS7RZvot52zXHsANKvzFRMKVNTP1DAz1ztlRGmJx1XV16PcE+6m35bYoTA==", "dev": true, "requires": { "concat-stream": "^1.6.2", "debug": "^4.1.1", "djv": "^2.1.2", "spawn-shell": "^2.1.0", - "yargs-parser": "^10.1.0" + "yargs-parser": "^18.1.3" }, "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -815,12 +809,13 @@ } }, "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } diff --git a/src/package.json b/src/package.json index 4aee8ae7..c354f02e 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.5", + "version": "10.6.6", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From fd703c4e344b0c7b8541a8fa556e8c4679bacd86 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Thu, 23 Jul 2020 15:29:09 +0100 Subject: [PATCH 12/30] Fix build order dependency (#66) --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 32dcbf21..235e2960 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -648,6 +648,7 @@ workflows: context: org-global requires: - build + - build-onboard-central-ledger - build-onboard-msisdn-oracle filters: tags: From 9af96c8b8d96204b808db68500b5319c0f9f3211 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Fri, 24 Jul 2020 09:52:37 +0100 Subject: [PATCH 13/30] Update finance-portal-lib in init container (#67) --- init/onboard-central-ledger/package-lock.json | 22 +++++++++++++++---- init/onboard-central-ledger/package.json | 4 ++-- src/package-lock.json | 2 +- src/package.json | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index 5d0eb13d..db3f6c76 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "10.6.6", + "version": "11.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -44,10 +44,11 @@ } }, "@mojaloop/finance-portal-lib": { - "version": "0.0.17-snapshot", - "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.17-snapshot.tgz", - "integrity": "sha512-kT6HUKi3sa8hNckFCmNBbPeI9B8O2f2fUtrpTA6gVTkz300YZPr4nVP+Gk2iQ+UHfkertsNdSaZsFUUBob9LdA==", + "version": "0.0.18-snapshot", + "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.18-snapshot.tgz", + "integrity": "sha512-om9A5q7RFkqHf3hTdin13bbqSm3XVDtfFJXmupYdvfnyfUGatfgNPMHNjfW08ttr/JJXh91kNIQ9VAxggBVbXg==", "requires": { + "abort-controller": "^3.0.0", "big.js": "5.2.2", "node-fetch": "2.3.0", "uuid": "3.3.2", @@ -78,6 +79,14 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "acorn": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", @@ -635,6 +644,11 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index 4fa4db8d..92e7bdaa 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -1,10 +1,10 @@ { "name": "onboard-central-ledger", - "version": "10.6.6", + "version": "11.0.0", "description": "", "main": "onboard-dfsp.js", "dependencies": { - "@mojaloop/finance-portal-lib": "0.0.17-snapshot", + "@mojaloop/finance-portal-lib": "0.0.18-snapshot", "node-fetch": "^2.6.0", "uuid": "^8.2.0" }, diff --git a/src/package-lock.json b/src/package-lock.json index 2043f032..53a5228f 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.6", + "version": "11.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index c354f02e..017e30d7 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "10.6.6", + "version": "11.0.0", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 7a17587bd3784f159a4a3bf5b66df25e27b38984 Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Tue, 28 Jul 2020 11:54:32 +0000 Subject: [PATCH 14/30] Modified to reflect changes in dependency (#68) * Modified to reflect changes in dependency * Modified package version more * version stuff * Version bump * Version bump --- init/onboard-central-ledger/onboard-dfsp.js | 20 ------------------- init/onboard-central-ledger/package-lock.json | 8 ++++---- init/onboard-central-ledger/package.json | 4 ++-- src/package-lock.json | 2 +- src/package.json | 2 +- 5 files changed, 8 insertions(+), 28 deletions(-) diff --git a/init/onboard-central-ledger/onboard-dfsp.js b/init/onboard-central-ledger/onboard-dfsp.js index 7229d70c..920f0099 100644 --- a/init/onboard-central-ledger/onboard-dfsp.js +++ b/init/onboard-central-ledger/onboard-dfsp.js @@ -31,7 +31,6 @@ function log(message) { } log(`ENV: AUTH_BEARER_TOKEN:\t\t\t\t${process.env.AUTH_BEARER_TOKEN}`); -log(`ENV: BASE_CENTRAL_LEDGER_ADMIN:\t\t\t${process.env.BASE_CENTRAL_LEDGER_ADMIN}`); log(`ENV: DFSP_CALLBACK_URL:\t\t\t\t${process.env.DFSP_CALLBACK_URL}`); log(`ENV: DFSP_CURRENCY:\t\t\t\t\t${process.env.DFSP_CURRENCY}`); log(`ENV: DFSP_NAME:\t\t\t\t\t${process.env.DFSP_NAME}`); @@ -46,7 +45,6 @@ log(`ENV: SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL:\t${process.env.SETTLEMENT_T const amount = process.env.FUNDS_IN_PREPARE_AMOUNT; const authToken = process.env.AUTH_BEARER_TOKEN; -const baseCentralLedgerAdmin = process.env.BASE_CENTRAL_LEDGER_ADMIN; const dfspCallbackUrl = process.env.DFSP_CALLBACK_URL; const dfspCurrency = process.env.DFSP_CURRENCY; const dfspName = process.env.DFSP_NAME; @@ -68,7 +66,6 @@ async function onboardDfsp() { dfspCurrency, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -99,7 +96,6 @@ async function onboardDfsp() { initialPosition, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -127,7 +123,6 @@ async function onboardDfsp() { dfspName, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -147,7 +142,6 @@ async function onboardDfsp() { settlementAccountId, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (innerResponse.ok) { @@ -180,7 +174,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -202,7 +195,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -224,7 +216,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -246,7 +237,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -268,7 +258,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -290,7 +279,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -312,7 +300,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -334,7 +321,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -356,7 +342,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -378,7 +363,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -400,7 +384,6 @@ async function onboardDfsp() { dfspCallbackUrl, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -422,7 +405,6 @@ async function onboardDfsp() { email: ndcAdjustmentEmail, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -444,7 +426,6 @@ async function onboardDfsp() { email: settlementTransferPositionChangeEmail, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { @@ -466,7 +447,6 @@ async function onboardDfsp() { email: ndcThresholdBreachEmail, authToken, hostCentralLedger, - baseCentralLedgerAdmin, fspiopSource, })); if (response.ok) { diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index db3f6c76..8d4340e3 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "11.0.0", + "version": "11.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -44,9 +44,9 @@ } }, "@mojaloop/finance-portal-lib": { - "version": "0.0.18-snapshot", - "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.18-snapshot.tgz", - "integrity": "sha512-om9A5q7RFkqHf3hTdin13bbqSm3XVDtfFJXmupYdvfnyfUGatfgNPMHNjfW08ttr/JJXh91kNIQ9VAxggBVbXg==", + "version": "0.0.19-snapshot", + "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.19-snapshot.tgz", + "integrity": "sha512-mFJ0Ewt7yPob+38sZWIf6MQ8crW282lzWROVnfEGWDmLZWuVSlZA9qqrhveD+ia7hys/sBItBPNBmRCov7DfWw==", "requires": { "abort-controller": "^3.0.0", "big.js": "5.2.2", diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index 92e7bdaa..1c11afbf 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -1,10 +1,10 @@ { "name": "onboard-central-ledger", - "version": "11.0.0", + "version": "11.0.1", "description": "", "main": "onboard-dfsp.js", "dependencies": { - "@mojaloop/finance-portal-lib": "0.0.18-snapshot", + "@mojaloop/finance-portal-lib": "0.0.19-snapshot", "node-fetch": "^2.6.0", "uuid": "^8.2.0" }, diff --git a/src/package-lock.json b/src/package-lock.json index 53a5228f..46a6c9a0 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.0.0", + "version": "11.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index 017e30d7..308f0f07 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.0.0", + "version": "11.0.1", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 5b785dce127651b259887805221026f8f7954da2 Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Tue, 28 Jul 2020 14:00:12 +0000 Subject: [PATCH 15/30] Add hub onboarding image (#69) * Code written * Fixes, changes * Added onboard hub accounts to CI * Updated CI * Update init/onboard-hub-accounts/Dockerfile Co-authored-by: Kamuela Franco Co-authored-by: Kamuela Franco --- .circleci/config.yml | 115 ++ init/onboard-hub-accounts/Dockerfile | 28 + .../onboard-hub-accounts.js | 64 + init/onboard-hub-accounts/package-lock.json | 1751 +++++++++++++++++ init/onboard-hub-accounts/package.json | 24 + 5 files changed, 1982 insertions(+) create mode 100644 init/onboard-hub-accounts/Dockerfile create mode 100644 init/onboard-hub-accounts/onboard-hub-accounts.js create mode 100644 init/onboard-hub-accounts/package-lock.json create mode 100644 init/onboard-hub-accounts/package.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 235e2960..3dcefd47 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -215,6 +215,29 @@ jobs: paths: - ./docker-image.tar + build-onboard-hub-accounts: + executor: default-machine + steps: + - checkout + - run: + name: Build Docker onboard-hub-accounts $CIRCLE_TAG image + command: > + echo "Building Docker image: onboard-hub-accounts $CIRCLE_TAG" + + docker build + --build-arg CREATED="$(date -u --iso-8601=seconds)" + --build-arg VERSION="$RELEASE_TAG" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" + -t $DOCKER_ORG/onboard-hub-accounts:$CIRCLE_TAG ./init/onboard-hub-accounts/ + - run: + name: Save docker image to workspace + command: docker save -o /tmp/docker-onboard-hub-accounts.tar $DOCKER_ORG/onboard-hub-accounts:$CIRCLE_TAG + - persist_to_workspace: + root: /tmp + paths: + - ./docker-onboard-hub-accounts.tar + build-onboard-central-ledger: executor: default-machine steps: @@ -284,6 +307,29 @@ jobs: paths: - ./docker-image.tar + build-local-onboard-hub-accounts: + executor: default-machine + steps: + - checkout + - run: + name: Build Docker onboard-hub-accounts local image for testing + command: > + echo "Building Docker image: onboard-hub-accounts local" + + docker build + --build-arg CREATED="$(date -u --iso-8601=seconds)" + --build-arg VERSION="local" + --build-arg SOURCE="$CIRCLE_REPOSITORY_URL" + --build-arg REVISION="$CIRCLE_SHA1" + -t mojaloop/onboard-hub-accounts:local ./init/onboard-hub-accounts/ + - run: + name: Save docker image to workspace + command: docker save -o /tmp/docker-onboard-hub-accounts.tar mojaloop/onboard-hub-accounts:local + - persist_to_workspace: + root: /tmp + paths: + - ./docker-onboard-hub-accounts.tar + build-local-onboard-central-ledger: executor: default-machine steps: @@ -430,6 +476,39 @@ jobs: -H 'cache-control: no-cache' \ -d "{\"text\": \"*${CIRCLE_PROJECT_REPONAME}* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" + publish-onboard-hub-accounts: + executor: default-machine + steps: + - checkout + - attach_workspace: + at: /tmp + - run: + name: Load the pre-built docker image for onboard-hub-accounts from workspace + command: docker load -i /tmp/docker-onboard-hub-accounts.tar + - run: + name: Login to Docker Hub + command: docker login -u $DOCKER_USER -p $DOCKER_PASS + - run: + name: Setup environment vars for release/snapshot + command: ./.circleci/_set_up_deploy_envs.sh + - run: + name: Re-tag pre built image + command: | + docker tag $DOCKER_ORG/onboard-hub-accounts:$CIRCLE_TAG $DOCKER_ORG/onboard-hub-accounts:$RELEASE_TAG + - run: + name: Publish Docker image $CIRCLE_TAG & Latest tag to Docker Hub for onboard-hub-accounts + command: | + echo "Publishing $DOCKER_ORG/onboard-hub-accounts:$CIRCLE_TAG" + docker push $DOCKER_ORG/onboard-hub-accounts:$CIRCLE_TAG + - run: + name: Slack announcement for tag releases + command: | + curl -X POST \ + $SLACK_WEBHOOK_ANNOUNCEMENT \ + -H 'Content-type: application/json' \ + -H 'cache-control: no-cache' \ + -d "{\"text\": \"*onboard-hub-accounts* - Release \`${CIRCLE_TAG}\`: https://github.com/mojaloop/${CIRCLE_PROJECT_REPONAME}/releases/tag/${CIRCLE_TAG}\"}" + publish-onboard-central-ledger: executor: default-machine steps: @@ -574,6 +653,16 @@ workflows: - /feature*/ - /bugfix*/ - /hotfix*/ + - build-local-onboard-hub-accounts: + context: org-global + requires: + - setup + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ - build-local-onboard-central-ledger: context: org-global requires: @@ -624,6 +713,16 @@ workflows: branches: ignore: - /.*/ + - build-onboard-hub-accounts: + context: org-global + requires: + - setup + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ + branches: + ignore: + - /.*/ - build-onboard-central-ledger: context: org-global requires: @@ -656,12 +755,26 @@ workflows: branches: ignore: - /.*/ + - publish-onboard-hub-accounts: + context: org-global + requires: + - build + - build-onboard-central-ledger + - build-onboard-msisdn-oracle + - build-onboard-hub-accounts + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ + branches: + ignore: + - /.*/ - publish-onboard-central-ledger: context: org-global requires: - build - build-onboard-central-ledger - build-onboard-msisdn-oracle + - build-onboard-hub-accounts filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ @@ -674,6 +787,7 @@ workflows: - build - build-onboard-central-ledger - build-onboard-msisdn-oracle + - build-onboard-hub-accounts filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?(\-hotfix(\.[0-9]+))?/ @@ -686,6 +800,7 @@ workflows: - publish - publish-onboard-central-ledger - publish-onboard-msisdn-oracle + - publish-onboard-hub-accounts filters: tags: only: /v[0-9]+(\.[0-9]+)*(\-snapshot)?/ diff --git a/init/onboard-hub-accounts/Dockerfile b/init/onboard-hub-accounts/Dockerfile new file mode 100644 index 00000000..44c5a45a --- /dev/null +++ b/init/onboard-hub-accounts/Dockerfile @@ -0,0 +1,28 @@ +FROM node:12.18.2-alpine as builder + +ARG CREATED +ARG SOURCE +ARG REVISION +ARG VERSION + +# See https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys and https://github.com/opencontainers/image-spec/blob/master/spec.md for info +LABEL org.opencontainers.image.created=${CREATED} +LABEL org.opencontainers.image.url="https://mojaloop.io/" +LABEL org.opencontainers.image.source=${SOURCE} +LABEL org.opencontainers.image.version=${VERSION} +LABEL org.opencontainers.image.revision=${REVISION} +LABEL org.opencontainers.image.title="onboard-central-ledger" +LABEL org.opencontainers.image.authors="matt.kingston@modusbox.com" +LABEL org.opencontainers.image.licenses="Apache-2.0" + +WORKDIR /opt/onboard-central-ledger +COPY package* *.js /opt/onboard-central-ledger/ + +RUN ["npm", "ci", "--production"] + +FROM node:12.18.2-alpine +WORKDIR /opt/onboard-central-ledger + +COPY --from=builder /opt/onboard-central-ledger . + +CMD ["node", "onboard-hub.js"] diff --git a/init/onboard-hub-accounts/onboard-hub-accounts.js b/init/onboard-hub-accounts/onboard-hub-accounts.js new file mode 100644 index 00000000..6cdd39ef --- /dev/null +++ b/init/onboard-hub-accounts/onboard-hub-accounts.js @@ -0,0 +1,64 @@ +const uuid = require('uuid'); +const { + onboarding: { + createHubAccount, + sendRequest, + }, +} = require('@mojaloop/finance-portal-lib'); + +function log(message) { + const timestamp = (new Date()).toISOString(); + // eslint-disable-next-line no-console + console.log(`[${timestamp}] ${message}`); +} + +console.log('ENV:'); +console.table({ + ACCOUNTS: process.env.ACCOUNTS, + AUTH_BEARER_TOKEN: process.env.AUTH_BEARER_TOKEN, + HOST_CENTRAL_LEDGER: process.env.HOST_CENTRAL_LEDGER, + HUB_OPERATOR_NAME: process.env.HUB_OPERATOR_NAME, +}); + +const accounts = JSON.parse(process.env.ACCOUNTS); +const authToken = process.env.AUTH_BEARER_TOKEN; +const hostCentralLedger = process.env.HOST_CENTRAL_LEDGER; +const fspiopSource = process.env.HUB_OPERATOR_NAME; + +async function onboardHubAccounts() { + try { + log('EXE: INIT: sendRequest->createHubAccounts'); + // Deliberately sequential to be more predictable and make debugging a little easier + await accounts.reduce((promise, acc) => promise.then(async () => { + const response = await sendRequest(createHubAccount({ + authToken, + fspiopSource, + hostCentralLedger, + ...acc + })); + if (response.ok) { + log('EXE: SUCC: sendRequest->createHubAccounts'); + } else { + const error = await response.json(); + // Allow re-registering of the same hub account + if ( + response.status === 400 && + error.errorInformation.errorCode === '3003' && + /already/.test(error.errorInformation.errorDescription) + ) { + log(`EXE: FAIL: sendRequest->createHubAccounts:\n${JSON.stringify(error)}`); + log('EXE: INFO: Allowed failure. Continuing.'); + } else { + throw new Error(`Response not OK/2XX: ${JSON.stringify(error)}`); + } + } + }) , Promise.resolve()); + + } catch ({ message }) { + log(`EXE: FAIL: sendRequest->createHubAccounts:\t${message}`); + process.exitCode = 1; + return; + } +} + +onboardHubAccounts(); diff --git a/init/onboard-hub-accounts/package-lock.json b/init/onboard-hub-accounts/package-lock.json new file mode 100644 index 00000000..ef818982 --- /dev/null +++ b/init/onboard-hub-accounts/package-lock.json @@ -0,0 +1,1751 @@ +{ + "name": "onboard-hub-accounts", + "version": "11.0.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.1" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@mojaloop/finance-portal-lib": { + "version": "0.0.20-snapshot", + "resolved": "https://registry.npmjs.org/@mojaloop/finance-portal-lib/-/finance-portal-lib-0.0.20-snapshot.tgz", + "integrity": "sha512-8ZV50K2aSdD+RhU3lZUwVFdDGWJKmeAP11JH7njT4wPzrgVklf9STu1fHx/3dqcnewGso3yEC0oNSER2Edvb6w==", + "requires": { + "abort-controller": "^3.0.0", + "big.js": "5.2.2", + "node-fetch": "2.3.0", + "uuid": "3.3.2", + "xml-js": "1.6.8" + }, + "dependencies": { + "node-fetch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", + "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, + "@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/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "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" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "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" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "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.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "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.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "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" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.2.0.tgz", + "integrity": "sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.0.0", + "eslint-visitor-keys": "^1.2.0", + "espree": "^7.1.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", + "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.9", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.21.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.21.2.tgz", + "integrity": "sha512-FEmxeGI6yaz+SnEB6YgNHlQK1Bs2DKLM+YF+vuTk5H8J9CLbJLtlPvRFgZZ2+sXiKAlN5dpdlrWOjK8ZoZJpQA==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz", + "integrity": "sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==", + "dev": true + }, + "espree": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz", + "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==", + "dev": true, + "requires": { + "acorn": "^7.2.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.2.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "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 + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "inquirer": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.2.0.tgz", + "integrity": "sha512-E0c4rPwr9ByePfNlTIB8z51kK1s2n6jrHuJeEHENl/sbq2G/S1auvibgEwNR4uSyiU+PiYHqSwsgGiXjG8p5ZQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "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.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "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-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "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" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "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.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "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.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "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-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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 + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xml-js": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.8.tgz", + "integrity": "sha512-kUv/geyN80d+s1T68uBfjoz+PjNUjwwf5AWWRwKRqqQaGozpMVsFsKYnenPsxlbN/VL7f0ia8NfLLPCDwX+95Q==", + "requires": { + "sax": "^1.2.4" + } + } + } +} diff --git a/init/onboard-hub-accounts/package.json b/init/onboard-hub-accounts/package.json new file mode 100644 index 00000000..f2817e6d --- /dev/null +++ b/init/onboard-hub-accounts/package.json @@ -0,0 +1,24 @@ +{ + "name": "onboard-hub-accounts", + "version": "11.0.2", + "description": "", + "main": "onboard-hub-accounts.js", + "dependencies": { + "@mojaloop/finance-portal-lib": "0.0.20-snapshot", + "node-fetch": "^2.6.0", + "uuid": "^8.2.0" + }, + "devDependencies": { + "eslint": "^7.2.0", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-plugin-import": "^2.21.2" + }, + "scripts": { + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "start": "node onboard-hub-accounts.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Matt Kingston ", + "license": "Apache-2.0" +} From bd8a3a2da8adada55006d8e689f7ffeab266c06f Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Tue, 28 Jul 2020 14:18:12 +0000 Subject: [PATCH 16/30] Bump versions (#70) --- init/onboard-central-ledger/package-lock.json | 2 +- init/onboard-central-ledger/package.json | 2 +- src/package-lock.json | 2 +- src/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index 8d4340e3..21e52565 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "11.0.1", + "version": "11.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index 1c11afbf..3f8a6cce 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "11.0.1", + "version": "11.0.2", "description": "", "main": "onboard-dfsp.js", "dependencies": { diff --git a/src/package-lock.json b/src/package-lock.json index 46a6c9a0..69986d34 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.0.1", + "version": "11.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index 308f0f07..90bebc1d 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.0.1", + "version": "11.0.2", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From fd99d16a9adc517eadc0b59d1530a749ee0fd970 Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Tue, 28 Jul 2020 16:26:38 +0000 Subject: [PATCH 17/30] Fixed onboard-hub-accounts Dockerfile error, bumped versions (#71) --- init/onboard-central-ledger/package-lock.json | 2 +- init/onboard-central-ledger/package.json | 2 +- init/onboard-hub-accounts/Dockerfile | 2 +- init/onboard-hub-accounts/package-lock.json | 2 +- init/onboard-hub-accounts/package.json | 2 +- src/package-lock.json | 2 +- src/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index 21e52565..2bb6a7f1 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "11.0.2", + "version": "11.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index 3f8a6cce..cec023ee 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -1,6 +1,6 @@ { "name": "onboard-central-ledger", - "version": "11.0.2", + "version": "11.0.3", "description": "", "main": "onboard-dfsp.js", "dependencies": { diff --git a/init/onboard-hub-accounts/Dockerfile b/init/onboard-hub-accounts/Dockerfile index 44c5a45a..aeb3611c 100644 --- a/init/onboard-hub-accounts/Dockerfile +++ b/init/onboard-hub-accounts/Dockerfile @@ -25,4 +25,4 @@ WORKDIR /opt/onboard-central-ledger COPY --from=builder /opt/onboard-central-ledger . -CMD ["node", "onboard-hub.js"] +CMD ["node", "onboard-hub-accounts.js"] diff --git a/init/onboard-hub-accounts/package-lock.json b/init/onboard-hub-accounts/package-lock.json index ef818982..9b319843 100644 --- a/init/onboard-hub-accounts/package-lock.json +++ b/init/onboard-hub-accounts/package-lock.json @@ -1,6 +1,6 @@ { "name": "onboard-hub-accounts", - "version": "11.0.2", + "version": "11.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/init/onboard-hub-accounts/package.json b/init/onboard-hub-accounts/package.json index f2817e6d..ac1a8c4f 100644 --- a/init/onboard-hub-accounts/package.json +++ b/init/onboard-hub-accounts/package.json @@ -1,6 +1,6 @@ { "name": "onboard-hub-accounts", - "version": "11.0.2", + "version": "11.0.3", "description": "", "main": "onboard-hub-accounts.js", "dependencies": { diff --git a/src/package-lock.json b/src/package-lock.json index 69986d34..841ecda4 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.0.2", + "version": "11.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index 90bebc1d..d513f2bb 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.0.2", + "version": "11.0.3", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 1a4b02b629f5dbbc4b3c825c4dc141ee8283b055 Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Fri, 14 Aug 2020 13:46:47 +0100 Subject: [PATCH 18/30] Add image scans and vulnerability checks for inits (#74) --- .circleci/config.yml | 252 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3dcefd47..f178bfc8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -170,6 +170,58 @@ jobs: path: ./audit/results prefix: audit + vulnerability-check-onboard-hub-accounts: + executor: default-docker + steps: + - checkout + - restore_cache: + key: dependency-cache-v1-{{ checksum "src/package-lock.json" }} + paths: + - src/node_modules + - src/lib/log/node_modules + - src/lib/validate/node_modules + - run: + name: Install general dependencies + command: *defaults_Dependencies + - run: + name: Update NPM install (using `npm ci`) + command: cd init/onboard-hub-accounts && npm ci + - run: + name: Create dir for test results + command: mkdir -p ./audit/results + - run: + name: Check for new npm vulnerabilities + command: cd src && npm run audit:check --silent -- --json > ../audit/results/auditResults.json + - store_artifacts: + path: ./audit/results + prefix: audit + + vulnerability-check-onboard-central-ledger: + executor: default-docker + steps: + - checkout + - restore_cache: + key: dependency-cache-v1-{{ checksum "src/package-lock.json" }} + paths: + - src/node_modules + - src/lib/log/node_modules + - src/lib/validate/node_modules + - run: + name: Install general dependencies + command: *defaults_Dependencies + - run: + name: Update NPM install (using `npm ci`) + command: cd init/onboard-central-ledger && npm ci + - run: + name: Create dir for test results + command: mkdir -p ./audit/results + - run: + name: Check for new npm vulnerabilities + command: cd src && npm run audit:check --silent -- --json > ../audit/results/auditResults.json + - store_artifacts: + path: ./audit/results + prefix: audit + audit-licenses: executor: default-docker steps: @@ -444,6 +496,156 @@ jobs: - store_artifacts: path: anchore-reports + image-scan-onboard-hub-accounts: + executor: anchore/anchore_engine + steps: + - setup_remote_docker + - checkout + - run: + name: Install AWS CLI dependencies + command: *defaults_awsCliDependencies + - attach_workspace: + at: /tmp + - run: + name: Load the pre-built docker image from workspace + command: docker load -i /tmp/docker-onboard-hub-accounts.tar + - anchore/analyze_local_image: + dockerfile_path: ./Dockerfile + image_name: mojaloop/onboard-hub-accounts:local + # Anchore bug: if policy_failure is `true`, reports don't get written - we manually check for failures below + policy_failure: false + timeout: '500' + - run: + name: Evaluate Failures. + command: | + if [[ ! $(which jq) ]]; then + (set +o pipefail; apk add jq || apt-get install -y jq || yum install -y jq) + fi + if [[ $(ls anchore-reports/*content-os*.json 2> /dev/null) ]]; then + printf "\n%s\n" "The following OS packages are installed:" + jq '[.content | sort_by(.package) | .[] | {package: .package, version: .version}]' anchore-reports/*content-os*.json + fi + if [[ $(ls anchore-reports/*vuln*.json 2> /dev/null) ]]; then + printf "\n%s\n" "The following vulnerabilities were found:" + jq '[.vulnerabilities | group_by(.package) | .[] | {package: .[0].package, vuln: [.[].vuln]}]' anchore-reports/*vuln*.json + fi + # - run: + # name: Upload Anchore reports to s3 + # command: | + # aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/${CIRCLE_PROJECT_REPONAME}/ --recursive + # aws s3 rm ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive --exclude "*" --include "${CIRCLE_PROJECT_REPONAME}*" + # aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive + + # TODO: Enable this when we want to increase the strictness of our security policies + # failCount=$(cat anchore-reports/*policy*.json | grep 'fail' | wc -l) + # echo "FailCount is: ${failCount}" + # if [ $failCount -gt 0 ]; then + # printf "Failed with a policy failure count of: ${failCount}" + # exit 1 + # fi + - store_artifacts: + path: anchore-reports + + image-scan-onboard-central-ledger: + executor: anchore/anchore_engine + steps: + - setup_remote_docker + - checkout + - run: + name: Install AWS CLI dependencies + command: *defaults_awsCliDependencies + - attach_workspace: + at: /tmp + - run: + name: Load the pre-built docker image from workspace + command: docker load -i /tmp/docker-onboard-central-ledger.tar + - anchore/analyze_local_image: + dockerfile_path: ./Dockerfile + image_name: mojaloop/onboard-central-ledger:local + # Anchore bug: if policy_failure is `true`, reports don't get written - we manually check for failures below + policy_failure: false + timeout: '500' + - run: + name: Evaluate Failures. + command: | + if [[ ! $(which jq) ]]; then + (set +o pipefail; apk add jq || apt-get install -y jq || yum install -y jq) + fi + if [[ $(ls anchore-reports/*content-os*.json 2> /dev/null) ]]; then + printf "\n%s\n" "The following OS packages are installed:" + jq '[.content | sort_by(.package) | .[] | {package: .package, version: .version}]' anchore-reports/*content-os*.json + fi + if [[ $(ls anchore-reports/*vuln*.json 2> /dev/null) ]]; then + printf "\n%s\n" "The following vulnerabilities were found:" + jq '[.vulnerabilities | group_by(.package) | .[] | {package: .[0].package, vuln: [.[].vuln]}]' anchore-reports/*vuln*.json + fi + # - run: + # name: Upload Anchore reports to s3 + # command: | + # aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/${CIRCLE_PROJECT_REPONAME}/ --recursive + # aws s3 rm ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive --exclude "*" --include "${CIRCLE_PROJECT_REPONAME}*" + # aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive + + # TODO: Enable this when we want to increase the strictness of our security policies + # failCount=$(cat anchore-reports/*policy*.json | grep 'fail' | wc -l) + # echo "FailCount is: ${failCount}" + # if [ $failCount -gt 0 ]; then + # printf "Failed with a policy failure count of: ${failCount}" + # exit 1 + # fi + - store_artifacts: + path: anchore-reports + + image-scan-onboard-msisdn-oracle: + executor: anchore/anchore_engine + steps: + - setup_remote_docker + - checkout + - run: + name: Install AWS CLI dependencies + command: *defaults_awsCliDependencies + - attach_workspace: + at: /tmp + - run: + name: Load the pre-built docker image from workspace + command: docker load -i /tmp/docker-onboard-msisdn-oracle.tar + - anchore/analyze_local_image: + dockerfile_path: ./Dockerfile + image_name: mojaloop/onboard-msisdn-oracle:local + # Anchore bug: if policy_failure is `true`, reports don't get written - we manually check for failures below + policy_failure: false + timeout: '500' + - run: + name: Evaluate Failures. + command: | + if [[ ! $(which jq) ]]; then + (set +o pipefail; apk add jq || apt-get install -y jq || yum install -y jq) + fi + if [[ $(ls anchore-reports/*content-os*.json 2> /dev/null) ]]; then + printf "\n%s\n" "The following OS packages are installed:" + jq '[.content | sort_by(.package) | .[] | {package: .package, version: .version}]' anchore-reports/*content-os*.json + fi + if [[ $(ls anchore-reports/*vuln*.json 2> /dev/null) ]]; then + printf "\n%s\n" "The following vulnerabilities were found:" + jq '[.vulnerabilities | group_by(.package) | .[] | {package: .[0].package, vuln: [.[].vuln]}]' anchore-reports/*vuln*.json + fi + # - run: + # name: Upload Anchore reports to s3 + # command: | + # aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/${CIRCLE_PROJECT_REPONAME}/ --recursive + # aws s3 rm ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive --exclude "*" --include "${CIRCLE_PROJECT_REPONAME}*" + # aws s3 cp anchore-reports ${AWS_S3_DIR_ANCHORE_REPORTS}/latest/ --recursive + + # TODO: Enable this when we want to increase the strictness of our security policies + # failCount=$(cat anchore-reports/*policy*.json | grep 'fail' | wc -l) + # echo "FailCount is: ${failCount}" + # if [ $failCount -gt 0 ]; then + # printf "Failed with a policy failure count of: ${failCount}" + # exit 1 + # fi + - store_artifacts: + path: anchore-reports + publish: executor: default-machine steps: @@ -633,6 +835,26 @@ workflows: - /feature*/ - /bugfix*/ - /hotfix*/ + - vulnerability-check-onboard-hub-accounts: + context: org-global + requires: + - setup + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ + - vulnerability-check-onboard-central-ledger: + context: org-global + requires: + - setup + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ - audit-licenses: context: org-global requires: @@ -703,6 +925,36 @@ workflows: - /feature*/ - /bugfix*/ - /hotfix*/ + - image-scan-onboard-hub-accounts: + context: org-global + requires: + - build-local-onboard-hub-accounts + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ + - image-scan-onboard-central-ledger: + context: org-global + requires: + - build-local-onboard-central-ledger + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ + - image-scan-onboard-msisdn-oracle: + context: org-global + requires: + - build-local-onboard-msisdn-oracle + filters: + branches: + ignore: + - /feature*/ + - /bugfix*/ + - /hotfix*/ - build: context: org-global requires: From a6724d4a6ff1f65be2e5402495388cf74d5a8a7b Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Fri, 14 Aug 2020 14:17:58 +0100 Subject: [PATCH 19/30] The chart in this repo is now redundant. Removing in favour of https://github.com/mojaloop/helm/tree/master/mojaloop-simulator. (#73) --- helm/.gitignore | 3 - helm/.helmignore | 25 -- helm/Chart.yaml | 5 - helm/templates/_helpers.tpl | 32 -- helm/templates/config-jws-public-keys.yaml | 26 -- helm/templates/config-rules.yaml | 15 - helm/templates/deployment.yaml | 259 ------------ helm/templates/horizontalpodautoscaler.yaml | 21 - helm/templates/ingress.yaml | 40 -- helm/templates/secret.yaml | 22 - helm/templates/service.yaml | 77 ---- helm/values.yaml | 429 -------------------- 12 files changed, 954 deletions(-) delete mode 100644 helm/.gitignore delete mode 100644 helm/.helmignore delete mode 100644 helm/Chart.yaml delete mode 100644 helm/templates/_helpers.tpl delete mode 100644 helm/templates/config-jws-public-keys.yaml delete mode 100644 helm/templates/config-rules.yaml delete mode 100644 helm/templates/deployment.yaml delete mode 100644 helm/templates/horizontalpodautoscaler.yaml delete mode 100644 helm/templates/ingress.yaml delete mode 100644 helm/templates/secret.yaml delete mode 100644 helm/templates/service.yaml delete mode 100644 helm/values.yaml diff --git a/helm/.gitignore b/helm/.gitignore deleted file mode 100644 index 9cc46ef1..00000000 --- a/helm/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# This way you can maintain a values-test.yaml in this repo for testing your changes to the chart, -# without accidentally including it in a packaged chart. -values-test.yaml diff --git a/helm/.helmignore b/helm/.helmignore deleted file mode 100644 index b7ece505..00000000 --- a/helm/.helmignore +++ /dev/null @@ -1,25 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*~ -# Various IDEs -.project -.idea/ -*.tmproj - -# This way you can maintain a values-test.yaml in this repo for testing your changes to the chart, -# without accidentally including it in a packaged chart. -values-test.yaml diff --git a/helm/Chart.yaml b/helm/Chart.yaml deleted file mode 100644 index 204a1729..00000000 --- a/helm/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: Helm Chart for the Mojaloop (SDK based) Simulator -name: mojaloop-simulator -version: 2.0.0 diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl deleted file mode 100644 index 090eca39..00000000 --- a/helm/templates/_helpers.tpl +++ /dev/null @@ -1,32 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "mojaloop-simulator.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "mojaloop-simulator.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "mojaloop-simulator.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} diff --git a/helm/templates/config-jws-public-keys.yaml b/helm/templates/config-jws-public-keys.yaml deleted file mode 100644 index 4284d1c4..00000000 --- a/helm/templates/config-jws-public-keys.yaml +++ /dev/null @@ -1,26 +0,0 @@ -{{- if .Values.simulators }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: sim-jws-public-keys - labels: - app: sim - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -data: - {{- range $name, $customConfig := .Values.simulators }} - {{- $config := merge $customConfig $.Values.defaults }} - {{- if and (eq ($config.config.schemeAdapter.env.VALIDATE_INBOUND_JWS | upper) "TRUE") (not $config.config.schemeAdapter.secrets.jws.pubKeyConfigMapName) }} - {{- if eq $config.config.schemeAdapter.secrets.jws.publicKey "" }} - {{- fail (printf "INBOUND_JWS enabled and jws public key not specified for '%s'. You need to specify %s.schemeAdapter.secrets.jws.publicKey or %s.schemeAdapter.secrets.jws.pubKeyConfigMapName." $name $name $name) }} - {{- end }} - {{ $name }}.pem: |- -{{ $config.config.schemeAdapter.secrets.jws.publicKey | indent 4 }} - {{- end }} - {{- end }} - {{- range $name, $key := .Values.sharedJWSPubKeys }} - {{ $name }}.pem: |- -{{ $key | indent 4 }} - {{- end }} -{{- end }} diff --git a/helm/templates/config-rules.yaml b/helm/templates/config-rules.yaml deleted file mode 100644 index 332504b6..00000000 --- a/helm/templates/config-rules.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- range $name, $customConfig := .Values.simulators }} -{{- $config := merge $customConfig $.Values.defaults }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: sim-{{ $name }}-rules - labels: - app: sim-{{ $name }} - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -data: - rules.json: {{ $config.config.backend.rules | quote }} ---- -{{- end }} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml deleted file mode 100644 index 77f8131d..00000000 --- a/helm/templates/deployment.yaml +++ /dev/null @@ -1,259 +0,0 @@ -{{- range $name, $customConfig := .Values.simulators }} -{{- $config := merge $customConfig $.Values.defaults }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sim-{{ $name }}-scheme-adapter - labels: - app: sim-{{ $name }}-scheme-adapter - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -spec: - replicas: {{ $config.replicaCount }} - selector: - matchLabels: - app: sim-{{ $name }}-scheme-adapter - release: {{ $.Release.Name }} - template: - metadata: - labels: - app: sim-{{ $name }}-scheme-adapter - release: {{ $.Release.Name }} - spec: - volumes: - {{- if eq ($config.config.schemeAdapter.env.JWS_SIGN | upper) "TRUE" }} - - name: jws-private-key - secret: - {{- if $config.config.schemeAdapter.secrets.jws.privKeySecretName }} - secretName: {{ $config.config.schemeAdapter.secrets.jws.privKeySecretName }} - {{- else }} - secretName: sim-{{ $name }}-jws-priv-key - {{- end }} - {{- end }} - - name: jws-public-keys - configMap: - {{- if $config.config.schemeAdapter.secrets.jws.publicKeyConfigMapName }} - name: {{ $config.config.schemeAdapter.secrets.jws.publicKeyConfigMapName }} - {{- else }} - name: sim-jws-public-keys - {{- end }} - {{- if $config.config.schemeAdapter.secrets.sim_tls_secrets_name }} - - name: tls-secrets - secret: - secretName: {{ $config.config.schemeAdapter.secrets.sim_tls_secrets_name }} - {{- end }} - {{- if $config.config.schemeAdapter.initContainers }} - initContainers: -{{ $config.config.schemeAdapter.initContainers | toYaml | indent 6 }} - {{- end }} - containers: - - name: scheme-adapter - image: "{{ $config.config.schemeAdapter.image.repository }}:{{ $config.config.schemeAdapter.image.tag }}" - imagePullPolicy: {{ $config.config.schemeAdapter.image.pullPolicy }} - ports: - - name: inboundapi - containerPort: 4000 - protocol: TCP - - name: outboundapi - containerPort: 4001 - protocol: TCP - {{- if $config.config.schemeAdapter.readinessProbe.enabled }} - readinessProbe: - httpGet: - path: / - port: 4001 - scheme: HTTP -{{ $config.config.backend.readinessProbe | toYaml | indent 10 -}} - {{- end }} - {{- if $config.config.schemeAdapter.livenessProbe.enabled }} - livenessProbe: - httpGet: - path: / - port: 4001 - scheme: HTTP -{{ $config.config.backend.livenessProbe | toYaml | indent 10 -}} - {{- end }} - volumeMounts: - - name: jws-public-keys - mountPath: {{ $config.config.schemeAdapter.env.JWS_VERIFICATION_KEYS_DIRECTORY }} - {{- if eq ($config.config.schemeAdapter.env.JWS_SIGN | upper) "TRUE" }} - - name: jws-private-key - mountPath: "/jwsSigningKey/" - {{- end }} - {{- if $config.config.schemeAdapter.secrets.sim_tls_secrets_name }} - - name: tls-secrets - mountPath: "/secrets/" - {{- end }} - env: - - name: CACHE_HOST - value: {{ printf "sim-%s-cache" $name | quote }} - - name: BACKEND_ENDPOINT - value: {{ printf "sim-%s-backend:3000" $name }} - - name: DFSP_ID - value: {{ $name | quote }} - {{- range $k, $v := $config.config.schemeAdapter.env }} - - name: {{ $k }} - value: {{ $v | quote }} - {{- end }} - resources: -{{ toYaml $config.config.schemeAdapter.resources | indent 10 }} - imagePullSecrets: - - name: {{ $config.config.imagePullSecretName }} - {{- with $config.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with $config.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with $config.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sim-{{ $name }}-backend - labels: - app: sim-{{ $name }}-backend - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -spec: - replicas: {{ $config.replicaCount }} - selector: - matchLabels: - app: sim-{{ $name }}-backend - release: {{ $.Release.Name }} - template: - metadata: - labels: - app: sim-{{ $name }}-backend - release: {{ $.Release.Name }} - spec: - {{- if $config.config.backend.initContainers }} - initContainers: -{{ $config.config.backend.initContainers | toYaml | indent 6 }} - {{- end }} - containers: - - name: backend - image: "{{ $config.config.backend.image.repository }}:{{ $config.config.backend.image.tag }}" - imagePullPolicy: {{ $config.config.backend.image.pullPolicy }} - ports: - - name: simapi - containerPort: 3000 - protocol: TCP - - name: reportapi - containerPort: 3002 - protocol: TCP - - name: testapi - containerPort: 3003 - protocol: TCP - {{- if $config.config.backend.readinessProbe.enabled }} - readinessProbe: - httpGet: - path: / - port: 3000 - scheme: HTTP -{{ $config.config.backend.readinessProbe | toYaml | indent 10 -}} - {{- end }} - {{- if $config.config.backend.livenessProbe.enabled }} - livenessProbe: - httpGet: - path: / - port: 3000 - scheme: HTTP -{{ $config.config.backend.livenessProbe | toYaml | indent 10 -}} - {{- end }} - env: - - name: OUTBOUND_ENDPOINT - value: "http://sim-{{ $name }}-scheme-adapter:{{ $config.config.schemeAdapter.env.OUTBOUND_LISTEN_PORT }}" - - name: SCHEME_NAME - value: {{ $name | quote }} - - name: DFSP_ID - value: {{ $name | quote }} - {{- range $k, $v := $config.config.backend.env }} - - name: {{ $k }} - value: {{ $v | quote }} - {{- end }} - resources: -{{ toYaml $config.config.backend.resources | indent 10 }} - volumeMounts: - - name: sim-rules - mountPath: /rules/ - volumes: - - name: sim-rules - configMap: - name: sim-{{ $name }}-rules - imagePullSecrets: - - name: {{ $config.config.imagePullSecretName }} - {{- with $config.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with $config.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with $config.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} ---- -{{- if $config.config.cache.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sim-{{ $name }}-cache - labels: - app: sim-{{ $name }}-cache - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -spec: - replicas: {{ $config.replicaCount }} - selector: - matchLabels: - app: sim-{{ $name }}-cache - release: {{ $.Release.Name }} - template: - metadata: - labels: - app: sim-{{ $name }}-cache - release: {{ $.Release.Name }} - spec: - containers: - - name: cache - image: "{{ $config.config.cache.image.repository }}:{{ $config.config.cache.image.tag }}" - imagePullPolicy: {{ $config.config.cache.image.pullPolicy }} - ports: - - name: redis - containerPort: 6379 - protocol: TCP - {{- if $config.config.cache.livenessProbe.enabled }} - livenessProbe: -{{ $config.config.backend.livenessProbe | toYaml | indent 10 -}} - exec: - command: - - sh - - -c - - redis-cli ping {{ $config.config.cache.livenessProbe.timeoutSeconds }} - {{- end }} - {{- if $config.config.cache.readinessProbe.enabled}} - readinessProbe: -{{ $config.config.backend.readinessProbe | toYaml | indent 10 -}} - exec: - command: - - sh - - -c - - redis-cli ping {{ $config.config.cache.readinessProbe.timeoutSeconds }} - {{- end }} - resources: -{{ toYaml $config.config.cache.resources | indent 12 }} ---- -{{- end }} -{{ end }} diff --git a/helm/templates/horizontalpodautoscaler.yaml b/helm/templates/horizontalpodautoscaler.yaml deleted file mode 100644 index 53dc3272..00000000 --- a/helm/templates/horizontalpodautoscaler.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- range $name, $customConfig := .Values.simulators }} -{{- $config := merge $customConfig $.Values.defaults }} -{{- if $config.config.schemeAdapter.scale.enabled }} -apiVersion: autoscaling/v2beta2 -kind: HorizontalPodAutoscaler -metadata: - name: sim-{{ $name }}-scheme-adapter - labels: - app: sim-{{ $name }}-scheme-adapter - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: sim-{{ $name }}-scheme-adapter -{{ $config.config.schemeAdapter.scale.spec | toYaml | indent 2 }} ---- -{{- end }} -{{ end }} diff --git a/helm/templates/ingress.yaml b/helm/templates/ingress.yaml deleted file mode 100644 index d20a8dc5..00000000 --- a/helm/templates/ingress.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{ if .Values.simulators }} -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: simulators - labels: - app: simulators - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -{{- with .Values.ingress.annotations }} - annotations: -{{ toYaml . | indent 4 }} -{{- end }} -spec: - rules: - {{- range $name, $customConfig := .Values.simulators }} - {{- $config := merge $customConfig $.Values.defaults }} - {{- if $config.ingress.enabled -}} - {{- range $host := $config.ingress.hosts }} - - host: {{ $host }} - http: - paths: - - path: /sim/{{ $name }}/outbound{{ if $.Values.ingress.modernIngressController }}(.*){{ end }} - backend: - serviceName: sim-{{ $name }}-scheme-adapter - servicePort: outboundapi - - path: /sim/{{ $name }}/inbound{{ if $.Values.ingress.modernIngressController }}(.*){{ end }} - backend: - serviceName: sim-{{ $name }}-scheme-adapter - servicePort: inboundapi - - path: /sim/{{ $name }}/test{{ if $.Values.ingress.modernIngressController }}(.*){{ end }} - backend: - serviceName: sim-{{ $name }}-backend - servicePort: testapi - {{- end }} - {{- end }} - {{- end }} ---- -{{ end }} diff --git a/helm/templates/secret.yaml b/helm/templates/secret.yaml deleted file mode 100644 index 16ddaea6..00000000 --- a/helm/templates/secret.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- range $name, $customConfig := .Values.simulators }} -{{- $config := merge $customConfig $.Values.defaults }} -{{- if eq ($config.config.schemeAdapter.env.JWS_SIGN | upper) "TRUE" }} -apiVersion: v1 -kind: Secret -metadata: - name: sim-{{ $name }}-jws-priv-key - labels: - app: sim-{{ $name }} - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -data: - # Note that due to a bug with helm 2.91 the `required` function in combination with a missing key - # will not work in place of this if statement. - {{- if eq $config.config.schemeAdapter.secrets.jws.privateKey "" }} - {{ fail (printf "JWS_SIGN enabled- JWS private key required for %s. You need to specify %s.schemeAdapter.secrets.jws.privateKey." $name $name) }} - {{- end }} - "private.key": {{ $config.config.schemeAdapter.secrets.jws.privateKey | b64enc }} ---- -{{- end }} -{{- end }} diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml deleted file mode 100644 index 1c096929..00000000 --- a/helm/templates/service.yaml +++ /dev/null @@ -1,77 +0,0 @@ -{{- range $name, $customConfig := .Values.simulators }} -{{- $config := merge $customConfig $.Values.defaults }} -apiVersion: v1 -kind: Service -metadata: - name: sim-{{ $name }}-backend - labels: - app: sim-{{ $name }}-backend - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -spec: - type: ClusterIP - ports: - - port: 3000 - protocol: TCP - name: simapi - targetPort: simapi - - port: 3002 - protocol: TCP - name: reportapi - targetPort: reportapi - - port: 3003 - protocol: TCP - name: testapi - targetPort: testapi - selector: - app: sim-{{ $name }}-backend - release: {{ $.Release.Name }} ---- -apiVersion: v1 -kind: Service -metadata: - name: sim-{{ $name }}-scheme-adapter - labels: - app: sim-{{ $name }}-scheme-adapter - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -spec: - type: ClusterIP - ports: - - port: 4000 - protocol: TCP - name: inboundapi - targetPort: inboundapi - - port: 4001 - protocol: TCP - name: outboundapi - targetPort: outboundapi - selector: - app: sim-{{ $name }}-scheme-adapter - release: {{ $.Release.Name }} ---- -{{- if $config.config.cache.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: sim-{{ $name }}-cache - labels: - app: sim-{{ $name }}-cache - chart: {{ template "mojaloop-simulator.chart" $ }} - release: {{ $.Release.Name }} - heritage: {{ $.Release.Service }} -spec: - type: ClusterIP - ports: - - port: 6379 - protocol: TCP - name: redis - targetPort: redis - selector: - app: sim-{{ $name }}-cache - release: {{ $.Release.Name }} -{{- end }} ---- -{{ end }} diff --git a/helm/values.yaml b/helm/values.yaml deleted file mode 100644 index 64a0cc22..00000000 --- a/helm/values.yaml +++ /dev/null @@ -1,429 +0,0 @@ -# Default values for mojaloop-simulator. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -# Usage: -# Add simulators to the simulators object. The following example will create two simulators, -# 'payerfsp' and 'payeefsp' that will be created with the default values available lower in this -# file. -# -# simulators: -# payerfsp: {} -# payeefsp: {} -# -# The default values can be overridden for all sims by modifying mojaloop-simulator.defaults in -# your parent chart. They can also be overriden per-simulator. The following example will result in -# a payerfsp without a cache and a payeefsp with a cache. -# -# simulators: -# payerfsp: -# config: -# cache: -# enabled: false -# payeefsp: {} - -# TODO & notes: -# * do the port _numbers_ matter at all? Can we get rid of them? -# * for Mowali, how are JWS and TLS secrets being set up? -# * support arbitrary init containers + config (that might just be config that goes into defaults -# or something?). Supply all config and volumes to the init containers. -# * create some test containers -# * parametrise imagePullSecretName (global? like https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters) -# * generate JWS private/public keys, so the user does not need to supply keys at all. -# * generate public key from private, so the user only needs to supply private keys for each sim? -# (_might_ be possible with a job or init container or similar). -# * support mTLS auto-cert generation -# * probably eliminate all config that shouldn't actually be changed by a user, e.g. -# JWS_VERIFICATION_KEYS_DIRECTORY. That's a good configuration option to have for other contexts, -# such as running the sim locally or in docker-compose but in this context it's _an -# implementation detail_. The chart user should not have to worry about it, and we should not -# have to test the effect of changing it. -# Also -# INBOUND_LISTEN_PORT -# OUTBOUND_LISTEN_PORT -# * make ingress more generic- do not preconfigure annotations -# * think about labels a little more carefully- the app should probably always be "mojaloop-simulator" -# * add config map and hashes to the deployments so that a configmap change triggers a rolling -# update -# * support JWS public keys for other entities. Add a note in the documentation that they must map -# directly to the value that will be received in the FSPIOP-Source (check this is correct) -# * update labels to be compliant. E.g. app.kubernetes.io/name or whatever -# * rename ".Values.defaults.config" as it's pretty a useless name -# * support arbitrary sidecars? -# * use the redis subchart? https://github.com/bitnami/charts/tree/master/bitnami/redis -# - this would mean a single instance of redis (probably good) -# - might need to have the simulators use separate databases per simulator, or prefix all of -# their keys with their own name, or something -# * allow the user to optionally specify the namespace, with the caveat that that namespace will -# need to be created manually before the release is deployed. There may be a horrible hack (which -# I have not tried) whereby all templates are moved to a different directory, say ./xtemplates, -# then all are imported using {{ .Files.Glob }} and {{ .Files.Get }} then templated into a single -# amazing template with {{ template }}. At the top of this template goes a namespace. The -# consequence of this is that the namespace is created first, enabling this beautiful pattern. -# Remember, with great power comes great responsibility. (In other words, we probably have a -# responsibility to _not_ do this). -# * should redis be a statefulset? optionally? what does the bitnami chart do? -# * move labels into helpers -# * autogenerate ILP stuff? -# * defaults.resources looks like it's used nowhere- check this and remove it as appropriate -# * look for references to replicaCount in the charts/values. Is it set, or whatever? -# * scale Redis -# * changing JWS_SIGNING_KEY_PATH currently breaks the chart because it's nastily hard-coded. It -# should be possible to use the Spring filepath functions to avoid this. Similarly, changing -# RULES_FILE will have a similar effect. Alternatively, make these unconfigured by default. I.e. -# comment them out, hard-code them and add a warning to the user in the config. (Is there a -# scenario where the user should want to configure them? I don't think so..). -# (https://masterminds.github.io/sprig/paths.html) -# * put sim inbound API on port 80 -# * supply more documentation, especially a range of examples, and preferably documentation that is -# executable -# * share configmaps, secrets with init containers -# * share an emptyDir volume between init containers and main containers -# * allow init containers to create secrets and put them on persistent volumes, or emptyDirs, then -# allow main containers to access those -# * do not put environment variables in configmaps, instead put them straight into the deployments. -# This makes the deployment much easier to manage. -# * Remember, labels are _for_ identifying stuff. So labels should probably be like "release" -# (.Release.Name or similar) "chart" (.Chart.Name or similar) "simulator" (e.g. payerfsp, -# payeefsp) "sim-component" (e.g. backend, scheme-adapter, cache) -# * can _probably_ remove port numbers from services to simplify chart (although perhaps not? try -# to port-forward with a named port instead of a numbered port?) - - -simulators: - # Every key added to this `simulators` object will be a simulator that takes on the default - # config below. The default is deliberately left empty so nothing is deployed by default. - # payerfsp: {} - # payeefsp: {} - -defaultProbes: &defaultProbes - livenessProbe: - enabled: true - initialDelaySeconds: 3 - periodSeconds: 30 - timeoutSeconds: 10 - successThreshold: 1 - failureThreshold: 3 - readinessProbe: - enabled: true - initialDelaySeconds: 3 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 3 - -ingress: - annotations: {} - # Set this to true if you're using nginx ingress controller >= v0.22.0. - # This affects the way your rewrite target will work. - # For more information see "Breaking changes" here: - # https://github.com/kubernetes/ingress-nginx/blob/master/Changelog.md#0220 - modernIngressController: true - -# If you enable JWS validation and intend to communicate via a switch you will almost certainly -# want to put your switch JWS public key in this array. The name of the property in this object -# will correspond directly to the name of the signing key (e.g., in the example below, -# `switch.pem`). Do not include the `.pem` extension, this will be added for you. The scheme -# adapter will use the FSPIOP-Source header content to identify the relevant signing key to use. -# The below example assumes your switch will use `FSPIOP-Source: switch`. If instead, for example, -# your switch is using `FSPIOP-Source: peter` you will need a property `peter` in the following -# object. Do not add the public keys of your simulators to this object. Instead, put them in -# `mojaloop-simulator.simulators.$yourSimName.config.schemeAdapter.secrets.jws.publicKey`. -sharedJWSPubKeys: - # switch: |- - # -----BEGIN PUBLIC KEY----- - # blah blah blah - # -----END PUBLIC KEY----- - -defaults: &defaults - # Changes to this object in the parent chart, for example 'mojaloop-simulator.defaults' will be - # applied to all simulators deployed by this child chart. - config: - imagePullSecretName: dock-casa-secret - - cache: - enabled: true - image: - repository: redis - tag: 5.0.4-alpine - pullPolicy: Always - <<: *defaultProbes - - schemeAdapter: - secrets: - jws: - # Use the privKeySecretName field if you would like to supply a JWS private key external - # to this chart. - # For example, if you create a private key called `sim-payerfsp-jws-signing-key` external - # to this chart, you would supply `privKeySecretName: sim-payerfsp-jws-signing-key` here. - # These fields will take precedence over `privateKey` and `publicKey` below. - # This field is best supplied per-simulator, however it's here for documentation - # purposes. - privKeySecretName: {} - # TODO: update `privKeySecretName` above to contain both a name and a key in the secret. - # Add documentation on usage. - # privKeySecret: {} - # name: - # key: - # - # The `pubKeyConfigMapName` field allows you to supply a ConfigMap containing JWS public - # keys external to this release, and have this release reference that ConfigMap to - # populate JWS public keys. The format of this ConfigMap must be as described for - # `sharedJWSPubKeys`, a map with one key per FSP/simulator corresponding to the - # FSPIOP-Source header that will be supplied by that FSP/simulator. - pubKeyConfigMapName: {} - # Supply per-simulator private and public keys here: - privateKey: '' - publicKey: '' - image: - repository: mojaloop/sdk-scheme-adapter - tag: v8.6.1 - pullPolicy: Always - <<: *defaultProbes - - # These will be supplied directly to the init containers array in the deployment for the - # scheme adapter. They should look exactly as you'd declare them inside the deployment. - # Example: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/#init-containers-in-use - initContainers: {} - - scale: - enabled: false - spec: - minReplicas: 1 - maxReplicas: 10 - metrics: - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: 80 - - env: - # This option is presented for consistency with the .env file. However, for the purposes of this chart, this port is _not_ configurable. - INBOUND_LISTEN_PORT: "4000" - - # This option is presented for consistency with the .env file. However, for the purposes of this chart, this port is _not_ configurable. - OUTBOUND_LISTEN_PORT: "4001" - - # Enable mutual TLS authentication. Useful when not running in a secure - # environment, i.e. when you're running it locally against your own implementation. - MUTUAL_TLS_ENABLED: "false" - - # Enable JWS verification and signing - VALIDATE_INBOUND_JWS: "false" - JWS_SIGN: "false" - - # applicable only if VALIDATE_INBOUND_JWS is "true" - # allows disabling of validation on incoming PUT /parties/{idType}/{idValue} requests - VALIDATE_INBOUND_PUT_PARTIES_JWS: "true" - - # applicable only if JWS_SIGN is "true" - # allows disabling of signing on outgoing PUT /parties/{idType}/{idValue} requests - JWS_SIGN_PUT_PARTIES: "true" - - # Path to JWS signing key (private key of THIS DFSP) - JWS_SIGNING_KEY_PATH: "/jwsSigningKey/private.key" # TODO: do not configure- will break the chart - JWS_VERIFICATION_KEYS_DIRECTORY: "/jwsVerificationKeys" - - # Location of certs and key required for TLS - IN_CA_CERT_PATH: "./secrets/cacert.pem" - IN_SERVER_CERT_PATH: "./secrets/servercert.pem" - IN_SERVER_KEY_PATH: "./secrets/serverkey.pem" - - OUT_CA_CERT_PATH: "./secrets/cacert.pem" - OUT_CLIENT_CERT_PATH: "./secrets/servercert.pem" - OUT_CLIENT_KEY_PATH: "./secrets/serverkey.pem" - - # The number of space characters by which to indent pretty-printed logs. If set to zero, log events - # will each be printed on a single line. - LOG_INDENT: "0" - - # REDIS CACHE CONNECTION - # CACHE_HOST: "" # Default is parametrised, but it's possible to override this - CACHE_PORT: "6379" - - # Switch or DFSP system under test Mojaloop API endpoint - # The option 'PEER_ENDPOINT' has no effect if the remaining three options 'ALS_ENDPOINT', 'QUOTES_ENDPOINT', 'TRANSFERS_ENDPOINT' are specified. - # Do not include the protocol, i.e. http. - PEER_ENDPOINT: "mojaloop-switch" - # ALS_ENDPOINT="mojaloop-switch-als" - # QUOTES_ENDPOINT="mojaloop-switch-quotes" - # TRANSFERS_ENDPOINT="mojaloop-switch-transfers" - - # This value specifies the endpoint the scheme adapter expects to communicate with the - # backend on. Do not include the protocol, i.e. http. - # You're very likely to break the functioning of this chart if you configure the following - # value. - # BACKEND_ENDPOINT: "localhost:3000" - - # FSPID of this DFSP - # Commented by default- you're likely to break the chart if you configure this value. - # DFSP_ID: "mojaloop-sdk" - - # Secret used for generation and verification of secure ILP - ILP_SECRET: "Quaixohyaesahju3thivuiChai5cahng" - - # expiry period in seconds for quote and transfers issued by the SDK - EXPIRY_SECONDS: "60" - - # if set to false the SDK will not automatically accept all returned quotes - # but will halt the transfer after a quote response is received. A further - # confirmation call will be required to complete the final transfer stage. - AUTO_ACCEPT_QUOTES: "false" - - # if set to false the SDK will not automatically accept a resolved party - # but will halt the transer after a party lookup response is received. A further - # confirmation call will be required to progress the transfer to quotes state. - AUTO_ACCEPT_PARTY: "false" - - # when set to true, when sending money via the outbound API, the SDK will use the value - # of FSPIOP-Source header from the received quote response as the payeeFsp value in the - # transfer prepare request body instead of the value received in the payee party lookup. - # This behaviour should be enabled when the SDK user DFSP is in a forex enabled switch - # ecosystem and expects quotes and transfers to be rerouted by the switch to forex - # entities i.e. forex providing DFSPs. Please see the SDK documentation and switch - # operator documentation for more information on forex use cases. - USE_QUOTE_SOURCE_FSP_AS_TRANSFER_PAYEE_FSP: "false" - - # set to true to validate ILP, otherwise false to ignore ILP - CHECK_ILP: "true" - - # set to true to enable test features such as request cacheing and retrieval endpoints - ENABLE_TEST_FEATURES: "true" - - # set to true to mock WSO2 oauth2 token endpoint - ENABLE_OAUTH_TOKEN_ENDPOINT: "false" - OAUTH_TOKEN_ENDPOINT_CLIENT_KEY: "test-client-key" - OAUTH_TOKEN_ENDPOINT_CLIENT_SECRET: "test-client-secret" - OAUTH_TOKEN_ENDPOINT_LISTEN_PORT: "6000" - - # WS02 Bearer Token specific to golden-fsp instance and environment - WS02_BEARER_TOKEN: "7718fa9b-be13-3fe7-87f0-a12cf1628168" - - # OAuth2 data used to obtain WSO2 bearer token - OAUTH_TOKEN_ENDPOINT: "" - OAUTH_CLIENT_KEY: "" - OAUTH_CLIENT_SECRET: "" - OAUTH_REFRESH_SECONDS: "3600" - - # Set to true to respect expirity timestamps - REJECT_EXPIRED_QUOTE_RESPONSES: "false" - REJECT_TRANSFERS_ON_EXPIRED_QUOTES: "false" - REJECT_EXPIRED_TRANSFER_FULFILS: "false" - - # Timeout for GET/POST/DELETE - PUT flow processing - REQUEST_PROCESSING_TIMEOUT_SECONDS: "30" - - # To allow transfer without a previous quote request, set this value to true. - # The incoming transfer request should consist of an ILP packet and a matching condition in this case. - # The fulfilment will be generated from the provided ILP packet, and must hash to the provided condition. - ALLOW_TRANSFER_WITHOUT_QUOTE: "false" - - INBOUND_MUTUAL_TLS_ENABLED: "false" - OUTBOUND_MUTUAL_TLS_ENABLED: "false" - - backend: - image: - repository: mojaloop/mojaloop-simulator - tag: v8.6.0-snapshot - pullPolicy: Always - <<: *defaultProbes - - # These will be supplied directly to the init containers array in the deployment for the - # backend. They should look exactly as you'd declare them inside the deployment. - # Example: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/#init-containers-in-use - initContainers: {} - - # Supply JSON rules here as a string - # Example: - # rules: |- - # [ - # { - # "ruleId": 1, - # .. etc. - # } - # ] - rules: |- - [] - - env: - ##### Section for simulator backend container ##### - # This is the endpoint the backend expects to communicate with the scheme adapter on. - # Include the protocol, i.e. http. - # It's not configured by default in this chart as the default value is calculated in a - # template and configuring it is likely to break communication between the backend and the - # scheme adapter. - # OUTBOUND_ENDPOINT: "http://localhost:4001" # within the pod - - # Enable mutual TLS authentication. Useful when the simulator is not running in a managed - # environment, i.e. when you're running it locally against your own implementation. - MUTUAL_TLS_ENABLED: "false" - - # Enable server-only TLS; i.e. serve on HTTPS instead of HTTP. - HTTPS_ENABLED: "false" - - # Location of certs and key required for TLS - CA_CERT_PATH: ./secrets/cacert.pem - SERVER_CERT_PATH: ./secrets/servercert.pem - SERVER_KEY_PATH: ./secrets/serverkey.pem - - # The number of space characters by which to indent pretty-printed logs. If set to zero, log events - # will each be printed on a single line. - LOG_INDENT: "0" - - # The name of the sqlite log file. This probably doesn't matter much to the user, except that - # setting :memory: will use an in-memory sqlite db, which will be faster and not consume disk - # space. However, it will also mean that the logs will be lost once the container is stopped. - SQLITE_LOG_FILE: ./log.sqlite - - # The DFSPID of this simulator. The simulator will accept any requests routed to - # FSPIOP-Destination: $SCHEME_NAME. Other requests will be rejected. - # Not set in this chart as these are calculated in templates. Setting this values is likely - # to break expected functionality. - # SCHEME_NAME: golden - # DFSP_ID: golden - - # The name of the sqlite model database. If you would like to start the simulator with preloaded - # state you can use a preexisting file. If running in a container, you can mount a sqlite file as a - # volume in the container to preserve state between runs. - # Use MODEL_DATABASE: :memory: for an ephemeral in-memory database - MODEL_DATABASE: ./model.sqlite - - # The simulator can automatically add fees when generating quote responses. Use this - # variable to control the fee amounts added. e.g. for a transfer of 100 USD a FEE_MULTIPLIER of 0.1 - # reuslts in fees of USD 10 being applied to the quote response - FEE_MULTIPLIER: "0.05" - - # Specifies the location of a rules file for the simulator backend. Rules can be used to produce - # specific simulator behaviours in response to incoming requests that match certain conditions. - # e.g. a rule can be used to trigger NDC errors given transfers between certain limits. - RULES_FILE: /rules/rules.json - - ingress: - enabled: true - path: / - hosts: - - mojaloop-simulators.local - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - - resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - - nodeSelector: {} - - tolerations: [] - - affinity: {} From b30746ac40feea34ede5a490de0c7757b333c07f Mon Sep 17 00:00:00 2001 From: Kamuela Franco Date: Wed, 19 Aug 2020 16:13:32 +0100 Subject: [PATCH 20/30] Update README with init container docs (#76) * Update README with init container docs * Add values-sims.example.yaml * Remove link --- README.md | 8 ++ docs/values-sims.example.yaml | 139 ++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 docs/values-sims.example.yaml diff --git a/README.md b/README.md index e67869a4..7d900098 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,14 @@ A diagram showing the logical architecture of the simulator in a test scenario c # Use +## Deploy with Helm and init containers (optional) +Three init containers, +- [onboard-hub-accounts](https://github.com/mojaloop/mojaloop-simulator/tree/master/init/onboard-hub-accounts) +- [onboard-central-ledger](https://github.com/mojaloop/mojaloop-simulator/tree/master/init/onboard-central-ledger) +- [onboard-msisdn-oracle](https://github.com/mojaloop/mojaloop-simulator/tree/master/init/onboard-msisdn-oracle) + +are provided for optional use and may make an automated deployment via Helm chart easier than otherwise. Please see the [example](docs/values-sims.example.yaml) config. + ## Pre-requisites 1. docker 2. docker-compose diff --git a/docs/values-sims.example.yaml b/docs/values-sims.example.yaml new file mode 100644 index 00000000..8682a9da --- /dev/null +++ b/docs/values-sims.example.yaml @@ -0,0 +1,139 @@ +prefix: "" + +# As per: +# https://github.com/mojaloop/helm/blob/4afd91b4d4c976e1f8d60495c677f1ba48b30192/mojaloop-simulator/values.yaml#L130-L134 +ingress: + ingressPathRewriteRegex: / + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + +defaults: + config: + backend: + env: + FEE_MULTIPLIER: "0.00" + schemeAdapter: + image: + tag: v10.6.3 + env: + VALIDATE_INBOUND_JWS: "true" + PEER_ENDPOINT: "interop-switch.huboperator.live" + JWS_SIGN: "true" + AUTO_ACCEPT_QUOTES: "true" + AUTO_ACCEPT_PARTY: "true" + EXPIRY_SECONDS: 30 + REQUEST_PROCESSING_TIMEOUT_SECONDS: 20 + USE_QUOTE_SOURCE_FSP_AS_TRANSFER_PAYEE_FSP: "true" + REJECT_TRANSFERS_ON_EXPIRED_QUOTES: "true" + ILP_SECRET: "Use2DwOwCea6VobuFScu3IcoEviS3Oth" + ingress: + enabled: true + hosts: + - "interop-switch.huboperator.live" + +simulators: + payerfsp: + config: + backend: # These are optional keys covering + rules: [] # rules-engine configured rules + schemeAdapter: + initContainers: + - name: onboard-hub-accounts + image: &hub_account_onboard_image mojaloop/onboard-hub-accounts:v11.0.3 + env: + - name: AUTH_BEARER_TOKEN + value: "6e35ccb3-ec22-51c9-b768-d12c3d289442" + - name: HOST_CENTRAL_LEDGER + value: "http://centralledger-service.ext-svcs.svc.cluster.local" + - name: HUB_OPERATOR_NAME + value: "hub_operator" + - name: ACCOUNTS + value: '[{ "type": "HUB_MULTILATERAL_SETTLEMENT", "currency": "USD" },{ "type": "HUB_RECONCILIATION", "currency": "USD" }]' + - name: onboard-central-ledger + image: ¢ral_ledger_onboard_image mojaloop/onboard-central-ledger:v11.0.3 + env: + - name: AUTH_BEARER_TOKEN + value: "6e35ccb3-ec22-51c9-b768-d12c3d289442" + - name: DFSP_CALLBACK_URL + value: "https://dfsp.huboperator.live:9999/payerfsp" + - name: DFSP_CURRENCY + value: "USD" + - name: DFSP_NAME + value: "payerfsp" + - name: FUNDS_IN_PREPARE_AMOUNT + value: "10000" + - name: HOST_CENTRAL_LEDGER + value: "http://centralledger-service.ext-svcs.svc.cluster.local" + - name: HUB_OPERATOR_NAME + value: "hub_operator" + - name: INITIAL_POSITION + value: "0" + - name: NET_DEBIT_CAP + value: "10000" + - name: NDC_ADJUSTMENT_EMAIL + value: "hub.operator@domain.com" + - name: NDC_THRESHOLD_BREACH_EMAIL + value: "hub.operator@domain.com" + - name: SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL + value: "hub.operator@domain.com" + - name: onboard-msisdn-oracle + image: &msisdn_onboard_image mojaloop/onboard-msisdn-oracle:v11.0.3 + env: + - name: HOST_PATHFINDER_ORACLE + value: pathfinder-oracle.ext-svcs.svc.cluster.local + - name: MSISDN_LIST + value: '[{"MSISDN":"12345678901","currency":"USD"}]' + - name: DFSP_NAME + value: payerfsp + + payeefsp: + config: + schemeAdapter: + initContainers: + - name: onboard-hub-accounts + image: *hub_account_onboard_image + env: + - name: AUTH_BEARER_TOKEN + value: "6e35ccb3-ec22-51c9-b768-d12c3d289442" + - name: HOST_CENTRAL_LEDGER + value: "http://centralledger-service.ext-svcs.svc.cluster.local" + - name: HUB_OPERATOR_NAME + value: "hub_operator" + - name: ACCOUNTS + value: '[{ "type": "HUB_MULTILATERAL_SETTLEMENT", "currency": "XOF" },{ "type": "HUB_RECONCILIATION", "currency": "XOF" }]' + - name: onboard-central-ledger + image: *central_ledger_onboard_image + env: + - name: AUTH_BEARER_TOKEN + value: "6e35ccb3-ec22-51c9-b768-d12c3d289442" + - name: DFSP_CALLBACK_URL + value: "https://dfsp.huboperator.live:9999/payeefsp" + - name: DFSP_CURRENCY + value: "XOF" + - name: DFSP_NAME + value: "payeefsp" + - name: FUNDS_IN_PREPARE_AMOUNT + value: "10000" + - name: HOST_CENTRAL_LEDGER + value: "http://centralledger-service.ext-svcs.svc.cluster.local" + - name: HUB_OPERATOR_NAME + value: "hub_operator" + - name: INITIAL_POSITION + value: "0" + - name: NET_DEBIT_CAP + value: "10000" + - name: NDC_ADJUSTMENT_EMAIL + value: "hub.operator@domain.com" + - name: NDC_THRESHOLD_BREACH_EMAIL + value: "hub.operator@domain.com" + - name: SETTLEMENT_TRANSFER_POSITION_CHANGE_EMAIL + value: "hub.operator@domain.com" + - name: onboard-msisdn-oracle + image: *msisdn_onboard_image + env: + - name: HOST_PATHFINDER_ORACLE + value: pathfinder-oracle.ext-svcs.svc.cluster.local + - name: MSISDN_LIST + value: '[{"MSISDN":"23456789012","currency":"USD"}]' + - name: DFSP_NAME + value: payeefsp From dab8b8e8d9e9b3aae0d35d87221f0b6bce1b78cd Mon Sep 17 00:00:00 2001 From: Valentin Genev Date: Thu, 20 Aug 2020 17:41:24 +0300 Subject: [PATCH 21/30] [WIP] Feature/#1572 payee notification (#75) * upstream merge * added PUT /transfers/transferId handling for notifications to payee * added unit tests * ordered package.json to trigger ci/cd pipeline * removed homeTransactionId from transfer.update Co-authored-by: Valentin Co-authored-by: James Bush <37296643+bushjames@users.noreply.github.com> --- src/models/transfer.js | 11 ++---- src/package.json | 5 ++- src/simulator/api.yaml | 79 +++++++++++++++++++++++++++++++++++++++ src/simulator/handlers.js | 21 +++++++++-- src/test/simulator.js | 17 +++++++++ 5 files changed, 120 insertions(+), 13 deletions(-) diff --git a/src/models/transfer.js b/src/models/transfer.js index cfe8c118..cf3266d2 100644 --- a/src/models/transfer.js +++ b/src/models/transfer.js @@ -75,16 +75,13 @@ module.exports = class Transfer { * @param {String} transferId The current transfer id. * @param {Object} TansferRequest The new transfer object. */ - async update(currentTransferId, transferRequest) { - const { homeTransactionId: newTransferId } = transferRequest; - const response = { newTransferId }; - const reqStr = JSON.stringify(transferRequest); - const resStr = JSON.stringify(response); + async update(currentTransferId, transferResponse) { + const resStr = JSON.stringify(transferResponse); await this.db.run(` UPDATE ${transferTable} - SET id = ?, request = ?, response = ? - WHERE id = ?`, [newTransferId, reqStr, resStr, currentTransferId]); + SET response = ? + WHERE id = ?`, [resStr, currentTransferId]); } /** diff --git a/src/package.json b/src/package.json index d513f2bb..dcf9ee2e 100644 --- a/src/package.json +++ b/src/package.json @@ -1,15 +1,16 @@ { "name": "mojaloop-simulator", - "version": "11.0.3", + "version": "11.1.0", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", "author": "Matt Kingston, ModusBox Inc.", "contributors": [ + "Aaron Reynoza ", "Kamuela Franco ", "Matt Kingston ", "Steven Oderayi ", - "Aaron Reynoza ", + "Valentin Genev ", "ModusBox", "Mowali" ], diff --git a/src/simulator/api.yaml b/src/simulator/api.yaml index faadb54b..64b048b0 100644 --- a/src/simulator/api.yaml +++ b/src/simulator/api.yaml @@ -183,6 +183,31 @@ paths: schema: $ref: '#/components/schemas/errorResponse' + /transfers/{transferId}: + put: + summary: Receive notification for a specific transfer + description: The HTTP request `PUT /transfers/{transferId}` is used to receive notification for transfer being fulfiled when the FSP is a Payee + tags: + - Transfers + parameters: + - $ref: '#/components/schemas/transferId' + requestBody: + description: An incoming notification for fulfiled transfer + content: + application/json: + schema: + $ref: '#/components/schemas/fulfilNotification' + responses: + 200: + description: The notification was accepted + 500: + description: An error occured processing the request + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + + /otp/{requestToPayId}: get: summary: Requests OTP @@ -958,6 +983,60 @@ components: message: type: string description: Error message text + + extensionList: + type: array + items: + $ref: '#/components/schemas/extensionItem' + minItems: 0 + maxItems: 16 + + extensionItem: + type: object + properties: + key: + type: string + minLength: 1 + maxLength: 32 + value: + type: string + minLength: 1 + maxLength: 128 + + transferState: + type: string + enum: + - RECEIVED + - RESERVED + - COMMITTED + - ABORTED + description: > + Below are the allowed values for the enumeration + - RECEIVED DFSP has received the transfer. + - RESERVED DFSP has reserved the transfer. + - COMMITTED DFSP has successfully performed the transfer. + - ABORTED DFSP has aborted the transfer due a rejection or failure to perform the transfer. + + fulfilNotification: + title: TransfersIDPatchResponse + type: object + description: PUT /transfers/{transferId} object + properties: + completedTimestamp: + $ref: '#/components/schemas/timestamp' + description: Time and date when the transaction was completed. + example: "2020-05-19T08:38:08.699-04:00" + transferState: + $ref: '#/components/schemas/transferState' + description: State of the transfer. + example: COMMITTED + extensionList: + $ref: '#/components/schemas/extensionList' + description: Optional extension, specific to deployment. + required: + - completedTimestamp + - transferState + diff --git a/src/simulator/handlers.js b/src/simulator/handlers.js index d501ea71..75371ec8 100644 --- a/src/simulator/handlers.js +++ b/src/simulator/handlers.js @@ -30,7 +30,6 @@ require('dotenv').config(); const { getStackOrInspect } = require('@internal/log'); const { ApiErrorCodes } = require('../models/errors.js'); - const getParticipantsByTypeAndId = async (ctx) => { try { const { idValue, idType } = ctx.state.path.params; @@ -48,7 +47,6 @@ const getParticipantsByTypeAndId = async (ctx) => { } }; - const getPartiesByTypeAndId = async (ctx) => { // TODO: check that the provided type was MSISDN? Or just encode that in the API spec.. try { @@ -80,7 +78,6 @@ const getOTPById = async (ctx) => { } }; - const postTransfers = async (ctx) => { try { const res = await ctx.state.model.transfer.create(ctx.request.body); @@ -94,6 +91,20 @@ const postTransfers = async (ctx) => { } }; +const putTransfersById = async (ctx) => { + try { + const res = await ctx.state.model.transfer.update(ctx.state.path.params.transferId, { + ...ctx.request.body, + }); + ctx.state.logger.log(`putTransfersById is returning body: ${util.inspect(res)}`); + ctx.response.body = ctx.request.body; + ctx.response.status = 200; + } catch (err) { + ctx.state.logger.log(`Error in putTransfersById: ${getStackOrInspect(err)}`); + ctx.response.body = ApiErrorCodes.SERVER_ERROR; + ctx.response.status = 500; + } +}; const postQuotes = async (ctx) => { try { @@ -121,7 +132,6 @@ const postBulkQuotes = async (ctx) => { } }; - const getBulkQuoteById = async (ctx) => { try { const { idValue } = ctx.state.path.params; @@ -222,6 +232,9 @@ const map = { '/otp/{requestToPayId}': { get: getOTPById, }, + '/transfers/{transferId}': { + put: putTransfersById, + }, }; diff --git a/src/test/simulator.js b/src/test/simulator.js index 4a369186..93f797fc 100644 --- a/src/test/simulator.js +++ b/src/test/simulator.js @@ -266,3 +266,20 @@ test('postBulkQuotes should handle 500 errors', async (t) => { t.deepEqual(t.context.response, expected, 'Response did not match expected'); t.pass(); }); + +test('putTransfersById should handle request', async (t) => { + // Arrange + // eslint-disable-next-line no-param-reassign + t.context.state.path = { params: { transferId: '1234' } }; + // eslint-disable-next-line no-throw-literal, no-param-reassign + t.context.request = { + body: { + completedTimestamp: '2017-11-15T14:16:09.663+01:00', + transferState: 'COMMITTED', + }, + }; + await map['/transfers/{transferId}'].put(t.context); + const expected = t.context.request.body; + t.deepEqual(t.context.response, { body: { ...expected }, status: 200 }, 'response is received'); + t.pass(); +}); From 900e19c6f23daa9730835c04cd5ba0139edb6169 Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Thu, 3 Sep 2020 19:34:43 +0100 Subject: [PATCH 22/30] Environment variable configuration of parties (#77) * Initial work- parties addable, but no tests, no functionality * Added test for preconfigured parties * Added config unit test * Update src/config.js * Update src/config.js * Updated config correctly. Duh. * Bumped version --- src/config.js | 2 ++ src/index.js | 4 ++-- src/models/model.js | 6 +++++- src/package-lock.json | 2 +- src/package.json | 2 +- src/test/admin.js | 2 +- src/test/model.js | 4 ++-- src/test/reports.js | 2 +- src/test/simulator.js | 2 +- src/test/test-api.js | 27 ++++++++++++++++++++++++++- src/test/unit/config.test.js | 7 ++++--- 11 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/config.js b/src/config.js index 92887f64..8b501280 100644 --- a/src/config.js +++ b/src/config.js @@ -57,6 +57,7 @@ const config = { reportApi: 3002, testApi: 3003, }, + parties: [], }; @@ -78,6 +79,7 @@ const setConfig = async (cfg) => { config.ports.simulatorApi = cfg.SIMULATOR_API_LISTEN_PORT || config.ports.simulatorApi; config.ports.reportApi = cfg.REPORT_API_LISTEN_PORT || config.ports.reportApi; config.ports.testApi = cfg.TEST_API_LISTEN_PORT || config.ports.testApi; + config.parties = cfg.PARTIES ? JSON.parse(cfg.PARTIES) : config.parties; }; diff --git a/src/index.js b/src/index.js index 7d64be6b..39ab65c0 100644 --- a/src/index.js +++ b/src/index.js @@ -64,6 +64,7 @@ const testApi = new Koa(); (async function start() { // Set up the config from the environment await setConfig(process.env); + const conf = getConfig(); // Set up a logger for each running server const space = Number(process.env.LOG_INDENT); @@ -81,7 +82,7 @@ const testApi = new Koa(); // Initialise the model const model = new Model(); - await model.init(process.env.MODEL_DATABASE); + await model.init({ databaseFilePath: process.env.MODEL_DATABASE, parties: conf.parties }); // Log raw to console as a last resort- if the logging framework crashes const failSafe = async (ctx, next) => { @@ -257,7 +258,6 @@ const testApi = new Koa(); // If config specifies TLS, start an HTTPS server; otherwise HTTP let simServer; - const conf = getConfig(); const simulatorPort = conf.ports.simulatorApi; const reportPort = conf.ports.reportApi; const testApiPort = conf.ports.testApi; diff --git a/src/models/model.js b/src/models/model.js index 7b5133f3..81593cd6 100644 --- a/src/models/model.js +++ b/src/models/model.js @@ -82,7 +82,7 @@ module.exports = class Model { * @param {String} databaseFilepath SqliteDB file path * @throws {Error} */ - async init(databaseFilepath) { + async init({ databaseFilepath, parties }) { if (this.db) { throw new Error('Attempted to initialise database twice'); } @@ -104,6 +104,10 @@ module.exports = class Model { this.transactionrequest = new TransactionRequest(this.db); this.transfer = new Transfer(this.db); this.bulkTransfer = new BulkTransfer(this.db); + + if (parties) { + await Promise.all(parties.map((p) => this.party.create(p))); + } } catch (err) { throw new Error(err); } diff --git a/src/package-lock.json b/src/package-lock.json index 841ecda4..ebdd3d0d 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.0.3", + "version": "11.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index dcf9ee2e..c743eaeb 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.1.0", + "version": "11.2.0", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", diff --git a/src/test/admin.js b/src/test/admin.js index 5cc2179b..bb4b2474 100644 --- a/src/test/admin.js +++ b/src/test/admin.js @@ -30,7 +30,7 @@ const { party, idType, idValue } = require('./constants'); test.beforeEach(async (t) => { const model = new Model(); - await model.init(':memory:'); + await model.init({ databaseFilepath: ':memory:' }); // eslint-disable-next-line no-param-reassign t.context = { state: { model }, response: {} }; }); diff --git a/src/test/model.js b/src/test/model.js index 5569c28d..ec317d37 100644 --- a/src/test/model.js +++ b/src/test/model.js @@ -39,7 +39,7 @@ const { test.beforeEach(async (t) => { const model = new Model(); - await model.init(':memory:'); + await model.init({ databaseFilepath: ':memory:' }); // eslint-disable-next-line no-param-reassign t.context = { model }; }); @@ -395,7 +395,7 @@ test('throws if we try to init the db incorrectly', async (t) => { }); // Assert - t.is(error.message, 'TypeError: Argument 0 must be a string', 'Invalid error message.'); + t.is(error.message, 'Cannot destructure property \'databaseFilepath\' of \'undefined\' as it is undefined.', 'Invalid error message.'); }); test('does nothing if trying to close a non existent db', async (t) => { diff --git a/src/test/reports.js b/src/test/reports.js index ccf903bd..a6156437 100644 --- a/src/test/reports.js +++ b/src/test/reports.js @@ -39,7 +39,7 @@ const validQuerystring = stringify({ START_DATE_TIME: '2019-05-20T21:20:56', END const nonFindableQuerystring = stringify({ START_DATE_TIME: '2019-05-19T21:20:00', END_DATE_TIME: '2019-05-20T21:20:56' }); test.before(async (t) => { - await model.init(process.env.MODEL_DATABASE); + await model.init({ databaseFilepath: process.env.MODEL_DATABASE }); Array.from({ length: 10 }).forEach(async (x, i) => { quote.quoteId = uuid(); await model.quote.create(quote); diff --git a/src/test/simulator.js b/src/test/simulator.js index 93f797fc..022cd795 100644 --- a/src/test/simulator.js +++ b/src/test/simulator.js @@ -38,7 +38,7 @@ const { ApiErrorCodes } = require('../models/errors'); test.beforeEach(async (t) => { const model = new Model(); - await model.init(':memory:'); + await model.init({ databaseFilepath: ':memory:' }); // eslint-disable-next-line no-param-reassign t.context = { state: { model, logger: console }, response: {}, diff --git a/src/test/test-api.js b/src/test/test-api.js index 3432b311..3cc5ec4b 100644 --- a/src/test/test-api.js +++ b/src/test/test-api.js @@ -114,9 +114,28 @@ const testOps = [ ]; +const preconfiguredParties = [ + { + ...party, + idValue: '123457', + }, + { + ...party, + idValue: '123458', + }, + { + ...party, + idValue: '123459', + }, + { + ...party, + idValue: '123456', + }, +]; + test.beforeEach(async (t) => { const model = new Model(); - await model.init(':memory:'); + await model.init({ databaseFilepath: ':memory:', parties: preconfiguredParties }); // eslint-disable-next-line no-param-reassign t.context = { state: { model, logger: console }, response: {} }; }); @@ -125,6 +144,12 @@ test.afterEach(async (t) => { await t.context.state.model.close(); }); +test.only('preconfigured parties should pre-exist', async (t) => { + await handlers.map['/repository/parties'].get(t.context); + const byId = (a, b) => Number(a.idValue) - Number(b.idValue); + t.deepEqual(t.context.response.body.sort(byId), preconfiguredParties.sort(byId)); +}); + test('should return 200 when reading a party', async (t) => { // eslint-disable-next-line no-param-reassign await handlers.map['/repository/parties'].get(t.context); diff --git a/src/test/unit/config.test.js b/src/test/unit/config.test.js index 5042e42e..53311612 100644 --- a/src/test/unit/config.test.js +++ b/src/test/unit/config.test.js @@ -28,7 +28,7 @@ const test = require('ava'); const { setConfig, getConfig } = require('../../config'); - +const { party } = require('../constants'); // Note: these were originally 3 different tests, which I had to combine into 1 // because of the way that ava tries to run the tests in paralell, which was causing @@ -39,10 +39,10 @@ test('Sets the basic config', async (t) => { const env = { MUTUAL_TLS_ENABLED: 'false', HTTPS_ENABLED: 'false', + PARTIES: JSON.stringify([party, party, party]), }; const expected = { - tls: - { + tls: { enabled: false, mutualTLS: { enabled: false }, creds: { ca: null, cert: null, key: null }, @@ -52,6 +52,7 @@ test('Sets the basic config', async (t) => { reportApi: 3002, testApi: 3003, }, + parties: [party, party, party], }; // Act From f3e9a1fa0b6f90c4f77c111a839a4aeaaa24a87f Mon Sep 17 00:00:00 2001 From: Matt Kingston Date: Thu, 3 Sep 2020 20:42:07 +0100 Subject: [PATCH 23/30] Improved Model.init doc. Fixed bug with server start. Bumped version. (#78) --- src/index.js | 2 +- src/models/model.js | 41 +++++++++++++++++++---------------------- src/package-lock.json | 2 +- src/package.json | 2 +- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/index.js b/src/index.js index 39ab65c0..7382c05f 100644 --- a/src/index.js +++ b/src/index.js @@ -82,7 +82,7 @@ const testApi = new Koa(); // Initialise the model const model = new Model(); - await model.init({ databaseFilePath: process.env.MODEL_DATABASE, parties: conf.parties }); + await model.init({ databaseFilepath: process.env.MODEL_DATABASE, parties: conf.parties }); // Log raw to console as a last resort- if the logging framework crashes const failSafe = async (ctx, next) => { diff --git a/src/models/model.js b/src/models/model.js index 81593cd6..0dca5879 100644 --- a/src/models/model.js +++ b/src/models/model.js @@ -79,7 +79,8 @@ module.exports = class Model { * Initialises db. * * @async - * @param {String} databaseFilepath SqliteDB file path + * @param {String} databaseFilepath SqliteDB file path + * @param [{Object}] parties Array of party objects to create after db initialisation * @throws {Error} */ async init({ databaseFilepath, parties }) { @@ -87,29 +88,25 @@ module.exports = class Model { throw new Error('Attempted to initialise database twice'); } - try { - this.db = await sqlite.open(databaseFilepath); - await this.db.run('PRAGMA foreign_keys = true'); - await this.db.run(createPartyTable); - await this.db.run(createQuoteTable); - await this.db.run(createTransactionRequestTable); - await this.db.run(createTransferTable); - await this.db.run(createPartyExtensionTable); - await this.db.run(createBulkQuoteTable); - await this.db.run(createBulkTransferTable); + this.db = await sqlite.open(databaseFilepath); + await this.db.run('PRAGMA foreign_keys = true'); + await this.db.run(createPartyTable); + await this.db.run(createQuoteTable); + await this.db.run(createTransactionRequestTable); + await this.db.run(createTransferTable); + await this.db.run(createPartyExtensionTable); + await this.db.run(createBulkQuoteTable); + await this.db.run(createBulkTransferTable); - this.party = new Party(this.db); - this.quote = new Quote(this.db); - this.bulkQuote = new BulkQuote(this.db); - this.transactionrequest = new TransactionRequest(this.db); - this.transfer = new Transfer(this.db); - this.bulkTransfer = new BulkTransfer(this.db); + this.party = new Party(this.db); + this.quote = new Quote(this.db); + this.bulkQuote = new BulkQuote(this.db); + this.transactionrequest = new TransactionRequest(this.db); + this.transfer = new Transfer(this.db); + this.bulkTransfer = new BulkTransfer(this.db); - if (parties) { - await Promise.all(parties.map((p) => this.party.create(p))); - } - } catch (err) { - throw new Error(err); + if (parties) { + await Promise.all(parties.map((p) => this.party.create(p))); } } }; diff --git a/src/package-lock.json b/src/package-lock.json index ebdd3d0d..6b1de95d 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.2.0", + "version": "11.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index c743eaeb..70added6 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.2.0", + "version": "11.2.1", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From c008db1ebd057d4738b495cf9983d207c4944d3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Nov 2020 15:56:34 +0800 Subject: [PATCH 24/30] Bump node-fetch from 2.6.0 to 2.6.1 in /src (#79) Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/bitinn/node-fetch/releases) - [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md) - [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/package-lock.json | 6 +++--- src/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/package-lock.json b/src/package-lock.json index 6b1de95d..56c1a0e6 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -3948,9 +3948,9 @@ "dev": true }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-pre-gyp": { "version": "0.11.0", diff --git a/src/package.json b/src/package.json index 70added6..b86a1a64 100644 --- a/src/package.json +++ b/src/package.json @@ -52,7 +52,7 @@ "koa": "2.11.0", "koa-body": "4.1.1", "mustache": "4.0.0", - "node-fetch": "2.6.0", + "node-fetch": "2.6.1", "sqlite": "3.0.3", "yamljs": "0.3.0" }, From 44e53387ece37b77011640ed9c15b90c06d9fbd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Nov 2020 16:32:51 +0800 Subject: [PATCH 25/30] Bump node-fetch from 2.6.0 to 2.6.1 in /init/onboard-hub-accounts (#81) Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/bitinn/node-fetch/releases) - [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md) - [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- init/onboard-hub-accounts/package-lock.json | 6 +++--- init/onboard-hub-accounts/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/init/onboard-hub-accounts/package-lock.json b/init/onboard-hub-accounts/package-lock.json index 9b319843..c10418a4 100644 --- a/init/onboard-hub-accounts/package-lock.json +++ b/init/onboard-hub-accounts/package-lock.json @@ -1124,9 +1124,9 @@ "dev": true }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "normalize-package-data": { "version": "2.5.0", diff --git a/init/onboard-hub-accounts/package.json b/init/onboard-hub-accounts/package.json index ac1a8c4f..78860b15 100644 --- a/init/onboard-hub-accounts/package.json +++ b/init/onboard-hub-accounts/package.json @@ -5,7 +5,7 @@ "main": "onboard-hub-accounts.js", "dependencies": { "@mojaloop/finance-portal-lib": "0.0.20-snapshot", - "node-fetch": "^2.6.0", + "node-fetch": "^2.6.1", "uuid": "^8.2.0" }, "devDependencies": { From 52acc98d782ed5428bf5a23f00e63104bdf30642 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Nov 2020 10:20:16 +0800 Subject: [PATCH 26/30] Bump node-fetch from 2.6.0 to 2.6.1 in /init/onboard-central-ledger (#80) Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/bitinn/node-fetch/releases) - [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md) - [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- init/onboard-central-ledger/package-lock.json | 6 +++--- init/onboard-central-ledger/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/init/onboard-central-ledger/package-lock.json b/init/onboard-central-ledger/package-lock.json index 2bb6a7f1..03bd694f 100644 --- a/init/onboard-central-ledger/package-lock.json +++ b/init/onboard-central-ledger/package-lock.json @@ -1124,9 +1124,9 @@ "dev": true }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "normalize-package-data": { "version": "2.5.0", diff --git a/init/onboard-central-ledger/package.json b/init/onboard-central-ledger/package.json index cec023ee..d8355a86 100644 --- a/init/onboard-central-ledger/package.json +++ b/init/onboard-central-ledger/package.json @@ -5,7 +5,7 @@ "main": "onboard-dfsp.js", "dependencies": { "@mojaloop/finance-portal-lib": "0.0.19-snapshot", - "node-fetch": "^2.6.0", + "node-fetch": "^2.6.1", "uuid": "^8.2.0" }, "devDependencies": { From 549554ae03a878736d2a2edfa33ffae51569181a Mon Sep 17 00:00:00 2001 From: Lewis Daly Date: Wed, 4 Nov 2020 13:44:05 +0800 Subject: [PATCH 27/30] chore(package): bump package to `11.2.2` (#83) --- src/package-lock.json | 2 +- src/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package-lock.json b/src/package-lock.json index 56c1a0e6..2db080e4 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.2.1", + "version": "11.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/package.json b/src/package.json index b86a1a64..07c5e28a 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.2.1", + "version": "11.2.2", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", From 552095f60221a851840ef122b579a58b20c1b4f5 Mon Sep 17 00:00:00 2001 From: Lewis Daly Date: Wed, 9 Dec 2020 20:44:06 +1100 Subject: [PATCH 28/30] chore: update license file (#84) --- LICENSE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 26fb7bdd..40350591 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,10 +1,10 @@ # LICENSE -Copyright © 2017 Bill & Melinda Gates Foundation +Copyright © 2020 Mojaloop Foundation -The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 -(the "License") and you may not use these files except in compliance with the [License](http://www.apache.org/licenses/LICENSE-2.0). You may obtain a copy of the License at +The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 +(the "License") and you may not use these files except in compliance with the [License](http://www.apache.org/licenses/LICENSE-2.0). -[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) +You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the [License](http://www.apache.org/licenses/LICENSE-2.0). From 9525923953e693bb9959c1600725165542eb6c8f Mon Sep 17 00:00:00 2001 From: shashi165 <33355509+shashi165@users.noreply.github.com> Date: Thu, 10 Dec 2020 10:23:43 -0600 Subject: [PATCH 29/30] Add "subIdValue" parameter for parties in simulator (#85) * added endpoint for subIdValue * added unit/coverage tests * fix linting * added simulator endpoints for subIdValue * fix audit issue --- src/audit-resolve.json | 30 +++ src/models/constants.js | 31 ++- src/models/model.js | 4 + src/models/party.js | 149 ++++++++++---- src/package-lock.json | 417 ++++++++++---------------------------- src/package.json | 2 +- src/simulator/api.yaml | 94 +++++++++ src/simulator/handlers.js | 14 +- src/test-api/api.yaml | 70 ++++++- src/test-api/handlers.js | 17 +- src/test/constants.js | 36 ++++ src/test/model.js | 108 +++++++++- 12 files changed, 595 insertions(+), 377 deletions(-) diff --git a/src/audit-resolve.json b/src/audit-resolve.json index c1cad85d..a9d8d4e2 100644 --- a/src/audit-resolve.json +++ b/src/audit-resolve.json @@ -4,6 +4,36 @@ "decision": "ignore", "madeAt": 1594258444388, "expiresAt": 1594863234907 + }, + "1589|sqlite>sqlite3>node-pre-gyp>rc>ini": { + "decision": "ignore", + "madeAt": 1607553157718, + "expiresAt": 1610145105148 + }, + "1589|00unidentified>sqlite>sqlite3>node-pre-gyp>rc>ini": { + "decision": "ignore", + "madeAt": 1607553157718, + "expiresAt": 1610145105148 + }, + "1589|00unidentified>00unidentified>sqlite>sqlite3>node-pre-gyp>rc>ini": { + "decision": "ignore", + "madeAt": 1607553157718, + "expiresAt": 1610145105148 + }, + "1589|ava>update-notifier>latest-version>package-json>registry-auth-token>rc>ini": { + "decision": "ignore", + "madeAt": 1607553157718, + "expiresAt": 1610145105148 + }, + "1589|ava>update-notifier>latest-version>package-json>registry-url>rc>ini": { + "decision": "ignore", + "madeAt": 1607553157718, + "expiresAt": 1610145105148 + }, + "1589|ava>update-notifier>is-installed-globally>global-dirs>ini": { + "decision": "ignore", + "madeAt": 1607553157718, + "expiresAt": 1610145105148 } }, "rules": {}, diff --git a/src/models/constants.js b/src/models/constants.js index ef7f1bf2..aa56baa5 100644 --- a/src/models/constants.js +++ b/src/models/constants.js @@ -38,19 +38,40 @@ CREATE TABLE IF NOT EXISTS ${partyTable} ( lastName TEXT, dateOfBirth TEXT, idType TEXT, - idValue TEXT NOT NULL PRIMARY KEY, + idValue TEXT NOT NULL, + subIdValue TEXT, CHECK(idValue <> '') ) `; + +// below index is a workaround to avoid the duplicates since sqlite treats every null as a unique value +// thus allowing to insert multiple records for same the idValue having subIdValue as NULL +const createPartyTableUniqueIndex = ` +CREATE UNIQUE INDEX IF NOT EXISTS idx_party_unique ON ${partyTable} ( + idValue, + IFNULL(subIdValue, '') +) +`; + const createPartyExtensionTable = ` CREATE TABLE IF NOT EXISTS ${partyExtensionTable} ( idValue TEXT NOT NULL, + subIdValue TEXT, key TEXT NOT NULL, - value TEXT NOT NULL, - PRIMARY KEY (idValue, key), - FOREIGN KEY (idValue) REFERENCES party(idValue) ON DELETE CASCADE + value TEXT NOT NULL ) `; + +// below index is a workaround to avoid the duplicates since sqlite treats every null as a unique value +// thus allowing to insert multiple records for same the idValue/key having subIdValue as NULL +const createPartyExtensionTableUniqueIndex = ` +CREATE UNIQUE INDEX IF NOT EXISTS idx_party_extension_unique ON ${partyExtensionTable} ( + idValue, + IFNULL(subIdValue, ''), + key +) +`; + const createQuoteTable = ` CREATE TABLE IF NOT EXISTS ${quoteTable} ( id TEXT NOT NULL PRIMARY KEY, @@ -114,4 +135,6 @@ module.exports = { createTransferTable, createTransactionRequestTable, createPartyExtensionTable, + createPartyTableUniqueIndex, + createPartyExtensionTableUniqueIndex, }; diff --git a/src/models/model.js b/src/models/model.js index 0dca5879..855a1ea8 100644 --- a/src/models/model.js +++ b/src/models/model.js @@ -38,12 +38,14 @@ const BulkTransfer = require('./bulkTransfer'); const { createPartyTable, + createPartyTableUniqueIndex, createQuoteTable, createBulkQuoteTable, createTransferTable, createBulkTransferTable, createTransactionRequestTable, createPartyExtensionTable, + createPartyExtensionTableUniqueIndex, } = require('./constants'); /** @@ -91,10 +93,12 @@ module.exports = class Model { this.db = await sqlite.open(databaseFilepath); await this.db.run('PRAGMA foreign_keys = true'); await this.db.run(createPartyTable); + await this.db.run(createPartyTableUniqueIndex); await this.db.run(createQuoteTable); await this.db.run(createTransactionRequestTable); await this.db.run(createTransferTable); await this.db.run(createPartyExtensionTable); + await this.db.run(createPartyExtensionTableUniqueIndex); await this.db.run(createBulkQuoteTable); await this.db.run(createBulkTransferTable); diff --git a/src/models/party.js b/src/models/party.js index bbff6198..8044f375 100644 --- a/src/models/party.js +++ b/src/models/party.js @@ -47,11 +47,19 @@ module.exports = class Party { * @async * @param {String} idType The party idType. * @param {String} idValue The party idValue. + * @param {String} subIdValue The optional party subIdValue. * @returns {Promise} Party object. */ - async get(idType, idValue) { - const res = await this.db.all(`SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, pe.key, pe.value FROM ${partyTable} p LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue WHERE p.idType = ? AND p.idValue = ?`, [idType, idValue]); + async get(idType, idValue, subIdValue = null) { + let res; + if (!subIdValue) { + res = await this.db.all(`SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, p.subIdValue, pe.key, pe.value FROM ${partyTable} p + LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue WHERE p.idType = ? AND p.idValue = ? AND p.subIdValue IS NULL AND pe.subIdValue IS NULL`, [idType, idValue]); + } else { + res = await this.db.all(`SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, p.subIdValue, pe.key, pe.value FROM ${partyTable} p + LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue AND p.subIdValue = pe.subIdValue WHERE p.idType = ? AND p.idValue = ? AND p.subIdValue = ?`, [idType, idValue, subIdValue]); + } const resultMap = {}; res.forEach((row) => { let party; @@ -67,6 +75,9 @@ module.exports = class Party { idType: row.idType, idValue: row.idValue, }; + if (row.subIdValue) { + party.subIdValue = row.subIdValue; + } resultMap[row.idValue] = party; } if (row.key) { @@ -89,12 +100,14 @@ module.exports = class Party { * @returns {Promise} Party object. */ async getAll() { - const res = await this.db.all(`SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, pe.key, pe.value FROM ${partyTable} p LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue`); + const res = await this.db.all(`SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, p.subIdValue, pe.key, pe.value FROM ${partyTable} p + LEFT JOIN ${partyExtensionTable} pe ON (p.idValue = pe.idValue AND pe.subIdValue IS NULL AND p.subIdValue IS NULL) OR (p.idValue = pe.idValue AND p.subIdValue = pe.subIdValue)`); + const resultMap = {}; res.forEach((row) => { let party; - if (resultMap[row.idValue]) { - party = resultMap[row.idValue]; + if (resultMap[`${row.idValue}-${row.subIdValue}`]) { + party = resultMap[`${row.idValue}-${row.subIdValue}`]; } else { party = { displayName: row.displayName, @@ -105,7 +118,10 @@ module.exports = class Party { idType: row.idType, idValue: row.idValue, }; - resultMap[row.idValue] = party; + if (row.subIdValue) { + party.subIdValue = row.subIdValue; + } + resultMap[`${row.idValue}-${row.subIdValue}`] = party; } if (row.key) { if (!party.extensionList) { @@ -126,19 +142,17 @@ module.exports = class Party { */ async create(party) { const { - displayName, firstName, middleName, lastName, dateOfBirth, idType, idValue, + displayName, firstName, middleName, lastName, dateOfBirth, idType, idValue, subIdValue, } = party; - await this.db.get(` - INSERT INTO ${partyTable} (displayName, firstName, middleName, lastName, dateOfBirth, idType, idValue) - VALUES (?, ?, ?, ?, ?, ?, ?)`, - [displayName, firstName, middleName, lastName, dateOfBirth, idType, idValue]); + await this.db.get(`INSERT INTO ${partyTable} (displayName, firstName, middleName, lastName, dateOfBirth, idType, idValue, subIdValue) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, + [displayName, firstName, middleName, lastName, dateOfBirth, idType, idValue, subIdValue]); if (party.extensionList) { const { extensionList } = party; extensionList.forEach((extension) => { - this.db.get(` - INSERT INTO ${partyExtensionTable} (idValue, key, value) - VALUES (?, ?, ?)`, - [idValue, extension.key, extension.value]); + this.db.get(`INSERT INTO ${partyExtensionTable} (idValue, subIdValue, key, value) + VALUES (?, ?, ?, ?)`, + [idValue, subIdValue, extension.key, extension.value]); }); } } @@ -147,39 +161,77 @@ module.exports = class Party { /** * Updates a party * - * @param {String} idValue The party idValue to update. * @param {Object} newParty The new Party object. + * @param {String} idType The party idType to update. + * @param {String} idValue The party idValue to update. + * @param {String} subIdValue The optional party subIdValue to update. */ - async update(idType, idValue, newParty) { + async update(newParty, idType, idValue, subIdValue = null) { const { displayName, firstName, middleName, lastName, dateOfBirth, } = newParty; - await this.db.run(` - UPDATE ${partyTable} - SET displayName = ?, firstName = ?, middleName = ?, lastName = ?, dateOfBirth = ?, idType = ?, idValue = ? - WHERE idType = ? AND idValue = ?`, - [displayName, - firstName, - middleName, - lastName, - dateOfBirth, - idType, - idValue, - idType, - idValue]); - if (newParty.extensionList) { - const { extensionList } = newParty; - extensionList.forEach((extension) => { - this.db.run(` - UPDATE ${partyExtensionTable} - SET value = ? - WHERE key = ?`, - [extension.value, extension.key]); - this.db.run(` - INSERT OR IGNORE INTO ${partyExtensionTable} (idValue, key, value) - VALUES (?, ?, ?)`, - [idValue, extension.key, extension.value]); - }); + if (!subIdValue) { + // If subIdValue is not passed then only updated the record where subIdValue IS NULL + // This will make sure we accidentally don't update all records for idValue by ignoring subIdValue + await this.db.run(` + UPDATE ${partyTable} + SET displayName = ?, firstName = ?, middleName = ?, lastName = ?, dateOfBirth = ?, idType = ?, idValue = ? + WHERE idType = ? AND idValue = ? AND subIdValue IS NULL`, + [displayName, + firstName, + middleName, + lastName, + dateOfBirth, + idType, + idValue, + idType, + idValue]); + + if (newParty.extensionList) { + const { extensionList } = newParty; + extensionList.forEach((extension) => { + this.db.run(` + UPDATE ${partyExtensionTable} + SET value = ? + WHERE key = ? AND idValue = ? AND subIdValue IS NULL`, + [extension.value, extension.key, idValue]); + this.db.run(` + INSERT OR IGNORE INTO ${partyExtensionTable} (idValue, subIdValue, key, value) + VALUES (?, ?, ?, ?)`, + [idValue, subIdValue, extension.key, extension.value]); + }); + } + } else { + // Update the record for a specific idValue and subIdValue + await this.db.run(` + UPDATE ${partyTable} + SET displayName = ?, firstName = ?, middleName = ?, lastName = ?, dateOfBirth = ?, idType = ?, idValue = ?, subIdValue = ? + WHERE idType = ? AND idValue = ? AND subIdValue = ?`, + [displayName, + firstName, + middleName, + lastName, + dateOfBirth, + idType, + idValue, + subIdValue, + idType, + idValue, + subIdValue]); + if (newParty.extensionList) { + const { extensionList } = newParty; + extensionList.forEach((extension) => { + this.db.run(` + UPDATE ${partyExtensionTable} + SET value = ? + WHERE key = ? AND idValue = ? AND subIdValue = ?`, + [extension.value, extension.key, idValue, subIdValue]); + this.db.run(` + INSERT OR IGNORE INTO ${partyExtensionTable} (idValue, subIdValue, key, value) + VALUES (?, ?, ?, ?)`, + [idValue, subIdValue, extension.key, extension.value]); + }); + } } } @@ -188,8 +240,15 @@ module.exports = class Party { * * @param {String} idType The party idType. * @param {String} idValue The party idValue. + * @param {String} subIdValue The optional party subIdValue. */ - async delete(idType, idValue) { - await this.db.run(`DELETE FROM ${partyTable} WHERE idType = ? AND idValue = ?`, [idType, idValue]); + async delete(idType, idValue, subIdValue = null) { + if (!subIdValue) { + await this.db.run(`DELETE FROM ${partyTable} WHERE idType = ? AND idValue = ? AND subIdValue IS NULL`, [idType, idValue]); + await this.db.run(`DELETE FROM ${partyExtensionTable} WHERE idValue = ? AND subIdValue IS NULL`, [idValue]); + } else { + await this.db.run(`DELETE FROM ${partyTable} WHERE idType = ? AND idValue = ? AND subIdValue = ?`, [idType, idValue, subIdValue]); + await this.db.run(`DELETE FROM ${partyExtensionTable} WHERE idValue = ? AND subIdValue = ?`, [idValue, subIdValue]); + } } }; diff --git a/src/package-lock.json b/src/package-lock.json index 2db080e4..f74dde54 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.2.2", + "version": "11.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -383,29 +383,6 @@ "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "json-schema-ref-parser": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.0.3.tgz", - "integrity": "sha512-Ds/0541IPed88JSiMb3CBeUsxfL5Eosc0r97z0QMSXiBJTYKZLhOAGZd8zFVfpkKaRb4zDAnumyFYxnHLmbQmw==", - "requires": { - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.12.1", - "ono": "^4.0.11" - } - }, - "openapi-jsonschema-parameters": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/openapi-jsonschema-parameters/-/openapi-jsonschema-parameters-1.1.0.tgz", - "integrity": "sha512-TCDHFK3oL842ne50EIymIXgvVbbMjohjjaieGDGW0hzbz3vJE9u3OjORB+p0IaKg5TbOsrpF8SNg3OvjcehBUg==", - "requires": { - "openapi-types": "^1.3.1" - } } } }, @@ -582,6 +559,13 @@ "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "dependencies": { + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + } } }, "ansi-align": { @@ -762,30 +746,12 @@ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "dev": true }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, "audit-resolve-core": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/audit-resolve-core/-/audit-resolve-core-1.1.8.tgz", @@ -906,29 +872,11 @@ } } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, "binary-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", @@ -1101,11 +1049,6 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -1353,14 +1296,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, "common-path-prefix": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", @@ -1569,14 +1504,6 @@ "fast-bind": "^1.0.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, "date-time": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/date-time/-/date-time-2.1.0.tgz", @@ -1587,9 +1514,9 @@ } }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { "ms": "^2.1.1" } @@ -1723,11 +1650,6 @@ } } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1806,15 +1728,6 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2308,9 +2221,9 @@ "dev": true }, "events": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", - "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" }, "events-to-array": { "version": "1.1.2", @@ -2318,11 +2231,6 @@ "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", "dev": true }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -2334,20 +2242,15 @@ "tmp": "^0.0.33" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, "fast-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-bind/-/fast-bind-1.0.0.tgz", "integrity": "sha1-f6llLLMyX1zR4lLWy08WDeGnbnU=" }, "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-diff": { "version": "1.2.0", @@ -2536,21 +2439,6 @@ } } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "format-util": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", @@ -2640,14 +2528,6 @@ "pump": "^3.0.0" } }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -2735,20 +2615,6 @@ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2829,6 +2695,20 @@ "requires": { "deep-equal": "~1.0.1", "http-errors": "~1.7.2" + }, + "dependencies": { + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + } } }, "http-cache-semantics": { @@ -2838,25 +2718,22 @@ "dev": true }, "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", + "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", "requires": { "depd": "~1.1.2", "inherits": "2.0.4", - "setprototypeof": "1.1.1", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + }, + "dependencies": { + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + } } }, "husky": { @@ -3099,9 +2976,9 @@ } }, "is-generator-function": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", - "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz", + "integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==" }, "is-glob": { "version": "4.0.1", @@ -3206,7 +3083,8 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, "is-windows": { "version": "1.0.2", @@ -3245,11 +3123,6 @@ "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, "istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", @@ -3429,11 +3302,6 @@ "esprima": "^4.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -3464,10 +3332,15 @@ "selectn": "^1.1.2" } }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "json-schema-ref-parser": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.0.3.tgz", + "integrity": "sha512-Ds/0541IPed88JSiMb3CBeUsxfL5Eosc0r97z0QMSXiBJTYKZLhOAGZd8zFVfpkKaRb4zDAnumyFYxnHLmbQmw==", + "requires": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.12.1", + "ono": "^4.0.11" + } }, "json-schema-traverse": { "version": "0.4.1", @@ -3480,11 +3353,6 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, "json5": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.2.tgz", @@ -3500,17 +3368,6 @@ "integrity": "sha1-T80kbcXQ44aRkHxEqwAveC0dlMw=", "dev": true }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, "keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -3837,16 +3694,16 @@ } }, "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" }, "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", "requires": { - "mime-db": "1.43.0" + "mime-db": "1.44.0" } }, "mimic-fn": { @@ -3916,9 +3773,9 @@ "dev": true }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" }, "natural-compare": { "version": "1.4.0", @@ -3927,9 +3784,9 @@ "dev": true }, "needle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.3.tgz", - "integrity": "sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz", + "integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==", "requires": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -4184,11 +4041,6 @@ } } }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4285,6 +4137,14 @@ "format-util": "^1.0.3" } }, + "openapi-jsonschema-parameters": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/openapi-jsonschema-parameters/-/openapi-jsonschema-parameters-1.1.0.tgz", + "integrity": "sha512-TCDHFK3oL842ne50EIymIXgvVbbMjohjjaieGDGW0hzbz3vJE9u3OjORB+p0IaKg5TbOsrpF8SNg3OvjcehBUg==", + "requires": { + "openapi-types": "^1.3.1" + } + }, "openapi-types": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-1.3.5.tgz", @@ -4492,11 +4352,6 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -4623,11 +4478,6 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -4653,9 +4503,9 @@ } }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" }, "raw-body": { "version": "2.4.1", @@ -4666,6 +4516,20 @@ "http-errors": "1.7.3", "iconv-lite": "0.4.24", "unpipe": "1.0.0" + }, + "dependencies": { + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + } } }, "rc": { @@ -4890,33 +4754,6 @@ "es6-error": "^4.0.1" } }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5260,29 +5097,12 @@ } }, "sqlite3": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.1.tgz", - "integrity": "sha512-CvT5XY+MWnn0HkbwVKJAyWEMfzpAPwnTiB3TobA5Mri44SrTovmmh499NPQP+gatkeOipqPlBLel7rn4E/PCQg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.2.0.tgz", + "integrity": "sha512-roEOz41hxui2Q7uYnWsjMOTry6TcNUNmp8audCx18gF10P2NknwdpF+E+HKvz/F2NvPKGGBF4NGc+ZPQ+AABwg==", "requires": { "nan": "^2.12.1", - "node-pre-gyp": "^0.11.0", - "request": "^2.87.0" - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "node-pre-gyp": "^0.11.0" } }, "stack-utils": { @@ -5642,15 +5462,6 @@ "hoek": "6.x.x" } }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "trim-off-newlines": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", @@ -5668,19 +5479,6 @@ "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -5756,9 +5554,9 @@ } }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", "requires": { "punycode": "^2.1.0" } @@ -5780,7 +5578,8 @@ "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true }, "v8-compile-cache": { "version": "2.1.0", @@ -5803,16 +5602,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/src/package.json b/src/package.json index 07c5e28a..dc0d5b85 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "11.2.2", + "version": "11.3.0", "description": "A canonical test example implementation of the parties, transfers and quotes resources of the Mojaloop API", "license": "Apache-2.0", "main": "index.js", diff --git a/src/simulator/api.yaml b/src/simulator/api.yaml index 64b048b0..43010553 100644 --- a/src/simulator/api.yaml +++ b/src/simulator/api.yaml @@ -52,6 +52,49 @@ paths: schema: $ref: '#/components/schemas/errorResponse' + /participants/{idType}/{idValue}/{subIdValue}: + get: + summary: Asks for the FSPID of the scheme participant that can handle transfers for the specified identifier type, value and subId value + tags: + - Participants + parameters: + - name: idType + in: path + required: true + schema: + $ref: '#/components/schemas/idType' + - name: idValue + in: path + required: true + schema: + $ref: '#/components/schemas/idValue' + - name: subIdValue + in: path + required: true + schema: + $ref: '#/components/schemas/subIdValue' + responses: + 200: + description: Response containing details of the requested party + content: + application/json: + schema: + $ref: '#/components/schemas/participantsResponse' + 404: + description: The party specified by the provided identifier type and value/subId is not known to the server + 400: + description: Malformed or missing required headers or parameters + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + 500: + description: An error occured processing the request + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + /parties/{idType}/{idValue}: get: summary: Requests information relating to a transfer party identified by the specified identifier type and value @@ -90,6 +133,49 @@ paths: schema: $ref: '#/components/schemas/errorResponse' + /parties/{idType}/{idValue}/{subIdValue}: + get: + summary: Requests information relating to a transfer party identified by the specified identifier type, value and subId value + tags: + - Parties + parameters: + - name: idType + in: path + required: true + schema: + $ref: '#/components/schemas/idType' + - name: idValue + in: path + required: true + schema: + $ref: '#/components/schemas/idValue' + - name: subIdValue + in: path + required: true + schema: + $ref: '#/components/schemas/subIdValue' + responses: + 200: + description: Response containing details of the requested party + content: + application/json: + schema: + $ref: '#/components/schemas/transferParty' + 404: + description: The party specified by the provided identifier type and value is not known to the server + 400: + description: Malformed or missing required headers or parameters + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + 500: + description: An error occured processing the request + content: + application/json: + schema: + $ref: '#/components/schemas/errorResponse' + /quoterequests: post: summary: Requests a quote for the specified transfer @@ -664,6 +750,11 @@ components: minLength: 1 maxLength: 128 + subIdValue: + type: string + minLength: 1 + maxLength: 128 + money: pattern: ^([0]|([1-9][0-9]{0,17}))([.][0-9]{0,3}[1-9])?$ type: string @@ -715,6 +806,9 @@ components: idValue: type: string description: The identifier string used to identify the sender + subIdValue: + type: string + description: The sub identifier string used to identify the sender displayName: type: string description: Display name of the sender if known diff --git a/src/simulator/handlers.js b/src/simulator/handlers.js index 75371ec8..2b5046f6 100644 --- a/src/simulator/handlers.js +++ b/src/simulator/handlers.js @@ -32,8 +32,8 @@ const { ApiErrorCodes } = require('../models/errors.js'); const getParticipantsByTypeAndId = async (ctx) => { try { - const { idValue, idType } = ctx.state.path.params; - const res = await ctx.state.model.party.get(idType, idValue); + const { idValue, idType, subIdValue } = ctx.state.path.params; + const res = await ctx.state.model.party.get(idType, idValue, subIdValue); if (!res) { ctx.response.body = ApiErrorCodes.ID_NOT_FOUND; ctx.response.status = 404; @@ -50,8 +50,8 @@ const getParticipantsByTypeAndId = async (ctx) => { const getPartiesByTypeAndId = async (ctx) => { // TODO: check that the provided type was MSISDN? Or just encode that in the API spec.. try { - const { idValue, idType } = ctx.state.path.params; - const res = await ctx.state.model.party.get(idType, idValue); + const { idValue, idType, subIdValue } = ctx.state.path.params; + const res = await ctx.state.model.party.get(idType, idValue, subIdValue); if (!res) { ctx.response.body = ApiErrorCodes.ID_NOT_FOUND; ctx.response.status = 404; @@ -205,9 +205,15 @@ const map = { '/participants/{idType}/{idValue}': { get: getParticipantsByTypeAndId, }, + '/participants/{idType}/{idValue}/{subIdValue}': { + get: getParticipantsByTypeAndId, + }, '/parties/{idType}/{idValue}': { get: getPartiesByTypeAndId, }, + '/parties/{idType}/{idValue}/{subIdValue}': { + get: getPartiesByTypeAndId, + }, '/quoterequests': { post: postQuotes, }, diff --git a/src/test-api/api.yaml b/src/test-api/api.yaml index c09ef749..bea3f8f9 100644 --- a/src/test-api/api.yaml +++ b/src/test-api/api.yaml @@ -78,7 +78,62 @@ paths: description: Deletes a party responses: '204': - description: The party was created + description: The party was deleted + '500': + description: An error occured processing the request + parameters: + - name: idType + in: path + required: true + schema: + $ref: '#/components/schemas/idType' + - name: idValue + in: path + required: true + schema: + $ref: '#/components/schemas/idValue' + + /repository/parties/{idType}/{idValue}/{subIdValue}: + put: + description: Modifies a party (subId) + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Party' + responses: + '204': + description: Party was created + '400': + description: The request was malformed + '500': + description: An error occured processing the request + parameters: + - name: idType + in: path + required: true + schema: + $ref: '#/components/schemas/idType' + - name: idValue + in: path + required: true + schema: + $ref: '#/components/schemas/idValue' + - name: subIdValue + in: path + required: true + schema: + $ref: '#/components/schemas/subIdValue' + get: + description: Get an existing party + responses: + '200': + description: Party data is returned + delete: + description: Deletes a party + responses: + '204': + description: The party was deleted '500': description: An error occured processing the request parameters: @@ -92,6 +147,11 @@ paths: required: true schema: $ref: '#/components/schemas/idValue' + - name: subIdValue + in: path + required: true + schema: + $ref: '#/components/schemas/subIdValue' components: schemas: @@ -186,6 +246,10 @@ components: type: string minLength: 1 maxLength: 128 + subIdValue: + type: string + minLength: 1 + maxLength: 128 extensionList: $ref: '#/components/schemas/ExtensionList' Extension: @@ -223,3 +287,7 @@ components: type: string minLength: 1 maxLength: 128 + subIdValue: + type: string + minLength: 1 + maxLength: 128 diff --git a/src/test-api/handlers.js b/src/test-api/handlers.js index 497b58bf..b12e722c 100644 --- a/src/test-api/handlers.js +++ b/src/test-api/handlers.js @@ -76,13 +76,13 @@ const readParties = async (ctx) => { const readParty = async (ctx) => { try { - const { idValue, idType } = ctx.state.path.params; + const { idValue, idType, subIdValue } = ctx.state.path.params; if (!idValue || !idType) { ctx.response.body = ApiErrorCodes.MISSING_ID_VALUE; ctx.response.status = 400; return; } - const res = await ctx.state.model.party.get(idType, idValue); + const res = await ctx.state.model.party.get(idType, idValue, subIdValue); if (!res) { ctx.response.body = ''; ctx.response.status = 404; @@ -97,7 +97,7 @@ const readParty = async (ctx) => { }; const updateParty = async (ctx) => { - const { idValue, idType } = ctx.state.path.params; + const { idValue, idType, subIdValue } = ctx.state.path.params; const model = ctx.request.body; if (!idValue || !idType) { ctx.response.body = ApiErrorCodes.MISSING_ID_VALUE; @@ -106,7 +106,7 @@ const updateParty = async (ctx) => { } try { - await ctx.state.model.party.update(idType, idValue, model); + await ctx.state.model.party.update(model, idType, idValue, subIdValue); ctx.response.status = 204; return; } catch (err) { @@ -116,7 +116,7 @@ const updateParty = async (ctx) => { }; const deleteParty = async (ctx) => { - const { idValue, idType } = ctx.state.path.params; + const { idValue, idType, subIdValue } = ctx.state.path.params; if (!idValue || !idType) { ctx.response.body = ApiErrorCodes.MISSING_ID_VALUE; ctx.response.status = 500; @@ -124,7 +124,7 @@ const deleteParty = async (ctx) => { } try { - await ctx.state.model.party.delete(idType, idValue); + await ctx.state.model.party.delete(idType, idValue, subIdValue); ctx.response.status = 204; return; } catch (err) { @@ -240,6 +240,11 @@ const map = { delete: deleteParty, get: readParty, }, + '/repository/parties/{idType}/{idValue}/{subIdValue}': { + put: updateParty, + delete: deleteParty, + get: readParty, + }, }; diff --git a/src/test/constants.js b/src/test/constants.js index d346b72d..e50c3e23 100644 --- a/src/test/constants.js +++ b/src/test/constants.js @@ -36,6 +36,7 @@ const bulkTransferId = uuid(); const transactionRequestId = uuid(); const idType = 'msisdn'; const idValue = uuid(); +const subIdValue = uuid(); const currency = '$'; const amount = 100; const amountType = 'SEND'; @@ -51,6 +52,17 @@ const party = { idValue, }; +const partyWithSubIdValue = { + displayName: randName, + firstName: randName.split(' ')[0] || '', + middleName: randName.split(' ')[1] || '', + lastName: randName.split(' ')[2] || '', + dateOfBirth: '1970-01-01T00:00:00.000Z', + idType, + idValue, + subIdValue, +}; + const partyCreate = { displayName: randName, firstName: randName.split(' ')[0] || '', @@ -71,6 +83,27 @@ const partyCreate = { ], }; +const partyCreateWithSubIdValue = { + displayName: randName, + firstName: randName.split(' ')[0] || '', + middleName: randName.split(' ')[1] || '', + lastName: randName.split(' ')[2] || '', + dateOfBirth: '1970-01-01T00:00:00.000Z', + idType, + idValue, + subIdValue, + extensionList: [ + { + key: 'accountType', + value: 'Wallet', + }, + { + key: 'accountNumber', + value: '12345343', + }, + ], +}; + const quote = { quoteId: idValue, @@ -324,4 +357,7 @@ module.exports = { idType, idValue, transferId, + partyWithSubIdValue, + partyCreateWithSubIdValue, + subIdValue, }; diff --git a/src/test/model.js b/src/test/model.js index ec317d37..cbc821be 100644 --- a/src/test/model.js +++ b/src/test/model.js @@ -34,7 +34,7 @@ const { cloneDeep } = require('./unit/TestUtils'); const { transfer, quote, newQuote, bulkQuote, newBulkQuote, transactionrequest, party, newTransfer, bulkTransfer, newBulkTransfer, bulkTransferId, idType, idValue, partyCreate, transferId, - transactionRequestId, + transactionRequestId, partyWithSubIdValue, partyCreateWithSubIdValue, subIdValue, } = require('./constants'); test.beforeEach(async (t) => { @@ -69,6 +69,17 @@ test('create and retrieve all parties', async (t) => { t.pass(); }); +test('create and retrieve all parties with subIdValue', async (t) => { + const { model } = t.context; + + await model.party.create(partyCreateWithSubIdValue); + const res = await model.party.getAll(); + if (!res) { + t.fail('Result not found'); + } + t.pass(); +}); + test('create and retrieve all parties duplicates', async (t) => { const { model } = t.context; await model.party.create(partyCreate); @@ -91,6 +102,17 @@ test('create and retrieve a party', async (t) => { t.pass(); }); +test('create and retrieve a party with subIdValue', async (t) => { + const { model } = t.context; + + await model.party.create(partyCreateWithSubIdValue); + const res = await model.party.get(idType, idValue, subIdValue); + if (!res) { + t.fail('Result not found'); + } + t.pass(); +}); + test('create and update a party', async (t) => { const { model } = t.context; const newParty = { @@ -114,11 +136,77 @@ test('create and update a party', async (t) => { }; await model.party.create(partyCreate); const orig = await model.party.get(idType, idValue); - await model.party.update(idType, idValue, newParty); + await model.party.update(newParty, idType, idValue); const changed = await model.party.get(idType, idValue); t.notDeepEqual({ orig }, { changed }); }); +test('create and update a party without extensionList', async (t) => { + const { model } = t.context; + const newParty = { + displayName: 'randName', + firstName: 'hello', + middleName: 'world', + lastName: 'lambda', + dateOfBirth: '1970-01-01T00:00:00.000Z', + idType, + idValue, + }; + await model.party.create(partyCreate); + const orig = await model.party.get(idType, idValue); + await model.party.update(newParty, idType, idValue); + const changed = await model.party.get(idType, idValue); + t.notDeepEqual({ orig }, { changed }); +}); + +test('create and update a party with subIdValue', async (t) => { + const { model } = t.context; + const newParty = { + displayName: 'randName', + firstName: 'hello', + middleName: 'world', + lastName: 'lambda', + dateOfBirth: '1970-01-01T00:00:00.000Z', + idType, + idValue, + subIdValue, + extensionList: [ + { + key: 'accountType', + value: 'Wallet', + }, + { + key: 'accountNumber', + value: '12345343', + }, + ], + }; + await model.party.create(partyCreateWithSubIdValue); + const orig = await model.party.get(idType, idValue, subIdValue); + await model.party.update(newParty, idType, idValue, subIdValue); + const changed = await model.party.get(idType, idValue, subIdValue); + t.notDeepEqual({ orig }, { changed }); +}); + +test('create and update a party with subIdValue without extensionList', async (t) => { + const { model } = t.context; + const newParty = { + displayName: 'randName', + firstName: 'hello', + middleName: 'world', + lastName: 'lambda', + dateOfBirth: '1970-01-01T00:00:00.000Z', + idType, + idValue, + subIdValue, + }; + await model.party.create(partyWithSubIdValue); + const orig = await model.party.get(idType, idValue, subIdValue); + await model.party.update(newParty, idType, idValue, subIdValue); + const changed = await model.party.get(idType, idValue, subIdValue); + t.notDeepEqual({ orig }, { changed }); +}); + test('retrieve a participant', async (t) => { const { model } = t.context; await model.party.create(party); @@ -126,6 +214,13 @@ test('retrieve a participant', async (t) => { t.truthy(res); }); +test('retrieve a participant with subIdValue', async (t) => { + const { model } = t.context; + await model.party.create(partyWithSubIdValue); + const res = await model.party.get(idType, idValue, subIdValue); + t.truthy(res); +}); + test('create and delete a party', async (t) => { const { model } = t.context; await model.party.create(partyCreate); @@ -135,6 +230,15 @@ test('create and delete a party', async (t) => { t.is(deleted, undefined); }); +test('create and delete a party with subIdValue', async (t) => { + const { model } = t.context; + await model.party.create(partyCreateWithSubIdValue); + await model.party.get(idType, idValue, subIdValue); + await model.party.delete(idType, idValue, subIdValue); + const deleted = await model.party.get(idType, idValue, subIdValue); + t.is(deleted, undefined); +}); + test('should be undefined for non existing participant', async (t) => { const { model } = t.context; const res = await model.party.get('hello', '000000'); From 927aa208175ec27aed994d322325f09b615d6230 Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Mon, 28 Dec 2020 14:40:38 -0500 Subject: [PATCH 30/30] chore: fix merge issues --- src/models/constants.js | 6 +----- src/models/party.js | 12 ++++++------ src/simulator/handlers.js | 1 - src/test/constants.js | 21 --------------------- src/test/simulator.js | 2 +- 5 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/models/constants.js b/src/models/constants.js index 5e256062..657786b9 100644 --- a/src/models/constants.js +++ b/src/models/constants.js @@ -126,8 +126,7 @@ CREATE TABLE IF NOT EXISTS ${partyAccountsTable} ( address TEXT NOT NULL PRIMARY KEY, currency TEXT NOT NULL, description TEXT NOT NULL, - idValue TEXT NOT NULL, - FOREIGN KEY (idValue) REFERENCES party(idValue) ON DELETE CASCADE + idValue TEXT NOT NULL ) `; @@ -143,11 +142,8 @@ module.exports = { createQuoteTable, createBulkQuoteTable, createBulkTransferTable, - createTransferTable, createTransactionRequestTable, createTransferTable, - transferTable, - partyExtensionTable, createPartyExtensionTable, createPartyTableUniqueIndex, createPartyExtensionTableUniqueIndex, diff --git a/src/models/party.js b/src/models/party.js index b4af3874..56faa934 100644 --- a/src/models/party.js +++ b/src/models/party.js @@ -55,16 +55,16 @@ module.exports = class Party { let res; if (!subIdValue) { res = await this.db.all(` - SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, p.subIdValue, pe.key, pe.value, pa.address, pa.currency, pa.description - FROM ${partyTable} p - LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue + SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, p.subIdValue, pe.key, pe.value, pa.address, pa.currency, pa.description + FROM ${partyTable} p + LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue LEFT JOIN ${partyAccountsTable} pa ON p.idValue = pa.idValue WHERE p.idType = ? AND p.idValue = ? AND p.subIdValue IS NULL AND pe.subIdValue IS NULL`, [idType, idValue]); } else { res = await this.db.all(` - SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, p.subIdValue, pe.key, pe.value, pa.address, pa.currency, pa.description - FROM ${partyTable} p - LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue AND p.subIdValue = pe.subIdValue + SELECT p.displayName, p.firstName, p.middleName, p.lastName, p.dateOfBirth, p.idType, p.idValue, p.subIdValue, pe.key, pe.value, pa.address, pa.currency, pa.description + FROM ${partyTable} p + LEFT JOIN ${partyExtensionTable} pe ON p.idValue = pe.idValue AND p.subIdValue = pe.subIdValue LEFT JOIN ${partyAccountsTable} pa ON p.idValue = pa.idValue WHERE p.idType = ? AND p.idValue = ? AND p.subIdValue = ?`, [idType, idValue, subIdValue]); } diff --git a/src/simulator/handlers.js b/src/simulator/handlers.js index f67f3113..90088afe 100644 --- a/src/simulator/handlers.js +++ b/src/simulator/handlers.js @@ -254,7 +254,6 @@ const map = { '/bulkTransfers/{idValue}': { get: getBulkTransferById, }, - }, '/signchallenge': { post: getSignedChallenge, }, diff --git a/src/test/constants.js b/src/test/constants.js index bc685d54..9ad9da8e 100644 --- a/src/test/constants.js +++ b/src/test/constants.js @@ -309,27 +309,6 @@ const transfer = { transactionType, }; -const newQuote = { - quoteId: uuid(), - transactionId: uuid(), - to: { - idType: 'MSISDN', - idValue: '0012345', - }, - from: { - idType: 'MSISDN', - idValue: '0067890', - }, - amountType: 'SEND', - amount: '100', - currency: 'USD', - feesAmount: '0.5', - feesCurrency: 'USD', - transactionType: 'TRANSFER', - initiator: 'PAYER', - initiatorType: 'CONSUMER', -}; - const newTransfer = { transferId: uuid(), quote: { diff --git a/src/test/simulator.js b/src/test/simulator.js index f5b19e58..c2ad12ef 100644 --- a/src/test/simulator.js +++ b/src/test/simulator.js @@ -31,7 +31,7 @@ const Model = require('../models/model'); const { map } = require('../simulator/handlers'); const { transfer, transferWithoutQuote, quote, transactionrequest, party, idType, idValue, - transactionRequestId, authorizationRequest, + transactionRequestId, bulkQuote, bulkTransfer, bulkTransferId, authorizationRequest, } = require('./constants'); const { ApiErrorCodes } = require('../models/errors');