diff --git a/.circleci/config.yml b/.circleci/config.yml index ebbe97cc..7e86ee10 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,6 +3,8 @@ version: 2.1 orbs: anchore: anchore/anchore-engine@1.6.0 +# TODO: Further evaluate what changes need to be pulled from master. +# File has not been updated to v11.3.0 ## # defaults # 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 e47ab085..951bbeda 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,9 @@ simulator.log # environments docker-compose.local.yml goldenpayerfsp -goldenpayeefsp \ No newline at end of file +goldenpayeefsp + +#vscode configs +.vscode/ +/init/.DS_Store +/.DS_Store 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). 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 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: {} 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..920f0099 --- /dev/null +++ b/init/onboard-central-ledger/onboard-dfsp.js @@ -0,0 +1,464 @@ +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: 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: 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 dfspCallbackUrl = process.env.DFSP_CALLBACK_URL; +const dfspCurrency = process.env.DFSP_CURRENCY; +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, + 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, + 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, + 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, + 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, + authToken, + hostCentralLedger, + 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, + authToken, + hostCentralLedger, + 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, + authToken, + hostCentralLedger, + 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, + authToken, + hostCentralLedger, + 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, + authToken, + hostCentralLedger, + 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, + authToken, + hostCentralLedger, + 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, + authToken, + hostCentralLedger, + 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, + 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, + 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, + authToken, + hostCentralLedger, + 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, + authToken, + hostCentralLedger, + 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, + 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, + 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, + 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..03bd694f --- /dev/null +++ b/init/onboard-central-ledger/package-lock.json @@ -0,0 +1,1751 @@ +{ + "name": "onboard-central-ledger", + "version": "11.0.3", + "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.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", + "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.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", + "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..d8355a86 --- /dev/null +++ b/init/onboard-central-ledger/package.json @@ -0,0 +1,24 @@ +{ + "name": "onboard-central-ledger", + "version": "11.0.3", + "description": "", + "main": "onboard-dfsp.js", + "dependencies": { + "@mojaloop/finance-portal-lib": "0.0.19-snapshot", + "node-fetch": "^2.6.1", + "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-hub-accounts/Dockerfile b/init/onboard-hub-accounts/Dockerfile new file mode 100644 index 00000000..aeb3611c --- /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-accounts.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..c10418a4 --- /dev/null +++ b/init/onboard-hub-accounts/package-lock.json @@ -0,0 +1,1751 @@ +{ + "name": "onboard-hub-accounts", + "version": "11.0.3", + "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.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", + "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..78860b15 --- /dev/null +++ b/init/onboard-hub-accounts/package.json @@ -0,0 +1,24 @@ +{ + "name": "onboard-hub-accounts", + "version": "11.0.3", + "description": "", + "main": "onboard-hub-accounts.js", + "dependencies": { + "@mojaloop/finance-portal-lib": "0.0.20-snapshot", + "node-fetch": "^2.6.1", + "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" +} 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..2daf8a1e --- /dev/null +++ b/init/onboard-msisdn-oracle/insert_msisdns.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env sh + +set -eux + +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 82d269f5..b94cd3e0 100644 --- a/src/audit-resolve.json +++ b/src/audit-resolve.json @@ -1,317 +1,41 @@ { "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": 1602252044897, - "expiresAt": 1604844018565 - }, "1500|npm-audit-resolver>audit-resolve-core>yargs-parser": { "decision": "ignore", - "madeAt": 1602252039657, - "expiresAt": 1604844018565 - }, - "1523|ava>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|eslint>inquirer>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|eslint>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|eslint>table>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|npm-audit-resolver>yargs-unparser>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/generator>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>@babel/generator>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>@babel/generator>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>@babel/generator>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>@babel/generator>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-module-imports>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/helper-member-expression-to-functions>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/helper-optimise-call-expression>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>@babel/helper-function-name>@babel/helper-get-function-arity>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>@babel/helper-function-name>@babel/helper-get-function-arity>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>@babel/helper-function-name>@babel/helper-get-function-arity>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>@babel/helper-function-name>@babel/helper-get-function-arity>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>@babel/helper-function-name>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>@babel/helper-function-name>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>@babel/helper-function-name>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>@babel/helper-function-name>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-simple-access>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/template>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>@babel/helper-function-name>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>@babel/helper-function-name>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>@babel/helper-function-name>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>@babel/helper-function-name>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>@babel/helper-split-export-declaration>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>@babel/helper-split-export-declaration>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>@babel/helper-split-export-declaration>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>@babel/helper-split-export-declaration>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-split-export-declaration>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-simple-access>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/types>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/generator>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>@babel/generator>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>@babel/generator>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>@babel/generator>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>@babel/generator>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>@babel/helper-replace-supers>@babel/traverse>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 - }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helpers>@babel/traverse>lodash": { - "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 + "madeAt": 1594258444388, + "expiresAt": 1594863234907 }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/traverse>lodash": { + "1589|sqlite>sqlite3>node-pre-gyp>rc>ini": { "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 + "madeAt": 1607553157718, + "expiresAt": 1610145105148 }, - "1523|nyc>istanbul-lib-instrument>@babel/traverse>lodash": { + "1589|00unidentified>sqlite>sqlite3>node-pre-gyp>rc>ini": { "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 + "madeAt": 1607553157718, + "expiresAt": 1610145105148 }, - "1523|nyc>istanbul-lib-instrument>@babel/core>@babel/helper-module-transforms>lodash": { + "1589|00unidentified>00unidentified>sqlite>sqlite3>node-pre-gyp>rc>ini": { "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 + "madeAt": 1607553157718, + "expiresAt": 1610145105148 }, - "1523|nyc>istanbul-lib-instrument>@babel/core>lodash": { + "1589|ava>update-notifier>latest-version>package-json>registry-auth-token>rc>ini": { "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 + "madeAt": 1607553157718, + "expiresAt": 1610145105148 }, - "1523|tap-xunit>xmlbuilder>lodash": { + "1589|ava>update-notifier>latest-version>package-json>registry-url>rc>ini": { "decision": "ignore", - "madeAt": 1602252048123, - "expiresAt": 1604844018565 + "madeAt": 1607553157718, + "expiresAt": 1610145105148 }, - "1556|node-fetch": { + "1589|ava>update-notifier>is-installed-globally>global-dirs>ini": { "decision": "ignore", - "madeAt": 1602252035571, - "expiresAt": 1604844018565 + "madeAt": 1607553157718, + "expiresAt": 1610145105148 } }, "rules": {}, "version": 1 -} \ No newline at end of file +} diff --git a/src/config.js b/src/config.js index 1e809764..8b501280 100644 --- a/src/config.js +++ b/src/config.js @@ -52,6 +52,12 @@ const config = { key: null, }, }, + ports: { + simulatorApi: 3000, + reportApi: 3002, + testApi: 3003, + }, + parties: [], }; @@ -70,6 +76,10 @@ 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; + config.parties = cfg.PARTIES ? JSON.parse(cfg.PARTIES) : config.parties; }; diff --git a/src/index.js b/src/index.js index 6d490b77..76958278 100644 --- a/src/index.js +++ b/src/index.js @@ -19,6 +19,9 @@ - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; @@ -85,6 +88,7 @@ async function rewriteContentTypeHeader(ctx, next) { (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); @@ -102,7 +106,7 @@ async function rewriteContentTypeHeader(ctx, next) { // 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) => { @@ -280,10 +284,9 @@ async function rewriteContentTypeHeader(ctx, next) { // 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..7e3e64d5 --- /dev/null +++ b/src/models/bulkTransfer.js @@ -0,0 +1,103 @@ +/***** + 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 }; + response.individualTransferResults = bulkTransferRequest.individualTransfers.map( + (transfer) => ({ transferId: transfer.transferId }), + ); + 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 45bb3a1a..657786b9 100644 --- a/src/models/constants.js +++ b/src/models/constants.js @@ -27,6 +27,8 @@ const partyTable = 'party'; const quoteTable = 'quote'; const transactionRequestTable = 'transactionRequest'; const transferTable = 'transfer'; +const bulkQuoteTable = 'bulkQuote'; +const bulkTransferTable = 'bulkTransfer'; const partyExtensionTable = 'partyExtension'; const createPartyTable = ` @@ -37,19 +39,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, @@ -60,6 +83,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, @@ -79,27 +112,41 @@ 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 <> '') +) +`; + const createAccountTable = ` 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 ) `; module.exports = { partyTable, quoteTable, + bulkQuoteTable, + transferTable, + bulkTransferTable, transactionRequestTable, + partyExtensionTable, createPartyTable, createQuoteTable, + createBulkQuoteTable, + createBulkTransferTable, createTransactionRequestTable, createTransferTable, - transferTable, - partyExtensionTable, createPartyExtensionTable, + createPartyTableUniqueIndex, + createPartyExtensionTableUniqueIndex, partyAccountsTable, createAccountTable, }; diff --git a/src/models/model.js b/src/models/model.js index 5c659e59..445d20f1 100644 --- a/src/models/model.js +++ b/src/models/model.js @@ -31,15 +31,21 @@ 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, + createPartyTableUniqueIndex, createQuoteTable, + createBulkQuoteTable, + createTransferTable, + createBulkTransferTable, createTransactionRequestTable, createPartyExtensionTable, + createPartyExtensionTableUniqueIndex, createAccountTable, } = require('./constants'); @@ -55,8 +61,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; } /** @@ -74,30 +82,37 @@ 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) { + async init({ databaseFilepath, parties }) { if (this.db) { 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(createAccountTable); + 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); + await this.db.run(createAccountTable); + + 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.transactionrequest = new TransactionRequest(this.db); - this.transfer = new Transfer(this.db); - } catch (err) { - throw new Error(err); + if (parties) { + await Promise.all(parties.map((p) => this.party.create(p))); } } }; diff --git a/src/models/party.js b/src/models/party.js index 737f083b..56faa934 100644 --- a/src/models/party.js +++ b/src/models/party.js @@ -47,16 +47,27 @@ 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, 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 = ?`, [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, 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 + LEFT JOIN ${partyAccountsTable} pa ON p.idValue = pa.idValue + WHERE p.idType = ? AND p.idValue = ? AND p.subIdValue = ?`, [idType, idValue, subIdValue]); + } const resultMap = {}; res.forEach((row) => { let party; @@ -72,6 +83,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) { @@ -105,15 +119,15 @@ module.exports = class Party { */ 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, 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`); + 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 pe.subIdValue IS NULL AND p.subIdValue IS NULL) OR (p.idValue = pe.idValue AND p.subIdValue = pe.subIdValue) + LEFT JOIN ${partyAccountsTable} pa ON p.idValue = pa.idValue`); 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, @@ -124,7 +138,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) { @@ -155,19 +172,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]); }); } if (party.accounts) { @@ -183,46 +198,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 (newParty.accounts) { - const { accounts } = newParty; - await Promise.all(accounts.map(async (account) => this.db.run(` - INSERT OR IGNORE INTO ${partyAccountsTable} (idValue, address, currency, description) - VALUES (?, ?, ?, ?);`, - [idValue, account.address, account.currency, account.description]))); + 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]); + }); + } } } @@ -231,8 +277,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/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-lock.json b/src/package-lock.json index fbc978a6..f74dde54 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "mojaloop-simulator", - "version": "9.4.1", + "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,49 +746,25 @@ "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.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 +775,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" } } } @@ -911,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", @@ -1106,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", @@ -1358,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", @@ -1574,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", @@ -1592,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" } @@ -1728,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", @@ -1811,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", @@ -2313,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", @@ -2323,26 +2231,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", - "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", @@ -2354,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", @@ -2556,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", @@ -2660,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", @@ -2755,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", @@ -2849,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": { @@ -2858,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": { @@ -3050,12 +2907,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", @@ -3125,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", @@ -3214,12 +3065,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", @@ -3238,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", @@ -3277,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", @@ -3461,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", @@ -3496,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", @@ -3512,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", @@ -3532,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", @@ -3649,15 +3474,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", @@ -3697,9 +3513,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 }, "lodash.clonedeep": { @@ -3815,15 +3631,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 +3668,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", @@ -3898,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": { @@ -3977,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", @@ -3988,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", @@ -4009,9 +3805,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", @@ -4245,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", @@ -4346,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", @@ -4409,17 +4208,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 +4228,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", @@ -4582,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", @@ -4713,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", @@ -4743,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", @@ -4756,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": { @@ -4980,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", @@ -5350,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": { @@ -5449,12 +5179,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", @@ -5738,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", @@ -5764,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", @@ -5852,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" } @@ -5876,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", @@ -5899,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", @@ -6187,33 +5880,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": "^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": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "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 +5946,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 +5977,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", diff --git a/src/package.json b/src/package.json index aa259586..dc0d5b85 100644 --- a/src/package.json +++ b/src/package.json @@ -1,12 +1,16 @@ { "name": "mojaloop-simulator", - "version": "9.4.1", + "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", "author": "Matt Kingston, ModusBox Inc.", "contributors": [ + "Aaron Reynoza ", + "Kamuela Franco ", "Matt Kingston ", + "Steven Oderayi ", + "Valentin Genev ", "ModusBox", "Mowali" ], @@ -48,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" }, 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 716ca5a0..6908aaf3 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 @@ -183,6 +269,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 @@ -215,6 +326,135 @@ 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' + /signchallenge: post: @@ -1062,6 +1302,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 @@ -1113,6 +1358,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 @@ -1130,6 +1378,225 @@ 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 + - 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 + - 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 @@ -1147,6 +1614,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})?))$ @@ -1161,6 +1629,59 @@ 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 AuthenticationInfo: title: AuthenticationInfo diff --git a/src/simulator/handlers.js b/src/simulator/handlers.js index 69cfb5ff..90088afe 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'; @@ -31,8 +34,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 +53,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; @@ -106,6 +109,21 @@ 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 { @@ -120,6 +138,36 @@ 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); @@ -133,6 +181,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; @@ -147,24 +224,45 @@ 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, }, + '/bulkQuotes': { + post: postBulkQuotes, + }, + '/bulkQuotes/{idValue}': { + get: getBulkQuoteById, + }, '/transactionrequests': { post: postTransactionRequests, }, '/transfers': { post: postTransfers, }, + '/bulkTransfers': { + post: postBulkTransfers, + }, + '/bulkTransfers/{idValue}': { + get: getBulkTransferById, + }, '/signchallenge': { post: getSignedChallenge, }, '/otp/{requestToPayId}': { get: getOTPById, }, + '/transfers/{transferId}': { + put: putTransfersById, + }, }; diff --git a/src/test-api/api.yaml b/src/test-api/api.yaml index 07e3c860..23c1f1d6 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,13 +147,18 @@ paths: required: true schema: $ref: '#/components/schemas/idValue' + - name: subIdValue + in: path + required: true + schema: + $ref: '#/components/schemas/subIdValue' components: schemas: 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 +171,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 +182,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 @@ -171,6 +246,10 @@ components: type: string minLength: 1 maxLength: 128 + subIdValue: + type: string + minLength: 1 + maxLength: 128 extensionList: $ref: '#/components/schemas/ExtensionList' accounts: @@ -234,3 +313,7 @@ components: type: string minLength: 1 maxLength: 128 + subIdValue: + type: string + minLength: 1 + maxLength: 128 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..b12e722c 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', }; @@ -70,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; @@ -91,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; @@ -100,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) { @@ -110,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; @@ -118,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) { @@ -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)}`); @@ -222,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/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/constants.js b/src/test/constants.js index 1df368b4..9ad9da8e 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,9 +32,11 @@ 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(); +const subIdValue = uuid(); const currency = '$'; const amount = 100; const amountType = 'SEND'; @@ -46,6 +51,18 @@ const party = { idType, 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] || '', @@ -78,6 +95,39 @@ 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', + }, + ], + accounts: [ + { + currency: 'USD', + description: 'savings', + address: 'moja.green.e1f3c3e0-a00f-49b6-a331-280fdd1b2c32', + }, + { + currency: 'USD', + description: 'checking', + address: 'moja.green.6de1a4af-faca-4f08-ac21-f5e3a5203f49', + }, + ], +}; + const quote = { quoteId: idValue, @@ -100,6 +150,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: { @@ -186,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: { @@ -229,6 +331,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, @@ -243,16 +409,24 @@ 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, + partyWithSubIdValue, + partyCreateWithSubIdValue, + subIdValue, authorizationRequest, - transactionRequestId, }; diff --git a/src/test/model.js b/src/test/model.js index dcb55242..d73abf92 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,14 +28,18 @@ 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, partyWithSubIdValue, partyCreateWithSubIdValue, subIdValue, } = 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 = { model }; }); @@ -61,6 +68,18 @@ 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); @@ -83,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 = { @@ -118,11 +148,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); @@ -130,6 +226,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); @@ -139,6 +242,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'); @@ -226,6 +338,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(); @@ -261,6 +444,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(); @@ -298,7 +511,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 4851fa28..c2ad12ef 100644 --- a/src/test/simulator.js +++ b/src/test/simulator.js @@ -18,24 +18,27 @@ * 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, authorizationRequest, + transactionRequestId, bulkQuote, bulkTransfer, bulkTransferId, authorizationRequest, } = require('./constants'); 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: {}, @@ -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 }; @@ -139,6 +176,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' } }; @@ -147,6 +200,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 @@ -184,3 +254,41 @@ 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(); +}); + +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(); +}); diff --git a/src/test/test-api.js b/src/test/test-api.js index eb79232c..3cc5ec4b 100644 --- a/src/test/test-api.js +++ b/src/test/test-api.js @@ -18,49 +18,124 @@ * Gates Foundation - Name Surname * Mowali + + * ModusBox + - Steven Oderayi -------------- ******/ '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'); -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', + }, + ], + }, }, -}]; + +]; + +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: {} }; }); @@ -69,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); @@ -121,20 +202,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..53311612 100644 --- a/src/test/unit/config.test.js +++ b/src/test/unit/config.test.js @@ -19,13 +19,16 @@ - Name Surname * Vessels Tech - Lewis Daly + + * ModusBox + - Steven Oderayi -------------- ******/ 'use strict'; 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 @@ -36,14 +39,20 @@ 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 }, }, + ports: { + simulatorApi: 3000, + reportApi: 3002, + testApi: 3003, + }, + parties: [party, party, party], }; // Act