From 0d2ce43af6ebe059cc6c03c90aba95a2e6596de1 Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Thu, 30 Jan 2025 14:28:44 +0100 Subject: [PATCH 01/13] Upgrade to node version 20.18.2 --- .node-version | 2 +- .nvmrc | 2 +- Dockerfile | 4 +- package.json | 10 +- .../newMessagesService.test.ts.snap | 6 +- .../__tests__/redisSessionStorage.test.ts | 4 +- .../__snapshots__/barcode.test.ts.snap | 2 +- yarn.lock | 1517 +++-------------- 8 files changed, 233 insertions(+), 1314 deletions(-) diff --git a/.node-version b/.node-version index d939939b2..0254b1e63 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -18.13.0 +20.18.2 diff --git a/.nvmrc b/.nvmrc index d939939b2..0254b1e63 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18.13.0 +20.18.2 diff --git a/Dockerfile b/Dockerfile index 9c6df6979..4a1eb4c8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18.13.0 as builder +FROM node:20.18.2 as builder WORKDIR /usr/src/app @@ -7,7 +7,7 @@ COPY / /usr/src/app/ RUN yarn install \ && yarn predeploy -FROM node:18.13.0-alpine +FROM node:20.18.2-alpine LABEL maintainer="https://pagopa.gov.it" # Install major CA certificates to cover diff --git a/package.json b/package.json index 653c8b159..606bbda91 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "description": "IO app and web backend", "main": "index.js", "engines": { - "node": "18.13.0" + "node": "20.18.2" }, "scripts": { "watch": "tsc -w", @@ -88,9 +88,9 @@ "@azure/storage-queue": "^12.0.0", "@pagopa/io-functions-app-sdk": "x", "@pagopa/io-functions-cgn-sdk": "x", - "@pagopa/io-functions-commons": "^29.1.1", + "@pagopa/io-functions-commons": "^29.3.0", "@pagopa/io-functions-eucovidcerts-sdk": "x", - "@pagopa/ts-commons": "^12.4.1", + "@pagopa/ts-commons": "^13.1.2", "@pagopa/winston-ts": "^2.2.0", "applicationinsights": "1.8.10", "body-parser": "^1.19.2", @@ -123,7 +123,7 @@ "winston": "^3.3.3" }, "devDependencies": { - "@pagopa/eslint-config": "^3.0.0", + "@pagopa/eslint-config": "^4.0.0", "@pagopa/openapi-codegen-ts": "^14.0.0", "@types/dotenv": "^4.0.2", "@types/express": "4.17.11", @@ -134,7 +134,7 @@ "@types/jsonwebtoken": "7.2.7", "@types/lolex": "2.1.3", "@types/morgan": "^1.7.35", - "@types/node": "~18.13.0", + "@types/node": "^20.17.0", "@types/node-fetch": "^2.1.2", "@types/passport": "^1.0.2", "@types/passport-http-bearer": "^1.0.34", diff --git a/src/services/__tests__/__snapshots__/newMessagesService.test.ts.snap b/src/services/__tests__/__snapshots__/newMessagesService.test.ts.snap index 9b39bd987..3d8f3438a 100644 --- a/src/services/__tests__/__snapshots__/newMessagesService.test.ts.snap +++ b/src/services/__tests__/__snapshots__/newMessagesService.test.ts.snap @@ -8,7 +8,7 @@ exports[`MessageService#getMessage returns a message with attachments from the A "content": { "attachments": [ { - "content": "iVBORw0KGgoAAAANSUhEUgAAAJ4AAACRCAYAAAAy0wGuAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAESklEQVR4nO3SQQ6CQAAEwf3/p/XkhTiBih6bxAO4TBnT55zzunw+1/X++ny9t95/el53f3XVV+fp3t3u3bn1vf6uf/1ft7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53C+3L+DTYPJVQMuVIVAAAAAElFTkSuQmCC", + "content": "iVBORw0KGgoAAAANSUhEUgAAAJ4AAACRCAYAAAAy0wGuAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAESUlEQVR4nO3SQQrCQAAEwf3/p/XkJTgkRa4teDDsTkXoc875XL6/z/X39fm6t+4/Pa+7b1311Xm6d7d7d07/z9v3fbo/dwvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoX35/wXNg8lVCPRV3IAAAAASUVORK5CYII=", "mime_type": "image/png", "name": "iup", }, @@ -18,7 +18,7 @@ exports[`MessageService#getMessage returns a message with attachments from the A "name": "iup", }, { - "content": "iVBORw0KGgoAAAANSUhEUgAAAJ4AAACRCAYAAAAy0wGuAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAESklEQVR4nO3SQQ6CQAAEwf3/p/XkhTiBih6bxAO4TBnT55zzunw+1/X++ny9t95/el53f3XVV+fp3t3u3bn1vf6uf/1ft7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53CG7uFZ746hTd2C898dQpv7Bae+eoU3tgtPPPVKbyxW3jmq1N4Y7fwzFen8MZu4ZmvTuGN3cIzX53C+3L+DTYPJVQMuVIVAAAAAElFTkSuQmCC", + "content": "iVBORw0KGgoAAAANSUhEUgAAAJ4AAACRCAYAAAAy0wGuAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAESUlEQVR4nO3SQQrCQAAEwf3/p/XkJTgkRa4teDDsTkXoc875XL6/z/X39fm6t+4/Pa+7b1311Xm6d7d7d07/z9v3fbo/dwvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoU3dgvPfHUKb+wWnvnqFN7YLTzz1Sm8sVt45qtTeGO38MxXp/DGbuGZr07hjd3CM1+dwhu7hWe+OoX35/wXNg8lVCPRV3IAAAAASUVORK5CYII=", "mime_type": "image/png", "name": "nre", }, @@ -28,7 +28,7 @@ exports[`MessageService#getMessage returns a message with attachments from the A "name": "nre", }, { - "content": "iVBORw0KGgoAAAANSUhEUgAAAaYAAACRCAYAAACIeRyiAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAgR0lEQVR4nN2TsY5jMQwD9/9/+q66ZnEENdK4eQZSJA5HtCT+/Pz8/Pn1+Xd+f2+/p/8lLq1L9dP7VLdxmq8pt/Gm96/8Up099/aeqY7OYTsn653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzqL3KtwTdjW8ONaw1sG9wrt/Gm96/8Up0992mAms4ObqpvvZP6on2i9dKx9qXpaB+3vK/t2TVXlEv9Ra41+GZsa7hxrYFtg3vlNt70/pVfqrPnPg1Q09nBTfWtd1JftE+0XjrWvjQd7eOW97U9u+aKcqm/yLUG34xtDTeuNbBtcK/cxpvev/JLdfbcpwFqOju4qb71TuqL9onWS8fal6ajfdzyvrZn11xRLvUXudbgm7Gt4ca1BrYN7pXbeNP7V36pzp77NEBNZwc31bfeSX3RPtF66Vj70nS0j1ve1/bsmivKpf4i1xp8M7Y13LjWwLbBvXIbb3r/yi/V2XOfBqjp7OCm+tY7qS/aJ1ovHWtfmo72ccv72p5dc0W51F/kWoNvxraGG9ca2Da4V27jTe9f+aU6e+7TADWdHdxU33on9UX7ROulY+1L09E+bnlf27NrriiX+otca/DN2NZw41oD2wb3ym286f0rv1Rnz30aoKazg5vqW++kvmifaL10rH1pOtrHLe9re3bNFeVSf5FrDb4Z2xpuXGtg2+BeuY03vX/ll+rsuU8D1HR2cFN9653UF+0TrZeOtS9NR/u45X1tz665olzq77///wtjHGiDMWyXRgAAAABJRU5ErkJggg==", + "content": "iVBORw0KGgoAAAANSUhEUgAAAaYAAACRCAYAAACIeRyiAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAfgElEQVR4nN2TO44dQQwD9/6XtiMnCwtiUdXJGHBg9+NXw5+fn58/v/7++/P739v/T7+beKkuxafvk+7GQ/Nuv5v40vdXfinOvvuWJ8XRO7R3snJSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTfyGsdvg2W6lI8LbYd7pV340vfX/mlOPvu6YA2nD3cSd/KSX3Rnqhemt/22/bY8n3tO7vuivJSfyOvdfg2WKpL8bTYdrhX3o0vfX/ll+Lsu6cD2nD2cCd9Kyf1RXuieml+22/bY8v3te/suivKS/2NvNbh22CpLsXTYtvhXnk3vvT9lV+Ks++eDmjD2cOd9K2c1Bftieql+W2/bY8t39e+s+uuKC/1N/Jah2+DpboUT4tth3vl3fjS91d+Kc6+ezqgDWcPd9K3clJftCeql+a3/bY9tnxf+86uu6K81N/Iax2+DZbqUjwtth3ulXfjS99f+aU4++7pgDacPdxJ38pJfdGeqF6a3/bb9tjyfe07u+6K8lJ/I691+DZYqkvxtNh2uFfejS99f+WX4uy7pwPacPZwJ30rJ/VFe6J6aX7bb9tjy/e17+y6K8pL/Y281uHbYKkuxdNi2+FeeTe+9P2VX4qz754OaMPZw530rZzUF+2J6qX5bb9tjy3f176z664oL/U38lqHb4OluhRPi22He+Xd+NL3V34pzr57OqANZw930rdyUl+0J6qX5rf9tj22fF/7zq67orzU38hrHb4NlupSPC22He6Vd+NL31/5pTj77umANpw93Enfykl90Z6oXprf9tv22PJ97Tu77oryUn8jr3X4NliqS/G02Ha4V96NL31/5Zfi7LunA9pw9nAnfSsn9UV7onppfttv22PL97Xv7Lorykv9jbzW4dtgqS7F02Lb4V55N770/ZVfirPvng5ow9nDnfStnNQX7Ynqpfltv22PLd/XvrPrrigv9TfyWodvg6W6FE+LbYd75d340vdXfinOvns6oA1nD3fSt3JSX7Qnqpfmt/22PbZ8X/vOrruivNTff3//F2McaINzuy2FAAAAAElFTkSuQmCC", "mime_type": "image/png", "name": "prescriber_fiscal_code", }, diff --git a/src/services/__tests__/redisSessionStorage.test.ts b/src/services/__tests__/redisSessionStorage.test.ts index 1b5e06cdd..53a9e7b48 100644 --- a/src/services/__tests__/redisSessionStorage.test.ts +++ b/src/services/__tests__/redisSessionStorage.test.ts @@ -145,7 +145,7 @@ describe("RedisSessionStorage#getBySessionToken", () => { expect(mockGet).toHaveBeenCalledTimes(1); expect(mockGet).toHaveBeenCalledWith(`SESSION-${aValidUser.session_token}`); expect(response).toEqual( - E.left(new SyntaxError("Unexpected token I in JSON at position 0")) + E.left(new SyntaxError("Unexpected token 'I', \"Invalid JSON\" is not valid JSON")) ); }); @@ -225,7 +225,7 @@ describe("RedisSessionStorage#getByMyPortalToken", () => { `SESSION-${aValidUser.session_token}` ); expect(response).toEqual( - E.left(new SyntaxError("Unexpected token I in JSON at position 0")) + E.left(new SyntaxError("Unexpected token 'I', \"Invalid JSON\" is not valid JSON")) ); }); diff --git a/src/utils/__tests__/__snapshots__/barcode.test.ts.snap b/src/utils/__tests__/__snapshots__/barcode.test.ts.snap index c4fc34124..78b11e89e 100644 --- a/src/utils/__tests__/__snapshots__/barcode.test.ts.snap +++ b/src/utils/__tests__/__snapshots__/barcode.test.ts.snap @@ -2,7 +2,7 @@ exports[`Barcode generator should return a valid svg and png 1`] = ` { - "png": "iVBORw0KGgoAAAANSUhEUgAAAaYAAACRCAYAAACIeRyiAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAihUlEQVR4nL2TQW5dMQwDc/9Lt6sumgdiKIqygSxikeZ8POrn5+fnz6+/f+f3/3Q/1alceqflc38v5V69q3RtX8pL8zS35SPe6z6QL+Vx/e1cdVq9dHkoJ+3Rluuqv8Sl5ltOypnqqFcf3bSQBOTq0g/S8qUL+OpdpWv7Ul6atxZ0u9h0f9UH8qU8rr+dq06rly4P5aQ92nJd9Ze41HzLSTlTHfXqo5sWkoBcXfpBWr50AV+9q3RtX8pL89aCbheb7q/6QL6Ux/W3c9Vp9dLloZy0R1uuq/4Sl5pvOSlnqqNefXTTQhKQq0s/SMuXLuCrd5Wu7Ut5ad5a0O1i0/1VH8iX8rj+dq46rV66PJST9mjLddVf4lLzLSflTHXUq49uWkgCcnXpB2n50gV89a7StX0pL81bC7pdbLq/6gP5Uh7X385Vp9VLl4dy0h5tua76S1xqvuWknKmOevXRTQtJQK4u/SAtX7qAr95VurYv5aV5a0G3i033V30gX8rj+tu56rR66fJQTtqjLddVf4lLzbeclDPVUa8+umkhCcjVpR+k5UsX8NW7Stf2pbw0by3odrHp/qoP5Et5XH87V51WL10eykl7tOW66i9xqfmWk3KmOurVRzctJAG5uvSDtHzpAr56V+navpSX5q0F3S423V/1gXwpj+tv56rT6qXLQzlpj7ZcV/0lLjXfclLOVEe9+uimhSQgV5d+kJYvXcBX7ypd25fy0ry1oNvFpvurPpAv5XH97Vx1Wr10eSgn7dGW66q/xKXmW07KmeqoVx/dtJAE5OrSD9LypQv46l2la/tSXpq3FnS72HR/1QfypTyuv52rTquXLg/lpD3acl31l7jUfMtJOVMd9eqjmxaSgFxd+kFavnQBX72rdG1fykvz1oJuF5vur/pAvpTH9bdz1Wn10uWhnLRHW66r/hKXmm85KWeqo159dNNCEpCrSz9Iy5cu4Kt3la7tS3lp3lrQ7WLT/VUfyJfyuP52rjqtXro8lJP2aMt11V/iUvMtJ+VMddSrj25aSAJydekHafnSBXz1rtK1fSkvzVsLul1sur/qA/lSHtffzlWn1UuXh3LSHm25rvpLXGq+5aScqY569dFNC0lAri79IC1fuoCv3lW6ti/lpXlrQbeLTfdXfSBfyuP627nqtHrp8lBO2qMt11V/iUvNt5yUM9VRrz66aSEJyNWlH6TlSxfw1btK1/alvDRvLeh2sen+qg/kS3lcfztXnVYvXR7KSXu05brqL3Gp+ZaTcqY66tVHNy0kAbm69IO0fOkCvnpX6dq+lJfmrQXdLjbdX/WBfCmP62/nqtPqpctDOWmPtlxX/SUuNd9yUs5UR7366KaFJCBXl36Qli9dwFfvKl3bl/LSvLWg28Wm+6s+kC/lcf3tXHVavXR5KCft0Zbrqr/EpeZbTsqZ6qhXH920kATk6tIP0vKlC/jqXaVr+1JemrcWdLvYdH/VB/KlPK6/natOq5cuD+WkPdpyXfWXuNR8y0k5Ux316qObFpKAXF36QVq+dAFfvat0bV/KS/PWgm4Xm+6v+kC+lMf1t3PVafXS5aGctEdbrqv+EpeabzkpZ6qjXn1000ISkKtLP0jLly7gq3eVru1LeWneWtDtYtP9VR/Il/K4/nauOq1eujyUk/Zoy3XVX+JS8y0n5Ux11KuPblpIAnJ16Qdp+dIFfPWu0rV9KS/NWwu6XWy6v+oD+VIe19/OVafVS5eHctIebbmu+ktcar7lpJypjnr10U0LSUCuLv0gLV+6gK/eVbq2L+WleWtBt4tN91d9IF/K4/rbueq0eunyUE7aoy3XVX+JS823nJQz1VGvPrppIQnI1aUfpOVLF/DVu0rX9qW8NG8t6Hax6f6qD+RLeVx/O1edVi9dHspJe7Tluuovcan5lpNypjrq1Uc3LSQBubr0g7R86QK+elfp2r6Ul+atBd0uNt1f9YF8KY/rb+eq0+qly0M5aY+2XFf9JS4133JSzlRHvfropoUkIFeXfpCWL13AV+8qXduX8tK8taDbxab7qz6QL+Vx/e1cdVq9dHkoJ+3Rluuqv8Sl5ltOypnqqFcf3bSQBOTq0g/S8qUL+OpdpWv7Ul6atxZ0u9h0f9UH8qU8rr+dq06rly4P5aQ92nJd9Ze41HzLSTlTHfXqo5sWkoBcXfpBWr50AV+9q3RtX8pL89aCbheb7q/6QL6Ux/W3c9Vp9dLloZy0R1uuq/4Sl5pvOSlnqqNefXTTQhKQq0s/SMuXLuCrd5Wu7Ut5ad5a0O1i0/1VH8iX8rj+dq46rV66PJST9mjLddVf4lLzLSflTHXUq49uWkgCcnXpB2n50gV89a7StX0pL81bC7pdbLq/6gP5Uh7X385Vp9VLl4dy0h5tua76S1xqvuWknKmOevXRTQtJQK4u/SAtX7qAr95VurYv5aV5a0G3i033V30gX8rj+tu56rR66fJQTtqjLddVf4lLzbeclDPVUa8+umkhCcjVpR+k5UsX8NW7Stf2pbw0by3odrHp/qoP5Et5XH87V51WL10eykl7tOW66i9xqfmWk3KmOurVRzctJAG5uvSDtHzpAr56V+navpSX5q0F3S423V/1gXwpj+tv56rT6qXLQzlpj7ZcV/0lLjXfclLOVEe9+uimhSQgV5d+kJYvXcBX7ypd25fy0ry1oNvFpvurPpAv5XH97Vx1Wr10eSgn7dGW66q/xKXmW07KmeqoVx/dtJAE5OrSD9LypQv46l2la/tSXpq3FnS72HR/1QfypTyuv52rTquXLg/lpD3acl31l7jUfMtJOVMd9eqjmxaSgFxd+kFavnQBX72rdG1fykvz1oJuF5vur/pAvpTH9bdz1Wn10uWhnLRHW66r/hKXmm85KWeqo159dNNCEpCrSz9Iy5cu4Kt3la7tS3lp3lrQ7WLT/VUfyJfyuP52rjqtXro8lJP2aMt11V/iUvMtJ+VMddSrj25aSAJydekHafnSBXz1rtK1fSkvzVsLul1sur/qA/lSHtffzlWn1UuXh3LSHm25rvpLXGq+5aScqY569dFNC0lAri79IC1fuoCv3lW6ti/lpXlrQbeLTfdXfSBfyuP627nqtHrp8lBO2qMt11V/iUvNt5yUM9VRrz66aSEJyNWlH6TlSxfw1btK1/alvDRvLeh2sen+qg/kS3lcfztXnVYvXR7KSXu05brqL3Gp+ZaTcqY66tVHNy0kAbm69IO0fOkCvnpX6dq+lJfmrQXdLjbdX/WBfCmP62/nqtPqpctDOWmPtlxX/SUuNd9yUs5UR7366KaFJCBXl36Qli9dwFfvKl3bl/LSvLWg28Wm+6s+kC/lcf3tXHVavXR5KCft0Zbrqr/EpeZbTsqZ6qhXH920kATk6tIP0vKlC/jqXaVr+1JemrcWdLvYdH/VB/KlPK6/natOq5cuD+WkPdpyXfWXuNR8y0k5Ux316qObFpKAXF36QVq+dAFfvat0bV/KS/PWgm4Xm+6v+kC+lMf1t3PVafXS5aGctEdbrqv+EpeabzkpZ6qjXn1000ISkKtLP0jLly7gq3eVru1LeWneWtDtYtP9VR/Il/K4/nauOq1eujyUk/Zoy3XVX+JS8y0n5Ux11KuPblpIAnJ16Qdp+dIFfPWu0rV9KS/NWwu6XWy6v+oD+VIe19/OVafVS5eHctIebbmu+ktcar7lpJypjnr10U0LSUCuLv0gLV+6gK/eVbq2L+WleWtBt4tN91d9IF/K4/rbueq0eunyUE7aoy3XVX+JS823nJQz1VGvPrppIQnI1aUfpOVLF/DVu0rX9qW8NG8t6Hax6f6qD+RLeVx/O1edVi9dHspJe7Tluuovcan5lpNypjrq1Uc3LSQBubr0g7R86QK+elfp2r6Ul+atBd0uNt1f9YF8KY/rb+eq0+qly0M5aY+2XFf9JS4133JSzlRHvfropoUkIFeXfpCWL13AV+8qXduX8tK8taDbxab7qz6QL+Vx/e1cdVq9dHkoJ+3Rluuqv8Sl5ltOypnqqFcf3bSQBOTq0g/S8qUL+OpdpWv7Ul6atxZ0u9h0f9UH8qU8rr+dq06rly4P5aQ92nJd9Ze41HzLSTlTHfXqo5sWkoBcXfpBWr50AV+9q3RtX8pL89aCbheb7q/6QL6Ux/W3c9Vp9dLloZy0R1uuq/4Sl5pvOSlnqqNefXTTQhKQq0s/SMuXLuCrd5Wu7Ut5ad5a0O1i0/1VH8iX8rj+dq46rV66PJST9mjLddVf4lLzLSflTHXUq49uWkgCcnXpB2n50gV89a7StX0pL81bC7pdbLq/6gP5Uh7X385Vp9VLl4dy0h5tua76S1xqvuWknKmOevXRTQtJQK4u/SAtX7qAr95VurYv5aV5a0G3i033V30gX8rj+tu56rR66fJQTtqjLddVf4lLzbeclDPVUa8+umkhCcjVpR+k5UsX8NW7Stf2pbw0by3odrHp/qoP5Et5XH87V51WL10eykl7tOW66i9xqfmWk3KmOurVRzctJAG5uvSDtHzpAr56V+navpSX5q0F3S423V/1gXwpj+tv56rT6qXLQzlpj7ZcV/0lLjXfclLOVEe9+uimhSQgV5d+kJYvXcBX7ypd25fy0ry1oNvFpvurPpAv5XH97Vx1Wr10eSgn7dGW66q/xKXmW07KmeqoVx/dtJAE5OrSD9LypQv46l2la/tSXpq3FnS72HR/1QfypTyuv52rTquXLg/lpD3acl31l7jUfMtJOVMd9eqjmxaSgFxd+kFavnQBX72rdG1fykvz1oJuF5vur/pAvpTH9bdz1Wn10uWhnLRHW66r/hKXmm85KWeqo159dNNCEpCrSz9Iy5cu4Kt3la7tS3lp3lrQ7WLT/VUfyJfyuP52rjqtXro8lJP2aMt11V/iUvMtJ+VMddSrj25aSAJydekHafnSBXz1rtK1fSkvzVsLul1sur/qA/lSHtffzlWn1UuXh3LSHm25rvpLXGq+5aScqY569dFNC0lAri79IC1fuoCv3lW6ti/lpXlrQbeLTfdXfSBfyuP627nqtHrp8lBO2qMt11V/iUvNt5yUM9VRrz66aSEJyNWlH6TlSxfw1btK1/alvDRvLeh2sen+qg/kS3lcfztXnVYvXR7KSXu05brqL3Gp+ZaTcqY66tVHNy0kAbm69IO0fOkCvnpX6dq+lJfmrQXdLjbdX/WBfCmP62/nqtPqpctDOWmPtlxX/SUuNd9yUs5UR7366KaFJCBXl36Qli9dwFfvKl3bl/LSvLWg28Wm+6s+kC/lcf3tXHVavXR5KCft0Zbrqr/EpeZbTsqZ6qhXH920kATk6tIP0vKlC/jqXaVr+1JemrcWdLvYdH/VB/KlPK6/natOq5cuD+WkPdpyXfWXuNR8y0k5Ux316qObFpKAXF36QVq+dAFfvat0bV/KS/PWgm4Xm+6v+kC+lMf1t3PVafXS5aGctEdbrqv+EpeabzkpZ6qjXn1000ISkKtLP0jLly7gq3eVru1LeWneWtDtYtP9VR/Il/K4/nauOq1eujyUk/Zoy3XVX+JS8y0n5Ux11KuPblpIAnJ16Qdp+dIFfPWu0rV9KS/NWwu6XWy6v+oD+VIe19/OVafVS5eHctIebbmu+ktcar7lpJypjnr10U0LSUCuLv0gLV+6gK/eVbq2L+WleWtBt4tN91d9IF/K4/rbueq0eunyUE7aoy3XVX+JS823nJQz1VGvPrppIQnI1aUfpOVLF/DVu0rX9qW8NG8t6Hax6f6qD+RLeVx/O1edVi9dHspJe7Tluuovcan5lpNypjrq1Uc3LSQBubr0g7R86QK+elfp2r6Ul+atBd0uNt1f9YF8KY/rb+eq0+qly0M5aY+2XFf9JS4133JSzlRHvfropoUkIFeXfpCWL13AV+8qXduX8tK8taDbxab7qz6QL+Vx/e1cdVq9dHkoJ+3Rluuqv8Sl5ltOypnqqFcf3bSQBOTq0g/S8qUL+OpdpWv7Ul6atxZ0u9h0f9UH8qU8rr+dq06rly4P5aQ92nJd9Ze41HzLSTlTHfXqo5sWkoBcXfpBWr50AV+9q3RtX8pL89aCbheb7q/6QL6Ux/W3c9Vp9dLloZy0R1uuq/4Sl5pvOSlnqqNefXTTQhKQq0s/SMuXLuCrd5Wu7Ut5ad5a0O1i0/1VH8iX8rj+dq46rV66PJST9mjLddVf4lLzLSflTHXUq49uWkgCcnXpB2n50gV89a7StX0pL81bC7pdbLq/6gP5Uh7X385Vp9VLl4dy0h5tua76S1xqvuWknKmOevXRTQtJQK4u/SAtX7qAr95VurYv5aV5a0G3i033V30gX8rj+tu56rR66fJQTtqjLddVf4lLzbeclDPVUa8+umkhCcjVpR+k5UsX8NW7Stf2pbw0by3odrHp/qoP5Et5XH87V51WL10eykl7tOW66i9xqfmWk3KmOurVRzctJAG5uvSDtHzpAr56V+navpSX5q0F3S423V/1gXwpj+tv56rT6qXLQzlpj7ZcV/0lLjXfclLOVEe9+uimhSQgV5d+kJYvXcBX7ypd25fy0ry1oNvFpvurPpAv5XH97Vx1Wr10eSgn7dGW66q/xKXmW07KmeqoVx/dtJAE5OrSD9LypQv46l2la/tSXpq3FnS72HR/1QfypTyuv52rTquXLg/lpD3acl31l7jUfMtJOVMd9eqjmxaSgFxd+kFavnQBX72rdG1fykvz1oJuF5vur/pAvpTH9bdz1Wn10uWhnLRHW66r/hKXmm85KWeqo159dNNCEpCrSz9Iy5cu4Kt3la7tS3lp3lrQ7WLT/VUfyJfyuP52rjqtXro8lJP2aMt11V/iUvMtJ+VMddSrj25aSAJydekHafnSBXz1rtK1fSkvzVsLul1sur/qA/lSHtffzlWn1UuXh3LSHm25rvpLXGq+5aScqY569dFNC0lAri79IC1fuoCv3lW6ti/lpXlrQbeLTfdXfSBfyuP627nqtHrp8lBO2qMt11V/iUvNt5yUM9VRrz66aSEJyNWlH6TlSxfw1btK1/alvDRvLeh2sen+qg/kS3lcfztXnVYvXR7KSXu05brqL3Gp+ZaTcqY66tVHNy0kAbm69IO0fOkCvnpX6dq+lJfmrQXdLjbdX/WBfCmP62/nqtPqpctDOWmPtlxX/SUuNd9yUs5UR7366KaFJCBXl36Qli9dwFfvKl3bl/LSvLWg28Wm+6s+kC/lcf3tXHVavXR5KCft0Zbrqr/EpeZbTsqZ6qhXH920kATk6tIP0vKlC/jqXaVr+1JemrcWdLvYdH/VB/KlPK6/natOq5cuD+WkPdpyXfWXuNR8y0k5Ux316qObFpKAXF36QVq+dAFfvat0bV/KS/PWgm4Xm+6v+kC+lMf1t3PVafXS5aGctEdbrqv+EpeabzkpZ6qjXn1000ISkKtLP0jLly7gq3eVru1LeWneWtDtYtP9VR/Il/K4/nauOq1eujyUk/Zoy3XVX+JS8y0n5Ux11KuPblpIAnJ16Qdp+dIFfPWu0rV9KS/NWwu6XWy6v+oD+VIe19/OVafVS5eHctIebbmu+ktcar7lpJypjnr10U0LSUCuLv0gLV+6gK/eVbq2L+WleWtBt4tN91d9IF/K4/rbueq0eunyUE7aoy3XVX+JS823nJQz1VGvPrppIQnI1aUfpOVLF/DVu0rX9qW8NG8t6Hax6f6qD+RLeVx/O1edVi9dHspJe7Tluuovcan5lpNypjrq1Uc3LSQBubr0g7R86QK+elfp2r6Ul+atBd0uNt1f9YF8KY/rb+eq0+qly0M5aY+2XFf9JS4133JSzlRHvfropoUkIFeXfpCWL13AV+8qXduX8tK8taDbxab7qz6QL+Vx/e1cdVq9dHkoJ+3Rluuqv8Sl5ltOypnqqFcf3bSQBOTq0g/S8qUL+OpdpWv7Ul6atxZ0u9h0f9UH8qU8rr+dq06rly4P5aQ92nJd9Ze41HzLSTlTHfXqo5sWkoBcXfpBWr50AV+9q3RtX8pL89aCbheb7q/6QL6Ux/W3c9Vp9dLloZy0R1uuq/4Sl5pvOSlnqqNefXTTQhKQq0s/SMuXLuCrd5Wu7Ut5ad5a0O1i0/1VH8iX8rj+dq46rV66PJST9mjLddVf4lLzLSflTHXUq49uWkgCcnXpB2n50gV89a7StX0pL81bC7pdbLq/6gP5Uh7X385Vp9VLl4dy0h5tua76S1xqvuWknKmOevXRTQtJQK4u/SAtX7qAr95VurYv5aV5a0G3i033V30gX8rj+tu56rR66fJQTtqjLddVf4lLzbeclDPVUa8+umkhCcjVpR+k5UsX8NW7Stf2pbw0by3odrHp/qoP5Et5XH87V51WL10eykl7tOW66i9xqfmWk3KmOurVRzctJAG5uvSDtHzpAr56V+navpSX5q0F3S423V/1gXwpj+tv56rT6qXLQzlpj7ZcV/0lLjXfclLOVEe9+uimhSQgV5d+kJYvXcBX7ypd25fy0ry1oNvFpvurPpAv5XH97Vx1Wr10eSgn7dGW66q/xKXmW07KmeqoVx/dtJAE5OrSD9LypQv46l2la/tSXpq3FnS72HR/1QfypTyuv52rTquXLg/lpD3acl31l7jUfMtJOVMd9eqjmxaSgFxd+kFavnQBX72rdG1fykvz1oJuF5vur/pAvpTH9bdz1Wn10uWhnLRHW66r/hKXmm85KWeqo159dNNCEpCrSz9Iy5cu4Kt3la7tS3lp3lrQ7WLT/VUfyJfyuP52rjqtXro8lJP2aMt11V/iUvMtJ+VMddSrj25aSAJydekHafnSBXz1rtK1fSkvzVsLul1sur/qA/lSHtffzlWn1UuXh3LSHm25rvpLXGq+5aScqY569dFNC0lAri79IC1fuoCv3lW6ti/lpXlrQbeLTfdXfSBfyuP627nqtHrp8lBO2qMt11V/iUvNt5yUM9VRrz66aSEJyNWlH6TlSxfw1btK1/alvDRvLeh2sen+qg/kS3lcfztXnVYvXR7KSXu05brqL3Gp+ZaTcqY66tVHNy0kAbm69IO0fOkCvnpX6dq+lJfmrQXdLjbdX/WBfCmP62/nqtPqpctDOWmPtlxX/SUuNd9yUs5UR7366KaFJCBXl36Qli9dwFfvKl3bl/LSvLWg28Wm+6s+kC/lcf3tXHVavXR5KCft0Zbrqr/EpeZbTsqZ6qhXH920kATk6tIP0vKlC/jqXaVr+1JemrcWdLvYdH/VB/KlPK6/natOq5cuD+WkPdpyXfWXuNR8y0k5Ux316qObFpKAXF36QVq+dAFfvat0bV/KS/PWgm4Xm+6v+kC+lMf1t3PVafXS5aGctEdbrqv+EpeabzkpZ6qjXn1000ISkKtLP0jLly7gq3eVru1LeWneWtDtYtP9VR/Il/K4/nauOq1eujyUk/Zoy3XVX+JS8y0n5Ux11KuPblpIAnJ16Qdp+dIFfPWu0rV9KS/NWwu6XWy6v+oD+VIe19/OVafVS5eHctIebbmu+ktcar7lpJypjnr10U0LSUCuLv0gLV+6gK/eVbq2L+WleWtBt4tN91d9IF/K4/rbueq0eunyUE7aoy3XVX+JS823nJQz1VGvPrppIQnI1aUfpOVLF/DVu0rX9qW8NG8t6Hax6f6qD+RLeVx/O1edVi9dHspJe7Tluuovcan5lpNypjrq1Uc3LSQBubr0g7R86QK+elfp2r6Ul+atBd0uNt1f9YF8KY/rb+eq0+qly0M5aY+2XFf9JS4133JSzlRHvfropoUkIFeXfpCWL13AV+8qXduX8tK8taDbxab7qz6QL+Vx/e1cdVq9dHkoJ+3Rluuqv8Sl5ltOypnqqFcf3bSQBOTq0g/S8qUL+OpdpWv7Ul6atxZ0u9h0f9UH8qU8rr+dq06rly4P5aQ92nJd9Ze41HzLSTlTHfXqo5sWkoBcXfpBWr50AV+9q3RtX8pL89aCbheb7q/6QL6Ux/W3c9Vp9dLloZy0R1uuq/4Sl5pvOSlnqqNefXTTQhKQq0s/SMuXLuCrd5Wu7Ut5ad5a0O1i0/1VH8iX8rj+dq46rV66PJST9mjLddVf4lLzLSflTHXUq49uWkgCcnXpB2n50gV89a7StX0pL81bC7pdbLq/6gP5Uh7X385Vp9VLl4dy0h5tua76S1xqvuWknKmOevXRTQtJQK4u/SAtX7qAr95VurYv5aV5a0G3i033V30gX8rj+tu56rR66fJQTtqjLddVf4lLzbeclDPVUa8+umkhCcjVpR+k5UsX8NW7Stf2pbw0by3odrHp/qoP5Et5XH87V51WL10eykl7tOW66i9xqfmWk3KmOurVRzctJAG5uvSDtHzpAr56V+navpSX5q0F3S423V/1gXwpj+tv56rT6qXLQzlpj7ZcV/0lLjXfclLOVEe9+uimhSQgV5d+kJYvXcBX7ypd25fy0ry1oNvFpvurPpAv5XH97Vx1Wr10eSgn7dGW66q/xKXmW07KmeqoVx/dtJAE5OrSD9LypQv46l2la/tSXpq3FnS72HR/1QfypTyuv52rTquXLg/lpD3acl31l7jUfMtJOVMd9eqjmxaSgFxd+kFavnQBX72rdG1fykvz1oJuF5vur/pAvpTH9bdz1Wn10uWhnLRHW66r/hKXmm85KWeqo159dNNCEpCrSz9Iy5cu4Kt3la7tS3lp3lrQ7WLT/VUfyJfyuP52rjqtXro8lJP2aMt11V/iUvMtJ+VMddSrj25aSAJydekHafnSBXz1rtK1fSkvzVsLul1sur/qA/lSHtffzlWn1UuXh3LSHm25rvpLXGq+5aScqY569dFNC0lAri79IC1fuoCv3lW6ti/lpXlrQbeLTfdXfSBfyuP627nqtHrp8lBO2qMt11V/iUvNt5yUM9VRrz66aSEJyNWlH6TlSxfw1btK1/alvDRvLeh2sen+qg/kS3lcfztXnVYvXR7KSXu05brqL3Gp+ZaTcqY66tVHNy0kAbm69IO0fOkCvnpX6dq+lJfmrQXdLjbdX/WBfCmP62/nqtPqpctDOWmPtlxX/SUuNd9yUs5UR7366KaFJCBXl36Qli9dwFfvKl3bl/LSvLWg28Wm+6s+kC/lcf3tXHVavXR5KCft0Zbrqr/EpeZbTsqZ6qhXH920kATk6tIP0vKlC/jqXaVr+1JemrcWdLvYdH/VB/KlPK6/natOq5cuD+WkPdpyXfWXuNR8y0k5Ux316qObFpKAXF36QVq+dAFfvat0bV/KS/PWgm4Xm+6v+kC+lMf1t3PVafXS5aGctEdbrqv+EpeabzkpZ6qjXn1000ISkKtLP0jLly7gq3eVru1LeWneWtDtYtP9VR/Il/K4/nauOq1eujyUk/Zoy3XVX+JS8y0n5Ux11KuPblpIAnJ16Qdp+dIFfPWu0rV9KS/NWwu6XWy6v+oD+VIe19/OVafVS5eHctIebbmu+ktcar7lpJypjnr10U0LSUCuLv0gLV+6gK/eVbq2L+WleWtBt4tN91d9IF/K4/rbueq0eunyUE7aoy3XVX+JS823nJQz1VGvPrppIQnI1aUfpOVLF/DVu0rX9qW8NG8t6Hax6f6qD+RLeVx/O1edVi9dHspJe7Tluuovcan5lpNypjrq1Uc3LSQBubr0g7R86QK+elfp2r6Ul+atBd0uNt1f9YF8KY/rb+eq0+qly0M5aY+2XFf9JS4133JSzlRHvfropoUkIFeXfpCWL13AV+8qXduX8tK8taDbxab7qz6QL+Vx/e1cdVq9dHkoJ+3Rluuqv8Sl5ltOypnqqFf/6f4CWq+i5liAyiwAAAAASUVORK5CYII=", + "png": "iVBORw0KGgoAAAANSUhEUgAAAaYAAACRCAYAAACIeRyiAAAAHnRFWHRTb2Z0d2FyZQBid2lwLWpzLm1ldGFmbG9vci5jb21Tnbi0AAAiP0lEQVR4nMWTwW4dMQwD8/8/3Z56aBbGkGNpN8A7xBbNIZb6+fn5+fPr9+/v9/903s6dfOmdKV2al3y33m3zWJ3lbfOkvlM64t3uA+ksT6qf9k3z2F6mPORje3TLtdVf4jrd33KSTztHvXrMtYUkoHTOfpApnV3At95t81id5W3zfLXYdL7VB9JZnlQ/7Zvmsb1MecjH9uiWa6u/xHW6v+Ukn3aOevWYawtJQOmc/SBTOruAb73b5rE6y9vm+Wqx6XyrD6SzPKl+2jfNY3uZ8pCP7dEt11Z/iet0f8tJPu0c9eox1xaSgNI5+0GmdHYB33q3zWN1lrfN89Vi0/lWH0hneVL9tG+ax/Yy5SEf26Nbrq3+Etfp/paTfNo56tVjri0kAaVz9oNM6ewCvvVum8fqLG+b56vFpvOtPpDO8qT6ad80j+1lykM+tke3XFv9Ja7T/S0n+bRz1KvHXFtIAkrn7AeZ0tkFfOvdNo/VWd42z1eLTedbfSCd5Un1075pHtvLlId8bI9uubb6S1yn+1tO8mnnqFePubaQBJTO2Q8ypbML+Na7bR6rs7xtnq8Wm863+kA6y5Pqp33TPLaXKQ/52B7dcm31l7hO97ec5NPOUa8ec20hCSidsx9kSmcX8K132zxWZ3nbPF8tNp1v9YF0lifVT/umeWwvUx7ysT265drqL3Gd7m85yaedo1495tpCElA6Zz/IlM4u4FvvtnmszvK2eb5abDrf6gPpLE+qn/ZN89hepjzkY3t0y7XVX+I63d9ykk87R716zLWFJKB0zn6QKZ1dwLfebfNYneVt83y12HS+1QfSWZ5UP+2b5rG9THnIx/bolmurv8R1ur/lJJ92jnr1mGsLSUDpnP0gUzq7gG+92+axOsvb5vlqsel8qw+kszypfto3zWN7mfKQj+3RLddWf4nrdH/LST7tHPXqMdcWkoDSOftBpnR2Ad96t81jdZa3zfPVYtP5Vh9IZ3lS/bRvmsf2MuUhH9ujW66t/hLX6f6Wk3zaOerVY64tJAGlc/aDTOnsAr71bpvH6ixvm+erxabzrT6QzvKk+mnfNI/tZcpDPrZHt1xb/SWu0/0tJ/m0c9Srx1xbSAJK5+wHmdLZBXzr3TaP1VneNs9Xi03nW30gneVJ9dO+aR7by5SHfGyPbrm2+ktcp/tbTvJp56hXj7m2kASUztkPMqWzC/jWu20eq7O8bZ6vFpvOt/pAOsuT6qd90zy2lykP+dge3XJt9Ze4Tve3nOTTzlGvHnNtIQkonbMfZEpnF/Ctd9s8Vmd52zxfLTadb/WBdJYn1U/7pnlsL1Me8rE9uuXa6i9xne5vOcmnnaNePebaQhJQOmc/yJTOLuBb77Z5rM7ytnm+Wmw63+oD6SxPqp/2TfPYXqY85GN7dMu11V/iOt3fcpJPO0e9esy1hSSgdM5+kCmdXcC33m3zWJ3lbfN8tdh0vtUH0lmeVD/tm+axvUx5yMf26JZrq7/Edbq/5SSfdo569ZhrC0lA6Zz9IFM6u4BvvdvmsTrL2+b5arHpfKsPpLM8qX7aN81je5nykI/t0S3XVn+J63R/y0k+7Rz16jHXFpKA0jn7QaZ0dgHferfNY3WWt83z1WLT+VYfSGd5Uv20b5rH9jLlIR/bo1uurf4S1+n+lpN82jnq1WOuLSQBpXP2g0zp7AK+9W6bx+osb5vnq8Wm860+kM7ypPpp3zSP7WXKQz62R7dcW/0lrtP9LSf5tHPUq8dcW0gCSufsB5nS2QV86902j9VZ3jbPV4tN51t9IJ3lSfXTvmke28uUh3xsj265tvpLXKf7W07yaeeoV4+5tpAElM7ZDzKlswv41rttHquzvG2erxabzrf6QDrLk+qnfdM8tpcpD/nYHt1ybfWXuE73t5zk085Rrx5zbSEJKJ2zH2RKZxfwrXfbPFZneds8Xy02nW/1gXSWJ9VP+6Z5bC9THvKxPbrl2uovcZ3ubznJp52jXj3m2kISUDpnP8iUzi7gW++2eazO8rZ5vlpsOt/qA+ksT6qf9k3z2F6mPORje3TLtdVf4jrd33KSTztHvXrMtYUkoHTOfpApnV3At95t81id5W3zfLXYdL7VB9JZnlQ/7Zvmsb1MecjH9uiWa6u/xHW6v+Ukn3aOevWYawtJQOmc/SBTOruAb73b5rE6y9vm+Wqx6XyrD6SzPKl+2jfNY3uZ8pCP7dEt11Z/iet0f8tJPu0c9eox1xaSgNI5+0GmdHYB33q3zWN1lrfN89Vi0/lWH0hneVL9tG+ax/Yy5SEf26Nbrq3+Etfp/paTfNo56tVjri0kAaVz9oNM6ewCvvVum8fqLG+b56vFpvOtPpDO8qT6ad80j+1lykM+tke3XFv9Ja7T/S0n+bRz1KvHXFtIAkrn7AeZ0tkFfOvdNo/VWd42z1eLTedbfSCd5Un1075pHtvLlId8bI9uubb6S1yn+1tO8mnnqFePubaQBJTO2Q8ypbML+Na7bR6rs7xtnq8Wm863+kA6y5Pqp33TPLaXKQ/52B7dcm31l7hO97ec5NPOUa8ec20hCSidsx9kSmcX8K132zxWZ3nbPF8tNp1v9YF0lifVT/umeWwvUx7ysT265drqL3Gd7m85yaedo1495tpCElA6Zz/IlM4u4FvvtnmszvK2eb5abDrf6gPpLE+qn/ZN89hepjzkY3t0y7XVX+I63d9ykk87R716zLWFJKB0zn6QKZ1dwLfebfNYneVt83y12HS+1QfSWZ5UP+2b5rG9THnIx/bolmurv8R1ur/lJJ92jnr1mGsLSUDpnP0gUzq7gG+92+axOsvb5vlqsel8qw+kszypfto3zWN7mfKQj+3RLddWf4nrdH/LST7tHPXqMdcWkoDSOftBpnR2Ad96t81jdZa3zfPVYtP5Vh9IZ3lS/bRvmsf2MuUhH9ujW66t/hLX6f6Wk3zaOerVY64tJAGlc/aDTOnsAr71bpvH6ixvm+erxabzrT6QzvKk+mnfNI/tZcpDPrZHt1xb/SWu0/0tJ/m0c9Srx1xbSAJK5+wHmdLZBXzr3TaP1VneNs9Xi03nW30gneVJ9dO+aR7by5SHfGyPbrm2+ktcp/tbTvJp56hXj7m2kASUztkPMqWzC/jWu20eq7O8bZ6vFpvOt/pAOsuT6qd90zy2lykP+dge3XJt9Ze4Tve3nOTTzlGvHnNtIQkonbMfZEpnF/Ctd9s8Vmd52zxfLTadb/WBdJYn1U/7pnlsL1Me8rE9uuXa6i9xne5vOcmnnaNePebaQhJQOmc/yJTOLuBb77Z5rM7ytnm+Wmw63+oD6SxPqp/2TfPYXqY85GN7dMu11V/iOt3fcpJPO0e9esy1hSSgdM5+kCmdXcC33m3zWJ3lbfN8tdh0vtUH0lmeVD/tm+axvUx5yMf26JZrq7/Edbq/5SSfdo569ZhrC0lA6Zz9IFM6u4BvvdvmsTrL2+b5arHpfKsPpLM8qX7aN81je5nykI/t0S3XVn+J63R/y0k+7Rz16jHXFpKA0jn7QaZ0dgHferfNY3WWt83z1WLT+VYfSGd5Uv20b5rH9jLlIR/bo1uurf4S1+n+lpN82jnq1WOuLSQBpXP2g0zp7AK+9W6bx+osb5vnq8Wm860+kM7ypPpp3zSP7WXKQz62R7dcW/0lrtP9LSf5tHPUq8dcW0gCSufsB5nS2QV86902j9VZ3jbPV4tN51t9IJ3lSfXTvmke28uUh3xsj265tvpLXKf7W07yaeeoV4+5tpAElM7ZDzKlswv41rttHquzvG2erxabzrf6QDrLk+qnfdM8tpcpD/nYHt1ybfWXuE73t5zk085Rrx5zbSEJKJ2zH2RKZxfwrXfbPFZneds8Xy02nW/1gXSWJ9VP+6Z5bC9THvKxPbrl2uovcZ3ubznJp52jXj3m2kISUDpnP8iUzi7gW++2eazO8rZ5vlpsOt/qA+ksT6qf9k3z2F6mPORje3TLtdVf4jrd33KSTztHvXrMtYUkoHTOfpApnV3At95t81id5W3zfLXYdL7VB9JZnlQ/7Zvmsb1MecjH9uiWa6u/xHW6v+Ukn3aOevWYawtJQOmc/SBTOruAb73b5rE6y9vm+Wqx6XyrD6SzPKl+2jfNY3uZ8pCP7dEt11Z/iet0f8tJPu0c9eox1xaSgNI5+0GmdHYB33q3zWN1lrfN89Vi0/lWH0hneVL9tG+ax/Yy5SEf26Nbrq3+Etfp/paTfNo56tVjri0kAaVz9oNM6ewCvvVum8fqLG+b56vFpvOtPpDO8qT6ad80j+1lykM+tke3XFv9Ja7T/S0n+bRz1KvHXFtIAkrn7AeZ0tkFfOvdNo/VWd42z1eLTedbfSCd5Un1075pHtvLlId8bI9uubb6S1yn+1tO8mnnqFePubaQBJTO2Q8ypbML+Na7bR6rs7xtnq8Wm863+kA6y5Pqp33TPLaXKQ/52B7dcm31l7hO97ec5NPOUa8ec20hCSidsx9kSmcX8K132zxWZ3nbPF8tNp1v9YF0lifVT/umeWwvUx7ysT265drqL3Gd7m85yaedo1495tpCElA6Zz/IlM4u4FvvtnmszvK2eb5abDrf6gPpLE+qn/ZN89hepjzkY3t0y7XVX+I63d9ykk87R716zLWFJKB0zn6QKZ1dwLfebfNYneVt83y12HS+1QfSWZ5UP+2b5rG9THnIx/bolmurv8R1ur/lJJ92jnr1mGsLSUDpnP0gUzq7gG+92+axOsvb5vlqsel8qw+kszypfto3zWN7mfKQj+3RLddWf4nrdH/LST7tHPXqMdcWkoDSOftBpnR2Ad96t81jdZa3zfPVYtP5Vh9IZ3lS/bRvmsf2MuUhH9ujW66t/hLX6f6Wk3zaOerVY64tJAGlc/aDTOnsAr71bpvH6ixvm+erxabzrT6QzvKk+mnfNI/tZcpDPrZHt1xb/SWu0/0tJ/m0c9Srx1xbSAJK5+wHmdLZBXzr3TaP1VneNs9Xi03nW30gneVJ9dO+aR7by5SHfGyPbrm2+ktcp/tbTvJp56hXj7m2kASUztkPMqWzC/jWu20eq7O8bZ6vFpvOt/pAOsuT6qd90zy2lykP+dge3XJt9Ze4Tve3nOTTzlGvHnNtIQkonbMfZEpnF/Ctd9s8Vmd52zxfLTadb/WBdJYn1U/7pnlsL1Me8rE9uuXa6i9xne5vOcmnnaNePebaQhJQOmc/yJTOLuBb77Z5rM7ytnm+Wmw63+oD6SxPqp/2TfPYXqY85GN7dMu11V/iOt3fcpJPO0e9esy1hSSgdM5+kCmdXcC33m3zWJ3lbfN8tdh0vtUH0lmeVD/tm+axvUx5yMf26JZrq7/Edbq/5SSfdo569ZhrC0lA6Zz9IFM6u4BvvdvmsTrL2+b5arHpfKsPpLM8qX7aN81je5nykI/t0S3XVn+J63R/y0k+7Rz16jHXFpKA0jn7QaZ0dgHferfNY3WWt83z1WLT+VYfSGd5Uv20b5rH9jLlIR/bo1uurf4S1+n+lpN82jnq1WOuLSQBpXP2g0zp7AK+9W6bx+osb5vnq8Wm860+kM7ypPpp3zSP7WXKQz62R7dcW/0lrtP9LSf5tHPUq8dcW0gCSufsB5nS2QV86902j9VZ3jbPV4tN51t9IJ3lSfXTvmke28uUh3xsj265tvpLXKf7W07yaeeoV4+5tpAElM7ZDzKlswv41rttHquzvG2erxabzrf6QDrLk+qnfdM8tpcpD/nYHt1ybfWXuE73t5zk085Rrx5zbSEJKJ2zH2RKZxfwrXfbPFZneds8Xy02nW/1gXSWJ9VP+6Z5bC9THvKxPbrl2uovcZ3ubznJp52jXj3m2kISUDpnP8iUzi7gW++2eazO8rZ5vlpsOt/qA+ksT6qf9k3z2F6mPORje3TLtdVf4jrd33KSTztHvXrMtYUkoHTOfpApnV3At95t81id5W3zfLXYdL7VB9JZnlQ/7Zvmsb1MecjH9uiWa6u/xHW6v+Ukn3aOevWYawtJQOmc/SBTOruAb73b5rE6y9vm+Wqx6XyrD6SzPKl+2jfNY3uZ8pCP7dEt11Z/iet0f8tJPu0c9eox1xaSgNI5+0GmdHYB33q3zWN1lrfN89Vi0/lWH0hneVL9tG+ax/Yy5SEf26Nbrq3+Etfp/paTfNo56tVjri0kAaVz9oNM6ewCvvVum8fqLG+b56vFpvOtPpDO8qT6ad80j+1lykM+tke3XFv9Ja7T/S0n+bRz1KvHXFtIAkrn7AeZ0tkFfOvdNo/VWd42z1eLTedbfSCd5Un1075pHtvLlId8bI9uubb6S1yn+1tO8mnnqFePubaQBJTO2Q8ypbML+Na7bR6rs7xtnq8Wm863+kA6y5Pqp33TPLaXKQ/52B7dcm31l7hO97ec5NPOUa8ec20hCSidsx9kSmcX8K132zxWZ3nbPF8tNp1v9YF0lifVT/umeWwvUx7ysT265drqL3Gd7m85yaedo1495tpCElA6Zz/IlM4u4FvvtnmszvK2eb5abDrf6gPpLE+qn/ZN89hepjzkY3t0y7XVX+I63d9ykk87R716zLWFJKB0zn6QKZ1dwLfebfNYneVt83y12HS+1QfSWZ5UP+2b5rG9THnIx/bolmurv8R1ur/lJJ92jnr1mGsLSUDpnP0gUzq7gG+92+axOsvb5vlqsel8qw+kszypfto3zWN7mfKQj+3RLddWf4nrdH/LST7tHPXqMdcWkoDSOftBpnR2Ad96t81jdZa3zfPVYtP5Vh9IZ3lS/bRvmsf2MuUhH9ujW66t/hLX6f6Wk3zaOerVY64tJAGlc/aDTOnsAr71bpvH6ixvm+erxabzrT6QzvKk+mnfNI/tZcpDPrZHt1xb/SWu0/0tJ/m0c9Srx1xbSAJK5+wHmdLZBXzr3TaP1VneNs9Xi03nW30gneVJ9dO+aR7by5SHfGyPbrm2+ktcp/tbTvJp56hXj7m2kASUztkPMqWzC/jWu20eq7O8bZ6vFpvOt/pAOsuT6qd90zy2lykP+dge3XJt9Ze4Tve3nOTTzlGvHnNtIQkonbMfZEpnF/Ctd9s8Vmd52zxfLTadb/WBdJYn1U/7pnlsL1Me8rE9uuXa6i9xne5vOcmnnaNePebaQhJQOmc/yJTOLuBb77Z5rM7ytnm+Wmw63+oD6SxPqp/2TfPYXqY85GN7dMu11V/iOt3fcpJPO0e9esy1hSSgdM5+kCmdXcC33m3zWJ3lbfN8tdh0vtUH0lmeVD/tm+axvUx5yMf26JZrq7/Edbq/5SSfdo569ZhrC0lA6Zz9IFM6u4BvvdvmsTrL2+b5arHpfKsPpLM8qX7aN81je5nykI/t0S3XVn+J63R/y0k+7Rz16jHXFpKA0jn7QaZ0dgHferfNY3WWt83z1WLT+VYfSGd5Uv20b5rH9jLlIR/bo1uurf4S1+n+lpN82jnq1WOuLSQBpXP2g0zp7AK+9W6bx+osb5vnq8Wm860+kM7ypPpp3zSP7WXKQz62R7dcW/0lrtP9LSf5tHPUq8dcW0gCSufsB5nS2QV86902j9VZ3jbPV4tN51t9IJ3lSfXTvmke28uUh3xsj265tvpLXKf7W07yaeeoV4+5tpAElM7ZDzKlswv41rttHquzvG2erxabzrf6QDrLk+qnfdM8tpcpD/nYHt1ybfWXuE73t5zk085Rrx5zbSEJKJ2zH2RKZxfwrXfbPFZneds8Xy02nW/1gXSWJ9VP+6Z5bC9THvKxPbrl2uovcZ3ubznJp52jXj3m2kISUDpnP8iUzi7gW++2eazO8rZ5vlpsOt/qA+ksT6qf9k3z2F6mPORje3TLtdVf4jrd33KSTztHvXrMtYUkoHTOfpApnV3At95t81id5W3zfLXYdL7VB9JZnlQ/7Zvmsb1MecjH9uiWa6u/xHW6v+Ukn3aOevWYawtJQOmc/SBTOruAb73b5rE6y9vm+Wqx6XyrD6SzPKl+2jfNY3uZ8pCP7dEt11Z/iet0f8tJPu0c9eox1xaSgNI5+0GmdHYB33q3zWN1lrfN89Vi0/lWH0hneVL9tG+ax/Yy5SEf26Nbrq3+Etfp/paTfNo56tVjri0kAaVz9oNM6ewCvvVum8fqLG+b56vFpvOtPpDO8qT6ad80j+1lykM+tke3XFv9Ja7T/S0n+bRz1KvHXFtIAkrn7AeZ0tkFfOvdNo/VWd42z1eLTedbfSCd5Un1075pHtvLlId8bI9uubb6S1yn+1tO8mnnqFePubaQBJTO2Q8ypbML+Na7bR6rs7xtnq8Wm863+kA6y5Pqp33TPLaXKQ/52B7dcm31l7hO97ec5NPOUa8ec20hCSidsx9kSmcX8K132zxWZ3nbPF8tNp1v9YF0lifVT/umeWwvUx7ysT265drqL3Gd7m85yaedo1495tpCElA6Zz/IlM4u4FvvtnmszvK2eb5abDrf6gPpLE+qn/ZN89hepjzkY3t0y7XVX+I63d9ykk87R716zLWFJKB0zn6QKZ1dwLfebfNYneVt83y12HS+1QfSWZ5UP+2b5rG9THnIx/bolmurv8R1ur/lJJ92jnr1mGsLSUDpnP0gUzq7gG+92+axOsvb5vlqsel8qw+kszypfto3zWN7mfKQj+3RLddWf4nrdH/LST7tHPXqMdcWkoDSOftBpnR2Ad96t81jdZa3zfPVYtP5Vh9IZ3lS/bRvmsf2MuUhH9ujW66t/hLX6f6Wk3zaOerVY64tJAGlc/aDTOnsAr71bpvH6ixvm+erxabzrT6QzvKk+mnfNI/tZcpDPrZHt1xb/SWu0/0tJ/m0c9Srx1xbSAJK5+wHmdLZBXzr3TaP1VneNs9Xi03nW30gneVJ9dO+aR7by5SHfGyPbrm2+ktcp/tbTvJp56hXj7m2kASUztkPMqWzC/jWu20eq7O8bZ6vFpvOt/pAOsuT6qd90zy2lykP+dge3XJt9Ze4Tve3nOTTzlGvHnNtIQkonbMfZEpnF/Ctd9s8Vmd52zxfLTadb/WBdJYn1U/7pnlsL1Me8rE9uuXa6i9xne5vOcmnnaNePebaQhJQOmc/yJTOLuBb77Z5rM7ytnm+Wmw63+oD6SxPqp/2TfPYXqY85GN7dMu11V/iOt3fcpJPO0e9esy1hSSgdM5+kCmdXcC33m3zWJ3lbfN8tdh0vtUH0lmeVD/tm+axvUx5yMf26JZrq7/Edbq/5SSfdo569ZhrC0lA6Zz9IFM6u4BvvdvmsTrL2+b5arHpfKsPpLM8qX7aN81je5nykI/t0S3XVn+J63R/y0k+7Rz16jHXFpKA0jn7QaZ0dgHferfNY3WWt83z1WLT+VYfSGd5Uv20b5rH9jLlIR/bo1uurf4S1+n+lpN82jnq1WOuLSQBpXP2g0zp7AK+9W6bx+osb5vnq8Wm860+kM7ypPpp3zSP7WXKQz62R7dcW/0lrtP9LSf5tHPUq8dcW0gCSufsB5nS2QV86902j9VZ3jbPV4tN51t9IJ3lSfXTvmke28uUh3xsj265tvpLXKf7W07yaeeoV4+5tpAElM7ZDzKlswv41rttHquzvG2erxabzrf6QDrLk+qnfdM8tpcpD/nYHt1ybfWXuE73t5zk085Rrx5zbSEJKJ2zH2RKZxfwrXfbPFZneds8Xy02nW/1gXSWJ9VP+6Z5bC9THvKxPbrl2uovcZ3ubznJp52jXj3m2kISUDpnP8iUzi7gW++2eazO8rZ5vlpsOt/qA+ksT6qf9k3z2F6mPORje3TLtdVf4jrd33KSTztHvXrMtYUkoHTOfpApnV3At95t81id5W3zfLXYdL7VB9JZnlQ/7Zvmsb1MecjH9uiWa6u/xHW6v+Ukn3aOevWYawtJQOmc/SBTOruAb73b5rE6y9vm+Wqx6XyrD6SzPKl+2jfNY3uZ8pCP7dEt11Z/iet0f8tJPu0c9eox1xaSgNI5+0GmdHYB33q3zWN1lrfN89Vi0/lWH0hneVL9tG+ax/Yy5SEf26Nbrq3+Etfp/paTfNo56tVjri0kAaVz9oNM6ewCvvVum8fqLG+b56vFpvOtPpDO8qT6ad80j+1lykM+tke3XFv9Ja7T/S0n+bRz1KvHXFtIAkrn7AeZ0tkFfOvdNo/VWd42z1eLTedbfSCd5Un1075pHtvLlId8bI9uubb6S1yn+1tO8mnnqFePubaQBJTO2Q8ypbML+Na7bR6rs7xtnq8Wm863+kA6y5Pqp33TPLaXKQ/52B7dcm31l7hO97ec5NPOUa8ec20hCSidsx9kSmcX8K132zxWZ3nbPF8tNp1v9YF0lifVT/umeWwvUx7ysT265drqL3Gd7m85yaedo1495tpCElA6Zz/IlM4u4FvvtnmszvK2eb5abDrf6gPpLE+qn/ZN89hepjzkY3t0y7XVX+I63d9ykk87R716zLWFJKB0zn6QKZ1dwLfebfNYneVt83y12HS+1QfSWZ5UP+2b5rG9THnIx/bolmurv8R1ur/lJJ92jnr1mGsLSUDpnP0gUzq7gG+92+axOsvb5vlqsel8qw+kszypfto3zWN7mfKQj+3RLddWf4nrdH/LST7tHPXqMdcWkoDSOftBpnR2Ad96t81jdZa3zfPVYtP5Vh9IZ3lS/bRvmsf2MuUhH9ujW66t/hLX6f6Wk3zaOerVY64tJAGlc/aDTOnsAr71bpvH6ixvm+erxabzrT6QzvKk+mnfNI/tZcpDPrZHt1xb/SWu0/0tJ/m0c9Srx1xbSAJK5+wHmdLZBXzr3TaP1VneNs9Xi03nW30gneVJ9dO+aR7by5SHfGyPbrm2+ktcp/tbTvJp56hXj7m2kASUztkPMqWzC/jWu20eq7O8bZ6vFpvOt/pAOsuT6qd90zy2lykP+dge3XJt9Ze4Tve3nOTTzlGvHnNtIQkonbMfZEpnF/Ctd9s8Vmd52zxfLTadb/WBdJYn1U/7pnlsL1Me8rE9uuXa6i9xne5vOcmnnaNePebaQhJQOmc/yJTOLuBb77Z5rM7ytnm+Wmw63+oD6SxPqp/2TfPYXqY85GN7dMu11V/iOt3fcpJPO0e9esy1hSSgdM5+kCmdXcC33m3zWJ3lbfN8tdh0vtUH0lmeVD/tm+axvUx5yMf26JZrq7/Edbq/5SSfdo569ZhrC0lA6Zz9IFM6u4BvvdvmsTrL2+b5arHpfKsPpLM8qX7aN81je5nykI/t0S3XVn+J63R/y0k+7Rz16jHXFpKA0jn7QaZ0dgHferfNY3WWt83z1WLT+VYfSGd5Uv20b5rH9jLlIR/bo1uurf4S1+n+lpN82jnq1WOuLSQBpXP2g0zp7AK+9W6bx+osb5vnq8Wm860+kM7ypPpp3zSP7WXKQz62R7dcW/0lrtP9LSf5tHPUq8dcW0gCSufsB5nS2QV86902j9VZ3jbPV4tN51t9IJ3lSfXTvmke28uUh3xsj265tvpLXKf7W07yaeeoV4+5tpAElM7ZDzKlswv41rttHquzvG2erxabzrf6QDrLk+qnfdM8tpcpD/nYHt1ybfWXuE73t5zk085Rrx5zbSEJKJ2zH2RKZxfwrXfbPFZneds8Xy02nW/1gXSWJ9VP+6Z5bC9THvKxPbrl2uovcZ3ubznJp52jXj3m2kISUDpnP8iUzi7gW++2eazO8rZ5vlpsOt/qA+ksT6qf9k3z2F6mPORje3TLtdVf4jrd33KSTztHvfpv7i9ar6LmlAFxIQAAAABJRU5ErkJggg==", "svg": "PHN2ZyB2ZXJzaW9uPSIxLjEiIHdpZHRoPSI0MjIiIGhlaWdodD0iMTQ1IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNCIgZD0iTTIgMTQ0TDIgME0zMiAxNDRMMzIgME00NiAxNDRMNDYgME03NiAxNDRMNzYgME05OCAxNDRMOTggME0xMTIgMTQ0TDExMiAwTTE1MCAxNDRMMTUwIDBNMTY0IDE0NEwxNjQgME0xNzggMTQ0TDE3OCAwTTIwOCAxNDRMMjA4IDBNMjM2IDE0NEwyMzYgME0yNDQgMTQ0TDI0NCAwTTI3OCAxNDRMMjc4IDBNMzA0IDE0NEwzMDQgME0zMTAgMTQ0TDMxMCAwTTM0MCAxNDRMMzQwIDBNMzU0IDE0NEwzNTQgME0zNzYgMTQ0TDM3NiAwTTM4MiAxNDRMMzgyIDBNMzg4IDE0NEwzODggME0zOTggMTQ0TDM5OCAwTTQyMCAxNDRMNDIwIDAiIC8+CjxwYXRoIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSIyIiBkPSJNNyAxNDRMNyAwTTEzIDE0NEwxMyAwTTIzIDE0NEwyMyAwTTQxIDE0NEw0MSAwTTU1IDE0NEw1NSAwTTY3IDE0NEw2NyAwTTg5IDE0NEw4OSAwTTEwNyAxNDRMMTA3IDBNMTIxIDE0NEwxMjEgME0xMzMgMTQ0TDEzMyAwTTE0MSAxNDRMMTQxIDBNMTg1IDE0NEwxODUgME0xOTkgMTQ0TDE5OSAwTTIxMyAxNDRMMjEzIDBNMjIxIDE0NEwyMjEgME0yNTEgMTQ0TDI1MSAwTTI2NSAxNDRMMjY1IDBNMjczIDE0NEwyNzMgME0yODcgMTQ0TDI4NyAwTTMyNSAxNDRMMzI1IDBNMzYzIDE0NEwzNjMgME0zNzEgMTQ0TDM3MSAwTTQxNSAxNDRMNDE1IDAiIC8+CjxwYXRoIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBkPSJNNjEgMTQ0TDYxIDBNODMgMTQ0TDgzIDBNMTI3IDE0NEwxMjcgME0xNTcgMTQ0TDE1NyAwTTE3MSAxNDRMMTcxIDBNMTkzIDE0NEwxOTMgME0yMjkgMTQ0TDIyOSAwTTI1OSAxNDRMMjU5IDBNMjk1IDE0NEwyOTUgME0zMTcgMTQ0TDMxNyAwTTMzMyAxNDRMMzMzIDBNMzQ3IDE0NEwzNDcgME00MDkgMTQ0TDQwOSAwIiAvPgo8L3N2Zz4K", } `; diff --git a/yarn.lock b/yarn.lock index 651b5fc70..405b73125 100644 --- a/yarn.lock +++ b/yarn.lock @@ -591,65 +591,22 @@ enabled "2.0.x" kuler "^2.0.0" -"@es-joy/jsdoccomment@~0.36.1": - version "0.36.1" - resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz#c37db40da36e4b848da5fd427a74bae3b004a30f" - integrity sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg== - dependencies: - comment-parser "1.3.1" - esquery "^1.4.0" - jsdoc-type-pratt-parser "~3.1.0" - -"@eslint-community/eslint-utils@^4.2.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.4.0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724" - integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ== - -"@eslint/eslintrc@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02" - integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.5.1" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@8.39.0": - version "8.39.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.39.0.tgz#58b536bcc843f4cd1e02a7e6171da5c040f4d44b" - integrity sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng== - -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== +"@eslint-community/eslint-utils@^4.4.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.5" + eslint-visitor-keys "^3.4.3" -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== +"@eslint-community/regexpp@^4.10.0": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@eslint/js@^9.0.0": + version "9.19.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.19.0.tgz#51dbb140ed6b49d05adc0b171c41e1a8713b7789" + integrity sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -920,24 +877,11 @@ "@nodelib/fs.stat" "2.0.3" run-parallel "^1.1.9" -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - "@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== -"@nodelib/fs.stat@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - "@nodelib/fs.walk@^1.2.3": version "1.2.4" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" @@ -946,14 +890,6 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" -"@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - "@opencensus/web-types@0.0.7": version "0.0.7" resolved "https://registry.yarnpkg.com/@opencensus/web-types/-/web-types-0.0.7.tgz#4426de1fe5aa8f624db395d2152b902874f0570a" @@ -964,25 +900,17 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/types/-/types-0.2.0.tgz#2a0afd40fa7026e39ea56a454642bda72b172f80" integrity sha512-GtwNB6BNDdsIPAYEdpp3JnOGO/3AJxjPvny53s3HERBdXSJTGQw8IRhiaTEX0b3w9P8+FwFZde4k+qkjn67aVw== -"@pagopa/eslint-config@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@pagopa/eslint-config/-/eslint-config-3.0.0.tgz#a773121788299eaeb9ba71c2ad2bf5ea795028d6" - integrity sha512-eYIPdiuYRbRPR5k0OuteRNqYb0Z2nfJ/lZohejB7ylfBeSDWwkaV8Z19AXP4RymE6oEesyPDZ6i0yNaE9tQrHw== - dependencies: - "@typescript-eslint/eslint-plugin" "^5.18.0" - "@typescript-eslint/parser" "^5.18.0" - eslint "^8.12.0" - eslint-config-prettier "^8.5.0" - eslint-plugin-extra-rules "^0.0.0-development" - eslint-plugin-fp "^2.3.0" - eslint-plugin-functional "^4.2.1" - eslint-plugin-import "^2.26.0" - eslint-plugin-jsdoc "^39.0.0" - eslint-plugin-prefer-arrow "^1.2.3" - eslint-plugin-prettier "^4.0.0" - eslint-plugin-react "^7.29.4" - eslint-plugin-sonarjs "^0.13.0" - prettier "^2.6.2" +"@pagopa/eslint-config@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@pagopa/eslint-config/-/eslint-config-4.0.1.tgz#55374cab53f162d9be6afe3b827c623caf3b4fb5" + integrity sha512-Ah6zt5wFEpf+e5CcPbRoDvHoTk+PyP7x5lpbrUhwBBgBZY+/x+LCrQGegMnlLGupjNdyF0FQxWl71BYgRrdXKQ== + dependencies: + "@eslint/js" "^9.0.0" + eslint-config-prettier "^9.1.0" + eslint-plugin-perfectionist "^2.9.0" + eslint-plugin-prettier "^5.1.3" + eslint-plugin-vitest "^0.5.3" + typescript-eslint "^7.6.0" "@pagopa/io-functions-app-sdk@x": version "5.13.0" @@ -1002,10 +930,10 @@ fp-ts "^2.10.5" io-ts "^2.2.16" -"@pagopa/io-functions-commons@^29.1.1": - version "29.1.2" - resolved "https://registry.yarnpkg.com/@pagopa/io-functions-commons/-/io-functions-commons-29.1.2.tgz#21c7b01b3e2fba457b0a82c4ec08b800f19128db" - integrity sha512-bI4zoC+/9apyZ7SWgjQe7iKrUxONC7Sn5fPja6uK/KT7Bb/hZlUwuWkxkweexk9YVTJiyWv696KlgzQox5aGgw== +"@pagopa/io-functions-commons@^29.3.0": + version "29.3.0" + resolved "https://registry.yarnpkg.com/@pagopa/io-functions-commons/-/io-functions-commons-29.3.0.tgz#3b7c7d2ed5eb51cc1ea603a1a0908b01a28f7684" + integrity sha512-CLVPjQ72gTkJTfPFskciWDReeXNq+DKUj5Ya3I5hh8Qi10U4FRaZcdrh9UkpxFOWmNblD/9ZBQN4otszLKNpew== dependencies: "@azure/cosmos" "^4.0.0" "@azure/data-tables" "^13.2.2" @@ -1068,14 +996,14 @@ semver "^7.3.7" validator "^13.7.0" -"@pagopa/ts-commons@^12.4.1": - version "12.6.0" - resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-12.6.0.tgz#2df8bd8f626f5e70d41736bf991a88c833f729b5" - integrity sha512-Sci1WD2TDmKVUGyAvBkcxAoXBDfVj9cgJBlRIai36oFuYxJfvdMx/34iZFP6detmXq/McnTESBF2Tz+aCh7DGQ== +"@pagopa/ts-commons@^13.1.1": + version "13.1.1" + resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-13.1.1.tgz#a8bef24022af7d49253d58626914273e142f79dd" + integrity sha512-IjmsrGwO9DFuU1IpzzBRNf3VIO9gd+gNdl4jGK4U1P7T47lWqozDqp6rPjF2sZfA1EoKnH5cFfgYT8uVsH0Z0g== dependencies: abort-controller "^3.0.0" agentkeepalive "^4.1.4" - applicationinsights "^1.8.10" + applicationinsights "^2.9.5" jose "^4.15.5" json-set-map "^1.1.2" jsonwebtoken "^9.0.1" @@ -1084,10 +1012,10 @@ ulid "^2.3.0" validator "^13.7.0" -"@pagopa/ts-commons@^13.1.1": - version "13.1.1" - resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-13.1.1.tgz#a8bef24022af7d49253d58626914273e142f79dd" - integrity sha512-IjmsrGwO9DFuU1IpzzBRNf3VIO9gd+gNdl4jGK4U1P7T47lWqozDqp6rPjF2sZfA1EoKnH5cFfgYT8uVsH0Z0g== +"@pagopa/ts-commons@^13.1.2": + version "13.1.2" + resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-13.1.2.tgz#c98b0ae2d9700ab670edfcda5b1cd46f3b79b35d" + integrity sha512-TAdqhbaTG5YPQIRyC5qs1qWYr/YPB1aPb1fEwCTOKVVmKZrguQxkAWqdkz6uDaKmKlkUKfOxsJTmMZu2/tpyfg== dependencies: abort-controller "^3.0.0" agentkeepalive "^4.1.4" @@ -1109,6 +1037,11 @@ io-ts "^2.2.16" winston "^3.7.2" +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + "@redis/bloom@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.1.0.tgz#64e310ddee72010676e14296076329e594a1f6c7" @@ -1376,16 +1309,11 @@ expect "^29.0.0" pretty-format "^29.0.0" -"@types/json-schema@^7.0.6", "@types/json-schema@^7.0.9": +"@types/json-schema@^7.0.6": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - "@types/jsonwebtoken@7.2.7": version "7.2.7" resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-7.2.7.tgz#5dd62e0c0a0c6f211c3c1d13d322360894625b47" @@ -1449,11 +1377,18 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@~18.13.0": +"@types/node@*": version "18.13.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850" integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== +"@types/node@~20.18.0": + version "20.17.16" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.16.tgz#b33b0edc1bf925b27349e494b871ca4451fabab4" + integrity sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw== + dependencies: + undici-types "~6.19.2" + "@types/passport-http-bearer@^1.0.34": version "1.0.37" resolved "https://registry.yarnpkg.com/@types/passport-http-bearer/-/passport-http-bearer-1.0.37.tgz#6882825a46717725f952731d17e1bb0a698155a4" @@ -1539,11 +1474,6 @@ "@types/tough-cookie" "*" form-data "^2.5.0" -"@types/semver@^7.3.12": - version "7.3.13" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" - integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== - "@types/send@*": version "0.17.1" resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" @@ -1641,89 +1571,86 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.18.0": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz#9b09ee1541bff1d2cebdcb87e7ce4a4003acde08" - integrity sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg== - dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.1" - "@typescript-eslint/type-utils" "5.59.1" - "@typescript-eslint/utils" "5.59.1" - debug "^4.3.4" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" +"@typescript-eslint/eslint-plugin@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3" + integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/type-utils" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/parser@^5.18.0": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.1.tgz#73c2c12127c5c1182d2e5b71a8fa2a85d215cbb4" - integrity sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g== +"@typescript-eslint/parser@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.18.0.tgz#83928d0f1b7f4afa974098c64b5ce6f9051f96a0" + integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== dependencies: - "@typescript-eslint/scope-manager" "5.59.1" - "@typescript-eslint/types" "5.59.1" - "@typescript-eslint/typescript-estree" "5.59.1" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz#8a20222719cebc5198618a5d44113705b51fd7fe" - integrity sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA== +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== dependencies: - "@typescript-eslint/types" "5.59.1" - "@typescript-eslint/visitor-keys" "5.59.1" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" -"@typescript-eslint/type-utils@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz#63981d61684fd24eda2f9f08c0a47ecb000a2111" - integrity sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw== +"@typescript-eslint/type-utils@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b" + integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== dependencies: - "@typescript-eslint/typescript-estree" "5.59.1" - "@typescript-eslint/utils" "5.59.1" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils" "7.18.0" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/types@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.1.tgz#03f3fedd1c044cb336ebc34cc7855f121991f41d" - integrity sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg== +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== -"@typescript-eslint/typescript-estree@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz#4aa546d27fd0d477c618f0ca00b483f0ec84c43c" - integrity sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA== +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== dependencies: - "@typescript-eslint/types" "5.59.1" - "@typescript-eslint/visitor-keys" "5.59.1" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.59.1", "@typescript-eslint/utils@^5.10.2": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.1.tgz#d89fc758ad23d2157cfae53f0b429bdf15db9473" - integrity sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.59.1" - "@typescript-eslint/types" "5.59.1" - "@typescript-eslint/typescript-estree" "5.59.1" - eslint-scope "^5.1.1" - semver "^7.3.7" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/visitor-keys@5.59.1": - version "5.59.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz#0d96c36efb6560d7fb8eb85de10442c10d8f6058" - integrity sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA== +"@typescript-eslint/utils@7.18.0", "@typescript-eslint/utils@^6.13.0 || ^7.0.0", "@typescript-eslint/utils@^7.7.1": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== dependencies: - "@typescript-eslint/types" "5.59.1" - eslint-visitor-keys "^3.3.0" + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== + dependencies: + "@typescript-eslint/types" "7.18.0" + eslint-visitor-keys "^3.4.3" a-sync-waterfall@^1.0.0: version "1.0.1" @@ -1750,28 +1677,6 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-jsx@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-2.0.1.tgz#0edf9878a5866bca625f52955a1ed9e7d8c5117e" - integrity sha1-Dt+YeKWGa8piX1KVWh7Z59jFEX4= - dependencies: - acorn "^2.0.1" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^2.0.1, acorn@^2.6.4: - version "2.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" - integrity sha1-q259nYhqrKiwhbwzEreaGYQz8Oc= - -acorn@^8.8.0: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== - agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1788,7 +1693,7 @@ agentkeepalive@^4.1.4: depd "^2.0.0" humanize-ms "^1.2.1" -ajv@^6.10.0, ajv@^6.12.4, ajv@^6.5.5: +ajv@^6.5.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1872,77 +1777,16 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== - dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= -array-includes@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.2.tgz#a8db03e0b88c8c6aeddc49cb132f9bcab4ebf9c8" - integrity sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - get-intrinsic "^1.0.1" - is-string "^1.0.5" - -array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - is-string "^1.0.7" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.flat@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -array.prototype.tosorted@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" - integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" - arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -2007,11 +1851,6 @@ auto-changelog@^2.2.1: parse-github-url "^1.0.2" semver "^6.3.0" -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - await-handler@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/await-handler/-/await-handler-1.1.2.tgz#329c19e9382599898bc12c80c47efdcdaa1b4992" @@ -2181,6 +2020,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -2245,14 +2091,6 @@ call-bind@^1.0.0: function-bind "^1.1.1" get-intrinsic "^1.0.0" -call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - call-me-maybe@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" @@ -2519,11 +2357,6 @@ commander@^9.4.1: resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== -comment-parser@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b" - integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA== - component-emitter@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -2534,11 +2367,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -console-assert@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/console-assert/-/console-assert-1.0.0.tgz#70167028ef08ec1667a0c687205a8360eb117367" - integrity sha1-cBZwKO8I7BZnoMaHIFqDYOsRc2c= - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -2599,13 +2427,6 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -create-eslint-index@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/create-eslint-index/-/create-eslint-index-1.0.0.tgz#d954372d86d5792fcd67e9f2b791b1ab162411bb" - integrity sha1-2VQ3LYbVeS/NZ+nyt5GxqxYkEbs= - dependencies: - lodash.get "^4.3.0" - cross-env@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941" @@ -2633,7 +2454,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1: shebang-command "^2.0.0" which "^2.0.1" -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -2666,7 +2487,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.3.2, debug@^4.3.4: +debug@4, debug@^4.1.0, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2704,16 +2525,6 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -deepmerge-ts@^4.0.3: - version "4.3.0" - resolved "https://registry.yarnpkg.com/deepmerge-ts/-/deepmerge-ts-4.3.0.tgz#432aff3cd09f947e36cdb3772a43960bf45327fe" - integrity sha512-if3ZYdkD2dClhnXR5reKtG98cwyaRT1NeugQoAPTTfsOpV9kqyeiBF9Qa5RHjemb3KzD5ulqygv6ED3t5j9eJw== - deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" @@ -2733,14 +2544,6 @@ define-properties@^1.1.2, define-properties@^1.1.3: dependencies: object-keys "^1.0.12" -define-properties@^1.1.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2807,20 +2610,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - dont-sniff-mimetype@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz#c7d0427f8bcb095762751252af59d148b0a623b2" @@ -2932,80 +2721,6 @@ es-abstract@^1.17.0-next.1: string.prototype.trimleft "^2.1.1" string.prototype.trimright "^2.1.1" -es-abstract@^1.18.0-next.1: - version "1.18.0-next.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" - integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" - integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== - dependencies: - array-buffer-byte-length "^1.0.0" - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.2.0" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.10" - is-weakref "^1.0.2" - object-inspect "^1.12.3" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.7" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" - -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - -es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== - dependencies: - has "^1.0.3" - es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -3045,264 +2760,52 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-ast-utils@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-ast-utils/-/eslint-ast-utils-1.1.0.tgz#3d58ba557801cfb1c941d68131ee9f8c34bd1586" - integrity sha512-otzzTim2/1+lVrlH19EfQQJEhVJSu0zOb9ygb3iapN6UlyaDtyRq4b5U1FuW0v1lRa9Fp/GJyHkSwm6NqABgCA== - dependencies: - lodash.get "^4.4.2" - lodash.zip "^4.2.0" - -eslint-config-prettier@^8.5.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" - integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== - -eslint-import-resolver-node@^0.3.7: - version "0.3.7" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== - dependencies: - debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" - -eslint-module-utils@^2.7.4: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== - dependencies: - debug "^3.2.7" - -eslint-plugin-extra-rules@^0.0.0-development: - version "0.0.0-development" - resolved "https://registry.yarnpkg.com/eslint-plugin-extra-rules/-/eslint-plugin-extra-rules-0.0.0-development.tgz#c3c1aed3086c39fd83c1b7a4fa3df9884b4abb48" - integrity sha1-w8Gu0whsOf2Dwbek+j35iEtKu0g= - dependencies: - console-assert "1.0.0" - espree "3.0.0-alpha-1" - quote "0.4.0" - -eslint-plugin-fp@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-fp/-/eslint-plugin-fp-2.3.0.tgz#376d2a108710e981980bdc3875e3b9920da0489c" - integrity sha1-N20qEIcQ6YGYC9w4deO5kg2gSJw= - dependencies: - create-eslint-index "^1.0.0" - eslint-ast-utils "^1.0.0" - lodash "^4.13.1" - req-all "^0.1.0" - -eslint-plugin-functional@^4.2.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-functional/-/eslint-plugin-functional-4.4.1.tgz#de967e2a307387281ff78466ab66967f17ff9e99" - integrity sha512-YhSfHS52Si62Sn126g9wGx+XnWMoWhwEt6ctVXfcJj+xMUiggjOqUVMca7fuLNzX8jYiNBIeU1Y0teHGePZ3NA== - dependencies: - "@typescript-eslint/utils" "^5.10.2" - deepmerge-ts "^4.0.3" - escape-string-regexp "^4.0.0" - semver "^7.3.7" - -eslint-plugin-import@^2.26.0: - version "2.27.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" - integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== - dependencies: - array-includes "^3.1.6" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" - eslint-module-utils "^2.7.4" - has "^1.0.3" - is-core-module "^2.11.0" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.values "^1.1.6" - resolve "^1.22.1" - semver "^6.3.0" - tsconfig-paths "^3.14.1" +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== -eslint-plugin-jsdoc@^39.0.0: - version "39.9.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.9.1.tgz#e9ce1723411fd7ea0933b3ef0dd02156ae3068e2" - integrity sha512-Rq2QY6BZP2meNIs48aZ3GlIlJgBqFCmR55+UBvaDkA3ZNQ0SvQXOs2QKkubakEijV8UbIVbVZKsOVN8G3MuqZw== +eslint-plugin-perfectionist@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-2.11.0.tgz#d5cc32e0d12b649357ca5b104a105793956759ba" + integrity sha512-XrtBtiu5rbQv88gl+1e2RQud9te9luYNvKIgM9emttQ2zutHPzY/AQUucwxscDKV4qlTkvLTxjOFvxqeDpPorw== dependencies: - "@es-joy/jsdoccomment" "~0.36.1" - comment-parser "1.3.1" - debug "^4.3.4" - escape-string-regexp "^4.0.0" - esquery "^1.4.0" - semver "^7.3.8" - spdx-expression-parse "^3.0.1" - -eslint-plugin-prefer-arrow@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz#e7fbb3fa4cd84ff1015b9c51ad86550e55041041" - integrity sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ== + "@typescript-eslint/utils" "^6.13.0 || ^7.0.0" + minimatch "^9.0.3" + natural-compare-lite "^1.4.0" -eslint-plugin-prettier@^4.0.0, eslint-plugin-prettier@^4.2.1: +eslint-plugin-prettier@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-react@^7.29.4: - version "7.32.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" - integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== - dependencies: - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - array.prototype.tosorted "^1.1.1" - doctrine "^2.1.0" - estraverse "^5.3.0" - jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - object.hasown "^1.1.2" - object.values "^1.1.6" - prop-types "^15.8.1" - resolve "^2.0.0-next.4" - semver "^6.3.0" - string.prototype.matchall "^4.0.8" - -eslint-plugin-sonarjs@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.13.0.tgz#c34d140cc90abaaed38f5a5201a2ccdebe398862" - integrity sha512-t3m7ta0EspzDxSOZh3cEOJIJVZgN/TlJYaBGnQlK6W/PZNbWep8q4RQskkJkA7/zwNpX0BaoEOSUUrqaADVoqA== - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" - integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== +eslint-plugin-prettier@^5.1.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz#c4af01691a6fa9905207f0fbba0d7bea0902cce5" + integrity sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw== dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" - integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== - -eslint@^8.12.0: - version "8.39.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.39.0.tgz#7fd20a295ef92d43809e914b70c39fd5a23cf3f1" - integrity sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.0.2" - "@eslint/js" "8.39.0" - "@humanwhocodes/config-array" "^0.11.8" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.2.0" - eslint-visitor-keys "^3.4.0" - espree "^9.5.1" - esquery "^1.4.2" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - find-up "^5.0.0" - glob-parent "^6.0.2" - globals "^13.19.0" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-sdsl "^4.1.4" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.1" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" + prettier-linter-helpers "^1.0.0" + synckit "^0.9.1" -espree@3.0.0-alpha-1: - version "3.0.0-alpha-1" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.0.0-alpha-1.tgz#ca1380bd81f2fae94b2638ae7cc449b71f91eaa3" - integrity sha1-yhOAvYHy+ulLJjiufMRJtx+R6qM= +eslint-plugin-vitest@^0.5.3: + version "0.5.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-vitest/-/eslint-plugin-vitest-0.5.4.tgz#2838a40ee116ba7c15eb6132df31371d960e3bf5" + integrity sha512-um+odCkccAHU53WdKAw39MY61+1x990uXjSPguUCq3VcEHdqJrOb8OTMrbYlY6f9jAKx7x98kLVlIe3RJeJqoQ== dependencies: - acorn "^2.6.4" - acorn-jsx "^2.0.1" + "@typescript-eslint/utils" "^7.7.1" -espree@^9.5.1: - version "9.5.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4" - integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg== - dependencies: - acorn "^8.8.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.0" +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0, esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -estraverse@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" @@ -3400,7 +2903,7 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: +fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -3426,11 +2929,6 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-sta resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - fast-safe-stringify@^2.0.4: version "2.0.7" resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" @@ -3474,13 +2972,6 @@ fecha@^4.2.0: resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.0.tgz#3ffb6395453e3f3efff850404f0a59b6747f5f41" integrity sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg== -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -3509,39 +3000,11 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067" - integrity sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA== - fn.name@1.x.x: version "1.1.0" resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -3642,21 +3105,6 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -functions-have-names@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - generic-pool@3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4" @@ -3672,7 +3120,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.0, get-intrinsic@^1.0.1, get-intrinsic@^1.0.2: +get-intrinsic@^1.0.0, get-intrinsic@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49" integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg== @@ -3681,15 +3129,6 @@ get-intrinsic@^1.0.0, get-intrinsic@^1.0.1, get-intrinsic@^1.0.2: has "^1.0.3" has-symbols "^1.0.1" -get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -3700,14 +3139,6 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -3722,13 +3153,6 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - glob@^7.0.0, glob@^7.1.2, glob@^7.1.3: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -3758,20 +3182,6 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== - dependencies: - type-fest "^0.20.2" - -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -3784,13 +3194,6 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -3801,10 +3204,10 @@ graceful-fs@^4.2.9: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== handlebars@^4.7.3, handlebars@~4.5.3: version "4.5.3" @@ -3830,11 +3233,6 @@ har-validator@~5.1.3: ajv "^6.5.5" har-schema "^2.0.0" -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -3845,35 +3243,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -4070,13 +3444,10 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" +ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== import-local@^3.0.2: version "3.1.0" @@ -4104,15 +3475,6 @@ inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.3, internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== - dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" - side-channel "^1.0.4" - interpret@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" @@ -4169,15 +3531,6 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -4188,13 +3541,6 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -4202,35 +3548,17 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-buffer@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.3, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - is-callable@^1.1.4, is-callable@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== -is-callable@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" - integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== - -is-core-module@^2.11.0, is-core-module@^2.9.0: +is-core-module@^2.11.0: version "2.12.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== @@ -4262,7 +3590,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1: +is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -4281,33 +3609,11 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== -is-negative-zero@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - is-plain-obj@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" @@ -4320,45 +3626,11 @@ is-regex@^1.0.5: dependencies: has "^1.0.3" -is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" - integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== - dependencies: - has-symbols "^1.0.1" - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - is-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - -is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - is-symbol@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -4366,36 +3638,11 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" -is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - is-whitespace-character@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" @@ -4834,12 +4081,7 @@ jose@^4.15.5: resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.5.tgz#6475d0f467ecd3c630a1b5dadd2735a7288df706" integrity sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg== -js-sdsl@^4.1.4: - version "4.4.0" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" - integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -4869,11 +4111,6 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsdoc-type-pratt-parser@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz#a4a56bdc6e82e5865ffd9febc5b1a227ff28e67e" - integrity sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -4935,23 +4172,11 @@ json-set-map@^1.1.2: resolved "https://registry.yarnpkg.com/json-set-map/-/json-set-map-1.1.2.tgz#536cbc6549d06e8af11f76cb4fbd441ed2389e6e" integrity sha512-x0TGwgcOG21jOa8wV1PWXDpSXUAKa1WuhMSHPBQhXU5Pb+4DdMrxOw5HMAWztVLP8KhSG5Kl5BoAOVF0aW63wA== -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -5015,14 +4240,6 @@ jsprim@^2.0.2: json-schema "0.4.0" verror "1.10.0" -"jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" - integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== - dependencies: - array-includes "^3.1.2" - object.assign "^4.1.2" - jwa@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" @@ -5060,14 +4277,6 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -5090,14 +4299,7 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.get@^4.0.0, lodash.get@^4.3.0, lodash.get@^4.4.2: +lodash.get@^4.0.0, lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= @@ -5142,11 +4344,6 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -5162,16 +4359,6 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= -lodash.zip@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" - integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA= - -lodash@^4.13.1: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -5206,13 +4393,6 @@ lolex@4.2.0: resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== -loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -5373,23 +4553,25 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.3, minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" @@ -5603,22 +4785,17 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-inspect@^1.12.3: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - object-inspect@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== -object-inspect@^1.8.0, object-inspect@^1.9.0: +object-inspect@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== @@ -5638,61 +4815,6 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.assign@^4.1.1, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.entries@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" - integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.fromentries@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" - integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.hasown@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" - integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== - dependencies: - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.values@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - on-finished@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -5784,18 +4906,6 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - 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" - ora@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" @@ -5815,7 +4925,7 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2, p-limit@^3.1.0: +p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -5829,25 +4939,11 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - parse-entities@^1.1.0: version "1.2.2" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" @@ -6014,11 +5110,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" @@ -6031,7 +5122,7 @@ prettier@^1.12.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.6.2, prettier@^2.8.8: +prettier@^2.8.8: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -6073,15 +5164,6 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - property-information@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-3.2.0.tgz#fd1483c8fbac61808f5fe359e7693a1f48a58331" @@ -6137,11 +5219,6 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -quote@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/quote/-/quote-0.4.0.tgz#10839217f6c1362b89194044d29b233fd7f32f01" - integrity sha1-EIOSF/bBNiuJGUBE0psjP9fzLwE= - range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -6175,11 +5252,6 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -react-is@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -6247,15 +5319,6 @@ referrer-policy@1.2.0, referrer-policy@^1.1.0: resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e" integrity sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA== -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" - rehype-stringify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/rehype-stringify/-/rehype-stringify-3.0.0.tgz#9fef0868213c2dce2f780b76f3d0488c85e819eb" @@ -6304,11 +5367,6 @@ repeat-string@^1.5.4: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -req-all@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/req-all/-/req-all-0.1.0.tgz#130051e2ace58a02eacbfc9d448577a736a9273a" - integrity sha1-EwBR4qzligLqy/ydRIV3pzapJzo= - request-ip@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611" @@ -6357,11 +5415,6 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" @@ -6379,7 +5432,7 @@ resolve@^1.1.6, resolve@^1.10.0: dependencies: path-parse "^1.0.6" -resolve@^1.20.0, resolve@^1.22.1: +resolve@^1.20.0: version "1.22.2" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== @@ -6388,15 +5441,6 @@ resolve@^1.20.0, resolve@^1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.4: - version "2.0.0-next.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -6417,13 +5461,6 @@ rimraf@^2.5.4: dependencies: glob "^7.1.3" -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - run-parallel@^1.1.9: version "1.1.10" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" @@ -6444,15 +5481,6 @@ safe-identifier@^0.4.2: resolved "https://registry.yarnpkg.com/safe-identifier/-/safe-identifier-0.4.2.tgz#cf6bfca31c2897c588092d1750d30ef501d59fcb" integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" - safe-stable-stringify@^2.3.1: version "2.4.2" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz#ec7b037768098bf65310d1d64370de0dc02353aa" @@ -6483,7 +5511,7 @@ semaphore@^1.0.5: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.x, semver@^7.3.5, semver@^7.3.8: +semver@7.x, semver@^7.3.5: version "7.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== @@ -6514,6 +5542,11 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + semver@~7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" @@ -6695,14 +5728,6 @@ spdx-expression-parse@^3.0.0: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" -spdx-expression-parse@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - spdx-license-ids@^3.0.0: version "3.0.5" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" @@ -6777,20 +5802,6 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.matchall@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" - integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.3" - side-channel "^1.0.4" - string.prototype.padend@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz#dc08f57a8010dc5c153550318f67e13adbb72ac3" @@ -6799,32 +5810,6 @@ string.prototype.padend@^3.0.0: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" -string.prototype.trim@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" - integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimend@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" - integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - string.prototype.trimleft@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" @@ -6841,23 +5826,6 @@ string.prototype.trimright@^2.1.1: define-properties "^1.1.3" function-bind "^1.1.1" -string.prototype.trimstart@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" - integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -6911,7 +5879,7 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -7038,6 +6006,14 @@ swagger-schema-official@2.0.0-bab6bed: resolved "https://registry.yarnpkg.com/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz#70070468d6d2977ca5237b2e519ca7d06a2ea3fd" integrity sha1-cAcEaNbSl3ylI3suUZyn0Gouo/0= +synckit@^0.9.1: + version "0.9.2" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" + integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -7052,11 +6028,6 @@ text-hex@1.0.x: resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -7133,6 +6104,11 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +ts-api-utils@^1.3.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== + ts-jest@^29.1.0: version "29.1.0" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" @@ -7166,17 +6142,7 @@ ts-pattern@^4.0.3: resolved "https://registry.yarnpkg.com/ts-pattern/-/ts-pattern-4.0.3.tgz#4b5a08ff61fcd5a9bbfe3c1e686c35420ef87bda" integrity sha512-OxQStbr1MKcYYz3YaXsFSBkMo3zjFODVkV8kaLfOak+sWSfx4B+jkOm/VoaWLhnMP+icnIcJ7ENYEnmpAv3jLg== -tsconfig-paths@^3.14.1: - version "3.14.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" - integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.10.0, tslib@^1.9.3: version "1.11.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== @@ -7186,12 +6152,10 @@ tslib@^2.2.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" +tslib@^2.6.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== tunnel-agent@^0.6.0: version "0.6.0" @@ -7210,23 +6174,11 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" @@ -7240,15 +6192,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -7256,6 +6199,15 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typescript-eslint@^7.6.0: + version "7.18.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-7.18.0.tgz#e90d57649b2ad37a7475875fa3e834a6d9f61eb2" + integrity sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA== + dependencies: + "@typescript-eslint/eslint-plugin" "7.18.0" + "@typescript-eslint/parser" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + typescript@4.9.5: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" @@ -7274,16 +6226,6 @@ ulid@^2.2.2, ulid@^2.3.0: resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - undefsafe@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" @@ -7294,6 +6236,11 @@ underscore@^1.12.1: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unherit@^1.0.4: version "1.1.3" resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" @@ -7515,34 +6462,11 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" - which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -7606,11 +6530,6 @@ winston@^3.3.3: triple-beam "^1.3.0" winston-transport "^4.4.0" -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" From 900327713e960e27f8f4ae2cbf13de6e88f0e7c6 Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Fri, 31 Jan 2025 10:53:16 +0100 Subject: [PATCH 02/13] Update peer dependencies Code fixes for dependencies update --- package.json | 14 +- src/app.ts | 2 +- src/controllers/bonusController.ts | 2 +- src/types/lollipop.ts | 4 +- yarn.lock | 5050 ++++++++++++++++------------ 5 files changed, 2892 insertions(+), 2180 deletions(-) diff --git a/package.json b/package.json index 606bbda91..536c7867e 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "homepage": "https://github.com/pagopa/io-backend#readme", "dependencies": { "@azure/data-tables": "^13.2.2", + "@azure/functions": "^3.2.0", "@azure/storage-queue": "^12.0.0", "@pagopa/io-functions-app-sdk": "x", "@pagopa/io-functions-cgn-sdk": "x", @@ -92,17 +93,17 @@ "@pagopa/io-functions-eucovidcerts-sdk": "x", "@pagopa/ts-commons": "^13.1.2", "@pagopa/winston-ts": "^2.2.0", - "applicationinsights": "1.8.10", + "applicationinsights": "^2.9.5", "body-parser": "^1.19.2", "bwip-js": "^2.0.6", "date-fns": "^1.30.1", "dotenv": "^6.0.0", "express": "4.17.3", "express-enforces-ssl": "1.1.0", - "fp-ts": "2.14.0", + "fp-ts": "^2.16.5", "helmet": "3.23.3", "http-graceful-shutdown": "^2.3.2", - "io-ts": "2.2.20", + "io-ts": "2.2.21", "io-ts-types": "^0.5.16", "monocle-ts": "^2.3.13", "morgan": "^1.9.1", @@ -151,13 +152,14 @@ "@types/xml2js": "^0.4.5", "auto-changelog": "^2.2.1", "dotenv-cli": "^3.1.0", + "eslint": "8.57.0", "eslint-plugin-prettier": "^4.2.1", "jest": "^29.5.0", "lolex": "4.2.0", "modclean": "^3.0.0-beta.1", "nodemon": "^2.0.22", "npm-run-all": "^4.1.3", - "prettier": "^2.8.8", + "prettier": "^3.0.0", "shx": "^0.3.2", "superagent": "^3.8.3", "supertest": "^3.3.0", @@ -200,8 +202,8 @@ }, "resolutions": { "handlebars": "~4.5.3", - "applicationinsights": "1.8.10", + "applicationinsights": "~2.9.5", "@types/serve-static": "1.13.10", - "@types/express-serve-static-core": "4.17.34" + "@types/express-serve-static-core": "~5.0.0" } } diff --git a/src/app.ts b/src/app.ts index e79a7b554..542f918bc 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1391,7 +1391,7 @@ function registerPublicRoutes(app: Express): void { // Liveness probe for Kubernetes. // @see // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-a-liveness-http-request - app.get("/ping", (_, res) => res.status(200).send("ok")); + app.get("/ping", (_, res) => { res.status(200).send("ok") }); } // eslint-disable-next-line max-params diff --git a/src/controllers/bonusController.ts b/src/controllers/bonusController.ts index b2227fdc3..02efa5c13 100644 --- a/src/controllers/bonusController.ts +++ b/src/controllers/bonusController.ts @@ -27,7 +27,7 @@ export const withBonusIdFromRequest = async ( f: (bonusId: NonEmptyString) => Promise ): Promise => withValidatedOrValidationError( - NonEmptyString.decode(req.param("bonus_id")), + NonEmptyString.decode(req.params["bonus_id"]), f ); diff --git a/src/types/lollipop.ts b/src/types/lollipop.ts index 822ba7840..2727f8638 100644 --- a/src/types/lollipop.ts +++ b/src/types/lollipop.ts @@ -1,6 +1,6 @@ -import { FiscalCode } from "@pagopa/io-functions-app-sdk/FiscalCode"; + import * as t from "io-ts"; -import { NonEmptyString, PatternString } from "@pagopa/ts-commons/lib/strings"; +import { FiscalCode, NonEmptyString, PatternString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; import { IResponseErrorValidation, diff --git a/yarn.lock b/yarn.lock index 405b73125..1a24c4876 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,12 +3,12 @@ "@ampproject/remapping@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" "@apidevtools/json-schema-ref-parser@^9.0.6": version "9.1.2" @@ -42,394 +42,295 @@ call-me-maybe "^1.0.1" z-schema "^5.0.1" -"@azure/abort-controller@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.1.tgz#8510935b25ac051e58920300e9d7b511ca6e656a" - integrity sha512-wP2Jw6uPp8DEDy0n4KNidvwzDjyVV2xnycEIq7nPzj1rHyb/r+t3OPeNT1INZePP2wy5ZqlwyuyOMTi0ePyY1A== +"@azure/abort-controller@^2.0.0", "@azure/abort-controller@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-2.1.2.tgz#42fe0ccab23841d9905812c58f1082d27784566d" + integrity sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA== dependencies: - tslib "^1.9.3" - -"@azure/core-asynciterator-polyfill@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz#dcccebb88406e5c76e0e1d52e8cc4c43a68b3ee7" - integrity sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg== + tslib "^2.6.2" -"@azure/core-auth@^1.0.0": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.0.2.tgz#7377c0cacf0e3c988ce321295bf5d2c174e0e288" - integrity sha512-zhPJObdrhz2ymIqGL1x8i3meEuaLz0UPjH9mOq9RGOlJB2Pb6K6xPtkHbRsfElgoO9USR4hH2XU5pLa4/JHHIw== +"@azure/core-auth@1.7.2": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.7.2.tgz#558b7cb7dd12b00beec07ae5df5907d74df1ebd9" + integrity sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g== dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-tracing" "1.0.0-preview.7" - "@opentelemetry/types" "^0.2.0" - tslib "^1.9.3" + "@azure/abort-controller" "^2.0.0" + "@azure/core-util" "^1.1.0" + tslib "^2.6.2" -"@azure/core-auth@^1.3.0", "@azure/core-auth@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.4.0.tgz#6fa9661c1705857820dbc216df5ba5665ac36a9e" - integrity sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ== +"@azure/core-auth@^1.3.0", "@azure/core-auth@^1.4.0", "@azure/core-auth@^1.7.1", "@azure/core-auth@^1.8.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.9.0.tgz#ac725b03fabe3c892371065ee9e2041bee0fd1ac" + integrity sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw== dependencies: - "@azure/abort-controller" "^1.0.0" - tslib "^2.2.0" + "@azure/abort-controller" "^2.0.0" + "@azure/core-util" "^1.11.0" + tslib "^2.6.2" -"@azure/core-client@^1.0.0": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.7.3.tgz#f8cb2a1f91e8bc4921fa2e745cfdfda3e6e491a3" - integrity sha512-kleJ1iUTxcO32Y06dH9Pfi9K4U+Tlb111WXEnbt7R/ne+NLRwppZiTGJuTD5VVoxTMK5NTbEtm5t2vcdNCFe2g== +"@azure/core-client@^1.0.0", "@azure/core-client@^1.3.0", "@azure/core-client@^1.6.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.9.2.tgz#6fc69cee2816883ab6c5cdd653ee4f2ff9774f74" + integrity sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w== dependencies: - "@azure/abort-controller" "^1.0.0" + "@azure/abort-controller" "^2.0.0" "@azure/core-auth" "^1.4.0" "@azure/core-rest-pipeline" "^1.9.1" "@azure/core-tracing" "^1.0.0" - "@azure/core-util" "^1.0.0" + "@azure/core-util" "^1.6.1" "@azure/logger" "^1.0.0" - tslib "^2.2.0" - -"@azure/core-http@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@azure/core-http/-/core-http-1.0.4.tgz#11b4190007a269c6c2b54986d45b8af338e9b8b7" - integrity sha512-UhQ4Tpgv6a/7fmvleXEpyQAg8FWcemqzAPY2F75QBygEDD4Hsz2fFujTAEUBQ1an+eNQjzk7EC7TTbqXOmiwAw== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-auth" "^1.0.0" - "@azure/core-tracing" "1.0.0-preview.7" - "@azure/logger" "^1.0.0" - "@opentelemetry/types" "^0.2.0" - "@types/node-fetch" "^2.5.0" - "@types/tunnel" "^0.0.1" - cross-env "^6.0.3" - form-data "^3.0.0" - node-fetch "^2.6.0" - process "^0.11.10" - tough-cookie "^3.0.1" - tslib "^1.10.0" - tunnel "^0.0.6" - uuid "^3.3.2" - xml2js "^0.4.19" + tslib "^2.6.2" -"@azure/core-paging@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@azure/core-paging/-/core-paging-1.1.0.tgz#568c0e6d6d7590902f1d9cbe7d7cefed427552f7" - integrity sha512-Di26joIBaa5E/YAIAcis2LytbNy/LKTmgj+CUYZ8aLnzrN8h9AgVNASYOFXf+weJFD0pyaTAeW4GAt6P9NDFWw== +"@azure/core-http-compat@^2.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz#d1585ada24ba750dc161d816169b33b35f762f0d" + integrity sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ== dependencies: - "@azure/core-asynciterator-polyfill" "^1.0.0" + "@azure/abort-controller" "^2.0.0" + "@azure/core-client" "^1.3.0" + "@azure/core-rest-pipeline" "^1.3.0" "@azure/core-paging@^1.1.1": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@azure/core-paging/-/core-paging-1.5.0.tgz#5a5b09353e636072e6a7fc38f7879e11d0afb15f" - integrity sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw== + version "1.6.2" + resolved "https://registry.yarnpkg.com/@azure/core-paging/-/core-paging-1.6.2.tgz#40d3860dc2df7f291d66350b2cfd9171526433e7" + integrity sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA== dependencies: - tslib "^2.2.0" + tslib "^2.6.2" -"@azure/core-rest-pipeline@^1.1.0", "@azure/core-rest-pipeline@^1.9.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.12.1.tgz#d49f3daa8d282347dda6395f489af0050087901f" - integrity sha512-SsyWQ+T5MFQRX+M8H/66AlaI6HyCbQStGfFngx2fuiW+vKI2DkhtOvbYodPyf9fOe/ARLWWc3ohX54lQ5Kmaog== +"@azure/core-rest-pipeline@1.16.3": + version "1.16.3" + resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.3.tgz#bde3bc3ebad7f885ddd9de6af5e5a8fc254b287e" + integrity sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w== dependencies: - "@azure/abort-controller" "^1.0.0" + "@azure/abort-controller" "^2.0.0" "@azure/core-auth" "^1.4.0" "@azure/core-tracing" "^1.0.1" - "@azure/core-util" "^1.3.0" + "@azure/core-util" "^1.9.0" "@azure/logger" "^1.0.0" - form-data "^4.0.0" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - tslib "^2.2.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + tslib "^2.6.2" -"@azure/core-rest-pipeline@^1.2.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.0.tgz#12c6d1601c5a598b8ccf37bb7c5daf421f7f7ea9" - integrity sha512-m6c4iAalfaf6sytOOQhLKFprEHSkSjQuRgkW7MTMnAN+GENDDL4XZJp7WKFnq9VpKUE+ggq+rp5xX9GI93lumw== +"@azure/core-rest-pipeline@^1.1.0", "@azure/core-rest-pipeline@^1.10.1", "@azure/core-rest-pipeline@^1.15.1", "@azure/core-rest-pipeline@^1.3.0", "@azure/core-rest-pipeline@^1.9.1": + version "1.18.2" + resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.2.tgz#fa3a83b412d4b3e33edca30a71b1d5838306c075" + integrity sha512-IkTf/DWKyCklEtN/WYW3lqEsIaUDshlzWRlZNNwSYtFcCBQz++OtOjxNpm8rr1VcbMS6RpjybQa3u6B6nG0zNw== dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-auth" "^1.4.0" + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.8.0" "@azure/core-tracing" "^1.0.1" - "@azure/core-util" "^1.0.0" + "@azure/core-util" "^1.11.0" "@azure/logger" "^1.0.0" - form-data "^4.0.0" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - tslib "^2.2.0" - uuid "^8.3.0" - -"@azure/core-tracing@1.0.0-preview.7": - version "1.0.0-preview.7" - resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.0.0-preview.7.tgz#e9ee9c88f0dcf50d8e5b468fc827203165ecbc3f" - integrity sha512-pkFCw6OiJrpR+aH1VQe6DYm3fK2KWCC5Jf3m/Pv1RxF08M1Xm08RCyQ5Qe0YyW5L16yYT2nnV48krVhYZ6SGFA== - dependencies: - "@opencensus/web-types" "0.0.7" - "@opentelemetry/types" "^0.2.0" - tslib "^1.9.3" - -"@azure/core-tracing@^1.0.0", "@azure/core-tracing@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.0.1.tgz#352a38cbea438c4a83c86b314f48017d70ba9503" - integrity sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw== - dependencies: - tslib "^2.2.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + tslib "^2.6.2" -"@azure/core-util@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.1.1.tgz#8f87b3dd468795df0f0849d9f096c3e7b29452c1" - integrity sha512-A4TBYVQCtHOigFb2ETiiKFDocBoI1Zk2Ui1KpI42aJSIDexF7DHQFpnjonltXAIU/ceH+1fsZAWWgvX6/AKzog== +"@azure/core-tracing@^1.0.0", "@azure/core-tracing@^1.0.1", "@azure/core-tracing@^1.1.1", "@azure/core-tracing@^1.1.2", "@azure/core-tracing@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.2.0.tgz#7be5d53c3522d639cf19042cbcdb19f71bc35ab2" + integrity sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg== dependencies: - "@azure/abort-controller" "^1.0.0" - tslib "^2.2.0" + tslib "^2.6.2" -"@azure/core-util@^1.3.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.4.0.tgz#c120a56b3e48a9e4d20619a0b00268ae9de891c7" - integrity sha512-eGAyJpm3skVQoLiRqm/xPa+SXi/NPDdSHMxbRAz2lSprd+Zs+qrpQGQQ2VQ3Nttu+nSZR4XoYQC71LbEI7jsig== +"@azure/core-util@^1.1.0", "@azure/core-util@^1.11.0", "@azure/core-util@^1.6.1", "@azure/core-util@^1.8.1", "@azure/core-util@^1.9.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.11.0.tgz#f530fc67e738aea872fbdd1cc8416e70219fada7" + integrity sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g== dependencies: - "@azure/abort-controller" "^1.0.0" - tslib "^2.2.0" + "@azure/abort-controller" "^2.0.0" + tslib "^2.6.2" -"@azure/core-xml@^1.0.0": - version "1.3.4" - resolved "https://registry.yarnpkg.com/@azure/core-xml/-/core-xml-1.3.4.tgz#516092f948b1b609b6c2afb8437acd204527e323" - integrity sha512-B1xI79Ur/u+KR69fGTcsMNj8KDjBSqAy0Ys6Byy4Qm1CqoUy7gCT5A7Pej0EBWRskuH6bpCwrAnosfmQEalkcg== +"@azure/core-xml@^1.0.0", "@azure/core-xml@^1.4.3": + version "1.4.4" + resolved "https://registry.yarnpkg.com/@azure/core-xml/-/core-xml-1.4.4.tgz#a8656751943bf492762f758d147d33dfcd933d9e" + integrity sha512-J4FYAqakGXcbfeZjwjMzjNcpcH4E+JtEBv+xcV1yL0Ydn/6wbQfeFKTCHh9wttAi0lmajHw7yBbHPRG+YHckZQ== dependencies: - fast-xml-parser "^4.2.4" - tslib "^2.2.0" + fast-xml-parser "^4.4.1" + tslib "^2.6.2" "@azure/cosmos@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@azure/cosmos/-/cosmos-4.0.0.tgz#5fda8b35cb62bbcda52159b96c4c3981a843d5b9" - integrity sha512-/Z27p1+FTkmjmm8jk90zi/HrczPHw2t8WecFnsnTe4xGocWl0Z4clP0YlLUTJPhRLWYa5upwD9rMvKJkS1f1kg== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-auth" "^1.3.0" - "@azure/core-rest-pipeline" "^1.2.0" - "@azure/core-tracing" "^1.0.0" - debug "^4.1.1" + version "4.2.0" + resolved "https://registry.yarnpkg.com/@azure/cosmos/-/cosmos-4.2.0.tgz#eb1379a6bf1d8e12d07151ce6e53f5248d63a715" + integrity sha512-acfAQTYLxgB/iZK7XvTVYe9NPk6DECEgcIXDQhyn7Uo4dGxeeW5D3YqLjLJrrzND5Iawer3eUQ5/iiLWvTGAxQ== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.7.1" + "@azure/core-rest-pipeline" "^1.15.1" + "@azure/core-tracing" "^1.1.1" + "@azure/core-util" "^1.8.1" fast-json-stable-stringify "^2.1.0" - jsbi "^3.1.3" - node-abort-controller "^3.0.0" - priorityqueuejs "^1.0.0" - semaphore "^1.0.5" - tslib "^2.2.0" - universal-user-agent "^6.0.0" - uuid "^8.3.0" + jsbi "^4.3.0" + priorityqueuejs "^2.0.0" + semaphore "^1.1.0" + tslib "^2.6.2" "@azure/data-tables@^13.2.2": - version "13.2.2" - resolved "https://registry.yarnpkg.com/@azure/data-tables/-/data-tables-13.2.2.tgz#9aa82992d7317a779ecf66436ffa96b887d8e616" - integrity sha512-Dq2Aq0mMMF0BPzYQKdBY/OtO7VemP/foh6z+mJpUO1hRL+65C1rGQUJf20LJHotSyU8wHb4HJzOs+Z50GXSy1w== + version "13.3.0" + resolved "https://registry.yarnpkg.com/@azure/data-tables/-/data-tables-13.3.0.tgz#dda5065fb550f4eb7a6dbfc7c70b71d0d33cee57" + integrity sha512-g5dbhURt151j1sEbAaAkQ5eVXiZeyZxzrmIO2q9qpvzdOiijRt+jmo8Nmy0QaMb1uGgPeEHtBaKjgS6lxN3/NA== dependencies: "@azure/core-auth" "^1.3.0" "@azure/core-client" "^1.0.0" "@azure/core-paging" "^1.1.1" "@azure/core-rest-pipeline" "^1.1.0" "@azure/core-tracing" "^1.0.0" + "@azure/core-util" "^1.6.1" "@azure/core-xml" "^1.0.0" "@azure/logger" "^1.0.0" tslib "^2.2.0" + +"@azure/functions@^3.2.0": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@azure/functions/-/functions-3.5.1.tgz#98ac5c18f84835fd5821de404c52abbd458871f6" + integrity sha512-6UltvJiuVpvHSwLcK/Zc6NfUwlkDLOFFx97BHCJzlWNsfiWwzwmTsxJXg4kE/LemKTHxPpfoPE+kOJ8hAdiKFQ== + dependencies: + iconv-lite "^0.6.3" + long "^4.0.0" uuid "^8.3.0" "@azure/logger@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.0.0.tgz#48b371dfb34288c8797e5c104f6c4fb45bf1772c" - integrity sha512-g2qLDgvmhyIxR3JVS8N67CyIOeFRKQlX/llxYJQr1OSGQqM3HTpVP8MjmjcEKbL/OIt2N9C9UFaNQuKOw1laOA== + version "1.1.4" + resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.1.4.tgz#223cbf2b424dfa66478ce9a4f575f59c6f379768" + integrity sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ== dependencies: - tslib "^1.9.3" - -"@azure/storage-queue@^12.0.0": - version "12.0.4" - resolved "https://registry.yarnpkg.com/@azure/storage-queue/-/storage-queue-12.0.4.tgz#76c25ddb2ebd2c9bdee0b29d7080796dbd35bf6b" - integrity sha512-P8uafGxkb33XHq/yqGy1+YwKkjsk/8NlfabK7/B7i4JqJTtwXgv5KK2vUvTC0TIkW1KOQTvqB6IJdk6bYC68Nw== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-http" "^1.0.3" - "@azure/core-paging" "^1.1.0" - "@azure/core-tracing" "1.0.0-preview.7" - "@azure/logger" "^1.0.0" - "@opentelemetry/types" "^0.2.0" - tslib "^1.10.0" + tslib "^2.6.2" -"@babel/code-frame@^7.0.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== +"@azure/opentelemetry-instrumentation-azure-sdk@^1.0.0-beta.5": + version "1.0.0-beta.7" + resolved "https://registry.yarnpkg.com/@azure/opentelemetry-instrumentation-azure-sdk/-/opentelemetry-instrumentation-azure-sdk-1.0.0-beta.7.tgz#db55c80a7778371312f8ff95a7b854a14e88dd76" + integrity sha512-boG33EDRcbw0Jo2cRgB6bccSirKOzYdYFMdcSsnOajLCLfJ8WIve3vxUMi7YZKxM8txZX/0cwzUU6crXmYxXZg== dependencies: - "@babel/highlight" "^7.8.3" + "@azure/core-tracing" "^1.2.0" + "@azure/logger" "^1.0.0" + "@opentelemetry/api" "^1.9.0" + "@opentelemetry/core" "^1.26.0" + "@opentelemetry/instrumentation" "^0.53.0" + tslib "^2.7.0" -"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.21.4": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" - integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== +"@azure/storage-queue@^12.0.0": + version "12.25.0" + resolved "https://registry.yarnpkg.com/@azure/storage-queue/-/storage-queue-12.25.0.tgz#69803070857d2341ab22941e2409ed5994e70f66" + integrity sha512-uoobHFbH/o7wIul/sCm32X2YFq6zb1XpNdpKIms9I60mwG3BBaOpEs5pgQV5a5ONG5WMSHlo8E1dNFB5ZZIa1g== dependencies: - "@babel/highlight" "^7.18.6" + "@azure/abort-controller" "^2.1.2" + "@azure/core-auth" "^1.4.0" + "@azure/core-client" "^1.6.2" + "@azure/core-http-compat" "^2.0.0" + "@azure/core-paging" "^1.1.1" + "@azure/core-rest-pipeline" "^1.10.1" + "@azure/core-tracing" "^1.1.2" + "@azure/core-util" "^1.6.1" + "@azure/core-xml" "^1.4.3" + "@azure/logger" "^1.0.0" + tslib "^2.2.0" -"@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== dependencies: - "@babel/highlight" "^7.18.6" + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" -"@babel/compat-data@^7.21.4": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.4.tgz#457ffe647c480dff59c2be092fc3acf71195c87f" - integrity sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g== +"@babel/compat-data@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.5.tgz#df93ac37f4417854130e21d72c66ff3d4b897fc7" + integrity sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg== -"@babel/core@^7.11.6", "@babel/core@^7.12.3": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.4.tgz#c6dc73242507b8e2a27fd13a9c1814f9fa34a659" - integrity sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA== +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.7.tgz#0439347a183b97534d52811144d763a17f9d2b24" + integrity sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.21.4" - "@babel/generator" "^7.21.4" - "@babel/helper-compilation-targets" "^7.21.4" - "@babel/helper-module-transforms" "^7.21.2" - "@babel/helpers" "^7.21.0" - "@babel/parser" "^7.21.4" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.4" - "@babel/types" "^7.21.4" - convert-source-map "^1.7.0" + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.5" + "@babel/helper-compilation-targets" "^7.26.5" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.7" + "@babel/parser" "^7.26.7" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.26.7" + "@babel/types" "^7.26.7" + convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.0" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.26.5", "@babel/generator@^7.7.2": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.5.tgz#e44d4ab3176bbcaf78a5725da5f1dc28802a9458" + integrity sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw== + dependencies: + "@babel/parser" "^7.26.5" + "@babel/types" "^7.26.5" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8" + integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA== + dependencies: + "@babel/compat-data" "^7.26.5" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" -"@babel/generator@^7.21.4", "@babel/generator@^7.7.2": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.4.tgz#64a94b7448989f421f919d5239ef553b37bb26bc" - integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA== +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== dependencies: - "@babel/types" "^7.21.4" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" -"@babel/helper-compilation-targets@^7.21.4": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz#770cd1ce0889097ceacb99418ee6934ef0572656" - integrity sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg== +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== dependencies: - "@babel/compat-data" "^7.21.4" - "@babel/helper-validator-option" "^7.21.0" - browserslist "^4.21.3" - lru-cache "^5.1.1" - semver "^6.3.0" + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" -"@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== - -"@babel/helper-function-name@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" - integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== - dependencies: - "@babel/template" "^7.20.7" - "@babel/types" "^7.21.0" - -"@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-module-transforms@^7.21.2": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" - integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.20.2" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.2" - "@babel/types" "^7.21.2" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" - integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== - -"@babel/helper-simple-access@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" - integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== - dependencies: - "@babel/types" "^7.20.2" - -"@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-string-parser@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" - integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== - -"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== - -"@babel/helper-validator-identifier@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" - integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== - -"@babel/helper-validator-option@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" - integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== - -"@babel/helpers@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" - integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== - dependencies: - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" - -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.8.0": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" + integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b" - integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg== +"@babel/helpers@^7.26.7": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.7.tgz#fd1d2a7c431b6e39290277aacfd8367857c576a4" + integrity sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.7" -"@babel/parser@^7.14.7", "@babel/parser@^7.21.4": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17" - integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.9", "@babel/parser@^7.26.5", "@babel/parser@^7.26.7": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.7.tgz#e114cd099e5f7d17b05368678da0fb9f69b3385c" + integrity sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w== + dependencies: + "@babel/types" "^7.26.7" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -445,14 +346,28 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz#3b1412847699eea739b4f2602c74ce36f6b0b0f7" + integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -467,13 +382,13 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" - integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290" + integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-plugin-utils" "^7.25.9" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -487,7 +402,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -515,7 +430,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== @@ -523,91 +445,117 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz#2751948e9b7c6d771a8efa59340c15d4a2891ff8" - integrity sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/template@^7.20.7", "@babel/template@^7.3.3": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" - integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - -"@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4", "@babel/traverse@^7.7.2": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.4.tgz#a836aca7b116634e97a6ed99976236b3282c9d36" - integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q== - dependencies: - "@babel/code-frame" "^7.21.4" - "@babel/generator" "^7.21.4" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.21.4" - "@babel/types" "^7.21.4" - debug "^4.1.0" + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399" + integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/template@^7.25.9", "@babel/template@^7.3.3": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.7": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.7.tgz#99a0a136f6a75e7fb8b0a1ace421e0b25994b8bb" + integrity sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.5" + "@babel/parser" "^7.26.7" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.7" + debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.3.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" - integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.5", "@babel/types@^7.26.7", "@babel/types@^7.3.3": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.7.tgz#5e2b89c0768e874d4d061961f3a5a153d71dc17a" + integrity sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg== dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" - to-fast-properties "^2.0.0" - -"@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.4", "@babel/types@^7.3.3": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.4.tgz#2d5d6bb7908699b3b416409ffd3b5daa25b030d4" - integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA== - dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" - to-fast-properties "^2.0.0" + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@colors/colors@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" - integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== "@dabh/diagnostics@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31" - integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== dependencies: colorspace "1.1.x" enabled "2.0.x" kuler "^2.0.0" -"@eslint-community/eslint-utils@^4.4.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.1" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== dependencies: eslint-visitor-keys "^3.4.3" -"@eslint-community/regexpp@^4.10.0": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": version "4.12.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + "@eslint/js@^9.0.0": version "9.19.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.19.0.tgz#51dbb140ed6b49d05adc0b171c41e1a8713b7789" integrity sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ== +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -619,115 +567,115 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2": +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.5.0.tgz#593a6c5c0d3f75689835f1b3b4688c4f8544cb57" - integrity sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ== +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.5.0.tgz#76674b96904484e8214614d17261cc491e5f1f03" - integrity sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ== +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: - "@jest/console" "^29.5.0" - "@jest/reporters" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^29.5.0" - jest-config "^29.5.0" - jest-haste-map "^29.5.0" - jest-message-util "^29.5.0" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-resolve-dependencies "^29.5.0" - jest-runner "^29.5.0" - jest-runtime "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" - jest-watcher "^29.5.0" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" micromatch "^4.0.4" - pretty-format "^29.5.0" + pretty-format "^29.7.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.5.0.tgz#9152d56317c1fdb1af389c46640ba74ef0bb4c65" - integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: - "@jest/fake-timers" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.5.0" + jest-mock "^29.7.0" -"@jest/expect-utils@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" - integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" -"@jest/expect@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.5.0.tgz#80952f5316b23c483fbca4363ce822af79c38fba" - integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: - expect "^29.5.0" - jest-snapshot "^29.5.0" + expect "^29.7.0" + jest-snapshot "^29.7.0" -"@jest/fake-timers@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.5.0.tgz#d4d09ec3286b3d90c60bdcd66ed28d35f1b4dc2c" - integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^29.5.0" - jest-mock "^29.5.0" - jest-util "^29.5.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -"@jest/globals@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.5.0.tgz#6166c0bfc374c58268677539d0c181f9c1833298" - integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: - "@jest/environment" "^29.5.0" - "@jest/expect" "^29.5.0" - "@jest/types" "^29.5.0" - jest-mock "^29.5.0" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" -"@jest/reporters@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.5.0.tgz#985dfd91290cd78ddae4914ba7921bcbabe8ac9b" - integrity sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA== +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@jridgewell/trace-mapping" "^0.3.15" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" @@ -735,170 +683,202 @@ glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.5.0" - jest-util "^29.5.0" - jest-worker "^29.5.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" - integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: - "@sinclair/typebox" "^0.25.16" + "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.4.3.tgz#ff8d05cbfff875d4a791ab679b4333df47951d20" - integrity sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w== +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: - "@jridgewell/trace-mapping" "^0.3.15" + "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.5.0.tgz#7c856a6ca84f45cc36926a4e9c6b57f1973f1408" - integrity sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz#34d7d82d3081abd523dbddc038a3ddcb9f6d3cc4" - integrity sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ== +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: - "@jest/test-result" "^29.5.0" + "@jest/test-result" "^29.7.0" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" + jest-haste-map "^29.7.0" slash "^3.0.0" -"@jest/transform@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.5.0.tgz#cf9c872d0965f0cbd32f1458aa44a2b1988b00f9" - integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^29.5.0" - "@jridgewell/trace-mapping" "^0.3.15" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^2.0.0" fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - jest-regex-util "^29.4.3" - jest-util "^29.5.0" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" write-file-atomic "^4.0.2" -"@jest/types@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" - integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: - "@jest/schemas" "^29.4.3" + "@jest/schemas" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== dependencies: - "@jridgewell/set-array" "^1.0.0" + "@jridgewell/set-array" "^1.2.1" "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.17": - version "0.3.18" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" "@jsdevtools/ono@^7.1.3": version "7.1.3" resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== +"@microsoft/applicationinsights-web-snippet@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web-snippet/-/applicationinsights-web-snippet-1.0.1.tgz#6bb788b2902e48bf5d460c38c6bb7fedd686ddd7" + integrity sha512-2IHAOaLauc8qaAitvWS+U931T+ze+7MNWrDHY47IENP5y2UA0vqJDu67kWZDdpCN1fFC77sfgfB+HV7SrKshnQ== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: - "@nodelib/fs.stat" "2.0.3" + "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - "@nodelib/fs.scandir" "2.1.3" + "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@opencensus/web-types@0.0.7": - version "0.0.7" - resolved "https://registry.yarnpkg.com/@opencensus/web-types/-/web-types-0.0.7.tgz#4426de1fe5aa8f624db395d2152b902874f0570a" - integrity sha512-xB+w7ZDAu3YBzqH44rCmG9/RlrOmFuDPt/bpf17eJr8eZSrLt7nc7LnWdxM9Mmoj/YKMHpxRg28txu3TcpiL+g== +"@opentelemetry/api-logs@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.53.0.tgz#c478cbd8120ec2547b64edfa03a552cfe42170be" + integrity sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw== + dependencies: + "@opentelemetry/api" "^1.0.0" + +"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.7.0", "@opentelemetry/api@^1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== -"@opentelemetry/types@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@opentelemetry/types/-/types-0.2.0.tgz#2a0afd40fa7026e39ea56a454642bda72b172f80" - integrity sha512-GtwNB6BNDdsIPAYEdpp3JnOGO/3AJxjPvny53s3HERBdXSJTGQw8IRhiaTEX0b3w9P8+FwFZde4k+qkjn67aVw== +"@opentelemetry/core@1.30.1", "@opentelemetry/core@^1.19.0", "@opentelemetry/core@^1.26.0": + version "1.30.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.30.1.tgz#a0b468bb396358df801881709ea38299fc30ab27" + integrity sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ== + dependencies: + "@opentelemetry/semantic-conventions" "1.28.0" + +"@opentelemetry/instrumentation@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.53.0.tgz#e6369e4015eb5112468a4d45d38dcada7dad892d" + integrity sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A== + dependencies: + "@opentelemetry/api-logs" "0.53.0" + "@types/shimmer" "^1.2.0" + import-in-the-middle "^1.8.1" + require-in-the-middle "^7.1.1" + semver "^7.5.2" + shimmer "^1.2.1" + +"@opentelemetry/resources@1.30.1": + version "1.30.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.30.1.tgz#a4eae17ebd96947fdc7a64f931ca4b71e18ce964" + integrity sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA== + dependencies: + "@opentelemetry/core" "1.30.1" + "@opentelemetry/semantic-conventions" "1.28.0" + +"@opentelemetry/sdk-trace-base@^1.19.0": + version "1.30.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz#41a42234096dc98e8f454d24551fc80b816feb34" + integrity sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg== + dependencies: + "@opentelemetry/core" "1.30.1" + "@opentelemetry/resources" "1.30.1" + "@opentelemetry/semantic-conventions" "1.28.0" + +"@opentelemetry/semantic-conventions@1.28.0", "@opentelemetry/semantic-conventions@^1.19.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz#337fb2bca0453d0726696e745f50064411f646d6" + integrity sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA== "@pagopa/eslint-config@^4.0.0": version "4.0.1" @@ -913,18 +893,18 @@ typescript-eslint "^7.6.0" "@pagopa/io-functions-app-sdk@x": - version "5.13.0" - resolved "https://registry.yarnpkg.com/@pagopa/io-functions-app-sdk/-/io-functions-app-sdk-5.13.0.tgz#e24664dea0b252e6ea96cd081991ff85eb5e53d6" - integrity sha512-n/RB+XFRsGhvNTzR/9jvo2q3L8mA3kEuVgWc9e+WK/t9da9P1hfLZVlOxxA4T2yHHRXEWGIS54Xc3y8iaJypGA== + version "5.18.0" + resolved "https://registry.yarnpkg.com/@pagopa/io-functions-app-sdk/-/io-functions-app-sdk-5.18.0.tgz#842f456ec2705e41f7bb9618a020abebf15ce615" + integrity sha512-QEAakZNAvRKbu/sg3Am+Z5KBs6GD49jtBzkLF+NQhq4mJtj72k9qCCtuvwR4yOhF/JL5yCZB4h0d7+TLB87h7Q== dependencies: "@pagopa/ts-commons" "^10.0.0" fp-ts "^2.10.5" io-ts "^2.2.16" "@pagopa/io-functions-cgn-sdk@x": - version "2.6.3" - resolved "https://registry.yarnpkg.com/@pagopa/io-functions-cgn-sdk/-/io-functions-cgn-sdk-2.6.3.tgz#17117ddf0190aca903e4f8cc80f0b79dde60be50" - integrity sha512-U7cv8MhNOw0O10/whRLZhh4F8HkWoh0BWAJ1O7mpVS4NhAaEGKnYzro/6/24CBBI3xbDpxtFvdS0A+ZerQmx7g== + version "2.6.5" + resolved "https://registry.yarnpkg.com/@pagopa/io-functions-cgn-sdk/-/io-functions-cgn-sdk-2.6.5.tgz#8d708bd6a5ac5160bdc9f90cad96841a1555649e" + integrity sha512-fQg7/dXDRXIorUNAZREnnmajswc2V4PimsnPzGZT4Wi9Ddf7qzdFa/EGPTURLPNTleiKIj0pC4IJGzwYT7mD2Q== dependencies: "@pagopa/ts-commons" "^10.0.0" fp-ts "^2.10.5" @@ -996,23 +976,7 @@ semver "^7.3.7" validator "^13.7.0" -"@pagopa/ts-commons@^13.1.1": - version "13.1.1" - resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-13.1.1.tgz#a8bef24022af7d49253d58626914273e142f79dd" - integrity sha512-IjmsrGwO9DFuU1IpzzBRNf3VIO9gd+gNdl4jGK4U1P7T47lWqozDqp6rPjF2sZfA1EoKnH5cFfgYT8uVsH0Z0g== - dependencies: - abort-controller "^3.0.0" - agentkeepalive "^4.1.4" - applicationinsights "^2.9.5" - jose "^4.15.5" - json-set-map "^1.1.2" - jsonwebtoken "^9.0.1" - node-fetch "^2.6.0" - semver "^7.5.2" - ulid "^2.3.0" - validator "^13.7.0" - -"@pagopa/ts-commons@^13.1.2": +"@pagopa/ts-commons@^13.1.1", "@pagopa/ts-commons@^13.1.2": version "13.1.2" resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-13.1.2.tgz#c98b0ae2d9700ab670edfcda5b1cd46f3b79b35d" integrity sha512-TAdqhbaTG5YPQIRyC5qs1qWYr/YPB1aPb1fEwCTOKVVmKZrguQxkAWqdkz6uDaKmKlkUKfOxsJTmMZu2/tpyfg== @@ -1042,39 +1006,39 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== -"@redis/bloom@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.1.0.tgz#64e310ddee72010676e14296076329e594a1f6c7" - integrity sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ== +"@redis/bloom@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" + integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== -"@redis/client@1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.4.2.tgz#2a3f5e98bc33b7b979390442e6e08f96e57fabdd" - integrity sha512-oUdEjE0I7JS5AyaAjkD3aOXn9NhO7XKyPyXEyrgFDu++VrVBHUPnV6dgEya9TcMuj5nIJRuCzCm8ZP+c9zCHPw== +"@redis/client@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.6.0.tgz#dcf4ae1319763db6fdddd6de7f0af68a352c30ea" + integrity sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg== dependencies: - cluster-key-slot "1.1.1" + cluster-key-slot "1.1.2" generic-pool "3.9.0" yallist "4.0.0" -"@redis/graph@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.0.tgz#cc2b82e5141a29ada2cce7d267a6b74baa6dd519" - integrity sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg== +"@redis/graph@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.1.tgz#8c10df2df7f7d02741866751764031a957a170ea" + integrity sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw== -"@redis/json@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.4.tgz#f372b5f93324e6ffb7f16aadcbcb4e5c3d39bda1" - integrity sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw== +"@redis/json@1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.7.tgz#016257fcd933c4cbcb9c49cde8a0961375c6893b" + integrity sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ== -"@redis/search@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.0.tgz#7abb18d431f27ceafe6bcb4dd83a3fa67e9ab4df" - integrity sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ== +"@redis/search@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.2.0.tgz#50976fd3f31168f585666f7922dde111c74567b8" + integrity sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw== -"@redis/time-series@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.4.tgz#af85eb080f6934580e4d3b58046026b6c2b18717" - integrity sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng== +"@redis/time-series@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.1.0.tgz#cba454c05ec201bd5547aaf55286d44682ac8eb5" + integrity sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g== "@sendgrid/client@^6.5.5": version "6.5.5" @@ -1101,41 +1065,36 @@ "@sendgrid/client" "^6.5.5" "@sendgrid/helpers" "^6.5.5" -"@sinclair/typebox@^0.25.16": - version "0.25.24" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" - integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@sinonjs/commons@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" - integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^10.0.2": - version "10.0.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" - integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: - "@sinonjs/commons" "^2.0.0" - -"@tootallnate/once@2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" - integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + "@sinonjs/commons" "^3.0.0" "@types/accepts@*": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" - integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ== + version "1.3.7" + resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.7.tgz#3b98b1889d2b2386604c2bbbe62e4fb51e95b265" + integrity sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ== dependencies: "@types/node" "*" "@types/babel__core@^7.1.14": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" - integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" @@ -1144,66 +1103,61 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.3.tgz#dfc508a85781e5698d5b33443416b6268c4b3e8d" - integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: - "@babel/types" "^7.3.0" + "@babel/types" "^7.20.7" "@types/body-parser@*": - version "1.19.0" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" - integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== dependencies: "@types/connect" "*" "@types/node" "*" "@types/caseless@*": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" - integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== - -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + version "0.12.5" + resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.5.tgz#db9468cb1b1b5a925b8f34822f1669df0c5472f5" + integrity sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg== "@types/connect@*": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" - integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" "@types/content-disposition@*": - version "0.5.4" - resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.4.tgz#de48cf01c79c9f1560bcfd8ae43217ab028657f8" - integrity sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ== + version "0.5.8" + resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.8.tgz#6742a5971f490dc41e59d277eee71361fea0b537" + integrity sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg== -"@types/cookiejar@*": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" - integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== +"@types/cookiejar@*", "@types/cookiejar@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78" + integrity sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q== "@types/cookies@*": - version "0.7.7" - resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.7.tgz#7a92453d1d16389c05a5301eef566f34946cfd81" - integrity sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA== + version "0.9.0" + resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.9.0.tgz#a2290cfb325f75f0f28720939bee854d4142aee2" + integrity sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q== dependencies: "@types/connect" "*" "@types/express" "*" @@ -1217,29 +1171,34 @@ dependencies: "@types/node" "*" -"@types/events@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - "@types/express-enforces-ssl@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/express-enforces-ssl/-/express-enforces-ssl-1.1.1.tgz#9b686f3aeb7279ae170bd1493546c836da43aac6" - integrity sha512-TGLJv2jZs5E26lAqLMmcsqPJi1F5SxEsKbqdyAyYa3sicanX29ZP/bVW+1M3q1/fshMvQhGaPxql8IV7sbTh4A== + version "1.1.4" + resolved "https://registry.yarnpkg.com/@types/express-enforces-ssl/-/express-enforces-ssl-1.1.4.tgz#01ae67560fb382b6505b32d9f801bed62b7cab34" + integrity sha512-RH+kdrWRfg0F52/WmKbXF+UHuw4NLhf4SJs5vBgQ7gq5+W9yXphRctO3bTM4LHEj00wb50SPF3n/d3yaSEtPhA== dependencies: "@types/express" "*" -"@types/express-serve-static-core@4.17.34", "@types/express-serve-static-core@^4.17.18": - version "4.17.34" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz#c119e85b75215178bc127de588e93100698ab4cc" - integrity sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w== +"@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^5.0.0", "@types/express-serve-static-core@~5.0.0": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz#41fec4ea20e9c7b22f024ab88a95c6bb288f51b8" + integrity sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" "@types/send" "*" -"@types/express@*", "@types/express@4.17.11": +"@types/express@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.0.tgz#13a7d1f75295e90d19ed6e74cab3678488eaa96c" + integrity sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/express@4.17.11": version "4.17.11" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545" integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg== @@ -1250,18 +1209,17 @@ "@types/serve-static" "*" "@types/glob@^5.0.35": - version "5.0.36" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.36.tgz#0c80a9c8664fc7d19781de229f287077fd622cb2" - integrity sha512-KEzSKuP2+3oOjYYjujue6Z3Yqis5HKA1BsIC+jZ1v3lrRNdsqyNNtX0rQf6LSuI4DJJ2z5UV//zBZCcvM0xikg== + version "5.0.38" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.38.tgz#20e29f3c6332f6b3329f34711ebb31a03dd74a51" + integrity sha512-rTtf75rwyP9G2qO5yRpYtdJ6aU1QqEhWbtW55qEgquEDa6bXW0s2TWZfDm02GuppjEozOWG/F2UnPq5hAQb+gw== dependencies: - "@types/events" "*" "@types/minimatch" "*" "@types/node" "*" "@types/graceful-fs@^4.1.3": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" - integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" @@ -1273,46 +1231,46 @@ "@types/express" "*" "@types/http-assert@*": - version "1.5.3" - resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.3.tgz#ef8e3d1a8d46c387f04ab0f2e8ab8cb0c5078661" - integrity sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA== + version "1.5.6" + resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.6.tgz#b6b657c38a2350d21ce213139f33b03b2b5fa431" + integrity sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw== "@types/http-errors@*": - version "1.8.1" - resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.1.tgz#e81ad28a60bee0328c6d2384e029aec626f1ae67" - integrity sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q== + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" "@types/jest@^29.5.1": - version "29.5.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.1.tgz#83c818aa9a87da27d6da85d3378e5a34d2f31a47" - integrity sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ== + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== dependencies: expect "^29.0.0" pretty-format "^29.0.0" "@types/json-schema@^7.0.6": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/jsonwebtoken@7.2.7": version "7.2.7" @@ -1322,21 +1280,21 @@ "@types/node" "*" "@types/keygrip@*": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" - integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.6.tgz#1749535181a2a9b02ac04a797550a8787345b740" + integrity sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ== "@types/koa-compose@*": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.5.tgz#85eb2e80ac50be95f37ccf8c407c09bbe3468e9d" - integrity sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ== + version "3.2.8" + resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.8.tgz#dec48de1f6b3d87f87320097686a915f1e954b57" + integrity sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA== dependencies: "@types/koa" "*" "@types/koa@*": - version "2.13.4" - resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.4.tgz#10620b3f24a8027ef5cbae88b393d1b31205726b" - integrity sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw== + version "2.15.0" + resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.15.0.tgz#eca43d76f527c803b491731f95df575636e7b6f2" + integrity sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g== dependencies: "@types/accepts" "*" "@types/content-disposition" "*" @@ -1352,37 +1310,44 @@ resolved "https://registry.yarnpkg.com/@types/lolex/-/lolex-2.1.3.tgz#793557c9b8ad319b4c8e4c6548b90893f4aa5f69" integrity sha512-nEipOLYyZJ4RKHCg7tlR37ewFy91oggmip2MBzPdVQ8QhTFqjcRhE8R0t4tfpDnSlxGWHoEGJl0UCC4kYhqoiw== +"@types/methods@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@types/methods/-/methods-1.1.4.tgz#d3b7ac30ac47c91054ea951ce9eed07b1051e547" + integrity sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ== + "@types/mime@^1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" - integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== "@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/morgan@^1.7.35": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.0.tgz#342119ae57fe67d36b91537143fc5aef16c2479f" - integrity sha512-warrzirh5dlTMaETytBTKR886pRXwr+SMZD87ZE13gLMR8Pzz69SiYFkvoDaii78qGP1iyBIUYz5GiXyryO//A== + version "1.9.9" + resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.9.tgz#d60dec3979e16c203a000159daa07d3fb7270d7f" + integrity sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ== dependencies: - "@types/express" "*" + "@types/node" "*" -"@types/node-fetch@^2.1.2", "@types/node-fetch@^2.5.0": - version "2.5.5" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.5.tgz#cd264e20a81f4600a6c52864d38e7fef72485e92" - integrity sha512-IWwjsyYjGw+em3xTvWVQi5MgYKbRs0du57klfTaZkv/B24AEQ/p/IopNeqIYNy3EsfHOpg8ieQSDomPcsYMHpA== +"@types/node-fetch@^2.1.2": + version "2.6.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03" + integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== dependencies: "@types/node" "*" - form-data "^3.0.0" + form-data "^4.0.0" "@types/node@*": - version "18.13.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850" - integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== + version "22.12.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.12.0.tgz#bf8af3b2af0837b5a62a368756ff2b705ae0048c" + integrity sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA== + dependencies: + undici-types "~6.20.0" -"@types/node@~20.18.0": +"@types/node@^20.17.0": version "20.17.16" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.16.tgz#b33b0edc1bf925b27349e494b871ca4451fabab4" integrity sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw== @@ -1390,72 +1355,67 @@ undici-types "~6.19.2" "@types/passport-http-bearer@^1.0.34": - version "1.0.37" - resolved "https://registry.yarnpkg.com/@types/passport-http-bearer/-/passport-http-bearer-1.0.37.tgz#6882825a46717725f952731d17e1bb0a698155a4" - integrity sha512-/2Z28LfgY7kP/GO75os+feTP+//qHfpYn3V7sWAl0kwNwyDT1eGgjO30OU+Lown00ogSee+fea8a0+fr/UpTXw== + version "1.0.41" + resolved "https://registry.yarnpkg.com/@types/passport-http-bearer/-/passport-http-bearer-1.0.41.tgz#ccf02934ff316fb16dcd147cd1c3abf623461093" + integrity sha512-ecW+9e8C+0id5iz3YZ+uIarsk/vaRPkKSajt1i1Am66t0mC9gDfQDKXZz9fnPOW2xKUufbmCSou4005VM94Feg== dependencies: "@types/express" "*" "@types/koa" "*" "@types/passport" "*" "@types/passport-local@^1.0.33": - version "1.0.33" - resolved "https://registry.yarnpkg.com/@types/passport-local/-/passport-local-1.0.33.tgz#d245b60c5b801cb3aeca1ffab557d5fe1534260d" - integrity sha512-+rn6ZIxje0jZ2+DAiWFI8vGG7ZFKB0hXx2cUdMmudSWsigSq6ES7Emso46r4HJk0qCgrZVfI8sJiM7HIYf4SbA== + version "1.0.38" + resolved "https://registry.yarnpkg.com/@types/passport-local/-/passport-local-1.0.38.tgz#8073758188645dde3515808999b1c218a6fe7141" + integrity sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg== dependencies: "@types/express" "*" "@types/passport" "*" "@types/passport-strategy" "*" "@types/passport-saml@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/passport-saml/-/passport-saml-1.1.1.tgz#f48db668ac3cd144be7c09a5a632807ce047931d" - integrity sha512-MkTJRvVLybgs7DgRUKXz4GfBs+lEkNDcTSmf2dD5BAlNeWvag4F4IknbjAHcY1o+6HLsOGrJ1Nf35exVxoJL5g== + version "1.1.7" + resolved "https://registry.yarnpkg.com/@types/passport-saml/-/passport-saml-1.1.7.tgz#d826f56cea567d3870e4570ff0fde655b3add5a0" + integrity sha512-pMKJvWlS06ZGXtWVbfULSYDYv9XlvDBhCmzkbuYOqfeVqfpgr2SJKRKvAZ3RK0TzNE2vO67WRSnMbPPz68TyEg== dependencies: "@types/express" "*" "@types/passport" "*" "@types/passport-strategy@*", "@types/passport-strategy@^0.2.35": - version "0.2.35" - resolved "https://registry.yarnpkg.com/@types/passport-strategy/-/passport-strategy-0.2.35.tgz#e52f5212279ea73f02d9b06af67efe9cefce2d0c" - integrity sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g== + version "0.2.38" + resolved "https://registry.yarnpkg.com/@types/passport-strategy/-/passport-strategy-0.2.38.tgz#482abba0b165cd4553ec8b748f30b022bd6c04d3" + integrity sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA== dependencies: "@types/express" "*" "@types/passport" "*" "@types/passport@*", "@types/passport@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/passport/-/passport-1.0.3.tgz#e459ed6c262bf0686684d1b05901be0d0b192a9c" - integrity sha512-nyztuxtDPQv9utCzU0qW7Gl8BY2Dn8BKlYAFFyxKipFxjaVd96celbkLCV/tRqqBUZ+JB8If3UfgV8347DTo3Q== + version "1.0.17" + resolved "https://registry.yarnpkg.com/@types/passport/-/passport-1.0.17.tgz#718a8d1f7000ebcf6bbc0853da1bc8c4bc7ea5e6" + integrity sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg== dependencies: "@types/express" "*" -"@types/prettier@^2.1.5": - version "2.7.2" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" - integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== - "@types/qr-image@^3.2.2": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@types/qr-image/-/qr-image-3.2.2.tgz#963346a18f0203f5a4cae767d7cdb78bb3601895" - integrity sha512-15nILh26cosGRYs5i9gemowO263cAKdIuLR1bwn2oKHL3vxqKyCoT0wXk41Lg6T3eIwo0go1jaGPZbejwMocZA== + version "3.2.9" + resolved "https://registry.yarnpkg.com/@types/qr-image/-/qr-image-3.2.9.tgz#0457d7adda32543f8ade10d409472ec57f75b456" + integrity sha512-vmqTI+ehoC07jtzjT9Dc+3eMpXTgdluD9orVHtp9bN1gE81SnOuMe9+EwmRuWfTH04YNyk1mihI/Vr7BIhUCZg== dependencies: "@types/node" "*" "@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + version "6.9.18" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.18.tgz#877292caa91f7c1b213032b34626505b746624c2" + integrity sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA== "@types/range-parser@*": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" - integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== "@types/range_check@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@types/range_check/-/range_check-1.4.0.tgz#040135701c22d1e4cbbefb4de2304c4d17f65638" - integrity sha512-Nz2HM497oh6XfVfnFssNv4+R2mQwXtzYIHwIAP9s9pxL4Rd0v6dea2ATAaTksvbUNtofvpfWGrF5bFhx1gp8gg== + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/range_check/-/range_check-1.4.2.tgz#6cf4a722dc2424782692fbeb6cda4ca153ea8a22" + integrity sha512-56MAq6Ioy/YPr0WIFjqEbVtNs7CxUoLWoWsPoJoxUnGhzbRvz2SAnTjoKu1MIUsKE7BBppiid64FFScas1FHtw== "@types/request-ip@^0.0.34": version "0.0.34" @@ -1465,9 +1425,9 @@ "@types/node" "*" "@types/request@^2.48.4": - version "2.48.8" - resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c" - integrity sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ== + version "2.48.12" + resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.12.tgz#0f590f615a10f87da18e9790ac94c29ec4c5ef30" + integrity sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw== dependencies: "@types/caseless" "*" "@types/node" "*" @@ -1475,9 +1435,9 @@ form-data "^2.5.0" "@types/send@*": - version "0.17.1" - resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" - integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== dependencies: "@types/mime" "^1" "@types/node" "*" @@ -1490,18 +1450,25 @@ "@types/mime" "^1" "@types/node" "*" +"@types/shimmer@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/shimmer/-/shimmer-1.2.0.tgz#9b706af96fa06416828842397a70dfbbf1c14ded" + integrity sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg== + "@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/superagent@*": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.7.tgz#a7d92d98c490ee0f802a127fdf149b9a114f77a5" - integrity sha512-JSwNPgRYjIC4pIeOqLwWwfGj6iP1n5NE6kNBEbGx2V8H78xCPwx7QpNp9plaI30+W3cFEzJO7BIIsXE+dbtaGg== + version "8.1.9" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-8.1.9.tgz#28bfe4658e469838ed0bf66d898354bcab21f49f" + integrity sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ== dependencies: - "@types/cookiejar" "*" + "@types/cookiejar" "^2.1.5" + "@types/methods" "^1.1.4" "@types/node" "*" + form-data "^4.0.0" "@types/superagent@^3.8.4": version "3.8.7" @@ -1512,9 +1479,9 @@ "@types/node" "*" "@types/supertest@^2.0.6": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.8.tgz#23801236e2b85204ed771a8e7c40febba7da2bda" - integrity sha512-wcax7/ip4XSSJRLbNzEIUVy2xjcBIZZAuSd2vtltQfRK7kxhx5WMHbLHkYdxN3wuQCrwpYrg86/9byDjPXoGMA== + version "2.0.16" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.16.tgz#7a1294edebecb960d957bbe9b26002a2b7f21cd7" + integrity sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg== dependencies: "@types/superagent" "*" @@ -1526,26 +1493,24 @@ "@types/swagger-schema-official" "*" "@types/swagger-schema-official@*": - version "2.0.21" - resolved "https://registry.yarnpkg.com/@types/swagger-schema-official/-/swagger-schema-official-2.0.21.tgz#56812a86dcd57ba60e5c51705ee96a2b2dc9b374" - integrity sha512-n9BbLOjR4Hre7B4TSGGMPohOgOg8tcp00uxqsIE00uuWQC0QuX57G1bqC1csLsk2DpTGtHkd0dEb3ipsCZ9dAA== + version "2.0.25" + resolved "https://registry.yarnpkg.com/@types/swagger-schema-official/-/swagger-schema-official-2.0.25.tgz#c8073914004d0a9c5412aeaf458d96e34c504840" + integrity sha512-T92Xav+Gf/Ik1uPW581nA+JftmjWPgskw/WBf4TJzxRG/SJ+DfNnNE+WuZ4mrXuzflQMqMkm1LSYjzYW7MB1Cg== "@types/tough-cookie@*": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" - integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== -"@types/tunnel@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.1.tgz#0d72774768b73df26f25df9184273a42da72b19c" - integrity sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A== - dependencies: - "@types/node" "*" +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== "@types/unist@^2.0.0", "@types/unist@^2.0.2": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" - integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== "@types/validator@^9.4.2": version "9.4.4" @@ -1553,21 +1518,21 @@ integrity sha512-7bWNKQ3lDMhRS2lxe1aHGTBijZ/a6wQfZmCtKJDefpb81sYd+FrfNqj6Gda1Tcw8bYK0gG1CVuNLWV2JS7K8Dw== "@types/xml2js@^0.4.5": - version "0.4.5" - resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.5.tgz#d21759b056f282d9c7066f15bbf5c19b908f22fa" - integrity sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w== + version "0.4.14" + resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.14.tgz#5d462a2a7330345e2309c6b549a183a376de8f9a" + integrity sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ== dependencies: "@types/node" "*" "@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": - version "17.0.24" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" - integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" @@ -1652,16 +1617,16 @@ "@typescript-eslint/types" "7.18.0" eslint-visitor-keys "^3.4.3" +"@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + a-sync-waterfall@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz#75b6b6aa72598b497a125e7a2770f14f4c8a1fa7" integrity sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -1677,23 +1642,34 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.8.2, acorn@^8.9.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== agentkeepalive@^4.1.4: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255" - integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== + version "4.6.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== dependencies: - debug "^4.1.0" - depd "^2.0.0" humanize-ms "^1.2.1" -ajv@^6.5.5: +ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1711,9 +1687,9 @@ ansi-escapes@^4.2.1: type-fest "^0.21.3" ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" + integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== ansi-regex@^5.0.1: version "5.0.1" @@ -1727,21 +1703,13 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" - ansi-styles@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" @@ -1755,15 +1723,23 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -applicationinsights@1.8.10, applicationinsights@^1.8.10, applicationinsights@^2.9.5: - version "1.8.10" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.8.10.tgz#fffa482cd1519880fb888536a87081ac05130667" - integrity sha512-ZLDA7mShh4mP2Z/HlFolmvhBPX1LfnbIWXrselyYVA7EKjHhri1fZzpu2EiWAmfbRxNBY6fRjoPJWbx5giKy4A== - dependencies: +applicationinsights@^1.8.10, applicationinsights@^2.9.5, applicationinsights@~2.9.5: + version "2.9.6" + resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-2.9.6.tgz#67528e667d7953c8dd57b5fb16e0a4714fc07aed" + integrity sha512-BLeBYJUZaKmnzqG/6Q/IFSCqpiVECjSTIvwozLex/1ZZpSxOjPiBxGMev+iIBfNZ2pc7vvnV7DuPOtsoG2DJeQ== + dependencies: + "@azure/core-auth" "1.7.2" + "@azure/core-rest-pipeline" "1.16.3" + "@azure/opentelemetry-instrumentation-azure-sdk" "^1.0.0-beta.5" + "@microsoft/applicationinsights-web-snippet" "1.0.1" + "@opentelemetry/api" "^1.7.0" + "@opentelemetry/core" "^1.19.0" + "@opentelemetry/sdk-trace-base" "^1.19.0" + "@opentelemetry/semantic-conventions" "^1.19.0" cls-hooked "^4.2.2" continuation-local-storage "^3.2.1" - diagnostic-channel "0.3.1" - diagnostic-channel-publishers "0.4.4" + diagnostic-channel "1.1.1" + diagnostic-channel-publishers "1.0.8" argparse@^1.0.7: version "1.0.10" @@ -1777,20 +1753,41 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== asap@^2.0.3: version "2.0.6" @@ -1798,16 +1795,21 @@ asap@^2.0.3: integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== async-hook-jl@^1.7.6: version "1.7.6" @@ -1824,32 +1826,34 @@ async-listener@^0.6.0: semver "^5.3.0" shimmer "^1.1.0" -async@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== - async@^3.2.3: - version "3.2.4" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" - integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== auto-changelog@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/auto-changelog/-/auto-changelog-2.2.1.tgz#a031fbf1dfe140dda2ec8c77a524031478a0e933" - integrity sha512-XlykJfZrXlWUAADBqGoN1elmntrRcx7oEymyYB3NRPEZxv0TfYHfivmwzejUMnwAdXKCgbQPo7GV5ULs3jwpfw== + version "2.5.0" + resolved "https://registry.yarnpkg.com/auto-changelog/-/auto-changelog-2.5.0.tgz#c7a3a203a99b54c3c7286b247911966581103c10" + integrity sha512-UTnLjT7I9U2U/xkCUH5buDlp8C7g0SGChfib+iDrJkamcj5kaMqNKHNfbKJw1kthJUq8sUo3i3q2S6FzO/l/wA== dependencies: - commander "^5.0.0" - handlebars "^4.7.3" - lodash.uniqby "^4.7.0" - node-fetch "^2.6.0" - parse-github-url "^1.0.2" - semver "^6.3.0" + commander "^7.2.0" + handlebars "^4.7.7" + import-cwd "^3.0.0" + node-fetch "^2.6.1" + parse-github-url "^1.0.3" + semver "^7.3.5" + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" await-handler@^1.1.0: version "1.1.2" @@ -1859,12 +1863,12 @@ await-handler@^1.1.0: aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== aws4@^1.8.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" - integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== + version "1.13.2" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" + integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== azure-storage@^2.10.5: version "2.10.7" @@ -1884,15 +1888,15 @@ azure-storage@^2.10.5: xml2js "~0.2.8" xmlbuilder "^9.0.7" -babel-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.5.0.tgz#3fe3ddb109198e78b1c88f9ebdecd5e4fc2f50a5" - integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: - "@jest/transform" "^29.5.0" + "@jest/transform" "^29.7.0" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.5.0" + babel-preset-jest "^29.6.3" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -1908,10 +1912,10 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" - integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -1919,29 +1923,32 @@ babel-plugin-jest-hoist@^29.5.0: "@types/babel__traverse" "^7.0.6" babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" -babel-preset-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" - integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^29.5.0" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" bail@^1.0.0: @@ -1950,9 +1957,9 @@ bail@^1.0.0: integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== basic-auth@~2.0.1: version "2.0.1" @@ -1964,14 +1971,14 @@ basic-auth@~2.0.1: bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== dependencies: tweetnacl "^0.14.3" binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== body-parser@1.19.2: version "1.19.2" @@ -1990,20 +1997,20 @@ body-parser@1.19.2: type-is "~1.6.18" body-parser@^1.19.2: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" - content-type "~1.0.4" + content-type "~1.0.5" debug "2.6.9" depd "2.0.0" destroy "1.2.0" http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" + qs "6.13.0" + raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -2027,29 +2034,29 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserify-mime@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/browserify-mime/-/browserify-mime-1.2.9.tgz#aeb1af28de6c0d7a6a2ce40adb68ff18422af31f" integrity sha512-uz+ItyJXBLb6wgon1ELEiVowJBEsy03PUWGRQU7cxxx9S+DW2hujPp+DaMYEOClRPzsn7NB99NtJ6pGnt8y+CQ== -browserslist@^4.21.3: - version "4.21.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" - integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== +browserslist@^4.24.0: + version "4.24.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" + integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== dependencies: - caniuse-lite "^1.0.30001400" - electron-to-chromium "^1.4.251" - node-releases "^2.0.6" - update-browserslist-db "^1.0.9" + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" -bs-logger@0.x: +bs-logger@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== @@ -2066,30 +2073,48 @@ bser@2.1.1: buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== buffer-from@^1.0.0, buffer-from@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== bwip-js@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/bwip-js/-/bwip-js-2.0.6.tgz#2189bf1ae9518974a5d73513605939989a98a17e" - integrity sha512-25zupM+tgx6NGmrg0kFhdkddeQ5+QnUMvHbb7cPNVbBdFDd0SOG3xRZ1ocGDEamhmM+fStglCLEkH21OpD4Y/w== + version "2.1.3" + resolved "https://registry.yarnpkg.com/bwip-js/-/bwip-js-2.1.3.tgz#f9c09b15caae50a406c5a8de5c2ae4ad4a931584" + integrity sha512-1Jf5eB+o6AzpwkHZPj63+/kGesLH30XLL0EC2PUrX+d0+4kMwCYMeqCuytlG318S/lcw27a2JOnZ9I8RO83Krg== bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" - integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w== +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840" + integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" + integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== + dependencies: + call-bind-apply-helpers "^1.0.1" + get-intrinsic "^1.2.6" call-me-maybe@^1.0.1: version "1.0.2" @@ -2114,24 +2139,24 @@ camelcase@^6.2.0: camelize@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= + integrity sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg== -caniuse-lite@^1.0.30001400: - version "1.0.30001442" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz#40337f1cf3be7c637b061e2f78582dc1daec0614" - integrity sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow== +caniuse-lite@^1.0.30001688: + version "1.0.30001696" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz#00c30a2fc11e3c98c25e5125418752af3ae2f49f" + integrity sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ== caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== ccount@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.1, chalk@^2.4.1: +chalk@^2.0.1, chalk@^2.3.1, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2148,10 +2173,10 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== +chalk@^4.0.0, chalk@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" @@ -2182,9 +2207,9 @@ character-reference-invalid@^1.0.0: integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== chokidar@^3.5.2: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -2197,9 +2222,9 @@ chokidar@^3.5.2: fsevents "~2.3.2" ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cidr-matcher@^2.1.1: version "2.1.1" @@ -2208,15 +2233,15 @@ cidr-matcher@^2.1.1: dependencies: ip6addr "^0.2.2" -cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +cjs-module-lexer@^1.0.0, cjs-module-lexer@^1.2.2: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== dependencies: restore-cursor "^2.0.0" @@ -2246,7 +2271,7 @@ cliui@^8.0.1: clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== cls-hooked@^4.2.2: version "4.2.2" @@ -2257,15 +2282,15 @@ cls-hooked@^4.2.2: emitter-listener "^1.0.1" semver "^5.4.1" -cluster-key-slot@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz#10ccb9ded0729464b6d2e7d714b100a2d1259d43" - integrity sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw== +cluster-key-slot@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== collapse-white-space@^1.0.0, collapse-white-space@^1.0.2: version "1.0.6" @@ -2273,11 +2298,11 @@ collapse-white-space@^1.0.0, collapse-white-space@^1.0.2: integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-convert@^1.9.0, color-convert@^1.9.1: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -2294,40 +2319,35 @@ color-convert@^2.0.1: color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.5.2: - version "1.5.3" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" - integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== dependencies: color-name "^1.0.0" simple-swizzle "^0.2.2" -color@3.0.x: - version "3.0.0" - resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" - integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w== +color@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - -colors@^1.2.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + color-convert "^1.9.3" + color-string "^1.6.0" colorspace@1.1.x: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5" - integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ== + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== dependencies: - color "3.0.x" + color "^3.1.3" text-hex "1.0.x" combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: @@ -2342,30 +2362,35 @@ comma-separated-tokens@^1.0.1: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== -commander@^2.7.1, commander@^2.9.0, commander@~2.20.3: +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.7.1, commander@^2.9.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^5.0.0, commander@^5.1.0: +commander@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@^9.4.1: - version "9.5.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" - integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== component-emitter@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + version "1.3.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" + integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== content-disposition@0.5.4: version "0.5.4" @@ -2379,10 +2404,10 @@ content-security-policy-builder@2.1.0: resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz#0a2364d769a3d7014eec79ff7699804deb8cfcbb" integrity sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ== -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== continuation-local-storage@^3.2.1: version "3.2.1" @@ -2392,11 +2417,6 @@ continuation-local-storage@^3.2.1: async-listener "^0.6.0" emitter-listener "^1.1.1" -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -2405,7 +2425,7 @@ convert-source-map@^2.0.0: cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.4.2: version "0.4.2" @@ -2413,31 +2433,42 @@ cookie@0.4.2: integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== cookiejar@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" - integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + version "2.1.4" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" + integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== core-js@^2.5.7: - version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" - integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== -cross-env@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941" - integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag== +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== dependencies: - cross-spawn "^7.0.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + version "6.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57" + integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw== dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -2445,19 +2476,10 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" - integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" @@ -2466,14 +2488,41 @@ cross-spawn@^7.0.3: dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== dependencies: assert-plus "^1.0.0" dasherize@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" - integrity sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg= + integrity sha512-APql/TZ6FdLEpf2z7/X2a2zyqK8juYtqaSVqxw9mYoQ64CXkfU15AeLh8pUszT8+fnYjgm6t0aIYpWKJbnLkuA== + +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" date-fns@^1.30.1: version "1.30.1" @@ -2487,69 +2536,71 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== dependencies: - ms "^2.1.1" + ms "^2.1.3" -debug@^3.2.7: +debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^4.1.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + version "1.0.4" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== dependencies: clone "^1.0.2" -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: - object-keys "^1.0.12" + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -depd@2.0.0, depd@^2.0.0, depd@~2.0.0: +depd@2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -2581,22 +2632,22 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diagnostic-channel-publishers@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.4.4.tgz#57c3b80b7e7f576f95be3a257d5e94550f0082d6" - integrity sha512-l126t01d2ZS9EreskvEtZPrcgstuvH3rbKy82oUhUrVmBaGx4hO9wECdl3cvZbKDYjMF3QJDB5z5dL9yWAjvZQ== +diagnostic-channel-publishers@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-1.0.8.tgz#700557a902c443cb11f999f19f50a8bb3be490a0" + integrity sha512-HmSm9hXxSPxA9BaLGY98QU1zsdjeCk113KjAYGPCen1ZP6mhVaTPzHd6UYv5r21DnWANi+f+NyPOHruGT9jpqQ== -diagnostic-channel@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.3.1.tgz#7faa143e107f861be3046539eb4908faab3f53fd" - integrity sha512-6eb9YRrimz8oTr5+JDzGmSYnXy5V7YnK5y/hd8AUDK1MssHjQKm9LlD6NSrHx4vMDF3+e/spI2hmWTviElgWZA== +diagnostic-channel@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-1.1.1.tgz#44b60972de9ee055c16216535b0e9db3f6a0efd0" + integrity sha512-r2HV5qFkUICyoaKlBEpLKHjxMXATUf/l+h8UZPGBHGLy4DDiY2sOLcIctax4eRnTw5wH2jTMExLntGPJ8eOJxw== dependencies: - semver "^5.3.0" + semver "^7.5.3" -diff-sequences@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" - integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^3.1.0: version "3.5.0" @@ -2610,15 +2661,22 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + dont-sniff-mimetype@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz#c7d0427f8bcb095762751252af59d148b0a623b2" integrity sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug== dotenv-cli@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-3.1.0.tgz#489f78b58bcc6971be2362ba27be73c5c08fd86f" - integrity sha512-sT16Zg7m71IVP/MX2ZBm6JBu6fy8aEgN9kJPywaYhBZnmq7MSQbpvCEhuiGPI08X8G+CQ1Gj/oZZUH1lGvGmqA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-3.2.0.tgz#002367c30992acb0b218b20fc01a8e18f13f85cf" + integrity sha512-zg/dfXISo7ntL3JKC+oj7eXEMg8LbOsARWTeypfVsmYtazDYOptmKLqA9u3LTee9x/sIPiLqmI6wskRP+89ohQ== dependencies: cross-spawn "^7.0.1" dotenv "^8.1.0" @@ -2636,14 +2694,23 @@ dotenv@^6.0.0: integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w== dotenv@^8.1.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" @@ -2658,12 +2725,19 @@ ecdsa-sig-formatter@1.0.11: ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" -electron-to-chromium@^1.4.251: - version "1.4.284" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" - integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== +electron-to-chromium@^1.5.73: + version "1.5.90" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz#4717e5a5413f95bbb12d0af14c35057e9c65e0b6" + integrity sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug== emitter-listener@^1.0.1, emitter-listener@^1.1.1: version "1.1.2" @@ -2695,7 +2769,7 @@ enabled@2.0.x: encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== error-ex@^1.3.1: version "1.3.2" @@ -2704,62 +2778,129 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1: - version "1.17.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" - integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.1.5" - is-regex "^1.0.5" - object-inspect "^1.7.0" +es-abstract@^1.23.2, es-abstract@^1.23.5, es-abstract@^1.23.9: + version "1.23.9" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.9.tgz#5b45994b7de78dada5c1bebf1379646b32b9d606" + integrity sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.2.7" + get-proto "^1.0.0" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-regex "^1.2.1" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.0" + math-intrinsics "^1.1.0" + object-inspect "^1.13.3" object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimleft "^2.1.1" - string.prototype.trimright "^2.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.3" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.18" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" -es6-object-assign@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" - integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" es6-promise@^3.0.2: version "3.3.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" - integrity sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM= + integrity sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + eslint-config-prettier@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" @@ -2796,20 +2937,105 @@ eslint-plugin-vitest@^0.5.3: dependencies: "@typescript-eslint/utils" "^7.7.1" -eslint-visitor-keys@^3.4.3: +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== +eslint@8.57.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== event-target-shim@^5.0.0: version "5.0.1" @@ -2834,23 +3060,23 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expect@^29.0.0, expect@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" - integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: - "@jest/expect-utils" "^29.5.0" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" express-enforces-ssl@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/express-enforces-ssl/-/express-enforces-ssl-1.1.0.tgz#cf29c6a61c5bdd802e2c7ed265a4a98e7487d1ac" - integrity sha1-zynGphxb3YAuLH7SZaSpjnSH0aw= + integrity sha512-s2p9nh2Q2++9XAqZqyCORk7KQTfrfKqB/Y5A4VfyRnwMQ2D6cHdDrZhvvGOV3FURTPuO3a6f9AD2Eso1pIo6CA== express@4.17.3: version "4.17.3" @@ -2896,55 +3122,55 @@ extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-safe-stringify@^2.0.4: - version "2.0.7" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" - integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-xml-parser@^4.2.4: - version "4.2.7" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.7.tgz#871f2ca299dc4334b29f8da3658c164e68395167" - integrity sha512-J8r6BriSLO1uj2miOk1NW0YVm8AGOOu3Si2HQp/cSmo6EA4m3fcwu2WKjJ4RK9wMLBtg69y1kS8baDiQBR41Ig== +fast-xml-parser@^4.4.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.1.tgz#a7e665ff79b7919100a5202f23984b6150f9b31e" + integrity sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w== dependencies: strnum "^1.0.5" fastq@^1.6.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.10.0.tgz#74dbefccade964932cdf500473ef302719c652bb" - integrity sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA== + version "1.19.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.0.tgz#a82c6b7c2bb4e44766d865f07997785fecfdcb89" + integrity sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA== dependencies: reusify "^1.0.4" @@ -2956,9 +3182,9 @@ fault@^1.0.1: format "^0.2.0" fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: bser "2.1.1" @@ -2968,14 +3194,28 @@ feature-policy@0.3.0: integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ== fecha@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.0.tgz#3ffb6395453e3f3efff850404f0a59b6747f5f41" - integrity sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg== + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -3000,38 +3240,59 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + fn.name@1.x.x: version "1.1.0" resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== +for-each@^0.3.3: + version "0.3.4" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.4.tgz#814517ffc303d1399b2564d8165318e735d0341c" + integrity sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw== + dependencies: + is-callable "^1.2.7" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== form-data@^2.3.1, form-data@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" - integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + version "2.5.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.2.tgz#dc653743d1de2fcc340ceea38079daf6e9069fd2" + integrity sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q== dependencies: asynckit "^0.4.0" combined-stream "^1.0.6" mime-types "^2.1.12" - -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" + safe-buffer "^5.2.1" form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -3057,29 +3318,24 @@ format@^0.2.0: integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== formidable@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" - integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== + version "1.2.6" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168" + integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ== forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fp-ts@2.14.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.14.0.tgz#97ac3d9f002dcd02f93ca1269ae14a7fcb805582" - integrity sha512-QLagLSYAgMA00pZzUzeksH/78Sd14y7+Gc2A8Yaja3/IpGOFMdm/gYBuDMxYqLsJ58iT5lz+bJb953RAeFfp1A== - -fp-ts@^2.10.5, fp-ts@^2.11.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.16.0.tgz#64e03314dfc1c7ce5e975d3496ac14bc3eb7f92e" - integrity sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ== +fp-ts@^2.10.5, fp-ts@^2.11.0, fp-ts@^2.16.5: + version "2.16.9" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.16.9.tgz#99628fc5e0bb3b432c4a16d8f4455247380bae8a" + integrity sha512-+I2+FnVB+tVaxcYyQkHUq7ZdKScaBlX53A41mxQtpIccsfyv8PzdzP7fzp2AY832T4aoK6UZ5WRX/ebGd8uZuQ== fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-extra@^6.0.0: version "6.0.1" @@ -3093,17 +3349,34 @@ fs-extra@^6.0.0: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== generic-pool@3.9.0: version "3.9.0" @@ -3120,29 +3393,53 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.0, get-intrinsic@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49" - integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.7.tgz#dcfcb33d3272e15f445d15124bc0a216189b9044" + integrity sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + function-bind "^1.1.2" + get-proto "^1.0.0" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== dependencies: assert-plus "^1.0.0" @@ -3153,19 +3450,14 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@^7.0.0, glob@^7.1.2, glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: - 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" + is-glob "^4.0.3" -glob@^7.1.4: +glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3182,6 +3474,21 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -3194,12 +3501,12 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -graceful-fs@^4.2.9: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -3209,7 +3516,7 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -handlebars@^4.7.3, handlebars@~4.5.3: +handlebars@^4.7.7, handlebars@~4.5.3: version "4.5.3" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482" integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA== @@ -3223,37 +3530,56 @@ handlebars@^4.7.3, handlebars@~4.5.3: har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== dependencies: - ajv "^6.5.5" + ajv "^6.12.3" har-schema "^2.0.0" +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - function-bind "^1.1.1" + has-symbols "^1.0.3" hash-base@^3.0.0: version "3.1.0" @@ -3264,6 +3590,13 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + hast-util-is-element@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz#3b3ed5159a2707c6137b48637fbfe068e175a425" @@ -3334,14 +3667,14 @@ hide-powered-by@1.1.0: integrity sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg== hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== hpkp@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672" - integrity sha1-EOFCJk52IVpdMMROxD3mTe5tFnI= + integrity sha512-TaZpC6cO/k3DFsjfzz1LnOobbVSq+J+7WpJxrVtN4L+8+BPQj8iBDRB2Dx49613N+e7/+ZSQ9ra+xZm7Blf4wg== hsts@2.2.0: version "2.2.0" @@ -3383,36 +3716,35 @@ http-errors@2.0.0: toidentifier "1.0.1" http-graceful-shutdown@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/http-graceful-shutdown/-/http-graceful-shutdown-2.3.2.tgz#2334e3036c88283567fdab5e371ffad327fb886e" - integrity sha512-Dn7fJjHWboN7WjNDuo7d7ZISdUlbnyQEtOjBwMGJig45ZztHQxCsnW9N89Pr3gb6VzvZy1HySgAu2Q98j6S17w== + version "2.4.0" + resolved "https://registry.yarnpkg.com/http-graceful-shutdown/-/http-graceful-shutdown-2.4.0.tgz#363300296fe8097b2404bf70f2ac29ecc0ed6ba7" + integrity sha512-Wj42gVFxJ/MJPQP5aC45FdsZpBiw3yw78MVfDmbPbPEZCJa5HqtRmc5cKTCBZ4emWZLptNg5p05zuYJlCa4lSA== dependencies: debug "^4.1.1" -http-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" - integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== dependencies: - "@tootallnate/once" "2" - agent-base "6" - debug "4" + agent-base "^7.1.0" + debug "^4.3.4" http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" sshpk "^1.7.0" -https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== +https-proxy-agent@^7.0.0: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== dependencies: - agent-base "6" + agent-base "^7.1.2" debug "4" human-signals@^2.1.0: @@ -3434,25 +3766,59 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" - integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= - -ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== -ignore@^5.3.1: +ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== +import-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92" + integrity sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg== + dependencies: + import-from "^3.0.0" + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" + integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ== + dependencies: + resolve-from "^5.0.0" + +import-in-the-middle@^1.8.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.12.0.tgz#80d6536a01d0708a6f119f30d22447d4eb9e5c63" + integrity sha512-yAgSE7GmtRcu4ZUSFX/4v69UGXwugFFSdIQJ14LHPOPPQrWv8Y7O9PHsw8Ovk7bKCLe4sjXMbZFqGFcLHpZ89w== + dependencies: + acorn "^8.8.2" + acorn-import-attributes "^1.9.5" + cjs-module-lexer "^1.2.2" + module-details-from-path "^1.0.3" + import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -3465,7 +3831,7 @@ imurmurhash@^0.1.4: inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -3475,30 +3841,39 @@ inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + interpret@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" - integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== io-ts-types@^0.5.16: - version "0.5.16" - resolved "https://registry.yarnpkg.com/io-ts-types/-/io-ts-types-0.5.16.tgz#e9eed75371e217c97050cc507915e8eedc250946" - integrity sha512-h9noYVfY9rlbmKI902SJdnV/06jgiT2chxG6lYDxaYNp88HscPi+SBCtmcU+m0E7WT5QSwt7sIMj93+qu0FEwQ== + version "0.5.19" + resolved "https://registry.yarnpkg.com/io-ts-types/-/io-ts-types-0.5.19.tgz#9c04fa73f15992436605218a5686b610efa7a5d3" + integrity sha512-kQOYYDZG5vKre+INIDZbLeDJe+oM+4zLpUkjXyTMyUfoCpjJNyi29ZLkuEAwcPufaYo3yu/BsemZtbdD+NtRfQ== -io-ts@2.2.20, io-ts@^2.2.16: - version "2.2.20" - resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-2.2.20.tgz#be42b75f6668a2c44f706f72ee6e4c906777c7f5" - integrity sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA== +io-ts@2.2.21: + version "2.2.21" + resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-2.2.21.tgz#4ef754176f7082a1099d04c7d5c4ea53267c530a" + integrity sha512-zz2Z69v9ZIC3mMLYWIeoUcwWD6f+O7yP92FMVVaXEOSZH1jnVBmET/urd/uoarD1WGBY4rCj8TAyMPzsGNzMFQ== -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= +io-ts@^2.2.16: + version "2.2.22" + resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-2.2.22.tgz#5ab0d3636fe8494a275f0266461ab019da4b8d0b" + integrity sha512-FHCCztTkHoV9mdBsHpocLpdTAfh956ZQcIkWQxxS0U5HT53vtrcuYdQneEJKH6xILaLNzXVl2Cvwtoy8XNN0AA== ip6@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/ip6/-/ip6-0.0.4.tgz#44c5a9db79e39d405201b4d78d13b3870e48db31" - integrity sha1-RMWp23njnUBSAbTXjROzhw5I2zE= + integrity sha512-0FJ0rKtTQYCp92ru/hNzNpmy2sa8nINqbuyiiVOI75+ltMtAly9dtEparm+xh//kndXL/s6FOdWzSYvUDiBpbg== ip6addr@^0.2.2: version "0.2.5" @@ -3511,7 +3886,7 @@ ip6addr@^0.2.2: ipaddr.js@1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" - integrity sha1-irpJyRknmVhb3WQ+DMtQ6K53e6Q= + integrity sha512-ku//LD7ie/m9UVGCm9KweBIIHP4mB0maNGvav6Hz778fQCNLQF7iZ+H/UuHuqmjJCHCpA5hw8hOeRKxZl8IlXw== ipaddr.js@1.9.1: version "1.9.1" @@ -3531,16 +3906,43 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-arrayish@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-async-function@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== + dependencies: + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3548,27 +3950,47 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.1.tgz#c20d0c654be05da4fbc23c562635c019e93daf89" + integrity sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + is-buffer@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.4, is-callable@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" - integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" - integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: - has "^1.0.3" + hasown "^2.0.2" -is-date-object@^1.0.1: +is-data-view@^1.0.1, is-data-view@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" is-decimal@^1.0.0: version "1.0.4" @@ -3578,7 +4000,14 @@ is-decimal@^1.0.0: is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" is-fullwidth-code-point@^3.0.0: version "3.0.0" @@ -3590,14 +4019,17 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-generator-function@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== dependencies: - is-extglob "^2.1.1" + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" -is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -3609,39 +4041,109 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-regex@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== dependencies: - has "^1.0.3" + call-bound "^1.0.3" is-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" - integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== +is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== dependencies: - has-symbols "^1.0.1" + which-typed-array "^1.1.16" is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.0.tgz#47e3472ae95a63fa9cf25660bcf0c181c39770ef" + integrity sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q== + dependencies: + call-bound "^1.0.2" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" is-whitespace-character@^1.0.0: version "1.0.4" @@ -3653,27 +4155,32 @@ is-word-character@^1.0.0: resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -3684,13 +4191,24 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" + make-dir "^4.0.0" supports-color "^7.1.0" istanbul-lib-source-maps@^4.0.0: @@ -3703,383 +4221,385 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.5" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" - integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== +jake@^10.8.5: + version "10.9.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" + integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" + jest-util "^29.7.0" p-limit "^3.1.0" -jest-circus@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.5.0.tgz#b5926989449e75bff0d59944bae083c9d7fb7317" - integrity sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA== +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: - "@jest/environment" "^29.5.0" - "@jest/expect" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - dedent "^0.7.0" + dedent "^1.0.0" is-generator-fn "^2.0.0" - jest-each "^29.5.0" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-runtime "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" p-limit "^3.1.0" - pretty-format "^29.5.0" + pretty-format "^29.7.0" pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.5.0.tgz#b34c20a6d35968f3ee47a7437ff8e53e086b4a67" - integrity sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw== +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@jest/core" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" + create-jest "^29.7.0" exit "^0.1.2" - graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" - prompts "^2.0.1" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" yargs "^17.3.1" -jest-config@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.5.0.tgz#3cc972faec8c8aaea9ae158c694541b79f3748da" - integrity sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA== +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.5.0" - "@jest/types" "^29.5.0" - babel-jest "^29.5.0" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^29.5.0" - jest-environment-node "^29.5.0" - jest-get-type "^29.4.3" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-runner "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^29.5.0" + pretty-format "^29.7.0" slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" - integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: chalk "^4.0.0" - diff-sequences "^29.4.3" - jest-get-type "^29.4.3" - pretty-format "^29.5.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-docblock@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" - integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: detect-newline "^3.0.0" -jest-each@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.5.0.tgz#fc6e7014f83eac68e22b7195598de8554c2e5c06" - integrity sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA== +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" - jest-get-type "^29.4.3" - jest-util "^29.5.0" - pretty-format "^29.5.0" - -jest-environment-node@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.5.0.tgz#f17219d0f0cc0e68e0727c58b792c040e332c967" - integrity sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/fake-timers" "^29.5.0" - "@jest/types" "^29.5.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.5.0" - jest-util "^29.5.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -jest-get-type@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" - integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== -jest-haste-map@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.5.0.tgz#69bd67dc9012d6e2723f20a945099e972b2e94de" - integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^29.4.3" - jest-util "^29.5.0" - jest-worker "^29.5.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz#cf4bdea9615c72bac4a3a7ba7e7930f9c0610c8c" - integrity sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow== +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - jest-get-type "^29.4.3" - pretty-format "^29.5.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-matcher-utils@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" - integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" - jest-diff "^29.5.0" - jest-get-type "^29.4.3" - pretty-format "^29.5.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-message-util@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" - integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^29.5.0" + pretty-format "^29.7.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed" - integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-util "^29.5.0" + jest-util "^29.7.0" jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" - integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz#f0ea29955996f49788bf70996052aa98e7befee4" - integrity sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg== +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: - jest-regex-util "^29.4.3" - jest-snapshot "^29.5.0" + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" -jest-resolve@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.5.0.tgz#b053cc95ad1d5f6327f0ac8aae9f98795475ecdc" - integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" + jest-haste-map "^29.7.0" jest-pnp-resolver "^1.2.2" - jest-util "^29.5.0" - jest-validate "^29.5.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" resolve "^1.20.0" resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.5.0.tgz#6a57c282eb0ef749778d444c1d758c6a7693b6f8" - integrity sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ== +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: - "@jest/console" "^29.5.0" - "@jest/environment" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^29.4.3" - jest-environment-node "^29.5.0" - jest-haste-map "^29.5.0" - jest-leak-detector "^29.5.0" - jest-message-util "^29.5.0" - jest-resolve "^29.5.0" - jest-runtime "^29.5.0" - jest-util "^29.5.0" - jest-watcher "^29.5.0" - jest-worker "^29.5.0" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.5.0.tgz#c83f943ee0c1da7eb91fa181b0811ebd59b03420" - integrity sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/fake-timers" "^29.5.0" - "@jest/globals" "^29.5.0" - "@jest/source-map" "^29.4.3" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - jest-message-util "^29.5.0" - jest-mock "^29.5.0" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.5.0.tgz#c9c1ce0331e5b63cd444e2f95a55a73b84b1e8ce" - integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/babel__traverse" "^7.0.6" - "@types/prettier" "^2.1.5" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^29.5.0" + expect "^29.7.0" graceful-fs "^4.2.9" - jest-diff "^29.5.0" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^29.5.0" - semver "^7.3.5" + pretty-format "^29.7.0" + semver "^7.5.3" -jest-util@^29.0.0, jest-util@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" - integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.5.0.tgz#8e5a8f36178d40e47138dc00866a5f3bd9916ffc" - integrity sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ== +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^29.5.0" + pretty-format "^29.7.0" -jest-watcher@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.5.0.tgz#cf7f0f949828ba65ddbbb45c743a382a4d911363" - integrity sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.13.1" - jest-util "^29.5.0" + jest-util "^29.7.0" string-length "^4.0.1" -jest-worker@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" - integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" - jest-util "^29.5.0" + jest-util "^29.7.0" merge-stream "^2.0.0" supports-color "^8.0.0" jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.5.0.tgz#f75157622f5ce7ad53028f2f8888ab53e1f1f24e" - integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - "@jest/core" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^29.5.0" + jest-cli "^29.7.0" -jose@^4.11.2: - version "4.13.1" - resolved "https://registry.yarnpkg.com/jose/-/jose-4.13.1.tgz#449111bb5ab171db85c03f1bd2cb1647ca06db1c" - integrity sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ== - -jose@^4.15.5: - version "4.15.5" - resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.5.tgz#6475d0f467ecd3c630a1b5dadd2735a7288df706" - integrity sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg== +jose@^4.11.2, jose@^4.15.5: + version "4.15.9" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.9.tgz#9b68eda29e9a0614c042fa29387196c7dd800100" + integrity sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA== js-tokens@^4.0.0: version "4.0.0" @@ -4087,9 +4607,9 @@ js-tokens@^4.0.0: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.12.0, js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -4101,20 +4621,25 @@ js-yaml@^4.0.0, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbi@^3.1.3: - version "3.2.5" - resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.5.tgz#b37bb90e0e5c2814c1c2a1bcd8c729888a2e37d6" - integrity sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ== +jsbi@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-4.3.0.tgz#b54ee074fb6fcbc00619559305c8f7e912b04741" + integrity sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g== jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== json-edm-parser@~0.1.2: version "0.1.2" @@ -4157,11 +4682,6 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - json-schema@0.4.0, json-schema@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" @@ -4172,12 +4692,17 @@ json-set-map@^1.1.2: resolved "https://registry.yarnpkg.com/json-set-map/-/json-set-map-1.1.2.tgz#536cbc6549d06e8af11f76cb4fbd441ed2389e6e" integrity sha512-x0TGwgcOG21jOa8wV1PWXDpSXUAKa1WuhMSHPBQhXU5Pb+4DdMrxOw5HMAWztVLP8KhSG5Kl5BoAOVF0aW63wA== +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^2.2.2, json5@^2.2.3: +json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -4197,7 +4722,7 @@ jsonparse@~1.2.0: jsonschema-draft4@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jsonschema-draft4/-/jsonschema-draft4-1.0.0.tgz#f0af2005054f0f0ade7ea2118614b69dc512d865" - integrity sha1-8K8gBQVPDwrefqIRhhS2ncUS2GU= + integrity sha512-sBV3UnQPRiyCTD6uzY/Oao2Yohv6KKgQq7zjPwjFHeR6scg/QSXnzDxdugsGaLQDmFUrUlTbMYdEE+72PizhGA== jsonschema@1.2.4: version "1.2.4" @@ -4221,13 +4746,13 @@ jsonwebtoken@^9.0.1: semver "^7.5.4" jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== dependencies: assert-plus "1.0.0" extsprintf "1.3.0" - json-schema "0.2.3" + json-schema "0.4.0" verror "1.10.0" jsprim@^2.0.2: @@ -4262,6 +4787,13 @@ kebab-case@^1.0.0: resolved "https://registry.yarnpkg.com/kebab-case/-/kebab-case-1.0.2.tgz#5eac97d5d220acf606d40e3c0ecfea21f1f9e1eb" integrity sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q== +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -4277,6 +4809,14 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -4285,7 +4825,7 @@ lines-and-columns@^1.1.6: load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== dependencies: graceful-fs "^4.1.2" parse-json "^4.0.0" @@ -4299,20 +4839,27 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.get@^4.0.0, lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: version "4.5.0" @@ -4322,42 +4869,42 @@ lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: lodash.isinteger@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== lodash.isnumber@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== lodash.isstring@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== -lodash.memoize@4.x: +lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash.uniqby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" - integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== log-symbols@^2.2.0: version "2.2.0" @@ -4366,23 +4913,13 @@ log-symbols@^2.2.0: dependencies: chalk "^2.0.1" -logform@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2" - integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg== - dependencies: - colors "^1.2.1" - fast-safe-stringify "^2.0.4" - fecha "^4.2.0" - ms "^2.1.1" - triple-beam "^1.3.0" - -logform@^2.3.2, logform@^2.4.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/logform/-/logform-2.4.2.tgz#a617983ac0334d0c3b942c34945380062795b47c" - integrity sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw== +logform@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.7.0.tgz#cfca97528ef290f2e125a08396805002b2d060d1" + integrity sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ== dependencies: - "@colors/colors" "1.5.0" + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" fecha "^4.2.0" ms "^2.1.1" safe-stable-stringify "^2.3.1" @@ -4393,6 +4930,11 @@ lolex@4.2.0: resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -4400,21 +4942,14 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: - semver "^6.0.0" + semver "^7.5.3" -make-error@1.x, make-error@^1.1.1: +make-error@^1.1.1, make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -4431,6 +4966,11 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -4472,17 +5012,17 @@ mdurl@^1.0.1: media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= + integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== merge-stream@^2.0.0: version "2.0.0" @@ -4497,34 +5037,22 @@ merge2@^1.3.0, merge2@^1.4.1: methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.4, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.43.0: - version "1.43.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" - integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== - mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.26" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" - integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== - dependencies: - mime-db "1.43.0" - -mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -4546,20 +5074,20 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimatch@^9.0.3, minimatch@^9.0.4: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" @@ -4567,22 +5095,22 @@ minimatch@^9.0.3, minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + integrity sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw== mkdirp@^0.5.1: - version "0.5.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" - integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "^1.2.5" + minimist "^1.2.6" modclean-patterns-default@latest: version "1.1.2" @@ -4606,6 +5134,11 @@ modclean@^3.0.0-beta.1: rimraf "^2.5.4" subdirs "^1.0.1" +module-details-from-path@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" + integrity sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A== + monocle-ts@^2.3.13: version "2.3.13" resolved "https://registry.yarnpkg.com/monocle-ts/-/monocle-ts-2.3.13.tgz#7c8af489613cd5175df2ea3c02c57c6151995e5d" @@ -4625,14 +5158,9 @@ morgan@^1.9.1: ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2, ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.0.0: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4645,7 +5173,7 @@ natural-compare-lite@^1.4.0: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== negotiator@0.6.3: version "0.6.3" @@ -4653,9 +5181,9 @@ negotiator@0.6.3: integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== neo-async@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" - integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== newtype-ts@^0.3.5: version "0.3.5" @@ -4672,32 +5200,22 @@ nocache@2.1.0: resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== -node-abort-controller@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.0.1.tgz#f91fa50b1dee3f909afabb7e261b1e1d6b0cb74e" - integrity sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw== - -node-fetch@^2.6.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" - integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== +node-fetch@^2.6.0, node-fetch@^2.6.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.6: - version "2.0.8" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae" - integrity sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== nodemailer-sendgrid@^1.0.3: version "1.0.3" @@ -4707,9 +5225,9 @@ nodemailer-sendgrid@^1.0.3: "@sendgrid/mail" "^6.2.1" nodemailer@^6.9.13: - version "6.9.13" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.13.tgz#5b292bf1e92645f4852ca872c56a6ba6c4a3d3d6" - integrity sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA== + version "6.10.0" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.10.0.tgz#1f24c9de94ad79c6206f66d132776b6503003912" + integrity sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA== nodemon@^2.0.22: version "2.0.22" @@ -4727,13 +5245,6 @@ nodemon@^2.0.22: touch "^3.1.0" undefsafe "^2.0.5" -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= - dependencies: - abbrev "1" - normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -4772,9 +5283,9 @@ npm-run-path@^4.0.1: path-key "^3.0.0" nunjucks@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/nunjucks/-/nunjucks-3.2.3.tgz#1b33615247290e94e28263b5d855ece765648a31" - integrity sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ== + version "3.2.4" + resolved "https://registry.yarnpkg.com/nunjucks/-/nunjucks-3.2.4.tgz#f0878eef528ce7b0aa35d67cc6898635fd74649e" + integrity sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ== dependencies: a-sync-waterfall "^1.0.0" asap "^2.0.3" @@ -4788,32 +5299,29 @@ oauth-sign@~0.9.0: object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" - integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== - -object-inspect@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" - integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== +object-inspect@^1.13.3: + version "1.13.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a" + integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" +object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" on-finished@2.4.1: version "2.4.1" @@ -4825,7 +5333,7 @@ on-finished@2.4.1: on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== dependencies: ee-first "1.1.1" @@ -4837,7 +5345,7 @@ on-headers@~1.0.2: once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" @@ -4851,7 +5359,7 @@ one-time@^1.0.0: onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== dependencies: mimic-fn "^1.0.0" @@ -4901,11 +5409,23 @@ openapi-types@^10.0.0: optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + integrity sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g== dependencies: minimist "~0.0.1" wordwrap "~0.0.2" +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + 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.5" + ora@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" @@ -4918,6 +5438,15 @@ ora@^2.1.0: strip-ansi "^4.0.0" wcwidth "^1.0.1" +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + dependencies: + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.0.0" + p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -4925,7 +5454,7 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.1.0: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -4939,11 +5468,25 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-entities@^1.1.0: version "1.2.2" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" @@ -4956,15 +5499,15 @@ parse-entities@^1.1.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" -parse-github-url@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.2.tgz#242d3b65cbcdda14bb50439e3242acf6971db395" - integrity sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw== +parse-github-url@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.3.tgz#2ab55642c8685b63fbe2a196f5abe4ae9bd68abc" + integrity sha512-tfalY5/4SqGaV/GIGzWyHnFjlpTPTNpENR9Ea2lLldSJ8EWXMsvacWucqY3m3I4YPtas15IxTLQVQ5NSYXPrww== parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== dependencies: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" @@ -4987,35 +5530,35 @@ parseurl@~1.3.3: passport-auth-token@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/passport-auth-token/-/passport-auth-token-1.0.1.tgz#1026588af258058fe6a471da5c64b8698e16e06a" - integrity sha1-ECZYivJYBY/mpHHaXGS4aY4W4Go= + integrity sha512-Dn0rq96wRaUqYs54D7wfuYicfwW5P10vEvvcMIOO4+EsZksB+i3S/qn35My+bvlw3xES74WNVfgeYaXr74/fSw== dependencies: passport-strategy "1.x.x" passport-http-bearer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz#147469ea3669e2a84c6167ef99dbb77e1f0098a8" - integrity sha1-FHRp6jZp4qhMYWfvmdu3fh8AmKg= + integrity sha512-SELQM+dOTuMigr9yu8Wo4Fm3ciFfkMq5h/ZQ8ffi4ELgZrX1xh9PlglqZdcUZ1upzJD/whVyt+YWF62s3U6Ipw== dependencies: passport-strategy "1.x.x" passport-http-custom-bearer@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/passport-http-custom-bearer/-/passport-http-custom-bearer-1.0.15.tgz#f82639423f710f46cf2216e11d28e25c2e482800" - integrity sha1-+CY5Qj9xD0bPIhbhHSjiXC5IKAA= + integrity sha512-1PedoeLunu0kPe9nWxuvJq8WVgwtR+mVYf7oyrtIR1ANxmNhUeuGhsBa7h249qg6khMbEWxo3Nn/quFZOGwSDQ== dependencies: passport-strategy "1.x.x" passport-local@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" - integrity sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4= + integrity sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow== dependencies: passport-strategy "1.x.x" passport-strategy@1.x.x, passport-strategy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" - integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= + integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== passport@^0.6.0: version "0.6.0" @@ -5034,19 +5577,19 @@ path-exists@^4.0.0: path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -5054,7 +5597,7 @@ path-parse@^1.0.6, path-parse@^1.0.7: path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== path-type@^3.0.0: version "3.0.0" @@ -5071,17 +5614,17 @@ path-type@^4.0.0: pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" - integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= + integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -5089,19 +5632,19 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pidtree@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.0.tgz#f6fada10fccc9f99bf50e90d0b23d72c9ebc2e6b" - integrity sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg== + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" @@ -5110,6 +5653,16 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" @@ -5122,35 +5675,30 @@ prettier@^1.12.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.8.8: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier@^3.0.0: + version "3.4.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f" + integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ== -pretty-format@^29.0.0, pretty-format@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" - integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== dependencies: - "@jest/schemas" "^29.4.3" + "@jest/schemas" "^29.6.3" ansi-styles "^5.0.0" react-is "^18.0.0" -priorityqueuejs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/priorityqueuejs/-/priorityqueuejs-1.0.0.tgz#2ee4f23c2560913e08c07ce5ccdd6de3df2c5af8" - integrity sha512-lg++21mreCEOuGWTbO5DnJKAdxfjrdN0S9ysoW9SzdSJvbkWpkaDdpG/cdsPCsEnoLUwmd9m3WcZhngW7yKA2g== +priorityqueuejs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/priorityqueuejs/-/priorityqueuejs-2.0.0.tgz#96064040edd847ee9dd3013d8e16297399a6bd4f" + integrity sha512-19BMarhgpq3x4ccvVi8k2QpJZcymo/iFUcrhPd4V96kYGovOdTsWwy7fxChYi4QY+m2EnGBWSX9Buakz+tWNQQ== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -5178,47 +5726,61 @@ proxy-addr@~2.0.7: ipaddr.js "1.9.1" psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" pstree.remy@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" - integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== qr-image@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/qr-image/-/qr-image-3.2.0.tgz#9fa8295beae50c4a149cf9f909a1db464a8672e8" - integrity sha1-n6gpW+rlDEoUnPn5CaHbRkqGcug= + integrity sha512-rXKDS5Sx3YipVsqmlMJsJsk6jXylEpiHRC2+nJy66fxA5ExYyGa4PqwteW69SaVmAb2OQ18HbYriT7cGQMbduw== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" -qs@6.9.7, qs@^6.5.1: +qs@6.9.7: version "6.9.7" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== +qs@^6.5.1: + version "6.14.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + qs@~6.5.2: version "6.5.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -5227,7 +5789,7 @@ range-parser@~1.2.1: range_check@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/range_check/-/range_check-1.4.0.tgz#cd87c7ac62c40ba9df69b8703c604f60c3748635" - integrity sha1-zYfHrGLEC6nfabhwPGBPYMN0hjU= + integrity sha512-UhRtGxKoAm7NQqAPj3P6JVUlgs3hehoV+pA593il2FiHYZUK49/535laoi3Rvz7lP04XLCAdgbL4TprpVZZ/IQ== dependencies: ip6 "0.0.4" ipaddr.js "1.2" @@ -5242,10 +5804,10 @@ raw-body@2.4.3: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" http-errors "2.0.0" @@ -5253,23 +5815,23 @@ raw-body@2.5.1: unpipe "1.0.0" react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== dependencies: load-json-file "^4.0.0" normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@^2.0.0, readable-stream@^2.3.5, readable-stream@^2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== +readable-stream@^2.0.0, readable-stream@^2.3.5: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -5279,10 +5841,10 @@ readable-stream@^2.0.0, readable-stream@^2.3.5, readable-stream@^2.3.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== +readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -5298,27 +5860,53 @@ readdirp@~3.6.0: rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== dependencies: resolve "^1.1.6" redis@^4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/redis/-/redis-4.5.1.tgz#f5a818970bb2dc5d60540bab41308640604c7d33" - integrity sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA== + version "4.7.0" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.7.0.tgz#b401787514d25dd0cfc22406d767937ba3be55d6" + integrity sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ== dependencies: - "@redis/bloom" "1.1.0" - "@redis/client" "1.4.2" - "@redis/graph" "1.1.0" - "@redis/json" "1.0.4" - "@redis/search" "1.1.0" - "@redis/time-series" "1.0.4" + "@redis/bloom" "1.2.0" + "@redis/client" "1.6.0" + "@redis/graph" "1.1.1" + "@redis/json" "1.0.7" + "@redis/search" "1.2.0" + "@redis/time-series" "1.1.0" referrer-policy@1.2.0, referrer-policy@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e" integrity sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA== +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3: + version "1.5.4" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" + rehype-stringify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/rehype-stringify/-/rehype-stringify-3.0.0.tgz#9fef0868213c2dce2f780b76f3d0488c85e819eb" @@ -5365,7 +5953,7 @@ remark-rehype@^3.0.0: repeat-string@^1.5.4: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== request-ip@^3.3.0: version "3.3.0" @@ -5403,6 +5991,15 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-in-the-middle@^7.1.1: + version "7.5.0" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-7.5.0.tgz#6466fa87d6297b46d3ceca99ec03f901cab35d11" + integrity sha512-/Tvpny/RVVicqlYTKwt/GtpZRsPG1CmJNhxVKGz+Sy/4MONfXCVNK69MFgGKdUt0/324q3ClI2dICcPgISrC8g== + dependencies: + debug "^4.3.5" + module-details-from-path "^1.0.3" + resolve "^1.22.8" + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -5415,36 +6012,34 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve.exports@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" - integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== - -resolve@^1.1.6, resolve@^1.10.0: - version "1.15.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" - integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== - dependencies: - path-parse "^1.0.6" + version "2.0.3" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== -resolve@^1.20.0: - version "1.22.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.8: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== dependencies: - is-core-module "^2.11.0" + is-core-module "^2.16.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== dependencies: onetime "^2.0.0" signal-exit "^3.0.2" @@ -5461,17 +6056,37 @@ rimraf@^2.5.4: dependencies: glob "^7.1.3" +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + run-parallel@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" - integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5481,12 +6096,29 @@ safe-identifier@^0.4.2: resolved "https://registry.yarnpkg.com/safe-identifier/-/safe-identifier-0.4.2.tgz#cf6bfca31c2897c588092d1750d30ef501d59fcb" integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w== +safe-push-apply@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== + dependencies: + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + safe-stable-stringify@^2.3.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz#ec7b037768098bf65310d1d64370de0dc02353aa" - integrity sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA== + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5496,56 +6128,25 @@ sax@0.5.x: resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" integrity sha512-c0YL9VcSfcdH3F1Qij9qpYJFpKFKMXNOkLWFssBL3RuF7ZS8oZhllR2rWlCRjDTJsfq3R6wbSsaRU6o0rkEdNw== -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -semaphore@^1.0.5: +semaphore@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@7.x, semver@^7.3.5: - version "7.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" - integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== - dependencies: - lru-cache "^6.0.0" - -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^7.3.7: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - -semver@^7.5.2: - version "7.6.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== - -semver@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.6.0: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: + version "7.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.0.tgz#9c6fe61d0c6f9fa9e26575162ee5a9180361b09c" + integrity sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ== semver@~7.0.0: version "7.0.0" @@ -5586,6 +6187,37 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== + dependencies: + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" @@ -5594,7 +6226,7 @@ setprototypeof@1.2.0: shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== dependencies: shebang-regex "^1.0.0" @@ -5608,7 +6240,7 @@ shebang-command@^2.0.0: shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== shebang-regex@^3.0.0: version "3.0.0" @@ -5616,41 +6248,71 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.6.1: - version "1.7.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + version "1.8.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a" + integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== -shelljs@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" - integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== +shelljs@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== dependencies: glob "^7.0.0" interpret "^1.0.0" rechoir "^0.6.2" -shimmer@^1.1.0, shimmer@^1.2.0: +shimmer@^1.1.0, shimmer@^1.2.0, shimmer@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== shx@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.2.tgz#40501ce14eb5e0cbcac7ddbd4b325563aad8c123" - integrity sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA== + version "0.3.4" + resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.4.tgz#74289230b4b663979167f94e1935901406e40f02" + integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g== dependencies: - es6-object-assign "^1.0.3" - minimist "^1.2.0" - shelljs "^0.8.1" + minimist "^1.2.3" + shelljs "^0.8.5" -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.0.6, side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" @@ -5660,7 +6322,7 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== dependencies: is-arrayish "^0.3.1" @@ -5690,14 +6352,14 @@ source-map-support@0.5.13: source-map "^0.6.0" source-map-support@^0.5.6: - version "0.5.16" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" - integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -5708,40 +6370,40 @@ space-separated-tokens@^1.0.0: integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + version "3.0.21" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz#6d6e980c9df2b6fc905343a3b2d702a6239536c3" + integrity sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg== sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + version "1.18.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -5756,12 +6418,12 @@ sshpk@^1.7.0: stack-chain@^1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= + integrity sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug== stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" - integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== stack-utils@^2.0.3: version "2.0.6" @@ -5803,28 +6465,46 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: strip-ansi "^6.0.1" string.prototype.padend@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz#dc08f57a8010dc5c153550318f67e13adbb72ac3" - integrity sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -string.prototype.trimleft@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" - integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== - dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" - -string.prototype.trimright@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" - integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== + version "3.1.6" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz#ba79cf8992609a91c872daa47c6bb144ee7f62a5" + integrity sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1: version "1.3.0" @@ -5853,7 +6533,7 @@ stringify-entities@^1.0.1: strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== dependencies: ansi-regex "^3.0.0" @@ -5867,7 +6547,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" @@ -5892,7 +6572,7 @@ strnum@^1.0.5: subdirs@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/subdirs/-/subdirs-1.0.1.tgz#d65264787476e4caf7efc5498fb740c69f626d48" - integrity sha1-1lJkeHR25Mr378VJj7dAxp9ibUg= + integrity sha512-KSbUKpwQIRcb5Th+l4EzxEZYpCwV/g0pQ348EV7CIM5YEEgzz2L1KJD8FCeTckTiE/TKn2u09DCxpdAL6/iFbg== dependencies: es6-promise "^3.0.2" @@ -5928,9 +6608,9 @@ supports-color@^5.3.0, supports-color@^5.5.0: has-flag "^3.0.0" supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" @@ -6004,7 +6684,7 @@ swagger-parser@^8.0.4: swagger-schema-official@2.0.0-bab6bed: version "2.0.0-bab6bed" resolved "https://registry.yarnpkg.com/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz#70070468d6d2977ca5237b2e519ca7d06a2ea3fd" - integrity sha1-cAcEaNbSl3ylI3suUZyn0Gouo/0= + integrity sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA== synckit@^0.9.1: version "0.9.2" @@ -6028,16 +6708,16 @@ text-hex@1.0.x: resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -6051,20 +6731,9 @@ toidentifier@1.0.1: integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== touch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" - integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== - dependencies: - nopt "~1.0.10" - -tough-cookie@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" - integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== - dependencies: - ip-regex "^2.1.0" - psl "^1.1.28" - punycode "^2.1.1" + version "3.1.1" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694" + integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA== tough-cookie@~2.5.0: version "2.5.0" @@ -6094,10 +6763,10 @@ trim@0.0.1: resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" integrity sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ== -triple-beam@^1.2.0, triple-beam@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" - integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== trough@^1.0.0: version "1.0.5" @@ -6110,18 +6779,19 @@ ts-api-utils@^1.3.0: integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== ts-jest@^29.1.0: - version "29.1.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" - integrity sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA== + version "29.2.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.5.tgz#591a3c108e1f5ebd013d3152142cb5472b399d63" + integrity sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA== dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" jest-util "^29.0.0" json5 "^2.2.3" - lodash.memoize "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "^21.0.1" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.6.3" + yargs-parser "^21.1.1" ts-node@^7.0.1: version "7.0.1" @@ -6138,21 +6808,11 @@ ts-node@^7.0.1: yn "^2.0.0" ts-pattern@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/ts-pattern/-/ts-pattern-4.0.3.tgz#4b5a08ff61fcd5a9bbfe3c1e686c35420ef87bda" - integrity sha512-OxQStbr1MKcYYz3YaXsFSBkMo3zjFODVkV8kaLfOak+sWSfx4B+jkOm/VoaWLhnMP+icnIcJ7ENYEnmpAv3jLg== - -tslib@^1.10.0, tslib@^1.9.3: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - -tslib@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== + version "4.3.0" + resolved "https://registry.yarnpkg.com/ts-pattern/-/ts-pattern-4.3.0.tgz#7a995b39342f1b00d1507c2d2f3b90ea16e178a6" + integrity sha512-pefrkcd4lmIVR0LA49Imjf9DYLK8vtWhqBPA3Ya1ir8xCW0O2yjL9dsCVvI7pCodLC5q7smNpEtDR2yVulQxOg== -tslib@^2.6.2: +tslib@^2.2.0, tslib@^2.6.2, tslib@^2.7.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -6160,25 +6820,32 @@ tslib@^2.6.2: tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== dependencies: safe-buffer "^5.0.1" -tunnel@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" - integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" @@ -6192,6 +6859,51 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -6214,33 +6926,45 @@ typescript@4.9.5: integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== uglify-js@^3.1.4: - version "3.8.0" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.8.0.tgz#f3541ae97b2f048d7e7e3aa4f39fd8a1f5d7a805" - integrity sha512-ugNSTT8ierCsDHso2jkBHXYrU8Y5/fY2ZUprfrJUiD7YpuFvV4jODLFmb3h4btQjqr5Nh4TX4XtgDfCU1WdioQ== - dependencies: - commander "~2.20.3" - source-map "~0.6.1" + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== ulid@^2.2.2, ulid@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + undefsafe@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== underscore@^1.12.1: - version "1.13.6" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" - integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== + version "1.13.7" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" + integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g== undici-types@~6.19.2: version "6.19.8" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + unherit@^1.0.4: version "1.1.3" resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" @@ -6316,11 +7040,6 @@ unist-util-visit@^1.0.0, unist-util-visit@^1.1.0: dependencies: unist-util-visit-parents "^2.0.0" -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -6329,15 +7048,15 @@ universalify@^0.1.0: unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" - integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== +update-browserslist-db@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz#97e9c96ab0ae7bcac08e9ae5151d26e6bc6b5580" + integrity sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.2.0" + picocolors "^1.1.1" uri-js@^4.2.2: version "4.4.1" @@ -6349,12 +7068,12 @@ uri-js@^4.2.2: util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utils-merge@1.0.1, utils-merge@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@^3.0.0, uuid@^3.3.2: version "3.4.0" @@ -6367,13 +7086,13 @@ uuid@^8.3.0: integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-to-istanbul@^9.0.1: - version "9.1.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" - integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" + convert-source-map "^2.0.0" validate-npm-package-license@^3.0.1: version "3.0.4" @@ -6388,25 +7107,20 @@ validator@^10.0.0, validator@^10.8.0: resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== -validator@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4" - integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg== - -validator@^13.7.0: - version "13.9.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" - integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== +validator@^13.6.0, validator@^13.7.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" + integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -6445,7 +7159,7 @@ walker@^1.0.8: wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== dependencies: defaults "^1.0.3" @@ -6462,10 +7176,62 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which-typed-array@^1.1.16, which-typed-array@^1.1.18: + version "1.1.18" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" + integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" + for-each "^0.3.3" + gopd "^1.2.0" + has-tostringtag "^1.0.2" which@^1.2.9: version "1.3.1" @@ -6481,59 +7247,41 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -winston-transport@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59" - integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw== - dependencies: - readable-stream "^2.3.7" - triple-beam "^1.2.0" - -winston-transport@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.5.0.tgz#6e7b0dd04d393171ed5e4e4905db265f7ab384fa" - integrity sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q== +winston-transport@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.9.0.tgz#3bba345de10297654ea6f33519424560003b3bf9" + integrity sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A== dependencies: - logform "^2.3.2" - readable-stream "^3.6.0" + logform "^2.7.0" + readable-stream "^3.6.2" triple-beam "^1.3.0" -winston@^3.1.0, winston@^3.7.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/winston/-/winston-3.8.2.tgz#56e16b34022eb4cff2638196d9646d7430fdad50" - integrity sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew== +winston@^3.1.0, winston@^3.3.3, winston@^3.7.2: + version "3.17.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.17.0.tgz#74b8665ce9b4ea7b29d0922cfccf852a08a11423" + integrity sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw== dependencies: - "@colors/colors" "1.5.0" + "@colors/colors" "^1.6.0" "@dabh/diagnostics" "^2.0.2" async "^3.2.3" is-stream "^2.0.0" - logform "^2.4.0" + logform "^2.7.0" one-time "^1.0.0" readable-stream "^3.4.0" safe-stable-stringify "^2.3.1" stack-trace "0.0.x" triple-beam "^1.3.0" - winston-transport "^4.5.0" + winston-transport "^4.9.0" -winston@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" - integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw== - dependencies: - "@dabh/diagnostics" "^2.0.2" - async "^3.1.0" - is-stream "^2.0.0" - logform "^2.2.0" - one-time "^1.0.0" - readable-stream "^3.4.0" - stack-trace "0.0.x" - triple-beam "^1.3.0" - winston-transport "^4.4.0" +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + integrity sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw== wrap-ansi@^6.2.0: version "6.2.0" @@ -6556,7 +7304,7 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^3.0.3: version "3.0.3" @@ -6589,14 +7337,6 @@ x-xss-protection@1.3.0: resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.3.0.tgz#3e3a8dd638da80421b0e9fff11a2dbe168f6d52c" integrity sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg== -xml2js@^0.4.19: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - xml2js@~0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.2.8.tgz#9b81690931631ff09d1957549faf54f4f980b3c2" @@ -6609,11 +7349,6 @@ xmlbuilder@^9.0.7: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ== -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - xtend@^4.0.0, xtend@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -6629,7 +7364,7 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@4.0.0, yallist@^4.0.0: +yallist@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== @@ -6639,14 +7374,6 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs-parser@^18.1.1: - version "18.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.1.tgz#bf7407b915427fc760fcbbccc6c82b4f0ffcbd37" - integrity sha512-KRHEsOM16IX7XuLnMOqImcPNbLVXMNHYAoFc3BKR8Ortl5gzDbtXvvEoGx9imk5E+X1VeNKNlcHr8B8vi+7ipA== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -6655,12 +7382,12 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^21.0.1, yargs-parser@^21.1.1: +yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^15.0.1: +yargs@^15.0.1, yargs@^15.0.2: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== @@ -6677,23 +7404,6 @@ yargs@^15.0.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^15.0.2: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.1" - yargs@^17.3.1: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" @@ -6710,7 +7420,7 @@ yargs@^17.3.1: yn@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" - integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo= + integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== yocto-queue@^0.1.0: version "0.1.0" @@ -6730,23 +7440,23 @@ z-schema@^3.23.0: commander "^2.7.1" z-schema@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-4.2.2.tgz#43fa2709ae5016885db50e1ce31b254b72c0886c" - integrity sha512-7bGR7LohxSdlK1EOdvA/OHksvKGE4jTLSjd8dBj9YKT0S43N9pdMZ0Z7GZt9mHrBFhbNTRh3Ky6Eu2MHsPJe8g== + version "4.2.4" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-4.2.4.tgz#73102a49512179b12a8ec50b1daa676b984da6e4" + integrity sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w== dependencies: lodash.get "^4.4.2" lodash.isequal "^4.5.0" - validator "^11.0.0" + validator "^13.6.0" optionalDependencies: commander "^2.7.1" z-schema@^5.0.1: - version "5.0.5" - resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.5.tgz#6805a48c5366a6125cae0e58752babfd503daf32" - integrity sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q== + version "5.0.6" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" + integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== dependencies: lodash.get "^4.4.2" lodash.isequal "^4.5.0" validator "^13.7.0" optionalDependencies: - commander "^9.4.1" + commander "^10.0.0" From 24356bd1bd56ca48395cc30f2808d515c0d25503 Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Fri, 31 Jan 2025 14:42:32 +0100 Subject: [PATCH 03/13] Update eslint config --- .eslintrc.js | 29 ----------------------------- eslint.config.mjs | 23 +++++++++++++++++++++++ package.json | 4 ++-- 3 files changed, 25 insertions(+), 31 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 eslint.config.mjs diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 6f8422539..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - "env": { - "browser": true, - "es6": true, - "node": true - }, - "ignorePatterns": [ - "node_modules", - "generated", - "**/__tests__/*", - "**/__mocks__/*", - "Dangerfile.*", - "*.d.ts" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module" - }, - "extends": [ - "@pagopa/eslint-config/strong", - ], - "rules": { - "prefer-arrow/prefer-arrow-functions": "off", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "no-invalid-this": "off" - } -}; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..850ea20e0 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,23 @@ +import pagopa from "@pagopa/eslint-config"; + +export default [ + ...pagopa, + { + rules: { + "prefer-arrow/prefer-arrow-functions": "off", + "@typescript-eslint/naming-convention": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "no-invalid-this": "off", + } + }, + { + ignores: [ + "node_modules", + "generated", + "**/__tests__/*", + "**/__mocks__/*", + "Dangerfile.*", + "*.d.ts" + ], + }, +]; \ No newline at end of file diff --git a/package.json b/package.json index 536c7867e..16228847a 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "build": "tsc", "build-noemit": "tsc --noEmit", "hot-reload": "nodemon --legacy-watch --watch ./dist/src --inspect=0.0.0.0:5859 --nolazy dist/src/server.js", - "lint": "eslint . -c .eslintrc.js --ext .ts,.tsx --cache", - "lint-autofix": "eslint . -c .eslintrc.js --ext .ts,.tsx --fix", + "lint": "eslint . --cache", + "lint-autofix": "eslint . --fix", "prettify": "prettier --write \"./**/*.ts\"", "test": "jest -i", "test:coverage": "jest -i --coverage", From d3c49d72c4cdeef83cd232c1e822e808e15d1566 Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Fri, 31 Jan 2025 14:50:00 +0100 Subject: [PATCH 04/13] Update node version --- .node-version | 2 +- .nvmrc | 2 +- Dockerfile | 4 ++-- package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.node-version b/.node-version index 0254b1e63..3516580bb 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20.18.2 +20.17.0 diff --git a/.nvmrc b/.nvmrc index 0254b1e63..3516580bb 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.18.2 +20.17.0 diff --git a/Dockerfile b/Dockerfile index 4a1eb4c8d..0317dff56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20.18.2 as builder +FROM node:20.17.0 as builder WORKDIR /usr/src/app @@ -7,7 +7,7 @@ COPY / /usr/src/app/ RUN yarn install \ && yarn predeploy -FROM node:20.18.2-alpine +FROM node:20.17.0-alpine LABEL maintainer="https://pagopa.gov.it" # Install major CA certificates to cover diff --git a/package.json b/package.json index 16228847a..3d5658edf 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "description": "IO app and web backend", "main": "index.js", "engines": { - "node": "20.18.2" + "node": "20.17.0" }, "scripts": { "watch": "tsc -w", From 090cbc0f3633c23bce94507c705ddb14d3305002 Mon Sep 17 00:00:00 2001 From: Daniele Manni Date: Fri, 31 Jan 2025 15:16:49 +0100 Subject: [PATCH 05/13] fix some eslint errors --- eslint.config.mjs | 39 +- src/@types/bwip-js/index.d.ts | 112 +- src/@types/passport-auth-token/index.d.ts | 11 +- .../passport-http-custom-bearer/index.d.ts | 57 +- src/__tests__/lollipop-consumer.test.ts | 4 +- src/adapters/pnFetch.ts | 205 ++-- src/app.ts | 518 ++++---- src/clients/api.ts | 4 +- src/clients/app-messages.client.ts | 3 +- src/clients/bonus.ts | 3 +- src/clients/cgn-operator-search.ts | 3 +- src/clients/cgn.ts | 4 +- src/clients/eucovidcert.client.ts | 4 +- src/clients/firstLollipopConsumer.ts | 5 +- src/clients/io-fims.ts | 3 +- src/clients/io-sign.ts | 3 +- src/clients/io-wallet.ts | 4 +- src/clients/lollipop.ts | 3 +- src/clients/pagopa.ts | 3 +- src/clients/pn-clients.ts | 17 +- src/clients/services-app-backend.ts | 3 +- src/clients/third-party-service-client.ts | 37 +- src/clients/trial-system.client.ts | 3 +- src/config.ts | 213 ++-- src/controllers/authenticationController.ts | 21 +- src/controllers/bonusController.ts | 60 +- src/controllers/cgnController.ts | 152 +-- .../cgnOperatorSearchController.ts | 211 ++-- src/controllers/eucovidcertController.ts | 30 +- src/controllers/fimsController.ts | 73 +- .../firstLollipopConsumerController.ts | 49 +- src/controllers/ioSignController.ts | 196 ++- src/controllers/ioWalletController.ts | 292 +++-- src/controllers/messagesController.ts | 351 +++--- src/controllers/notificationController.ts | 54 +- src/controllers/pagoPAProxyController.ts | 56 +- src/controllers/pnController.ts | 53 +- src/controllers/profileController.ts | 77 +- .../serviceAppBackendController.ts | 69 +- src/controllers/servicesController.ts | 39 +- src/controllers/sessionController.ts | 9 +- src/controllers/sessionLockController.ts | 591 +++++---- src/controllers/ssoController.ts | 11 +- src/controllers/trialController.ts | 41 +- .../userDataProcessingController.ts | 68 +- src/controllers/userMetadataController.ts | 23 +- src/server.ts | 43 +- src/services/IPagoPAClientFactory.ts | 2 +- src/services/ISessionStorage.ts | 61 +- src/services/IUserMetadataStorage.ts | 13 +- src/services/apiClientFactory.ts | 2 +- src/services/authenticationLockService.ts | 108 +- src/services/bonusService.ts | 60 +- src/services/cgnOperatorSearchService.ts | 172 +-- src/services/cgnService.ts | 228 ++-- src/services/eucovidcertService.ts | 33 +- src/services/fimsService.ts | 21 +- src/services/functionAppService.ts | 49 +- src/services/ioSignService.ts | 200 ++- src/services/ioWalletService.ts | 294 ++--- src/services/lollipopService.ts | 7 +- src/services/newMessagesService.ts | 1008 ++++++++------- src/services/notificationService.ts | 99 +- src/services/notificationServiceFactory.ts | 19 +- src/services/pagoPAClientFactory.ts | 6 +- src/services/pagoPAProxyService.ts | 135 +- src/services/pnService.ts | 6 +- src/services/profileService.ts | 212 ++-- src/services/redisSessionStorage.ts | 1085 +++++++++-------- src/services/redisStorageUtils.ts | 80 +- src/services/redisUserMetadataStorage.ts | 141 +-- src/services/servicesAppBackendService.ts | 91 +- src/services/trialService.ts | 57 +- src/services/userDataProcessingService.ts | 102 +- src/strategies/bearerMyPortalTokenStrategy.ts | 9 +- src/strategies/bearerSessionTokenStrategy.ts | 9 +- src/types/IDPEntityDescriptor.ts | 2 +- src/types/assertionRef.ts | 9 +- src/types/booleans.ts | 6 +- src/types/commons.ts | 11 +- src/types/fiscalCode.ts | 5 +- src/types/lollipop.ts | 62 +- src/types/notification.ts | 2 +- src/types/pathParams.ts | 46 +- src/types/profile.ts | 14 +- src/types/token.ts | 6 +- src/types/user.ts | 23 +- src/utils/AsyncIterableTask.ts | 46 +- src/utils/appinsights.ts | 63 +- src/utils/attachments.ts | 13 +- src/utils/barcode.ts | 18 +- src/utils/container.ts | 1 + src/utils/date.ts | 12 +- src/utils/errorsFormatter.ts | 8 +- src/utils/express.ts | 34 +- src/utils/fastLogin.ts | 4 +- src/utils/featureFlag.ts | 4 +- src/utils/file-type.ts | 11 +- src/utils/gracefulShutdown.ts | 7 +- src/utils/logger.ts | 4 +- src/utils/lollipop.ts | 212 ++-- src/utils/middleware/checkIP.ts | 19 +- src/utils/middleware/dueDate.ts | 9 +- src/utils/middleware/express.ts | 6 +- src/utils/middleware/lollipop.ts | 53 +- src/utils/network.ts | 12 +- src/utils/ognl.ts | 57 +- src/utils/package.ts | 19 +- src/utils/profile.ts | 33 +- src/utils/qrcode.ts | 16 +- src/utils/redis.ts | 35 +- src/utils/responses.ts | 57 +- src/utils/separated-list.ts | 10 +- src/utils/strategies.ts | 15 +- src/utils/thirdPartyConfig.ts | 18 +- src/utils/url.ts | 6 +- 116 files changed, 4562 insertions(+), 4565 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 850ea20e0..f0e5a1276 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,23 +1,24 @@ import pagopa from "@pagopa/eslint-config"; export default [ - ...pagopa, - { - rules: { - "prefer-arrow/prefer-arrow-functions": "off", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "no-invalid-this": "off", - } + ...pagopa, + { + rules: { + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/naming-convention": "off", + "no-invalid-this": "off", + "prefer-arrow/prefer-arrow-functions": "off", }, - { - ignores: [ - "node_modules", - "generated", - "**/__tests__/*", - "**/__mocks__/*", - "Dangerfile.*", - "*.d.ts" - ], - }, -]; \ No newline at end of file + }, + { + ignores: [ + "node_modules", + "generated", + "dist", + "**/__tests__/*", + "**/__mocks__/*", + "Dangerfile.*", + "*.d.ts", + ], + }, +]; diff --git a/src/@types/bwip-js/index.d.ts b/src/@types/bwip-js/index.d.ts index 276001e6b..321280aa1 100644 --- a/src/@types/bwip-js/index.d.ts +++ b/src/@types/bwip-js/index.d.ts @@ -1,7 +1,7 @@ declare module "bwip-js" { export interface IFontLib { - lookup: (arg0: any) => any; getpaths: (arg0: any, arg1: any, arg2: number, arg3: number) => any; + lookup: (arg0: any) => any; } export const FontLib: IFontLib; @@ -12,83 +12,83 @@ declare module "bwip-js" { export function toBuffer( opts: ToBufferOptions, - callback: (err: string | Error, png: Buffer) => void + callback: (err: Error | string, png: Buffer) => void, ): void; interface ToBufferOptions { + addontextfont?: string; + addontextsize?: number; + + addontextxoffset?: number; + addontextyoffset?: number; + + alttext?: boolean; + backgroundcolor?: string; + + barcolor?: string; bcid: string; - text: string; + boraderbottom?: number; - parse?: boolean; - parsefunc?: boolean; + bordercolor?: string; - height?: number; - width?: number; + borderleft?: number; + borderright?: number; + bordertop?: number; + borderwidth?: number; + guardheight?: number; + guardleftpos?: number; - scaleX?: number; - scaleY?: number; - scale?: number; + guardleftypos?: number; + guardrightpos?: number; - rotate?: "N" | "R" | "L" | "I"; + guardrightypos?: number; + guardwhitespace?: boolean; + guardwidth?: number; + height?: number; - paddingwidth?: number; + includecheck?: boolean; + includecheckintext?: boolean; + includetext?: boolean; + inkspread?: number; + + inkspreadh?: number; + inkspreadv?: number; + monochrome?: boolean; + paddingbottom?: number; paddingheight?: number; paddingleft?: number; + paddingright?: number; paddingtop?: number; - paddingbottom?: number; + paddingwidth?: number; + parse?: boolean; - monochrome?: boolean; - alttext?: boolean; + parsefunc?: boolean; + rotate?: "I" | "L" | "N" | "R"; + scale?: number; + scaleX?: number; - includetext?: boolean; + scaleY?: number; + showborder?: boolean; + sizelimit?: number; + text: string; + textcolor?: string; textfont?: string; - textsize?: number; textgaps?: number; + textsize?: number; + textxalign?: - | "offleft" - | "left" | "center" - | "right" + | "justify" + | "left" + | "offleft" | "offright" - | "justify"; - textyalign?: "below" | "center" | "above"; + | "right"; textxoffset?: number; - textyoffset?: number; - showborder?: boolean; - borderwidth?: number; - borderleft?: number; - borderright?: number; - bordertop?: number; - boraderbottom?: number; - - barcolor?: string; - backgroundcolor?: string; - bordercolor?: string; - textcolor?: string; - - addontextxoffset?: number; - addontextyoffset?: number; - addontextfont?: string; - addontextsize?: number; - - guardwhitespace?: boolean; - guardwidth?: number; - guardheight?: number; - guardleftpos?: number; - guardrightpos?: number; - guardleftypos?: number; - guardrightypos?: number; - - sizelimit?: number; - - includecheck?: boolean; - includecheckintext?: boolean; - - inkspread?: number; - inkspreadh?: number; - inkspreadv?: number; + textyalign?: "above" | "below" | "center"; + textyoffset?: number; + width?: number; } } diff --git a/src/@types/passport-auth-token/index.d.ts b/src/@types/passport-auth-token/index.d.ts index 95e57bfbf..752c260be 100644 --- a/src/@types/passport-auth-token/index.d.ts +++ b/src/@types/passport-auth-token/index.d.ts @@ -5,18 +5,19 @@ declare module "passport-auth-token"; interface IVerifyOptions { - readonly tokenFields: ReadonlyArray; - readonly headerFields: ReadonlyArray; - readonly passReqToCallback: boolean; - readonly params: boolean; + readonly headerFields: readonly string[]; readonly optional: boolean; + readonly params: boolean; + readonly passReqToCallback: boolean; + readonly tokenFields: readonly string[]; } type VerifyFunction = ( token: string, - done: (error: any, user?: any, options?: IVerifyOptions) => void + done: (error: any, user?: any, options?: IVerifyOptions) => void, ) => void; +// eslint-disable-next-line @typescript-eslint/no-extraneous-class declare class Strategy { constructor(verify: VerifyFunction); } diff --git a/src/@types/passport-http-custom-bearer/index.d.ts b/src/@types/passport-http-custom-bearer/index.d.ts index 97e708f5c..2b3be667f 100644 --- a/src/@types/passport-http-custom-bearer/index.d.ts +++ b/src/@types/passport-http-custom-bearer/index.d.ts @@ -3,61 +3,56 @@ */ declare module "passport-http-custom-bearer" { - import passport = require("passport"); import express = require("express"); import koa = require("koa"); + import passport = require("passport"); interface IStrategyOptions { bodyName?: string; headerName?: string; + passReqToCallback?: boolean | undefined; queryName?: string; - scope?: string | Array | undefined; realm?: string | undefined; - passReqToCallback?: boolean | undefined; + scope?: string | string[] | undefined; } interface IVerifyOptions { message?: string | undefined; - scope: string | Array; + scope: string | string[]; } - interface VerifyFunction { - ( - token: string, - done: (error: any, user?: any, options?: IVerifyOptions | string) => void - ): void; - } + type VerifyFunction = ( + token: string, + done: (error: any, user?: any, options?: IVerifyOptions | string) => void, + ) => void; interface IKoaContextContainer { ctx: koa.Context; } - type KoaPassportExpressRequestMock = Partial & - IKoaContextContainer; - - interface VerifyFunctionWithRequest { - ( - req: express.Request, - token: string, - done: (error: any, user?: any, options?: IVerifyOptions | string) => void - ): void; - } - interface VerifyFunctionWithContext { - ( - req: KoaPassportExpressRequestMock, - token: string, - done: (error: any, user?: any, options?: IVerifyOptions | string) => void - ): void; - } + type KoaPassportExpressRequestMock = IKoaContextContainer & + Partial; + + type VerifyFunctionWithRequest = ( + req: express.Request, + token: string, + done: (error: any, user?: any, options?: IVerifyOptions | string) => void, + ) => void; + type VerifyFunctionWithContext = ( + req: KoaPassportExpressRequestMock, + token: string, + done: (error: any, user?: any, options?: IVerifyOptions | string) => void, + ) => void; type VerifyFunctions = | VerifyFunction - | VerifyFunctionWithRequest - | VerifyFunctionWithContext; + | VerifyFunctionWithContext + | VerifyFunctionWithRequest; class Strategy implements passport.Strategy { + name: string; constructor(verify: VerifyFunction); - constructor(options: IStrategyOptions, verify: T); - name: string; + constructor(options: IStrategyOptions, verify: T); + // eslint-disable-next-line @typescript-eslint/ban-types authenticate(req: express.Request, options?: Object): void; } } diff --git a/src/__tests__/lollipop-consumer.test.ts b/src/__tests__/lollipop-consumer.test.ts index 73a323625..f1d490457 100644 --- a/src/__tests__/lollipop-consumer.test.ts +++ b/src/__tests__/lollipop-consumer.test.ts @@ -60,7 +60,7 @@ const lollipopConsumerApp = express(); lollipopConsumerApp.use( bodyParser.json({ verify: (_req, res: express.Response, buf, _encoding: BufferEncoding) => { - // eslint-disable-next-line functional/immutable-data + res.locals.body = buf; }, }) @@ -123,7 +123,7 @@ describe("lollipopSign", () => { buf, _encoding: BufferEncoding ) => { - // eslint-disable-next-line functional/immutable-data + res.locals.body = buf; }, }) diff --git a/src/adapters/pnFetch.ts b/src/adapters/pnFetch.ts index 5cd8f9e63..ac7d92d4d 100644 --- a/src/adapters/pnFetch.ts +++ b/src/adapters/pnFetch.ts @@ -1,48 +1,49 @@ /* eslint-disable max-params */ -import { URL } from "url"; -import { flow, pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; -import * as E from "fp-ts/Either"; -import * as TE from "fp-ts/TaskEither"; -import * as O from "fp-ts/Option"; +import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; import { FiscalCode, NonEmptyString, Ulid, } from "@pagopa/ts-commons/lib/strings"; -import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; -import { Response as NodeResponse } from "node-fetch"; +import { eventLog } from "@pagopa/winston-ts"; +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; +import * as TE from "fp-ts/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; import { NotificationAttachmentDownloadMetadataResponse } from "generated/piattaforma-notifiche/NotificationAttachmentDownloadMetadataResponse"; -import { match } from "ts-pattern"; -import { LollipopLocalsType } from "src/types/lollipop"; -import { Fetch } from "src/clients/third-party-service-client"; +import * as t from "io-ts"; +import { Response as NodeResponse } from "node-fetch"; import nodeFetch from "node-fetch"; -import { eventLog } from "@pagopa/winston-ts"; +import { Fetch } from "src/clients/third-party-service-client"; +import { LollipopLocalsType } from "src/types/lollipop"; +import { match } from "ts-pattern"; +import { URL } from "url"; + import { PnAPIClient } from "../clients/pn-clients"; -import { errorsToError } from "../utils/errorsFormatter"; -import { pathParamsFromUrl } from "../types/pathParams"; import { PN_CONFIGURATION_ID } from "../config"; +import { pathParamsFromUrl } from "../types/pathParams"; +import { errorsToError } from "../utils/errorsFormatter"; const getPath = (input: RequestInfo | URL): string => input instanceof URL ? `${input.pathname}${input.search}` : typeof input === "string" - ? `${new URL(input).pathname}${new URL(input).search}` - : `${new URL(input.url).pathname}${new URL(input.url).search}`; + ? `${new URL(input).pathname}${new URL(input).search}` + : `${new URL(input.url).pathname}${new URL(input.url).search}`; export const ThirdPartyMessagesUrl = pathParamsFromUrl( RegExp("^[/]+messages[/]+([^/]+)$"), - ([id]) => `/messages/${id}` + ([id]) => `/messages/${id}`, ); export const ThirdPartyAttachmentUrl = pathParamsFromUrl( RegExp("^[/]+messages[/]+([^/]+)/(.+)$"), - ([id, url]) => `/messages/${id}/${url}` + ([id, url]) => `/messages/${id}/${url}`, ); export const ThirdPartyPreconditionUrl = pathParamsFromUrl( RegExp("^[/]+messages[/]+([^/]+)/precondition$"), - ([id]) => `/messages/${id}/precondition` + ([id]) => `/messages/${id}/precondition`, ); // document path @@ -52,7 +53,7 @@ const attachmentPnDocument = "[/]+attachments[/]+documents[/]+([^/]+)$"; export const PnDocumentUrl = pathParamsFromUrl( RegExp(`${basePnDocument}${attachmentPnDocument}`), ([iun, docIdx]) => - `/delivery/notifications/received/${iun}/attachments/documents/${docIdx}` + `/delivery/notifications/received/${iun}/attachments/documents/${docIdx}`, ); // payment path @@ -61,7 +62,7 @@ const attachmentPnPayment = export const PnPaymentUrl = pathParamsFromUrl( RegExp(`${basePnDocument}${attachmentPnPayment}`), ([iun, docName, docIdx]) => - `/delivery/notifications/received/${iun}/attachments/payment/${docName}/?attachmentIdx=${docIdx}` + `/delivery/notifications/received/${iun}/attachments/payment/${docName}/?attachmentIdx=${docIdx}`, ); /** @@ -86,8 +87,8 @@ const retrievePrecondition = ( pnUrl: string, pnApiKey: string, fiscalCode: FiscalCode, - [iun]: ReadonlyArray, - lollipopLocals?: LollipopLocalsType + [iun]: readonly string[], + lollipopLocals?: LollipopLocalsType, ) => pipe( () => @@ -102,10 +103,10 @@ const retrievePrecondition = ( TE.chain( TE.fromPredicate( (r) => r.status === 200, - (r) => Error(`Failed to fetch PN ReceivedPrecondition: ${r.status}`) - ) + (r) => Error(`Failed to fetch PN ReceivedPrecondition: ${r.status}`), + ), ), - TE.map((response) => response.value) + TE.map((response) => response.value), ); const retrieveNotificationDetails = ( @@ -113,8 +114,8 @@ const retrieveNotificationDetails = ( pnUrl: string, pnApiKey: string, fiscalCode: FiscalCode, - [iun]: ReadonlyArray, - lollipopLocals?: LollipopLocalsType + [iun]: readonly string[], + lollipopLocals?: LollipopLocalsType, ) => pipe( () => @@ -128,21 +129,21 @@ const retrieveNotificationDetails = ( TE.chain( TE.fromPredicate( (r) => r.status === 200, - (r) => Error(`Failed to fetch PN ReceivedNotification: ${r.status}`) - ) + (r) => Error(`Failed to fetch PN ReceivedNotification: ${r.status}`), + ), ), - TE.map((response) => response.value) + TE.map((response) => response.value), ); const checkHeaders = ( - headers?: HeadersInit + headers?: HeadersInit, ): TE.TaskEither => pipe( headers, O.fromNullable, E.fromOption(() => Error("Missing fiscal_code in headers")), E.chain(flow(WithFiscalCode.decode, E.mapLeft(errorsToError))), - TE.fromEither + TE.fromEither, ); export const errorResponse = (error: Error): Response => @@ -157,7 +158,7 @@ export const errorResponse = (error: Error): Response => new NodeResponse(JSON.stringify(problem), { status: problem.status, statusText: problem.title, - }) as unknown as Response // cast required: the same cast is used in clients code generation + }) as unknown as Response, // cast required: the same cast is used in clients code generation ); export const retryResponse = (retryAfter: number): Response => @@ -173,7 +174,7 @@ export const retryResponse = (retryAfter: number): Response => headers: { "Retry-After": `${retryAfter}` }, status: problem.status, statusText: problem.title, - }) as unknown as Response // cast required: the same cast is used in clients code generation + }) as unknown as Response, // cast required: the same cast is used in clients code generation ); export const redirectPrecondition = @@ -183,7 +184,7 @@ export const redirectPrecondition = pnApiKey: string, url: string, lollipopLocals?: LollipopLocalsType, - init?: RequestInit + init?: RequestInit, ) => (): Promise => pipe( @@ -212,26 +213,25 @@ export const redirectPrecondition = pnApiKey, headers.fiscal_code, params, - lollipopLocals - ) - ) - ) - ) + lollipopLocals, + ), + ), + ), + ), ), TE.map( - // eslint-disable-next-line sonarjs/no-identical-functions (body) => new NodeResponse(JSON.stringify(body), { status: 200, statusText: "OK", - }) as unknown as Response // cast required: the same cast is used in clients code generation + }) as unknown as Response, // cast required: the same cast is used in clients code generation ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call retrievePrecondition`, { message, name: "pn.precondition.error" }, ]), TE.mapLeft(errorResponse), - TE.toUnion + TE.toUnion, )(); export const redirectMessages = @@ -241,7 +241,7 @@ export const redirectMessages = pnApiKey: string, url: string, lollipopLocals?: LollipopLocalsType, - init?: RequestInit + init?: RequestInit, ) => (): Promise => pipe( @@ -270,26 +270,25 @@ export const redirectMessages = pnApiKey, headers.fiscal_code, params, - lollipopLocals - ) - ) - ) - ) + lollipopLocals, + ), + ), + ), + ), ), TE.map( - // eslint-disable-next-line sonarjs/no-identical-functions (body) => new NodeResponse(JSON.stringify(body), { status: 200, statusText: "OK", - }) as unknown as Response // cast required: the same cast is used in clients code generation + }) as unknown as Response, // cast required: the same cast is used in clients code generation ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call retrieveNotificationDetails`, { message, name: "pn.notification.error" }, ]), TE.mapLeft(errorResponse), - TE.toUnion + TE.toUnion, )(); const getPnDocument = ( @@ -298,7 +297,7 @@ const getPnDocument = ( pnApiKey: string, url: string, fiscalCode: FiscalCode, - lollipopLocals?: LollipopLocalsType + lollipopLocals?: LollipopLocalsType, ): TE.TaskEither => pipe( url, @@ -316,22 +315,22 @@ const getPnDocument = ( "x-pagopa-cx-taxid": fiscalCode, ...lollipopLocals, }), - E.toError + E.toError, ), TE.chainEitherK(E.mapLeft(errorsToError)), TE.chain( TE.fromPredicate( (r) => r.status === 200, (r) => - Error(`Failed to fetch PN SentNotificationDocument: ${r.status}`) - ) + Error(`Failed to fetch PN SentNotificationDocument: ${r.status}`), + ), ), TE.map( (response) => - response.value as NotificationAttachmentDownloadMetadataResponse - ) - ) - ) + response.value as NotificationAttachmentDownloadMetadataResponse, + ), + ), + ), ); const getPnPayment = ( @@ -340,7 +339,7 @@ const getPnPayment = ( pnApiKey: string, url: string, fiscalCode: FiscalCode, - lollipopLocals?: LollipopLocalsType + lollipopLocals?: LollipopLocalsType, ): TE.TaskEither => pipe( url, @@ -359,7 +358,7 @@ const getPnPayment = ( "x-pagopa-cx-taxid": fiscalCode, ...lollipopLocals, }), - E.toError + E.toError, ), TE.chainEitherK(E.mapLeft(errorsToError)), TE.chain( @@ -367,16 +366,16 @@ const getPnPayment = ( (r) => r.status === 200, (r) => Error( - `Failed to fetch PN ReceivedNotificationAttachment: ${r.status}` - ) - ) + `Failed to fetch PN ReceivedNotificationAttachment: ${r.status}`, + ), + ), ), TE.map( (response) => - response.value as NotificationAttachmentDownloadMetadataResponse - ) - ) - ) + response.value as NotificationAttachmentDownloadMetadataResponse, + ), + ), + ), ); export const redirectAttachment = @@ -386,7 +385,7 @@ export const redirectAttachment = pnApiKey: string, url: string, lollipopLocals?: LollipopLocalsType, - init?: RequestInit + init?: RequestInit, ) => (): Promise => pipe( @@ -413,9 +412,9 @@ export const redirectAttachment = pnApiKey, au, headers.fiscal_code, - lollipopLocals + lollipopLocals, ); - } + }, ) .when( (au) => E.isRight(PnPaymentUrl.decode(au)), @@ -430,17 +429,17 @@ export const redirectAttachment = pnApiKey, au, headers.fiscal_code, - lollipopLocals + lollipopLocals, ); - } + }, ) .otherwise((au) => TE.left( new Error( - `Can not distinguish a PnDocumentUrl from a PnPaymentUrl with the url ${au}` - ) - ) - ) + `Can not distinguish a PnDocumentUrl from a PnPaymentUrl with the url ${au}`, + ), + ), + ), ), TE.chain((attachment) => pipe( @@ -454,11 +453,11 @@ export const redirectAttachment = (r) => r.status === 200, (r) => Error( - `Failed to fetch PN download attachment: ${r.status}` - ) - ) - ) - ) + `Failed to fetch PN download attachment: ${r.status}`, + ), + ), + ), + ), ), E.getOrElse((_) => pipe( @@ -466,19 +465,19 @@ export const redirectAttachment = t.number.decode, E.mapLeft(errorsToError), TE.fromEither, - TE.map((r) => retryResponse(r)) - ) - ) - ) - ) - ) + TE.map((r) => retryResponse(r)), + ), + ), + ), + ), + ), ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call getPnDocumentUrl`, { message, name: "pn.attachment.error" }, ]), TE.mapLeft(errorResponse), - TE.toUnion + TE.toUnion, )(); export const pnFetch = @@ -487,13 +486,13 @@ export const pnFetch = configurationId: Ulid, pnUrl: string, pnApiKey: string, - lollipopLocals?: LollipopLocalsType + lollipopLocals?: LollipopLocalsType, ): typeof fetch => (input, init) => { eventLog.peek.info( configurationId === PN_CONFIGURATION_ID ? [`Calling PN api`, { name: "lollipop.pn.api" }] - : ["Calling third party api", { name: "lollipop.third-party.api" }] + : ["Calling third party api", { name: "lollipop.third-party.api" }], ); return configurationId === PN_CONFIGURATION_ID ? match(getPath(input)) @@ -506,8 +505,8 @@ export const pnFetch = pnApiKey, url, lollipopLocals, - init - ) + init, + ), ) .when( (url) => E.isRight(ThirdPartyPreconditionUrl.decode(url)), @@ -518,8 +517,8 @@ export const pnFetch = pnApiKey, url, lollipopLocals, - init - ) + init, + ), ) .when( (url) => E.isRight(ThirdPartyAttachmentUrl.decode(url)), @@ -530,19 +529,19 @@ export const pnFetch = pnApiKey, url, lollipopLocals, - init - ) + init, + ), ) .otherwise((url) => pipe( TE.left( new Error( - `[pnFetch] Can not find a Piattaforma Notifiche implementation for ${url}` - ) + `[pnFetch] Can not find a Piattaforma Notifiche implementation for ${url}`, + ), ), TE.mapLeft(errorResponse), - TE.toUnion - ) + TE.toUnion, + ), )() : origFetch(input, init); }; diff --git a/src/app.ts b/src/app.ts index 542f918bc..d9a38af9a 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,16 +1,4 @@ /* eslint-disable max-lines-per-function */ -/** - * Main entry point for the Digital Citizenship proxy. - */ -import * as bodyParser from "body-parser"; -import * as express from "express"; -import * as helmet from "helmet"; -import * as morgan from "morgan"; -import * as passport from "passport"; - -import { Express } from "express"; -import expressEnforcesSsl = require("express-enforces-ssl"); - import { TableClient } from "@azure/data-tables"; import { NodeEnvironment, @@ -19,14 +7,24 @@ import { import { ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { CIDR, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as appInsights from "applicationinsights"; +/** + * Main entry point for the Digital Citizenship proxy. + */ +import * as bodyParser from "body-parser"; +import * as express from "express"; +import { Express } from "express"; import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; -import { ServerInfo } from "../generated/public/ServerInfo"; +import * as helmet from "helmet"; +import * as morgan from "morgan"; +import * as passport from "passport"; +import { ServerInfo } from "../generated/public/ServerInfo"; import { VersionPerPlatform } from "../generated/public/VersionPerPlatform"; -import { getUserIdentity } from "./controllers/authenticationController"; +import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; +import { LollipopApiClient } from "./clients/lollipop"; import { API_CLIENT, APP_MESSAGES_API_CLIENT, @@ -40,16 +38,16 @@ import { FF_ENABLE_NOTIFY_ENDPOINT, FF_ENABLE_SESSION_ENDPOINTS, FF_EUCOVIDCERT_ENABLED, - FF_IO_SIGN_ENABLED, FF_IO_FIMS_ENABLED, + FF_IO_SIGN_ENABLED, FF_IO_WALLET_ENABLED, FF_ROUTING_PUSH_NOTIF, FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST, FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, FF_TRIAL_SYSTEM_ENABLED, FIRST_LOLLIPOP_CONSUMER_CLIENT, - IO_SIGN_API_CLIENT, IO_FIMS_API_CLIENT, + IO_SIGN_API_CLIENT, IO_SIGN_SERVICE_ID, IO_WALLET_API_CLIENT, LOCKED_PROFILES_STORAGE_CONNECTION_STRING, @@ -57,13 +55,13 @@ import { LOLLIPOP_API_CLIENT, LOLLIPOP_REVOKE_QUEUE_NAME, LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING, - NOTIFICATIONS_QUEUE_NAME, - NOTIFICATIONS_STORAGE_CONNECTION_STRING, NOTIFICATION_DEFAULT_SUBJECT, NOTIFICATION_DEFAULT_TITLE, + NOTIFICATIONS_QUEUE_NAME, + NOTIFICATIONS_STORAGE_CONNECTION_STRING, PAGOPA_CLIENT, - PNAddressBookConfig, PN_ADDRESS_BOOK_CLIENT_SELECTOR, + PNAddressBookConfig, PUSH_NOTIFICATIONS_QUEUE_NAME, PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING, ROOT_REDIRECT_URL, @@ -72,42 +70,41 @@ import { TRIAL_SYSTEM_CLIENT, URL_TOKEN_STRATEGY, } from "./config"; -import MessagesController from "./controllers/messagesController"; -import NotificationController from "./controllers/notificationController"; -import PagoPAProxyController from "./controllers/pagoPAProxyController"; -import ProfileController from "./controllers/profileController"; -import ServicesController from "./controllers/servicesController"; -import SessionController from "./controllers/sessionController"; -import UserMetadataController from "./controllers/userMetadataController"; - -import { log } from "./utils/logger"; -import checkIP from "./utils/middleware/checkIP"; - -import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; -import { LollipopApiClient } from "./clients/lollipop"; +import { getUserIdentity } from "./controllers/authenticationController"; import BonusController from "./controllers/bonusController"; import CgnController from "./controllers/cgnController"; import CgnOperatorSearchController from "./controllers/cgnOperatorSearchController"; import EUCovidCertController from "./controllers/eucovidcertController"; +import IoFimsController from "./controllers/fimsController"; import { firstLollipopSign } from "./controllers/firstLollipopConsumerController"; import IoSignController from "./controllers/ioSignController"; +import IoWalletController from "./controllers/ioWalletController"; +import MessagesController from "./controllers/messagesController"; +import NotificationController from "./controllers/notificationController"; +import PagoPAProxyController from "./controllers/pagoPAProxyController"; import { getPNActivationController, upsertPNActivationController, } from "./controllers/pnController"; +import ProfileController from "./controllers/profileController"; import ServicesAppBackendController from "./controllers/serviceAppBackendController"; +import ServicesController from "./controllers/servicesController"; +import SessionController from "./controllers/sessionController"; import SessionLockController from "./controllers/sessionLockController"; import { getUserForMyPortal } from "./controllers/ssoController"; +import TrialController from "./controllers/trialController"; import UserDataProcessingController from "./controllers/userDataProcessingController"; +import UserMetadataController from "./controllers/userMetadataController"; import { ISessionStorage } from "./services/ISessionStorage"; import AuthenticationLockService from "./services/authenticationLockService"; import BonusService from "./services/bonusService"; import CgnOperatorSearchService from "./services/cgnOperatorSearchService"; import CgnService from "./services/cgnService"; import EUCovidCertService from "./services/eucovidcertService"; +import IoFimsService from "./services/fimsService"; import FunctionsAppService from "./services/functionAppService"; import IoSignService from "./services/ioSignService"; -import IoFimsService from "./services/fimsService"; +import IoWalletService from "./services/ioWalletService"; import LollipopService from "./services/lollipopService"; import NewMessagesService from "./services/newMessagesService"; import NotificationService from "./services/notificationService"; @@ -121,6 +118,7 @@ import ProfileService from "./services/profileService"; import RedisSessionStorage from "./services/redisSessionStorage"; import RedisUserMetadataStorage from "./services/redisUserMetadataStorage"; import ServicesAppBackendService from "./services/servicesAppBackendService"; +import TrialService from "./services/trialService"; import UserDataProcessingService from "./services/userDataProcessingService"; import bearerMyPortalTokenStrategy from "./strategies/bearerMyPortalTokenStrategy"; import bearerSessionTokenStrategy from "./strategies/bearerSessionTokenStrategy"; @@ -128,6 +126,8 @@ import { User } from "./types/user"; import { attachTrackingData } from "./utils/appinsights"; import { getRequiredENVVar } from "./utils/container"; import { constantExpressHandler, toExpressHandler } from "./utils/express"; +import { log } from "./utils/logger"; +import checkIP from "./utils/middleware/checkIP"; import { expressErrorMiddleware } from "./utils/middleware/express"; import { expressLollipopMiddleware, @@ -139,11 +139,8 @@ import { } from "./utils/package"; import { RedisClientMode, RedisClientSelector } from "./utils/redis"; import { ResponseErrorDismissed } from "./utils/responses"; -import TrialService from "./services/trialService"; -import TrialController from "./controllers/trialController"; -import IoWalletController from "./controllers/ioWalletController"; -import IoWalletService from "./services/ioWalletService"; -import IoFimsController from "./controllers/fimsController"; + +import expressEnforcesSsl = require("express-enforces-ssl"); const defaultModule = { // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -151,53 +148,53 @@ const defaultModule = { }; export interface IAppFactoryParameters { - readonly env: NodeEnvironment; - readonly appInsightsClient?: appInsights.TelemetryClient; - readonly allowNotifyIPSourceRange: ReadonlyArray; - readonly allowMyPortalIPSourceRange: ReadonlyArray; - readonly allowSessionHandleIPSourceRange: ReadonlyArray; - readonly authenticationBasePath: string; readonly APIBasePath: string; readonly BonusAPIBasePath: string; - readonly MyPortalBasePath: string; readonly CGNAPIBasePath: string; readonly CGNOperatorSearchAPIBasePath: string; - readonly IoSignAPIBasePath: string; + readonly EUCovidCertBasePath: string; readonly IoFimsAPIBasePath: string; + readonly IoSignAPIBasePath: string; readonly IoWalletAPIBasePath: string; - readonly EUCovidCertBasePath: string; + readonly MyPortalBasePath: string; readonly ServicesAppBackendBasePath: string; readonly TrialSystemBasePath: string; + readonly allowMyPortalIPSourceRange: readonly CIDR[]; + readonly allowNotifyIPSourceRange: readonly CIDR[]; + readonly allowSessionHandleIPSourceRange: readonly CIDR[]; + readonly appInsightsClient?: appInsights.TelemetryClient; + readonly authenticationBasePath: string; + readonly env: NodeEnvironment; } // eslint-disable-next-line max-lines-per-function, sonarjs/cognitive-complexity export async function newApp({ - env, - allowNotifyIPSourceRange, - allowMyPortalIPSourceRange, - allowSessionHandleIPSourceRange, - appInsightsClient, - authenticationBasePath, APIBasePath, BonusAPIBasePath, - MyPortalBasePath, CGNAPIBasePath, - IoSignAPIBasePath, - IoFimsAPIBasePath, - IoWalletAPIBasePath, CGNOperatorSearchAPIBasePath, EUCovidCertBasePath, + IoFimsAPIBasePath, + IoSignAPIBasePath, + IoWalletAPIBasePath, + MyPortalBasePath, ServicesAppBackendBasePath, TrialSystemBasePath, + allowMyPortalIPSourceRange, + allowNotifyIPSourceRange, + allowSessionHandleIPSourceRange, + appInsightsClient, + authenticationBasePath, + env, }: IAppFactoryParameters): Promise { const isDevEnvironment = ENV === NodeEnvironmentEnum.DEVELOPMENT; const REDIS_CLIENT_SELECTOR = await RedisClientSelector( !isDevEnvironment, - appInsightsClient + appInsightsClient, )( getRequiredENVVar("REDIS_URL"), process.env.REDIS_PASSWORD, - process.env.REDIS_PORT + process.env.REDIS_PORT, ); // Create the Session Storage service @@ -206,7 +203,7 @@ export async function newApp({ // Add the strategy to authenticate proxy clients. passport.use( "bearer.session", - bearerSessionTokenStrategy(SESSION_STORAGE, attachTrackingData) + bearerSessionTokenStrategy(SESSION_STORAGE, attachTrackingData), ); // Add the strategy to authenticate MyPortal clients. @@ -261,8 +258,8 @@ export async function newApp({ req.user, User.decode, E.map((user) => String(user.fiscal_code).slice(0, 6)), - E.getOrElse(() => "") - ) + E.getOrElse(() => ""), + ), ); const obfuscateToken = (originalUrl: string) => @@ -270,7 +267,7 @@ export async function newApp({ // Obfuscate token in url on morgan logs morgan.token("obfuscated_url", (req: express.Request, _) => - obfuscateToken(req.originalUrl) + obfuscateToken(req.originalUrl), ); const loggerFormat = @@ -286,10 +283,9 @@ export async function newApp({ app.use( bodyParser.json({ verify: (_req, res: express.Response, buf, _encoding: BufferEncoding) => { - // eslint-disable-next-line functional/immutable-data res.locals.body = buf; }, - }) + }), ); // Parse an urlencoded body. @@ -316,11 +312,11 @@ export async function newApp({ // Create the profile service const tableClient = TableClient.fromConnectionString( LOCKED_PROFILES_STORAGE_CONNECTION_STRING, - LOCKED_PROFILES_TABLE_NAME + LOCKED_PROFILES_TABLE_NAME, ); const PROFILE_SERVICE = new ProfileService(API_CLIENT); const AUTHENTICATION_LOCK_SERVICE = new AuthenticationLockService( - tableClient + tableClient, ); // Create the bonus service @@ -337,28 +333,28 @@ export async function newApp({ // Create the cgn operator search service const CGN_OPERATOR_SEARCH_SERVICE = new CgnOperatorSearchService( - CGN_OPERATOR_SEARCH_API_CLIENT + CGN_OPERATOR_SEARCH_API_CLIENT, ); // Create the EUCovidCert service const EUCOVIDCERT_SERVICE = new EUCovidCertService( - EUCOVIDCERT_API_CLIENT + EUCOVIDCERT_API_CLIENT, ); // Create the user data processing service const USER_DATA_PROCESSING_SERVICE = new UserDataProcessingService( - API_CLIENT + API_CLIENT, ); // Create the the io-services-app-backend service const SERVICES_APP_BACKEND_SERVICE = new ServicesAppBackendService( - SERVICES_APP_BACKEND_CLIENT + SERVICES_APP_BACKEND_CLIENT, ); // Create the io wallet const IO_WALLET_SERVICE = new IoWalletService( IO_WALLET_API_CLIENT, - TRIAL_SYSTEM_CLIENT + TRIAL_SYSTEM_CLIENT, ); // Create the Notification Service @@ -367,14 +363,14 @@ export async function newApp({ () => new NotificationService( NOTIFICATIONS_STORAGE_CONNECTION_STRING, - NOTIFICATIONS_QUEUE_NAME + NOTIFICATIONS_QUEUE_NAME, ), (err) => - new Error(`Error initializing Notification Service: [${err}]`) + new Error(`Error initializing Notification Service: [${err}]`), ), E.getOrElseW((err) => { throw err; - }) + }), ); // Create the Notification Service @@ -383,16 +379,16 @@ export async function newApp({ () => new NotificationService( PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING, - PUSH_NOTIFICATIONS_QUEUE_NAME + PUSH_NOTIFICATIONS_QUEUE_NAME, ), (err) => new Error( - `Error initializing Push Notification Service: [${err}]` - ) + `Error initializing Push Notification Service: [${err}]`, + ), ), E.getOrElseW((err) => { throw err; - }) + }), ); const notificationServiceFactory = getNotificationServiceFactory( @@ -400,7 +396,7 @@ export async function newApp({ PUSH_NOTIFICATION_SERVICE, FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST, FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, - FF_ROUTING_PUSH_NOTIF + FF_ROUTING_PUSH_NOTIF, ); const LOLLIPOP_SERVICE = pipe( @@ -408,13 +404,13 @@ export async function newApp({ () => new LollipopService( LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING, - LOLLIPOP_REVOKE_QUEUE_NAME + LOLLIPOP_REVOKE_QUEUE_NAME, ), - (err) => new Error(`Error initializing LollipopService: [${err}]`) + (err) => new Error(`Error initializing LollipopService: [${err}]`), ), E.getOrElseW((err) => { throw err; - }) + }), ); const TRIAL_SERVICE = new TrialService(TRIAL_SYSTEM_CLIENT); @@ -429,27 +425,27 @@ export async function newApp({ LOLLIPOP_API_CLIENT, SESSION_STORAGE, FIRST_LOLLIPOP_CONSUMER_CLIENT, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerAuthenticationRoutes( app, authenticationBasePath, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); // Create the function app service. const FN_APP_SERVICE = new FunctionsAppService(API_CLIENT); // Create the new messages service. const APP_MESSAGES_SERVICE = new NewMessagesService( - APP_MESSAGES_API_CLIENT + APP_MESSAGES_API_CLIENT, ); const PAGOPA_PROXY_SERVICE = new PagoPAProxyService(PAGOPA_CLIENT); // Register the user metadata storage service. const USER_METADATA_STORAGE = new RedisUserMetadataStorage( - REDIS_CLIENT_SELECTOR.selectOne(RedisClientMode.FAST) + REDIS_CLIENT_SELECTOR.selectOne(RedisClientMode.FAST), ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerAPIRoutes( @@ -466,7 +462,7 @@ export async function newApp({ USER_METADATA_STORAGE, USER_DATA_PROCESSING_SERVICE, authMiddlewares.bearerSession, - LOLLIPOP_API_CLIENT + LOLLIPOP_API_CLIENT, ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerSessionAPIRoutes( @@ -478,7 +474,7 @@ export async function newApp({ USER_METADATA_STORAGE, LOLLIPOP_SERVICE, AUTHENTICATION_LOCK_SERVICE, - notificationServiceFactory + notificationServiceFactory, ); if (FF_BONUS_ENABLED) { // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -486,7 +482,7 @@ export async function newApp({ app, BonusAPIBasePath, BONUS_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); } if (FF_CGN_ENABLED) { @@ -495,7 +491,7 @@ export async function newApp({ app, CGNAPIBasePath, CGN_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -504,7 +500,7 @@ export async function newApp({ CGNOperatorSearchAPIBasePath, CGN_SERVICE, CGN_OPERATOR_SEARCH_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); } @@ -517,7 +513,7 @@ export async function newApp({ PROFILE_SERVICE, authMiddlewares.bearerSession, LOLLIPOP_API_CLIENT, - SESSION_STORAGE + SESSION_STORAGE, ); } @@ -528,7 +524,7 @@ export async function newApp({ IoFimsAPIBasePath, IO_FIMS_SERVICE, PROFILE_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); } @@ -538,7 +534,7 @@ export async function newApp({ app, EUCovidCertBasePath, EUCOVIDCERT_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); } @@ -547,14 +543,14 @@ export async function newApp({ app, MyPortalBasePath, allowMyPortalIPSourceRange, - authMiddlewares.bearerMyPortal + authMiddlewares.bearerMyPortal, ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerServicesAppBackendRoutes( app, ServicesAppBackendBasePath, SERVICES_APP_BACKEND_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); if ( @@ -567,7 +563,7 @@ export async function newApp({ app, PNAddressBookConfig.PN_ACTIVATION_BASE_PATH, pnService, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); } @@ -577,7 +573,7 @@ export async function newApp({ app, TrialSystemBasePath, TRIAL_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); } @@ -587,19 +583,19 @@ export async function newApp({ app, IoWalletAPIBasePath, IO_WALLET_SERVICE, - authMiddlewares.bearerSession + authMiddlewares.bearerSession, ); } return { app }; }, - (err) => new Error(`Error on app routes setup: [${err}]`) + (err) => new Error(`Error on app routes setup: [${err}]`), ), TE.map((_) => { _.app.on("server:stop", () => { // Graceful redis connection shutdown. for (const client of REDIS_CLIENT_SELECTOR.select( - RedisClientMode.ALL + RedisClientMode.ALL, )) { log.info(`Graceful closing redis connection`); pipe( @@ -609,10 +605,10 @@ export async function newApp({ log.error( `An Error occurred closing the redis connection: [${ E.toError(err).message - }]` - ) - ) - ) + }]`, + ), + ), + ), ); } }); @@ -628,22 +624,22 @@ export async function newApp({ TE.getOrElse((err) => { app.emit("server:stop"); throw err; - }) + }), )(); } function registerMyPortalRoutes( app: Express, basePath: string, - allowMyPortalIPSourceRange: ReadonlyArray, + allowMyPortalIPSourceRange: readonly CIDR[], // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerMyPortalTokenAuth: any + bearerMyPortalTokenAuth: any, ): void { app.get( `${basePath}/user`, checkIP(allowMyPortalIPSourceRange), bearerMyPortalTokenAuth, - toExpressHandler(getUserForMyPortal) + toExpressHandler(getUserForMyPortal), ); } @@ -652,7 +648,7 @@ function registerServicesAppBackendRoutes( basePath: string, servicesAppBackendService: ServicesAppBackendService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const servicesAppBackendController: ServicesAppBackendController = new ServicesAppBackendController(servicesAppBackendService); @@ -662,8 +658,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.findInstitutions, - servicesAppBackendController - ) + servicesAppBackendController, + ), ); app.get( @@ -671,8 +667,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.getFeaturedInstitutions, - servicesAppBackendController - ) + servicesAppBackendController, + ), ); app.get( @@ -680,8 +676,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.findInstutionServices, - servicesAppBackendController - ) + servicesAppBackendController, + ), ); app.get( @@ -689,8 +685,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.getFeaturedServices, - servicesAppBackendController - ) + servicesAppBackendController, + ), ); app.get( @@ -698,8 +694,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.getServiceById, - servicesAppBackendController - ) + servicesAppBackendController, + ), ); } @@ -708,7 +704,7 @@ function registerEUCovidCertAPIRoutes( basePath: string, eucovidcertService: EUCovidCertService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const eucovidCertController: EUCovidCertController = new EUCovidCertController(eucovidcertService); @@ -718,8 +714,8 @@ function registerEUCovidCertAPIRoutes( bearerSessionTokenAuth, toExpressHandler( eucovidCertController.getEUCovidCertificate, - eucovidCertController - ) + eucovidCertController, + ), ); } @@ -727,7 +723,7 @@ function registerEUCovidCertAPIRoutes( function registerAPIRoutes( app: Express, basePath: string, - _allowNotifyIPSourceRange: ReadonlyArray, + _allowNotifyIPSourceRange: readonly CIDR[], // eslint-disable-next-line @typescript-eslint/no-explicit-any urlTokenAuth: any, profileService: ProfileService, @@ -740,21 +736,21 @@ function registerAPIRoutes( userDataProcessingService: UserDataProcessingService, // eslint-disable-next-line @typescript-eslint/no-explicit-any bearerSessionTokenAuth: any, - lollipopClient: ReturnType + lollipopClient: ReturnType, ): void { const profileController: ProfileController = new ProfileController( profileService, - sessionStorage + sessionStorage, ); const messagesController: MessagesController = new MessagesController( appMessagesService, lollipopClient, - sessionStorage + sessionStorage, ); const servicesController: ServicesController = new ServicesController( - fnAppService + fnAppService, ); const notificationController: NotificationController = @@ -764,7 +760,7 @@ function registerAPIRoutes( }); const sessionController: SessionController = new SessionController( - sessionStorage + sessionStorage, ); const pagoPAProxyController: PagoPAProxyController = @@ -779,19 +775,19 @@ function registerAPIRoutes( app.get( `${basePath}/profile`, bearerSessionTokenAuth, - toExpressHandler(profileController.getProfile, profileController) + toExpressHandler(profileController.getProfile, profileController), ); app.get( `${basePath}/api-profile`, bearerSessionTokenAuth, - toExpressHandler(profileController.getApiProfile, profileController) + toExpressHandler(profileController.getApiProfile, profileController), ); app.post( `${basePath}/profile`, bearerSessionTokenAuth, - toExpressHandler(profileController.updateProfile, profileController) + toExpressHandler(profileController.updateProfile, profileController), ); app.post( @@ -799,14 +795,17 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( profileController.startEmailValidationProcess, - profileController - ) + profileController, + ), ); app.get( `${basePath}/user-metadata`, bearerSessionTokenAuth, - toExpressHandler(userMetadataController.getMetadata, userMetadataController) + toExpressHandler( + userMetadataController.getMetadata, + userMetadataController, + ), ); app.post( @@ -814,8 +813,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userMetadataController.upsertMetadata, - userMetadataController - ) + userMetadataController, + ), ); app.post( @@ -823,8 +822,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userDataProcessingController.upsertUserDataProcessing, - userDataProcessingController - ) + userDataProcessingController, + ), ); app.get( @@ -832,8 +831,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userDataProcessingController.getUserDataProcessing, - userDataProcessingController - ) + userDataProcessingController, + ), ); app.delete( @@ -841,26 +840,29 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userDataProcessingController.abortUserDataProcessing, - userDataProcessingController - ) + userDataProcessingController, + ), ); app.get( `${basePath}/messages`, bearerSessionTokenAuth, - toExpressHandler(messagesController.getMessagesByUser, messagesController) + toExpressHandler(messagesController.getMessagesByUser, messagesController), ); app.get( `${basePath}/messages/:id`, bearerSessionTokenAuth, - toExpressHandler(messagesController.getMessage, messagesController) + toExpressHandler(messagesController.getMessage, messagesController), ); app.put( `${basePath}/messages/:id/message-status`, bearerSessionTokenAuth, - toExpressHandler(messagesController.upsertMessageStatus, messagesController) + toExpressHandler( + messagesController.upsertMessageStatus, + messagesController, + ), ); app.get( @@ -868,8 +870,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( messagesController.getThirdPartyMessagePrecondition, - messagesController - ) + messagesController, + ), ); app.get( @@ -877,8 +879,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( messagesController.getThirdPartyMessage, - messagesController - ) + messagesController, + ), ); app.get( @@ -886,14 +888,14 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( messagesController.getThirdPartyMessageAttachment, - messagesController - ) + messagesController, + ), ); app.get( `${basePath}/services/:id`, bearerSessionTokenAuth, - toExpressHandler(servicesController.getService, servicesController) + toExpressHandler(servicesController.getService, servicesController), ); app.get( @@ -901,8 +903,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( servicesController.getServicePreferences, - servicesController - ) + servicesController, + ), ); app.post( @@ -910,8 +912,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( servicesController.upsertServicePreferences, - servicesController - ) + servicesController, + ), ); app.get( @@ -919,8 +921,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( (_) => Promise.resolve(ResponseSuccessJson({ items: [] })), - servicesController - ) + servicesController, + ), ); app.put( @@ -928,22 +930,22 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( notificationController.createOrUpdateInstallation, - notificationController - ) + notificationController, + ), ); if (FF_ENABLE_NOTIFY_ENDPOINT) { app.post( `${basePath}/notify`, urlTokenAuth, - toExpressHandler(notificationController.notify, notificationController) + toExpressHandler(notificationController.notify, notificationController), ); } app.get( `${basePath}/sessions`, bearerSessionTokenAuth, - toExpressHandler(sessionController.listSessions, sessionController) + toExpressHandler(sessionController.listSessions, sessionController), ); app.get( @@ -951,8 +953,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( pagoPAProxyController.getPaymentInfo, - pagoPAProxyController - ) + pagoPAProxyController, + ), ); app.post( @@ -960,8 +962,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( pagoPAProxyController.activatePayment, - pagoPAProxyController - ) + pagoPAProxyController, + ), ); app.get( @@ -969,8 +971,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( pagoPAProxyController.getActivationStatus, - pagoPAProxyController - ) + pagoPAProxyController, + ), ); } @@ -978,14 +980,14 @@ function registerAPIRoutes( function registerSessionAPIRoutes( app: Express, basePath: string, - _allowSessionHandleIPSourceRange: ReadonlyArray, + _allowSessionHandleIPSourceRange: readonly CIDR[], // eslint-disable-next-line @typescript-eslint/no-explicit-any urlTokenAuth: any, sessionStorage: RedisSessionStorage, userMetadataStorage: RedisUserMetadataStorage, lollipopService: LollipopService, authenticationLockService: AuthenticationLockService, - notificationServiceFactory: NotificationServiceFactory + notificationServiceFactory: NotificationServiceFactory, ): void { if (FF_ENABLE_SESSION_ENDPOINTS) { const sessionLockController: SessionLockController = @@ -994,7 +996,7 @@ function registerSessionAPIRoutes( userMetadataStorage, lollipopService, authenticationLockService, - notificationServiceFactory + notificationServiceFactory, ); app.get( @@ -1002,8 +1004,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.getUserSession, - sessionLockController - ) + sessionLockController, + ), ); app.post( @@ -1011,8 +1013,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.lockUserSession, - sessionLockController - ) + sessionLockController, + ), ); app.post( @@ -1020,8 +1022,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.deleteUserSession, - sessionLockController - ) + sessionLockController, + ), ); app.delete( @@ -1029,8 +1031,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.unlockUserSession, - sessionLockController - ) + sessionLockController, + ), ); app.post( @@ -1038,8 +1040,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.lockUserAuthentication, - sessionLockController - ) + sessionLockController, + ), ); app.post( @@ -1047,8 +1049,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.unlockUserAuthentication, - sessionLockController - ) + sessionLockController, + ), ); app.get( @@ -1056,8 +1058,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.getUserSessionState, - sessionLockController - ) + sessionLockController, + ), ); } } @@ -1067,59 +1069,59 @@ function registerCgnAPIRoutes( basePath: string, cgnService: CgnService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const cgnController: CgnController = new CgnController( cgnService, - TEST_CGN_FISCAL_CODES + TEST_CGN_FISCAL_CODES, ); app.get( `${basePath}/status`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getCgnStatus, cgnController) + toExpressHandler(cgnController.getCgnStatus, cgnController), ); app.get( `${basePath}/eyca/status`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getEycaStatus, cgnController) + toExpressHandler(cgnController.getEycaStatus, cgnController), ); app.post( `${basePath}/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.startCgnActivation, cgnController) + toExpressHandler(cgnController.startCgnActivation, cgnController), ); app.get( `${basePath}/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getCgnActivation, cgnController) + toExpressHandler(cgnController.getCgnActivation, cgnController), ); app.post( `${basePath}/eyca/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.startEycaActivation, cgnController) + toExpressHandler(cgnController.startEycaActivation, cgnController), ); app.get( `${basePath}/eyca/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getEycaActivation, cgnController) + toExpressHandler(cgnController.getEycaActivation, cgnController), ); app.post( `${basePath}/delete`, bearerSessionTokenAuth, - toExpressHandler(cgnController.startCgnUnsubscription, cgnController) + toExpressHandler(cgnController.startCgnUnsubscription, cgnController), ); app.post( `${basePath}/otp`, bearerSessionTokenAuth, - toExpressHandler(cgnController.generateOtp, cgnController) + toExpressHandler(cgnController.generateOtp, cgnController), ); } @@ -1132,11 +1134,11 @@ function registerIoSignAPIRoutes( // eslint-disable-next-line @typescript-eslint/no-explicit-any bearerSessionTokenAuth: any, lollipopClient: ReturnType, - sessionStorage: ISessionStorage + sessionStorage: ISessionStorage, ): void { const ioSignController: IoSignController = new IoSignController( ioSignService, - profileService + profileService, ); app.get( @@ -1145,39 +1147,39 @@ function registerIoSignAPIRoutes( constantExpressHandler( ResponseSuccessJson({ serviceId: IO_SIGN_SERVICE_ID as NonEmptyString, - }) - ) + }), + ), ); app.post( `${basePath}/qtsp/clauses/filled_document`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.createFilledDocument, ioSignController) + toExpressHandler(ioSignController.createFilledDocument, ioSignController), ); app.get( `${basePath}/qtsp/clauses`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.getQtspClausesMetadata, ioSignController) + toExpressHandler(ioSignController.getQtspClausesMetadata, ioSignController), ); app.post( `${basePath}/signatures`, bearerSessionTokenAuth, expressLollipopMiddlewareLegacy(lollipopClient, sessionStorage), - toExpressHandler(ioSignController.createSignature, ioSignController) + toExpressHandler(ioSignController.createSignature, ioSignController), ); app.get( `${basePath}/signature-requests`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.getSignatureRequests, ioSignController) + toExpressHandler(ioSignController.getSignatureRequests, ioSignController), ); app.get( `${basePath}/signature-requests/:id`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.getSignatureRequest, ioSignController) + toExpressHandler(ioSignController.getSignatureRequest, ioSignController), ); } @@ -1187,23 +1189,23 @@ function registerIoFimsAPIRoutes( ioFimsService: IoFimsService, profileService: ProfileService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const ioFimsController: IoFimsController = new IoFimsController( ioFimsService, - profileService + profileService, ); app.get( `${basePath}/accesses`, bearerSessionTokenAuth, - toExpressHandler(ioFimsController.getAccessHistory, ioFimsController) + toExpressHandler(ioFimsController.getAccessHistory, ioFimsController), ); app.post( `${basePath}/export-requests`, bearerSessionTokenAuth, - toExpressHandler(ioFimsController.requestExport, ioFimsController) + toExpressHandler(ioFimsController.requestExport, ioFimsController), ); } @@ -1213,7 +1215,7 @@ function registerCgnOperatorSearchAPIRoutes( cgnService: CgnService, cgnOperatorSearchService: CgnOperatorSearchService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const cgnOperatorController: CgnOperatorSearchController = new CgnOperatorSearchController(cgnService, cgnOperatorSearchService); @@ -1223,26 +1225,26 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getPublishedProductCategories, - cgnOperatorController - ) + cgnOperatorController, + ), ); app.get( `${basePath}/merchants/:merchantId`, bearerSessionTokenAuth, - toExpressHandler(cgnOperatorController.getMerchant, cgnOperatorController) + toExpressHandler(cgnOperatorController.getMerchant, cgnOperatorController), ); app.get( `${basePath}/count`, bearerSessionTokenAuth, - toExpressHandler(cgnOperatorController.count, cgnOperatorController) + toExpressHandler(cgnOperatorController.count, cgnOperatorController), ); app.post( `${basePath}/search`, bearerSessionTokenAuth, - toExpressHandler(cgnOperatorController.search, cgnOperatorController) + toExpressHandler(cgnOperatorController.search, cgnOperatorController), ); app.post( @@ -1250,8 +1252,8 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getOnlineMerchants, - cgnOperatorController - ) + cgnOperatorController, + ), ); app.post( @@ -1259,8 +1261,8 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getOfflineMerchants, - cgnOperatorController - ) + cgnOperatorController, + ), ); app.get( @@ -1268,8 +1270,8 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getDiscountBucketCode, - cgnOperatorController - ) + cgnOperatorController, + ), ); } @@ -1278,20 +1280,20 @@ function registerBonusAPIRoutes( basePath: string, bonusService: BonusService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const bonusController: BonusController = new BonusController(bonusService); app.post( `${basePath}/bonus/vacanze/eligibility`, bearerSessionTokenAuth, - constantExpressHandler(ResponseErrorDismissed) + constantExpressHandler(ResponseErrorDismissed), ); app.get( `${basePath}/bonus/vacanze/eligibility`, bearerSessionTokenAuth, - toExpressHandler(bonusController.getBonusEligibilityCheck, bonusController) + toExpressHandler(bonusController.getBonusEligibilityCheck, bonusController), ); app.get( @@ -1299,20 +1301,20 @@ function registerBonusAPIRoutes( bearerSessionTokenAuth, toExpressHandler( bonusController.getLatestBonusActivationById, - bonusController - ) + bonusController, + ), ); app.get( `${basePath}/bonus/vacanze/activations`, bearerSessionTokenAuth, - toExpressHandler(bonusController.getAllBonusActivations, bonusController) + toExpressHandler(bonusController.getAllBonusActivations, bonusController), ); app.post( `${basePath}/bonus/vacanze/activations`, bearerSessionTokenAuth, - constantExpressHandler(ResponseErrorDismissed) + constantExpressHandler(ResponseErrorDismissed), ); } @@ -1321,12 +1323,12 @@ function registerAuthenticationRoutes( app: Express, authBasePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { app.get( `${authBasePath}/user-identity`, bearerSessionTokenAuth, - toExpressHandler(getUserIdentity) + toExpressHandler(getUserIdentity), ); } @@ -1335,18 +1337,20 @@ function registerPNRoutes( pnBasePath: string, pnService: ReturnType, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ) { app.get( `${pnBasePath}/activation`, bearerSessionTokenAuth, - toExpressHandler(getPNActivationController(pnService.getPnActivation)) + toExpressHandler(getPNActivationController(pnService.getPnActivation)), ); app.post( `${pnBasePath}/activation`, bearerSessionTokenAuth, - toExpressHandler(upsertPNActivationController(pnService.upsertPnActivation)) + toExpressHandler( + upsertPNActivationController(pnService.upsertPnActivation), + ), ); } @@ -1356,11 +1360,11 @@ function registerPublicRoutes(app: Express): void { // The minimum app version that support this API const minAppVersion = getObjectFromPackageJson( "min_app_version", - VersionPerPlatform + VersionPerPlatform, ); const minAppVersionPagoPa = getObjectFromPackageJson( "min_app_version_pagopa", - VersionPerPlatform + VersionPerPlatform, ); app.get("/", (_, res) => { @@ -1374,14 +1378,14 @@ function registerPublicRoutes(app: Express): void { O.getOrElse(() => ({ android: "UNKNOWN", ios: "UNKNOWN", - })) + })), ), min_app_version_pagopa: pipe( minAppVersionPagoPa, O.getOrElse(() => ({ android: "UNKNOWN", ios: "UNKNOWN", - })) + })), ), version, }; @@ -1391,7 +1395,9 @@ function registerPublicRoutes(app: Express): void { // Liveness probe for Kubernetes. // @see // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-a-liveness-http-request - app.get("/ping", (_, res) => { res.status(200).send("ok") }); + app.get("/ping", (_, res) => { + res.status(200).send("ok"); + }); } // eslint-disable-next-line max-params @@ -1402,13 +1408,13 @@ function registerFirstLollipopConsumer( sessionStorage: ISessionStorage, firstLollipopConsumerClient: ReturnType, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { app.post( `${basePath}/sign`, bearerSessionTokenAuth, expressLollipopMiddleware(lollipopClient, sessionStorage), - toExpressHandler(firstLollipopSign(firstLollipopConsumerClient)) + toExpressHandler(firstLollipopSign(firstLollipopConsumerClient)), ); } @@ -1417,20 +1423,20 @@ function registerTrialSystemAPIRoutes( basePath: string, trialService: TrialService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const trialController: TrialController = new TrialController(trialService); app.post( `${basePath}/trials/:trialId/subscriptions`, bearerSessionTokenAuth, - toExpressHandler(trialController.createTrialSubscription, trialController) + toExpressHandler(trialController.createTrialSubscription, trialController), ); app.get( `${basePath}/trials/:trialId/subscriptions`, bearerSessionTokenAuth, - toExpressHandler(trialController.getTrialSubscription, trialController) + toExpressHandler(trialController.getTrialSubscription, trialController), ); } @@ -1439,14 +1445,14 @@ function registerIoWalletAPIRoutes( basePath: string, ioWalletService: IoWalletService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any + bearerSessionTokenAuth: any, ): void { const ioWalletController = new IoWalletController(ioWalletService); app.get( `${basePath}/nonce`, bearerSessionTokenAuth, - toExpressHandler(ioWalletController.getNonce, ioWalletController) + toExpressHandler(ioWalletController.getNonce, ioWalletController), ); app.post( @@ -1454,8 +1460,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.createWalletInstance, - ioWalletController - ) + ioWalletController, + ), ); app.post( @@ -1463,8 +1469,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.createWalletAttestation, - ioWalletController - ) + ioWalletController, + ), ); // TODO SIW-1843 @@ -1473,8 +1479,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.setCurrentWalletInstanceStatus, - ioWalletController - ) + ioWalletController, + ), ); app.get( @@ -1482,8 +1488,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.getWalletInstanceStatus, - ioWalletController - ) + ioWalletController, + ), ); app.put( @@ -1491,8 +1497,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.setWalletInstanceStatus, - ioWalletController - ) + ioWalletController, + ), ); } diff --git a/src/clients/api.ts b/src/clients/api.ts index bbf7c2fb4..ea4eec560 100644 --- a/src/clients/api.ts +++ b/src/clients/api.ts @@ -1,10 +1,10 @@ -import nodeFetch from "node-fetch"; import { Client, createClient } from "@pagopa/io-functions-app-sdk/client"; +import nodeFetch from "node-fetch"; export function APIClient( baseUrl: string, token: string, - fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch // TODO: customize fetch with timeout + fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch, // TODO: customize fetch with timeout ): Client<"SubscriptionKey"> { return createClient<"SubscriptionKey">({ basePath: "", diff --git a/src/clients/app-messages.client.ts b/src/clients/app-messages.client.ts index cbd4f21c4..767b89b01 100644 --- a/src/clients/app-messages.client.ts +++ b/src/clients/app-messages.client.ts @@ -1,11 +1,12 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-messages-api/client"; export function AppMessagesAPIClient( token: string, baseUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"SubscriptionKey"> { return createClient<"SubscriptionKey">({ basePath: "", diff --git a/src/clients/bonus.ts b/src/clients/bonus.ts index 95d870c1a..676e86bc6 100644 --- a/src/clients/bonus.ts +++ b/src/clients/bonus.ts @@ -1,10 +1,11 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-bonus-api/client"; export function BonusAPIClient( token: string, baseUrl: string, - fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch + fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch, ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath: "", diff --git a/src/clients/cgn-operator-search.ts b/src/clients/cgn-operator-search.ts index 0da466687..28bc3d666 100644 --- a/src/clients/cgn-operator-search.ts +++ b/src/clients/cgn-operator-search.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient, @@ -9,7 +10,7 @@ export function CgnOperatorSearchAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath, diff --git a/src/clients/cgn.ts b/src/clients/cgn.ts index 598a00295..022c02894 100644 --- a/src/clients/cgn.ts +++ b/src/clients/cgn.ts @@ -1,12 +1,12 @@ -import nodeFetch from "node-fetch"; import { Client, createClient } from "@pagopa/io-functions-cgn-sdk/client"; +import nodeFetch from "node-fetch"; export function CgnAPIClient( token: string, baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath, diff --git a/src/clients/eucovidcert.client.ts b/src/clients/eucovidcert.client.ts index 2ce023073..981332090 100644 --- a/src/clients/eucovidcert.client.ts +++ b/src/clients/eucovidcert.client.ts @@ -1,14 +1,14 @@ -import nodeFetch from "node-fetch"; import { Client, createClient, } from "@pagopa/io-functions-eucovidcerts-sdk/client"; +import nodeFetch from "node-fetch"; export function EUCovidCertAPIClient( token: string, baseUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath: "", diff --git a/src/clients/firstLollipopConsumer.ts b/src/clients/firstLollipopConsumer.ts index bcdc27ed5..d962505b6 100644 --- a/src/clients/firstLollipopConsumer.ts +++ b/src/clients/firstLollipopConsumer.ts @@ -1,7 +1,8 @@ import * as nodeFetch from "node-fetch"; + import { - createClient, Client, + createClient, } from "../../generated/lollipop-first-consumer/client"; export function FirstLollipopConsumerClient( @@ -9,7 +10,7 @@ export function FirstLollipopConsumerClient( baseUrl: string, basePath?: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"ApiKeyAuth"> { return createClient<"ApiKeyAuth">({ basePath, diff --git a/src/clients/io-fims.ts b/src/clients/io-fims.ts index 023c62831..db0ef4023 100644 --- a/src/clients/io-fims.ts +++ b/src/clients/io-fims.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-fims-api/client"; export function IoFimsAPIClient( @@ -6,7 +7,7 @@ export function IoFimsAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"FunctionsKey"> { return createClient<"FunctionsKey">({ basePath, diff --git a/src/clients/io-sign.ts b/src/clients/io-sign.ts index b76bf5e84..746e685ae 100644 --- a/src/clients/io-sign.ts +++ b/src/clients/io-sign.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-sign-api/client"; export function IoSignAPIClient( @@ -6,7 +7,7 @@ export function IoSignAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"FunctionsKey"> { return createClient<"FunctionsKey">({ basePath, diff --git a/src/clients/io-wallet.ts b/src/clients/io-wallet.ts index 99e4885b5..dc5b8cca6 100644 --- a/src/clients/io-wallet.ts +++ b/src/clients/io-wallet.ts @@ -2,14 +2,14 @@ import { Client, createClient } from "../../generated/io-wallet-api/client"; type Fetch = ( input: RequestInfo | URL, - init?: RequestInit | undefined + init?: RequestInit | undefined, ) => Promise; export function IoWalletAPIClient( token: string, basePath: string, baseUrl: string, - fetchApi: Fetch + fetchApi: Fetch, ): Client<"FunctionsKey"> { return createClient<"FunctionsKey">({ basePath, diff --git a/src/clients/lollipop.ts b/src/clients/lollipop.ts index 0a37d127e..0b148a624 100644 --- a/src/clients/lollipop.ts +++ b/src/clients/lollipop.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/lollipop-api/client"; export function LollipopApiClient( @@ -6,7 +7,7 @@ export function LollipopApiClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"ApiKeyAuth"> { return createClient<"ApiKeyAuth">({ basePath, diff --git a/src/clients/pagopa.ts b/src/clients/pagopa.ts index 8b991bc38..897bd31a1 100644 --- a/src/clients/pagopa.ts +++ b/src/clients/pagopa.ts @@ -1,10 +1,11 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/pagopa-proxy/client"; export function PagoPAClient( baseUrl: string, apiKey: string, - fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch + fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch, ): Client<"apiKeyHeader"> { return createClient<"apiKeyHeader">({ basePath: "", diff --git a/src/clients/pn-clients.ts b/src/clients/pn-clients.ts index a97faddb2..3eb9e5bd7 100644 --- a/src/clients/pn-clients.ts +++ b/src/clients/pn-clients.ts @@ -1,6 +1,6 @@ -import nodeFetch from "node-fetch"; import { ValidUrl } from "@pagopa/ts-commons/lib/url"; -import { stripTrailingSlashIfPresent } from "../utils/url"; +import nodeFetch from "node-fetch"; + import { Client, createClient, @@ -9,11 +9,12 @@ import { Client as AddressBookClient, createClient as createAddressBookClient, } from "../../generated/piattaforma-notifiche-courtesy/client"; +import { stripTrailingSlashIfPresent } from "../utils/url"; export function PnAPIClient( baseUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client { return createClient({ baseUrl, @@ -31,7 +32,7 @@ export const PnAddressBookIOClient = ( baseUrl: string, apiKey: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): AddressBookClient<"ApiKeyAuth"> => createAddressBookClient({ basePath: "", @@ -49,9 +50,9 @@ export type PnAddressBookIOClient = typeof PnAddressBookIOClient; * Available PN environments */ export enum PNEnvironment { + DEV = "DEV", PRODUCTION = "PRODUCTION", UAT = "UAT", - DEV = "DEV", } /** @@ -64,7 +65,7 @@ export const PNClientFactory = pnApiUrlUAT: ValidUrl, pnApiKeyUAT: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ) => (pnEnvironment: PNEnvironment) => { switch (pnEnvironment) { @@ -72,13 +73,13 @@ export const PNClientFactory = return PnAddressBookIOClient( stripTrailingSlashIfPresent(pnApiUrlProd), pnApiKeyProd, - fetchApi + fetchApi, ); case PNEnvironment.UAT: return PnAddressBookIOClient( stripTrailingSlashIfPresent(pnApiUrlUAT), pnApiKeyUAT, - fetchApi + fetchApi, ); default: throw new Error("Unimplemented PN Environment"); diff --git a/src/clients/services-app-backend.ts b/src/clients/services-app-backend.ts index 3c1e858a0..6bc591564 100644 --- a/src/clients/services-app-backend.ts +++ b/src/clients/services-app-backend.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient, @@ -8,7 +9,7 @@ export function ServicesAppBackendAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client { return createClient({ basePath, diff --git a/src/clients/third-party-service-client.ts b/src/clients/third-party-service-client.ts index c3257f0c5..e8598e636 100644 --- a/src/clients/third-party-service-client.ts +++ b/src/clients/third-party-service-client.ts @@ -1,25 +1,24 @@ -import { pipe } from "fp-ts/lib/function"; - import { FiscalCode } from "@pagopa/io-functions-app-sdk/FiscalCode"; -import { LollipopLocalsType } from "src/types/lollipop"; import { eventLog } from "@pagopa/winston-ts"; -import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; - +import { pipe } from "fp-ts/lib/function"; import { RCAuthenticationConfig } from "generated/io-messages-api/RCAuthenticationConfig"; import { RCConfigurationProdEnvironment } from "generated/io-messages-api/RCConfigurationProdEnvironment"; +import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; import { RCConfigurationTestEnvironment } from "generated/io-messages-api/RCConfigurationTestEnvironment"; import { Ulid } from "generated/parameters/Ulid"; -import { pnFetch } from "../adapters/pnFetch"; +import { LollipopLocalsType } from "src/types/lollipop"; + import { Client, createClient, } from "../../generated/third-party-service/client"; +import { pnFetch } from "../adapters/pnFetch"; // --- export type Fetch = ( input: RequestInfo | URL, - init?: RequestInit | undefined + init?: RequestInit | undefined, ) => Promise; export type ThirdPartyServiceClient = typeof getThirdPartyServiceClient; @@ -65,7 +64,7 @@ const withPNFetch = environment: | RCConfigurationProdEnvironment | RCConfigurationTestEnvironment, - lollipopLocals?: LollipopLocalsType + lollipopLocals?: LollipopLocalsType, ) => (fetchApi: Fetch): Fetch => pnFetch( @@ -73,7 +72,7 @@ const withPNFetch = configurationId, environment.base_url, environment.details_authentication.key, - lollipopLocals + lollipopLocals, ) as Fetch; // ------------------ @@ -89,21 +88,21 @@ export const getThirdPartyServiceClient = ( remoteContentConfiguration: RCConfigurationPublic, fetchApi: Fetch, - maybeLollipopLocals?: LollipopLocalsType + maybeLollipopLocals?: LollipopLocalsType, ) => (fiscalCode: FiscalCode): Client<"fiscal_code"> => { const environment = remoteContentConfiguration.test_environment?.test_users.includes( - fiscalCode + fiscalCode, ) ? remoteContentConfiguration.test_environment - : remoteContentConfiguration.prod_environment ?? + : (remoteContentConfiguration.prod_environment ?? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - remoteContentConfiguration.test_environment!; + remoteContentConfiguration.test_environment!); eventLog.peek.info( remoteContentConfiguration.test_environment?.test_users.includes( - fiscalCode + fiscalCode, ) ? [ "Third party client pointing to test environment", @@ -112,11 +111,11 @@ export const getThirdPartyServiceClient = : [ "Third party client pointing to prod environment", { name: "lollipop.third-party.prod" }, - ] + ], ); eventLog.peek.info( remoteContentConfiguration.test_environment?.test_users.includes( - fiscalCode + fiscalCode, ) ? [ "Fiscal code included in testUsers", @@ -125,7 +124,7 @@ export const getThirdPartyServiceClient = : [ "Fiscal code not included in testUsers", { name: "lollipop.testUsers.fiscal-code" }, - ] + ], ); const fetchApiWithRedirectAndAuthentication = pipe( @@ -135,8 +134,8 @@ export const getThirdPartyServiceClient = withPNFetch( remoteContentConfiguration.configuration_id, environment, - maybeLollipopLocals - ) + maybeLollipopLocals, + ), ); return createClient<"fiscal_code">({ diff --git a/src/clients/trial-system.client.ts b/src/clients/trial-system.client.ts index 9ac586555..07bf7f996 100644 --- a/src/clients/trial-system.client.ts +++ b/src/clients/trial-system.client.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/trial-system-api/client"; export function TrialSystemAPIClient( @@ -6,7 +7,7 @@ export function TrialSystemAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ): Client<"ApiKeyAuth"> { return createClient<"ApiKeyAuth">({ basePath, diff --git a/src/config.ts b/src/config.ts index 75dc5223a..c03dead32 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,51 +2,50 @@ * Defines services and register them to the Service Container. */ -import * as dotenv from "dotenv"; -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; -import * as t from "io-ts"; import { agent } from "@pagopa/ts-commons"; - import { getNodeEnvironmentFromProcessEnv } from "@pagopa/ts-commons/lib/environment"; -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; -import { HttpsUrlFromString, UrlFromString } from "@pagopa/ts-commons/lib/url"; - import { AbortableFetch, setFetchTimeout, toFetch, } from "@pagopa/ts-commons/lib/fetch"; +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { Millisecond } from "@pagopa/ts-commons/lib/units"; +import { HttpsUrlFromString, UrlFromString } from "@pagopa/ts-commons/lib/url"; +import * as dotenv from "dotenv"; +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; import { pipe } from "fp-ts/lib/function"; -import { CgnAPIClient } from "./clients/cgn"; -import { log } from "./utils/logger"; -import urlTokenStrategy from "./strategies/urlTokenStrategy"; -import { getRequiredENVVar } from "./utils/container"; -import PagoPAClientFactory from "./services/pagoPAClientFactory"; -import ApiClientFactory from "./services/apiClientFactory"; +import * as t from "io-ts"; + +import { AppMessagesAPIClient } from "./clients/app-messages.client"; import { BonusAPIClient } from "./clients/bonus"; -import { decodeCIDRs } from "./utils/network"; +import { CgnAPIClient } from "./clients/cgn"; import { CgnOperatorSearchAPIClient } from "./clients/cgn-operator-search"; -import { ServicesAppBackendAPIClient } from "./clients/services-app-backend"; import { EUCovidCertAPIClient } from "./clients/eucovidcert.client"; -import { ognlTypeFor } from "./utils/ognl"; -import { AppMessagesAPIClient } from "./clients/app-messages.client"; -import { PNClientFactory } from "./clients/pn-clients"; +import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; +import { IoFimsAPIClient } from "./clients/io-fims"; import { IoSignAPIClient } from "./clients/io-sign"; +import { IoWalletAPIClient } from "./clients/io-wallet"; +import { LollipopApiClient } from "./clients/lollipop"; +import { PNClientFactory } from "./clients/pn-clients"; +import { ServicesAppBackendAPIClient } from "./clients/services-app-backend"; +import { TrialSystemAPIClient } from "./clients/trial-system.client"; +import ApiClientFactory from "./services/apiClientFactory"; +import PagoPAClientFactory from "./services/pagoPAClientFactory"; +import urlTokenStrategy from "./strategies/urlTokenStrategy"; +import { getRequiredENVVar } from "./utils/container"; import { FeatureFlag, FeatureFlagEnum, getIsUserEligibleForNewFeature, } from "./utils/featureFlag"; +import { log } from "./utils/logger"; +import { decodeCIDRs } from "./utils/network"; +import { ognlTypeFor } from "./utils/ognl"; import { CommaSeparatedListOf } from "./utils/separated-list"; -import { LollipopApiClient } from "./clients/lollipop"; -import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; -import { TrialSystemAPIClient } from "./clients/trial-system.client"; -import { IoWalletAPIClient } from "./clients/io-wallet"; -import { IoFimsAPIClient } from "./clients/io-fims"; // Without this, the environment variables loaded by dotenv aren't available in // this file. @@ -60,24 +59,24 @@ export const SERVER_PORT = process.env.PORT || DEFAULT_SERVER_PORT; export const ENV = getNodeEnvironmentFromProcessEnv(process.env); // Default cache control max-age value is 5 minutes -const DEFAULT_CACHE_MAX_AGE_SECONDS: string = "300"; +const DEFAULT_CACHE_MAX_AGE_SECONDS = "300"; // Resolve cache control default max-age value // @deprecated this value is not used anymore. export const CACHE_MAX_AGE_SECONDS: number = parseInt( process.env.CACHE_MAX_AGE_SECONDS || DEFAULT_CACHE_MAX_AGE_SECONDS, - 10 + 10, ); // Default cache control max-age value is 1 hour -const DEFAULT_CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS: string = "3600"; +const DEFAULT_CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS = "3600"; // Resolve cache control default max-age value // @deprecated this value is not used anymore. export const CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS: number = parseInt( process.env.CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS || DEFAULT_CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS, - 10 + 10, ); // IP(s) or CIDR(s) allowed for notification @@ -87,11 +86,11 @@ export const ALLOW_NOTIFY_IP_SOURCE_RANGE = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid ALLOW_NOTIFY_IP_SOURCE_RANGE environment variable: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); // IP(s) or CIDR(s) allowed for myportal endpoint @@ -101,11 +100,11 @@ export const ALLOW_MYPORTAL_IP_SOURCE_RANGE = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid ALLOW_MYPORTAL_IP_SOURCE_RANGE environment variable: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); // IP(s) or CIDR(s) allowed for handling sessions @@ -115,11 +114,11 @@ export const ALLOW_SESSION_HANDLER_IP_SOURCE_RANGE = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid ALLOW_SESSION_HANDLER_IP_SOURCE_RANGE environment variable: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); const DEFAULT_REQUEST_TIMEOUT_MS = 10000 as Millisecond; @@ -129,7 +128,7 @@ const DEFAULT_REQUEST_TIMEOUT_MS = 10000 as Millisecond; const abortableFetch = AbortableFetch(agent.getFetch(process.env)); const fetchWithTimeout = setFetchTimeout( DEFAULT_REQUEST_TIMEOUT_MS, - abortableFetch + abortableFetch, ); const httpOrHttpsApiFetch = toFetch(fetchWithTimeout); @@ -146,8 +145,8 @@ export const getHttpsApiFetchWithBearer = (bearer: string) => toFetch( setFetchTimeout( DEFAULT_REQUEST_TIMEOUT_MS, - AbortableFetch(bearerAuthFetch(httpOrHttpsApiFetch, bearer)) - ) + AbortableFetch(bearerAuthFetch(httpOrHttpsApiFetch, bearer)), + ), ); export const API_KEY = getRequiredENVVar("API_KEY"); @@ -156,7 +155,7 @@ export const API_BASE_PATH = getRequiredENVVar("API_BASE_PATH"); export const API_CLIENT = new ApiClientFactory( API_KEY, API_URL, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const APP_MESSAGES_API_KEY = getRequiredENVVar("APP_MESSAGES_API_KEY"); @@ -165,7 +164,7 @@ export const APP_MESSAGES_API_URL = getRequiredENVVar("APP_MESSAGES_API_URL"); export const APP_MESSAGES_API_CLIENT = AppMessagesAPIClient( APP_MESSAGES_API_KEY, APP_MESSAGES_API_URL, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const BONUS_API_KEY = getRequiredENVVar("BONUS_API_KEY"); @@ -174,7 +173,7 @@ export const BONUS_API_BASE_PATH = getRequiredENVVar("BONUS_API_BASE_PATH"); export const BONUS_API_CLIENT = BonusAPIClient( BONUS_API_KEY, BONUS_API_URL, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const IO_SIGN_API_KEY = getRequiredENVVar("IO_SIGN_API_KEY"); @@ -185,7 +184,7 @@ export const IO_SIGN_API_CLIENT = IoSignAPIClient( IO_SIGN_API_KEY, IO_SIGN_API_URL, IO_SIGN_API_BASE_PATH, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const IO_FIMS_API_KEY = getRequiredENVVar("IO_FIMS_API_KEY"); @@ -195,7 +194,7 @@ export const IO_FIMS_API_CLIENT = IoFimsAPIClient( IO_FIMS_API_KEY, IO_FIMS_API_URL, IO_FIMS_API_BASE_PATH, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const CGN_API_KEY = getRequiredENVVar("CGN_API_KEY"); @@ -205,73 +204,73 @@ export const CGN_API_CLIENT = CgnAPIClient( CGN_API_KEY, CGN_API_URL, CGN_API_BASE_PATH, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING" + "LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING", ); export const LOLLIPOP_REVOKE_QUEUE_NAME = getRequiredENVVar( - "LOLLIPOP_REVOKE_QUEUE_NAME" + "LOLLIPOP_REVOKE_QUEUE_NAME", ); export const LOLLIPOP_API_KEY = getRequiredENVVar("LOLLIPOP_API_KEY"); export const LOLLIPOP_API_URL = getRequiredENVVar("LOLLIPOP_API_URL"); export const LOLLIPOP_API_BASE_PATH = getRequiredENVVar( - "LOLLIPOP_API_BASE_PATH" + "LOLLIPOP_API_BASE_PATH", ); export const LOLLIPOP_API_CLIENT = LollipopApiClient( LOLLIPOP_API_KEY, LOLLIPOP_API_URL, LOLLIPOP_API_BASE_PATH, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const FIRST_LOLLIPOP_CONSUMER_CLIENT = FirstLollipopConsumerClient( // We access to the first lollipop consumer implementation that is now located // within the Lollipop function. LOLLIPOP_API_KEY, - LOLLIPOP_API_URL + LOLLIPOP_API_URL, ); export const CGN_OPERATOR_SEARCH_API_KEY = getRequiredENVVar( - "CGN_OPERATOR_SEARCH_API_KEY" + "CGN_OPERATOR_SEARCH_API_KEY", ); export const CGN_OPERATOR_SEARCH_API_URL = getRequiredENVVar( - "CGN_OPERATOR_SEARCH_API_URL" + "CGN_OPERATOR_SEARCH_API_URL", ); export const CGN_OPERATOR_SEARCH_API_BASE_PATH = getRequiredENVVar( - "CGN_OPERATOR_SEARCH_API_BASE_PATH" + "CGN_OPERATOR_SEARCH_API_BASE_PATH", ); export const CGN_OPERATOR_SEARCH_API_CLIENT = CgnOperatorSearchAPIClient( CGN_OPERATOR_SEARCH_API_KEY, CGN_OPERATOR_SEARCH_API_URL, CGN_OPERATOR_SEARCH_API_BASE_PATH, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const EUCOVIDCERT_API_KEY = getRequiredENVVar("EUCOVIDCERT_API_KEY"); export const EUCOVIDCERT_API_URL = getRequiredENVVar("EUCOVIDCERT_API_URL"); export const EUCOVIDCERT_API_BASE_PATH = getRequiredENVVar( - "EUCOVIDCERT_API_BASE_PATH" + "EUCOVIDCERT_API_BASE_PATH", ); export const EUCOVIDCERT_API_CLIENT = EUCovidCertAPIClient( EUCOVIDCERT_API_KEY, EUCOVIDCERT_API_URL, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const SERVICES_APP_BACKEND_API_BASE_PATH = getRequiredENVVar( - "SERVICES_APP_BACKEND_API_BASE_PATH" + "SERVICES_APP_BACKEND_API_BASE_PATH", ); export const SERVICES_APP_BACKEND_API_URL = getRequiredENVVar( - "SERVICES_APP_BACKEND_API_URL" + "SERVICES_APP_BACKEND_API_URL", ); // TODO: creare servicesAppBackend client export const SERVICES_APP_BACKEND_CLIENT = ServicesAppBackendAPIClient( SERVICES_APP_BACKEND_API_URL, SERVICES_APP_BACKEND_API_BASE_PATH, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); /** @@ -306,11 +305,11 @@ export const PNAddressBookConfig = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PN Address book configuration envs: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); export const PN_ADDRESS_BOOK_CLIENT_SELECTOR: O.Option< @@ -325,11 +324,11 @@ export const PN_ADDRESS_BOOK_CLIENT_SELECTOR: O.Option< pnConfig.PN_API_KEY, pnConfig.PN_API_URL_UAT, pnConfig.PN_API_KEY_UAT, - httpOrHttpsApiFetch - ) - ) + httpOrHttpsApiFetch, + ), + ), ), - E.toUnion + E.toUnion, ); // HTTPs-only fetch with optional keepalive agent @@ -346,18 +345,18 @@ export const PAGOPA_CLIENT = new PagoPAClientFactory( pagoPAApiKeyProd, pagoPAApiUrlTest, pagoPAApiKeyTest, - simpleHttpsApiFetch + simpleHttpsApiFetch, ); // API endpoint mount. export const AUTHENTICATION_BASE_PATH = getRequiredENVVar( - "AUTHENTICATION_BASE_PATH" + "AUTHENTICATION_BASE_PATH", ); export const MYPORTAL_BASE_PATH = getRequiredENVVar("MYPORTAL_BASE_PATH"); export const SERVICES_APP_BACKEND_BASE_PATH = getRequiredENVVar( - "SERVICES_APP_BACKEND_BASE_PATH" + "SERVICES_APP_BACKEND_BASE_PATH", ); // Token needed to receive API calls (notifications, metadata update) from io-functions-services @@ -368,18 +367,18 @@ export const URL_TOKEN_STRATEGY = urlTokenStrategy(PRE_SHARED_KEY); // Needed to forward push notifications actions events export const NOTIFICATIONS_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "NOTIFICATIONS_STORAGE_CONNECTION_STRING" + "NOTIFICATIONS_STORAGE_CONNECTION_STRING", ); export const NOTIFICATIONS_QUEUE_NAME = getRequiredENVVar( - "NOTIFICATIONS_QUEUE_NAME" + "NOTIFICATIONS_QUEUE_NAME", ); // Needed to forward push notifications actions events export const PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING" + "PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING", ); export const PUSH_NOTIFICATIONS_QUEUE_NAME = getRequiredENVVar( - "PUSH_NOTIFICATIONS_QUEUE_NAME" + "PUSH_NOTIFICATIONS_QUEUE_NAME", ); // Root redirect @@ -388,10 +387,10 @@ const DEFAULT_ROOT_REDIRECT_URL = pipe( HttpsUrlFromString.decode, E.getOrElseW((errs) => { log.error( - `Invalid DEFAULT_ROOT_REDIRECT_URL variable: ${readableReport(errs)}` + `Invalid DEFAULT_ROOT_REDIRECT_URL variable: ${readableReport(errs)}`, ); return process.exit(1); - }) + }), ); export const ROOT_REDIRECT_URL = pipe( @@ -401,18 +400,18 @@ export const ROOT_REDIRECT_URL = pipe( log.warn( `Missing or invalid ROOT_REDIRECT_URL variable, defaulting to "${ DEFAULT_ROOT_REDIRECT_URL.href - }": ${readableReport(errs)}` + }": ${readableReport(errs)}`, ); return DEFAULT_ROOT_REDIRECT_URL; - }) + }), ); // Needed to verify if a profile has been locked export const LOCKED_PROFILES_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "LOCKED_PROFILES_STORAGE_CONNECTION_STRING" + "LOCKED_PROFILES_STORAGE_CONNECTION_STRING", ); export const LOCKED_PROFILES_TABLE_NAME = getRequiredENVVar( - "LOCKED_PROFILES_TABLE_NAME" + "LOCKED_PROFILES_TABLE_NAME", ); // Push notifications @@ -423,7 +422,7 @@ export const NOTIFICATION_DEFAULT_TITLE = "Hai un nuovo messaggio su IO"; export const BARCODE_ALGORITHM = pipe( process.env.BARCODE_ALGORITHM, NonEmptyString.decode, - E.getOrElse(() => "code128" as NonEmptyString) + E.getOrElse(() => "code128" as NonEmptyString), ); // Application insights sampling percentage @@ -442,9 +441,9 @@ export const TEST_CGN_FISCAL_CODES = pipe( CommaSeparatedListOf(FiscalCode).decode, E.getOrElseW((err) => { throw new Error( - `Invalid TEST_CGN_FISCAL_CODES value: ${readableReport(err)}` + `Invalid TEST_CGN_FISCAL_CODES value: ${readableReport(err)}`, ); - }) + }), ); // PEC SERVER config @@ -468,11 +467,11 @@ export const PECSERVERS = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PECSERVERS environment variable: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); // @@ -486,7 +485,7 @@ export const PECSERVERS = pipe( const IS_APPBACKENDLI = pipe( O.fromNullable(process.env.IS_APPBACKENDLI), O.map((val) => val.toLowerCase() === "true"), - O.getOrElse(() => false) + O.getOrElse(() => false), ); export const FF_ENABLE_NOTIFY_ENDPOINT = IS_APPBACKENDLI; @@ -499,11 +498,11 @@ export const PN_SERVICE_ID = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PN_SERVICE_ID environment variable: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); export const PN_CONFIGURATION_ID = pipe( @@ -512,17 +511,17 @@ export const PN_CONFIGURATION_ID = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PN_CONFIGURATION_ID environment variable: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); export const FF_ROUTING_PUSH_NOTIF = pipe( process.env.FF_ROUTING_PUSH_NOTIF, FeatureFlag.decode, - E.getOrElse((_) => FeatureFlagEnum.NONE) + E.getOrElse((_) => FeatureFlagEnum.NONE), ); export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( @@ -531,16 +530,16 @@ export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST environment variable: ${readableReport( - errs - )}` + errs, + )}`, ); return process.exit(1); - }) + }), ); export const FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX = pipe( process.env.FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, NonEmptyString.decode, - E.getOrElse((_) => "XYZ" as NonEmptyString) + E.getOrElse((_) => "XYZ" as NonEmptyString), ); // UNIQUE EMAIL ENFORCEMENT variables @@ -548,7 +547,7 @@ export const FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX = pipe( export const FF_UNIQUE_EMAIL_ENFORCEMENT = pipe( process.env.FF_UNIQUE_EMAIL_ENFORCEMENT, FeatureFlag.decode, - E.getOrElseW(() => FeatureFlagEnum.NONE) + E.getOrElseW(() => FeatureFlagEnum.NONE), ); export const UNIQUE_EMAIL_ENFORCEMENT_USERS = pipe( @@ -557,16 +556,16 @@ export const UNIQUE_EMAIL_ENFORCEMENT_USERS = pipe( CommaSeparatedListOf(FiscalCode).decode, E.getOrElseW((err) => { throw new Error( - `Invalid UNIQUE_EMAIL_ENFORCEMENT_USERS value: ${readableReport(err)}` + `Invalid UNIQUE_EMAIL_ENFORCEMENT_USERS value: ${readableReport(err)}`, ); - }) + }), ); export const FF_UNIQUE_EMAIL_ENFORCEMENT_ENABLED = getIsUserEligibleForNewFeature( (fiscalCode) => UNIQUE_EMAIL_ENFORCEMENT_USERS.includes(fiscalCode), () => false, - FF_UNIQUE_EMAIL_ENFORCEMENT + FF_UNIQUE_EMAIL_ENFORCEMENT, ); // ####### TRIAL_SYSTEM ######## @@ -574,30 +573,30 @@ export const FF_TRIAL_SYSTEM_ENABLED = process.env.FF_TRIAL_SYSTEM_ENABLED === "1"; export const TRIAL_SYSTEM_API_BASE_PATH = getRequiredENVVar( - "TRIAL_SYSTEM_API_BASE_PATH" + "TRIAL_SYSTEM_API_BASE_PATH", ); export const TRIAL_SYSTEM_API_KEY = getRequiredENVVar("TRIAL_SYSTEM_APIM_KEY"); export const TRIAL_SYSTEM_API_URL = getRequiredENVVar("TRIAL_SYSTEM_APIM_URL"); export const TRIAL_SYSTEM_APIM_BASE_PATH = getRequiredENVVar( - "TRIAL_SYSTEM_APIM_BASE_PATH" + "TRIAL_SYSTEM_APIM_BASE_PATH", ); export const TRIAL_SYSTEM_CLIENT = TrialSystemAPIClient( TRIAL_SYSTEM_API_KEY, TRIAL_SYSTEM_API_URL, - TRIAL_SYSTEM_APIM_BASE_PATH + TRIAL_SYSTEM_APIM_BASE_PATH, ); export const IO_WALLET_API_KEY = getRequiredENVVar("IO_WALLET_API_KEY"); export const IO_WALLET_API_URL = getRequiredENVVar("IO_WALLET_API_URL"); export const IO_WALLET_API_BASE_PATH = getRequiredENVVar( - "IO_WALLET_API_BASE_PATH" + "IO_WALLET_API_BASE_PATH", ); export const IO_WALLET_TRIAL_ID = getRequiredENVVar("IO_WALLET_TRIAL_ID"); export const IO_WALLET_API_CLIENT = IoWalletAPIClient( IO_WALLET_API_KEY, IO_WALLET_API_BASE_PATH, IO_WALLET_API_URL, - httpOrHttpsApiFetch + httpOrHttpsApiFetch, ); export const FF_IO_WALLET_ENABLED = process.env.FF_IO_WALLET_ENABLED === "1"; export const FF_IO_WALLET_TRIAL_ENABLED = diff --git a/src/controllers/authenticationController.ts b/src/controllers/authenticationController.ts index c04076397..003bfd23c 100644 --- a/src/controllers/authenticationController.ts +++ b/src/controllers/authenticationController.ts @@ -4,8 +4,6 @@ * the IDP. */ -import * as express from "express"; -import * as E from "fp-ts/lib/Either"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -13,20 +11,21 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - +import * as express from "express"; +import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; -import { UserIdentity } from "../../generated/auth/UserIdentity"; +import { UserIdentity } from "../../generated/auth/UserIdentity"; import { exactUserIdentityDecode, withUserFromRequest } from "../types/user"; /** * Returns the user identity stored after the login process. */ export const getUserIdentity: ( - req: express.Request + req: express.Request, ) => Promise< - | IResponseErrorValidation | IResponseErrorInternal + | IResponseErrorValidation | IResponseSuccessJson > = (req) => withUserFromRequest(req, async (user) => @@ -34,7 +33,7 @@ export const getUserIdentity: ( user, UserIdentity.decode, E.mapLeft((_) => - ResponseErrorInternal("Unexpected User Identity data format.") + ResponseErrorInternal("Unexpected User Identity data format."), ), E.map((_) => pipe( @@ -42,9 +41,9 @@ export const getUserIdentity: ( exactUserIdentityDecode, E.mapLeft((_1) => ResponseErrorInternal("Exact decode failed.")), E.map(ResponseSuccessJson), - E.toUnion - ) + E.toUnion, + ), ), - E.toUnion - ) + E.toUnion, + ), ); diff --git a/src/controllers/bonusController.ts b/src/controllers/bonusController.ts index 02efa5c13..8e6069996 100644 --- a/src/controllers/bonusController.ts +++ b/src/controllers/bonusController.ts @@ -3,7 +3,6 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; import { IResponseErrorGone, IResponseErrorInternal, @@ -12,11 +11,12 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { PaginatedBonusActivationsCollection } from "generated/io-bonus-api/PaginatedBonusActivationsCollection"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import BonusService from "src/services/bonusService"; + import { EligibilityCheck } from "../../generated/io-bonus-api/EligibilityCheck"; import { InstanceId } from "../../generated/io-bonus-api/InstanceId"; import { withUserFromRequest } from "../types/user"; @@ -24,15 +24,28 @@ import { withValidatedOrValidationError } from "../utils/responses"; export const withBonusIdFromRequest = async ( req: express.Request, - f: (bonusId: NonEmptyString) => Promise + f: (bonusId: NonEmptyString) => Promise, ): Promise => withValidatedOrValidationError( NonEmptyString.decode(req.params["bonus_id"]), - f + f, ); export default class BonusController { - constructor(private readonly bonusService: BonusService) {} + /** + * Get all IDs of the bonus activations requested by + * the authenticated user or by any between his family member + */ + public readonly getAllBonusActivations = ( + req: express.Request, + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson + > => + withUserFromRequest(req, (user) => + this.bonusService.getAllBonusActivations(user), + ); /** * Starts a request for a bonus for the current user. @@ -40,17 +53,17 @@ export default class BonusController { * */ public readonly getBonusEligibilityCheck = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation - | IResponseErrorNotFound + | IResponseErrorGone | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessAccepted - | IResponseErrorGone | IResponseSuccessJson > => withUserFromRequest(req, (user) => - this.bonusService.getBonusEligibilityCheck(user) + this.bonusService.getBonusEligibilityCheck(user), ); /** @@ -59,32 +72,19 @@ export default class BonusController { * */ public readonly getLatestBonusActivationById = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation - | IResponseErrorNotFound | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessAccepted | IResponseSuccessJson > => withUserFromRequest(req, (user) => withBonusIdFromRequest(req, (bonusId) => - this.bonusService.getLatestBonusActivationById(user, bonusId) - ) + this.bonusService.getLatestBonusActivationById(user, bonusId), + ), ); - /** - * Get all IDs of the bonus activations requested by - * the authenticated user or by any between his family member - */ - public readonly getAllBonusActivations = ( - req: express.Request - ): Promise< - | IResponseErrorValidation - | IResponseErrorInternal - | IResponseSuccessJson - > => - withUserFromRequest(req, (user) => - this.bonusService.getAllBonusActivations(user) - ); + constructor(private readonly bonusService: BonusService) {} } diff --git a/src/controllers/cgnController.ts b/src/controllers/cgnController.ts index 3901178fa..2646afd2b 100644 --- a/src/controllers/cgnController.ts +++ b/src/controllers/cgnController.ts @@ -3,7 +3,9 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; +import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; +import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; +import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -15,21 +17,19 @@ import { IResponseSuccessRedirectToResource, ResponseErrorForbiddenNotAuthorized, } from "@pagopa/ts-commons/lib/responses"; - -import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; -import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import { Otp } from "generated/cgn/Otp"; -import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; + import { Card } from "../../generated/cgn/Card"; -import CgnService from "../../src/services/cgnService"; import { InstanceId } from "../../generated/cgn/InstanceId"; +import CgnService from "../../src/services/cgnService"; import { User, withUserFromRequest } from "../types/user"; export const withAllowedUser = async ( user: User, - allowedFiscalCodes: ReadonlyArray, - f: (user: User) => Promise + allowedFiscalCodes: readonly FiscalCode[], + f: (user: User) => Promise, ) => allowedFiscalCodes.length === 0 || allowedFiscalCodes.includes(user.fiscal_code) @@ -37,171 +37,171 @@ export const withAllowedUser = async ( : ResponseErrorForbiddenNotAuthorized; export default class CgnController { - constructor( - private readonly cgnService: CgnService, - private readonly allowedFiscalCodes: ReadonlyArray - ) {} - /** - * Get the Cgn status for the current user. + * Generate a CGN OTP for the current user. */ - public readonly getCgnStatus = ( - req: express.Request + public readonly generateOtp = ( + req: express.Request, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getCgnStatus - ) + this.cgnService.generateOtp, + ), ); /** - * Get the Eyca Card status for the current user. + * Get Cgn activation's process status for the current user. */ - public readonly getEycaStatus = ( - req: express.Request + public readonly getCgnActivation = ( + req: express.Request, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getEycaStatus - ) + this.cgnService.getCgnActivation, + ), ); /** - * Start a Cgn activation for the current user. + * Get the Cgn status for the current user. */ - public readonly startCgnActivation = ( - req: express.Request + public readonly getCgnStatus = ( + req: express.Request, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessRedirectToResource - | IResponseSuccessAccepted + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.startCgnActivation - ) + this.cgnService.getCgnStatus, + ), ); /** - * Get Cgn activation's process status for the current user. + * Get EYCA card activation's process status for the current user. */ - public readonly getCgnActivation = ( - req: express.Request + public readonly getEycaActivation = ( + req: express.Request, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getCgnActivation - ) + this.cgnService.getEycaActivation, + ), ); /** - * Get EYCA card activation's process status for the current user. + * Get the Eyca Card status for the current user. */ - public readonly getEycaActivation = ( - req: express.Request + public readonly getEycaStatus = ( + req: express.Request, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getEycaActivation - ) + this.cgnService.getEycaStatus, + ), ); /** - * Start an EYCA activation for the current user. + * Start a Cgn activation for the current user. */ - public readonly startEycaActivation = ( - req: express.Request + public readonly startCgnActivation = ( + req: express.Request, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessRedirectToResource | IResponseSuccessAccepted + | IResponseSuccessRedirectToResource > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.startEycaActivation - ) + this.cgnService.startCgnActivation, + ), ); /** * Start a Cgn unsubscription for the current user. */ public readonly startCgnUnsubscription = ( - req: express.Request + req: express.Request, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessRedirectToResource | IResponseSuccessAccepted + | IResponseSuccessRedirectToResource > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.startCgnUnsubscription - ) + this.cgnService.startCgnUnsubscription, + ), ); /** - * Generate a CGN OTP for the current user. + * Start an EYCA activation for the current user. */ - public readonly generateOtp = ( - req: express.Request + public readonly startEycaActivation = ( + req: express.Request, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseSuccessAccepted + | IResponseSuccessRedirectToResource > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.generateOtp - ) + this.cgnService.startEycaActivation, + ), ); + + constructor( + private readonly cgnService: CgnService, + private readonly allowedFiscalCodes: readonly FiscalCode[], + ) {} } diff --git a/src/controllers/cgnOperatorSearchController.ts b/src/controllers/cgnOperatorSearchController.ts index 1dc446f30..de2d5e880 100644 --- a/src/controllers/cgnOperatorSearchController.ts +++ b/src/controllers/cgnOperatorSearchController.ts @@ -4,7 +4,6 @@ */ import { IResponseErrorForbiddenNotAuthorized } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; import { IResponse, IResponseErrorInternal, @@ -15,61 +14,83 @@ import { ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import CgnService from "src/services/cgnService"; +import * as express from "express"; import * as E from "fp-ts/Either"; -import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; -import { Card } from "generated/cgn/Card"; import { pipe } from "fp-ts/lib/function"; -import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; +import { Card } from "generated/cgn/Card"; import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; +import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; +import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; +import CgnService from "src/services/cgnService"; + import { Merchant } from "../../generated/cgn-operator-search/Merchant"; import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; -import { GetPublishedCategoriesParameters } from "../../generated/parameters/GetPublishedCategoriesParameters"; import { PublishedProductCategoriesResult } from "../../generated/cgn-operator-search/PublishedProductCategoriesResult"; import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; import { SearchRequest } from "../../generated/io-cgn-operator-search-api/SearchRequest"; +import { GetPublishedCategoriesParameters } from "../../generated/parameters/GetPublishedCategoriesParameters"; import CgnOperatorSearchService from "../services/cgnOperatorSearchService"; import { User, withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; export default class CgnOperatorSearchController { - constructor( - private readonly cgnService: CgnService, - private readonly cgnOperatorSearchService: CgnOperatorSearchService - ) {} + private readonly eligibleUserOrError = async ( + user: User, + ): Promise< + E.Either< + IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, + string + > + > => { + const cgnStatusResponse = await this.cgnService.getCgnStatus(user); + + return pipe( + cgnStatusResponse, + E.fromPredicate(this.isCgnStatusResponseSuccess, () => + ResponseErrorInternal("Cannot retrieve cgn card status"), + ), + E.map((res) => res.value.status), + E.chainW( + E.fromPredicate( + (status) => status === "ACTIVATED", + () => ResponseErrorForbiddenNotAuthorized, + ), + ), + ); + }; + + private readonly isCgnStatusResponseSuccess = ( + res: IResponse, + ): res is IResponseSuccessJson => res.kind === "IResponseSuccessJson"; /** - * Get an array of CGN product categories that have at least a published discount + * Count CGN merchants/discounts */ - public readonly getPublishedProductCategories = ( - req: express.Request + public readonly count = ( + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, async (_) => - withValidatedOrValidationError( - GetPublishedCategoriesParameters.decode(req.query), - (params) => - this.cgnOperatorSearchService.getPublishedProductCategories(params) - ) + this.cgnOperatorSearchService.count(), ); /** - * Get the CGN operator/merchant by its identifier. + * Get a discount bucket code by discount identifier. */ - public readonly getMerchant = ( - req: express.Request + public readonly getDiscountBucketCode = ( + req: express.Request, ): Promise< - | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => { const eligibleUserOrErrorResult = await this.eligibleUserOrError(user); @@ -78,42 +99,56 @@ export default class CgnOperatorSearchController { } return withValidatedOrValidationError( - NonEmptyString.decode(req.params.merchantId), - (merchantId) => this.cgnOperatorSearchService.getMerchant(merchantId) + NonEmptyString.decode(req.params.discountId), + (discountId) => + this.cgnOperatorSearchService.getDiscountBucketCode(discountId), ); }); /** - * Count CGN merchants/discounts + * Get the CGN operator/merchant by its identifier. */ - public readonly count = ( - req: express.Request + public readonly getMerchant = ( + req: express.Request, ): Promise< - | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => - this.cgnOperatorSearchService.count() - ); + withUserFromRequest(req, async (user) => { + const eligibleUserOrErrorResult = await this.eligibleUserOrError(user); + if (E.isLeft(eligibleUserOrErrorResult)) { + return eligibleUserOrErrorResult.left; + } + + return withValidatedOrValidationError( + NonEmptyString.decode(req.params.merchantId), + (merchantId) => this.cgnOperatorSearchService.getMerchant(merchantId), + ); + }); /** - * Search CGN merchants/discounts that matches with search criteria + * Get an array of CGN offline merchants that matches with search criteria + * expressed in OfflineMerchantSearchRequest */ - public readonly search = ( - req: express.Request + public readonly getOfflineMerchants = ( + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, async (_) => withValidatedOrValidationError( - SearchRequest.decode(req.body), - (searchRequest) => this.cgnOperatorSearchService.search(searchRequest) - ) + OfflineMerchantSearchRequest.decode(req.body), + (offlineSearchRequest) => + this.cgnOperatorSearchService.getOfflineMerchants( + offlineSearchRequest, + ), + ), ); /** @@ -121,94 +156,60 @@ export default class CgnOperatorSearchController { * expressed in OnlineMerchantSearchRequest */ public readonly getOnlineMerchants = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (_) => withValidatedOrValidationError( OnlineMerchantSearchRequest.decode(req.body), (onlineSearchRequest) => - this.cgnOperatorSearchService.getOnlineMerchants(onlineSearchRequest) - ) + this.cgnOperatorSearchService.getOnlineMerchants(onlineSearchRequest), + ), ); /** - * Get an array of CGN offline merchants that matches with search criteria - * expressed in OfflineMerchantSearchRequest + * Get an array of CGN product categories that have at least a published discount */ - public readonly getOfflineMerchants = ( - req: express.Request + public readonly getPublishedProductCategories = ( + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, async (_) => withValidatedOrValidationError( - OfflineMerchantSearchRequest.decode(req.body), - (offlineSearchRequest) => - this.cgnOperatorSearchService.getOfflineMerchants( - offlineSearchRequest - ) - ) + GetPublishedCategoriesParameters.decode(req.query), + (params) => + this.cgnOperatorSearchService.getPublishedProductCategories(params), + ), ); /** - * Get a discount bucket code by discount identifier. + * Search CGN merchants/discounts that matches with search criteria */ - public readonly getDiscountBucketCode = ( - req: express.Request + public readonly search = ( + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => - withUserFromRequest(req, async (user) => { - const eligibleUserOrErrorResult = await this.eligibleUserOrError(user); - if (E.isLeft(eligibleUserOrErrorResult)) { - return eligibleUserOrErrorResult.left; - } - - return withValidatedOrValidationError( - NonEmptyString.decode(req.params.discountId), - (discountId) => - this.cgnOperatorSearchService.getDiscountBucketCode(discountId) - ); - }); - - private readonly isCgnStatusResponseSuccess = ( - res: IResponse - ): res is IResponseSuccessJson => res.kind === "IResponseSuccessJson"; - - private readonly eligibleUserOrError = async ( - user: User - ): Promise< - E.Either< - IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, - string - > - > => { - const cgnStatusResponse = await this.cgnService.getCgnStatus(user); - - return pipe( - cgnStatusResponse, - E.fromPredicate(this.isCgnStatusResponseSuccess, () => - ResponseErrorInternal("Cannot retrieve cgn card status") + withUserFromRequest(req, async (_) => + withValidatedOrValidationError( + SearchRequest.decode(req.body), + (searchRequest) => this.cgnOperatorSearchService.search(searchRequest), ), - E.map((res) => res.value.status), - E.chainW( - E.fromPredicate( - (status) => status === "ACTIVATED", - () => ResponseErrorForbiddenNotAuthorized - ) - ) ); - }; + + constructor( + private readonly cgnService: CgnService, + private readonly cgnOperatorSearchService: CgnOperatorSearchService, + ) {} } diff --git a/src/controllers/eucovidcertController.ts b/src/controllers/eucovidcertController.ts index 35d0178eb..1bd7a7f65 100644 --- a/src/controllers/eucovidcertController.ts +++ b/src/controllers/eucovidcertController.ts @@ -1,5 +1,4 @@ -import * as express from "express"; - +import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; import { IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, @@ -7,36 +6,37 @@ import { IResponseErrorValidation, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; -import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; import { GetCertificateParams } from "../../generated/eucovidcert/GetCertificateParams"; import { PreferredLanguages } from "../../generated/eucovidcert/PreferredLanguages"; -import { withValidatedOrValidationError } from "../utils/responses"; import EUCovidService from "../services/eucovidcertService"; import { withUserFromRequest } from "../types/user"; +import { withValidatedOrValidationError } from "../utils/responses"; export const withGetCertificateParams = async ( req: express.Request, - f: (auth_code: string, preferred_languages?: PreferredLanguages) => Promise + f: ( + auth_code: string, + preferred_languages?: PreferredLanguages, + ) => Promise, ) => withValidatedOrValidationError( GetCertificateParams.decode(req.body.accessData), - (val) => f(val.auth_code, val.preferred_languages) + (val) => f(val.auth_code, val.preferred_languages), ); export default class EUCovidCertController { - constructor(private readonly eucovidCertService: EUCovidService) {} - /** * Get the EU Covid Certificate for the current user. */ public readonly getEUCovidCertificate = ( - req: express.Request + req: express.Request, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, (user) => @@ -44,8 +44,10 @@ export default class EUCovidCertController { this.eucovidCertService.getEUCovidCertificate( user, auth_code, - preferred_languages - ) - ) + preferred_languages, + ), + ), ); + + constructor(private readonly eucovidCertService: EUCovidService) {} } diff --git a/src/controllers/fimsController.ts b/src/controllers/fimsController.ts index a4d918191..e70ffe894 100644 --- a/src/controllers/fimsController.ts +++ b/src/controllers/fimsController.ts @@ -3,10 +3,6 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; -import * as t from "io-ts"; - import { IResponseErrorConflict, IResponseErrorInternal, @@ -15,18 +11,17 @@ import { IResponseSuccessJson, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; - -import { pipe } from "fp-ts/lib/function"; import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; - +import * as express from "express"; +import * as TE from "fp-ts/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { AccessHistoryPage } from "generated/io-fims/AccessHistoryPage"; import { ExportRequest } from "generated/io-fims/ExportRequest"; +import * as t from "io-ts"; import IoFimsService from "../services/fimsService"; - -import { withUserFromRequest } from "../types/user"; import ProfileService from "../services/profileService"; - +import { withUserFromRequest } from "../types/user"; import { profileWithEmailValidatedOrError } from "../utils/profile"; const responseErrorInternal = (reason: string) => (e: Error) => @@ -43,14 +38,14 @@ const responseErrorInternal = (reason: string) => (e: Error) => const getAccessHistory = ( ioFimsService: IoFimsService, fiscalCode: FiscalCode, - page?: string + page?: string, ) => pipe( TE.tryCatch( () => ioFimsService.getAccessHistory(fiscalCode, page), - () => new Error("Error while fetching the access history") + () => new Error("Error while fetching the access history"), ), - TE.mapLeft(responseErrorInternal("Fetching error")) + TE.mapLeft(responseErrorInternal("Fetching error")), ); /** @@ -64,28 +59,17 @@ const getAccessHistory = ( const requestExport = ( ioFimsService: IoFimsService, fiscalCode: FiscalCode, - email: EmailString + email: EmailString, ) => pipe( TE.tryCatch( () => ioFimsService.requestExport(fiscalCode, email), - () => new Error("Error while requesting the export") + () => new Error("Error while requesting the export"), ), - TE.mapLeft(responseErrorInternal("Error while requesting the export")) + TE.mapLeft(responseErrorInternal("Error while requesting the export")), ); export default class IoFimsController { - /** - * Constructs an instance of IoFimsController. - * - * @param ioFimsService - The service responsible for FIMS operations. - * @param profileService - The service responsible for profile operations. - */ - constructor( - private readonly ioFimsService: IoFimsService, - private readonly profileService: ProfileService - ) {} - /** * Retrieves the access history for a user. * @@ -96,10 +80,10 @@ export default class IoFimsController { * - `IResponseSuccessJson` if the access history is successfully retrieved. */ public readonly getAccessHistory = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -108,10 +92,10 @@ export default class IoFimsController { TE.fromEither, TE.altW(() => TE.right(undefined)), TE.flatMap((page) => - getAccessHistory(this.ioFimsService, user.fiscal_code, page) + getAccessHistory(this.ioFimsService, user.fiscal_code, page), ), - TE.toUnion - )() + TE.toUnion, + )(), ); /** @@ -126,11 +110,11 @@ export default class IoFimsController { * - `IResponseSuccessAccepted` if the export request is accepted. */ public readonly requestExport = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorConflict | IResponseErrorInternal + | IResponseErrorValidation | IResponseSuccessAccepted > => withUserFromRequest(req, async (user) => @@ -138,13 +122,24 @@ export default class IoFimsController { profileWithEmailValidatedOrError(this.profileService, user), TE.mapLeft( responseErrorInternal( - "Error retrieving a user profile with validated email address" - ) + "Error retrieving a user profile with validated email address", + ), ), TE.flatMap((profile) => - requestExport(this.ioFimsService, profile.fiscal_code, profile.email) + requestExport(this.ioFimsService, profile.fiscal_code, profile.email), ), - TE.toUnion - )() + TE.toUnion, + )(), ); + + /** + * Constructs an instance of IoFimsController. + * + * @param ioFimsService - The service responsible for FIMS operations. + * @param profileService - The service responsible for profile operations. + */ + constructor( + private readonly ioFimsService: IoFimsService, + private readonly profileService: ProfileService, + ) {} } diff --git a/src/controllers/firstLollipopConsumerController.ts b/src/controllers/firstLollipopConsumerController.ts index b79dbe3e1..049e70167 100644 --- a/src/controllers/firstLollipopConsumerController.ts +++ b/src/controllers/firstLollipopConsumerController.ts @@ -1,3 +1,4 @@ +import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -5,20 +6,18 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; -import { flow, pipe } from "fp-ts/lib/function"; -import * as TE from "fp-ts/TaskEither"; -import * as E from "fp-ts/Either"; -import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import { pick } from "@pagopa/ts-commons/lib/types"; +import * as express from "express"; +import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; import { SignMessageResponse } from "../../generated/first-lc-proxy-models/SignMessageResponse"; - -import { logLollipopSignRequest } from "../utils/appinsights"; import { FirstLollipopConsumerClient } from "../clients/firstLollipopConsumer"; -import { ResLocals } from "../utils/express"; import { withLollipopLocals, withRequiredRawBody } from "../types/lollipop"; +import { logLollipopSignRequest } from "../utils/appinsights"; +import { ResLocals } from "../utils/express"; const FIRST_LOLLIPOP_CONSUMER_ID = "fist-lollipop-consumer" as NonEmptyString; @@ -26,10 +25,10 @@ export const firstLollipopSign = (client: ReturnType) => async ( req: express.Request, - locals?: T + locals?: T, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal + | IResponseErrorValidation | IResponseSuccessJson > => pipe( @@ -44,41 +43,41 @@ export const firstLollipopSign = client.signMessage({ ...localsWithBody, }), - () => ResponseErrorInternal("Error calling the Lollipop Consumer") + () => ResponseErrorInternal("Error calling the Lollipop Consumer"), ), TE.chainFirstW( flow( E.map((res) => pick(["status"], res)), E.mapLeft( - flow(readableReportSimplified, (message) => new Error(message)) + flow(readableReportSimplified, (message) => new Error(message)), ), logLollipopSignRequest(FIRST_LOLLIPOP_CONSUMER_ID)( localsWithBody, - req + req, ), - TE.of - ) - ) - ) + TE.of, + ), + ), + ), ), TE.chainEitherKW( E.mapLeft( flow(readableReportSimplified, (message) => ResponseErrorInternal( - `Unexpected Lollipop consumer response: ${message}` - ) - ) - ) + `Unexpected Lollipop consumer response: ${message}`, + ), + ), + ), ), TE.chain((response) => response.status === 200 ? TE.right(response.value) : TE.left( ResponseErrorInternal( - `signMessage returned ${response.status}: ${response.value?.title},${response.value?.detail}` - ) - ) + `signMessage returned ${response.status}: ${response.value?.title},${response.value?.detail}`, + ), + ), ), TE.map((lcResponse) => ResponseSuccessJson(lcResponse)), - TE.toUnion + TE.toUnion, )(); diff --git a/src/controllers/ioSignController.ts b/src/controllers/ioSignController.ts index 8b71d5bbf..0389b9527 100644 --- a/src/controllers/ioSignController.ts +++ b/src/controllers/ioSignController.ts @@ -3,12 +3,7 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; -import * as E from "fp-ts/Either"; -import * as t from "io-ts"; -import { sequenceS } from "fp-ts/lib/Apply"; - +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -18,42 +13,43 @@ import { ResponseErrorInternal, ResponseErrorValidation, } from "@pagopa/ts-commons/lib/responses"; - -import { pipe } from "fp-ts/lib/function"; import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import * as express from "express"; +import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; +import { sequenceS } from "fp-ts/lib/Apply"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; import { Errors } from "io-ts"; -import { - withValidatedOrValidationError, - withCatchAsInternalError, -} from "../utils/responses"; + +import { CreateFilledDocument } from "../../generated/io-sign/CreateFilledDocument"; +import { CreateSignatureBody } from "../../generated/io-sign/CreateSignatureBody"; +import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; +import { Id } from "../../generated/io-sign/Id"; import { IssuerEnvironment, IssuerEnvironmentEnum, } from "../../generated/io-sign/IssuerEnvironment"; -import IoSignService from "../services/ioSignService"; -import { ResLocals } from "../utils/express"; -import { LollipopLocalsType, withLollipopLocals } from "../types/lollipop"; -import { Id } from "../../generated/io-sign/Id"; import { QtspClausesMetadataDetailView } from "../../generated/io-sign/QtspClausesMetadataDetailView"; import { SignatureDetailView } from "../../generated/io-sign/SignatureDetailView"; import { SignatureRequestDetailView } from "../../generated/io-sign/SignatureRequestDetailView"; -import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; -import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; - -import { CreateFilledDocument } from "../../generated/io-sign/CreateFilledDocument"; -import { CreateSignatureBody } from "../../generated/io-sign/CreateSignatureBody"; - -import { withUserFromRequest } from "../types/user"; +import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; +import IoSignService from "../services/ioSignService"; import ProfileService from "../services/profileService"; - +import { LollipopLocalsType, withLollipopLocals } from "../types/lollipop"; +import { withUserFromRequest } from "../types/user"; +import { ResLocals } from "../utils/express"; import { profileWithEmailValidatedOrError } from "../utils/profile"; +import { + withCatchAsInternalError, + withValidatedOrValidationError, +} from "../utils/responses"; const responseErrorValidation = (errs: Errors) => ResponseErrorValidation( "Bad request", - errorsToReadableMessages(errs).join(" / ") + errorsToReadableMessages(errs).join(" / "), ); export const IoSignLollipopLocalsType = t.intersection([ @@ -70,7 +66,7 @@ export type IoSignLollipopLocalsType = t.TypeOf< export const withIoSignCustomLollipopLocalsFromRequest = (req: express.Request) => ( - lollipopLocals: LollipopLocalsType + lollipopLocals: LollipopLocalsType, ): E.Either => pipe( { @@ -81,24 +77,24 @@ export const withIoSignCustomLollipopLocalsFromRequest = req.headers["x-pagopa-lollipop-custom-tos-challenge"], }, IoSignLollipopLocalsType.decode, - E.mapLeft(responseErrorValidation) + E.mapLeft(responseErrorValidation), ); const responseErrorInternal = (reason: string) => (e: Error) => ResponseErrorInternal(`${reason} | ${e.message}`); const toErrorRetrievingTheSignerId = ResponseErrorInternal( - `Error retrieving the signer id for this user` + `Error retrieving the signer id for this user`, ); export const retrieveSignerId = ( ioSignService: IoSignService, - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ) => pipe( TE.tryCatch( () => ioSignService.getSignerByFiscalCode(fiscalCode), - E.toError + E.toError, ), TE.chain( TE.fromPredicate( @@ -107,30 +103,25 @@ export const retrieveSignerId = ( (e) => e.kind === "IResponseErrorNotFound" ? new Error( - `Your profile is not enabled to use this service. | ${e.detail}` + `Your profile is not enabled to use this service. | ${e.detail}`, ) : new Error( - `An error occurred while retrieving the signer id. | ${e.detail}` - ) - ) - ) + `An error occurred while retrieving the signer id. | ${e.detail}`, + ), + ), + ), ); export default class IoSignController { - constructor( - private readonly ioSignService: IoSignService, - private readonly profileService: ProfileService - ) {} - /** * Given the url of a PDF document with empty fields, * fill in the PDF form and return the url of the filled document. */ public readonly createFilledDocument = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessRedirectToResource< FilledDocumentDetailView, FilledDocumentDetailView @@ -147,30 +138,30 @@ export default class IoSignController { sequenceS(TE.ApplySeq)({ signerId: pipe( retrieveSignerId(this.ioSignService, user.fiscal_code), - TE.mapLeft(() => toErrorRetrievingTheSignerId) + TE.mapLeft(() => toErrorRetrievingTheSignerId), ), userProfile: pipe( profileWithEmailValidatedOrError(this.profileService, user), TE.mapLeft( responseErrorInternal( - "Error retrieving a user profile with validated email address" - ) - ) + "Error retrieving a user profile with validated email address", + ), + ), ), }), - TE.map(({ userProfile, signerId }) => + TE.map(({ signerId, userProfile }) => this.ioSignService.createFilledDocument( body.document_url, userProfile.email, user.family_name as NonEmptyString, user.name as NonEmptyString, - signerId.value.id - ) - ) - ) + signerId.value.id, + ), + ), + ), ), - TE.toUnion - )() + TE.toUnion, + )(), ); /** @@ -178,11 +169,11 @@ export default class IoSignController { */ public readonly createSignature = async ( req: express.Request, - locals?: T + locals?: T, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, (user) => @@ -199,15 +190,15 @@ export default class IoSignController { sequenceS(TE.ApplySeq)({ signerId: pipe( retrieveSignerId(this.ioSignService, user.fiscal_code), - TE.mapLeft(() => toErrorRetrievingTheSignerId) + TE.mapLeft(() => toErrorRetrievingTheSignerId), ), userProfile: pipe( profileWithEmailValidatedOrError(this.profileService, user), TE.mapLeft( responseErrorInternal( - "Error retrieving a user profile with validated email address" - ) - ) + "Error retrieving a user profile with validated email address", + ), + ), ), }), TE.chainW(({ signerId, userProfile }) => @@ -222,31 +213,49 @@ export default class IoSignController { email: userProfile.email, }, signerId: signerId.value.id, - })) - ) + })), + ), ), - TE.map(({ signerId, body }) => + TE.map(({ body, signerId }) => this.ioSignService.createSignature( ioSignLollipopLocals, body, - signerId - ) - ) - ) + signerId, + ), + ), + ), ), - TE.toUnion - )() + TE.toUnion, + )(), + ); + + public readonly getQtspClausesMetadata = ( + req: express.Request, + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => + withValidatedOrValidationError( + IssuerEnvironment.decode( + "x-iosign-issuer-environment" in req.headers + ? req.headers["x-iosign-issuer-environment"] + : IssuerEnvironmentEnum.TEST, + ), + this.ioSignService.getQtspClausesMetadata, + ), ); /** * Get a Signature Request from id */ public readonly getSignatureRequest = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -257,31 +266,33 @@ export default class IoSignController { Id.decode, TE.fromEither, TE.mapLeft((_) => - ResponseErrorInternal(`Error validating the signature request id`) - ) + ResponseErrorInternal( + `Error validating the signature request id`, + ), + ), ), signerId: pipe( retrieveSignerId(this.ioSignService, user.fiscal_code), TE.mapLeft(() => toErrorRetrievingTheSignerId), - TE.map((response) => response.value.id) + TE.map((response) => response.value.id), ), }), - TE.map(({ signerId, signatureRequestId: id }) => - this.ioSignService.getSignatureRequest(id, signerId) + TE.map(({ signatureRequestId: id, signerId }) => + this.ioSignService.getSignatureRequest(id, signerId), ), - TE.toUnion - )() + TE.toUnion, + )(), ); /** * Get Signature Requests list from Signer */ public readonly getSignatureRequests = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -290,25 +301,12 @@ export default class IoSignController { TE.mapLeft(() => toErrorRetrievingTheSignerId), TE.map((response) => response.value.id), TE.map((signerId) => this.ioSignService.getSignatureRequests(signerId)), - TE.toUnion - )() + TE.toUnion, + )(), ); - public readonly getQtspClausesMetadata = ( - req: express.Request - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => - withValidatedOrValidationError( - IssuerEnvironment.decode( - "x-iosign-issuer-environment" in req.headers - ? req.headers["x-iosign-issuer-environment"] - : IssuerEnvironmentEnum.TEST - ), - this.ioSignService.getQtspClausesMetadata - ) - ); + constructor( + private readonly ioSignService: IoSignService, + private readonly profileService: ProfileService, + ) {} } diff --git a/src/controllers/ioWalletController.ts b/src/controllers/ioWalletController.ts index a0c64bdb0..c3ec7d5c1 100644 --- a/src/controllers/ioWalletController.ts +++ b/src/controllers/ioWalletController.ts @@ -3,12 +3,8 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; -import * as E from "fp-ts/Either"; - +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { - getResponseErrorForbiddenNotAuthorized, IResponseErrorForbiddenNotAuthorized, IResponseErrorGeneric, IResponseErrorInternal, @@ -18,54 +14,78 @@ import { IResponseSuccessJson, IResponseSuccessNoContent, ResponseErrorValidation, + getResponseErrorForbiddenNotAuthorized, } from "@pagopa/ts-commons/lib/responses"; - -import { pipe } from "fp-ts/lib/function"; +import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; +import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; import { sequenceS } from "fp-ts/lib/Apply"; +import { pipe } from "fp-ts/lib/function"; import { Errors } from "io-ts"; -import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; -import IoWalletService from "../services/ioWalletService"; -import { NonceDetailView } from "../../generated/io-wallet/NonceDetailView"; -import { withUserFromRequest } from "../types/user"; -import { CreateWalletInstanceBody } from "../../generated/io-wallet/CreateWalletInstanceBody"; import { CreateWalletAttestationBody } from "../../generated/io-wallet/CreateWalletAttestationBody"; -import { WalletAttestationView } from "../../generated/io-wallet/WalletAttestationView"; -import { FF_IO_WALLET_TRIAL_ENABLED } from "../config"; +import { CreateWalletInstanceBody } from "../../generated/io-wallet/CreateWalletInstanceBody"; +import { NonceDetailView } from "../../generated/io-wallet/NonceDetailView"; import { SetWalletInstanceStatusBody } from "../../generated/io-wallet/SetWalletInstanceStatusBody"; +import { WalletAttestationView } from "../../generated/io-wallet/WalletAttestationView"; import { WalletInstanceData } from "../../generated/io-wallet/WalletInstanceData"; +import { FF_IO_WALLET_TRIAL_ENABLED } from "../config"; +import IoWalletService from "../services/ioWalletService"; +import { withUserFromRequest } from "../types/user"; const toValidationError = (errors: Errors) => ResponseErrorValidation( "Bad request", - `Error validating the request body: ${readableReport(errors)}` + `Error validating the request body: ${readableReport(errors)}`, ); export default class IoWalletController { - constructor(private readonly ioWalletService: IoWalletService) {} + private readonly ensureFiscalCodeIsAllowed = (fiscalCode: FiscalCode) => + FF_IO_WALLET_TRIAL_ENABLED + ? pipe( + fiscalCode, + NonEmptyString.decode, + TE.fromEither, + TE.chainW(this.ensureUserIsAllowed), + TE.mapLeft(() => + getResponseErrorForbiddenNotAuthorized( + "Not authorized to perform this action", + ), + ), + ) + : TE.right(undefined); - /** - * Get nonce - */ - public readonly getNonce = (): Promise< - | IResponseErrorInternal - | IResponseSuccessJson - | IResponseErrorServiceUnavailable - > => this.ioWalletService.getNonce(); + private readonly ensureUserIsAllowed = ( + userId: NonEmptyString, + ): TE.TaskEither => + pipe( + TE.tryCatch( + () => this.ioWalletService.getSubscription(userId), + E.toError, + ), + // if a successful response with state != "ACTIVE" or an error is returned, return left + TE.chain((response) => + response.kind === "IResponseSuccessJson" && + response.value.state === "ACTIVE" + ? TE.right(undefined) + : TE.left(new Error()), + ), + ); /** - * Create a Wallet Instance + * Create a Wallet Attestation */ - public readonly createWalletInstance = ( - req: express.Request + public readonly createWalletAttestation = ( + req: express.Request, ): Promise< - | IResponseErrorInternal - | IResponseErrorGeneric - | IResponseErrorValidation - | IResponseSuccessNoContent | IResponseErrorForbiddenNotAuthorized + | IResponseErrorGeneric + | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorServiceUnavailable + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => pipe( @@ -73,36 +93,34 @@ export default class IoWalletController { TE.chainW(() => pipe( req.body, - CreateWalletInstanceBody.decode, + CreateWalletAttestationBody.decode, E.mapLeft(toValidationError), - TE.fromEither - ) + TE.fromEither, + ), ), - TE.map(({ challenge, key_attestation, hardware_key_tag }) => - this.ioWalletService.createWalletInstance( - challenge, - hardware_key_tag, - key_attestation, - user.fiscal_code - ) + TE.map(({ assertion, grant_type }) => + this.ioWalletService.createWalletAttestation( + assertion, + grant_type, + user.fiscal_code, + ), ), - TE.toUnion - )() + TE.toUnion, + )(), ); /** - * Create a Wallet Attestation + * Create a Wallet Instance */ - public readonly createWalletAttestation = ( - req: express.Request + public readonly createWalletInstance = ( + req: express.Request, ): Promise< - | IResponseErrorInternal - | IResponseErrorGeneric - | IResponseErrorValidation | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson - | IResponseErrorNotFound + | IResponseErrorGeneric + | IResponseErrorInternal | IResponseErrorServiceUnavailable + | IResponseErrorValidation + | IResponseSuccessNoContent > => withUserFromRequest(req, async (user) => pipe( @@ -110,76 +128,77 @@ export default class IoWalletController { TE.chainW(() => pipe( req.body, - CreateWalletAttestationBody.decode, + CreateWalletInstanceBody.decode, E.mapLeft(toValidationError), - TE.fromEither - ) + TE.fromEither, + ), ), - TE.map(({ grant_type, assertion }) => - this.ioWalletService.createWalletAttestation( - assertion, - grant_type, - user.fiscal_code - ) + TE.map(({ challenge, hardware_key_tag, key_attestation }) => + this.ioWalletService.createWalletInstance( + challenge, + hardware_key_tag, + key_attestation, + user.fiscal_code, + ), ), - TE.toUnion - )() + TE.toUnion, + )(), ); /** - * Update current Wallet Instance status. + * Get nonce */ - public readonly setWalletInstanceStatus = ( - req: express.Request + public readonly getNonce = (): Promise< + | IResponseErrorInternal + | IResponseErrorServiceUnavailable + | IResponseSuccessJson + > => this.ioWalletService.getNonce(); + + /** + * Get current Wallet Instance status. + */ + public readonly getWalletInstanceStatus = ( + req: express.Request, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseSuccessNoContent + | IResponseErrorNotFound | IResponseErrorServiceUnavailable | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => pipe( this.ensureFiscalCodeIsAllowed(user.fiscal_code), TE.chainW(() => pipe( - sequenceS(E.Apply)({ - body: pipe( - req.body, - SetWalletInstanceStatusBody.decode, - E.mapLeft(toValidationError) - ), - id: pipe( - NonEmptyString.decode(req.params.walletInstanceId), - E.mapLeft(toValidationError) - ), - }), - TE.fromEither - ) + NonEmptyString.decode(req.params.walletInstanceId), + E.mapLeft(toValidationError), + TE.fromEither, + ), ), - TE.map(({ id, body: { status } }) => - this.ioWalletService.setWalletInstanceStatus( - id, - status, - user.fiscal_code - ) + TE.map((walletInstanceId) => + this.ioWalletService.getWalletInstanceStatus( + walletInstanceId, + user.fiscal_code, + ), ), - TE.toUnion - )() + TE.toUnion, + )(), ); /** * Update current Wallet Instance status. */ public readonly setCurrentWalletInstanceStatus = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorInternal + | IResponseErrorForbiddenNotAuthorized | IResponseErrorGeneric - | IResponseSuccessNoContent + | IResponseErrorInternal | IResponseErrorServiceUnavailable | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessNoContent > => withUserFromRequest(req, async (user) => pipe( @@ -189,81 +208,60 @@ export default class IoWalletController { req.body, SetWalletInstanceStatusBody.decode, E.mapLeft(toValidationError), - TE.fromEither - ) + TE.fromEither, + ), ), TE.map(({ status }) => this.ioWalletService.setCurrentWalletInstanceStatus( status, - user.fiscal_code - ) + user.fiscal_code, + ), ), - TE.toUnion - )() + TE.toUnion, + )(), ); /** - * Get current Wallet Instance status. + * Update current Wallet Instance status. */ - public readonly getWalletInstanceStatus = ( - req: express.Request + public readonly setWalletInstanceStatus = ( + req: express.Request, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseSuccessJson - | IResponseErrorNotFound | IResponseErrorServiceUnavailable | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessNoContent > => withUserFromRequest(req, async (user) => pipe( this.ensureFiscalCodeIsAllowed(user.fiscal_code), TE.chainW(() => pipe( - NonEmptyString.decode(req.params.walletInstanceId), - E.mapLeft(toValidationError), - TE.fromEither - ) + sequenceS(E.Apply)({ + body: pipe( + req.body, + SetWalletInstanceStatusBody.decode, + E.mapLeft(toValidationError), + ), + id: pipe( + NonEmptyString.decode(req.params.walletInstanceId), + E.mapLeft(toValidationError), + ), + }), + TE.fromEither, + ), ), - TE.map((walletInstanceId) => - this.ioWalletService.getWalletInstanceStatus( - walletInstanceId, - user.fiscal_code - ) + TE.map(({ body: { status }, id }) => + this.ioWalletService.setWalletInstanceStatus( + id, + status, + user.fiscal_code, + ), ), - TE.toUnion - )() + TE.toUnion, + )(), ); - private readonly ensureUserIsAllowed = ( - userId: NonEmptyString - ): TE.TaskEither => - pipe( - TE.tryCatch( - () => this.ioWalletService.getSubscription(userId), - E.toError - ), - // if a successful response with state != "ACTIVE" or an error is returned, return left - TE.chain((response) => - response.kind === "IResponseSuccessJson" && - response.value.state === "ACTIVE" - ? TE.right(undefined) - : TE.left(new Error()) - ) - ); - - private readonly ensureFiscalCodeIsAllowed = (fiscalCode: FiscalCode) => - FF_IO_WALLET_TRIAL_ENABLED - ? pipe( - fiscalCode, - NonEmptyString.decode, - TE.fromEither, - TE.chainW(this.ensureUserIsAllowed), - TE.mapLeft(() => - getResponseErrorForbiddenNotAuthorized( - "Not authorized to perform this action" - ) - ) - ) - : TE.right(undefined); + constructor(private readonly ioWalletService: IoWalletService) {} } diff --git a/src/controllers/messagesController.ts b/src/controllers/messagesController.ts index 338b8f633..8fa55a485 100644 --- a/src/controllers/messagesController.ts +++ b/src/controllers/messagesController.ts @@ -3,7 +3,7 @@ * forwarding the call to the API system. */ -import * as express from "express"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorBadGateway, IResponseErrorInternal, @@ -14,147 +14,66 @@ import { IResponseSuccessJson, IResponseSuccessNoContent, } from "@pagopa/ts-commons/lib/responses"; - -import { CreatedMessageWithContentAndAttachments } from "generated/backend/CreatedMessageWithContentAndAttachments"; import { IResponseErrorForbiddenNotAuthorized, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; -import * as t from "io-ts"; -import { pipe } from "fp-ts/lib/function"; -import * as TE from "fp-ts/TaskEither"; +import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; import * as B from "fp-ts/boolean"; -import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; -import NewMessagesService from "src/services/newMessagesService"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import { pipe } from "fp-ts/lib/function"; +import { CreatedMessageWithContentAndAttachments } from "generated/backend/CreatedMessageWithContentAndAttachments"; +import * as t from "io-ts"; import * as QueryString from "qs"; -import { User, withUserFromRequest } from "../types/user"; +import NewMessagesService from "src/services/newMessagesService"; -import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; -import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; import { PaginatedPublicMessagesCollection } from "../../generated/backend/PaginatedPublicMessagesCollection"; -import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; -import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; -import { - withValidatedOrValidationError, - IResponseSuccessOctet, - IResponseErrorNotImplemented, - IResponseErrorUnsupportedMediaType, -} from "../utils/responses"; -import { LollipopLocalsType, LollipopRequiredHeaders } from "../types/lollipop"; +import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; +import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; +import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; +import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; import { LollipopApiClient } from "../clients/lollipop"; import { ISessionStorage } from "../services/ISessionStorage"; +import { LollipopLocalsType, LollipopRequiredHeaders } from "../types/lollipop"; +import { User, withUserFromRequest } from "../types/user"; import { extractLollipopLocalsFromLollipopHeadersLegacy } from "../utils/lollipop"; import { checkIfLollipopIsEnabled } from "../utils/lollipop"; +import { + IResponseErrorNotImplemented, + IResponseErrorUnsupportedMediaType, + IResponseSuccessOctet, + withValidatedOrValidationError, +} from "../utils/responses"; export const withGetThirdPartyAttachmentParams = async ( req: express.Request, - f: (id: Ulid, attachment_url: NonEmptyString) => Promise + f: (id: Ulid, attachment_url: NonEmptyString) => Promise, ) => withValidatedOrValidationError(Ulid.decode(req.params.id), (id) => withValidatedOrValidationError( pipe( QueryString.stringify(req.query, { addQueryPrefix: true }), (queryString) => `${req.params.attachment_url}${queryString}`, - NonEmptyString.decode + NonEmptyString.decode, ), - (attachment_url) => f(id, attachment_url) - ) + (attachment_url) => f(id, attachment_url), + ), ); export default class MessagesController { - // eslint-disable-next-line max-params - constructor( - private readonly messageService: NewMessagesService, - private readonly lollipopClient: ReturnType, - private readonly sessionStorage: ISessionStorage - ) {} - - /** - * Returns the messages for the user identified by the provided fiscal code. - */ - public readonly getMessagesByUser = ( - req: express.Request - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withUserFromRequest(req, async (user) => - withValidatedOrValidationError( - GetMessagesParameters.decode({ - /* eslint-disable sort-keys */ - pageSize: req.query.page_size, - enrichResultData: req.query.enrich_result_data, - getArchivedMessages: req.query.archived, - maximumId: req.query.maximum_id, - minimumId: req.query.minimum_id, - /* eslint-enable sort-keys */ - }), - (params) => this.messageService.getMessagesByUser(user, params) - ) - ); - - /** - * Returns the message identified by the message id. - */ - public readonly getMessage = ( - req: express.Request - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withUserFromRequest(req, async (user) => - withValidatedOrValidationError( - GetMessageParameters.decode({ - id: req.params.id, - public_message: req.query.public_message, - }), - (params) => this.messageService.getMessage(user, params) - ) - ); - - public readonly upsertMessageStatus = ( - req: express.Request - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withUserFromRequest(req, async (user) => - withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => - withValidatedOrValidationError( - MessageStatusChange.decode(req.body), - (change) => - this.messageService.upsertMessageStatus( - user.fiscal_code, - messageId, - change - ) - ) - ) - ); - public readonly checkLollipopAndGetLocalsOrDefault = ( req: express.Request, user: User, - messageId: Ulid + messageId: Ulid, ) => pipe( this.messageService.getThirdPartyMessageFnApp( user.fiscal_code, - messageId + messageId, ), TE.bindTo("message"), TE.bindW("remoteContentConfiguration", ({ message }) => @@ -162,16 +81,16 @@ export default class MessagesController { message.content.third_party_data.configuration_id, TE.fromNullable( ResponseErrorInternal( - "ConfigurationId missing in ThirdPartyData, cannot get remote content configuration" - ) + "ConfigurationId missing in ThirdPartyData, cannot get remote content configuration", + ), ), TE.chain((configId) => - this.messageService.getRCConfiguration(configId) - ) - ) + this.messageService.getRCConfiguration(configId), + ), + ), ), TE.bindW("hasLollipopEnabled", ({ remoteContentConfiguration }) => - checkIfLollipopIsEnabled(user.fiscal_code, remoteContentConfiguration) + checkIfLollipopIsEnabled(user.fiscal_code, remoteContentConfiguration), ), TE.bindW("lollipopLocals", ({ hasLollipopEnabled }) => pipe( @@ -185,8 +104,8 @@ export default class MessagesController { (e) => TE.left( ResponseErrorInternal( - `Bad request ${errorsToReadableMessages(e).join(" / ")}` - ) + `Bad request ${errorsToReadableMessages(e).join(" / ")}`, + ), ), (lollipopHeaders) => pipe( @@ -194,132 +113,212 @@ export default class MessagesController { this.lollipopClient, this.sessionStorage, user.fiscal_code, - lollipopHeaders + lollipopHeaders, ), TE.mapLeft((_) => ResponseErrorInternal( - "Error extracting lollipop locals" - ) - ) - ) - ) - ) - ) - ) - ) + "Error extracting lollipop locals", + ), + ), + ), + ), + ), + ), + ), + ), ); /** - * Returns the precondition for the required third party message. + * Returns the message identified by the message id. */ - public readonly getThirdPartyMessagePrecondition = async ( - req: express.Request + public readonly getMessage = ( + req: express.Request, ): Promise< | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson + > => + withUserFromRequest(req, async (user) => + withValidatedOrValidationError( + GetMessageParameters.decode({ + id: req.params.id, + public_message: req.query.public_message, + }), + (params) => this.messageService.getMessage(user, params), + ), + ); + + /** + * Returns the messages for the user identified by the provided fiscal code. + */ + public readonly getMessagesByUser = ( + req: express.Request, + ): Promise< + | IResponseErrorInternal | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseSuccessNoContent - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => - withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => - pipe( - this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), - TE.chainW(({ message, lollipopLocals, remoteContentConfiguration }) => - TE.tryCatch( - () => - this.messageService.getThirdPartyMessagePrecondition( - message, - remoteContentConfiguration, - lollipopLocals as LollipopLocalsType - ), - (_) => - ResponseErrorInternal( - "Error getting preconditions from third party service" - ) - ) - ), - TE.toUnion - )() - ) + withValidatedOrValidationError( + GetMessagesParameters.decode({ + enrichResultData: req.query.enrich_result_data, + getArchivedMessages: req.query.archived, + maximumId: req.query.maximum_id, + minimumId: req.query.minimum_id, + /* eslint-disable sort-keys */ + pageSize: req.query.page_size, + /* eslint-enable sort-keys */ + }), + (params) => this.messageService.getMessagesByUser(user, params), + ), ); /** * Returns the Third Party message identified by the message id. */ public readonly getThirdPartyMessage = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation + | IResponseErrorBadGateway | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorBadGateway + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => pipe( this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), - TE.chainW(({ message, lollipopLocals, remoteContentConfiguration }) => + TE.chainW(({ lollipopLocals, message, remoteContentConfiguration }) => TE.tryCatch( () => this.messageService.getThirdPartyMessage( message, remoteContentConfiguration, - lollipopLocals as LollipopLocalsType + lollipopLocals as LollipopLocalsType, ), (_) => ResponseErrorInternal( - "Error getting message from third party service" - ) - ) + "Error getting message from third party service", + ), + ), ), - TE.toUnion - )() - ) + TE.toUnion, + )(), + ), ); /** * Returns the Third Party message attachments identified by the Third Party message id and the attachment relative url. */ public readonly getThirdPartyMessageAttachment = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorInternal - | IResponseErrorServiceUnavailable - | IResponseErrorValidation | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorTooManyRequests | IResponseErrorNotImplemented + | IResponseErrorServiceUnavailable + | IResponseErrorTooManyRequests | IResponseErrorUnsupportedMediaType + | IResponseErrorValidation | IResponseSuccessOctet > => withUserFromRequest(req, (user) => withGetThirdPartyAttachmentParams(req, async (messageId, attachmentUrl) => pipe( this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), - TE.chainW(({ message, lollipopLocals, remoteContentConfiguration }) => + TE.chainW(({ lollipopLocals, message, remoteContentConfiguration }) => TE.tryCatch( () => this.messageService.getThirdPartyAttachment( message, attachmentUrl, remoteContentConfiguration, - lollipopLocals as LollipopLocalsType + lollipopLocals as LollipopLocalsType, ), (_) => ResponseErrorInternal( - "Error getting attachment from third party service" - ) - ) + "Error getting attachment from third party service", + ), + ), ), - TE.toUnion - )() - ) + TE.toUnion, + )(), + ), ); + + /** + * Returns the precondition for the required third party message. + */ + public readonly getThirdPartyMessagePrecondition = async ( + req: express.Request, + ): Promise< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation + | IResponseSuccessJson + | IResponseSuccessNoContent + > => + withUserFromRequest(req, async (user) => + withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => + pipe( + this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), + TE.chainW(({ lollipopLocals, message, remoteContentConfiguration }) => + TE.tryCatch( + () => + this.messageService.getThirdPartyMessagePrecondition( + message, + remoteContentConfiguration, + lollipopLocals as LollipopLocalsType, + ), + (_) => + ResponseErrorInternal( + "Error getting preconditions from third party service", + ), + ), + ), + TE.toUnion, + )(), + ), + ); + + public readonly upsertMessageStatus = ( + req: express.Request, + ): Promise< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation + | IResponseSuccessJson + > => + withUserFromRequest(req, async (user) => + withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => + withValidatedOrValidationError( + MessageStatusChange.decode(req.body), + (change) => + this.messageService.upsertMessageStatus( + user.fiscal_code, + messageId, + change, + ), + ), + ), + ); + + // eslint-disable-next-line max-params + constructor( + private readonly messageService: NewMessagesService, + private readonly lollipopClient: ReturnType, + private readonly sessionStorage: ISessionStorage, + ) {} } diff --git a/src/controllers/notificationController.ts b/src/controllers/notificationController.ts index d884957d1..d48a7a51e 100644 --- a/src/controllers/notificationController.ts +++ b/src/controllers/notificationController.ts @@ -2,25 +2,23 @@ * This controller handles webhook requests from the API backend. */ -import * as express from "express"; import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - +import { Millisecond } from "@pagopa/ts-commons/lib/units"; +import * as express from "express"; import * as E from "fp-ts/lib/Either"; import * as TE from "fp-ts/lib/TaskEither"; -import { Millisecond } from "@pagopa/ts-commons/lib/units"; import { pipe } from "fp-ts/lib/function"; import { NotificationServiceFactory } from "src/services/notificationServiceFactory"; + import { Installation } from "../../generated/backend/Installation"; import { InstallationID } from "../../generated/backend/InstallationID"; - import { Notification } from "../../generated/notifications/Notification"; import { SuccessResponse } from "../../generated/notifications/SuccessResponse"; - import RedisSessionStorage from "../services/redisSessionStorage"; import { withUserFromRequest } from "../types/user"; import { log } from "../utils/logger"; @@ -37,14 +35,8 @@ export interface INotificationControllerOptions { } export default class NotificationController { - constructor( - private readonly notificationServiceFactory: NotificationServiceFactory, - private readonly sessionStorage: RedisSessionStorage, - private readonly opts: INotificationControllerOptions - ) {} - public readonly notify = async ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -58,9 +50,9 @@ export default class NotificationController { TE.tryCatch( () => this.sessionStorage.userHasActiveSessionsOrLV( - data.message.fiscal_code + data.message.fiscal_code, ), - E.toError + E.toError, ), TE.chain(TE.fromEither), TE.map(async (userHasActiveSessions) => @@ -68,28 +60,34 @@ export default class NotificationController { ? // send the full message only if the user has an // active session and the message content is defined await this.notificationServiceFactory( - data.message.fiscal_code + data.message.fiscal_code, ).notify(data, data.message.content.subject) : // send a generic message // if the user does not have an active session // or the message content is not defined await this.notificationServiceFactory( - data.message.fiscal_code + data.message.fiscal_code, ).notify( data, this.opts.notificationDefaultSubject, - this.opts.notificationDefaultTitle - ) + this.opts.notificationDefaultTitle, + ), ), TE.getOrElse((error) => { throw error; - }) - )() - ) + }), + )(), + ), ); + constructor( + private readonly notificationServiceFactory: NotificationServiceFactory, + private readonly sessionStorage: RedisSessionStorage, + private readonly opts: INotificationControllerOptions, + ) {} + public async createOrUpdateInstallation( - req: express.Request + req: express.Request, ): Promise> { return withUserFromRequest(req, async (user) => withValidatedOrValidationError( @@ -107,19 +105,19 @@ export default class NotificationController { delay(10000 as Millisecond) .then(() => this.notificationServiceFactory( - user.fiscal_code - ).createOrUpdateInstallation(user.fiscal_code, installation) + user.fiscal_code, + ).createOrUpdateInstallation(user.fiscal_code, installation), ) .catch((err) => { log.error( "Cannot create installation: %s", - JSON.stringify(err) + JSON.stringify(err), ); }); return ResponseSuccessJson({ message: "ok" }); - } - ) - ) + }, + ), + ), ); } } diff --git a/src/controllers/pagoPAProxyController.ts b/src/controllers/pagoPAProxyController.ts index 2de10c2bb..84544de6d 100644 --- a/src/controllers/pagoPAProxyController.ts +++ b/src/controllers/pagoPAProxyController.ts @@ -1,19 +1,17 @@ -import * as express from "express"; -import * as t from "io-ts"; import { IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - -import PagoPAProxyService from "../services/pagoPAProxyService"; +import * as express from "express"; +import * as t from "io-ts"; import { PaymentActivationsGetResponse } from "../../generated/backend/PaymentActivationsGetResponse"; import { PaymentActivationsPostResponse } from "../../generated/backend/PaymentActivationsPostResponse"; import { PaymentRequestsGetResponse } from "../../generated/backend/PaymentRequestsGetResponse"; import { PaymentActivationsPostRequest } from "../../generated/pagopa-proxy/PaymentActivationsPostRequest"; - +import PagoPAProxyService from "../services/pagoPAProxyService"; import { withValidatedOrInternalError } from "../utils/responses"; const parsePagopaTestParam = (testParam: unknown) => @@ -24,28 +22,12 @@ const parsePagopaTestParam = (testParam: unknown) => */ export default class PagoPAProxyController { - constructor(private readonly pagoPAProxyService: PagoPAProxyService) {} - - public readonly getPaymentInfo = async ( - req: express.Request - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson - > => - withValidatedOrInternalError(t.string.decode(req.params.rptId), (rptId) => - this.pagoPAProxyService.getPaymentInfo( - rptId, - parsePagopaTestParam(req.query.test) - ) - ); - public readonly activatePayment = async ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson > => withValidatedOrInternalError( @@ -53,16 +35,16 @@ export default class PagoPAProxyController { (paymentActivationsPostRequest) => this.pagoPAProxyService.activatePayment( paymentActivationsPostRequest, - parsePagopaTestParam(req.query.test) - ) + parsePagopaTestParam(req.query.test), + ), ); public readonly getActivationStatus = async ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson > => withValidatedOrInternalError( @@ -70,7 +52,23 @@ export default class PagoPAProxyController { (codiceContestoPagamento) => this.pagoPAProxyService.getActivationStatus( codiceContestoPagamento, - parsePagopaTestParam(req.query.test) - ) + parsePagopaTestParam(req.query.test), + ), ); + + public readonly getPaymentInfo = async ( + req: express.Request, + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson + > => + withValidatedOrInternalError(t.string.decode(req.params.rptId), (rptId) => + this.pagoPAProxyService.getPaymentInfo( + rptId, + parsePagopaTestParam(req.query.test), + ), + ); + + constructor(private readonly pagoPAProxyService: PagoPAProxyService) {} } diff --git a/src/controllers/pnController.ts b/src/controllers/pnController.ts index 6d73c0a1f..6ebf6c724 100644 --- a/src/controllers/pnController.ts +++ b/src/controllers/pnController.ts @@ -6,19 +6,20 @@ import { ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; +import * as TE from "fp-ts/TaskEither"; import { pipe } from "fp-ts/lib/function"; + +import { PNActivation } from "../../generated/api_piattaforma-notifiche-courtesy/PNActivation"; import { PNEnvironment } from "../clients/pn-clients"; +import { PNService } from "../services/pnService"; import { withUserFromRequest } from "../types/user"; import { IResponseNoContent, ResponseNoContent, withValidatedOrValidationError, } from "../utils/responses"; -import { PNActivation } from "../../generated/api_piattaforma-notifiche-courtesy/PNActivation"; -import { PNService } from "../services/pnService"; /** * Upsert the Activation for `Avvisi di Cortesia` Piattaforma Notifiche @@ -27,9 +28,9 @@ import { PNService } from "../services/pnService"; export const upsertPNActivationController = (upsertPnActivation: ReturnType["upsertPnActivation"]) => ( - req: express.Request + req: express.Request, ): Promise< - IResponseErrorValidation | IResponseErrorInternal | IResponseNoContent + IResponseErrorInternal | IResponseErrorValidation | IResponseNoContent > => withUserFromRequest(req, async (user) => withValidatedOrValidationError(PNActivation.decode(req.body), (payload) => @@ -39,7 +40,7 @@ export const upsertPNActivationController = O.getOrElse(() => false), TE.of, TE.map((isTest) => - isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION + isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION, ), TE.chainW((pnEnvironment) => pipe( @@ -48,14 +49,14 @@ export const upsertPNActivationController = upsertPnActivation(pnEnvironment, user.fiscal_code, { activationStatus: payload.activation_status, }), - () => ResponseErrorInternal("Error calling the PN service") + () => ResponseErrorInternal("Error calling the PN service"), ), TE.chainEitherKW( E.mapLeft(() => - ResponseErrorInternal("Unexpected PN service response") - ) - ) - ) + ResponseErrorInternal("Unexpected PN service response"), + ), + ), + ), ), TE.map((_) => { switch (_.status) { @@ -63,24 +64,24 @@ export const upsertPNActivationController = return ResponseNoContent(); case 400: return ResponseErrorInternal( - "PN service response is bad request" + "PN service response is bad request", ); default: return ResponseErrorInternal("Unexpected response status code"); } }), - TE.toUnion - )() - ) + TE.toUnion, + )(), + ), ); export const getPNActivationController = (getPnActivation: ReturnType["getPnActivation"]) => ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -90,20 +91,20 @@ export const getPNActivationController = O.getOrElse(() => false), TE.of, TE.map((isTest) => - isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION + isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION, ), TE.chainW((pnEnvironment) => pipe( TE.tryCatch( () => getPnActivation(pnEnvironment, user.fiscal_code), - () => ResponseErrorInternal("Error calling the PN service") + () => ResponseErrorInternal("Error calling the PN service"), ), TE.chainEitherKW( E.mapLeft(() => - ResponseErrorInternal("Unexpected PN service response") - ) - ) - ) + ResponseErrorInternal("Unexpected PN service response"), + ), + ), + ), ), TE.map((pnActivationResponse) => { switch (pnActivationResponse.status) { @@ -119,12 +120,12 @@ export const getPNActivationController = }); case 400: return ResponseErrorInternal( - "PN service response is bad request" + "PN service response is bad request", ); default: return ResponseErrorInternal("Unexpected response status code"); } }), - TE.toUnion - )() + TE.toUnion, + )(), ); diff --git a/src/controllers/profileController.ts b/src/controllers/profileController.ts index d579b7701..e9386fd66 100644 --- a/src/controllers/profileController.ts +++ b/src/controllers/profileController.ts @@ -3,7 +3,7 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; +import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -14,33 +14,42 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import { ISessionStorage } from "src/services/ISessionStorage"; -import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { Profile } from "../../generated/backend/Profile"; - import ProfileService from "../services/profileService"; import { profileMissingErrorResponse } from "../types/profile"; import { withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; export default class ProfileController { - constructor( - private readonly profileService: ProfileService, - private readonly sessionStorage: ISessionStorage - ) {} + /** + * Returns the profile for the user identified by the provided fiscal + * code stored into the API. + */ + public readonly getApiProfile = ( + req: express.Request, + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation + | IResponseSuccessJson + > => + withUserFromRequest(req, (user) => this.profileService.getApiProfile(user)); /** * Returns the profile for the user identified by the provided fiscal * code. */ public readonly getProfile = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => { @@ -51,33 +60,34 @@ export default class ProfileController { }); /** - * Returns the profile for the user identified by the provided fiscal - * code stored into the API. + * Send an email to start the email validation process */ - public readonly getApiProfile = ( - req: express.Request + public readonly startEmailValidationProcess = ( + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal - | IResponseErrorTooManyRequests | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorTooManyRequests + | IResponseErrorValidation + | IResponseSuccessAccepted > => - withUserFromRequest(req, (user) => this.profileService.getApiProfile(user)); + withUserFromRequest(req, async (user) => + this.profileService.emailValidationProcess(user), + ); /** * Update the preferences for the user identified by the provided * fiscal code. */ public readonly updateProfile = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseErrorInternal | IResponseErrorConflict - | IResponseErrorTooManyRequests + | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorPreconditionFailed + | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -86,23 +96,12 @@ export default class ProfileController { async (extendedProfile) => { await this.sessionStorage.delPagoPaNoticeEmail(user); return this.profileService.updateProfile(user, extendedProfile); - } - ) + }, + ), ); - /** - * Send an email to start the email validation process - */ - public readonly startEmailValidationProcess = ( - req: express.Request - ): Promise< - | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseErrorInternal - | IResponseErrorTooManyRequests - | IResponseSuccessAccepted - > => - withUserFromRequest(req, async (user) => - this.profileService.emailValidationProcess(user) - ); + constructor( + private readonly profileService: ProfileService, + private readonly sessionStorage: ISessionStorage, + ) {} } diff --git a/src/controllers/serviceAppBackendController.ts b/src/controllers/serviceAppBackendController.ts index d9cfbc869..816ea766c 100644 --- a/src/controllers/serviceAppBackendController.ts +++ b/src/controllers/serviceAppBackendController.ts @@ -7,11 +7,12 @@ import { import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; + import { FeaturedServices } from "../../generated/services-app-backend/FeaturedServices"; -import { Institutions } from "../../generated/services-app-backend/Institutions"; import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; +import { Institutions } from "../../generated/services-app-backend/Institutions"; import { InstitutionsResource } from "../../generated/services-app-backend/InstitutionsResource"; import { ScopeType } from "../../generated/services-app-backend/ScopeType"; import { ServiceDetails } from "../../generated/services-app-backend/ServiceDetails"; @@ -28,12 +29,8 @@ const parseOptionalNumberParam = (numberParam?: unknown) => numberParam ? Number(numberParam) : undefined; export default class ServicesAppBackendController { - constructor( - private readonly servicesAppBackendService: ServicesAppBackendService - ) {} - public readonly findInstitutions = async ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -45,54 +42,58 @@ export default class ServicesAppBackendController { O.fromNullable, O.foldW( () => E.right(undefined), - (scope) => ScopeType.decode(scope) - ) + (scope) => ScopeType.decode(scope), + ), ), (scope) => this.servicesAppBackendService.findInstitutions( parseOptionalStringParam(req.query.search), scope, parseOptionalNumberParam(req.query.limit), - parseOptionalNumberParam(req.query.offset) - ) + parseOptionalNumberParam(req.query.offset), + ), ); - public readonly getServiceById = async ( - req: express.Request + public readonly findInstutionServices = async ( + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withValidatedOrInternalError( - NonEmptyString.decode(req.params.serviceId), - (serviceId) => this.servicesAppBackendService.getServiceById(serviceId) + NonEmptyString.decode(req.params.institutionId), + (institutionId) => + this.servicesAppBackendService.findInstutionServices( + institutionId, + parseOptionalNumberParam(req.query.limit), + parseOptionalNumberParam(req.query.offset), + ), ); - public readonly getFeaturedServices = async ( - _req: express.Request - ): Promise> => - this.servicesAppBackendService.getFeaturedServices(); - public readonly getFeaturedInstitutions = async ( - _req: express.Request + _req: express.Request, ): Promise> => this.servicesAppBackendService.getFeaturedInstitutions(); - public readonly findInstutionServices = async ( - req: express.Request + public readonly getFeaturedServices = async ( + _req: express.Request, + ): Promise> => + this.servicesAppBackendService.getFeaturedServices(); + + public readonly getServiceById = async ( + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseSuccessJson > => withValidatedOrInternalError( - NonEmptyString.decode(req.params.institutionId), - (institutionId) => - this.servicesAppBackendService.findInstutionServices( - institutionId, - parseOptionalNumberParam(req.query.limit), - parseOptionalNumberParam(req.query.offset) - ) + NonEmptyString.decode(req.params.serviceId), + (serviceId) => this.servicesAppBackendService.getServiceById(serviceId), ); + + constructor( + private readonly servicesAppBackendService: ServicesAppBackendService, + ) {} } diff --git a/src/controllers/servicesController.ts b/src/controllers/servicesController.ts index 1697bab35..4cd797441 100644 --- a/src/controllers/servicesController.ts +++ b/src/controllers/servicesController.ts @@ -12,30 +12,27 @@ import { IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; -import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; -import { withUserFromRequest } from "../../src/types/user"; -import { withValidatedOrValidationError } from "../../src/utils/responses"; +import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; import { ServicePreference } from "../../generated/backend/ServicePreference"; import { ServicePublic } from "../../generated/backend/ServicePublic"; import { UpsertServicePreference } from "../../generated/backend/UpsertServicePreference"; - +import { withUserFromRequest } from "../../src/types/user"; +import { withValidatedOrValidationError } from "../../src/utils/responses"; import FunctionsAppService from "../services/functionAppService"; export default class ServicesController { - constructor(private readonly fnAppService: FunctionsAppService) {} - /** * Returns the service identified by the provided id * code. */ public readonly getService = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => this.fnAppService.getService(req.params.id); @@ -43,34 +40,34 @@ export default class ServicesController { * Returns the service preferences for the provided service id */ public readonly getServicePreferences = ( - req: express.Request + req: express.Request, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorConflict | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => withValidatedOrValidationError( PathTraversalSafePathParam.decode(req.params.id), (serviceId) => - this.fnAppService.getServicePreferences(user.fiscal_code, serviceId) - ) + this.fnAppService.getServicePreferences(user.fiscal_code, serviceId), + ), ); /** * Create or Update the service preferences for the provided service id */ public readonly upsertServicePreferences = ( - req: express.Request + req: express.Request, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorConflict | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -83,9 +80,11 @@ export default class ServicesController { this.fnAppService.upsertServicePreferences( user.fiscal_code, serviceId, - pref - ) - ) - ) + pref, + ), + ), + ), ); + + constructor(private readonly fnAppService: FunctionsAppService) {} } diff --git a/src/controllers/sessionController.ts b/src/controllers/sessionController.ts index a749bd119..c3fd2c0bb 100644 --- a/src/controllers/sessionController.ts +++ b/src/controllers/sessionController.ts @@ -2,7 +2,6 @@ * This controller returns data about the current user session */ -import * as express from "express"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -10,16 +9,16 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import * as E from "fp-ts/lib/Either"; + import { SessionsList } from "../../generated/backend/SessionsList"; import RedisSessionStorage from "../services/redisSessionStorage"; import { withUserFromRequest } from "../types/user"; export default class SessionController { - constructor(private readonly sessionStorage: RedisSessionStorage) {} - public readonly listSessions = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -35,4 +34,6 @@ export default class SessionController { } return ResponseSuccessJson(sessionsList.right); }); + + constructor(private readonly sessionStorage: RedisSessionStorage) {} } diff --git a/src/controllers/sessionLockController.ts b/src/controllers/sessionLockController.ts index cf4a44702..0a1ca3e1f 100644 --- a/src/controllers/sessionLockController.ts +++ b/src/controllers/sessionLockController.ts @@ -2,7 +2,7 @@ * This controller returns data about the current user session */ -import * as express from "express"; +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -15,141 +15,169 @@ import { ResponseErrorValidation, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as E from "fp-ts/lib/Either"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import { addSeconds } from "date-fns"; +import * as express from "express"; import * as AP from "fp-ts/lib/Apply"; -import * as TE from "fp-ts/lib/TaskEither"; +import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as ROA from "fp-ts/lib/ReadonlyArray"; - -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import { pipe, flow, constVoid } from "fp-ts/lib/function"; import { ReadonlyNonEmptyArray } from "fp-ts/lib/ReadonlyNonEmptyArray"; +import * as TE from "fp-ts/lib/TaskEither"; +import { constVoid, flow, pipe } from "fp-ts/lib/function"; import { OutputOf } from "io-ts"; -import { addSeconds } from "date-fns"; -import { - IResponseNoContent, - ResponseNoContent, - withValidatedOrValidationError, -} from "../utils/responses"; -import { SuccessResponse } from "../types/commons"; -import LollipopService from "../services/lollipopService"; -import { withFiscalCodeFromRequestParams } from "../types/fiscalCode"; -import RedisSessionStorage from "../services/redisSessionStorage"; -import RedisUserMetadataStorage from "../services/redisUserMetadataStorage"; -import AuthenticationLockService, { - NotReleasedAuthenticationLockData, -} from "../services/authenticationLockService"; -import { NotificationServiceFactory } from "../services/notificationServiceFactory"; -import { UserSessionInfo } from "../../generated/session/UserSessionInfo"; import { AuthLockBody } from "../../generated/session/AuthLockBody"; import { AuthUnlockBody } from "../../generated/session/AuthUnlockBody"; -import { SessionState } from "../../generated/session/SessionState"; import { TypeEnum as LoginTypeEnum } from "../../generated/session/SessionInfo"; +import { SessionState } from "../../generated/session/SessionState"; import { UnlockCode } from "../../generated/session/UnlockCode"; +import { UserSessionInfo } from "../../generated/session/UserSessionInfo"; +import AuthenticationLockService, { + NotReleasedAuthenticationLockData, +} from "../services/authenticationLockService"; +import LollipopService from "../services/lollipopService"; +import { NotificationServiceFactory } from "../services/notificationServiceFactory"; +import RedisSessionStorage from "../services/redisSessionStorage"; +import RedisUserMetadataStorage from "../services/redisUserMetadataStorage"; +import { SuccessResponse } from "../types/commons"; +import { withFiscalCodeFromRequestParams } from "../types/fiscalCode"; +import { + IResponseNoContent, + ResponseNoContent, + withValidatedOrValidationError, +} from "../utils/responses"; const ERROR_CHECK_USER_AUTH_LOCK = "Something went wrong while checking the user authentication lock"; export const withUnlockCodeParams = async ( req: express.Request, - f: (authLockBody: AuthLockBody) => Promise + f: (authLockBody: AuthLockBody) => Promise, ) => withValidatedOrValidationError(AuthLockBody.decode(req.body), (unlockCode) => - f(unlockCode) + f(unlockCode), ); export const withAuthUnlockBodyParams = async ( req: express.Request, - f: (authLockBody: AuthUnlockBody) => Promise + f: (authLockBody: AuthUnlockBody) => Promise, ) => withValidatedOrValidationError( AuthUnlockBody.decode(req.body), - (unlockCode) => f(unlockCode) + (unlockCode) => f(unlockCode), ); export default class SessionLockController { - constructor( - private readonly sessionStorage: RedisSessionStorage, - private readonly metadataStorage: RedisUserMetadataStorage, - private readonly lollipopService: LollipopService, - private readonly authenticationLockService: AuthenticationLockService, - private readonly notificationServiceFactory: NotificationServiceFactory - ) {} + private readonly buildInvalidateUserSessionTask = (fiscalCode: FiscalCode) => + [ + // revoke pubkey + pipe( + TE.tryCatch( + () => + // retrieve the assertionRef for the user + this.sessionStorage.getLollipopAssertionRefForUser(fiscalCode), + E.toError, + ), + TE.chain(TE.fromEither), + TE.chain( + flow( + O.map((assertionRef) => + TE.tryCatch( + () => + // fire and forget the queue message + new Promise((resolve) => { + this.lollipopService + .revokePreviousAssertionRef(assertionRef) + .catch(constVoid); + resolve(true); + }), + E.toError, + ), + ), + // continue if there's no assertionRef on redis + O.getOrElse(() => TE.of(true)), + ), + ), + ), + // delete the assertionRef for the user + pipe( + TE.tryCatch( + () => this.sessionStorage.delLollipopDataForUser(fiscalCode), + E.toError, + ), + TE.chain(TE.fromEither), + ), + // removes all sessions + pipe( + TE.tryCatch( + () => this.sessionStorage.delUserAllSessions(fiscalCode), + E.toError, + ), + TE.chain(TE.fromEither), + ), + ] as const; - /** - * Get a user session info - * - * @param req expects fiscal_code as a path param - * - * @returns a promise with the encoded User Session response - */ - public readonly getUserSession = ( - req: express.Request - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson - > => + private readonly clearInstallation = (fiscalCode: FiscalCode) => pipe( - req.params.fiscal_code, - FiscalCode.decode, - E.mapLeft((err) => - ResponseErrorValidation("Invalid Fiscal Code", readableReport(err)) + TE.tryCatch( + () => + this.notificationServiceFactory(fiscalCode).deleteInstallation( + fiscalCode, + ), + (err) => + Error( + `Cannot delete Notification Installation: ${JSON.stringify(err)}`, + ), ), - TE.fromEither, - TE.chainW((fiscalCode) => - pipe( - TE.tryCatch( - () => this.sessionStorage.userHasActiveSessionsOrLV(fiscalCode), - E.toError + TE.chain( + flow( + TE.fromPredicate( + (response) => response.kind === "IResponseSuccessJson", + (err) => + Error( + `Cannot delete Notification Installation: ${ + err.detail ?? "Not Defined" + }`, + ), ), - TE.chain(TE.fromEither), - TE.mapLeft((e) => ResponseErrorInternal(`${e.message} [${e}]`)) - ) + TE.map(() => true), + ), ), - TE.map((active) => UserSessionInfo.encode({ active })), - TE.map(ResponseSuccessJson), - TE.toUnion - )(); + ); - /** - * Lock a user account and clear all its session data - * - * @param req expects fiscal_code as a path param - * - * @returns a promise with the encoded response object - */ - public readonly lockUserSession = ( - req: express.Request - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson + private readonly unlockuserAuthenticationLockData = ( + fiscalCode: FiscalCode, + maybeUnlockCode: O.Option, + authLockData: ReadonlyNonEmptyArray, + ): TE.TaskEither< + IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, + true > => - withFiscalCodeFromRequestParams(req, (fiscalCode) => - pipe( - AP.sequenceT(TE.ApplicativeSeq)( - // lock the account - pipe( - TE.tryCatch( - () => this.sessionStorage.setBlockedUser(fiscalCode), - E.toError - ), - TE.chain(TE.fromEither) + pipe( + {}, + TE.fromPredicate( + () => + O.isNone(maybeUnlockCode) || + authLockData.some((data) => data.rowKey === maybeUnlockCode.value), + () => ResponseErrorForbiddenNotAuthorized, + ), + TE.map(() => + O.isSome(maybeUnlockCode) + ? [maybeUnlockCode.value] + : authLockData.map((data) => data.rowKey), + ), + TE.chainW((codesToUnlock) => + pipe( + this.authenticationLockService.unlockUserAuthentication( + fiscalCode, + codesToUnlock, + ), + TE.mapLeft(() => + ResponseErrorInternal("Error releasing user authentication lock"), ), - ...this.buildInvalidateUserSessionTask(fiscalCode), - // removes all metadata - pipe( - TE.tryCatch(() => this.metadataStorage.del(fiscalCode), E.toError), - TE.chain(TE.fromEither) - ) ), - TE.mapLeft((err) => ResponseErrorInternal(err.message)), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), - TE.toUnion - )() + ), ); /** @@ -161,7 +189,7 @@ export default class SessionLockController { * @returns a promise with the encoded response object */ public readonly deleteUserSession = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -170,50 +198,102 @@ export default class SessionLockController { withFiscalCodeFromRequestParams(req, (fiscalCode) => pipe( ROA.sequence(TE.ApplicativeSeq)( - this.buildInvalidateUserSessionTask(fiscalCode) + this.buildInvalidateUserSessionTask(fiscalCode), ), TE.mapLeft((err) => ResponseErrorInternal(err.message)), TE.map((_) => ResponseSuccessJson({ message: "ok" })), - TE.toUnion - )() + TE.toUnion, + )(), ); /** - * Unlock a user account + * Get a user session info * * @param req expects fiscal_code as a path param * - * @returns a promise with the encoded response object + * @returns a promise with the encoded User Session response */ - public readonly unlockUserSession = ( - req: express.Request + public readonly getUserSession = ( + req: express.Request, ): Promise< | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => pipe( req.params.fiscal_code, FiscalCode.decode, E.mapLeft((err) => - ResponseErrorValidation("Invalid fiscal code", readableReport(err)) + ResponseErrorValidation("Invalid Fiscal Code", readableReport(err)), ), TE.fromEither, TE.chainW((fiscalCode) => - // unlock the account pipe( TE.tryCatch( - () => this.sessionStorage.unsetBlockedUser(fiscalCode), - E.toError + () => this.sessionStorage.userHasActiveSessionsOrLV(fiscalCode), + E.toError, ), TE.chain(TE.fromEither), - TE.mapLeft((err) => ResponseErrorInternal(err.message)) - ) + TE.mapLeft((e) => ResponseErrorInternal(`${e.message} [${e}]`)), + ), ), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), - TE.toUnion + TE.map((active) => UserSessionInfo.encode({ active })), + TE.map(ResponseSuccessJson), + TE.toUnion, )(); + public readonly getUserSessionState = ( + req: express.Request, + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson> + > => + withFiscalCodeFromRequestParams(req, (fiscalCode) => + pipe( + AP.sequenceS(TE.ApplicativePar)({ + isUserAuthenticationLocked: pipe( + this.authenticationLockService.isUserAuthenticationLocked( + fiscalCode, + ), + TE.mapLeft((_) => + ResponseErrorInternal( + `Error reading the auth lock info: [${_.message}]`, + ), + ), + ), + maybeSessionRemaningTTL: pipe( + this.sessionStorage.getSessionRemainingTTL(fiscalCode), + TE.mapLeft((err) => + ResponseErrorInternal( + `Error reading the session info: [${err.message}]`, + ), + ), + ), + }), + TE.map(({ isUserAuthenticationLocked, maybeSessionRemaningTTL }) => + O.isNone(maybeSessionRemaningTTL) + ? SessionState.encode({ + access_enabled: !isUserAuthenticationLocked, + session_info: { active: false }, + }) + : SessionState.encode({ + access_enabled: !isUserAuthenticationLocked, + session_info: { + active: true, + expiration_date: addSeconds( + new Date(), + maybeSessionRemaningTTL.value.ttl, + ), + type: LoginTypeEnum[maybeSessionRemaningTTL.value.type], + }, + }), + ), + TE.map(ResponseSuccessJson), + TE.toUnion, + )(), + ); + /** * Release a lock previously set by the user * @@ -222,11 +302,11 @@ export default class SessionLockController { * @returns a promise with the encoded response object */ public readonly lockUserAuthentication = ( - req: express.Request + req: express.Request, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorConflict | IResponseNoContent > => withFiscalCodeFromRequestParams(req, (fiscalCode) => @@ -239,8 +319,8 @@ export default class SessionLockController { (isUserAuthenticationLocked) => !isUserAuthenticationLocked, () => ResponseErrorConflict( - "Another user authentication lock has already been applied" - ) + "Another user authentication lock has already been applied", + ), ), TE.chainW((_) => pipe( @@ -253,18 +333,60 @@ export default class SessionLockController { // if clean up went well, lock user session this.authenticationLockService.lockUserAuthentication( fiscalCode, - authLockBody.unlock_code - ) + authLockBody.unlock_code, + ), ), - TE.mapLeft((err) => ResponseErrorInternal(err.message)) - ) + TE.mapLeft((err) => ResponseErrorInternal(err.message)), + ), ), TE.map((_) => ResponseNoContent()), - TE.toUnion - )() - ) + TE.toUnion, + )(), + ), ); + /** + * Lock a user account and clear all its session data + * + * @param req expects fiscal_code as a path param + * + * @returns a promise with the encoded response object + */ + public readonly lockUserSession = ( + req: express.Request, + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson + > => + withFiscalCodeFromRequestParams(req, (fiscalCode) => + pipe( + AP.sequenceT(TE.ApplicativeSeq)( + // lock the account + pipe( + TE.tryCatch( + () => this.sessionStorage.setBlockedUser(fiscalCode), + E.toError, + ), + TE.chain(TE.fromEither), + ), + ...this.buildInvalidateUserSessionTask(fiscalCode), + // removes all metadata + pipe( + TE.tryCatch(() => this.metadataStorage.del(fiscalCode), E.toError), + TE.chain(TE.fromEither), + ), + ), + TE.mapLeft((err) => ResponseErrorInternal(err.message)), + TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.toUnion, + )(), + ); + + // ------------------------------ + // private methods + // ------------------------------ + /** * Lock a user authentication and clear all its session data * @@ -273,10 +395,10 @@ export default class SessionLockController { * @returns a promise with the encoded response object */ public readonly unlockUserAuthentication = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal | IResponseErrorValidation | IResponseNoContent > => @@ -290,12 +412,12 @@ export default class SessionLockController { TE.bind("authLockData", () => pipe( this.authenticationLockService.getUserAuthenticationLockData( - fiscalCode + fiscalCode, ), TE.mapLeft((_) => - ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK) - ) - ) + ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK), + ), + ), ), TE.chainW(({ authLockData, maybeUnlockCode }) => ROA.isNonEmpty(authLockData) @@ -303,181 +425,58 @@ export default class SessionLockController { this.unlockuserAuthenticationLockData( fiscalCode, maybeUnlockCode, - authLockData + authLockData, ) : // User auth is NOT locked - TE.of(true) + TE.of(true), ), TE.map((_) => ResponseNoContent()), - TE.toUnion - )() - ) + TE.toUnion, + )(), + ), ); - public readonly getUserSessionState = ( - req: express.Request + /** + * Unlock a user account + * + * @param req expects fiscal_code as a path param + * + * @returns a promise with the encoded response object + */ + public readonly unlockUserSession = ( + req: express.Request, ): Promise< | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessJson> - > => - withFiscalCodeFromRequestParams(req, (fiscalCode) => - pipe( - AP.sequenceS(TE.ApplicativePar)({ - isUserAuthenticationLocked: pipe( - this.authenticationLockService.isUserAuthenticationLocked( - fiscalCode - ), - TE.mapLeft((_) => - ResponseErrorInternal( - `Error reading the auth lock info: [${_.message}]` - ) - ) - ), - maybeSessionRemaningTTL: pipe( - this.sessionStorage.getSessionRemainingTTL(fiscalCode), - TE.mapLeft((err) => - ResponseErrorInternal( - `Error reading the session info: [${err.message}]` - ) - ) - ), - }), - TE.map(({ isUserAuthenticationLocked, maybeSessionRemaningTTL }) => - O.isNone(maybeSessionRemaningTTL) - ? SessionState.encode({ - access_enabled: !isUserAuthenticationLocked, - session_info: { active: false }, - }) - : SessionState.encode({ - access_enabled: !isUserAuthenticationLocked, - session_info: { - active: true, - expiration_date: addSeconds( - new Date(), - maybeSessionRemaningTTL.value.ttl - ), - type: LoginTypeEnum[maybeSessionRemaningTTL.value.type], - }, - }) - ), - TE.map(ResponseSuccessJson), - TE.toUnion - )() - ); - - // ------------------------------ - // private methods - // ------------------------------ - - private readonly buildInvalidateUserSessionTask = (fiscalCode: FiscalCode) => - [ - // revoke pubkey - pipe( - TE.tryCatch( - () => - // retrieve the assertionRef for the user - this.sessionStorage.getLollipopAssertionRefForUser(fiscalCode), - E.toError - ), - TE.chain(TE.fromEither), - TE.chain( - flow( - O.map((assertionRef) => - TE.tryCatch( - () => - // fire and forget the queue message - new Promise((resolve) => { - this.lollipopService - .revokePreviousAssertionRef(assertionRef) - .catch(constVoid); - resolve(true); - }), - E.toError - ) - ), - // continue if there's no assertionRef on redis - O.getOrElse(() => TE.of(true)) - ) - ) - ), - // delete the assertionRef for the user - pipe( - TE.tryCatch( - () => this.sessionStorage.delLollipopDataForUser(fiscalCode), - E.toError - ), - TE.chain(TE.fromEither) - ), - // removes all sessions - pipe( - TE.tryCatch( - () => this.sessionStorage.delUserAllSessions(fiscalCode), - E.toError - ), - TE.chain(TE.fromEither) - ), - ] as const; - - private readonly clearInstallation = (fiscalCode: FiscalCode) => - pipe( - TE.tryCatch( - () => - this.notificationServiceFactory(fiscalCode).deleteInstallation( - fiscalCode - ), - (err) => - Error( - `Cannot delete Notification Installation: ${JSON.stringify(err)}` - ) - ), - TE.chain( - flow( - TE.fromPredicate( - (response) => response.kind === "IResponseSuccessJson", - (err) => - Error( - `Cannot delete Notification Installation: ${ - err.detail ?? "Not Defined" - }` - ) - ), - TE.map(() => true) - ) - ) - ); - - private readonly unlockuserAuthenticationLockData = ( - fiscalCode: FiscalCode, - maybeUnlockCode: O.Option, - authLockData: ReadonlyNonEmptyArray - ): TE.TaskEither< - IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, - true + | IResponseSuccessJson > => pipe( - {}, - TE.fromPredicate( - () => - O.isNone(maybeUnlockCode) || - authLockData.some((data) => data.rowKey === maybeUnlockCode.value), - () => ResponseErrorForbiddenNotAuthorized - ), - TE.map(() => - O.isSome(maybeUnlockCode) - ? [maybeUnlockCode.value] - : authLockData.map((data) => data.rowKey) + req.params.fiscal_code, + FiscalCode.decode, + E.mapLeft((err) => + ResponseErrorValidation("Invalid fiscal code", readableReport(err)), ), - TE.chainW((codesToUnlock) => + TE.fromEither, + TE.chainW((fiscalCode) => + // unlock the account pipe( - this.authenticationLockService.unlockUserAuthentication( - fiscalCode, - codesToUnlock + TE.tryCatch( + () => this.sessionStorage.unsetBlockedUser(fiscalCode), + E.toError, ), - TE.mapLeft(() => - ResponseErrorInternal("Error releasing user authentication lock") - ) - ) - ) - ); + TE.chain(TE.fromEither), + TE.mapLeft((err) => ResponseErrorInternal(err.message)), + ), + ), + TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.toUnion, + )(); + + constructor( + private readonly sessionStorage: RedisSessionStorage, + private readonly metadataStorage: RedisUserMetadataStorage, + private readonly lollipopService: LollipopService, + private readonly authenticationLockService: AuthenticationLockService, + private readonly notificationServiceFactory: NotificationServiceFactory, + ) {} } diff --git a/src/controllers/ssoController.ts b/src/controllers/ssoController.ts index 26fdc8642..e40f0b029 100644 --- a/src/controllers/ssoController.ts +++ b/src/controllers/ssoController.ts @@ -1,13 +1,14 @@ /** * This controller handles requests made from MyPortal. */ -import { Request } from "express"; import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; +import { Request } from "express"; + import { MyPortalUser } from "../../generated/myportal/MyPortalUser"; import { withUserFromRequest } from "../types/user"; import { withValidatedOrInternalError } from "../utils/responses"; @@ -17,10 +18,10 @@ import { withValidatedOrInternalError } from "../utils/responses"; * code. */ export const getUserForMyPortal = ( - req: Request + req: Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -30,6 +31,6 @@ export const getUserForMyPortal = ( fiscal_code: user.fiscal_code, name: user.name, }), - (_) => ResponseSuccessJson(_) - ) + (_) => ResponseSuccessJson(_), + ), ); diff --git a/src/controllers/trialController.ts b/src/controllers/trialController.ts index 273a4e773..a304015a4 100644 --- a/src/controllers/trialController.ts +++ b/src/controllers/trialController.ts @@ -3,7 +3,6 @@ * forwarding the call to the API system. */ -import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -14,31 +13,28 @@ import { IResponseSuccessRedirectToResource, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import TrialService from "src/services/trialService"; + +import { Subscription } from "../../generated/trial-system/Subscription"; +import { SubscriptionStateEnum } from "../../generated/trial-system/SubscriptionState"; +import { TrialId } from "../../generated/trial-system-api/TrialId"; import { FF_IO_WALLET_TRIAL_ENABLED, IO_WALLET_TRIAL_ID, } from "../../src/config"; -import { TrialId } from "../../generated/trial-system-api/TrialId"; import { withUserFromRequest } from "../types/user"; - import { withValidatedOrValidationError } from "../utils/responses"; -import { Subscription } from "../../generated/trial-system/Subscription"; -import { SubscriptionStateEnum } from "../../generated/trial-system/SubscriptionState"; export default class TrialController { - // eslint-disable-next-line max-params - constructor(private readonly trialService: TrialService) {} - public readonly createTrialSubscription = ( - req: express.Request + req: express.Request, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorConflict + | IResponseErrorValidation | IResponseSuccessAccepted | IResponseSuccessRedirectToResource > => @@ -48,17 +44,17 @@ export default class TrialController { (trialId) => withValidatedOrValidationError( NonEmptyString.decode(user.fiscal_code), - (userId) => this.trialService.createSubscription(userId, trialId) - ) - ) + (userId) => this.trialService.createSubscription(userId, trialId), + ), + ), ); public readonly getTrialSubscription = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -69,15 +65,18 @@ export default class TrialController { trialId !== IO_WALLET_TRIAL_ID || FF_IO_WALLET_TRIAL_ENABLED ? withValidatedOrValidationError( NonEmptyString.decode(user.fiscal_code), - (userId) => this.trialService.getSubscription(userId, trialId) + (userId) => this.trialService.getSubscription(userId, trialId), ) : Promise.resolve( ResponseSuccessJson({ createdAt: new Date(), state: SubscriptionStateEnum.ACTIVE, trialId, - }) - ) - ) + }), + ), + ), ); + + // eslint-disable-next-line max-params + constructor(private readonly trialService: TrialService) {} } diff --git a/src/controllers/userDataProcessingController.ts b/src/controllers/userDataProcessingController.ts index d088bb567..575921b45 100644 --- a/src/controllers/userDataProcessingController.ts +++ b/src/controllers/userDataProcessingController.ts @@ -3,7 +3,6 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -13,6 +12,7 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import { UserDataProcessing } from "../../generated/backend/UserDataProcessing"; import { UserDataProcessingChoice } from "../../generated/backend/UserDataProcessingChoice"; @@ -22,32 +22,28 @@ import { withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; export default class UserDataProcessingController { - constructor( - private readonly userDataProcessingService: UserDataProcessingService - ) {} - /** - * upsert a user data processing request for the user identified by the provided - * fiscal code. + * Abort the user data processing of a specific user. */ - public readonly upsertUserDataProcessing = ( - req: express.Request + public readonly abortUserDataProcessing = ( + req: express.Request, ): Promise< - | IResponseErrorValidation + | IResponseErrorConflict | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorConflict - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessAccepted > => withUserFromRequest(req, async (user) => withValidatedOrValidationError( - UserDataProcessingChoiceRequest.decode(req.body), + UserDataProcessingChoice.decode(req.params.choice), (dataProcessingChoice) => - this.userDataProcessingService.upsertUserDataProcessing( + this.userDataProcessingService.abortUserDataProcessing( user, - dataProcessingChoice - ) - ) + dataProcessingChoice, + ), + ), ); /** @@ -55,12 +51,12 @@ export default class UserDataProcessingController { * fiscal code and userDataProcessing choice. */ public readonly getUserDataProcessing = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation - | IResponseErrorNotFound | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -69,32 +65,36 @@ export default class UserDataProcessingController { (dataProcessingChoice) => this.userDataProcessingService.getUserDataProcessing( user, - dataProcessingChoice - ) - ) + dataProcessingChoice, + ), + ), ); /** - * Abort the user data processing of a specific user. + * upsert a user data processing request for the user identified by the provided + * fiscal code. */ - public readonly abortUserDataProcessing = ( - req: express.Request + public readonly upsertUserDataProcessing = ( + req: express.Request, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorTooManyRequests - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseErrorConflict - | IResponseSuccessAccepted + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => withValidatedOrValidationError( - UserDataProcessingChoice.decode(req.params.choice), + UserDataProcessingChoiceRequest.decode(req.body), (dataProcessingChoice) => - this.userDataProcessingService.abortUserDataProcessing( + this.userDataProcessingService.upsertUserDataProcessing( user, - dataProcessingChoice - ) - ) + dataProcessingChoice, + ), + ), ); + + constructor( + private readonly userDataProcessingService: UserDataProcessingService, + ) {} } diff --git a/src/controllers/userMetadataController.ts b/src/controllers/userMetadataController.ts index 979e433b3..1cfdfc007 100644 --- a/src/controllers/userMetadataController.ts +++ b/src/controllers/userMetadataController.ts @@ -3,7 +3,6 @@ * redis database through the user metadata storage service. */ -import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -13,9 +12,8 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - +import * as express from "express"; import * as E from "fp-ts/lib/Either"; -import { IResponseNoContent, ResponseNoContent } from "../utils/responses"; import { UserMetadata } from "../../generated/backend/UserMetadata"; import { IUserMetadataStorage } from "../services/IUserMetadataStorage"; @@ -24,19 +22,18 @@ import { metadataNotFoundError, } from "../services/redisUserMetadataStorage"; import { withUserFromRequest } from "../types/user"; +import { IResponseNoContent, ResponseNoContent } from "../utils/responses"; import { withValidatedOrValidationError } from "../utils/responses"; export default class UserMetadataController { - constructor(private readonly userMetadataStorage: IUserMetadataStorage) {} - /** * Returns the metadata for the current authenticated user. */ public readonly getMetadata = ( - req: express.Request + req: express.Request, ): Promise< - | IResponseErrorValidation | IResponseErrorInternal + | IResponseErrorValidation | IResponseNoContent | IResponseSuccessJson > => @@ -58,11 +55,11 @@ export default class UserMetadataController { * Story https://www.pivotaltracker.com/story/show/167064659 */ public readonly upsertMetadata = ( - req: express.Request + req: express.Request, ): Promise< | IResponseErrorConflict - | IResponseErrorValidation | IResponseErrorInternal + | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -71,7 +68,7 @@ export default class UserMetadataController { async (metadata) => { const setMetadataResponse = await this.userMetadataStorage.set( user, - metadata + metadata, ); if (E.isLeft(setMetadataResponse)) { if (setMetadataResponse.left === invalidVersionNumberError) { @@ -80,7 +77,9 @@ export default class UserMetadataController { return ResponseErrorInternal(setMetadataResponse.left.message); } return ResponseSuccessJson(metadata); - } - ) + }, + ), ); + + constructor(private readonly userMetadataStorage: IUserMetadataStorage) {} } diff --git a/src/server.ts b/src/server.ts index 3b2731d63..9f0269d1b 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,17 +1,18 @@ /** * Main entry point for the Digital Citizenship proxy. */ -import * as http from "http"; -import * as https from "https"; -import * as fs from "fs"; -import * as path from "path"; -import * as appInsights from "applicationinsights"; -import * as O from "fp-ts/lib/Option"; +import { withApplicationInsight } from "@pagopa/io-functions-commons/dist/src/utils/transports/application_insight"; import { NodeEnvironmentEnum } from "@pagopa/ts-commons/lib/environment"; -import { pipe } from "fp-ts/lib/function"; import { useWinstonFor } from "@pagopa/winston-ts"; import { LoggerId } from "@pagopa/winston-ts/dist/types/logging"; -import { withApplicationInsight } from "@pagopa/io-functions-commons/dist/src/utils/transports/application_insight"; +import * as appInsights from "applicationinsights"; +import * as O from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; +import * as fs from "fs"; +import * as http from "http"; +import * as https from "https"; +import * as path from "path"; + import { newApp } from "./app"; import { ALLOW_MYPORTAL_IP_SOURCE_RANGE, @@ -34,11 +35,10 @@ import { TRIAL_SYSTEM_API_BASE_PATH, } from "./config"; import { - initAppInsights, StartupEventName, + initAppInsights, trackStartupTime, } from "./utils/appinsights"; - import { initHttpGracefulShutdown } from "./utils/gracefulShutdown"; import { log } from "./utils/logger"; import { getCurrentBackendVersion } from "./utils/package"; @@ -68,7 +68,6 @@ const shutdownTimeout: number = process.env.DEFAULT_SHUTDOWN_TIMEOUT_MILLIS ? parseInt(process.env.DEFAULT_SHUTDOWN_TIMEOUT_MILLIS, 10) : DEFAULT_SHUTDOWN_TIMEOUT_MILLIS; -// eslint-disable-next-line functional/no-let let server: http.Server | https.Server; const timer = TimeTracer(); @@ -90,16 +89,16 @@ const maybeAppInsightsClient = pipe( samplingPercentage: process.env.APPINSIGHTS_SAMPLING_PERCENTAGE ? parseInt(process.env.APPINSIGHTS_SAMPLING_PERCENTAGE, 10) : DEFAULT_APPINSIGHTS_SAMPLING_PERCENTAGE, - }) + }), ), O.chainFirst((telemetryClient) => O.some( useWinstonFor({ loggerId: LoggerId.event, transports: [withApplicationInsight(telemetryClient, "io-backend")], - }) - ) - ) + }), + ), + ), ); newApp({ @@ -131,11 +130,11 @@ newApp({ const certPath = path.resolve(__dirname, "../../certs"); const privateKey = fs.readFileSync( path.join(certPath, "key.pem"), - "utf8" + "utf8", ); const certificate = fs.readFileSync( path.join(certPath, "cert.pem"), - "utf8" + "utf8", ); const options = { cert: certificate, key: privateKey }; server = https.createServer(options, app).listen(443, () => { @@ -144,8 +143,8 @@ newApp({ pipe( maybeAppInsightsClient, O.map((_) => - trackStartupTime(_, StartupEventName.SERVER, startupTimeMs) - ) + trackStartupTime(_, StartupEventName.SERVER, startupTimeMs), + ), ); }); } else { @@ -156,8 +155,8 @@ newApp({ pipe( maybeAppInsightsClient, O.map((_) => - trackStartupTime(_, StartupEventName.SERVER, startupTimeMs) - ) + trackStartupTime(_, StartupEventName.SERVER, startupTimeMs), + ), ); }); } @@ -168,7 +167,7 @@ newApp({ O.map((appInsightsClient) => { appInsightsClient.flush(); appInsights.dispose(); - }) + }), ); log.info("HTTP server close."); }); diff --git a/src/services/IPagoPAClientFactory.ts b/src/services/IPagoPAClientFactory.ts index a70a6f353..047fc0eb8 100644 --- a/src/services/IPagoPAClientFactory.ts +++ b/src/services/IPagoPAClientFactory.ts @@ -13,6 +13,6 @@ export interface IPagoPAClientFactoryInterface { * Retrieves a configured instance of the API client. */ readonly getClient: ( - environment: PagoPAEnvironment + environment: PagoPAEnvironment, ) => ReturnType; } diff --git a/src/services/ISessionStorage.ts b/src/services/ISessionStorage.ts index a34f09651..ed31a76bf 100644 --- a/src/services/ISessionStorage.ts +++ b/src/services/ISessionStorage.ts @@ -2,30 +2,51 @@ * Interface for the session storage services. */ +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; + import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; +import { LollipopData } from "../types/assertionRef"; import { MyPortalToken, SessionToken } from "../types/token"; import { User } from "../types/user"; -import { LollipopData } from "../types/assertionRef"; import { ActiveSessionInfo } from "../utils/fastLogin"; export interface ISessionStorage { /** - * Retrieves a value from the cache using the session token. + * Removes a value from the cache. */ - readonly getBySessionToken: ( - token: SessionToken - ) => Promise>>; + readonly del: (user: User) => Promise>; + + /** + * Delete the Lollipop assertionRef related to an user + * + * @param fiscalCode A user fiscal code + */ + readonly delLollipopDataForUser: ( + fiscalCode: FiscalCode, + ) => Promise>; + + readonly delPagoPaNoticeEmail: (user: User) => Promise>; + + readonly delUserAllSessions: ( + fiscalCode: FiscalCode, + ) => Promise>; /** * Retrieves a value from the cache using the myportal token. */ readonly getByMyPortalToken: ( - token: MyPortalToken + token: MyPortalToken, + ) => Promise>>; + + /** + * Retrieves a value from the cache using the session token. + */ + readonly getBySessionToken: ( + token: SessionToken, ) => Promise>>; /** @@ -35,7 +56,7 @@ export interface ISessionStorage { * @param fiscalCode The fiscalCode value used to get the related assertionRef */ readonly getLollipopAssertionRefForUser: ( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ) => Promise>>; /** @@ -44,29 +65,9 @@ export interface ISessionStorage { * @param fiscalCode The fiscalCode value used to get the related assertionRef */ readonly getLollipopDataForUser: ( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ) => Promise>>; - /** - * Delete the Lollipop assertionRef related to an user - * - * @param fiscalCode A user fiscal code - */ - readonly delLollipopDataForUser: ( - fiscalCode: FiscalCode - ) => Promise>; - - /** - * Removes a value from the cache. - */ - readonly del: (user: User) => Promise>; - - readonly delPagoPaNoticeEmail: (user: User) => Promise>; - - readonly delUserAllSessions: ( - fiscalCode: FiscalCode - ) => Promise>; - /** * Retrieve the remining TTL for the CF-AssertionRef record * and the Login Type (`LEGACY` of `LV`). @@ -77,6 +78,6 @@ export interface ISessionStorage { * @param fiscalCode */ readonly getSessionRemainingTTL: ( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ) => TE.TaskEither>; } diff --git a/src/services/IUserMetadataStorage.ts b/src/services/IUserMetadataStorage.ts index 6b60ba278..5b033966c 100644 --- a/src/services/IUserMetadataStorage.ts +++ b/src/services/IUserMetadataStorage.ts @@ -4,19 +4,20 @@ import { Either } from "fp-ts/lib/Either"; import { UserMetadata } from "generated/backend/UserMetadata"; + import { User } from "../types/user"; export interface IUserMetadataStorage { + /** + * Retrieves User Metadata information from Redis Storage + */ + readonly get: (user: User) => Promise>; + /** * Stores a User Metadata information into Redis Storage */ readonly set: ( user: User, - payload: UserMetadata + payload: UserMetadata, ) => Promise>; - - /** - * Retrieves User Metadata information from Redis Storage - */ - readonly get: (user: User) => Promise>; } diff --git a/src/services/apiClientFactory.ts b/src/services/apiClientFactory.ts index adc9acb49..e370a8358 100644 --- a/src/services/apiClientFactory.ts +++ b/src/services/apiClientFactory.ts @@ -15,7 +15,7 @@ export default class ApiClientFactory implements IApiClientFactoryInterface { apiKey: string, apiUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any + fetchApi: typeof fetch = nodeFetch as any, ) { this.apiClient = APIClient(apiUrl, apiKey, fetchApi); } diff --git a/src/services/authenticationLockService.ts b/src/services/authenticationLockService.ts index f304909b9..78631735a 100644 --- a/src/services/authenticationLockService.ts +++ b/src/services/authenticationLockService.ts @@ -4,57 +4,68 @@ */ import { TableClient, TransactionAction, odata } from "@azure/data-tables"; - -import * as t from "io-ts"; - -import { flow, identity, pipe } from "fp-ts/lib/function"; +import { DateFromString } from "@pagopa/ts-commons/lib/dates"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as ROA from "fp-ts/ReadonlyArray"; import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/lib/Either"; -import * as ROA from "fp-ts/ReadonlyArray"; - -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import { DateFromString } from "@pagopa/ts-commons/lib/dates"; - -import { errorsToError } from "../utils/errorsFormatter"; -import * as AI from "../utils/AsyncIterableTask"; +import { flow, identity, pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; import { UnlockCode } from "../../generated/session/UnlockCode"; +import * as AI from "../utils/AsyncIterableTask"; +import { errorsToError } from "../utils/errorsFormatter"; export type NotReleasedAuthenticationLockData = t.TypeOf< typeof NotReleasedAuthenticationLockData >; const NotReleasedAuthenticationLockData = t.type({ - partitionKey: FiscalCode, - rowKey: UnlockCode, - // eslint-disable-next-line sort-keys CreatedAt: DateFromString, + partitionKey: FiscalCode, + + rowKey: UnlockCode, }); export default class AuthenticationLockService { - constructor(private readonly tableClient: TableClient) {} + private readonly getUserAuthenticationLocks = (fiscalCode: FiscalCode) => + pipe( + this.tableClient.listEntities({ + queryOptions: { + filter: odata`PartitionKey eq ${fiscalCode} and not Released`, + }, + }), + AI.fromAsyncIterable, + AI.foldTaskEither(E.toError), + TE.chainEitherK( + flow( + t.array(NotReleasedAuthenticationLockData).decode, + E.mapLeft(errorsToError), + ), + ), + ); /** - * Check whether user authentication is locked + * Retrieve all the user authentication lock data records * * @param fiscalCode the user fiscal code - * @returns true if user authentication is locked, false otherwise + * @returns a list of all the user authentication lock data, if exists */ - public readonly isUserAuthenticationLocked = ( - fiscalCode: FiscalCode - ): TE.TaskEither => - pipe(this.getUserAuthenticationLocks(fiscalCode), TE.map(ROA.isNonEmpty)); + public readonly getUserAuthenticationLockData = ( + fiscalCode: FiscalCode, + ): TE.TaskEither => + this.getUserAuthenticationLocks(fiscalCode); /** - * Retrieve all the user authentication lock data records + * Check whether user authentication is locked * * @param fiscalCode the user fiscal code - * @returns a list of all the user authentication lock data, if exists + * @returns true if user authentication is locked, false otherwise */ - public readonly getUserAuthenticationLockData = ( - fiscalCode: FiscalCode - ): TE.TaskEither> => - this.getUserAuthenticationLocks(fiscalCode); + public readonly isUserAuthenticationLocked = ( + fiscalCode: FiscalCode, + ): TE.TaskEither => + pipe(this.getUserAuthenticationLocks(fiscalCode), TE.map(ROA.isNonEmpty)); /** * Lock the user authentication @@ -65,21 +76,21 @@ export default class AuthenticationLockService { */ public readonly lockUserAuthentication = ( fiscalCode: FiscalCode, - unlockCode: UnlockCode + unlockCode: UnlockCode, ): TE.TaskEither => pipe( TE.tryCatch( () => this.tableClient.createEntity({ - partitionKey: fiscalCode, - rowKey: unlockCode, - // eslint-disable-next-line sort-keys CreatedAt: new Date(), + partitionKey: fiscalCode, + + rowKey: unlockCode, }), - (_) => new Error("Something went wrong creating the record") + (_) => new Error("Something went wrong creating the record"), ), - TE.map((_) => true as const) + TE.map((_) => true as const), ); /** @@ -91,7 +102,7 @@ export default class AuthenticationLockService { */ public readonly unlockUserAuthentication = ( fiscalCode: FiscalCode, - unlockCodes: ReadonlyArray + unlockCodes: readonly UnlockCode[], ): TE.TaskEither => pipe( unlockCodes, @@ -100,44 +111,29 @@ export default class AuthenticationLockService { [ "update", { - partitionKey: fiscalCode, - rowKey: unlockCode, // eslint-disable-next-line sort-keys Released: true, + partitionKey: fiscalCode, + rowKey: unlockCode, }, - ] as TransactionAction + ] as TransactionAction, ), (actions) => TE.tryCatch( () => this.tableClient.submitTransaction(Array.from(actions)), - identity + identity, ), TE.filterOrElseW( (response) => response.status === 202, - () => void 0 + () => void 0, ), TE.mapLeft(() => new Error("Something went wrong updating the record")), - TE.map(() => true as const) + TE.map(() => true as const), ); // ----------------------------------- // Private Methods // ----------------------------------- - private readonly getUserAuthenticationLocks = (fiscalCode: FiscalCode) => - pipe( - this.tableClient.listEntities({ - queryOptions: { - filter: odata`PartitionKey eq ${fiscalCode} and not Released`, - }, - }), - AI.fromAsyncIterable, - AI.foldTaskEither(E.toError), - TE.chainEitherK( - flow( - t.array(NotReleasedAuthenticationLockData).decode, - E.mapLeft(errorsToError) - ) - ) - ); + constructor(private readonly tableClient: TableClient) {} } diff --git a/src/services/bonusService.ts b/src/services/bonusService.ts index 1504b65ab..7e5f647b2 100644 --- a/src/services/bonusService.ts +++ b/src/services/bonusService.ts @@ -14,16 +14,17 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as TE from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { PaginatedBonusActivationsCollection } from "generated/io-bonus-api/PaginatedBonusActivationsCollection"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { pipe } from "fp-ts/lib/function"; + import { EligibilityCheck } from "../../generated/io-bonus-api/EligibilityCheck"; import { InstanceId } from "../../generated/io-bonus-api/InstanceId"; - import { BonusAPIClient } from "../clients/bonus"; import { User } from "../types/user"; +import { readableProblem } from "../utils/errorsFormatter"; import { withQrcode } from "../utils/qrcode"; import { ResponseErrorStatusNotDefinedInSpec, @@ -31,21 +32,34 @@ import { withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; export default class BonusService { - constructor(private readonly bonusApiClient: ReturnType) {} + /** + * Get all IDs of the bonus activations requested by + * the authenticated user or by any between his family member + * + */ + public readonly getAllBonusActivations = ( + _: User, + ): Promise< + | IResponseErrorInternal + | IResponseSuccessJson + > => + // According to the removal of the vacation bonus from APP-IO, this API will always return an empty array + Promise.resolve( + ResponseSuccessJson({ items: [] } as PaginatedBonusActivationsCollection), + ); /** * Retrieve the status of an eligibility check previously started */ public readonly getBonusEligibilityCheck = ( - user: User + user: User, ): Promise< + | IResponseErrorGone | IResponseErrorInternal - | IResponseSuccessAccepted | IResponseErrorNotFound - | IResponseErrorGone + | IResponseSuccessAccepted | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -64,7 +78,7 @@ export default class BonusService { case 404: return ResponseErrorNotFound( "EligibilityCheck not found", - `Could not find an eligibility check for fiscal code ${user.fiscal_code}` + `Could not find an eligibility check for fiscal code ${user.fiscal_code}`, ); case 410: return ResponseErrorGone("EligibilityCheck expired"); @@ -81,11 +95,11 @@ export default class BonusService { */ public readonly getLatestBonusActivationById = ( user: User, - bonusId: NonEmptyString + bonusId: NonEmptyString, ): Promise< | IResponseErrorInternal - | IResponseSuccessAccepted | IResponseErrorNotFound + | IResponseSuccessAccepted | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -102,10 +116,10 @@ export default class BonusService { TE.map((bonus) => ResponseSuccessJson(bonus)), TE.mapLeft((err) => ResponseErrorInternal( - `Cannot encode qrcode: ${JSON.stringify(err)}` - ) + `Cannot encode qrcode: ${JSON.stringify(err)}`, + ), ), - TE.toUnion + TE.toUnion, )(); case 202: return ResponseSuccessAccepted(); @@ -114,7 +128,7 @@ export default class BonusService { case 404: return ResponseErrorNotFound( "BonusActivation not found", - `Could not find a bonus activation for fiscal code: ${user.fiscal_code} and bonus id ${bonusId}` + `Could not find a bonus activation for fiscal code: ${user.fiscal_code} and bonus id ${bonusId}`, ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -124,19 +138,5 @@ export default class BonusService { }); }); - /** - * Get all IDs of the bonus activations requested by - * the authenticated user or by any between his family member - * - */ - public readonly getAllBonusActivations = ( - _: User - ): Promise< - | IResponseErrorInternal - | IResponseSuccessJson - > => - // According to the removal of the vacation bonus from APP-IO, this API will always return an empty array - Promise.resolve( - ResponseSuccessJson({ items: [] } as PaginatedBonusActivationsCollection) - ); + constructor(private readonly bonusApiClient: ReturnType) {} } diff --git a/src/services/cgnOperatorSearchService.ts b/src/services/cgnOperatorSearchService.ts index 195131dd4..934fe88d6 100644 --- a/src/services/cgnOperatorSearchService.ts +++ b/src/services/cgnOperatorSearchService.ts @@ -1,6 +1,7 @@ /** * This service interacts with the GCN operator search API */ +import { IResponseType } from "@pagopa/ts-commons/lib/requests"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -11,27 +12,26 @@ import { ResponseErrorNotFound, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { IResponseType } from "@pagopa/ts-commons/lib/requests"; +import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; import { PublishedProductCategoriesResult } from "generated/io-cgn-operator-search-api/PublishedProductCategoriesResult"; -import { GetPublishedCategoriesParameters } from "generated/parameters/GetPublishedCategoriesParameters"; import { SearchRequest } from "generated/io-cgn-operator-search-api/SearchRequest"; import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; -import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; +import { GetPublishedCategoriesParameters } from "generated/parameters/GetPublishedCategoriesParameters"; + import { Merchant } from "../../generated/cgn-operator-search/Merchant"; +import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; +import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; +import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; +import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; +import { CgnOperatorSearchAPIClient } from "../../src/clients/cgn-operator-search"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; -import { CgnOperatorSearchAPIClient } from "../../src/clients/cgn-operator-search"; -import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; -import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; -import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; -import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; type ClientResponses = | IResponseType<200, T> @@ -40,77 +40,90 @@ type ClientResponses = type ServiceResponses = | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessJson; export default class CgnService { - constructor( - private readonly cgnOperatorSearchApiClient: ReturnType - ) {} + private readonly mapResponse = ( + response: ClientResponses, + ): ServiceResponses => { + switch (response.status) { + case 200: + return ResponseSuccessJson(response.value); + case 404: + return ResponseErrorNotFound("Not Found", "Operator Not found"); + case 500: + return ResponseErrorInternal(readableProblem(response.value)); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }; /** - * Get an array of CGN product categories that have at least a published discount + * Count CGN merchants/discounts */ - public readonly getPublishedProductCategories = ( - params: GetPublishedCategoriesParameters - ): Promise> => + public readonly count = (): Promise> => withCatchAsInternalError(async () => { - const validated = - await this.cgnOperatorSearchApiClient.getPublishedProductCategories( - params - ); + const validated = await this.cgnOperatorSearchApiClient.count({}); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses - ) + this.mapResponse(response as ClientResponses), ); }); /** - * Get the CGN operator/merchant by its identifier. + * Get a discount bucket code by discount identifier. */ - public readonly getMerchant = ( - merchantId: NonEmptyString - ): Promise> => + public readonly getDiscountBucketCode = ( + discountId: NonEmptyString, + ): Promise> => withCatchAsInternalError(async () => { - const validated = await this.cgnOperatorSearchApiClient.getMerchant({ - merchantId, - }); + const validated = + await this.cgnOperatorSearchApiClient.getDiscountBucketCode({ + discountId, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse(response as ClientResponses) + this.mapResponse( + response as ClientResponses, + ), ); }); /** - * Count CGN merchants/discounts + * Get the CGN operator/merchant by its identifier. */ - public readonly count = (): Promise> => + public readonly getMerchant = ( + merchantId: NonEmptyString, + ): Promise> => withCatchAsInternalError(async () => { - const validated = await this.cgnOperatorSearchApiClient.count({}); + const validated = await this.cgnOperatorSearchApiClient.getMerchant({ + merchantId, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse(response as ClientResponses) + this.mapResponse(response as ClientResponses), ); }); /** - * Search CGN merchants/discounts that matches with search criteria + * Get an array of CGN offline merchants that matches with search criteria + * expressed in OfflineMerchantSearchRequest */ - public readonly search = ( - searchRequest: SearchRequest - ): Promise> => + public readonly getOfflineMerchants = ( + offlineMerchantSearchRequest: OfflineMerchantSearchRequest, + ): Promise> => withCatchAsInternalError(async () => { - const validated = await this.cgnOperatorSearchApiClient.search({ - body: searchRequest, - }); + const validated = + await this.cgnOperatorSearchApiClient.getOfflineMerchants({ + body: offlineMerchantSearchRequest, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses - ) + this.mapResponse( + response as ClientResponses, + ), ); }); @@ -119,7 +132,7 @@ export default class CgnService { * expressed in OnlineMerchantSearchRequest */ public readonly getOnlineMerchants = ( - onlineMerchantSearchRequest: OnlineMerchantSearchRequest + onlineMerchantSearchRequest: OnlineMerchantSearchRequest, ): Promise> => withCatchAsInternalError(async () => { const validated = @@ -129,62 +142,49 @@ export default class CgnService { return withValidatedOrInternalError(validated, (response) => this.mapResponse( - response as ClientResponses - ) + response as ClientResponses, + ), ); }); /** - * Get an array of CGN offline merchants that matches with search criteria - * expressed in OfflineMerchantSearchRequest + * Get an array of CGN product categories that have at least a published discount */ - public readonly getOfflineMerchants = ( - offlineMerchantSearchRequest: OfflineMerchantSearchRequest - ): Promise> => + public readonly getPublishedProductCategories = ( + params: GetPublishedCategoriesParameters, + ): Promise> => withCatchAsInternalError(async () => { const validated = - await this.cgnOperatorSearchApiClient.getOfflineMerchants({ - body: offlineMerchantSearchRequest, - }); + await this.cgnOperatorSearchApiClient.getPublishedProductCategories( + params, + ); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses - ) + this.mapResponse( + response as ClientResponses, + ), ); }); /** - * Get a discount bucket code by discount identifier. + * Search CGN merchants/discounts that matches with search criteria */ - public readonly getDiscountBucketCode = ( - discountId: NonEmptyString - ): Promise> => + public readonly search = ( + searchRequest: SearchRequest, + ): Promise> => withCatchAsInternalError(async () => { - const validated = - await this.cgnOperatorSearchApiClient.getDiscountBucketCode({ - discountId, - }); + const validated = await this.cgnOperatorSearchApiClient.search({ + body: searchRequest, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses - ) + this.mapResponse( + response as ClientResponses, + ), ); }); - private readonly mapResponse = ( - response: ClientResponses - ): ServiceResponses => { - switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); - case 404: - return ResponseErrorNotFound("Not Found", "Operator Not found"); - case 500: - return ResponseErrorInternal(readableProblem(response.value)); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }; + constructor( + private readonly cgnOperatorSearchApiClient: ReturnType, + ) {} } diff --git a/src/services/cgnService.ts b/src/services/cgnService.ts index 07ef65ea1..a288bb6b9 100644 --- a/src/services/cgnService.ts +++ b/src/services/cgnService.ts @@ -2,6 +2,12 @@ * This service interactsnwith the Bonus API */ +import { Card } from "@pagopa/io-functions-cgn-sdk/Card"; +import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; +import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; +import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; +import { InstanceId } from "@pagopa/io-functions-cgn-sdk/InstanceId"; +import { Otp } from "@pagopa/io-functions-cgn-sdk/Otp"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -19,41 +25,32 @@ import { ResponseSuccessJson, ResponseSuccessRedirectToResource, } from "@pagopa/ts-commons/lib/responses"; - import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; -import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; -import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; -import { InstanceId } from "@pagopa/io-functions-cgn-sdk/InstanceId"; -import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; -import { Card } from "@pagopa/io-functions-cgn-sdk/Card"; -import { Otp } from "@pagopa/io-functions-cgn-sdk/Otp"; + import { CgnAPIClient } from "../../src/clients/cgn"; import { User } from "../types/user"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; export default class CgnService { - constructor(private readonly cgnApiClient: ReturnType) {} - /** - * Get the current CGN Status related to the user. + * generate a CGN OTP */ - public readonly getCgnStatus = ( - user: User + public readonly generateOtp = ( + user: User, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getCgnStatus({ + const validated = await this.cgnApiClient.generateOtp({ fiscalcode: user.fiscal_code, }); @@ -63,8 +60,8 @@ export default class CgnService { return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); - case 404: - return ResponseErrorNotFound("Not Found", "CGN not found"); + case 403: + return ResponseErrorForbiddenNotAuthorized; case 500: return ResponseErrorInternal(readableProblem(response.value)); default: @@ -74,20 +71,18 @@ export default class CgnService { }); /** - * Get the current Eyca Card Status related to the user. + * Get CGN activation status details for the logged user. */ - public readonly getEycaStatus = ( - user: User + public readonly getCgnActivation = ( + user: User, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getEycaStatus({ + const validated = await this.cgnApiClient.getCgnActivation({ fiscalcode: user.fiscal_code, }); @@ -97,13 +92,10 @@ export default class CgnService { return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; case 404: - return ResponseErrorNotFound("Not Found", "Eyca Card not found"); - case 409: - return ResponseErrorConflict( - "EYCA Card is missing while citizen is eligible to obtain it or a CGN is already activated" + return ResponseErrorNotFound( + "Not Found", + "No User CGN activation found", ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -114,45 +106,30 @@ export default class CgnService { }); /** - * Start a CGN activation process for the logged user. + * Get the current CGN Status related to the user. */ - public readonly startCgnActivation = ( - user: User + public readonly getCgnStatus = ( + user: User, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessRedirectToResource - | IResponseSuccessAccepted + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.startCgnActivation({ + const validated = await this.cgnApiClient.getCgnStatus({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 201: - return ResponseSuccessRedirectToResource( - response.value, - pipe( - response.headers.Location, - O.fromNullable, - O.getOrElse(() => "/api/v1/cgn/activation") - ), - response.value - ); - case 202: - return ResponseSuccessAccepted(); + case 200: + return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; - case 409: - return ResponseErrorConflict( - "Cannot start a new CGN activation because the CGN is already active, revoked or expired" - ); + case 404: + return ResponseErrorNotFound("Not Found", "CGN not found"); case 500: return ResponseErrorInternal(readableProblem(response.value)); default: @@ -162,18 +139,18 @@ export default class CgnService { }); /** - * Get CGN activation status details for the logged user. + * Get EYCA's activation status detail for the logged user. */ - public readonly getCgnActivation = ( - user: User + public readonly getEycaActivation = ( + user: User, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getCgnActivation({ + const validated = await this.cgnApiClient.getEycaActivation({ fiscalcode: user.fiscal_code, }); @@ -186,7 +163,7 @@ export default class CgnService { case 404: return ResponseErrorNotFound( "Not Found", - "No User CGN activation found" + "No EYCA Card activation found", ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -197,44 +174,36 @@ export default class CgnService { }); /** - * Start an EYCA activation for the logged user. + * Get the current Eyca Card Status related to the user. */ - public readonly startEycaActivation = ( - user: User + public readonly getEycaStatus = ( + user: User, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessRedirectToResource - | IResponseSuccessAccepted + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.startEycaActivation({ + const validated = await this.cgnApiClient.getEycaStatus({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 201: - return ResponseSuccessRedirectToResource( - response.value, - pipe( - response.headers.Location, - O.fromNullable, - O.getOrElse(() => "/api/v1/cgn/eyca/activation") - ), - response.value - ); - case 202: - return ResponseSuccessAccepted(); + case 200: + return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: return ResponseErrorForbiddenNotAuthorized; + case 404: + return ResponseErrorNotFound("Not Found", "Eyca Card not found"); case 409: return ResponseErrorConflict( - "Cannot start a new EYCA activation because EYCA card is already active, revoked or expired" + "EYCA Card is missing while citizen is eligible to obtain it or a CGN is already activated", ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -245,31 +214,44 @@ export default class CgnService { }); /** - * Get EYCA's activation status detail for the logged user. + * Start a CGN activation process for the logged user. */ - public readonly getEycaActivation = ( - user: User + public readonly startCgnActivation = ( + user: User, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseSuccessAccepted + | IResponseSuccessRedirectToResource > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getEycaActivation({ + const validated = await this.cgnApiClient.startCgnActivation({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); + case 201: + return ResponseSuccessRedirectToResource( + response.value, + pipe( + response.headers.Location, + O.fromNullable, + O.getOrElse(() => "/api/v1/cgn/activation"), + ), + response.value, + ); + case 202: + return ResponseSuccessAccepted(); case 401: return ResponseErrorUnexpectedAuthProblem(); - case 404: - return ResponseErrorNotFound( - "Not Found", - "No EYCA Card activation found" + case 403: + return ResponseErrorForbiddenNotAuthorized; + case 409: + return ResponseErrorConflict( + "Cannot start a new CGN activation because the CGN is already active, revoked or expired", ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -283,14 +265,14 @@ export default class CgnService { * Start a CGN unsubscription process for the logged user. */ public readonly startCgnUnsubscription = ( - user: User + user: User, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorConflict - | IResponseSuccessRedirectToResource | IResponseSuccessAccepted + | IResponseSuccessRedirectToResource > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.startCgnUnsubscription({ @@ -305,9 +287,9 @@ export default class CgnService { pipe( response.headers.Location, O.fromNullable, - O.getOrElse(() => "/api/v1/cgn/delete") + O.getOrElse(() => "/api/v1/cgn/delete"), ), - response.value + response.value, ); case 202: return ResponseSuccessAccepted(); @@ -317,7 +299,7 @@ export default class CgnService { return ResponseErrorForbiddenNotAuthorized; case 409: return ResponseErrorConflict( - "Cannot start a new CGN unsubscription" + "Cannot start a new CGN unsubscription", ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -328,29 +310,45 @@ export default class CgnService { }); /** - * generate a CGN OTP + * Start an EYCA activation for the logged user. */ - public readonly generateOtp = ( - user: User + public readonly startEycaActivation = ( + user: User, ): Promise< + | IResponseErrorConflict + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseSuccessJson + | IResponseSuccessAccepted + | IResponseSuccessRedirectToResource > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.generateOtp({ + const validated = await this.cgnApiClient.startEycaActivation({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); + case 201: + return ResponseSuccessRedirectToResource( + response.value, + pipe( + response.headers.Location, + O.fromNullable, + O.getOrElse(() => "/api/v1/cgn/eyca/activation"), + ), + response.value, + ); + case 202: + return ResponseSuccessAccepted(); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: return ResponseErrorForbiddenNotAuthorized; + case 409: + return ResponseErrorConflict( + "Cannot start a new EYCA activation because EYCA card is already active, revoked or expired", + ); case 500: return ResponseErrorInternal(readableProblem(response.value)); default: @@ -358,4 +356,6 @@ export default class CgnService { } }); }); + + constructor(private readonly cgnApiClient: ReturnType) {} } diff --git a/src/services/eucovidcertService.ts b/src/services/eucovidcertService.ts index 2cacaaa5c..886497e47 100644 --- a/src/services/eucovidcertService.ts +++ b/src/services/eucovidcertService.ts @@ -1,3 +1,5 @@ +import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; +import { PreferredLanguages } from "@pagopa/io-functions-eucovidcerts-sdk/PreferredLanguages"; import { HttpStatusCodeEnum, IResponseErrorForbiddenNotAuthorized, @@ -11,18 +13,15 @@ import { ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; -import { PreferredLanguages } from "@pagopa/io-functions-eucovidcerts-sdk/PreferredLanguages"; -import { readableProblem } from "../utils/errorsFormatter"; import { EUCovidCertAPIClient } from "../clients/eucovidcert.client"; - +import { User } from "../types/user"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; -import { User } from "../types/user"; /** * Returns a `504` `Gateway Timeout` error @@ -34,7 +33,7 @@ export function ResponseGatewayTimeout(detail: string): IResponseErrorInternal { ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_504, "Gateway Timeout", - detail + detail, ), kind: "IResponseErrorInternal", }; @@ -46,35 +45,31 @@ export function ResponseGatewayTimeout(detail: string): IResponseErrorInternal { * @param detail The error message */ export function ResponseErrorNotFound403( - detail: string + detail: string, ): IResponseErrorNotFound { return { ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_403, "Not Found", - detail + detail, ), kind: "IResponseErrorNotFound", }; } export default class EUCovidCertService { - constructor( - private readonly eucovidCertApiClient: ReturnType - ) {} - /** * Get the EU Covid Certificte Status related to the user and auth_code */ public readonly getEUCovidCertificate = ( user: User, auth_code: string, - preferred_languages?: PreferredLanguages + preferred_languages?: PreferredLanguages, ): Promise< + | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorForbiddenNotAuthorized + | IResponseErrorValidation | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -93,13 +88,13 @@ export default class EUCovidCertService { case 400: return ResponseErrorValidation( "Bad Request", - "Payload has bad format" + "Payload has bad format", ); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: return ResponseErrorNotFound403( - "Access data provided are invalid or no Certificate has been emitted for the given Citizen" + "Access data provided are invalid or no Certificate has been emitted for the given Citizen", ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -110,4 +105,8 @@ export default class EUCovidCertService { } }); }); + + constructor( + private readonly eucovidCertApiClient: ReturnType, + ) {} } diff --git a/src/services/fimsService.ts b/src/services/fimsService.ts index b070a848b..8e46b2481 100644 --- a/src/services/fimsService.ts +++ b/src/services/fimsService.ts @@ -14,14 +14,11 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; - import { AccessHistoryPage } from "generated/io-fims-api/AccessHistoryPage"; import { ExportRequest } from "generated/io-fims-api/ExportRequest"; import { IoFimsAPIClient } from "../clients/io-fims"; - import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, @@ -31,11 +28,9 @@ import { const invalidRequest = "Invalid request"; export default class FimsService { - constructor(private readonly ioFimsApiClient: ReturnType) {} - public readonly getAccessHistory = ( fiscalCode: FiscalCode, - page?: string + page?: string, ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -53,11 +48,11 @@ export default class FimsService { case 422: return ResponseErrorValidation( invalidRequest, - `An error occurred while validating the request body | ${response.value}` + `An error occurred while validating the request body | ${response.value}`, ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -67,10 +62,10 @@ export default class FimsService { public readonly requestExport = ( fiscalCode: FiscalCode, - email: EmailString + email: EmailString, ): Promise< - | IResponseErrorInternal | IResponseErrorConflict + | IResponseErrorInternal | IResponseErrorValidation | IResponseSuccessAccepted > => @@ -90,15 +85,17 @@ export default class FimsService { case 422: return ResponseErrorValidation( invalidRequest, - `An error occurred while validating the request body | ${response.value}` + `An error occurred while validating the request body | ${response.value}`, ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); default: return ResponseErrorStatusNotDefinedInSpec(response); } }); }); + + constructor(private readonly ioFimsApiClient: ReturnType) {} } diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index cf9cf96e4..92e0e7260 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -15,17 +15,15 @@ import { ResponseErrorValidation, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - -import * as E from "fp-ts/Either"; - import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { PromiseType } from "@pagopa/ts-commons/lib/types"; +import * as E from "fp-ts/Either"; import { UpsertServicePreference } from "generated/backend/UpsertServicePreference"; import { APIClient } from "src/clients/api"; -import { ServicePreference } from "../../generated/backend/ServicePreference"; -import { ServicePublic } from "../../generated/backend/ServicePublic"; import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; +import { ServicePreference } from "../../generated/backend/ServicePreference"; +import { ServicePublic } from "../../generated/backend/ServicePublic"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, @@ -35,14 +33,13 @@ import { } from "../utils/responses"; import { IApiClientFactoryInterface } from "./IApiClientFactory"; -type RightOf> = T extends E.Right - ? R - : never; +type RightOf> = + T extends E.Right ? R : never; const handleGetServicePreferencesResponse = ( response: RightOf< PromiseType["getServicePreferences"]>> - > + >, ) => { switch (response.status) { case 200: @@ -56,7 +53,7 @@ const handleGetServicePreferencesResponse = ( case 409: return ResponseErrorConflict( response.value.detail ?? - "The Profile is not in the correct preference mode" + "The Profile is not in the correct preference mode", ); case 429: return ResponseErrorTooManyRequests(); @@ -68,13 +65,11 @@ const handleGetServicePreferencesResponse = ( // ---------------------- export default class FunctionsAppService { - constructor(private readonly apiClient: IApiClientFactoryInterface) {} - /** * Retrieve all the information about the service that has sent a message. */ public readonly getService = ( - serviceId: string + serviceId: string, ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -92,13 +87,13 @@ export default class FunctionsAppService { response.status === 200 ? withValidatedOrInternalError( ServicePublic.decode(response.value), - ResponseSuccessJson + ResponseSuccessJson, ) : response.status === 404 - ? ResponseErrorNotFound("Not found", "Service not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound("Not found", "Service not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status), ); }); @@ -107,13 +102,13 @@ export default class FunctionsAppService { */ public readonly getServicePreferences = ( fiscalCode: FiscalCode, - serviceId: PathTraversalSafePathParam + serviceId: PathTraversalSafePathParam, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseErrorConflict | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -126,7 +121,7 @@ export default class FunctionsAppService { return withValidatedOrInternalError( validated, - handleGetServicePreferencesResponse + handleGetServicePreferencesResponse, ); }); @@ -136,13 +131,13 @@ export default class FunctionsAppService { public readonly upsertServicePreferences = ( fiscalCode: FiscalCode, serviceId: PathTraversalSafePathParam, - servicePreferences: UpsertServicePreference + servicePreferences: UpsertServicePreference, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseErrorConflict | IResponseErrorTooManyRequests + | IResponseErrorValidation | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -156,7 +151,9 @@ export default class FunctionsAppService { return withValidatedOrInternalError( validated, - handleGetServicePreferencesResponse + handleGetServicePreferencesResponse, ); }); + + constructor(private readonly apiClient: IApiClientFactoryInterface) {} } diff --git a/src/services/ioSignService.ts b/src/services/ioSignService.ts index 4667a58e5..0f87e60cc 100644 --- a/src/services/ioSignService.ts +++ b/src/services/ioSignService.ts @@ -16,37 +16,33 @@ import { ResponseSuccessJson, ResponseSuccessRedirectToResource, } from "@pagopa/ts-commons/lib/responses"; - -import * as O from "fp-ts/lib/Option"; -import { flow, pipe } from "fp-ts/lib/function"; - -import * as t from "io-ts"; - import { EmailString, FiscalCode, NonEmptyString, } from "@pagopa/ts-commons/lib/strings"; import * as E from "fp-ts/Either"; -import { CreateSignatureBody as CreateSignatureBodyApiModel } from "../../generated/io-sign-api/CreateSignatureBody"; -import { IssuerEnvironment } from "../../generated/io-sign/IssuerEnvironment"; -import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; -import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; +import * as O from "fp-ts/lib/Option"; +import { flow, pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; + import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; import { Id } from "../../generated/io-sign/Id"; - +import { IssuerEnvironment } from "../../generated/io-sign/IssuerEnvironment"; import { QtspClausesMetadataDetailView } from "../../generated/io-sign/QtspClausesMetadataDetailView"; - import { SignatureDetailView } from "../../generated/io-sign/SignatureDetailView"; import { SignatureRequestDetailView } from "../../generated/io-sign/SignatureRequestDetailView"; +import { CreateSignatureBody as CreateSignatureBodyApiModel } from "../../generated/io-sign-api/CreateSignatureBody"; +import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; +import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; import { IoSignAPIClient } from "../clients/io-sign"; +import { IoSignLollipopLocalsType } from "../controllers/ioSignController"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; -import { IoSignLollipopLocalsType } from "../controllers/ioSignController"; import { ResponseErrorNotFound403 } from "./eucovidcertService"; const internalServerError = "Internal server error"; @@ -58,63 +54,25 @@ const userNotFound = export const getEnvironmentFromHeaders = flow( O.fromPredicate( (headers: object): headers is Headers => - headers && "get" in headers && typeof headers.get === "function" + headers && "get" in headers && typeof headers.get === "function", ), O.map((headers) => headers.get("x-io-sign-environment")), O.chain(O.fromNullable), O.chainEitherK(t.keyof({ prod: true, test: true }).decode), - O.getOrElse(() => "prod") + O.getOrElse(() => "prod"), ); export default class IoSignService { - constructor(private readonly ioSignApiClient: ReturnType) {} - - /** - * Get the Signer id related to the user. - */ - public readonly getSignerByFiscalCode = ( - fiscalCode: FiscalCode - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const validated = await this.ioSignApiClient.getSignerByFiscalCode({ - body: { fiscal_code: fiscalCode }, - }); - return withValidatedOrInternalError(validated, (response) => { - switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); - case 400: - return ResponseErrorValidation( - invalidRequest, - `An error occurred while validating the request body | ${response.value}` - ); - case 403: - return ResponseErrorNotFound403(userNotFound); - case 500: - return ResponseErrorInternal( - `Internal server error | ${response.value}` - ); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }); - }); - public readonly createFilledDocument = ( document_url: NonEmptyString, email: EmailString, family_name: NonEmptyString, name: NonEmptyString, - signerId: Id + signerId: Id, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorValidation | IResponseSuccessRedirectToResource< FilledDocumentDetailView, FilledDocumentDetailView @@ -138,14 +96,14 @@ export default class IoSignService { pipe( response.headers.Location, O.fromNullable, - O.getOrElse(() => response.value.filled_document_url) + O.getOrElse(() => response.value.filled_document_url), ), - response.value + response.value, ); case 400: return ResponseErrorValidation( invalidRequest, - `An error occurred while validating the request body | ${response.value}` + `An error occurred while validating the request body | ${response.value}`, ); case 404: return ResponseErrorNotFound(resourcesNotFound, userNotFound); @@ -157,8 +115,8 @@ export default class IoSignService { response.value, ProblemJson.decode, E.map(readableProblem), - E.getOrElse(() => internalServerError) - ) + E.getOrElse(() => internalServerError), + ), ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -167,31 +125,48 @@ export default class IoSignService { }); /** - * Get the QTSP clauses + * Create a Signature from a Signature Request */ - public readonly getQtspClausesMetadata = ( - issuerEnvironment: IssuerEnvironment + public readonly createSignature = ( + ioSignLollipopLocals: IoSignLollipopLocalsType, + body: CreateSignatureBodyApiModel, + signerId: Id, ): Promise< - IResponseErrorInternal | IResponseSuccessJson + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorValidation + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioSignApiClient.getQtspClausesMetadata({ - "x-iosign-issuer-environment": issuerEnvironment, + const validated = await this.ioSignApiClient.createSignature({ + ...ioSignLollipopLocals, + body, + "x-iosign-signer-id": signerId, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); + case 400: + return ResponseErrorValidation( + invalidRequest, + `An error occurred while validating the request body | ${response.value}`, + ); + case 404: + return ResponseErrorNotFound( + resourcesNotFound, + "Signature request not found", + ); + case 403: + return ResponseErrorNotFound403(userNotFound); case 500: return ResponseErrorInternal( - // TODO [SFEQS-1199]: When the code for openapi-codegen-ts is fixed, refactor this section. - // Now, it generates incorrect output whenever the http status is 500. [SFEQS-1199] pipe( response.value, ProblemJson.decode, E.map(readableProblem), - E.getOrElse(() => internalServerError) - ) + E.getOrElse(() => internalServerError), + ), ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -200,48 +175,31 @@ export default class IoSignService { }); /** - * Create a Signature from a Signature Request + * Get the QTSP clauses */ - public readonly createSignature = ( - ioSignLollipopLocals: IoSignLollipopLocalsType, - body: CreateSignatureBodyApiModel, - signerId: Id + public readonly getQtspClausesMetadata = ( + issuerEnvironment: IssuerEnvironment, ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseSuccessJson + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioSignApiClient.createSignature({ - ...ioSignLollipopLocals, - body, - "x-iosign-signer-id": signerId, + const validated = await this.ioSignApiClient.getQtspClausesMetadata({ + "x-iosign-issuer-environment": issuerEnvironment, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); - case 400: - return ResponseErrorValidation( - invalidRequest, - `An error occurred while validating the request body | ${response.value}` - ); - case 404: - return ResponseErrorNotFound( - resourcesNotFound, - "Signature request not found" - ); - case 403: - return ResponseErrorNotFound403(userNotFound); case 500: return ResponseErrorInternal( + // TODO [SFEQS-1199]: When the code for openapi-codegen-ts is fixed, refactor this section. + // Now, it generates incorrect output whenever the http status is 500. [SFEQS-1199] pipe( response.value, ProblemJson.decode, E.map(readableProblem), - E.getOrElse(() => internalServerError) - ) + E.getOrElse(() => internalServerError), + ), ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -254,7 +212,7 @@ export default class IoSignService { */ public readonly getSignatureRequest = ( signatureRequestId: Id, - signerId: Id + signerId: Id, ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -274,7 +232,7 @@ export default class IoSignService { .status(HttpStatusCodeEnum.HTTP_STATUS_200) .header( "x-io-sign-environment", - getEnvironmentFromHeaders(response.headers) + getEnvironmentFromHeaders(response.headers), ) .json(response.value), kind: "IResponseSuccessJson", @@ -283,7 +241,7 @@ export default class IoSignService { case 404: return ResponseErrorNotFound( resourcesNotFound, - "Signature request not found" + "Signature request not found", ); case 403: return ResponseErrorNotFound403(userNotFound); @@ -297,7 +255,7 @@ export default class IoSignService { * Get Signature Requests list from Signer */ public readonly getSignatureRequests = ( - signerId: Id + signerId: Id, ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -318,4 +276,42 @@ export default class IoSignService { } }); }); + + /** + * Get the Signer id related to the user. + */ + public readonly getSignerByFiscalCode = ( + fiscalCode: FiscalCode, + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorValidation + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => { + const validated = await this.ioSignApiClient.getSignerByFiscalCode({ + body: { fiscal_code: fiscalCode }, + }); + return withValidatedOrInternalError(validated, (response) => { + switch (response.status) { + case 200: + return ResponseSuccessJson(response.value); + case 400: + return ResponseErrorValidation( + invalidRequest, + `An error occurred while validating the request body | ${response.value}`, + ); + case 403: + return ResponseErrorNotFound403(userNotFound); + case 500: + return ResponseErrorInternal( + `Internal server error | ${response.value}`, + ); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }); + }); + + constructor(private readonly ioSignApiClient: ReturnType) {} } diff --git a/src/services/ioWalletService.ts b/src/services/ioWalletService.ts index daba993b8..fbf021cc0 100644 --- a/src/services/ioWalletService.ts +++ b/src/services/ioWalletService.ts @@ -4,7 +4,6 @@ */ import { - getResponseErrorForbiddenNotAuthorized, IResponseErrorForbiddenNotAuthorized, IResponseErrorGeneric, IResponseErrorInternal, @@ -18,25 +17,26 @@ import { ResponseErrorServiceTemporarilyUnavailable, ResponseSuccessJson, ResponseSuccessNoContent, + getResponseErrorForbiddenNotAuthorized, } from "@pagopa/ts-commons/lib/responses"; - import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { NonceDetailView } from "generated/io-wallet-api/NonceDetailView"; -import { Grant_typeEnum } from "generated/io-wallet-api/CreateWalletAttestationBody"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/Option"; +import { pipe } from "fp-ts/lib/function"; +import { Grant_typeEnum } from "generated/io-wallet-api/CreateWalletAttestationBody"; +import { NonceDetailView } from "generated/io-wallet-api/NonceDetailView"; + +import { SetWalletInstanceStatusWithFiscalCodeData } from "../../generated/io-wallet-api/SetWalletInstanceStatusWithFiscalCodeData"; +import { WalletAttestationView } from "../../generated/io-wallet-api/WalletAttestationView"; +import { WalletInstanceData } from "../../generated/io-wallet-api/WalletInstanceData"; +import { Subscription } from "../../generated/trial-system-api/Subscription"; import { IoWalletAPIClient } from "../clients/io-wallet"; +import { TrialSystemAPIClient } from "../clients/trial-system.client"; +import { IO_WALLET_TRIAL_ID } from "../config"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; -import { IO_WALLET_TRIAL_ID } from "../config"; -import { TrialSystemAPIClient } from "../clients/trial-system.client"; -import { Subscription } from "../../generated/trial-system-api/Subscription"; -import { WalletAttestationView } from "../../generated/io-wallet-api/WalletAttestationView"; -import { SetWalletInstanceStatusWithFiscalCodeData } from "../../generated/io-wallet-api/SetWalletInstanceStatusWithFiscalCodeData"; -import { WalletInstanceData } from "../../generated/io-wallet-api/WalletInstanceData"; const unprocessableContentError = "Unprocessable Content"; const invalidRequest = "Your request didn't validate"; @@ -48,35 +48,62 @@ const conflictErrorDetail = "There has been a conflict"; const serviceUnavailableDetail = "Service Unavailable. Please try again later"; export default class IoWalletService { - constructor( - private readonly ioWalletApiClient: ReturnType, - private readonly trialSystemApiClient: ReturnType< - typeof TrialSystemAPIClient - > - ) {} - /** - * Get a nonce. + * Create a Wallet Attestation. */ - public readonly getNonce = (): Promise< + public readonly createWalletAttestation = ( + assertion: NonEmptyString, + grant_type: Grant_typeEnum, + fiscal_code: FiscalCode, + ): Promise< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorGeneric | IResponseErrorInternal - | IResponseSuccessJson + | IResponseErrorNotFound | IResponseErrorServiceUnavailable + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.getNonce({}); + const validated = await this.ioWalletApiClient.createWalletAttestation({ + body: { + assertion, + fiscal_code, + grant_type, + }, + }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); + case 403: + return getResponseErrorForbiddenNotAuthorized( + "Wallet instance has been revoked", + ); + case 404: + return ResponseErrorNotFound( + "Not Found", + "Wallet instance not found", + ); + case 409: + return ResponseErrorGeneric( + response.status, + conflictErrorTitle, + conflictErrorDetail, + ); + case 422: + return ResponseErrorGeneric( + response.status, + unprocessableContentError, + invalidRequest, + ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10" + "10", ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -91,12 +118,12 @@ export default class IoWalletService { challenge: NonEmptyString, hardware_key_tag: NonEmptyString, key_attestation: NonEmptyString, - fiscal_code: FiscalCode + fiscal_code: FiscalCode, ): Promise< - | IResponseErrorInternal | IResponseErrorGeneric - | IResponseSuccessNoContent + | IResponseErrorInternal | IResponseErrorServiceUnavailable + | IResponseSuccessNoContent > => withCatchAsInternalError(async () => { const validated = await this.ioWalletApiClient.createWalletInstance({ @@ -115,22 +142,22 @@ export default class IoWalletService { return ResponseErrorGeneric( response.status, conflictErrorTitle, - conflictErrorDetail + conflictErrorDetail, ); case 422: return ResponseErrorGeneric( response.status, unprocessableContentError, - invalidRequest + invalidRequest, ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10" + "10", ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -139,61 +166,27 @@ export default class IoWalletService { }); /** - * Create a Wallet Attestation. + * Get a nonce. */ - public readonly createWalletAttestation = ( - assertion: NonEmptyString, - grant_type: Grant_typeEnum, - fiscal_code: FiscalCode - ): Promise< + public readonly getNonce = (): Promise< | IResponseErrorInternal - | IResponseErrorGeneric - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorNotFound - | IResponseSuccessJson | IResponseErrorServiceUnavailable + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.createWalletAttestation({ - body: { - assertion, - fiscal_code, - grant_type, - }, - }); + const validated = await this.ioWalletApiClient.getNonce({}); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); - case 403: - return getResponseErrorForbiddenNotAuthorized( - "Wallet instance has been revoked" - ); - case 404: - return ResponseErrorNotFound( - "Not Found", - "Wallet instance not found" - ); - case 409: - return ResponseErrorGeneric( - response.status, - conflictErrorTitle, - conflictErrorDetail - ); - case 422: - return ResponseErrorGeneric( - response.status, - unprocessableContentError, - invalidRequest - ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10" + "10", ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -202,36 +195,85 @@ export default class IoWalletService { }); /** - * Update current Wallet Instance status. + * Get the subscription given a specific user. */ - public readonly setWalletInstanceStatus = ( + public readonly getSubscription = async ( + userId: NonEmptyString, + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseSuccessJson> + > => + withCatchAsInternalError(async () => { + const validated = await this.trialSystemApiClient.getSubscription({ + trialId: IO_WALLET_TRIAL_ID, + userId, + }); + + return withValidatedOrInternalError(validated, (response) => { + switch (response.status) { + case 200: + return pipe( + { + createdAt: response.value.createdAt, + state: response.value.state, + }, + ResponseSuccessJson, + ); + case 401: + return ResponseErrorInternal("Internal server error"); + case 404: + return ResponseErrorNotFound("Not Found", "Subscription not found"); + case 500: + return ResponseErrorInternal( + pipe( + response.value.detail, + O.fromNullable, + O.getOrElse(() => "Cannot get subscription"), + ), + ); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }); + }); + + /** + * Get current Wallet Instance status. + */ + public readonly getWalletInstanceStatus = ( id: NonEmptyString, - status: SetWalletInstanceStatusWithFiscalCodeData["status"], - fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"] + fiscal_code: FiscalCode, ): Promise< | IResponseErrorInternal - | IResponseSuccessNoContent + | IResponseErrorNotFound | IResponseErrorServiceUnavailable + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.setWalletInstanceStatus({ - body: { fiscal_code, status }, + const validated = await this.ioWalletApiClient.getWalletInstanceStatus({ + "fiscal-code": fiscal_code, id, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 204: - return ResponseSuccessNoContent(); + case 200: + return ResponseSuccessJson(response.value); + case 404: + return ResponseErrorNotFound( + "Not Found", + "Wallet instance not found", + ); case 400: case 422: case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10" + "10", ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -244,12 +286,12 @@ export default class IoWalletService { */ public readonly setCurrentWalletInstanceStatus = ( status: SetWalletInstanceStatusWithFiscalCodeData["status"], - fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"] + fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"], ): Promise< - | IResponseErrorInternal | IResponseErrorGeneric - | IResponseSuccessNoContent + | IResponseErrorInternal | IResponseErrorServiceUnavailable + | IResponseSuccessNoContent > => withCatchAsInternalError(async () => { const validated = @@ -264,16 +306,16 @@ export default class IoWalletService { return ResponseErrorGeneric( response.status, unprocessableContentError, - invalidRequest + invalidRequest, ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10" + "10", ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -282,41 +324,36 @@ export default class IoWalletService { }); /** - * Get current Wallet Instance status. + * Update current Wallet Instance status. */ - public readonly getWalletInstanceStatus = ( + public readonly setWalletInstanceStatus = ( id: NonEmptyString, - fiscal_code: FiscalCode + status: SetWalletInstanceStatusWithFiscalCodeData["status"], + fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"], ): Promise< - | IResponseSuccessJson - | IResponseErrorNotFound | IResponseErrorInternal | IResponseErrorServiceUnavailable + | IResponseSuccessNoContent > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.getWalletInstanceStatus({ - "fiscal-code": fiscal_code, + const validated = await this.ioWalletApiClient.setWalletInstanceStatus({ + body: { fiscal_code, status }, id, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); - case 404: - return ResponseErrorNotFound( - "Not Found", - "Wallet instance not found" - ); + case 204: + return ResponseSuccessNoContent(); case 400: case 422: case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}` + `Internal server error | ${response.value}`, ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10" + "10", ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -324,47 +361,10 @@ export default class IoWalletService { }); }); - /** - * Get the subscription given a specific user. - */ - public readonly getSubscription = async ( - userId: NonEmptyString - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseSuccessJson> - > => - withCatchAsInternalError(async () => { - const validated = await this.trialSystemApiClient.getSubscription({ - trialId: IO_WALLET_TRIAL_ID, - userId, - }); - - return withValidatedOrInternalError(validated, (response) => { - switch (response.status) { - case 200: - return pipe( - { - createdAt: response.value.createdAt, - state: response.value.state, - }, - ResponseSuccessJson - ); - case 401: - return ResponseErrorInternal("Internal server error"); - case 404: - return ResponseErrorNotFound("Not Found", "Subscription not found"); - case 500: - return ResponseErrorInternal( - pipe( - response.value.detail, - O.fromNullable, - O.getOrElse(() => "Cannot get subscription") - ) - ); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }); - }); + constructor( + private readonly ioWalletApiClient: ReturnType, + private readonly trialSystemApiClient: ReturnType< + typeof TrialSystemAPIClient + >, + ) {} } diff --git a/src/services/lollipopService.ts b/src/services/lollipopService.ts index d956d4370..0a32412df 100644 --- a/src/services/lollipopService.ts +++ b/src/services/lollipopService.ts @@ -1,5 +1,6 @@ import { QueueClient, QueueSendMessageResponse } from "@azure/storage-queue"; import { RevokeAssertionRefInfo } from "@pagopa/io-functions-commons/dist/src/entities/revoke_assertion_ref_info"; + import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; import { base64EncodeObject } from "../utils/messages"; @@ -8,11 +9,11 @@ export default class LollipopService { constructor( private readonly queueStorageConnectionString: string, - private readonly queueName: string + private readonly queueName: string, ) { this.queueClient = new QueueClient( this.queueStorageConnectionString, - this.queueName + this.queueName, ); } @@ -23,7 +24,7 @@ export default class LollipopService { * @param assertionRef the pub key identifier */ public revokePreviousAssertionRef( - assertionRef: AssertionRef + assertionRef: AssertionRef, ): Promise { const revokeMessage = RevokeAssertionRefInfo.encode({ assertion_ref: assertionRef, diff --git a/src/services/newMessagesService.ts b/src/services/newMessagesService.ts index 962316fff..60875c9c8 100644 --- a/src/services/newMessagesService.ts +++ b/src/services/newMessagesService.ts @@ -1,56 +1,67 @@ /** * This service retrieves messages from the API system using an API client. */ -import * as t from "io-ts"; -import nodeFetch from "node-fetch"; import { + IResponseErrorBadGateway, IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, - IResponseErrorServiceUnavailable, IResponseErrorNotFound, + IResponseErrorServiceUnavailable, IResponseErrorTooManyRequests, IResponseErrorValidation, IResponseSuccessJson, - ResponseErrorNotFound, - ResponseErrorTooManyRequests, - ResponseSuccessJson, + IResponseSuccessNoContent, + ResponseErrorBadGateway, ResponseErrorForbiddenNotAuthorized, ResponseErrorInternal, - ResponseErrorValidation, + ResponseErrorNotFound, ResponseErrorServiceTemporarilyUnavailable, - IResponseSuccessNoContent, - ResponseErrorBadGateway, - IResponseErrorBadGateway, + ResponseErrorTooManyRequests, + ResponseErrorValidation, + ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { AppMessagesAPIClient } from "src/clients/app-messages.client"; import { FiscalCode, NonEmptyString, Ulid, } from "@pagopa/ts-commons/lib/strings"; -import { pipe, flow } from "fp-ts/lib/function"; -import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; import * as T from "fp-ts/Task"; -import { LollipopLocalsType } from "src/types/lollipop"; +import * as TE from "fp-ts/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; -import { - Fetch, - getThirdPartyServiceClient, -} from "../clients/third-party-service-client"; -import { PN_SERVICE_ID } from "../config"; -import { MessageSubject } from "../../generated/backend/MessageSubject"; +import * as t from "io-ts"; +import nodeFetch from "node-fetch"; +import { AppMessagesAPIClient } from "src/clients/app-messages.client"; +import { LollipopLocalsType } from "src/types/lollipop"; + +import { CreatedMessageWithContentAndAttachments } from "../../generated/backend/CreatedMessageWithContentAndAttachments"; import { InvalidThirdPartyMessageTypeEnum } from "../../generated/backend/InvalidThirdPartyMessageType"; +import { MessageBodyMarkdown } from "../../generated/backend/MessageBodyMarkdown"; +import { MessageSubject } from "../../generated/backend/MessageSubject"; +import { ThirdPartyData } from "../../generated/backend/ThirdPartyData"; +import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; +import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; import { CreatedMessageWithContent } from "../../generated/io-messages-api/CreatedMessageWithContent"; +import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; +import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; import { PaginatedPublicMessagesCollection } from "../../generated/io-messages-api/PaginatedPublicMessagesCollection"; import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; -import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; -import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; -import { CreatedMessageWithContentAndAttachments } from "../../generated/backend/CreatedMessageWithContentAndAttachments"; -import { getPrescriptionAttachments } from "../utils/attachments"; +import { + ThirdPartyMessage, + ThirdPartyMessageDetails, +} from "../../generated/third-party-service/ThirdPartyMessage"; +import { + Fetch, + getThirdPartyServiceClient, +} from "../clients/third-party-service-client"; +import { PN_SERVICE_ID } from "../config"; import { User } from "../types/user"; +import { getPrescriptionAttachments } from "../utils/attachments"; +import { FileType, getIsFileTypeForTypes } from "../utils/file-type"; +import { log } from "../utils/logger"; import { IResponseErrorUnsupportedMediaType, IResponseSuccessOctet, @@ -63,16 +74,6 @@ import { withValidatedOrInternalError, wrapValidationWithInternalError, } from "../utils/responses"; -import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; -import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; -import { - ThirdPartyMessage, - ThirdPartyMessageDetails, -} from "../../generated/third-party-service/ThirdPartyMessage"; -import { ThirdPartyData } from "../../generated/backend/ThirdPartyData"; -import { log } from "../utils/logger"; -import { FileType, getIsFileTypeForTypes } from "../utils/file-type"; -import { MessageBodyMarkdown } from "../../generated/backend/MessageBodyMarkdown"; const ALLOWED_TYPES: ReadonlySet = new Set(["pdf"]); @@ -90,336 +91,48 @@ export type MessageWithThirdPartyData = t.TypeOf< >; const isMessageWithThirdPartyData = ( - value: CreatedMessageWithContent + value: CreatedMessageWithContent, ): value is MessageWithThirdPartyData => E.isRight(MessageWithThirdPartyData.decode(value)); export default class NewMessagesService { - constructor( - private readonly apiClient: ReturnType - ) {} - - /** - * Retrieves all messages for a specific user. - */ - public readonly getMessagesByUser = ( - user: User, - params: GetMessagesParameters - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const validated = await this.apiClient.getMessagesByUser({ - /* eslint-disable sort-keys */ - fiscal_code: user.fiscal_code, - page_size: params.pageSize, - enrich_result_data: params.enrichResultData, - archived: params.getArchivedMessages, - maximum_id: params.maximumId, - minimum_id: params.minimumId, - /* eslint-enable sort-keys */ - }); - - return withValidatedOrInternalError(validated, (response) => - response.status === 200 - ? ResponseSuccessJson(response.value) - : response.status === 404 - ? ResponseErrorNotFound("Not found", "User not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) - ); - }); - - /** - * Retrieves a specific message. - */ - public readonly getMessage = async ( - user: User, - params: GetMessageParameters - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const res = await this.apiClient.getMessage({ - fiscal_code: user.fiscal_code, - id: params.id, - public_message: params.public_message, - }); - - const resMessageContent = pipe( - res, - E.map((_) => (_.status === 200 ? { ..._, value: _.value.message } : _)) - ); - - return withValidatedOrInternalError( - resMessageContent, - async (response) => { - if (response.status === 200) { - const messageWithContent = response.value; - const maybePrescriptionData = O.fromNullable( - messageWithContent.content.prescription_data - ); - - return O.isNone(maybePrescriptionData) - ? ResponseSuccessJson(messageWithContent) - : pipe( - getPrescriptionAttachments(maybePrescriptionData.value), - T.map((attachments) => ({ - ...messageWithContent, - content: { - ...messageWithContent.content, - attachments, - }, - })), - T.map(ResponseSuccessJson) - )(); - } - - return response.status === 404 - ? ResponseErrorNotFound("Not found", "Message not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status); - } - ); - }); - - /** - * Retrieve the service preferences fot the defined user and service - */ - public readonly upsertMessageStatus = ( - fiscalCode: FiscalCode, - messageId: Ulid, - messageStatusChange: MessageStatusChange - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const validated = await this.apiClient.upsertMessageStatusAttributes({ - body: messageStatusChange, - fiscal_code: fiscalCode, - id: messageId, - }); - - // eslint-disable-next-line sonarjs/no-identical-functions - return withValidatedOrInternalError(validated, (response) => { - switch (response.status) { - case 200: - return ResponseSuccessJson({ - is_archived: response.value.is_archived, - is_read: response.value.is_read, - }); - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; - case 404: - return ResponseErrorNotFound( - "Not Found", - "Message status not found" - ); - case 429: - return ResponseErrorTooManyRequests(); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }); - }); - - // ------------------------------ - // THIRD_PARTY MESSAGE - // ------------------------------ - - /** - * Retrieves the precondition of a specific Third-Party message. - */ - public readonly getThirdPartyMessagePrecondition = async ( + // return an error otherwise + private readonly getThirdPartyAttachmentFromThirdPartyService = ( message: MessageWithThirdPartyData, + attachmentUrl: NonEmptyString, remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation + lollipopLocals?: LollipopLocalsType, + ): TE.TaskEither< | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal | IResponseErrorNotFound + | IResponseErrorServiceUnavailable | IResponseErrorTooManyRequests - | IResponseSuccessNoContent - | IResponseSuccessJson + | IResponseErrorValidation, + Buffer > => pipe( - this.getThirdPartyMessagePreconditionFromThirdPartyService( - message, + getThirdPartyServiceClient( remoteContentConfiguration, - lollipopLocals + nodeFetch as unknown as Fetch, + lollipopLocals, ), - TE.map(ResponseSuccessJson), - TE.toUnion - )(); - - /** - * Retrieves a specific Third-Party message. - */ - public readonly getThirdPartyMessage = async ( - message: MessageWithThirdPartyData, - remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorBadGateway - | IResponseSuccessJson - > => - pipe( - pipe( - this.getThirdPartyMessageFromThirdPartyService( - message, - remoteContentConfiguration, - lollipopLocals + TE.of, + TE.map((getClientByFiscalCode) => + getClientByFiscalCode(message.fiscal_code), + ), + TE.chainW((client) => + TE.tryCatch( + () => + client.getThirdPartyMessageAttachment({ + attachment_url: attachmentUrl, + id: message.content.third_party_data.id, + ...lollipopLocals, + }), + (e) => ResponseErrorInternal(E.toError(e).message), ), - TE.map((thirdPartyMessage) => ({ - ...message, - third_party_message: thirdPartyMessage, - })) ), - TE.map(ResponseSuccessJson), - TE.toUnion - )(); - - /** - * Retrieves an attachment related to a message - */ - public readonly getThirdPartyAttachment = async ( - message: MessageWithThirdPartyData, - attachmentUrl: NonEmptyString, - remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType - ): Promise< - | IResponseErrorInternal - | IResponseErrorServiceUnavailable - | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorUnsupportedMediaType - | IResponseSuccessOctet - > => - pipe( - pipe( - this.getThirdPartyAttachmentFromThirdPartyService( - message, - attachmentUrl, - remoteContentConfiguration, - lollipopLocals - ) - ), - TE.filterOrElseW(getIsFileTypeForTypes(ALLOWED_TYPES), () => - ResponseErrorUnsupportedMediaType( - "The requested file is not a valid PDF" - ) - ), - TE.map(ResponseSuccessOctet), - TE.toUnion - )(); - - public readonly getThirdPartyMessageFnApp = ( - fiscalCode: FiscalCode, - messageId: Ulid - ): TE.TaskEither< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorNotFound - | IResponseErrorTooManyRequests, - MessageWithThirdPartyData - > => - pipe( - TE.tryCatch( - () => - this.apiClient.getMessage({ - fiscal_code: fiscalCode, - id: messageId, - }), - (e) => ResponseErrorInternal(E.toError(e).message) - ), - TE.chain(wrapValidationWithInternalError), - - TE.chainW( - flow( - (response) => - response.status === 200 - ? E.of(response.value.message) - : E.left(response), - TE.fromEither, - TE.mapLeft((response) => { - log.error( - `newMessagesService|getThirdPartyMessageFnApp|result:${ - response.status - } [title: ${response.value?.title ?? "No title"}, detail: ${ - response.value?.detail ?? "No detail" - }, type: ${response.value?.type ?? "No type"}]` - ); - return response; - }), - TE.mapLeft((response) => { - switch (response.status) { - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 404: - return ResponseErrorNotFound("Not found", "Message not found"); - case 429: - return ResponseErrorTooManyRequests(); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }) - ) - ), - TE.chainW( - // MessageWithThirdPartyData.is fails, we need to check the decode instead - TE.fromPredicate(isMessageWithThirdPartyData, () => - ResponseErrorValidation( - "Bad request", - "The message retrieved is not a valid message with third-party data" - ) - ) - ) - ); - - public readonly getRCConfiguration = ( - configurationId: Ulid - ): TE.TaskEither< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorNotFound - | IResponseErrorTooManyRequests, - RCConfigurationPublic - > => - pipe( - TE.tryCatch( - () => - this.apiClient.getRCConfiguration({ - id: configurationId, - }), - (e) => ResponseErrorInternal(E.toError(e).message) - ), - TE.chain(wrapValidationWithInternalError), - + TE.chainW(wrapValidationWithInternalError), TE.chainW( flow( (response) => @@ -427,71 +140,80 @@ export default class NewMessagesService { TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getRCConfiguration|result:${ + `newMessagesService|getThirdPartyAttachmentFromThirdPartyService|invocation returned an error:${ response.status - } [title: ${response.value?.title ?? "No title"}, detail: ${ - response.value?.detail ?? "No detail" - }, type: ${response.value?.type ?? "No type"}]` + } [title: ${response.value?.title ?? "No title"}, detail: ${ + response.value?.detail ?? "No details" + }, type: ${response.value?.type ?? "No type"}])`, ); return response; }), - TE.mapLeft((response) => { - switch (response.status) { - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 404: - return ResponseErrorNotFound( - "Not found", - "RC Configuration not found" - ); - case 429: - return ResponseErrorTooManyRequests(); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }) - ) - ) + TE.mapLeft( + flow((response) => { + switch (response.status) { + case 400: + return ResponseErrorValidation(ERROR_MESSAGE_400, ""); + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 403: + return ResponseErrorForbiddenNotAuthorized; + case 404: + return ResponseErrorNotFound( + "Not found", + "Attachment from Third Party service not found", + ); + case 429: + return ResponseErrorTooManyRequests(); + case 500: + return ResponseErrorInternal(ERROR_MESSAGE_500); + case 503: + const retryAfter = response.headers["Retry-After"] ?? "10"; + return ResponseErrorServiceTemporarilyUnavailable( + ERROR_MESSAGE_503, + retryAfter, + ); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }), + ), + ), + ), ); - // ------------------------------------ - // Private Functions - // ------------------------------------ - - // Retrieve a ThirdParty message precondition for a specific message, if exists // return an error otherwise - private readonly getThirdPartyMessagePreconditionFromThirdPartyService = ( + private readonly getThirdPartyMessageFromThirdPartyService = ( message: MessageWithThirdPartyData, remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType + lollipopLocals?: LollipopLocalsType, ): TE.TaskEither< - | IResponseErrorInternal - | IResponseErrorValidation + | IResponseErrorBadGateway | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseSuccessNoContent, - ThirdPartyMessagePrecondition + | IResponseErrorValidation, + ThirdPartyMessage > => pipe( getThirdPartyServiceClient( remoteContentConfiguration, nodeFetch as unknown as Fetch, - lollipopLocals + lollipopLocals, ), TE.of, TE.map((getClientByFiscalCode) => - getClientByFiscalCode(message.fiscal_code) + getClientByFiscalCode(message.fiscal_code), ), - TE.chain((client) => + TE.chainW((client) => TE.tryCatch( () => - client.getThirdPartyMessagePrecondition({ + client.getThirdPartyMessageDetails({ id: message.content.third_party_data.id, ...lollipopLocals, }), - (e) => ResponseErrorInternal(E.toError(e).message) - ) + (e) => ResponseErrorInternal(E.toError(e).message), + ), ), TE.chainW(wrapValidationWithInternalError), TE.chainW( @@ -501,12 +223,11 @@ export default class NewMessagesService { TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getThirdPartyMessagePreconditionFromThirdPartyService|invocation returned an error:${ + `newMessagesService|getThirdPartyMessageFromThirdPartyService|invocation returned an error:${ response.status } [title: ${response.value?.title ?? "No title"}, detail: ${ - // eslint-disable-next-line sonarjs/no-duplicate-string response.value?.detail ?? "No details" - }, type: ${response.value?.type ?? "No type"}]` + }, type: ${response.value?.type ?? "No type"}]`, ); return response; }), @@ -514,10 +235,7 @@ export default class NewMessagesService { flow((response) => { switch (response.status) { case 400: - return ResponseErrorValidation( - ERROR_MESSAGE_400, - "Third party service returned 400" - ); + return ResponseErrorValidation(ERROR_MESSAGE_400, ""); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: @@ -525,7 +243,7 @@ export default class NewMessagesService { case 404: return ResponseErrorNotFound( "Not found", - "Message from Third Party service not found" + "Message from Third Party service not found", ); case 429: return ResponseErrorTooManyRequests(); @@ -534,46 +252,48 @@ export default class NewMessagesService { default: return ResponseErrorStatusNotDefinedInSpec(response); } - }) - ) - ) - ) + }), + ), + TE.chainW((response) => + this.validateThirdPartyMessageResponse(message, response), + ), + ), + ), ); - // Retrieve a ThirdParty message detail from related service, if exists // return an error otherwise - private readonly getThirdPartyMessageFromThirdPartyService = ( + private readonly getThirdPartyMessagePreconditionFromThirdPartyService = ( message: MessageWithThirdPartyData, remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType + lollipopLocals?: LollipopLocalsType, ): TE.TaskEither< - | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorBadGateway, - ThirdPartyMessage + | IResponseErrorValidation + | IResponseSuccessNoContent, + ThirdPartyMessagePrecondition > => pipe( getThirdPartyServiceClient( remoteContentConfiguration, nodeFetch as unknown as Fetch, - lollipopLocals + lollipopLocals, ), TE.of, TE.map((getClientByFiscalCode) => - getClientByFiscalCode(message.fiscal_code) + getClientByFiscalCode(message.fiscal_code), ), - TE.chainW((client) => + TE.chain((client) => TE.tryCatch( () => - client.getThirdPartyMessageDetails({ + client.getThirdPartyMessagePrecondition({ id: message.content.third_party_data.id, ...lollipopLocals, }), - (e) => ResponseErrorInternal(E.toError(e).message) - ) + (e) => ResponseErrorInternal(E.toError(e).message), + ), ), TE.chainW(wrapValidationWithInternalError), TE.chainW( @@ -583,21 +303,22 @@ export default class NewMessagesService { TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getThirdPartyMessageFromThirdPartyService|invocation returned an error:${ + `newMessagesService|getThirdPartyMessagePreconditionFromThirdPartyService|invocation returned an error:${ response.status } [title: ${response.value?.title ?? "No title"}, detail: ${ - // eslint-disable-next-line sonarjs/no-duplicate-string response.value?.detail ?? "No details" - }, type: ${response.value?.type ?? "No type"}]` + }, type: ${response.value?.type ?? "No type"}]`, ); return response; }), TE.mapLeft( - // eslint-disable-next-line sonarjs/no-identical-functions flow((response) => { switch (response.status) { case 400: - return ResponseErrorValidation(ERROR_MESSAGE_400, ""); + return ResponseErrorValidation( + ERROR_MESSAGE_400, + "Third party service returned 400", + ); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: @@ -605,7 +326,7 @@ export default class NewMessagesService { case 404: return ResponseErrorNotFound( "Not found", - "Message from Third Party service not found" + "Message from Third Party service not found", ); case 429: return ResponseErrorTooManyRequests(); @@ -614,18 +335,15 @@ export default class NewMessagesService { default: return ResponseErrorStatusNotDefinedInSpec(response); } - }) + }), ), - TE.chainW((response) => - this.validateThirdPartyMessageResponse(message, response) - ) - ) - ) + ), + ), ); private readonly validateThirdPartyMessageResponse = ( message: MessageWithThirdPartyData, - response: ThirdPartyMessageDetails + response: ThirdPartyMessageDetails, ): TE.TaskEither => { // PN does not need this validation because it is managed in a different way with different specs if (message.sender_service_id === PN_SERVICE_ID) { @@ -640,8 +358,8 @@ export default class NewMessagesService { ) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.ATTACHMENTS_NOT_PRESENT - ) + InvalidThirdPartyMessageTypeEnum.ATTACHMENTS_NOT_PRESENT, + ), ); } // if has_remote_content is true and there is no remote content than an error must be thrown @@ -650,8 +368,8 @@ export default class NewMessagesService { if (shouldContainRemoteContent && !response.details) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.REMOTE_CONTENT_NOT_PRESENT - ) + InvalidThirdPartyMessageTypeEnum.REMOTE_CONTENT_NOT_PRESENT, + ), ); } // if has_remote_content is true and the remote markdown is not between 80 and 10000 characters than an error must be throw @@ -659,8 +377,8 @@ export default class NewMessagesService { if (shouldContainRemoteContent && !isMarkdownValid) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.MARKDOWN_VALIDATION_ERROR - ) + InvalidThirdPartyMessageTypeEnum.MARKDOWN_VALIDATION_ERROR, + ), ); } // if has_remote_content is true and the remote subject is not between 10 and 121 characters than an error must be throw @@ -668,8 +386,8 @@ export default class NewMessagesService { if (shouldContainRemoteContent && !isSubjectValid) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.SUBJECT_VALIDATION_ERROR - ) + InvalidThirdPartyMessageTypeEnum.SUBJECT_VALIDATION_ERROR, + ), ); } // return a validated response by checking the flags @@ -688,90 +406,368 @@ export default class NewMessagesService { }); }; - // Retrieve a ThirdParty attachment from related service, if exists - // return an error otherwise - private readonly getThirdPartyAttachmentFromThirdPartyService = ( - message: MessageWithThirdPartyData, - attachmentUrl: NonEmptyString, - remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType - ): TE.TaskEither< + // ------------------------------ + // THIRD_PARTY MESSAGE + // ------------------------------ + + /** + * Retrieves a specific message. + */ + public readonly getMessage = async ( + user: User, + params: GetMessageParameters, + ): Promise< | IResponseErrorInternal - | IResponseErrorServiceUnavailable - | IResponseErrorValidation - | IResponseErrorForbiddenNotAuthorized | IResponseErrorNotFound - | IResponseErrorTooManyRequests, - Buffer + | IResponseErrorTooManyRequests + | IResponseSuccessJson > => - pipe( - getThirdPartyServiceClient( - remoteContentConfiguration, - nodeFetch as unknown as Fetch, - lollipopLocals - ), - TE.of, - TE.map((getClientByFiscalCode) => - getClientByFiscalCode(message.fiscal_code) - ), - TE.chainW((client) => - TE.tryCatch( - () => - client.getThirdPartyMessageAttachment({ - attachment_url: attachmentUrl, - id: message.content.third_party_data.id, - ...lollipopLocals, - }), - (e) => ResponseErrorInternal(E.toError(e).message) - ) - ), - TE.chainW(wrapValidationWithInternalError), - TE.chainW( - flow( + withCatchAsInternalError(async () => { + const res = await this.apiClient.getMessage({ + fiscal_code: user.fiscal_code, + id: params.id, + public_message: params.public_message, + }); + + const resMessageContent = pipe( + res, + E.map((_) => (_.status === 200 ? { ..._, value: _.value.message } : _)), + ); + + return withValidatedOrInternalError( + resMessageContent, + async (response) => { + if (response.status === 200) { + const messageWithContent = response.value; + const maybePrescriptionData = O.fromNullable( + messageWithContent.content.prescription_data, + ); + + return O.isNone(maybePrescriptionData) + ? ResponseSuccessJson(messageWithContent) + : pipe( + getPrescriptionAttachments(maybePrescriptionData.value), + T.map((attachments) => ({ + ...messageWithContent, + content: { + ...messageWithContent.content, + attachments, + }, + })), + T.map(ResponseSuccessJson), + )(); + } + + return response.status === 404 + ? ResponseErrorNotFound("Not found", "Message not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status); + }, + ); + }); + + /** + * Retrieves all messages for a specific user. + */ + public readonly getMessagesByUser = ( + user: User, + params: GetMessagesParameters, + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => { + const validated = await this.apiClient.getMessagesByUser({ + archived: params.getArchivedMessages, + enrich_result_data: params.enrichResultData, + /* eslint-disable sort-keys */ + fiscal_code: user.fiscal_code, + maximum_id: params.maximumId, + minimum_id: params.minimumId, + page_size: params.pageSize, + /* eslint-enable sort-keys */ + }); + + return withValidatedOrInternalError(validated, (response) => + response.status === 200 + ? ResponseSuccessJson(response.value) + : response.status === 404 + ? ResponseErrorNotFound("Not found", "User not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status), + ); + }); + + public readonly getRCConfiguration = ( + configurationId: Ulid, + ): TE.TaskEither< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation, + RCConfigurationPublic + > => + pipe( + TE.tryCatch( + () => + this.apiClient.getRCConfiguration({ + id: configurationId, + }), + (e) => ResponseErrorInternal(E.toError(e).message), + ), + TE.chain(wrapValidationWithInternalError), + + TE.chainW( + flow( (response) => response.status === 200 ? E.of(response.value) : E.left(response), TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getThirdPartyAttachmentFromThirdPartyService|invocation returned an error:${ + `newMessagesService|getRCConfiguration|result:${ response.status - } [title: ${response.value?.title ?? "No title"}, detail: ${ - // eslint-disable-next-line sonarjs/no-duplicate-string - response.value?.detail ?? "No details" - }, type: ${response.value?.type ?? "No type"}])` + } [title: ${response.value?.title ?? "No title"}, detail: ${ + response.value?.detail ?? "No detail" + }, type: ${response.value?.type ?? "No type"}]`, ); return response; }), - TE.mapLeft( - flow((response) => { - switch (response.status) { - case 400: - return ResponseErrorValidation(ERROR_MESSAGE_400, ""); - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; - case 404: - return ResponseErrorNotFound( - "Not found", - "Attachment from Third Party service not found" - ); - case 429: - return ResponseErrorTooManyRequests(); - case 500: - return ResponseErrorInternal(ERROR_MESSAGE_500); - case 503: - const retryAfter = response.headers["Retry-After"] ?? "10"; - return ResponseErrorServiceTemporarilyUnavailable( - ERROR_MESSAGE_503, - retryAfter - ); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }) - ) - ) - ) + TE.mapLeft((response) => { + switch (response.status) { + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 404: + return ResponseErrorNotFound( + "Not found", + "RC Configuration not found", + ); + case 429: + return ResponseErrorTooManyRequests(); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }), + ), + ), ); + + /** + * Retrieves an attachment related to a message + */ + public readonly getThirdPartyAttachment = async ( + message: MessageWithThirdPartyData, + attachmentUrl: NonEmptyString, + remoteContentConfiguration: RCConfigurationPublic, + lollipopLocals?: LollipopLocalsType, + ): Promise< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorServiceUnavailable + | IResponseErrorTooManyRequests + | IResponseErrorUnsupportedMediaType + | IResponseErrorValidation + | IResponseSuccessOctet + > => + pipe( + pipe( + this.getThirdPartyAttachmentFromThirdPartyService( + message, + attachmentUrl, + remoteContentConfiguration, + lollipopLocals, + ), + ), + TE.filterOrElseW(getIsFileTypeForTypes(ALLOWED_TYPES), () => + ResponseErrorUnsupportedMediaType( + "The requested file is not a valid PDF", + ), + ), + TE.map(ResponseSuccessOctet), + TE.toUnion, + )(); + + /** + * Retrieves a specific Third-Party message. + */ + public readonly getThirdPartyMessage = async ( + message: MessageWithThirdPartyData, + remoteContentConfiguration: RCConfigurationPublic, + lollipopLocals?: LollipopLocalsType, + ): Promise< + | IResponseErrorBadGateway + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation + | IResponseSuccessJson + > => + pipe( + pipe( + this.getThirdPartyMessageFromThirdPartyService( + message, + remoteContentConfiguration, + lollipopLocals, + ), + TE.map((thirdPartyMessage) => ({ + ...message, + third_party_message: thirdPartyMessage, + })), + ), + TE.map(ResponseSuccessJson), + TE.toUnion, + )(); + + // ------------------------------------ + // Private Functions + // ------------------------------------ + + // Retrieve a ThirdParty message precondition for a specific message, if exists + public readonly getThirdPartyMessageFnApp = ( + fiscalCode: FiscalCode, + messageId: Ulid, + ): TE.TaskEither< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation, + MessageWithThirdPartyData + > => + pipe( + TE.tryCatch( + () => + this.apiClient.getMessage({ + fiscal_code: fiscalCode, + id: messageId, + }), + (e) => ResponseErrorInternal(E.toError(e).message), + ), + TE.chain(wrapValidationWithInternalError), + + TE.chainW( + flow( + (response) => + response.status === 200 + ? E.of(response.value.message) + : E.left(response), + TE.fromEither, + TE.mapLeft((response) => { + log.error( + `newMessagesService|getThirdPartyMessageFnApp|result:${ + response.status + } [title: ${response.value?.title ?? "No title"}, detail: ${ + response.value?.detail ?? "No detail" + }, type: ${response.value?.type ?? "No type"}]`, + ); + return response; + }), + TE.mapLeft((response) => { + switch (response.status) { + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 404: + return ResponseErrorNotFound("Not found", "Message not found"); + case 429: + return ResponseErrorTooManyRequests(); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }), + ), + ), + TE.chainW( + // MessageWithThirdPartyData.is fails, we need to check the decode instead + TE.fromPredicate(isMessageWithThirdPartyData, () => + ResponseErrorValidation( + "Bad request", + "The message retrieved is not a valid message with third-party data", + ), + ), + ), + ); + + // Retrieve a ThirdParty message detail from related service, if exists + /** + * Retrieves the precondition of a specific Third-Party message. + */ + public readonly getThirdPartyMessagePrecondition = async ( + message: MessageWithThirdPartyData, + remoteContentConfiguration: RCConfigurationPublic, + lollipopLocals?: LollipopLocalsType, + ): Promise< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation + | IResponseSuccessJson + | IResponseSuccessNoContent + > => + pipe( + this.getThirdPartyMessagePreconditionFromThirdPartyService( + message, + remoteContentConfiguration, + lollipopLocals, + ), + TE.map(ResponseSuccessJson), + TE.toUnion, + )(); + + /** + * Retrieve the service preferences fot the defined user and service + */ + public readonly upsertMessageStatus = ( + fiscalCode: FiscalCode, + messageId: Ulid, + messageStatusChange: MessageStatusChange, + ): Promise< + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorValidation + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => { + const validated = await this.apiClient.upsertMessageStatusAttributes({ + body: messageStatusChange, + fiscal_code: fiscalCode, + id: messageId, + }); + + return withValidatedOrInternalError(validated, (response) => { + switch (response.status) { + case 200: + return ResponseSuccessJson({ + is_archived: response.value.is_archived, + is_read: response.value.is_read, + }); + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 403: + return ResponseErrorForbiddenNotAuthorized; + case 404: + return ResponseErrorNotFound( + "Not Found", + "Message status not found", + ); + case 429: + return ResponseErrorTooManyRequests(); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }); + }); + + // Retrieve a ThirdParty attachment from related service, if exists + constructor( + private readonly apiClient: ReturnType, + ) {} } diff --git a/src/services/notificationService.ts b/src/services/notificationService.ts index 17ac89318..7dff5ca38 100644 --- a/src/services/notificationService.ts +++ b/src/services/notificationService.ts @@ -2,16 +2,16 @@ * This service post a notification to the Notification queue. */ +import { QueueClient } from "@azure/storage-queue"; import { IResponseErrorInternal, IResponseSuccessJson, ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - -import { QueueClient } from "@azure/storage-queue"; import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; + import { FiscalCode } from "../../generated/backend/FiscalCode"; import { Installation } from "../../generated/backend/Installation"; import { @@ -29,55 +29,14 @@ import { } from "../../generated/messages/NotifyMessage"; import { Notification } from "../../generated/notifications/Notification"; import { SuccessResponse } from "../../generated/notifications/SuccessResponse"; - import { toFiscalCodeHash } from "../types/notification"; import { base64EncodeObject } from "../utils/messages"; export default class NotificationService { private readonly notificationQueueClient: QueueClient; - constructor( - private readonly queueStorageConnectionString: string, - private readonly queueName: string - ) { - this.notificationQueueClient = new QueueClient( - this.queueStorageConnectionString, - this.queueName - ); - } - - public readonly notify = ( - notification: Notification, - notificationSubject: string, - notificationTitle?: string - ): Promise< - IResponseErrorInternal | IResponseSuccessJson - > => { - const notifyMessage: NotifyMessage = { - installationId: toFiscalCodeHash(notification.message.fiscal_code), - kind: NotifyKind[NotificationMessageKindEnum.Notify], - payload: { - message: notificationSubject, - message_id: notification.message.id, - title: pipe( - notificationTitle, - O.fromNullable, - O.getOrElse(() => `${notification.sender_metadata.organization_name}`) - ), - }, - }; - return this.notificationQueueClient - .sendMessage(base64EncodeObject(notifyMessage)) - .then(() => ResponseSuccessJson({ message: "ok" })) - .catch((error) => - ResponseErrorInternal( - `Error while sending notify message to the queue [${error.message}]` - ) - ); - }; - public readonly createOrUpdateInstallation = ( fiscalCode: FiscalCode, - installation: Installation + installation: Installation, ): Promise< IResponseErrorInternal | IResponseSuccessJson > => { @@ -98,13 +57,13 @@ export default class NotificationService { .then(() => ResponseSuccessJson({ message: "ok" })) .catch((error) => ResponseErrorInternal( - `Error while sending create or update installation message to the queue [${error.message}]` - ) + `Error while sending create or update installation message to the queue [${error.message}]`, + ), ); }; public readonly deleteInstallation = ( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ): Promise< IResponseErrorInternal | IResponseSuccessJson > => { @@ -117,8 +76,50 @@ export default class NotificationService { .then(() => ResponseSuccessJson({ message: "ok" })) .catch((error) => ResponseErrorInternal( - `Error while sending delete installation message to the queue [${error.message}]` - ) + `Error while sending delete installation message to the queue [${error.message}]`, + ), + ); + }; + + public readonly notify = ( + notification: Notification, + notificationSubject: string, + notificationTitle?: string, + ): Promise< + IResponseErrorInternal | IResponseSuccessJson + > => { + const notifyMessage: NotifyMessage = { + installationId: toFiscalCodeHash(notification.message.fiscal_code), + kind: NotifyKind[NotificationMessageKindEnum.Notify], + payload: { + message: notificationSubject, + message_id: notification.message.id, + title: pipe( + notificationTitle, + O.fromNullable, + O.getOrElse( + () => `${notification.sender_metadata.organization_name}`, + ), + ), + }, + }; + return this.notificationQueueClient + .sendMessage(base64EncodeObject(notifyMessage)) + .then(() => ResponseSuccessJson({ message: "ok" })) + .catch((error) => + ResponseErrorInternal( + `Error while sending notify message to the queue [${error.message}]`, + ), ); }; + + constructor( + private readonly queueStorageConnectionString: string, + private readonly queueName: string, + ) { + this.notificationQueueClient = new QueueClient( + this.queueStorageConnectionString, + this.queueName, + ); + } } diff --git a/src/services/notificationServiceFactory.ts b/src/services/notificationServiceFactory.ts index a45ff6c2a..87bf13557 100644 --- a/src/services/notificationServiceFactory.ts +++ b/src/services/notificationServiceFactory.ts @@ -3,12 +3,11 @@ import * as B from "fp-ts/boolean"; import { flow } from "fp-ts/lib/function"; import { FiscalCode } from "../../generated/io-bonus-api/FiscalCode"; +import { toFiscalCodeHash } from "../types/notification"; import { FeatureFlag, getIsUserEligibleForNewFeature, } from "../utils/featureFlag"; -import { toFiscalCodeHash } from "../types/notification"; - import NotificationService from "./notificationService"; /** @@ -17,7 +16,7 @@ import NotificationService from "./notificationService"; * @returns */ const getIsUserACanaryTestUser = ( - regex: string + regex: string, ): ((sha: NonEmptyString) => boolean) => { const regExp = new RegExp(regex); return (sha: NonEmptyString): boolean => regExp.test(sha); @@ -26,35 +25,35 @@ const getIsUserACanaryTestUser = ( // ------------------------------------------ export type NotificationServiceFactory = ( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ) => NotificationService; export const getNotificationServiceFactory: ( oldNotificationService: NotificationService, newNotificationService: NotificationService, - betaTesters: ReadonlyArray, + betaTesters: readonly FiscalCode[], canaryTestUserRegex: NonEmptyString, - ff: FeatureFlag + ff: FeatureFlag, ) => NotificationServiceFactory = ( oldNotificationService, newNotificationService, betaTesters, canaryTestUserRegex, - ff + ff, ) => { const isUserACanaryTestUser = getIsUserACanaryTestUser(canaryTestUserRegex); const isUserEligible = getIsUserEligibleForNewFeature( (cf) => betaTesters.includes(cf), (cf) => isUserACanaryTestUser(toFiscalCodeHash(cf)), - ff + ff, ); return flow( isUserEligible, B.fold( () => oldNotificationService, - () => newNotificationService - ) + () => newNotificationService, + ), ); }; diff --git a/src/services/pagoPAClientFactory.ts b/src/services/pagoPAClientFactory.ts index f4e0480a2..5d14e63f1 100644 --- a/src/services/pagoPAClientFactory.ts +++ b/src/services/pagoPAClientFactory.ts @@ -24,17 +24,17 @@ export default class PagoPAClientFactory pagoPAApiKeyUAT: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch + fetchApi: typeof fetch = nodeFetch as any as typeof fetch, ) { this.prodApiClient = PagoPAClient( pagoPAApiUrlProd, pagoPAApiKeyProd, - fetchApi + fetchApi, ); this.testApiClient = PagoPAClient( pagoPAApiUrlUAT, pagoPAApiKeyUAT, - fetchApi + fetchApi, ); } diff --git a/src/services/pagoPAProxyService.ts b/src/services/pagoPAProxyService.ts index a1bc936c2..2772240cc 100644 --- a/src/services/pagoPAProxyService.ts +++ b/src/services/pagoPAProxyService.ts @@ -13,7 +13,6 @@ import { PaymentActivationsGetResponse } from "../../generated/backend/PaymentAc import { PaymentActivationsPostResponse } from "../../generated/backend/PaymentActivationsPostResponse"; import { PaymentRequestsGetResponse } from "../../generated/backend/PaymentRequestsGetResponse"; import { PaymentActivationsPostRequest } from "../../generated/pagopa-proxy/PaymentActivationsPostRequest"; - import { ResponsePaymentError, withCatchAsInternalError, @@ -25,123 +24,125 @@ import { } from "./IPagoPAClientFactory"; export default class PagoPAProxyService { - constructor(private readonly pagoPAClient: IPagoPAClientFactoryInterface) {} - /** - * Retrieve information about a payment. + * Require a lock (activation) for a payment. */ - public readonly getPaymentInfo = ( - rptId: string, - isTest: boolean + public readonly activatePayment = async ( + paymentActivationsPostRequest: PaymentActivationsPostRequest, + isTest: boolean, ): Promise< | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => withCatchAsInternalError(async () => { const client = this.pagoPAClient.getClient( - isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION + isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION, ); - const validated = await client.getPaymentInfo({ - rpt_id_from_string: rptId, + const validated = await client.activatePayment({ + paymentActivationsPostRequest, }); + return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - PaymentRequestsGetResponse.decode(response.value), - ResponseSuccessJson + PaymentActivationsPostResponse.decode(response.value), + ResponseSuccessJson, ) : response.status === 400 - ? ResponseErrorValidation( - // eslint-disable-next-line sonarjs/no-duplicate-string - response.value.title || "Bad request (upstream)", - // eslint-disable-next-line sonarjs/no-duplicate-string - response.value.detail || "Bad request response from upstream API" - ) - : ResponsePaymentError( - response.value.detail, - response.value.detail_v2 - ) + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + response.value.detail || + "Bad request response from upstream API", + ) + : ResponsePaymentError( + response.value.detail, + response.value.detail_v2, + ), ); }); /** - * Require a lock (activation) for a payment. + * Check the activation status to retrieve the paymentId. */ - public readonly activatePayment = async ( - paymentActivationsPostRequest: PaymentActivationsPostRequest, - isTest: boolean + public readonly getActivationStatus = ( + codiceContestoPagamento: string, + isTest: boolean, ): Promise< | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withCatchAsInternalError(async () => { const client = this.pagoPAClient.getClient( - isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION + isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION, ); - const validated = await client.activatePayment({ - paymentActivationsPostRequest, + const validated = await client.getActivationStatus({ + codice_contesto_pagamento: codiceContestoPagamento, }); - return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - PaymentActivationsPostResponse.decode(response.value), - ResponseSuccessJson + PaymentActivationsGetResponse.decode(response.value), + ResponseSuccessJson, ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - response.value.detail || "Bad request response from upstream API" - ) - : ResponsePaymentError( - response.value.detail, - response.value.detail_v2 - ) + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + response.value.detail || + "Bad request response from upstream API", + ) + : response.status === 404 + ? ResponseErrorNotFound( + response.value.title || "Not found (upstream)", + response.value.detail || "Not found response from upstream", + ) + : ResponseErrorInternal( + response.value.detail || + "Internal server error response from upstream", + ), ); }); /** - * Check the activation status to retrieve the paymentId. + * Retrieve information about a payment. */ - public readonly getActivationStatus = ( - codiceContestoPagamento: string, - isTest: boolean + public readonly getPaymentInfo = ( + rptId: string, + isTest: boolean, ): Promise< | IResponseErrorInternal | IResponseErrorValidation - | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseSuccessJson > => withCatchAsInternalError(async () => { const client = this.pagoPAClient.getClient( - isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION + isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION, ); - const validated = await client.getActivationStatus({ - codice_contesto_pagamento: codiceContestoPagamento, + const validated = await client.getPaymentInfo({ + rpt_id_from_string: rptId, }); return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - PaymentActivationsGetResponse.decode(response.value), - ResponseSuccessJson + PaymentRequestsGetResponse.decode(response.value), + ResponseSuccessJson, ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - response.value.detail || "Bad request response from upstream API" - ) - : response.status === 404 - ? ResponseErrorNotFound( - response.value.title || "Not found (upstream)", - response.value.detail || "Not found response from upstream" - ) - : ResponseErrorInternal( - response.value.detail || - "Internal server error response from upstream" - ) + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + + response.value.detail || + "Bad request response from upstream API", + ) + : ResponsePaymentError( + response.value.detail, + response.value.detail_v2, + ), ); }); + + constructor(private readonly pagoPAClient: IPagoPAClientFactoryInterface) {} } diff --git a/src/services/pnService.ts b/src/services/pnService.ts index 1172e1aa3..1ba915e68 100644 --- a/src/services/pnService.ts +++ b/src/services/pnService.ts @@ -1,13 +1,13 @@ +import { FiscalCode } from "../../generated/backend/FiscalCode"; import { IoCourtesyDigitalAddressActivation } from "../../generated/piattaforma-notifiche-courtesy/IoCourtesyDigitalAddressActivation"; import { PNClientFactory, PNEnvironment } from "../clients/pn-clients"; -import { FiscalCode } from "../../generated/backend/FiscalCode"; const upsertPnActivationService = (PnAddressBookIOClientSelector: ReturnType) => ( pnEnvironment: PNEnvironment, fiscalCode: FiscalCode, - activationStatusPayload: IoCourtesyDigitalAddressActivation + activationStatusPayload: IoCourtesyDigitalAddressActivation, ) => PnAddressBookIOClientSelector(pnEnvironment).setCourtesyAddressIo({ body: activationStatusPayload, @@ -22,7 +22,7 @@ const getPnActivationService = }); export const PNService = ( - PnAddressBookIOClientSelector: ReturnType + PnAddressBookIOClientSelector: ReturnType, ) => ({ getPnActivation: getPnActivationService(PnAddressBookIOClientSelector), upsertPnActivation: upsertPnActivationService(PnAddressBookIOClientSelector), diff --git a/src/services/profileService.ts b/src/services/profileService.ts index 32cebb846..7499e1981 100644 --- a/src/services/profileService.ts +++ b/src/services/profileService.ts @@ -3,6 +3,10 @@ * an API client. */ +import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; +import { NewProfile } from "@pagopa/io-functions-app-sdk/NewProfile"; +import { Profile as ProfileApi } from "@pagopa/io-functions-app-sdk/Profile"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -19,17 +23,11 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; -import { pipe } from "fp-ts/lib/function"; import * as E from "fp-ts/lib/Either"; -import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; -import { NewProfile } from "@pagopa/io-functions-app-sdk/NewProfile"; -import { Profile as ProfileApi } from "@pagopa/io-functions-app-sdk/Profile"; +import { pipe } from "fp-ts/lib/function"; import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { Profile as ProfileBackend } from "../../generated/backend/Profile"; - import { toInitializedProfile } from "../types/profile"; import { User } from "../types/user"; import { @@ -40,66 +38,78 @@ import { import { IApiClientFactoryInterface } from "./IApiClientFactory"; export default class ProfileService { - constructor(private readonly apiClient: IApiClientFactoryInterface) {} - /** - * Retrieves the profile for a specific user. + * Create the profile of a specific user. */ - public readonly getProfile = ( - user: User + public readonly createProfile = async ( + user: User, + newProfile: NewProfile, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorTooManyRequests - | IResponseErrorNotFound - | IResponseSuccessJson + // This Service response is not binded with any API response, so we remove any payload + // from this Response Success JSON. + | IResponseSuccessJson> > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.getProfile({ + const validated = await client.createProfile({ + body: newProfile, fiscal_code: user.fiscal_code, }); - return withValidatedOrInternalError(validated, (response) => { - if (response.status === 200) { - // we need an ExtendedProfile (and that's what we should have got) but - // since the response may be an ExtendedProfile or a LimitedProfile - // depending on the credentials, we must decode it as an - // ExtendedProfile to be sure it's what we need. - const validatedExtendedProfile = ExtendedProfileApi.decode( - response.value - ); - - return withValidatedOrInternalError(validatedExtendedProfile, (p) => - ResponseSuccessJson(toInitializedProfile(p, user)) - ); - } - - if (response.status === 404) { - return ResponseErrorNotFound("Not Found", "Profile not found"); - } - - // The user has sent too many requests in a given amount of time ("rate limiting"). - if (response.status === 429) { - return ResponseErrorTooManyRequests(); - } - - if (response.status === 500) { - return ResponseErrorInternal( - `Error retrieving the profile [${response.value.detail}]` - ); - } + return withValidatedOrInternalError(validated, (response) => + response.status === 200 + ? // An empty response. + ResponseSuccessJson({}) + : response.status === 409 + ? ResponseErrorConflict( + response.value || + "A user with the provided fiscal code already exists", + ) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status), + ); + }); + }; - return unhandledResponseStatus(response.status); + /** + * Resend the email to complete email validation process + */ + public readonly emailValidationProcess = async ( + user: User, + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseSuccessAccepted + > => { + const client = this.apiClient.getClient(); + return withCatchAsInternalError(async () => { + const validated = await client.startEmailValidationProcess({ + body: { name: user.name }, + fiscal_code: user.fiscal_code, }); + return withValidatedOrInternalError(validated, (response) => + response.status === 202 + ? ResponseSuccessAccepted() + : response.status === 404 + ? ResponseErrorNotFound("Not found", "User not found.") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status), + ); }); }; public readonly getApiProfile = ( - user: User + user: User, ): Promise< | IResponseErrorInternal - | IResponseErrorTooManyRequests | IResponseErrorNotFound + | IResponseErrorTooManyRequests | IResponseSuccessJson > => { const client = this.apiClient.getClient(); @@ -113,10 +123,10 @@ export default class ProfileService { response.value, ExtendedProfileApi.decode, E.mapLeft((_) => - ResponseErrorInternal(errorsToReadableMessages(_).join(" / ")) + ResponseErrorInternal(errorsToReadableMessages(_).join(" / ")), ), E.map(ResponseSuccessJson), - E.toUnion + E.toUnion, ); } // The profile doesn't exists for the user @@ -131,7 +141,7 @@ export default class ProfileService { if (response.status === 500) { return ResponseErrorInternal( - `Error retrieving the profile [${response.value.detail}]` + `Error retrieving the profile [${response.value.detail}]`, ); } @@ -141,39 +151,54 @@ export default class ProfileService { }; /** - * Create the profile of a specific user. + * Retrieves the profile for a specific user. */ - public readonly createProfile = async ( + public readonly getProfile = ( user: User, - newProfile: NewProfile ): Promise< | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorConflict - // This Service response is not binded with any API response, so we remove any payload - // from this Response Success JSON. - | IResponseSuccessJson> + | IResponseSuccessJson > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.createProfile({ - body: newProfile, + const validated = await client.getProfile({ fiscal_code: user.fiscal_code, }); - return withValidatedOrInternalError(validated, (response) => - response.status === 200 - ? // An empty response. - ResponseSuccessJson({}) - : response.status === 409 - ? ResponseErrorConflict( - response.value || - "A user with the provided fiscal code already exists" - ) - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) - ); + return withValidatedOrInternalError(validated, (response) => { + if (response.status === 200) { + // we need an ExtendedProfile (and that's what we should have got) but + // since the response may be an ExtendedProfile or a LimitedProfile + // depending on the credentials, we must decode it as an + // ExtendedProfile to be sure it's what we need. + const validatedExtendedProfile = ExtendedProfileApi.decode( + response.value, + ); + + return withValidatedOrInternalError(validatedExtendedProfile, (p) => + ResponseSuccessJson(toInitializedProfile(p, user)), + ); + } + + if (response.status === 404) { + return ResponseErrorNotFound("Not Found", "Profile not found"); + } + + // The user has sent too many requests in a given amount of time ("rate limiting"). + if (response.status === 429) { + return ResponseErrorTooManyRequests(); + } + + if (response.status === 500) { + return ResponseErrorInternal( + `Error retrieving the profile [${response.value.detail}]`, + ); + } + + return unhandledResponseStatus(response.status); + }); }); }; @@ -182,13 +207,13 @@ export default class ProfileService { */ public readonly updateProfile = async ( user: User, - profileBackend: ProfileBackend + profileBackend: ProfileBackend, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorConflict - | IResponseErrorTooManyRequests | IResponseErrorPreconditionFailed + | IResponseErrorTooManyRequests | IResponseSuccessJson > => { const client = this.apiClient.getClient(); @@ -208,18 +233,18 @@ export default class ProfileService { switch (response.status) { case 200: return ResponseSuccessJson( - toInitializedProfile(response.value, user) + toInitializedProfile(response.value, user), ); case 404: return ResponseErrorNotFound("Not found", "User not found"); case 409: return ResponseErrorConflict( - response.value || "Cannot update profile with wrong version" + response.value || "Cannot update profile with wrong version", ); case 412: return ResponseErrorPreconditionFailed( "The provided e-mail address is not unique", - response.value.type + response.value.type, ); case 429: return ResponseErrorTooManyRequests(); @@ -227,36 +252,9 @@ export default class ProfileService { return unhandledResponseStatus(response.status); } }); - }) + }), ); }; - /** - * Resend the email to complete email validation process - */ - public readonly emailValidationProcess = async ( - user: User - ): Promise< - | IResponseErrorInternal - | IResponseErrorTooManyRequests - | IResponseErrorNotFound - | IResponseSuccessAccepted - > => { - const client = this.apiClient.getClient(); - return withCatchAsInternalError(async () => { - const validated = await client.startEmailValidationProcess({ - body: { name: user.name }, - fiscal_code: user.fiscal_code, - }); - return withValidatedOrInternalError(validated, (response) => - response.status === 202 - ? ResponseSuccessAccepted() - : response.status === 404 - ? ResponseErrorNotFound("Not found", "User not found.") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) - ); - }); - }; + constructor(private readonly apiClient: IApiClientFactoryInterface) {} } diff --git a/src/services/redisSessionStorage.ts b/src/services/redisSessionStorage.ts index 0534a7eda..50d108c72 100644 --- a/src/services/redisSessionStorage.ts +++ b/src/services/redisSessionStorage.ts @@ -2,28 +2,29 @@ * This service uses the Redis client to store and retrieve session information. */ -import { isArray } from "util"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import * as A from "fp-ts/lib/Array"; -import * as ROA from "fp-ts/lib/ReadonlyArray"; import * as E from "fp-ts/lib/Either"; +import { Either } from "fp-ts/lib/Either"; +import { NonEmptyArray } from "fp-ts/lib/NonEmptyArray"; import * as O from "fp-ts/lib/Option"; -import * as B from "fp-ts/lib/boolean"; +import { Option } from "fp-ts/lib/Option"; +import * as ROA from "fp-ts/lib/ReadonlyArray"; import * as R from "fp-ts/lib/Record"; import * as TE from "fp-ts/lib/TaskEither"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { TaskEither } from "fp-ts/lib/TaskEither"; -import { Either } from "fp-ts/lib/Either"; -import { Option } from "fp-ts/lib/Option"; -import { flow, pipe, identity } from "fp-ts/lib/function"; -import { NonEmptyArray } from "fp-ts/lib/NonEmptyArray"; -import { - NullableBackendAssertionRefFromString, - LollipopData, -} from "../types/assertionRef"; +import * as B from "fp-ts/lib/boolean"; +import { flow, identity, pipe } from "fp-ts/lib/function"; +import { isArray } from "util"; + import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; import { SessionInfo } from "../../generated/backend/SessionInfo"; import { SessionsList } from "../../generated/backend/SessionsList"; +import { + LollipopData, + NullableBackendAssertionRefFromString, +} from "../types/assertionRef"; import { assertUnreachable } from "../types/commons"; import { BPDToken, @@ -34,8 +35,8 @@ import { ZendeskToken, } from "../types/token"; import { User, UserV1, UserV2, UserV3, UserV4, UserV5 } from "../types/user"; -import { log } from "../utils/logger"; import { ActiveSessionInfo, LoginTypeEnum } from "../utils/fastLogin"; +import { log } from "../utils/logger"; import { RedisClientMode, RedisClientSelectorType } from "../utils/redis"; import { ISessionStorage } from "./ISessionStorage"; import RedisStorageUtils from "./redisStorageUtils"; @@ -74,150 +75,297 @@ export default class RedisSessionStorage super(); } - /** - * {@inheritDoc} - */ - public async getBySessionToken( - token: SessionToken - ): Promise>> { - const errorOrSession = await this.loadSessionBySessionToken(token); - - if (E.isLeft(errorOrSession)) { - if (errorOrSession.left === sessionNotFoundError) { - return E.right(O.none); - } - return E.left(errorOrSession.left); - } - - const user = errorOrSession.right; + private arrayStringReplyAsync( + command: TE.TaskEither, + ): Promise>> { + return pipe( + command, + TE.chain( + TE.fromPredicate( + (res): res is NonEmptyArray => isArray(res) && res.length > 0, + () => sessionNotFoundError, + ), + ), + )(); + } - return E.right(O.some(user)); + private delSessionsSet(fiscalCode: FiscalCode): Promise> { + return pipe( + TE.tryCatch(() => { + log.info( + `Deleting sessions set ${userSessionsSetKeyPrefix}${fiscalCode}`, + ); + return this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .del(`${userSessionsSetKeyPrefix}${fiscalCode}`); + }, E.toError), + TE.map(() => true), + )(); } /** - * {@inheritDoc} + * Given a token, it removes user session token and wallet token + * + * @param token */ - public async getByMyPortalToken( - token: MyPortalToken - ): Promise>> { - const errorOrSession = await this.loadSessionByToken( - myPortalTokenPrefix, - token - ); - - if (E.isLeft(errorOrSession)) { - if (errorOrSession.left === sessionNotFoundError) { - return E.right(O.none); - } - return E.left(errorOrSession.left); + private async delSingleSession( + token: SessionToken, + ): Promise> { + try { + const user: User = pipe( + await this.loadSessionBySessionToken(token), + E.getOrElseW((err) => { + throw err; + }), + ); + return this.del(user); + } catch (error) { + // as it's a delete, if the query fails for a NotFoudn error, it might be considered a success + return error === sessionNotFoundError + ? E.right(true) + : E.left(E.toError(error)); } + } - const user = errorOrSession.right; - - return E.right(O.some(user)); + private getUserTokens( + user: User, + ): Record { + const requiredTokens = { + session_info: { + prefix: sessionInfoKeyPrefix, + value: user.session_token, + }, + session_token: { + prefix: sessionKeyPrefix, + value: user.session_token, + }, + wallet_token: { + prefix: walletKeyPrefix, + value: user.wallet_token, + }, + }; + if (UserV5.is(user)) { + return { + ...requiredTokens, + bpd_token: { + prefix: bpdTokenPrefix, + value: user.bpd_token, + }, + fims_token: { + prefix: fimsTokenPrefix, + value: user.fims_token, + }, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + zendesk_token: { + prefix: zendeskTokenPrefix, + value: user.zendesk_token, + }, + }; + } + if (UserV4.is(user)) { + return { + ...requiredTokens, + bpd_token: { + prefix: bpdTokenPrefix, + value: user.bpd_token, + }, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + zendesk_token: { + prefix: zendeskTokenPrefix, + value: user.zendesk_token, + }, + }; + } + if (UserV3.is(user)) { + return { + ...requiredTokens, + bpd_token: { + prefix: bpdTokenPrefix, + value: user.bpd_token, + }, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + }; + } + if (UserV2.is(user)) { + return { + ...requiredTokens, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + }; + } + if (UserV1.is(user)) { + return { + ...requiredTokens, + }; + } + return assertUnreachable(user); } /** - * {@inheritDoc} + * Return a Session for this token. */ - public async del(user: User): Promise> { - const tokens: ReadonlyArray = R.collect( - (_, { prefix, value }) => `${prefix}${value}` - )(this.getUserTokens(user)); - - const deleteTokensPromiseV2 = await pipe( - tokens, - ROA.map((singleToken) => - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .del(singleToken), - E.toError - ) - ), - ROA.sequence(TE.ApplicativeSeq), - TE.map(ROA.reduce(0, (current, next) => current + next)), - this.integerReplyAsync(tokens.length), - this.falsyResponseToErrorAsync( - new Error("Unexpected response from redis client deleting user tokens.") - ) - )(); - - if (E.isLeft(deleteTokensPromiseV2)) { - return E.left( - new Error( - `value [${deleteTokensPromiseV2.left.message}] at RedisSessionStorage.del` - ) - ); - } - - // Remove SESSIONINFO reference from USERSESSIONS Set - // this operation is executed in background and doesn't compromise - // the logout process. - pipe( + private async loadSessionBySessionToken( + token: SessionToken, + ): Promise> { + return pipe( TE.tryCatch( () => this.redisClientSelector .selectOne(RedisClientMode.FAST) - .sRem( - `${userSessionsSetKeyPrefix}${user.fiscal_code}`, - `${sessionInfoKeyPrefix}${user.session_token}` - ), - E.toError + .get(`${sessionKeyPrefix}${token}`), + E.toError, + ), + TE.chain( + flow( + O.fromNullable, + E.fromOption(() => sessionNotFoundError), + E.chain(this.parseUser), + TE.fromEither, + ), ), - TE.mapLeft((_) => { - log.warn(`Error updating USERSESSIONS Set for ${user.fiscal_code}`); - }) - )().catch(() => void 0); - return E.right(true); - } - - public async listUserSessions( - user: User - ): Promise> { - // If some user session was expired we update the USERSESSION Redis set. - await this.clearExpiredSetValues(user.fiscal_code); - - const sessionKeys = await this.readSessionInfoKeys(user.fiscal_code); - - if (E.isLeft(sessionKeys)) { - return E.left(sessionKeys.left); - } - - return pipe( - this.mGet([...sessionKeys.right]), - TE.map((keys) => - this.parseUserSessionList( - keys.filter((key) => key !== null) as ReadonlyArray - ) - ) )(); } /** - * Remove expired `SESSIONINFO` value from the `USERSESSION` redis set. - * - * @param fiscalCode + * Return a Session for this token. */ - public async clearExpiredSetValues( - fiscalCode: string - ): Promise>> { - const userSessionSetKey = `${userSessionsSetKeyPrefix}${fiscalCode}`; - const keysV2 = await pipe( + private loadSessionByToken( + prefix: string, + token: BPDToken | FIMSToken | MyPortalToken | WalletToken | ZendeskToken, + ): Promise> { + return pipe( TE.tryCatch( () => this.redisClientSelector .selectOne(RedisClientMode.FAST) - .sMembers(userSessionSetKey), - E.toError + .get(`${prefix}${token}`), + E.toError, + ), + TE.chain( + flow( + O.fromNullable, + TE.fromOption(() => sessionNotFoundError), + ), + ), + TE.chain((value) => + pipe( + TE.tryCatch( + () => this.loadSessionBySessionToken(value as SessionToken), + E.toError, + ), + TE.chain(TE.fromEither), + ), + ), + )(); + } + + private mGet(keys: string[]): TaskEither { + return pipe( + keys, + A.map((singleKey) => + TE.tryCatch(() => { + const redis_client = this.redisClientSelector.selectOne( + RedisClientMode.FAST, + ); + return redis_client.get.bind(redis_client)(singleKey); + }, E.toError), + ), + A.sequence(TE.ApplicativePar), + ); + } + + private parseUser(value: string): Either { + return pipe( + E.parseJSON(value, E.toError), + E.chain( + flow( + User.decode, + E.mapLeft( + (err) => new Error(errorsToReadableMessages(err).join("/")), + ), + ), + ), + ); + } + + private parseUserSessionList( + userSessionTokensResult: readonly string[], + ): SessionsList { + return userSessionTokensResult.reduce( + (prev: SessionsList, _) => + pipe( + E.parseJSON(_, E.toError), + E.chain((data) => + pipe( + SessionInfo.decode(data), + E.mapLeft( + (err) => new Error(errorsToReadableMessages(err).join("/")), + ), + ), + ), + E.fold( + (err) => { + log.warn("Unable to decode the session info: %s. Skipped.", err); + return prev; + }, + (sessionInfo) => ({ + sessions: [...prev.sessions, sessionInfo], + }), + ), + ), + { sessions: [] } as SessionsList, + ); + } + + private readSessionInfoKeys( + fiscalCode: FiscalCode, + ): Promise> { + return pipe( + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .sMembers(`${userSessionsSetKeyPrefix}${fiscalCode}`), + E.toError, + ), + this.arrayStringReplyAsync, + ); + } + + /** + * Remove expired `SESSIONINFO` value from the `USERSESSION` redis set. + * + * @param fiscalCode + */ + public async clearExpiredSetValues( + fiscalCode: string, + ): Promise[]> { + const userSessionSetKey = `${userSessionsSetKeyPrefix}${fiscalCode}`; + const keysV2 = await pipe( + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .sMembers(userSessionSetKey), + E.toError, ), TE.mapLeft((err) => { log.error("Error reading set members: %s", err); - // eslint-disable-next-line functional/prefer-readonly-type + return [] as string[]; }), - TE.toUnion + TE.toUnion, )(); const activeKeys = await Promise.all( @@ -228,15 +376,15 @@ export default class RedisSessionStorage this.redisClientSelector .selectOne(RedisClientMode.FAST) .exists(key), - E.toError + E.toError, ), TE.chainW(TE.fromPredicate((response) => !!response, identity)), TE.bimap( () => key, - () => key - ) - )() - ) + () => key, + ), + )(), + ), ); return await Promise.all( @@ -246,139 +394,107 @@ export default class RedisSessionStorage .map((key) => this.redisClientSelector .selectOne(RedisClientMode.FAST) - .sRem(userSessionSetKey, key.left) + .sRem(userSessionSetKey, key.left), ), (keysRemPromises) => keysRemPromises.map((promise) => pipe( TE.tryCatch(() => promise, E.toError), this.integerReplyAsync(), - (task) => task() - ) - ) - ) + (task) => task(), + ), + ), + ), ); } /** - * @deprecated use `userHasActiveSessionsOrLV` instead + * {@inheritDoc} */ - public async userHasActiveSessions( - fiscalCode: FiscalCode - ): Promise> { - const sessionKeys = await this.readSessionInfoKeys(fiscalCode); - if (E.isLeft(sessionKeys)) { - return sessionKeys.left === sessionNotFoundError - ? E.right(false) - : E.left(sessionKeys.left); - } - const errorOrSessionTokens = await pipe( - this.mGet([...sessionKeys.right]), - TE.map((keys) => - this.parseUserSessionList( - keys.filter((key): key is string => key !== null) - ).sessions.map( - (session) => `${sessionKeyPrefix}${session.sessionToken}` - ) - ) + public async del(user: User): Promise> { + const tokens: readonly string[] = R.collect( + (_, { prefix, value }) => `${prefix}${value}`, + )(this.getUserTokens(user)); + + const deleteTokensPromiseV2 = await pipe( + tokens, + ROA.map((singleToken) => + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .del(singleToken), + E.toError, + ), + ), + ROA.sequence(TE.ApplicativeSeq), + TE.map(ROA.reduce(0, (current, next) => current + next)), + this.integerReplyAsync(tokens.length), + this.falsyResponseToErrorAsync( + new Error( + "Unexpected response from redis client deleting user tokens.", + ), + ), )(); - if (E.isLeft(errorOrSessionTokens)) { - return E.left(errorOrSessionTokens.left); - } else if (errorOrSessionTokens.right.length === 0) { - return E.right(false); + if (E.isLeft(deleteTokensPromiseV2)) { + return E.left( + new Error( + `value [${deleteTokensPromiseV2.left.message}] at RedisSessionStorage.del`, + ), + ); } - return pipe( - this.mGet(errorOrSessionTokens.right), - // Skipping null values from the array - TE.map(A.filter((key): key is string => key !== null)), - TE.map((_) => _.length > 0) - )(); - } - - /** - * Check if user id logged in, by checking the presence of LollipopData. - * It returns true if login type is LV or a LEGACY session exists, false otherwise - * - * @param fiscalCode - * @returns true if login type is LV or a LEGACY session exists, false otherwise - */ - public async userHasActiveSessionsOrLV( - fiscalCode: FiscalCode - ): Promise> { - return await pipe( - await this.getLollipopDataForUser(fiscalCode), - TE.fromEither, - TE.chain( - flow( - O.map((data) => - pipe( - data.loginType === LoginTypeEnum.LV, - B.fold( - // if login type is not LV, check for active user sessions - () => - pipe( - TE.tryCatch( - () => this.userHasActiveSessions(fiscalCode), - E.toError - ), - TE.chainEitherK(identity) - ), - // if login type is LV, return true - () => TE.of(true) - ) - ) - ), - // ff no LollipopData was found, return false - O.getOrElseW(() => TE.of(false)) - ) - ) - )(); + // Remove SESSIONINFO reference from USERSESSIONS Set + // this operation is executed in background and doesn't compromise + // the logout process. + pipe( + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .sRem( + `${userSessionsSetKeyPrefix}${user.fiscal_code}`, + `${sessionInfoKeyPrefix}${user.session_token}`, + ), + E.toError, + ), + TE.mapLeft(() => { + log.warn(`Error updating USERSESSIONS Set for ${user.fiscal_code}`); + }), + )().catch(() => void 0); + return E.right(true); } /** - * Insert a user in the list of blocked account - * - * @param fiscalCode id of the user - * - * @returns a promise with either an error or true + * {@inheritDoc} */ - public setBlockedUser(fiscalCode: FiscalCode): Promise> { + public async delLollipopDataForUser(fiscalCode: FiscalCode) { return pipe( - TE.tryCatch(() => { - log.info(`Adding ${fiscalCode} to ${blockedUserSetKey} set`); - return this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .sAdd(blockedUserSetKey, fiscalCode); - }, E.toError), - TE.map((_) => true) + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .del(`${lollipopDataPrefix}${fiscalCode}`), + E.toError, + ), + this.integerReplyAsync(), )(); } /** - * Remove a user from the list of blocked account - * - * @param fiscalCode id of the user - * - * @returns a promise with either an error or true + * Delete notify email cache related to an user */ - public unsetBlockedUser( - fiscalCode: FiscalCode - ): Promise> { + public async delPagoPaNoticeEmail(user: User): Promise> { return pipe( - TE.tryCatch(() => { - log.info(`Removing ${fiscalCode} from ${blockedUserSetKey} set`); - return this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .sRem(blockedUserSetKey, fiscalCode); - }, E.toError), - this.integerReplyAsync(1), - this.falsyResponseToErrorAsync( - new Error( - "Unexpected response from redis client deleting blockedUserKey" - ) - ) + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .del(`${noticeEmailPrefix}${user.session_token}`), + E.toError, + ), + TE.map(() => true), )(); } @@ -388,12 +504,12 @@ export default class RedisSessionStorage * @param fiscalCode */ public async delUserAllSessions( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ): Promise> { const errorOrSessions = await this.readSessionInfoKeys(fiscalCode); const delEverySession = ( - sessionTokens: ReadonlyArray + sessionTokens: readonly SessionToken[], ): TaskEither => pipe( A.sequence(TE.ApplicativePar)( @@ -403,19 +519,19 @@ export default class RedisSessionStorage pipe( sessionToken, SessionToken.decode, - E.mapLeft((_) => new Error("Error decoding token")) - ) + E.mapLeft(() => new Error("Error decoding token")), + ), ), TE.chain((token: SessionToken) => pipe( TE.tryCatch(() => this.delSingleSession(token), E.toError), - TE.chain(TE.fromEither) - ) - ) - ) - ) + TE.chain(TE.fromEither), + ), + ), + ), + ), ), - TE.map(() => true) + TE.map(() => true), ); return pipe( @@ -428,44 +544,79 @@ export default class RedisSessionStorage delEverySession( sessionInfoKeys.map( (sessionInfoKey) => - sessionInfoKey.replace(sessionInfoKeyPrefix, "") as SessionToken - ) - ) + sessionInfoKey.replace( + sessionInfoKeyPrefix, + "", + ) as SessionToken, + ), + ), ), - TE.chain((_) => + TE.chain(() => pipe( TE.tryCatch(() => this.delSessionsSet(fiscalCode), E.toError), - TE.chain(TE.fromEither) - ) - ) + TE.chain(TE.fromEither), + ), + ), )(); } + // ---------------------------------------------- + // Private methods + // ---------------------------------------------- + + // This mGet fires a bunch of GET operation to prevent CROSS-SLOT errors on the cluster /** - * Delete notify email cache related to an user + * {@inheritDoc} */ - public async delPagoPaNoticeEmail(user: User): Promise> { - return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .del(`${noticeEmailPrefix}${user.session_token}`), - E.toError - ), - TE.map((_) => true) - )(); + public async getByMyPortalToken( + token: MyPortalToken, + ): Promise>> { + const errorOrSession = await this.loadSessionByToken( + myPortalTokenPrefix, + token, + ); + + if (E.isLeft(errorOrSession)) { + if (errorOrSession.left === sessionNotFoundError) { + return E.right(O.none); + } + return E.left(errorOrSession.left); + } + + const user = errorOrSession.right; + + return E.right(O.some(user)); + } + + /** + * {@inheritDoc} + */ + public async getBySessionToken( + token: SessionToken, + ): Promise>> { + const errorOrSession = await this.loadSessionBySessionToken(token); + + if (E.isLeft(errorOrSession)) { + if (errorOrSession.left === sessionNotFoundError) { + return E.right(O.none); + } + return E.left(errorOrSession.left); + } + + const user = errorOrSession.right; + + return E.right(O.some(user)); } /** * {@inheritDoc} */ public async getLollipopAssertionRefForUser( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ): Promise>> { return pipe( await this.getLollipopDataForUser(fiscalCode), - E.map(O.map((data) => data.assertionRef)) + E.map(O.map((data) => data.assertionRef)), ); } @@ -473,7 +624,7 @@ export default class RedisSessionStorage * {@inheritDoc} */ public async getLollipopDataForUser( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ): Promise>> { return pipe( TE.tryCatch( @@ -481,7 +632,7 @@ export default class RedisSessionStorage this.redisClientSelector .selectOne(RedisClientMode.SAFE) .get(`${lollipopDataPrefix}${fiscalCode}`), - E.toError + E.toError, ), TE.chain( flow( @@ -496,17 +647,17 @@ export default class RedisSessionStorage { assertionRef: storedValue, loginType: LoginTypeEnum.LEGACY, - } - ) - ) + }, + ), + ), ), E.mapLeft( (validationErrors) => - new Error(errorsToReadableMessages(validationErrors).join("/")) + new Error(errorsToReadableMessages(validationErrors).join("/")), ), - TE.fromEither - ) - ) + TE.fromEither, + ), + ), )(); } @@ -514,7 +665,7 @@ export default class RedisSessionStorage * {@inheritDoc} */ public getSessionRemainingTTL( - fiscalCode: FiscalCode + fiscalCode: FiscalCode, ): TE.TaskEither> { return pipe( TE.tryCatch( @@ -525,13 +676,13 @@ export default class RedisSessionStorage this.redisClientSelector .selectOne(RedisClientMode.SAFE) .ttl(`${lollipopDataPrefix}${fiscalCode}`), - E.toError + E.toError, ), TE.chain( TE.fromPredicate( (_) => _ !== -1, - () => new Error("Unexpected missing CF-AssertionRef TTL") - ) + () => new Error("Unexpected missing CF-AssertionRef TTL"), + ), ), TE.map(flow(O.fromPredicate((ttl) => ttl > 0))), TE.chain((maybeTtl) => @@ -540,308 +691,164 @@ export default class RedisSessionStorage : pipe( TE.tryCatch( () => this.getLollipopDataForUser(fiscalCode), - E.toError + E.toError, ), TE.chain(TE.fromEither), TE.chain( TE.fromPredicate( O.isSome, - () => new Error("Unexpected missing value") - ) + () => new Error("Unexpected missing value"), + ), ), TE.map(({ value }) => - O.some({ ttl: maybeTtl.value, type: value.loginType }) - ) - ) - ) + O.some({ ttl: maybeTtl.value, type: value.loginType }), + ), + ), + ), ); } - /** - * {@inheritDoc} - */ - public async delLollipopDataForUser(fiscalCode: FiscalCode) { - return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .del(`${lollipopDataPrefix}${fiscalCode}`), - E.toError - ), - this.integerReplyAsync() - )(); - } + public async listUserSessions( + user: User, + ): Promise> { + // If some user session was expired we update the USERSESSION Redis set. + await this.clearExpiredSetValues(user.fiscal_code); - // ---------------------------------------------- - // Private methods - // ---------------------------------------------- + const sessionKeys = await this.readSessionInfoKeys(user.fiscal_code); + + if (E.isLeft(sessionKeys)) { + return E.left(sessionKeys.left); + } - // This mGet fires a bunch of GET operation to prevent CROSS-SLOT errors on the cluster - // eslint-disable-next-line functional/prefer-readonly-type - private mGet(keys: string[]): TaskEither> { return pipe( - keys, - A.map((singleKey) => - TE.tryCatch(() => { - const redis_client = this.redisClientSelector.selectOne( - RedisClientMode.FAST - ); - return redis_client.get.bind(redis_client)(singleKey); - }, E.toError) + this.mGet([...sessionKeys.right]), + TE.map((keys) => + this.parseUserSessionList( + keys.filter((key) => key !== null) as readonly string[], + ), ), - A.sequence(TE.ApplicativePar) - ); + )(); } /** - * Given a token, it removes user session token and wallet token + * Insert a user in the list of blocked account * - * @param token + * @param fiscalCode id of the user + * + * @returns a promise with either an error or true */ - private async delSingleSession( - token: SessionToken - ): Promise> { - try { - const user: User = pipe( - await this.loadSessionBySessionToken(token), - E.getOrElseW((err) => { - throw err; - }) - ); - return this.del(user); - } catch (error) { - // as it's a delete, if the query fails for a NotFoudn error, it might be considered a success - return error === sessionNotFoundError - ? E.right(true) - : E.left(E.toError(error)); - } - } - - private delSessionsSet(fiscalCode: FiscalCode): Promise> { + public setBlockedUser(fiscalCode: FiscalCode): Promise> { return pipe( TE.tryCatch(() => { - log.info( - `Deleting sessions set ${userSessionsSetKeyPrefix}${fiscalCode}` - ); + log.info(`Adding ${fiscalCode} to ${blockedUserSetKey} set`); return this.redisClientSelector .selectOne(RedisClientMode.FAST) - .del(`${userSessionsSetKeyPrefix}${fiscalCode}`); + .sAdd(blockedUserSetKey, fiscalCode); }, E.toError), - TE.map((_) => true) + TE.map(() => true), )(); } /** - * Return a Session for this token. + * Remove a user from the list of blocked account + * + * @param fiscalCode id of the user + * + * @returns a promise with either an error or true */ - private async loadSessionBySessionToken( - token: SessionToken - ): Promise> { + public unsetBlockedUser( + fiscalCode: FiscalCode, + ): Promise> { return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .get(`${sessionKeyPrefix}${token}`), - E.toError + TE.tryCatch(() => { + log.info(`Removing ${fiscalCode} from ${blockedUserSetKey} set`); + return this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .sRem(blockedUserSetKey, fiscalCode); + }, E.toError), + this.integerReplyAsync(1), + this.falsyResponseToErrorAsync( + new Error( + "Unexpected response from redis client deleting blockedUserKey", + ), ), - TE.chain( - flow( - O.fromNullable, - E.fromOption(() => sessionNotFoundError), - E.chain(this.parseUser), - TE.fromEither - ) - ) )(); } /** - * Return a Session for this token. + * @deprecated use `userHasActiveSessionsOrLV` instead */ - private loadSessionByToken( - prefix: string, - token: WalletToken | MyPortalToken | BPDToken | ZendeskToken | FIMSToken - ): Promise> { - return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .get(`${prefix}${token}`), - E.toError - ), - TE.chain( - flow( - O.fromNullable, - TE.fromOption(() => sessionNotFoundError) - ) + public async userHasActiveSessions( + fiscalCode: FiscalCode, + ): Promise> { + const sessionKeys = await this.readSessionInfoKeys(fiscalCode); + if (E.isLeft(sessionKeys)) { + return sessionKeys.left === sessionNotFoundError + ? E.right(false) + : E.left(sessionKeys.left); + } + const errorOrSessionTokens = await pipe( + this.mGet([...sessionKeys.right]), + TE.map((keys) => + this.parseUserSessionList( + keys.filter((key): key is string => key !== null), + ).sessions.map( + (session) => `${sessionKeyPrefix}${session.sessionToken}`, + ), ), - TE.chain((value) => - pipe( - TE.tryCatch( - () => this.loadSessionBySessionToken(value as SessionToken), - E.toError - ), - TE.chain(TE.fromEither) - ) - ) )(); - } - private readSessionInfoKeys( - fiscalCode: FiscalCode - ): Promise>> { - return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .sMembers(`${userSessionsSetKeyPrefix}${fiscalCode}`), - E.toError - ), - this.arrayStringReplyAsync - ); - } + if (E.isLeft(errorOrSessionTokens)) { + return E.left(errorOrSessionTokens.left); + } else if (errorOrSessionTokens.right.length === 0) { + return E.right(false); + } - private arrayStringReplyAsync( - command: TE.TaskEither> - ): Promise>> { return pipe( - command, - TE.chain( - TE.fromPredicate( - (res): res is NonEmptyArray => isArray(res) && res.length > 0, - () => sessionNotFoundError - ) - ) + this.mGet(errorOrSessionTokens.right), + // Skipping null values from the array + TE.map(A.filter((key): key is string => key !== null)), + TE.map((_) => _.length > 0), )(); } - private parseUser(value: string): Either { - return pipe( - E.parseJSON(value, E.toError), - E.chain( + /** + * Check if user id logged in, by checking the presence of LollipopData. + * It returns true if login type is LV or a LEGACY session exists, false otherwise + * + * @param fiscalCode + * @returns true if login type is LV or a LEGACY session exists, false otherwise + */ + public async userHasActiveSessionsOrLV( + fiscalCode: FiscalCode, + ): Promise> { + return await pipe( + await this.getLollipopDataForUser(fiscalCode), + TE.fromEither, + TE.chain( flow( - User.decode, - E.mapLeft((err) => new Error(errorsToReadableMessages(err).join("/"))) - ) - ) - ); - } - - private parseUserSessionList( - userSessionTokensResult: ReadonlyArray - ): SessionsList { - return userSessionTokensResult.reduce( - (prev: SessionsList, _) => - pipe( - E.parseJSON(_, E.toError), - E.chain((data) => + O.map((data) => pipe( - SessionInfo.decode(data), - E.mapLeft( - (err) => new Error(errorsToReadableMessages(err).join("/")) - ) - ) + data.loginType === LoginTypeEnum.LV, + B.fold( + // if login type is not LV, check for active user sessions + () => + pipe( + TE.tryCatch( + () => this.userHasActiveSessions(fiscalCode), + E.toError, + ), + TE.chainEitherK(identity), + ), + // if login type is LV, return true + () => TE.of(true), + ), + ), ), - E.fold( - (err) => { - log.warn("Unable to decode the session info: %s. Skipped.", err); - return prev; - }, - (sessionInfo) => ({ - sessions: [...prev.sessions, sessionInfo], - }) - ) + // ff no LollipopData was found, return false + O.getOrElseW(() => TE.of(false)), ), - { sessions: [] } as SessionsList - ); - } - - private getUserTokens( - user: User - ): Record { - const requiredTokens = { - session_info: { - prefix: sessionInfoKeyPrefix, - value: user.session_token, - }, - session_token: { - prefix: sessionKeyPrefix, - value: user.session_token, - }, - wallet_token: { - prefix: walletKeyPrefix, - value: user.wallet_token, - }, - }; - if (UserV5.is(user)) { - return { - ...requiredTokens, - bpd_token: { - prefix: bpdTokenPrefix, - value: user.bpd_token, - }, - fims_token: { - prefix: fimsTokenPrefix, - value: user.fims_token, - }, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - zendesk_token: { - prefix: zendeskTokenPrefix, - value: user.zendesk_token, - }, - }; - } - if (UserV4.is(user)) { - return { - ...requiredTokens, - bpd_token: { - prefix: bpdTokenPrefix, - value: user.bpd_token, - }, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - zendesk_token: { - prefix: zendeskTokenPrefix, - value: user.zendesk_token, - }, - }; - } - if (UserV3.is(user)) { - return { - ...requiredTokens, - bpd_token: { - prefix: bpdTokenPrefix, - value: user.bpd_token, - }, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - }; - } - if (UserV2.is(user)) { - return { - ...requiredTokens, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - }; - } - if (UserV1.is(user)) { - return { - ...requiredTokens, - }; - } - return assertUnreachable(user); + ), + )(); } } diff --git a/src/services/redisStorageUtils.ts b/src/services/redisStorageUtils.ts index df554ce4d..4991b2c7a 100644 --- a/src/services/redisStorageUtils.ts +++ b/src/services/redisStorageUtils.ts @@ -1,34 +1,36 @@ -import { isNumber } from "util"; import * as E from "fp-ts/lib/Either"; import { Either } from "fp-ts/lib/Either"; import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; +import { isNumber } from "util"; export default class RedisStorageUtils { /** - * Parse a Redis single string reply. * - * @see https://redis.io/topics/protocol#simple-string-reply. * @deprecated */ - protected singleStringReply( - err: Error | null, - reply: "OK" | undefined - ): Either { - if (err) { - return E.left(err); + protected falsyResponseToError( + response: Either, + error: Error, + ): Either { + if (E.isLeft(response)) { + return E.left(response.left); + } else { + if (response.right) { + return E.right(true); + } + return E.left(error); } - - return E.right(reply === "OK"); } - protected singleStringReplyAsync( - command: TE.TaskEither - ) { - return pipe( - command, - TE.map((reply) => reply === "OK") - ); + protected falsyResponseToErrorAsync(error: Error) { + return ( + response: TE.TaskEither, + ): TE.TaskEither => + pipe( + response, + TE.chain((_) => (_ ? TE.right(_) : TE.left(error))), + ); } /** @@ -40,7 +42,7 @@ export default class RedisStorageUtils { protected integerReply( err: Error | null, reply: unknown, - expectedReply?: number + expectedReply?: number, ): Either { if (err) { return E.left(err); @@ -53,7 +55,7 @@ export default class RedisStorageUtils { protected integerReplyAsync(expectedReply?: number) { return ( - command: TE.TaskEither + command: TE.TaskEither, ): TE.TaskEither => pipe( command, @@ -62,35 +64,33 @@ export default class RedisStorageUtils { return TE.right(false); } return TE.right(isNumber(reply)); - }) + }), ); } /** + * Parse a Redis single string reply. * + * @see https://redis.io/topics/protocol#simple-string-reply. * @deprecated */ - protected falsyResponseToError( - response: Either, - error: Error - ): Either { - if (E.isLeft(response)) { - return E.left(response.left); - } else { - if (response.right) { - return E.right(true); - } - return E.left(error); + protected singleStringReply( + err: Error | null, + reply: "OK" | undefined, + ): Either { + if (err) { + return E.left(err); } + + return E.right(reply === "OK"); } - protected falsyResponseToErrorAsync(error: Error) { - return ( - response: TE.TaskEither - ): TE.TaskEither => - pipe( - response, - TE.chain((_) => (_ ? TE.right(_) : TE.left(error))) - ); + protected singleStringReplyAsync( + command: TE.TaskEither, + ) { + return pipe( + command, + TE.map((reply) => reply === "OK"), + ); } } diff --git a/src/services/redisUserMetadataStorage.ts b/src/services/redisUserMetadataStorage.ts index ce5962e90..a2e0314b4 100644 --- a/src/services/redisUserMetadataStorage.ts +++ b/src/services/redisUserMetadataStorage.ts @@ -1,12 +1,13 @@ -import * as redis from "redis"; -import * as E from "fp-ts/lib/Either"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as E from "fp-ts/lib/Either"; import { Either } from "fp-ts/lib/Either"; -import * as TE from "fp-ts/lib/TaskEither"; -import * as O from "fp-ts/lib/Option"; import { parse } from "fp-ts/lib/Json"; +import * as O from "fp-ts/lib/Option"; +import * as TE from "fp-ts/lib/TaskEither"; import { flow, pipe } from "fp-ts/lib/function"; +import * as redis from "redis"; + import { UserMetadata } from "../../generated/backend/UserMetadata"; import { User } from "../types/user"; import { log } from "../utils/logger"; @@ -26,11 +27,72 @@ export default class RedisUserMetadataStorage implements IUserMetadataStorage { constructor( - private readonly redisClient: redis.RedisClientType | redis.RedisClusterType + private readonly redisClient: + | redis.RedisClientType + | redis.RedisClusterType, ) { super(); } + private loadUserMetadataByFiscalCode( + fiscalCode: string, + ): Promise> { + return pipe( + TE.tryCatch( + () => this.redisClient.get(`${userMetadataPrefix}${fiscalCode}`), + () => new Error("REDIS CLIENT ERROR"), + ), + TE.chain( + flow( + O.fromNullable, + TE.fromOption(() => metadataNotFoundError), + ), + ), + TE.chain( + flow( + parse, + E.mapLeft(() => new Error("Unable to parse the user metadata json")), + TE.fromEither, + TE.chain( + flow( + UserMetadata.decode, + TE.fromEither, + TE.mapLeft((err) => { + log.error( + "Unable to decode the user metadata: %s", + errorsToReadableMessages(err).join("|"), + ); + return new Error("Unable to decode the user metadata"); + }), + ), + ), + ), + ), + )(); + } + + /** + * Delete all user metdata + * + * {@inheritDoc} + */ + public del(fiscalCode: FiscalCode): Promise> { + return pipe( + TE.tryCatch(() => { + log.info(`Deleting metadata for ${fiscalCode}`); + return this.redisClient.del(`${userMetadataPrefix}${fiscalCode}`); + }, E.toError), + TE.map(() => true), + )(); + } + + /** + * {@inheritDoc} + */ + public async get(user: User): Promise> { + return this.loadUserMetadataByFiscalCode(user.fiscal_code); + } + /** * {@inheritDoc} * @@ -39,10 +101,10 @@ export default class RedisUserMetadataStorage */ public async set( user: User, - payload: UserMetadata + payload: UserMetadata, ): Promise> { const getUserMetadataResult = await this.loadUserMetadataByFiscalCode( - user.fiscal_code + user.fiscal_code, ); if ( E.isRight(getUserMetadataResult) && @@ -61,70 +123,11 @@ export default class RedisUserMetadataStorage () => this.redisClient.set( `${userMetadataPrefix}${user.fiscal_code}`, - JSON.stringify(payload) + JSON.stringify(payload), ), - E.toError + E.toError, ), - this.singleStringReplyAsync - )(); - } - - /** - * {@inheritDoc} - */ - public async get(user: User): Promise> { - return this.loadUserMetadataByFiscalCode(user.fiscal_code); - } - - /** - * Delete all user metdata - * - * {@inheritDoc} - */ - public del(fiscalCode: FiscalCode): Promise> { - return pipe( - TE.tryCatch(() => { - log.info(`Deleting metadata for ${fiscalCode}`); - return this.redisClient.del(`${userMetadataPrefix}${fiscalCode}`); - }, E.toError), - TE.map(() => true) - )(); - } - - private loadUserMetadataByFiscalCode( - fiscalCode: string - ): Promise> { - return pipe( - TE.tryCatch( - () => this.redisClient.get(`${userMetadataPrefix}${fiscalCode}`), - () => new Error("REDIS CLIENT ERROR") - ), - TE.chain( - flow( - O.fromNullable, - TE.fromOption(() => metadataNotFoundError) - ) - ), - TE.chain( - flow( - parse, - E.mapLeft(() => new Error("Unable to parse the user metadata json")), - TE.fromEither, - TE.chain( - flow( - UserMetadata.decode, - TE.fromEither, - TE.mapLeft((err) => { - log.error( - "Unable to decode the user metadata: %s", - errorsToReadableMessages(err).join("|") - ); - return new Error("Unable to decode the user metadata"); - }) - ) - ) - ) - ) + this.singleStringReplyAsync, )(); } } diff --git a/src/services/servicesAppBackendService.ts b/src/services/servicesAppBackendService.ts index fc4f943ed..ae4c9f821 100644 --- a/src/services/servicesAppBackendService.ts +++ b/src/services/servicesAppBackendService.ts @@ -6,6 +6,7 @@ import { ResponseErrorNotFound, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; + import { FeaturedServices } from "../../generated/services-app-backend/FeaturedServices"; import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; import { Institutions } from "../../generated/services-app-backend/Institutions"; @@ -21,15 +22,11 @@ import { // TODO: Aggiungere le altre operazioni del service export default class ServicesAppBackendService { - constructor( - private readonly apiClient: ReturnType - ) {} - public readonly findInstitutions = ( search?: string, scope?: ScopeType, limit?: number, - offset?: number + offset?: number, ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -47,93 +44,97 @@ export default class ServicesAppBackendService { response.status === 200 ? withValidatedOrInternalError( InstitutionsResource.decode(response.value), - ResponseSuccessJson + ResponseSuccessJson, ) - : unhandledResponseStatus(response.status) + : unhandledResponseStatus(response.status), ); }); - public readonly getServiceById = ( - serviceId: string + public readonly findInstutionServices = ( + // TODO: fix institutionId type + institutionId: string, + limit?: number, + offset?: number, ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseSuccessJson + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.getServiceById({ - serviceId, + const validated = await this.apiClient.findInstutionServices({ + institutionId, + limit, + offset, }); + // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - ServiceDetails.decode(response.value), - ResponseSuccessJson + InstitutionServicesResource.decode(response.value), + ResponseSuccessJson, ) - : response.status === 404 - ? ResponseErrorNotFound("Not found", "Service not found") - : unhandledResponseStatus(response.status) + : unhandledResponseStatus(response.status), ); }); - public readonly getFeaturedServices = (): Promise< - IResponseErrorInternal | IResponseSuccessJson + public readonly getFeaturedInstitutions = (): Promise< + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.getFeaturedServices({}); + const validated = await this.apiClient.getFeaturedInstitutions({}); // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - FeaturedServices.decode(response.value), - ResponseSuccessJson + Institutions.decode(response.value), + ResponseSuccessJson, ) - : unhandledResponseStatus(response.status) + : unhandledResponseStatus(response.status), ); }); - public readonly getFeaturedInstitutions = (): Promise< - IResponseErrorInternal | IResponseSuccessJson + public readonly getFeaturedServices = (): Promise< + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.getFeaturedInstitutions({}); + const validated = await this.apiClient.getFeaturedServices({}); // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - Institutions.decode(response.value), - ResponseSuccessJson + FeaturedServices.decode(response.value), + ResponseSuccessJson, ) - : unhandledResponseStatus(response.status) + : unhandledResponseStatus(response.status), ); }); - public readonly findInstutionServices = ( - // TODO: fix institutionId type - institutionId: string, - limit?: number, - offset?: number + public readonly getServiceById = ( + serviceId: string, ): Promise< - IResponseErrorInternal | IResponseSuccessJson + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.findInstutionServices({ - institutionId, - limit, - offset, + const validated = await this.apiClient.getServiceById({ + serviceId, }); - // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - InstitutionServicesResource.decode(response.value), - ResponseSuccessJson + ServiceDetails.decode(response.value), + ResponseSuccessJson, ) - : unhandledResponseStatus(response.status) + : response.status === 404 + ? ResponseErrorNotFound("Not found", "Service not found") + : unhandledResponseStatus(response.status), ); }); + + constructor( + private readonly apiClient: ReturnType, + ) {} } diff --git a/src/services/trialService.ts b/src/services/trialService.ts index 6e5cb6144..deb308bdb 100644 --- a/src/services/trialService.ts +++ b/src/services/trialService.ts @@ -2,50 +2,47 @@ * This service retrieves messages from the API system using an API client. */ import { + IResponseErrorConflict, IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, - ResponseErrorNotFound, - ResponseErrorInternal, - ResponseErrorValidation, IResponseSuccessAccepted, + IResponseSuccessJson, IResponseSuccessRedirectToResource, - ResponseSuccessRedirectToResource, - ResponseSuccessAccepted, ResponseErrorConflict, - IResponseErrorConflict, - IResponseSuccessJson, + ResponseErrorInternal, + ResponseErrorNotFound, + ResponseErrorValidation, + ResponseSuccessAccepted, ResponseSuccessJson, + ResponseSuccessRedirectToResource, } from "@pagopa/ts-commons/lib/responses"; -import { TrialSystemAPIClient } from "src/clients/trial-system.client"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/Option"; +import { pipe } from "fp-ts/lib/function"; +import { TrialSystemAPIClient } from "src/clients/trial-system.client"; + +import { Subscription } from "../../generated/trial-system/Subscription"; +import { TrialId } from "../../generated/trial-system-api/TrialId"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; -import { TrialId } from "../../generated/trial-system-api/TrialId"; -import { Subscription } from "../../generated/trial-system/Subscription"; export default class TrialService { - constructor( - private readonly apiClient: ReturnType - ) {} - /** * Subscribe a user to a specific trial. */ public readonly createSubscription = async ( userId: NonEmptyString, - trialId: TrialId + trialId: TrialId, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorConflict + | IResponseErrorValidation | IResponseSuccessAccepted | IResponseSuccessRedirectToResource > => @@ -70,8 +67,8 @@ export default class TrialService { ResponseSuccessRedirectToResource( resBody, `/api/v1/trials/${trialId}/subscriptions`, - resBody - ) + resBody, + ), ); case 202: return ResponseSuccessAccepted(); @@ -81,8 +78,8 @@ export default class TrialService { pipe( response.value.detail, O.fromNullable, - O.getOrElse(() => "Malformed request") - ) + O.getOrElse(() => "Malformed request"), + ), ); case 401: return ResponseErrorUnexpectedAuthProblem(); @@ -95,8 +92,8 @@ export default class TrialService { pipe( response.value.detail, O.fromNullable, - O.getOrElse(() => "Cannot create subscription") - ) + O.getOrElse(() => "Cannot create subscription"), + ), ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -109,7 +106,7 @@ export default class TrialService { */ public readonly getSubscription = async ( userId: NonEmptyString, - trialId: TrialId + trialId: TrialId, ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -130,7 +127,7 @@ export default class TrialService { state: response.value.state, trialId: response.value.trialId, }, - ResponseSuccessJson + ResponseSuccessJson, ); case 401: return ResponseErrorUnexpectedAuthProblem(); @@ -141,12 +138,16 @@ export default class TrialService { pipe( response.value.detail, O.fromNullable, - O.getOrElse(() => "Cannot get subscription") - ) + O.getOrElse(() => "Cannot get subscription"), + ), ); default: return ResponseErrorStatusNotDefinedInSpec(response); } }); }); + + constructor( + private readonly apiClient: ReturnType, + ) {} } diff --git a/src/services/userDataProcessingService.ts b/src/services/userDataProcessingService.ts index 344366796..a4583120d 100644 --- a/src/services/userDataProcessingService.ts +++ b/src/services/userDataProcessingService.ts @@ -3,6 +3,9 @@ * an API client. */ +import { UserDataProcessing } from "@pagopa/io-functions-app-sdk/UserDataProcessing"; +import { UserDataProcessingChoice } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoice"; +import { UserDataProcessingChoiceRequest } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoiceRequest"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -17,12 +20,9 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; +import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; -import * as O from "fp-ts/lib/Option"; -import { UserDataProcessing } from "@pagopa/io-functions-app-sdk/UserDataProcessing"; -import { UserDataProcessingChoice } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoice"; -import { UserDataProcessingChoiceRequest } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoiceRequest"; import { User } from "../types/user"; import { unhandledResponseStatus, @@ -32,40 +32,42 @@ import { import { IApiClientFactoryInterface } from "./IApiClientFactory"; export default class UserDataProcessingService { - constructor(private readonly apiClient: IApiClientFactoryInterface) {} - /** - * Create the user data processing of a specific user. + * Abort the user data processing of a specific user. */ - public readonly upsertUserDataProcessing = async ( + public readonly abortUserDataProcessing = async ( user: User, - userDataProcessingChoiceRequest: UserDataProcessingChoiceRequest + userDataProcessingChoiceParam: UserDataProcessingChoice, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal + | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorConflict - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessAccepted > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.upsertUserDataProcessing({ - body: userDataProcessingChoiceRequest, + const validated = await client.abortUserDataProcessing({ + choice: userDataProcessingChoiceParam, fiscal_code: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => - response.status === 200 - ? ResponseSuccessJson(response.value) - : response.status === 429 - ? ResponseErrorTooManyRequests() - : response.status === 409 - ? ResponseErrorConflict( - pipe( - O.fromNullable(response.value.detail), - O.getOrElse(() => "Conflict") + response.status === 202 + ? ResponseSuccessAccepted() + : response.status === 404 + ? ResponseErrorNotFound( + "Not Found", + "User data processing not found", ) - ) - : unhandledResponseStatus(response.status) + : response.status === 409 + ? ResponseErrorConflict( + "Cannot abort user data processing request", + ) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status), ); }); }; @@ -75,11 +77,11 @@ export default class UserDataProcessingService { */ public readonly getUserDataProcessing = async ( user: User, - userDataProcessingChoiceParam: UserDataProcessingChoice + userDataProcessingChoiceParam: UserDataProcessingChoice, ): Promise< | IResponseErrorInternal - | IResponseErrorTooManyRequests | IResponseErrorNotFound + | IResponseErrorTooManyRequests | IResponseSuccessJson > => { const client = this.apiClient.getClient(); @@ -93,46 +95,52 @@ export default class UserDataProcessingService { response.status === 200 ? ResponseSuccessJson(response.value) : response.status === 404 - ? ResponseErrorNotFound("Not Found", "User data processing not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound( + "Not Found", + "User data processing not found", + ) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status), ); }); }; /** - * Abort the user data processing of a specific user. + * Create the user data processing of a specific user. */ - public readonly abortUserDataProcessing = async ( + public readonly upsertUserDataProcessing = async ( user: User, - userDataProcessingChoiceParam: UserDataProcessingChoice + userDataProcessingChoiceRequest: UserDataProcessingChoiceRequest, ): Promise< + | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorTooManyRequests - | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseErrorConflict - | IResponseSuccessAccepted + | IResponseSuccessJson > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.abortUserDataProcessing({ - choice: userDataProcessingChoiceParam, + const validated = await client.upsertUserDataProcessing({ + body: userDataProcessingChoiceRequest, fiscal_code: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => - response.status === 202 - ? ResponseSuccessAccepted() - : response.status === 404 - ? ResponseErrorNotFound("Not Found", "User data processing not found") - : response.status === 409 - ? ResponseErrorConflict("Cannot abort user data processing request") + response.status === 200 + ? ResponseSuccessJson(response.value) : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorTooManyRequests() + : response.status === 409 + ? ResponseErrorConflict( + pipe( + O.fromNullable(response.value.detail), + O.getOrElse(() => "Conflict"), + ), + ) + : unhandledResponseStatus(response.status), ); }); }; + + constructor(private readonly apiClient: IApiClientFactoryInterface) {} } diff --git a/src/strategies/bearerMyPortalTokenStrategy.ts b/src/strategies/bearerMyPortalTokenStrategy.ts index 23a009533..afd0483e1 100644 --- a/src/strategies/bearerMyPortalTokenStrategy.ts +++ b/src/strategies/bearerMyPortalTokenStrategy.ts @@ -6,13 +6,14 @@ import * as express from "express"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; import * as passport from "passport-http-bearer"; + import { ISessionStorage } from "../services/ISessionStorage"; import { MyPortalToken } from "../types/token"; import { User } from "../types/user"; -import { fulfill, StrategyDoneFunction } from "../utils/strategies"; +import { StrategyDoneFunction, fulfill } from "../utils/strategies"; const bearerMyPortalTokenStrategy = ( - sessionStorage: ISessionStorage + sessionStorage: ISessionStorage, ): passport.Strategy => { const options = { passReqToCallback: true, @@ -38,9 +39,9 @@ const bearerMyPortalTokenStrategy = ( // The error is forwarded to the express error middleware done(e); } - } + }, ); - } + }, ); }; diff --git a/src/strategies/bearerSessionTokenStrategy.ts b/src/strategies/bearerSessionTokenStrategy.ts index 37a7d2df9..f00017596 100644 --- a/src/strategies/bearerSessionTokenStrategy.ts +++ b/src/strategies/bearerSessionTokenStrategy.ts @@ -8,14 +8,15 @@ import { Either } from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import { Option } from "fp-ts/lib/Option"; import * as passport from "passport-http-bearer"; + import { ISessionStorage } from "../services/ISessionStorage"; import { SessionToken } from "../types/token"; import { User } from "../types/user"; -import { fulfill, StrategyDoneFunction } from "../utils/strategies"; +import { StrategyDoneFunction, fulfill } from "../utils/strategies"; const bearerSessionTokenStrategy = ( sessionStorage: ISessionStorage, - onValidUser?: (user: User) => void + onValidUser?: (user: User) => void, ): passport.Strategy => { const options = { passReqToCallback: true, @@ -48,9 +49,9 @@ const bearerSessionTokenStrategy = ( // The error is forwarded to the express error middleware done(e); } - } + }, ); - } + }, ); }; diff --git a/src/types/IDPEntityDescriptor.ts b/src/types/IDPEntityDescriptor.ts index 055c5917c..e3f01e8df 100644 --- a/src/types/IDPEntityDescriptor.ts +++ b/src/types/IDPEntityDescriptor.ts @@ -1,6 +1,6 @@ +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as t from "io-ts"; import { nonEmptyArray as createNonEmptyArrayFromArray } from "io-ts-types/lib/nonEmptyArray"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; export const IDPEntityDescriptor = t.interface({ cert: createNonEmptyArrayFromArray(NonEmptyString), diff --git a/src/types/assertionRef.ts b/src/types/assertionRef.ts index 7da471de5..a156ac4dd 100644 --- a/src/types/assertionRef.ts +++ b/src/types/assertionRef.ts @@ -1,10 +1,9 @@ -import * as t from "io-ts"; import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; import { JsonFromString } from "io-ts-types"; -import { LoginType } from "../utils/fastLogin"; - import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; +import { LoginType } from "../utils/fastLogin"; // LollipopData export type LollipopData = t.TypeOf; @@ -32,9 +31,9 @@ const LollipopDataFromCompact = new t.Type< pipe( val, (data) => ({ assertionRef: data.a, loginType: data.t }), - (data) => LollipopData.validate(data, _context) + (data) => LollipopData.validate(data, _context), ), - (val) => ({ a: val.assertionRef, t: val.loginType }) + (val) => ({ a: val.assertionRef, t: val.loginType }), ); // --------------------- diff --git a/src/types/booleans.ts b/src/types/booleans.ts index edc29ba65..3290b7030 100644 --- a/src/types/booleans.ts +++ b/src/types/booleans.ts @@ -22,7 +22,7 @@ export const BooleanFromString: BooleanFromString = new t.Type< s === "true" ? t.success(true) : s === "false" - ? t.success(false) - : t.failure(s, c), - String + ? t.success(false) + : t.failure(s, c), + String, ); diff --git a/src/types/commons.ts b/src/types/commons.ts index 232194210..c2b7f0242 100644 --- a/src/types/commons.ts +++ b/src/types/commons.ts @@ -14,6 +14,7 @@ export type SuccessResponse = t.TypeOf; export const STRINGS_RECORD = t.record(t.string, t.string); export type STRINGS_RECORD = t.TypeOf; +// eslint-disable-next-line @typescript-eslint/no-unused-vars export function assertUnreachable(_: never): never { throw new Error("Unexpected type error"); } @@ -27,9 +28,9 @@ export const IoLoginHostUrl = PatternString("^(https?|iologin):"); * @returns either a decode error or the array of decoded items */ export const CommaSeparatedListOf = (decoder: t.Mixed) => - new t.Type>, string, unknown>( + new t.Type[], string, unknown>( `CommaSeparatedListOf<${decoder.name}>`, - (value: unknown): value is ReadonlyArray> => + (value: unknown): value is readonly t.TypeOf[] => Array.isArray(value) && value.every((e) => decoder.is(e)), (input) => t.readonlyArray(decoder).decode( @@ -39,8 +40,8 @@ export const CommaSeparatedListOf = (decoder: t.Mixed) => .map((e) => e.trim()) .filter(Boolean) : !input - ? [] // fallback to empty array in case of empty input - : input // it should not happen, but in case we let the decoder fail + ? [] // fallback to empty array in case of empty input + : input, // it should not happen, but in case we let the decoder fail ), - String + String, ); diff --git a/src/types/fiscalCode.ts b/src/types/fiscalCode.ts index ad3e34646..ce4698a81 100644 --- a/src/types/fiscalCode.ts +++ b/src/types/fiscalCode.ts @@ -1,10 +1,11 @@ -import * as express from "express"; import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; + import { withValidatedOrValidationError } from "../utils/responses"; export const withFiscalCodeFromRequestParams = async ( req: express.Request, - f: (fiscalCode: FiscalCode) => Promise + f: (fiscalCode: FiscalCode) => Promise, ): Promise => withValidatedOrValidationError(FiscalCode.decode(req.params.fiscal_code), f); diff --git a/src/types/lollipop.ts b/src/types/lollipop.ts index 2727f8638..adc1ebab9 100644 --- a/src/types/lollipop.ts +++ b/src/types/lollipop.ts @@ -1,32 +1,36 @@ - -import * as t from "io-ts"; -import { FiscalCode, NonEmptyString, PatternString } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; import { IResponseErrorValidation, ResponseErrorValidation, } from "@pagopa/ts-commons/lib/responses"; +import { + FiscalCode, + NonEmptyString, + PatternString, +} from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import * as E from "fp-ts/Either"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/Option"; -import { - JwkPubKeyHashAlgorithm, - JwkPubKeyHashAlgorithmEnum, -} from "../../generated/lollipop-api/JwkPubKeyHashAlgorithm"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; + import { AssertionRefSha256 } from "../../generated/backend/AssertionRefSha256"; import { AssertionRefSha384 } from "../../generated/backend/AssertionRefSha384"; import { AssertionRefSha512 } from "../../generated/backend/AssertionRefSha512"; -import { withValidatedOrValidationError } from "../utils/responses"; -import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; -import { AssertionType } from "../../generated/lollipop-api/AssertionType"; -import { JwkPubKeyToken } from "../../generated/lollipop-api/JwkPubKeyToken"; -import { ResLocals } from "../utils/express"; +import { LollipopContentDigest } from "../../generated/lollipop/LollipopContentDigest"; import { LollipopMethod } from "../../generated/lollipop/LollipopMethod"; import { LollipopOriginalURL } from "../../generated/lollipop/LollipopOriginalURL"; import { LollipopSignature } from "../../generated/lollipop/LollipopSignature"; -import { LollipopContentDigest } from "../../generated/lollipop/LollipopContentDigest"; import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; +import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; +import { AssertionType } from "../../generated/lollipop-api/AssertionType"; +import { + JwkPubKeyHashAlgorithm, + JwkPubKeyHashAlgorithmEnum, +} from "../../generated/lollipop-api/JwkPubKeyHashAlgorithm"; +import { JwkPubKeyToken } from "../../generated/lollipop-api/JwkPubKeyToken"; import LollipopService from "../services/lollipopService"; +import { ResLocals } from "../utils/express"; +import { withValidatedOrValidationError } from "../utils/responses"; export interface LollipopParams { readonly isLollipopEnabled: boolean; @@ -60,10 +64,10 @@ export const LollipopLocalsType = t.intersection([ ]); export type LollipopLocalsType = t.TypeOf; -type LollipopLocalsWithBody = LollipopLocalsType & { +type LollipopLocalsWithBody = { readonly body: Buffer; readonly ["content-digest"]: LollipopContentDigest; -}; +} & LollipopLocalsType; /** * Utility function that validate locals to check if all @@ -74,13 +78,13 @@ type LollipopLocalsWithBody = LollipopLocalsType & { * @param locals express res.locals vars injected by toExpressHandler middleware */ export const withLollipopLocals = ( - locals?: T + locals?: T, ): E.Either => pipe( locals, E.fromPredicate(LollipopLocalsType.is, () => - ResponseErrorValidation("Bad request", "Error initializiang lollipop") - ) + ResponseErrorValidation("Bad request", "Error initializiang lollipop"), + ), ); /** @@ -100,7 +104,7 @@ export const withLollipopLocals = ( * @param locals locals validated by withLollipopLocals */ export const withRequiredRawBody = ( - locals?: LollipopLocalsType + locals?: LollipopLocalsType, ): E.Either => pipe( locals, @@ -110,9 +114,9 @@ export const withRequiredRawBody = ( () => ResponseErrorValidation( "Bad request", - "Missing required body or content-digest" - ) - ) + "Missing required body or content-digest", + ), + ), ); /** @@ -126,11 +130,11 @@ export const withRequiredRawBody = ( */ export const withLollipopHeadersFromRequest = async ( req: express.Request, - f: (lollipopHeaders: LollipopRequiredHeaders) => Promise + f: (lollipopHeaders: LollipopRequiredHeaders) => Promise, ): Promise => withValidatedOrValidationError( t.exact(LollipopRequiredHeaders).decode(req.headers), - f + f, ); const Sha256Thumbprint = PatternString("^([A-Za-z0-9-_=]{1,44})$"); @@ -139,7 +143,7 @@ const Sha512Thumbprint = PatternString("^([A-Za-z0-9-_=]{1,88})$"); export const Thumbprint = t.union( [Sha256Thumbprint, Sha384Thumbprint, Sha512Thumbprint], - "Thumbprint" + "Thumbprint", ); export type Thumbprint = t.TypeOf; @@ -151,12 +155,12 @@ export const algoToAssertionRefSet = new Set([ ]); export const getAlgoFromAssertionRef = ( - assertionRef: AssertionRef + assertionRef: AssertionRef, ): JwkPubKeyHashAlgorithm => pipe( Array.from(algoToAssertionRefSet), (ar) => ar.find((entry) => entry.type.is(assertionRef)), O.fromNullable, O.map((pubKeyHashAlgo) => pubKeyHashAlgo.algo), - O.getOrElseW(() => void 0 as never) + O.getOrElseW(() => void 0 as never), ); diff --git a/src/types/notification.ts b/src/types/notification.ts index b720dbce3..7c911088d 100644 --- a/src/types/notification.ts +++ b/src/types/notification.ts @@ -2,9 +2,9 @@ * This file contains the CreatedMessageEventSenderMetadata and Notification models. */ +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as crypto from "crypto"; import * as t from "io-ts"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import { FiscalCode } from "../../generated/backend/FiscalCode"; diff --git a/src/types/pathParams.ts b/src/types/pathParams.ts index 68ee59b3d..4d019ef01 100644 --- a/src/types/pathParams.ts +++ b/src/types/pathParams.ts @@ -1,28 +1,28 @@ -import { pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; -export type Encoder = (params: ReadonlyArray) => string; +export type Encoder = (params: readonly string[]) => string; const createSingleError = - (input: unknown, context: t.Context, errorMessage: string) => (): t.Errors => - [ - { - context, - message: errorMessage, - value: input, - }, - ]; + (input: unknown, context: t.Context, errorMessage: string) => + (): t.Errors => [ + { + context, + message: errorMessage, + value: input, + }, + ]; -export type PathParams = t.Type, string, unknown>; +export type PathParams = t.Type; export const pathParamsFromUrl = ( decodeTemplate: RegExp, - encodeTemplate: Encoder + encodeTemplate: Encoder, ): PathParams => - new t.Type, string, unknown>( + new t.Type( "pathParamsFromUrl", - (u: unknown): u is ReadonlyArray => + (u: unknown): u is readonly string[] => Array.isArray(u) && u.every((value) => typeof value === "string"), (input, context) => pipe( @@ -34,9 +34,9 @@ export const pathParamsFromUrl = ( createSingleError( input, context, - `input is not a valid ${decodeTemplate}` - ) - ) + `input is not a valid ${decodeTemplate}`, + ), + ), ), E.map((i) => decodeTemplate.exec(i)), E.map(O.fromNullable), @@ -45,11 +45,11 @@ export const pathParamsFromUrl = ( createSingleError( input, context, - `Should not be here: input is a valid decodeTemplate but its execution failed!` - ) - ) + `Should not be here: input is a valid decodeTemplate but its execution failed!`, + ), + ), ), - E.map((a) => a.slice(1)) // remove the first element because it is the path itself and just return params + E.map((a) => a.slice(1)), // remove the first element because it is the path itself and just return params ), - encodeTemplate + encodeTemplate, ); diff --git a/src/types/profile.ts b/src/types/profile.ts index a30fc44ad..33e10fbc4 100644 --- a/src/types/profile.ts +++ b/src/types/profile.ts @@ -2,7 +2,7 @@ * This file contains the ProfileWithEmail and ProfileWithoutEmail models and * some functions to validate and convert type to and from them. */ -import * as O from "fp-ts/lib/Option"; +import { ExtendedProfile } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -10,10 +10,10 @@ import { IResponseSuccessJson, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; +import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; -import { ExtendedProfile } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; -import { InitializedProfile } from "../../generated/backend/InitializedProfile"; +import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { formatDate } from "../utils/date"; import { User } from "./user"; @@ -22,7 +22,7 @@ import { User } from "./user"; */ export const toInitializedProfile = ( profile: ExtendedProfile, - user: User + user: User, ): InitializedProfile => ({ accepted_tos_version: profile.accepted_tos_version, blocked_inbox_or_channels: profile.blocked_inbox_or_channels, @@ -37,7 +37,7 @@ export const toInitializedProfile = ( is_email_already_taken: profile.is_email_already_taken, is_email_enabled: pipe( O.fromNullable(profile.is_email_enabled), - O.getOrElseW(() => true) + O.getOrElseW(() => true), ), is_email_validated: profile.is_email_validated, is_inbox_enabled: profile.is_inbox_enabled, @@ -58,9 +58,9 @@ export const profileMissingErrorResponse = export const notFoundProfileToInternalServerError = ( getProfileResponse: | IResponseErrorInternal - | IResponseErrorTooManyRequests | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorTooManyRequests + | IResponseSuccessJson, ) => getProfileResponse.kind === "IResponseErrorNotFound" ? profileMissingErrorResponse diff --git a/src/types/token.ts b/src/types/token.ts index 04d9e5e07..44bedc752 100644 --- a/src/types/token.ts +++ b/src/types/token.ts @@ -1,7 +1,7 @@ -import * as t from "io-ts"; import { tag } from "@pagopa/ts-commons/lib/types"; -import { PecServerConfig } from "src/config"; import * as TE from "fp-ts/TaskEither"; +import * as t from "io-ts"; +import { PecServerConfig } from "src/config"; interface ISessionTokenTag { readonly kind: "SessionToken"; @@ -40,5 +40,5 @@ export const FIMSToken = tag()(t.string); export type FIMSToken = t.TypeOf; export type PecBearerGeneratorT = ( - config: PecServerConfig + config: PecServerConfig, ) => TE.TaskEither; diff --git a/src/types/user.ts b/src/types/user.ts index b89716dcc..67c153e8f 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -3,20 +3,19 @@ * validate and convert type to and from them. */ +import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; -import * as t from "io-ts"; -import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; - import { pipe } from "fp-ts/lib/function"; -import { EmailAddress } from "../../generated/backend/EmailAddress"; -import { FiscalCode } from "../../generated/backend/FiscalCode"; -import { SpidLevel } from "../../generated/backend/SpidLevel"; +import * as t from "io-ts"; import { CieUserIdentity } from "../../generated/auth/CieUserIdentity"; import { SpidUserIdentity } from "../../generated/auth/SpidUserIdentity"; import { UserIdentity } from "../../generated/auth/UserIdentity"; +import { EmailAddress } from "../../generated/backend/EmailAddress"; +import { FiscalCode } from "../../generated/backend/FiscalCode"; +import { SpidLevel } from "../../generated/backend/SpidLevel"; import { withValidatedOrValidationError } from "../utils/responses"; import { BPDToken, @@ -42,8 +41,8 @@ export const UserWithoutTokens = t.intersection([ t.partial({ nameID: t.string, nameIDFormat: t.string, - sessionIndex: t.string, session_tracking_id: t.string, // unique ID used for tracking in appinsights + sessionIndex: t.string, spid_email: EmailAddress, spid_idp: t.string, }), @@ -103,13 +102,13 @@ export type User = t.TypeOf; * @param user */ export function isSpidUserIdentity( - user: CieUserIdentity | SpidUserIdentity + user: CieUserIdentity | SpidUserIdentity, ): user is SpidUserIdentity { return (user as SpidUserIdentity).spid_email !== undefined; } export function exactUserIdentityDecode( - user: UserIdentity + user: UserIdentity, ): E.Either { return isSpidUserIdentity(user) ? t.exact(SpidUserIdentity.type).decode(user) @@ -118,15 +117,15 @@ export function exactUserIdentityDecode( export const withUserFromRequest = async ( req: express.Request, - f: (user: User) => Promise + f: (user: User) => Promise, ): Promise => withValidatedOrValidationError(User.decode(req.user), f); export const withOptionalUserFromRequest = async ( req: express.Request, - f: (user: O.Option) => Promise + f: (user: O.Option) => Promise, ): Promise => withValidatedOrValidationError( req.user ? pipe(User.decode(req.user), E.map(O.some)) : E.right(O.none), - f + f, ); diff --git a/src/utils/AsyncIterableTask.ts b/src/utils/AsyncIterableTask.ts index 3d2f6567d..407d03acd 100644 --- a/src/utils/AsyncIterableTask.ts +++ b/src/utils/AsyncIterableTask.ts @@ -1,13 +1,12 @@ -import * as T from "fp-ts/lib/Task"; -import * as TE from "fp-ts/lib/TaskEither"; - import { - asyncIterableToPageArray, IPage, + asyncIterableToPageArray, mapAsyncIterator, } from "@pagopa/io-functions-commons/dist/src/utils/async"; -import { pipe } from "fp-ts/lib/function"; import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers"; +import * as T from "fp-ts/lib/Task"; +import * as TE from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; /** * @category model @@ -20,7 +19,7 @@ export type AsyncIterableTask = T.Task>; */ const mapAsyncIterable = ( source: AsyncIterable, - f: (t: T) => V | Promise + f: (t: T) => Promise | V, ): AsyncIterable => { const iter = source[Symbol.asyncIterator](); const iterMapped = mapAsyncIterator(iter, f); @@ -37,12 +36,12 @@ const mapAsyncIterable = ( * @category Functor */ export const map: ( - f: (a: A) => B | Promise + f: (a: A) => B | Promise, ) => // eslint-disable-next-line @typescript-eslint/explicit-function-return-type (fa: AsyncIterableTask) => AsyncIterableTask = (f) => (fa) => pipe( fa, - T.map((_) => mapAsyncIterable(_, f)) + T.map((_) => mapAsyncIterable(_, f)), ); export const mapIterable = @@ -51,11 +50,11 @@ export const mapIterable = pipe(fa, T.map(f)); export const fromAsyncIterable = ( - a: AsyncIterable + a: AsyncIterable, ): AsyncIterableTask => T.of(a); export const fromAsyncIterator = ( - a: AsyncIterator + a: AsyncIterator, ): AsyncIterableTask => fromAsyncIterable({ [Symbol.asyncIterator]: () => a, @@ -64,11 +63,11 @@ export const fromAsyncIterator = ( /** * Process an AsyncIterableTask and return an array of results */ -export const fold = (fa: AsyncIterableTask): T.Task> => +export const fold = (fa: AsyncIterableTask): T.Task => pipe( fa, // eslint-disable-next-line @typescript-eslint/no-use-before-define, @typescript-eslint/explicit-function-return-type - T.chain((_) => foldIterableArray(_)) + T.chain((_) => foldIterableArray(_)), ); /** @@ -76,12 +75,12 @@ export const fold = (fa: AsyncIterableTask): T.Task> => */ export const foldTaskEither = (onError: (err: unknown) => E) => - (fa: AsyncIterableTask): TE.TaskEither> => + (fa: AsyncIterableTask): TE.TaskEither => pipe( fa, TE.fromTask, // eslint-disable-next-line @typescript-eslint/no-use-before-define - TE.chain((_) => TE.tryCatch(() => foldIterableArray(_)(), onError)) + TE.chain((_) => TE.tryCatch(() => foldIterableArray(_)(), onError)), ); /** @@ -92,11 +91,9 @@ export const foldTaskEither = */ const foldIterableArray = (asyncIterable: AsyncIterable) => - async (): Promise> => { - // eslint-disable-next-line functional/prefer-readonly-type + async (): Promise => { const array: A[] = []; for await (const variable of asyncIterable) { - // eslint-disable-next-line functional/immutable-data array.push(variable); } return array; @@ -111,7 +108,7 @@ export const run = (fa: AsyncIterableTask): T.Task => for await (const _ of asyncIterable) { // nothing to do: this is done to resolve the async iterator } - }) + }), ); /** @@ -121,7 +118,7 @@ export const reduceTaskEither = ( onError: (err: unknown) => E, initialValue: B, - reducer: (prev: B, curr: A) => B | Promise + reducer: (prev: B, curr: A) => B | Promise, ) => (fa: AsyncIterableTask): TE.TaskEither => pipe( @@ -131,9 +128,9 @@ export const reduceTaskEither = TE.tryCatch( // eslint-disable-next-line @typescript-eslint/no-use-before-define reduceIterableArray(initialValue, reducer)(_), - onError - ) - ) + onError, + ), + ), ); /** @@ -144,7 +141,6 @@ const reduceIterableArray = (initialValue: B, reducer: (prev: B, curr: A) => B | Promise) => (asyncIterable: AsyncIterable) => async (): Promise => { - // eslint-disable-next-line functional/no-let let p: B = initialValue; for await (const variable of asyncIterable) { @@ -163,6 +159,6 @@ export const toPageArray = fa, TE.fromTask, TE.chain((_) => - TE.tryCatch(() => asyncIterableToPageArray(_, pageSize), onError) - ) + TE.tryCatch(() => asyncIterableToPageArray(_, pageSize), onError), + ), ); diff --git a/src/utils/appinsights.ts b/src/utils/appinsights.ts index 2bd78557d..9d83d9bc7 100644 --- a/src/utils/appinsights.ts +++ b/src/utils/appinsights.ts @@ -1,19 +1,20 @@ -import * as appInsights from "applicationinsights"; +import { + sha256, + validateDigestHeader, +} from "@pagopa/io-functions-commons/dist/src/utils/crypto"; import { ApplicationInsightsConfig, initAppInsights as startAppInsights, } from "@pagopa/ts-commons/lib/appinsights"; -import { eventLog } from "@pagopa/winston-ts"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { pipe } from "fp-ts/lib/function"; -import * as O from "fp-ts/lib/Option"; +import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; +import { eventLog } from "@pagopa/winston-ts"; +import * as appInsights from "applicationinsights"; import { Request } from "express"; import * as E from "fp-ts/lib/Either"; -import { - sha256, - validateDigestHeader, -} from "@pagopa/io-functions-commons/dist/src/utils/crypto"; -import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; +import * as O from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; + import { LollipopLocalsType } from "../types/lollipop"; import { toFiscalCodeHash } from "../types/notification"; import { User } from "../types/user"; @@ -46,41 +47,37 @@ export function attachTrackingData(user: User): void { customProperties.setProperty( USER_TRACKING_ID_KEY, - toFiscalCodeHash(user.fiscal_code) + toFiscalCodeHash(user.fiscal_code), ); if (user.session_tracking_id !== undefined) { customProperties.setProperty( SESSION_TRACKING_ID_KEY, - user.session_tracking_id + user.session_tracking_id, ); } } export function sessionIdPreprocessor( envelope: appInsights.Contracts.Envelope, - context?: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - readonly [name: string]: any; - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + context?: Readonly>, ): boolean { if (context !== undefined) { try { const userTrackingId = context.correlationContext.customProperties.getProperty( - USER_TRACKING_ID_KEY + USER_TRACKING_ID_KEY, ); if (userTrackingId !== undefined) { - // eslint-disable-next-line functional/immutable-data envelope.tags[appInsights.defaultClient.context.keys.userId] = userTrackingId; } const sessionTrackingId = context.correlationContext.customProperties.getProperty( - SESSION_TRACKING_ID_KEY + SESSION_TRACKING_ID_KEY, ); if (sessionTrackingId !== undefined) { - // eslint-disable-next-line functional/immutable-data envelope.tags[appInsights.defaultClient.context.keys.sessionId] = sessionTrackingId; } @@ -99,7 +96,7 @@ export enum StartupEventName { export const trackStartupTime = ( telemetryClient: appInsights.TelemetryClient, type: StartupEventName, - timeMs: bigint + timeMs: bigint, ): void => { telemetryClient.trackEvent({ name: type, @@ -120,7 +117,7 @@ export const trackStartupTime = ( */ export function initAppInsights( instrumentationKey: string, - config: ApplicationInsightsConfig = {} + config: ApplicationInsightsConfig = {}, ): appInsights.TelemetryClient { startAppInsights(instrumentationKey, config); appInsights.defaultClient.addTelemetryProcessor(sessionIdPreprocessor); @@ -130,11 +127,11 @@ export function initAppInsights( export const LOLLIPOP_SIGN_EVENT_NAME = "lollipop.sign"; export type LCResponseLogLollipop = ( - lcResponse: E.Either + lcResponse: E.Either, ) => void; export type RequestLogLollipop = ( lollipopParams: LollipopLocalsType, - req: Request + req: Request, ) => LCResponseLogLollipop; /** @@ -151,10 +148,10 @@ export const logLollipopSignRequest = (lollipopConsumerId: NonEmptyString) => < // eslint-disable-next-line @typescript-eslint/no-explicit-any - T extends Exclude, LollipopLocalsType> + T extends Exclude, LollipopLocalsType>, >( lollipopParams: LollipopLocalsType & T, - req: Request + req: Request, ): LCResponseLogLollipop => (lcResponse: E.Either) => { pipe( @@ -171,35 +168,35 @@ export const logLollipopSignRequest = pipe( E.tryCatch( () => validateDigestHeader(contentDigest, lollipopParams.body), - E.toError + E.toError, ), E.fold( () => false, - () => true - ) - ) + () => true, + ), + ), ), - O.toUndefined + O.toUndefined, ), // A string rapresenting the response from the LC. lc_response: pipe( lcResponse, E.map(JSON.stringify), E.mapLeft((err) => err.message), - E.toUnion + E.toUnion, ), lollipop_consumer_id: lollipopConsumerId, method: req.method, original_url: req.originalUrl, // The fiscal code will be sent hashed to the logs ["x-pagopa-lollipop-user-id"]: sha256( - lollipopHeadersWithoutBody["x-pagopa-lollipop-user-id"] + lollipopHeadersWithoutBody["x-pagopa-lollipop-user-id"], ), })), O.map(withoutUndefinedValues), eventLog.option.info((lollipopEventData) => [ `Lollipop Request log`, lollipopEventData, - ]) + ]), ); }; diff --git a/src/utils/attachments.ts b/src/utils/attachments.ts index 9803b6508..61e737fe2 100644 --- a/src/utils/attachments.ts +++ b/src/utils/attachments.ts @@ -1,10 +1,11 @@ import * as A from "fp-ts/lib/Array"; -import { pipe } from "fp-ts/lib/function"; import * as T from "fp-ts/lib/Task"; import { Task } from "fp-ts/lib/Task"; import * as TE from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { MessageAttachment } from "generated/backend/MessageAttachment"; import { PrescriptionData } from "generated/backend/PrescriptionData"; + import { toBarcode } from "./barcode"; const MIME_TYPES = { @@ -27,7 +28,7 @@ const toBarcodeAttachments = (name: string, value: string) => { content: barcodes.svg, mime_type: MIME_TYPES.svg, name }, ]), TE.mapLeft(() => []), - TE.toUnion + TE.toUnion, ); /** @@ -36,17 +37,17 @@ const toBarcodeAttachments = (name: string, value: string) => * the rendered barcode (svg and png) for each field. */ export function getPrescriptionAttachments( - prescriptionData: PrescriptionData -): Task> { + prescriptionData: PrescriptionData, +): Task { return pipe( A.sequence(T.ApplicativePar)([ toBarcodeAttachments("iup", prescriptionData.iup), toBarcodeAttachments("nre", prescriptionData.nre), toBarcodeAttachments( "prescriber_fiscal_code", - prescriptionData.prescriber_fiscal_code as string + prescriptionData.prescriber_fiscal_code as string, ), ]), - T.map(A.flatten) + T.map(A.flatten), ); } diff --git a/src/utils/barcode.ts b/src/utils/barcode.ts index a58210442..c03765751 100644 --- a/src/utils/barcode.ts +++ b/src/utils/barcode.ts @@ -2,9 +2,10 @@ import * as bwipjs from "bwip-js"; import { ToBufferOptions } from "bwip-js"; import * as AP from "fp-ts/lib/Apply"; import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/lib/TaskEither"; import { TaskEither } from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; + import { BARCODE_ALGORITHM } from "../../src/config"; import { DrawingSVG } from "./bwipjs-svg"; @@ -27,7 +28,8 @@ const toBufferSvg = (options: ToBufferOptions) => const svg = bwipjs.render(opts, DrawingSVG(opts, bwipjs.FontLib)); return Buffer.from(svg); }, - (errs) => new Error(`Cannot generate svg barcode|${errs}`) as Error | string + (errs) => + new Error(`Cannot generate svg barcode|${errs}`) as Error | string, ); /** @@ -41,7 +43,7 @@ const toBufferPng = TE.taskify(bwipjs.toBuffer); */ export function toBarcode( text: string, - bcid = BARCODE_ALGORITHM + bcid = BARCODE_ALGORITHM, ): TaskEither { const options = { bcid, @@ -58,16 +60,16 @@ export function toBarcode( E.left( typeof errorOrString === "string" ? new Error(errorOrString) - : errorOrString - ) + : errorOrString, + ), ), (images) => TE.fromEither( E.right({ png: images.png.toString("base64"), svg: images.svg.toString("base64"), - }) - ) - ) + }), + ), + ), ); } diff --git a/src/utils/container.ts b/src/utils/container.ts index f4335c327..e8eb2add7 100644 --- a/src/utils/container.ts +++ b/src/utils/container.ts @@ -1,4 +1,5 @@ import * as fs from "fs"; + import { log } from "./logger"; /** diff --git a/src/utils/date.ts b/src/utils/date.ts index c92dc22a1..341fb2fdc 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,10 +1,10 @@ import { PatternString } from "@pagopa/ts-commons/lib/strings"; import { addYears, format, isAfter } from "date-fns"; -import { pipe } from "fp-ts/lib/function"; +import * as E from "fp-ts/Either"; import { Option, tryCatch } from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; import { FiscalCode } from "generated/backend/FiscalCode"; import * as t from "io-ts"; -import * as E from "fp-ts/Either"; /** * Returns a comparator of two dates that returns true if @@ -16,7 +16,7 @@ export const isOlderThan = (years: number) => (dateOfBirth: Date, when: Date) => export const isValidDate = (d: Date) => d instanceof Date && !isNaN(d.getTime()); -const months: { readonly [k: string]: number } = { +const months: Readonly> = { ["A"]: 1, ["B"]: 2, ["C"]: 3, @@ -92,7 +92,7 @@ const isDate = (v: t.mixed): v is Date => v instanceof Date; * */ const STRICT_UTC_ISO8601_FULL_REGEX = PatternString( - "^\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(\\.\\d+)?[+-](\\d{2})\\:(\\d{2})$" + "^\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(\\.\\d+)?[+-](\\d{2})\\:(\\d{2})$", ); // 2021-12-22T10:56:03+01:00 /** @@ -111,9 +111,9 @@ export const StrictUTCISODateFromString = new t.Type( E.chain((s) => { const d = new Date(s); return isNaN(d.getTime()) ? t.failure(s, c) : t.success(d); - }) + }), ), - (a) => a.toISOString() + (a) => a.toISOString(), ); export type StrictUTCISODateFromString = t.TypeOf< diff --git a/src/utils/errorsFormatter.ts b/src/utils/errorsFormatter.ts index b5d576f12..bafadb3e6 100644 --- a/src/utils/errorsFormatter.ts +++ b/src/utils/errorsFormatter.ts @@ -1,6 +1,6 @@ -import { Errors } from "io-ts"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; +import { Errors } from "io-ts"; /** * Merge into one single Error several errors provided in input and add a context description @@ -10,13 +10,13 @@ import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; * @returns A single Error instance with a formatted message. */ export function multipleErrorsFormatter( - errors: ReadonlyArray, - context: string + errors: readonly Error[], + context: string, ): Error { return new Error( errors .map((_) => `value [${_.message}]`) - .join(` at [context: ${context}]\n`) + .join(` at [context: ${context}]\n`), ); } diff --git a/src/utils/express.ts b/src/utils/express.ts index feb42bd74..a5d9f94af 100644 --- a/src/utils/express.ts +++ b/src/utils/express.ts @@ -1,25 +1,24 @@ -import * as express from "express"; import { IResponse, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; -import { flow, pipe } from "fp-ts/lib/function"; +import * as express from "express"; import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; export type ExpressMiddleware = ( req: express.Request, res: express.Response, - next: express.NextFunction + next: express.NextFunction, ) => void; -export type ResLocals = Record & { - // eslint-disable-next-line functional/prefer-readonly-type - detail?: string; - // eslint-disable-next-line functional/prefer-readonly-type +export type ResLocals = { body?: Buffer; -}; + + detail?: string; +} & Record; /** * Convenience method that transforms a function (handler), * which takes an express.Request as input and returns an IResponse, @@ -27,14 +26,13 @@ export type ResLocals = Record & { */ export function toExpressHandler( handler: (req: express.Request, locals?: L) => Promise>, - object?: P + object?: P, ): (req: express.Request, res: express.Response) => void { - return (req, res): Promise => + return (req, res) => handler .call(object, req, res.locals) .catch(ResponseErrorInternal) .then((response) => { - // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }); @@ -48,27 +46,26 @@ export function toExpressHandler( */ export function toExpressMiddleware( handler: (req: express.Request) => Promise | undefined>, - object?: P + object?: P, ): ExpressMiddleware { return (req, res, next): Promise => pipe( TE.tryCatch( () => handler.call(object, req), - flow(E.toError, (e) => ResponseErrorInternal(e.message)) + flow(E.toError, (e) => ResponseErrorInternal(e.message)), ), TE.chainW( flow( O.fromNullable, O.map(TE.left), - O.getOrElseW(() => TE.right(next())) - ) + O.getOrElseW(() => TE.right(next())), + ), ), TE.mapLeft((response) => { - // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }), - TE.toUnion + TE.toUnion, )(); } @@ -76,10 +73,9 @@ export function toExpressMiddleware( * An Express handler that always respond with the same response object */ export function constantExpressHandler( - response: IResponse + response: IResponse, ): (req: express.Request, res: express.Response) => void { return (_, res) => { - // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }; diff --git a/src/utils/fastLogin.ts b/src/utils/fastLogin.ts index 770a1bdc0..42e9a9fbc 100644 --- a/src/utils/fastLogin.ts +++ b/src/utils/fastLogin.ts @@ -1,9 +1,9 @@ -import * as t from "io-ts"; import { enumType } from "@pagopa/ts-commons/lib/types"; +import * as t from "io-ts"; export enum LoginTypeEnum { - "LV" = "LV", "LEGACY" = "LEGACY", + "LV" = "LV", } export type LoginTypeT = t.TypeOf; export const LoginType = enumType(LoginTypeEnum, "LoginType"); diff --git a/src/utils/featureFlag.ts b/src/utils/featureFlag.ts index e741baa3e..597703bd6 100644 --- a/src/utils/featureFlag.ts +++ b/src/utils/featureFlag.ts @@ -10,7 +10,7 @@ export enum FeatureFlagEnum { export const FeatureFlag = enumType( FeatureFlagEnum, - "FeatureFlag" + "FeatureFlag", ); export type FeatureFlag = t.TypeOf; @@ -19,7 +19,7 @@ export const getIsUserEligibleForNewFeature = ( isUserBeta: (i: T) => boolean, isUserCanary: (i: T) => boolean, - featureFlag: FeatureFlag + featureFlag: FeatureFlag, ): ((i: T) => boolean) => (i): boolean => { switch (featureFlag) { diff --git a/src/utils/file-type.ts b/src/utils/file-type.ts index 56be79b4b..06f3b09dc 100644 --- a/src/utils/file-type.ts +++ b/src/utils/file-type.ts @@ -1,9 +1,9 @@ -import { pipe } from "fp-ts/lib/function"; +import * as EQ from "fp-ts/Eq"; import * as RS from "fp-ts/ReadonlySet"; +import { pipe } from "fp-ts/lib/function"; import { match } from "ts-pattern"; -import * as EQ from "fp-ts/Eq"; -export type FileType = "pdf" | "any"; +export type FileType = "any" | "pdf"; /** * Verify if the input buffer contains a PDF using the magic number in the first bytes (see https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) @@ -16,6 +16,7 @@ export const isPdf = (data: Buffer) => data.toString("binary", 0, 4) === "%PDF"; /** * Allow any file type */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars export const isAny = (_: Buffer) => true; export const typeToCheck = (type: FileType) => @@ -28,7 +29,7 @@ export const typeToCheck = (type: FileType) => * Compare two functions: will return true if the functions have the same body */ export const eqFunction: EQ.Eq> = EQ.fromEquals( - (f1, f2) => f1.toString() === f2.toString() + (f1, f2) => f1.toString() === f2.toString(), ); /** @@ -42,5 +43,5 @@ export const getIsFileTypeForTypes = pipe( types, RS.map(eqFunction)(typeToCheck), - RS.some((is) => is(data)) + RS.some((is) => is(data)), ); diff --git a/src/utils/gracefulShutdown.ts b/src/utils/gracefulShutdown.ts index a7ce15a17..41aad49bd 100644 --- a/src/utils/gracefulShutdown.ts +++ b/src/utils/gracefulShutdown.ts @@ -1,13 +1,14 @@ -import * as http from "http"; -import * as https from "https"; import { Express } from "express"; +import * as http from "http"; import * as httpGracefulShutdown from "http-graceful-shutdown"; +import * as https from "https"; + import { log } from "./logger"; export function initHttpGracefulShutdown( server: http.Server | https.Server, app: Express, - options: httpGracefulShutdown.Options + options: httpGracefulShutdown.Options, ): void { log.info("Initializing server graceful shutdown"); httpGracefulShutdown(server, { diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 72bb82ceb..a0aa7345e 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,14 +1,14 @@ import * as logform from "logform"; import { createLogger, format, transports } from "winston"; -const { timestamp, printf } = logform.format; +const { printf, timestamp } = logform.format; export const log = createLogger({ format: format.combine( timestamp(), format.splat(), format.simple(), - printf((nfo) => `${nfo.timestamp} [${nfo.level}]: ${nfo.message}`) + printf((nfo) => `${nfo.timestamp} [${nfo.level}]: ${nfo.message}`), ), transports: [new transports.Console()], }); diff --git a/src/utils/lollipop.ts b/src/utils/lollipop.ts index 8cd1228f6..bceb7f9e4 100644 --- a/src/utils/lollipop.ts +++ b/src/utils/lollipop.ts @@ -1,38 +1,39 @@ -import { flow, identity, pipe } from "fp-ts/lib/function"; +import { sha256 } from "@pagopa/io-functions-commons/dist/src/utils/crypto"; +import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, ResponseErrorForbiddenNotAuthorized, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; -import * as E from "fp-ts/Either"; -import { ulid } from "ulid"; import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; +import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import { eventLog } from "@pagopa/winston-ts"; -import { sha256 } from "@pagopa/io-functions-commons/dist/src/utils/crypto"; -import { Errors } from "io-ts"; +import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; -import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import * as RA from "fp-ts/ReadonlyArray"; import * as TE from "fp-ts/TaskEither"; -import { RCConfigurationPublic } from "../../generated/io-messages-api/RCConfigurationPublic"; +import { flow, identity, pipe } from "fp-ts/lib/function"; +import { Errors } from "io-ts"; +import { ulid } from "ulid"; + import { AssertionRef } from "../../generated/backend/AssertionRef"; -import { ISessionStorage } from "../services/ISessionStorage"; +import { RCConfigurationPublic } from "../../generated/io-messages-api/RCConfigurationPublic"; +import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; +import { LcParams } from "../../generated/lollipop-api/LcParams"; import { LollipopApiClient } from "../clients/lollipop"; +import { ISessionStorage } from "../services/ISessionStorage"; import { LollipopLocalsType, LollipopRequiredHeaders, Thumbprint, getAlgoFromAssertionRef, } from "../types/lollipop"; -import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; -import { LcParams } from "../../generated/lollipop-api/LcParams"; import { log } from "./logger"; type ErrorsResponses = - | IResponseErrorInternal - | IResponseErrorForbiddenNotAuthorized; + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorInternal; const LOLLIPOP_SIGN_ERROR_EVENT_NAME = "lollipop.error.sign"; const NONCE_REGEX = new RegExp(';?nonce="([^"]+)";?'); @@ -40,7 +41,7 @@ const NONCE_REGEX = new RegExp(';?nonce="([^"]+)";?'); const KEY_ID_REGEX = new RegExp(';?keyid="([^"]+)";?'); const getNonceOrUlid = ( - lollipopSignatureInput: LollipopSignatureInput + lollipopSignatureInput: LollipopSignatureInput, ): NonEmptyString => { // The nonce value must be the first regex group // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -52,7 +53,7 @@ const getNonceOrUlid = ( }; export const getKeyThumbprintFromSignature = ( - lollipopSignatureInput: LollipopSignatureInput + lollipopSignatureInput: LollipopSignatureInput, ): E.Either => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, thumbprint, ...__] = KEY_ID_REGEX.exec(lollipopSignatureInput) ?? [ @@ -64,7 +65,7 @@ export const getKeyThumbprintFromSignature = ( export const checkIfLollipopIsEnabled = ( fiscalCode: FiscalCode, - remoteContentConfiguration: RCConfigurationPublic + remoteContentConfiguration: RCConfigurationPublic, ) => pipe( TE.of(remoteContentConfiguration), @@ -79,23 +80,23 @@ export const checkIfLollipopIsEnabled = ( TE.map( (config) => config.is_lollipop_enabled && - !config.disable_lollipop_for.includes(fiscalCode) - ) + !config.disable_lollipop_for.includes(fiscalCode), + ), ); const getAndValidateAssertionRefForUser = ( sessionStorage: ISessionStorage, fiscalCode: FiscalCode, operationId: NonEmptyString, - keyThumbprint: Thumbprint + keyThumbprint: Thumbprint, ): TE.TaskEither< - IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, + IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, AssertionRef > => pipe( TE.tryCatch( () => sessionStorage.getLollipopAssertionRefForUser(fiscalCode), - E.toError + E.toError, ), TE.chainEitherK(identity), eventLog.taskEither.errorLeft((err) => [ @@ -109,7 +110,7 @@ const getAndValidateAssertionRefForUser = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error reading the assertionRef from redis [%s]", - err.message + err.message, ); return ResponseErrorInternal("Error retrieving the assertionRef"); }), @@ -120,7 +121,7 @@ const getAndValidateAssertionRefForUser = ( (assertionRef) => assertionRef === `${getAlgoFromAssertionRef(assertionRef)}-${keyThumbprint}`, - () => ResponseErrorForbiddenNotAuthorized + () => ResponseErrorForbiddenNotAuthorized, ), eventLog.taskEither.errorLeft(() => [ `AssertionRef is different from stored one`, @@ -129,12 +130,11 @@ const getAndValidateAssertionRefForUser = ( name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, operation_id: operationId, }, - ]) - ) - ) + ]), + ), + ), ); -/* eslint-disable sonarjs/no-identical-functions */ /** * @deprecated */ @@ -142,17 +142,16 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( lollipopClient: ReturnType, sessionStorage: ISessionStorage, fiscalCode: FiscalCode, - lollipopHeaders: LollipopRequiredHeaders + lollipopHeaders: LollipopRequiredHeaders, ) => pipe( - // eslint-disable-next-line sonarjs/no-duplicate-string TE.of(getNonceOrUlid(lollipopHeaders["signature-input"])), TE.bindTo("operationId"), TE.bind("assertionRef", ({ operationId }) => pipe( TE.tryCatch( () => sessionStorage.getLollipopAssertionRefForUser(fiscalCode), - E.toError + E.toError, ), TE.chainEitherK(identity), eventLog.taskEither.errorLeft((err) => [ @@ -166,12 +165,12 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error reading the assertionRef from redis [%s]", - err.message + err.message, ); return ResponseErrorInternal("Error retrieving the assertionRef"); }), - TE.chainW(TE.fromOption(() => ResponseErrorForbiddenNotAuthorized)) - ) + TE.chainW(TE.fromOption(() => ResponseErrorForbiddenNotAuthorized)), + ), ), TE.bindW("generateLCParamsResponse", ({ assertionRef, operationId }) => pipe( @@ -183,7 +182,7 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( operation_id: operationId, }, }), - E.toError + E.toError, ), eventLog.taskEither.errorLeft((error) => [ `Error trying to call the Lollipop function service | ${error.message}`, @@ -197,21 +196,21 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error trying to call the Lollipop function service [%s]", - err.message + err.message, ); return ResponseErrorInternal( - "Error calling the Lollipop function service" + "Error calling the Lollipop function service", ); - }) - ) + }), + ), ), - TE.chain(({ generateLCParamsResponse, assertionRef, operationId }) => + TE.chain(({ assertionRef, generateLCParamsResponse, operationId }) => pipe( generateLCParamsResponse, TE.fromEither, eventLog.taskEither.errorLeft((err) => [ `Unexpected response from the lollipop function service | ${readableReportSimplified( - err + err, )}`, { assertion_ref: assertionRef, @@ -223,10 +222,10 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error calling the Lollipop function service [%s]", - readableReportSimplified(err) + readableReportSimplified(err), ); return ResponseErrorInternal( - "Unexpected response from lollipop service" + "Unexpected response from lollipop service", ); }), TE.chainW((lollipopRes) => @@ -234,10 +233,12 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( lollipopRes.status === 200 ? TE.of(lollipopRes.value) : lollipopRes.status === 403 - ? TE.left(ResponseErrorForbiddenNotAuthorized) - : TE.left( - ResponseErrorInternal("The lollipop service returns an error") - ), + ? TE.left(ResponseErrorForbiddenNotAuthorized) + : TE.left( + ResponseErrorInternal( + "The lollipop service returns an error", + ), + ), eventLog.taskEither.errorLeft((errorResponse) => [ `The lollipop function service returns an error | ${errorResponse.kind}`, { @@ -246,10 +247,10 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, operation_id: operationId, }, - ]) - ) - ) - ) + ]), + ), + ), + ), ), TE.map( (lcParams) => @@ -260,19 +261,19 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( ["x-pagopa-lollipop-public-key"]: lcParams.pub_key, ["x-pagopa-lollipop-user-id"]: fiscalCode, ...lollipopHeaders, - } as LollipopLocalsType) + }) as LollipopLocalsType, ), eventLog.taskEither.info((lcLocals) => [ "Lollipop locals to be sent to third party api", { ...Object.keys(lcLocals), name: "lollipop.locals.info" }, - ]) + ]), ); const retrieveLCParams = ( assertionRef: AssertionRef, lollipopClient: ReturnType, operationId: NonEmptyString, - fiscalCode?: FiscalCode + fiscalCode?: FiscalCode, ): TE.TaskEither< IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, O.Option @@ -286,7 +287,7 @@ const retrieveLCParams = ( operation_id: operationId, }, }), - E.toError + E.toError, ), eventLog.taskEither.errorLeft((error) => [ `Error trying to call the Lollipop function service | ${error.message}`, @@ -300,10 +301,10 @@ const retrieveLCParams = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error trying to call the Lollipop function service [%s]", - err.message + err.message, ); return ResponseErrorInternal( - "Error calling the Lollipop function service" + "Error calling the Lollipop function service", ); }), TE.chain( @@ -311,7 +312,7 @@ const retrieveLCParams = ( TE.fromEither, eventLog.taskEither.errorLeft((err) => [ `Unexpected response from the lollipop function service | ${readableReportSimplified( - err + err, )}`, withoutUndefinedValues({ assertion_ref: assertionRef, @@ -323,27 +324,29 @@ const retrieveLCParams = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error calling the Lollipop function service [%s]", - readableReportSimplified(err) + readableReportSimplified(err), ); return ResponseErrorInternal( - "Unexpected response from lollipop service" + "Unexpected response from lollipop service", ); - }) - ) + }), + ), ), TE.chainW((lollipopRes) => pipe( lollipopRes.status === 200 ? TE.of>( - O.some(lollipopRes.value) + O.some(lollipopRes.value), ) : lollipopRes.status === 403 - ? TE.left(ResponseErrorForbiddenNotAuthorized) - : lollipopRes.status === 404 - ? TE.right(O.none) - : TE.left( - ResponseErrorInternal("The lollipop service returns an error") - ), + ? TE.left(ResponseErrorForbiddenNotAuthorized) + : lollipopRes.status === 404 + ? TE.right(O.none) + : TE.left( + ResponseErrorInternal( + "The lollipop service returns an error", + ), + ), eventLog.taskEither.errorLeft((errorResponse) => [ `The lollipop function service returns an error | ${errorResponse.kind}`, withoutUndefinedValues({ @@ -352,18 +355,18 @@ const retrieveLCParams = ( name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, operation_id: operationId, }), - ]) - ) - ) + ]), + ), + ), ); export const extractLollipopLocalsFromLollipopHeaders = ( lollipopClient: ReturnType, sessionStorage: ISessionStorage, lollipopHeaders: LollipopRequiredHeaders, - fiscalCode?: FiscalCode + fiscalCode?: FiscalCode, ): TE.TaskEither< - IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, + IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, LollipopLocalsType > => pipe( @@ -381,10 +384,10 @@ export const extractLollipopLocalsFromLollipopHeaders = ( }, ]), E.mapLeft(() => - ResponseErrorInternal("Invalid assertionRef in signature params") + ResponseErrorInternal("Invalid assertionRef in signature params"), ), - TE.fromEither - ) + TE.fromEither, + ), ), TE.bind("assertionRefSet", ({ keyThumbprint, operationId }) => pipe( @@ -395,19 +398,19 @@ export const extractLollipopLocalsFromLollipopHeaders = ( sessionStorage, fc, operationId, - keyThumbprint + keyThumbprint, ), - TE.map((assertionRef) => [assertionRef]) - ) + TE.map((assertionRef) => [assertionRef]), + ), ), O.getOrElse(() => TE.of([ `sha256-${keyThumbprint}` as AssertionRef, `sha384-${keyThumbprint}` as AssertionRef, `sha512-${keyThumbprint}` as AssertionRef, - ]) - ) - ) + ]), + ), + ), ), TE.bindW("lcParams", ({ assertionRefSet, operationId }) => pipe( @@ -418,33 +421,33 @@ export const extractLollipopLocalsFromLollipopHeaders = ( assertionRef, lollipopClient, operationId, - fiscalCode + fiscalCode, ), TE.chainW((_) => - O.isSome(_) ? TE.left(_.value) : TE.right(O.none) - ) - ) + O.isSome(_) ? TE.left(_.value) : TE.right(O.none), + ), + ), ), TE.fold( (_) => LcParams.is(_) ? TE.right(_) : _.kind === "IResponseErrorInternal" || - _.kind === "IResponseErrorForbiddenNotAuthorized" - ? TE.left(_) - : TE.left( - ResponseErrorInternal( - "Unexpected result given from retrieveLCParams" - ) - ), + _.kind === "IResponseErrorForbiddenNotAuthorized" + ? TE.left(_) + : TE.left( + ResponseErrorInternal( + "Unexpected result given from retrieveLCParams", + ), + ), () => TE.left< IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - >(ResponseErrorInternal("Missing assertion ref")) - ) - ) + >(ResponseErrorInternal("Missing assertion ref")), + ), + ), ), - TE.chainFirst(({ operationId, lcParams, keyThumbprint }) => + TE.chainFirst(({ keyThumbprint, lcParams, operationId }) => pipe( O.fromNullable(fiscalCode), O.map(() => TE.of(true)), @@ -454,12 +457,12 @@ export const extractLollipopLocalsFromLollipopHeaders = ( sessionStorage, lcParams.fiscal_code, operationId, - keyThumbprint + keyThumbprint, ), - TE.map(() => true) - ) - ) - ) + TE.map(() => true), + ), + ), + ), ), TE.map( ({ lcParams }) => @@ -472,11 +475,10 @@ export const extractLollipopLocalsFromLollipopHeaders = ( // the authorization is equal to the one from the lollipop function ["x-pagopa-lollipop-user-id"]: fiscalCode || lcParams.fiscal_code, ...lollipopHeaders, - } as LollipopLocalsType) + }) as LollipopLocalsType, ), eventLog.taskEither.info((lcLocals) => [ "Lollipop locals to be sent to third party api", { ...Object.keys(lcLocals), name: "lollipop.locals.info" }, - ]) + ]), ); -/* eslint-enable sonarjs/no-identical-functions */ diff --git a/src/utils/middleware/checkIP.ts b/src/utils/middleware/checkIP.ts index 57915b79b..9caa6442b 100644 --- a/src/utils/middleware/checkIP.ts +++ b/src/utils/middleware/checkIP.ts @@ -2,41 +2,42 @@ * An Express middleware that checks if source IP falls into a CIDR range. */ -import * as express from "express"; -import * as E from "fp-ts/lib/Either"; import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { CIDR, IPString } from "@pagopa/ts-commons/lib/strings"; -import * as rangeCheck from "range_check"; +import * as express from "express"; +import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; +import * as rangeCheck from "range_check"; + import { log } from "../logger"; import { decodeIPAddressFromReq } from "../network"; export default function checkIP( - range: ReadonlyArray + range: readonly CIDR[], ): ( req: express.Request, res: express.Response, - next: express.NextFunction + next: express.NextFunction, ) => void { return ( req: express.Request, res: express.Response, - next: express.NextFunction + next: express.NextFunction, ): void => { const errorOrIPString = pipe( decodeIPAddressFromReq(req), E.alt(() => // use x-client-ip instead of x-forwarded-for // for internal calls (same vnet) - IPString.decode(req.headers["x-client-ip"]) - ) + IPString.decode(req.headers["x-client-ip"]), + ), ); if (E.isLeft(errorOrIPString)) { log.error( `Cannot decode source IP: (req.ip=${req.ip},x-client-ip=${ req.headers["x-client-ip"] - },error=${readableReport(errorOrIPString.left)}.` + },error=${readableReport(errorOrIPString.left)}.`, ); res.status(400).send("Bad request"); } else { diff --git a/src/utils/middleware/dueDate.ts b/src/utils/middleware/dueDate.ts index 0a555c750..8b85b1f72 100644 --- a/src/utils/middleware/dueDate.ts +++ b/src/utils/middleware/dueDate.ts @@ -1,5 +1,6 @@ -import { NextFunction, Request, Response } from "express"; import { ResponseErrorNotFound } from "@pagopa/ts-commons/lib/responses"; +import { NextFunction, Request, Response } from "express"; + import { log } from "../logger"; /** @@ -10,7 +11,7 @@ import { log } from "../logger"; * @param dueDate date until the resource is valid */ export function dueDateMiddleware( - dueDate: Date + dueDate: Date, ): (req: Request, res: Response, next: NextFunction) => void { return (req, res, next) => { const now = new Date(); @@ -18,11 +19,11 @@ export function dueDateMiddleware( log.warn( `An ${req.method.toUpperCase()} ${ req.path - } request has landed at ${now.toISOString()} although it was supposed to expire at ${dueDate.toISOString()}.` + } request has landed at ${now.toISOString()} although it was supposed to expire at ${dueDate.toISOString()}.`, ); ResponseErrorNotFound( "Expired resource", - "The resource you asked for is no longer available" + "The resource you asked for is no longer available", ).apply(res); } else { next(); diff --git a/src/utils/middleware/express.ts b/src/utils/middleware/express.ts index 8a9f863e0..77d3b65be 100644 --- a/src/utils/middleware/express.ts +++ b/src/utils/middleware/express.ts @@ -1,5 +1,6 @@ -import { NextFunction, Request, Response } from "express"; import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; +import { NextFunction, Request, Response } from "express"; + import { log } from "../logger"; /** @@ -12,7 +13,8 @@ export function expressErrorMiddleware( err: Error, _: Request, res: Response, - __: NextFunction + // eslint-disable-next-line @typescript-eslint/no-unused-vars + __: NextFunction, ): void { log.error("An exception occurred during http request: %s", err.message); // Send a ResponseErrorInternal only if a response was not already sent to the client diff --git a/src/utils/middleware/lollipop.ts b/src/utils/middleware/lollipop.ts index 75a8cca88..88313fc37 100644 --- a/src/utils/middleware/lollipop.ts +++ b/src/utils/middleware/lollipop.ts @@ -1,28 +1,29 @@ -import { Request, Response, NextFunction } from "express"; -import * as TE from "fp-ts/TaskEither"; -import { pipe } from "fp-ts/lib/function"; import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; +import { NextFunction, Request, Response } from "express"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; +import * as TE from "fp-ts/TaskEither"; +import { pipe } from "fp-ts/lib/function"; + +import { LollipopApiClient } from "../../clients/lollipop"; +import { ISessionStorage } from "../../services/ISessionStorage"; +import { withLollipopHeadersFromRequest } from "../../types/lollipop"; import { withOptionalUserFromRequest, withUserFromRequest, } from "../../types/user"; -import { LollipopApiClient } from "../../clients/lollipop"; -import { withLollipopHeadersFromRequest } from "../../types/lollipop"; import { log } from "../logger"; import { extractLollipopLocalsFromLollipopHeaders, extractLollipopLocalsFromLollipopHeadersLegacy, } from "../lollipop"; -import { ISessionStorage } from "../../services/ISessionStorage"; /** * @deprecated */ export const expressLollipopMiddlewareLegacy: ( lollipopClient: ReturnType, - sessionStorage: ISessionStorage + sessionStorage: ISessionStorage, ) => (req: Request, res: Response, next: NextFunction) => Promise = (lollipopClient, sessionStorage) => (req, res, next) => pipe( @@ -35,38 +36,36 @@ export const expressLollipopMiddlewareLegacy: ( lollipopClient, sessionStorage, user.fiscal_code, - lollipopHeaders + lollipopHeaders, ), TE.map((lollipopLocals) => { - // eslint-disable-next-line functional/immutable-data res.locals = { ...res.locals, ...lollipopLocals }; }), - TE.toUnion - )() - ) + TE.toUnion, + )(), + ), ), (err) => { log.error( "lollipopMiddleware|error executing the middleware [%s]", - E.toError(err).message + E.toError(err).message, ); return ResponseErrorInternal("Error executing middleware"); - } + }, ), TE.chain((maybeErrorResponse) => maybeErrorResponse === undefined ? TE.of(void 0) - : TE.left(maybeErrorResponse) + : TE.left(maybeErrorResponse), ), TE.mapLeft((response) => response.apply(res)), TE.map(() => next()), - TE.toUnion + TE.toUnion, )(); -/* eslint-disable sonarjs/no-identical-functions */ export const expressLollipopMiddleware: ( lollipopClient: ReturnType, - sessionStorage: ISessionStorage + sessionStorage: ISessionStorage, ) => (req: Request, res: Response, next: NextFunction) => Promise = (lollipopClient, sessionStorage) => (req, res, next) => pipe( @@ -79,31 +78,29 @@ export const expressLollipopMiddleware: ( lollipopClient, sessionStorage, lollipopHeaders, - O.toUndefined(user)?.fiscal_code + O.toUndefined(user)?.fiscal_code, ), TE.map((lollipopLocals) => { - // eslint-disable-next-line functional/immutable-data res.locals = { ...res.locals, ...lollipopLocals }; }), - TE.toUnion - )() - ) + TE.toUnion, + )(), + ), ), (err) => { log.error( "lollipopMiddleware|error executing the middleware [%s]", - E.toError(err).message + E.toError(err).message, ); return ResponseErrorInternal("Error executing middleware"); - } + }, ), TE.chain((maybeErrorResponse) => maybeErrorResponse === undefined ? TE.of(void 0) - : TE.left(maybeErrorResponse) + : TE.left(maybeErrorResponse), ), TE.mapLeft((response) => response.apply(res)), TE.map(() => next()), - TE.toUnion + TE.toUnion, )(); -/* eslint-enable sonarjs/no-identical-functions */ diff --git a/src/utils/network.ts b/src/utils/network.ts index 310a34158..a4b927ed7 100644 --- a/src/utils/network.ts +++ b/src/utils/network.ts @@ -1,21 +1,19 @@ -import { Either } from "fp-ts/lib/Either"; -import { array, Errors } from "io-ts"; import { CIDR, IPString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; +import { Either } from "fp-ts/lib/Either"; +import { Errors, array } from "io-ts"; /** * Parse a comma separated string of CIDR(s) or IP(s) into an array */ -export function decodeCIDRs( - cidrs?: string -): Either> { +export function decodeCIDRs(cidrs?: string): Either { return array(CIDR).decode( cidrs // may be a comma separated list of CIDR(s) or IP(s) ?.split(",") .map((c) => c.trim()) // if we read a plain IP then append '/32' - .map((c) => (c.indexOf("/") !== -1 ? c : c + "/32")) + .map((c) => (c.indexOf("/") !== -1 ? c : c + "/32")), ); } @@ -26,5 +24,5 @@ export function decodeCIDRs( * contained in the x-forwarded-for header */ export const decodeIPAddressFromReq = ( - req: express.Request + req: express.Request, ): Either => IPString.decode(req.ip); diff --git a/src/utils/ognl.ts b/src/utils/ognl.ts index 1ea0beb0c..08ff5476f 100644 --- a/src/utils/ognl.ts +++ b/src/utils/ognl.ts @@ -1,7 +1,7 @@ -import { pipe } from "fp-ts/function"; +import * as E from "fp-ts/Either"; import * as R from "fp-ts/Record"; +import { pipe } from "fp-ts/function"; import * as t from "io-ts"; -import * as E from "fp-ts/Either"; /** * Porting of lodash "set" function. @@ -14,31 +14,29 @@ import * as E from "fp-ts/Either"; // eslint-disable-next-line @typescript-eslint/ban-types export const set = ( obj: T, - path: string | ReadonlyArray, + path: readonly string[] | string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - value: any + value: any, ): T => { if (Object(obj) !== obj) { return obj; } // When obj is not an object // If not yet an array, get the keys from the string-path - const splittedpath: ReadonlyArray = !Array.isArray(path) + const splittedpath: readonly string[] = !Array.isArray(path) ? path.toString().match(/[^.[\]]+/g) || [] : path; - // eslint-disable-next-line functional/immutable-data + splittedpath.slice(0, -1).reduce( ( // eslint-disable-next-line @typescript-eslint/no-explicit-any a: any, c, - _i + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _i, ) => // Iterate all of them except the last one - Object(a[c]) === a[c] - ? a[c] - : // eslint-disable-next-line functional/immutable-data - (a[c] = {}), - obj + Object(a[c]) === a[c] ? a[c] : (a[c] = {}), + obj, )[splittedpath[splittedpath.length - 1]] = value; return obj; }; @@ -53,7 +51,7 @@ export const set = ( */ export const nestifyPrefixedType = ( env: Record, - prefix: string + prefix: string, ): Record => pipe( env, @@ -61,11 +59,11 @@ export const nestifyPrefixedType = ( R.reduceWithIndex({}, (k, b, a) => set( b, - // eslint-disable-next-line functional/immutable-data + k.split("_").splice(1).join("."), - a - ) - ) + a, + ), + ), ); const isRecordOfString = (i: unknown): i is Record => @@ -74,14 +72,13 @@ const isRecordOfString = (i: unknown): i is Record => !Object.keys(i).some((property) => typeof property !== "string"); const createNotRecordOfStringErrorL = - (input: unknown, context: t.Context) => (): t.Errors => - [ - { - context, - message: "input is not a valid record of string", - value: input, - }, - ]; + (input: unknown, context: t.Context) => (): t.Errors => [ + { + context, + message: "input is not a valid record of string", + value: input, + }, + ]; /** * Create a io-ts decoder for the input type. @@ -94,7 +91,7 @@ const createNotRecordOfStringErrorL = */ export const ognlTypeFor = ( type: t.Mixed, - prefix: string + prefix: string, ): t.Type => new t.Type( "OGNL", @@ -104,11 +101,11 @@ export const ognlTypeFor = ( input, E.fromPredicate( isRecordOfString, - createNotRecordOfStringErrorL(input, context) + createNotRecordOfStringErrorL(input, context), ), E.chainW((inputRecord) => - type.validate(nestifyPrefixedType(inputRecord, prefix), context) - ) + type.validate(nestifyPrefixedType(inputRecord, prefix), context), + ), ), - t.identity + t.identity, ); diff --git a/src/utils/package.ts b/src/utils/package.ts index 2208a9dbb..a9e7701ed 100644 --- a/src/utils/package.ts +++ b/src/utils/package.ts @@ -1,8 +1,9 @@ -import * as O from "fp-ts/lib/Option"; import * as E from "fp-ts/lib/Either"; -import * as t from "io-ts"; -import { pipe } from "fp-ts/lib/function"; +import * as O from "fp-ts/lib/Option"; import { Option } from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; + import * as packageJson from "../../package.json"; /** @@ -10,11 +11,11 @@ import * as packageJson from "../../package.json"; * If it doesn't exists, returns 'UNKNOWN' */ export const getValueFromPackageJson = ( - key: keyof typeof packageJson + key: keyof typeof packageJson, ): string => pipe( t.string.decode(packageJson[key]), - E.getOrElse(() => "UNKNOWN") + E.getOrElse(() => "UNKNOWN"), ); /** @@ -23,14 +24,14 @@ export const getValueFromPackageJson = ( */ export const getObjectFromPackageJson = ( key: keyof typeof packageJson, - type: t.Type + type: t.Type, ): Option => pipe( type.decode(packageJson[key]), E.fold( - (_) => O.none, - (_) => O.some(_) - ) + () => O.none, + (_) => O.some(_), + ), ); /** diff --git a/src/utils/profile.ts b/src/utils/profile.ts index 5f2ae48ff..b7f3594bf 100644 --- a/src/utils/profile.ts +++ b/src/utils/profile.ts @@ -1,12 +1,13 @@ -import * as TE from "fp-ts/lib/TaskEither"; -import * as E from "fp-ts/lib/Either"; -import * as t from "io-ts"; import { IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import * as E from "fp-ts/lib/Either"; +import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; -import { User } from "../../src/types/user"; -import ProfileService from "../../src/services/profileService"; -import { InitializedProfile } from "../../generated/backend/InitializedProfile"; +import * as t from "io-ts"; + import { EmailAddress } from "../../generated/backend/EmailAddress"; +import { InitializedProfile } from "../../generated/backend/InitializedProfile"; +import ProfileService from "../../src/services/profileService"; +import { User } from "../../src/types/user"; // define a type that represents a Profile with a non optional email address const ProfileWithEmail = t.intersection([ @@ -28,7 +29,7 @@ const ProfileWithEmailValidated = t.brand( ProfileWithEmail, (p): p is t.Branded => !!(p.email && p.is_email_validated), - "HasValidEmailAddress" + "HasValidEmailAddress", ); type ProfileWithEmailValidated = t.TypeOf; @@ -42,28 +43,26 @@ type ProfileWithEmailValidated = t.TypeOf; */ export const profileWithEmailValidatedOrError = ( profileService: ProfileService, - user: User + user: User, ) => pipe( TE.tryCatch( () => profileService.getProfile(user), - () => new Error("Error retrieving user profile") + () => new Error("Error retrieving user profile"), ), TE.chain( TE.fromPredicate( (r): r is IResponseSuccessJson => r.kind === "IResponseSuccessJson", - (e) => new Error(`Error retrieving user profile | ${e.detail}`) - ) + (e) => new Error(`Error retrieving user profile | ${e.detail}`), + ), ), TE.chainW((profile) => pipe( profile.value, ProfileWithEmailValidated.decode, - E.mapLeft( - (_) => new Error("Profile has not a validated email address") - ), - TE.fromEither - ) - ) + E.mapLeft(() => new Error("Profile has not a validated email address")), + TE.fromEither, + ), + ), ); diff --git a/src/utils/qrcode.ts b/src/utils/qrcode.ts index a331ee396..caede5ed6 100644 --- a/src/utils/qrcode.ts +++ b/src/utils/qrcode.ts @@ -1,8 +1,8 @@ import * as AP from "fp-ts/lib/Apply"; import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/lib/TaskEither"; import { TaskEither } from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { BonusActivation } from "generated/io-bonus-api/BonusActivation"; import { image } from "qr-image"; @@ -17,10 +17,9 @@ const fixQrcodeFill = (svgStr: string): string => svgStr.replace(" { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/prefer-readonly-type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const chunks: any[] = []; return new Promise((resolve, reject) => { - // eslint-disable-next-line functional/immutable-data stream.on("data", (chunk) => chunks.push(chunk)); stream.on("error", reject); stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); @@ -28,10 +27,9 @@ function streamToString(stream: NodeJS.ReadableStream): Promise { } function streamToBuffer(stream: NodeJS.ReadableStream): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/prefer-readonly-type + // eslint-disable-next-line @typescript-eslint/no-explicit-any const chunks: any[] = []; return new Promise((resolve, reject) => { - // eslint-disable-next-line functional/immutable-data stream.on("data", (chunk) => chunks.push(chunk)); stream.on("error", reject); stream.on("end", () => resolve(Buffer.concat(chunks))); @@ -39,17 +37,17 @@ function streamToBuffer(stream: NodeJS.ReadableStream): Promise { } const streamToBufferTask = ( - stream: NodeJS.ReadableStream + stream: NodeJS.ReadableStream, ): TaskEither => TE.tryCatch(() => streamToBuffer(stream), E.toError); const streamToStringTask = ( - stream: NodeJS.ReadableStream + stream: NodeJS.ReadableStream, ): TaskEither => TE.tryCatch(() => streamToString(stream), E.toError); export function withQrcode( - bonus: BonusActivation + bonus: BonusActivation, ): TaskEither { return pipe( AP.sequenceS(TE.ApplicativePar)({ @@ -68,6 +66,6 @@ export function withQrcode( mime_type: MIME_TYPES.svg, }, ], - })) + })), ); } diff --git a/src/utils/redis.ts b/src/utils/redis.ts index 6dc8cdddd..e216a51ad 100644 --- a/src/utils/redis.ts +++ b/src/utils/redis.ts @@ -1,8 +1,9 @@ -import * as redis from "redis"; import * as appInsights from "applicationinsights"; -import { pipe } from "fp-ts/lib/function"; -import * as RA from "fp-ts/lib/ReadonlyArray"; import * as O from "fp-ts/lib/Option"; +import * as RA from "fp-ts/lib/ReadonlyArray"; +import { pipe } from "fp-ts/lib/function"; +import * as redis from "redis"; + import { keyPrefixes } from "../services/redisSessionStorage"; import { log } from "./logger"; @@ -12,21 +13,21 @@ export const obfuscateTokensInfo = (message: string) => RA.findFirst((key) => message.includes(key)), O.map((key) => // eslint-disable-next-line no-useless-escape - message.replace(new RegExp(`\\"${key}\\w+\\"`), `"${key}redacted"`) + message.replace(new RegExp(`\\"${key}\\w+\\"`), `"${key}redacted"`), ), - O.getOrElse(() => message) + O.getOrElse(() => message), ); export const createClusterRedisClient = ( enableTls: boolean, appInsightsClient?: appInsights.TelemetryClient, - useReplicas: boolean = true + useReplicas = true, ) => async ( redisUrl: string, password?: string, - port?: string + port?: string, ): Promise => { const DEFAULT_REDIS_PORT = enableTls ? "6380" : "6379"; const prefixUrl = enableTls ? "rediss://" : "redis://"; @@ -45,7 +46,7 @@ export const createClusterRedisClient = password, socket: { // TODO: We can add a whitelist with all the IP addresses of the redis clsuter - checkServerIdentity: (_hostname, _cert) => undefined, + checkServerIdentity: () => undefined, keepAlive: 2000, tls: enableTls, }, @@ -74,16 +75,16 @@ export const createClusterRedisClient = redisClient.on( "reconnecting", ({ - delay, attempt, + delay, }: { - readonly delay: number; readonly attempt: number; + readonly delay: number; }) => { log.warn( "[REDIS reconnecting] a reconnection events occurs [delay %s] [attempt %s]", delay, - attempt + attempt, ); appInsightsClient?.trackEvent({ name: "io-backend.redis.reconnecting", @@ -93,7 +94,7 @@ export const createClusterRedisClient = }, tagOverrides: { samplingEnabled: "false" }, }); - } + }, ); await redisClient.connect(); return redisClient; @@ -101,7 +102,7 @@ export const createClusterRedisClient = // eslint-disable-next-line @typescript-eslint/consistent-type-definitions export type Selector = { - readonly select: (type: T) => ReadonlyArray; + readonly select: (type: T) => readonly S[]; readonly selectOne: (type: T) => S; }; @@ -112,8 +113,8 @@ export type RedisClientSelectorType = Selector< export enum RedisClientMode { "ALL" = "ALL", - "SAFE" = "SAFE", "FAST" = "FAST", + "SAFE" = "SAFE", } export const RedisClientSelector = @@ -121,16 +122,16 @@ export const RedisClientSelector = async ( redisUrl: string, password?: string, - port?: string + port?: string, ): Promise => { const FAST_REDIS_CLIENT = await createClusterRedisClient( enableTls, - appInsightsClient + appInsightsClient, )(redisUrl, password, port); const SAFE_REDIS_CLIENT = await createClusterRedisClient( enableTls, appInsightsClient, - false + false, )(redisUrl, password, port); const select = (t: RedisClientMode) => { switch (t) { diff --git a/src/utils/responses.ts b/src/utils/responses.ts index 2b6f9fd13..6e6df275b 100644 --- a/src/utils/responses.ts +++ b/src/utils/responses.ts @@ -1,14 +1,8 @@ -import * as express from "express"; -import { PaymentFaultEnum } from "generated/pagopa-proxy/PaymentFault"; -import { PaymentFaultV2Enum } from "generated/pagopa-proxy/PaymentFaultV2"; -import { PaymentProblemJson } from "generated/pagopa-proxy/PaymentProblemJson"; -import * as t from "io-ts"; -import * as E from "fp-ts/lib/Either"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IWithinRangeIntegerTag, WithinRangeInteger, } from "@pagopa/ts-commons/lib/numbers"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { HttpStatusCodeEnum, IResponse, @@ -19,8 +13,15 @@ import { ResponseErrorNotFound, ResponseErrorValidation, } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import * as TE from "fp-ts/TaskEither"; +import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; +import { PaymentFaultEnum } from "generated/pagopa-proxy/PaymentFault"; +import { PaymentFaultV2Enum } from "generated/pagopa-proxy/PaymentFaultV2"; +import { PaymentProblemJson } from "generated/pagopa-proxy/PaymentProblemJson"; +import * as t from "io-ts"; + import { errorsToError } from "./errorsFormatter"; /** @@ -46,7 +47,7 @@ export function ResponseNoContent(): IResponseNoContent { */ export const ResponseErrorDismissed = ResponseErrorNotFound( "Expired resource", - "The resource you asked for is no longer available" + "The resource you asked for is no longer available", ); /** @@ -54,8 +55,8 @@ export const ResponseErrorDismissed = ResponseErrorNotFound( */ export const withCatchAsInternalError = ( f: () => Promise, - message: string = "Exception while calling upstream API (likely a timeout)." -): Promise => + message = "Exception while calling upstream API (likely a timeout).", +): Promise => f().catch((_) => { // eslint-disable-next-line no-console console.error(_); @@ -63,7 +64,7 @@ export const withCatchAsInternalError = ( }); export const unhandledResponseStatus = ( - status: number + status: number, ): IResponseErrorInternal => ResponseErrorInternal(`unhandled API response status [${status}]`); @@ -73,11 +74,11 @@ export const unhandledResponseStatus = ( */ export const withValidatedOrInternalError = ( validated: t.Validation, - f: (p: T) => U -): U | IResponseErrorInternal => + f: (p: T) => U, +): IResponseErrorInternal | U => E.isLeft(validated) ? ResponseErrorInternal( - errorsToReadableMessages(validated.left).join(" / ") + errorsToReadableMessages(validated.left).join(" / "), ) : f(validated.right); @@ -87,12 +88,12 @@ export const withValidatedOrInternalError = ( */ export const withValidatedOrValidationError = ( response: t.Validation, - f: (p: T) => U -): U | IResponseErrorValidation => + f: (p: T) => U, +): IResponseErrorValidation | U => E.isLeft(response) ? ResponseErrorValidation( "Bad request", - errorsToReadableMessages(response.left).join(" / ") + errorsToReadableMessages(response.left).join(" / "), ) : f(response.right); @@ -108,7 +109,7 @@ export interface IResponseErrorUnauthorizedForLegalReasons */ export function ResponseErrorUnauthorizedForLegalReasons( title: string, - detail: string + detail: string, ): IResponseErrorUnauthorizedForLegalReasons { return { ...ResponseErrorGeneric(HttpStatusCodeEnum.HTTP_STATUS_451, title, detail), @@ -130,13 +131,13 @@ export interface IResponseErrorUnauthorized * Returns an unauthorized error response with status code 401. */ export function ResponseErrorUnauthorized( - detail: string + detail: string, ): IResponseErrorUnauthorized { return { ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_401, "Unauthorized", - detail + detail, ), ...{ detail: `Unauthorized: ${detail}`, @@ -168,7 +169,7 @@ export type IResponsePaymentInternalError = IResponse<"IResponseErrorInternal">; */ export const ResponsePaymentError = ( detail: PaymentFaultEnum, - detailV2: PaymentFaultV2Enum + detailV2: PaymentFaultV2Enum, ): IResponsePaymentInternalError => { const problem: PaymentProblemJson = { detail, @@ -200,7 +201,7 @@ export interface IResponseSuccessOctet * @param o The object to return to the client */ export const ResponseSuccessOctet = ( - o: Buffer + o: Buffer, ): IResponseSuccessOctet => ({ apply: (res) => res @@ -212,12 +213,12 @@ export const ResponseSuccessOctet = ( }); export const wrapValidationWithInternalError: ( - fa: t.Validation + fa: t.Validation, ) => TE.TaskEither = (fa) => pipe( TE.fromEither(fa), TE.mapLeft(errorsToError), - TE.mapLeft((e) => ResponseErrorInternal(e.message)) + TE.mapLeft((e) => ResponseErrorInternal(e.message)), ); /** @@ -231,12 +232,12 @@ export interface IResponseErrorNotImplemented * Returns a Not Implemented error response with status code 501. */ export const ResponseErrorNotImplemented = ( - detail: string + detail: string, ): IResponseErrorNotImplemented => ({ ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_501, "Not Implemented", - detail + detail, ), ...{ detail: `Not Implemented: ${detail}`, @@ -255,12 +256,12 @@ export interface IResponseErrorUnsupportedMediaType * Returns an `Unsupported Media Type` error response with status code 415. */ export const ResponseErrorUnsupportedMediaType = ( - detail: string + detail: string, ): IResponseErrorUnsupportedMediaType => ({ ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_415, "Unsupported Media Type", - detail + detail, ), ...{ detail, diff --git a/src/utils/separated-list.ts b/src/utils/separated-list.ts index d3f34e7d4..2cc1933c5 100644 --- a/src/utils/separated-list.ts +++ b/src/utils/separated-list.ts @@ -11,9 +11,9 @@ import * as t from "io-ts"; */ export const GetArbitrarySeparatedListOf = (separator: string) => (decoder: t.Mixed) => - new t.Type>, string, unknown>( + new t.Type[], string, unknown>( `ArbitrarySeparatedListOf<${decoder.name}>`, - (value: unknown): value is ReadonlyArray> => + (value: unknown): value is readonly t.TypeOf[] => Array.isArray(value) && value.every((e) => decoder.is(e)), (input) => t.readonlyArray(decoder).decode( @@ -23,10 +23,10 @@ export const GetArbitrarySeparatedListOf = .map((e) => e.trim()) .filter(Boolean) : !input - ? [] // fallback to empty array in case of empty input - : input // it should not happen, but in case we let the decoder fail + ? [] // fallback to empty array in case of empty input + : input, // it should not happen, but in case we let the decoder fail ), - String + String, ); export const CommaSeparatedListOf = GetArbitrarySeparatedListOf(","); diff --git a/src/utils/strategies.ts b/src/utils/strategies.ts index d4f52efd4..5cd5b63bc 100644 --- a/src/utils/strategies.ts +++ b/src/utils/strategies.ts @@ -1,9 +1,10 @@ +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; -import { IVerifyOptions } from "passport-http-bearer"; -import * as E from "fp-ts/Either"; import { pipe } from "fp-ts/lib/function"; -import * as O from "fp-ts/Option"; +import { IVerifyOptions } from "passport-http-bearer"; + import { User } from "../types/user"; export type StrategyDoneFunction = ( @@ -11,7 +12,7 @@ export type StrategyDoneFunction = ( error: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any user?: any, - options?: IVerifyOptions | string + options?: IVerifyOptions | string, ) => void; /** @@ -21,7 +22,7 @@ export type StrategyDoneFunction = ( */ export function fulfill( errorOrUser: Either>, - done: StrategyDoneFunction + done: StrategyDoneFunction, ): void { pipe( errorOrUser, @@ -29,7 +30,7 @@ export function fulfill( (error) => done(error), // passport-http-custom-bearer uses the last options parameter // we need to pass it as an empty string or we get an error - (user) => done(undefined, O.isNone(user) ? false : user.value, "") - ) + (user) => done(undefined, O.isNone(user) ? false : user.value, ""), + ), ); } diff --git a/src/utils/thirdPartyConfig.ts b/src/utils/thirdPartyConfig.ts index 9a606dfdc..1d12ae9f7 100644 --- a/src/utils/thirdPartyConfig.ts +++ b/src/utils/thirdPartyConfig.ts @@ -1,9 +1,7 @@ /* eslint-disable sort-keys */ -import * as t from "io-ts"; - import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; - +import * as t from "io-ts"; import { BooleanFromString, JsonFromString, withFallback } from "io-ts-types"; export const ClientCert = t.interface({ @@ -14,9 +12,9 @@ export const ClientCert = t.interface({ export type ApiKeyAuthenticationConfig = t.TypeOf; export const ApiKeyAuthenticationConfig = t.interface({ - type: t.literal("API_KEY"), - key: NonEmptyString, header_key_name: NonEmptyString, + key: NonEmptyString, + type: t.literal("API_KEY"), }); export type AuthenticationConfig = t.TypeOf; @@ -43,11 +41,11 @@ export const TestEnvironmentConfig = t.intersection([ export type ThirdPartyConfigBase = t.TypeOf; export const ThirdPartyConfigBase = t.interface({ - serviceId: NonEmptyString, - schemaKind: NonEmptyString, - jsonSchema: NonEmptyString, - isLollipopEnabled: BooleanFromString, disableLollipopFor: t.readonlyArray(FiscalCode), + isLollipopEnabled: BooleanFromString, + jsonSchema: NonEmptyString, + schemaKind: NonEmptyString, + serviceId: NonEmptyString, }); /** @@ -78,6 +76,6 @@ export type ThirdPartyConfigListFromString = t.TypeOf< >; export const ThirdPartyConfigListFromString = withFallback( JsonFromString, - [] + [], ).pipe(ThirdPartyConfigList); // ^^^ take [] as fallback if JSON.parse fails, but do not override ThirdPartyConfigList validation diff --git a/src/utils/url.ts b/src/utils/url.ts index e662279c2..0f94b3264 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,12 +1,12 @@ import { ValidUrl } from "@pagopa/ts-commons/lib/url"; -import { identity, pipe } from "fp-ts/lib/function"; import * as E from "fp-ts/lib/Either"; +import { identity, pipe } from "fp-ts/lib/function"; import * as S from "fp-ts/lib/string"; export const stripTrailingSlashIfPresent = (aValidUrl: ValidUrl): string => pipe( aValidUrl.href, - E.fromPredicate(S.endsWith("/"), (_) => aValidUrl.href), + E.fromPredicate(S.endsWith("/"), () => aValidUrl.href), E.map(S.slice(0, aValidUrl.href.length - 1)), - E.fold(identity, identity) + E.fold(identity, identity), ); From 85274dc7b5ed54db8ede90b797b174e18309c1be Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Fri, 31 Jan 2025 15:50:14 +0100 Subject: [PATCH 06/13] Reversed @types/express-serve-static-core version --- package.json | 2 +- src/controllers/bonusController.ts | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 3d5658edf..10f4c974a 100644 --- a/package.json +++ b/package.json @@ -204,6 +204,6 @@ "handlebars": "~4.5.3", "applicationinsights": "~2.9.5", "@types/serve-static": "1.13.10", - "@types/express-serve-static-core": "~5.0.0" + "@types/express-serve-static-core": "4.17.34" } } diff --git a/src/controllers/bonusController.ts b/src/controllers/bonusController.ts index 8e6069996..64bc07d7b 100644 --- a/src/controllers/bonusController.ts +++ b/src/controllers/bonusController.ts @@ -27,7 +27,7 @@ export const withBonusIdFromRequest = async ( f: (bonusId: NonEmptyString) => Promise, ): Promise => withValidatedOrValidationError( - NonEmptyString.decode(req.params["bonus_id"]), + NonEmptyString.decode(req.param("bonus_id")), f, ); diff --git a/yarn.lock b/yarn.lock index 1a24c4876..d2502fc58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1178,10 +1178,10 @@ dependencies: "@types/express" "*" -"@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^5.0.0", "@types/express-serve-static-core@~5.0.0": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz#41fec4ea20e9c7b22f024ab88a95c6bb288f51b8" - integrity sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA== +"@types/express-serve-static-core@4.17.34", "@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^5.0.0": + version "4.17.34" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz#c119e85b75215178bc127de588e93100698ab4cc" + integrity sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w== dependencies: "@types/node" "*" "@types/qs" "*" From f01186f9790c5233411053c21f40e29f1f75fd4e Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Fri, 31 Jan 2025 15:51:34 +0100 Subject: [PATCH 07/13] Remove unused vars Remove undefined eslint rules --- src/adapters/pnFetch.ts | 7 +-- src/app.ts | 8 +-- src/config.ts | 4 +- src/controllers/authenticationController.ts | 4 +- .../cgnOperatorSearchController.ts | 12 ++--- src/controllers/ioSignController.ts | 2 +- src/controllers/messagesController.ts | 8 +-- src/controllers/notificationController.ts | 52 +++++++++---------- .../serviceAppBackendController.ts | 2 + src/controllers/sessionLockController.ts | 16 +++--- src/services/authenticationLockService.ts | 4 +- src/services/bonusService.ts | 1 + src/services/ioWalletService.ts | 1 - src/services/newMessagesService.ts | 1 + 14 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/adapters/pnFetch.ts b/src/adapters/pnFetch.ts index ac7d92d4d..81b10ea9f 100644 --- a/src/adapters/pnFetch.ts +++ b/src/adapters/pnFetch.ts @@ -196,7 +196,7 @@ export const redirectPrecondition = ThirdPartyPreconditionUrl.decode, E.mapLeft(errorsToError), TE.fromEither, - eventLog.taskEither.info((_) => [ + eventLog.taskEither.info(() => [ `pn.precondition.call`, { locals: lollipopLocals @@ -253,7 +253,7 @@ export const redirectMessages = ThirdPartyMessagesUrl.decode, E.mapLeft(errorsToError), TE.fromEither, - eventLog.taskEither.info((_) => [ + eventLog.taskEither.info(() => [ `pn.notification.call`, { locals: lollipopLocals @@ -397,6 +397,7 @@ export const redirectAttachment = ThirdPartyAttachmentUrl.decode, E.mapLeft(errorsToError), TE.fromEither, + // eslint-disable-next-line @typescript-eslint/no-unused-vars TE.chain(([_id, getAttachmentUrl]) => match(getAttachmentUrl) .when( @@ -459,7 +460,7 @@ export const redirectAttachment = ), ), ), - E.getOrElse((_) => + E.getOrElse(() => pipe( attachment.retryAfter, t.number.decode, diff --git a/src/app.ts b/src/app.ts index d9a38af9a..2233f8dde 100644 --- a/src/app.ts +++ b/src/app.ts @@ -167,7 +167,6 @@ export interface IAppFactoryParameters { readonly env: NodeEnvironment; } -// eslint-disable-next-line max-lines-per-function, sonarjs/cognitive-complexity export async function newApp({ APIBasePath, BonusAPIBasePath, @@ -253,7 +252,7 @@ export async function newApp({ // Adds the user fiscal code // we take only the first 6 characters of the fiscal code - morgan.token("fiscal_code_short", (req: express.Request, _) => + morgan.token("fiscal_code_short", (req: express.Request) => pipe( req.user, User.decode, @@ -266,7 +265,7 @@ export async function newApp({ originalUrl.replace(/([?&]token=|[?&]access_token=)([^&]*)/g, "$1REDACTED"); // Obfuscate token in url on morgan logs - morgan.token("obfuscated_url", (req: express.Request, _) => + morgan.token("obfuscated_url", (req: express.Request) => obfuscateToken(req.originalUrl), ); @@ -282,6 +281,7 @@ export async function newApp({ // Parse the incoming request body. This is needed by Passport spid strategy. app.use( bodyParser.json({ + // eslint-disable-next-line @typescript-eslint/no-unused-vars verify: (_req, res: express.Response, buf, _encoding: BufferEncoding) => { res.locals.body = buf; }, @@ -920,7 +920,7 @@ function registerAPIRoutes( `${basePath}/services`, bearerSessionTokenAuth, toExpressHandler( - (_) => Promise.resolve(ResponseSuccessJson({ items: [] })), + () => Promise.resolve(ResponseSuccessJson({ items: [] })), servicesController, ), ); diff --git a/src/config.ts b/src/config.ts index c03dead32..773de69f2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -521,7 +521,7 @@ export const PN_CONFIGURATION_ID = pipe( export const FF_ROUTING_PUSH_NOTIF = pipe( process.env.FF_ROUTING_PUSH_NOTIF, FeatureFlag.decode, - E.getOrElse((_) => FeatureFlagEnum.NONE), + E.getOrElse(() => FeatureFlagEnum.NONE), ); export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( @@ -539,7 +539,7 @@ export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( export const FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX = pipe( process.env.FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, NonEmptyString.decode, - E.getOrElse((_) => "XYZ" as NonEmptyString), + E.getOrElse(() => "XYZ" as NonEmptyString), ); // UNIQUE EMAIL ENFORCEMENT variables diff --git a/src/controllers/authenticationController.ts b/src/controllers/authenticationController.ts index 003bfd23c..7395b633f 100644 --- a/src/controllers/authenticationController.ts +++ b/src/controllers/authenticationController.ts @@ -32,14 +32,14 @@ export const getUserIdentity: ( pipe( user, UserIdentity.decode, - E.mapLeft((_) => + E.mapLeft(() => ResponseErrorInternal("Unexpected User Identity data format."), ), E.map((_) => pipe( _, exactUserIdentityDecode, - E.mapLeft((_1) => ResponseErrorInternal("Exact decode failed.")), + E.mapLeft(() => ResponseErrorInternal("Exact decode failed.")), E.map(ResponseSuccessJson), E.toUnion, ), diff --git a/src/controllers/cgnOperatorSearchController.ts b/src/controllers/cgnOperatorSearchController.ts index de2d5e880..1e4001d32 100644 --- a/src/controllers/cgnOperatorSearchController.ts +++ b/src/controllers/cgnOperatorSearchController.ts @@ -76,9 +76,7 @@ export default class CgnOperatorSearchController { | IResponseErrorValidation | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => - this.cgnOperatorSearchService.count(), - ); + withUserFromRequest(req, async () => this.cgnOperatorSearchService.count()); /** * Get a discount bucket code by discount identifier. @@ -141,7 +139,7 @@ export default class CgnOperatorSearchController { | IResponseErrorValidation | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( OfflineMerchantSearchRequest.decode(req.body), (offlineSearchRequest) => @@ -163,7 +161,7 @@ export default class CgnOperatorSearchController { | IResponseErrorValidation | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( OnlineMerchantSearchRequest.decode(req.body), (onlineSearchRequest) => @@ -182,7 +180,7 @@ export default class CgnOperatorSearchController { | IResponseErrorValidation | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( GetPublishedCategoriesParameters.decode(req.query), (params) => @@ -201,7 +199,7 @@ export default class CgnOperatorSearchController { | IResponseErrorValidation | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( SearchRequest.decode(req.body), (searchRequest) => this.cgnOperatorSearchService.search(searchRequest), diff --git a/src/controllers/ioSignController.ts b/src/controllers/ioSignController.ts index 0389b9527..5ee800466 100644 --- a/src/controllers/ioSignController.ts +++ b/src/controllers/ioSignController.ts @@ -265,7 +265,7 @@ export default class IoSignController { req.params.id, Id.decode, TE.fromEither, - TE.mapLeft((_) => + TE.mapLeft(() => ResponseErrorInternal( `Error validating the signature request id`, ), diff --git a/src/controllers/messagesController.ts b/src/controllers/messagesController.ts index 8fa55a485..af07c7850 100644 --- a/src/controllers/messagesController.ts +++ b/src/controllers/messagesController.ts @@ -115,7 +115,7 @@ export default class MessagesController { user.fiscal_code, lollipopHeaders, ), - TE.mapLeft((_) => + TE.mapLeft(() => ResponseErrorInternal( "Error extracting lollipop locals", ), @@ -203,7 +203,7 @@ export default class MessagesController { remoteContentConfiguration, lollipopLocals as LollipopLocalsType, ), - (_) => + () => ResponseErrorInternal( "Error getting message from third party service", ), @@ -243,7 +243,7 @@ export default class MessagesController { remoteContentConfiguration, lollipopLocals as LollipopLocalsType, ), - (_) => + () => ResponseErrorInternal( "Error getting attachment from third party service", ), @@ -280,7 +280,7 @@ export default class MessagesController { remoteContentConfiguration, lollipopLocals as LollipopLocalsType, ), - (_) => + () => ResponseErrorInternal( "Error getting preconditions from third party service", ), diff --git a/src/controllers/notificationController.ts b/src/controllers/notificationController.ts index d48a7a51e..028f2159a 100644 --- a/src/controllers/notificationController.ts +++ b/src/controllers/notificationController.ts @@ -90,33 +90,31 @@ export default class NotificationController { req: express.Request, ): Promise> { return withUserFromRequest(req, async (user) => - withValidatedOrValidationError( - InstallationID.decode(req.params.id), - (_) => - withValidatedOrValidationError( - Installation.decode(req.body), - (installation) => { - // async fire & forget - // On login, we do a deleteInstallation to prevent a device to be associated with a previous user, which might be a different one - // We have empirical evidence that such deleteInstallation is processed after the createOrUpdateInstallation, - // so that the installation we are recording after login is lost - // The correct order of execution must be enforced by the processing notifications service. - // Anyway, to quickly mitigate the disservice to our users, we apply this temporary workaround - delay(10000 as Millisecond) - .then(() => - this.notificationServiceFactory( - user.fiscal_code, - ).createOrUpdateInstallation(user.fiscal_code, installation), - ) - .catch((err) => { - log.error( - "Cannot create installation: %s", - JSON.stringify(err), - ); - }); - return ResponseSuccessJson({ message: "ok" }); - }, - ), + withValidatedOrValidationError(InstallationID.decode(req.params.id), () => + withValidatedOrValidationError( + Installation.decode(req.body), + (installation) => { + // async fire & forget + // On login, we do a deleteInstallation to prevent a device to be associated with a previous user, which might be a different one + // We have empirical evidence that such deleteInstallation is processed after the createOrUpdateInstallation, + // so that the installation we are recording after login is lost + // The correct order of execution must be enforced by the processing notifications service. + // Anyway, to quickly mitigate the disservice to our users, we apply this temporary workaround + delay(10000 as Millisecond) + .then(() => + this.notificationServiceFactory( + user.fiscal_code, + ).createOrUpdateInstallation(user.fiscal_code, installation), + ) + .catch((err) => { + log.error( + "Cannot create installation: %s", + JSON.stringify(err), + ); + }); + return ResponseSuccessJson({ message: "ok" }); + }, + ), ), ); } diff --git a/src/controllers/serviceAppBackendController.ts b/src/controllers/serviceAppBackendController.ts index 816ea766c..572bf5216 100644 --- a/src/controllers/serviceAppBackendController.ts +++ b/src/controllers/serviceAppBackendController.ts @@ -72,11 +72,13 @@ export default class ServicesAppBackendController { ); public readonly getFeaturedInstitutions = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _req: express.Request, ): Promise> => this.servicesAppBackendService.getFeaturedInstitutions(); public readonly getFeaturedServices = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _req: express.Request, ): Promise> => this.servicesAppBackendService.getFeaturedServices(); diff --git a/src/controllers/sessionLockController.ts b/src/controllers/sessionLockController.ts index 0a1ca3e1f..89c7061d0 100644 --- a/src/controllers/sessionLockController.ts +++ b/src/controllers/sessionLockController.ts @@ -201,7 +201,7 @@ export default class SessionLockController { this.buildInvalidateUserSessionTask(fiscalCode), ), TE.mapLeft((err) => ResponseErrorInternal(err.message)), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.map(() => ResponseSuccessJson({ message: "ok" })), TE.toUnion, )(), ); @@ -314,7 +314,7 @@ export default class SessionLockController { pipe( // lock the authentication this.authenticationLockService.isUserAuthenticationLocked(fiscalCode), - TE.mapLeft((_) => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK)), + TE.mapLeft(() => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK)), TE.filterOrElseW( (isUserAuthenticationLocked) => !isUserAuthenticationLocked, () => @@ -322,7 +322,7 @@ export default class SessionLockController { "Another user authentication lock has already been applied", ), ), - TE.chainW((_) => + TE.chainW(() => pipe( AP.sequenceT(TE.ApplicativeSeq)( // clear session data @@ -339,7 +339,7 @@ export default class SessionLockController { TE.mapLeft((err) => ResponseErrorInternal(err.message)), ), ), - TE.map((_) => ResponseNoContent()), + TE.map(() => ResponseNoContent()), TE.toUnion, )(), ), @@ -378,7 +378,7 @@ export default class SessionLockController { ), ), TE.mapLeft((err) => ResponseErrorInternal(err.message)), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.map(() => ResponseSuccessJson({ message: "ok" })), TE.toUnion, )(), ); @@ -414,7 +414,7 @@ export default class SessionLockController { this.authenticationLockService.getUserAuthenticationLockData( fiscalCode, ), - TE.mapLeft((_) => + TE.mapLeft(() => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK), ), ), @@ -430,7 +430,7 @@ export default class SessionLockController { : // User auth is NOT locked TE.of(true), ), - TE.map((_) => ResponseNoContent()), + TE.map(() => ResponseNoContent()), TE.toUnion, )(), ), @@ -468,7 +468,7 @@ export default class SessionLockController { TE.mapLeft((err) => ResponseErrorInternal(err.message)), ), ), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.map(() => ResponseSuccessJson({ message: "ok" })), TE.toUnion, )(); diff --git a/src/services/authenticationLockService.ts b/src/services/authenticationLockService.ts index 78631735a..f0534582c 100644 --- a/src/services/authenticationLockService.ts +++ b/src/services/authenticationLockService.ts @@ -88,9 +88,9 @@ export default class AuthenticationLockService { rowKey: unlockCode, }), - (_) => new Error("Something went wrong creating the record"), + () => new Error("Something went wrong creating the record"), ), - TE.map((_) => true as const), + TE.map(() => true as const), ); /** diff --git a/src/services/bonusService.ts b/src/services/bonusService.ts index 7e5f647b2..bd818a1e5 100644 --- a/src/services/bonusService.ts +++ b/src/services/bonusService.ts @@ -40,6 +40,7 @@ export default class BonusService { * */ public readonly getAllBonusActivations = ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _: User, ): Promise< | IResponseErrorInternal diff --git a/src/services/ioWalletService.ts b/src/services/ioWalletService.ts index fbf021cc0..ea763d0dc 100644 --- a/src/services/ioWalletService.ts +++ b/src/services/ioWalletService.ts @@ -1,4 +1,3 @@ -/* eslint-disable sonarjs/no-identical-functions */ /** * This service interacts with the IO Wallet API */ diff --git a/src/services/newMessagesService.ts b/src/services/newMessagesService.ts index 60875c9c8..104ec8b2c 100644 --- a/src/services/newMessagesService.ts +++ b/src/services/newMessagesService.ts @@ -167,6 +167,7 @@ export default class NewMessagesService { case 500: return ResponseErrorInternal(ERROR_MESSAGE_500); case 503: + // eslint-disable-next-line no-case-declarations const retryAfter = response.headers["Retry-After"] ?? "10"; return ResponseErrorServiceTemporarilyUnavailable( ERROR_MESSAGE_503, From 95bae90b8677caca99e157ac359d99b8f2b1d582 Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Fri, 31 Jan 2025 16:02:18 +0100 Subject: [PATCH 08/13] Fix lint for no-explicit-any --- src/@types/bwip-js/index.d.ts | 3 +++ src/@types/passport-auth-token/index.d.ts | 1 + src/@types/passport-http-custom-bearer/index.d.ts | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/@types/bwip-js/index.d.ts b/src/@types/bwip-js/index.d.ts index 321280aa1..a1b330043 100644 --- a/src/@types/bwip-js/index.d.ts +++ b/src/@types/bwip-js/index.d.ts @@ -1,6 +1,8 @@ declare module "bwip-js" { export interface IFontLib { + // eslint-disable-next-line @typescript-eslint/no-explicit-any getpaths: (arg0: any, arg1: any, arg2: number, arg3: number) => any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any lookup: (arg0: any) => any; } @@ -8,6 +10,7 @@ declare module "bwip-js" { export function fixupOptions(opts: ToBufferOptions): void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any export function render(opts: ToBufferOptions, drawing: any): string; export function toBuffer( diff --git a/src/@types/passport-auth-token/index.d.ts b/src/@types/passport-auth-token/index.d.ts index 752c260be..4105e20e8 100644 --- a/src/@types/passport-auth-token/index.d.ts +++ b/src/@types/passport-auth-token/index.d.ts @@ -14,6 +14,7 @@ interface IVerifyOptions { type VerifyFunction = ( token: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any done: (error: any, user?: any, options?: IVerifyOptions) => void, ) => void; diff --git a/src/@types/passport-http-custom-bearer/index.d.ts b/src/@types/passport-http-custom-bearer/index.d.ts index 2b3be667f..f69bc444a 100644 --- a/src/@types/passport-http-custom-bearer/index.d.ts +++ b/src/@types/passport-http-custom-bearer/index.d.ts @@ -22,6 +22,7 @@ declare module "passport-http-custom-bearer" { type VerifyFunction = ( token: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any done: (error: any, user?: any, options?: IVerifyOptions | string) => void, ) => void; @@ -34,11 +35,13 @@ declare module "passport-http-custom-bearer" { type VerifyFunctionWithRequest = ( req: express.Request, token: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any done: (error: any, user?: any, options?: IVerifyOptions | string) => void, ) => void; type VerifyFunctionWithContext = ( req: KoaPassportExpressRequestMock, token: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any done: (error: any, user?: any, options?: IVerifyOptions | string) => void, ) => void; From 3a1f321a470e7b3ed04dd411a5661db42c877a2d Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Mon, 3 Feb 2025 16:05:25 +0100 Subject: [PATCH 09/13] Revert "fix some eslint errors" This reverts commits 090cbc0f3633c23bce94507c705ddb14d3305002, f01186f9790c5233411053c21f40e29f1f75fd4e and 95bae90b8677caca99e157ac359d99b8f2b1d582. --- eslint.config.mjs | 39 +- src/@types/bwip-js/index.d.ts | 115 +- src/@types/passport-auth-token/index.d.ts | 12 +- .../passport-http-custom-bearer/index.d.ts | 60 +- src/__tests__/lollipop-consumer.test.ts | 4 +- src/adapters/pnFetch.ts | 212 ++-- src/app.ts | 526 ++++---- src/clients/api.ts | 4 +- src/clients/app-messages.client.ts | 3 +- src/clients/bonus.ts | 3 +- src/clients/cgn-operator-search.ts | 3 +- src/clients/cgn.ts | 4 +- src/clients/eucovidcert.client.ts | 4 +- src/clients/firstLollipopConsumer.ts | 5 +- src/clients/io-fims.ts | 3 +- src/clients/io-sign.ts | 3 +- src/clients/io-wallet.ts | 4 +- src/clients/lollipop.ts | 3 +- src/clients/pagopa.ts | 3 +- src/clients/pn-clients.ts | 17 +- src/clients/services-app-backend.ts | 3 +- src/clients/third-party-service-client.ts | 37 +- src/clients/trial-system.client.ts | 3 +- src/config.ts | 213 ++-- src/controllers/authenticationController.ts | 25 +- src/controllers/bonusController.ts | 62 +- src/controllers/cgnController.ts | 152 +-- .../cgnOperatorSearchController.ts | 219 ++-- src/controllers/eucovidcertController.ts | 30 +- src/controllers/fimsController.ts | 73 +- .../firstLollipopConsumerController.ts | 49 +- src/controllers/ioSignController.ts | 198 +-- src/controllers/ioWalletController.ts | 292 ++--- src/controllers/messagesController.ts | 357 +++--- src/controllers/notificationController.ts | 96 +- src/controllers/pagoPAProxyController.ts | 56 +- src/controllers/pnController.ts | 53 +- src/controllers/profileController.ts | 77 +- .../serviceAppBackendController.ts | 71 +- src/controllers/servicesController.ts | 39 +- src/controllers/sessionController.ts | 9 +- src/controllers/sessionLockController.ts | 603 ++++----- src/controllers/ssoController.ts | 11 +- src/controllers/trialController.ts | 41 +- .../userDataProcessingController.ts | 68 +- src/controllers/userMetadataController.ts | 23 +- src/server.ts | 43 +- src/services/IPagoPAClientFactory.ts | 2 +- src/services/ISessionStorage.ts | 61 +- src/services/IUserMetadataStorage.ts | 13 +- src/services/apiClientFactory.ts | 2 +- src/services/authenticationLockService.ts | 108 +- src/services/bonusService.ts | 61 +- src/services/cgnOperatorSearchService.ts | 172 +-- src/services/cgnService.ts | 228 ++-- src/services/eucovidcertService.ts | 33 +- src/services/fimsService.ts | 21 +- src/services/functionAppService.ts | 49 +- src/services/ioSignService.ts | 200 +-- src/services/ioWalletService.ts | 295 ++--- src/services/lollipopService.ts | 7 +- src/services/newMessagesService.ts | 999 +++++++-------- src/services/notificationService.ts | 99 +- src/services/notificationServiceFactory.ts | 19 +- src/services/pagoPAClientFactory.ts | 6 +- src/services/pagoPAProxyService.ts | 135 +- src/services/pnService.ts | 6 +- src/services/profileService.ts | 212 ++-- src/services/redisSessionStorage.ts | 1085 ++++++++--------- src/services/redisStorageUtils.ts | 80 +- src/services/redisUserMetadataStorage.ts | 141 ++- src/services/servicesAppBackendService.ts | 91 +- src/services/trialService.ts | 57 +- src/services/userDataProcessingService.ts | 102 +- src/strategies/bearerMyPortalTokenStrategy.ts | 9 +- src/strategies/bearerSessionTokenStrategy.ts | 9 +- src/types/IDPEntityDescriptor.ts | 2 +- src/types/assertionRef.ts | 9 +- src/types/booleans.ts | 6 +- src/types/commons.ts | 11 +- src/types/fiscalCode.ts | 5 +- src/types/lollipop.ts | 62 +- src/types/notification.ts | 2 +- src/types/pathParams.ts | 46 +- src/types/profile.ts | 14 +- src/types/token.ts | 6 +- src/types/user.ts | 23 +- src/utils/AsyncIterableTask.ts | 46 +- src/utils/appinsights.ts | 63 +- src/utils/attachments.ts | 13 +- src/utils/barcode.ts | 18 +- src/utils/container.ts | 1 - src/utils/date.ts | 12 +- src/utils/errorsFormatter.ts | 8 +- src/utils/express.ts | 34 +- src/utils/fastLogin.ts | 4 +- src/utils/featureFlag.ts | 4 +- src/utils/file-type.ts | 11 +- src/utils/gracefulShutdown.ts | 7 +- src/utils/logger.ts | 4 +- src/utils/lollipop.ts | 212 ++-- src/utils/middleware/checkIP.ts | 19 +- src/utils/middleware/dueDate.ts | 9 +- src/utils/middleware/express.ts | 6 +- src/utils/middleware/lollipop.ts | 53 +- src/utils/network.ts | 12 +- src/utils/ognl.ts | 57 +- src/utils/package.ts | 19 +- src/utils/profile.ts | 33 +- src/utils/qrcode.ts | 16 +- src/utils/redis.ts | 35 +- src/utils/responses.ts | 57 +- src/utils/separated-list.ts | 10 +- src/utils/strategies.ts | 15 +- src/utils/thirdPartyConfig.ts | 18 +- src/utils/url.ts | 6 +- 116 files changed, 4608 insertions(+), 4612 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index f0e5a1276..850ea20e0 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,24 +1,23 @@ import pagopa from "@pagopa/eslint-config"; export default [ - ...pagopa, - { - rules: { - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/naming-convention": "off", - "no-invalid-this": "off", - "prefer-arrow/prefer-arrow-functions": "off", + ...pagopa, + { + rules: { + "prefer-arrow/prefer-arrow-functions": "off", + "@typescript-eslint/naming-convention": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "no-invalid-this": "off", + } }, - }, - { - ignores: [ - "node_modules", - "generated", - "dist", - "**/__tests__/*", - "**/__mocks__/*", - "Dangerfile.*", - "*.d.ts", - ], - }, -]; + { + ignores: [ + "node_modules", + "generated", + "**/__tests__/*", + "**/__mocks__/*", + "Dangerfile.*", + "*.d.ts" + ], + }, +]; \ No newline at end of file diff --git a/src/@types/bwip-js/index.d.ts b/src/@types/bwip-js/index.d.ts index a1b330043..276001e6b 100644 --- a/src/@types/bwip-js/index.d.ts +++ b/src/@types/bwip-js/index.d.ts @@ -1,97 +1,94 @@ declare module "bwip-js" { export interface IFontLib { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - getpaths: (arg0: any, arg1: any, arg2: number, arg3: number) => any; - // eslint-disable-next-line @typescript-eslint/no-explicit-any lookup: (arg0: any) => any; + getpaths: (arg0: any, arg1: any, arg2: number, arg3: number) => any; } export const FontLib: IFontLib; export function fixupOptions(opts: ToBufferOptions): void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any export function render(opts: ToBufferOptions, drawing: any): string; export function toBuffer( opts: ToBufferOptions, - callback: (err: Error | string, png: Buffer) => void, + callback: (err: string | Error, png: Buffer) => void ): void; interface ToBufferOptions { - addontextfont?: string; - addontextsize?: number; - - addontextxoffset?: number; - addontextyoffset?: number; - - alttext?: boolean; - backgroundcolor?: string; - - barcolor?: string; bcid: string; - boraderbottom?: number; - - bordercolor?: string; - - borderleft?: number; - borderright?: number; - bordertop?: number; - borderwidth?: number; - guardheight?: number; - guardleftpos?: number; + text: string; - guardleftypos?: number; - guardrightpos?: number; + parse?: boolean; + parsefunc?: boolean; - guardrightypos?: number; - guardwhitespace?: boolean; - guardwidth?: number; height?: number; + width?: number; - includecheck?: boolean; - includecheckintext?: boolean; - includetext?: boolean; - inkspread?: number; + scaleX?: number; + scaleY?: number; + scale?: number; - inkspreadh?: number; - inkspreadv?: number; - monochrome?: boolean; - paddingbottom?: number; + rotate?: "N" | "R" | "L" | "I"; + + paddingwidth?: number; paddingheight?: number; paddingleft?: number; - paddingright?: number; paddingtop?: number; - paddingwidth?: number; - parse?: boolean; + paddingbottom?: number; - parsefunc?: boolean; - rotate?: "I" | "L" | "N" | "R"; - scale?: number; - scaleX?: number; + monochrome?: boolean; + alttext?: boolean; - scaleY?: number; - showborder?: boolean; - sizelimit?: number; - text: string; - textcolor?: string; + includetext?: boolean; textfont?: string; - textgaps?: number; - textsize?: number; + textgaps?: number; textxalign?: - | "center" - | "justify" - | "left" | "offleft" + | "left" + | "center" + | "right" | "offright" - | "right"; + | "justify"; + textyalign?: "below" | "center" | "above"; textxoffset?: number; - - textyalign?: "above" | "below" | "center"; textyoffset?: number; - width?: number; + + showborder?: boolean; + borderwidth?: number; + borderleft?: number; + borderright?: number; + bordertop?: number; + boraderbottom?: number; + + barcolor?: string; + backgroundcolor?: string; + bordercolor?: string; + textcolor?: string; + + addontextxoffset?: number; + addontextyoffset?: number; + addontextfont?: string; + addontextsize?: number; + + guardwhitespace?: boolean; + guardwidth?: number; + guardheight?: number; + guardleftpos?: number; + guardrightpos?: number; + guardleftypos?: number; + guardrightypos?: number; + + sizelimit?: number; + + includecheck?: boolean; + includecheckintext?: boolean; + + inkspread?: number; + inkspreadh?: number; + inkspreadv?: number; } } diff --git a/src/@types/passport-auth-token/index.d.ts b/src/@types/passport-auth-token/index.d.ts index 4105e20e8..95e57bfbf 100644 --- a/src/@types/passport-auth-token/index.d.ts +++ b/src/@types/passport-auth-token/index.d.ts @@ -5,20 +5,18 @@ declare module "passport-auth-token"; interface IVerifyOptions { - readonly headerFields: readonly string[]; - readonly optional: boolean; - readonly params: boolean; + readonly tokenFields: ReadonlyArray; + readonly headerFields: ReadonlyArray; readonly passReqToCallback: boolean; - readonly tokenFields: readonly string[]; + readonly params: boolean; + readonly optional: boolean; } type VerifyFunction = ( token: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - done: (error: any, user?: any, options?: IVerifyOptions) => void, + done: (error: any, user?: any, options?: IVerifyOptions) => void ) => void; -// eslint-disable-next-line @typescript-eslint/no-extraneous-class declare class Strategy { constructor(verify: VerifyFunction); } diff --git a/src/@types/passport-http-custom-bearer/index.d.ts b/src/@types/passport-http-custom-bearer/index.d.ts index f69bc444a..97e708f5c 100644 --- a/src/@types/passport-http-custom-bearer/index.d.ts +++ b/src/@types/passport-http-custom-bearer/index.d.ts @@ -3,59 +3,61 @@ */ declare module "passport-http-custom-bearer" { + import passport = require("passport"); import express = require("express"); import koa = require("koa"); - import passport = require("passport"); interface IStrategyOptions { bodyName?: string; headerName?: string; - passReqToCallback?: boolean | undefined; queryName?: string; + scope?: string | Array | undefined; realm?: string | undefined; - scope?: string | string[] | undefined; + passReqToCallback?: boolean | undefined; } interface IVerifyOptions { message?: string | undefined; - scope: string | string[]; + scope: string | Array; } - type VerifyFunction = ( - token: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - done: (error: any, user?: any, options?: IVerifyOptions | string) => void, - ) => void; + interface VerifyFunction { + ( + token: string, + done: (error: any, user?: any, options?: IVerifyOptions | string) => void + ): void; + } interface IKoaContextContainer { ctx: koa.Context; } - type KoaPassportExpressRequestMock = IKoaContextContainer & - Partial; - - type VerifyFunctionWithRequest = ( - req: express.Request, - token: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - done: (error: any, user?: any, options?: IVerifyOptions | string) => void, - ) => void; - type VerifyFunctionWithContext = ( - req: KoaPassportExpressRequestMock, - token: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - done: (error: any, user?: any, options?: IVerifyOptions | string) => void, - ) => void; + type KoaPassportExpressRequestMock = Partial & + IKoaContextContainer; + + interface VerifyFunctionWithRequest { + ( + req: express.Request, + token: string, + done: (error: any, user?: any, options?: IVerifyOptions | string) => void + ): void; + } + interface VerifyFunctionWithContext { + ( + req: KoaPassportExpressRequestMock, + token: string, + done: (error: any, user?: any, options?: IVerifyOptions | string) => void + ): void; + } type VerifyFunctions = | VerifyFunction - | VerifyFunctionWithContext - | VerifyFunctionWithRequest; + | VerifyFunctionWithRequest + | VerifyFunctionWithContext; class Strategy implements passport.Strategy { - name: string; constructor(verify: VerifyFunction); - constructor(options: IStrategyOptions, verify: T); - // eslint-disable-next-line @typescript-eslint/ban-types + + name: string; authenticate(req: express.Request, options?: Object): void; } } diff --git a/src/__tests__/lollipop-consumer.test.ts b/src/__tests__/lollipop-consumer.test.ts index f1d490457..73a323625 100644 --- a/src/__tests__/lollipop-consumer.test.ts +++ b/src/__tests__/lollipop-consumer.test.ts @@ -60,7 +60,7 @@ const lollipopConsumerApp = express(); lollipopConsumerApp.use( bodyParser.json({ verify: (_req, res: express.Response, buf, _encoding: BufferEncoding) => { - + // eslint-disable-next-line functional/immutable-data res.locals.body = buf; }, }) @@ -123,7 +123,7 @@ describe("lollipopSign", () => { buf, _encoding: BufferEncoding ) => { - + // eslint-disable-next-line functional/immutable-data res.locals.body = buf; }, }) diff --git a/src/adapters/pnFetch.ts b/src/adapters/pnFetch.ts index 81b10ea9f..5cd8f9e63 100644 --- a/src/adapters/pnFetch.ts +++ b/src/adapters/pnFetch.ts @@ -1,49 +1,48 @@ /* eslint-disable max-params */ -import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; +import { URL } from "url"; +import { flow, pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; +import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; +import * as O from "fp-ts/Option"; import { FiscalCode, NonEmptyString, Ulid, } from "@pagopa/ts-commons/lib/strings"; -import { eventLog } from "@pagopa/winston-ts"; -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; -import * as TE from "fp-ts/TaskEither"; -import { flow, pipe } from "fp-ts/lib/function"; -import { NotificationAttachmentDownloadMetadataResponse } from "generated/piattaforma-notifiche/NotificationAttachmentDownloadMetadataResponse"; -import * as t from "io-ts"; +import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; import { Response as NodeResponse } from "node-fetch"; -import nodeFetch from "node-fetch"; -import { Fetch } from "src/clients/third-party-service-client"; -import { LollipopLocalsType } from "src/types/lollipop"; +import { NotificationAttachmentDownloadMetadataResponse } from "generated/piattaforma-notifiche/NotificationAttachmentDownloadMetadataResponse"; import { match } from "ts-pattern"; -import { URL } from "url"; - +import { LollipopLocalsType } from "src/types/lollipop"; +import { Fetch } from "src/clients/third-party-service-client"; +import nodeFetch from "node-fetch"; +import { eventLog } from "@pagopa/winston-ts"; import { PnAPIClient } from "../clients/pn-clients"; -import { PN_CONFIGURATION_ID } from "../config"; -import { pathParamsFromUrl } from "../types/pathParams"; import { errorsToError } from "../utils/errorsFormatter"; +import { pathParamsFromUrl } from "../types/pathParams"; +import { PN_CONFIGURATION_ID } from "../config"; const getPath = (input: RequestInfo | URL): string => input instanceof URL ? `${input.pathname}${input.search}` : typeof input === "string" - ? `${new URL(input).pathname}${new URL(input).search}` - : `${new URL(input.url).pathname}${new URL(input.url).search}`; + ? `${new URL(input).pathname}${new URL(input).search}` + : `${new URL(input.url).pathname}${new URL(input.url).search}`; export const ThirdPartyMessagesUrl = pathParamsFromUrl( RegExp("^[/]+messages[/]+([^/]+)$"), - ([id]) => `/messages/${id}`, + ([id]) => `/messages/${id}` ); export const ThirdPartyAttachmentUrl = pathParamsFromUrl( RegExp("^[/]+messages[/]+([^/]+)/(.+)$"), - ([id, url]) => `/messages/${id}/${url}`, + ([id, url]) => `/messages/${id}/${url}` ); export const ThirdPartyPreconditionUrl = pathParamsFromUrl( RegExp("^[/]+messages[/]+([^/]+)/precondition$"), - ([id]) => `/messages/${id}/precondition`, + ([id]) => `/messages/${id}/precondition` ); // document path @@ -53,7 +52,7 @@ const attachmentPnDocument = "[/]+attachments[/]+documents[/]+([^/]+)$"; export const PnDocumentUrl = pathParamsFromUrl( RegExp(`${basePnDocument}${attachmentPnDocument}`), ([iun, docIdx]) => - `/delivery/notifications/received/${iun}/attachments/documents/${docIdx}`, + `/delivery/notifications/received/${iun}/attachments/documents/${docIdx}` ); // payment path @@ -62,7 +61,7 @@ const attachmentPnPayment = export const PnPaymentUrl = pathParamsFromUrl( RegExp(`${basePnDocument}${attachmentPnPayment}`), ([iun, docName, docIdx]) => - `/delivery/notifications/received/${iun}/attachments/payment/${docName}/?attachmentIdx=${docIdx}`, + `/delivery/notifications/received/${iun}/attachments/payment/${docName}/?attachmentIdx=${docIdx}` ); /** @@ -87,8 +86,8 @@ const retrievePrecondition = ( pnUrl: string, pnApiKey: string, fiscalCode: FiscalCode, - [iun]: readonly string[], - lollipopLocals?: LollipopLocalsType, + [iun]: ReadonlyArray, + lollipopLocals?: LollipopLocalsType ) => pipe( () => @@ -103,10 +102,10 @@ const retrievePrecondition = ( TE.chain( TE.fromPredicate( (r) => r.status === 200, - (r) => Error(`Failed to fetch PN ReceivedPrecondition: ${r.status}`), - ), + (r) => Error(`Failed to fetch PN ReceivedPrecondition: ${r.status}`) + ) ), - TE.map((response) => response.value), + TE.map((response) => response.value) ); const retrieveNotificationDetails = ( @@ -114,8 +113,8 @@ const retrieveNotificationDetails = ( pnUrl: string, pnApiKey: string, fiscalCode: FiscalCode, - [iun]: readonly string[], - lollipopLocals?: LollipopLocalsType, + [iun]: ReadonlyArray, + lollipopLocals?: LollipopLocalsType ) => pipe( () => @@ -129,21 +128,21 @@ const retrieveNotificationDetails = ( TE.chain( TE.fromPredicate( (r) => r.status === 200, - (r) => Error(`Failed to fetch PN ReceivedNotification: ${r.status}`), - ), + (r) => Error(`Failed to fetch PN ReceivedNotification: ${r.status}`) + ) ), - TE.map((response) => response.value), + TE.map((response) => response.value) ); const checkHeaders = ( - headers?: HeadersInit, + headers?: HeadersInit ): TE.TaskEither => pipe( headers, O.fromNullable, E.fromOption(() => Error("Missing fiscal_code in headers")), E.chain(flow(WithFiscalCode.decode, E.mapLeft(errorsToError))), - TE.fromEither, + TE.fromEither ); export const errorResponse = (error: Error): Response => @@ -158,7 +157,7 @@ export const errorResponse = (error: Error): Response => new NodeResponse(JSON.stringify(problem), { status: problem.status, statusText: problem.title, - }) as unknown as Response, // cast required: the same cast is used in clients code generation + }) as unknown as Response // cast required: the same cast is used in clients code generation ); export const retryResponse = (retryAfter: number): Response => @@ -174,7 +173,7 @@ export const retryResponse = (retryAfter: number): Response => headers: { "Retry-After": `${retryAfter}` }, status: problem.status, statusText: problem.title, - }) as unknown as Response, // cast required: the same cast is used in clients code generation + }) as unknown as Response // cast required: the same cast is used in clients code generation ); export const redirectPrecondition = @@ -184,7 +183,7 @@ export const redirectPrecondition = pnApiKey: string, url: string, lollipopLocals?: LollipopLocalsType, - init?: RequestInit, + init?: RequestInit ) => (): Promise => pipe( @@ -196,7 +195,7 @@ export const redirectPrecondition = ThirdPartyPreconditionUrl.decode, E.mapLeft(errorsToError), TE.fromEither, - eventLog.taskEither.info(() => [ + eventLog.taskEither.info((_) => [ `pn.precondition.call`, { locals: lollipopLocals @@ -213,25 +212,26 @@ export const redirectPrecondition = pnApiKey, headers.fiscal_code, params, - lollipopLocals, - ), - ), - ), - ), + lollipopLocals + ) + ) + ) + ) ), TE.map( + // eslint-disable-next-line sonarjs/no-identical-functions (body) => new NodeResponse(JSON.stringify(body), { status: 200, statusText: "OK", - }) as unknown as Response, // cast required: the same cast is used in clients code generation + }) as unknown as Response // cast required: the same cast is used in clients code generation ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call retrievePrecondition`, { message, name: "pn.precondition.error" }, ]), TE.mapLeft(errorResponse), - TE.toUnion, + TE.toUnion )(); export const redirectMessages = @@ -241,7 +241,7 @@ export const redirectMessages = pnApiKey: string, url: string, lollipopLocals?: LollipopLocalsType, - init?: RequestInit, + init?: RequestInit ) => (): Promise => pipe( @@ -253,7 +253,7 @@ export const redirectMessages = ThirdPartyMessagesUrl.decode, E.mapLeft(errorsToError), TE.fromEither, - eventLog.taskEither.info(() => [ + eventLog.taskEither.info((_) => [ `pn.notification.call`, { locals: lollipopLocals @@ -270,25 +270,26 @@ export const redirectMessages = pnApiKey, headers.fiscal_code, params, - lollipopLocals, - ), - ), - ), - ), + lollipopLocals + ) + ) + ) + ) ), TE.map( + // eslint-disable-next-line sonarjs/no-identical-functions (body) => new NodeResponse(JSON.stringify(body), { status: 200, statusText: "OK", - }) as unknown as Response, // cast required: the same cast is used in clients code generation + }) as unknown as Response // cast required: the same cast is used in clients code generation ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call retrieveNotificationDetails`, { message, name: "pn.notification.error" }, ]), TE.mapLeft(errorResponse), - TE.toUnion, + TE.toUnion )(); const getPnDocument = ( @@ -297,7 +298,7 @@ const getPnDocument = ( pnApiKey: string, url: string, fiscalCode: FiscalCode, - lollipopLocals?: LollipopLocalsType, + lollipopLocals?: LollipopLocalsType ): TE.TaskEither => pipe( url, @@ -315,22 +316,22 @@ const getPnDocument = ( "x-pagopa-cx-taxid": fiscalCode, ...lollipopLocals, }), - E.toError, + E.toError ), TE.chainEitherK(E.mapLeft(errorsToError)), TE.chain( TE.fromPredicate( (r) => r.status === 200, (r) => - Error(`Failed to fetch PN SentNotificationDocument: ${r.status}`), - ), + Error(`Failed to fetch PN SentNotificationDocument: ${r.status}`) + ) ), TE.map( (response) => - response.value as NotificationAttachmentDownloadMetadataResponse, - ), - ), - ), + response.value as NotificationAttachmentDownloadMetadataResponse + ) + ) + ) ); const getPnPayment = ( @@ -339,7 +340,7 @@ const getPnPayment = ( pnApiKey: string, url: string, fiscalCode: FiscalCode, - lollipopLocals?: LollipopLocalsType, + lollipopLocals?: LollipopLocalsType ): TE.TaskEither => pipe( url, @@ -358,7 +359,7 @@ const getPnPayment = ( "x-pagopa-cx-taxid": fiscalCode, ...lollipopLocals, }), - E.toError, + E.toError ), TE.chainEitherK(E.mapLeft(errorsToError)), TE.chain( @@ -366,16 +367,16 @@ const getPnPayment = ( (r) => r.status === 200, (r) => Error( - `Failed to fetch PN ReceivedNotificationAttachment: ${r.status}`, - ), - ), + `Failed to fetch PN ReceivedNotificationAttachment: ${r.status}` + ) + ) ), TE.map( (response) => - response.value as NotificationAttachmentDownloadMetadataResponse, - ), - ), - ), + response.value as NotificationAttachmentDownloadMetadataResponse + ) + ) + ) ); export const redirectAttachment = @@ -385,7 +386,7 @@ export const redirectAttachment = pnApiKey: string, url: string, lollipopLocals?: LollipopLocalsType, - init?: RequestInit, + init?: RequestInit ) => (): Promise => pipe( @@ -397,7 +398,6 @@ export const redirectAttachment = ThirdPartyAttachmentUrl.decode, E.mapLeft(errorsToError), TE.fromEither, - // eslint-disable-next-line @typescript-eslint/no-unused-vars TE.chain(([_id, getAttachmentUrl]) => match(getAttachmentUrl) .when( @@ -413,9 +413,9 @@ export const redirectAttachment = pnApiKey, au, headers.fiscal_code, - lollipopLocals, + lollipopLocals ); - }, + } ) .when( (au) => E.isRight(PnPaymentUrl.decode(au)), @@ -430,17 +430,17 @@ export const redirectAttachment = pnApiKey, au, headers.fiscal_code, - lollipopLocals, + lollipopLocals ); - }, + } ) .otherwise((au) => TE.left( new Error( - `Can not distinguish a PnDocumentUrl from a PnPaymentUrl with the url ${au}`, - ), - ), - ), + `Can not distinguish a PnDocumentUrl from a PnPaymentUrl with the url ${au}` + ) + ) + ) ), TE.chain((attachment) => pipe( @@ -454,31 +454,31 @@ export const redirectAttachment = (r) => r.status === 200, (r) => Error( - `Failed to fetch PN download attachment: ${r.status}`, - ), - ), - ), - ), + `Failed to fetch PN download attachment: ${r.status}` + ) + ) + ) + ) ), - E.getOrElse(() => + E.getOrElse((_) => pipe( attachment.retryAfter, t.number.decode, E.mapLeft(errorsToError), TE.fromEither, - TE.map((r) => retryResponse(r)), - ), - ), - ), - ), - ), + TE.map((r) => retryResponse(r)) + ) + ) + ) + ) + ) ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call getPnDocumentUrl`, { message, name: "pn.attachment.error" }, ]), TE.mapLeft(errorResponse), - TE.toUnion, + TE.toUnion )(); export const pnFetch = @@ -487,13 +487,13 @@ export const pnFetch = configurationId: Ulid, pnUrl: string, pnApiKey: string, - lollipopLocals?: LollipopLocalsType, + lollipopLocals?: LollipopLocalsType ): typeof fetch => (input, init) => { eventLog.peek.info( configurationId === PN_CONFIGURATION_ID ? [`Calling PN api`, { name: "lollipop.pn.api" }] - : ["Calling third party api", { name: "lollipop.third-party.api" }], + : ["Calling third party api", { name: "lollipop.third-party.api" }] ); return configurationId === PN_CONFIGURATION_ID ? match(getPath(input)) @@ -506,8 +506,8 @@ export const pnFetch = pnApiKey, url, lollipopLocals, - init, - ), + init + ) ) .when( (url) => E.isRight(ThirdPartyPreconditionUrl.decode(url)), @@ -518,8 +518,8 @@ export const pnFetch = pnApiKey, url, lollipopLocals, - init, - ), + init + ) ) .when( (url) => E.isRight(ThirdPartyAttachmentUrl.decode(url)), @@ -530,19 +530,19 @@ export const pnFetch = pnApiKey, url, lollipopLocals, - init, - ), + init + ) ) .otherwise((url) => pipe( TE.left( new Error( - `[pnFetch] Can not find a Piattaforma Notifiche implementation for ${url}`, - ), + `[pnFetch] Can not find a Piattaforma Notifiche implementation for ${url}` + ) ), TE.mapLeft(errorResponse), - TE.toUnion, - ), + TE.toUnion + ) )() : origFetch(input, init); }; diff --git a/src/app.ts b/src/app.ts index 2233f8dde..542f918bc 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,4 +1,16 @@ /* eslint-disable max-lines-per-function */ +/** + * Main entry point for the Digital Citizenship proxy. + */ +import * as bodyParser from "body-parser"; +import * as express from "express"; +import * as helmet from "helmet"; +import * as morgan from "morgan"; +import * as passport from "passport"; + +import { Express } from "express"; +import expressEnforcesSsl = require("express-enforces-ssl"); + import { TableClient } from "@azure/data-tables"; import { NodeEnvironment, @@ -7,24 +19,14 @@ import { import { ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { CIDR, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as appInsights from "applicationinsights"; -/** - * Main entry point for the Digital Citizenship proxy. - */ -import * as bodyParser from "body-parser"; -import * as express from "express"; -import { Express } from "express"; import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; -import * as helmet from "helmet"; -import * as morgan from "morgan"; -import * as passport from "passport"; - import { ServerInfo } from "../generated/public/ServerInfo"; + import { VersionPerPlatform } from "../generated/public/VersionPerPlatform"; -import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; -import { LollipopApiClient } from "./clients/lollipop"; +import { getUserIdentity } from "./controllers/authenticationController"; import { API_CLIENT, APP_MESSAGES_API_CLIENT, @@ -38,16 +40,16 @@ import { FF_ENABLE_NOTIFY_ENDPOINT, FF_ENABLE_SESSION_ENDPOINTS, FF_EUCOVIDCERT_ENABLED, - FF_IO_FIMS_ENABLED, FF_IO_SIGN_ENABLED, + FF_IO_FIMS_ENABLED, FF_IO_WALLET_ENABLED, FF_ROUTING_PUSH_NOTIF, FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST, FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, FF_TRIAL_SYSTEM_ENABLED, FIRST_LOLLIPOP_CONSUMER_CLIENT, - IO_FIMS_API_CLIENT, IO_SIGN_API_CLIENT, + IO_FIMS_API_CLIENT, IO_SIGN_SERVICE_ID, IO_WALLET_API_CLIENT, LOCKED_PROFILES_STORAGE_CONNECTION_STRING, @@ -55,13 +57,13 @@ import { LOLLIPOP_API_CLIENT, LOLLIPOP_REVOKE_QUEUE_NAME, LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING, - NOTIFICATION_DEFAULT_SUBJECT, - NOTIFICATION_DEFAULT_TITLE, NOTIFICATIONS_QUEUE_NAME, NOTIFICATIONS_STORAGE_CONNECTION_STRING, + NOTIFICATION_DEFAULT_SUBJECT, + NOTIFICATION_DEFAULT_TITLE, PAGOPA_CLIENT, - PN_ADDRESS_BOOK_CLIENT_SELECTOR, PNAddressBookConfig, + PN_ADDRESS_BOOK_CLIENT_SELECTOR, PUSH_NOTIFICATIONS_QUEUE_NAME, PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING, ROOT_REDIRECT_URL, @@ -70,41 +72,42 @@ import { TRIAL_SYSTEM_CLIENT, URL_TOKEN_STRATEGY, } from "./config"; -import { getUserIdentity } from "./controllers/authenticationController"; +import MessagesController from "./controllers/messagesController"; +import NotificationController from "./controllers/notificationController"; +import PagoPAProxyController from "./controllers/pagoPAProxyController"; +import ProfileController from "./controllers/profileController"; +import ServicesController from "./controllers/servicesController"; +import SessionController from "./controllers/sessionController"; +import UserMetadataController from "./controllers/userMetadataController"; + +import { log } from "./utils/logger"; +import checkIP from "./utils/middleware/checkIP"; + +import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; +import { LollipopApiClient } from "./clients/lollipop"; import BonusController from "./controllers/bonusController"; import CgnController from "./controllers/cgnController"; import CgnOperatorSearchController from "./controllers/cgnOperatorSearchController"; import EUCovidCertController from "./controllers/eucovidcertController"; -import IoFimsController from "./controllers/fimsController"; import { firstLollipopSign } from "./controllers/firstLollipopConsumerController"; import IoSignController from "./controllers/ioSignController"; -import IoWalletController from "./controllers/ioWalletController"; -import MessagesController from "./controllers/messagesController"; -import NotificationController from "./controllers/notificationController"; -import PagoPAProxyController from "./controllers/pagoPAProxyController"; import { getPNActivationController, upsertPNActivationController, } from "./controllers/pnController"; -import ProfileController from "./controllers/profileController"; import ServicesAppBackendController from "./controllers/serviceAppBackendController"; -import ServicesController from "./controllers/servicesController"; -import SessionController from "./controllers/sessionController"; import SessionLockController from "./controllers/sessionLockController"; import { getUserForMyPortal } from "./controllers/ssoController"; -import TrialController from "./controllers/trialController"; import UserDataProcessingController from "./controllers/userDataProcessingController"; -import UserMetadataController from "./controllers/userMetadataController"; import { ISessionStorage } from "./services/ISessionStorage"; import AuthenticationLockService from "./services/authenticationLockService"; import BonusService from "./services/bonusService"; import CgnOperatorSearchService from "./services/cgnOperatorSearchService"; import CgnService from "./services/cgnService"; import EUCovidCertService from "./services/eucovidcertService"; -import IoFimsService from "./services/fimsService"; import FunctionsAppService from "./services/functionAppService"; import IoSignService from "./services/ioSignService"; -import IoWalletService from "./services/ioWalletService"; +import IoFimsService from "./services/fimsService"; import LollipopService from "./services/lollipopService"; import NewMessagesService from "./services/newMessagesService"; import NotificationService from "./services/notificationService"; @@ -118,7 +121,6 @@ import ProfileService from "./services/profileService"; import RedisSessionStorage from "./services/redisSessionStorage"; import RedisUserMetadataStorage from "./services/redisUserMetadataStorage"; import ServicesAppBackendService from "./services/servicesAppBackendService"; -import TrialService from "./services/trialService"; import UserDataProcessingService from "./services/userDataProcessingService"; import bearerMyPortalTokenStrategy from "./strategies/bearerMyPortalTokenStrategy"; import bearerSessionTokenStrategy from "./strategies/bearerSessionTokenStrategy"; @@ -126,8 +128,6 @@ import { User } from "./types/user"; import { attachTrackingData } from "./utils/appinsights"; import { getRequiredENVVar } from "./utils/container"; import { constantExpressHandler, toExpressHandler } from "./utils/express"; -import { log } from "./utils/logger"; -import checkIP from "./utils/middleware/checkIP"; import { expressErrorMiddleware } from "./utils/middleware/express"; import { expressLollipopMiddleware, @@ -139,8 +139,11 @@ import { } from "./utils/package"; import { RedisClientMode, RedisClientSelector } from "./utils/redis"; import { ResponseErrorDismissed } from "./utils/responses"; - -import expressEnforcesSsl = require("express-enforces-ssl"); +import TrialService from "./services/trialService"; +import TrialController from "./controllers/trialController"; +import IoWalletController from "./controllers/ioWalletController"; +import IoWalletService from "./services/ioWalletService"; +import IoFimsController from "./controllers/fimsController"; const defaultModule = { // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -148,52 +151,53 @@ const defaultModule = { }; export interface IAppFactoryParameters { + readonly env: NodeEnvironment; + readonly appInsightsClient?: appInsights.TelemetryClient; + readonly allowNotifyIPSourceRange: ReadonlyArray; + readonly allowMyPortalIPSourceRange: ReadonlyArray; + readonly allowSessionHandleIPSourceRange: ReadonlyArray; + readonly authenticationBasePath: string; readonly APIBasePath: string; readonly BonusAPIBasePath: string; + readonly MyPortalBasePath: string; readonly CGNAPIBasePath: string; readonly CGNOperatorSearchAPIBasePath: string; - readonly EUCovidCertBasePath: string; - readonly IoFimsAPIBasePath: string; readonly IoSignAPIBasePath: string; + readonly IoFimsAPIBasePath: string; readonly IoWalletAPIBasePath: string; - readonly MyPortalBasePath: string; + readonly EUCovidCertBasePath: string; readonly ServicesAppBackendBasePath: string; readonly TrialSystemBasePath: string; - readonly allowMyPortalIPSourceRange: readonly CIDR[]; - readonly allowNotifyIPSourceRange: readonly CIDR[]; - readonly allowSessionHandleIPSourceRange: readonly CIDR[]; - readonly appInsightsClient?: appInsights.TelemetryClient; - readonly authenticationBasePath: string; - readonly env: NodeEnvironment; } +// eslint-disable-next-line max-lines-per-function, sonarjs/cognitive-complexity export async function newApp({ + env, + allowNotifyIPSourceRange, + allowMyPortalIPSourceRange, + allowSessionHandleIPSourceRange, + appInsightsClient, + authenticationBasePath, APIBasePath, BonusAPIBasePath, + MyPortalBasePath, CGNAPIBasePath, - CGNOperatorSearchAPIBasePath, - EUCovidCertBasePath, - IoFimsAPIBasePath, IoSignAPIBasePath, + IoFimsAPIBasePath, IoWalletAPIBasePath, - MyPortalBasePath, + CGNOperatorSearchAPIBasePath, + EUCovidCertBasePath, ServicesAppBackendBasePath, TrialSystemBasePath, - allowMyPortalIPSourceRange, - allowNotifyIPSourceRange, - allowSessionHandleIPSourceRange, - appInsightsClient, - authenticationBasePath, - env, }: IAppFactoryParameters): Promise { const isDevEnvironment = ENV === NodeEnvironmentEnum.DEVELOPMENT; const REDIS_CLIENT_SELECTOR = await RedisClientSelector( !isDevEnvironment, - appInsightsClient, + appInsightsClient )( getRequiredENVVar("REDIS_URL"), process.env.REDIS_PASSWORD, - process.env.REDIS_PORT, + process.env.REDIS_PORT ); // Create the Session Storage service @@ -202,7 +206,7 @@ export async function newApp({ // Add the strategy to authenticate proxy clients. passport.use( "bearer.session", - bearerSessionTokenStrategy(SESSION_STORAGE, attachTrackingData), + bearerSessionTokenStrategy(SESSION_STORAGE, attachTrackingData) ); // Add the strategy to authenticate MyPortal clients. @@ -252,21 +256,21 @@ export async function newApp({ // Adds the user fiscal code // we take only the first 6 characters of the fiscal code - morgan.token("fiscal_code_short", (req: express.Request) => + morgan.token("fiscal_code_short", (req: express.Request, _) => pipe( req.user, User.decode, E.map((user) => String(user.fiscal_code).slice(0, 6)), - E.getOrElse(() => ""), - ), + E.getOrElse(() => "") + ) ); const obfuscateToken = (originalUrl: string) => originalUrl.replace(/([?&]token=|[?&]access_token=)([^&]*)/g, "$1REDACTED"); // Obfuscate token in url on morgan logs - morgan.token("obfuscated_url", (req: express.Request) => - obfuscateToken(req.originalUrl), + morgan.token("obfuscated_url", (req: express.Request, _) => + obfuscateToken(req.originalUrl) ); const loggerFormat = @@ -281,11 +285,11 @@ export async function newApp({ // Parse the incoming request body. This is needed by Passport spid strategy. app.use( bodyParser.json({ - // eslint-disable-next-line @typescript-eslint/no-unused-vars verify: (_req, res: express.Response, buf, _encoding: BufferEncoding) => { + // eslint-disable-next-line functional/immutable-data res.locals.body = buf; }, - }), + }) ); // Parse an urlencoded body. @@ -312,11 +316,11 @@ export async function newApp({ // Create the profile service const tableClient = TableClient.fromConnectionString( LOCKED_PROFILES_STORAGE_CONNECTION_STRING, - LOCKED_PROFILES_TABLE_NAME, + LOCKED_PROFILES_TABLE_NAME ); const PROFILE_SERVICE = new ProfileService(API_CLIENT); const AUTHENTICATION_LOCK_SERVICE = new AuthenticationLockService( - tableClient, + tableClient ); // Create the bonus service @@ -333,28 +337,28 @@ export async function newApp({ // Create the cgn operator search service const CGN_OPERATOR_SEARCH_SERVICE = new CgnOperatorSearchService( - CGN_OPERATOR_SEARCH_API_CLIENT, + CGN_OPERATOR_SEARCH_API_CLIENT ); // Create the EUCovidCert service const EUCOVIDCERT_SERVICE = new EUCovidCertService( - EUCOVIDCERT_API_CLIENT, + EUCOVIDCERT_API_CLIENT ); // Create the user data processing service const USER_DATA_PROCESSING_SERVICE = new UserDataProcessingService( - API_CLIENT, + API_CLIENT ); // Create the the io-services-app-backend service const SERVICES_APP_BACKEND_SERVICE = new ServicesAppBackendService( - SERVICES_APP_BACKEND_CLIENT, + SERVICES_APP_BACKEND_CLIENT ); // Create the io wallet const IO_WALLET_SERVICE = new IoWalletService( IO_WALLET_API_CLIENT, - TRIAL_SYSTEM_CLIENT, + TRIAL_SYSTEM_CLIENT ); // Create the Notification Service @@ -363,14 +367,14 @@ export async function newApp({ () => new NotificationService( NOTIFICATIONS_STORAGE_CONNECTION_STRING, - NOTIFICATIONS_QUEUE_NAME, + NOTIFICATIONS_QUEUE_NAME ), (err) => - new Error(`Error initializing Notification Service: [${err}]`), + new Error(`Error initializing Notification Service: [${err}]`) ), E.getOrElseW((err) => { throw err; - }), + }) ); // Create the Notification Service @@ -379,16 +383,16 @@ export async function newApp({ () => new NotificationService( PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING, - PUSH_NOTIFICATIONS_QUEUE_NAME, + PUSH_NOTIFICATIONS_QUEUE_NAME ), (err) => new Error( - `Error initializing Push Notification Service: [${err}]`, - ), + `Error initializing Push Notification Service: [${err}]` + ) ), E.getOrElseW((err) => { throw err; - }), + }) ); const notificationServiceFactory = getNotificationServiceFactory( @@ -396,7 +400,7 @@ export async function newApp({ PUSH_NOTIFICATION_SERVICE, FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST, FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, - FF_ROUTING_PUSH_NOTIF, + FF_ROUTING_PUSH_NOTIF ); const LOLLIPOP_SERVICE = pipe( @@ -404,13 +408,13 @@ export async function newApp({ () => new LollipopService( LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING, - LOLLIPOP_REVOKE_QUEUE_NAME, + LOLLIPOP_REVOKE_QUEUE_NAME ), - (err) => new Error(`Error initializing LollipopService: [${err}]`), + (err) => new Error(`Error initializing LollipopService: [${err}]`) ), E.getOrElseW((err) => { throw err; - }), + }) ); const TRIAL_SERVICE = new TrialService(TRIAL_SYSTEM_CLIENT); @@ -425,27 +429,27 @@ export async function newApp({ LOLLIPOP_API_CLIENT, SESSION_STORAGE, FIRST_LOLLIPOP_CONSUMER_CLIENT, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerAuthenticationRoutes( app, authenticationBasePath, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); // Create the function app service. const FN_APP_SERVICE = new FunctionsAppService(API_CLIENT); // Create the new messages service. const APP_MESSAGES_SERVICE = new NewMessagesService( - APP_MESSAGES_API_CLIENT, + APP_MESSAGES_API_CLIENT ); const PAGOPA_PROXY_SERVICE = new PagoPAProxyService(PAGOPA_CLIENT); // Register the user metadata storage service. const USER_METADATA_STORAGE = new RedisUserMetadataStorage( - REDIS_CLIENT_SELECTOR.selectOne(RedisClientMode.FAST), + REDIS_CLIENT_SELECTOR.selectOne(RedisClientMode.FAST) ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerAPIRoutes( @@ -462,7 +466,7 @@ export async function newApp({ USER_METADATA_STORAGE, USER_DATA_PROCESSING_SERVICE, authMiddlewares.bearerSession, - LOLLIPOP_API_CLIENT, + LOLLIPOP_API_CLIENT ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerSessionAPIRoutes( @@ -474,7 +478,7 @@ export async function newApp({ USER_METADATA_STORAGE, LOLLIPOP_SERVICE, AUTHENTICATION_LOCK_SERVICE, - notificationServiceFactory, + notificationServiceFactory ); if (FF_BONUS_ENABLED) { // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -482,7 +486,7 @@ export async function newApp({ app, BonusAPIBasePath, BONUS_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); } if (FF_CGN_ENABLED) { @@ -491,7 +495,7 @@ export async function newApp({ app, CGNAPIBasePath, CGN_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -500,7 +504,7 @@ export async function newApp({ CGNOperatorSearchAPIBasePath, CGN_SERVICE, CGN_OPERATOR_SEARCH_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); } @@ -513,7 +517,7 @@ export async function newApp({ PROFILE_SERVICE, authMiddlewares.bearerSession, LOLLIPOP_API_CLIENT, - SESSION_STORAGE, + SESSION_STORAGE ); } @@ -524,7 +528,7 @@ export async function newApp({ IoFimsAPIBasePath, IO_FIMS_SERVICE, PROFILE_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); } @@ -534,7 +538,7 @@ export async function newApp({ app, EUCovidCertBasePath, EUCOVIDCERT_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); } @@ -543,14 +547,14 @@ export async function newApp({ app, MyPortalBasePath, allowMyPortalIPSourceRange, - authMiddlewares.bearerMyPortal, + authMiddlewares.bearerMyPortal ); // eslint-disable-next-line @typescript-eslint/no-use-before-define registerServicesAppBackendRoutes( app, ServicesAppBackendBasePath, SERVICES_APP_BACKEND_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); if ( @@ -563,7 +567,7 @@ export async function newApp({ app, PNAddressBookConfig.PN_ACTIVATION_BASE_PATH, pnService, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); } @@ -573,7 +577,7 @@ export async function newApp({ app, TrialSystemBasePath, TRIAL_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); } @@ -583,19 +587,19 @@ export async function newApp({ app, IoWalletAPIBasePath, IO_WALLET_SERVICE, - authMiddlewares.bearerSession, + authMiddlewares.bearerSession ); } return { app }; }, - (err) => new Error(`Error on app routes setup: [${err}]`), + (err) => new Error(`Error on app routes setup: [${err}]`) ), TE.map((_) => { _.app.on("server:stop", () => { // Graceful redis connection shutdown. for (const client of REDIS_CLIENT_SELECTOR.select( - RedisClientMode.ALL, + RedisClientMode.ALL )) { log.info(`Graceful closing redis connection`); pipe( @@ -605,10 +609,10 @@ export async function newApp({ log.error( `An Error occurred closing the redis connection: [${ E.toError(err).message - }]`, - ), - ), - ), + }]` + ) + ) + ) ); } }); @@ -624,22 +628,22 @@ export async function newApp({ TE.getOrElse((err) => { app.emit("server:stop"); throw err; - }), + }) )(); } function registerMyPortalRoutes( app: Express, basePath: string, - allowMyPortalIPSourceRange: readonly CIDR[], + allowMyPortalIPSourceRange: ReadonlyArray, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerMyPortalTokenAuth: any, + bearerMyPortalTokenAuth: any ): void { app.get( `${basePath}/user`, checkIP(allowMyPortalIPSourceRange), bearerMyPortalTokenAuth, - toExpressHandler(getUserForMyPortal), + toExpressHandler(getUserForMyPortal) ); } @@ -648,7 +652,7 @@ function registerServicesAppBackendRoutes( basePath: string, servicesAppBackendService: ServicesAppBackendService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const servicesAppBackendController: ServicesAppBackendController = new ServicesAppBackendController(servicesAppBackendService); @@ -658,8 +662,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.findInstitutions, - servicesAppBackendController, - ), + servicesAppBackendController + ) ); app.get( @@ -667,8 +671,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.getFeaturedInstitutions, - servicesAppBackendController, - ), + servicesAppBackendController + ) ); app.get( @@ -676,8 +680,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.findInstutionServices, - servicesAppBackendController, - ), + servicesAppBackendController + ) ); app.get( @@ -685,8 +689,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.getFeaturedServices, - servicesAppBackendController, - ), + servicesAppBackendController + ) ); app.get( @@ -694,8 +698,8 @@ function registerServicesAppBackendRoutes( bearerSessionTokenAuth, toExpressHandler( servicesAppBackendController.getServiceById, - servicesAppBackendController, - ), + servicesAppBackendController + ) ); } @@ -704,7 +708,7 @@ function registerEUCovidCertAPIRoutes( basePath: string, eucovidcertService: EUCovidCertService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const eucovidCertController: EUCovidCertController = new EUCovidCertController(eucovidcertService); @@ -714,8 +718,8 @@ function registerEUCovidCertAPIRoutes( bearerSessionTokenAuth, toExpressHandler( eucovidCertController.getEUCovidCertificate, - eucovidCertController, - ), + eucovidCertController + ) ); } @@ -723,7 +727,7 @@ function registerEUCovidCertAPIRoutes( function registerAPIRoutes( app: Express, basePath: string, - _allowNotifyIPSourceRange: readonly CIDR[], + _allowNotifyIPSourceRange: ReadonlyArray, // eslint-disable-next-line @typescript-eslint/no-explicit-any urlTokenAuth: any, profileService: ProfileService, @@ -736,21 +740,21 @@ function registerAPIRoutes( userDataProcessingService: UserDataProcessingService, // eslint-disable-next-line @typescript-eslint/no-explicit-any bearerSessionTokenAuth: any, - lollipopClient: ReturnType, + lollipopClient: ReturnType ): void { const profileController: ProfileController = new ProfileController( profileService, - sessionStorage, + sessionStorage ); const messagesController: MessagesController = new MessagesController( appMessagesService, lollipopClient, - sessionStorage, + sessionStorage ); const servicesController: ServicesController = new ServicesController( - fnAppService, + fnAppService ); const notificationController: NotificationController = @@ -760,7 +764,7 @@ function registerAPIRoutes( }); const sessionController: SessionController = new SessionController( - sessionStorage, + sessionStorage ); const pagoPAProxyController: PagoPAProxyController = @@ -775,19 +779,19 @@ function registerAPIRoutes( app.get( `${basePath}/profile`, bearerSessionTokenAuth, - toExpressHandler(profileController.getProfile, profileController), + toExpressHandler(profileController.getProfile, profileController) ); app.get( `${basePath}/api-profile`, bearerSessionTokenAuth, - toExpressHandler(profileController.getApiProfile, profileController), + toExpressHandler(profileController.getApiProfile, profileController) ); app.post( `${basePath}/profile`, bearerSessionTokenAuth, - toExpressHandler(profileController.updateProfile, profileController), + toExpressHandler(profileController.updateProfile, profileController) ); app.post( @@ -795,17 +799,14 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( profileController.startEmailValidationProcess, - profileController, - ), + profileController + ) ); app.get( `${basePath}/user-metadata`, bearerSessionTokenAuth, - toExpressHandler( - userMetadataController.getMetadata, - userMetadataController, - ), + toExpressHandler(userMetadataController.getMetadata, userMetadataController) ); app.post( @@ -813,8 +814,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userMetadataController.upsertMetadata, - userMetadataController, - ), + userMetadataController + ) ); app.post( @@ -822,8 +823,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userDataProcessingController.upsertUserDataProcessing, - userDataProcessingController, - ), + userDataProcessingController + ) ); app.get( @@ -831,8 +832,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userDataProcessingController.getUserDataProcessing, - userDataProcessingController, - ), + userDataProcessingController + ) ); app.delete( @@ -840,29 +841,26 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( userDataProcessingController.abortUserDataProcessing, - userDataProcessingController, - ), + userDataProcessingController + ) ); app.get( `${basePath}/messages`, bearerSessionTokenAuth, - toExpressHandler(messagesController.getMessagesByUser, messagesController), + toExpressHandler(messagesController.getMessagesByUser, messagesController) ); app.get( `${basePath}/messages/:id`, bearerSessionTokenAuth, - toExpressHandler(messagesController.getMessage, messagesController), + toExpressHandler(messagesController.getMessage, messagesController) ); app.put( `${basePath}/messages/:id/message-status`, bearerSessionTokenAuth, - toExpressHandler( - messagesController.upsertMessageStatus, - messagesController, - ), + toExpressHandler(messagesController.upsertMessageStatus, messagesController) ); app.get( @@ -870,8 +868,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( messagesController.getThirdPartyMessagePrecondition, - messagesController, - ), + messagesController + ) ); app.get( @@ -879,8 +877,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( messagesController.getThirdPartyMessage, - messagesController, - ), + messagesController + ) ); app.get( @@ -888,14 +886,14 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( messagesController.getThirdPartyMessageAttachment, - messagesController, - ), + messagesController + ) ); app.get( `${basePath}/services/:id`, bearerSessionTokenAuth, - toExpressHandler(servicesController.getService, servicesController), + toExpressHandler(servicesController.getService, servicesController) ); app.get( @@ -903,8 +901,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( servicesController.getServicePreferences, - servicesController, - ), + servicesController + ) ); app.post( @@ -912,17 +910,17 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( servicesController.upsertServicePreferences, - servicesController, - ), + servicesController + ) ); app.get( `${basePath}/services`, bearerSessionTokenAuth, toExpressHandler( - () => Promise.resolve(ResponseSuccessJson({ items: [] })), - servicesController, - ), + (_) => Promise.resolve(ResponseSuccessJson({ items: [] })), + servicesController + ) ); app.put( @@ -930,22 +928,22 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( notificationController.createOrUpdateInstallation, - notificationController, - ), + notificationController + ) ); if (FF_ENABLE_NOTIFY_ENDPOINT) { app.post( `${basePath}/notify`, urlTokenAuth, - toExpressHandler(notificationController.notify, notificationController), + toExpressHandler(notificationController.notify, notificationController) ); } app.get( `${basePath}/sessions`, bearerSessionTokenAuth, - toExpressHandler(sessionController.listSessions, sessionController), + toExpressHandler(sessionController.listSessions, sessionController) ); app.get( @@ -953,8 +951,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( pagoPAProxyController.getPaymentInfo, - pagoPAProxyController, - ), + pagoPAProxyController + ) ); app.post( @@ -962,8 +960,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( pagoPAProxyController.activatePayment, - pagoPAProxyController, - ), + pagoPAProxyController + ) ); app.get( @@ -971,8 +969,8 @@ function registerAPIRoutes( bearerSessionTokenAuth, toExpressHandler( pagoPAProxyController.getActivationStatus, - pagoPAProxyController, - ), + pagoPAProxyController + ) ); } @@ -980,14 +978,14 @@ function registerAPIRoutes( function registerSessionAPIRoutes( app: Express, basePath: string, - _allowSessionHandleIPSourceRange: readonly CIDR[], + _allowSessionHandleIPSourceRange: ReadonlyArray, // eslint-disable-next-line @typescript-eslint/no-explicit-any urlTokenAuth: any, sessionStorage: RedisSessionStorage, userMetadataStorage: RedisUserMetadataStorage, lollipopService: LollipopService, authenticationLockService: AuthenticationLockService, - notificationServiceFactory: NotificationServiceFactory, + notificationServiceFactory: NotificationServiceFactory ): void { if (FF_ENABLE_SESSION_ENDPOINTS) { const sessionLockController: SessionLockController = @@ -996,7 +994,7 @@ function registerSessionAPIRoutes( userMetadataStorage, lollipopService, authenticationLockService, - notificationServiceFactory, + notificationServiceFactory ); app.get( @@ -1004,8 +1002,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.getUserSession, - sessionLockController, - ), + sessionLockController + ) ); app.post( @@ -1013,8 +1011,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.lockUserSession, - sessionLockController, - ), + sessionLockController + ) ); app.post( @@ -1022,8 +1020,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.deleteUserSession, - sessionLockController, - ), + sessionLockController + ) ); app.delete( @@ -1031,8 +1029,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.unlockUserSession, - sessionLockController, - ), + sessionLockController + ) ); app.post( @@ -1040,8 +1038,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.lockUserAuthentication, - sessionLockController, - ), + sessionLockController + ) ); app.post( @@ -1049,8 +1047,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.unlockUserAuthentication, - sessionLockController, - ), + sessionLockController + ) ); app.get( @@ -1058,8 +1056,8 @@ function registerSessionAPIRoutes( urlTokenAuth, toExpressHandler( sessionLockController.getUserSessionState, - sessionLockController, - ), + sessionLockController + ) ); } } @@ -1069,59 +1067,59 @@ function registerCgnAPIRoutes( basePath: string, cgnService: CgnService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const cgnController: CgnController = new CgnController( cgnService, - TEST_CGN_FISCAL_CODES, + TEST_CGN_FISCAL_CODES ); app.get( `${basePath}/status`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getCgnStatus, cgnController), + toExpressHandler(cgnController.getCgnStatus, cgnController) ); app.get( `${basePath}/eyca/status`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getEycaStatus, cgnController), + toExpressHandler(cgnController.getEycaStatus, cgnController) ); app.post( `${basePath}/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.startCgnActivation, cgnController), + toExpressHandler(cgnController.startCgnActivation, cgnController) ); app.get( `${basePath}/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getCgnActivation, cgnController), + toExpressHandler(cgnController.getCgnActivation, cgnController) ); app.post( `${basePath}/eyca/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.startEycaActivation, cgnController), + toExpressHandler(cgnController.startEycaActivation, cgnController) ); app.get( `${basePath}/eyca/activation`, bearerSessionTokenAuth, - toExpressHandler(cgnController.getEycaActivation, cgnController), + toExpressHandler(cgnController.getEycaActivation, cgnController) ); app.post( `${basePath}/delete`, bearerSessionTokenAuth, - toExpressHandler(cgnController.startCgnUnsubscription, cgnController), + toExpressHandler(cgnController.startCgnUnsubscription, cgnController) ); app.post( `${basePath}/otp`, bearerSessionTokenAuth, - toExpressHandler(cgnController.generateOtp, cgnController), + toExpressHandler(cgnController.generateOtp, cgnController) ); } @@ -1134,11 +1132,11 @@ function registerIoSignAPIRoutes( // eslint-disable-next-line @typescript-eslint/no-explicit-any bearerSessionTokenAuth: any, lollipopClient: ReturnType, - sessionStorage: ISessionStorage, + sessionStorage: ISessionStorage ): void { const ioSignController: IoSignController = new IoSignController( ioSignService, - profileService, + profileService ); app.get( @@ -1147,39 +1145,39 @@ function registerIoSignAPIRoutes( constantExpressHandler( ResponseSuccessJson({ serviceId: IO_SIGN_SERVICE_ID as NonEmptyString, - }), - ), + }) + ) ); app.post( `${basePath}/qtsp/clauses/filled_document`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.createFilledDocument, ioSignController), + toExpressHandler(ioSignController.createFilledDocument, ioSignController) ); app.get( `${basePath}/qtsp/clauses`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.getQtspClausesMetadata, ioSignController), + toExpressHandler(ioSignController.getQtspClausesMetadata, ioSignController) ); app.post( `${basePath}/signatures`, bearerSessionTokenAuth, expressLollipopMiddlewareLegacy(lollipopClient, sessionStorage), - toExpressHandler(ioSignController.createSignature, ioSignController), + toExpressHandler(ioSignController.createSignature, ioSignController) ); app.get( `${basePath}/signature-requests`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.getSignatureRequests, ioSignController), + toExpressHandler(ioSignController.getSignatureRequests, ioSignController) ); app.get( `${basePath}/signature-requests/:id`, bearerSessionTokenAuth, - toExpressHandler(ioSignController.getSignatureRequest, ioSignController), + toExpressHandler(ioSignController.getSignatureRequest, ioSignController) ); } @@ -1189,23 +1187,23 @@ function registerIoFimsAPIRoutes( ioFimsService: IoFimsService, profileService: ProfileService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const ioFimsController: IoFimsController = new IoFimsController( ioFimsService, - profileService, + profileService ); app.get( `${basePath}/accesses`, bearerSessionTokenAuth, - toExpressHandler(ioFimsController.getAccessHistory, ioFimsController), + toExpressHandler(ioFimsController.getAccessHistory, ioFimsController) ); app.post( `${basePath}/export-requests`, bearerSessionTokenAuth, - toExpressHandler(ioFimsController.requestExport, ioFimsController), + toExpressHandler(ioFimsController.requestExport, ioFimsController) ); } @@ -1215,7 +1213,7 @@ function registerCgnOperatorSearchAPIRoutes( cgnService: CgnService, cgnOperatorSearchService: CgnOperatorSearchService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const cgnOperatorController: CgnOperatorSearchController = new CgnOperatorSearchController(cgnService, cgnOperatorSearchService); @@ -1225,26 +1223,26 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getPublishedProductCategories, - cgnOperatorController, - ), + cgnOperatorController + ) ); app.get( `${basePath}/merchants/:merchantId`, bearerSessionTokenAuth, - toExpressHandler(cgnOperatorController.getMerchant, cgnOperatorController), + toExpressHandler(cgnOperatorController.getMerchant, cgnOperatorController) ); app.get( `${basePath}/count`, bearerSessionTokenAuth, - toExpressHandler(cgnOperatorController.count, cgnOperatorController), + toExpressHandler(cgnOperatorController.count, cgnOperatorController) ); app.post( `${basePath}/search`, bearerSessionTokenAuth, - toExpressHandler(cgnOperatorController.search, cgnOperatorController), + toExpressHandler(cgnOperatorController.search, cgnOperatorController) ); app.post( @@ -1252,8 +1250,8 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getOnlineMerchants, - cgnOperatorController, - ), + cgnOperatorController + ) ); app.post( @@ -1261,8 +1259,8 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getOfflineMerchants, - cgnOperatorController, - ), + cgnOperatorController + ) ); app.get( @@ -1270,8 +1268,8 @@ function registerCgnOperatorSearchAPIRoutes( bearerSessionTokenAuth, toExpressHandler( cgnOperatorController.getDiscountBucketCode, - cgnOperatorController, - ), + cgnOperatorController + ) ); } @@ -1280,20 +1278,20 @@ function registerBonusAPIRoutes( basePath: string, bonusService: BonusService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const bonusController: BonusController = new BonusController(bonusService); app.post( `${basePath}/bonus/vacanze/eligibility`, bearerSessionTokenAuth, - constantExpressHandler(ResponseErrorDismissed), + constantExpressHandler(ResponseErrorDismissed) ); app.get( `${basePath}/bonus/vacanze/eligibility`, bearerSessionTokenAuth, - toExpressHandler(bonusController.getBonusEligibilityCheck, bonusController), + toExpressHandler(bonusController.getBonusEligibilityCheck, bonusController) ); app.get( @@ -1301,20 +1299,20 @@ function registerBonusAPIRoutes( bearerSessionTokenAuth, toExpressHandler( bonusController.getLatestBonusActivationById, - bonusController, - ), + bonusController + ) ); app.get( `${basePath}/bonus/vacanze/activations`, bearerSessionTokenAuth, - toExpressHandler(bonusController.getAllBonusActivations, bonusController), + toExpressHandler(bonusController.getAllBonusActivations, bonusController) ); app.post( `${basePath}/bonus/vacanze/activations`, bearerSessionTokenAuth, - constantExpressHandler(ResponseErrorDismissed), + constantExpressHandler(ResponseErrorDismissed) ); } @@ -1323,12 +1321,12 @@ function registerAuthenticationRoutes( app: Express, authBasePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { app.get( `${authBasePath}/user-identity`, bearerSessionTokenAuth, - toExpressHandler(getUserIdentity), + toExpressHandler(getUserIdentity) ); } @@ -1337,20 +1335,18 @@ function registerPNRoutes( pnBasePath: string, pnService: ReturnType, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ) { app.get( `${pnBasePath}/activation`, bearerSessionTokenAuth, - toExpressHandler(getPNActivationController(pnService.getPnActivation)), + toExpressHandler(getPNActivationController(pnService.getPnActivation)) ); app.post( `${pnBasePath}/activation`, bearerSessionTokenAuth, - toExpressHandler( - upsertPNActivationController(pnService.upsertPnActivation), - ), + toExpressHandler(upsertPNActivationController(pnService.upsertPnActivation)) ); } @@ -1360,11 +1356,11 @@ function registerPublicRoutes(app: Express): void { // The minimum app version that support this API const minAppVersion = getObjectFromPackageJson( "min_app_version", - VersionPerPlatform, + VersionPerPlatform ); const minAppVersionPagoPa = getObjectFromPackageJson( "min_app_version_pagopa", - VersionPerPlatform, + VersionPerPlatform ); app.get("/", (_, res) => { @@ -1378,14 +1374,14 @@ function registerPublicRoutes(app: Express): void { O.getOrElse(() => ({ android: "UNKNOWN", ios: "UNKNOWN", - })), + })) ), min_app_version_pagopa: pipe( minAppVersionPagoPa, O.getOrElse(() => ({ android: "UNKNOWN", ios: "UNKNOWN", - })), + })) ), version, }; @@ -1395,9 +1391,7 @@ function registerPublicRoutes(app: Express): void { // Liveness probe for Kubernetes. // @see // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-a-liveness-http-request - app.get("/ping", (_, res) => { - res.status(200).send("ok"); - }); + app.get("/ping", (_, res) => { res.status(200).send("ok") }); } // eslint-disable-next-line max-params @@ -1408,13 +1402,13 @@ function registerFirstLollipopConsumer( sessionStorage: ISessionStorage, firstLollipopConsumerClient: ReturnType, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { app.post( `${basePath}/sign`, bearerSessionTokenAuth, expressLollipopMiddleware(lollipopClient, sessionStorage), - toExpressHandler(firstLollipopSign(firstLollipopConsumerClient)), + toExpressHandler(firstLollipopSign(firstLollipopConsumerClient)) ); } @@ -1423,20 +1417,20 @@ function registerTrialSystemAPIRoutes( basePath: string, trialService: TrialService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const trialController: TrialController = new TrialController(trialService); app.post( `${basePath}/trials/:trialId/subscriptions`, bearerSessionTokenAuth, - toExpressHandler(trialController.createTrialSubscription, trialController), + toExpressHandler(trialController.createTrialSubscription, trialController) ); app.get( `${basePath}/trials/:trialId/subscriptions`, bearerSessionTokenAuth, - toExpressHandler(trialController.getTrialSubscription, trialController), + toExpressHandler(trialController.getTrialSubscription, trialController) ); } @@ -1445,14 +1439,14 @@ function registerIoWalletAPIRoutes( basePath: string, ioWalletService: IoWalletService, // eslint-disable-next-line @typescript-eslint/no-explicit-any - bearerSessionTokenAuth: any, + bearerSessionTokenAuth: any ): void { const ioWalletController = new IoWalletController(ioWalletService); app.get( `${basePath}/nonce`, bearerSessionTokenAuth, - toExpressHandler(ioWalletController.getNonce, ioWalletController), + toExpressHandler(ioWalletController.getNonce, ioWalletController) ); app.post( @@ -1460,8 +1454,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.createWalletInstance, - ioWalletController, - ), + ioWalletController + ) ); app.post( @@ -1469,8 +1463,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.createWalletAttestation, - ioWalletController, - ), + ioWalletController + ) ); // TODO SIW-1843 @@ -1479,8 +1473,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.setCurrentWalletInstanceStatus, - ioWalletController, - ), + ioWalletController + ) ); app.get( @@ -1488,8 +1482,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.getWalletInstanceStatus, - ioWalletController, - ), + ioWalletController + ) ); app.put( @@ -1497,8 +1491,8 @@ function registerIoWalletAPIRoutes( bearerSessionTokenAuth, toExpressHandler( ioWalletController.setWalletInstanceStatus, - ioWalletController, - ), + ioWalletController + ) ); } diff --git a/src/clients/api.ts b/src/clients/api.ts index ea4eec560..bbf7c2fb4 100644 --- a/src/clients/api.ts +++ b/src/clients/api.ts @@ -1,10 +1,10 @@ -import { Client, createClient } from "@pagopa/io-functions-app-sdk/client"; import nodeFetch from "node-fetch"; +import { Client, createClient } from "@pagopa/io-functions-app-sdk/client"; export function APIClient( baseUrl: string, token: string, - fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch, // TODO: customize fetch with timeout + fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch // TODO: customize fetch with timeout ): Client<"SubscriptionKey"> { return createClient<"SubscriptionKey">({ basePath: "", diff --git a/src/clients/app-messages.client.ts b/src/clients/app-messages.client.ts index 767b89b01..cbd4f21c4 100644 --- a/src/clients/app-messages.client.ts +++ b/src/clients/app-messages.client.ts @@ -1,12 +1,11 @@ import nodeFetch from "node-fetch"; - import { Client, createClient } from "../../generated/io-messages-api/client"; export function AppMessagesAPIClient( token: string, baseUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"SubscriptionKey"> { return createClient<"SubscriptionKey">({ basePath: "", diff --git a/src/clients/bonus.ts b/src/clients/bonus.ts index 676e86bc6..95d870c1a 100644 --- a/src/clients/bonus.ts +++ b/src/clients/bonus.ts @@ -1,11 +1,10 @@ import nodeFetch from "node-fetch"; - import { Client, createClient } from "../../generated/io-bonus-api/client"; export function BonusAPIClient( token: string, baseUrl: string, - fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch, + fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath: "", diff --git a/src/clients/cgn-operator-search.ts b/src/clients/cgn-operator-search.ts index 28bc3d666..0da466687 100644 --- a/src/clients/cgn-operator-search.ts +++ b/src/clients/cgn-operator-search.ts @@ -1,5 +1,4 @@ import nodeFetch from "node-fetch"; - import { Client, createClient, @@ -10,7 +9,7 @@ export function CgnOperatorSearchAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath, diff --git a/src/clients/cgn.ts b/src/clients/cgn.ts index 022c02894..598a00295 100644 --- a/src/clients/cgn.ts +++ b/src/clients/cgn.ts @@ -1,12 +1,12 @@ -import { Client, createClient } from "@pagopa/io-functions-cgn-sdk/client"; import nodeFetch from "node-fetch"; +import { Client, createClient } from "@pagopa/io-functions-cgn-sdk/client"; export function CgnAPIClient( token: string, baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath, diff --git a/src/clients/eucovidcert.client.ts b/src/clients/eucovidcert.client.ts index 981332090..2ce023073 100644 --- a/src/clients/eucovidcert.client.ts +++ b/src/clients/eucovidcert.client.ts @@ -1,14 +1,14 @@ +import nodeFetch from "node-fetch"; import { Client, createClient, } from "@pagopa/io-functions-eucovidcerts-sdk/client"; -import nodeFetch from "node-fetch"; export function EUCovidCertAPIClient( token: string, baseUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"ApiKey"> { return createClient<"ApiKey">({ basePath: "", diff --git a/src/clients/firstLollipopConsumer.ts b/src/clients/firstLollipopConsumer.ts index d962505b6..bcdc27ed5 100644 --- a/src/clients/firstLollipopConsumer.ts +++ b/src/clients/firstLollipopConsumer.ts @@ -1,8 +1,7 @@ import * as nodeFetch from "node-fetch"; - import { - Client, createClient, + Client, } from "../../generated/lollipop-first-consumer/client"; export function FirstLollipopConsumerClient( @@ -10,7 +9,7 @@ export function FirstLollipopConsumerClient( baseUrl: string, basePath?: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"ApiKeyAuth"> { return createClient<"ApiKeyAuth">({ basePath, diff --git a/src/clients/io-fims.ts b/src/clients/io-fims.ts index db0ef4023..023c62831 100644 --- a/src/clients/io-fims.ts +++ b/src/clients/io-fims.ts @@ -1,5 +1,4 @@ import nodeFetch from "node-fetch"; - import { Client, createClient } from "../../generated/io-fims-api/client"; export function IoFimsAPIClient( @@ -7,7 +6,7 @@ export function IoFimsAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"FunctionsKey"> { return createClient<"FunctionsKey">({ basePath, diff --git a/src/clients/io-sign.ts b/src/clients/io-sign.ts index 746e685ae..b76bf5e84 100644 --- a/src/clients/io-sign.ts +++ b/src/clients/io-sign.ts @@ -1,5 +1,4 @@ import nodeFetch from "node-fetch"; - import { Client, createClient } from "../../generated/io-sign-api/client"; export function IoSignAPIClient( @@ -7,7 +6,7 @@ export function IoSignAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"FunctionsKey"> { return createClient<"FunctionsKey">({ basePath, diff --git a/src/clients/io-wallet.ts b/src/clients/io-wallet.ts index dc5b8cca6..99e4885b5 100644 --- a/src/clients/io-wallet.ts +++ b/src/clients/io-wallet.ts @@ -2,14 +2,14 @@ import { Client, createClient } from "../../generated/io-wallet-api/client"; type Fetch = ( input: RequestInfo | URL, - init?: RequestInit | undefined, + init?: RequestInit | undefined ) => Promise; export function IoWalletAPIClient( token: string, basePath: string, baseUrl: string, - fetchApi: Fetch, + fetchApi: Fetch ): Client<"FunctionsKey"> { return createClient<"FunctionsKey">({ basePath, diff --git a/src/clients/lollipop.ts b/src/clients/lollipop.ts index 0b148a624..0a37d127e 100644 --- a/src/clients/lollipop.ts +++ b/src/clients/lollipop.ts @@ -1,5 +1,4 @@ import nodeFetch from "node-fetch"; - import { Client, createClient } from "../../generated/lollipop-api/client"; export function LollipopApiClient( @@ -7,7 +6,7 @@ export function LollipopApiClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"ApiKeyAuth"> { return createClient<"ApiKeyAuth">({ basePath, diff --git a/src/clients/pagopa.ts b/src/clients/pagopa.ts index 897bd31a1..8b991bc38 100644 --- a/src/clients/pagopa.ts +++ b/src/clients/pagopa.ts @@ -1,11 +1,10 @@ import nodeFetch from "node-fetch"; - import { Client, createClient } from "../../generated/pagopa-proxy/client"; export function PagoPAClient( baseUrl: string, apiKey: string, - fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch, + fetchApi: typeof fetch = nodeFetch as unknown as typeof fetch ): Client<"apiKeyHeader"> { return createClient<"apiKeyHeader">({ basePath: "", diff --git a/src/clients/pn-clients.ts b/src/clients/pn-clients.ts index 3eb9e5bd7..a97faddb2 100644 --- a/src/clients/pn-clients.ts +++ b/src/clients/pn-clients.ts @@ -1,6 +1,6 @@ -import { ValidUrl } from "@pagopa/ts-commons/lib/url"; import nodeFetch from "node-fetch"; - +import { ValidUrl } from "@pagopa/ts-commons/lib/url"; +import { stripTrailingSlashIfPresent } from "../utils/url"; import { Client, createClient, @@ -9,12 +9,11 @@ import { Client as AddressBookClient, createClient as createAddressBookClient, } from "../../generated/piattaforma-notifiche-courtesy/client"; -import { stripTrailingSlashIfPresent } from "../utils/url"; export function PnAPIClient( baseUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client { return createClient({ baseUrl, @@ -32,7 +31,7 @@ export const PnAddressBookIOClient = ( baseUrl: string, apiKey: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): AddressBookClient<"ApiKeyAuth"> => createAddressBookClient({ basePath: "", @@ -50,9 +49,9 @@ export type PnAddressBookIOClient = typeof PnAddressBookIOClient; * Available PN environments */ export enum PNEnvironment { - DEV = "DEV", PRODUCTION = "PRODUCTION", UAT = "UAT", + DEV = "DEV", } /** @@ -65,7 +64,7 @@ export const PNClientFactory = pnApiUrlUAT: ValidUrl, pnApiKeyUAT: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ) => (pnEnvironment: PNEnvironment) => { switch (pnEnvironment) { @@ -73,13 +72,13 @@ export const PNClientFactory = return PnAddressBookIOClient( stripTrailingSlashIfPresent(pnApiUrlProd), pnApiKeyProd, - fetchApi, + fetchApi ); case PNEnvironment.UAT: return PnAddressBookIOClient( stripTrailingSlashIfPresent(pnApiUrlUAT), pnApiKeyUAT, - fetchApi, + fetchApi ); default: throw new Error("Unimplemented PN Environment"); diff --git a/src/clients/services-app-backend.ts b/src/clients/services-app-backend.ts index 6bc591564..3c1e858a0 100644 --- a/src/clients/services-app-backend.ts +++ b/src/clients/services-app-backend.ts @@ -1,5 +1,4 @@ import nodeFetch from "node-fetch"; - import { Client, createClient, @@ -9,7 +8,7 @@ export function ServicesAppBackendAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client { return createClient({ basePath, diff --git a/src/clients/third-party-service-client.ts b/src/clients/third-party-service-client.ts index e8598e636..c3257f0c5 100644 --- a/src/clients/third-party-service-client.ts +++ b/src/clients/third-party-service-client.ts @@ -1,24 +1,25 @@ +import { pipe } from "fp-ts/lib/function"; + import { FiscalCode } from "@pagopa/io-functions-app-sdk/FiscalCode"; +import { LollipopLocalsType } from "src/types/lollipop"; import { eventLog } from "@pagopa/winston-ts"; -import { pipe } from "fp-ts/lib/function"; +import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; + import { RCAuthenticationConfig } from "generated/io-messages-api/RCAuthenticationConfig"; import { RCConfigurationProdEnvironment } from "generated/io-messages-api/RCConfigurationProdEnvironment"; -import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; import { RCConfigurationTestEnvironment } from "generated/io-messages-api/RCConfigurationTestEnvironment"; import { Ulid } from "generated/parameters/Ulid"; -import { LollipopLocalsType } from "src/types/lollipop"; - +import { pnFetch } from "../adapters/pnFetch"; import { Client, createClient, } from "../../generated/third-party-service/client"; -import { pnFetch } from "../adapters/pnFetch"; // --- export type Fetch = ( input: RequestInfo | URL, - init?: RequestInit | undefined, + init?: RequestInit | undefined ) => Promise; export type ThirdPartyServiceClient = typeof getThirdPartyServiceClient; @@ -64,7 +65,7 @@ const withPNFetch = environment: | RCConfigurationProdEnvironment | RCConfigurationTestEnvironment, - lollipopLocals?: LollipopLocalsType, + lollipopLocals?: LollipopLocalsType ) => (fetchApi: Fetch): Fetch => pnFetch( @@ -72,7 +73,7 @@ const withPNFetch = configurationId, environment.base_url, environment.details_authentication.key, - lollipopLocals, + lollipopLocals ) as Fetch; // ------------------ @@ -88,21 +89,21 @@ export const getThirdPartyServiceClient = ( remoteContentConfiguration: RCConfigurationPublic, fetchApi: Fetch, - maybeLollipopLocals?: LollipopLocalsType, + maybeLollipopLocals?: LollipopLocalsType ) => (fiscalCode: FiscalCode): Client<"fiscal_code"> => { const environment = remoteContentConfiguration.test_environment?.test_users.includes( - fiscalCode, + fiscalCode ) ? remoteContentConfiguration.test_environment - : (remoteContentConfiguration.prod_environment ?? + : remoteContentConfiguration.prod_environment ?? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - remoteContentConfiguration.test_environment!); + remoteContentConfiguration.test_environment!; eventLog.peek.info( remoteContentConfiguration.test_environment?.test_users.includes( - fiscalCode, + fiscalCode ) ? [ "Third party client pointing to test environment", @@ -111,11 +112,11 @@ export const getThirdPartyServiceClient = : [ "Third party client pointing to prod environment", { name: "lollipop.third-party.prod" }, - ], + ] ); eventLog.peek.info( remoteContentConfiguration.test_environment?.test_users.includes( - fiscalCode, + fiscalCode ) ? [ "Fiscal code included in testUsers", @@ -124,7 +125,7 @@ export const getThirdPartyServiceClient = : [ "Fiscal code not included in testUsers", { name: "lollipop.testUsers.fiscal-code" }, - ], + ] ); const fetchApiWithRedirectAndAuthentication = pipe( @@ -134,8 +135,8 @@ export const getThirdPartyServiceClient = withPNFetch( remoteContentConfiguration.configuration_id, environment, - maybeLollipopLocals, - ), + maybeLollipopLocals + ) ); return createClient<"fiscal_code">({ diff --git a/src/clients/trial-system.client.ts b/src/clients/trial-system.client.ts index 07bf7f996..9ac586555 100644 --- a/src/clients/trial-system.client.ts +++ b/src/clients/trial-system.client.ts @@ -1,5 +1,4 @@ import nodeFetch from "node-fetch"; - import { Client, createClient } from "../../generated/trial-system-api/client"; export function TrialSystemAPIClient( @@ -7,7 +6,7 @@ export function TrialSystemAPIClient( baseUrl: string, basePath: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ): Client<"ApiKeyAuth"> { return createClient<"ApiKeyAuth">({ basePath, diff --git a/src/config.ts b/src/config.ts index 773de69f2..75dc5223a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,50 +2,51 @@ * Defines services and register them to the Service Container. */ +import * as dotenv from "dotenv"; +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; +import * as t from "io-ts"; import { agent } from "@pagopa/ts-commons"; + import { getNodeEnvironmentFromProcessEnv } from "@pagopa/ts-commons/lib/environment"; +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; +import { HttpsUrlFromString, UrlFromString } from "@pagopa/ts-commons/lib/url"; + import { AbortableFetch, setFetchTimeout, toFetch, } from "@pagopa/ts-commons/lib/fetch"; -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { Millisecond } from "@pagopa/ts-commons/lib/units"; -import { HttpsUrlFromString, UrlFromString } from "@pagopa/ts-commons/lib/url"; -import * as dotenv from "dotenv"; -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; import { pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; - -import { AppMessagesAPIClient } from "./clients/app-messages.client"; -import { BonusAPIClient } from "./clients/bonus"; import { CgnAPIClient } from "./clients/cgn"; +import { log } from "./utils/logger"; +import urlTokenStrategy from "./strategies/urlTokenStrategy"; +import { getRequiredENVVar } from "./utils/container"; +import PagoPAClientFactory from "./services/pagoPAClientFactory"; +import ApiClientFactory from "./services/apiClientFactory"; +import { BonusAPIClient } from "./clients/bonus"; +import { decodeCIDRs } from "./utils/network"; import { CgnOperatorSearchAPIClient } from "./clients/cgn-operator-search"; +import { ServicesAppBackendAPIClient } from "./clients/services-app-backend"; import { EUCovidCertAPIClient } from "./clients/eucovidcert.client"; -import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; -import { IoFimsAPIClient } from "./clients/io-fims"; -import { IoSignAPIClient } from "./clients/io-sign"; -import { IoWalletAPIClient } from "./clients/io-wallet"; -import { LollipopApiClient } from "./clients/lollipop"; +import { ognlTypeFor } from "./utils/ognl"; +import { AppMessagesAPIClient } from "./clients/app-messages.client"; import { PNClientFactory } from "./clients/pn-clients"; -import { ServicesAppBackendAPIClient } from "./clients/services-app-backend"; -import { TrialSystemAPIClient } from "./clients/trial-system.client"; -import ApiClientFactory from "./services/apiClientFactory"; -import PagoPAClientFactory from "./services/pagoPAClientFactory"; -import urlTokenStrategy from "./strategies/urlTokenStrategy"; -import { getRequiredENVVar } from "./utils/container"; +import { IoSignAPIClient } from "./clients/io-sign"; import { FeatureFlag, FeatureFlagEnum, getIsUserEligibleForNewFeature, } from "./utils/featureFlag"; -import { log } from "./utils/logger"; -import { decodeCIDRs } from "./utils/network"; -import { ognlTypeFor } from "./utils/ognl"; import { CommaSeparatedListOf } from "./utils/separated-list"; +import { LollipopApiClient } from "./clients/lollipop"; +import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; +import { TrialSystemAPIClient } from "./clients/trial-system.client"; +import { IoWalletAPIClient } from "./clients/io-wallet"; +import { IoFimsAPIClient } from "./clients/io-fims"; // Without this, the environment variables loaded by dotenv aren't available in // this file. @@ -59,24 +60,24 @@ export const SERVER_PORT = process.env.PORT || DEFAULT_SERVER_PORT; export const ENV = getNodeEnvironmentFromProcessEnv(process.env); // Default cache control max-age value is 5 minutes -const DEFAULT_CACHE_MAX_AGE_SECONDS = "300"; +const DEFAULT_CACHE_MAX_AGE_SECONDS: string = "300"; // Resolve cache control default max-age value // @deprecated this value is not used anymore. export const CACHE_MAX_AGE_SECONDS: number = parseInt( process.env.CACHE_MAX_AGE_SECONDS || DEFAULT_CACHE_MAX_AGE_SECONDS, - 10, + 10 ); // Default cache control max-age value is 1 hour -const DEFAULT_CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS = "3600"; +const DEFAULT_CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS: string = "3600"; // Resolve cache control default max-age value // @deprecated this value is not used anymore. export const CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS: number = parseInt( process.env.CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS || DEFAULT_CGN_OPERATOR_SEARCH_CACHE_MAX_AGE_SECONDS, - 10, + 10 ); // IP(s) or CIDR(s) allowed for notification @@ -86,11 +87,11 @@ export const ALLOW_NOTIFY_IP_SOURCE_RANGE = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid ALLOW_NOTIFY_IP_SOURCE_RANGE environment variable: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); // IP(s) or CIDR(s) allowed for myportal endpoint @@ -100,11 +101,11 @@ export const ALLOW_MYPORTAL_IP_SOURCE_RANGE = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid ALLOW_MYPORTAL_IP_SOURCE_RANGE environment variable: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); // IP(s) or CIDR(s) allowed for handling sessions @@ -114,11 +115,11 @@ export const ALLOW_SESSION_HANDLER_IP_SOURCE_RANGE = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid ALLOW_SESSION_HANDLER_IP_SOURCE_RANGE environment variable: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); const DEFAULT_REQUEST_TIMEOUT_MS = 10000 as Millisecond; @@ -128,7 +129,7 @@ const DEFAULT_REQUEST_TIMEOUT_MS = 10000 as Millisecond; const abortableFetch = AbortableFetch(agent.getFetch(process.env)); const fetchWithTimeout = setFetchTimeout( DEFAULT_REQUEST_TIMEOUT_MS, - abortableFetch, + abortableFetch ); const httpOrHttpsApiFetch = toFetch(fetchWithTimeout); @@ -145,8 +146,8 @@ export const getHttpsApiFetchWithBearer = (bearer: string) => toFetch( setFetchTimeout( DEFAULT_REQUEST_TIMEOUT_MS, - AbortableFetch(bearerAuthFetch(httpOrHttpsApiFetch, bearer)), - ), + AbortableFetch(bearerAuthFetch(httpOrHttpsApiFetch, bearer)) + ) ); export const API_KEY = getRequiredENVVar("API_KEY"); @@ -155,7 +156,7 @@ export const API_BASE_PATH = getRequiredENVVar("API_BASE_PATH"); export const API_CLIENT = new ApiClientFactory( API_KEY, API_URL, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const APP_MESSAGES_API_KEY = getRequiredENVVar("APP_MESSAGES_API_KEY"); @@ -164,7 +165,7 @@ export const APP_MESSAGES_API_URL = getRequiredENVVar("APP_MESSAGES_API_URL"); export const APP_MESSAGES_API_CLIENT = AppMessagesAPIClient( APP_MESSAGES_API_KEY, APP_MESSAGES_API_URL, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const BONUS_API_KEY = getRequiredENVVar("BONUS_API_KEY"); @@ -173,7 +174,7 @@ export const BONUS_API_BASE_PATH = getRequiredENVVar("BONUS_API_BASE_PATH"); export const BONUS_API_CLIENT = BonusAPIClient( BONUS_API_KEY, BONUS_API_URL, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const IO_SIGN_API_KEY = getRequiredENVVar("IO_SIGN_API_KEY"); @@ -184,7 +185,7 @@ export const IO_SIGN_API_CLIENT = IoSignAPIClient( IO_SIGN_API_KEY, IO_SIGN_API_URL, IO_SIGN_API_BASE_PATH, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const IO_FIMS_API_KEY = getRequiredENVVar("IO_FIMS_API_KEY"); @@ -194,7 +195,7 @@ export const IO_FIMS_API_CLIENT = IoFimsAPIClient( IO_FIMS_API_KEY, IO_FIMS_API_URL, IO_FIMS_API_BASE_PATH, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const CGN_API_KEY = getRequiredENVVar("CGN_API_KEY"); @@ -204,73 +205,73 @@ export const CGN_API_CLIENT = CgnAPIClient( CGN_API_KEY, CGN_API_URL, CGN_API_BASE_PATH, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING", + "LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING" ); export const LOLLIPOP_REVOKE_QUEUE_NAME = getRequiredENVVar( - "LOLLIPOP_REVOKE_QUEUE_NAME", + "LOLLIPOP_REVOKE_QUEUE_NAME" ); export const LOLLIPOP_API_KEY = getRequiredENVVar("LOLLIPOP_API_KEY"); export const LOLLIPOP_API_URL = getRequiredENVVar("LOLLIPOP_API_URL"); export const LOLLIPOP_API_BASE_PATH = getRequiredENVVar( - "LOLLIPOP_API_BASE_PATH", + "LOLLIPOP_API_BASE_PATH" ); export const LOLLIPOP_API_CLIENT = LollipopApiClient( LOLLIPOP_API_KEY, LOLLIPOP_API_URL, LOLLIPOP_API_BASE_PATH, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const FIRST_LOLLIPOP_CONSUMER_CLIENT = FirstLollipopConsumerClient( // We access to the first lollipop consumer implementation that is now located // within the Lollipop function. LOLLIPOP_API_KEY, - LOLLIPOP_API_URL, + LOLLIPOP_API_URL ); export const CGN_OPERATOR_SEARCH_API_KEY = getRequiredENVVar( - "CGN_OPERATOR_SEARCH_API_KEY", + "CGN_OPERATOR_SEARCH_API_KEY" ); export const CGN_OPERATOR_SEARCH_API_URL = getRequiredENVVar( - "CGN_OPERATOR_SEARCH_API_URL", + "CGN_OPERATOR_SEARCH_API_URL" ); export const CGN_OPERATOR_SEARCH_API_BASE_PATH = getRequiredENVVar( - "CGN_OPERATOR_SEARCH_API_BASE_PATH", + "CGN_OPERATOR_SEARCH_API_BASE_PATH" ); export const CGN_OPERATOR_SEARCH_API_CLIENT = CgnOperatorSearchAPIClient( CGN_OPERATOR_SEARCH_API_KEY, CGN_OPERATOR_SEARCH_API_URL, CGN_OPERATOR_SEARCH_API_BASE_PATH, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const EUCOVIDCERT_API_KEY = getRequiredENVVar("EUCOVIDCERT_API_KEY"); export const EUCOVIDCERT_API_URL = getRequiredENVVar("EUCOVIDCERT_API_URL"); export const EUCOVIDCERT_API_BASE_PATH = getRequiredENVVar( - "EUCOVIDCERT_API_BASE_PATH", + "EUCOVIDCERT_API_BASE_PATH" ); export const EUCOVIDCERT_API_CLIENT = EUCovidCertAPIClient( EUCOVIDCERT_API_KEY, EUCOVIDCERT_API_URL, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const SERVICES_APP_BACKEND_API_BASE_PATH = getRequiredENVVar( - "SERVICES_APP_BACKEND_API_BASE_PATH", + "SERVICES_APP_BACKEND_API_BASE_PATH" ); export const SERVICES_APP_BACKEND_API_URL = getRequiredENVVar( - "SERVICES_APP_BACKEND_API_URL", + "SERVICES_APP_BACKEND_API_URL" ); // TODO: creare servicesAppBackend client export const SERVICES_APP_BACKEND_CLIENT = ServicesAppBackendAPIClient( SERVICES_APP_BACKEND_API_URL, SERVICES_APP_BACKEND_API_BASE_PATH, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); /** @@ -305,11 +306,11 @@ export const PNAddressBookConfig = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PN Address book configuration envs: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); export const PN_ADDRESS_BOOK_CLIENT_SELECTOR: O.Option< @@ -324,11 +325,11 @@ export const PN_ADDRESS_BOOK_CLIENT_SELECTOR: O.Option< pnConfig.PN_API_KEY, pnConfig.PN_API_URL_UAT, pnConfig.PN_API_KEY_UAT, - httpOrHttpsApiFetch, - ), - ), + httpOrHttpsApiFetch + ) + ) ), - E.toUnion, + E.toUnion ); // HTTPs-only fetch with optional keepalive agent @@ -345,18 +346,18 @@ export const PAGOPA_CLIENT = new PagoPAClientFactory( pagoPAApiKeyProd, pagoPAApiUrlTest, pagoPAApiKeyTest, - simpleHttpsApiFetch, + simpleHttpsApiFetch ); // API endpoint mount. export const AUTHENTICATION_BASE_PATH = getRequiredENVVar( - "AUTHENTICATION_BASE_PATH", + "AUTHENTICATION_BASE_PATH" ); export const MYPORTAL_BASE_PATH = getRequiredENVVar("MYPORTAL_BASE_PATH"); export const SERVICES_APP_BACKEND_BASE_PATH = getRequiredENVVar( - "SERVICES_APP_BACKEND_BASE_PATH", + "SERVICES_APP_BACKEND_BASE_PATH" ); // Token needed to receive API calls (notifications, metadata update) from io-functions-services @@ -367,18 +368,18 @@ export const URL_TOKEN_STRATEGY = urlTokenStrategy(PRE_SHARED_KEY); // Needed to forward push notifications actions events export const NOTIFICATIONS_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "NOTIFICATIONS_STORAGE_CONNECTION_STRING", + "NOTIFICATIONS_STORAGE_CONNECTION_STRING" ); export const NOTIFICATIONS_QUEUE_NAME = getRequiredENVVar( - "NOTIFICATIONS_QUEUE_NAME", + "NOTIFICATIONS_QUEUE_NAME" ); // Needed to forward push notifications actions events export const PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING", + "PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING" ); export const PUSH_NOTIFICATIONS_QUEUE_NAME = getRequiredENVVar( - "PUSH_NOTIFICATIONS_QUEUE_NAME", + "PUSH_NOTIFICATIONS_QUEUE_NAME" ); // Root redirect @@ -387,10 +388,10 @@ const DEFAULT_ROOT_REDIRECT_URL = pipe( HttpsUrlFromString.decode, E.getOrElseW((errs) => { log.error( - `Invalid DEFAULT_ROOT_REDIRECT_URL variable: ${readableReport(errs)}`, + `Invalid DEFAULT_ROOT_REDIRECT_URL variable: ${readableReport(errs)}` ); return process.exit(1); - }), + }) ); export const ROOT_REDIRECT_URL = pipe( @@ -400,18 +401,18 @@ export const ROOT_REDIRECT_URL = pipe( log.warn( `Missing or invalid ROOT_REDIRECT_URL variable, defaulting to "${ DEFAULT_ROOT_REDIRECT_URL.href - }": ${readableReport(errs)}`, + }": ${readableReport(errs)}` ); return DEFAULT_ROOT_REDIRECT_URL; - }), + }) ); // Needed to verify if a profile has been locked export const LOCKED_PROFILES_STORAGE_CONNECTION_STRING = getRequiredENVVar( - "LOCKED_PROFILES_STORAGE_CONNECTION_STRING", + "LOCKED_PROFILES_STORAGE_CONNECTION_STRING" ); export const LOCKED_PROFILES_TABLE_NAME = getRequiredENVVar( - "LOCKED_PROFILES_TABLE_NAME", + "LOCKED_PROFILES_TABLE_NAME" ); // Push notifications @@ -422,7 +423,7 @@ export const NOTIFICATION_DEFAULT_TITLE = "Hai un nuovo messaggio su IO"; export const BARCODE_ALGORITHM = pipe( process.env.BARCODE_ALGORITHM, NonEmptyString.decode, - E.getOrElse(() => "code128" as NonEmptyString), + E.getOrElse(() => "code128" as NonEmptyString) ); // Application insights sampling percentage @@ -441,9 +442,9 @@ export const TEST_CGN_FISCAL_CODES = pipe( CommaSeparatedListOf(FiscalCode).decode, E.getOrElseW((err) => { throw new Error( - `Invalid TEST_CGN_FISCAL_CODES value: ${readableReport(err)}`, + `Invalid TEST_CGN_FISCAL_CODES value: ${readableReport(err)}` ); - }), + }) ); // PEC SERVER config @@ -467,11 +468,11 @@ export const PECSERVERS = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PECSERVERS environment variable: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); // @@ -485,7 +486,7 @@ export const PECSERVERS = pipe( const IS_APPBACKENDLI = pipe( O.fromNullable(process.env.IS_APPBACKENDLI), O.map((val) => val.toLowerCase() === "true"), - O.getOrElse(() => false), + O.getOrElse(() => false) ); export const FF_ENABLE_NOTIFY_ENDPOINT = IS_APPBACKENDLI; @@ -498,11 +499,11 @@ export const PN_SERVICE_ID = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PN_SERVICE_ID environment variable: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); export const PN_CONFIGURATION_ID = pipe( @@ -511,17 +512,17 @@ export const PN_CONFIGURATION_ID = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid PN_CONFIGURATION_ID environment variable: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); export const FF_ROUTING_PUSH_NOTIF = pipe( process.env.FF_ROUTING_PUSH_NOTIF, FeatureFlag.decode, - E.getOrElse(() => FeatureFlagEnum.NONE), + E.getOrElse((_) => FeatureFlagEnum.NONE) ); export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( @@ -530,16 +531,16 @@ export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( E.getOrElseW((errs) => { log.error( `Missing or invalid FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST environment variable: ${readableReport( - errs, - )}`, + errs + )}` ); return process.exit(1); - }), + }) ); export const FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX = pipe( process.env.FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, NonEmptyString.decode, - E.getOrElse(() => "XYZ" as NonEmptyString), + E.getOrElse((_) => "XYZ" as NonEmptyString) ); // UNIQUE EMAIL ENFORCEMENT variables @@ -547,7 +548,7 @@ export const FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX = pipe( export const FF_UNIQUE_EMAIL_ENFORCEMENT = pipe( process.env.FF_UNIQUE_EMAIL_ENFORCEMENT, FeatureFlag.decode, - E.getOrElseW(() => FeatureFlagEnum.NONE), + E.getOrElseW(() => FeatureFlagEnum.NONE) ); export const UNIQUE_EMAIL_ENFORCEMENT_USERS = pipe( @@ -556,16 +557,16 @@ export const UNIQUE_EMAIL_ENFORCEMENT_USERS = pipe( CommaSeparatedListOf(FiscalCode).decode, E.getOrElseW((err) => { throw new Error( - `Invalid UNIQUE_EMAIL_ENFORCEMENT_USERS value: ${readableReport(err)}`, + `Invalid UNIQUE_EMAIL_ENFORCEMENT_USERS value: ${readableReport(err)}` ); - }), + }) ); export const FF_UNIQUE_EMAIL_ENFORCEMENT_ENABLED = getIsUserEligibleForNewFeature( (fiscalCode) => UNIQUE_EMAIL_ENFORCEMENT_USERS.includes(fiscalCode), () => false, - FF_UNIQUE_EMAIL_ENFORCEMENT, + FF_UNIQUE_EMAIL_ENFORCEMENT ); // ####### TRIAL_SYSTEM ######## @@ -573,30 +574,30 @@ export const FF_TRIAL_SYSTEM_ENABLED = process.env.FF_TRIAL_SYSTEM_ENABLED === "1"; export const TRIAL_SYSTEM_API_BASE_PATH = getRequiredENVVar( - "TRIAL_SYSTEM_API_BASE_PATH", + "TRIAL_SYSTEM_API_BASE_PATH" ); export const TRIAL_SYSTEM_API_KEY = getRequiredENVVar("TRIAL_SYSTEM_APIM_KEY"); export const TRIAL_SYSTEM_API_URL = getRequiredENVVar("TRIAL_SYSTEM_APIM_URL"); export const TRIAL_SYSTEM_APIM_BASE_PATH = getRequiredENVVar( - "TRIAL_SYSTEM_APIM_BASE_PATH", + "TRIAL_SYSTEM_APIM_BASE_PATH" ); export const TRIAL_SYSTEM_CLIENT = TrialSystemAPIClient( TRIAL_SYSTEM_API_KEY, TRIAL_SYSTEM_API_URL, - TRIAL_SYSTEM_APIM_BASE_PATH, + TRIAL_SYSTEM_APIM_BASE_PATH ); export const IO_WALLET_API_KEY = getRequiredENVVar("IO_WALLET_API_KEY"); export const IO_WALLET_API_URL = getRequiredENVVar("IO_WALLET_API_URL"); export const IO_WALLET_API_BASE_PATH = getRequiredENVVar( - "IO_WALLET_API_BASE_PATH", + "IO_WALLET_API_BASE_PATH" ); export const IO_WALLET_TRIAL_ID = getRequiredENVVar("IO_WALLET_TRIAL_ID"); export const IO_WALLET_API_CLIENT = IoWalletAPIClient( IO_WALLET_API_KEY, IO_WALLET_API_BASE_PATH, IO_WALLET_API_URL, - httpOrHttpsApiFetch, + httpOrHttpsApiFetch ); export const FF_IO_WALLET_ENABLED = process.env.FF_IO_WALLET_ENABLED === "1"; export const FF_IO_WALLET_TRIAL_ENABLED = diff --git a/src/controllers/authenticationController.ts b/src/controllers/authenticationController.ts index 7395b633f..c04076397 100644 --- a/src/controllers/authenticationController.ts +++ b/src/controllers/authenticationController.ts @@ -4,6 +4,8 @@ * the IDP. */ +import * as express from "express"; +import * as E from "fp-ts/lib/Either"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -11,39 +13,38 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; -import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; +import { pipe } from "fp-ts/lib/function"; import { UserIdentity } from "../../generated/auth/UserIdentity"; + import { exactUserIdentityDecode, withUserFromRequest } from "../types/user"; /** * Returns the user identity stored after the login process. */ export const getUserIdentity: ( - req: express.Request, + req: express.Request ) => Promise< - | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorInternal | IResponseSuccessJson > = (req) => withUserFromRequest(req, async (user) => pipe( user, UserIdentity.decode, - E.mapLeft(() => - ResponseErrorInternal("Unexpected User Identity data format."), + E.mapLeft((_) => + ResponseErrorInternal("Unexpected User Identity data format.") ), E.map((_) => pipe( _, exactUserIdentityDecode, - E.mapLeft(() => ResponseErrorInternal("Exact decode failed.")), + E.mapLeft((_1) => ResponseErrorInternal("Exact decode failed.")), E.map(ResponseSuccessJson), - E.toUnion, - ), + E.toUnion + ) ), - E.toUnion, - ), + E.toUnion + ) ); diff --git a/src/controllers/bonusController.ts b/src/controllers/bonusController.ts index 64bc07d7b..d01995359 100644 --- a/src/controllers/bonusController.ts +++ b/src/controllers/bonusController.ts @@ -3,6 +3,7 @@ * app by forwarding the call to the API system. */ +import * as express from "express"; import { IResponseErrorGone, IResponseErrorInternal, @@ -11,12 +12,11 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; + import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { PaginatedBonusActivationsCollection } from "generated/io-bonus-api/PaginatedBonusActivationsCollection"; +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import BonusService from "src/services/bonusService"; - import { EligibilityCheck } from "../../generated/io-bonus-api/EligibilityCheck"; import { InstanceId } from "../../generated/io-bonus-api/InstanceId"; import { withUserFromRequest } from "../types/user"; @@ -24,28 +24,15 @@ import { withValidatedOrValidationError } from "../utils/responses"; export const withBonusIdFromRequest = async ( req: express.Request, - f: (bonusId: NonEmptyString) => Promise, + f: (bonusId: NonEmptyString) => Promise ): Promise => withValidatedOrValidationError( NonEmptyString.decode(req.param("bonus_id")), - f, + f ); export default class BonusController { - /** - * Get all IDs of the bonus activations requested by - * the authenticated user or by any between his family member - */ - public readonly getAllBonusActivations = ( - req: express.Request, - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson - > => - withUserFromRequest(req, (user) => - this.bonusService.getAllBonusActivations(user), - ); + constructor(private readonly bonusService: BonusService) {} /** * Starts a request for a bonus for the current user. @@ -53,17 +40,17 @@ export default class BonusController { * */ public readonly getBonusEligibilityCheck = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorGone - | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorInternal | IResponseSuccessAccepted + | IResponseErrorGone | IResponseSuccessJson > => withUserFromRequest(req, (user) => - this.bonusService.getBonusEligibilityCheck(user), + this.bonusService.getBonusEligibilityCheck(user) ); /** @@ -72,19 +59,32 @@ export default class BonusController { * */ public readonly getLatestBonusActivationById = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorInternal | IResponseSuccessAccepted | IResponseSuccessJson > => withUserFromRequest(req, (user) => withBonusIdFromRequest(req, (bonusId) => - this.bonusService.getLatestBonusActivationById(user, bonusId), - ), + this.bonusService.getLatestBonusActivationById(user, bonusId) + ) ); - constructor(private readonly bonusService: BonusService) {} -} + /** + * Get all IDs of the bonus activations requested by + * the authenticated user or by any between his family member + */ + public readonly getAllBonusActivations = ( + req: express.Request + ): Promise< + | IResponseErrorValidation + | IResponseErrorInternal + | IResponseSuccessJson + > => + withUserFromRequest(req, (user) => + this.bonusService.getAllBonusActivations(user) + ); +} \ No newline at end of file diff --git a/src/controllers/cgnController.ts b/src/controllers/cgnController.ts index 2646afd2b..3901178fa 100644 --- a/src/controllers/cgnController.ts +++ b/src/controllers/cgnController.ts @@ -3,9 +3,7 @@ * app by forwarding the call to the API system. */ -import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; -import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; -import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; +import * as express from "express"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -17,19 +15,21 @@ import { IResponseSuccessRedirectToResource, ResponseErrorForbiddenNotAuthorized, } from "@pagopa/ts-commons/lib/responses"; + +import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; +import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; import { Otp } from "generated/cgn/Otp"; - +import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; import { Card } from "../../generated/cgn/Card"; -import { InstanceId } from "../../generated/cgn/InstanceId"; import CgnService from "../../src/services/cgnService"; +import { InstanceId } from "../../generated/cgn/InstanceId"; import { User, withUserFromRequest } from "../types/user"; export const withAllowedUser = async ( user: User, - allowedFiscalCodes: readonly FiscalCode[], - f: (user: User) => Promise, + allowedFiscalCodes: ReadonlyArray, + f: (user: User) => Promise ) => allowedFiscalCodes.length === 0 || allowedFiscalCodes.includes(user.fiscal_code) @@ -37,171 +37,171 @@ export const withAllowedUser = async ( : ResponseErrorForbiddenNotAuthorized; export default class CgnController { + constructor( + private readonly cgnService: CgnService, + private readonly allowedFiscalCodes: ReadonlyArray + ) {} + /** - * Generate a CGN OTP for the current user. + * Get the Cgn status for the current user. */ - public readonly generateOtp = ( - req: express.Request, + public readonly getCgnStatus = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.generateOtp, - ), + this.cgnService.getCgnStatus + ) ); /** - * Get Cgn activation's process status for the current user. + * Get the Eyca Card status for the current user. */ - public readonly getCgnActivation = ( - req: express.Request, + public readonly getEycaStatus = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getCgnActivation, - ), + this.cgnService.getEycaStatus + ) ); /** - * Get the Cgn status for the current user. + * Start a Cgn activation for the current user. */ - public readonly getCgnStatus = ( - req: express.Request, + public readonly startCgnActivation = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict + | IResponseSuccessRedirectToResource + | IResponseSuccessAccepted > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getCgnStatus, - ), + this.cgnService.startCgnActivation + ) ); /** - * Get EYCA card activation's process status for the current user. + * Get Cgn activation's process status for the current user. */ - public readonly getEycaActivation = ( - req: express.Request, + public readonly getCgnActivation = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getEycaActivation, - ), + this.cgnService.getCgnActivation + ) ); /** - * Get the Eyca Card status for the current user. + * Get EYCA card activation's process status for the current user. */ - public readonly getEycaStatus = ( - req: express.Request, + public readonly getEycaActivation = ( + req: express.Request ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.getEycaStatus, - ), + this.cgnService.getEycaActivation + ) ); /** - * Start a Cgn activation for the current user. + * Start an EYCA activation for the current user. */ - public readonly startCgnActivation = ( - req: express.Request, + public readonly startEycaActivation = ( + req: express.Request ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessAccepted + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict | IResponseSuccessRedirectToResource + | IResponseSuccessAccepted > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.startCgnActivation, - ), + this.cgnService.startEycaActivation + ) ); /** * Start a Cgn unsubscription for the current user. */ public readonly startCgnUnsubscription = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessAccepted + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict | IResponseSuccessRedirectToResource + | IResponseSuccessAccepted > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.startCgnUnsubscription, - ), + this.cgnService.startCgnUnsubscription + ) ); /** - * Start an EYCA activation for the current user. + * Generate a CGN OTP for the current user. */ - public readonly startEycaActivation = ( - req: express.Request, + public readonly generateOtp = ( + req: express.Request ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessAccepted - | IResponseSuccessRedirectToResource + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withUserFromRequest(req, (user) => withAllowedUser( user, this.allowedFiscalCodes, - this.cgnService.startEycaActivation, - ), + this.cgnService.generateOtp + ) ); - - constructor( - private readonly cgnService: CgnService, - private readonly allowedFiscalCodes: readonly FiscalCode[], - ) {} } diff --git a/src/controllers/cgnOperatorSearchController.ts b/src/controllers/cgnOperatorSearchController.ts index 1e4001d32..1dc446f30 100644 --- a/src/controllers/cgnOperatorSearchController.ts +++ b/src/controllers/cgnOperatorSearchController.ts @@ -4,6 +4,7 @@ */ import { IResponseErrorForbiddenNotAuthorized } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import { IResponse, IResponseErrorInternal, @@ -14,81 +15,61 @@ import { ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; +import CgnService from "src/services/cgnService"; import * as E from "fp-ts/Either"; -import { pipe } from "fp-ts/lib/function"; -import { Card } from "generated/cgn/Card"; -import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; +import { Card } from "generated/cgn/Card"; +import { pipe } from "fp-ts/lib/function"; import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; -import CgnService from "src/services/cgnService"; - +import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; import { Merchant } from "../../generated/cgn-operator-search/Merchant"; import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; +import { GetPublishedCategoriesParameters } from "../../generated/parameters/GetPublishedCategoriesParameters"; import { PublishedProductCategoriesResult } from "../../generated/cgn-operator-search/PublishedProductCategoriesResult"; import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; import { SearchRequest } from "../../generated/io-cgn-operator-search-api/SearchRequest"; -import { GetPublishedCategoriesParameters } from "../../generated/parameters/GetPublishedCategoriesParameters"; import CgnOperatorSearchService from "../services/cgnOperatorSearchService"; import { User, withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; export default class CgnOperatorSearchController { - private readonly eligibleUserOrError = async ( - user: User, - ): Promise< - E.Either< - IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, - string - > - > => { - const cgnStatusResponse = await this.cgnService.getCgnStatus(user); - - return pipe( - cgnStatusResponse, - E.fromPredicate(this.isCgnStatusResponseSuccess, () => - ResponseErrorInternal("Cannot retrieve cgn card status"), - ), - E.map((res) => res.value.status), - E.chainW( - E.fromPredicate( - (status) => status === "ACTIVATED", - () => ResponseErrorForbiddenNotAuthorized, - ), - ), - ); - }; - - private readonly isCgnStatusResponseSuccess = ( - res: IResponse, - ): res is IResponseSuccessJson => res.kind === "IResponseSuccessJson"; + constructor( + private readonly cgnService: CgnService, + private readonly cgnOperatorSearchService: CgnOperatorSearchService + ) {} /** - * Count CGN merchants/discounts + * Get an array of CGN product categories that have at least a published discount */ - public readonly count = ( - req: express.Request, + public readonly getPublishedProductCategories = ( + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => - withUserFromRequest(req, async () => this.cgnOperatorSearchService.count()); + withUserFromRequest(req, async (_) => + withValidatedOrValidationError( + GetPublishedCategoriesParameters.decode(req.query), + (params) => + this.cgnOperatorSearchService.getPublishedProductCategories(params) + ) + ); /** - * Get a discount bucket code by discount identifier. + * Get the CGN operator/merchant by its identifier. */ - public readonly getDiscountBucketCode = ( - req: express.Request, + public readonly getMerchant = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => { const eligibleUserOrErrorResult = await this.eligibleUserOrError(user); @@ -97,56 +78,42 @@ export default class CgnOperatorSearchController { } return withValidatedOrValidationError( - NonEmptyString.decode(req.params.discountId), - (discountId) => - this.cgnOperatorSearchService.getDiscountBucketCode(discountId), + NonEmptyString.decode(req.params.merchantId), + (merchantId) => this.cgnOperatorSearchService.getMerchant(merchantId) ); }); /** - * Get the CGN operator/merchant by its identifier. + * Count CGN merchants/discounts */ - public readonly getMerchant = ( - req: express.Request, + public readonly count = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => - withUserFromRequest(req, async (user) => { - const eligibleUserOrErrorResult = await this.eligibleUserOrError(user); - if (E.isLeft(eligibleUserOrErrorResult)) { - return eligibleUserOrErrorResult.left; - } - - return withValidatedOrValidationError( - NonEmptyString.decode(req.params.merchantId), - (merchantId) => this.cgnOperatorSearchService.getMerchant(merchantId), - ); - }); + withUserFromRequest(req, async (_) => + this.cgnOperatorSearchService.count() + ); /** - * Get an array of CGN offline merchants that matches with search criteria - * expressed in OfflineMerchantSearchRequest + * Search CGN merchants/discounts that matches with search criteria */ - public readonly getOfflineMerchants = ( - req: express.Request, + public readonly search = ( + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => - withUserFromRequest(req, async () => + withUserFromRequest(req, async (_) => withValidatedOrValidationError( - OfflineMerchantSearchRequest.decode(req.body), - (offlineSearchRequest) => - this.cgnOperatorSearchService.getOfflineMerchants( - offlineSearchRequest, - ), - ), + SearchRequest.decode(req.body), + (searchRequest) => this.cgnOperatorSearchService.search(searchRequest) + ) ); /** @@ -154,60 +121,94 @@ export default class CgnOperatorSearchController { * expressed in OnlineMerchantSearchRequest */ public readonly getOnlineMerchants = ( - req: express.Request, + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation | IResponseSuccessJson > => - withUserFromRequest(req, async () => + withUserFromRequest(req, async (_) => withValidatedOrValidationError( OnlineMerchantSearchRequest.decode(req.body), (onlineSearchRequest) => - this.cgnOperatorSearchService.getOnlineMerchants(onlineSearchRequest), - ), + this.cgnOperatorSearchService.getOnlineMerchants(onlineSearchRequest) + ) ); /** - * Get an array of CGN product categories that have at least a published discount + * Get an array of CGN offline merchants that matches with search criteria + * expressed in OfflineMerchantSearchRequest */ - public readonly getPublishedProductCategories = ( - req: express.Request, + public readonly getOfflineMerchants = ( + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => - withUserFromRequest(req, async () => + withUserFromRequest(req, async (_) => withValidatedOrValidationError( - GetPublishedCategoriesParameters.decode(req.query), - (params) => - this.cgnOperatorSearchService.getPublishedProductCategories(params), - ), + OfflineMerchantSearchRequest.decode(req.body), + (offlineSearchRequest) => + this.cgnOperatorSearchService.getOfflineMerchants( + offlineSearchRequest + ) + ) ); /** - * Search CGN merchants/discounts that matches with search criteria + * Get a discount bucket code by discount identifier. */ - public readonly search = ( - req: express.Request, + public readonly getDiscountBucketCode = ( + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => - withUserFromRequest(req, async () => - withValidatedOrValidationError( - SearchRequest.decode(req.body), - (searchRequest) => this.cgnOperatorSearchService.search(searchRequest), + withUserFromRequest(req, async (user) => { + const eligibleUserOrErrorResult = await this.eligibleUserOrError(user); + if (E.isLeft(eligibleUserOrErrorResult)) { + return eligibleUserOrErrorResult.left; + } + + return withValidatedOrValidationError( + NonEmptyString.decode(req.params.discountId), + (discountId) => + this.cgnOperatorSearchService.getDiscountBucketCode(discountId) + ); + }); + + private readonly isCgnStatusResponseSuccess = ( + res: IResponse + ): res is IResponseSuccessJson => res.kind === "IResponseSuccessJson"; + + private readonly eligibleUserOrError = async ( + user: User + ): Promise< + E.Either< + IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, + string + > + > => { + const cgnStatusResponse = await this.cgnService.getCgnStatus(user); + + return pipe( + cgnStatusResponse, + E.fromPredicate(this.isCgnStatusResponseSuccess, () => + ResponseErrorInternal("Cannot retrieve cgn card status") ), + E.map((res) => res.value.status), + E.chainW( + E.fromPredicate( + (status) => status === "ACTIVATED", + () => ResponseErrorForbiddenNotAuthorized + ) + ) ); - - constructor( - private readonly cgnService: CgnService, - private readonly cgnOperatorSearchService: CgnOperatorSearchService, - ) {} + }; } diff --git a/src/controllers/eucovidcertController.ts b/src/controllers/eucovidcertController.ts index 1bd7a7f65..35d0178eb 100644 --- a/src/controllers/eucovidcertController.ts +++ b/src/controllers/eucovidcertController.ts @@ -1,4 +1,5 @@ -import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; +import * as express from "express"; + import { IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, @@ -6,37 +7,36 @@ import { IResponseErrorValidation, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; +import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; import { GetCertificateParams } from "../../generated/eucovidcert/GetCertificateParams"; import { PreferredLanguages } from "../../generated/eucovidcert/PreferredLanguages"; +import { withValidatedOrValidationError } from "../utils/responses"; import EUCovidService from "../services/eucovidcertService"; import { withUserFromRequest } from "../types/user"; -import { withValidatedOrValidationError } from "../utils/responses"; export const withGetCertificateParams = async ( req: express.Request, - f: ( - auth_code: string, - preferred_languages?: PreferredLanguages, - ) => Promise, + f: (auth_code: string, preferred_languages?: PreferredLanguages) => Promise ) => withValidatedOrValidationError( GetCertificateParams.decode(req.body.accessData), - (val) => f(val.auth_code, val.preferred_languages), + (val) => f(val.auth_code, val.preferred_languages) ); export default class EUCovidCertController { + constructor(private readonly eucovidCertService: EUCovidService) {} + /** * Get the EU Covid Certificate for the current user. */ public readonly getEUCovidCertificate = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized | IResponseSuccessJson > => withUserFromRequest(req, (user) => @@ -44,10 +44,8 @@ export default class EUCovidCertController { this.eucovidCertService.getEUCovidCertificate( user, auth_code, - preferred_languages, - ), - ), + preferred_languages + ) + ) ); - - constructor(private readonly eucovidCertService: EUCovidService) {} } diff --git a/src/controllers/fimsController.ts b/src/controllers/fimsController.ts index e70ffe894..a4d918191 100644 --- a/src/controllers/fimsController.ts +++ b/src/controllers/fimsController.ts @@ -3,6 +3,10 @@ * app by forwarding the call to the API system. */ +import * as express from "express"; +import * as TE from "fp-ts/TaskEither"; +import * as t from "io-ts"; + import { IResponseErrorConflict, IResponseErrorInternal, @@ -11,17 +15,18 @@ import { IResponseSuccessJson, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; -import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; + import { pipe } from "fp-ts/lib/function"; +import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; + import { AccessHistoryPage } from "generated/io-fims/AccessHistoryPage"; import { ExportRequest } from "generated/io-fims/ExportRequest"; -import * as t from "io-ts"; import IoFimsService from "../services/fimsService"; -import ProfileService from "../services/profileService"; + import { withUserFromRequest } from "../types/user"; +import ProfileService from "../services/profileService"; + import { profileWithEmailValidatedOrError } from "../utils/profile"; const responseErrorInternal = (reason: string) => (e: Error) => @@ -38,14 +43,14 @@ const responseErrorInternal = (reason: string) => (e: Error) => const getAccessHistory = ( ioFimsService: IoFimsService, fiscalCode: FiscalCode, - page?: string, + page?: string ) => pipe( TE.tryCatch( () => ioFimsService.getAccessHistory(fiscalCode, page), - () => new Error("Error while fetching the access history"), + () => new Error("Error while fetching the access history") ), - TE.mapLeft(responseErrorInternal("Fetching error")), + TE.mapLeft(responseErrorInternal("Fetching error")) ); /** @@ -59,17 +64,28 @@ const getAccessHistory = ( const requestExport = ( ioFimsService: IoFimsService, fiscalCode: FiscalCode, - email: EmailString, + email: EmailString ) => pipe( TE.tryCatch( () => ioFimsService.requestExport(fiscalCode, email), - () => new Error("Error while requesting the export"), + () => new Error("Error while requesting the export") ), - TE.mapLeft(responseErrorInternal("Error while requesting the export")), + TE.mapLeft(responseErrorInternal("Error while requesting the export")) ); export default class IoFimsController { + /** + * Constructs an instance of IoFimsController. + * + * @param ioFimsService - The service responsible for FIMS operations. + * @param profileService - The service responsible for profile operations. + */ + constructor( + private readonly ioFimsService: IoFimsService, + private readonly profileService: ProfileService + ) {} + /** * Retrieves the access history for a user. * @@ -80,10 +96,10 @@ export default class IoFimsController { * - `IResponseSuccessJson` if the access history is successfully retrieved. */ public readonly getAccessHistory = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorInternal | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -92,10 +108,10 @@ export default class IoFimsController { TE.fromEither, TE.altW(() => TE.right(undefined)), TE.flatMap((page) => - getAccessHistory(this.ioFimsService, user.fiscal_code, page), + getAccessHistory(this.ioFimsService, user.fiscal_code, page) ), - TE.toUnion, - )(), + TE.toUnion + )() ); /** @@ -110,11 +126,11 @@ export default class IoFimsController { * - `IResponseSuccessAccepted` if the export request is accepted. */ public readonly requestExport = ( - req: express.Request, + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorValidation | IResponseSuccessAccepted > => withUserFromRequest(req, async (user) => @@ -122,24 +138,13 @@ export default class IoFimsController { profileWithEmailValidatedOrError(this.profileService, user), TE.mapLeft( responseErrorInternal( - "Error retrieving a user profile with validated email address", - ), + "Error retrieving a user profile with validated email address" + ) ), TE.flatMap((profile) => - requestExport(this.ioFimsService, profile.fiscal_code, profile.email), + requestExport(this.ioFimsService, profile.fiscal_code, profile.email) ), - TE.toUnion, - )(), + TE.toUnion + )() ); - - /** - * Constructs an instance of IoFimsController. - * - * @param ioFimsService - The service responsible for FIMS operations. - * @param profileService - The service responsible for profile operations. - */ - constructor( - private readonly ioFimsService: IoFimsService, - private readonly profileService: ProfileService, - ) {} } diff --git a/src/controllers/firstLollipopConsumerController.ts b/src/controllers/firstLollipopConsumerController.ts index 049e70167..b79dbe3e1 100644 --- a/src/controllers/firstLollipopConsumerController.ts +++ b/src/controllers/firstLollipopConsumerController.ts @@ -1,4 +1,3 @@ -import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -6,18 +5,20 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { pick } from "@pagopa/ts-commons/lib/types"; import * as express from "express"; -import * as E from "fp-ts/Either"; -import * as TE from "fp-ts/TaskEither"; import { flow, pipe } from "fp-ts/lib/function"; +import * as TE from "fp-ts/TaskEither"; +import * as E from "fp-ts/Either"; +import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import { pick } from "@pagopa/ts-commons/lib/types"; import { SignMessageResponse } from "../../generated/first-lc-proxy-models/SignMessageResponse"; -import { FirstLollipopConsumerClient } from "../clients/firstLollipopConsumer"; -import { withLollipopLocals, withRequiredRawBody } from "../types/lollipop"; + import { logLollipopSignRequest } from "../utils/appinsights"; +import { FirstLollipopConsumerClient } from "../clients/firstLollipopConsumer"; import { ResLocals } from "../utils/express"; +import { withLollipopLocals, withRequiredRawBody } from "../types/lollipop"; const FIRST_LOLLIPOP_CONSUMER_ID = "fist-lollipop-consumer" as NonEmptyString; @@ -25,10 +26,10 @@ export const firstLollipopSign = (client: ReturnType) => async ( req: express.Request, - locals?: T, + locals?: T ): Promise< - | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorInternal | IResponseSuccessJson > => pipe( @@ -43,41 +44,41 @@ export const firstLollipopSign = client.signMessage({ ...localsWithBody, }), - () => ResponseErrorInternal("Error calling the Lollipop Consumer"), + () => ResponseErrorInternal("Error calling the Lollipop Consumer") ), TE.chainFirstW( flow( E.map((res) => pick(["status"], res)), E.mapLeft( - flow(readableReportSimplified, (message) => new Error(message)), + flow(readableReportSimplified, (message) => new Error(message)) ), logLollipopSignRequest(FIRST_LOLLIPOP_CONSUMER_ID)( localsWithBody, - req, + req ), - TE.of, - ), - ), - ), + TE.of + ) + ) + ) ), TE.chainEitherKW( E.mapLeft( flow(readableReportSimplified, (message) => ResponseErrorInternal( - `Unexpected Lollipop consumer response: ${message}`, - ), - ), - ), + `Unexpected Lollipop consumer response: ${message}` + ) + ) + ) ), TE.chain((response) => response.status === 200 ? TE.right(response.value) : TE.left( ResponseErrorInternal( - `signMessage returned ${response.status}: ${response.value?.title},${response.value?.detail}`, - ), - ), + `signMessage returned ${response.status}: ${response.value?.title},${response.value?.detail}` + ) + ) ), TE.map((lcResponse) => ResponseSuccessJson(lcResponse)), - TE.toUnion, + TE.toUnion )(); diff --git a/src/controllers/ioSignController.ts b/src/controllers/ioSignController.ts index 5ee800466..8b71d5bbf 100644 --- a/src/controllers/ioSignController.ts +++ b/src/controllers/ioSignController.ts @@ -3,7 +3,12 @@ * app by forwarding the call to the API system. */ -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import * as express from "express"; +import * as TE from "fp-ts/TaskEither"; +import * as E from "fp-ts/Either"; +import * as t from "io-ts"; +import { sequenceS } from "fp-ts/lib/Apply"; + import { IResponseErrorInternal, IResponseErrorNotFound, @@ -13,43 +18,42 @@ import { ResponseErrorInternal, ResponseErrorValidation, } from "@pagopa/ts-commons/lib/responses"; -import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; -import * as E from "fp-ts/Either"; -import * as TE from "fp-ts/TaskEither"; -import { sequenceS } from "fp-ts/lib/Apply"; + import { pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; +import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { Errors } from "io-ts"; - -import { CreateFilledDocument } from "../../generated/io-sign/CreateFilledDocument"; -import { CreateSignatureBody } from "../../generated/io-sign/CreateSignatureBody"; -import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; -import { Id } from "../../generated/io-sign/Id"; +import { + withValidatedOrValidationError, + withCatchAsInternalError, +} from "../utils/responses"; import { IssuerEnvironment, IssuerEnvironmentEnum, } from "../../generated/io-sign/IssuerEnvironment"; +import IoSignService from "../services/ioSignService"; +import { ResLocals } from "../utils/express"; +import { LollipopLocalsType, withLollipopLocals } from "../types/lollipop"; +import { Id } from "../../generated/io-sign/Id"; import { QtspClausesMetadataDetailView } from "../../generated/io-sign/QtspClausesMetadataDetailView"; import { SignatureDetailView } from "../../generated/io-sign/SignatureDetailView"; import { SignatureRequestDetailView } from "../../generated/io-sign/SignatureRequestDetailView"; -import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; -import IoSignService from "../services/ioSignService"; -import ProfileService from "../services/profileService"; -import { LollipopLocalsType, withLollipopLocals } from "../types/lollipop"; +import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; +import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; + +import { CreateFilledDocument } from "../../generated/io-sign/CreateFilledDocument"; +import { CreateSignatureBody } from "../../generated/io-sign/CreateSignatureBody"; + import { withUserFromRequest } from "../types/user"; -import { ResLocals } from "../utils/express"; +import ProfileService from "../services/profileService"; + import { profileWithEmailValidatedOrError } from "../utils/profile"; -import { - withCatchAsInternalError, - withValidatedOrValidationError, -} from "../utils/responses"; const responseErrorValidation = (errs: Errors) => ResponseErrorValidation( "Bad request", - errorsToReadableMessages(errs).join(" / "), + errorsToReadableMessages(errs).join(" / ") ); export const IoSignLollipopLocalsType = t.intersection([ @@ -66,7 +70,7 @@ export type IoSignLollipopLocalsType = t.TypeOf< export const withIoSignCustomLollipopLocalsFromRequest = (req: express.Request) => ( - lollipopLocals: LollipopLocalsType, + lollipopLocals: LollipopLocalsType ): E.Either => pipe( { @@ -77,24 +81,24 @@ export const withIoSignCustomLollipopLocalsFromRequest = req.headers["x-pagopa-lollipop-custom-tos-challenge"], }, IoSignLollipopLocalsType.decode, - E.mapLeft(responseErrorValidation), + E.mapLeft(responseErrorValidation) ); const responseErrorInternal = (reason: string) => (e: Error) => ResponseErrorInternal(`${reason} | ${e.message}`); const toErrorRetrievingTheSignerId = ResponseErrorInternal( - `Error retrieving the signer id for this user`, + `Error retrieving the signer id for this user` ); export const retrieveSignerId = ( ioSignService: IoSignService, - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ) => pipe( TE.tryCatch( () => ioSignService.getSignerByFiscalCode(fiscalCode), - E.toError, + E.toError ), TE.chain( TE.fromPredicate( @@ -103,25 +107,30 @@ export const retrieveSignerId = ( (e) => e.kind === "IResponseErrorNotFound" ? new Error( - `Your profile is not enabled to use this service. | ${e.detail}`, + `Your profile is not enabled to use this service. | ${e.detail}` ) : new Error( - `An error occurred while retrieving the signer id. | ${e.detail}`, - ), - ), - ), + `An error occurred while retrieving the signer id. | ${e.detail}` + ) + ) + ) ); export default class IoSignController { + constructor( + private readonly ioSignService: IoSignService, + private readonly profileService: ProfileService + ) {} + /** * Given the url of a PDF document with empty fields, * fill in the PDF form and return the url of the filled document. */ public readonly createFilledDocument = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessRedirectToResource< FilledDocumentDetailView, FilledDocumentDetailView @@ -138,30 +147,30 @@ export default class IoSignController { sequenceS(TE.ApplySeq)({ signerId: pipe( retrieveSignerId(this.ioSignService, user.fiscal_code), - TE.mapLeft(() => toErrorRetrievingTheSignerId), + TE.mapLeft(() => toErrorRetrievingTheSignerId) ), userProfile: pipe( profileWithEmailValidatedOrError(this.profileService, user), TE.mapLeft( responseErrorInternal( - "Error retrieving a user profile with validated email address", - ), - ), + "Error retrieving a user profile with validated email address" + ) + ) ), }), - TE.map(({ signerId, userProfile }) => + TE.map(({ userProfile, signerId }) => this.ioSignService.createFilledDocument( body.document_url, userProfile.email, user.family_name as NonEmptyString, user.name as NonEmptyString, - signerId.value.id, - ), - ), - ), + signerId.value.id + ) + ) + ) ), - TE.toUnion, - )(), + TE.toUnion + )() ); /** @@ -169,11 +178,11 @@ export default class IoSignController { */ public readonly createSignature = async ( req: express.Request, - locals?: T, + locals?: T ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessJson > => withUserFromRequest(req, (user) => @@ -190,15 +199,15 @@ export default class IoSignController { sequenceS(TE.ApplySeq)({ signerId: pipe( retrieveSignerId(this.ioSignService, user.fiscal_code), - TE.mapLeft(() => toErrorRetrievingTheSignerId), + TE.mapLeft(() => toErrorRetrievingTheSignerId) ), userProfile: pipe( profileWithEmailValidatedOrError(this.profileService, user), TE.mapLeft( responseErrorInternal( - "Error retrieving a user profile with validated email address", - ), - ), + "Error retrieving a user profile with validated email address" + ) + ) ), }), TE.chainW(({ signerId, userProfile }) => @@ -213,49 +222,31 @@ export default class IoSignController { email: userProfile.email, }, signerId: signerId.value.id, - })), - ), + })) + ) ), - TE.map(({ body, signerId }) => + TE.map(({ signerId, body }) => this.ioSignService.createSignature( ioSignLollipopLocals, body, - signerId, - ), - ), - ), - ), - TE.toUnion, - )(), - ); - - public readonly getQtspClausesMetadata = ( - req: express.Request, - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => - withValidatedOrValidationError( - IssuerEnvironment.decode( - "x-iosign-issuer-environment" in req.headers - ? req.headers["x-iosign-issuer-environment"] - : IssuerEnvironmentEnum.TEST, + signerId + ) + ) + ) ), - this.ioSignService.getQtspClausesMetadata, - ), + TE.toUnion + )() ); /** * Get a Signature Request from id */ public readonly getSignatureRequest = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -265,34 +256,32 @@ export default class IoSignController { req.params.id, Id.decode, TE.fromEither, - TE.mapLeft(() => - ResponseErrorInternal( - `Error validating the signature request id`, - ), - ), + TE.mapLeft((_) => + ResponseErrorInternal(`Error validating the signature request id`) + ) ), signerId: pipe( retrieveSignerId(this.ioSignService, user.fiscal_code), TE.mapLeft(() => toErrorRetrievingTheSignerId), - TE.map((response) => response.value.id), + TE.map((response) => response.value.id) ), }), - TE.map(({ signatureRequestId: id, signerId }) => - this.ioSignService.getSignatureRequest(id, signerId), + TE.map(({ signerId, signatureRequestId: id }) => + this.ioSignService.getSignatureRequest(id, signerId) ), - TE.toUnion, - )(), + TE.toUnion + )() ); /** * Get Signature Requests list from Signer */ public readonly getSignatureRequests = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -301,12 +290,25 @@ export default class IoSignController { TE.mapLeft(() => toErrorRetrievingTheSignerId), TE.map((response) => response.value.id), TE.map((signerId) => this.ioSignService.getSignatureRequests(signerId)), - TE.toUnion, - )(), + TE.toUnion + )() ); - constructor( - private readonly ioSignService: IoSignService, - private readonly profileService: ProfileService, - ) {} + public readonly getQtspClausesMetadata = ( + req: express.Request + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => + withValidatedOrValidationError( + IssuerEnvironment.decode( + "x-iosign-issuer-environment" in req.headers + ? req.headers["x-iosign-issuer-environment"] + : IssuerEnvironmentEnum.TEST + ), + this.ioSignService.getQtspClausesMetadata + ) + ); } diff --git a/src/controllers/ioWalletController.ts b/src/controllers/ioWalletController.ts index c3ec7d5c1..a0c64bdb0 100644 --- a/src/controllers/ioWalletController.ts +++ b/src/controllers/ioWalletController.ts @@ -3,8 +3,12 @@ * app by forwarding the call to the API system. */ -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; +import * as express from "express"; +import * as TE from "fp-ts/TaskEither"; +import * as E from "fp-ts/Either"; + import { + getResponseErrorForbiddenNotAuthorized, IResponseErrorForbiddenNotAuthorized, IResponseErrorGeneric, IResponseErrorInternal, @@ -14,113 +18,54 @@ import { IResponseSuccessJson, IResponseSuccessNoContent, ResponseErrorValidation, - getResponseErrorForbiddenNotAuthorized, } from "@pagopa/ts-commons/lib/responses"; -import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; -import * as E from "fp-ts/Either"; -import * as TE from "fp-ts/TaskEither"; -import { sequenceS } from "fp-ts/lib/Apply"; + import { pipe } from "fp-ts/lib/function"; +import { sequenceS } from "fp-ts/lib/Apply"; import { Errors } from "io-ts"; +import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; +import IoWalletService from "../services/ioWalletService"; -import { CreateWalletAttestationBody } from "../../generated/io-wallet/CreateWalletAttestationBody"; -import { CreateWalletInstanceBody } from "../../generated/io-wallet/CreateWalletInstanceBody"; import { NonceDetailView } from "../../generated/io-wallet/NonceDetailView"; -import { SetWalletInstanceStatusBody } from "../../generated/io-wallet/SetWalletInstanceStatusBody"; +import { withUserFromRequest } from "../types/user"; +import { CreateWalletInstanceBody } from "../../generated/io-wallet/CreateWalletInstanceBody"; +import { CreateWalletAttestationBody } from "../../generated/io-wallet/CreateWalletAttestationBody"; import { WalletAttestationView } from "../../generated/io-wallet/WalletAttestationView"; -import { WalletInstanceData } from "../../generated/io-wallet/WalletInstanceData"; import { FF_IO_WALLET_TRIAL_ENABLED } from "../config"; -import IoWalletService from "../services/ioWalletService"; -import { withUserFromRequest } from "../types/user"; +import { SetWalletInstanceStatusBody } from "../../generated/io-wallet/SetWalletInstanceStatusBody"; +import { WalletInstanceData } from "../../generated/io-wallet/WalletInstanceData"; const toValidationError = (errors: Errors) => ResponseErrorValidation( "Bad request", - `Error validating the request body: ${readableReport(errors)}`, + `Error validating the request body: ${readableReport(errors)}` ); export default class IoWalletController { - private readonly ensureFiscalCodeIsAllowed = (fiscalCode: FiscalCode) => - FF_IO_WALLET_TRIAL_ENABLED - ? pipe( - fiscalCode, - NonEmptyString.decode, - TE.fromEither, - TE.chainW(this.ensureUserIsAllowed), - TE.mapLeft(() => - getResponseErrorForbiddenNotAuthorized( - "Not authorized to perform this action", - ), - ), - ) - : TE.right(undefined); - - private readonly ensureUserIsAllowed = ( - userId: NonEmptyString, - ): TE.TaskEither => - pipe( - TE.tryCatch( - () => this.ioWalletService.getSubscription(userId), - E.toError, - ), - // if a successful response with state != "ACTIVE" or an error is returned, return left - TE.chain((response) => - response.kind === "IResponseSuccessJson" && - response.value.state === "ACTIVE" - ? TE.right(undefined) - : TE.left(new Error()), - ), - ); + constructor(private readonly ioWalletService: IoWalletService) {} /** - * Create a Wallet Attestation + * Get nonce */ - public readonly createWalletAttestation = ( - req: express.Request, - ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorGeneric + public readonly getNonce = (): Promise< | IResponseErrorInternal - | IResponseErrorNotFound + | IResponseSuccessJson | IResponseErrorServiceUnavailable - | IResponseErrorValidation - | IResponseSuccessJson - > => - withUserFromRequest(req, async (user) => - pipe( - this.ensureFiscalCodeIsAllowed(user.fiscal_code), - TE.chainW(() => - pipe( - req.body, - CreateWalletAttestationBody.decode, - E.mapLeft(toValidationError), - TE.fromEither, - ), - ), - TE.map(({ assertion, grant_type }) => - this.ioWalletService.createWalletAttestation( - assertion, - grant_type, - user.fiscal_code, - ), - ), - TE.toUnion, - )(), - ); + > => this.ioWalletService.getNonce(); /** * Create a Wallet Instance */ public readonly createWalletInstance = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorGeneric | IResponseErrorInternal - | IResponseErrorServiceUnavailable + | IResponseErrorGeneric | IResponseErrorValidation | IResponseSuccessNoContent + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorServiceUnavailable > => withUserFromRequest(req, async (user) => pipe( @@ -130,75 +75,111 @@ export default class IoWalletController { req.body, CreateWalletInstanceBody.decode, E.mapLeft(toValidationError), - TE.fromEither, - ), + TE.fromEither + ) ), - TE.map(({ challenge, hardware_key_tag, key_attestation }) => + TE.map(({ challenge, key_attestation, hardware_key_tag }) => this.ioWalletService.createWalletInstance( challenge, hardware_key_tag, key_attestation, - user.fiscal_code, - ), + user.fiscal_code + ) ), - TE.toUnion, - )(), + TE.toUnion + )() ); /** - * Get nonce + * Create a Wallet Attestation */ - public readonly getNonce = (): Promise< + public readonly createWalletAttestation = ( + req: express.Request + ): Promise< | IResponseErrorInternal + | IResponseErrorGeneric + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson + | IResponseErrorNotFound | IResponseErrorServiceUnavailable - | IResponseSuccessJson - > => this.ioWalletService.getNonce(); + > => + withUserFromRequest(req, async (user) => + pipe( + this.ensureFiscalCodeIsAllowed(user.fiscal_code), + TE.chainW(() => + pipe( + req.body, + CreateWalletAttestationBody.decode, + E.mapLeft(toValidationError), + TE.fromEither + ) + ), + TE.map(({ grant_type, assertion }) => + this.ioWalletService.createWalletAttestation( + assertion, + grant_type, + user.fiscal_code + ) + ), + TE.toUnion + )() + ); /** - * Get current Wallet Instance status. + * Update current Wallet Instance status. */ - public readonly getWalletInstanceStatus = ( - req: express.Request, + public readonly setWalletInstanceStatus = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound + | IResponseSuccessNoContent | IResponseErrorServiceUnavailable | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorForbiddenNotAuthorized > => withUserFromRequest(req, async (user) => pipe( this.ensureFiscalCodeIsAllowed(user.fiscal_code), TE.chainW(() => pipe( - NonEmptyString.decode(req.params.walletInstanceId), - E.mapLeft(toValidationError), - TE.fromEither, - ), + sequenceS(E.Apply)({ + body: pipe( + req.body, + SetWalletInstanceStatusBody.decode, + E.mapLeft(toValidationError) + ), + id: pipe( + NonEmptyString.decode(req.params.walletInstanceId), + E.mapLeft(toValidationError) + ), + }), + TE.fromEither + ) ), - TE.map((walletInstanceId) => - this.ioWalletService.getWalletInstanceStatus( - walletInstanceId, - user.fiscal_code, - ), + TE.map(({ id, body: { status } }) => + this.ioWalletService.setWalletInstanceStatus( + id, + status, + user.fiscal_code + ) ), - TE.toUnion, - )(), + TE.toUnion + )() ); /** * Update current Wallet Instance status. */ public readonly setCurrentWalletInstanceStatus = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorGeneric | IResponseErrorInternal + | IResponseErrorGeneric + | IResponseSuccessNoContent | IResponseErrorServiceUnavailable | IResponseErrorValidation - | IResponseSuccessNoContent + | IResponseErrorForbiddenNotAuthorized > => withUserFromRequest(req, async (user) => pipe( @@ -208,60 +189,81 @@ export default class IoWalletController { req.body, SetWalletInstanceStatusBody.decode, E.mapLeft(toValidationError), - TE.fromEither, - ), + TE.fromEither + ) ), TE.map(({ status }) => this.ioWalletService.setCurrentWalletInstanceStatus( status, - user.fiscal_code, - ), + user.fiscal_code + ) ), - TE.toUnion, - )(), + TE.toUnion + )() ); /** - * Update current Wallet Instance status. + * Get current Wallet Instance status. */ - public readonly setWalletInstanceStatus = ( - req: express.Request, + public readonly getWalletInstanceStatus = ( + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseSuccessJson + | IResponseErrorNotFound | IResponseErrorServiceUnavailable | IResponseErrorValidation - | IResponseSuccessNoContent + | IResponseErrorForbiddenNotAuthorized > => withUserFromRequest(req, async (user) => pipe( this.ensureFiscalCodeIsAllowed(user.fiscal_code), TE.chainW(() => pipe( - sequenceS(E.Apply)({ - body: pipe( - req.body, - SetWalletInstanceStatusBody.decode, - E.mapLeft(toValidationError), - ), - id: pipe( - NonEmptyString.decode(req.params.walletInstanceId), - E.mapLeft(toValidationError), - ), - }), - TE.fromEither, - ), + NonEmptyString.decode(req.params.walletInstanceId), + E.mapLeft(toValidationError), + TE.fromEither + ) ), - TE.map(({ body: { status }, id }) => - this.ioWalletService.setWalletInstanceStatus( - id, - status, - user.fiscal_code, - ), + TE.map((walletInstanceId) => + this.ioWalletService.getWalletInstanceStatus( + walletInstanceId, + user.fiscal_code + ) ), - TE.toUnion, - )(), + TE.toUnion + )() ); - constructor(private readonly ioWalletService: IoWalletService) {} + private readonly ensureUserIsAllowed = ( + userId: NonEmptyString + ): TE.TaskEither => + pipe( + TE.tryCatch( + () => this.ioWalletService.getSubscription(userId), + E.toError + ), + // if a successful response with state != "ACTIVE" or an error is returned, return left + TE.chain((response) => + response.kind === "IResponseSuccessJson" && + response.value.state === "ACTIVE" + ? TE.right(undefined) + : TE.left(new Error()) + ) + ); + + private readonly ensureFiscalCodeIsAllowed = (fiscalCode: FiscalCode) => + FF_IO_WALLET_TRIAL_ENABLED + ? pipe( + fiscalCode, + NonEmptyString.decode, + TE.fromEither, + TE.chainW(this.ensureUserIsAllowed), + TE.mapLeft(() => + getResponseErrorForbiddenNotAuthorized( + "Not authorized to perform this action" + ) + ) + ) + : TE.right(undefined); } diff --git a/src/controllers/messagesController.ts b/src/controllers/messagesController.ts index af07c7850..338b8f633 100644 --- a/src/controllers/messagesController.ts +++ b/src/controllers/messagesController.ts @@ -3,7 +3,7 @@ * forwarding the call to the API system. */ -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import * as express from "express"; import { IResponseErrorBadGateway, IResponseErrorInternal, @@ -14,66 +14,147 @@ import { IResponseSuccessJson, IResponseSuccessNoContent, } from "@pagopa/ts-commons/lib/responses"; + +import { CreatedMessageWithContentAndAttachments } from "generated/backend/CreatedMessageWithContentAndAttachments"; import { IResponseErrorForbiddenNotAuthorized, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; -import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; -import * as E from "fp-ts/Either"; +import * as t from "io-ts"; +import { pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/TaskEither"; +import * as E from "fp-ts/Either"; import * as B from "fp-ts/boolean"; -import { pipe } from "fp-ts/lib/function"; -import { CreatedMessageWithContentAndAttachments } from "generated/backend/CreatedMessageWithContentAndAttachments"; -import * as t from "io-ts"; -import * as QueryString from "qs"; +import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; import NewMessagesService from "src/services/newMessagesService"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import * as QueryString from "qs"; +import { User, withUserFromRequest } from "../types/user"; -import { PaginatedPublicMessagesCollection } from "../../generated/backend/PaginatedPublicMessagesCollection"; -import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; -import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; -import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; +import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; +import { PaginatedPublicMessagesCollection } from "../../generated/backend/PaginatedPublicMessagesCollection"; import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; -import { LollipopApiClient } from "../clients/lollipop"; -import { ISessionStorage } from "../services/ISessionStorage"; -import { LollipopLocalsType, LollipopRequiredHeaders } from "../types/lollipop"; -import { User, withUserFromRequest } from "../types/user"; -import { extractLollipopLocalsFromLollipopHeadersLegacy } from "../utils/lollipop"; -import { checkIfLollipopIsEnabled } from "../utils/lollipop"; +import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; +import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; import { + withValidatedOrValidationError, + IResponseSuccessOctet, IResponseErrorNotImplemented, IResponseErrorUnsupportedMediaType, - IResponseSuccessOctet, - withValidatedOrValidationError, } from "../utils/responses"; +import { LollipopLocalsType, LollipopRequiredHeaders } from "../types/lollipop"; +import { LollipopApiClient } from "../clients/lollipop"; +import { ISessionStorage } from "../services/ISessionStorage"; +import { extractLollipopLocalsFromLollipopHeadersLegacy } from "../utils/lollipop"; +import { checkIfLollipopIsEnabled } from "../utils/lollipop"; export const withGetThirdPartyAttachmentParams = async ( req: express.Request, - f: (id: Ulid, attachment_url: NonEmptyString) => Promise, + f: (id: Ulid, attachment_url: NonEmptyString) => Promise ) => withValidatedOrValidationError(Ulid.decode(req.params.id), (id) => withValidatedOrValidationError( pipe( QueryString.stringify(req.query, { addQueryPrefix: true }), (queryString) => `${req.params.attachment_url}${queryString}`, - NonEmptyString.decode, + NonEmptyString.decode ), - (attachment_url) => f(id, attachment_url), - ), + (attachment_url) => f(id, attachment_url) + ) ); export default class MessagesController { + // eslint-disable-next-line max-params + constructor( + private readonly messageService: NewMessagesService, + private readonly lollipopClient: ReturnType, + private readonly sessionStorage: ISessionStorage + ) {} + + /** + * Returns the messages for the user identified by the provided fiscal code. + */ + public readonly getMessagesByUser = ( + req: express.Request + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseSuccessJson + > => + withUserFromRequest(req, async (user) => + withValidatedOrValidationError( + GetMessagesParameters.decode({ + /* eslint-disable sort-keys */ + pageSize: req.query.page_size, + enrichResultData: req.query.enrich_result_data, + getArchivedMessages: req.query.archived, + maximumId: req.query.maximum_id, + minimumId: req.query.minimum_id, + /* eslint-enable sort-keys */ + }), + (params) => this.messageService.getMessagesByUser(user, params) + ) + ); + + /** + * Returns the message identified by the message id. + */ + public readonly getMessage = ( + req: express.Request + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseSuccessJson + > => + withUserFromRequest(req, async (user) => + withValidatedOrValidationError( + GetMessageParameters.decode({ + id: req.params.id, + public_message: req.query.public_message, + }), + (params) => this.messageService.getMessage(user, params) + ) + ); + + public readonly upsertMessageStatus = ( + req: express.Request + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorTooManyRequests + | IResponseSuccessJson + > => + withUserFromRequest(req, async (user) => + withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => + withValidatedOrValidationError( + MessageStatusChange.decode(req.body), + (change) => + this.messageService.upsertMessageStatus( + user.fiscal_code, + messageId, + change + ) + ) + ) + ); + public readonly checkLollipopAndGetLocalsOrDefault = ( req: express.Request, user: User, - messageId: Ulid, + messageId: Ulid ) => pipe( this.messageService.getThirdPartyMessageFnApp( user.fiscal_code, - messageId, + messageId ), TE.bindTo("message"), TE.bindW("remoteContentConfiguration", ({ message }) => @@ -81,16 +162,16 @@ export default class MessagesController { message.content.third_party_data.configuration_id, TE.fromNullable( ResponseErrorInternal( - "ConfigurationId missing in ThirdPartyData, cannot get remote content configuration", - ), + "ConfigurationId missing in ThirdPartyData, cannot get remote content configuration" + ) ), TE.chain((configId) => - this.messageService.getRCConfiguration(configId), - ), - ), + this.messageService.getRCConfiguration(configId) + ) + ) ), TE.bindW("hasLollipopEnabled", ({ remoteContentConfiguration }) => - checkIfLollipopIsEnabled(user.fiscal_code, remoteContentConfiguration), + checkIfLollipopIsEnabled(user.fiscal_code, remoteContentConfiguration) ), TE.bindW("lollipopLocals", ({ hasLollipopEnabled }) => pipe( @@ -104,8 +185,8 @@ export default class MessagesController { (e) => TE.left( ResponseErrorInternal( - `Bad request ${errorsToReadableMessages(e).join(" / ")}`, - ), + `Bad request ${errorsToReadableMessages(e).join(" / ")}` + ) ), (lollipopHeaders) => pipe( @@ -113,212 +194,132 @@ export default class MessagesController { this.lollipopClient, this.sessionStorage, user.fiscal_code, - lollipopHeaders, + lollipopHeaders ), - TE.mapLeft(() => + TE.mapLeft((_) => ResponseErrorInternal( - "Error extracting lollipop locals", - ), - ), - ), - ), - ), - ), - ), - ), + "Error extracting lollipop locals" + ) + ) + ) + ) + ) + ) + ) + ) ); /** - * Returns the message identified by the message id. + * Returns the precondition for the required third party message. */ - public readonly getMessage = ( - req: express.Request, + public readonly getThirdPartyMessagePrecondition = async ( + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests | IResponseErrorValidation - | IResponseSuccessJson - > => - withUserFromRequest(req, async (user) => - withValidatedOrValidationError( - GetMessageParameters.decode({ - id: req.params.id, - public_message: req.query.public_message, - }), - (params) => this.messageService.getMessage(user, params), - ), - ); - - /** - * Returns the messages for the user identified by the provided fiscal code. - */ - public readonly getMessagesByUser = ( - req: express.Request, - ): Promise< - | IResponseErrorInternal + | IResponseErrorForbiddenNotAuthorized | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessNoContent + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => - withValidatedOrValidationError( - GetMessagesParameters.decode({ - enrichResultData: req.query.enrich_result_data, - getArchivedMessages: req.query.archived, - maximumId: req.query.maximum_id, - minimumId: req.query.minimum_id, - /* eslint-disable sort-keys */ - pageSize: req.query.page_size, - /* eslint-enable sort-keys */ - }), - (params) => this.messageService.getMessagesByUser(user, params), - ), + withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => + pipe( + this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), + TE.chainW(({ message, lollipopLocals, remoteContentConfiguration }) => + TE.tryCatch( + () => + this.messageService.getThirdPartyMessagePrecondition( + message, + remoteContentConfiguration, + lollipopLocals as LollipopLocalsType + ), + (_) => + ResponseErrorInternal( + "Error getting preconditions from third party service" + ) + ) + ), + TE.toUnion + )() + ) ); /** * Returns the Third Party message identified by the message id. */ public readonly getThirdPartyMessage = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorBadGateway - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation + | IResponseErrorBadGateway | IResponseSuccessJson > => withUserFromRequest(req, async (user) => withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => pipe( this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), - TE.chainW(({ lollipopLocals, message, remoteContentConfiguration }) => + TE.chainW(({ message, lollipopLocals, remoteContentConfiguration }) => TE.tryCatch( () => this.messageService.getThirdPartyMessage( message, remoteContentConfiguration, - lollipopLocals as LollipopLocalsType, + lollipopLocals as LollipopLocalsType ), - () => + (_) => ResponseErrorInternal( - "Error getting message from third party service", - ), - ), + "Error getting message from third party service" + ) + ) ), - TE.toUnion, - )(), - ), + TE.toUnion + )() + ) ); /** * Returns the Third Party message attachments identified by the Third Party message id and the attachment relative url. */ public readonly getThirdPartyMessageAttachment = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorNotImplemented | IResponseErrorServiceUnavailable + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorNotFound | IResponseErrorTooManyRequests + | IResponseErrorNotImplemented | IResponseErrorUnsupportedMediaType - | IResponseErrorValidation | IResponseSuccessOctet > => withUserFromRequest(req, (user) => withGetThirdPartyAttachmentParams(req, async (messageId, attachmentUrl) => pipe( this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), - TE.chainW(({ lollipopLocals, message, remoteContentConfiguration }) => + TE.chainW(({ message, lollipopLocals, remoteContentConfiguration }) => TE.tryCatch( () => this.messageService.getThirdPartyAttachment( message, attachmentUrl, remoteContentConfiguration, - lollipopLocals as LollipopLocalsType, - ), - () => - ResponseErrorInternal( - "Error getting attachment from third party service", - ), - ), - ), - TE.toUnion, - )(), - ), - ); - - /** - * Returns the precondition for the required third party message. - */ - public readonly getThirdPartyMessagePrecondition = async ( - req: express.Request, - ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessJson - | IResponseSuccessNoContent - > => - withUserFromRequest(req, async (user) => - withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => - pipe( - this.checkLollipopAndGetLocalsOrDefault(req, user, messageId), - TE.chainW(({ lollipopLocals, message, remoteContentConfiguration }) => - TE.tryCatch( - () => - this.messageService.getThirdPartyMessagePrecondition( - message, - remoteContentConfiguration, - lollipopLocals as LollipopLocalsType, + lollipopLocals as LollipopLocalsType ), - () => + (_) => ResponseErrorInternal( - "Error getting preconditions from third party service", - ), - ), + "Error getting attachment from third party service" + ) + ) ), - TE.toUnion, - )(), - ), + TE.toUnion + )() + ) ); - - public readonly upsertMessageStatus = ( - req: express.Request, - ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessJson - > => - withUserFromRequest(req, async (user) => - withValidatedOrValidationError(Ulid.decode(req.params.id), (messageId) => - withValidatedOrValidationError( - MessageStatusChange.decode(req.body), - (change) => - this.messageService.upsertMessageStatus( - user.fiscal_code, - messageId, - change, - ), - ), - ), - ); - - // eslint-disable-next-line max-params - constructor( - private readonly messageService: NewMessagesService, - private readonly lollipopClient: ReturnType, - private readonly sessionStorage: ISessionStorage, - ) {} } diff --git a/src/controllers/notificationController.ts b/src/controllers/notificationController.ts index 028f2159a..d884957d1 100644 --- a/src/controllers/notificationController.ts +++ b/src/controllers/notificationController.ts @@ -2,23 +2,25 @@ * This controller handles webhook requests from the API backend. */ +import * as express from "express"; import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { Millisecond } from "@pagopa/ts-commons/lib/units"; -import * as express from "express"; + import * as E from "fp-ts/lib/Either"; import * as TE from "fp-ts/lib/TaskEither"; +import { Millisecond } from "@pagopa/ts-commons/lib/units"; import { pipe } from "fp-ts/lib/function"; import { NotificationServiceFactory } from "src/services/notificationServiceFactory"; - import { Installation } from "../../generated/backend/Installation"; import { InstallationID } from "../../generated/backend/InstallationID"; + import { Notification } from "../../generated/notifications/Notification"; import { SuccessResponse } from "../../generated/notifications/SuccessResponse"; + import RedisSessionStorage from "../services/redisSessionStorage"; import { withUserFromRequest } from "../types/user"; import { log } from "../utils/logger"; @@ -35,8 +37,14 @@ export interface INotificationControllerOptions { } export default class NotificationController { + constructor( + private readonly notificationServiceFactory: NotificationServiceFactory, + private readonly sessionStorage: RedisSessionStorage, + private readonly opts: INotificationControllerOptions + ) {} + public readonly notify = async ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -50,9 +58,9 @@ export default class NotificationController { TE.tryCatch( () => this.sessionStorage.userHasActiveSessionsOrLV( - data.message.fiscal_code, + data.message.fiscal_code ), - E.toError, + E.toError ), TE.chain(TE.fromEither), TE.map(async (userHasActiveSessions) => @@ -60,62 +68,58 @@ export default class NotificationController { ? // send the full message only if the user has an // active session and the message content is defined await this.notificationServiceFactory( - data.message.fiscal_code, + data.message.fiscal_code ).notify(data, data.message.content.subject) : // send a generic message // if the user does not have an active session // or the message content is not defined await this.notificationServiceFactory( - data.message.fiscal_code, + data.message.fiscal_code ).notify( data, this.opts.notificationDefaultSubject, - this.opts.notificationDefaultTitle, - ), + this.opts.notificationDefaultTitle + ) ), TE.getOrElse((error) => { throw error; - }), - )(), - ), + }) + )() + ) ); - constructor( - private readonly notificationServiceFactory: NotificationServiceFactory, - private readonly sessionStorage: RedisSessionStorage, - private readonly opts: INotificationControllerOptions, - ) {} - public async createOrUpdateInstallation( - req: express.Request, + req: express.Request ): Promise> { return withUserFromRequest(req, async (user) => - withValidatedOrValidationError(InstallationID.decode(req.params.id), () => - withValidatedOrValidationError( - Installation.decode(req.body), - (installation) => { - // async fire & forget - // On login, we do a deleteInstallation to prevent a device to be associated with a previous user, which might be a different one - // We have empirical evidence that such deleteInstallation is processed after the createOrUpdateInstallation, - // so that the installation we are recording after login is lost - // The correct order of execution must be enforced by the processing notifications service. - // Anyway, to quickly mitigate the disservice to our users, we apply this temporary workaround - delay(10000 as Millisecond) - .then(() => - this.notificationServiceFactory( - user.fiscal_code, - ).createOrUpdateInstallation(user.fiscal_code, installation), - ) - .catch((err) => { - log.error( - "Cannot create installation: %s", - JSON.stringify(err), - ); - }); - return ResponseSuccessJson({ message: "ok" }); - }, - ), - ), + withValidatedOrValidationError( + InstallationID.decode(req.params.id), + (_) => + withValidatedOrValidationError( + Installation.decode(req.body), + (installation) => { + // async fire & forget + // On login, we do a deleteInstallation to prevent a device to be associated with a previous user, which might be a different one + // We have empirical evidence that such deleteInstallation is processed after the createOrUpdateInstallation, + // so that the installation we are recording after login is lost + // The correct order of execution must be enforced by the processing notifications service. + // Anyway, to quickly mitigate the disservice to our users, we apply this temporary workaround + delay(10000 as Millisecond) + .then(() => + this.notificationServiceFactory( + user.fiscal_code + ).createOrUpdateInstallation(user.fiscal_code, installation) + ) + .catch((err) => { + log.error( + "Cannot create installation: %s", + JSON.stringify(err) + ); + }); + return ResponseSuccessJson({ message: "ok" }); + } + ) + ) ); } } diff --git a/src/controllers/pagoPAProxyController.ts b/src/controllers/pagoPAProxyController.ts index 84544de6d..2de10c2bb 100644 --- a/src/controllers/pagoPAProxyController.ts +++ b/src/controllers/pagoPAProxyController.ts @@ -1,17 +1,19 @@ +import * as express from "express"; +import * as t from "io-ts"; import { IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; -import * as t from "io-ts"; + +import PagoPAProxyService from "../services/pagoPAProxyService"; import { PaymentActivationsGetResponse } from "../../generated/backend/PaymentActivationsGetResponse"; import { PaymentActivationsPostResponse } from "../../generated/backend/PaymentActivationsPostResponse"; import { PaymentRequestsGetResponse } from "../../generated/backend/PaymentRequestsGetResponse"; import { PaymentActivationsPostRequest } from "../../generated/pagopa-proxy/PaymentActivationsPostRequest"; -import PagoPAProxyService from "../services/pagoPAProxyService"; + import { withValidatedOrInternalError } from "../utils/responses"; const parsePagopaTestParam = (testParam: unknown) => @@ -22,12 +24,28 @@ const parsePagopaTestParam = (testParam: unknown) => */ export default class PagoPAProxyController { + constructor(private readonly pagoPAProxyService: PagoPAProxyService) {} + + public readonly getPaymentInfo = async ( + req: express.Request + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson + > => + withValidatedOrInternalError(t.string.decode(req.params.rptId), (rptId) => + this.pagoPAProxyService.getPaymentInfo( + rptId, + parsePagopaTestParam(req.query.test) + ) + ); + public readonly activatePayment = async ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessJson > => withValidatedOrInternalError( @@ -35,16 +53,16 @@ export default class PagoPAProxyController { (paymentActivationsPostRequest) => this.pagoPAProxyService.activatePayment( paymentActivationsPostRequest, - parsePagopaTestParam(req.query.test), - ), + parsePagopaTestParam(req.query.test) + ) ); public readonly getActivationStatus = async ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessJson > => withValidatedOrInternalError( @@ -52,23 +70,7 @@ export default class PagoPAProxyController { (codiceContestoPagamento) => this.pagoPAProxyService.getActivationStatus( codiceContestoPagamento, - parsePagopaTestParam(req.query.test), - ), + parsePagopaTestParam(req.query.test) + ) ); - - public readonly getPaymentInfo = async ( - req: express.Request, - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson - > => - withValidatedOrInternalError(t.string.decode(req.params.rptId), (rptId) => - this.pagoPAProxyService.getPaymentInfo( - rptId, - parsePagopaTestParam(req.query.test), - ), - ); - - constructor(private readonly pagoPAProxyService: PagoPAProxyService) {} } diff --git a/src/controllers/pnController.ts b/src/controllers/pnController.ts index 6ebf6c724..6d73c0a1f 100644 --- a/src/controllers/pnController.ts +++ b/src/controllers/pnController.ts @@ -6,20 +6,19 @@ import { ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; +import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; -import * as TE from "fp-ts/TaskEither"; import { pipe } from "fp-ts/lib/function"; - -import { PNActivation } from "../../generated/api_piattaforma-notifiche-courtesy/PNActivation"; import { PNEnvironment } from "../clients/pn-clients"; -import { PNService } from "../services/pnService"; import { withUserFromRequest } from "../types/user"; import { IResponseNoContent, ResponseNoContent, withValidatedOrValidationError, } from "../utils/responses"; +import { PNActivation } from "../../generated/api_piattaforma-notifiche-courtesy/PNActivation"; +import { PNService } from "../services/pnService"; /** * Upsert the Activation for `Avvisi di Cortesia` Piattaforma Notifiche @@ -28,9 +27,9 @@ import { export const upsertPNActivationController = (upsertPnActivation: ReturnType["upsertPnActivation"]) => ( - req: express.Request, + req: express.Request ): Promise< - IResponseErrorInternal | IResponseErrorValidation | IResponseNoContent + IResponseErrorValidation | IResponseErrorInternal | IResponseNoContent > => withUserFromRequest(req, async (user) => withValidatedOrValidationError(PNActivation.decode(req.body), (payload) => @@ -40,7 +39,7 @@ export const upsertPNActivationController = O.getOrElse(() => false), TE.of, TE.map((isTest) => - isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION, + isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION ), TE.chainW((pnEnvironment) => pipe( @@ -49,14 +48,14 @@ export const upsertPNActivationController = upsertPnActivation(pnEnvironment, user.fiscal_code, { activationStatus: payload.activation_status, }), - () => ResponseErrorInternal("Error calling the PN service"), + () => ResponseErrorInternal("Error calling the PN service") ), TE.chainEitherKW( E.mapLeft(() => - ResponseErrorInternal("Unexpected PN service response"), - ), - ), - ), + ResponseErrorInternal("Unexpected PN service response") + ) + ) + ) ), TE.map((_) => { switch (_.status) { @@ -64,24 +63,24 @@ export const upsertPNActivationController = return ResponseNoContent(); case 400: return ResponseErrorInternal( - "PN service response is bad request", + "PN service response is bad request" ); default: return ResponseErrorInternal("Unexpected response status code"); } }), - TE.toUnion, - )(), - ), + TE.toUnion + )() + ) ); export const getPNActivationController = (getPnActivation: ReturnType["getPnActivation"]) => ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorInternal | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -91,20 +90,20 @@ export const getPNActivationController = O.getOrElse(() => false), TE.of, TE.map((isTest) => - isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION, + isTest ? PNEnvironment.UAT : PNEnvironment.PRODUCTION ), TE.chainW((pnEnvironment) => pipe( TE.tryCatch( () => getPnActivation(pnEnvironment, user.fiscal_code), - () => ResponseErrorInternal("Error calling the PN service"), + () => ResponseErrorInternal("Error calling the PN service") ), TE.chainEitherKW( E.mapLeft(() => - ResponseErrorInternal("Unexpected PN service response"), - ), - ), - ), + ResponseErrorInternal("Unexpected PN service response") + ) + ) + ) ), TE.map((pnActivationResponse) => { switch (pnActivationResponse.status) { @@ -120,12 +119,12 @@ export const getPNActivationController = }); case 400: return ResponseErrorInternal( - "PN service response is bad request", + "PN service response is bad request" ); default: return ResponseErrorInternal("Unexpected response status code"); } }), - TE.toUnion, - )(), + TE.toUnion + )() ); diff --git a/src/controllers/profileController.ts b/src/controllers/profileController.ts index e9386fd66..d579b7701 100644 --- a/src/controllers/profileController.ts +++ b/src/controllers/profileController.ts @@ -3,7 +3,7 @@ * app by forwarding the call to the API system. */ -import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; +import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -14,42 +14,33 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; import { ISessionStorage } from "src/services/ISessionStorage"; +import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { Profile } from "../../generated/backend/Profile"; + import ProfileService from "../services/profileService"; import { profileMissingErrorResponse } from "../types/profile"; import { withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; export default class ProfileController { - /** - * Returns the profile for the user identified by the provided fiscal - * code stored into the API. - */ - public readonly getApiProfile = ( - req: express.Request, - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessJson - > => - withUserFromRequest(req, (user) => this.profileService.getApiProfile(user)); + constructor( + private readonly profileService: ProfileService, + private readonly sessionStorage: ISessionStorage + ) {} /** * Returns the profile for the user identified by the provided fiscal * code. */ public readonly getProfile = ( - req: express.Request, + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorInternal | IResponseErrorTooManyRequests - | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => { @@ -60,34 +51,33 @@ export default class ProfileController { }); /** - * Send an email to start the email validation process + * Returns the profile for the user identified by the provided fiscal + * code stored into the API. */ - public readonly startEmailValidationProcess = ( - req: express.Request, + public readonly getApiProfile = ( + req: express.Request ): Promise< + | IResponseErrorValidation | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessAccepted + | IResponseErrorNotFound + | IResponseSuccessJson > => - withUserFromRequest(req, async (user) => - this.profileService.emailValidationProcess(user), - ); + withUserFromRequest(req, (user) => this.profileService.getApiProfile(user)); /** * Update the preferences for the user identified by the provided * fiscal code. */ public readonly updateProfile = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorConflict - | IResponseErrorInternal + | IResponseErrorValidation | IResponseErrorNotFound - | IResponseErrorPreconditionFailed + | IResponseErrorInternal + | IResponseErrorConflict | IResponseErrorTooManyRequests - | IResponseErrorValidation + | IResponseErrorPreconditionFailed | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -96,12 +86,23 @@ export default class ProfileController { async (extendedProfile) => { await this.sessionStorage.delPagoPaNoticeEmail(user); return this.profileService.updateProfile(user, extendedProfile); - }, - ), + } + ) ); - constructor( - private readonly profileService: ProfileService, - private readonly sessionStorage: ISessionStorage, - ) {} + /** + * Send an email to start the email validation process + */ + public readonly startEmailValidationProcess = ( + req: express.Request + ): Promise< + | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorInternal + | IResponseErrorTooManyRequests + | IResponseSuccessAccepted + > => + withUserFromRequest(req, async (user) => + this.profileService.emailValidationProcess(user) + ); } diff --git a/src/controllers/serviceAppBackendController.ts b/src/controllers/serviceAppBackendController.ts index 572bf5216..d9cfbc869 100644 --- a/src/controllers/serviceAppBackendController.ts +++ b/src/controllers/serviceAppBackendController.ts @@ -7,12 +7,11 @@ import { import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; import * as E from "fp-ts/lib/Either"; -import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; - +import * as O from "fp-ts/lib/Option"; import { FeaturedServices } from "../../generated/services-app-backend/FeaturedServices"; -import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; import { Institutions } from "../../generated/services-app-backend/Institutions"; +import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; import { InstitutionsResource } from "../../generated/services-app-backend/InstitutionsResource"; import { ScopeType } from "../../generated/services-app-backend/ScopeType"; import { ServiceDetails } from "../../generated/services-app-backend/ServiceDetails"; @@ -29,8 +28,12 @@ const parseOptionalNumberParam = (numberParam?: unknown) => numberParam ? Number(numberParam) : undefined; export default class ServicesAppBackendController { + constructor( + private readonly servicesAppBackendService: ServicesAppBackendService + ) {} + public readonly findInstitutions = async ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -42,60 +45,54 @@ export default class ServicesAppBackendController { O.fromNullable, O.foldW( () => E.right(undefined), - (scope) => ScopeType.decode(scope), - ), + (scope) => ScopeType.decode(scope) + ) ), (scope) => this.servicesAppBackendService.findInstitutions( parseOptionalStringParam(req.query.search), scope, parseOptionalNumberParam(req.query.limit), - parseOptionalNumberParam(req.query.offset), - ), + parseOptionalNumberParam(req.query.offset) + ) ); - public readonly findInstutionServices = async ( - req: express.Request, + public readonly getServiceById = async ( + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseSuccessJson > => withValidatedOrInternalError( - NonEmptyString.decode(req.params.institutionId), - (institutionId) => - this.servicesAppBackendService.findInstutionServices( - institutionId, - parseOptionalNumberParam(req.query.limit), - parseOptionalNumberParam(req.query.offset), - ), + NonEmptyString.decode(req.params.serviceId), + (serviceId) => this.servicesAppBackendService.getServiceById(serviceId) ); - public readonly getFeaturedInstitutions = async ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _req: express.Request, - ): Promise> => - this.servicesAppBackendService.getFeaturedInstitutions(); - public readonly getFeaturedServices = async ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _req: express.Request, + _req: express.Request ): Promise> => this.servicesAppBackendService.getFeaturedServices(); - public readonly getServiceById = async ( - req: express.Request, + public readonly getFeaturedInstitutions = async ( + _req: express.Request + ): Promise> => + this.servicesAppBackendService.getFeaturedInstitutions(); + + public readonly findInstutionServices = async ( + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseSuccessJson + | IResponseErrorValidation + | IResponseSuccessJson > => withValidatedOrInternalError( - NonEmptyString.decode(req.params.serviceId), - (serviceId) => this.servicesAppBackendService.getServiceById(serviceId), + NonEmptyString.decode(req.params.institutionId), + (institutionId) => + this.servicesAppBackendService.findInstutionServices( + institutionId, + parseOptionalNumberParam(req.query.limit), + parseOptionalNumberParam(req.query.offset) + ) ); - - constructor( - private readonly servicesAppBackendService: ServicesAppBackendService, - ) {} } diff --git a/src/controllers/servicesController.ts b/src/controllers/servicesController.ts index 4cd797441..1697bab35 100644 --- a/src/controllers/servicesController.ts +++ b/src/controllers/servicesController.ts @@ -12,27 +12,30 @@ import { IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; - import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; +import { withUserFromRequest } from "../../src/types/user"; +import { withValidatedOrValidationError } from "../../src/utils/responses"; + import { ServicePreference } from "../../generated/backend/ServicePreference"; import { ServicePublic } from "../../generated/backend/ServicePublic"; import { UpsertServicePreference } from "../../generated/backend/UpsertServicePreference"; -import { withUserFromRequest } from "../../src/types/user"; -import { withValidatedOrValidationError } from "../../src/utils/responses"; + import FunctionsAppService from "../services/functionAppService"; export default class ServicesController { + constructor(private readonly fnAppService: FunctionsAppService) {} + /** * Returns the service identified by the provided id * code. */ public readonly getService = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal + | IResponseErrorValidation | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation | IResponseSuccessJson > => this.fnAppService.getService(req.params.id); @@ -40,34 +43,34 @@ export default class ServicesController { * Returns the service preferences for the provided service id */ public readonly getServicePreferences = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorConflict | IResponseErrorInternal + | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorConflict | IResponseErrorTooManyRequests - | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => withValidatedOrValidationError( PathTraversalSafePathParam.decode(req.params.id), (serviceId) => - this.fnAppService.getServicePreferences(user.fiscal_code, serviceId), - ), + this.fnAppService.getServicePreferences(user.fiscal_code, serviceId) + ) ); /** * Create or Update the service preferences for the provided service id */ public readonly upsertServicePreferences = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorConflict | IResponseErrorInternal + | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorConflict | IResponseErrorTooManyRequests - | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -80,11 +83,9 @@ export default class ServicesController { this.fnAppService.upsertServicePreferences( user.fiscal_code, serviceId, - pref, - ), - ), - ), + pref + ) + ) + ) ); - - constructor(private readonly fnAppService: FunctionsAppService) {} } diff --git a/src/controllers/sessionController.ts b/src/controllers/sessionController.ts index c3fd2c0bb..a749bd119 100644 --- a/src/controllers/sessionController.ts +++ b/src/controllers/sessionController.ts @@ -2,6 +2,7 @@ * This controller returns data about the current user session */ +import * as express from "express"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -9,16 +10,16 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; import * as E from "fp-ts/lib/Either"; - import { SessionsList } from "../../generated/backend/SessionsList"; import RedisSessionStorage from "../services/redisSessionStorage"; import { withUserFromRequest } from "../types/user"; export default class SessionController { + constructor(private readonly sessionStorage: RedisSessionStorage) {} + public readonly listSessions = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -34,6 +35,4 @@ export default class SessionController { } return ResponseSuccessJson(sessionsList.right); }); - - constructor(private readonly sessionStorage: RedisSessionStorage) {} } diff --git a/src/controllers/sessionLockController.ts b/src/controllers/sessionLockController.ts index 89c7061d0..cf4a44702 100644 --- a/src/controllers/sessionLockController.ts +++ b/src/controllers/sessionLockController.ts @@ -2,7 +2,7 @@ * This controller returns data about the current user session */ -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; +import * as express from "express"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -15,169 +15,141 @@ import { ResponseErrorValidation, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import { addSeconds } from "date-fns"; -import * as express from "express"; -import * as AP from "fp-ts/lib/Apply"; import * as E from "fp-ts/lib/Either"; +import * as AP from "fp-ts/lib/Apply"; +import * as TE from "fp-ts/lib/TaskEither"; import * as O from "fp-ts/lib/Option"; import * as ROA from "fp-ts/lib/ReadonlyArray"; + +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import { pipe, flow, constVoid } from "fp-ts/lib/function"; import { ReadonlyNonEmptyArray } from "fp-ts/lib/ReadonlyNonEmptyArray"; -import * as TE from "fp-ts/lib/TaskEither"; -import { constVoid, flow, pipe } from "fp-ts/lib/function"; import { OutputOf } from "io-ts"; - -import { AuthLockBody } from "../../generated/session/AuthLockBody"; -import { AuthUnlockBody } from "../../generated/session/AuthUnlockBody"; -import { TypeEnum as LoginTypeEnum } from "../../generated/session/SessionInfo"; -import { SessionState } from "../../generated/session/SessionState"; -import { UnlockCode } from "../../generated/session/UnlockCode"; -import { UserSessionInfo } from "../../generated/session/UserSessionInfo"; -import AuthenticationLockService, { - NotReleasedAuthenticationLockData, -} from "../services/authenticationLockService"; -import LollipopService from "../services/lollipopService"; -import { NotificationServiceFactory } from "../services/notificationServiceFactory"; -import RedisSessionStorage from "../services/redisSessionStorage"; -import RedisUserMetadataStorage from "../services/redisUserMetadataStorage"; -import { SuccessResponse } from "../types/commons"; -import { withFiscalCodeFromRequestParams } from "../types/fiscalCode"; +import { addSeconds } from "date-fns"; import { IResponseNoContent, ResponseNoContent, withValidatedOrValidationError, } from "../utils/responses"; +import { SuccessResponse } from "../types/commons"; +import LollipopService from "../services/lollipopService"; +import { withFiscalCodeFromRequestParams } from "../types/fiscalCode"; +import RedisSessionStorage from "../services/redisSessionStorage"; +import RedisUserMetadataStorage from "../services/redisUserMetadataStorage"; +import AuthenticationLockService, { + NotReleasedAuthenticationLockData, +} from "../services/authenticationLockService"; +import { NotificationServiceFactory } from "../services/notificationServiceFactory"; + +import { UserSessionInfo } from "../../generated/session/UserSessionInfo"; +import { AuthLockBody } from "../../generated/session/AuthLockBody"; +import { AuthUnlockBody } from "../../generated/session/AuthUnlockBody"; +import { SessionState } from "../../generated/session/SessionState"; +import { TypeEnum as LoginTypeEnum } from "../../generated/session/SessionInfo"; +import { UnlockCode } from "../../generated/session/UnlockCode"; const ERROR_CHECK_USER_AUTH_LOCK = "Something went wrong while checking the user authentication lock"; export const withUnlockCodeParams = async ( req: express.Request, - f: (authLockBody: AuthLockBody) => Promise, + f: (authLockBody: AuthLockBody) => Promise ) => withValidatedOrValidationError(AuthLockBody.decode(req.body), (unlockCode) => - f(unlockCode), + f(unlockCode) ); export const withAuthUnlockBodyParams = async ( req: express.Request, - f: (authLockBody: AuthUnlockBody) => Promise, + f: (authLockBody: AuthUnlockBody) => Promise ) => withValidatedOrValidationError( AuthUnlockBody.decode(req.body), - (unlockCode) => f(unlockCode), + (unlockCode) => f(unlockCode) ); export default class SessionLockController { - private readonly buildInvalidateUserSessionTask = (fiscalCode: FiscalCode) => - [ - // revoke pubkey - pipe( - TE.tryCatch( - () => - // retrieve the assertionRef for the user - this.sessionStorage.getLollipopAssertionRefForUser(fiscalCode), - E.toError, - ), - TE.chain(TE.fromEither), - TE.chain( - flow( - O.map((assertionRef) => - TE.tryCatch( - () => - // fire and forget the queue message - new Promise((resolve) => { - this.lollipopService - .revokePreviousAssertionRef(assertionRef) - .catch(constVoid); - resolve(true); - }), - E.toError, - ), - ), - // continue if there's no assertionRef on redis - O.getOrElse(() => TE.of(true)), - ), - ), - ), - // delete the assertionRef for the user - pipe( - TE.tryCatch( - () => this.sessionStorage.delLollipopDataForUser(fiscalCode), - E.toError, - ), - TE.chain(TE.fromEither), - ), - // removes all sessions - pipe( - TE.tryCatch( - () => this.sessionStorage.delUserAllSessions(fiscalCode), - E.toError, - ), - TE.chain(TE.fromEither), - ), - ] as const; + constructor( + private readonly sessionStorage: RedisSessionStorage, + private readonly metadataStorage: RedisUserMetadataStorage, + private readonly lollipopService: LollipopService, + private readonly authenticationLockService: AuthenticationLockService, + private readonly notificationServiceFactory: NotificationServiceFactory + ) {} - private readonly clearInstallation = (fiscalCode: FiscalCode) => + /** + * Get a user session info + * + * @param req expects fiscal_code as a path param + * + * @returns a promise with the encoded User Session response + */ + public readonly getUserSession = ( + req: express.Request + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson + > => pipe( - TE.tryCatch( - () => - this.notificationServiceFactory(fiscalCode).deleteInstallation( - fiscalCode, - ), - (err) => - Error( - `Cannot delete Notification Installation: ${JSON.stringify(err)}`, - ), + req.params.fiscal_code, + FiscalCode.decode, + E.mapLeft((err) => + ResponseErrorValidation("Invalid Fiscal Code", readableReport(err)) ), - TE.chain( - flow( - TE.fromPredicate( - (response) => response.kind === "IResponseSuccessJson", - (err) => - Error( - `Cannot delete Notification Installation: ${ - err.detail ?? "Not Defined" - }`, - ), + TE.fromEither, + TE.chainW((fiscalCode) => + pipe( + TE.tryCatch( + () => this.sessionStorage.userHasActiveSessionsOrLV(fiscalCode), + E.toError ), - TE.map(() => true), - ), + TE.chain(TE.fromEither), + TE.mapLeft((e) => ResponseErrorInternal(`${e.message} [${e}]`)) + ) ), - ); + TE.map((active) => UserSessionInfo.encode({ active })), + TE.map(ResponseSuccessJson), + TE.toUnion + )(); - private readonly unlockuserAuthenticationLockData = ( - fiscalCode: FiscalCode, - maybeUnlockCode: O.Option, - authLockData: ReadonlyNonEmptyArray, - ): TE.TaskEither< - IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, - true + /** + * Lock a user account and clear all its session data + * + * @param req expects fiscal_code as a path param + * + * @returns a promise with the encoded response object + */ + public readonly lockUserSession = ( + req: express.Request + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseSuccessJson > => - pipe( - {}, - TE.fromPredicate( - () => - O.isNone(maybeUnlockCode) || - authLockData.some((data) => data.rowKey === maybeUnlockCode.value), - () => ResponseErrorForbiddenNotAuthorized, - ), - TE.map(() => - O.isSome(maybeUnlockCode) - ? [maybeUnlockCode.value] - : authLockData.map((data) => data.rowKey), - ), - TE.chainW((codesToUnlock) => - pipe( - this.authenticationLockService.unlockUserAuthentication( - fiscalCode, - codesToUnlock, - ), - TE.mapLeft(() => - ResponseErrorInternal("Error releasing user authentication lock"), + withFiscalCodeFromRequestParams(req, (fiscalCode) => + pipe( + AP.sequenceT(TE.ApplicativeSeq)( + // lock the account + pipe( + TE.tryCatch( + () => this.sessionStorage.setBlockedUser(fiscalCode), + E.toError + ), + TE.chain(TE.fromEither) ), + ...this.buildInvalidateUserSessionTask(fiscalCode), + // removes all metadata + pipe( + TE.tryCatch(() => this.metadataStorage.del(fiscalCode), E.toError), + TE.chain(TE.fromEither) + ) ), - ), + TE.mapLeft((err) => ResponseErrorInternal(err.message)), + TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.toUnion + )() ); /** @@ -189,7 +161,7 @@ export default class SessionLockController { * @returns a promise with the encoded response object */ public readonly deleteUserSession = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -198,102 +170,50 @@ export default class SessionLockController { withFiscalCodeFromRequestParams(req, (fiscalCode) => pipe( ROA.sequence(TE.ApplicativeSeq)( - this.buildInvalidateUserSessionTask(fiscalCode), + this.buildInvalidateUserSessionTask(fiscalCode) ), TE.mapLeft((err) => ResponseErrorInternal(err.message)), - TE.map(() => ResponseSuccessJson({ message: "ok" })), - TE.toUnion, - )(), + TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.toUnion + )() ); /** - * Get a user session info + * Unlock a user account * * @param req expects fiscal_code as a path param * - * @returns a promise with the encoded User Session response + * @returns a promise with the encoded response object */ - public readonly getUserSession = ( - req: express.Request, + public readonly unlockUserSession = ( + req: express.Request ): Promise< | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => pipe( req.params.fiscal_code, FiscalCode.decode, E.mapLeft((err) => - ResponseErrorValidation("Invalid Fiscal Code", readableReport(err)), + ResponseErrorValidation("Invalid fiscal code", readableReport(err)) ), TE.fromEither, TE.chainW((fiscalCode) => + // unlock the account pipe( TE.tryCatch( - () => this.sessionStorage.userHasActiveSessionsOrLV(fiscalCode), - E.toError, + () => this.sessionStorage.unsetBlockedUser(fiscalCode), + E.toError ), TE.chain(TE.fromEither), - TE.mapLeft((e) => ResponseErrorInternal(`${e.message} [${e}]`)), - ), + TE.mapLeft((err) => ResponseErrorInternal(err.message)) + ) ), - TE.map((active) => UserSessionInfo.encode({ active })), - TE.map(ResponseSuccessJson), - TE.toUnion, + TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.toUnion )(); - public readonly getUserSessionState = ( - req: express.Request, - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson> - > => - withFiscalCodeFromRequestParams(req, (fiscalCode) => - pipe( - AP.sequenceS(TE.ApplicativePar)({ - isUserAuthenticationLocked: pipe( - this.authenticationLockService.isUserAuthenticationLocked( - fiscalCode, - ), - TE.mapLeft((_) => - ResponseErrorInternal( - `Error reading the auth lock info: [${_.message}]`, - ), - ), - ), - maybeSessionRemaningTTL: pipe( - this.sessionStorage.getSessionRemainingTTL(fiscalCode), - TE.mapLeft((err) => - ResponseErrorInternal( - `Error reading the session info: [${err.message}]`, - ), - ), - ), - }), - TE.map(({ isUserAuthenticationLocked, maybeSessionRemaningTTL }) => - O.isNone(maybeSessionRemaningTTL) - ? SessionState.encode({ - access_enabled: !isUserAuthenticationLocked, - session_info: { active: false }, - }) - : SessionState.encode({ - access_enabled: !isUserAuthenticationLocked, - session_info: { - active: true, - expiration_date: addSeconds( - new Date(), - maybeSessionRemaningTTL.value.ttl, - ), - type: LoginTypeEnum[maybeSessionRemaningTTL.value.type], - }, - }), - ), - TE.map(ResponseSuccessJson), - TE.toUnion, - )(), - ); - /** * Release a lock previously set by the user * @@ -302,11 +222,11 @@ export default class SessionLockController { * @returns a promise with the encoded response object */ public readonly lockUserAuthentication = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorConflict | IResponseNoContent > => withFiscalCodeFromRequestParams(req, (fiscalCode) => @@ -314,15 +234,15 @@ export default class SessionLockController { pipe( // lock the authentication this.authenticationLockService.isUserAuthenticationLocked(fiscalCode), - TE.mapLeft(() => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK)), + TE.mapLeft((_) => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK)), TE.filterOrElseW( (isUserAuthenticationLocked) => !isUserAuthenticationLocked, () => ResponseErrorConflict( - "Another user authentication lock has already been applied", - ), + "Another user authentication lock has already been applied" + ) ), - TE.chainW(() => + TE.chainW((_) => pipe( AP.sequenceT(TE.ApplicativeSeq)( // clear session data @@ -333,60 +253,18 @@ export default class SessionLockController { // if clean up went well, lock user session this.authenticationLockService.lockUserAuthentication( fiscalCode, - authLockBody.unlock_code, - ), + authLockBody.unlock_code + ) ), - TE.mapLeft((err) => ResponseErrorInternal(err.message)), - ), - ), - TE.map(() => ResponseNoContent()), - TE.toUnion, - )(), - ), - ); - - /** - * Lock a user account and clear all its session data - * - * @param req expects fiscal_code as a path param - * - * @returns a promise with the encoded response object - */ - public readonly lockUserSession = ( - req: express.Request, - ): Promise< - | IResponseErrorInternal - | IResponseErrorValidation - | IResponseSuccessJson - > => - withFiscalCodeFromRequestParams(req, (fiscalCode) => - pipe( - AP.sequenceT(TE.ApplicativeSeq)( - // lock the account - pipe( - TE.tryCatch( - () => this.sessionStorage.setBlockedUser(fiscalCode), - E.toError, - ), - TE.chain(TE.fromEither), + TE.mapLeft((err) => ResponseErrorInternal(err.message)) + ) ), - ...this.buildInvalidateUserSessionTask(fiscalCode), - // removes all metadata - pipe( - TE.tryCatch(() => this.metadataStorage.del(fiscalCode), E.toError), - TE.chain(TE.fromEither), - ), - ), - TE.mapLeft((err) => ResponseErrorInternal(err.message)), - TE.map(() => ResponseSuccessJson({ message: "ok" })), - TE.toUnion, - )(), + TE.map((_) => ResponseNoContent()), + TE.toUnion + )() + ) ); - // ------------------------------ - // private methods - // ------------------------------ - /** * Lock a user authentication and clear all its session data * @@ -395,10 +273,10 @@ export default class SessionLockController { * @returns a promise with the encoded response object */ public readonly unlockUserAuthentication = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseErrorForbiddenNotAuthorized | IResponseErrorValidation | IResponseNoContent > => @@ -412,12 +290,12 @@ export default class SessionLockController { TE.bind("authLockData", () => pipe( this.authenticationLockService.getUserAuthenticationLockData( - fiscalCode, - ), - TE.mapLeft(() => - ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK), + fiscalCode ), - ), + TE.mapLeft((_) => + ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK) + ) + ) ), TE.chainW(({ authLockData, maybeUnlockCode }) => ROA.isNonEmpty(authLockData) @@ -425,58 +303,181 @@ export default class SessionLockController { this.unlockuserAuthenticationLockData( fiscalCode, maybeUnlockCode, - authLockData, + authLockData ) : // User auth is NOT locked - TE.of(true), + TE.of(true) ), - TE.map(() => ResponseNoContent()), - TE.toUnion, - )(), - ), + TE.map((_) => ResponseNoContent()), + TE.toUnion + )() + ) ); - /** - * Unlock a user account - * - * @param req expects fiscal_code as a path param - * - * @returns a promise with the encoded response object - */ - public readonly unlockUserSession = ( - req: express.Request, + public readonly getUserSessionState = ( + req: express.Request ): Promise< | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson> > => - pipe( - req.params.fiscal_code, - FiscalCode.decode, - E.mapLeft((err) => - ResponseErrorValidation("Invalid fiscal code", readableReport(err)), - ), - TE.fromEither, - TE.chainW((fiscalCode) => - // unlock the account - pipe( - TE.tryCatch( - () => this.sessionStorage.unsetBlockedUser(fiscalCode), - E.toError, + withFiscalCodeFromRequestParams(req, (fiscalCode) => + pipe( + AP.sequenceS(TE.ApplicativePar)({ + isUserAuthenticationLocked: pipe( + this.authenticationLockService.isUserAuthenticationLocked( + fiscalCode + ), + TE.mapLeft((_) => + ResponseErrorInternal( + `Error reading the auth lock info: [${_.message}]` + ) + ) ), - TE.chain(TE.fromEither), - TE.mapLeft((err) => ResponseErrorInternal(err.message)), + maybeSessionRemaningTTL: pipe( + this.sessionStorage.getSessionRemainingTTL(fiscalCode), + TE.mapLeft((err) => + ResponseErrorInternal( + `Error reading the session info: [${err.message}]` + ) + ) + ), + }), + TE.map(({ isUserAuthenticationLocked, maybeSessionRemaningTTL }) => + O.isNone(maybeSessionRemaningTTL) + ? SessionState.encode({ + access_enabled: !isUserAuthenticationLocked, + session_info: { active: false }, + }) + : SessionState.encode({ + access_enabled: !isUserAuthenticationLocked, + session_info: { + active: true, + expiration_date: addSeconds( + new Date(), + maybeSessionRemaningTTL.value.ttl + ), + type: LoginTypeEnum[maybeSessionRemaningTTL.value.type], + }, + }) ), + TE.map(ResponseSuccessJson), + TE.toUnion + )() + ); + + // ------------------------------ + // private methods + // ------------------------------ + + private readonly buildInvalidateUserSessionTask = (fiscalCode: FiscalCode) => + [ + // revoke pubkey + pipe( + TE.tryCatch( + () => + // retrieve the assertionRef for the user + this.sessionStorage.getLollipopAssertionRefForUser(fiscalCode), + E.toError + ), + TE.chain(TE.fromEither), + TE.chain( + flow( + O.map((assertionRef) => + TE.tryCatch( + () => + // fire and forget the queue message + new Promise((resolve) => { + this.lollipopService + .revokePreviousAssertionRef(assertionRef) + .catch(constVoid); + resolve(true); + }), + E.toError + ) + ), + // continue if there's no assertionRef on redis + O.getOrElse(() => TE.of(true)) + ) + ) ), - TE.map(() => ResponseSuccessJson({ message: "ok" })), - TE.toUnion, - )(); + // delete the assertionRef for the user + pipe( + TE.tryCatch( + () => this.sessionStorage.delLollipopDataForUser(fiscalCode), + E.toError + ), + TE.chain(TE.fromEither) + ), + // removes all sessions + pipe( + TE.tryCatch( + () => this.sessionStorage.delUserAllSessions(fiscalCode), + E.toError + ), + TE.chain(TE.fromEither) + ), + ] as const; - constructor( - private readonly sessionStorage: RedisSessionStorage, - private readonly metadataStorage: RedisUserMetadataStorage, - private readonly lollipopService: LollipopService, - private readonly authenticationLockService: AuthenticationLockService, - private readonly notificationServiceFactory: NotificationServiceFactory, - ) {} + private readonly clearInstallation = (fiscalCode: FiscalCode) => + pipe( + TE.tryCatch( + () => + this.notificationServiceFactory(fiscalCode).deleteInstallation( + fiscalCode + ), + (err) => + Error( + `Cannot delete Notification Installation: ${JSON.stringify(err)}` + ) + ), + TE.chain( + flow( + TE.fromPredicate( + (response) => response.kind === "IResponseSuccessJson", + (err) => + Error( + `Cannot delete Notification Installation: ${ + err.detail ?? "Not Defined" + }` + ) + ), + TE.map(() => true) + ) + ) + ); + + private readonly unlockuserAuthenticationLockData = ( + fiscalCode: FiscalCode, + maybeUnlockCode: O.Option, + authLockData: ReadonlyNonEmptyArray + ): TE.TaskEither< + IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, + true + > => + pipe( + {}, + TE.fromPredicate( + () => + O.isNone(maybeUnlockCode) || + authLockData.some((data) => data.rowKey === maybeUnlockCode.value), + () => ResponseErrorForbiddenNotAuthorized + ), + TE.map(() => + O.isSome(maybeUnlockCode) + ? [maybeUnlockCode.value] + : authLockData.map((data) => data.rowKey) + ), + TE.chainW((codesToUnlock) => + pipe( + this.authenticationLockService.unlockUserAuthentication( + fiscalCode, + codesToUnlock + ), + TE.mapLeft(() => + ResponseErrorInternal("Error releasing user authentication lock") + ) + ) + ) + ); } diff --git a/src/controllers/ssoController.ts b/src/controllers/ssoController.ts index e40f0b029..26fdc8642 100644 --- a/src/controllers/ssoController.ts +++ b/src/controllers/ssoController.ts @@ -1,14 +1,13 @@ /** * This controller handles requests made from MyPortal. */ +import { Request } from "express"; import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { Request } from "express"; - import { MyPortalUser } from "../../generated/myportal/MyPortalUser"; import { withUserFromRequest } from "../types/user"; import { withValidatedOrInternalError } from "../utils/responses"; @@ -18,10 +17,10 @@ import { withValidatedOrInternalError } from "../utils/responses"; * code. */ export const getUserForMyPortal = ( - req: Request, + req: Request ): Promise< - | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorInternal | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -31,6 +30,6 @@ export const getUserForMyPortal = ( fiscal_code: user.fiscal_code, name: user.name, }), - (_) => ResponseSuccessJson(_), - ), + (_) => ResponseSuccessJson(_) + ) ); diff --git a/src/controllers/trialController.ts b/src/controllers/trialController.ts index a304015a4..273a4e773 100644 --- a/src/controllers/trialController.ts +++ b/src/controllers/trialController.ts @@ -3,6 +3,7 @@ * forwarding the call to the API system. */ +import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -13,28 +14,31 @@ import { IResponseSuccessRedirectToResource, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; + import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; import TrialService from "src/services/trialService"; - -import { Subscription } from "../../generated/trial-system/Subscription"; -import { SubscriptionStateEnum } from "../../generated/trial-system/SubscriptionState"; -import { TrialId } from "../../generated/trial-system-api/TrialId"; import { FF_IO_WALLET_TRIAL_ENABLED, IO_WALLET_TRIAL_ID, } from "../../src/config"; +import { TrialId } from "../../generated/trial-system-api/TrialId"; import { withUserFromRequest } from "../types/user"; + import { withValidatedOrValidationError } from "../utils/responses"; +import { Subscription } from "../../generated/trial-system/Subscription"; +import { SubscriptionStateEnum } from "../../generated/trial-system/SubscriptionState"; export default class TrialController { + // eslint-disable-next-line max-params + constructor(private readonly trialService: TrialService) {} + public readonly createTrialSubscription = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorConflict | IResponseSuccessAccepted | IResponseSuccessRedirectToResource > => @@ -44,17 +48,17 @@ export default class TrialController { (trialId) => withValidatedOrValidationError( NonEmptyString.decode(user.fiscal_code), - (userId) => this.trialService.createSubscription(userId, trialId), - ), - ), + (userId) => this.trialService.createSubscription(userId, trialId) + ) + ) ); public readonly getTrialSubscription = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -65,18 +69,15 @@ export default class TrialController { trialId !== IO_WALLET_TRIAL_ID || FF_IO_WALLET_TRIAL_ENABLED ? withValidatedOrValidationError( NonEmptyString.decode(user.fiscal_code), - (userId) => this.trialService.getSubscription(userId, trialId), + (userId) => this.trialService.getSubscription(userId, trialId) ) : Promise.resolve( ResponseSuccessJson({ createdAt: new Date(), state: SubscriptionStateEnum.ACTIVE, trialId, - }), - ), - ), + }) + ) + ) ); - - // eslint-disable-next-line max-params - constructor(private readonly trialService: TrialService) {} } diff --git a/src/controllers/userDataProcessingController.ts b/src/controllers/userDataProcessingController.ts index 575921b45..d088bb567 100644 --- a/src/controllers/userDataProcessingController.ts +++ b/src/controllers/userDataProcessingController.ts @@ -3,6 +3,7 @@ * app by forwarding the call to the API system. */ +import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -12,7 +13,6 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; import { UserDataProcessing } from "../../generated/backend/UserDataProcessing"; import { UserDataProcessingChoice } from "../../generated/backend/UserDataProcessingChoice"; @@ -22,28 +22,32 @@ import { withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; export default class UserDataProcessingController { + constructor( + private readonly userDataProcessingService: UserDataProcessingService + ) {} + /** - * Abort the user data processing of a specific user. + * upsert a user data processing request for the user identified by the provided + * fiscal code. */ - public readonly abortUserDataProcessing = ( - req: express.Request, + public readonly upsertUserDataProcessing = ( + req: express.Request ): Promise< - | IResponseErrorConflict + | IResponseErrorValidation | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessAccepted + | IResponseErrorConflict + | IResponseSuccessJson > => withUserFromRequest(req, async (user) => withValidatedOrValidationError( - UserDataProcessingChoice.decode(req.params.choice), + UserDataProcessingChoiceRequest.decode(req.body), (dataProcessingChoice) => - this.userDataProcessingService.abortUserDataProcessing( + this.userDataProcessingService.upsertUserDataProcessing( user, - dataProcessingChoice, - ), - ), + dataProcessingChoice + ) + ) ); /** @@ -51,12 +55,12 @@ export default class UserDataProcessingController { * fiscal code and userDataProcessing choice. */ public readonly getUserDataProcessing = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorInternal + | IResponseErrorValidation | IResponseErrorNotFound + | IResponseErrorInternal | IResponseErrorTooManyRequests - | IResponseErrorValidation | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -65,36 +69,32 @@ export default class UserDataProcessingController { (dataProcessingChoice) => this.userDataProcessingService.getUserDataProcessing( user, - dataProcessingChoice, - ), - ), + dataProcessingChoice + ) + ) ); /** - * upsert a user data processing request for the user identified by the provided - * fiscal code. + * Abort the user data processing of a specific user. */ - public readonly upsertUserDataProcessing = ( - req: express.Request, + public readonly abortUserDataProcessing = ( + req: express.Request ): Promise< - | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorTooManyRequests + | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorConflict + | IResponseSuccessAccepted > => withUserFromRequest(req, async (user) => withValidatedOrValidationError( - UserDataProcessingChoiceRequest.decode(req.body), + UserDataProcessingChoice.decode(req.params.choice), (dataProcessingChoice) => - this.userDataProcessingService.upsertUserDataProcessing( + this.userDataProcessingService.abortUserDataProcessing( user, - dataProcessingChoice, - ), - ), + dataProcessingChoice + ) + ) ); - - constructor( - private readonly userDataProcessingService: UserDataProcessingService, - ) {} } diff --git a/src/controllers/userMetadataController.ts b/src/controllers/userMetadataController.ts index 1cfdfc007..979e433b3 100644 --- a/src/controllers/userMetadataController.ts +++ b/src/controllers/userMetadataController.ts @@ -3,6 +3,7 @@ * redis database through the user metadata storage service. */ +import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -12,8 +13,9 @@ import { ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; + import * as E from "fp-ts/lib/Either"; +import { IResponseNoContent, ResponseNoContent } from "../utils/responses"; import { UserMetadata } from "../../generated/backend/UserMetadata"; import { IUserMetadataStorage } from "../services/IUserMetadataStorage"; @@ -22,18 +24,19 @@ import { metadataNotFoundError, } from "../services/redisUserMetadataStorage"; import { withUserFromRequest } from "../types/user"; -import { IResponseNoContent, ResponseNoContent } from "../utils/responses"; import { withValidatedOrValidationError } from "../utils/responses"; export default class UserMetadataController { + constructor(private readonly userMetadataStorage: IUserMetadataStorage) {} + /** * Returns the metadata for the current authenticated user. */ public readonly getMetadata = ( - req: express.Request, + req: express.Request ): Promise< - | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorInternal | IResponseNoContent | IResponseSuccessJson > => @@ -55,11 +58,11 @@ export default class UserMetadataController { * Story https://www.pivotaltracker.com/story/show/167064659 */ public readonly upsertMetadata = ( - req: express.Request, + req: express.Request ): Promise< | IResponseErrorConflict - | IResponseErrorInternal | IResponseErrorValidation + | IResponseErrorInternal | IResponseSuccessJson > => withUserFromRequest(req, async (user) => @@ -68,7 +71,7 @@ export default class UserMetadataController { async (metadata) => { const setMetadataResponse = await this.userMetadataStorage.set( user, - metadata, + metadata ); if (E.isLeft(setMetadataResponse)) { if (setMetadataResponse.left === invalidVersionNumberError) { @@ -77,9 +80,7 @@ export default class UserMetadataController { return ResponseErrorInternal(setMetadataResponse.left.message); } return ResponseSuccessJson(metadata); - }, - ), + } + ) ); - - constructor(private readonly userMetadataStorage: IUserMetadataStorage) {} } diff --git a/src/server.ts b/src/server.ts index 9f0269d1b..3b2731d63 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,18 +1,17 @@ /** * Main entry point for the Digital Citizenship proxy. */ -import { withApplicationInsight } from "@pagopa/io-functions-commons/dist/src/utils/transports/application_insight"; -import { NodeEnvironmentEnum } from "@pagopa/ts-commons/lib/environment"; -import { useWinstonFor } from "@pagopa/winston-ts"; -import { LoggerId } from "@pagopa/winston-ts/dist/types/logging"; -import * as appInsights from "applicationinsights"; -import * as O from "fp-ts/lib/Option"; -import { pipe } from "fp-ts/lib/function"; -import * as fs from "fs"; import * as http from "http"; import * as https from "https"; +import * as fs from "fs"; import * as path from "path"; - +import * as appInsights from "applicationinsights"; +import * as O from "fp-ts/lib/Option"; +import { NodeEnvironmentEnum } from "@pagopa/ts-commons/lib/environment"; +import { pipe } from "fp-ts/lib/function"; +import { useWinstonFor } from "@pagopa/winston-ts"; +import { LoggerId } from "@pagopa/winston-ts/dist/types/logging"; +import { withApplicationInsight } from "@pagopa/io-functions-commons/dist/src/utils/transports/application_insight"; import { newApp } from "./app"; import { ALLOW_MYPORTAL_IP_SOURCE_RANGE, @@ -35,10 +34,11 @@ import { TRIAL_SYSTEM_API_BASE_PATH, } from "./config"; import { - StartupEventName, initAppInsights, + StartupEventName, trackStartupTime, } from "./utils/appinsights"; + import { initHttpGracefulShutdown } from "./utils/gracefulShutdown"; import { log } from "./utils/logger"; import { getCurrentBackendVersion } from "./utils/package"; @@ -68,6 +68,7 @@ const shutdownTimeout: number = process.env.DEFAULT_SHUTDOWN_TIMEOUT_MILLIS ? parseInt(process.env.DEFAULT_SHUTDOWN_TIMEOUT_MILLIS, 10) : DEFAULT_SHUTDOWN_TIMEOUT_MILLIS; +// eslint-disable-next-line functional/no-let let server: http.Server | https.Server; const timer = TimeTracer(); @@ -89,16 +90,16 @@ const maybeAppInsightsClient = pipe( samplingPercentage: process.env.APPINSIGHTS_SAMPLING_PERCENTAGE ? parseInt(process.env.APPINSIGHTS_SAMPLING_PERCENTAGE, 10) : DEFAULT_APPINSIGHTS_SAMPLING_PERCENTAGE, - }), + }) ), O.chainFirst((telemetryClient) => O.some( useWinstonFor({ loggerId: LoggerId.event, transports: [withApplicationInsight(telemetryClient, "io-backend")], - }), - ), - ), + }) + ) + ) ); newApp({ @@ -130,11 +131,11 @@ newApp({ const certPath = path.resolve(__dirname, "../../certs"); const privateKey = fs.readFileSync( path.join(certPath, "key.pem"), - "utf8", + "utf8" ); const certificate = fs.readFileSync( path.join(certPath, "cert.pem"), - "utf8", + "utf8" ); const options = { cert: certificate, key: privateKey }; server = https.createServer(options, app).listen(443, () => { @@ -143,8 +144,8 @@ newApp({ pipe( maybeAppInsightsClient, O.map((_) => - trackStartupTime(_, StartupEventName.SERVER, startupTimeMs), - ), + trackStartupTime(_, StartupEventName.SERVER, startupTimeMs) + ) ); }); } else { @@ -155,8 +156,8 @@ newApp({ pipe( maybeAppInsightsClient, O.map((_) => - trackStartupTime(_, StartupEventName.SERVER, startupTimeMs), - ), + trackStartupTime(_, StartupEventName.SERVER, startupTimeMs) + ) ); }); } @@ -167,7 +168,7 @@ newApp({ O.map((appInsightsClient) => { appInsightsClient.flush(); appInsights.dispose(); - }), + }) ); log.info("HTTP server close."); }); diff --git a/src/services/IPagoPAClientFactory.ts b/src/services/IPagoPAClientFactory.ts index 047fc0eb8..a70a6f353 100644 --- a/src/services/IPagoPAClientFactory.ts +++ b/src/services/IPagoPAClientFactory.ts @@ -13,6 +13,6 @@ export interface IPagoPAClientFactoryInterface { * Retrieves a configured instance of the API client. */ readonly getClient: ( - environment: PagoPAEnvironment, + environment: PagoPAEnvironment ) => ReturnType; } diff --git a/src/services/ISessionStorage.ts b/src/services/ISessionStorage.ts index ed31a76bf..a34f09651 100644 --- a/src/services/ISessionStorage.ts +++ b/src/services/ISessionStorage.ts @@ -2,51 +2,30 @@ * Interface for the session storage services. */ -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; - import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; -import { LollipopData } from "../types/assertionRef"; import { MyPortalToken, SessionToken } from "../types/token"; import { User } from "../types/user"; +import { LollipopData } from "../types/assertionRef"; import { ActiveSessionInfo } from "../utils/fastLogin"; export interface ISessionStorage { /** - * Removes a value from the cache. - */ - readonly del: (user: User) => Promise>; - - /** - * Delete the Lollipop assertionRef related to an user - * - * @param fiscalCode A user fiscal code + * Retrieves a value from the cache using the session token. */ - readonly delLollipopDataForUser: ( - fiscalCode: FiscalCode, - ) => Promise>; - - readonly delPagoPaNoticeEmail: (user: User) => Promise>; - - readonly delUserAllSessions: ( - fiscalCode: FiscalCode, - ) => Promise>; + readonly getBySessionToken: ( + token: SessionToken + ) => Promise>>; /** * Retrieves a value from the cache using the myportal token. */ readonly getByMyPortalToken: ( - token: MyPortalToken, - ) => Promise>>; - - /** - * Retrieves a value from the cache using the session token. - */ - readonly getBySessionToken: ( - token: SessionToken, + token: MyPortalToken ) => Promise>>; /** @@ -56,7 +35,7 @@ export interface ISessionStorage { * @param fiscalCode The fiscalCode value used to get the related assertionRef */ readonly getLollipopAssertionRefForUser: ( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ) => Promise>>; /** @@ -65,9 +44,29 @@ export interface ISessionStorage { * @param fiscalCode The fiscalCode value used to get the related assertionRef */ readonly getLollipopDataForUser: ( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ) => Promise>>; + /** + * Delete the Lollipop assertionRef related to an user + * + * @param fiscalCode A user fiscal code + */ + readonly delLollipopDataForUser: ( + fiscalCode: FiscalCode + ) => Promise>; + + /** + * Removes a value from the cache. + */ + readonly del: (user: User) => Promise>; + + readonly delPagoPaNoticeEmail: (user: User) => Promise>; + + readonly delUserAllSessions: ( + fiscalCode: FiscalCode + ) => Promise>; + /** * Retrieve the remining TTL for the CF-AssertionRef record * and the Login Type (`LEGACY` of `LV`). @@ -78,6 +77,6 @@ export interface ISessionStorage { * @param fiscalCode */ readonly getSessionRemainingTTL: ( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ) => TE.TaskEither>; } diff --git a/src/services/IUserMetadataStorage.ts b/src/services/IUserMetadataStorage.ts index 5b033966c..6b60ba278 100644 --- a/src/services/IUserMetadataStorage.ts +++ b/src/services/IUserMetadataStorage.ts @@ -4,20 +4,19 @@ import { Either } from "fp-ts/lib/Either"; import { UserMetadata } from "generated/backend/UserMetadata"; - import { User } from "../types/user"; export interface IUserMetadataStorage { - /** - * Retrieves User Metadata information from Redis Storage - */ - readonly get: (user: User) => Promise>; - /** * Stores a User Metadata information into Redis Storage */ readonly set: ( user: User, - payload: UserMetadata, + payload: UserMetadata ) => Promise>; + + /** + * Retrieves User Metadata information from Redis Storage + */ + readonly get: (user: User) => Promise>; } diff --git a/src/services/apiClientFactory.ts b/src/services/apiClientFactory.ts index e370a8358..adc9acb49 100644 --- a/src/services/apiClientFactory.ts +++ b/src/services/apiClientFactory.ts @@ -15,7 +15,7 @@ export default class ApiClientFactory implements IApiClientFactoryInterface { apiKey: string, apiUrl: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any, + fetchApi: typeof fetch = nodeFetch as any ) { this.apiClient = APIClient(apiUrl, apiKey, fetchApi); } diff --git a/src/services/authenticationLockService.ts b/src/services/authenticationLockService.ts index f0534582c..f304909b9 100644 --- a/src/services/authenticationLockService.ts +++ b/src/services/authenticationLockService.ts @@ -4,57 +4,35 @@ */ import { TableClient, TransactionAction, odata } from "@azure/data-tables"; -import { DateFromString } from "@pagopa/ts-commons/lib/dates"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import * as ROA from "fp-ts/ReadonlyArray"; + +import * as t from "io-ts"; + +import { flow, identity, pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/lib/Either"; -import { flow, identity, pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; +import * as ROA from "fp-ts/ReadonlyArray"; + +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import { DateFromString } from "@pagopa/ts-commons/lib/dates"; -import { UnlockCode } from "../../generated/session/UnlockCode"; -import * as AI from "../utils/AsyncIterableTask"; import { errorsToError } from "../utils/errorsFormatter"; +import * as AI from "../utils/AsyncIterableTask"; + +import { UnlockCode } from "../../generated/session/UnlockCode"; export type NotReleasedAuthenticationLockData = t.TypeOf< typeof NotReleasedAuthenticationLockData >; const NotReleasedAuthenticationLockData = t.type({ - // eslint-disable-next-line sort-keys - CreatedAt: DateFromString, partitionKey: FiscalCode, - rowKey: UnlockCode, + + // eslint-disable-next-line sort-keys + CreatedAt: DateFromString, }); export default class AuthenticationLockService { - private readonly getUserAuthenticationLocks = (fiscalCode: FiscalCode) => - pipe( - this.tableClient.listEntities({ - queryOptions: { - filter: odata`PartitionKey eq ${fiscalCode} and not Released`, - }, - }), - AI.fromAsyncIterable, - AI.foldTaskEither(E.toError), - TE.chainEitherK( - flow( - t.array(NotReleasedAuthenticationLockData).decode, - E.mapLeft(errorsToError), - ), - ), - ); - - /** - * Retrieve all the user authentication lock data records - * - * @param fiscalCode the user fiscal code - * @returns a list of all the user authentication lock data, if exists - */ - public readonly getUserAuthenticationLockData = ( - fiscalCode: FiscalCode, - ): TE.TaskEither => - this.getUserAuthenticationLocks(fiscalCode); + constructor(private readonly tableClient: TableClient) {} /** * Check whether user authentication is locked @@ -63,10 +41,21 @@ export default class AuthenticationLockService { * @returns true if user authentication is locked, false otherwise */ public readonly isUserAuthenticationLocked = ( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ): TE.TaskEither => pipe(this.getUserAuthenticationLocks(fiscalCode), TE.map(ROA.isNonEmpty)); + /** + * Retrieve all the user authentication lock data records + * + * @param fiscalCode the user fiscal code + * @returns a list of all the user authentication lock data, if exists + */ + public readonly getUserAuthenticationLockData = ( + fiscalCode: FiscalCode + ): TE.TaskEither> => + this.getUserAuthenticationLocks(fiscalCode); + /** * Lock the user authentication * @@ -76,21 +65,21 @@ export default class AuthenticationLockService { */ public readonly lockUserAuthentication = ( fiscalCode: FiscalCode, - unlockCode: UnlockCode, + unlockCode: UnlockCode ): TE.TaskEither => pipe( TE.tryCatch( () => this.tableClient.createEntity({ - // eslint-disable-next-line sort-keys - CreatedAt: new Date(), partitionKey: fiscalCode, - rowKey: unlockCode, + + // eslint-disable-next-line sort-keys + CreatedAt: new Date(), }), - () => new Error("Something went wrong creating the record"), + (_) => new Error("Something went wrong creating the record") ), - TE.map(() => true as const), + TE.map((_) => true as const) ); /** @@ -102,7 +91,7 @@ export default class AuthenticationLockService { */ public readonly unlockUserAuthentication = ( fiscalCode: FiscalCode, - unlockCodes: readonly UnlockCode[], + unlockCodes: ReadonlyArray ): TE.TaskEither => pipe( unlockCodes, @@ -111,29 +100,44 @@ export default class AuthenticationLockService { [ "update", { - // eslint-disable-next-line sort-keys - Released: true, partitionKey: fiscalCode, rowKey: unlockCode, + // eslint-disable-next-line sort-keys + Released: true, }, - ] as TransactionAction, + ] as TransactionAction ), (actions) => TE.tryCatch( () => this.tableClient.submitTransaction(Array.from(actions)), - identity, + identity ), TE.filterOrElseW( (response) => response.status === 202, - () => void 0, + () => void 0 ), TE.mapLeft(() => new Error("Something went wrong updating the record")), - TE.map(() => true as const), + TE.map(() => true as const) ); // ----------------------------------- // Private Methods // ----------------------------------- - constructor(private readonly tableClient: TableClient) {} + private readonly getUserAuthenticationLocks = (fiscalCode: FiscalCode) => + pipe( + this.tableClient.listEntities({ + queryOptions: { + filter: odata`PartitionKey eq ${fiscalCode} and not Released`, + }, + }), + AI.fromAsyncIterable, + AI.foldTaskEither(E.toError), + TE.chainEitherK( + flow( + t.array(NotReleasedAuthenticationLockData).decode, + E.mapLeft(errorsToError) + ) + ) + ); } diff --git a/src/services/bonusService.ts b/src/services/bonusService.ts index bd818a1e5..1504b65ab 100644 --- a/src/services/bonusService.ts +++ b/src/services/bonusService.ts @@ -14,17 +14,16 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as TE from "fp-ts/lib/TaskEither"; -import { pipe } from "fp-ts/lib/function"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { PaginatedBonusActivationsCollection } from "generated/io-bonus-api/PaginatedBonusActivationsCollection"; - +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import { pipe } from "fp-ts/lib/function"; import { EligibilityCheck } from "../../generated/io-bonus-api/EligibilityCheck"; import { InstanceId } from "../../generated/io-bonus-api/InstanceId"; + import { BonusAPIClient } from "../clients/bonus"; import { User } from "../types/user"; -import { readableProblem } from "../utils/errorsFormatter"; import { withQrcode } from "../utils/qrcode"; import { ResponseErrorStatusNotDefinedInSpec, @@ -32,35 +31,21 @@ import { withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; +import { readableProblem } from "../utils/errorsFormatter"; export default class BonusService { - /** - * Get all IDs of the bonus activations requested by - * the authenticated user or by any between his family member - * - */ - public readonly getAllBonusActivations = ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _: User, - ): Promise< - | IResponseErrorInternal - | IResponseSuccessJson - > => - // According to the removal of the vacation bonus from APP-IO, this API will always return an empty array - Promise.resolve( - ResponseSuccessJson({ items: [] } as PaginatedBonusActivationsCollection), - ); + constructor(private readonly bonusApiClient: ReturnType) {} /** * Retrieve the status of an eligibility check previously started */ public readonly getBonusEligibilityCheck = ( - user: User, + user: User ): Promise< - | IResponseErrorGone | IResponseErrorInternal - | IResponseErrorNotFound | IResponseSuccessAccepted + | IResponseErrorNotFound + | IResponseErrorGone | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -79,7 +64,7 @@ export default class BonusService { case 404: return ResponseErrorNotFound( "EligibilityCheck not found", - `Could not find an eligibility check for fiscal code ${user.fiscal_code}`, + `Could not find an eligibility check for fiscal code ${user.fiscal_code}` ); case 410: return ResponseErrorGone("EligibilityCheck expired"); @@ -96,11 +81,11 @@ export default class BonusService { */ public readonly getLatestBonusActivationById = ( user: User, - bonusId: NonEmptyString, + bonusId: NonEmptyString ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseSuccessAccepted + | IResponseErrorNotFound | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -117,10 +102,10 @@ export default class BonusService { TE.map((bonus) => ResponseSuccessJson(bonus)), TE.mapLeft((err) => ResponseErrorInternal( - `Cannot encode qrcode: ${JSON.stringify(err)}`, - ), + `Cannot encode qrcode: ${JSON.stringify(err)}` + ) ), - TE.toUnion, + TE.toUnion )(); case 202: return ResponseSuccessAccepted(); @@ -129,7 +114,7 @@ export default class BonusService { case 404: return ResponseErrorNotFound( "BonusActivation not found", - `Could not find a bonus activation for fiscal code: ${user.fiscal_code} and bonus id ${bonusId}`, + `Could not find a bonus activation for fiscal code: ${user.fiscal_code} and bonus id ${bonusId}` ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -139,5 +124,19 @@ export default class BonusService { }); }); - constructor(private readonly bonusApiClient: ReturnType) {} + /** + * Get all IDs of the bonus activations requested by + * the authenticated user or by any between his family member + * + */ + public readonly getAllBonusActivations = ( + _: User + ): Promise< + | IResponseErrorInternal + | IResponseSuccessJson + > => + // According to the removal of the vacation bonus from APP-IO, this API will always return an empty array + Promise.resolve( + ResponseSuccessJson({ items: [] } as PaginatedBonusActivationsCollection) + ); } diff --git a/src/services/cgnOperatorSearchService.ts b/src/services/cgnOperatorSearchService.ts index 934fe88d6..195131dd4 100644 --- a/src/services/cgnOperatorSearchService.ts +++ b/src/services/cgnOperatorSearchService.ts @@ -1,7 +1,6 @@ /** * This service interacts with the GCN operator search API */ -import { IResponseType } from "@pagopa/ts-commons/lib/requests"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -12,26 +11,27 @@ import { ResponseErrorNotFound, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; + import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; +import { IResponseType } from "@pagopa/ts-commons/lib/requests"; import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; import { PublishedProductCategoriesResult } from "generated/io-cgn-operator-search-api/PublishedProductCategoriesResult"; +import { GetPublishedCategoriesParameters } from "generated/parameters/GetPublishedCategoriesParameters"; import { SearchRequest } from "generated/io-cgn-operator-search-api/SearchRequest"; import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; -import { GetPublishedCategoriesParameters } from "generated/parameters/GetPublishedCategoriesParameters"; - +import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; import { Merchant } from "../../generated/cgn-operator-search/Merchant"; -import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; -import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; -import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; -import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; -import { CgnOperatorSearchAPIClient } from "../../src/clients/cgn-operator-search"; -import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; +import { readableProblem } from "../utils/errorsFormatter"; +import { CgnOperatorSearchAPIClient } from "../../src/clients/cgn-operator-search"; +import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; +import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; +import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; +import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; type ClientResponses = | IResponseType<200, T> @@ -40,90 +40,77 @@ type ClientResponses = type ServiceResponses = | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessJson; export default class CgnService { - private readonly mapResponse = ( - response: ClientResponses, - ): ServiceResponses => { - switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); - case 404: - return ResponseErrorNotFound("Not Found", "Operator Not found"); - case 500: - return ResponseErrorInternal(readableProblem(response.value)); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }; + constructor( + private readonly cgnOperatorSearchApiClient: ReturnType + ) {} /** - * Count CGN merchants/discounts + * Get an array of CGN product categories that have at least a published discount */ - public readonly count = (): Promise> => + public readonly getPublishedProductCategories = ( + params: GetPublishedCategoriesParameters + ): Promise> => withCatchAsInternalError(async () => { - const validated = await this.cgnOperatorSearchApiClient.count({}); + const validated = + await this.cgnOperatorSearchApiClient.getPublishedProductCategories( + params + ); return withValidatedOrInternalError(validated, (response) => - this.mapResponse(response as ClientResponses), + this.mapResponse( + response as ClientResponses + ) ); }); /** - * Get a discount bucket code by discount identifier. + * Get the CGN operator/merchant by its identifier. */ - public readonly getDiscountBucketCode = ( - discountId: NonEmptyString, - ): Promise> => + public readonly getMerchant = ( + merchantId: NonEmptyString + ): Promise> => withCatchAsInternalError(async () => { - const validated = - await this.cgnOperatorSearchApiClient.getDiscountBucketCode({ - discountId, - }); + const validated = await this.cgnOperatorSearchApiClient.getMerchant({ + merchantId, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses, - ), + this.mapResponse(response as ClientResponses) ); }); /** - * Get the CGN operator/merchant by its identifier. + * Count CGN merchants/discounts */ - public readonly getMerchant = ( - merchantId: NonEmptyString, - ): Promise> => + public readonly count = (): Promise> => withCatchAsInternalError(async () => { - const validated = await this.cgnOperatorSearchApiClient.getMerchant({ - merchantId, - }); + const validated = await this.cgnOperatorSearchApiClient.count({}); return withValidatedOrInternalError(validated, (response) => - this.mapResponse(response as ClientResponses), + this.mapResponse(response as ClientResponses) ); }); /** - * Get an array of CGN offline merchants that matches with search criteria - * expressed in OfflineMerchantSearchRequest + * Search CGN merchants/discounts that matches with search criteria */ - public readonly getOfflineMerchants = ( - offlineMerchantSearchRequest: OfflineMerchantSearchRequest, - ): Promise> => + public readonly search = ( + searchRequest: SearchRequest + ): Promise> => withCatchAsInternalError(async () => { - const validated = - await this.cgnOperatorSearchApiClient.getOfflineMerchants({ - body: offlineMerchantSearchRequest, - }); + const validated = await this.cgnOperatorSearchApiClient.search({ + body: searchRequest, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses, - ), + this.mapResponse( + response as ClientResponses + ) ); }); @@ -132,7 +119,7 @@ export default class CgnService { * expressed in OnlineMerchantSearchRequest */ public readonly getOnlineMerchants = ( - onlineMerchantSearchRequest: OnlineMerchantSearchRequest, + onlineMerchantSearchRequest: OnlineMerchantSearchRequest ): Promise> => withCatchAsInternalError(async () => { const validated = @@ -142,49 +129,62 @@ export default class CgnService { return withValidatedOrInternalError(validated, (response) => this.mapResponse( - response as ClientResponses, - ), + response as ClientResponses + ) ); }); /** - * Get an array of CGN product categories that have at least a published discount + * Get an array of CGN offline merchants that matches with search criteria + * expressed in OfflineMerchantSearchRequest */ - public readonly getPublishedProductCategories = ( - params: GetPublishedCategoriesParameters, - ): Promise> => + public readonly getOfflineMerchants = ( + offlineMerchantSearchRequest: OfflineMerchantSearchRequest + ): Promise> => withCatchAsInternalError(async () => { const validated = - await this.cgnOperatorSearchApiClient.getPublishedProductCategories( - params, - ); + await this.cgnOperatorSearchApiClient.getOfflineMerchants({ + body: offlineMerchantSearchRequest, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses, - ), + this.mapResponse( + response as ClientResponses + ) ); }); /** - * Search CGN merchants/discounts that matches with search criteria + * Get a discount bucket code by discount identifier. */ - public readonly search = ( - searchRequest: SearchRequest, - ): Promise> => + public readonly getDiscountBucketCode = ( + discountId: NonEmptyString + ): Promise> => withCatchAsInternalError(async () => { - const validated = await this.cgnOperatorSearchApiClient.search({ - body: searchRequest, - }); + const validated = + await this.cgnOperatorSearchApiClient.getDiscountBucketCode({ + discountId, + }); return withValidatedOrInternalError(validated, (response) => - this.mapResponse( - response as ClientResponses, - ), + this.mapResponse( + response as ClientResponses + ) ); }); - constructor( - private readonly cgnOperatorSearchApiClient: ReturnType, - ) {} + private readonly mapResponse = ( + response: ClientResponses + ): ServiceResponses => { + switch (response.status) { + case 200: + return ResponseSuccessJson(response.value); + case 404: + return ResponseErrorNotFound("Not Found", "Operator Not found"); + case 500: + return ResponseErrorInternal(readableProblem(response.value)); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }; } diff --git a/src/services/cgnService.ts b/src/services/cgnService.ts index a288bb6b9..07ef65ea1 100644 --- a/src/services/cgnService.ts +++ b/src/services/cgnService.ts @@ -2,12 +2,6 @@ * This service interactsnwith the Bonus API */ -import { Card } from "@pagopa/io-functions-cgn-sdk/Card"; -import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; -import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; -import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; -import { InstanceId } from "@pagopa/io-functions-cgn-sdk/InstanceId"; -import { Otp } from "@pagopa/io-functions-cgn-sdk/Otp"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -25,32 +19,41 @@ import { ResponseSuccessJson, ResponseSuccessRedirectToResource, } from "@pagopa/ts-commons/lib/responses"; + import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; - +import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; +import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; +import { InstanceId } from "@pagopa/io-functions-cgn-sdk/InstanceId"; +import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; +import { Card } from "@pagopa/io-functions-cgn-sdk/Card"; +import { Otp } from "@pagopa/io-functions-cgn-sdk/Otp"; import { CgnAPIClient } from "../../src/clients/cgn"; import { User } from "../types/user"; -import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; +import { readableProblem } from "../utils/errorsFormatter"; export default class CgnService { + constructor(private readonly cgnApiClient: ReturnType) {} + /** - * generate a CGN OTP + * Get the current CGN Status related to the user. */ - public readonly generateOtp = ( - user: User, + public readonly getCgnStatus = ( + user: User ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.generateOtp({ + const validated = await this.cgnApiClient.getCgnStatus({ fiscalcode: user.fiscal_code, }); @@ -60,8 +63,8 @@ export default class CgnService { return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; + case 404: + return ResponseErrorNotFound("Not Found", "CGN not found"); case 500: return ResponseErrorInternal(readableProblem(response.value)); default: @@ -71,18 +74,20 @@ export default class CgnService { }); /** - * Get CGN activation status details for the logged user. + * Get the current Eyca Card Status related to the user. */ - public readonly getCgnActivation = ( - user: User, + public readonly getEycaStatus = ( + user: User ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getCgnActivation({ + const validated = await this.cgnApiClient.getEycaStatus({ fiscalcode: user.fiscal_code, }); @@ -92,10 +97,13 @@ export default class CgnService { return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); + case 403: + return ResponseErrorForbiddenNotAuthorized; case 404: - return ResponseErrorNotFound( - "Not Found", - "No User CGN activation found", + return ResponseErrorNotFound("Not Found", "Eyca Card not found"); + case 409: + return ResponseErrorConflict( + "EYCA Card is missing while citizen is eligible to obtain it or a CGN is already activated" ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -106,30 +114,45 @@ export default class CgnService { }); /** - * Get the current CGN Status related to the user. + * Start a CGN activation process for the logged user. */ - public readonly getCgnStatus = ( - user: User, + public readonly startCgnActivation = ( + user: User ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict + | IResponseSuccessRedirectToResource + | IResponseSuccessAccepted > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getCgnStatus({ + const validated = await this.cgnApiClient.startCgnActivation({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); + case 201: + return ResponseSuccessRedirectToResource( + response.value, + pipe( + response.headers.Location, + O.fromNullable, + O.getOrElse(() => "/api/v1/cgn/activation") + ), + response.value + ); + case 202: + return ResponseSuccessAccepted(); case 401: return ResponseErrorUnexpectedAuthProblem(); - case 404: - return ResponseErrorNotFound("Not Found", "CGN not found"); + case 403: + return ResponseErrorForbiddenNotAuthorized; + case 409: + return ResponseErrorConflict( + "Cannot start a new CGN activation because the CGN is already active, revoked or expired" + ); case 500: return ResponseErrorInternal(readableProblem(response.value)); default: @@ -139,18 +162,18 @@ export default class CgnService { }); /** - * Get EYCA's activation status detail for the logged user. + * Get CGN activation status details for the logged user. */ - public readonly getEycaActivation = ( - user: User, + public readonly getCgnActivation = ( + user: User ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getEycaActivation({ + const validated = await this.cgnApiClient.getCgnActivation({ fiscalcode: user.fiscal_code, }); @@ -163,7 +186,7 @@ export default class CgnService { case 404: return ResponseErrorNotFound( "Not Found", - "No EYCA Card activation found", + "No User CGN activation found" ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -174,36 +197,44 @@ export default class CgnService { }); /** - * Get the current Eyca Card Status related to the user. + * Start an EYCA activation for the logged user. */ - public readonly getEycaStatus = ( - user: User, + public readonly startEycaActivation = ( + user: User ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict + | IResponseSuccessRedirectToResource + | IResponseSuccessAccepted > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.getEycaStatus({ + const validated = await this.cgnApiClient.startEycaActivation({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); + case 201: + return ResponseSuccessRedirectToResource( + response.value, + pipe( + response.headers.Location, + O.fromNullable, + O.getOrElse(() => "/api/v1/cgn/eyca/activation") + ), + response.value + ); + case 202: + return ResponseSuccessAccepted(); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: return ResponseErrorForbiddenNotAuthorized; - case 404: - return ResponseErrorNotFound("Not Found", "Eyca Card not found"); case 409: return ResponseErrorConflict( - "EYCA Card is missing while citizen is eligible to obtain it or a CGN is already activated", + "Cannot start a new EYCA activation because EYCA card is already active, revoked or expired" ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -214,44 +245,31 @@ export default class CgnService { }); /** - * Start a CGN activation process for the logged user. + * Get EYCA's activation status detail for the logged user. */ - public readonly startCgnActivation = ( - user: User, + public readonly getEycaActivation = ( + user: User ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessAccepted - | IResponseSuccessRedirectToResource + | IResponseErrorNotFound + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.startCgnActivation({ + const validated = await this.cgnApiClient.getEycaActivation({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 201: - return ResponseSuccessRedirectToResource( - response.value, - pipe( - response.headers.Location, - O.fromNullable, - O.getOrElse(() => "/api/v1/cgn/activation"), - ), - response.value, - ); - case 202: - return ResponseSuccessAccepted(); + case 200: + return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; - case 409: - return ResponseErrorConflict( - "Cannot start a new CGN activation because the CGN is already active, revoked or expired", + case 404: + return ResponseErrorNotFound( + "Not Found", + "No EYCA Card activation found" ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -265,14 +283,14 @@ export default class CgnService { * Start a CGN unsubscription process for the logged user. */ public readonly startCgnUnsubscription = ( - user: User, + user: User ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessAccepted + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorConflict | IResponseSuccessRedirectToResource + | IResponseSuccessAccepted > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.startCgnUnsubscription({ @@ -287,9 +305,9 @@ export default class CgnService { pipe( response.headers.Location, O.fromNullable, - O.getOrElse(() => "/api/v1/cgn/delete"), + O.getOrElse(() => "/api/v1/cgn/delete") ), - response.value, + response.value ); case 202: return ResponseSuccessAccepted(); @@ -299,7 +317,7 @@ export default class CgnService { return ResponseErrorForbiddenNotAuthorized; case 409: return ResponseErrorConflict( - "Cannot start a new CGN unsubscription", + "Cannot start a new CGN unsubscription" ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -310,45 +328,29 @@ export default class CgnService { }); /** - * Start an EYCA activation for the logged user. + * generate a CGN OTP */ - public readonly startEycaActivation = ( - user: User, + public readonly generateOtp = ( + user: User ): Promise< - | IResponseErrorConflict - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessAccepted - | IResponseSuccessRedirectToResource + | IResponseErrorForbiddenNotAuthorized + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.cgnApiClient.startEycaActivation({ + const validated = await this.cgnApiClient.generateOtp({ fiscalcode: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 201: - return ResponseSuccessRedirectToResource( - response.value, - pipe( - response.headers.Location, - O.fromNullable, - O.getOrElse(() => "/api/v1/cgn/eyca/activation"), - ), - response.value, - ); - case 202: - return ResponseSuccessAccepted(); + case 200: + return ResponseSuccessJson(response.value); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: return ResponseErrorForbiddenNotAuthorized; - case 409: - return ResponseErrorConflict( - "Cannot start a new EYCA activation because EYCA card is already active, revoked or expired", - ); case 500: return ResponseErrorInternal(readableProblem(response.value)); default: @@ -356,6 +358,4 @@ export default class CgnService { } }); }); - - constructor(private readonly cgnApiClient: ReturnType) {} } diff --git a/src/services/eucovidcertService.ts b/src/services/eucovidcertService.ts index 886497e47..2cacaaa5c 100644 --- a/src/services/eucovidcertService.ts +++ b/src/services/eucovidcertService.ts @@ -1,5 +1,3 @@ -import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; -import { PreferredLanguages } from "@pagopa/io-functions-eucovidcerts-sdk/PreferredLanguages"; import { HttpStatusCodeEnum, IResponseErrorForbiddenNotAuthorized, @@ -13,15 +11,18 @@ import { ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import { EUCovidCertAPIClient } from "../clients/eucovidcert.client"; -import { User } from "../types/user"; +import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; +import { PreferredLanguages } from "@pagopa/io-functions-eucovidcerts-sdk/PreferredLanguages"; import { readableProblem } from "../utils/errorsFormatter"; +import { EUCovidCertAPIClient } from "../clients/eucovidcert.client"; + import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; +import { User } from "../types/user"; /** * Returns a `504` `Gateway Timeout` error @@ -33,7 +34,7 @@ export function ResponseGatewayTimeout(detail: string): IResponseErrorInternal { ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_504, "Gateway Timeout", - detail, + detail ), kind: "IResponseErrorInternal", }; @@ -45,31 +46,35 @@ export function ResponseGatewayTimeout(detail: string): IResponseErrorInternal { * @param detail The error message */ export function ResponseErrorNotFound403( - detail: string, + detail: string ): IResponseErrorNotFound { return { ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_403, "Not Found", - detail, + detail ), kind: "IResponseErrorNotFound", }; } export default class EUCovidCertService { + constructor( + private readonly eucovidCertApiClient: ReturnType + ) {} + /** * Get the EU Covid Certificte Status related to the user and auth_code */ public readonly getEUCovidCertificate = ( user: User, auth_code: string, - preferred_languages?: PreferredLanguages, + preferred_languages?: PreferredLanguages ): Promise< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorForbiddenNotAuthorized | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -88,13 +93,13 @@ export default class EUCovidCertService { case 400: return ResponseErrorValidation( "Bad Request", - "Payload has bad format", + "Payload has bad format" ); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: return ResponseErrorNotFound403( - "Access data provided are invalid or no Certificate has been emitted for the given Citizen", + "Access data provided are invalid or no Certificate has been emitted for the given Citizen" ); case 500: return ResponseErrorInternal(readableProblem(response.value)); @@ -105,8 +110,4 @@ export default class EUCovidCertService { } }); }); - - constructor( - private readonly eucovidCertApiClient: ReturnType, - ) {} } diff --git a/src/services/fimsService.ts b/src/services/fimsService.ts index 8e46b2481..b070a848b 100644 --- a/src/services/fimsService.ts +++ b/src/services/fimsService.ts @@ -14,11 +14,14 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; + import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; + import { AccessHistoryPage } from "generated/io-fims-api/AccessHistoryPage"; import { ExportRequest } from "generated/io-fims-api/ExportRequest"; import { IoFimsAPIClient } from "../clients/io-fims"; + import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, @@ -28,9 +31,11 @@ import { const invalidRequest = "Invalid request"; export default class FimsService { + constructor(private readonly ioFimsApiClient: ReturnType) {} + public readonly getAccessHistory = ( fiscalCode: FiscalCode, - page?: string, + page?: string ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -48,11 +53,11 @@ export default class FimsService { case 422: return ResponseErrorValidation( invalidRequest, - `An error occurred while validating the request body | ${response.value}`, + `An error occurred while validating the request body | ${response.value}` ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -62,10 +67,10 @@ export default class FimsService { public readonly requestExport = ( fiscalCode: FiscalCode, - email: EmailString, + email: EmailString ): Promise< - | IResponseErrorConflict | IResponseErrorInternal + | IResponseErrorConflict | IResponseErrorValidation | IResponseSuccessAccepted > => @@ -85,17 +90,15 @@ export default class FimsService { case 422: return ResponseErrorValidation( invalidRequest, - `An error occurred while validating the request body | ${response.value}`, + `An error occurred while validating the request body | ${response.value}` ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); default: return ResponseErrorStatusNotDefinedInSpec(response); } }); }); - - constructor(private readonly ioFimsApiClient: ReturnType) {} } diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index 92e0e7260..cf9cf96e4 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -15,15 +15,17 @@ import { ResponseErrorValidation, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; + +import * as E from "fp-ts/Either"; + import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { PromiseType } from "@pagopa/ts-commons/lib/types"; -import * as E from "fp-ts/Either"; import { UpsertServicePreference } from "generated/backend/UpsertServicePreference"; import { APIClient } from "src/clients/api"; - -import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; import { ServicePreference } from "../../generated/backend/ServicePreference"; import { ServicePublic } from "../../generated/backend/ServicePublic"; + +import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, @@ -33,13 +35,14 @@ import { } from "../utils/responses"; import { IApiClientFactoryInterface } from "./IApiClientFactory"; -type RightOf> = - T extends E.Right ? R : never; +type RightOf> = T extends E.Right + ? R + : never; const handleGetServicePreferencesResponse = ( response: RightOf< PromiseType["getServicePreferences"]>> - >, + > ) => { switch (response.status) { case 200: @@ -53,7 +56,7 @@ const handleGetServicePreferencesResponse = ( case 409: return ResponseErrorConflict( response.value.detail ?? - "The Profile is not in the correct preference mode", + "The Profile is not in the correct preference mode" ); case 429: return ResponseErrorTooManyRequests(); @@ -65,11 +68,13 @@ const handleGetServicePreferencesResponse = ( // ---------------------- export default class FunctionsAppService { + constructor(private readonly apiClient: IApiClientFactoryInterface) {} + /** * Retrieve all the information about the service that has sent a message. */ public readonly getService = ( - serviceId: string, + serviceId: string ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -87,13 +92,13 @@ export default class FunctionsAppService { response.status === 200 ? withValidatedOrInternalError( ServicePublic.decode(response.value), - ResponseSuccessJson, + ResponseSuccessJson ) : response.status === 404 - ? ResponseErrorNotFound("Not found", "Service not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status), + ? ResponseErrorNotFound("Not found", "Service not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); @@ -102,13 +107,13 @@ export default class FunctionsAppService { */ public readonly getServicePreferences = ( fiscalCode: FiscalCode, - serviceId: PathTraversalSafePathParam, + serviceId: PathTraversalSafePathParam ): Promise< - | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorTooManyRequests | IResponseErrorValidation + | IResponseErrorConflict + | IResponseErrorTooManyRequests | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -121,7 +126,7 @@ export default class FunctionsAppService { return withValidatedOrInternalError( validated, - handleGetServicePreferencesResponse, + handleGetServicePreferencesResponse ); }); @@ -131,13 +136,13 @@ export default class FunctionsAppService { public readonly upsertServicePreferences = ( fiscalCode: FiscalCode, serviceId: PathTraversalSafePathParam, - servicePreferences: UpsertServicePreference, + servicePreferences: UpsertServicePreference ): Promise< - | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorTooManyRequests | IResponseErrorValidation + | IResponseErrorConflict + | IResponseErrorTooManyRequests | IResponseSuccessJson > => withCatchAsInternalError(async () => { @@ -151,9 +156,7 @@ export default class FunctionsAppService { return withValidatedOrInternalError( validated, - handleGetServicePreferencesResponse, + handleGetServicePreferencesResponse ); }); - - constructor(private readonly apiClient: IApiClientFactoryInterface) {} } diff --git a/src/services/ioSignService.ts b/src/services/ioSignService.ts index 0f87e60cc..4667a58e5 100644 --- a/src/services/ioSignService.ts +++ b/src/services/ioSignService.ts @@ -16,33 +16,37 @@ import { ResponseSuccessJson, ResponseSuccessRedirectToResource, } from "@pagopa/ts-commons/lib/responses"; + +import * as O from "fp-ts/lib/Option"; +import { flow, pipe } from "fp-ts/lib/function"; + +import * as t from "io-ts"; + import { EmailString, FiscalCode, NonEmptyString, } from "@pagopa/ts-commons/lib/strings"; import * as E from "fp-ts/Either"; -import * as O from "fp-ts/lib/Option"; -import { flow, pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; - +import { CreateSignatureBody as CreateSignatureBodyApiModel } from "../../generated/io-sign-api/CreateSignatureBody"; +import { IssuerEnvironment } from "../../generated/io-sign/IssuerEnvironment"; +import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; +import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; import { Id } from "../../generated/io-sign/Id"; -import { IssuerEnvironment } from "../../generated/io-sign/IssuerEnvironment"; + import { QtspClausesMetadataDetailView } from "../../generated/io-sign/QtspClausesMetadataDetailView"; + import { SignatureDetailView } from "../../generated/io-sign/SignatureDetailView"; import { SignatureRequestDetailView } from "../../generated/io-sign/SignatureRequestDetailView"; -import { CreateSignatureBody as CreateSignatureBodyApiModel } from "../../generated/io-sign-api/CreateSignatureBody"; -import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; -import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; import { IoSignAPIClient } from "../clients/io-sign"; -import { IoSignLollipopLocalsType } from "../controllers/ioSignController"; -import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; +import { readableProblem } from "../utils/errorsFormatter"; +import { IoSignLollipopLocalsType } from "../controllers/ioSignController"; import { ResponseErrorNotFound403 } from "./eucovidcertService"; const internalServerError = "Internal server error"; @@ -54,25 +58,63 @@ const userNotFound = export const getEnvironmentFromHeaders = flow( O.fromPredicate( (headers: object): headers is Headers => - headers && "get" in headers && typeof headers.get === "function", + headers && "get" in headers && typeof headers.get === "function" ), O.map((headers) => headers.get("x-io-sign-environment")), O.chain(O.fromNullable), O.chainEitherK(t.keyof({ prod: true, test: true }).decode), - O.getOrElse(() => "prod"), + O.getOrElse(() => "prod") ); export default class IoSignService { + constructor(private readonly ioSignApiClient: ReturnType) {} + + /** + * Get the Signer id related to the user. + */ + public readonly getSignerByFiscalCode = ( + fiscalCode: FiscalCode + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => { + const validated = await this.ioSignApiClient.getSignerByFiscalCode({ + body: { fiscal_code: fiscalCode }, + }); + return withValidatedOrInternalError(validated, (response) => { + switch (response.status) { + case 200: + return ResponseSuccessJson(response.value); + case 400: + return ResponseErrorValidation( + invalidRequest, + `An error occurred while validating the request body | ${response.value}` + ); + case 403: + return ResponseErrorNotFound403(userNotFound); + case 500: + return ResponseErrorInternal( + `Internal server error | ${response.value}` + ); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }); + }); + public readonly createFilledDocument = ( document_url: NonEmptyString, email: EmailString, family_name: NonEmptyString, name: NonEmptyString, - signerId: Id, + signerId: Id ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound | IResponseSuccessRedirectToResource< FilledDocumentDetailView, FilledDocumentDetailView @@ -96,14 +138,14 @@ export default class IoSignService { pipe( response.headers.Location, O.fromNullable, - O.getOrElse(() => response.value.filled_document_url), + O.getOrElse(() => response.value.filled_document_url) ), - response.value, + response.value ); case 400: return ResponseErrorValidation( invalidRequest, - `An error occurred while validating the request body | ${response.value}`, + `An error occurred while validating the request body | ${response.value}` ); case 404: return ResponseErrorNotFound(resourcesNotFound, userNotFound); @@ -115,8 +157,8 @@ export default class IoSignService { response.value, ProblemJson.decode, E.map(readableProblem), - E.getOrElse(() => internalServerError), - ), + E.getOrElse(() => internalServerError) + ) ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -125,48 +167,31 @@ export default class IoSignService { }); /** - * Create a Signature from a Signature Request + * Get the QTSP clauses */ - public readonly createSignature = ( - ioSignLollipopLocals: IoSignLollipopLocalsType, - body: CreateSignatureBodyApiModel, - signerId: Id, + public readonly getQtspClausesMetadata = ( + issuerEnvironment: IssuerEnvironment ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioSignApiClient.createSignature({ - ...ioSignLollipopLocals, - body, - "x-iosign-signer-id": signerId, + const validated = await this.ioSignApiClient.getQtspClausesMetadata({ + "x-iosign-issuer-environment": issuerEnvironment, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); - case 400: - return ResponseErrorValidation( - invalidRequest, - `An error occurred while validating the request body | ${response.value}`, - ); - case 404: - return ResponseErrorNotFound( - resourcesNotFound, - "Signature request not found", - ); - case 403: - return ResponseErrorNotFound403(userNotFound); case 500: return ResponseErrorInternal( + // TODO [SFEQS-1199]: When the code for openapi-codegen-ts is fixed, refactor this section. + // Now, it generates incorrect output whenever the http status is 500. [SFEQS-1199] pipe( response.value, ProblemJson.decode, E.map(readableProblem), - E.getOrElse(() => internalServerError), - ), + E.getOrElse(() => internalServerError) + ) ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -175,31 +200,48 @@ export default class IoSignService { }); /** - * Get the QTSP clauses + * Create a Signature from a Signature Request */ - public readonly getQtspClausesMetadata = ( - issuerEnvironment: IssuerEnvironment, + public readonly createSignature = ( + ioSignLollipopLocals: IoSignLollipopLocalsType, + body: CreateSignatureBodyApiModel, + signerId: Id ): Promise< - IResponseErrorInternal | IResponseSuccessJson + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioSignApiClient.getQtspClausesMetadata({ - "x-iosign-issuer-environment": issuerEnvironment, + const validated = await this.ioSignApiClient.createSignature({ + ...ioSignLollipopLocals, + body, + "x-iosign-signer-id": signerId, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); + case 400: + return ResponseErrorValidation( + invalidRequest, + `An error occurred while validating the request body | ${response.value}` + ); + case 404: + return ResponseErrorNotFound( + resourcesNotFound, + "Signature request not found" + ); + case 403: + return ResponseErrorNotFound403(userNotFound); case 500: return ResponseErrorInternal( - // TODO [SFEQS-1199]: When the code for openapi-codegen-ts is fixed, refactor this section. - // Now, it generates incorrect output whenever the http status is 500. [SFEQS-1199] pipe( response.value, ProblemJson.decode, E.map(readableProblem), - E.getOrElse(() => internalServerError), - ), + E.getOrElse(() => internalServerError) + ) ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -212,7 +254,7 @@ export default class IoSignService { */ public readonly getSignatureRequest = ( signatureRequestId: Id, - signerId: Id, + signerId: Id ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -232,7 +274,7 @@ export default class IoSignService { .status(HttpStatusCodeEnum.HTTP_STATUS_200) .header( "x-io-sign-environment", - getEnvironmentFromHeaders(response.headers), + getEnvironmentFromHeaders(response.headers) ) .json(response.value), kind: "IResponseSuccessJson", @@ -241,7 +283,7 @@ export default class IoSignService { case 404: return ResponseErrorNotFound( resourcesNotFound, - "Signature request not found", + "Signature request not found" ); case 403: return ResponseErrorNotFound403(userNotFound); @@ -255,7 +297,7 @@ export default class IoSignService { * Get Signature Requests list from Signer */ public readonly getSignatureRequests = ( - signerId: Id, + signerId: Id ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -276,42 +318,4 @@ export default class IoSignService { } }); }); - - /** - * Get the Signer id related to the user. - */ - public readonly getSignerByFiscalCode = ( - fiscalCode: FiscalCode, - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorValidation - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const validated = await this.ioSignApiClient.getSignerByFiscalCode({ - body: { fiscal_code: fiscalCode }, - }); - return withValidatedOrInternalError(validated, (response) => { - switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); - case 400: - return ResponseErrorValidation( - invalidRequest, - `An error occurred while validating the request body | ${response.value}`, - ); - case 403: - return ResponseErrorNotFound403(userNotFound); - case 500: - return ResponseErrorInternal( - `Internal server error | ${response.value}`, - ); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }); - }); - - constructor(private readonly ioSignApiClient: ReturnType) {} } diff --git a/src/services/ioWalletService.ts b/src/services/ioWalletService.ts index ea763d0dc..daba993b8 100644 --- a/src/services/ioWalletService.ts +++ b/src/services/ioWalletService.ts @@ -1,8 +1,10 @@ +/* eslint-disable sonarjs/no-identical-functions */ /** * This service interacts with the IO Wallet API */ import { + getResponseErrorForbiddenNotAuthorized, IResponseErrorForbiddenNotAuthorized, IResponseErrorGeneric, IResponseErrorInternal, @@ -16,26 +18,25 @@ import { ResponseErrorServiceTemporarilyUnavailable, ResponseSuccessJson, ResponseSuccessNoContent, - getResponseErrorForbiddenNotAuthorized, } from "@pagopa/ts-commons/lib/responses"; + import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import * as O from "fp-ts/Option"; -import { pipe } from "fp-ts/lib/function"; -import { Grant_typeEnum } from "generated/io-wallet-api/CreateWalletAttestationBody"; import { NonceDetailView } from "generated/io-wallet-api/NonceDetailView"; - -import { SetWalletInstanceStatusWithFiscalCodeData } from "../../generated/io-wallet-api/SetWalletInstanceStatusWithFiscalCodeData"; -import { WalletAttestationView } from "../../generated/io-wallet-api/WalletAttestationView"; -import { WalletInstanceData } from "../../generated/io-wallet-api/WalletInstanceData"; -import { Subscription } from "../../generated/trial-system-api/Subscription"; +import { Grant_typeEnum } from "generated/io-wallet-api/CreateWalletAttestationBody"; +import { pipe } from "fp-ts/lib/function"; +import * as O from "fp-ts/Option"; import { IoWalletAPIClient } from "../clients/io-wallet"; -import { TrialSystemAPIClient } from "../clients/trial-system.client"; -import { IO_WALLET_TRIAL_ID } from "../config"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; +import { IO_WALLET_TRIAL_ID } from "../config"; +import { TrialSystemAPIClient } from "../clients/trial-system.client"; +import { Subscription } from "../../generated/trial-system-api/Subscription"; +import { WalletAttestationView } from "../../generated/io-wallet-api/WalletAttestationView"; +import { SetWalletInstanceStatusWithFiscalCodeData } from "../../generated/io-wallet-api/SetWalletInstanceStatusWithFiscalCodeData"; +import { WalletInstanceData } from "../../generated/io-wallet-api/WalletInstanceData"; const unprocessableContentError = "Unprocessable Content"; const invalidRequest = "Your request didn't validate"; @@ -47,62 +48,35 @@ const conflictErrorDetail = "There has been a conflict"; const serviceUnavailableDetail = "Service Unavailable. Please try again later"; export default class IoWalletService { + constructor( + private readonly ioWalletApiClient: ReturnType, + private readonly trialSystemApiClient: ReturnType< + typeof TrialSystemAPIClient + > + ) {} + /** - * Create a Wallet Attestation. + * Get a nonce. */ - public readonly createWalletAttestation = ( - assertion: NonEmptyString, - grant_type: Grant_typeEnum, - fiscal_code: FiscalCode, - ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorGeneric + public readonly getNonce = (): Promise< | IResponseErrorInternal - | IResponseErrorNotFound + | IResponseSuccessJson | IResponseErrorServiceUnavailable - | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.createWalletAttestation({ - body: { - assertion, - fiscal_code, - grant_type, - }, - }); + const validated = await this.ioWalletApiClient.getNonce({}); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); - case 403: - return getResponseErrorForbiddenNotAuthorized( - "Wallet instance has been revoked", - ); - case 404: - return ResponseErrorNotFound( - "Not Found", - "Wallet instance not found", - ); - case 409: - return ResponseErrorGeneric( - response.status, - conflictErrorTitle, - conflictErrorDetail, - ); - case 422: - return ResponseErrorGeneric( - response.status, - unprocessableContentError, - invalidRequest, - ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10", + "10" ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -117,12 +91,12 @@ export default class IoWalletService { challenge: NonEmptyString, hardware_key_tag: NonEmptyString, key_attestation: NonEmptyString, - fiscal_code: FiscalCode, + fiscal_code: FiscalCode ): Promise< - | IResponseErrorGeneric | IResponseErrorInternal - | IResponseErrorServiceUnavailable + | IResponseErrorGeneric | IResponseSuccessNoContent + | IResponseErrorServiceUnavailable > => withCatchAsInternalError(async () => { const validated = await this.ioWalletApiClient.createWalletInstance({ @@ -141,22 +115,22 @@ export default class IoWalletService { return ResponseErrorGeneric( response.status, conflictErrorTitle, - conflictErrorDetail, + conflictErrorDetail ); case 422: return ResponseErrorGeneric( response.status, unprocessableContentError, - invalidRequest, + invalidRequest ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10", + "10" ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -165,71 +139,61 @@ export default class IoWalletService { }); /** - * Get a nonce. + * Create a Wallet Attestation. */ - public readonly getNonce = (): Promise< + public readonly createWalletAttestation = ( + assertion: NonEmptyString, + grant_type: Grant_typeEnum, + fiscal_code: FiscalCode + ): Promise< | IResponseErrorInternal + | IResponseErrorGeneric + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorNotFound + | IResponseSuccessJson | IResponseErrorServiceUnavailable - | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.getNonce({}); + const validated = await this.ioWalletApiClient.createWalletAttestation({ + body: { + assertion, + fiscal_code, + grant_type, + }, + }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: return ResponseSuccessJson(response.value); + case 403: + return getResponseErrorForbiddenNotAuthorized( + "Wallet instance has been revoked" + ); + case 404: + return ResponseErrorNotFound( + "Not Found", + "Wallet instance not found" + ); + case 409: + return ResponseErrorGeneric( + response.status, + conflictErrorTitle, + conflictErrorDetail + ); + case 422: + return ResponseErrorGeneric( + response.status, + unprocessableContentError, + invalidRequest + ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10", - ); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }); - }); - - /** - * Get the subscription given a specific user. - */ - public readonly getSubscription = async ( - userId: NonEmptyString, - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseSuccessJson> - > => - withCatchAsInternalError(async () => { - const validated = await this.trialSystemApiClient.getSubscription({ - trialId: IO_WALLET_TRIAL_ID, - userId, - }); - - return withValidatedOrInternalError(validated, (response) => { - switch (response.status) { - case 200: - return pipe( - { - createdAt: response.value.createdAt, - state: response.value.state, - }, - ResponseSuccessJson, - ); - case 401: - return ResponseErrorInternal("Internal server error"); - case 404: - return ResponseErrorNotFound("Not Found", "Subscription not found"); - case 500: - return ResponseErrorInternal( - pipe( - response.value.detail, - O.fromNullable, - O.getOrElse(() => "Cannot get subscription"), - ), + "10" ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -238,41 +202,36 @@ export default class IoWalletService { }); /** - * Get current Wallet Instance status. + * Update current Wallet Instance status. */ - public readonly getWalletInstanceStatus = ( + public readonly setWalletInstanceStatus = ( id: NonEmptyString, - fiscal_code: FiscalCode, + status: SetWalletInstanceStatusWithFiscalCodeData["status"], + fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"] ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound + | IResponseSuccessNoContent | IResponseErrorServiceUnavailable - | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.getWalletInstanceStatus({ - "fiscal-code": fiscal_code, + const validated = await this.ioWalletApiClient.setWalletInstanceStatus({ + body: { fiscal_code, status }, id, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 200: - return ResponseSuccessJson(response.value); - case 404: - return ResponseErrorNotFound( - "Not Found", - "Wallet instance not found", - ); + case 204: + return ResponseSuccessNoContent(); case 400: case 422: case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10", + "10" ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -285,12 +244,12 @@ export default class IoWalletService { */ public readonly setCurrentWalletInstanceStatus = ( status: SetWalletInstanceStatusWithFiscalCodeData["status"], - fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"], + fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"] ): Promise< - | IResponseErrorGeneric | IResponseErrorInternal - | IResponseErrorServiceUnavailable + | IResponseErrorGeneric | IResponseSuccessNoContent + | IResponseErrorServiceUnavailable > => withCatchAsInternalError(async () => { const validated = @@ -305,16 +264,16 @@ export default class IoWalletService { return ResponseErrorGeneric( response.status, unprocessableContentError, - invalidRequest, + invalidRequest ); case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10", + "10" ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -323,36 +282,41 @@ export default class IoWalletService { }); /** - * Update current Wallet Instance status. + * Get current Wallet Instance status. */ - public readonly setWalletInstanceStatus = ( + public readonly getWalletInstanceStatus = ( id: NonEmptyString, - status: SetWalletInstanceStatusWithFiscalCodeData["status"], - fiscal_code: SetWalletInstanceStatusWithFiscalCodeData["fiscal_code"], + fiscal_code: FiscalCode ): Promise< + | IResponseSuccessJson + | IResponseErrorNotFound | IResponseErrorInternal | IResponseErrorServiceUnavailable - | IResponseSuccessNoContent > => withCatchAsInternalError(async () => { - const validated = await this.ioWalletApiClient.setWalletInstanceStatus({ - body: { fiscal_code, status }, + const validated = await this.ioWalletApiClient.getWalletInstanceStatus({ + "fiscal-code": fiscal_code, id, }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { - case 204: - return ResponseSuccessNoContent(); + case 200: + return ResponseSuccessJson(response.value); + case 404: + return ResponseErrorNotFound( + "Not Found", + "Wallet instance not found" + ); case 400: case 422: case 500: return ResponseErrorInternal( - `Internal server error | ${response.value}`, + `Internal server error | ${response.value}` ); case 503: return ResponseErrorServiceTemporarilyUnavailable( serviceUnavailableDetail, - "10", + "10" ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -360,10 +324,47 @@ export default class IoWalletService { }); }); - constructor( - private readonly ioWalletApiClient: ReturnType, - private readonly trialSystemApiClient: ReturnType< - typeof TrialSystemAPIClient - >, - ) {} + /** + * Get the subscription given a specific user. + */ + public readonly getSubscription = async ( + userId: NonEmptyString + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseSuccessJson> + > => + withCatchAsInternalError(async () => { + const validated = await this.trialSystemApiClient.getSubscription({ + trialId: IO_WALLET_TRIAL_ID, + userId, + }); + + return withValidatedOrInternalError(validated, (response) => { + switch (response.status) { + case 200: + return pipe( + { + createdAt: response.value.createdAt, + state: response.value.state, + }, + ResponseSuccessJson + ); + case 401: + return ResponseErrorInternal("Internal server error"); + case 404: + return ResponseErrorNotFound("Not Found", "Subscription not found"); + case 500: + return ResponseErrorInternal( + pipe( + response.value.detail, + O.fromNullable, + O.getOrElse(() => "Cannot get subscription") + ) + ); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }); + }); } diff --git a/src/services/lollipopService.ts b/src/services/lollipopService.ts index 0a32412df..d956d4370 100644 --- a/src/services/lollipopService.ts +++ b/src/services/lollipopService.ts @@ -1,6 +1,5 @@ import { QueueClient, QueueSendMessageResponse } from "@azure/storage-queue"; import { RevokeAssertionRefInfo } from "@pagopa/io-functions-commons/dist/src/entities/revoke_assertion_ref_info"; - import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; import { base64EncodeObject } from "../utils/messages"; @@ -9,11 +8,11 @@ export default class LollipopService { constructor( private readonly queueStorageConnectionString: string, - private readonly queueName: string, + private readonly queueName: string ) { this.queueClient = new QueueClient( this.queueStorageConnectionString, - this.queueName, + this.queueName ); } @@ -24,7 +23,7 @@ export default class LollipopService { * @param assertionRef the pub key identifier */ public revokePreviousAssertionRef( - assertionRef: AssertionRef, + assertionRef: AssertionRef ): Promise { const revokeMessage = RevokeAssertionRefInfo.encode({ assertion_ref: assertionRef, diff --git a/src/services/newMessagesService.ts b/src/services/newMessagesService.ts index 104ec8b2c..962316fff 100644 --- a/src/services/newMessagesService.ts +++ b/src/services/newMessagesService.ts @@ -1,67 +1,56 @@ /** * This service retrieves messages from the API system using an API client. */ +import * as t from "io-ts"; +import nodeFetch from "node-fetch"; import { - IResponseErrorBadGateway, IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, - IResponseErrorNotFound, IResponseErrorServiceUnavailable, + IResponseErrorNotFound, IResponseErrorTooManyRequests, IResponseErrorValidation, IResponseSuccessJson, - IResponseSuccessNoContent, - ResponseErrorBadGateway, - ResponseErrorForbiddenNotAuthorized, - ResponseErrorInternal, ResponseErrorNotFound, - ResponseErrorServiceTemporarilyUnavailable, ResponseErrorTooManyRequests, - ResponseErrorValidation, ResponseSuccessJson, + ResponseErrorForbiddenNotAuthorized, + ResponseErrorInternal, + ResponseErrorValidation, + ResponseErrorServiceTemporarilyUnavailable, + IResponseSuccessNoContent, + ResponseErrorBadGateway, + IResponseErrorBadGateway, } from "@pagopa/ts-commons/lib/responses"; +import { AppMessagesAPIClient } from "src/clients/app-messages.client"; import { FiscalCode, NonEmptyString, Ulid, } from "@pagopa/ts-commons/lib/strings"; +import { pipe, flow } from "fp-ts/lib/function"; +import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; import * as T from "fp-ts/Task"; -import * as TE from "fp-ts/TaskEither"; -import { flow, pipe } from "fp-ts/lib/function"; -import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; -import * as t from "io-ts"; -import nodeFetch from "node-fetch"; -import { AppMessagesAPIClient } from "src/clients/app-messages.client"; import { LollipopLocalsType } from "src/types/lollipop"; - -import { CreatedMessageWithContentAndAttachments } from "../../generated/backend/CreatedMessageWithContentAndAttachments"; -import { InvalidThirdPartyMessageTypeEnum } from "../../generated/backend/InvalidThirdPartyMessageType"; -import { MessageBodyMarkdown } from "../../generated/backend/MessageBodyMarkdown"; -import { MessageSubject } from "../../generated/backend/MessageSubject"; -import { ThirdPartyData } from "../../generated/backend/ThirdPartyData"; -import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; -import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; -import { CreatedMessageWithContent } from "../../generated/io-messages-api/CreatedMessageWithContent"; -import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; -import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; -import { PaginatedPublicMessagesCollection } from "../../generated/io-messages-api/PaginatedPublicMessagesCollection"; -import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; -import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; -import { - ThirdPartyMessage, - ThirdPartyMessageDetails, -} from "../../generated/third-party-service/ThirdPartyMessage"; +import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; import { Fetch, getThirdPartyServiceClient, } from "../clients/third-party-service-client"; import { PN_SERVICE_ID } from "../config"; -import { User } from "../types/user"; +import { MessageSubject } from "../../generated/backend/MessageSubject"; +import { InvalidThirdPartyMessageTypeEnum } from "../../generated/backend/InvalidThirdPartyMessageType"; +import { CreatedMessageWithContent } from "../../generated/io-messages-api/CreatedMessageWithContent"; +import { PaginatedPublicMessagesCollection } from "../../generated/io-messages-api/PaginatedPublicMessagesCollection"; +import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; +import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; +import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; +import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; +import { CreatedMessageWithContentAndAttachments } from "../../generated/backend/CreatedMessageWithContentAndAttachments"; import { getPrescriptionAttachments } from "../utils/attachments"; -import { FileType, getIsFileTypeForTypes } from "../utils/file-type"; -import { log } from "../utils/logger"; +import { User } from "../types/user"; import { IResponseErrorUnsupportedMediaType, IResponseSuccessOctet, @@ -74,6 +63,16 @@ import { withValidatedOrInternalError, wrapValidationWithInternalError, } from "../utils/responses"; +import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; +import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; +import { + ThirdPartyMessage, + ThirdPartyMessageDetails, +} from "../../generated/third-party-service/ThirdPartyMessage"; +import { ThirdPartyData } from "../../generated/backend/ThirdPartyData"; +import { log } from "../utils/logger"; +import { FileType, getIsFileTypeForTypes } from "../utils/file-type"; +import { MessageBodyMarkdown } from "../../generated/backend/MessageBodyMarkdown"; const ALLOWED_TYPES: ReadonlySet = new Set(["pdf"]); @@ -91,130 +90,408 @@ export type MessageWithThirdPartyData = t.TypeOf< >; const isMessageWithThirdPartyData = ( - value: CreatedMessageWithContent, + value: CreatedMessageWithContent ): value is MessageWithThirdPartyData => E.isRight(MessageWithThirdPartyData.decode(value)); export default class NewMessagesService { - // return an error otherwise - private readonly getThirdPartyAttachmentFromThirdPartyService = ( + constructor( + private readonly apiClient: ReturnType + ) {} + + /** + * Retrieves all messages for a specific user. + */ + public readonly getMessagesByUser = ( + user: User, + params: GetMessagesParameters + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => { + const validated = await this.apiClient.getMessagesByUser({ + /* eslint-disable sort-keys */ + fiscal_code: user.fiscal_code, + page_size: params.pageSize, + enrich_result_data: params.enrichResultData, + archived: params.getArchivedMessages, + maximum_id: params.maximumId, + minimum_id: params.minimumId, + /* eslint-enable sort-keys */ + }); + + return withValidatedOrInternalError(validated, (response) => + response.status === 200 + ? ResponseSuccessJson(response.value) + : response.status === 404 + ? ResponseErrorNotFound("Not found", "User not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) + ); + }); + + /** + * Retrieves a specific message. + */ + public readonly getMessage = async ( + user: User, + params: GetMessageParameters + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => { + const res = await this.apiClient.getMessage({ + fiscal_code: user.fiscal_code, + id: params.id, + public_message: params.public_message, + }); + + const resMessageContent = pipe( + res, + E.map((_) => (_.status === 200 ? { ..._, value: _.value.message } : _)) + ); + + return withValidatedOrInternalError( + resMessageContent, + async (response) => { + if (response.status === 200) { + const messageWithContent = response.value; + const maybePrescriptionData = O.fromNullable( + messageWithContent.content.prescription_data + ); + + return O.isNone(maybePrescriptionData) + ? ResponseSuccessJson(messageWithContent) + : pipe( + getPrescriptionAttachments(maybePrescriptionData.value), + T.map((attachments) => ({ + ...messageWithContent, + content: { + ...messageWithContent.content, + attachments, + }, + })), + T.map(ResponseSuccessJson) + )(); + } + + return response.status === 404 + ? ResponseErrorNotFound("Not found", "Message not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status); + } + ); + }); + + /** + * Retrieve the service preferences fot the defined user and service + */ + public readonly upsertMessageStatus = ( + fiscalCode: FiscalCode, + messageId: Ulid, + messageStatusChange: MessageStatusChange + ): Promise< + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorTooManyRequests + | IResponseSuccessJson + > => + withCatchAsInternalError(async () => { + const validated = await this.apiClient.upsertMessageStatusAttributes({ + body: messageStatusChange, + fiscal_code: fiscalCode, + id: messageId, + }); + + // eslint-disable-next-line sonarjs/no-identical-functions + return withValidatedOrInternalError(validated, (response) => { + switch (response.status) { + case 200: + return ResponseSuccessJson({ + is_archived: response.value.is_archived, + is_read: response.value.is_read, + }); + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 403: + return ResponseErrorForbiddenNotAuthorized; + case 404: + return ResponseErrorNotFound( + "Not Found", + "Message status not found" + ); + case 429: + return ResponseErrorTooManyRequests(); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }); + }); + + // ------------------------------ + // THIRD_PARTY MESSAGE + // ------------------------------ + + /** + * Retrieves the precondition of a specific Third-Party message. + */ + public readonly getThirdPartyMessagePrecondition = async ( message: MessageWithThirdPartyData, - attachmentUrl: NonEmptyString, remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType, - ): TE.TaskEither< - | IResponseErrorForbiddenNotAuthorized + lollipopLocals?: LollipopLocalsType + ): Promise< | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized | IResponseErrorNotFound - | IResponseErrorServiceUnavailable | IResponseErrorTooManyRequests - | IResponseErrorValidation, - Buffer + | IResponseSuccessNoContent + | IResponseSuccessJson > => pipe( - getThirdPartyServiceClient( + this.getThirdPartyMessagePreconditionFromThirdPartyService( + message, remoteContentConfiguration, - nodeFetch as unknown as Fetch, - lollipopLocals, - ), - TE.of, - TE.map((getClientByFiscalCode) => - getClientByFiscalCode(message.fiscal_code), + lollipopLocals ), - TE.chainW((client) => - TE.tryCatch( - () => - client.getThirdPartyMessageAttachment({ - attachment_url: attachmentUrl, - id: message.content.third_party_data.id, - ...lollipopLocals, - }), - (e) => ResponseErrorInternal(E.toError(e).message), + TE.map(ResponseSuccessJson), + TE.toUnion + )(); + + /** + * Retrieves a specific Third-Party message. + */ + public readonly getThirdPartyMessage = async ( + message: MessageWithThirdPartyData, + remoteContentConfiguration: RCConfigurationPublic, + lollipopLocals?: LollipopLocalsType + ): Promise< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorBadGateway + | IResponseSuccessJson + > => + pipe( + pipe( + this.getThirdPartyMessageFromThirdPartyService( + message, + remoteContentConfiguration, + lollipopLocals ), + TE.map((thirdPartyMessage) => ({ + ...message, + third_party_message: thirdPartyMessage, + })) ), - TE.chainW(wrapValidationWithInternalError), + TE.map(ResponseSuccessJson), + TE.toUnion + )(); + + /** + * Retrieves an attachment related to a message + */ + public readonly getThirdPartyAttachment = async ( + message: MessageWithThirdPartyData, + attachmentUrl: NonEmptyString, + remoteContentConfiguration: RCConfigurationPublic, + lollipopLocals?: LollipopLocalsType + ): Promise< + | IResponseErrorInternal + | IResponseErrorServiceUnavailable + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorNotFound + | IResponseErrorTooManyRequests + | IResponseErrorUnsupportedMediaType + | IResponseSuccessOctet + > => + pipe( + pipe( + this.getThirdPartyAttachmentFromThirdPartyService( + message, + attachmentUrl, + remoteContentConfiguration, + lollipopLocals + ) + ), + TE.filterOrElseW(getIsFileTypeForTypes(ALLOWED_TYPES), () => + ResponseErrorUnsupportedMediaType( + "The requested file is not a valid PDF" + ) + ), + TE.map(ResponseSuccessOctet), + TE.toUnion + )(); + + public readonly getThirdPartyMessageFnApp = ( + fiscalCode: FiscalCode, + messageId: Ulid + ): TE.TaskEither< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorNotFound + | IResponseErrorTooManyRequests, + MessageWithThirdPartyData + > => + pipe( + TE.tryCatch( + () => + this.apiClient.getMessage({ + fiscal_code: fiscalCode, + id: messageId, + }), + (e) => ResponseErrorInternal(E.toError(e).message) + ), + TE.chain(wrapValidationWithInternalError), + TE.chainW( flow( (response) => - response.status === 200 ? E.of(response.value) : E.left(response), + response.status === 200 + ? E.of(response.value.message) + : E.left(response), TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getThirdPartyAttachmentFromThirdPartyService|invocation returned an error:${ + `newMessagesService|getThirdPartyMessageFnApp|result:${ response.status - } [title: ${response.value?.title ?? "No title"}, detail: ${ - response.value?.detail ?? "No details" - }, type: ${response.value?.type ?? "No type"}])`, + } [title: ${response.value?.title ?? "No title"}, detail: ${ + response.value?.detail ?? "No detail" + }, type: ${response.value?.type ?? "No type"}]` ); return response; }), - TE.mapLeft( - flow((response) => { - switch (response.status) { - case 400: - return ResponseErrorValidation(ERROR_MESSAGE_400, ""); - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; - case 404: - return ResponseErrorNotFound( - "Not found", - "Attachment from Third Party service not found", - ); - case 429: - return ResponseErrorTooManyRequests(); - case 500: - return ResponseErrorInternal(ERROR_MESSAGE_500); - case 503: - // eslint-disable-next-line no-case-declarations - const retryAfter = response.headers["Retry-After"] ?? "10"; - return ResponseErrorServiceTemporarilyUnavailable( - ERROR_MESSAGE_503, - retryAfter, - ); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }), - ), - ), + TE.mapLeft((response) => { + switch (response.status) { + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 404: + return ResponseErrorNotFound("Not found", "Message not found"); + case 429: + return ResponseErrorTooManyRequests(); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }) + ) + ), + TE.chainW( + // MessageWithThirdPartyData.is fails, we need to check the decode instead + TE.fromPredicate(isMessageWithThirdPartyData, () => + ResponseErrorValidation( + "Bad request", + "The message retrieved is not a valid message with third-party data" + ) + ) + ) + ); + + public readonly getRCConfiguration = ( + configurationId: Ulid + ): TE.TaskEither< + | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized + | IResponseErrorNotFound + | IResponseErrorTooManyRequests, + RCConfigurationPublic + > => + pipe( + TE.tryCatch( + () => + this.apiClient.getRCConfiguration({ + id: configurationId, + }), + (e) => ResponseErrorInternal(E.toError(e).message) ), + TE.chain(wrapValidationWithInternalError), + + TE.chainW( + flow( + (response) => + response.status === 200 ? E.of(response.value) : E.left(response), + TE.fromEither, + TE.mapLeft((response) => { + log.error( + `newMessagesService|getRCConfiguration|result:${ + response.status + } [title: ${response.value?.title ?? "No title"}, detail: ${ + response.value?.detail ?? "No detail" + }, type: ${response.value?.type ?? "No type"}]` + ); + return response; + }), + TE.mapLeft((response) => { + switch (response.status) { + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 404: + return ResponseErrorNotFound( + "Not found", + "RC Configuration not found" + ); + case 429: + return ResponseErrorTooManyRequests(); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }) + ) + ) ); + // ------------------------------------ + // Private Functions + // ------------------------------------ + + // Retrieve a ThirdParty message precondition for a specific message, if exists // return an error otherwise - private readonly getThirdPartyMessageFromThirdPartyService = ( + private readonly getThirdPartyMessagePreconditionFromThirdPartyService = ( message: MessageWithThirdPartyData, remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType, + lollipopLocals?: LollipopLocalsType ): TE.TaskEither< - | IResponseErrorBadGateway - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation, - ThirdPartyMessage + | IResponseSuccessNoContent, + ThirdPartyMessagePrecondition > => pipe( getThirdPartyServiceClient( remoteContentConfiguration, nodeFetch as unknown as Fetch, - lollipopLocals, + lollipopLocals ), TE.of, TE.map((getClientByFiscalCode) => - getClientByFiscalCode(message.fiscal_code), + getClientByFiscalCode(message.fiscal_code) ), - TE.chainW((client) => + TE.chain((client) => TE.tryCatch( () => - client.getThirdPartyMessageDetails({ + client.getThirdPartyMessagePrecondition({ id: message.content.third_party_data.id, ...lollipopLocals, }), - (e) => ResponseErrorInternal(E.toError(e).message), - ), + (e) => ResponseErrorInternal(E.toError(e).message) + ) ), TE.chainW(wrapValidationWithInternalError), TE.chainW( @@ -224,11 +501,12 @@ export default class NewMessagesService { TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getThirdPartyMessageFromThirdPartyService|invocation returned an error:${ + `newMessagesService|getThirdPartyMessagePreconditionFromThirdPartyService|invocation returned an error:${ response.status } [title: ${response.value?.title ?? "No title"}, detail: ${ + // eslint-disable-next-line sonarjs/no-duplicate-string response.value?.detail ?? "No details" - }, type: ${response.value?.type ?? "No type"}]`, + }, type: ${response.value?.type ?? "No type"}]` ); return response; }), @@ -236,7 +514,10 @@ export default class NewMessagesService { flow((response) => { switch (response.status) { case 400: - return ResponseErrorValidation(ERROR_MESSAGE_400, ""); + return ResponseErrorValidation( + ERROR_MESSAGE_400, + "Third party service returned 400" + ); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: @@ -244,7 +525,7 @@ export default class NewMessagesService { case 404: return ResponseErrorNotFound( "Not found", - "Message from Third Party service not found", + "Message from Third Party service not found" ); case 429: return ResponseErrorTooManyRequests(); @@ -253,48 +534,46 @@ export default class NewMessagesService { default: return ResponseErrorStatusNotDefinedInSpec(response); } - }), - ), - TE.chainW((response) => - this.validateThirdPartyMessageResponse(message, response), - ), - ), - ), + }) + ) + ) + ) ); + // Retrieve a ThirdParty message detail from related service, if exists // return an error otherwise - private readonly getThirdPartyMessagePreconditionFromThirdPartyService = ( + private readonly getThirdPartyMessageFromThirdPartyService = ( message: MessageWithThirdPartyData, remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType, + lollipopLocals?: LollipopLocalsType ): TE.TaskEither< - | IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessNoContent, - ThirdPartyMessagePrecondition + | IResponseErrorBadGateway, + ThirdPartyMessage > => pipe( getThirdPartyServiceClient( remoteContentConfiguration, nodeFetch as unknown as Fetch, - lollipopLocals, + lollipopLocals ), TE.of, TE.map((getClientByFiscalCode) => - getClientByFiscalCode(message.fiscal_code), + getClientByFiscalCode(message.fiscal_code) ), - TE.chain((client) => + TE.chainW((client) => TE.tryCatch( () => - client.getThirdPartyMessagePrecondition({ + client.getThirdPartyMessageDetails({ id: message.content.third_party_data.id, ...lollipopLocals, }), - (e) => ResponseErrorInternal(E.toError(e).message), - ), + (e) => ResponseErrorInternal(E.toError(e).message) + ) ), TE.chainW(wrapValidationWithInternalError), TE.chainW( @@ -304,22 +583,21 @@ export default class NewMessagesService { TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getThirdPartyMessagePreconditionFromThirdPartyService|invocation returned an error:${ + `newMessagesService|getThirdPartyMessageFromThirdPartyService|invocation returned an error:${ response.status } [title: ${response.value?.title ?? "No title"}, detail: ${ + // eslint-disable-next-line sonarjs/no-duplicate-string response.value?.detail ?? "No details" - }, type: ${response.value?.type ?? "No type"}]`, + }, type: ${response.value?.type ?? "No type"}]` ); return response; }), TE.mapLeft( + // eslint-disable-next-line sonarjs/no-identical-functions flow((response) => { switch (response.status) { case 400: - return ResponseErrorValidation( - ERROR_MESSAGE_400, - "Third party service returned 400", - ); + return ResponseErrorValidation(ERROR_MESSAGE_400, ""); case 401: return ResponseErrorUnexpectedAuthProblem(); case 403: @@ -327,7 +605,7 @@ export default class NewMessagesService { case 404: return ResponseErrorNotFound( "Not found", - "Message from Third Party service not found", + "Message from Third Party service not found" ); case 429: return ResponseErrorTooManyRequests(); @@ -336,15 +614,18 @@ export default class NewMessagesService { default: return ResponseErrorStatusNotDefinedInSpec(response); } - }), + }) ), - ), - ), + TE.chainW((response) => + this.validateThirdPartyMessageResponse(message, response) + ) + ) + ) ); private readonly validateThirdPartyMessageResponse = ( message: MessageWithThirdPartyData, - response: ThirdPartyMessageDetails, + response: ThirdPartyMessageDetails ): TE.TaskEither => { // PN does not need this validation because it is managed in a different way with different specs if (message.sender_service_id === PN_SERVICE_ID) { @@ -359,8 +640,8 @@ export default class NewMessagesService { ) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.ATTACHMENTS_NOT_PRESENT, - ), + InvalidThirdPartyMessageTypeEnum.ATTACHMENTS_NOT_PRESENT + ) ); } // if has_remote_content is true and there is no remote content than an error must be thrown @@ -369,8 +650,8 @@ export default class NewMessagesService { if (shouldContainRemoteContent && !response.details) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.REMOTE_CONTENT_NOT_PRESENT, - ), + InvalidThirdPartyMessageTypeEnum.REMOTE_CONTENT_NOT_PRESENT + ) ); } // if has_remote_content is true and the remote markdown is not between 80 and 10000 characters than an error must be throw @@ -378,8 +659,8 @@ export default class NewMessagesService { if (shouldContainRemoteContent && !isMarkdownValid) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.MARKDOWN_VALIDATION_ERROR, - ), + InvalidThirdPartyMessageTypeEnum.MARKDOWN_VALIDATION_ERROR + ) ); } // if has_remote_content is true and the remote subject is not between 10 and 121 characters than an error must be throw @@ -387,8 +668,8 @@ export default class NewMessagesService { if (shouldContainRemoteContent && !isSubjectValid) { return TE.left( ResponseErrorBadGateway( - InvalidThirdPartyMessageTypeEnum.SUBJECT_VALIDATION_ERROR, - ), + InvalidThirdPartyMessageTypeEnum.SUBJECT_VALIDATION_ERROR + ) ); } // return a validated response by checking the flags @@ -407,368 +688,90 @@ export default class NewMessagesService { }); }; - // ------------------------------ - // THIRD_PARTY MESSAGE - // ------------------------------ - - /** - * Retrieves a specific message. - */ - public readonly getMessage = async ( - user: User, - params: GetMessageParameters, - ): Promise< + // Retrieve a ThirdParty attachment from related service, if exists + // return an error otherwise + private readonly getThirdPartyAttachmentFromThirdPartyService = ( + message: MessageWithThirdPartyData, + attachmentUrl: NonEmptyString, + remoteContentConfiguration: RCConfigurationPublic, + lollipopLocals?: LollipopLocalsType + ): TE.TaskEither< | IResponseErrorInternal + | IResponseErrorServiceUnavailable + | IResponseErrorValidation + | IResponseErrorForbiddenNotAuthorized | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const res = await this.apiClient.getMessage({ - fiscal_code: user.fiscal_code, - id: params.id, - public_message: params.public_message, - }); - - const resMessageContent = pipe( - res, - E.map((_) => (_.status === 200 ? { ..._, value: _.value.message } : _)), - ); - - return withValidatedOrInternalError( - resMessageContent, - async (response) => { - if (response.status === 200) { - const messageWithContent = response.value; - const maybePrescriptionData = O.fromNullable( - messageWithContent.content.prescription_data, - ); - - return O.isNone(maybePrescriptionData) - ? ResponseSuccessJson(messageWithContent) - : pipe( - getPrescriptionAttachments(maybePrescriptionData.value), - T.map((attachments) => ({ - ...messageWithContent, - content: { - ...messageWithContent.content, - attachments, - }, - })), - T.map(ResponseSuccessJson), - )(); - } - - return response.status === 404 - ? ResponseErrorNotFound("Not found", "Message not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status); - }, - ); - }); - - /** - * Retrieves all messages for a specific user. - */ - public readonly getMessagesByUser = ( - user: User, - params: GetMessagesParameters, - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const validated = await this.apiClient.getMessagesByUser({ - archived: params.getArchivedMessages, - enrich_result_data: params.enrichResultData, - /* eslint-disable sort-keys */ - fiscal_code: user.fiscal_code, - maximum_id: params.maximumId, - minimum_id: params.minimumId, - page_size: params.pageSize, - /* eslint-enable sort-keys */ - }); - - return withValidatedOrInternalError(validated, (response) => - response.status === 200 - ? ResponseSuccessJson(response.value) - : response.status === 404 - ? ResponseErrorNotFound("Not found", "User not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status), - ); - }); - - public readonly getRCConfiguration = ( - configurationId: Ulid, - ): TE.TaskEither< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation, - RCConfigurationPublic - > => - pipe( - TE.tryCatch( - () => - this.apiClient.getRCConfiguration({ - id: configurationId, - }), - (e) => ResponseErrorInternal(E.toError(e).message), - ), - TE.chain(wrapValidationWithInternalError), - - TE.chainW( - flow( - (response) => - response.status === 200 ? E.of(response.value) : E.left(response), - TE.fromEither, - TE.mapLeft((response) => { - log.error( - `newMessagesService|getRCConfiguration|result:${ - response.status - } [title: ${response.value?.title ?? "No title"}, detail: ${ - response.value?.detail ?? "No detail" - }, type: ${response.value?.type ?? "No type"}]`, - ); - return response; - }), - TE.mapLeft((response) => { - switch (response.status) { - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 404: - return ResponseErrorNotFound( - "Not found", - "RC Configuration not found", - ); - case 429: - return ResponseErrorTooManyRequests(); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }), - ), - ), - ); - - /** - * Retrieves an attachment related to a message - */ - public readonly getThirdPartyAttachment = async ( - message: MessageWithThirdPartyData, - attachmentUrl: NonEmptyString, - remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType, - ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorServiceUnavailable - | IResponseErrorTooManyRequests - | IResponseErrorUnsupportedMediaType - | IResponseErrorValidation - | IResponseSuccessOctet + | IResponseErrorTooManyRequests, + Buffer > => pipe( - pipe( - this.getThirdPartyAttachmentFromThirdPartyService( - message, - attachmentUrl, - remoteContentConfiguration, - lollipopLocals, - ), - ), - TE.filterOrElseW(getIsFileTypeForTypes(ALLOWED_TYPES), () => - ResponseErrorUnsupportedMediaType( - "The requested file is not a valid PDF", - ), + getThirdPartyServiceClient( + remoteContentConfiguration, + nodeFetch as unknown as Fetch, + lollipopLocals ), - TE.map(ResponseSuccessOctet), - TE.toUnion, - )(); - - /** - * Retrieves a specific Third-Party message. - */ - public readonly getThirdPartyMessage = async ( - message: MessageWithThirdPartyData, - remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType, - ): Promise< - | IResponseErrorBadGateway - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessJson - > => - pipe( - pipe( - this.getThirdPartyMessageFromThirdPartyService( - message, - remoteContentConfiguration, - lollipopLocals, - ), - TE.map((thirdPartyMessage) => ({ - ...message, - third_party_message: thirdPartyMessage, - })), + TE.of, + TE.map((getClientByFiscalCode) => + getClientByFiscalCode(message.fiscal_code) ), - TE.map(ResponseSuccessJson), - TE.toUnion, - )(); - - // ------------------------------------ - // Private Functions - // ------------------------------------ - - // Retrieve a ThirdParty message precondition for a specific message, if exists - public readonly getThirdPartyMessageFnApp = ( - fiscalCode: FiscalCode, - messageId: Ulid, - ): TE.TaskEither< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation, - MessageWithThirdPartyData - > => - pipe( - TE.tryCatch( - () => - this.apiClient.getMessage({ - fiscal_code: fiscalCode, - id: messageId, - }), - (e) => ResponseErrorInternal(E.toError(e).message), + TE.chainW((client) => + TE.tryCatch( + () => + client.getThirdPartyMessageAttachment({ + attachment_url: attachmentUrl, + id: message.content.third_party_data.id, + ...lollipopLocals, + }), + (e) => ResponseErrorInternal(E.toError(e).message) + ) ), - TE.chain(wrapValidationWithInternalError), - + TE.chainW(wrapValidationWithInternalError), TE.chainW( flow( (response) => - response.status === 200 - ? E.of(response.value.message) - : E.left(response), + response.status === 200 ? E.of(response.value) : E.left(response), TE.fromEither, TE.mapLeft((response) => { log.error( - `newMessagesService|getThirdPartyMessageFnApp|result:${ + `newMessagesService|getThirdPartyAttachmentFromThirdPartyService|invocation returned an error:${ response.status - } [title: ${response.value?.title ?? "No title"}, detail: ${ - response.value?.detail ?? "No detail" - }, type: ${response.value?.type ?? "No type"}]`, + } [title: ${response.value?.title ?? "No title"}, detail: ${ + // eslint-disable-next-line sonarjs/no-duplicate-string + response.value?.detail ?? "No details" + }, type: ${response.value?.type ?? "No type"}])` ); return response; }), - TE.mapLeft((response) => { - switch (response.status) { - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 404: - return ResponseErrorNotFound("Not found", "Message not found"); - case 429: - return ResponseErrorTooManyRequests(); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }), - ), - ), - TE.chainW( - // MessageWithThirdPartyData.is fails, we need to check the decode instead - TE.fromPredicate(isMessageWithThirdPartyData, () => - ResponseErrorValidation( - "Bad request", - "The message retrieved is not a valid message with third-party data", - ), - ), - ), + TE.mapLeft( + flow((response) => { + switch (response.status) { + case 400: + return ResponseErrorValidation(ERROR_MESSAGE_400, ""); + case 401: + return ResponseErrorUnexpectedAuthProblem(); + case 403: + return ResponseErrorForbiddenNotAuthorized; + case 404: + return ResponseErrorNotFound( + "Not found", + "Attachment from Third Party service not found" + ); + case 429: + return ResponseErrorTooManyRequests(); + case 500: + return ResponseErrorInternal(ERROR_MESSAGE_500); + case 503: + const retryAfter = response.headers["Retry-After"] ?? "10"; + return ResponseErrorServiceTemporarilyUnavailable( + ERROR_MESSAGE_503, + retryAfter + ); + default: + return ResponseErrorStatusNotDefinedInSpec(response); + } + }) + ) + ) + ) ); - - // Retrieve a ThirdParty message detail from related service, if exists - /** - * Retrieves the precondition of a specific Third-Party message. - */ - public readonly getThirdPartyMessagePrecondition = async ( - message: MessageWithThirdPartyData, - remoteContentConfiguration: RCConfigurationPublic, - lollipopLocals?: LollipopLocalsType, - ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessJson - | IResponseSuccessNoContent - > => - pipe( - this.getThirdPartyMessagePreconditionFromThirdPartyService( - message, - remoteContentConfiguration, - lollipopLocals, - ), - TE.map(ResponseSuccessJson), - TE.toUnion, - )(); - - /** - * Retrieve the service preferences fot the defined user and service - */ - public readonly upsertMessageStatus = ( - fiscalCode: FiscalCode, - messageId: Ulid, - messageStatusChange: MessageStatusChange, - ): Promise< - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessJson - > => - withCatchAsInternalError(async () => { - const validated = await this.apiClient.upsertMessageStatusAttributes({ - body: messageStatusChange, - fiscal_code: fiscalCode, - id: messageId, - }); - - return withValidatedOrInternalError(validated, (response) => { - switch (response.status) { - case 200: - return ResponseSuccessJson({ - is_archived: response.value.is_archived, - is_read: response.value.is_read, - }); - case 401: - return ResponseErrorUnexpectedAuthProblem(); - case 403: - return ResponseErrorForbiddenNotAuthorized; - case 404: - return ResponseErrorNotFound( - "Not Found", - "Message status not found", - ); - case 429: - return ResponseErrorTooManyRequests(); - default: - return ResponseErrorStatusNotDefinedInSpec(response); - } - }); - }); - - // Retrieve a ThirdParty attachment from related service, if exists - constructor( - private readonly apiClient: ReturnType, - ) {} } diff --git a/src/services/notificationService.ts b/src/services/notificationService.ts index 7dff5ca38..17ac89318 100644 --- a/src/services/notificationService.ts +++ b/src/services/notificationService.ts @@ -2,16 +2,16 @@ * This service post a notification to the Notification queue. */ -import { QueueClient } from "@azure/storage-queue"; import { IResponseErrorInternal, IResponseSuccessJson, ResponseErrorInternal, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; + +import { QueueClient } from "@azure/storage-queue"; import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; - import { FiscalCode } from "../../generated/backend/FiscalCode"; import { Installation } from "../../generated/backend/Installation"; import { @@ -29,14 +29,55 @@ import { } from "../../generated/messages/NotifyMessage"; import { Notification } from "../../generated/notifications/Notification"; import { SuccessResponse } from "../../generated/notifications/SuccessResponse"; + import { toFiscalCodeHash } from "../types/notification"; import { base64EncodeObject } from "../utils/messages"; export default class NotificationService { private readonly notificationQueueClient: QueueClient; + constructor( + private readonly queueStorageConnectionString: string, + private readonly queueName: string + ) { + this.notificationQueueClient = new QueueClient( + this.queueStorageConnectionString, + this.queueName + ); + } + + public readonly notify = ( + notification: Notification, + notificationSubject: string, + notificationTitle?: string + ): Promise< + IResponseErrorInternal | IResponseSuccessJson + > => { + const notifyMessage: NotifyMessage = { + installationId: toFiscalCodeHash(notification.message.fiscal_code), + kind: NotifyKind[NotificationMessageKindEnum.Notify], + payload: { + message: notificationSubject, + message_id: notification.message.id, + title: pipe( + notificationTitle, + O.fromNullable, + O.getOrElse(() => `${notification.sender_metadata.organization_name}`) + ), + }, + }; + return this.notificationQueueClient + .sendMessage(base64EncodeObject(notifyMessage)) + .then(() => ResponseSuccessJson({ message: "ok" })) + .catch((error) => + ResponseErrorInternal( + `Error while sending notify message to the queue [${error.message}]` + ) + ); + }; + public readonly createOrUpdateInstallation = ( fiscalCode: FiscalCode, - installation: Installation, + installation: Installation ): Promise< IResponseErrorInternal | IResponseSuccessJson > => { @@ -57,13 +98,13 @@ export default class NotificationService { .then(() => ResponseSuccessJson({ message: "ok" })) .catch((error) => ResponseErrorInternal( - `Error while sending create or update installation message to the queue [${error.message}]`, - ), + `Error while sending create or update installation message to the queue [${error.message}]` + ) ); }; public readonly deleteInstallation = ( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ): Promise< IResponseErrorInternal | IResponseSuccessJson > => { @@ -76,50 +117,8 @@ export default class NotificationService { .then(() => ResponseSuccessJson({ message: "ok" })) .catch((error) => ResponseErrorInternal( - `Error while sending delete installation message to the queue [${error.message}]`, - ), - ); - }; - - public readonly notify = ( - notification: Notification, - notificationSubject: string, - notificationTitle?: string, - ): Promise< - IResponseErrorInternal | IResponseSuccessJson - > => { - const notifyMessage: NotifyMessage = { - installationId: toFiscalCodeHash(notification.message.fiscal_code), - kind: NotifyKind[NotificationMessageKindEnum.Notify], - payload: { - message: notificationSubject, - message_id: notification.message.id, - title: pipe( - notificationTitle, - O.fromNullable, - O.getOrElse( - () => `${notification.sender_metadata.organization_name}`, - ), - ), - }, - }; - return this.notificationQueueClient - .sendMessage(base64EncodeObject(notifyMessage)) - .then(() => ResponseSuccessJson({ message: "ok" })) - .catch((error) => - ResponseErrorInternal( - `Error while sending notify message to the queue [${error.message}]`, - ), + `Error while sending delete installation message to the queue [${error.message}]` + ) ); }; - - constructor( - private readonly queueStorageConnectionString: string, - private readonly queueName: string, - ) { - this.notificationQueueClient = new QueueClient( - this.queueStorageConnectionString, - this.queueName, - ); - } } diff --git a/src/services/notificationServiceFactory.ts b/src/services/notificationServiceFactory.ts index 87bf13557..a45ff6c2a 100644 --- a/src/services/notificationServiceFactory.ts +++ b/src/services/notificationServiceFactory.ts @@ -3,11 +3,12 @@ import * as B from "fp-ts/boolean"; import { flow } from "fp-ts/lib/function"; import { FiscalCode } from "../../generated/io-bonus-api/FiscalCode"; -import { toFiscalCodeHash } from "../types/notification"; import { FeatureFlag, getIsUserEligibleForNewFeature, } from "../utils/featureFlag"; +import { toFiscalCodeHash } from "../types/notification"; + import NotificationService from "./notificationService"; /** @@ -16,7 +17,7 @@ import NotificationService from "./notificationService"; * @returns */ const getIsUserACanaryTestUser = ( - regex: string, + regex: string ): ((sha: NonEmptyString) => boolean) => { const regExp = new RegExp(regex); return (sha: NonEmptyString): boolean => regExp.test(sha); @@ -25,35 +26,35 @@ const getIsUserACanaryTestUser = ( // ------------------------------------------ export type NotificationServiceFactory = ( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ) => NotificationService; export const getNotificationServiceFactory: ( oldNotificationService: NotificationService, newNotificationService: NotificationService, - betaTesters: readonly FiscalCode[], + betaTesters: ReadonlyArray, canaryTestUserRegex: NonEmptyString, - ff: FeatureFlag, + ff: FeatureFlag ) => NotificationServiceFactory = ( oldNotificationService, newNotificationService, betaTesters, canaryTestUserRegex, - ff, + ff ) => { const isUserACanaryTestUser = getIsUserACanaryTestUser(canaryTestUserRegex); const isUserEligible = getIsUserEligibleForNewFeature( (cf) => betaTesters.includes(cf), (cf) => isUserACanaryTestUser(toFiscalCodeHash(cf)), - ff, + ff ); return flow( isUserEligible, B.fold( () => oldNotificationService, - () => newNotificationService, - ), + () => newNotificationService + ) ); }; diff --git a/src/services/pagoPAClientFactory.ts b/src/services/pagoPAClientFactory.ts index 5d14e63f1..f4e0480a2 100644 --- a/src/services/pagoPAClientFactory.ts +++ b/src/services/pagoPAClientFactory.ts @@ -24,17 +24,17 @@ export default class PagoPAClientFactory pagoPAApiKeyUAT: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any - fetchApi: typeof fetch = nodeFetch as any as typeof fetch, + fetchApi: typeof fetch = nodeFetch as any as typeof fetch ) { this.prodApiClient = PagoPAClient( pagoPAApiUrlProd, pagoPAApiKeyProd, - fetchApi, + fetchApi ); this.testApiClient = PagoPAClient( pagoPAApiUrlUAT, pagoPAApiKeyUAT, - fetchApi, + fetchApi ); } diff --git a/src/services/pagoPAProxyService.ts b/src/services/pagoPAProxyService.ts index 2772240cc..a1bc936c2 100644 --- a/src/services/pagoPAProxyService.ts +++ b/src/services/pagoPAProxyService.ts @@ -13,6 +13,7 @@ import { PaymentActivationsGetResponse } from "../../generated/backend/PaymentAc import { PaymentActivationsPostResponse } from "../../generated/backend/PaymentActivationsPostResponse"; import { PaymentRequestsGetResponse } from "../../generated/backend/PaymentRequestsGetResponse"; import { PaymentActivationsPostRequest } from "../../generated/pagopa-proxy/PaymentActivationsPostRequest"; + import { ResponsePaymentError, withCatchAsInternalError, @@ -24,125 +25,123 @@ import { } from "./IPagoPAClientFactory"; export default class PagoPAProxyService { + constructor(private readonly pagoPAClient: IPagoPAClientFactoryInterface) {} + /** - * Require a lock (activation) for a payment. + * Retrieve information about a payment. */ - public readonly activatePayment = async ( - paymentActivationsPostRequest: PaymentActivationsPostRequest, - isTest: boolean, + public readonly getPaymentInfo = ( + rptId: string, + isTest: boolean ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseSuccessJson > => withCatchAsInternalError(async () => { const client = this.pagoPAClient.getClient( - isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION, + isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION ); - const validated = await client.activatePayment({ - paymentActivationsPostRequest, + const validated = await client.getPaymentInfo({ + rpt_id_from_string: rptId, }); - return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - PaymentActivationsPostResponse.decode(response.value), - ResponseSuccessJson, + PaymentRequestsGetResponse.decode(response.value), + ResponseSuccessJson ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - response.value.detail || - "Bad request response from upstream API", - ) - : ResponsePaymentError( - response.value.detail, - response.value.detail_v2, - ), + ? ResponseErrorValidation( + // eslint-disable-next-line sonarjs/no-duplicate-string + response.value.title || "Bad request (upstream)", + // eslint-disable-next-line sonarjs/no-duplicate-string + response.value.detail || "Bad request response from upstream API" + ) + : ResponsePaymentError( + response.value.detail, + response.value.detail_v2 + ) ); }); /** - * Check the activation status to retrieve the paymentId. + * Require a lock (activation) for a payment. */ - public readonly getActivationStatus = ( - codiceContestoPagamento: string, - isTest: boolean, + public readonly activatePayment = async ( + paymentActivationsPostRequest: PaymentActivationsPostRequest, + isTest: boolean ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseSuccessJson > => withCatchAsInternalError(async () => { const client = this.pagoPAClient.getClient( - isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION, + isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION ); - const validated = await client.getActivationStatus({ - codice_contesto_pagamento: codiceContestoPagamento, + const validated = await client.activatePayment({ + paymentActivationsPostRequest, }); + return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - PaymentActivationsGetResponse.decode(response.value), - ResponseSuccessJson, + PaymentActivationsPostResponse.decode(response.value), + ResponseSuccessJson ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - response.value.detail || - "Bad request response from upstream API", - ) - : response.status === 404 - ? ResponseErrorNotFound( - response.value.title || "Not found (upstream)", - response.value.detail || "Not found response from upstream", - ) - : ResponseErrorInternal( - response.value.detail || - "Internal server error response from upstream", - ), + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + response.value.detail || "Bad request response from upstream API" + ) + : ResponsePaymentError( + response.value.detail, + response.value.detail_v2 + ) ); }); /** - * Retrieve information about a payment. + * Check the activation status to retrieve the paymentId. */ - public readonly getPaymentInfo = ( - rptId: string, - isTest: boolean, + public readonly getActivationStatus = ( + codiceContestoPagamento: string, + isTest: boolean ): Promise< | IResponseErrorInternal | IResponseErrorValidation - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseSuccessJson > => withCatchAsInternalError(async () => { const client = this.pagoPAClient.getClient( - isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION, + isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION ); - const validated = await client.getPaymentInfo({ - rpt_id_from_string: rptId, + const validated = await client.getActivationStatus({ + codice_contesto_pagamento: codiceContestoPagamento, }); return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - PaymentRequestsGetResponse.decode(response.value), - ResponseSuccessJson, + PaymentActivationsGetResponse.decode(response.value), + ResponseSuccessJson ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - - response.value.detail || - "Bad request response from upstream API", - ) - : ResponsePaymentError( - response.value.detail, - response.value.detail_v2, - ), + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + response.value.detail || "Bad request response from upstream API" + ) + : response.status === 404 + ? ResponseErrorNotFound( + response.value.title || "Not found (upstream)", + response.value.detail || "Not found response from upstream" + ) + : ResponseErrorInternal( + response.value.detail || + "Internal server error response from upstream" + ) ); }); - - constructor(private readonly pagoPAClient: IPagoPAClientFactoryInterface) {} } diff --git a/src/services/pnService.ts b/src/services/pnService.ts index 1ba915e68..1172e1aa3 100644 --- a/src/services/pnService.ts +++ b/src/services/pnService.ts @@ -1,13 +1,13 @@ -import { FiscalCode } from "../../generated/backend/FiscalCode"; import { IoCourtesyDigitalAddressActivation } from "../../generated/piattaforma-notifiche-courtesy/IoCourtesyDigitalAddressActivation"; import { PNClientFactory, PNEnvironment } from "../clients/pn-clients"; +import { FiscalCode } from "../../generated/backend/FiscalCode"; const upsertPnActivationService = (PnAddressBookIOClientSelector: ReturnType) => ( pnEnvironment: PNEnvironment, fiscalCode: FiscalCode, - activationStatusPayload: IoCourtesyDigitalAddressActivation, + activationStatusPayload: IoCourtesyDigitalAddressActivation ) => PnAddressBookIOClientSelector(pnEnvironment).setCourtesyAddressIo({ body: activationStatusPayload, @@ -22,7 +22,7 @@ const getPnActivationService = }); export const PNService = ( - PnAddressBookIOClientSelector: ReturnType, + PnAddressBookIOClientSelector: ReturnType ) => ({ getPnActivation: getPnActivationService(PnAddressBookIOClientSelector), upsertPnActivation: upsertPnActivationService(PnAddressBookIOClientSelector), diff --git a/src/services/profileService.ts b/src/services/profileService.ts index 7499e1981..32cebb846 100644 --- a/src/services/profileService.ts +++ b/src/services/profileService.ts @@ -3,10 +3,6 @@ * an API client. */ -import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; -import { NewProfile } from "@pagopa/io-functions-app-sdk/NewProfile"; -import { Profile as ProfileApi } from "@pagopa/io-functions-app-sdk/Profile"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -23,11 +19,17 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as E from "fp-ts/lib/Either"; + +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { pipe } from "fp-ts/lib/function"; +import * as E from "fp-ts/lib/Either"; +import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; +import { NewProfile } from "@pagopa/io-functions-app-sdk/NewProfile"; +import { Profile as ProfileApi } from "@pagopa/io-functions-app-sdk/Profile"; import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { Profile as ProfileBackend } from "../../generated/backend/Profile"; + import { toInitializedProfile } from "../types/profile"; import { User } from "../types/user"; import { @@ -38,78 +40,66 @@ import { import { IApiClientFactoryInterface } from "./IApiClientFactory"; export default class ProfileService { + constructor(private readonly apiClient: IApiClientFactoryInterface) {} + /** - * Create the profile of a specific user. + * Retrieves the profile for a specific user. */ - public readonly createProfile = async ( - user: User, - newProfile: NewProfile, + public readonly getProfile = ( + user: User ): Promise< - | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorTooManyRequests - // This Service response is not binded with any API response, so we remove any payload - // from this Response Success JSON. - | IResponseSuccessJson> + | IResponseErrorNotFound + | IResponseSuccessJson > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.createProfile({ - body: newProfile, + const validated = await client.getProfile({ fiscal_code: user.fiscal_code, }); - return withValidatedOrInternalError(validated, (response) => - response.status === 200 - ? // An empty response. - ResponseSuccessJson({}) - : response.status === 409 - ? ResponseErrorConflict( - response.value || - "A user with the provided fiscal code already exists", - ) - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status), - ); - }); - }; + return withValidatedOrInternalError(validated, (response) => { + if (response.status === 200) { + // we need an ExtendedProfile (and that's what we should have got) but + // since the response may be an ExtendedProfile or a LimitedProfile + // depending on the credentials, we must decode it as an + // ExtendedProfile to be sure it's what we need. + const validatedExtendedProfile = ExtendedProfileApi.decode( + response.value + ); - /** - * Resend the email to complete email validation process - */ - public readonly emailValidationProcess = async ( - user: User, - ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseErrorTooManyRequests - | IResponseSuccessAccepted - > => { - const client = this.apiClient.getClient(); - return withCatchAsInternalError(async () => { - const validated = await client.startEmailValidationProcess({ - body: { name: user.name }, - fiscal_code: user.fiscal_code, + return withValidatedOrInternalError(validatedExtendedProfile, (p) => + ResponseSuccessJson(toInitializedProfile(p, user)) + ); + } + + if (response.status === 404) { + return ResponseErrorNotFound("Not Found", "Profile not found"); + } + + // The user has sent too many requests in a given amount of time ("rate limiting"). + if (response.status === 429) { + return ResponseErrorTooManyRequests(); + } + + if (response.status === 500) { + return ResponseErrorInternal( + `Error retrieving the profile [${response.value.detail}]` + ); + } + + return unhandledResponseStatus(response.status); }); - return withValidatedOrInternalError(validated, (response) => - response.status === 202 - ? ResponseSuccessAccepted() - : response.status === 404 - ? ResponseErrorNotFound("Not found", "User not found.") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status), - ); }); }; public readonly getApiProfile = ( - user: User, + user: User ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorTooManyRequests + | IResponseErrorNotFound | IResponseSuccessJson > => { const client = this.apiClient.getClient(); @@ -123,10 +113,10 @@ export default class ProfileService { response.value, ExtendedProfileApi.decode, E.mapLeft((_) => - ResponseErrorInternal(errorsToReadableMessages(_).join(" / ")), + ResponseErrorInternal(errorsToReadableMessages(_).join(" / ")) ), E.map(ResponseSuccessJson), - E.toUnion, + E.toUnion ); } // The profile doesn't exists for the user @@ -141,7 +131,7 @@ export default class ProfileService { if (response.status === 500) { return ResponseErrorInternal( - `Error retrieving the profile [${response.value.detail}]`, + `Error retrieving the profile [${response.value.detail}]` ); } @@ -151,54 +141,39 @@ export default class ProfileService { }; /** - * Retrieves the profile for a specific user. + * Create the profile of a specific user. */ - public readonly getProfile = ( + public readonly createProfile = async ( user: User, + newProfile: NewProfile ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseSuccessJson + | IResponseErrorConflict + // This Service response is not binded with any API response, so we remove any payload + // from this Response Success JSON. + | IResponseSuccessJson> > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.getProfile({ + const validated = await client.createProfile({ + body: newProfile, fiscal_code: user.fiscal_code, }); - return withValidatedOrInternalError(validated, (response) => { - if (response.status === 200) { - // we need an ExtendedProfile (and that's what we should have got) but - // since the response may be an ExtendedProfile or a LimitedProfile - // depending on the credentials, we must decode it as an - // ExtendedProfile to be sure it's what we need. - const validatedExtendedProfile = ExtendedProfileApi.decode( - response.value, - ); - - return withValidatedOrInternalError(validatedExtendedProfile, (p) => - ResponseSuccessJson(toInitializedProfile(p, user)), - ); - } - - if (response.status === 404) { - return ResponseErrorNotFound("Not Found", "Profile not found"); - } - - // The user has sent too many requests in a given amount of time ("rate limiting"). - if (response.status === 429) { - return ResponseErrorTooManyRequests(); - } - - if (response.status === 500) { - return ResponseErrorInternal( - `Error retrieving the profile [${response.value.detail}]`, - ); - } - - return unhandledResponseStatus(response.status); - }); + return withValidatedOrInternalError(validated, (response) => + response.status === 200 + ? // An empty response. + ResponseSuccessJson({}) + : response.status === 409 + ? ResponseErrorConflict( + response.value || + "A user with the provided fiscal code already exists" + ) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) + ); }); }; @@ -207,13 +182,13 @@ export default class ProfileService { */ public readonly updateProfile = async ( user: User, - profileBackend: ProfileBackend, + profileBackend: ProfileBackend ): Promise< - | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorNotFound - | IResponseErrorPreconditionFailed + | IResponseErrorConflict | IResponseErrorTooManyRequests + | IResponseErrorPreconditionFailed | IResponseSuccessJson > => { const client = this.apiClient.getClient(); @@ -233,18 +208,18 @@ export default class ProfileService { switch (response.status) { case 200: return ResponseSuccessJson( - toInitializedProfile(response.value, user), + toInitializedProfile(response.value, user) ); case 404: return ResponseErrorNotFound("Not found", "User not found"); case 409: return ResponseErrorConflict( - response.value || "Cannot update profile with wrong version", + response.value || "Cannot update profile with wrong version" ); case 412: return ResponseErrorPreconditionFailed( "The provided e-mail address is not unique", - response.value.type, + response.value.type ); case 429: return ResponseErrorTooManyRequests(); @@ -252,9 +227,36 @@ export default class ProfileService { return unhandledResponseStatus(response.status); } }); - }), + }) ); }; - constructor(private readonly apiClient: IApiClientFactoryInterface) {} + /** + * Resend the email to complete email validation process + */ + public readonly emailValidationProcess = async ( + user: User + ): Promise< + | IResponseErrorInternal + | IResponseErrorTooManyRequests + | IResponseErrorNotFound + | IResponseSuccessAccepted + > => { + const client = this.apiClient.getClient(); + return withCatchAsInternalError(async () => { + const validated = await client.startEmailValidationProcess({ + body: { name: user.name }, + fiscal_code: user.fiscal_code, + }); + return withValidatedOrInternalError(validated, (response) => + response.status === 202 + ? ResponseSuccessAccepted() + : response.status === 404 + ? ResponseErrorNotFound("Not found", "User not found.") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) + ); + }); + }; } diff --git a/src/services/redisSessionStorage.ts b/src/services/redisSessionStorage.ts index 50d108c72..0534a7eda 100644 --- a/src/services/redisSessionStorage.ts +++ b/src/services/redisSessionStorage.ts @@ -2,29 +2,28 @@ * This service uses the Redis client to store and retrieve session information. */ -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import { isArray } from "util"; import * as A from "fp-ts/lib/Array"; +import * as ROA from "fp-ts/lib/ReadonlyArray"; import * as E from "fp-ts/lib/Either"; -import { Either } from "fp-ts/lib/Either"; -import { NonEmptyArray } from "fp-ts/lib/NonEmptyArray"; import * as O from "fp-ts/lib/Option"; -import { Option } from "fp-ts/lib/Option"; -import * as ROA from "fp-ts/lib/ReadonlyArray"; +import * as B from "fp-ts/lib/boolean"; import * as R from "fp-ts/lib/Record"; import * as TE from "fp-ts/lib/TaskEither"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { TaskEither } from "fp-ts/lib/TaskEither"; -import * as B from "fp-ts/lib/boolean"; -import { flow, identity, pipe } from "fp-ts/lib/function"; -import { isArray } from "util"; - -import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; -import { SessionInfo } from "../../generated/backend/SessionInfo"; -import { SessionsList } from "../../generated/backend/SessionsList"; +import { Either } from "fp-ts/lib/Either"; +import { Option } from "fp-ts/lib/Option"; +import { flow, pipe, identity } from "fp-ts/lib/function"; +import { NonEmptyArray } from "fp-ts/lib/NonEmptyArray"; import { - LollipopData, NullableBackendAssertionRefFromString, + LollipopData, } from "../types/assertionRef"; +import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; +import { SessionInfo } from "../../generated/backend/SessionInfo"; +import { SessionsList } from "../../generated/backend/SessionsList"; import { assertUnreachable } from "../types/commons"; import { BPDToken, @@ -35,8 +34,8 @@ import { ZendeskToken, } from "../types/token"; import { User, UserV1, UserV2, UserV3, UserV4, UserV5 } from "../types/user"; -import { ActiveSessionInfo, LoginTypeEnum } from "../utils/fastLogin"; import { log } from "../utils/logger"; +import { ActiveSessionInfo, LoginTypeEnum } from "../utils/fastLogin"; import { RedisClientMode, RedisClientSelectorType } from "../utils/redis"; import { ISessionStorage } from "./ISessionStorage"; import RedisStorageUtils from "./redisStorageUtils"; @@ -75,297 +74,150 @@ export default class RedisSessionStorage super(); } - private arrayStringReplyAsync( - command: TE.TaskEither, - ): Promise>> { - return pipe( - command, - TE.chain( - TE.fromPredicate( - (res): res is NonEmptyArray => isArray(res) && res.length > 0, - () => sessionNotFoundError, - ), - ), - )(); - } + /** + * {@inheritDoc} + */ + public async getBySessionToken( + token: SessionToken + ): Promise>> { + const errorOrSession = await this.loadSessionBySessionToken(token); - private delSessionsSet(fiscalCode: FiscalCode): Promise> { - return pipe( - TE.tryCatch(() => { - log.info( - `Deleting sessions set ${userSessionsSetKeyPrefix}${fiscalCode}`, - ); - return this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .del(`${userSessionsSetKeyPrefix}${fiscalCode}`); - }, E.toError), - TE.map(() => true), - )(); + if (E.isLeft(errorOrSession)) { + if (errorOrSession.left === sessionNotFoundError) { + return E.right(O.none); + } + return E.left(errorOrSession.left); + } + + const user = errorOrSession.right; + + return E.right(O.some(user)); } /** - * Given a token, it removes user session token and wallet token - * - * @param token + * {@inheritDoc} */ - private async delSingleSession( - token: SessionToken, - ): Promise> { - try { - const user: User = pipe( - await this.loadSessionBySessionToken(token), - E.getOrElseW((err) => { - throw err; - }), - ); - return this.del(user); - } catch (error) { - // as it's a delete, if the query fails for a NotFoudn error, it might be considered a success - return error === sessionNotFoundError - ? E.right(true) - : E.left(E.toError(error)); - } - } + public async getByMyPortalToken( + token: MyPortalToken + ): Promise>> { + const errorOrSession = await this.loadSessionByToken( + myPortalTokenPrefix, + token + ); - private getUserTokens( - user: User, - ): Record { - const requiredTokens = { - session_info: { - prefix: sessionInfoKeyPrefix, - value: user.session_token, - }, - session_token: { - prefix: sessionKeyPrefix, - value: user.session_token, - }, - wallet_token: { - prefix: walletKeyPrefix, - value: user.wallet_token, - }, - }; - if (UserV5.is(user)) { - return { - ...requiredTokens, - bpd_token: { - prefix: bpdTokenPrefix, - value: user.bpd_token, - }, - fims_token: { - prefix: fimsTokenPrefix, - value: user.fims_token, - }, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - zendesk_token: { - prefix: zendeskTokenPrefix, - value: user.zendesk_token, - }, - }; - } - if (UserV4.is(user)) { - return { - ...requiredTokens, - bpd_token: { - prefix: bpdTokenPrefix, - value: user.bpd_token, - }, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - zendesk_token: { - prefix: zendeskTokenPrefix, - value: user.zendesk_token, - }, - }; - } - if (UserV3.is(user)) { - return { - ...requiredTokens, - bpd_token: { - prefix: bpdTokenPrefix, - value: user.bpd_token, - }, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - }; - } - if (UserV2.is(user)) { - return { - ...requiredTokens, - myportal_token: { - prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, - }; - } - if (UserV1.is(user)) { - return { - ...requiredTokens, - }; + if (E.isLeft(errorOrSession)) { + if (errorOrSession.left === sessionNotFoundError) { + return E.right(O.none); + } + return E.left(errorOrSession.left); } - return assertUnreachable(user); + + const user = errorOrSession.right; + + return E.right(O.some(user)); } /** - * Return a Session for this token. + * {@inheritDoc} */ - private async loadSessionBySessionToken( - token: SessionToken, - ): Promise> { - return pipe( + public async del(user: User): Promise> { + const tokens: ReadonlyArray = R.collect( + (_, { prefix, value }) => `${prefix}${value}` + )(this.getUserTokens(user)); + + const deleteTokensPromiseV2 = await pipe( + tokens, + ROA.map((singleToken) => + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .del(singleToken), + E.toError + ) + ), + ROA.sequence(TE.ApplicativeSeq), + TE.map(ROA.reduce(0, (current, next) => current + next)), + this.integerReplyAsync(tokens.length), + this.falsyResponseToErrorAsync( + new Error("Unexpected response from redis client deleting user tokens.") + ) + )(); + + if (E.isLeft(deleteTokensPromiseV2)) { + return E.left( + new Error( + `value [${deleteTokensPromiseV2.left.message}] at RedisSessionStorage.del` + ) + ); + } + + // Remove SESSIONINFO reference from USERSESSIONS Set + // this operation is executed in background and doesn't compromise + // the logout process. + pipe( TE.tryCatch( () => this.redisClientSelector .selectOne(RedisClientMode.FAST) - .get(`${sessionKeyPrefix}${token}`), - E.toError, - ), - TE.chain( - flow( - O.fromNullable, - E.fromOption(() => sessionNotFoundError), - E.chain(this.parseUser), - TE.fromEither, - ), + .sRem( + `${userSessionsSetKeyPrefix}${user.fiscal_code}`, + `${sessionInfoKeyPrefix}${user.session_token}` + ), + E.toError ), + TE.mapLeft((_) => { + log.warn(`Error updating USERSESSIONS Set for ${user.fiscal_code}`); + }) + )().catch(() => void 0); + return E.right(true); + } + + public async listUserSessions( + user: User + ): Promise> { + // If some user session was expired we update the USERSESSION Redis set. + await this.clearExpiredSetValues(user.fiscal_code); + + const sessionKeys = await this.readSessionInfoKeys(user.fiscal_code); + + if (E.isLeft(sessionKeys)) { + return E.left(sessionKeys.left); + } + + return pipe( + this.mGet([...sessionKeys.right]), + TE.map((keys) => + this.parseUserSessionList( + keys.filter((key) => key !== null) as ReadonlyArray + ) + ) )(); } /** - * Return a Session for this token. + * Remove expired `SESSIONINFO` value from the `USERSESSION` redis set. + * + * @param fiscalCode */ - private loadSessionByToken( - prefix: string, - token: BPDToken | FIMSToken | MyPortalToken | WalletToken | ZendeskToken, - ): Promise> { - return pipe( + public async clearExpiredSetValues( + fiscalCode: string + ): Promise>> { + const userSessionSetKey = `${userSessionsSetKeyPrefix}${fiscalCode}`; + const keysV2 = await pipe( TE.tryCatch( () => this.redisClientSelector .selectOne(RedisClientMode.FAST) - .get(`${prefix}${token}`), - E.toError, - ), - TE.chain( - flow( - O.fromNullable, - TE.fromOption(() => sessionNotFoundError), - ), - ), - TE.chain((value) => - pipe( - TE.tryCatch( - () => this.loadSessionBySessionToken(value as SessionToken), - E.toError, - ), - TE.chain(TE.fromEither), - ), - ), - )(); - } - - private mGet(keys: string[]): TaskEither { - return pipe( - keys, - A.map((singleKey) => - TE.tryCatch(() => { - const redis_client = this.redisClientSelector.selectOne( - RedisClientMode.FAST, - ); - return redis_client.get.bind(redis_client)(singleKey); - }, E.toError), - ), - A.sequence(TE.ApplicativePar), - ); - } - - private parseUser(value: string): Either { - return pipe( - E.parseJSON(value, E.toError), - E.chain( - flow( - User.decode, - E.mapLeft( - (err) => new Error(errorsToReadableMessages(err).join("/")), - ), - ), - ), - ); - } - - private parseUserSessionList( - userSessionTokensResult: readonly string[], - ): SessionsList { - return userSessionTokensResult.reduce( - (prev: SessionsList, _) => - pipe( - E.parseJSON(_, E.toError), - E.chain((data) => - pipe( - SessionInfo.decode(data), - E.mapLeft( - (err) => new Error(errorsToReadableMessages(err).join("/")), - ), - ), - ), - E.fold( - (err) => { - log.warn("Unable to decode the session info: %s. Skipped.", err); - return prev; - }, - (sessionInfo) => ({ - sessions: [...prev.sessions, sessionInfo], - }), - ), - ), - { sessions: [] } as SessionsList, - ); - } - - private readSessionInfoKeys( - fiscalCode: FiscalCode, - ): Promise> { - return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .sMembers(`${userSessionsSetKeyPrefix}${fiscalCode}`), - E.toError, - ), - this.arrayStringReplyAsync, - ); - } - - /** - * Remove expired `SESSIONINFO` value from the `USERSESSION` redis set. - * - * @param fiscalCode - */ - public async clearExpiredSetValues( - fiscalCode: string, - ): Promise[]> { - const userSessionSetKey = `${userSessionsSetKeyPrefix}${fiscalCode}`; - const keysV2 = await pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .sMembers(userSessionSetKey), - E.toError, + .sMembers(userSessionSetKey), + E.toError ), TE.mapLeft((err) => { log.error("Error reading set members: %s", err); - + // eslint-disable-next-line functional/prefer-readonly-type return [] as string[]; }), - TE.toUnion, + TE.toUnion )(); const activeKeys = await Promise.all( @@ -376,15 +228,15 @@ export default class RedisSessionStorage this.redisClientSelector .selectOne(RedisClientMode.FAST) .exists(key), - E.toError, + E.toError ), TE.chainW(TE.fromPredicate((response) => !!response, identity)), TE.bimap( () => key, - () => key, - ), - )(), - ), + () => key + ) + )() + ) ); return await Promise.all( @@ -394,107 +246,139 @@ export default class RedisSessionStorage .map((key) => this.redisClientSelector .selectOne(RedisClientMode.FAST) - .sRem(userSessionSetKey, key.left), + .sRem(userSessionSetKey, key.left) ), (keysRemPromises) => keysRemPromises.map((promise) => pipe( TE.tryCatch(() => promise, E.toError), this.integerReplyAsync(), - (task) => task(), - ), - ), - ), + (task) => task() + ) + ) + ) ); } /** - * {@inheritDoc} + * @deprecated use `userHasActiveSessionsOrLV` instead */ - public async del(user: User): Promise> { - const tokens: readonly string[] = R.collect( - (_, { prefix, value }) => `${prefix}${value}`, - )(this.getUserTokens(user)); - - const deleteTokensPromiseV2 = await pipe( - tokens, - ROA.map((singleToken) => - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .del(singleToken), - E.toError, - ), - ), - ROA.sequence(TE.ApplicativeSeq), - TE.map(ROA.reduce(0, (current, next) => current + next)), - this.integerReplyAsync(tokens.length), - this.falsyResponseToErrorAsync( - new Error( - "Unexpected response from redis client deleting user tokens.", - ), - ), + public async userHasActiveSessions( + fiscalCode: FiscalCode + ): Promise> { + const sessionKeys = await this.readSessionInfoKeys(fiscalCode); + if (E.isLeft(sessionKeys)) { + return sessionKeys.left === sessionNotFoundError + ? E.right(false) + : E.left(sessionKeys.left); + } + const errorOrSessionTokens = await pipe( + this.mGet([...sessionKeys.right]), + TE.map((keys) => + this.parseUserSessionList( + keys.filter((key): key is string => key !== null) + ).sessions.map( + (session) => `${sessionKeyPrefix}${session.sessionToken}` + ) + ) )(); - if (E.isLeft(deleteTokensPromiseV2)) { - return E.left( - new Error( - `value [${deleteTokensPromiseV2.left.message}] at RedisSessionStorage.del`, - ), - ); + if (E.isLeft(errorOrSessionTokens)) { + return E.left(errorOrSessionTokens.left); + } else if (errorOrSessionTokens.right.length === 0) { + return E.right(false); } - // Remove SESSIONINFO reference from USERSESSIONS Set - // this operation is executed in background and doesn't compromise - // the logout process. - pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .sRem( - `${userSessionsSetKeyPrefix}${user.fiscal_code}`, - `${sessionInfoKeyPrefix}${user.session_token}`, - ), - E.toError, - ), - TE.mapLeft(() => { - log.warn(`Error updating USERSESSIONS Set for ${user.fiscal_code}`); - }), - )().catch(() => void 0); - return E.right(true); + return pipe( + this.mGet(errorOrSessionTokens.right), + // Skipping null values from the array + TE.map(A.filter((key): key is string => key !== null)), + TE.map((_) => _.length > 0) + )(); } /** - * {@inheritDoc} + * Check if user id logged in, by checking the presence of LollipopData. + * It returns true if login type is LV or a LEGACY session exists, false otherwise + * + * @param fiscalCode + * @returns true if login type is LV or a LEGACY session exists, false otherwise */ - public async delLollipopDataForUser(fiscalCode: FiscalCode) { + public async userHasActiveSessionsOrLV( + fiscalCode: FiscalCode + ): Promise> { + return await pipe( + await this.getLollipopDataForUser(fiscalCode), + TE.fromEither, + TE.chain( + flow( + O.map((data) => + pipe( + data.loginType === LoginTypeEnum.LV, + B.fold( + // if login type is not LV, check for active user sessions + () => + pipe( + TE.tryCatch( + () => this.userHasActiveSessions(fiscalCode), + E.toError + ), + TE.chainEitherK(identity) + ), + // if login type is LV, return true + () => TE.of(true) + ) + ) + ), + // ff no LollipopData was found, return false + O.getOrElseW(() => TE.of(false)) + ) + ) + )(); + } + + /** + * Insert a user in the list of blocked account + * + * @param fiscalCode id of the user + * + * @returns a promise with either an error or true + */ + public setBlockedUser(fiscalCode: FiscalCode): Promise> { return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .del(`${lollipopDataPrefix}${fiscalCode}`), - E.toError, - ), - this.integerReplyAsync(), + TE.tryCatch(() => { + log.info(`Adding ${fiscalCode} to ${blockedUserSetKey} set`); + return this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .sAdd(blockedUserSetKey, fiscalCode); + }, E.toError), + TE.map((_) => true) )(); } /** - * Delete notify email cache related to an user + * Remove a user from the list of blocked account + * + * @param fiscalCode id of the user + * + * @returns a promise with either an error or true */ - public async delPagoPaNoticeEmail(user: User): Promise> { + public unsetBlockedUser( + fiscalCode: FiscalCode + ): Promise> { return pipe( - TE.tryCatch( - () => - this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .del(`${noticeEmailPrefix}${user.session_token}`), - E.toError, - ), - TE.map(() => true), + TE.tryCatch(() => { + log.info(`Removing ${fiscalCode} from ${blockedUserSetKey} set`); + return this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .sRem(blockedUserSetKey, fiscalCode); + }, E.toError), + this.integerReplyAsync(1), + this.falsyResponseToErrorAsync( + new Error( + "Unexpected response from redis client deleting blockedUserKey" + ) + ) )(); } @@ -504,12 +388,12 @@ export default class RedisSessionStorage * @param fiscalCode */ public async delUserAllSessions( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ): Promise> { const errorOrSessions = await this.readSessionInfoKeys(fiscalCode); const delEverySession = ( - sessionTokens: readonly SessionToken[], + sessionTokens: ReadonlyArray ): TaskEither => pipe( A.sequence(TE.ApplicativePar)( @@ -519,19 +403,19 @@ export default class RedisSessionStorage pipe( sessionToken, SessionToken.decode, - E.mapLeft(() => new Error("Error decoding token")), - ), + E.mapLeft((_) => new Error("Error decoding token")) + ) ), TE.chain((token: SessionToken) => pipe( TE.tryCatch(() => this.delSingleSession(token), E.toError), - TE.chain(TE.fromEither), - ), - ), - ), - ), + TE.chain(TE.fromEither) + ) + ) + ) + ) ), - TE.map(() => true), + TE.map(() => true) ); return pipe( @@ -544,79 +428,44 @@ export default class RedisSessionStorage delEverySession( sessionInfoKeys.map( (sessionInfoKey) => - sessionInfoKey.replace( - sessionInfoKeyPrefix, - "", - ) as SessionToken, - ), - ), + sessionInfoKey.replace(sessionInfoKeyPrefix, "") as SessionToken + ) + ) ), - TE.chain(() => + TE.chain((_) => pipe( TE.tryCatch(() => this.delSessionsSet(fiscalCode), E.toError), - TE.chain(TE.fromEither), - ), - ), + TE.chain(TE.fromEither) + ) + ) )(); } - // ---------------------------------------------- - // Private methods - // ---------------------------------------------- - - // This mGet fires a bunch of GET operation to prevent CROSS-SLOT errors on the cluster /** - * {@inheritDoc} + * Delete notify email cache related to an user */ - public async getByMyPortalToken( - token: MyPortalToken, - ): Promise>> { - const errorOrSession = await this.loadSessionByToken( - myPortalTokenPrefix, - token, - ); - - if (E.isLeft(errorOrSession)) { - if (errorOrSession.left === sessionNotFoundError) { - return E.right(O.none); - } - return E.left(errorOrSession.left); - } - - const user = errorOrSession.right; - - return E.right(O.some(user)); - } - - /** - * {@inheritDoc} - */ - public async getBySessionToken( - token: SessionToken, - ): Promise>> { - const errorOrSession = await this.loadSessionBySessionToken(token); - - if (E.isLeft(errorOrSession)) { - if (errorOrSession.left === sessionNotFoundError) { - return E.right(O.none); - } - return E.left(errorOrSession.left); - } - - const user = errorOrSession.right; - - return E.right(O.some(user)); + public async delPagoPaNoticeEmail(user: User): Promise> { + return pipe( + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .del(`${noticeEmailPrefix}${user.session_token}`), + E.toError + ), + TE.map((_) => true) + )(); } /** * {@inheritDoc} */ public async getLollipopAssertionRefForUser( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ): Promise>> { return pipe( await this.getLollipopDataForUser(fiscalCode), - E.map(O.map((data) => data.assertionRef)), + E.map(O.map((data) => data.assertionRef)) ); } @@ -624,7 +473,7 @@ export default class RedisSessionStorage * {@inheritDoc} */ public async getLollipopDataForUser( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ): Promise>> { return pipe( TE.tryCatch( @@ -632,7 +481,7 @@ export default class RedisSessionStorage this.redisClientSelector .selectOne(RedisClientMode.SAFE) .get(`${lollipopDataPrefix}${fiscalCode}`), - E.toError, + E.toError ), TE.chain( flow( @@ -647,17 +496,17 @@ export default class RedisSessionStorage { assertionRef: storedValue, loginType: LoginTypeEnum.LEGACY, - }, - ), - ), + } + ) + ) ), E.mapLeft( (validationErrors) => - new Error(errorsToReadableMessages(validationErrors).join("/")), + new Error(errorsToReadableMessages(validationErrors).join("/")) ), - TE.fromEither, - ), - ), + TE.fromEither + ) + ) )(); } @@ -665,7 +514,7 @@ export default class RedisSessionStorage * {@inheritDoc} */ public getSessionRemainingTTL( - fiscalCode: FiscalCode, + fiscalCode: FiscalCode ): TE.TaskEither> { return pipe( TE.tryCatch( @@ -676,13 +525,13 @@ export default class RedisSessionStorage this.redisClientSelector .selectOne(RedisClientMode.SAFE) .ttl(`${lollipopDataPrefix}${fiscalCode}`), - E.toError, + E.toError ), TE.chain( TE.fromPredicate( (_) => _ !== -1, - () => new Error("Unexpected missing CF-AssertionRef TTL"), - ), + () => new Error("Unexpected missing CF-AssertionRef TTL") + ) ), TE.map(flow(O.fromPredicate((ttl) => ttl > 0))), TE.chain((maybeTtl) => @@ -691,164 +540,308 @@ export default class RedisSessionStorage : pipe( TE.tryCatch( () => this.getLollipopDataForUser(fiscalCode), - E.toError, + E.toError ), TE.chain(TE.fromEither), TE.chain( TE.fromPredicate( O.isSome, - () => new Error("Unexpected missing value"), - ), + () => new Error("Unexpected missing value") + ) ), TE.map(({ value }) => - O.some({ ttl: maybeTtl.value, type: value.loginType }), - ), - ), - ), + O.some({ ttl: maybeTtl.value, type: value.loginType }) + ) + ) + ) ); } - public async listUserSessions( - user: User, - ): Promise> { - // If some user session was expired we update the USERSESSION Redis set. - await this.clearExpiredSetValues(user.fiscal_code); - - const sessionKeys = await this.readSessionInfoKeys(user.fiscal_code); + /** + * {@inheritDoc} + */ + public async delLollipopDataForUser(fiscalCode: FiscalCode) { + return pipe( + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .del(`${lollipopDataPrefix}${fiscalCode}`), + E.toError + ), + this.integerReplyAsync() + )(); + } - if (E.isLeft(sessionKeys)) { - return E.left(sessionKeys.left); - } + // ---------------------------------------------- + // Private methods + // ---------------------------------------------- + // This mGet fires a bunch of GET operation to prevent CROSS-SLOT errors on the cluster + // eslint-disable-next-line functional/prefer-readonly-type + private mGet(keys: string[]): TaskEither> { return pipe( - this.mGet([...sessionKeys.right]), - TE.map((keys) => - this.parseUserSessionList( - keys.filter((key) => key !== null) as readonly string[], - ), + keys, + A.map((singleKey) => + TE.tryCatch(() => { + const redis_client = this.redisClientSelector.selectOne( + RedisClientMode.FAST + ); + return redis_client.get.bind(redis_client)(singleKey); + }, E.toError) ), - )(); + A.sequence(TE.ApplicativePar) + ); } /** - * Insert a user in the list of blocked account - * - * @param fiscalCode id of the user + * Given a token, it removes user session token and wallet token * - * @returns a promise with either an error or true + * @param token */ - public setBlockedUser(fiscalCode: FiscalCode): Promise> { + private async delSingleSession( + token: SessionToken + ): Promise> { + try { + const user: User = pipe( + await this.loadSessionBySessionToken(token), + E.getOrElseW((err) => { + throw err; + }) + ); + return this.del(user); + } catch (error) { + // as it's a delete, if the query fails for a NotFoudn error, it might be considered a success + return error === sessionNotFoundError + ? E.right(true) + : E.left(E.toError(error)); + } + } + + private delSessionsSet(fiscalCode: FiscalCode): Promise> { return pipe( TE.tryCatch(() => { - log.info(`Adding ${fiscalCode} to ${blockedUserSetKey} set`); + log.info( + `Deleting sessions set ${userSessionsSetKeyPrefix}${fiscalCode}` + ); return this.redisClientSelector .selectOne(RedisClientMode.FAST) - .sAdd(blockedUserSetKey, fiscalCode); + .del(`${userSessionsSetKeyPrefix}${fiscalCode}`); }, E.toError), - TE.map(() => true), + TE.map((_) => true) )(); } /** - * Remove a user from the list of blocked account - * - * @param fiscalCode id of the user - * - * @returns a promise with either an error or true + * Return a Session for this token. */ - public unsetBlockedUser( - fiscalCode: FiscalCode, - ): Promise> { + private async loadSessionBySessionToken( + token: SessionToken + ): Promise> { return pipe( - TE.tryCatch(() => { - log.info(`Removing ${fiscalCode} from ${blockedUserSetKey} set`); - return this.redisClientSelector - .selectOne(RedisClientMode.FAST) - .sRem(blockedUserSetKey, fiscalCode); - }, E.toError), - this.integerReplyAsync(1), - this.falsyResponseToErrorAsync( - new Error( - "Unexpected response from redis client deleting blockedUserKey", - ), + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .get(`${sessionKeyPrefix}${token}`), + E.toError ), + TE.chain( + flow( + O.fromNullable, + E.fromOption(() => sessionNotFoundError), + E.chain(this.parseUser), + TE.fromEither + ) + ) )(); } /** - * @deprecated use `userHasActiveSessionsOrLV` instead + * Return a Session for this token. */ - public async userHasActiveSessions( - fiscalCode: FiscalCode, - ): Promise> { - const sessionKeys = await this.readSessionInfoKeys(fiscalCode); - if (E.isLeft(sessionKeys)) { - return sessionKeys.left === sessionNotFoundError - ? E.right(false) - : E.left(sessionKeys.left); - } - const errorOrSessionTokens = await pipe( - this.mGet([...sessionKeys.right]), - TE.map((keys) => - this.parseUserSessionList( - keys.filter((key): key is string => key !== null), - ).sessions.map( - (session) => `${sessionKeyPrefix}${session.sessionToken}`, - ), + private loadSessionByToken( + prefix: string, + token: WalletToken | MyPortalToken | BPDToken | ZendeskToken | FIMSToken + ): Promise> { + return pipe( + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .get(`${prefix}${token}`), + E.toError ), + TE.chain( + flow( + O.fromNullable, + TE.fromOption(() => sessionNotFoundError) + ) + ), + TE.chain((value) => + pipe( + TE.tryCatch( + () => this.loadSessionBySessionToken(value as SessionToken), + E.toError + ), + TE.chain(TE.fromEither) + ) + ) )(); + } - if (E.isLeft(errorOrSessionTokens)) { - return E.left(errorOrSessionTokens.left); - } else if (errorOrSessionTokens.right.length === 0) { - return E.right(false); - } + private readSessionInfoKeys( + fiscalCode: FiscalCode + ): Promise>> { + return pipe( + TE.tryCatch( + () => + this.redisClientSelector + .selectOne(RedisClientMode.FAST) + .sMembers(`${userSessionsSetKeyPrefix}${fiscalCode}`), + E.toError + ), + this.arrayStringReplyAsync + ); + } + private arrayStringReplyAsync( + command: TE.TaskEither> + ): Promise>> { return pipe( - this.mGet(errorOrSessionTokens.right), - // Skipping null values from the array - TE.map(A.filter((key): key is string => key !== null)), - TE.map((_) => _.length > 0), + command, + TE.chain( + TE.fromPredicate( + (res): res is NonEmptyArray => isArray(res) && res.length > 0, + () => sessionNotFoundError + ) + ) )(); } - /** - * Check if user id logged in, by checking the presence of LollipopData. - * It returns true if login type is LV or a LEGACY session exists, false otherwise - * - * @param fiscalCode - * @returns true if login type is LV or a LEGACY session exists, false otherwise - */ - public async userHasActiveSessionsOrLV( - fiscalCode: FiscalCode, - ): Promise> { - return await pipe( - await this.getLollipopDataForUser(fiscalCode), - TE.fromEither, - TE.chain( + private parseUser(value: string): Either { + return pipe( + E.parseJSON(value, E.toError), + E.chain( flow( - O.map((data) => + User.decode, + E.mapLeft((err) => new Error(errorsToReadableMessages(err).join("/"))) + ) + ) + ); + } + + private parseUserSessionList( + userSessionTokensResult: ReadonlyArray + ): SessionsList { + return userSessionTokensResult.reduce( + (prev: SessionsList, _) => + pipe( + E.parseJSON(_, E.toError), + E.chain((data) => pipe( - data.loginType === LoginTypeEnum.LV, - B.fold( - // if login type is not LV, check for active user sessions - () => - pipe( - TE.tryCatch( - () => this.userHasActiveSessions(fiscalCode), - E.toError, - ), - TE.chainEitherK(identity), - ), - // if login type is LV, return true - () => TE.of(true), - ), - ), + SessionInfo.decode(data), + E.mapLeft( + (err) => new Error(errorsToReadableMessages(err).join("/")) + ) + ) ), - // ff no LollipopData was found, return false - O.getOrElseW(() => TE.of(false)), + E.fold( + (err) => { + log.warn("Unable to decode the session info: %s. Skipped.", err); + return prev; + }, + (sessionInfo) => ({ + sessions: [...prev.sessions, sessionInfo], + }) + ) ), - ), - )(); + { sessions: [] } as SessionsList + ); + } + + private getUserTokens( + user: User + ): Record { + const requiredTokens = { + session_info: { + prefix: sessionInfoKeyPrefix, + value: user.session_token, + }, + session_token: { + prefix: sessionKeyPrefix, + value: user.session_token, + }, + wallet_token: { + prefix: walletKeyPrefix, + value: user.wallet_token, + }, + }; + if (UserV5.is(user)) { + return { + ...requiredTokens, + bpd_token: { + prefix: bpdTokenPrefix, + value: user.bpd_token, + }, + fims_token: { + prefix: fimsTokenPrefix, + value: user.fims_token, + }, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + zendesk_token: { + prefix: zendeskTokenPrefix, + value: user.zendesk_token, + }, + }; + } + if (UserV4.is(user)) { + return { + ...requiredTokens, + bpd_token: { + prefix: bpdTokenPrefix, + value: user.bpd_token, + }, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + zendesk_token: { + prefix: zendeskTokenPrefix, + value: user.zendesk_token, + }, + }; + } + if (UserV3.is(user)) { + return { + ...requiredTokens, + bpd_token: { + prefix: bpdTokenPrefix, + value: user.bpd_token, + }, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + }; + } + if (UserV2.is(user)) { + return { + ...requiredTokens, + myportal_token: { + prefix: myPortalTokenPrefix, + value: user.myportal_token, + }, + }; + } + if (UserV1.is(user)) { + return { + ...requiredTokens, + }; + } + return assertUnreachable(user); } } diff --git a/src/services/redisStorageUtils.ts b/src/services/redisStorageUtils.ts index 4991b2c7a..df554ce4d 100644 --- a/src/services/redisStorageUtils.ts +++ b/src/services/redisStorageUtils.ts @@ -1,36 +1,34 @@ +import { isNumber } from "util"; import * as E from "fp-ts/lib/Either"; import { Either } from "fp-ts/lib/Either"; import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; -import { isNumber } from "util"; export default class RedisStorageUtils { /** + * Parse a Redis single string reply. * + * @see https://redis.io/topics/protocol#simple-string-reply. * @deprecated */ - protected falsyResponseToError( - response: Either, - error: Error, - ): Either { - if (E.isLeft(response)) { - return E.left(response.left); - } else { - if (response.right) { - return E.right(true); - } - return E.left(error); + protected singleStringReply( + err: Error | null, + reply: "OK" | undefined + ): Either { + if (err) { + return E.left(err); } + + return E.right(reply === "OK"); } - protected falsyResponseToErrorAsync(error: Error) { - return ( - response: TE.TaskEither, - ): TE.TaskEither => - pipe( - response, - TE.chain((_) => (_ ? TE.right(_) : TE.left(error))), - ); + protected singleStringReplyAsync( + command: TE.TaskEither + ) { + return pipe( + command, + TE.map((reply) => reply === "OK") + ); } /** @@ -42,7 +40,7 @@ export default class RedisStorageUtils { protected integerReply( err: Error | null, reply: unknown, - expectedReply?: number, + expectedReply?: number ): Either { if (err) { return E.left(err); @@ -55,7 +53,7 @@ export default class RedisStorageUtils { protected integerReplyAsync(expectedReply?: number) { return ( - command: TE.TaskEither, + command: TE.TaskEither ): TE.TaskEither => pipe( command, @@ -64,33 +62,35 @@ export default class RedisStorageUtils { return TE.right(false); } return TE.right(isNumber(reply)); - }), + }) ); } /** - * Parse a Redis single string reply. * - * @see https://redis.io/topics/protocol#simple-string-reply. * @deprecated */ - protected singleStringReply( - err: Error | null, - reply: "OK" | undefined, - ): Either { - if (err) { - return E.left(err); + protected falsyResponseToError( + response: Either, + error: Error + ): Either { + if (E.isLeft(response)) { + return E.left(response.left); + } else { + if (response.right) { + return E.right(true); + } + return E.left(error); } - - return E.right(reply === "OK"); } - protected singleStringReplyAsync( - command: TE.TaskEither, - ) { - return pipe( - command, - TE.map((reply) => reply === "OK"), - ); + protected falsyResponseToErrorAsync(error: Error) { + return ( + response: TE.TaskEither + ): TE.TaskEither => + pipe( + response, + TE.chain((_) => (_ ? TE.right(_) : TE.left(error))) + ); } } diff --git a/src/services/redisUserMetadataStorage.ts b/src/services/redisUserMetadataStorage.ts index a2e0314b4..ce5962e90 100644 --- a/src/services/redisUserMetadataStorage.ts +++ b/src/services/redisUserMetadataStorage.ts @@ -1,13 +1,12 @@ +import * as redis from "redis"; +import * as E from "fp-ts/lib/Either"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import * as E from "fp-ts/lib/Either"; import { Either } from "fp-ts/lib/Either"; -import { parse } from "fp-ts/lib/Json"; -import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; +import * as O from "fp-ts/lib/Option"; +import { parse } from "fp-ts/lib/Json"; import { flow, pipe } from "fp-ts/lib/function"; -import * as redis from "redis"; - import { UserMetadata } from "../../generated/backend/UserMetadata"; import { User } from "../types/user"; import { log } from "../utils/logger"; @@ -27,72 +26,11 @@ export default class RedisUserMetadataStorage implements IUserMetadataStorage { constructor( - private readonly redisClient: - | redis.RedisClientType - | redis.RedisClusterType, + private readonly redisClient: redis.RedisClientType | redis.RedisClusterType ) { super(); } - private loadUserMetadataByFiscalCode( - fiscalCode: string, - ): Promise> { - return pipe( - TE.tryCatch( - () => this.redisClient.get(`${userMetadataPrefix}${fiscalCode}`), - () => new Error("REDIS CLIENT ERROR"), - ), - TE.chain( - flow( - O.fromNullable, - TE.fromOption(() => metadataNotFoundError), - ), - ), - TE.chain( - flow( - parse, - E.mapLeft(() => new Error("Unable to parse the user metadata json")), - TE.fromEither, - TE.chain( - flow( - UserMetadata.decode, - TE.fromEither, - TE.mapLeft((err) => { - log.error( - "Unable to decode the user metadata: %s", - errorsToReadableMessages(err).join("|"), - ); - return new Error("Unable to decode the user metadata"); - }), - ), - ), - ), - ), - )(); - } - - /** - * Delete all user metdata - * - * {@inheritDoc} - */ - public del(fiscalCode: FiscalCode): Promise> { - return pipe( - TE.tryCatch(() => { - log.info(`Deleting metadata for ${fiscalCode}`); - return this.redisClient.del(`${userMetadataPrefix}${fiscalCode}`); - }, E.toError), - TE.map(() => true), - )(); - } - - /** - * {@inheritDoc} - */ - public async get(user: User): Promise> { - return this.loadUserMetadataByFiscalCode(user.fiscal_code); - } - /** * {@inheritDoc} * @@ -101,10 +39,10 @@ export default class RedisUserMetadataStorage */ public async set( user: User, - payload: UserMetadata, + payload: UserMetadata ): Promise> { const getUserMetadataResult = await this.loadUserMetadataByFiscalCode( - user.fiscal_code, + user.fiscal_code ); if ( E.isRight(getUserMetadataResult) && @@ -123,11 +61,70 @@ export default class RedisUserMetadataStorage () => this.redisClient.set( `${userMetadataPrefix}${user.fiscal_code}`, - JSON.stringify(payload), + JSON.stringify(payload) ), - E.toError, + E.toError ), - this.singleStringReplyAsync, + this.singleStringReplyAsync + )(); + } + + /** + * {@inheritDoc} + */ + public async get(user: User): Promise> { + return this.loadUserMetadataByFiscalCode(user.fiscal_code); + } + + /** + * Delete all user metdata + * + * {@inheritDoc} + */ + public del(fiscalCode: FiscalCode): Promise> { + return pipe( + TE.tryCatch(() => { + log.info(`Deleting metadata for ${fiscalCode}`); + return this.redisClient.del(`${userMetadataPrefix}${fiscalCode}`); + }, E.toError), + TE.map(() => true) + )(); + } + + private loadUserMetadataByFiscalCode( + fiscalCode: string + ): Promise> { + return pipe( + TE.tryCatch( + () => this.redisClient.get(`${userMetadataPrefix}${fiscalCode}`), + () => new Error("REDIS CLIENT ERROR") + ), + TE.chain( + flow( + O.fromNullable, + TE.fromOption(() => metadataNotFoundError) + ) + ), + TE.chain( + flow( + parse, + E.mapLeft(() => new Error("Unable to parse the user metadata json")), + TE.fromEither, + TE.chain( + flow( + UserMetadata.decode, + TE.fromEither, + TE.mapLeft((err) => { + log.error( + "Unable to decode the user metadata: %s", + errorsToReadableMessages(err).join("|") + ); + return new Error("Unable to decode the user metadata"); + }) + ) + ) + ) + ) )(); } } diff --git a/src/services/servicesAppBackendService.ts b/src/services/servicesAppBackendService.ts index ae4c9f821..fc4f943ed 100644 --- a/src/services/servicesAppBackendService.ts +++ b/src/services/servicesAppBackendService.ts @@ -6,7 +6,6 @@ import { ResponseErrorNotFound, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; - import { FeaturedServices } from "../../generated/services-app-backend/FeaturedServices"; import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; import { Institutions } from "../../generated/services-app-backend/Institutions"; @@ -22,11 +21,15 @@ import { // TODO: Aggiungere le altre operazioni del service export default class ServicesAppBackendService { + constructor( + private readonly apiClient: ReturnType + ) {} + public readonly findInstitutions = ( search?: string, scope?: ScopeType, limit?: number, - offset?: number, + offset?: number ): Promise< | IResponseErrorInternal | IResponseErrorValidation @@ -44,97 +47,93 @@ export default class ServicesAppBackendService { response.status === 200 ? withValidatedOrInternalError( InstitutionsResource.decode(response.value), - ResponseSuccessJson, + ResponseSuccessJson ) - : unhandledResponseStatus(response.status), + : unhandledResponseStatus(response.status) ); }); - public readonly findInstutionServices = ( - // TODO: fix institutionId type - institutionId: string, - limit?: number, - offset?: number, + public readonly getServiceById = ( + serviceId: string ): Promise< - IResponseErrorInternal | IResponseSuccessJson + | IResponseErrorInternal + | IResponseErrorNotFound + | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.findInstutionServices({ - institutionId, - limit, - offset, + const validated = await this.apiClient.getServiceById({ + serviceId, }); - // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - InstitutionServicesResource.decode(response.value), - ResponseSuccessJson, + ServiceDetails.decode(response.value), + ResponseSuccessJson ) - : unhandledResponseStatus(response.status), + : response.status === 404 + ? ResponseErrorNotFound("Not found", "Service not found") + : unhandledResponseStatus(response.status) ); }); - public readonly getFeaturedInstitutions = (): Promise< - IResponseErrorInternal | IResponseSuccessJson + public readonly getFeaturedServices = (): Promise< + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.getFeaturedInstitutions({}); + const validated = await this.apiClient.getFeaturedServices({}); // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - Institutions.decode(response.value), - ResponseSuccessJson, + FeaturedServices.decode(response.value), + ResponseSuccessJson ) - : unhandledResponseStatus(response.status), + : unhandledResponseStatus(response.status) ); }); - public readonly getFeaturedServices = (): Promise< - IResponseErrorInternal | IResponseSuccessJson + public readonly getFeaturedInstitutions = (): Promise< + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.getFeaturedServices({}); + const validated = await this.apiClient.getFeaturedInstitutions({}); // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - FeaturedServices.decode(response.value), - ResponseSuccessJson, + Institutions.decode(response.value), + ResponseSuccessJson ) - : unhandledResponseStatus(response.status), + : unhandledResponseStatus(response.status) ); }); - public readonly getServiceById = ( - serviceId: string, + public readonly findInstutionServices = ( + // TODO: fix institutionId type + institutionId: string, + limit?: number, + offset?: number ): Promise< - | IResponseErrorInternal - | IResponseErrorNotFound - | IResponseSuccessJson + IResponseErrorInternal | IResponseSuccessJson > => withCatchAsInternalError(async () => { - const validated = await this.apiClient.getServiceById({ - serviceId, + const validated = await this.apiClient.findInstutionServices({ + institutionId, + limit, + offset, }); + // TODO: sistemare i vari return return withValidatedOrInternalError(validated, (response) => response.status === 200 ? withValidatedOrInternalError( - ServiceDetails.decode(response.value), - ResponseSuccessJson, + InstitutionServicesResource.decode(response.value), + ResponseSuccessJson ) - : response.status === 404 - ? ResponseErrorNotFound("Not found", "Service not found") - : unhandledResponseStatus(response.status), + : unhandledResponseStatus(response.status) ); }); - - constructor( - private readonly apiClient: ReturnType, - ) {} } diff --git a/src/services/trialService.ts b/src/services/trialService.ts index deb308bdb..6e5cb6144 100644 --- a/src/services/trialService.ts +++ b/src/services/trialService.ts @@ -2,47 +2,50 @@ * This service retrieves messages from the API system using an API client. */ import { - IResponseErrorConflict, IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, - IResponseSuccessAccepted, - IResponseSuccessJson, - IResponseSuccessRedirectToResource, - ResponseErrorConflict, - ResponseErrorInternal, ResponseErrorNotFound, + ResponseErrorInternal, ResponseErrorValidation, + IResponseSuccessAccepted, + IResponseSuccessRedirectToResource, + ResponseSuccessRedirectToResource, ResponseSuccessAccepted, + ResponseErrorConflict, + IResponseErrorConflict, + IResponseSuccessJson, ResponseSuccessJson, - ResponseSuccessRedirectToResource, } from "@pagopa/ts-commons/lib/responses"; +import { TrialSystemAPIClient } from "src/clients/trial-system.client"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import * as O from "fp-ts/Option"; import { pipe } from "fp-ts/lib/function"; -import { TrialSystemAPIClient } from "src/clients/trial-system.client"; - -import { Subscription } from "../../generated/trial-system/Subscription"; -import { TrialId } from "../../generated/trial-system-api/TrialId"; +import * as O from "fp-ts/Option"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError, } from "../utils/responses"; +import { TrialId } from "../../generated/trial-system-api/TrialId"; +import { Subscription } from "../../generated/trial-system/Subscription"; export default class TrialService { + constructor( + private readonly apiClient: ReturnType + ) {} + /** * Subscribe a user to a specific trial. */ public readonly createSubscription = async ( userId: NonEmptyString, - trialId: TrialId, + trialId: TrialId ): Promise< - | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorValidation + | IResponseErrorNotFound + | IResponseErrorConflict | IResponseSuccessAccepted | IResponseSuccessRedirectToResource > => @@ -67,8 +70,8 @@ export default class TrialService { ResponseSuccessRedirectToResource( resBody, `/api/v1/trials/${trialId}/subscriptions`, - resBody, - ), + resBody + ) ); case 202: return ResponseSuccessAccepted(); @@ -78,8 +81,8 @@ export default class TrialService { pipe( response.value.detail, O.fromNullable, - O.getOrElse(() => "Malformed request"), - ), + O.getOrElse(() => "Malformed request") + ) ); case 401: return ResponseErrorUnexpectedAuthProblem(); @@ -92,8 +95,8 @@ export default class TrialService { pipe( response.value.detail, O.fromNullable, - O.getOrElse(() => "Cannot create subscription"), - ), + O.getOrElse(() => "Cannot create subscription") + ) ); default: return ResponseErrorStatusNotDefinedInSpec(response); @@ -106,7 +109,7 @@ export default class TrialService { */ public readonly getSubscription = async ( userId: NonEmptyString, - trialId: TrialId, + trialId: TrialId ): Promise< | IResponseErrorInternal | IResponseErrorNotFound @@ -127,7 +130,7 @@ export default class TrialService { state: response.value.state, trialId: response.value.trialId, }, - ResponseSuccessJson, + ResponseSuccessJson ); case 401: return ResponseErrorUnexpectedAuthProblem(); @@ -138,16 +141,12 @@ export default class TrialService { pipe( response.value.detail, O.fromNullable, - O.getOrElse(() => "Cannot get subscription"), - ), + O.getOrElse(() => "Cannot get subscription") + ) ); default: return ResponseErrorStatusNotDefinedInSpec(response); } }); }); - - constructor( - private readonly apiClient: ReturnType, - ) {} } diff --git a/src/services/userDataProcessingService.ts b/src/services/userDataProcessingService.ts index a4583120d..344366796 100644 --- a/src/services/userDataProcessingService.ts +++ b/src/services/userDataProcessingService.ts @@ -3,9 +3,6 @@ * an API client. */ -import { UserDataProcessing } from "@pagopa/io-functions-app-sdk/UserDataProcessing"; -import { UserDataProcessingChoice } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoice"; -import { UserDataProcessingChoiceRequest } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoiceRequest"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -20,9 +17,12 @@ import { ResponseSuccessAccepted, ResponseSuccessJson, } from "@pagopa/ts-commons/lib/responses"; -import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; +import * as O from "fp-ts/lib/Option"; +import { UserDataProcessing } from "@pagopa/io-functions-app-sdk/UserDataProcessing"; +import { UserDataProcessingChoice } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoice"; +import { UserDataProcessingChoiceRequest } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoiceRequest"; import { User } from "../types/user"; import { unhandledResponseStatus, @@ -32,42 +32,40 @@ import { import { IApiClientFactoryInterface } from "./IApiClientFactory"; export default class UserDataProcessingService { + constructor(private readonly apiClient: IApiClientFactoryInterface) {} + /** - * Abort the user data processing of a specific user. + * Create the user data processing of a specific user. */ - public readonly abortUserDataProcessing = async ( + public readonly upsertUserDataProcessing = async ( user: User, - userDataProcessingChoiceParam: UserDataProcessingChoice, + userDataProcessingChoiceRequest: UserDataProcessingChoiceRequest ): Promise< - | IResponseErrorConflict | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseErrorValidation - | IResponseSuccessAccepted + | IResponseErrorConflict + | IResponseSuccessJson > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.abortUserDataProcessing({ - choice: userDataProcessingChoiceParam, + const validated = await client.upsertUserDataProcessing({ + body: userDataProcessingChoiceRequest, fiscal_code: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => - response.status === 202 - ? ResponseSuccessAccepted() - : response.status === 404 - ? ResponseErrorNotFound( - "Not Found", - "User data processing not found", + response.status === 200 + ? ResponseSuccessJson(response.value) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : response.status === 409 + ? ResponseErrorConflict( + pipe( + O.fromNullable(response.value.detail), + O.getOrElse(() => "Conflict") ) - : response.status === 409 - ? ResponseErrorConflict( - "Cannot abort user data processing request", - ) - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status), + ) + : unhandledResponseStatus(response.status) ); }); }; @@ -77,11 +75,11 @@ export default class UserDataProcessingService { */ public readonly getUserDataProcessing = async ( user: User, - userDataProcessingChoiceParam: UserDataProcessingChoice, + userDataProcessingChoiceParam: UserDataProcessingChoice ): Promise< | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorTooManyRequests + | IResponseErrorNotFound | IResponseSuccessJson > => { const client = this.apiClient.getClient(); @@ -95,52 +93,46 @@ export default class UserDataProcessingService { response.status === 200 ? ResponseSuccessJson(response.value) : response.status === 404 - ? ResponseErrorNotFound( - "Not Found", - "User data processing not found", - ) - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status), + ? ResponseErrorNotFound("Not Found", "User data processing not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); }; /** - * Create the user data processing of a specific user. + * Abort the user data processing of a specific user. */ - public readonly upsertUserDataProcessing = async ( + public readonly abortUserDataProcessing = async ( user: User, - userDataProcessingChoiceRequest: UserDataProcessingChoiceRequest, + userDataProcessingChoiceParam: UserDataProcessingChoice ): Promise< - | IResponseErrorConflict | IResponseErrorInternal | IResponseErrorTooManyRequests - | IResponseSuccessJson + | IResponseErrorNotFound + | IResponseErrorValidation + | IResponseErrorConflict + | IResponseSuccessAccepted > => { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { - const validated = await client.upsertUserDataProcessing({ - body: userDataProcessingChoiceRequest, + const validated = await client.abortUserDataProcessing({ + choice: userDataProcessingChoiceParam, fiscal_code: user.fiscal_code, }); return withValidatedOrInternalError(validated, (response) => - response.status === 200 - ? ResponseSuccessJson(response.value) + response.status === 202 + ? ResponseSuccessAccepted() + : response.status === 404 + ? ResponseErrorNotFound("Not Found", "User data processing not found") + : response.status === 409 + ? ResponseErrorConflict("Cannot abort user data processing request") : response.status === 429 - ? ResponseErrorTooManyRequests() - : response.status === 409 - ? ResponseErrorConflict( - pipe( - O.fromNullable(response.value.detail), - O.getOrElse(() => "Conflict"), - ), - ) - : unhandledResponseStatus(response.status), + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); }; - - constructor(private readonly apiClient: IApiClientFactoryInterface) {} } diff --git a/src/strategies/bearerMyPortalTokenStrategy.ts b/src/strategies/bearerMyPortalTokenStrategy.ts index afd0483e1..23a009533 100644 --- a/src/strategies/bearerMyPortalTokenStrategy.ts +++ b/src/strategies/bearerMyPortalTokenStrategy.ts @@ -6,14 +6,13 @@ import * as express from "express"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; import * as passport from "passport-http-bearer"; - import { ISessionStorage } from "../services/ISessionStorage"; import { MyPortalToken } from "../types/token"; import { User } from "../types/user"; -import { StrategyDoneFunction, fulfill } from "../utils/strategies"; +import { fulfill, StrategyDoneFunction } from "../utils/strategies"; const bearerMyPortalTokenStrategy = ( - sessionStorage: ISessionStorage, + sessionStorage: ISessionStorage ): passport.Strategy => { const options = { passReqToCallback: true, @@ -39,9 +38,9 @@ const bearerMyPortalTokenStrategy = ( // The error is forwarded to the express error middleware done(e); } - }, + } ); - }, + } ); }; diff --git a/src/strategies/bearerSessionTokenStrategy.ts b/src/strategies/bearerSessionTokenStrategy.ts index f00017596..37a7d2df9 100644 --- a/src/strategies/bearerSessionTokenStrategy.ts +++ b/src/strategies/bearerSessionTokenStrategy.ts @@ -8,15 +8,14 @@ import { Either } from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import { Option } from "fp-ts/lib/Option"; import * as passport from "passport-http-bearer"; - import { ISessionStorage } from "../services/ISessionStorage"; import { SessionToken } from "../types/token"; import { User } from "../types/user"; -import { StrategyDoneFunction, fulfill } from "../utils/strategies"; +import { fulfill, StrategyDoneFunction } from "../utils/strategies"; const bearerSessionTokenStrategy = ( sessionStorage: ISessionStorage, - onValidUser?: (user: User) => void, + onValidUser?: (user: User) => void ): passport.Strategy => { const options = { passReqToCallback: true, @@ -49,9 +48,9 @@ const bearerSessionTokenStrategy = ( // The error is forwarded to the express error middleware done(e); } - }, + } ); - }, + } ); }; diff --git a/src/types/IDPEntityDescriptor.ts b/src/types/IDPEntityDescriptor.ts index e3f01e8df..055c5917c 100644 --- a/src/types/IDPEntityDescriptor.ts +++ b/src/types/IDPEntityDescriptor.ts @@ -1,6 +1,6 @@ -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as t from "io-ts"; import { nonEmptyArray as createNonEmptyArrayFromArray } from "io-ts-types/lib/nonEmptyArray"; +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; export const IDPEntityDescriptor = t.interface({ cert: createNonEmptyArrayFromArray(NonEmptyString), diff --git a/src/types/assertionRef.ts b/src/types/assertionRef.ts index a156ac4dd..7da471de5 100644 --- a/src/types/assertionRef.ts +++ b/src/types/assertionRef.ts @@ -1,10 +1,11 @@ -import { pipe } from "fp-ts/lib/function"; import * as t from "io-ts"; +import { pipe } from "fp-ts/lib/function"; import { JsonFromString } from "io-ts-types"; -import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; import { LoginType } from "../utils/fastLogin"; +import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; + // LollipopData export type LollipopData = t.TypeOf; export const LollipopData = t.type({ @@ -31,9 +32,9 @@ const LollipopDataFromCompact = new t.Type< pipe( val, (data) => ({ assertionRef: data.a, loginType: data.t }), - (data) => LollipopData.validate(data, _context), + (data) => LollipopData.validate(data, _context) ), - (val) => ({ a: val.assertionRef, t: val.loginType }), + (val) => ({ a: val.assertionRef, t: val.loginType }) ); // --------------------- diff --git a/src/types/booleans.ts b/src/types/booleans.ts index 3290b7030..edc29ba65 100644 --- a/src/types/booleans.ts +++ b/src/types/booleans.ts @@ -22,7 +22,7 @@ export const BooleanFromString: BooleanFromString = new t.Type< s === "true" ? t.success(true) : s === "false" - ? t.success(false) - : t.failure(s, c), - String, + ? t.success(false) + : t.failure(s, c), + String ); diff --git a/src/types/commons.ts b/src/types/commons.ts index c2b7f0242..232194210 100644 --- a/src/types/commons.ts +++ b/src/types/commons.ts @@ -14,7 +14,6 @@ export type SuccessResponse = t.TypeOf; export const STRINGS_RECORD = t.record(t.string, t.string); export type STRINGS_RECORD = t.TypeOf; -// eslint-disable-next-line @typescript-eslint/no-unused-vars export function assertUnreachable(_: never): never { throw new Error("Unexpected type error"); } @@ -28,9 +27,9 @@ export const IoLoginHostUrl = PatternString("^(https?|iologin):"); * @returns either a decode error or the array of decoded items */ export const CommaSeparatedListOf = (decoder: t.Mixed) => - new t.Type[], string, unknown>( + new t.Type>, string, unknown>( `CommaSeparatedListOf<${decoder.name}>`, - (value: unknown): value is readonly t.TypeOf[] => + (value: unknown): value is ReadonlyArray> => Array.isArray(value) && value.every((e) => decoder.is(e)), (input) => t.readonlyArray(decoder).decode( @@ -40,8 +39,8 @@ export const CommaSeparatedListOf = (decoder: t.Mixed) => .map((e) => e.trim()) .filter(Boolean) : !input - ? [] // fallback to empty array in case of empty input - : input, // it should not happen, but in case we let the decoder fail + ? [] // fallback to empty array in case of empty input + : input // it should not happen, but in case we let the decoder fail ), - String, + String ); diff --git a/src/types/fiscalCode.ts b/src/types/fiscalCode.ts index ce4698a81..ad3e34646 100644 --- a/src/types/fiscalCode.ts +++ b/src/types/fiscalCode.ts @@ -1,11 +1,10 @@ +import * as express from "express"; import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; - import { withValidatedOrValidationError } from "../utils/responses"; export const withFiscalCodeFromRequestParams = async ( req: express.Request, - f: (fiscalCode: FiscalCode) => Promise, + f: (fiscalCode: FiscalCode) => Promise ): Promise => withValidatedOrValidationError(FiscalCode.decode(req.params.fiscal_code), f); diff --git a/src/types/lollipop.ts b/src/types/lollipop.ts index adc1ebab9..2727f8638 100644 --- a/src/types/lollipop.ts +++ b/src/types/lollipop.ts @@ -1,36 +1,32 @@ + +import * as t from "io-ts"; +import { FiscalCode, NonEmptyString, PatternString } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import { IResponseErrorValidation, ResponseErrorValidation, } from "@pagopa/ts-commons/lib/responses"; -import { - FiscalCode, - NonEmptyString, - PatternString, -} from "@pagopa/ts-commons/lib/strings"; -import * as express from "express"; import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; import { pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; - +import * as O from "fp-ts/Option"; +import { + JwkPubKeyHashAlgorithm, + JwkPubKeyHashAlgorithmEnum, +} from "../../generated/lollipop-api/JwkPubKeyHashAlgorithm"; import { AssertionRefSha256 } from "../../generated/backend/AssertionRefSha256"; import { AssertionRefSha384 } from "../../generated/backend/AssertionRefSha384"; import { AssertionRefSha512 } from "../../generated/backend/AssertionRefSha512"; -import { LollipopContentDigest } from "../../generated/lollipop/LollipopContentDigest"; +import { withValidatedOrValidationError } from "../utils/responses"; +import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; +import { AssertionType } from "../../generated/lollipop-api/AssertionType"; +import { JwkPubKeyToken } from "../../generated/lollipop-api/JwkPubKeyToken"; +import { ResLocals } from "../utils/express"; import { LollipopMethod } from "../../generated/lollipop/LollipopMethod"; import { LollipopOriginalURL } from "../../generated/lollipop/LollipopOriginalURL"; import { LollipopSignature } from "../../generated/lollipop/LollipopSignature"; +import { LollipopContentDigest } from "../../generated/lollipop/LollipopContentDigest"; import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; -import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; -import { AssertionType } from "../../generated/lollipop-api/AssertionType"; -import { - JwkPubKeyHashAlgorithm, - JwkPubKeyHashAlgorithmEnum, -} from "../../generated/lollipop-api/JwkPubKeyHashAlgorithm"; -import { JwkPubKeyToken } from "../../generated/lollipop-api/JwkPubKeyToken"; import LollipopService from "../services/lollipopService"; -import { ResLocals } from "../utils/express"; -import { withValidatedOrValidationError } from "../utils/responses"; export interface LollipopParams { readonly isLollipopEnabled: boolean; @@ -64,10 +60,10 @@ export const LollipopLocalsType = t.intersection([ ]); export type LollipopLocalsType = t.TypeOf; -type LollipopLocalsWithBody = { +type LollipopLocalsWithBody = LollipopLocalsType & { readonly body: Buffer; readonly ["content-digest"]: LollipopContentDigest; -} & LollipopLocalsType; +}; /** * Utility function that validate locals to check if all @@ -78,13 +74,13 @@ type LollipopLocalsWithBody = { * @param locals express res.locals vars injected by toExpressHandler middleware */ export const withLollipopLocals = ( - locals?: T, + locals?: T ): E.Either => pipe( locals, E.fromPredicate(LollipopLocalsType.is, () => - ResponseErrorValidation("Bad request", "Error initializiang lollipop"), - ), + ResponseErrorValidation("Bad request", "Error initializiang lollipop") + ) ); /** @@ -104,7 +100,7 @@ export const withLollipopLocals = ( * @param locals locals validated by withLollipopLocals */ export const withRequiredRawBody = ( - locals?: LollipopLocalsType, + locals?: LollipopLocalsType ): E.Either => pipe( locals, @@ -114,9 +110,9 @@ export const withRequiredRawBody = ( () => ResponseErrorValidation( "Bad request", - "Missing required body or content-digest", - ), - ), + "Missing required body or content-digest" + ) + ) ); /** @@ -130,11 +126,11 @@ export const withRequiredRawBody = ( */ export const withLollipopHeadersFromRequest = async ( req: express.Request, - f: (lollipopHeaders: LollipopRequiredHeaders) => Promise, + f: (lollipopHeaders: LollipopRequiredHeaders) => Promise ): Promise => withValidatedOrValidationError( t.exact(LollipopRequiredHeaders).decode(req.headers), - f, + f ); const Sha256Thumbprint = PatternString("^([A-Za-z0-9-_=]{1,44})$"); @@ -143,7 +139,7 @@ const Sha512Thumbprint = PatternString("^([A-Za-z0-9-_=]{1,88})$"); export const Thumbprint = t.union( [Sha256Thumbprint, Sha384Thumbprint, Sha512Thumbprint], - "Thumbprint", + "Thumbprint" ); export type Thumbprint = t.TypeOf; @@ -155,12 +151,12 @@ export const algoToAssertionRefSet = new Set([ ]); export const getAlgoFromAssertionRef = ( - assertionRef: AssertionRef, + assertionRef: AssertionRef ): JwkPubKeyHashAlgorithm => pipe( Array.from(algoToAssertionRefSet), (ar) => ar.find((entry) => entry.type.is(assertionRef)), O.fromNullable, O.map((pubKeyHashAlgo) => pubKeyHashAlgo.algo), - O.getOrElseW(() => void 0 as never), + O.getOrElseW(() => void 0 as never) ); diff --git a/src/types/notification.ts b/src/types/notification.ts index 7c911088d..b720dbce3 100644 --- a/src/types/notification.ts +++ b/src/types/notification.ts @@ -2,9 +2,9 @@ * This file contains the CreatedMessageEventSenderMetadata and Notification models. */ -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as crypto from "crypto"; import * as t from "io-ts"; +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import { FiscalCode } from "../../generated/backend/FiscalCode"; diff --git a/src/types/pathParams.ts b/src/types/pathParams.ts index 4d019ef01..68ee59b3d 100644 --- a/src/types/pathParams.ts +++ b/src/types/pathParams.ts @@ -1,28 +1,28 @@ -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; import { pipe } from "fp-ts/lib/function"; import * as t from "io-ts"; +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; -export type Encoder = (params: readonly string[]) => string; +export type Encoder = (params: ReadonlyArray) => string; const createSingleError = - (input: unknown, context: t.Context, errorMessage: string) => - (): t.Errors => [ - { - context, - message: errorMessage, - value: input, - }, - ]; + (input: unknown, context: t.Context, errorMessage: string) => (): t.Errors => + [ + { + context, + message: errorMessage, + value: input, + }, + ]; -export type PathParams = t.Type; +export type PathParams = t.Type, string, unknown>; export const pathParamsFromUrl = ( decodeTemplate: RegExp, - encodeTemplate: Encoder, + encodeTemplate: Encoder ): PathParams => - new t.Type( + new t.Type, string, unknown>( "pathParamsFromUrl", - (u: unknown): u is readonly string[] => + (u: unknown): u is ReadonlyArray => Array.isArray(u) && u.every((value) => typeof value === "string"), (input, context) => pipe( @@ -34,9 +34,9 @@ export const pathParamsFromUrl = ( createSingleError( input, context, - `input is not a valid ${decodeTemplate}`, - ), - ), + `input is not a valid ${decodeTemplate}` + ) + ) ), E.map((i) => decodeTemplate.exec(i)), E.map(O.fromNullable), @@ -45,11 +45,11 @@ export const pathParamsFromUrl = ( createSingleError( input, context, - `Should not be here: input is a valid decodeTemplate but its execution failed!`, - ), - ), + `Should not be here: input is a valid decodeTemplate but its execution failed!` + ) + ) ), - E.map((a) => a.slice(1)), // remove the first element because it is the path itself and just return params + E.map((a) => a.slice(1)) // remove the first element because it is the path itself and just return params ), - encodeTemplate, + encodeTemplate ); diff --git a/src/types/profile.ts b/src/types/profile.ts index 33e10fbc4..a30fc44ad 100644 --- a/src/types/profile.ts +++ b/src/types/profile.ts @@ -2,7 +2,7 @@ * This file contains the ProfileWithEmail and ProfileWithoutEmail models and * some functions to validate and convert type to and from them. */ -import { ExtendedProfile } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; +import * as O from "fp-ts/lib/Option"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -10,10 +10,10 @@ import { IResponseSuccessJson, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; -import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; - +import { ExtendedProfile } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { InitializedProfile } from "../../generated/backend/InitializedProfile"; + import { formatDate } from "../utils/date"; import { User } from "./user"; @@ -22,7 +22,7 @@ import { User } from "./user"; */ export const toInitializedProfile = ( profile: ExtendedProfile, - user: User, + user: User ): InitializedProfile => ({ accepted_tos_version: profile.accepted_tos_version, blocked_inbox_or_channels: profile.blocked_inbox_or_channels, @@ -37,7 +37,7 @@ export const toInitializedProfile = ( is_email_already_taken: profile.is_email_already_taken, is_email_enabled: pipe( O.fromNullable(profile.is_email_enabled), - O.getOrElseW(() => true), + O.getOrElseW(() => true) ), is_email_validated: profile.is_email_validated, is_inbox_enabled: profile.is_inbox_enabled, @@ -58,9 +58,9 @@ export const profileMissingErrorResponse = export const notFoundProfileToInternalServerError = ( getProfileResponse: | IResponseErrorInternal - | IResponseErrorNotFound | IResponseErrorTooManyRequests - | IResponseSuccessJson, + | IResponseErrorNotFound + | IResponseSuccessJson ) => getProfileResponse.kind === "IResponseErrorNotFound" ? profileMissingErrorResponse diff --git a/src/types/token.ts b/src/types/token.ts index 44bedc752..04d9e5e07 100644 --- a/src/types/token.ts +++ b/src/types/token.ts @@ -1,7 +1,7 @@ -import { tag } from "@pagopa/ts-commons/lib/types"; -import * as TE from "fp-ts/TaskEither"; import * as t from "io-ts"; +import { tag } from "@pagopa/ts-commons/lib/types"; import { PecServerConfig } from "src/config"; +import * as TE from "fp-ts/TaskEither"; interface ISessionTokenTag { readonly kind: "SessionToken"; @@ -40,5 +40,5 @@ export const FIMSToken = tag()(t.string); export type FIMSToken = t.TypeOf; export type PecBearerGeneratorT = ( - config: PecServerConfig, + config: PecServerConfig ) => TE.TaskEither; diff --git a/src/types/user.ts b/src/types/user.ts index 67c153e8f..b89716dcc 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -3,19 +3,20 @@ * validate and convert type to and from them. */ -import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; -import { pipe } from "fp-ts/lib/function"; import * as t from "io-ts"; +import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; -import { CieUserIdentity } from "../../generated/auth/CieUserIdentity"; -import { SpidUserIdentity } from "../../generated/auth/SpidUserIdentity"; -import { UserIdentity } from "../../generated/auth/UserIdentity"; +import { pipe } from "fp-ts/lib/function"; import { EmailAddress } from "../../generated/backend/EmailAddress"; import { FiscalCode } from "../../generated/backend/FiscalCode"; import { SpidLevel } from "../../generated/backend/SpidLevel"; + +import { CieUserIdentity } from "../../generated/auth/CieUserIdentity"; +import { SpidUserIdentity } from "../../generated/auth/SpidUserIdentity"; +import { UserIdentity } from "../../generated/auth/UserIdentity"; import { withValidatedOrValidationError } from "../utils/responses"; import { BPDToken, @@ -41,8 +42,8 @@ export const UserWithoutTokens = t.intersection([ t.partial({ nameID: t.string, nameIDFormat: t.string, - session_tracking_id: t.string, // unique ID used for tracking in appinsights sessionIndex: t.string, + session_tracking_id: t.string, // unique ID used for tracking in appinsights spid_email: EmailAddress, spid_idp: t.string, }), @@ -102,13 +103,13 @@ export type User = t.TypeOf; * @param user */ export function isSpidUserIdentity( - user: CieUserIdentity | SpidUserIdentity, + user: CieUserIdentity | SpidUserIdentity ): user is SpidUserIdentity { return (user as SpidUserIdentity).spid_email !== undefined; } export function exactUserIdentityDecode( - user: UserIdentity, + user: UserIdentity ): E.Either { return isSpidUserIdentity(user) ? t.exact(SpidUserIdentity.type).decode(user) @@ -117,15 +118,15 @@ export function exactUserIdentityDecode( export const withUserFromRequest = async ( req: express.Request, - f: (user: User) => Promise, + f: (user: User) => Promise ): Promise => withValidatedOrValidationError(User.decode(req.user), f); export const withOptionalUserFromRequest = async ( req: express.Request, - f: (user: O.Option) => Promise, + f: (user: O.Option) => Promise ): Promise => withValidatedOrValidationError( req.user ? pipe(User.decode(req.user), E.map(O.some)) : E.right(O.none), - f, + f ); diff --git a/src/utils/AsyncIterableTask.ts b/src/utils/AsyncIterableTask.ts index 407d03acd..3d2f6567d 100644 --- a/src/utils/AsyncIterableTask.ts +++ b/src/utils/AsyncIterableTask.ts @@ -1,12 +1,13 @@ +import * as T from "fp-ts/lib/Task"; +import * as TE from "fp-ts/lib/TaskEither"; + import { - IPage, asyncIterableToPageArray, + IPage, mapAsyncIterator, } from "@pagopa/io-functions-commons/dist/src/utils/async"; -import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers"; -import * as T from "fp-ts/lib/Task"; -import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; +import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers"; /** * @category model @@ -19,7 +20,7 @@ export type AsyncIterableTask = T.Task>; */ const mapAsyncIterable = ( source: AsyncIterable, - f: (t: T) => Promise | V, + f: (t: T) => V | Promise ): AsyncIterable => { const iter = source[Symbol.asyncIterator](); const iterMapped = mapAsyncIterator(iter, f); @@ -36,12 +37,12 @@ const mapAsyncIterable = ( * @category Functor */ export const map: ( - f: (a: A) => B | Promise, + f: (a: A) => B | Promise ) => // eslint-disable-next-line @typescript-eslint/explicit-function-return-type (fa: AsyncIterableTask) => AsyncIterableTask = (f) => (fa) => pipe( fa, - T.map((_) => mapAsyncIterable(_, f)), + T.map((_) => mapAsyncIterable(_, f)) ); export const mapIterable = @@ -50,11 +51,11 @@ export const mapIterable = pipe(fa, T.map(f)); export const fromAsyncIterable = ( - a: AsyncIterable, + a: AsyncIterable ): AsyncIterableTask => T.of(a); export const fromAsyncIterator = ( - a: AsyncIterator, + a: AsyncIterator ): AsyncIterableTask => fromAsyncIterable({ [Symbol.asyncIterator]: () => a, @@ -63,11 +64,11 @@ export const fromAsyncIterator = ( /** * Process an AsyncIterableTask and return an array of results */ -export const fold = (fa: AsyncIterableTask): T.Task => +export const fold = (fa: AsyncIterableTask): T.Task> => pipe( fa, // eslint-disable-next-line @typescript-eslint/no-use-before-define, @typescript-eslint/explicit-function-return-type - T.chain((_) => foldIterableArray(_)), + T.chain((_) => foldIterableArray(_)) ); /** @@ -75,12 +76,12 @@ export const fold = (fa: AsyncIterableTask): T.Task => */ export const foldTaskEither = (onError: (err: unknown) => E) => - (fa: AsyncIterableTask): TE.TaskEither => + (fa: AsyncIterableTask): TE.TaskEither> => pipe( fa, TE.fromTask, // eslint-disable-next-line @typescript-eslint/no-use-before-define - TE.chain((_) => TE.tryCatch(() => foldIterableArray(_)(), onError)), + TE.chain((_) => TE.tryCatch(() => foldIterableArray(_)(), onError)) ); /** @@ -91,9 +92,11 @@ export const foldTaskEither = */ const foldIterableArray = (asyncIterable: AsyncIterable) => - async (): Promise => { + async (): Promise> => { + // eslint-disable-next-line functional/prefer-readonly-type const array: A[] = []; for await (const variable of asyncIterable) { + // eslint-disable-next-line functional/immutable-data array.push(variable); } return array; @@ -108,7 +111,7 @@ export const run = (fa: AsyncIterableTask): T.Task => for await (const _ of asyncIterable) { // nothing to do: this is done to resolve the async iterator } - }), + }) ); /** @@ -118,7 +121,7 @@ export const reduceTaskEither = ( onError: (err: unknown) => E, initialValue: B, - reducer: (prev: B, curr: A) => B | Promise, + reducer: (prev: B, curr: A) => B | Promise ) => (fa: AsyncIterableTask): TE.TaskEither => pipe( @@ -128,9 +131,9 @@ export const reduceTaskEither = TE.tryCatch( // eslint-disable-next-line @typescript-eslint/no-use-before-define reduceIterableArray(initialValue, reducer)(_), - onError, - ), - ), + onError + ) + ) ); /** @@ -141,6 +144,7 @@ const reduceIterableArray = (initialValue: B, reducer: (prev: B, curr: A) => B | Promise) => (asyncIterable: AsyncIterable) => async (): Promise => { + // eslint-disable-next-line functional/no-let let p: B = initialValue; for await (const variable of asyncIterable) { @@ -159,6 +163,6 @@ export const toPageArray = fa, TE.fromTask, TE.chain((_) => - TE.tryCatch(() => asyncIterableToPageArray(_, pageSize), onError), - ), + TE.tryCatch(() => asyncIterableToPageArray(_, pageSize), onError) + ) ); diff --git a/src/utils/appinsights.ts b/src/utils/appinsights.ts index 9d83d9bc7..2bd78557d 100644 --- a/src/utils/appinsights.ts +++ b/src/utils/appinsights.ts @@ -1,20 +1,19 @@ -import { - sha256, - validateDigestHeader, -} from "@pagopa/io-functions-commons/dist/src/utils/crypto"; +import * as appInsights from "applicationinsights"; import { ApplicationInsightsConfig, initAppInsights as startAppInsights, } from "@pagopa/ts-commons/lib/appinsights"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import { eventLog } from "@pagopa/winston-ts"; -import * as appInsights from "applicationinsights"; +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import { pipe } from "fp-ts/lib/function"; +import * as O from "fp-ts/lib/Option"; import { Request } from "express"; import * as E from "fp-ts/lib/Either"; -import * as O from "fp-ts/lib/Option"; -import { pipe } from "fp-ts/lib/function"; - +import { + sha256, + validateDigestHeader, +} from "@pagopa/io-functions-commons/dist/src/utils/crypto"; +import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import { LollipopLocalsType } from "../types/lollipop"; import { toFiscalCodeHash } from "../types/notification"; import { User } from "../types/user"; @@ -47,37 +46,41 @@ export function attachTrackingData(user: User): void { customProperties.setProperty( USER_TRACKING_ID_KEY, - toFiscalCodeHash(user.fiscal_code), + toFiscalCodeHash(user.fiscal_code) ); if (user.session_tracking_id !== undefined) { customProperties.setProperty( SESSION_TRACKING_ID_KEY, - user.session_tracking_id, + user.session_tracking_id ); } } export function sessionIdPreprocessor( envelope: appInsights.Contracts.Envelope, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - context?: Readonly>, + context?: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readonly [name: string]: any; + } ): boolean { if (context !== undefined) { try { const userTrackingId = context.correlationContext.customProperties.getProperty( - USER_TRACKING_ID_KEY, + USER_TRACKING_ID_KEY ); if (userTrackingId !== undefined) { + // eslint-disable-next-line functional/immutable-data envelope.tags[appInsights.defaultClient.context.keys.userId] = userTrackingId; } const sessionTrackingId = context.correlationContext.customProperties.getProperty( - SESSION_TRACKING_ID_KEY, + SESSION_TRACKING_ID_KEY ); if (sessionTrackingId !== undefined) { + // eslint-disable-next-line functional/immutable-data envelope.tags[appInsights.defaultClient.context.keys.sessionId] = sessionTrackingId; } @@ -96,7 +99,7 @@ export enum StartupEventName { export const trackStartupTime = ( telemetryClient: appInsights.TelemetryClient, type: StartupEventName, - timeMs: bigint, + timeMs: bigint ): void => { telemetryClient.trackEvent({ name: type, @@ -117,7 +120,7 @@ export const trackStartupTime = ( */ export function initAppInsights( instrumentationKey: string, - config: ApplicationInsightsConfig = {}, + config: ApplicationInsightsConfig = {} ): appInsights.TelemetryClient { startAppInsights(instrumentationKey, config); appInsights.defaultClient.addTelemetryProcessor(sessionIdPreprocessor); @@ -127,11 +130,11 @@ export function initAppInsights( export const LOLLIPOP_SIGN_EVENT_NAME = "lollipop.sign"; export type LCResponseLogLollipop = ( - lcResponse: E.Either, + lcResponse: E.Either ) => void; export type RequestLogLollipop = ( lollipopParams: LollipopLocalsType, - req: Request, + req: Request ) => LCResponseLogLollipop; /** @@ -148,10 +151,10 @@ export const logLollipopSignRequest = (lollipopConsumerId: NonEmptyString) => < // eslint-disable-next-line @typescript-eslint/no-explicit-any - T extends Exclude, LollipopLocalsType>, + T extends Exclude, LollipopLocalsType> >( lollipopParams: LollipopLocalsType & T, - req: Request, + req: Request ): LCResponseLogLollipop => (lcResponse: E.Either) => { pipe( @@ -168,35 +171,35 @@ export const logLollipopSignRequest = pipe( E.tryCatch( () => validateDigestHeader(contentDigest, lollipopParams.body), - E.toError, + E.toError ), E.fold( () => false, - () => true, - ), - ), + () => true + ) + ) ), - O.toUndefined, + O.toUndefined ), // A string rapresenting the response from the LC. lc_response: pipe( lcResponse, E.map(JSON.stringify), E.mapLeft((err) => err.message), - E.toUnion, + E.toUnion ), lollipop_consumer_id: lollipopConsumerId, method: req.method, original_url: req.originalUrl, // The fiscal code will be sent hashed to the logs ["x-pagopa-lollipop-user-id"]: sha256( - lollipopHeadersWithoutBody["x-pagopa-lollipop-user-id"], + lollipopHeadersWithoutBody["x-pagopa-lollipop-user-id"] ), })), O.map(withoutUndefinedValues), eventLog.option.info((lollipopEventData) => [ `Lollipop Request log`, lollipopEventData, - ]), + ]) ); }; diff --git a/src/utils/attachments.ts b/src/utils/attachments.ts index 61e737fe2..9803b6508 100644 --- a/src/utils/attachments.ts +++ b/src/utils/attachments.ts @@ -1,11 +1,10 @@ import * as A from "fp-ts/lib/Array"; +import { pipe } from "fp-ts/lib/function"; import * as T from "fp-ts/lib/Task"; import { Task } from "fp-ts/lib/Task"; import * as TE from "fp-ts/lib/TaskEither"; -import { pipe } from "fp-ts/lib/function"; import { MessageAttachment } from "generated/backend/MessageAttachment"; import { PrescriptionData } from "generated/backend/PrescriptionData"; - import { toBarcode } from "./barcode"; const MIME_TYPES = { @@ -28,7 +27,7 @@ const toBarcodeAttachments = (name: string, value: string) => { content: barcodes.svg, mime_type: MIME_TYPES.svg, name }, ]), TE.mapLeft(() => []), - TE.toUnion, + TE.toUnion ); /** @@ -37,17 +36,17 @@ const toBarcodeAttachments = (name: string, value: string) => * the rendered barcode (svg and png) for each field. */ export function getPrescriptionAttachments( - prescriptionData: PrescriptionData, -): Task { + prescriptionData: PrescriptionData +): Task> { return pipe( A.sequence(T.ApplicativePar)([ toBarcodeAttachments("iup", prescriptionData.iup), toBarcodeAttachments("nre", prescriptionData.nre), toBarcodeAttachments( "prescriber_fiscal_code", - prescriptionData.prescriber_fiscal_code as string, + prescriptionData.prescriber_fiscal_code as string ), ]), - T.map(A.flatten), + T.map(A.flatten) ); } diff --git a/src/utils/barcode.ts b/src/utils/barcode.ts index c03765751..a58210442 100644 --- a/src/utils/barcode.ts +++ b/src/utils/barcode.ts @@ -2,10 +2,9 @@ import * as bwipjs from "bwip-js"; import { ToBufferOptions } from "bwip-js"; import * as AP from "fp-ts/lib/Apply"; import * as E from "fp-ts/lib/Either"; +import { pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/lib/TaskEither"; import { TaskEither } from "fp-ts/lib/TaskEither"; -import { pipe } from "fp-ts/lib/function"; - import { BARCODE_ALGORITHM } from "../../src/config"; import { DrawingSVG } from "./bwipjs-svg"; @@ -28,8 +27,7 @@ const toBufferSvg = (options: ToBufferOptions) => const svg = bwipjs.render(opts, DrawingSVG(opts, bwipjs.FontLib)); return Buffer.from(svg); }, - (errs) => - new Error(`Cannot generate svg barcode|${errs}`) as Error | string, + (errs) => new Error(`Cannot generate svg barcode|${errs}`) as Error | string ); /** @@ -43,7 +41,7 @@ const toBufferPng = TE.taskify(bwipjs.toBuffer); */ export function toBarcode( text: string, - bcid = BARCODE_ALGORITHM, + bcid = BARCODE_ALGORITHM ): TaskEither { const options = { bcid, @@ -60,16 +58,16 @@ export function toBarcode( E.left( typeof errorOrString === "string" ? new Error(errorOrString) - : errorOrString, - ), + : errorOrString + ) ), (images) => TE.fromEither( E.right({ png: images.png.toString("base64"), svg: images.svg.toString("base64"), - }), - ), - ), + }) + ) + ) ); } diff --git a/src/utils/container.ts b/src/utils/container.ts index e8eb2add7..f4335c327 100644 --- a/src/utils/container.ts +++ b/src/utils/container.ts @@ -1,5 +1,4 @@ import * as fs from "fs"; - import { log } from "./logger"; /** diff --git a/src/utils/date.ts b/src/utils/date.ts index 341fb2fdc..c92dc22a1 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,10 +1,10 @@ import { PatternString } from "@pagopa/ts-commons/lib/strings"; import { addYears, format, isAfter } from "date-fns"; -import * as E from "fp-ts/Either"; -import { Option, tryCatch } from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; +import { Option, tryCatch } from "fp-ts/lib/Option"; import { FiscalCode } from "generated/backend/FiscalCode"; import * as t from "io-ts"; +import * as E from "fp-ts/Either"; /** * Returns a comparator of two dates that returns true if @@ -16,7 +16,7 @@ export const isOlderThan = (years: number) => (dateOfBirth: Date, when: Date) => export const isValidDate = (d: Date) => d instanceof Date && !isNaN(d.getTime()); -const months: Readonly> = { +const months: { readonly [k: string]: number } = { ["A"]: 1, ["B"]: 2, ["C"]: 3, @@ -92,7 +92,7 @@ const isDate = (v: t.mixed): v is Date => v instanceof Date; * */ const STRICT_UTC_ISO8601_FULL_REGEX = PatternString( - "^\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(\\.\\d+)?[+-](\\d{2})\\:(\\d{2})$", + "^\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(\\.\\d+)?[+-](\\d{2})\\:(\\d{2})$" ); // 2021-12-22T10:56:03+01:00 /** @@ -111,9 +111,9 @@ export const StrictUTCISODateFromString = new t.Type( E.chain((s) => { const d = new Date(s); return isNaN(d.getTime()) ? t.failure(s, c) : t.success(d); - }), + }) ), - (a) => a.toISOString(), + (a) => a.toISOString() ); export type StrictUTCISODateFromString = t.TypeOf< diff --git a/src/utils/errorsFormatter.ts b/src/utils/errorsFormatter.ts index bafadb3e6..b5d576f12 100644 --- a/src/utils/errorsFormatter.ts +++ b/src/utils/errorsFormatter.ts @@ -1,6 +1,6 @@ +import { Errors } from "io-ts"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; -import { Errors } from "io-ts"; /** * Merge into one single Error several errors provided in input and add a context description @@ -10,13 +10,13 @@ import { Errors } from "io-ts"; * @returns A single Error instance with a formatted message. */ export function multipleErrorsFormatter( - errors: readonly Error[], - context: string, + errors: ReadonlyArray, + context: string ): Error { return new Error( errors .map((_) => `value [${_.message}]`) - .join(` at [context: ${context}]\n`), + .join(` at [context: ${context}]\n`) ); } diff --git a/src/utils/express.ts b/src/utils/express.ts index a5d9f94af..feb42bd74 100644 --- a/src/utils/express.ts +++ b/src/utils/express.ts @@ -1,24 +1,25 @@ +import * as express from "express"; import { IResponse, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; +import { flow, pipe } from "fp-ts/lib/function"; import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; -import { flow, pipe } from "fp-ts/lib/function"; export type ExpressMiddleware = ( req: express.Request, res: express.Response, - next: express.NextFunction, + next: express.NextFunction ) => void; -export type ResLocals = { - body?: Buffer; - +export type ResLocals = Record & { + // eslint-disable-next-line functional/prefer-readonly-type detail?: string; -} & Record; + // eslint-disable-next-line functional/prefer-readonly-type + body?: Buffer; +}; /** * Convenience method that transforms a function (handler), * which takes an express.Request as input and returns an IResponse, @@ -26,13 +27,14 @@ export type ResLocals = { */ export function toExpressHandler( handler: (req: express.Request, locals?: L) => Promise>, - object?: P, + object?: P ): (req: express.Request, res: express.Response) => void { - return (req, res) => + return (req, res): Promise => handler .call(object, req, res.locals) .catch(ResponseErrorInternal) .then((response) => { + // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }); @@ -46,26 +48,27 @@ export function toExpressHandler( */ export function toExpressMiddleware( handler: (req: express.Request) => Promise | undefined>, - object?: P, + object?: P ): ExpressMiddleware { return (req, res, next): Promise => pipe( TE.tryCatch( () => handler.call(object, req), - flow(E.toError, (e) => ResponseErrorInternal(e.message)), + flow(E.toError, (e) => ResponseErrorInternal(e.message)) ), TE.chainW( flow( O.fromNullable, O.map(TE.left), - O.getOrElseW(() => TE.right(next())), - ), + O.getOrElseW(() => TE.right(next())) + ) ), TE.mapLeft((response) => { + // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }), - TE.toUnion, + TE.toUnion )(); } @@ -73,9 +76,10 @@ export function toExpressMiddleware( * An Express handler that always respond with the same response object */ export function constantExpressHandler( - response: IResponse, + response: IResponse ): (req: express.Request, res: express.Response) => void { return (_, res) => { + // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }; diff --git a/src/utils/fastLogin.ts b/src/utils/fastLogin.ts index 42e9a9fbc..770a1bdc0 100644 --- a/src/utils/fastLogin.ts +++ b/src/utils/fastLogin.ts @@ -1,9 +1,9 @@ -import { enumType } from "@pagopa/ts-commons/lib/types"; import * as t from "io-ts"; +import { enumType } from "@pagopa/ts-commons/lib/types"; export enum LoginTypeEnum { - "LEGACY" = "LEGACY", "LV" = "LV", + "LEGACY" = "LEGACY", } export type LoginTypeT = t.TypeOf; export const LoginType = enumType(LoginTypeEnum, "LoginType"); diff --git a/src/utils/featureFlag.ts b/src/utils/featureFlag.ts index 597703bd6..e741baa3e 100644 --- a/src/utils/featureFlag.ts +++ b/src/utils/featureFlag.ts @@ -10,7 +10,7 @@ export enum FeatureFlagEnum { export const FeatureFlag = enumType( FeatureFlagEnum, - "FeatureFlag", + "FeatureFlag" ); export type FeatureFlag = t.TypeOf; @@ -19,7 +19,7 @@ export const getIsUserEligibleForNewFeature = ( isUserBeta: (i: T) => boolean, isUserCanary: (i: T) => boolean, - featureFlag: FeatureFlag, + featureFlag: FeatureFlag ): ((i: T) => boolean) => (i): boolean => { switch (featureFlag) { diff --git a/src/utils/file-type.ts b/src/utils/file-type.ts index 06f3b09dc..56be79b4b 100644 --- a/src/utils/file-type.ts +++ b/src/utils/file-type.ts @@ -1,9 +1,9 @@ -import * as EQ from "fp-ts/Eq"; -import * as RS from "fp-ts/ReadonlySet"; import { pipe } from "fp-ts/lib/function"; +import * as RS from "fp-ts/ReadonlySet"; import { match } from "ts-pattern"; +import * as EQ from "fp-ts/Eq"; -export type FileType = "any" | "pdf"; +export type FileType = "pdf" | "any"; /** * Verify if the input buffer contains a PDF using the magic number in the first bytes (see https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) @@ -16,7 +16,6 @@ export const isPdf = (data: Buffer) => data.toString("binary", 0, 4) === "%PDF"; /** * Allow any file type */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars export const isAny = (_: Buffer) => true; export const typeToCheck = (type: FileType) => @@ -29,7 +28,7 @@ export const typeToCheck = (type: FileType) => * Compare two functions: will return true if the functions have the same body */ export const eqFunction: EQ.Eq> = EQ.fromEquals( - (f1, f2) => f1.toString() === f2.toString(), + (f1, f2) => f1.toString() === f2.toString() ); /** @@ -43,5 +42,5 @@ export const getIsFileTypeForTypes = pipe( types, RS.map(eqFunction)(typeToCheck), - RS.some((is) => is(data)), + RS.some((is) => is(data)) ); diff --git a/src/utils/gracefulShutdown.ts b/src/utils/gracefulShutdown.ts index 41aad49bd..a7ce15a17 100644 --- a/src/utils/gracefulShutdown.ts +++ b/src/utils/gracefulShutdown.ts @@ -1,14 +1,13 @@ -import { Express } from "express"; import * as http from "http"; -import * as httpGracefulShutdown from "http-graceful-shutdown"; import * as https from "https"; - +import { Express } from "express"; +import * as httpGracefulShutdown from "http-graceful-shutdown"; import { log } from "./logger"; export function initHttpGracefulShutdown( server: http.Server | https.Server, app: Express, - options: httpGracefulShutdown.Options, + options: httpGracefulShutdown.Options ): void { log.info("Initializing server graceful shutdown"); httpGracefulShutdown(server, { diff --git a/src/utils/logger.ts b/src/utils/logger.ts index a0aa7345e..72bb82ceb 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,14 +1,14 @@ import * as logform from "logform"; import { createLogger, format, transports } from "winston"; -const { printf, timestamp } = logform.format; +const { timestamp, printf } = logform.format; export const log = createLogger({ format: format.combine( timestamp(), format.splat(), format.simple(), - printf((nfo) => `${nfo.timestamp} [${nfo.level}]: ${nfo.message}`), + printf((nfo) => `${nfo.timestamp} [${nfo.level}]: ${nfo.message}`) ), transports: [new transports.Console()], }); diff --git a/src/utils/lollipop.ts b/src/utils/lollipop.ts index bceb7f9e4..8cd1228f6 100644 --- a/src/utils/lollipop.ts +++ b/src/utils/lollipop.ts @@ -1,39 +1,38 @@ -import { sha256 } from "@pagopa/io-functions-commons/dist/src/utils/crypto"; -import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; +import { flow, identity, pipe } from "fp-ts/lib/function"; import { IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, ResponseErrorForbiddenNotAuthorized, ResponseErrorInternal, } from "@pagopa/ts-commons/lib/responses"; +import * as E from "fp-ts/Either"; +import { ulid } from "ulid"; import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; +import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { eventLog } from "@pagopa/winston-ts"; -import * as E from "fp-ts/Either"; +import { sha256 } from "@pagopa/io-functions-commons/dist/src/utils/crypto"; +import { Errors } from "io-ts"; import * as O from "fp-ts/Option"; +import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import * as RA from "fp-ts/ReadonlyArray"; import * as TE from "fp-ts/TaskEither"; -import { flow, identity, pipe } from "fp-ts/lib/function"; -import { Errors } from "io-ts"; -import { ulid } from "ulid"; - -import { AssertionRef } from "../../generated/backend/AssertionRef"; import { RCConfigurationPublic } from "../../generated/io-messages-api/RCConfigurationPublic"; -import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; -import { LcParams } from "../../generated/lollipop-api/LcParams"; -import { LollipopApiClient } from "../clients/lollipop"; +import { AssertionRef } from "../../generated/backend/AssertionRef"; import { ISessionStorage } from "../services/ISessionStorage"; +import { LollipopApiClient } from "../clients/lollipop"; import { LollipopLocalsType, LollipopRequiredHeaders, Thumbprint, getAlgoFromAssertionRef, } from "../types/lollipop"; +import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; +import { LcParams } from "../../generated/lollipop-api/LcParams"; import { log } from "./logger"; type ErrorsResponses = - | IResponseErrorForbiddenNotAuthorized - | IResponseErrorInternal; + | IResponseErrorInternal + | IResponseErrorForbiddenNotAuthorized; const LOLLIPOP_SIGN_ERROR_EVENT_NAME = "lollipop.error.sign"; const NONCE_REGEX = new RegExp(';?nonce="([^"]+)";?'); @@ -41,7 +40,7 @@ const NONCE_REGEX = new RegExp(';?nonce="([^"]+)";?'); const KEY_ID_REGEX = new RegExp(';?keyid="([^"]+)";?'); const getNonceOrUlid = ( - lollipopSignatureInput: LollipopSignatureInput, + lollipopSignatureInput: LollipopSignatureInput ): NonEmptyString => { // The nonce value must be the first regex group // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -53,7 +52,7 @@ const getNonceOrUlid = ( }; export const getKeyThumbprintFromSignature = ( - lollipopSignatureInput: LollipopSignatureInput, + lollipopSignatureInput: LollipopSignatureInput ): E.Either => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, thumbprint, ...__] = KEY_ID_REGEX.exec(lollipopSignatureInput) ?? [ @@ -65,7 +64,7 @@ export const getKeyThumbprintFromSignature = ( export const checkIfLollipopIsEnabled = ( fiscalCode: FiscalCode, - remoteContentConfiguration: RCConfigurationPublic, + remoteContentConfiguration: RCConfigurationPublic ) => pipe( TE.of(remoteContentConfiguration), @@ -80,23 +79,23 @@ export const checkIfLollipopIsEnabled = ( TE.map( (config) => config.is_lollipop_enabled && - !config.disable_lollipop_for.includes(fiscalCode), - ), + !config.disable_lollipop_for.includes(fiscalCode) + ) ); const getAndValidateAssertionRefForUser = ( sessionStorage: ISessionStorage, fiscalCode: FiscalCode, operationId: NonEmptyString, - keyThumbprint: Thumbprint, + keyThumbprint: Thumbprint ): TE.TaskEither< - IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, + IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, AssertionRef > => pipe( TE.tryCatch( () => sessionStorage.getLollipopAssertionRefForUser(fiscalCode), - E.toError, + E.toError ), TE.chainEitherK(identity), eventLog.taskEither.errorLeft((err) => [ @@ -110,7 +109,7 @@ const getAndValidateAssertionRefForUser = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error reading the assertionRef from redis [%s]", - err.message, + err.message ); return ResponseErrorInternal("Error retrieving the assertionRef"); }), @@ -121,7 +120,7 @@ const getAndValidateAssertionRefForUser = ( (assertionRef) => assertionRef === `${getAlgoFromAssertionRef(assertionRef)}-${keyThumbprint}`, - () => ResponseErrorForbiddenNotAuthorized, + () => ResponseErrorForbiddenNotAuthorized ), eventLog.taskEither.errorLeft(() => [ `AssertionRef is different from stored one`, @@ -130,11 +129,12 @@ const getAndValidateAssertionRefForUser = ( name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, operation_id: operationId, }, - ]), - ), - ), + ]) + ) + ) ); +/* eslint-disable sonarjs/no-identical-functions */ /** * @deprecated */ @@ -142,16 +142,17 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( lollipopClient: ReturnType, sessionStorage: ISessionStorage, fiscalCode: FiscalCode, - lollipopHeaders: LollipopRequiredHeaders, + lollipopHeaders: LollipopRequiredHeaders ) => pipe( + // eslint-disable-next-line sonarjs/no-duplicate-string TE.of(getNonceOrUlid(lollipopHeaders["signature-input"])), TE.bindTo("operationId"), TE.bind("assertionRef", ({ operationId }) => pipe( TE.tryCatch( () => sessionStorage.getLollipopAssertionRefForUser(fiscalCode), - E.toError, + E.toError ), TE.chainEitherK(identity), eventLog.taskEither.errorLeft((err) => [ @@ -165,12 +166,12 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error reading the assertionRef from redis [%s]", - err.message, + err.message ); return ResponseErrorInternal("Error retrieving the assertionRef"); }), - TE.chainW(TE.fromOption(() => ResponseErrorForbiddenNotAuthorized)), - ), + TE.chainW(TE.fromOption(() => ResponseErrorForbiddenNotAuthorized)) + ) ), TE.bindW("generateLCParamsResponse", ({ assertionRef, operationId }) => pipe( @@ -182,7 +183,7 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( operation_id: operationId, }, }), - E.toError, + E.toError ), eventLog.taskEither.errorLeft((error) => [ `Error trying to call the Lollipop function service | ${error.message}`, @@ -196,21 +197,21 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error trying to call the Lollipop function service [%s]", - err.message, + err.message ); return ResponseErrorInternal( - "Error calling the Lollipop function service", + "Error calling the Lollipop function service" ); - }), - ), + }) + ) ), - TE.chain(({ assertionRef, generateLCParamsResponse, operationId }) => + TE.chain(({ generateLCParamsResponse, assertionRef, operationId }) => pipe( generateLCParamsResponse, TE.fromEither, eventLog.taskEither.errorLeft((err) => [ `Unexpected response from the lollipop function service | ${readableReportSimplified( - err, + err )}`, { assertion_ref: assertionRef, @@ -222,10 +223,10 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error calling the Lollipop function service [%s]", - readableReportSimplified(err), + readableReportSimplified(err) ); return ResponseErrorInternal( - "Unexpected response from lollipop service", + "Unexpected response from lollipop service" ); }), TE.chainW((lollipopRes) => @@ -233,12 +234,10 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( lollipopRes.status === 200 ? TE.of(lollipopRes.value) : lollipopRes.status === 403 - ? TE.left(ResponseErrorForbiddenNotAuthorized) - : TE.left( - ResponseErrorInternal( - "The lollipop service returns an error", - ), - ), + ? TE.left(ResponseErrorForbiddenNotAuthorized) + : TE.left( + ResponseErrorInternal("The lollipop service returns an error") + ), eventLog.taskEither.errorLeft((errorResponse) => [ `The lollipop function service returns an error | ${errorResponse.kind}`, { @@ -247,10 +246,10 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, operation_id: operationId, }, - ]), - ), - ), - ), + ]) + ) + ) + ) ), TE.map( (lcParams) => @@ -261,19 +260,19 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( ["x-pagopa-lollipop-public-key"]: lcParams.pub_key, ["x-pagopa-lollipop-user-id"]: fiscalCode, ...lollipopHeaders, - }) as LollipopLocalsType, + } as LollipopLocalsType) ), eventLog.taskEither.info((lcLocals) => [ "Lollipop locals to be sent to third party api", { ...Object.keys(lcLocals), name: "lollipop.locals.info" }, - ]), + ]) ); const retrieveLCParams = ( assertionRef: AssertionRef, lollipopClient: ReturnType, operationId: NonEmptyString, - fiscalCode?: FiscalCode, + fiscalCode?: FiscalCode ): TE.TaskEither< IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, O.Option @@ -287,7 +286,7 @@ const retrieveLCParams = ( operation_id: operationId, }, }), - E.toError, + E.toError ), eventLog.taskEither.errorLeft((error) => [ `Error trying to call the Lollipop function service | ${error.message}`, @@ -301,10 +300,10 @@ const retrieveLCParams = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error trying to call the Lollipop function service [%s]", - err.message, + err.message ); return ResponseErrorInternal( - "Error calling the Lollipop function service", + "Error calling the Lollipop function service" ); }), TE.chain( @@ -312,7 +311,7 @@ const retrieveLCParams = ( TE.fromEither, eventLog.taskEither.errorLeft((err) => [ `Unexpected response from the lollipop function service | ${readableReportSimplified( - err, + err )}`, withoutUndefinedValues({ assertion_ref: assertionRef, @@ -324,29 +323,27 @@ const retrieveLCParams = ( TE.mapLeft((err) => { log.error( "lollipopMiddleware|error calling the Lollipop function service [%s]", - readableReportSimplified(err), + readableReportSimplified(err) ); return ResponseErrorInternal( - "Unexpected response from lollipop service", + "Unexpected response from lollipop service" ); - }), - ), + }) + ) ), TE.chainW((lollipopRes) => pipe( lollipopRes.status === 200 ? TE.of>( - O.some(lollipopRes.value), + O.some(lollipopRes.value) ) : lollipopRes.status === 403 - ? TE.left(ResponseErrorForbiddenNotAuthorized) - : lollipopRes.status === 404 - ? TE.right(O.none) - : TE.left( - ResponseErrorInternal( - "The lollipop service returns an error", - ), - ), + ? TE.left(ResponseErrorForbiddenNotAuthorized) + : lollipopRes.status === 404 + ? TE.right(O.none) + : TE.left( + ResponseErrorInternal("The lollipop service returns an error") + ), eventLog.taskEither.errorLeft((errorResponse) => [ `The lollipop function service returns an error | ${errorResponse.kind}`, withoutUndefinedValues({ @@ -355,18 +352,18 @@ const retrieveLCParams = ( name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, operation_id: operationId, }), - ]), - ), - ), + ]) + ) + ) ); export const extractLollipopLocalsFromLollipopHeaders = ( lollipopClient: ReturnType, sessionStorage: ISessionStorage, lollipopHeaders: LollipopRequiredHeaders, - fiscalCode?: FiscalCode, + fiscalCode?: FiscalCode ): TE.TaskEither< - IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal, + IResponseErrorInternal | IResponseErrorForbiddenNotAuthorized, LollipopLocalsType > => pipe( @@ -384,10 +381,10 @@ export const extractLollipopLocalsFromLollipopHeaders = ( }, ]), E.mapLeft(() => - ResponseErrorInternal("Invalid assertionRef in signature params"), + ResponseErrorInternal("Invalid assertionRef in signature params") ), - TE.fromEither, - ), + TE.fromEither + ) ), TE.bind("assertionRefSet", ({ keyThumbprint, operationId }) => pipe( @@ -398,19 +395,19 @@ export const extractLollipopLocalsFromLollipopHeaders = ( sessionStorage, fc, operationId, - keyThumbprint, + keyThumbprint ), - TE.map((assertionRef) => [assertionRef]), - ), + TE.map((assertionRef) => [assertionRef]) + ) ), O.getOrElse(() => TE.of([ `sha256-${keyThumbprint}` as AssertionRef, `sha384-${keyThumbprint}` as AssertionRef, `sha512-${keyThumbprint}` as AssertionRef, - ]), - ), - ), + ]) + ) + ) ), TE.bindW("lcParams", ({ assertionRefSet, operationId }) => pipe( @@ -421,33 +418,33 @@ export const extractLollipopLocalsFromLollipopHeaders = ( assertionRef, lollipopClient, operationId, - fiscalCode, + fiscalCode ), TE.chainW((_) => - O.isSome(_) ? TE.left(_.value) : TE.right(O.none), - ), - ), + O.isSome(_) ? TE.left(_.value) : TE.right(O.none) + ) + ) ), TE.fold( (_) => LcParams.is(_) ? TE.right(_) : _.kind === "IResponseErrorInternal" || - _.kind === "IResponseErrorForbiddenNotAuthorized" - ? TE.left(_) - : TE.left( - ResponseErrorInternal( - "Unexpected result given from retrieveLCParams", - ), - ), + _.kind === "IResponseErrorForbiddenNotAuthorized" + ? TE.left(_) + : TE.left( + ResponseErrorInternal( + "Unexpected result given from retrieveLCParams" + ) + ), () => TE.left< IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal - >(ResponseErrorInternal("Missing assertion ref")), - ), - ), + >(ResponseErrorInternal("Missing assertion ref")) + ) + ) ), - TE.chainFirst(({ keyThumbprint, lcParams, operationId }) => + TE.chainFirst(({ operationId, lcParams, keyThumbprint }) => pipe( O.fromNullable(fiscalCode), O.map(() => TE.of(true)), @@ -457,12 +454,12 @@ export const extractLollipopLocalsFromLollipopHeaders = ( sessionStorage, lcParams.fiscal_code, operationId, - keyThumbprint, + keyThumbprint ), - TE.map(() => true), - ), - ), - ), + TE.map(() => true) + ) + ) + ) ), TE.map( ({ lcParams }) => @@ -475,10 +472,11 @@ export const extractLollipopLocalsFromLollipopHeaders = ( // the authorization is equal to the one from the lollipop function ["x-pagopa-lollipop-user-id"]: fiscalCode || lcParams.fiscal_code, ...lollipopHeaders, - }) as LollipopLocalsType, + } as LollipopLocalsType) ), eventLog.taskEither.info((lcLocals) => [ "Lollipop locals to be sent to third party api", { ...Object.keys(lcLocals), name: "lollipop.locals.info" }, - ]), + ]) ); +/* eslint-enable sonarjs/no-identical-functions */ diff --git a/src/utils/middleware/checkIP.ts b/src/utils/middleware/checkIP.ts index 9caa6442b..57915b79b 100644 --- a/src/utils/middleware/checkIP.ts +++ b/src/utils/middleware/checkIP.ts @@ -2,42 +2,41 @@ * An Express middleware that checks if source IP falls into a CIDR range. */ -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; -import { CIDR, IPString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; +import { CIDR, IPString } from "@pagopa/ts-commons/lib/strings"; import * as rangeCheck from "range_check"; - +import { pipe } from "fp-ts/lib/function"; import { log } from "../logger"; import { decodeIPAddressFromReq } from "../network"; export default function checkIP( - range: readonly CIDR[], + range: ReadonlyArray ): ( req: express.Request, res: express.Response, - next: express.NextFunction, + next: express.NextFunction ) => void { return ( req: express.Request, res: express.Response, - next: express.NextFunction, + next: express.NextFunction ): void => { const errorOrIPString = pipe( decodeIPAddressFromReq(req), E.alt(() => // use x-client-ip instead of x-forwarded-for // for internal calls (same vnet) - IPString.decode(req.headers["x-client-ip"]), - ), + IPString.decode(req.headers["x-client-ip"]) + ) ); if (E.isLeft(errorOrIPString)) { log.error( `Cannot decode source IP: (req.ip=${req.ip},x-client-ip=${ req.headers["x-client-ip"] - },error=${readableReport(errorOrIPString.left)}.`, + },error=${readableReport(errorOrIPString.left)}.` ); res.status(400).send("Bad request"); } else { diff --git a/src/utils/middleware/dueDate.ts b/src/utils/middleware/dueDate.ts index 8b85b1f72..0a555c750 100644 --- a/src/utils/middleware/dueDate.ts +++ b/src/utils/middleware/dueDate.ts @@ -1,6 +1,5 @@ -import { ResponseErrorNotFound } from "@pagopa/ts-commons/lib/responses"; import { NextFunction, Request, Response } from "express"; - +import { ResponseErrorNotFound } from "@pagopa/ts-commons/lib/responses"; import { log } from "../logger"; /** @@ -11,7 +10,7 @@ import { log } from "../logger"; * @param dueDate date until the resource is valid */ export function dueDateMiddleware( - dueDate: Date, + dueDate: Date ): (req: Request, res: Response, next: NextFunction) => void { return (req, res, next) => { const now = new Date(); @@ -19,11 +18,11 @@ export function dueDateMiddleware( log.warn( `An ${req.method.toUpperCase()} ${ req.path - } request has landed at ${now.toISOString()} although it was supposed to expire at ${dueDate.toISOString()}.`, + } request has landed at ${now.toISOString()} although it was supposed to expire at ${dueDate.toISOString()}.` ); ResponseErrorNotFound( "Expired resource", - "The resource you asked for is no longer available", + "The resource you asked for is no longer available" ).apply(res); } else { next(); diff --git a/src/utils/middleware/express.ts b/src/utils/middleware/express.ts index 77d3b65be..8a9f863e0 100644 --- a/src/utils/middleware/express.ts +++ b/src/utils/middleware/express.ts @@ -1,6 +1,5 @@ -import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import { NextFunction, Request, Response } from "express"; - +import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import { log } from "../logger"; /** @@ -13,8 +12,7 @@ export function expressErrorMiddleware( err: Error, _: Request, res: Response, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - __: NextFunction, + __: NextFunction ): void { log.error("An exception occurred during http request: %s", err.message); // Send a ResponseErrorInternal only if a response was not already sent to the client diff --git a/src/utils/middleware/lollipop.ts b/src/utils/middleware/lollipop.ts index 88313fc37..75a8cca88 100644 --- a/src/utils/middleware/lollipop.ts +++ b/src/utils/middleware/lollipop.ts @@ -1,29 +1,28 @@ +import { Request, Response, NextFunction } from "express"; +import * as TE from "fp-ts/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; -import { NextFunction, Request, Response } from "express"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; -import * as TE from "fp-ts/TaskEither"; -import { pipe } from "fp-ts/lib/function"; - -import { LollipopApiClient } from "../../clients/lollipop"; -import { ISessionStorage } from "../../services/ISessionStorage"; -import { withLollipopHeadersFromRequest } from "../../types/lollipop"; import { withOptionalUserFromRequest, withUserFromRequest, } from "../../types/user"; +import { LollipopApiClient } from "../../clients/lollipop"; +import { withLollipopHeadersFromRequest } from "../../types/lollipop"; import { log } from "../logger"; import { extractLollipopLocalsFromLollipopHeaders, extractLollipopLocalsFromLollipopHeadersLegacy, } from "../lollipop"; +import { ISessionStorage } from "../../services/ISessionStorage"; /** * @deprecated */ export const expressLollipopMiddlewareLegacy: ( lollipopClient: ReturnType, - sessionStorage: ISessionStorage, + sessionStorage: ISessionStorage ) => (req: Request, res: Response, next: NextFunction) => Promise = (lollipopClient, sessionStorage) => (req, res, next) => pipe( @@ -36,36 +35,38 @@ export const expressLollipopMiddlewareLegacy: ( lollipopClient, sessionStorage, user.fiscal_code, - lollipopHeaders, + lollipopHeaders ), TE.map((lollipopLocals) => { + // eslint-disable-next-line functional/immutable-data res.locals = { ...res.locals, ...lollipopLocals }; }), - TE.toUnion, - )(), - ), + TE.toUnion + )() + ) ), (err) => { log.error( "lollipopMiddleware|error executing the middleware [%s]", - E.toError(err).message, + E.toError(err).message ); return ResponseErrorInternal("Error executing middleware"); - }, + } ), TE.chain((maybeErrorResponse) => maybeErrorResponse === undefined ? TE.of(void 0) - : TE.left(maybeErrorResponse), + : TE.left(maybeErrorResponse) ), TE.mapLeft((response) => response.apply(res)), TE.map(() => next()), - TE.toUnion, + TE.toUnion )(); +/* eslint-disable sonarjs/no-identical-functions */ export const expressLollipopMiddleware: ( lollipopClient: ReturnType, - sessionStorage: ISessionStorage, + sessionStorage: ISessionStorage ) => (req: Request, res: Response, next: NextFunction) => Promise = (lollipopClient, sessionStorage) => (req, res, next) => pipe( @@ -78,29 +79,31 @@ export const expressLollipopMiddleware: ( lollipopClient, sessionStorage, lollipopHeaders, - O.toUndefined(user)?.fiscal_code, + O.toUndefined(user)?.fiscal_code ), TE.map((lollipopLocals) => { + // eslint-disable-next-line functional/immutable-data res.locals = { ...res.locals, ...lollipopLocals }; }), - TE.toUnion, - )(), - ), + TE.toUnion + )() + ) ), (err) => { log.error( "lollipopMiddleware|error executing the middleware [%s]", - E.toError(err).message, + E.toError(err).message ); return ResponseErrorInternal("Error executing middleware"); - }, + } ), TE.chain((maybeErrorResponse) => maybeErrorResponse === undefined ? TE.of(void 0) - : TE.left(maybeErrorResponse), + : TE.left(maybeErrorResponse) ), TE.mapLeft((response) => response.apply(res)), TE.map(() => next()), - TE.toUnion, + TE.toUnion )(); +/* eslint-enable sonarjs/no-identical-functions */ diff --git a/src/utils/network.ts b/src/utils/network.ts index a4b927ed7..310a34158 100644 --- a/src/utils/network.ts +++ b/src/utils/network.ts @@ -1,19 +1,21 @@ +import { Either } from "fp-ts/lib/Either"; +import { array, Errors } from "io-ts"; import { CIDR, IPString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; -import { Either } from "fp-ts/lib/Either"; -import { Errors, array } from "io-ts"; /** * Parse a comma separated string of CIDR(s) or IP(s) into an array */ -export function decodeCIDRs(cidrs?: string): Either { +export function decodeCIDRs( + cidrs?: string +): Either> { return array(CIDR).decode( cidrs // may be a comma separated list of CIDR(s) or IP(s) ?.split(",") .map((c) => c.trim()) // if we read a plain IP then append '/32' - .map((c) => (c.indexOf("/") !== -1 ? c : c + "/32")), + .map((c) => (c.indexOf("/") !== -1 ? c : c + "/32")) ); } @@ -24,5 +26,5 @@ export function decodeCIDRs(cidrs?: string): Either { * contained in the x-forwarded-for header */ export const decodeIPAddressFromReq = ( - req: express.Request, + req: express.Request ): Either => IPString.decode(req.ip); diff --git a/src/utils/ognl.ts b/src/utils/ognl.ts index 08ff5476f..1ea0beb0c 100644 --- a/src/utils/ognl.ts +++ b/src/utils/ognl.ts @@ -1,7 +1,7 @@ -import * as E from "fp-ts/Either"; -import * as R from "fp-ts/Record"; import { pipe } from "fp-ts/function"; +import * as R from "fp-ts/Record"; import * as t from "io-ts"; +import * as E from "fp-ts/Either"; /** * Porting of lodash "set" function. @@ -14,29 +14,31 @@ import * as t from "io-ts"; // eslint-disable-next-line @typescript-eslint/ban-types export const set = ( obj: T, - path: readonly string[] | string, + path: string | ReadonlyArray, // eslint-disable-next-line @typescript-eslint/no-explicit-any - value: any, + value: any ): T => { if (Object(obj) !== obj) { return obj; } // When obj is not an object // If not yet an array, get the keys from the string-path - const splittedpath: readonly string[] = !Array.isArray(path) + const splittedpath: ReadonlyArray = !Array.isArray(path) ? path.toString().match(/[^.[\]]+/g) || [] : path; - + // eslint-disable-next-line functional/immutable-data splittedpath.slice(0, -1).reduce( ( // eslint-disable-next-line @typescript-eslint/no-explicit-any a: any, c, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _i, + _i ) => // Iterate all of them except the last one - Object(a[c]) === a[c] ? a[c] : (a[c] = {}), - obj, + Object(a[c]) === a[c] + ? a[c] + : // eslint-disable-next-line functional/immutable-data + (a[c] = {}), + obj )[splittedpath[splittedpath.length - 1]] = value; return obj; }; @@ -51,7 +53,7 @@ export const set = ( */ export const nestifyPrefixedType = ( env: Record, - prefix: string, + prefix: string ): Record => pipe( env, @@ -59,11 +61,11 @@ export const nestifyPrefixedType = ( R.reduceWithIndex({}, (k, b, a) => set( b, - + // eslint-disable-next-line functional/immutable-data k.split("_").splice(1).join("."), - a, - ), - ), + a + ) + ) ); const isRecordOfString = (i: unknown): i is Record => @@ -72,13 +74,14 @@ const isRecordOfString = (i: unknown): i is Record => !Object.keys(i).some((property) => typeof property !== "string"); const createNotRecordOfStringErrorL = - (input: unknown, context: t.Context) => (): t.Errors => [ - { - context, - message: "input is not a valid record of string", - value: input, - }, - ]; + (input: unknown, context: t.Context) => (): t.Errors => + [ + { + context, + message: "input is not a valid record of string", + value: input, + }, + ]; /** * Create a io-ts decoder for the input type. @@ -91,7 +94,7 @@ const createNotRecordOfStringErrorL = */ export const ognlTypeFor = ( type: t.Mixed, - prefix: string, + prefix: string ): t.Type => new t.Type( "OGNL", @@ -101,11 +104,11 @@ export const ognlTypeFor = ( input, E.fromPredicate( isRecordOfString, - createNotRecordOfStringErrorL(input, context), + createNotRecordOfStringErrorL(input, context) ), E.chainW((inputRecord) => - type.validate(nestifyPrefixedType(inputRecord, prefix), context), - ), + type.validate(nestifyPrefixedType(inputRecord, prefix), context) + ) ), - t.identity, + t.identity ); diff --git a/src/utils/package.ts b/src/utils/package.ts index a9e7701ed..2208a9dbb 100644 --- a/src/utils/package.ts +++ b/src/utils/package.ts @@ -1,9 +1,8 @@ -import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; -import { Option } from "fp-ts/lib/Option"; -import { pipe } from "fp-ts/lib/function"; +import * as E from "fp-ts/lib/Either"; import * as t from "io-ts"; - +import { pipe } from "fp-ts/lib/function"; +import { Option } from "fp-ts/lib/Option"; import * as packageJson from "../../package.json"; /** @@ -11,11 +10,11 @@ import * as packageJson from "../../package.json"; * If it doesn't exists, returns 'UNKNOWN' */ export const getValueFromPackageJson = ( - key: keyof typeof packageJson, + key: keyof typeof packageJson ): string => pipe( t.string.decode(packageJson[key]), - E.getOrElse(() => "UNKNOWN"), + E.getOrElse(() => "UNKNOWN") ); /** @@ -24,14 +23,14 @@ export const getValueFromPackageJson = ( */ export const getObjectFromPackageJson = ( key: keyof typeof packageJson, - type: t.Type, + type: t.Type ): Option => pipe( type.decode(packageJson[key]), E.fold( - () => O.none, - (_) => O.some(_), - ), + (_) => O.none, + (_) => O.some(_) + ) ); /** diff --git a/src/utils/profile.ts b/src/utils/profile.ts index b7f3594bf..5f2ae48ff 100644 --- a/src/utils/profile.ts +++ b/src/utils/profile.ts @@ -1,13 +1,12 @@ -import { IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; -import * as E from "fp-ts/lib/Either"; import * as TE from "fp-ts/lib/TaskEither"; -import { pipe } from "fp-ts/lib/function"; +import * as E from "fp-ts/lib/Either"; import * as t from "io-ts"; - -import { EmailAddress } from "../../generated/backend/EmailAddress"; -import { InitializedProfile } from "../../generated/backend/InitializedProfile"; -import ProfileService from "../../src/services/profileService"; +import { IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import { pipe } from "fp-ts/lib/function"; import { User } from "../../src/types/user"; +import ProfileService from "../../src/services/profileService"; +import { InitializedProfile } from "../../generated/backend/InitializedProfile"; +import { EmailAddress } from "../../generated/backend/EmailAddress"; // define a type that represents a Profile with a non optional email address const ProfileWithEmail = t.intersection([ @@ -29,7 +28,7 @@ const ProfileWithEmailValidated = t.brand( ProfileWithEmail, (p): p is t.Branded => !!(p.email && p.is_email_validated), - "HasValidEmailAddress", + "HasValidEmailAddress" ); type ProfileWithEmailValidated = t.TypeOf; @@ -43,26 +42,28 @@ type ProfileWithEmailValidated = t.TypeOf; */ export const profileWithEmailValidatedOrError = ( profileService: ProfileService, - user: User, + user: User ) => pipe( TE.tryCatch( () => profileService.getProfile(user), - () => new Error("Error retrieving user profile"), + () => new Error("Error retrieving user profile") ), TE.chain( TE.fromPredicate( (r): r is IResponseSuccessJson => r.kind === "IResponseSuccessJson", - (e) => new Error(`Error retrieving user profile | ${e.detail}`), - ), + (e) => new Error(`Error retrieving user profile | ${e.detail}`) + ) ), TE.chainW((profile) => pipe( profile.value, ProfileWithEmailValidated.decode, - E.mapLeft(() => new Error("Profile has not a validated email address")), - TE.fromEither, - ), - ), + E.mapLeft( + (_) => new Error("Profile has not a validated email address") + ), + TE.fromEither + ) + ) ); diff --git a/src/utils/qrcode.ts b/src/utils/qrcode.ts index caede5ed6..a331ee396 100644 --- a/src/utils/qrcode.ts +++ b/src/utils/qrcode.ts @@ -1,8 +1,8 @@ import * as AP from "fp-ts/lib/Apply"; import * as E from "fp-ts/lib/Either"; +import { pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/lib/TaskEither"; import { TaskEither } from "fp-ts/lib/TaskEither"; -import { pipe } from "fp-ts/lib/function"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { BonusActivation } from "generated/io-bonus-api/BonusActivation"; import { image } from "qr-image"; @@ -17,9 +17,10 @@ const fixQrcodeFill = (svgStr: string): string => svgStr.replace(" { - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/prefer-readonly-type const chunks: any[] = []; return new Promise((resolve, reject) => { + // eslint-disable-next-line functional/immutable-data stream.on("data", (chunk) => chunks.push(chunk)); stream.on("error", reject); stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); @@ -27,9 +28,10 @@ function streamToString(stream: NodeJS.ReadableStream): Promise { } function streamToBuffer(stream: NodeJS.ReadableStream): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/prefer-readonly-type const chunks: any[] = []; return new Promise((resolve, reject) => { + // eslint-disable-next-line functional/immutable-data stream.on("data", (chunk) => chunks.push(chunk)); stream.on("error", reject); stream.on("end", () => resolve(Buffer.concat(chunks))); @@ -37,17 +39,17 @@ function streamToBuffer(stream: NodeJS.ReadableStream): Promise { } const streamToBufferTask = ( - stream: NodeJS.ReadableStream, + stream: NodeJS.ReadableStream ): TaskEither => TE.tryCatch(() => streamToBuffer(stream), E.toError); const streamToStringTask = ( - stream: NodeJS.ReadableStream, + stream: NodeJS.ReadableStream ): TaskEither => TE.tryCatch(() => streamToString(stream), E.toError); export function withQrcode( - bonus: BonusActivation, + bonus: BonusActivation ): TaskEither { return pipe( AP.sequenceS(TE.ApplicativePar)({ @@ -66,6 +68,6 @@ export function withQrcode( mime_type: MIME_TYPES.svg, }, ], - })), + })) ); } diff --git a/src/utils/redis.ts b/src/utils/redis.ts index e216a51ad..6dc8cdddd 100644 --- a/src/utils/redis.ts +++ b/src/utils/redis.ts @@ -1,9 +1,8 @@ +import * as redis from "redis"; import * as appInsights from "applicationinsights"; -import * as O from "fp-ts/lib/Option"; -import * as RA from "fp-ts/lib/ReadonlyArray"; import { pipe } from "fp-ts/lib/function"; -import * as redis from "redis"; - +import * as RA from "fp-ts/lib/ReadonlyArray"; +import * as O from "fp-ts/lib/Option"; import { keyPrefixes } from "../services/redisSessionStorage"; import { log } from "./logger"; @@ -13,21 +12,21 @@ export const obfuscateTokensInfo = (message: string) => RA.findFirst((key) => message.includes(key)), O.map((key) => // eslint-disable-next-line no-useless-escape - message.replace(new RegExp(`\\"${key}\\w+\\"`), `"${key}redacted"`), + message.replace(new RegExp(`\\"${key}\\w+\\"`), `"${key}redacted"`) ), - O.getOrElse(() => message), + O.getOrElse(() => message) ); export const createClusterRedisClient = ( enableTls: boolean, appInsightsClient?: appInsights.TelemetryClient, - useReplicas = true, + useReplicas: boolean = true ) => async ( redisUrl: string, password?: string, - port?: string, + port?: string ): Promise => { const DEFAULT_REDIS_PORT = enableTls ? "6380" : "6379"; const prefixUrl = enableTls ? "rediss://" : "redis://"; @@ -46,7 +45,7 @@ export const createClusterRedisClient = password, socket: { // TODO: We can add a whitelist with all the IP addresses of the redis clsuter - checkServerIdentity: () => undefined, + checkServerIdentity: (_hostname, _cert) => undefined, keepAlive: 2000, tls: enableTls, }, @@ -75,16 +74,16 @@ export const createClusterRedisClient = redisClient.on( "reconnecting", ({ - attempt, delay, + attempt, }: { - readonly attempt: number; readonly delay: number; + readonly attempt: number; }) => { log.warn( "[REDIS reconnecting] a reconnection events occurs [delay %s] [attempt %s]", delay, - attempt, + attempt ); appInsightsClient?.trackEvent({ name: "io-backend.redis.reconnecting", @@ -94,7 +93,7 @@ export const createClusterRedisClient = }, tagOverrides: { samplingEnabled: "false" }, }); - }, + } ); await redisClient.connect(); return redisClient; @@ -102,7 +101,7 @@ export const createClusterRedisClient = // eslint-disable-next-line @typescript-eslint/consistent-type-definitions export type Selector = { - readonly select: (type: T) => readonly S[]; + readonly select: (type: T) => ReadonlyArray; readonly selectOne: (type: T) => S; }; @@ -113,8 +112,8 @@ export type RedisClientSelectorType = Selector< export enum RedisClientMode { "ALL" = "ALL", - "FAST" = "FAST", "SAFE" = "SAFE", + "FAST" = "FAST", } export const RedisClientSelector = @@ -122,16 +121,16 @@ export const RedisClientSelector = async ( redisUrl: string, password?: string, - port?: string, + port?: string ): Promise => { const FAST_REDIS_CLIENT = await createClusterRedisClient( enableTls, - appInsightsClient, + appInsightsClient )(redisUrl, password, port); const SAFE_REDIS_CLIENT = await createClusterRedisClient( enableTls, appInsightsClient, - false, + false )(redisUrl, password, port); const select = (t: RedisClientMode) => { switch (t) { diff --git a/src/utils/responses.ts b/src/utils/responses.ts index 6e6df275b..2b6f9fd13 100644 --- a/src/utils/responses.ts +++ b/src/utils/responses.ts @@ -1,8 +1,14 @@ +import * as express from "express"; +import { PaymentFaultEnum } from "generated/pagopa-proxy/PaymentFault"; +import { PaymentFaultV2Enum } from "generated/pagopa-proxy/PaymentFaultV2"; +import { PaymentProblemJson } from "generated/pagopa-proxy/PaymentProblemJson"; +import * as t from "io-ts"; +import * as E from "fp-ts/lib/Either"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IWithinRangeIntegerTag, WithinRangeInteger, } from "@pagopa/ts-commons/lib/numbers"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { HttpStatusCodeEnum, IResponse, @@ -13,15 +19,8 @@ import { ResponseErrorNotFound, ResponseErrorValidation, } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; import * as TE from "fp-ts/TaskEither"; -import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; -import { PaymentFaultEnum } from "generated/pagopa-proxy/PaymentFault"; -import { PaymentFaultV2Enum } from "generated/pagopa-proxy/PaymentFaultV2"; -import { PaymentProblemJson } from "generated/pagopa-proxy/PaymentProblemJson"; -import * as t from "io-ts"; - import { errorsToError } from "./errorsFormatter"; /** @@ -47,7 +46,7 @@ export function ResponseNoContent(): IResponseNoContent { */ export const ResponseErrorDismissed = ResponseErrorNotFound( "Expired resource", - "The resource you asked for is no longer available", + "The resource you asked for is no longer available" ); /** @@ -55,8 +54,8 @@ export const ResponseErrorDismissed = ResponseErrorNotFound( */ export const withCatchAsInternalError = ( f: () => Promise, - message = "Exception while calling upstream API (likely a timeout).", -): Promise => + message: string = "Exception while calling upstream API (likely a timeout)." +): Promise => f().catch((_) => { // eslint-disable-next-line no-console console.error(_); @@ -64,7 +63,7 @@ export const withCatchAsInternalError = ( }); export const unhandledResponseStatus = ( - status: number, + status: number ): IResponseErrorInternal => ResponseErrorInternal(`unhandled API response status [${status}]`); @@ -74,11 +73,11 @@ export const unhandledResponseStatus = ( */ export const withValidatedOrInternalError = ( validated: t.Validation, - f: (p: T) => U, -): IResponseErrorInternal | U => + f: (p: T) => U +): U | IResponseErrorInternal => E.isLeft(validated) ? ResponseErrorInternal( - errorsToReadableMessages(validated.left).join(" / "), + errorsToReadableMessages(validated.left).join(" / ") ) : f(validated.right); @@ -88,12 +87,12 @@ export const withValidatedOrInternalError = ( */ export const withValidatedOrValidationError = ( response: t.Validation, - f: (p: T) => U, -): IResponseErrorValidation | U => + f: (p: T) => U +): U | IResponseErrorValidation => E.isLeft(response) ? ResponseErrorValidation( "Bad request", - errorsToReadableMessages(response.left).join(" / "), + errorsToReadableMessages(response.left).join(" / ") ) : f(response.right); @@ -109,7 +108,7 @@ export interface IResponseErrorUnauthorizedForLegalReasons */ export function ResponseErrorUnauthorizedForLegalReasons( title: string, - detail: string, + detail: string ): IResponseErrorUnauthorizedForLegalReasons { return { ...ResponseErrorGeneric(HttpStatusCodeEnum.HTTP_STATUS_451, title, detail), @@ -131,13 +130,13 @@ export interface IResponseErrorUnauthorized * Returns an unauthorized error response with status code 401. */ export function ResponseErrorUnauthorized( - detail: string, + detail: string ): IResponseErrorUnauthorized { return { ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_401, "Unauthorized", - detail, + detail ), ...{ detail: `Unauthorized: ${detail}`, @@ -169,7 +168,7 @@ export type IResponsePaymentInternalError = IResponse<"IResponseErrorInternal">; */ export const ResponsePaymentError = ( detail: PaymentFaultEnum, - detailV2: PaymentFaultV2Enum, + detailV2: PaymentFaultV2Enum ): IResponsePaymentInternalError => { const problem: PaymentProblemJson = { detail, @@ -201,7 +200,7 @@ export interface IResponseSuccessOctet * @param o The object to return to the client */ export const ResponseSuccessOctet = ( - o: Buffer, + o: Buffer ): IResponseSuccessOctet => ({ apply: (res) => res @@ -213,12 +212,12 @@ export const ResponseSuccessOctet = ( }); export const wrapValidationWithInternalError: ( - fa: t.Validation, + fa: t.Validation ) => TE.TaskEither = (fa) => pipe( TE.fromEither(fa), TE.mapLeft(errorsToError), - TE.mapLeft((e) => ResponseErrorInternal(e.message)), + TE.mapLeft((e) => ResponseErrorInternal(e.message)) ); /** @@ -232,12 +231,12 @@ export interface IResponseErrorNotImplemented * Returns a Not Implemented error response with status code 501. */ export const ResponseErrorNotImplemented = ( - detail: string, + detail: string ): IResponseErrorNotImplemented => ({ ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_501, "Not Implemented", - detail, + detail ), ...{ detail: `Not Implemented: ${detail}`, @@ -256,12 +255,12 @@ export interface IResponseErrorUnsupportedMediaType * Returns an `Unsupported Media Type` error response with status code 415. */ export const ResponseErrorUnsupportedMediaType = ( - detail: string, + detail: string ): IResponseErrorUnsupportedMediaType => ({ ...ResponseErrorGeneric( HttpStatusCodeEnum.HTTP_STATUS_415, "Unsupported Media Type", - detail, + detail ), ...{ detail, diff --git a/src/utils/separated-list.ts b/src/utils/separated-list.ts index 2cc1933c5..d3f34e7d4 100644 --- a/src/utils/separated-list.ts +++ b/src/utils/separated-list.ts @@ -11,9 +11,9 @@ import * as t from "io-ts"; */ export const GetArbitrarySeparatedListOf = (separator: string) => (decoder: t.Mixed) => - new t.Type[], string, unknown>( + new t.Type>, string, unknown>( `ArbitrarySeparatedListOf<${decoder.name}>`, - (value: unknown): value is readonly t.TypeOf[] => + (value: unknown): value is ReadonlyArray> => Array.isArray(value) && value.every((e) => decoder.is(e)), (input) => t.readonlyArray(decoder).decode( @@ -23,10 +23,10 @@ export const GetArbitrarySeparatedListOf = .map((e) => e.trim()) .filter(Boolean) : !input - ? [] // fallback to empty array in case of empty input - : input, // it should not happen, but in case we let the decoder fail + ? [] // fallback to empty array in case of empty input + : input // it should not happen, but in case we let the decoder fail ), - String, + String ); export const CommaSeparatedListOf = GetArbitrarySeparatedListOf(","); diff --git a/src/utils/strategies.ts b/src/utils/strategies.ts index 5cd5b63bc..d4f52efd4 100644 --- a/src/utils/strategies.ts +++ b/src/utils/strategies.ts @@ -1,10 +1,9 @@ -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; -import { pipe } from "fp-ts/lib/function"; import { IVerifyOptions } from "passport-http-bearer"; - +import * as E from "fp-ts/Either"; +import { pipe } from "fp-ts/lib/function"; +import * as O from "fp-ts/Option"; import { User } from "../types/user"; export type StrategyDoneFunction = ( @@ -12,7 +11,7 @@ export type StrategyDoneFunction = ( error: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any user?: any, - options?: IVerifyOptions | string, + options?: IVerifyOptions | string ) => void; /** @@ -22,7 +21,7 @@ export type StrategyDoneFunction = ( */ export function fulfill( errorOrUser: Either>, - done: StrategyDoneFunction, + done: StrategyDoneFunction ): void { pipe( errorOrUser, @@ -30,7 +29,7 @@ export function fulfill( (error) => done(error), // passport-http-custom-bearer uses the last options parameter // we need to pass it as an empty string or we get an error - (user) => done(undefined, O.isNone(user) ? false : user.value, ""), - ), + (user) => done(undefined, O.isNone(user) ? false : user.value, "") + ) ); } diff --git a/src/utils/thirdPartyConfig.ts b/src/utils/thirdPartyConfig.ts index 1d12ae9f7..9a606dfdc 100644 --- a/src/utils/thirdPartyConfig.ts +++ b/src/utils/thirdPartyConfig.ts @@ -1,7 +1,9 @@ /* eslint-disable sort-keys */ -import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as t from "io-ts"; + +import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; + import { BooleanFromString, JsonFromString, withFallback } from "io-ts-types"; export const ClientCert = t.interface({ @@ -12,9 +14,9 @@ export const ClientCert = t.interface({ export type ApiKeyAuthenticationConfig = t.TypeOf; export const ApiKeyAuthenticationConfig = t.interface({ - header_key_name: NonEmptyString, - key: NonEmptyString, type: t.literal("API_KEY"), + key: NonEmptyString, + header_key_name: NonEmptyString, }); export type AuthenticationConfig = t.TypeOf; @@ -41,11 +43,11 @@ export const TestEnvironmentConfig = t.intersection([ export type ThirdPartyConfigBase = t.TypeOf; export const ThirdPartyConfigBase = t.interface({ - disableLollipopFor: t.readonlyArray(FiscalCode), - isLollipopEnabled: BooleanFromString, - jsonSchema: NonEmptyString, - schemaKind: NonEmptyString, serviceId: NonEmptyString, + schemaKind: NonEmptyString, + jsonSchema: NonEmptyString, + isLollipopEnabled: BooleanFromString, + disableLollipopFor: t.readonlyArray(FiscalCode), }); /** @@ -76,6 +78,6 @@ export type ThirdPartyConfigListFromString = t.TypeOf< >; export const ThirdPartyConfigListFromString = withFallback( JsonFromString, - [], + [] ).pipe(ThirdPartyConfigList); // ^^^ take [] as fallback if JSON.parse fails, but do not override ThirdPartyConfigList validation diff --git a/src/utils/url.ts b/src/utils/url.ts index 0f94b3264..e662279c2 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,12 +1,12 @@ import { ValidUrl } from "@pagopa/ts-commons/lib/url"; -import * as E from "fp-ts/lib/Either"; import { identity, pipe } from "fp-ts/lib/function"; +import * as E from "fp-ts/lib/Either"; import * as S from "fp-ts/lib/string"; export const stripTrailingSlashIfPresent = (aValidUrl: ValidUrl): string => pipe( aValidUrl.href, - E.fromPredicate(S.endsWith("/"), () => aValidUrl.href), + E.fromPredicate(S.endsWith("/"), (_) => aValidUrl.href), E.map(S.slice(0, aValidUrl.href.length - 1)), - E.fold(identity, identity), + E.fold(identity, identity) ); From bc3fe00b9513ef0cd08e25befcb604e7f4e0c450 Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Mon, 3 Feb 2025 16:13:29 +0100 Subject: [PATCH 10/13] Update eslint config Update prettierrc Fix linting --- .prettierrc | 1 + eslint.config.mjs | 15 ++++++++++++++- src/adapters/pnFetch.ts | 9 ++++----- src/app.ts | 7 ++++--- src/config.ts | 4 ++-- src/controllers/authenticationController.ts | 4 ++-- src/controllers/cgnOperatorSearchController.ts | 10 +++++----- src/controllers/ioSignController.ts | 2 +- src/controllers/messagesController.ts | 8 ++++---- src/controllers/notificationController.ts | 2 +- src/controllers/serviceAppBackendController.ts | 2 ++ src/controllers/sessionLockController.ts | 16 ++++++++-------- src/server.ts | 1 - src/services/authenticationLockService.ts | 4 ++-- src/services/bonusService.ts | 1 + src/services/ioWalletService.ts | 1 - src/services/newMessagesService.ts | 6 +----- src/services/pagoPAProxyService.ts | 2 -- src/services/redisSessionStorage.ts | 18 ++++++++---------- src/types/commons.ts | 1 + src/types/lollipop.ts | 1 - src/utils/AsyncIterableTask.ts | 5 +---- src/utils/appinsights.ts | 2 -- src/utils/express.ts | 6 +----- src/utils/file-type.ts | 1 + src/utils/lollipop.ts | 3 --- src/utils/middleware/express.ts | 1 + src/utils/middleware/lollipop.ts | 4 ---- src/utils/ognl.ts | 6 ++---- src/utils/package.ts | 2 +- src/utils/profile.ts | 2 +- src/utils/qrcode.ts | 6 ++---- src/utils/redis.ts | 1 + src/utils/url.ts | 2 +- 34 files changed, 73 insertions(+), 83 deletions(-) diff --git a/.prettierrc b/.prettierrc index 8a5e085f5..99560558a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,2 +1,3 @@ # .prettierrc parser: typescript +trailingComma: "none" \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index 850ea20e0..3f63eef91 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -4,8 +4,20 @@ export default [ ...pagopa, { rules: { + "comma-dangle": "off", + "perfectionist/sort-classes": "off", + "perfectionist/sort-enums": "off", + "perfectionist/sort-imports": "off", + "perfectionist/sort-interfaces": "off", + "perfectionist/sort-intersection-types": "off", + "perfectionist/sort-named-imports": "off", + "perfectionist/sort-objects": "off", + "perfectionist/sort-object-types": "off", + "perfectionist/sort-union-types": "off", "prefer-arrow/prefer-arrow-functions": "off", + "@typescript-eslint/array-type": ["error", { default: "generic" }], "@typescript-eslint/naming-convention": "off", + "@typescript-eslint/no-inferrable-types": "off", "@typescript-eslint/explicit-function-return-type": "off", "no-invalid-this": "off", } @@ -14,10 +26,11 @@ export default [ ignores: [ "node_modules", "generated", + "dist", "**/__tests__/*", "**/__mocks__/*", "Dangerfile.*", - "*.d.ts" + "**/*.d.ts" ], }, ]; \ No newline at end of file diff --git a/src/adapters/pnFetch.ts b/src/adapters/pnFetch.ts index 5cd8f9e63..c49d7cec4 100644 --- a/src/adapters/pnFetch.ts +++ b/src/adapters/pnFetch.ts @@ -195,7 +195,7 @@ export const redirectPrecondition = ThirdPartyPreconditionUrl.decode, E.mapLeft(errorsToError), TE.fromEither, - eventLog.taskEither.info((_) => [ + eventLog.taskEither.info(() => [ `pn.precondition.call`, { locals: lollipopLocals @@ -219,7 +219,6 @@ export const redirectPrecondition = ) ), TE.map( - // eslint-disable-next-line sonarjs/no-identical-functions (body) => new NodeResponse(JSON.stringify(body), { status: 200, @@ -253,7 +252,7 @@ export const redirectMessages = ThirdPartyMessagesUrl.decode, E.mapLeft(errorsToError), TE.fromEither, - eventLog.taskEither.info((_) => [ + eventLog.taskEither.info(() => [ `pn.notification.call`, { locals: lollipopLocals @@ -277,7 +276,6 @@ export const redirectMessages = ) ), TE.map( - // eslint-disable-next-line sonarjs/no-identical-functions (body) => new NodeResponse(JSON.stringify(body), { status: 200, @@ -398,6 +396,7 @@ export const redirectAttachment = ThirdPartyAttachmentUrl.decode, E.mapLeft(errorsToError), TE.fromEither, + // eslint-disable-next-line @typescript-eslint/no-unused-vars TE.chain(([_id, getAttachmentUrl]) => match(getAttachmentUrl) .when( @@ -460,7 +459,7 @@ export const redirectAttachment = ) ) ), - E.getOrElse((_) => + E.getOrElse(() => pipe( attachment.retryAfter, t.number.decode, diff --git a/src/app.ts b/src/app.ts index 542f918bc..14032186a 100644 --- a/src/app.ts +++ b/src/app.ts @@ -170,7 +170,6 @@ export interface IAppFactoryParameters { readonly TrialSystemBasePath: string; } -// eslint-disable-next-line max-lines-per-function, sonarjs/cognitive-complexity export async function newApp({ env, allowNotifyIPSourceRange, @@ -256,6 +255,7 @@ export async function newApp({ // Adds the user fiscal code // we take only the first 6 characters of the fiscal code + // eslint-disable-next-line @typescript-eslint/no-unused-vars morgan.token("fiscal_code_short", (req: express.Request, _) => pipe( req.user, @@ -269,6 +269,7 @@ export async function newApp({ originalUrl.replace(/([?&]token=|[?&]access_token=)([^&]*)/g, "$1REDACTED"); // Obfuscate token in url on morgan logs + // eslint-disable-next-line @typescript-eslint/no-unused-vars morgan.token("obfuscated_url", (req: express.Request, _) => obfuscateToken(req.originalUrl) ); @@ -285,8 +286,8 @@ export async function newApp({ // Parse the incoming request body. This is needed by Passport spid strategy. app.use( bodyParser.json({ + // eslint-disable-next-line @typescript-eslint/no-unused-vars verify: (_req, res: express.Response, buf, _encoding: BufferEncoding) => { - // eslint-disable-next-line functional/immutable-data res.locals.body = buf; }, }) @@ -918,7 +919,7 @@ function registerAPIRoutes( `${basePath}/services`, bearerSessionTokenAuth, toExpressHandler( - (_) => Promise.resolve(ResponseSuccessJson({ items: [] })), + () => Promise.resolve(ResponseSuccessJson({ items: [] })), servicesController ) ); diff --git a/src/config.ts b/src/config.ts index 75dc5223a..15df9b910 100644 --- a/src/config.ts +++ b/src/config.ts @@ -522,7 +522,7 @@ export const PN_CONFIGURATION_ID = pipe( export const FF_ROUTING_PUSH_NOTIF = pipe( process.env.FF_ROUTING_PUSH_NOTIF, FeatureFlag.decode, - E.getOrElse((_) => FeatureFlagEnum.NONE) + E.getOrElse(() => FeatureFlagEnum.NONE) ); export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( @@ -540,7 +540,7 @@ export const FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST = pipe( export const FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX = pipe( process.env.FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, NonEmptyString.decode, - E.getOrElse((_) => "XYZ" as NonEmptyString) + E.getOrElse(() => "XYZ" as NonEmptyString) ); // UNIQUE EMAIL ENFORCEMENT variables diff --git a/src/controllers/authenticationController.ts b/src/controllers/authenticationController.ts index c04076397..3c4e949a2 100644 --- a/src/controllers/authenticationController.ts +++ b/src/controllers/authenticationController.ts @@ -33,14 +33,14 @@ export const getUserIdentity: ( pipe( user, UserIdentity.decode, - E.mapLeft((_) => + E.mapLeft(() => ResponseErrorInternal("Unexpected User Identity data format.") ), E.map((_) => pipe( _, exactUserIdentityDecode, - E.mapLeft((_1) => ResponseErrorInternal("Exact decode failed.")), + E.mapLeft(() => ResponseErrorInternal("Exact decode failed.")), E.map(ResponseSuccessJson), E.toUnion ) diff --git a/src/controllers/cgnOperatorSearchController.ts b/src/controllers/cgnOperatorSearchController.ts index 1dc446f30..59dac92ef 100644 --- a/src/controllers/cgnOperatorSearchController.ts +++ b/src/controllers/cgnOperatorSearchController.ts @@ -51,7 +51,7 @@ export default class CgnOperatorSearchController { | IResponseErrorNotFound | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( GetPublishedCategoriesParameters.decode(req.query), (params) => @@ -94,7 +94,7 @@ export default class CgnOperatorSearchController { | IResponseErrorNotFound | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => this.cgnOperatorSearchService.count() ); @@ -109,7 +109,7 @@ export default class CgnOperatorSearchController { | IResponseErrorNotFound | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( SearchRequest.decode(req.body), (searchRequest) => this.cgnOperatorSearchService.search(searchRequest) @@ -128,7 +128,7 @@ export default class CgnOperatorSearchController { | IResponseErrorNotFound | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( OnlineMerchantSearchRequest.decode(req.body), (onlineSearchRequest) => @@ -148,7 +148,7 @@ export default class CgnOperatorSearchController { | IResponseErrorNotFound | IResponseSuccessJson > => - withUserFromRequest(req, async (_) => + withUserFromRequest(req, async () => withValidatedOrValidationError( OfflineMerchantSearchRequest.decode(req.body), (offlineSearchRequest) => diff --git a/src/controllers/ioSignController.ts b/src/controllers/ioSignController.ts index 8b71d5bbf..f8f531c99 100644 --- a/src/controllers/ioSignController.ts +++ b/src/controllers/ioSignController.ts @@ -256,7 +256,7 @@ export default class IoSignController { req.params.id, Id.decode, TE.fromEither, - TE.mapLeft((_) => + TE.mapLeft(() => ResponseErrorInternal(`Error validating the signature request id`) ) ), diff --git a/src/controllers/messagesController.ts b/src/controllers/messagesController.ts index 338b8f633..cc9cfddd2 100644 --- a/src/controllers/messagesController.ts +++ b/src/controllers/messagesController.ts @@ -196,7 +196,7 @@ export default class MessagesController { user.fiscal_code, lollipopHeaders ), - TE.mapLeft((_) => + TE.mapLeft(() => ResponseErrorInternal( "Error extracting lollipop locals" ) @@ -235,7 +235,7 @@ export default class MessagesController { remoteContentConfiguration, lollipopLocals as LollipopLocalsType ), - (_) => + () => ResponseErrorInternal( "Error getting preconditions from third party service" ) @@ -272,7 +272,7 @@ export default class MessagesController { remoteContentConfiguration, lollipopLocals as LollipopLocalsType ), - (_) => + () => ResponseErrorInternal( "Error getting message from third party service" ) @@ -312,7 +312,7 @@ export default class MessagesController { remoteContentConfiguration, lollipopLocals as LollipopLocalsType ), - (_) => + () => ResponseErrorInternal( "Error getting attachment from third party service" ) diff --git a/src/controllers/notificationController.ts b/src/controllers/notificationController.ts index d884957d1..9241ad7bc 100644 --- a/src/controllers/notificationController.ts +++ b/src/controllers/notificationController.ts @@ -94,7 +94,7 @@ export default class NotificationController { return withUserFromRequest(req, async (user) => withValidatedOrValidationError( InstallationID.decode(req.params.id), - (_) => + () => withValidatedOrValidationError( Installation.decode(req.body), (installation) => { diff --git a/src/controllers/serviceAppBackendController.ts b/src/controllers/serviceAppBackendController.ts index d9cfbc869..6c0d17f85 100644 --- a/src/controllers/serviceAppBackendController.ts +++ b/src/controllers/serviceAppBackendController.ts @@ -70,11 +70,13 @@ export default class ServicesAppBackendController { ); public readonly getFeaturedServices = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _req: express.Request ): Promise> => this.servicesAppBackendService.getFeaturedServices(); public readonly getFeaturedInstitutions = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _req: express.Request ): Promise> => this.servicesAppBackendService.getFeaturedInstitutions(); diff --git a/src/controllers/sessionLockController.ts b/src/controllers/sessionLockController.ts index cf4a44702..179a5d1c1 100644 --- a/src/controllers/sessionLockController.ts +++ b/src/controllers/sessionLockController.ts @@ -147,7 +147,7 @@ export default class SessionLockController { ) ), TE.mapLeft((err) => ResponseErrorInternal(err.message)), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.map(() => ResponseSuccessJson({ message: "ok" })), TE.toUnion )() ); @@ -173,7 +173,7 @@ export default class SessionLockController { this.buildInvalidateUserSessionTask(fiscalCode) ), TE.mapLeft((err) => ResponseErrorInternal(err.message)), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.map(() => ResponseSuccessJson({ message: "ok" })), TE.toUnion )() ); @@ -210,7 +210,7 @@ export default class SessionLockController { TE.mapLeft((err) => ResponseErrorInternal(err.message)) ) ), - TE.map((_) => ResponseSuccessJson({ message: "ok" })), + TE.map(() => ResponseSuccessJson({ message: "ok" })), TE.toUnion )(); @@ -234,7 +234,7 @@ export default class SessionLockController { pipe( // lock the authentication this.authenticationLockService.isUserAuthenticationLocked(fiscalCode), - TE.mapLeft((_) => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK)), + TE.mapLeft(() => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK)), TE.filterOrElseW( (isUserAuthenticationLocked) => !isUserAuthenticationLocked, () => @@ -242,7 +242,7 @@ export default class SessionLockController { "Another user authentication lock has already been applied" ) ), - TE.chainW((_) => + TE.chainW(() => pipe( AP.sequenceT(TE.ApplicativeSeq)( // clear session data @@ -259,7 +259,7 @@ export default class SessionLockController { TE.mapLeft((err) => ResponseErrorInternal(err.message)) ) ), - TE.map((_) => ResponseNoContent()), + TE.map(() => ResponseNoContent()), TE.toUnion )() ) @@ -292,7 +292,7 @@ export default class SessionLockController { this.authenticationLockService.getUserAuthenticationLockData( fiscalCode ), - TE.mapLeft((_) => + TE.mapLeft(() => ResponseErrorInternal(ERROR_CHECK_USER_AUTH_LOCK) ) ) @@ -308,7 +308,7 @@ export default class SessionLockController { : // User auth is NOT locked TE.of(true) ), - TE.map((_) => ResponseNoContent()), + TE.map(() => ResponseNoContent()), TE.toUnion )() ) diff --git a/src/server.ts b/src/server.ts index 3b2731d63..367afa497 100644 --- a/src/server.ts +++ b/src/server.ts @@ -68,7 +68,6 @@ const shutdownTimeout: number = process.env.DEFAULT_SHUTDOWN_TIMEOUT_MILLIS ? parseInt(process.env.DEFAULT_SHUTDOWN_TIMEOUT_MILLIS, 10) : DEFAULT_SHUTDOWN_TIMEOUT_MILLIS; -// eslint-disable-next-line functional/no-let let server: http.Server | https.Server; const timer = TimeTracer(); diff --git a/src/services/authenticationLockService.ts b/src/services/authenticationLockService.ts index f304909b9..1f1442695 100644 --- a/src/services/authenticationLockService.ts +++ b/src/services/authenticationLockService.ts @@ -77,9 +77,9 @@ export default class AuthenticationLockService { // eslint-disable-next-line sort-keys CreatedAt: new Date(), }), - (_) => new Error("Something went wrong creating the record") + () => new Error("Something went wrong creating the record") ), - TE.map((_) => true as const) + TE.map(() => true as const) ); /** diff --git a/src/services/bonusService.ts b/src/services/bonusService.ts index 1504b65ab..b839ebe79 100644 --- a/src/services/bonusService.ts +++ b/src/services/bonusService.ts @@ -130,6 +130,7 @@ export default class BonusService { * */ public readonly getAllBonusActivations = ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _: User ): Promise< | IResponseErrorInternal diff --git a/src/services/ioWalletService.ts b/src/services/ioWalletService.ts index daba993b8..05e766047 100644 --- a/src/services/ioWalletService.ts +++ b/src/services/ioWalletService.ts @@ -1,4 +1,3 @@ -/* eslint-disable sonarjs/no-identical-functions */ /** * This service interacts with the IO Wallet API */ diff --git a/src/services/newMessagesService.ts b/src/services/newMessagesService.ts index 962316fff..fbe8b41b8 100644 --- a/src/services/newMessagesService.ts +++ b/src/services/newMessagesService.ts @@ -213,7 +213,6 @@ export default class NewMessagesService { id: messageId, }); - // eslint-disable-next-line sonarjs/no-identical-functions return withValidatedOrInternalError(validated, (response) => { switch (response.status) { case 200: @@ -504,7 +503,6 @@ export default class NewMessagesService { `newMessagesService|getThirdPartyMessagePreconditionFromThirdPartyService|invocation returned an error:${ response.status } [title: ${response.value?.title ?? "No title"}, detail: ${ - // eslint-disable-next-line sonarjs/no-duplicate-string response.value?.detail ?? "No details" }, type: ${response.value?.type ?? "No type"}]` ); @@ -586,14 +584,12 @@ export default class NewMessagesService { `newMessagesService|getThirdPartyMessageFromThirdPartyService|invocation returned an error:${ response.status } [title: ${response.value?.title ?? "No title"}, detail: ${ - // eslint-disable-next-line sonarjs/no-duplicate-string response.value?.detail ?? "No details" }, type: ${response.value?.type ?? "No type"}]` ); return response; }), TE.mapLeft( - // eslint-disable-next-line sonarjs/no-identical-functions flow((response) => { switch (response.status) { case 400: @@ -736,7 +732,6 @@ export default class NewMessagesService { `newMessagesService|getThirdPartyAttachmentFromThirdPartyService|invocation returned an error:${ response.status } [title: ${response.value?.title ?? "No title"}, detail: ${ - // eslint-disable-next-line sonarjs/no-duplicate-string response.value?.detail ?? "No details" }, type: ${response.value?.type ?? "No type"}])` ); @@ -761,6 +756,7 @@ export default class NewMessagesService { case 500: return ResponseErrorInternal(ERROR_MESSAGE_500); case 503: + // eslint-disable-next-line no-case-declarations const retryAfter = response.headers["Retry-After"] ?? "10"; return ResponseErrorServiceTemporarilyUnavailable( ERROR_MESSAGE_503, diff --git a/src/services/pagoPAProxyService.ts b/src/services/pagoPAProxyService.ts index a1bc936c2..35b22e59e 100644 --- a/src/services/pagoPAProxyService.ts +++ b/src/services/pagoPAProxyService.ts @@ -53,9 +53,7 @@ export default class PagoPAProxyService { ) : response.status === 400 ? ResponseErrorValidation( - // eslint-disable-next-line sonarjs/no-duplicate-string response.value.title || "Bad request (upstream)", - // eslint-disable-next-line sonarjs/no-duplicate-string response.value.detail || "Bad request response from upstream API" ) : ResponsePaymentError( diff --git a/src/services/redisSessionStorage.ts b/src/services/redisSessionStorage.ts index 0534a7eda..8638712d6 100644 --- a/src/services/redisSessionStorage.ts +++ b/src/services/redisSessionStorage.ts @@ -166,7 +166,7 @@ export default class RedisSessionStorage ), E.toError ), - TE.mapLeft((_) => { + TE.mapLeft(() => { log.warn(`Error updating USERSESSIONS Set for ${user.fiscal_code}`); }) )().catch(() => void 0); @@ -214,8 +214,7 @@ export default class RedisSessionStorage ), TE.mapLeft((err) => { log.error("Error reading set members: %s", err); - // eslint-disable-next-line functional/prefer-readonly-type - return [] as string[]; + return [] as Array; }), TE.toUnion )(); @@ -352,7 +351,7 @@ export default class RedisSessionStorage .selectOne(RedisClientMode.FAST) .sAdd(blockedUserSetKey, fiscalCode); }, E.toError), - TE.map((_) => true) + TE.map(() => true) )(); } @@ -403,7 +402,7 @@ export default class RedisSessionStorage pipe( sessionToken, SessionToken.decode, - E.mapLeft((_) => new Error("Error decoding token")) + E.mapLeft(() => new Error("Error decoding token")) ) ), TE.chain((token: SessionToken) => @@ -432,7 +431,7 @@ export default class RedisSessionStorage ) ) ), - TE.chain((_) => + TE.chain(() => pipe( TE.tryCatch(() => this.delSessionsSet(fiscalCode), E.toError), TE.chain(TE.fromEither) @@ -453,7 +452,7 @@ export default class RedisSessionStorage .del(`${noticeEmailPrefix}${user.session_token}`), E.toError ), - TE.map((_) => true) + TE.map(() => true) )(); } @@ -578,8 +577,7 @@ export default class RedisSessionStorage // ---------------------------------------------- // This mGet fires a bunch of GET operation to prevent CROSS-SLOT errors on the cluster - // eslint-disable-next-line functional/prefer-readonly-type - private mGet(keys: string[]): TaskEither> { + private mGet(keys: Array): TaskEither> { return pipe( keys, A.map((singleKey) => @@ -628,7 +626,7 @@ export default class RedisSessionStorage .selectOne(RedisClientMode.FAST) .del(`${userSessionsSetKeyPrefix}${fiscalCode}`); }, E.toError), - TE.map((_) => true) + TE.map(() => true) )(); } diff --git a/src/types/commons.ts b/src/types/commons.ts index 232194210..cd9ca4465 100644 --- a/src/types/commons.ts +++ b/src/types/commons.ts @@ -14,6 +14,7 @@ export type SuccessResponse = t.TypeOf; export const STRINGS_RECORD = t.record(t.string, t.string); export type STRINGS_RECORD = t.TypeOf; +// eslint-disable-next-line @typescript-eslint/no-unused-vars export function assertUnreachable(_: never): never { throw new Error("Unexpected type error"); } diff --git a/src/types/lollipop.ts b/src/types/lollipop.ts index 2727f8638..15dc4af4e 100644 --- a/src/types/lollipop.ts +++ b/src/types/lollipop.ts @@ -1,4 +1,3 @@ - import * as t from "io-ts"; import { FiscalCode, NonEmptyString, PatternString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; diff --git a/src/utils/AsyncIterableTask.ts b/src/utils/AsyncIterableTask.ts index 3d2f6567d..54d8545ef 100644 --- a/src/utils/AsyncIterableTask.ts +++ b/src/utils/AsyncIterableTask.ts @@ -93,10 +93,8 @@ export const foldTaskEither = const foldIterableArray = (asyncIterable: AsyncIterable) => async (): Promise> => { - // eslint-disable-next-line functional/prefer-readonly-type - const array: A[] = []; + const array: Array = []; for await (const variable of asyncIterable) { - // eslint-disable-next-line functional/immutable-data array.push(variable); } return array; @@ -144,7 +142,6 @@ const reduceIterableArray = (initialValue: B, reducer: (prev: B, curr: A) => B | Promise) => (asyncIterable: AsyncIterable) => async (): Promise => { - // eslint-disable-next-line functional/no-let let p: B = initialValue; for await (const variable of asyncIterable) { diff --git a/src/utils/appinsights.ts b/src/utils/appinsights.ts index 2bd78557d..63e18626e 100644 --- a/src/utils/appinsights.ts +++ b/src/utils/appinsights.ts @@ -71,7 +71,6 @@ export function sessionIdPreprocessor( USER_TRACKING_ID_KEY ); if (userTrackingId !== undefined) { - // eslint-disable-next-line functional/immutable-data envelope.tags[appInsights.defaultClient.context.keys.userId] = userTrackingId; } @@ -80,7 +79,6 @@ export function sessionIdPreprocessor( SESSION_TRACKING_ID_KEY ); if (sessionTrackingId !== undefined) { - // eslint-disable-next-line functional/immutable-data envelope.tags[appInsights.defaultClient.context.keys.sessionId] = sessionTrackingId; } diff --git a/src/utils/express.ts b/src/utils/express.ts index feb42bd74..c1870e733 100644 --- a/src/utils/express.ts +++ b/src/utils/express.ts @@ -15,9 +15,7 @@ export type ExpressMiddleware = ( ) => void; export type ResLocals = Record & { - // eslint-disable-next-line functional/prefer-readonly-type detail?: string; - // eslint-disable-next-line functional/prefer-readonly-type body?: Buffer; }; /** @@ -29,12 +27,12 @@ export function toExpressHandler( handler: (req: express.Request, locals?: L) => Promise>, object?: P ): (req: express.Request, res: express.Response) => void { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type return (req, res): Promise => handler .call(object, req, res.locals) .catch(ResponseErrorInternal) .then((response) => { - // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }); @@ -64,7 +62,6 @@ export function toExpressMiddleware( ) ), TE.mapLeft((response) => { - // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }), @@ -79,7 +76,6 @@ export function constantExpressHandler( response: IResponse ): (req: express.Request, res: express.Response) => void { return (_, res) => { - // eslint-disable-next-line functional/immutable-data res.locals.detail = response.detail; response.apply(res); }; diff --git a/src/utils/file-type.ts b/src/utils/file-type.ts index 56be79b4b..6aa10c70c 100644 --- a/src/utils/file-type.ts +++ b/src/utils/file-type.ts @@ -16,6 +16,7 @@ export const isPdf = (data: Buffer) => data.toString("binary", 0, 4) === "%PDF"; /** * Allow any file type */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars export const isAny = (_: Buffer) => true; export const typeToCheck = (type: FileType) => diff --git a/src/utils/lollipop.ts b/src/utils/lollipop.ts index 8cd1228f6..06bf91998 100644 --- a/src/utils/lollipop.ts +++ b/src/utils/lollipop.ts @@ -134,7 +134,6 @@ const getAndValidateAssertionRefForUser = ( ) ); -/* eslint-disable sonarjs/no-identical-functions */ /** * @deprecated */ @@ -145,7 +144,6 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( lollipopHeaders: LollipopRequiredHeaders ) => pipe( - // eslint-disable-next-line sonarjs/no-duplicate-string TE.of(getNonceOrUlid(lollipopHeaders["signature-input"])), TE.bindTo("operationId"), TE.bind("assertionRef", ({ operationId }) => @@ -479,4 +477,3 @@ export const extractLollipopLocalsFromLollipopHeaders = ( { ...Object.keys(lcLocals), name: "lollipop.locals.info" }, ]) ); -/* eslint-enable sonarjs/no-identical-functions */ diff --git a/src/utils/middleware/express.ts b/src/utils/middleware/express.ts index 8a9f863e0..6edf8deb3 100644 --- a/src/utils/middleware/express.ts +++ b/src/utils/middleware/express.ts @@ -12,6 +12,7 @@ export function expressErrorMiddleware( err: Error, _: Request, res: Response, + // eslint-disable-next-line @typescript-eslint/no-unused-vars __: NextFunction ): void { log.error("An exception occurred during http request: %s", err.message); diff --git a/src/utils/middleware/lollipop.ts b/src/utils/middleware/lollipop.ts index 75a8cca88..8207655ff 100644 --- a/src/utils/middleware/lollipop.ts +++ b/src/utils/middleware/lollipop.ts @@ -38,7 +38,6 @@ export const expressLollipopMiddlewareLegacy: ( lollipopHeaders ), TE.map((lollipopLocals) => { - // eslint-disable-next-line functional/immutable-data res.locals = { ...res.locals, ...lollipopLocals }; }), TE.toUnion @@ -63,7 +62,6 @@ export const expressLollipopMiddlewareLegacy: ( TE.toUnion )(); -/* eslint-disable sonarjs/no-identical-functions */ export const expressLollipopMiddleware: ( lollipopClient: ReturnType, sessionStorage: ISessionStorage @@ -82,7 +80,6 @@ export const expressLollipopMiddleware: ( O.toUndefined(user)?.fiscal_code ), TE.map((lollipopLocals) => { - // eslint-disable-next-line functional/immutable-data res.locals = { ...res.locals, ...lollipopLocals }; }), TE.toUnion @@ -106,4 +103,3 @@ export const expressLollipopMiddleware: ( TE.map(() => next()), TE.toUnion )(); -/* eslint-enable sonarjs/no-identical-functions */ diff --git a/src/utils/ognl.ts b/src/utils/ognl.ts index 1ea0beb0c..e560b3226 100644 --- a/src/utils/ognl.ts +++ b/src/utils/ognl.ts @@ -25,19 +25,18 @@ export const set = ( const splittedpath: ReadonlyArray = !Array.isArray(path) ? path.toString().match(/[^.[\]]+/g) || [] : path; - // eslint-disable-next-line functional/immutable-data splittedpath.slice(0, -1).reduce( ( // eslint-disable-next-line @typescript-eslint/no-explicit-any a: any, c, + // eslint-disable-next-line @typescript-eslint/no-unused-vars _i ) => // Iterate all of them except the last one Object(a[c]) === a[c] ? a[c] - : // eslint-disable-next-line functional/immutable-data - (a[c] = {}), + : (a[c] = {}), obj )[splittedpath[splittedpath.length - 1]] = value; return obj; @@ -61,7 +60,6 @@ export const nestifyPrefixedType = ( R.reduceWithIndex({}, (k, b, a) => set( b, - // eslint-disable-next-line functional/immutable-data k.split("_").splice(1).join("."), a ) diff --git a/src/utils/package.ts b/src/utils/package.ts index 2208a9dbb..88298d9a8 100644 --- a/src/utils/package.ts +++ b/src/utils/package.ts @@ -28,7 +28,7 @@ export const getObjectFromPackageJson = ( pipe( type.decode(packageJson[key]), E.fold( - (_) => O.none, + () => O.none, (_) => O.some(_) ) ); diff --git a/src/utils/profile.ts b/src/utils/profile.ts index 5f2ae48ff..21a5fc10a 100644 --- a/src/utils/profile.ts +++ b/src/utils/profile.ts @@ -61,7 +61,7 @@ export const profileWithEmailValidatedOrError = ( profile.value, ProfileWithEmailValidated.decode, E.mapLeft( - (_) => new Error("Profile has not a validated email address") + () => new Error("Profile has not a validated email address") ), TE.fromEither ) diff --git a/src/utils/qrcode.ts b/src/utils/qrcode.ts index a331ee396..075356799 100644 --- a/src/utils/qrcode.ts +++ b/src/utils/qrcode.ts @@ -17,10 +17,9 @@ const fixQrcodeFill = (svgStr: string): string => svgStr.replace(" { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/prefer-readonly-type + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/array-type const chunks: any[] = []; return new Promise((resolve, reject) => { - // eslint-disable-next-line functional/immutable-data stream.on("data", (chunk) => chunks.push(chunk)); stream.on("error", reject); stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); @@ -28,10 +27,9 @@ function streamToString(stream: NodeJS.ReadableStream): Promise { } function streamToBuffer(stream: NodeJS.ReadableStream): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/prefer-readonly-type + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/array-type const chunks: any[] = []; return new Promise((resolve, reject) => { - // eslint-disable-next-line functional/immutable-data stream.on("data", (chunk) => chunks.push(chunk)); stream.on("error", reject); stream.on("end", () => resolve(Buffer.concat(chunks))); diff --git a/src/utils/redis.ts b/src/utils/redis.ts index 6dc8cdddd..c4b499a42 100644 --- a/src/utils/redis.ts +++ b/src/utils/redis.ts @@ -45,6 +45,7 @@ export const createClusterRedisClient = password, socket: { // TODO: We can add a whitelist with all the IP addresses of the redis clsuter + // eslint-disable-next-line @typescript-eslint/no-unused-vars checkServerIdentity: (_hostname, _cert) => undefined, keepAlive: 2000, tls: enableTls, diff --git a/src/utils/url.ts b/src/utils/url.ts index e662279c2..14fdd1bb5 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -6,7 +6,7 @@ import * as S from "fp-ts/lib/string"; export const stripTrailingSlashIfPresent = (aValidUrl: ValidUrl): string => pipe( aValidUrl.href, - E.fromPredicate(S.endsWith("/"), (_) => aValidUrl.href), + E.fromPredicate(S.endsWith("/"), () => aValidUrl.href), E.map(S.slice(0, aValidUrl.href.length - 1)), E.fold(identity, identity) ); From 2de075e9a21d7dd7e5a13225010210e9ecf29d3f Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Mon, 3 Feb 2025 16:16:55 +0100 Subject: [PATCH 11/13] Fix trailing comma lint --- eslint.config.mjs | 66 +++++------ src/adapters/pnFetch.ts | 48 ++++---- src/app.ts | 40 ++++--- src/clients/api.ts | 4 +- src/clients/app-messages.client.ts | 4 +- src/clients/bonus.ts | 4 +- src/clients/cgn-operator-search.ts | 6 +- src/clients/cgn.ts | 4 +- src/clients/eucovidcert.client.ts | 6 +- src/clients/firstLollipopConsumer.ts | 6 +- src/clients/io-fims.ts | 4 +- src/clients/io-sign.ts | 4 +- src/clients/io-wallet.ts | 4 +- src/clients/lollipop.ts | 4 +- src/clients/pagopa.ts | 4 +- src/clients/pn-clients.ts | 12 +- src/clients/services-app-backend.ts | 6 +- src/clients/third-party-service-client.ts | 22 ++-- src/clients/trial-system.client.ts | 4 +- src/config.ts | 16 +-- src/controllers/authenticationController.ts | 2 +- src/controllers/bonusController.ts | 4 +- src/controllers/cgnController.ts | 2 +- .../cgnOperatorSearchController.ts | 6 +- src/controllers/eucovidcertController.ts | 2 +- src/controllers/fimsController.ts | 2 +- .../firstLollipopConsumerController.ts | 4 +- src/controllers/ioSignController.ts | 22 ++-- src/controllers/ioWalletController.ts | 4 +- src/controllers/messagesController.ts | 10 +- src/controllers/notificationController.ts | 56 +++++---- src/controllers/pagoPAProxyController.ts | 2 +- src/controllers/pnController.ts | 10 +- src/controllers/profileController.ts | 2 +- .../serviceAppBackendController.ts | 4 +- src/controllers/servicesController.ts | 2 +- src/controllers/sessionController.ts | 2 +- src/controllers/sessionLockController.ts | 16 +-- src/controllers/ssoController.ts | 4 +- src/controllers/trialController.ts | 6 +- .../userDataProcessingController.ts | 2 +- src/controllers/userMetadataController.ts | 4 +- src/server.ts | 12 +- src/services/IPagoPAClientFactory.ts | 2 +- src/services/authenticationLockService.ts | 12 +- src/services/bonusService.ts | 8 +- src/services/cgnOperatorSearchService.ts | 14 +-- src/services/cgnService.ts | 20 ++-- src/services/eucovidcertService.ts | 12 +- src/services/fimsService.ts | 10 +- src/services/functionAppService.ts | 23 ++-- src/services/ioSignService.ts | 22 ++-- src/services/ioWalletService.ts | 22 ++-- src/services/lollipopService.ts | 2 +- src/services/newMessagesService.ts | 52 ++++----- src/services/notificationService.ts | 16 +-- src/services/notificationServiceFactory.ts | 2 +- src/services/pagoPAClientFactory.ts | 2 +- src/services/pagoPAProxyService.ts | 73 ++++++------ src/services/pnService.ts | 6 +- src/services/profileService.ts | 36 +++--- src/services/redisSessionStorage.ts | 48 ++++---- src/services/servicesAppBackendService.ts | 14 +-- src/services/trialService.ts | 14 +-- src/services/userDataProcessingService.ts | 56 +++++---- src/strategies/bearerMyPortalTokenStrategy.ts | 2 +- src/strategies/bearerSessionTokenStrategy.ts | 2 +- src/types/IDPEntityDescriptor.ts | 2 +- src/types/assertionRef.ts | 6 +- src/types/booleans.ts | 4 +- src/types/commons.ts | 6 +- src/types/lollipop.ts | 22 ++-- src/types/pathParams.ts | 16 +-- src/types/profile.ts | 4 +- src/types/user.ts | 26 ++--- src/utils/AsyncIterableTask.ts | 6 +- src/utils/appinsights.ts | 20 ++-- src/utils/attachments.ts | 6 +- src/utils/barcode.ts | 6 +- src/utils/date.ts | 4 +- src/utils/express.ts | 2 +- src/utils/fastLogin.ts | 4 +- src/utils/featureFlag.ts | 2 +- src/utils/gracefulShutdown.ts | 2 +- src/utils/logger.ts | 2 +- src/utils/lollipop.ts | 110 +++++++++--------- src/utils/middleware/lollipop.ts | 4 +- src/utils/ognl.ts | 25 ++-- src/utils/profile.ts | 8 +- src/utils/qrcode.ts | 12 +- src/utils/redis.ts | 24 ++-- src/utils/responses.ts | 30 ++--- src/utils/separated-list.ts | 4 +- src/utils/thirdPartyConfig.ts | 22 ++-- src/utils/timer.ts | 2 +- 95 files changed, 651 insertions(+), 648 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 3f63eef91..e4a30a16b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,36 +1,36 @@ import pagopa from "@pagopa/eslint-config"; export default [ - ...pagopa, - { - rules: { - "comma-dangle": "off", - "perfectionist/sort-classes": "off", - "perfectionist/sort-enums": "off", - "perfectionist/sort-imports": "off", - "perfectionist/sort-interfaces": "off", - "perfectionist/sort-intersection-types": "off", - "perfectionist/sort-named-imports": "off", - "perfectionist/sort-objects": "off", - "perfectionist/sort-object-types": "off", - "perfectionist/sort-union-types": "off", - "prefer-arrow/prefer-arrow-functions": "off", - "@typescript-eslint/array-type": ["error", { default: "generic" }], - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "no-invalid-this": "off", - } - }, - { - ignores: [ - "node_modules", - "generated", - "dist", - "**/__tests__/*", - "**/__mocks__/*", - "Dangerfile.*", - "**/*.d.ts" - ], - }, -]; \ No newline at end of file + ...pagopa, + { + rules: { + "comma-dangle": "off", + "perfectionist/sort-classes": "off", + "perfectionist/sort-enums": "off", + "perfectionist/sort-imports": "off", + "perfectionist/sort-interfaces": "off", + "perfectionist/sort-intersection-types": "off", + "perfectionist/sort-named-imports": "off", + "perfectionist/sort-objects": "off", + "perfectionist/sort-object-types": "off", + "perfectionist/sort-union-types": "off", + "prefer-arrow/prefer-arrow-functions": "off", + "@typescript-eslint/array-type": ["error", { default: "generic" }], + "@typescript-eslint/naming-convention": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "no-invalid-this": "off" + } + }, + { + ignores: [ + "node_modules", + "generated", + "dist", + "**/__tests__/*", + "**/__mocks__/*", + "Dangerfile.*", + "**/*.d.ts" + ] + } +]; diff --git a/src/adapters/pnFetch.ts b/src/adapters/pnFetch.ts index c49d7cec4..c0578343a 100644 --- a/src/adapters/pnFetch.ts +++ b/src/adapters/pnFetch.ts @@ -8,7 +8,7 @@ import * as O from "fp-ts/Option"; import { FiscalCode, NonEmptyString, - Ulid, + Ulid } from "@pagopa/ts-commons/lib/strings"; import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; import { Response as NodeResponse } from "node-fetch"; @@ -27,8 +27,8 @@ const getPath = (input: RequestInfo | URL): string => input instanceof URL ? `${input.pathname}${input.search}` : typeof input === "string" - ? `${new URL(input).pathname}${new URL(input).search}` - : `${new URL(input.url).pathname}${new URL(input.url).search}`; + ? `${new URL(input).pathname}${new URL(input).search}` + : `${new URL(input.url).pathname}${new URL(input.url).search}`; export const ThirdPartyMessagesUrl = pathParamsFromUrl( RegExp("^[/]+messages[/]+([^/]+)$"), @@ -74,8 +74,8 @@ const withAccept_iojson = ...init, headers: { ...(init?.headers ?? {}), - Accept: "application/io+json", - }, + Accept: "application/io+json" + } }); const WithFiscalCode = t.interface({ fiscal_code: FiscalCode }); @@ -96,7 +96,7 @@ const retrievePrecondition = ( ApiKeyAuth: pnApiKey, iun, "x-pagopa-cx-taxid": fiscalCode, - ...lollipopLocals, + ...lollipopLocals }), TE.mapLeft(errorsToError), TE.chain( @@ -122,7 +122,7 @@ const retrieveNotificationDetails = ( ApiKeyAuth: pnApiKey, iun, "x-pagopa-cx-taxid": fiscalCode, - ...lollipopLocals, + ...lollipopLocals }), TE.mapLeft(errorsToError), TE.chain( @@ -150,13 +150,13 @@ export const errorResponse = (error: Error): Response => { detail: error.message, status: 500, - title: "Error fetching PN data", + title: "Error fetching PN data" }, ProblemJson.encode, (problem) => new NodeResponse(JSON.stringify(problem), { status: problem.status, - statusText: problem.title, + statusText: problem.title }) as unknown as Response // cast required: the same cast is used in clients code generation ); @@ -165,14 +165,14 @@ export const retryResponse = (retryAfter: number): Response => { detail: "Data is not ready yet", status: 503, - title: "Error fetching PN data", + title: "Error fetching PN data" }, ProblemJson.encode, (problem) => new NodeResponse(JSON.stringify(problem), { headers: { "Retry-After": `${retryAfter}` }, status: problem.status, - statusText: problem.title, + statusText: problem.title }) as unknown as Response // cast required: the same cast is used in clients code generation ); @@ -201,8 +201,8 @@ export const redirectPrecondition = locals: lollipopLocals ? Object.keys(lollipopLocals) : "No lollipop locals", - name: "pn.precondition.call", - }, + name: "pn.precondition.call" + } ]), TE.chain((params) => pipe( @@ -222,12 +222,12 @@ export const redirectPrecondition = (body) => new NodeResponse(JSON.stringify(body), { status: 200, - statusText: "OK", + statusText: "OK" }) as unknown as Response // cast required: the same cast is used in clients code generation ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call retrievePrecondition`, - { message, name: "pn.precondition.error" }, + { message, name: "pn.precondition.error" } ]), TE.mapLeft(errorResponse), TE.toUnion @@ -258,8 +258,8 @@ export const redirectMessages = locals: lollipopLocals ? Object.keys(lollipopLocals) : "No lollipop locals", - name: "pn.notification.call", - }, + name: "pn.notification.call" + } ]), TE.chain((params) => pipe( @@ -279,12 +279,12 @@ export const redirectMessages = (body) => new NodeResponse(JSON.stringify(body), { status: 200, - statusText: "OK", + statusText: "OK" }) as unknown as Response // cast required: the same cast is used in clients code generation ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call retrieveNotificationDetails`, - { message, name: "pn.notification.error" }, + { message, name: "pn.notification.error" } ]), TE.mapLeft(errorResponse), TE.toUnion @@ -312,7 +312,7 @@ const getPnDocument = ( docIdx: Number(docIdx), iun, "x-pagopa-cx-taxid": fiscalCode, - ...lollipopLocals, + ...lollipopLocals }), E.toError ), @@ -355,7 +355,7 @@ const getPnPayment = ( attachmentName: docName, iun, "x-pagopa-cx-taxid": fiscalCode, - ...lollipopLocals, + ...lollipopLocals }), E.toError ), @@ -404,7 +404,7 @@ export const redirectAttachment = (au) => { eventLog.peek.info([ `Calling PN with lollipopLocals: ${lollipopLocals}`, - { name: "lollipo.pn.api.attachment" }, + { name: "lollipo.pn.api.attachment" } ]); return getPnDocument( origFetch, @@ -421,7 +421,7 @@ export const redirectAttachment = (au) => { eventLog.peek.info([ `Calling PN with lollipopLocals: ${lollipopLocals}`, - { name: "lollipo.pn.api.payment" }, + { name: "lollipo.pn.api.payment" } ]); return getPnPayment( origFetch, @@ -474,7 +474,7 @@ export const redirectAttachment = ), eventLog.taskEither.errorLeft(({ message }) => [ `Something went wrong trying to call getPnDocumentUrl`, - { message, name: "pn.attachment.error" }, + { message, name: "pn.attachment.error" } ]), TE.mapLeft(errorResponse), TE.toUnion diff --git a/src/app.ts b/src/app.ts index 14032186a..999f66019 100644 --- a/src/app.ts +++ b/src/app.ts @@ -14,7 +14,7 @@ import expressEnforcesSsl = require("express-enforces-ssl"); import { TableClient } from "@azure/data-tables"; import { NodeEnvironment, - NodeEnvironmentEnum, + NodeEnvironmentEnum } from "@pagopa/ts-commons/lib/environment"; import { ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { CIDR, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; @@ -70,7 +70,7 @@ import { SERVICES_APP_BACKEND_CLIENT, TEST_CGN_FISCAL_CODES, TRIAL_SYSTEM_CLIENT, - URL_TOKEN_STRATEGY, + URL_TOKEN_STRATEGY } from "./config"; import MessagesController from "./controllers/messagesController"; import NotificationController from "./controllers/notificationController"; @@ -93,7 +93,7 @@ import { firstLollipopSign } from "./controllers/firstLollipopConsumerController import IoSignController from "./controllers/ioSignController"; import { getPNActivationController, - upsertPNActivationController, + upsertPNActivationController } from "./controllers/pnController"; import ServicesAppBackendController from "./controllers/serviceAppBackendController"; import SessionLockController from "./controllers/sessionLockController"; @@ -113,7 +113,7 @@ import NewMessagesService from "./services/newMessagesService"; import NotificationService from "./services/notificationService"; import { NotificationServiceFactory, - getNotificationServiceFactory, + getNotificationServiceFactory } from "./services/notificationServiceFactory"; import PagoPAProxyService from "./services/pagoPAProxyService"; import { PNService } from "./services/pnService"; @@ -131,11 +131,11 @@ import { constantExpressHandler, toExpressHandler } from "./utils/express"; import { expressErrorMiddleware } from "./utils/middleware/express"; import { expressLollipopMiddleware, - expressLollipopMiddlewareLegacy, + expressLollipopMiddlewareLegacy } from "./utils/middleware/lollipop"; import { getCurrentBackendVersion, - getObjectFromPackageJson, + getObjectFromPackageJson } from "./utils/package"; import { RedisClientMode, RedisClientSelector } from "./utils/redis"; import { ResponseErrorDismissed } from "./utils/responses"; @@ -147,7 +147,7 @@ import IoFimsController from "./controllers/fimsController"; const defaultModule = { // eslint-disable-next-line @typescript-eslint/no-use-before-define - newApp, + newApp }; export interface IAppFactoryParameters { @@ -187,7 +187,7 @@ export async function newApp({ CGNOperatorSearchAPIBasePath, EUCovidCertBasePath, ServicesAppBackendBasePath, - TrialSystemBasePath, + TrialSystemBasePath }: IAppFactoryParameters): Promise { const isDevEnvironment = ENV === NodeEnvironmentEnum.DEVELOPMENT; const REDIS_CLIENT_SELECTOR = await RedisClientSelector( @@ -217,14 +217,14 @@ export async function newApp({ // Creates middlewares for each implemented strategy const authMiddlewares = { bearerMyPortal: passport.authenticate("bearer.myportal", { - session: false, + session: false }), bearerSession: passport.authenticate("bearer.session", { - session: false, + session: false }), urlToken: passport.authenticate("authtoken", { - session: false, - }), + session: false + }) }; // Create and setup the Express app. @@ -289,7 +289,7 @@ export async function newApp({ // eslint-disable-next-line @typescript-eslint/no-unused-vars verify: (_req, res: express.Response, buf, _encoding: BufferEncoding) => { res.locals.body = buf; - }, + } }) ); @@ -761,7 +761,7 @@ function registerAPIRoutes( const notificationController: NotificationController = new NotificationController(notificationServiceFactory, sessionStorage, { notificationDefaultSubject: NOTIFICATION_DEFAULT_SUBJECT, - notificationDefaultTitle: NOTIFICATION_DEFAULT_TITLE, + notificationDefaultTitle: NOTIFICATION_DEFAULT_TITLE }); const sessionController: SessionController = new SessionController( @@ -1145,7 +1145,7 @@ function registerIoSignAPIRoutes( bearerSessionTokenAuth, constantExpressHandler( ResponseSuccessJson({ - serviceId: IO_SIGN_SERVICE_ID as NonEmptyString, + serviceId: IO_SIGN_SERVICE_ID as NonEmptyString }) ) ); @@ -1374,17 +1374,17 @@ function registerPublicRoutes(app: Express): void { minAppVersion, O.getOrElse(() => ({ android: "UNKNOWN", - ios: "UNKNOWN", + ios: "UNKNOWN" })) ), min_app_version_pagopa: pipe( minAppVersionPagoPa, O.getOrElse(() => ({ android: "UNKNOWN", - ios: "UNKNOWN", + ios: "UNKNOWN" })) ), - version, + version }; res.status(200).json(serverInfo); }); @@ -1392,7 +1392,9 @@ function registerPublicRoutes(app: Express): void { // Liveness probe for Kubernetes. // @see // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-a-liveness-http-request - app.get("/ping", (_, res) => { res.status(200).send("ok") }); + app.get("/ping", (_, res) => { + res.status(200).send("ok"); + }); } // eslint-disable-next-line max-params diff --git a/src/clients/api.ts b/src/clients/api.ts index bbf7c2fb4..cfb8425c2 100644 --- a/src/clients/api.ts +++ b/src/clients/api.ts @@ -15,8 +15,8 @@ export function APIClient( ...params, // please refer to source api spec for actual header mapping // https://github.com/pagopa/io-functions-app/blob/master/openapi/index.yaml#:~:text=%20%20SubscriptionKey: - SubscriptionKey: token, - }), + SubscriptionKey: token + }) }); } diff --git a/src/clients/app-messages.client.ts b/src/clients/app-messages.client.ts index cbd4f21c4..538a76c1d 100644 --- a/src/clients/app-messages.client.ts +++ b/src/clients/app-messages.client.ts @@ -19,8 +19,8 @@ export function AppMessagesAPIClient( // @ts-ignore op({ ...params, - SubscriptionKey: token, - }), + SubscriptionKey: token + }) }); } diff --git a/src/clients/bonus.ts b/src/clients/bonus.ts index 95d870c1a..a0ef88a28 100644 --- a/src/clients/bonus.ts +++ b/src/clients/bonus.ts @@ -15,8 +15,8 @@ export function BonusAPIClient( ...params, // please refer to source api spec for actual header mapping // https://github.com/pagopa/io-functions-bonus/blob/master/openapi/index.yaml#:~:text=%20%20ApiKey: - ApiKey: token, - }), + ApiKey: token + }) }); } diff --git a/src/clients/cgn-operator-search.ts b/src/clients/cgn-operator-search.ts index 0da466687..fc6eacc1c 100644 --- a/src/clients/cgn-operator-search.ts +++ b/src/clients/cgn-operator-search.ts @@ -1,7 +1,7 @@ import nodeFetch from "node-fetch"; import { Client, - createClient, + createClient } from "../../generated/io-cgn-operator-search-api/client"; export function CgnOperatorSearchAPIClient( @@ -18,8 +18,8 @@ export function CgnOperatorSearchAPIClient( withDefaults: (op) => (params) => op({ ...params, - ApiKey: token, - }), + ApiKey: token + }) }); } diff --git a/src/clients/cgn.ts b/src/clients/cgn.ts index 598a00295..ebe48ccf4 100644 --- a/src/clients/cgn.ts +++ b/src/clients/cgn.ts @@ -15,8 +15,8 @@ export function CgnAPIClient( withDefaults: (op) => (params) => op({ ...params, - ApiKey: token, - }), + ApiKey: token + }) }); } diff --git a/src/clients/eucovidcert.client.ts b/src/clients/eucovidcert.client.ts index 2ce023073..3e06a7a43 100644 --- a/src/clients/eucovidcert.client.ts +++ b/src/clients/eucovidcert.client.ts @@ -1,7 +1,7 @@ import nodeFetch from "node-fetch"; import { Client, - createClient, + createClient } from "@pagopa/io-functions-eucovidcerts-sdk/client"; export function EUCovidCertAPIClient( @@ -17,8 +17,8 @@ export function EUCovidCertAPIClient( withDefaults: (op) => (params) => op({ ...params, - ApiKey: token, - }), + ApiKey: token + }) }); } diff --git a/src/clients/firstLollipopConsumer.ts b/src/clients/firstLollipopConsumer.ts index bcdc27ed5..6afc8d43a 100644 --- a/src/clients/firstLollipopConsumer.ts +++ b/src/clients/firstLollipopConsumer.ts @@ -1,7 +1,7 @@ import * as nodeFetch from "node-fetch"; import { createClient, - Client, + Client } from "../../generated/lollipop-first-consumer/client"; export function FirstLollipopConsumerClient( @@ -18,8 +18,8 @@ export function FirstLollipopConsumerClient( withDefaults: (op) => (params) => op({ ...params, - ApiKeyAuth: token, - }), + ApiKeyAuth: token + }) }); } diff --git a/src/clients/io-fims.ts b/src/clients/io-fims.ts index 023c62831..815d7136e 100644 --- a/src/clients/io-fims.ts +++ b/src/clients/io-fims.ts @@ -15,8 +15,8 @@ export function IoFimsAPIClient( withDefaults: (op) => (params) => op({ ...params, - FunctionsKey: token, - }), + FunctionsKey: token + }) }); } diff --git a/src/clients/io-sign.ts b/src/clients/io-sign.ts index b76bf5e84..4c6a3d0cb 100644 --- a/src/clients/io-sign.ts +++ b/src/clients/io-sign.ts @@ -15,8 +15,8 @@ export function IoSignAPIClient( withDefaults: (op) => (params) => op({ ...params, - FunctionsKey: token, - }), + FunctionsKey: token + }) }); } diff --git a/src/clients/io-wallet.ts b/src/clients/io-wallet.ts index 99e4885b5..2e7c5c23f 100644 --- a/src/clients/io-wallet.ts +++ b/src/clients/io-wallet.ts @@ -18,8 +18,8 @@ export function IoWalletAPIClient( withDefaults: (op) => (params) => op({ ...params, - FunctionsKey: token, - }), + FunctionsKey: token + }) }); } diff --git a/src/clients/lollipop.ts b/src/clients/lollipop.ts index 0a37d127e..19fa48e34 100644 --- a/src/clients/lollipop.ts +++ b/src/clients/lollipop.ts @@ -15,8 +15,8 @@ export function LollipopApiClient( withDefaults: (op) => (params) => op({ ...params, - ApiKeyAuth: token, - }), + ApiKeyAuth: token + }) }); } diff --git a/src/clients/pagopa.ts b/src/clients/pagopa.ts index 8b991bc38..fdb646261 100644 --- a/src/clients/pagopa.ts +++ b/src/clients/pagopa.ts @@ -13,8 +13,8 @@ export function PagoPAClient( withDefaults: (op) => (params) => op({ ...params, - apiKeyHeader: apiKey, - }), + apiKeyHeader: apiKey + }) }); } diff --git a/src/clients/pn-clients.ts b/src/clients/pn-clients.ts index a97faddb2..42ce1c612 100644 --- a/src/clients/pn-clients.ts +++ b/src/clients/pn-clients.ts @@ -3,11 +3,11 @@ import { ValidUrl } from "@pagopa/ts-commons/lib/url"; import { stripTrailingSlashIfPresent } from "../utils/url"; import { Client, - createClient, + createClient } from "../../generated/piattaforma-notifiche/client"; import { Client as AddressBookClient, - createClient as createAddressBookClient, + createClient as createAddressBookClient } from "../../generated/piattaforma-notifiche-courtesy/client"; export function PnAPIClient( @@ -17,7 +17,7 @@ export function PnAPIClient( ): Client { return createClient({ baseUrl, - fetchApi, + fetchApi }); } export type PnAPIClient = typeof PnAPIClient; @@ -40,8 +40,8 @@ export const PnAddressBookIOClient = ( withDefaults: (op) => (params) => op({ ...params, - ApiKeyAuth: apiKey, - }), + ApiKeyAuth: apiKey + }) }); export type PnAddressBookIOClient = typeof PnAddressBookIOClient; @@ -51,7 +51,7 @@ export type PnAddressBookIOClient = typeof PnAddressBookIOClient; export enum PNEnvironment { PRODUCTION = "PRODUCTION", UAT = "UAT", - DEV = "DEV", + DEV = "DEV" } /** diff --git a/src/clients/services-app-backend.ts b/src/clients/services-app-backend.ts index 3c1e858a0..4915808dc 100644 --- a/src/clients/services-app-backend.ts +++ b/src/clients/services-app-backend.ts @@ -1,7 +1,7 @@ import nodeFetch from "node-fetch"; import { Client, - createClient, + createClient } from "../../generated/services-app-backend/client"; export function ServicesAppBackendAPIClient( @@ -16,8 +16,8 @@ export function ServicesAppBackendAPIClient( fetchApi, withDefaults: (op) => (params) => op({ - ...params, - }), + ...params + }) }); } diff --git a/src/clients/third-party-service-client.ts b/src/clients/third-party-service-client.ts index c3257f0c5..130d50349 100644 --- a/src/clients/third-party-service-client.ts +++ b/src/clients/third-party-service-client.ts @@ -12,7 +12,7 @@ import { Ulid } from "generated/parameters/Ulid"; import { pnFetch } from "../adapters/pnFetch"; import { Client, - createClient, + createClient } from "../../generated/third-party-service/client"; // --- @@ -38,8 +38,8 @@ const withApiKey = ...init, headers: { ...(init?.headers ?? {}), - ...{ [authConfig.header_key_name]: authConfig.key }, - }, + ...{ [authConfig.header_key_name]: authConfig.key } + } }); /** @@ -97,9 +97,9 @@ export const getThirdPartyServiceClient = fiscalCode ) ? remoteContentConfiguration.test_environment - : remoteContentConfiguration.prod_environment ?? + : (remoteContentConfiguration.prod_environment ?? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - remoteContentConfiguration.test_environment!; + remoteContentConfiguration.test_environment!); eventLog.peek.info( remoteContentConfiguration.test_environment?.test_users.includes( @@ -107,11 +107,11 @@ export const getThirdPartyServiceClient = ) ? [ "Third party client pointing to test environment", - { name: "lollipop.third-party.test" }, + { name: "lollipop.third-party.test" } ] : [ "Third party client pointing to prod environment", - { name: "lollipop.third-party.prod" }, + { name: "lollipop.third-party.prod" } ] ); eventLog.peek.info( @@ -120,11 +120,11 @@ export const getThirdPartyServiceClient = ) ? [ "Fiscal code included in testUsers", - { name: "lollipop.testUsers.fiscal-code" }, + { name: "lollipop.testUsers.fiscal-code" } ] : [ "Fiscal code not included in testUsers", - { name: "lollipop.testUsers.fiscal-code" }, + { name: "lollipop.testUsers.fiscal-code" } ] ); @@ -146,7 +146,7 @@ export const getThirdPartyServiceClient = withDefaults: (op) => (params) => op({ ...params, - fiscal_code: fiscalCode, - }), + fiscal_code: fiscalCode + }) }); }; diff --git a/src/clients/trial-system.client.ts b/src/clients/trial-system.client.ts index 9ac586555..d29edd3d6 100644 --- a/src/clients/trial-system.client.ts +++ b/src/clients/trial-system.client.ts @@ -15,8 +15,8 @@ export function TrialSystemAPIClient( withDefaults: (op) => (params) => op({ ...params, - ApiKeyAuth: token, - }), + ApiKeyAuth: token + }) }); } diff --git a/src/config.ts b/src/config.ts index 15df9b910..ba0943939 100644 --- a/src/config.ts +++ b/src/config.ts @@ -15,7 +15,7 @@ import { HttpsUrlFromString, UrlFromString } from "@pagopa/ts-commons/lib/url"; import { AbortableFetch, setFetchTimeout, - toFetch, + toFetch } from "@pagopa/ts-commons/lib/fetch"; import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; @@ -39,7 +39,7 @@ import { IoSignAPIClient } from "./clients/io-sign"; import { FeatureFlag, FeatureFlagEnum, - getIsUserEligibleForNewFeature, + getIsUserEligibleForNewFeature } from "./utils/featureFlag"; import { CommaSeparatedListOf } from "./utils/separated-list"; import { LollipopApiClient } from "./clients/lollipop"; @@ -139,7 +139,7 @@ const bearerAuthFetch = (input, init) => origFetch(input, { ...init, - headers: { Authorization: `Bearer ${bearerToken}` }, + headers: { Authorization: `Bearer ${bearerToken}` } }); export const getHttpsApiFetchWithBearer = (bearer: string) => @@ -288,15 +288,15 @@ const IEnabledPnAddressBookConfig = t.interface({ PN_API_KEY: NonEmptyString, PN_API_KEY_UAT: NonEmptyString, PN_API_URL: UrlFromString, - PN_API_URL_UAT: UrlFromString, + PN_API_URL_UAT: UrlFromString }); type IEnabledPnAddressBookConfig = t.TypeOf; const IPNAddressBookConfig = t.union([ IEnabledPnAddressBookConfig, t.partial({ - FF_PN_ACTIVATION_ENABLED: t.literal("0"), - }), + FF_PN_ACTIVATION_ENABLED: t.literal("0") + }) ]); type IPNAddressBookConfig = t.TypeOf; @@ -452,13 +452,13 @@ export const PecServerConfig = t.interface({ basePath: t.string, secret: NonEmptyString, serviceId: NonEmptyString, - url: NonEmptyString, + url: NonEmptyString }); export type PecServerConfig = t.TypeOf; export const PecServersConfig = t.interface({ aruba: PecServerConfig, - poste: PecServerConfig, + poste: PecServerConfig }); export type PecServersConfig = t.TypeOf; diff --git a/src/controllers/authenticationController.ts b/src/controllers/authenticationController.ts index 3c4e949a2..deb5dfe14 100644 --- a/src/controllers/authenticationController.ts +++ b/src/controllers/authenticationController.ts @@ -11,7 +11,7 @@ import { IResponseErrorValidation, IResponseSuccessJson, ResponseErrorInternal, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { pipe } from "fp-ts/lib/function"; diff --git a/src/controllers/bonusController.ts b/src/controllers/bonusController.ts index d01995359..78d7743a4 100644 --- a/src/controllers/bonusController.ts +++ b/src/controllers/bonusController.ts @@ -10,7 +10,7 @@ import { IResponseErrorNotFound, IResponseErrorValidation, IResponseSuccessAccepted, - IResponseSuccessJson, + IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; @@ -87,4 +87,4 @@ export default class BonusController { withUserFromRequest(req, (user) => this.bonusService.getAllBonusActivations(user) ); -} \ No newline at end of file +} diff --git a/src/controllers/cgnController.ts b/src/controllers/cgnController.ts index 3901178fa..bcc7e033c 100644 --- a/src/controllers/cgnController.ts +++ b/src/controllers/cgnController.ts @@ -13,7 +13,7 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, IResponseSuccessRedirectToResource, - ResponseErrorForbiddenNotAuthorized, + ResponseErrorForbiddenNotAuthorized } from "@pagopa/ts-commons/lib/responses"; import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; diff --git a/src/controllers/cgnOperatorSearchController.ts b/src/controllers/cgnOperatorSearchController.ts index 59dac92ef..82717f191 100644 --- a/src/controllers/cgnOperatorSearchController.ts +++ b/src/controllers/cgnOperatorSearchController.ts @@ -12,7 +12,7 @@ import { IResponseErrorValidation, IResponseSuccessJson, ResponseErrorForbiddenNotAuthorized, - ResponseErrorInternal, + ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import CgnService from "src/services/cgnService"; @@ -94,9 +94,7 @@ export default class CgnOperatorSearchController { | IResponseErrorNotFound | IResponseSuccessJson > => - withUserFromRequest(req, async () => - this.cgnOperatorSearchService.count() - ); + withUserFromRequest(req, async () => this.cgnOperatorSearchService.count()); /** * Search CGN merchants/discounts that matches with search criteria diff --git a/src/controllers/eucovidcertController.ts b/src/controllers/eucovidcertController.ts index 35d0178eb..831b55799 100644 --- a/src/controllers/eucovidcertController.ts +++ b/src/controllers/eucovidcertController.ts @@ -5,7 +5,7 @@ import { IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, - IResponseSuccessJson, + IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; diff --git a/src/controllers/fimsController.ts b/src/controllers/fimsController.ts index a4d918191..52c1765cc 100644 --- a/src/controllers/fimsController.ts +++ b/src/controllers/fimsController.ts @@ -13,7 +13,7 @@ import { IResponseErrorValidation, IResponseSuccessAccepted, IResponseSuccessJson, - ResponseErrorInternal, + ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import { pipe } from "fp-ts/lib/function"; diff --git a/src/controllers/firstLollipopConsumerController.ts b/src/controllers/firstLollipopConsumerController.ts index b79dbe3e1..65c65164a 100644 --- a/src/controllers/firstLollipopConsumerController.ts +++ b/src/controllers/firstLollipopConsumerController.ts @@ -3,7 +3,7 @@ import { IResponseErrorValidation, IResponseSuccessJson, ResponseErrorInternal, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; import { flow, pipe } from "fp-ts/lib/function"; @@ -42,7 +42,7 @@ export const firstLollipopSign = TE.tryCatch( () => client.signMessage({ - ...localsWithBody, + ...localsWithBody }), () => ResponseErrorInternal("Error calling the Lollipop Consumer") ), diff --git a/src/controllers/ioSignController.ts b/src/controllers/ioSignController.ts index f8f531c99..2ad8ba607 100644 --- a/src/controllers/ioSignController.ts +++ b/src/controllers/ioSignController.ts @@ -16,7 +16,7 @@ import { IResponseSuccessJson, IResponseSuccessRedirectToResource, ResponseErrorInternal, - ResponseErrorValidation, + ResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import { pipe } from "fp-ts/lib/function"; @@ -25,11 +25,11 @@ import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { Errors } from "io-ts"; import { withValidatedOrValidationError, - withCatchAsInternalError, + withCatchAsInternalError } from "../utils/responses"; import { IssuerEnvironment, - IssuerEnvironmentEnum, + IssuerEnvironmentEnum } from "../../generated/io-sign/IssuerEnvironment"; import IoSignService from "../services/ioSignService"; import { ResLocals } from "../utils/express"; @@ -60,8 +60,8 @@ export const IoSignLollipopLocalsType = t.intersection([ LollipopLocalsType, t.type({ ["x-pagopa-lollipop-custom-sign-challenge"]: NonEmptyString, - ["x-pagopa-lollipop-custom-tos-challenge"]: NonEmptyString, - }), + ["x-pagopa-lollipop-custom-tos-challenge"]: NonEmptyString + }) ]); export type IoSignLollipopLocalsType = t.TypeOf< typeof IoSignLollipopLocalsType @@ -78,7 +78,7 @@ export const withIoSignCustomLollipopLocalsFromRequest = ["x-pagopa-lollipop-custom-sign-challenge"]: req.headers["x-pagopa-lollipop-custom-sign-challenge"], ["x-pagopa-lollipop-custom-tos-challenge"]: - req.headers["x-pagopa-lollipop-custom-tos-challenge"], + req.headers["x-pagopa-lollipop-custom-tos-challenge"] }, IoSignLollipopLocalsType.decode, E.mapLeft(responseErrorValidation) @@ -156,7 +156,7 @@ export default class IoSignController { "Error retrieving a user profile with validated email address" ) ) - ), + ) }), TE.map(({ userProfile, signerId }) => this.ioSignService.createFilledDocument( @@ -208,7 +208,7 @@ export default class IoSignController { "Error retrieving a user profile with validated email address" ) ) - ), + ) }), TE.chainW(({ signerId, userProfile }) => pipe( @@ -219,9 +219,9 @@ export default class IoSignController { TE.map((signatureBody) => ({ body: { ...signatureBody, - email: userProfile.email, + email: userProfile.email }, - signerId: signerId.value.id, + signerId: signerId.value.id })) ) ), @@ -264,7 +264,7 @@ export default class IoSignController { retrieveSignerId(this.ioSignService, user.fiscal_code), TE.mapLeft(() => toErrorRetrievingTheSignerId), TE.map((response) => response.value.id) - ), + ) }), TE.map(({ signerId, signatureRequestId: id }) => this.ioSignService.getSignatureRequest(id, signerId) diff --git a/src/controllers/ioWalletController.ts b/src/controllers/ioWalletController.ts index a0c64bdb0..30afd0718 100644 --- a/src/controllers/ioWalletController.ts +++ b/src/controllers/ioWalletController.ts @@ -17,7 +17,7 @@ import { IResponseErrorValidation, IResponseSuccessJson, IResponseSuccessNoContent, - ResponseErrorValidation, + ResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import { pipe } from "fp-ts/lib/function"; @@ -152,7 +152,7 @@ export default class IoWalletController { id: pipe( NonEmptyString.decode(req.params.walletInstanceId), E.mapLeft(toValidationError) - ), + ) }), TE.fromEither ) diff --git a/src/controllers/messagesController.ts b/src/controllers/messagesController.ts index cc9cfddd2..29e661f88 100644 --- a/src/controllers/messagesController.ts +++ b/src/controllers/messagesController.ts @@ -12,13 +12,13 @@ import { IResponseErrorTooManyRequests, IResponseErrorValidation, IResponseSuccessJson, - IResponseSuccessNoContent, + IResponseSuccessNoContent } from "@pagopa/ts-commons/lib/responses"; import { CreatedMessageWithContentAndAttachments } from "generated/backend/CreatedMessageWithContentAndAttachments"; import { IResponseErrorForbiddenNotAuthorized, - ResponseErrorInternal, + ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import * as t from "io-ts"; import { pipe } from "fp-ts/lib/function"; @@ -42,7 +42,7 @@ import { withValidatedOrValidationError, IResponseSuccessOctet, IResponseErrorNotImplemented, - IResponseErrorUnsupportedMediaType, + IResponseErrorUnsupportedMediaType } from "../utils/responses"; import { LollipopLocalsType, LollipopRequiredHeaders } from "../types/lollipop"; import { LollipopApiClient } from "../clients/lollipop"; @@ -93,7 +93,7 @@ export default class MessagesController { enrichResultData: req.query.enrich_result_data, getArchivedMessages: req.query.archived, maximumId: req.query.maximum_id, - minimumId: req.query.minimum_id, + minimumId: req.query.minimum_id /* eslint-enable sort-keys */ }), (params) => this.messageService.getMessagesByUser(user, params) @@ -116,7 +116,7 @@ export default class MessagesController { withValidatedOrValidationError( GetMessageParameters.decode({ id: req.params.id, - public_message: req.query.public_message, + public_message: req.query.public_message }), (params) => this.messageService.getMessage(user, params) ) diff --git a/src/controllers/notificationController.ts b/src/controllers/notificationController.ts index 9241ad7bc..57ee81d24 100644 --- a/src/controllers/notificationController.ts +++ b/src/controllers/notificationController.ts @@ -7,7 +7,7 @@ import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/lib/Either"; @@ -26,7 +26,7 @@ import { withUserFromRequest } from "../types/user"; import { log } from "../utils/logger"; import { withCatchAsInternalError, - withValidatedOrValidationError, + withValidatedOrValidationError } from "../utils/responses"; const delay = (ms: Millisecond) => new Promise((ok) => setTimeout(ok, ms)); @@ -92,33 +92,31 @@ export default class NotificationController { req: express.Request ): Promise> { return withUserFromRequest(req, async (user) => - withValidatedOrValidationError( - InstallationID.decode(req.params.id), - () => - withValidatedOrValidationError( - Installation.decode(req.body), - (installation) => { - // async fire & forget - // On login, we do a deleteInstallation to prevent a device to be associated with a previous user, which might be a different one - // We have empirical evidence that such deleteInstallation is processed after the createOrUpdateInstallation, - // so that the installation we are recording after login is lost - // The correct order of execution must be enforced by the processing notifications service. - // Anyway, to quickly mitigate the disservice to our users, we apply this temporary workaround - delay(10000 as Millisecond) - .then(() => - this.notificationServiceFactory( - user.fiscal_code - ).createOrUpdateInstallation(user.fiscal_code, installation) - ) - .catch((err) => { - log.error( - "Cannot create installation: %s", - JSON.stringify(err) - ); - }); - return ResponseSuccessJson({ message: "ok" }); - } - ) + withValidatedOrValidationError(InstallationID.decode(req.params.id), () => + withValidatedOrValidationError( + Installation.decode(req.body), + (installation) => { + // async fire & forget + // On login, we do a deleteInstallation to prevent a device to be associated with a previous user, which might be a different one + // We have empirical evidence that such deleteInstallation is processed after the createOrUpdateInstallation, + // so that the installation we are recording after login is lost + // The correct order of execution must be enforced by the processing notifications service. + // Anyway, to quickly mitigate the disservice to our users, we apply this temporary workaround + delay(10000 as Millisecond) + .then(() => + this.notificationServiceFactory( + user.fiscal_code + ).createOrUpdateInstallation(user.fiscal_code, installation) + ) + .catch((err) => { + log.error( + "Cannot create installation: %s", + JSON.stringify(err) + ); + }); + return ResponseSuccessJson({ message: "ok" }); + } + ) ) ); } diff --git a/src/controllers/pagoPAProxyController.ts b/src/controllers/pagoPAProxyController.ts index 2de10c2bb..aca6252dd 100644 --- a/src/controllers/pagoPAProxyController.ts +++ b/src/controllers/pagoPAProxyController.ts @@ -4,7 +4,7 @@ import { IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, - IResponseSuccessJson, + IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import PagoPAProxyService from "../services/pagoPAProxyService"; diff --git a/src/controllers/pnController.ts b/src/controllers/pnController.ts index 6d73c0a1f..29668aaa0 100644 --- a/src/controllers/pnController.ts +++ b/src/controllers/pnController.ts @@ -3,7 +3,7 @@ import { IResponseErrorValidation, IResponseSuccessJson, ResponseErrorInternal, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; import * as TE from "fp-ts/TaskEither"; @@ -15,7 +15,7 @@ import { withUserFromRequest } from "../types/user"; import { IResponseNoContent, ResponseNoContent, - withValidatedOrValidationError, + withValidatedOrValidationError } from "../utils/responses"; import { PNActivation } from "../../generated/api_piattaforma-notifiche-courtesy/PNActivation"; import { PNService } from "../services/pnService"; @@ -46,7 +46,7 @@ export const upsertPNActivationController = TE.tryCatch( () => upsertPnActivation(pnEnvironment, user.fiscal_code, { - activationStatus: payload.activation_status, + activationStatus: payload.activation_status }), () => ResponseErrorInternal("Error calling the PN service") ), @@ -109,13 +109,13 @@ export const getPNActivationController = switch (pnActivationResponse.status) { case 200: return ResponseSuccessJson({ - activation_status: pnActivationResponse.value.activationStatus, + activation_status: pnActivationResponse.value.activationStatus }); case 404: // When the activation is missing on PN // false default value was returned. return ResponseSuccessJson({ - activation_status: false, + activation_status: false }); case 400: return ResponseErrorInternal( diff --git a/src/controllers/profileController.ts b/src/controllers/profileController.ts index d579b7701..5d78ab1dc 100644 --- a/src/controllers/profileController.ts +++ b/src/controllers/profileController.ts @@ -12,7 +12,7 @@ import { IResponseErrorTooManyRequests, IResponseErrorValidation, IResponseSuccessAccepted, - IResponseSuccessJson, + IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { ISessionStorage } from "src/services/ISessionStorage"; diff --git a/src/controllers/serviceAppBackendController.ts b/src/controllers/serviceAppBackendController.ts index 6c0d17f85..14271400f 100644 --- a/src/controllers/serviceAppBackendController.ts +++ b/src/controllers/serviceAppBackendController.ts @@ -2,7 +2,7 @@ import { IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, - IResponseSuccessJson, + IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; @@ -18,7 +18,7 @@ import { ServiceDetails } from "../../generated/services-app-backend/ServiceDeta import ServicesAppBackendService from "../services/servicesAppBackendService"; import { withValidatedOrInternalError, - withValidatedOrValidationError, + withValidatedOrValidationError } from "../utils/responses"; const parseOptionalStringParam = (stringParam?: unknown) => diff --git a/src/controllers/servicesController.ts b/src/controllers/servicesController.ts index 1697bab35..684d93c79 100644 --- a/src/controllers/servicesController.ts +++ b/src/controllers/servicesController.ts @@ -9,7 +9,7 @@ import { IResponseErrorNotFound, IResponseErrorTooManyRequests, IResponseErrorValidation, - IResponseSuccessJson, + IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; diff --git a/src/controllers/sessionController.ts b/src/controllers/sessionController.ts index a749bd119..89a73a801 100644 --- a/src/controllers/sessionController.ts +++ b/src/controllers/sessionController.ts @@ -8,7 +8,7 @@ import { IResponseErrorValidation, IResponseSuccessJson, ResponseErrorInternal, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/lib/Either"; import { SessionsList } from "../../generated/backend/SessionsList"; diff --git a/src/controllers/sessionLockController.ts b/src/controllers/sessionLockController.ts index 179a5d1c1..58b79aa7e 100644 --- a/src/controllers/sessionLockController.ts +++ b/src/controllers/sessionLockController.ts @@ -13,7 +13,7 @@ import { ResponseErrorForbiddenNotAuthorized, ResponseErrorInternal, ResponseErrorValidation, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/lib/Either"; import * as AP from "fp-ts/lib/Apply"; @@ -30,7 +30,7 @@ import { addSeconds } from "date-fns"; import { IResponseNoContent, ResponseNoContent, - withValidatedOrValidationError, + withValidatedOrValidationError } from "../utils/responses"; import { SuccessResponse } from "../types/commons"; import LollipopService from "../services/lollipopService"; @@ -38,7 +38,7 @@ import { withFiscalCodeFromRequestParams } from "../types/fiscalCode"; import RedisSessionStorage from "../services/redisSessionStorage"; import RedisUserMetadataStorage from "../services/redisUserMetadataStorage"; import AuthenticationLockService, { - NotReleasedAuthenticationLockData, + NotReleasedAuthenticationLockData } from "../services/authenticationLockService"; import { NotificationServiceFactory } from "../services/notificationServiceFactory"; @@ -341,13 +341,13 @@ export default class SessionLockController { `Error reading the session info: [${err.message}]` ) ) - ), + ) }), TE.map(({ isUserAuthenticationLocked, maybeSessionRemaningTTL }) => O.isNone(maybeSessionRemaningTTL) ? SessionState.encode({ access_enabled: !isUserAuthenticationLocked, - session_info: { active: false }, + session_info: { active: false } }) : SessionState.encode({ access_enabled: !isUserAuthenticationLocked, @@ -357,8 +357,8 @@ export default class SessionLockController { new Date(), maybeSessionRemaningTTL.value.ttl ), - type: LoginTypeEnum[maybeSessionRemaningTTL.value.type], - }, + type: LoginTypeEnum[maybeSessionRemaningTTL.value.type] + } }) ), TE.map(ResponseSuccessJson), @@ -416,7 +416,7 @@ export default class SessionLockController { E.toError ), TE.chain(TE.fromEither) - ), + ) ] as const; private readonly clearInstallation = (fiscalCode: FiscalCode) => diff --git a/src/controllers/ssoController.ts b/src/controllers/ssoController.ts index 26fdc8642..7ffc5e02d 100644 --- a/src/controllers/ssoController.ts +++ b/src/controllers/ssoController.ts @@ -6,7 +6,7 @@ import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { MyPortalUser } from "../../generated/myportal/MyPortalUser"; import { withUserFromRequest } from "../types/user"; @@ -28,7 +28,7 @@ export const getUserForMyPortal = ( MyPortalUser.decode({ family_name: user.family_name, fiscal_code: user.fiscal_code, - name: user.name, + name: user.name }), (_) => ResponseSuccessJson(_) ) diff --git a/src/controllers/trialController.ts b/src/controllers/trialController.ts index 273a4e773..58fb447d3 100644 --- a/src/controllers/trialController.ts +++ b/src/controllers/trialController.ts @@ -12,14 +12,14 @@ import { IResponseSuccessAccepted, IResponseSuccessJson, IResponseSuccessRedirectToResource, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import TrialService from "src/services/trialService"; import { FF_IO_WALLET_TRIAL_ENABLED, - IO_WALLET_TRIAL_ID, + IO_WALLET_TRIAL_ID } from "../../src/config"; import { TrialId } from "../../generated/trial-system-api/TrialId"; import { withUserFromRequest } from "../types/user"; @@ -75,7 +75,7 @@ export default class TrialController { ResponseSuccessJson({ createdAt: new Date(), state: SubscriptionStateEnum.ACTIVE, - trialId, + trialId }) ) ) diff --git a/src/controllers/userDataProcessingController.ts b/src/controllers/userDataProcessingController.ts index d088bb567..87ffd305f 100644 --- a/src/controllers/userDataProcessingController.ts +++ b/src/controllers/userDataProcessingController.ts @@ -11,7 +11,7 @@ import { IResponseErrorTooManyRequests, IResponseErrorValidation, IResponseSuccessAccepted, - IResponseSuccessJson, + IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { UserDataProcessing } from "../../generated/backend/UserDataProcessing"; diff --git a/src/controllers/userMetadataController.ts b/src/controllers/userMetadataController.ts index 979e433b3..f4be0b463 100644 --- a/src/controllers/userMetadataController.ts +++ b/src/controllers/userMetadataController.ts @@ -11,7 +11,7 @@ import { IResponseSuccessJson, ResponseErrorConflict, ResponseErrorInternal, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/lib/Either"; @@ -21,7 +21,7 @@ import { UserMetadata } from "../../generated/backend/UserMetadata"; import { IUserMetadataStorage } from "../services/IUserMetadataStorage"; import { invalidVersionNumberError, - metadataNotFoundError, + metadataNotFoundError } from "../services/redisUserMetadataStorage"; import { withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; diff --git a/src/server.ts b/src/server.ts index 367afa497..f024d9caa 100644 --- a/src/server.ts +++ b/src/server.ts @@ -31,12 +31,12 @@ import { MYPORTAL_BASE_PATH, SERVER_PORT, SERVICES_APP_BACKEND_BASE_PATH, - TRIAL_SYSTEM_API_BASE_PATH, + TRIAL_SYSTEM_API_BASE_PATH } from "./config"; import { initAppInsights, StartupEventName, - trackStartupTime, + trackStartupTime } from "./utils/appinsights"; import { initHttpGracefulShutdown } from "./utils/gracefulShutdown"; @@ -88,14 +88,14 @@ const maybeAppInsightsClient = pipe( disableAppInsights: process.env.APPINSIGHTS_DISABLED === "true", samplingPercentage: process.env.APPINSIGHTS_SAMPLING_PERCENTAGE ? parseInt(process.env.APPINSIGHTS_SAMPLING_PERCENTAGE, 10) - : DEFAULT_APPINSIGHTS_SAMPLING_PERCENTAGE, + : DEFAULT_APPINSIGHTS_SAMPLING_PERCENTAGE }) ), O.chainFirst((telemetryClient) => O.some( useWinstonFor({ loggerId: LoggerId.event, - transports: [withApplicationInsight(telemetryClient, "io-backend")], + transports: [withApplicationInsight(telemetryClient, "io-backend")] }) ) ) @@ -118,7 +118,7 @@ newApp({ allowSessionHandleIPSourceRange: ALLOW_SESSION_HANDLER_IP_SOURCE_RANGE, appInsightsClient: O.toUndefined(maybeAppInsightsClient), authenticationBasePath, - env: ENV, + env: ENV }) .then((app) => { const startupTimeMs = timer.getElapsedMilliseconds(); @@ -178,7 +178,7 @@ newApp({ log.info("Server graceful shutdown complete."); }, signals: shutdownSignals, - timeout: shutdownTimeout, + timeout: shutdownTimeout }); }) .catch((err) => { diff --git a/src/services/IPagoPAClientFactory.ts b/src/services/IPagoPAClientFactory.ts index a70a6f353..214c7941b 100644 --- a/src/services/IPagoPAClientFactory.ts +++ b/src/services/IPagoPAClientFactory.ts @@ -5,7 +5,7 @@ import { PagoPAClient } from "../clients/pagopa"; export enum PagoPAEnvironment { PRODUCTION = "PRODUCTION", - TEST = "TEST", + TEST = "TEST" } export interface IPagoPAClientFactoryInterface { diff --git a/src/services/authenticationLockService.ts b/src/services/authenticationLockService.ts index 1f1442695..62b575545 100644 --- a/src/services/authenticationLockService.ts +++ b/src/services/authenticationLockService.ts @@ -28,7 +28,7 @@ const NotReleasedAuthenticationLockData = t.type({ rowKey: UnlockCode, // eslint-disable-next-line sort-keys - CreatedAt: DateFromString, + CreatedAt: DateFromString }); export default class AuthenticationLockService { @@ -75,7 +75,7 @@ export default class AuthenticationLockService { rowKey: unlockCode, // eslint-disable-next-line sort-keys - CreatedAt: new Date(), + CreatedAt: new Date() }), () => new Error("Something went wrong creating the record") ), @@ -103,8 +103,8 @@ export default class AuthenticationLockService { partitionKey: fiscalCode, rowKey: unlockCode, // eslint-disable-next-line sort-keys - Released: true, - }, + Released: true + } ] as TransactionAction ), (actions) => @@ -128,8 +128,8 @@ export default class AuthenticationLockService { pipe( this.tableClient.listEntities({ queryOptions: { - filter: odata`PartitionKey eq ${fiscalCode} and not Released`, - }, + filter: odata`PartitionKey eq ${fiscalCode} and not Released` + } }), AI.fromAsyncIterable, AI.foldTaskEither(E.toError), diff --git a/src/services/bonusService.ts b/src/services/bonusService.ts index b839ebe79..c4a1c3c7f 100644 --- a/src/services/bonusService.ts +++ b/src/services/bonusService.ts @@ -12,7 +12,7 @@ import { ResponseErrorInternal, ResponseErrorNotFound, ResponseSuccessAccepted, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as TE from "fp-ts/lib/TaskEither"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; @@ -29,7 +29,7 @@ import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { readableProblem } from "../utils/errorsFormatter"; @@ -50,7 +50,7 @@ export default class BonusService { > => withCatchAsInternalError(async () => { const validated = await this.bonusApiClient.getBonusEligibilityCheck({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -91,7 +91,7 @@ export default class BonusService { withCatchAsInternalError(async () => { const validated = await this.bonusApiClient.getLatestBonusActivationById({ bonus_id: bonusId, - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { diff --git a/src/services/cgnOperatorSearchService.ts b/src/services/cgnOperatorSearchService.ts index 195131dd4..d5d4b2967 100644 --- a/src/services/cgnOperatorSearchService.ts +++ b/src/services/cgnOperatorSearchService.ts @@ -9,7 +9,7 @@ import { ProblemJson, ResponseErrorInternal, ResponseErrorNotFound, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; @@ -24,7 +24,7 @@ import { Merchant } from "../../generated/cgn-operator-search/Merchant"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { readableProblem } from "../utils/errorsFormatter"; import { CgnOperatorSearchAPIClient } from "../../src/clients/cgn-operator-search"; @@ -76,7 +76,7 @@ export default class CgnService { ): Promise> => withCatchAsInternalError(async () => { const validated = await this.cgnOperatorSearchApiClient.getMerchant({ - merchantId, + merchantId }); return withValidatedOrInternalError(validated, (response) => @@ -104,7 +104,7 @@ export default class CgnService { ): Promise> => withCatchAsInternalError(async () => { const validated = await this.cgnOperatorSearchApiClient.search({ - body: searchRequest, + body: searchRequest }); return withValidatedOrInternalError(validated, (response) => @@ -124,7 +124,7 @@ export default class CgnService { withCatchAsInternalError(async () => { const validated = await this.cgnOperatorSearchApiClient.getOnlineMerchants({ - body: onlineMerchantSearchRequest, + body: onlineMerchantSearchRequest }); return withValidatedOrInternalError(validated, (response) => @@ -144,7 +144,7 @@ export default class CgnService { withCatchAsInternalError(async () => { const validated = await this.cgnOperatorSearchApiClient.getOfflineMerchants({ - body: offlineMerchantSearchRequest, + body: offlineMerchantSearchRequest }); return withValidatedOrInternalError(validated, (response) => @@ -163,7 +163,7 @@ export default class CgnService { withCatchAsInternalError(async () => { const validated = await this.cgnOperatorSearchApiClient.getDiscountBucketCode({ - discountId, + discountId }); return withValidatedOrInternalError(validated, (response) => diff --git a/src/services/cgnService.ts b/src/services/cgnService.ts index 07ef65ea1..70d8f97f7 100644 --- a/src/services/cgnService.ts +++ b/src/services/cgnService.ts @@ -17,7 +17,7 @@ import { ResponseErrorNotFound, ResponseSuccessAccepted, ResponseSuccessJson, - ResponseSuccessRedirectToResource, + ResponseSuccessRedirectToResource } from "@pagopa/ts-commons/lib/responses"; import * as O from "fp-ts/lib/Option"; @@ -34,7 +34,7 @@ import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { readableProblem } from "../utils/errorsFormatter"; export default class CgnService { @@ -54,7 +54,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.getCgnStatus({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -88,7 +88,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.getEycaStatus({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -128,7 +128,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.startCgnActivation({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -174,7 +174,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.getCgnActivation({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -211,7 +211,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.startEycaActivation({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -257,7 +257,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.getEycaActivation({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -294,7 +294,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.startCgnUnsubscription({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -340,7 +340,7 @@ export default class CgnService { > => withCatchAsInternalError(async () => { const validated = await this.cgnApiClient.generateOtp({ - fiscalcode: user.fiscal_code, + fiscalcode: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { diff --git a/src/services/eucovidcertService.ts b/src/services/eucovidcertService.ts index 2cacaaa5c..c324d4386 100644 --- a/src/services/eucovidcertService.ts +++ b/src/services/eucovidcertService.ts @@ -8,7 +8,7 @@ import { ResponseErrorGeneric, ResponseErrorInternal, ResponseErrorValidation, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; @@ -20,7 +20,7 @@ import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { User } from "../types/user"; @@ -36,7 +36,7 @@ export function ResponseGatewayTimeout(detail: string): IResponseErrorInternal { "Gateway Timeout", detail ), - kind: "IResponseErrorInternal", + kind: "IResponseErrorInternal" }; } @@ -54,7 +54,7 @@ export function ResponseErrorNotFound403( "Not Found", detail ), - kind: "IResponseErrorNotFound", + kind: "IResponseErrorNotFound" }; } @@ -82,8 +82,8 @@ export default class EUCovidCertService { accessData: { auth_code, fiscal_code: user.fiscal_code, - preferred_languages, - }, + preferred_languages + } }); return withValidatedOrInternalError(validated, (response) => { diff --git a/src/services/fimsService.ts b/src/services/fimsService.ts index b070a848b..4745e8974 100644 --- a/src/services/fimsService.ts +++ b/src/services/fimsService.ts @@ -12,7 +12,7 @@ import { ResponseErrorInternal, ResponseErrorValidation, ResponseSuccessAccepted, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; @@ -25,7 +25,7 @@ import { IoFimsAPIClient } from "../clients/io-fims"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; const invalidRequest = "Invalid request"; @@ -44,7 +44,7 @@ export default class FimsService { withCatchAsInternalError(async () => { const validated = await this.ioFimsApiClient.getAccessHistory({ page, - user: fiscalCode, + user: fiscalCode }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -77,9 +77,9 @@ export default class FimsService { withCatchAsInternalError(async () => { const validated = await this.ioFimsApiClient.requestExport({ body: { - email, + email }, - user: fiscalCode, + user: fiscalCode }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index cf9cf96e4..468c39e15 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -13,7 +13,7 @@ import { ResponseErrorNotFound, ResponseErrorTooManyRequests, ResponseErrorValidation, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/Either"; @@ -31,13 +31,12 @@ import { ResponseErrorUnexpectedAuthProblem, unhandledResponseStatus, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { IApiClientFactoryInterface } from "./IApiClientFactory"; -type RightOf> = T extends E.Right - ? R - : never; +type RightOf> = + T extends E.Right ? R : never; const handleGetServicePreferencesResponse = ( response: RightOf< @@ -85,7 +84,7 @@ export default class FunctionsAppService { const client = this.apiClient.getClient(); const validated = await client.getService({ - service_id: serviceId, + service_id: serviceId }); return withValidatedOrInternalError(validated, (response) => @@ -95,10 +94,10 @@ export default class FunctionsAppService { ResponseSuccessJson ) : response.status === 404 - ? ResponseErrorNotFound("Not found", "Service not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound("Not found", "Service not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); @@ -121,7 +120,7 @@ export default class FunctionsAppService { const validated = await client.getServicePreferences({ fiscal_code: fiscalCode, - service_id: serviceId, + service_id: serviceId }); return withValidatedOrInternalError( @@ -151,7 +150,7 @@ export default class FunctionsAppService { const validated = await client.upsertServicePreferences({ body: servicePreferences, fiscal_code: fiscalCode, - service_id: serviceId, + service_id: serviceId }); return withValidatedOrInternalError( diff --git a/src/services/ioSignService.ts b/src/services/ioSignService.ts index 4667a58e5..ad11a336a 100644 --- a/src/services/ioSignService.ts +++ b/src/services/ioSignService.ts @@ -14,7 +14,7 @@ import { ResponseErrorNotFound, ResponseErrorValidation, ResponseSuccessJson, - ResponseSuccessRedirectToResource, + ResponseSuccessRedirectToResource } from "@pagopa/ts-commons/lib/responses"; import * as O from "fp-ts/lib/Option"; @@ -25,7 +25,7 @@ import * as t from "io-ts"; import { EmailString, FiscalCode, - NonEmptyString, + NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as E from "fp-ts/Either"; import { CreateSignatureBody as CreateSignatureBodyApiModel } from "../../generated/io-sign-api/CreateSignatureBody"; @@ -43,7 +43,7 @@ import { IoSignAPIClient } from "../clients/io-sign"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { readableProblem } from "../utils/errorsFormatter"; import { IoSignLollipopLocalsType } from "../controllers/ioSignController"; @@ -82,7 +82,7 @@ export default class IoSignService { > => withCatchAsInternalError(async () => { const validated = await this.ioSignApiClient.getSignerByFiscalCode({ - body: { fiscal_code: fiscalCode }, + body: { fiscal_code: fiscalCode } }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -126,9 +126,9 @@ export default class IoSignService { document_url, email, family_name, - name, + name }, - "x-iosign-signer-id": signerId, + "x-iosign-signer-id": signerId }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -176,7 +176,7 @@ export default class IoSignService { > => withCatchAsInternalError(async () => { const validated = await this.ioSignApiClient.getQtspClausesMetadata({ - "x-iosign-issuer-environment": issuerEnvironment, + "x-iosign-issuer-environment": issuerEnvironment }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -216,7 +216,7 @@ export default class IoSignService { const validated = await this.ioSignApiClient.createSignature({ ...ioSignLollipopLocals, body, - "x-iosign-signer-id": signerId, + "x-iosign-signer-id": signerId }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -263,7 +263,7 @@ export default class IoSignService { withCatchAsInternalError(async () => { const validated = await this.ioSignApiClient.getSignatureRequestById({ id: signatureRequestId, - "x-iosign-signer-id": signerId, + "x-iosign-signer-id": signerId }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -278,7 +278,7 @@ export default class IoSignService { ) .json(response.value), kind: "IResponseSuccessJson", - value: response.value, + value: response.value }; case 404: return ResponseErrorNotFound( @@ -305,7 +305,7 @@ export default class IoSignService { > => withCatchAsInternalError(async () => { const validated = await this.ioSignApiClient.getSignatureRequests({ - "x-iosign-signer-id": signerId, + "x-iosign-signer-id": signerId }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { diff --git a/src/services/ioWalletService.ts b/src/services/ioWalletService.ts index 05e766047..e0109fc01 100644 --- a/src/services/ioWalletService.ts +++ b/src/services/ioWalletService.ts @@ -16,7 +16,7 @@ import { ResponseErrorNotFound, ResponseErrorServiceTemporarilyUnavailable, ResponseSuccessJson, - ResponseSuccessNoContent, + ResponseSuccessNoContent } from "@pagopa/ts-commons/lib/responses"; import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; @@ -28,7 +28,7 @@ import { IoWalletAPIClient } from "../clients/io-wallet"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { IO_WALLET_TRIAL_ID } from "../config"; import { TrialSystemAPIClient } from "../clients/trial-system.client"; @@ -103,8 +103,8 @@ export default class IoWalletService { challenge, fiscal_code, hardware_key_tag, - key_attestation, - }, + key_attestation + } }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -157,8 +157,8 @@ export default class IoWalletService { body: { assertion, fiscal_code, - grant_type, - }, + grant_type + } }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -215,7 +215,7 @@ export default class IoWalletService { withCatchAsInternalError(async () => { const validated = await this.ioWalletApiClient.setWalletInstanceStatus({ body: { fiscal_code, status }, - id, + id }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -253,7 +253,7 @@ export default class IoWalletService { withCatchAsInternalError(async () => { const validated = await this.ioWalletApiClient.setCurrentWalletInstanceStatus({ - body: { fiscal_code, status }, + body: { fiscal_code, status } }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -295,7 +295,7 @@ export default class IoWalletService { withCatchAsInternalError(async () => { const validated = await this.ioWalletApiClient.getWalletInstanceStatus({ "fiscal-code": fiscal_code, - id, + id }); return withValidatedOrInternalError(validated, (response) => { switch (response.status) { @@ -336,7 +336,7 @@ export default class IoWalletService { withCatchAsInternalError(async () => { const validated = await this.trialSystemApiClient.getSubscription({ trialId: IO_WALLET_TRIAL_ID, - userId, + userId }); return withValidatedOrInternalError(validated, (response) => { @@ -345,7 +345,7 @@ export default class IoWalletService { return pipe( { createdAt: response.value.createdAt, - state: response.value.state, + state: response.value.state }, ResponseSuccessJson ); diff --git a/src/services/lollipopService.ts b/src/services/lollipopService.ts index d956d4370..1cf148deb 100644 --- a/src/services/lollipopService.ts +++ b/src/services/lollipopService.ts @@ -26,7 +26,7 @@ export default class LollipopService { assertionRef: AssertionRef ): Promise { const revokeMessage = RevokeAssertionRefInfo.encode({ - assertion_ref: assertionRef, + assertion_ref: assertionRef }); return this.queueClient.sendMessage(base64EncodeObject(revokeMessage)); } diff --git a/src/services/newMessagesService.ts b/src/services/newMessagesService.ts index fbe8b41b8..181c6af06 100644 --- a/src/services/newMessagesService.ts +++ b/src/services/newMessagesService.ts @@ -20,13 +20,13 @@ import { ResponseErrorServiceTemporarilyUnavailable, IResponseSuccessNoContent, ResponseErrorBadGateway, - IResponseErrorBadGateway, + IResponseErrorBadGateway } from "@pagopa/ts-commons/lib/responses"; import { AppMessagesAPIClient } from "src/clients/app-messages.client"; import { FiscalCode, NonEmptyString, - Ulid, + Ulid } from "@pagopa/ts-commons/lib/strings"; import { pipe, flow } from "fp-ts/lib/function"; import * as TE from "fp-ts/TaskEither"; @@ -37,7 +37,7 @@ import { LollipopLocalsType } from "src/types/lollipop"; import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; import { Fetch, - getThirdPartyServiceClient, + getThirdPartyServiceClient } from "../clients/third-party-service-client"; import { PN_SERVICE_ID } from "../config"; import { MessageSubject } from "../../generated/backend/MessageSubject"; @@ -61,13 +61,13 @@ import { unhandledResponseStatus, withCatchAsInternalError, withValidatedOrInternalError, - wrapValidationWithInternalError, + wrapValidationWithInternalError } from "../utils/responses"; import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; import { ThirdPartyMessage, - ThirdPartyMessageDetails, + ThirdPartyMessageDetails } from "../../generated/third-party-service/ThirdPartyMessage"; import { ThirdPartyData } from "../../generated/backend/ThirdPartyData"; import { log } from "../utils/logger"; @@ -83,7 +83,7 @@ const ERROR_MESSAGE_400 = "Bad request"; export const MessageWithThirdPartyData = t.intersection([ CreatedMessageWithContent, - t.interface({ content: t.interface({ third_party_data: ThirdPartyData }) }), + t.interface({ content: t.interface({ third_party_data: ThirdPartyData }) }) ]); export type MessageWithThirdPartyData = t.TypeOf< typeof MessageWithThirdPartyData @@ -119,7 +119,7 @@ export default class NewMessagesService { enrich_result_data: params.enrichResultData, archived: params.getArchivedMessages, maximum_id: params.maximumId, - minimum_id: params.minimumId, + minimum_id: params.minimumId /* eslint-enable sort-keys */ }); @@ -127,10 +127,10 @@ export default class NewMessagesService { response.status === 200 ? ResponseSuccessJson(response.value) : response.status === 404 - ? ResponseErrorNotFound("Not found", "User not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound("Not found", "User not found") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); @@ -150,7 +150,7 @@ export default class NewMessagesService { const res = await this.apiClient.getMessage({ fiscal_code: user.fiscal_code, id: params.id, - public_message: params.public_message, + public_message: params.public_message }); const resMessageContent = pipe( @@ -175,8 +175,8 @@ export default class NewMessagesService { ...messageWithContent, content: { ...messageWithContent.content, - attachments, - }, + attachments + } })), T.map(ResponseSuccessJson) )(); @@ -185,8 +185,8 @@ export default class NewMessagesService { return response.status === 404 ? ResponseErrorNotFound("Not found", "Message not found") : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status); + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status); } ); }); @@ -210,7 +210,7 @@ export default class NewMessagesService { const validated = await this.apiClient.upsertMessageStatusAttributes({ body: messageStatusChange, fiscal_code: fiscalCode, - id: messageId, + id: messageId }); return withValidatedOrInternalError(validated, (response) => { @@ -218,7 +218,7 @@ export default class NewMessagesService { case 200: return ResponseSuccessJson({ is_archived: response.value.is_archived, - is_read: response.value.is_read, + is_read: response.value.is_read }); case 401: return ResponseErrorUnexpectedAuthProblem(); @@ -292,7 +292,7 @@ export default class NewMessagesService { ), TE.map((thirdPartyMessage) => ({ ...message, - third_party_message: thirdPartyMessage, + third_party_message: thirdPartyMessage })) ), TE.map(ResponseSuccessJson), @@ -351,7 +351,7 @@ export default class NewMessagesService { () => this.apiClient.getMessage({ fiscal_code: fiscalCode, - id: messageId, + id: messageId }), (e) => ResponseErrorInternal(E.toError(e).message) ), @@ -413,7 +413,7 @@ export default class NewMessagesService { TE.tryCatch( () => this.apiClient.getRCConfiguration({ - id: configurationId, + id: configurationId }), (e) => ResponseErrorInternal(E.toError(e).message) ), @@ -487,7 +487,7 @@ export default class NewMessagesService { () => client.getThirdPartyMessagePrecondition({ id: message.content.third_party_data.id, - ...lollipopLocals, + ...lollipopLocals }), (e) => ResponseErrorInternal(E.toError(e).message) ) @@ -568,7 +568,7 @@ export default class NewMessagesService { () => client.getThirdPartyMessageDetails({ id: message.content.third_party_data.id, - ...lollipopLocals, + ...lollipopLocals }), (e) => ResponseErrorInternal(E.toError(e).message) ) @@ -679,8 +679,8 @@ export default class NewMessagesService { : { ...response.details, markdown: message.content.markdown, - subject: message.content.subject, - }, + subject: message.content.subject + } }); }; @@ -716,7 +716,7 @@ export default class NewMessagesService { client.getThirdPartyMessageAttachment({ attachment_url: attachmentUrl, id: message.content.third_party_data.id, - ...lollipopLocals, + ...lollipopLocals }), (e) => ResponseErrorInternal(E.toError(e).message) ) diff --git a/src/services/notificationService.ts b/src/services/notificationService.ts index 17ac89318..22cb01e20 100644 --- a/src/services/notificationService.ts +++ b/src/services/notificationService.ts @@ -6,7 +6,7 @@ import { IResponseErrorInternal, IResponseSuccessJson, ResponseErrorInternal, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { QueueClient } from "@azure/storage-queue"; @@ -16,16 +16,16 @@ import { FiscalCode } from "../../generated/backend/FiscalCode"; import { Installation } from "../../generated/backend/Installation"; import { CreateOrUpdateInstallationMessage, - KindEnum as CreateOrUpdateKind, + KindEnum as CreateOrUpdateKind } from "../../generated/messages/CreateOrUpdateInstallationMessage"; import { DeleteInstallationMessage, - KindEnum as DeleteKind, + KindEnum as DeleteKind } from "../../generated/messages/DeleteInstallationMessage"; import { NotificationMessageKindEnum } from "../../generated/messages/NotificationMessageKind"; import { KindEnum as NotifyKind, - NotifyMessage, + NotifyMessage } from "../../generated/messages/NotifyMessage"; import { Notification } from "../../generated/notifications/Notification"; import { SuccessResponse } from "../../generated/notifications/SuccessResponse"; @@ -62,8 +62,8 @@ export default class NotificationService { notificationTitle, O.fromNullable, O.getOrElse(() => `${notification.sender_metadata.organization_name}`) - ), - }, + ) + } }; return this.notificationQueueClient .sendMessage(base64EncodeObject(notifyMessage)) @@ -91,7 +91,7 @@ export default class NotificationService { ], platform: installation.platform, pushChannel: installation.pushChannel, - tags: [toFiscalCodeHash(fiscalCode)], + tags: [toFiscalCodeHash(fiscalCode)] }; return this.notificationQueueClient .sendMessage(base64EncodeObject(azureInstallation)) @@ -110,7 +110,7 @@ export default class NotificationService { > => { const deleteMessage: DeleteInstallationMessage = { installationId: toFiscalCodeHash(fiscalCode), - kind: DeleteKind[NotificationMessageKindEnum.DeleteInstallation], + kind: DeleteKind[NotificationMessageKindEnum.DeleteInstallation] }; return this.notificationQueueClient .sendMessage(base64EncodeObject(deleteMessage)) diff --git a/src/services/notificationServiceFactory.ts b/src/services/notificationServiceFactory.ts index a45ff6c2a..e92601528 100644 --- a/src/services/notificationServiceFactory.ts +++ b/src/services/notificationServiceFactory.ts @@ -5,7 +5,7 @@ import { flow } from "fp-ts/lib/function"; import { FiscalCode } from "../../generated/io-bonus-api/FiscalCode"; import { FeatureFlag, - getIsUserEligibleForNewFeature, + getIsUserEligibleForNewFeature } from "../utils/featureFlag"; import { toFiscalCodeHash } from "../types/notification"; diff --git a/src/services/pagoPAClientFactory.ts b/src/services/pagoPAClientFactory.ts index f4e0480a2..bd7a84775 100644 --- a/src/services/pagoPAClientFactory.ts +++ b/src/services/pagoPAClientFactory.ts @@ -7,7 +7,7 @@ import nodeFetch from "node-fetch"; import { PagoPAClient } from "../clients/pagopa"; import { IPagoPAClientFactoryInterface, - PagoPAEnvironment, + PagoPAEnvironment } from "./IPagoPAClientFactory"; // TODO: this class is actually useless as PagoPAClient is immutable, it can be removed diff --git a/src/services/pagoPAProxyService.ts b/src/services/pagoPAProxyService.ts index 35b22e59e..592f30ace 100644 --- a/src/services/pagoPAProxyService.ts +++ b/src/services/pagoPAProxyService.ts @@ -6,7 +6,7 @@ import { ResponseErrorInternal, ResponseErrorNotFound, ResponseErrorValidation, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { PaymentActivationsGetResponse } from "../../generated/backend/PaymentActivationsGetResponse"; @@ -17,11 +17,11 @@ import { PaymentActivationsPostRequest } from "../../generated/pagopa-proxy/Paym import { ResponsePaymentError, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { IPagoPAClientFactoryInterface, - PagoPAEnvironment, + PagoPAEnvironment } from "./IPagoPAClientFactory"; export default class PagoPAProxyService { @@ -43,7 +43,7 @@ export default class PagoPAProxyService { isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION ); const validated = await client.getPaymentInfo({ - rpt_id_from_string: rptId, + rpt_id_from_string: rptId }); return withValidatedOrInternalError(validated, (response) => response.status === 200 @@ -52,14 +52,15 @@ export default class PagoPAProxyService { ResponseSuccessJson ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - response.value.detail || "Bad request response from upstream API" - ) - : ResponsePaymentError( - response.value.detail, - response.value.detail_v2 - ) + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + response.value.detail || + "Bad request response from upstream API" + ) + : ResponsePaymentError( + response.value.detail, + response.value.detail_v2 + ) ); }); @@ -80,7 +81,7 @@ export default class PagoPAProxyService { isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION ); const validated = await client.activatePayment({ - paymentActivationsPostRequest, + paymentActivationsPostRequest }); return withValidatedOrInternalError(validated, (response) => @@ -90,14 +91,15 @@ export default class PagoPAProxyService { ResponseSuccessJson ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - response.value.detail || "Bad request response from upstream API" - ) - : ResponsePaymentError( - response.value.detail, - response.value.detail_v2 - ) + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + response.value.detail || + "Bad request response from upstream API" + ) + : ResponsePaymentError( + response.value.detail, + response.value.detail_v2 + ) ); }); @@ -118,7 +120,7 @@ export default class PagoPAProxyService { isTest ? PagoPAEnvironment.TEST : PagoPAEnvironment.PRODUCTION ); const validated = await client.getActivationStatus({ - codice_contesto_pagamento: codiceContestoPagamento, + codice_contesto_pagamento: codiceContestoPagamento }); return withValidatedOrInternalError(validated, (response) => response.status === 200 @@ -127,19 +129,20 @@ export default class PagoPAProxyService { ResponseSuccessJson ) : response.status === 400 - ? ResponseErrorValidation( - response.value.title || "Bad request (upstream)", - response.value.detail || "Bad request response from upstream API" - ) - : response.status === 404 - ? ResponseErrorNotFound( - response.value.title || "Not found (upstream)", - response.value.detail || "Not found response from upstream" - ) - : ResponseErrorInternal( - response.value.detail || - "Internal server error response from upstream" - ) + ? ResponseErrorValidation( + response.value.title || "Bad request (upstream)", + response.value.detail || + "Bad request response from upstream API" + ) + : response.status === 404 + ? ResponseErrorNotFound( + response.value.title || "Not found (upstream)", + response.value.detail || "Not found response from upstream" + ) + : ResponseErrorInternal( + response.value.detail || + "Internal server error response from upstream" + ) ); }); } diff --git a/src/services/pnService.ts b/src/services/pnService.ts index 1172e1aa3..b1a4b5df6 100644 --- a/src/services/pnService.ts +++ b/src/services/pnService.ts @@ -11,19 +11,19 @@ const upsertPnActivationService = ) => PnAddressBookIOClientSelector(pnEnvironment).setCourtesyAddressIo({ body: activationStatusPayload, - "x-pagopa-cx-taxid": fiscalCode, + "x-pagopa-cx-taxid": fiscalCode }); const getPnActivationService = (PnAddressBookIOClientSelector: ReturnType) => (pnEnvironment: PNEnvironment, fiscalCode: FiscalCode) => PnAddressBookIOClientSelector(pnEnvironment).getCourtesyAddressIo({ - "x-pagopa-cx-taxid": fiscalCode, + "x-pagopa-cx-taxid": fiscalCode }); export const PNService = ( PnAddressBookIOClientSelector: ReturnType ) => ({ getPnActivation: getPnActivationService(PnAddressBookIOClientSelector), - upsertPnActivation: upsertPnActivationService(PnAddressBookIOClientSelector), + upsertPnActivation: upsertPnActivationService(PnAddressBookIOClientSelector) }); diff --git a/src/services/profileService.ts b/src/services/profileService.ts index 32cebb846..e1c68fa68 100644 --- a/src/services/profileService.ts +++ b/src/services/profileService.ts @@ -17,7 +17,7 @@ import { ResponseErrorPreconditionFailed, ResponseErrorTooManyRequests, ResponseSuccessAccepted, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; @@ -35,7 +35,7 @@ import { User } from "../types/user"; import { unhandledResponseStatus, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { IApiClientFactoryInterface } from "./IApiClientFactory"; @@ -56,7 +56,7 @@ export default class ProfileService { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { const validated = await client.getProfile({ - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -105,7 +105,7 @@ export default class ProfileService { const client = this.apiClient.getClient(); return withCatchAsInternalError(async () => { const validated = await client.getProfile({ - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { if (response.status === 200) { @@ -158,7 +158,7 @@ export default class ProfileService { return withCatchAsInternalError(async () => { const validated = await client.createProfile({ body: newProfile, - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => @@ -166,13 +166,13 @@ export default class ProfileService { ? // An empty response. ResponseSuccessJson({}) : response.status === 409 - ? ResponseErrorConflict( - response.value || - "A user with the provided fiscal code already exists" - ) - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorConflict( + response.value || + "A user with the provided fiscal code already exists" + ) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); }; @@ -201,7 +201,7 @@ export default class ProfileService { withCatchAsInternalError(async () => { const validated = await client.updateProfile({ body: { ...extendedProfileApi, name: user.name }, - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => { @@ -246,16 +246,16 @@ export default class ProfileService { return withCatchAsInternalError(async () => { const validated = await client.startEmailValidationProcess({ body: { name: user.name }, - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => response.status === 202 ? ResponseSuccessAccepted() : response.status === 404 - ? ResponseErrorNotFound("Not found", "User not found.") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound("Not found", "User not found.") + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); }; diff --git a/src/services/redisSessionStorage.ts b/src/services/redisSessionStorage.ts index 8638712d6..42b94f72e 100644 --- a/src/services/redisSessionStorage.ts +++ b/src/services/redisSessionStorage.ts @@ -19,7 +19,7 @@ import { flow, pipe, identity } from "fp-ts/lib/function"; import { NonEmptyArray } from "fp-ts/lib/NonEmptyArray"; import { NullableBackendAssertionRefFromString, - LollipopData, + LollipopData } from "../types/assertionRef"; import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; import { SessionInfo } from "../../generated/backend/SessionInfo"; @@ -31,7 +31,7 @@ import { MyPortalToken, SessionToken, WalletToken, - ZendeskToken, + ZendeskToken } from "../types/token"; import { User, UserV1, UserV2, UserV3, UserV4, UserV5 } from "../types/user"; import { log } from "../utils/logger"; @@ -62,7 +62,7 @@ export const keyPrefixes = [ sessionInfoKeyPrefix, noticeEmailPrefix, blockedUserSetKey, - lollipopDataPrefix, + lollipopDataPrefix ]; export const sessionNotFoundError = new Error("Session not found"); @@ -494,7 +494,7 @@ export default class RedisSessionStorage : // Remap plain string to LollipopData { assertionRef: storedValue, - loginType: LoginTypeEnum.LEGACY, + loginType: LoginTypeEnum.LEGACY } ) ) @@ -750,7 +750,7 @@ export default class RedisSessionStorage return prev; }, (sessionInfo) => ({ - sessions: [...prev.sessions, sessionInfo], + sessions: [...prev.sessions, sessionInfo] }) ) ), @@ -764,36 +764,36 @@ export default class RedisSessionStorage const requiredTokens = { session_info: { prefix: sessionInfoKeyPrefix, - value: user.session_token, + value: user.session_token }, session_token: { prefix: sessionKeyPrefix, - value: user.session_token, + value: user.session_token }, wallet_token: { prefix: walletKeyPrefix, - value: user.wallet_token, - }, + value: user.wallet_token + } }; if (UserV5.is(user)) { return { ...requiredTokens, bpd_token: { prefix: bpdTokenPrefix, - value: user.bpd_token, + value: user.bpd_token }, fims_token: { prefix: fimsTokenPrefix, - value: user.fims_token, + value: user.fims_token }, myportal_token: { prefix: myPortalTokenPrefix, - value: user.myportal_token, + value: user.myportal_token }, zendesk_token: { prefix: zendeskTokenPrefix, - value: user.zendesk_token, - }, + value: user.zendesk_token + } }; } if (UserV4.is(user)) { @@ -801,16 +801,16 @@ export default class RedisSessionStorage ...requiredTokens, bpd_token: { prefix: bpdTokenPrefix, - value: user.bpd_token, + value: user.bpd_token }, myportal_token: { prefix: myPortalTokenPrefix, - value: user.myportal_token, + value: user.myportal_token }, zendesk_token: { prefix: zendeskTokenPrefix, - value: user.zendesk_token, - }, + value: user.zendesk_token + } }; } if (UserV3.is(user)) { @@ -818,12 +818,12 @@ export default class RedisSessionStorage ...requiredTokens, bpd_token: { prefix: bpdTokenPrefix, - value: user.bpd_token, + value: user.bpd_token }, myportal_token: { prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, + value: user.myportal_token + } }; } if (UserV2.is(user)) { @@ -831,13 +831,13 @@ export default class RedisSessionStorage ...requiredTokens, myportal_token: { prefix: myPortalTokenPrefix, - value: user.myportal_token, - }, + value: user.myportal_token + } }; } if (UserV1.is(user)) { return { - ...requiredTokens, + ...requiredTokens }; } return assertUnreachable(user); diff --git a/src/services/servicesAppBackendService.ts b/src/services/servicesAppBackendService.ts index fc4f943ed..dde82d822 100644 --- a/src/services/servicesAppBackendService.ts +++ b/src/services/servicesAppBackendService.ts @@ -4,7 +4,7 @@ import { IResponseErrorValidation, IResponseSuccessJson, ResponseErrorNotFound, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { FeaturedServices } from "../../generated/services-app-backend/FeaturedServices"; import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; @@ -16,7 +16,7 @@ import { ServicesAppBackendAPIClient } from "../clients/services-app-backend"; import { unhandledResponseStatus, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; // TODO: Aggiungere le altre operazioni del service @@ -40,7 +40,7 @@ export default class ServicesAppBackendService { limit, offset, scope, - search, + search }); return withValidatedOrInternalError(validated, (response) => @@ -62,7 +62,7 @@ export default class ServicesAppBackendService { > => withCatchAsInternalError(async () => { const validated = await this.apiClient.getServiceById({ - serviceId, + serviceId }); return withValidatedOrInternalError(validated, (response) => @@ -72,8 +72,8 @@ export default class ServicesAppBackendService { ResponseSuccessJson ) : response.status === 404 - ? ResponseErrorNotFound("Not found", "Service not found") - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound("Not found", "Service not found") + : unhandledResponseStatus(response.status) ); }); @@ -123,7 +123,7 @@ export default class ServicesAppBackendService { const validated = await this.apiClient.findInstutionServices({ institutionId, limit, - offset, + offset }); // TODO: sistemare i vari return diff --git a/src/services/trialService.ts b/src/services/trialService.ts index 6e5cb6144..00d613217 100644 --- a/src/services/trialService.ts +++ b/src/services/trialService.ts @@ -15,7 +15,7 @@ import { ResponseErrorConflict, IResponseErrorConflict, IResponseSuccessJson, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { TrialSystemAPIClient } from "src/clients/trial-system.client"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; @@ -25,7 +25,7 @@ import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { TrialId } from "../../generated/trial-system-api/TrialId"; import { Subscription } from "../../generated/trial-system/Subscription"; @@ -52,9 +52,9 @@ export default class TrialService { withCatchAsInternalError(async () => { const validated = await this.apiClient.createSubscription({ body: { - userId, + userId }, - trialId, + trialId }); return withValidatedOrInternalError(validated, (response) => { @@ -64,7 +64,7 @@ export default class TrialService { { createdAt: response.value.createdAt, state: response.value.state, - trialId: response.value.trialId, + trialId: response.value.trialId }, (resBody) => ResponseSuccessRedirectToResource( @@ -118,7 +118,7 @@ export default class TrialService { withCatchAsInternalError(async () => { const validated = await this.apiClient.getSubscription({ trialId, - userId, + userId }); return withValidatedOrInternalError(validated, (response) => { @@ -128,7 +128,7 @@ export default class TrialService { { createdAt: response.value.createdAt, state: response.value.state, - trialId: response.value.trialId, + trialId: response.value.trialId }, ResponseSuccessJson ); diff --git a/src/services/userDataProcessingService.ts b/src/services/userDataProcessingService.ts index 344366796..427ad9d4a 100644 --- a/src/services/userDataProcessingService.ts +++ b/src/services/userDataProcessingService.ts @@ -15,7 +15,7 @@ import { ResponseErrorNotFound, ResponseErrorTooManyRequests, ResponseSuccessAccepted, - ResponseSuccessJson, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { pipe } from "fp-ts/lib/function"; @@ -27,7 +27,7 @@ import { User } from "../types/user"; import { unhandledResponseStatus, withCatchAsInternalError, - withValidatedOrInternalError, + withValidatedOrInternalError } from "../utils/responses"; import { IApiClientFactoryInterface } from "./IApiClientFactory"; @@ -50,22 +50,22 @@ export default class UserDataProcessingService { return withCatchAsInternalError(async () => { const validated = await client.upsertUserDataProcessing({ body: userDataProcessingChoiceRequest, - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => response.status === 200 ? ResponseSuccessJson(response.value) : response.status === 429 - ? ResponseErrorTooManyRequests() - : response.status === 409 - ? ResponseErrorConflict( - pipe( - O.fromNullable(response.value.detail), - O.getOrElse(() => "Conflict") - ) - ) - : unhandledResponseStatus(response.status) + ? ResponseErrorTooManyRequests() + : response.status === 409 + ? ResponseErrorConflict( + pipe( + O.fromNullable(response.value.detail), + O.getOrElse(() => "Conflict") + ) + ) + : unhandledResponseStatus(response.status) ); }); }; @@ -86,17 +86,20 @@ export default class UserDataProcessingService { return withCatchAsInternalError(async () => { const validated = await client.getUserDataProcessing({ choice: userDataProcessingChoiceParam, - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => response.status === 200 ? ResponseSuccessJson(response.value) : response.status === 404 - ? ResponseErrorNotFound("Not Found", "User data processing not found") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound( + "Not Found", + "User data processing not found" + ) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); }; @@ -119,19 +122,24 @@ export default class UserDataProcessingService { return withCatchAsInternalError(async () => { const validated = await client.abortUserDataProcessing({ choice: userDataProcessingChoiceParam, - fiscal_code: user.fiscal_code, + fiscal_code: user.fiscal_code }); return withValidatedOrInternalError(validated, (response) => response.status === 202 ? ResponseSuccessAccepted() : response.status === 404 - ? ResponseErrorNotFound("Not Found", "User data processing not found") - : response.status === 409 - ? ResponseErrorConflict("Cannot abort user data processing request") - : response.status === 429 - ? ResponseErrorTooManyRequests() - : unhandledResponseStatus(response.status) + ? ResponseErrorNotFound( + "Not Found", + "User data processing not found" + ) + : response.status === 409 + ? ResponseErrorConflict( + "Cannot abort user data processing request" + ) + : response.status === 429 + ? ResponseErrorTooManyRequests() + : unhandledResponseStatus(response.status) ); }); }; diff --git a/src/strategies/bearerMyPortalTokenStrategy.ts b/src/strategies/bearerMyPortalTokenStrategy.ts index 23a009533..d2fbbdf59 100644 --- a/src/strategies/bearerMyPortalTokenStrategy.ts +++ b/src/strategies/bearerMyPortalTokenStrategy.ts @@ -17,7 +17,7 @@ const bearerMyPortalTokenStrategy = ( const options = { passReqToCallback: true, realm: "Proxy API", - scope: "request", + scope: "request" }; return new passport.Strategy( options, diff --git a/src/strategies/bearerSessionTokenStrategy.ts b/src/strategies/bearerSessionTokenStrategy.ts index 37a7d2df9..73750b9a5 100644 --- a/src/strategies/bearerSessionTokenStrategy.ts +++ b/src/strategies/bearerSessionTokenStrategy.ts @@ -20,7 +20,7 @@ const bearerSessionTokenStrategy = ( const options = { passReqToCallback: true, realm: "Proxy API", - scope: "request", + scope: "request" }; return new passport.Strategy( options, diff --git a/src/types/IDPEntityDescriptor.ts b/src/types/IDPEntityDescriptor.ts index 055c5917c..107db2da8 100644 --- a/src/types/IDPEntityDescriptor.ts +++ b/src/types/IDPEntityDescriptor.ts @@ -9,7 +9,7 @@ export const IDPEntityDescriptor = t.interface({ entryPoint: t.string, - logoutUrl: t.string, + logoutUrl: t.string }); export type IDPEntityDescriptor = t.TypeOf; diff --git a/src/types/assertionRef.ts b/src/types/assertionRef.ts index 7da471de5..94cc3c43d 100644 --- a/src/types/assertionRef.ts +++ b/src/types/assertionRef.ts @@ -10,14 +10,14 @@ import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; export type LollipopData = t.TypeOf; export const LollipopData = t.type({ assertionRef: AssertionRef, - loginType: LoginType, + loginType: LoginType }); // CompactLollipopData type CompactLollipopData = t.TypeOf; const CompactLollipopData = t.type({ a: AssertionRef, - t: LoginType, + t: LoginType }); // LollipopDataFromCompact @@ -55,5 +55,5 @@ export const NullableBackendAssertionRefFromString = t.union([ t.null, t.undefined, AssertionRef, - LollipopDataFromString, + LollipopDataFromString ]); diff --git a/src/types/booleans.ts b/src/types/booleans.ts index edc29ba65..80702e689 100644 --- a/src/types/booleans.ts +++ b/src/types/booleans.ts @@ -22,7 +22,7 @@ export const BooleanFromString: BooleanFromString = new t.Type< s === "true" ? t.success(true) : s === "false" - ? t.success(false) - : t.failure(s, c), + ? t.success(false) + : t.failure(s, c), String ); diff --git a/src/types/commons.ts b/src/types/commons.ts index cd9ca4465..3833e3b78 100644 --- a/src/types/commons.ts +++ b/src/types/commons.ts @@ -6,7 +6,7 @@ import { PatternString } from "@pagopa/ts-commons/lib/strings"; import * as t from "io-ts"; export const SuccessResponse = t.interface({ - message: t.string, + message: t.string }); export type SuccessResponse = t.TypeOf; @@ -40,8 +40,8 @@ export const CommaSeparatedListOf = (decoder: t.Mixed) => .map((e) => e.trim()) .filter(Boolean) : !input - ? [] // fallback to empty array in case of empty input - : input // it should not happen, but in case we let the decoder fail + ? [] // fallback to empty array in case of empty input + : input // it should not happen, but in case we let the decoder fail ), String ); diff --git a/src/types/lollipop.ts b/src/types/lollipop.ts index 15dc4af4e..9cdd260ec 100644 --- a/src/types/lollipop.ts +++ b/src/types/lollipop.ts @@ -1,16 +1,20 @@ import * as t from "io-ts"; -import { FiscalCode, NonEmptyString, PatternString } from "@pagopa/ts-commons/lib/strings"; +import { + FiscalCode, + NonEmptyString, + PatternString +} from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; import { IResponseErrorValidation, - ResponseErrorValidation, + ResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/Either"; import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/Option"; import { JwkPubKeyHashAlgorithm, - JwkPubKeyHashAlgorithmEnum, + JwkPubKeyHashAlgorithmEnum } from "../../generated/lollipop-api/JwkPubKeyHashAlgorithm"; import { AssertionRefSha256 } from "../../generated/backend/AssertionRefSha256"; import { AssertionRefSha384 } from "../../generated/backend/AssertionRefSha384"; @@ -37,9 +41,9 @@ export const LollipopRequiredHeaders = t.intersection([ signature: LollipopSignature, ["signature-input"]: LollipopSignatureInput, ["x-pagopa-lollipop-original-method"]: LollipopMethod, - ["x-pagopa-lollipop-original-url"]: LollipopOriginalURL, + ["x-pagopa-lollipop-original-url"]: LollipopOriginalURL }), - t.partial({ ["content-digest"]: LollipopContentDigest }), + t.partial({ ["content-digest"]: LollipopContentDigest }) ]); export type LollipopRequiredHeaders = t.TypeOf; @@ -50,12 +54,12 @@ export const LollipopLocalsType = t.intersection([ ["x-pagopa-lollipop-assertion-type"]: AssertionType, ["x-pagopa-lollipop-auth-jwt"]: NonEmptyString, ["x-pagopa-lollipop-public-key"]: JwkPubKeyToken, - ["x-pagopa-lollipop-user-id"]: FiscalCode, + ["x-pagopa-lollipop-user-id"]: FiscalCode }), t.partial({ body: t.any, - ["content-digest"]: LollipopContentDigest, - }), + ["content-digest"]: LollipopContentDigest + }) ]); export type LollipopLocalsType = t.TypeOf; @@ -146,7 +150,7 @@ export type Thumbprint = t.TypeOf; export const algoToAssertionRefSet = new Set([ { algo: JwkPubKeyHashAlgorithmEnum.sha256, type: AssertionRefSha256 }, { algo: JwkPubKeyHashAlgorithmEnum.sha384, type: AssertionRefSha384 }, - { algo: JwkPubKeyHashAlgorithmEnum.sha512, type: AssertionRefSha512 }, + { algo: JwkPubKeyHashAlgorithmEnum.sha512, type: AssertionRefSha512 } ]); export const getAlgoFromAssertionRef = ( diff --git a/src/types/pathParams.ts b/src/types/pathParams.ts index 68ee59b3d..14644b22f 100644 --- a/src/types/pathParams.ts +++ b/src/types/pathParams.ts @@ -6,14 +6,14 @@ import * as O from "fp-ts/Option"; export type Encoder = (params: ReadonlyArray) => string; const createSingleError = - (input: unknown, context: t.Context, errorMessage: string) => (): t.Errors => - [ - { - context, - message: errorMessage, - value: input, - }, - ]; + (input: unknown, context: t.Context, errorMessage: string) => + (): t.Errors => [ + { + context, + message: errorMessage, + value: input + } + ]; export type PathParams = t.Type, string, unknown>; export const pathParamsFromUrl = ( diff --git a/src/types/profile.ts b/src/types/profile.ts index a30fc44ad..768d8a34b 100644 --- a/src/types/profile.ts +++ b/src/types/profile.ts @@ -8,7 +8,7 @@ import { IResponseErrorNotFound, IResponseErrorTooManyRequests, IResponseSuccessJson, - ResponseErrorInternal, + ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import { pipe } from "fp-ts/lib/function"; import { ExtendedProfile } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; @@ -49,7 +49,7 @@ export const toInitializedProfile = ( reminder_status: profile.reminder_status, service_preferences_settings: profile.service_preferences_settings, spid_email: user.spid_email, - version: profile.version, + version: profile.version }); export const profileMissingErrorResponse = diff --git a/src/types/user.ts b/src/types/user.ts index b89716dcc..0d14435e0 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -24,7 +24,7 @@ import { MyPortalToken, SessionToken, WalletToken, - ZendeskToken, + ZendeskToken } from "./token"; // required attributes @@ -37,7 +37,7 @@ export const UserWithoutTokens = t.intersection([ family_name: t.string, fiscal_code: FiscalCode, name: t.string, - spid_level: SpidLevel, + spid_level: SpidLevel }), t.partial({ nameID: t.string, @@ -45,14 +45,14 @@ export const UserWithoutTokens = t.intersection([ sessionIndex: t.string, session_tracking_id: t.string, // unique ID used for tracking in appinsights spid_email: EmailAddress, - spid_idp: t.string, - }), + spid_idp: t.string + }) ]); export type UserWithoutTokens = t.TypeOf; const RequiredUserTokensV1 = t.interface({ session_token: SessionToken, - wallet_token: WalletToken, + wallet_token: WalletToken }); export const UserV1 = t.intersection([UserWithoutTokens, RequiredUserTokensV1]); export type UserV1 = t.TypeOf; @@ -60,8 +60,8 @@ export type UserV1 = t.TypeOf; const RequiredUserTokensV2 = t.intersection([ RequiredUserTokensV1, t.interface({ - myportal_token: MyPortalToken, - }), + myportal_token: MyPortalToken + }) ]); export const UserV2 = t.intersection([UserWithoutTokens, RequiredUserTokensV2]); export type UserV2 = t.TypeOf; @@ -69,8 +69,8 @@ export type UserV2 = t.TypeOf; const RequiredUserTokensV3 = t.intersection([ RequiredUserTokensV2, t.interface({ - bpd_token: BPDToken, - }), + bpd_token: BPDToken + }) ]); export const UserV3 = t.intersection([UserWithoutTokens, RequiredUserTokensV3]); export type UserV3 = t.TypeOf; @@ -78,8 +78,8 @@ export type UserV3 = t.TypeOf; const RequiredUserTokensV4 = t.intersection([ RequiredUserTokensV3, t.interface({ - zendesk_token: ZendeskToken, - }), + zendesk_token: ZendeskToken + }) ]); export const UserV4 = t.intersection([UserWithoutTokens, RequiredUserTokensV4]); export type UserV4 = t.TypeOf; @@ -87,8 +87,8 @@ export type UserV4 = t.TypeOf; const RequiredUserTokensV5 = t.intersection([ RequiredUserTokensV4, t.interface({ - fims_token: FIMSToken, - }), + fims_token: FIMSToken + }) ]); export const UserV5 = t.intersection([UserWithoutTokens, RequiredUserTokensV5]); export type UserV5 = t.TypeOf; diff --git a/src/utils/AsyncIterableTask.ts b/src/utils/AsyncIterableTask.ts index 54d8545ef..829ae5526 100644 --- a/src/utils/AsyncIterableTask.ts +++ b/src/utils/AsyncIterableTask.ts @@ -4,7 +4,7 @@ import * as TE from "fp-ts/lib/TaskEither"; import { asyncIterableToPageArray, IPage, - mapAsyncIterator, + mapAsyncIterator } from "@pagopa/io-functions-commons/dist/src/utils/async"; import { pipe } from "fp-ts/lib/function"; import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers"; @@ -26,7 +26,7 @@ const mapAsyncIterable = ( const iterMapped = mapAsyncIterator(iter, f); return { // eslint-disable-next-line @typescript-eslint/no-explicit-any - [Symbol.asyncIterator]: (): AsyncIterator => iterMapped, + [Symbol.asyncIterator]: (): AsyncIterator => iterMapped }; }; @@ -58,7 +58,7 @@ export const fromAsyncIterator = ( a: AsyncIterator ): AsyncIterableTask => fromAsyncIterable({ - [Symbol.asyncIterator]: () => a, + [Symbol.asyncIterator]: () => a }); /** diff --git a/src/utils/appinsights.ts b/src/utils/appinsights.ts index 63e18626e..8e148cb51 100644 --- a/src/utils/appinsights.ts +++ b/src/utils/appinsights.ts @@ -1,7 +1,7 @@ import * as appInsights from "applicationinsights"; import { ApplicationInsightsConfig, - initAppInsights as startAppInsights, + initAppInsights as startAppInsights } from "@pagopa/ts-commons/lib/appinsights"; import { eventLog } from "@pagopa/winston-ts"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; @@ -11,7 +11,7 @@ import { Request } from "express"; import * as E from "fp-ts/lib/Either"; import { sha256, - validateDigestHeader, + validateDigestHeader } from "@pagopa/io-functions-commons/dist/src/utils/crypto"; import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import { LollipopLocalsType } from "../types/lollipop"; @@ -59,10 +59,8 @@ export function attachTrackingData(user: User): void { export function sessionIdPreprocessor( envelope: appInsights.Contracts.Envelope, - context?: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - readonly [name: string]: any; - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + context?: Readonly> ): boolean { if (context !== undefined) { try { @@ -91,7 +89,7 @@ export function sessionIdPreprocessor( export enum StartupEventName { SERVER = "api-backend.httpserver.startup", - SPID = "api-backend.spid.config", + SPID = "api-backend.spid.config" } export const trackStartupTime = ( @@ -102,9 +100,9 @@ export const trackStartupTime = ( telemetryClient.trackEvent({ name: type, properties: { - time: timeMs.toString(), + time: timeMs.toString() }, - tagOverrides: { samplingEnabled: "false" }, + tagOverrides: { samplingEnabled: "false" } }); }; @@ -192,12 +190,12 @@ export const logLollipopSignRequest = // The fiscal code will be sent hashed to the logs ["x-pagopa-lollipop-user-id"]: sha256( lollipopHeadersWithoutBody["x-pagopa-lollipop-user-id"] - ), + ) })), O.map(withoutUndefinedValues), eventLog.option.info((lollipopEventData) => [ `Lollipop Request log`, - lollipopEventData, + lollipopEventData ]) ); }; diff --git a/src/utils/attachments.ts b/src/utils/attachments.ts index 9803b6508..a3b6bf00f 100644 --- a/src/utils/attachments.ts +++ b/src/utils/attachments.ts @@ -9,7 +9,7 @@ import { toBarcode } from "./barcode"; const MIME_TYPES = { png: "image/png", - svg: "image/svg+xml", + svg: "image/svg+xml" }; /** @@ -24,7 +24,7 @@ const toBarcodeAttachments = (name: string, value: string) => toBarcode(value), TE.map((barcodes) => [ { content: barcodes.png, mime_type: MIME_TYPES.png, name }, - { content: barcodes.svg, mime_type: MIME_TYPES.svg, name }, + { content: barcodes.svg, mime_type: MIME_TYPES.svg, name } ]), TE.mapLeft(() => []), TE.toUnion @@ -45,7 +45,7 @@ export function getPrescriptionAttachments( toBarcodeAttachments( "prescriber_fiscal_code", prescriptionData.prescriber_fiscal_code as string - ), + ) ]), T.map(A.flatten) ); diff --git a/src/utils/barcode.ts b/src/utils/barcode.ts index a58210442..9d38025e7 100644 --- a/src/utils/barcode.ts +++ b/src/utils/barcode.ts @@ -45,12 +45,12 @@ export function toBarcode( ): TaskEither { const options = { bcid, - text, + text }; return pipe( AP.sequenceS(TE.ApplicativePar)({ png: toBufferPng(options), - svg: TE.fromEither(toBufferSvg(options)), + svg: TE.fromEither(toBufferSvg(options)) }), TE.fold( (errorOrString) => @@ -65,7 +65,7 @@ export function toBarcode( TE.fromEither( E.right({ png: images.png.toString("base64"), - svg: images.svg.toString("base64"), + svg: images.svg.toString("base64") }) ) ) diff --git a/src/utils/date.ts b/src/utils/date.ts index c92dc22a1..3ca878ece 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -16,7 +16,7 @@ export const isOlderThan = (years: number) => (dateOfBirth: Date, when: Date) => export const isValidDate = (d: Date) => d instanceof Date && !isNaN(d.getTime()); -const months: { readonly [k: string]: number } = { +const months: Readonly> = { ["A"]: 1, ["B"]: 2, ["C"]: 3, @@ -28,7 +28,7 @@ const months: { readonly [k: string]: number } = { ["P"]: 9, ["R"]: 10, ["S"]: 11, - ["T"]: 12, + ["T"]: 12 }; /** diff --git a/src/utils/express.ts b/src/utils/express.ts index c1870e733..0f1ed8cde 100644 --- a/src/utils/express.ts +++ b/src/utils/express.ts @@ -1,7 +1,7 @@ import * as express from "express"; import { IResponse, - ResponseErrorInternal, + ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import { flow, pipe } from "fp-ts/lib/function"; import * as E from "fp-ts/lib/Either"; diff --git a/src/utils/fastLogin.ts b/src/utils/fastLogin.ts index 770a1bdc0..61a767c9c 100644 --- a/src/utils/fastLogin.ts +++ b/src/utils/fastLogin.ts @@ -3,13 +3,13 @@ import { enumType } from "@pagopa/ts-commons/lib/types"; export enum LoginTypeEnum { "LV" = "LV", - "LEGACY" = "LEGACY", + "LEGACY" = "LEGACY" } export type LoginTypeT = t.TypeOf; export const LoginType = enumType(LoginTypeEnum, "LoginType"); export const ActiveSessionInfo = t.type({ ttl: t.number, - type: LoginType, + type: LoginType }); export type ActiveSessionInfo = t.TypeOf; diff --git a/src/utils/featureFlag.ts b/src/utils/featureFlag.ts index e741baa3e..ea156a576 100644 --- a/src/utils/featureFlag.ts +++ b/src/utils/featureFlag.ts @@ -5,7 +5,7 @@ export enum FeatureFlagEnum { ALL = "ALL", BETA = "BETA", CANARY = "CANARY", - NONE = "NONE", + NONE = "NONE" } export const FeatureFlag = enumType( diff --git a/src/utils/gracefulShutdown.ts b/src/utils/gracefulShutdown.ts index a7ce15a17..f5d14e5ce 100644 --- a/src/utils/gracefulShutdown.ts +++ b/src/utils/gracefulShutdown.ts @@ -17,6 +17,6 @@ export function initHttpGracefulShutdown( options.finally(); } app.emit("server:stop"); - }, + } }); } diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 72bb82ceb..e1a43ca29 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -10,5 +10,5 @@ export const log = createLogger({ format.simple(), printf((nfo) => `${nfo.timestamp} [${nfo.level}]: ${nfo.message}`) ), - transports: [new transports.Console()], + transports: [new transports.Console()] }); diff --git a/src/utils/lollipop.ts b/src/utils/lollipop.ts index 06bf91998..639fd6822 100644 --- a/src/utils/lollipop.ts +++ b/src/utils/lollipop.ts @@ -3,7 +3,7 @@ import { IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, ResponseErrorForbiddenNotAuthorized, - ResponseErrorInternal, + ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/Either"; import { ulid } from "ulid"; @@ -24,7 +24,7 @@ import { LollipopLocalsType, LollipopRequiredHeaders, Thumbprint, - getAlgoFromAssertionRef, + getAlgoFromAssertionRef } from "../types/lollipop"; import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; import { LcParams } from "../../generated/lollipop-api/LcParams"; @@ -46,7 +46,7 @@ const getNonceOrUlid = ( // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, nonce, ...__] = NONCE_REGEX.exec(lollipopSignatureInput) ?? [ null, - ulid(), + ulid() ]; return nonce as NonEmptyString; }; @@ -57,7 +57,7 @@ export const getKeyThumbprintFromSignature = ( // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, thumbprint, ...__] = KEY_ID_REGEX.exec(lollipopSignatureInput) ?? [ null, - null, + null ]; return Thumbprint.decode(thumbprint); }; @@ -73,8 +73,8 @@ export const checkIfLollipopIsEnabled = ( { isLollipopDisabledFor: config.disable_lollipop_for.includes(fiscalCode), isLollipopEnabled: config.is_lollipop_enabled, - name: "lollipop.status.info", - }, + name: "lollipop.status.info" + } ]), TE.map( (config) => @@ -103,8 +103,8 @@ const getAndValidateAssertionRefForUser = ( { fiscal_code: sha256(fiscalCode), name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }, + operation_id: operationId + } ]), TE.mapLeft((err) => { log.error( @@ -127,8 +127,8 @@ const getAndValidateAssertionRefForUser = ( { fiscal_code: sha256(fiscalCode), name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }, + operation_id: operationId + } ]) ) ) @@ -158,8 +158,8 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( { fiscal_code: sha256(fiscalCode), name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }, + operation_id: operationId + } ]), TE.mapLeft((err) => { log.error( @@ -178,8 +178,8 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( lollipopClient.generateLCParams({ assertion_ref: assertionRef, body: { - operation_id: operationId, - }, + operation_id: operationId + } }), E.toError ), @@ -189,8 +189,8 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( assertion_ref: assertionRef, fiscal_code: sha256(fiscalCode), name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }, + operation_id: operationId + } ]), TE.mapLeft((err) => { log.error( @@ -215,8 +215,8 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( assertion_ref: assertionRef, fiscal_code: sha256(fiscalCode), name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }, + operation_id: operationId + } ]), TE.mapLeft((err) => { log.error( @@ -232,18 +232,20 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( lollipopRes.status === 200 ? TE.of(lollipopRes.value) : lollipopRes.status === 403 - ? TE.left(ResponseErrorForbiddenNotAuthorized) - : TE.left( - ResponseErrorInternal("The lollipop service returns an error") - ), + ? TE.left(ResponseErrorForbiddenNotAuthorized) + : TE.left( + ResponseErrorInternal( + "The lollipop service returns an error" + ) + ), eventLog.taskEither.errorLeft((errorResponse) => [ `The lollipop function service returns an error | ${errorResponse.kind}`, { assertion_ref: assertionRef, fiscal_code: sha256(fiscalCode), name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }, + operation_id: operationId + } ]) ) ) @@ -257,12 +259,12 @@ export const extractLollipopLocalsFromLollipopHeadersLegacy = ( ["x-pagopa-lollipop-auth-jwt"]: lcParams.lc_authentication_bearer, ["x-pagopa-lollipop-public-key"]: lcParams.pub_key, ["x-pagopa-lollipop-user-id"]: fiscalCode, - ...lollipopHeaders, - } as LollipopLocalsType) + ...lollipopHeaders + }) as LollipopLocalsType ), eventLog.taskEither.info((lcLocals) => [ "Lollipop locals to be sent to third party api", - { ...Object.keys(lcLocals), name: "lollipop.locals.info" }, + { ...Object.keys(lcLocals), name: "lollipop.locals.info" } ]) ); @@ -281,8 +283,8 @@ const retrieveLCParams = ( lollipopClient.generateLCParams({ assertion_ref: assertionRef, body: { - operation_id: operationId, - }, + operation_id: operationId + } }), E.toError ), @@ -292,8 +294,8 @@ const retrieveLCParams = ( assertion_ref: assertionRef, fiscal_code: fiscalCode ? sha256(fiscalCode) : undefined, name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }), + operation_id: operationId + }) ]), TE.mapLeft((err) => { log.error( @@ -315,8 +317,8 @@ const retrieveLCParams = ( assertion_ref: assertionRef, fiscal_code: fiscalCode ? sha256(fiscalCode) : undefined, name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }), + operation_id: operationId + }) ]), TE.mapLeft((err) => { log.error( @@ -336,20 +338,20 @@ const retrieveLCParams = ( O.some(lollipopRes.value) ) : lollipopRes.status === 403 - ? TE.left(ResponseErrorForbiddenNotAuthorized) - : lollipopRes.status === 404 - ? TE.right(O.none) - : TE.left( - ResponseErrorInternal("The lollipop service returns an error") - ), + ? TE.left(ResponseErrorForbiddenNotAuthorized) + : lollipopRes.status === 404 + ? TE.right(O.none) + : TE.left( + ResponseErrorInternal("The lollipop service returns an error") + ), eventLog.taskEither.errorLeft((errorResponse) => [ `The lollipop function service returns an error | ${errorResponse.kind}`, withoutUndefinedValues({ assertion_ref: assertionRef, fiscal_code: fiscalCode ? sha256(fiscalCode) : undefined, name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }), + operation_id: operationId + }) ]) ) ) @@ -375,8 +377,8 @@ export const extractLollipopLocalsFromLollipopHeaders = ( { fiscal_code: fiscalCode ? sha256(fiscalCode) : undefined, name: LOLLIPOP_SIGN_ERROR_EVENT_NAME, - operation_id: operationId, - }, + operation_id: operationId + } ]), E.mapLeft(() => ResponseErrorInternal("Invalid assertionRef in signature params") @@ -402,7 +404,7 @@ export const extractLollipopLocalsFromLollipopHeaders = ( TE.of([ `sha256-${keyThumbprint}` as AssertionRef, `sha384-${keyThumbprint}` as AssertionRef, - `sha512-${keyThumbprint}` as AssertionRef, + `sha512-${keyThumbprint}` as AssertionRef ]) ) ) @@ -428,13 +430,13 @@ export const extractLollipopLocalsFromLollipopHeaders = ( LcParams.is(_) ? TE.right(_) : _.kind === "IResponseErrorInternal" || - _.kind === "IResponseErrorForbiddenNotAuthorized" - ? TE.left(_) - : TE.left( - ResponseErrorInternal( - "Unexpected result given from retrieveLCParams" - ) - ), + _.kind === "IResponseErrorForbiddenNotAuthorized" + ? TE.left(_) + : TE.left( + ResponseErrorInternal( + "Unexpected result given from retrieveLCParams" + ) + ), () => TE.left< IResponseErrorForbiddenNotAuthorized | IResponseErrorInternal @@ -469,11 +471,11 @@ export const extractLollipopLocalsFromLollipopHeaders = ( // It's possible to improve security by verifying that the fiscal code from // the authorization is equal to the one from the lollipop function ["x-pagopa-lollipop-user-id"]: fiscalCode || lcParams.fiscal_code, - ...lollipopHeaders, - } as LollipopLocalsType) + ...lollipopHeaders + }) as LollipopLocalsType ), eventLog.taskEither.info((lcLocals) => [ "Lollipop locals to be sent to third party api", - { ...Object.keys(lcLocals), name: "lollipop.locals.info" }, + { ...Object.keys(lcLocals), name: "lollipop.locals.info" } ]) ); diff --git a/src/utils/middleware/lollipop.ts b/src/utils/middleware/lollipop.ts index 8207655ff..e2a7ba7a9 100644 --- a/src/utils/middleware/lollipop.ts +++ b/src/utils/middleware/lollipop.ts @@ -6,14 +6,14 @@ import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; import { withOptionalUserFromRequest, - withUserFromRequest, + withUserFromRequest } from "../../types/user"; import { LollipopApiClient } from "../../clients/lollipop"; import { withLollipopHeadersFromRequest } from "../../types/lollipop"; import { log } from "../logger"; import { extractLollipopLocalsFromLollipopHeaders, - extractLollipopLocalsFromLollipopHeadersLegacy, + extractLollipopLocalsFromLollipopHeadersLegacy } from "../lollipop"; import { ISessionStorage } from "../../services/ISessionStorage"; diff --git a/src/utils/ognl.ts b/src/utils/ognl.ts index e560b3226..f635ce1ad 100644 --- a/src/utils/ognl.ts +++ b/src/utils/ognl.ts @@ -34,9 +34,7 @@ export const set = ( _i ) => // Iterate all of them except the last one - Object(a[c]) === a[c] - ? a[c] - : (a[c] = {}), + Object(a[c]) === a[c] ? a[c] : (a[c] = {}), obj )[splittedpath[splittedpath.length - 1]] = value; return obj; @@ -58,11 +56,7 @@ export const nestifyPrefixedType = ( env, R.filterWithIndex((fieldName) => fieldName.split("_")[0] === prefix), R.reduceWithIndex({}, (k, b, a) => - set( - b, - k.split("_").splice(1).join("."), - a - ) + set(b, k.split("_").splice(1).join("."), a) ) ); @@ -72,14 +66,13 @@ const isRecordOfString = (i: unknown): i is Record => !Object.keys(i).some((property) => typeof property !== "string"); const createNotRecordOfStringErrorL = - (input: unknown, context: t.Context) => (): t.Errors => - [ - { - context, - message: "input is not a valid record of string", - value: input, - }, - ]; + (input: unknown, context: t.Context) => (): t.Errors => [ + { + context, + message: "input is not a valid record of string", + value: input + } + ]; /** * Create a io-ts decoder for the input type. diff --git a/src/utils/profile.ts b/src/utils/profile.ts index 21a5fc10a..bd41ff00c 100644 --- a/src/utils/profile.ts +++ b/src/utils/profile.ts @@ -11,9 +11,9 @@ import { EmailAddress } from "../../generated/backend/EmailAddress"; // define a type that represents a Profile with a non optional email address const ProfileWithEmail = t.intersection([ t.type({ - email: EmailAddress, + email: EmailAddress }), - InitializedProfile, + InitializedProfile ]); type ProfileWithEmail = t.TypeOf; @@ -60,9 +60,7 @@ export const profileWithEmailValidatedOrError = ( pipe( profile.value, ProfileWithEmailValidated.decode, - E.mapLeft( - () => new Error("Profile has not a validated email address") - ), + E.mapLeft(() => new Error("Profile has not a validated email address")), TE.fromEither ) ) diff --git a/src/utils/qrcode.ts b/src/utils/qrcode.ts index 075356799..cfc5c0f88 100644 --- a/src/utils/qrcode.ts +++ b/src/utils/qrcode.ts @@ -9,7 +9,7 @@ import { image } from "qr-image"; const MIME_TYPES = { png: "image/png", - svg: "image/svg+xml", + svg: "image/svg+xml" }; // Needed to display the SVG into the mobile App @@ -52,20 +52,20 @@ export function withQrcode( return pipe( AP.sequenceS(TE.ApplicativePar)({ pngBuffer: streamToBufferTask(image(bonus.id, { type: "png" })), - svgString: streamToStringTask(image(bonus.id, { type: "svg" })), + svgString: streamToStringTask(image(bonus.id, { type: "svg" })) }), TE.map(({ pngBuffer, svgString }) => ({ ...bonus, qr_code: [ { content: pngBuffer.toString("base64"), - mime_type: MIME_TYPES.png, + mime_type: MIME_TYPES.png }, { content: Buffer.from(fixQrcodeFill(svgString)).toString("base64"), - mime_type: MIME_TYPES.svg, - }, - ], + mime_type: MIME_TYPES.svg + } + ] })) ); } diff --git a/src/utils/redis.ts b/src/utils/redis.ts index c4b499a42..437dccda5 100644 --- a/src/utils/redis.ts +++ b/src/utils/redis.ts @@ -48,15 +48,15 @@ export const createClusterRedisClient = // eslint-disable-next-line @typescript-eslint/no-unused-vars checkServerIdentity: (_hostname, _cert) => undefined, keepAlive: 2000, - tls: enableTls, - }, + tls: enableTls + } }, rootNodes: [ { - url: `${completeRedisUrl}:${redisPort}`, - }, + url: `${completeRedisUrl}:${redisPort}` + } ], - useReplicas, + useReplicas }); redisClient.on("error", (err) => { log.error("[REDIS Error] an error occurs on redis client: %s", err); @@ -67,16 +67,16 @@ export const createClusterRedisClient = message: err instanceof Object ? obfuscateTokensInfo(JSON.stringify(err)) - : "", + : "" }, - tagOverrides: { samplingEnabled: "false" }, + tagOverrides: { samplingEnabled: "false" } }); }); redisClient.on( "reconnecting", ({ delay, - attempt, + attempt }: { readonly delay: number; readonly attempt: number; @@ -90,9 +90,9 @@ export const createClusterRedisClient = name: "io-backend.redis.reconnecting", properties: { attempt, - delay, + delay }, - tagOverrides: { samplingEnabled: "false" }, + tagOverrides: { samplingEnabled: "false" } }); } ); @@ -114,7 +114,7 @@ export type RedisClientSelectorType = Selector< export enum RedisClientMode { "ALL" = "ALL", "SAFE" = "SAFE", - "FAST" = "FAST", + "FAST" = "FAST" } export const RedisClientSelector = @@ -151,6 +151,6 @@ export const RedisClientSelector = }; return { select, - selectOne: (t) => select(t)[0], + selectOne: (t) => select(t)[0] }; }; diff --git a/src/utils/responses.ts b/src/utils/responses.ts index 2b6f9fd13..470a86cb5 100644 --- a/src/utils/responses.ts +++ b/src/utils/responses.ts @@ -7,7 +7,7 @@ import * as E from "fp-ts/lib/Either"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IWithinRangeIntegerTag, - WithinRangeInteger, + WithinRangeInteger } from "@pagopa/ts-commons/lib/numbers"; import { HttpStatusCodeEnum, @@ -17,7 +17,7 @@ import { ResponseErrorGeneric, ResponseErrorInternal, ResponseErrorNotFound, - ResponseErrorValidation, + ResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import * as TE from "fp-ts/TaskEither"; import { pipe } from "fp-ts/lib/function"; @@ -37,7 +37,7 @@ export function ResponseNoContent(): IResponseNoContent { return { apply: (res: express.Response): unknown => res.status(204).json({}), kind: "IResponseNoContent", - value: {}, + value: {} }; } @@ -114,8 +114,8 @@ export function ResponseErrorUnauthorizedForLegalReasons( ...ResponseErrorGeneric(HttpStatusCodeEnum.HTTP_STATUS_451, title, detail), ...{ detail: `${title}: ${detail}`, - kind: "IResponseErrorUnauthorizedForLegalReasons", - }, + kind: "IResponseErrorUnauthorizedForLegalReasons" + } }; } @@ -140,8 +140,8 @@ export function ResponseErrorUnauthorized( ), ...{ detail: `Unauthorized: ${detail}`, - kind: "IResponseErrorUnauthorized", - }, + kind: "IResponseErrorUnauthorized" + } }; } @@ -158,7 +158,7 @@ export const ResponseErrorUnexpectedAuthProblem = () => export type HttpStatusCode = t.TypeOf; export const HttpStatusCode = t.union([ WithinRangeInteger<100, 599, IWithinRangeIntegerTag<100, 599>>(100, 599), - t.literal(599), + t.literal(599) ]); export type IResponsePaymentInternalError = IResponse<"IResponseErrorInternal">; @@ -174,7 +174,7 @@ export const ResponsePaymentError = ( detail, detail_v2: detailV2, status: HttpStatusCodeEnum.HTTP_STATUS_500 as HttpStatusCode, - title: "Internal server error", + title: "Internal server error" }; return { apply: (res) => @@ -182,7 +182,7 @@ export const ResponsePaymentError = ( .status(HttpStatusCodeEnum.HTTP_STATUS_500) .set("Content-Type", "application/problem+json") .json(problem), - kind: "IResponseErrorInternal", + kind: "IResponseErrorInternal" }; }; @@ -208,7 +208,7 @@ export const ResponseSuccessOctet = ( .set("Content-Type", "application/octet-stream") .end(o), kind: "IResponseSuccessOctet", - value: o, + value: o }); export const wrapValidationWithInternalError: ( @@ -240,8 +240,8 @@ export const ResponseErrorNotImplemented = ( ), ...{ detail: `Not Implemented: ${detail}`, - kind: "IResponseErrorNotImplemented", - }, + kind: "IResponseErrorNotImplemented" + } }); /** @@ -264,6 +264,6 @@ export const ResponseErrorUnsupportedMediaType = ( ), ...{ detail, - kind: "IResponseErrorUnsupportedMediaType", - }, + kind: "IResponseErrorUnsupportedMediaType" + } }); diff --git a/src/utils/separated-list.ts b/src/utils/separated-list.ts index d3f34e7d4..f1d52988a 100644 --- a/src/utils/separated-list.ts +++ b/src/utils/separated-list.ts @@ -23,8 +23,8 @@ export const GetArbitrarySeparatedListOf = .map((e) => e.trim()) .filter(Boolean) : !input - ? [] // fallback to empty array in case of empty input - : input // it should not happen, but in case we let the decoder fail + ? [] // fallback to empty array in case of empty input + : input // it should not happen, but in case we let the decoder fail ), String ); diff --git a/src/utils/thirdPartyConfig.ts b/src/utils/thirdPartyConfig.ts index 9a606dfdc..fe106b76f 100644 --- a/src/utils/thirdPartyConfig.ts +++ b/src/utils/thirdPartyConfig.ts @@ -9,14 +9,14 @@ import { BooleanFromString, JsonFromString, withFallback } from "io-ts-types"; export const ClientCert = t.interface({ client_cert: NonEmptyString, client_key: NonEmptyString, - server_ca: NonEmptyString, + server_ca: NonEmptyString }); export type ApiKeyAuthenticationConfig = t.TypeOf; export const ApiKeyAuthenticationConfig = t.interface({ type: t.literal("API_KEY"), key: NonEmptyString, - header_key_name: NonEmptyString, + header_key_name: NonEmptyString }); export type AuthenticationConfig = t.TypeOf; @@ -24,21 +24,21 @@ export const AuthenticationConfig = t.intersection([ // Right now we only handle API_KEY // In future we will also handle BEARER and TOKEN authentications ApiKeyAuthenticationConfig, - t.partial({ cert: ClientCert }), + t.partial({ cert: ClientCert }) ]); export type EnvironmentConfig = t.TypeOf; export const EnvironmentConfig = t.interface({ baseUrl: NonEmptyString, - detailsAuthentication: AuthenticationConfig, + detailsAuthentication: AuthenticationConfig }); export type TestEnvironmentConfig = t.TypeOf; export const TestEnvironmentConfig = t.intersection([ t.interface({ - testUsers: t.readonlyArray(FiscalCode), + testUsers: t.readonlyArray(FiscalCode) }), - EnvironmentConfig, + EnvironmentConfig ]); export type ThirdPartyConfigBase = t.TypeOf; @@ -47,7 +47,7 @@ export const ThirdPartyConfigBase = t.interface({ schemaKind: NonEmptyString, jsonSchema: NonEmptyString, isLollipopEnabled: BooleanFromString, - disableLollipopFor: t.readonlyArray(FiscalCode), + disableLollipopFor: t.readonlyArray(FiscalCode) }); /** @@ -61,13 +61,13 @@ export const ThirdPartyConfig = t.intersection([ t.union([ t.intersection([ t.interface({ prodEnvironment: EnvironmentConfig }), - t.partial({ testEnvironment: TestEnvironmentConfig }), + t.partial({ testEnvironment: TestEnvironmentConfig }) ]), t.intersection([ t.partial({ prodEnvironment: EnvironmentConfig }), - t.interface({ testEnvironment: TestEnvironmentConfig }), - ]), - ]), + t.interface({ testEnvironment: TestEnvironmentConfig }) + ]) + ]) ]); export type ThirdPartyConfigList = t.TypeOf; diff --git a/src/utils/timer.ts b/src/utils/timer.ts index a0a01c207..33e5341d3 100644 --- a/src/utils/timer.ts +++ b/src/utils/timer.ts @@ -2,6 +2,6 @@ export const TimeTracer = () => { const startTime: bigint = process.hrtime.bigint(); return { getElapsedMilliseconds: (): bigint => - (process.hrtime.bigint() - startTime) / BigInt(1000000), + (process.hrtime.bigint() - startTime) / BigInt(1000000) }; }; From 2631a8019779a3c6fef861bd0f595db393ebcf54 Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Mon, 3 Feb 2025 16:33:23 +0100 Subject: [PATCH 12/13] Enable sort-imports on eslint --- eslint.config.mjs | 2 - src/adapters/pnFetch.ts | 29 ++++---- src/app.ts | 67 +++++++++--------- src/clients/api.ts | 2 +- src/clients/app-messages.client.ts | 1 + src/clients/bonus.ts | 1 + src/clients/cgn-operator-search.ts | 1 + src/clients/cgn.ts | 2 +- src/clients/eucovidcert.client.ts | 2 +- src/clients/firstLollipopConsumer.ts | 5 +- src/clients/io-fims.ts | 1 + src/clients/io-sign.ts | 1 + src/clients/lollipop.ts | 1 + src/clients/pagopa.ts | 1 + src/clients/pn-clients.ts | 5 +- src/clients/services-app-backend.ts | 1 + src/clients/third-party-service-client.ts | 11 ++- src/clients/trial-system.client.ts | 1 + src/config.ts | 47 +++++++------ src/controllers/authenticationController.ts | 7 +- src/controllers/bonusController.ts | 6 +- src/controllers/cgnController.ts | 12 ++-- .../cgnOperatorSearchController.ts | 13 ++-- src/controllers/eucovidcertController.ts | 7 +- src/controllers/fimsController.ts | 15 ++-- .../firstLollipopConsumerController.ts | 15 ++-- src/controllers/ioSignController.ts | 46 ++++++------- src/controllers/ioWalletController.ts | 30 ++++---- src/controllers/messagesController.ts | 41 ++++++----- src/controllers/notificationController.ts | 8 +-- src/controllers/pagoPAProxyController.ts | 8 +-- src/controllers/pnController.ts | 7 +- src/controllers/profileController.ts | 5 +- .../serviceAppBackendController.ts | 5 +- src/controllers/servicesController.ts | 7 +- src/controllers/sessionController.ts | 3 +- src/controllers/sessionLockController.ts | 47 +++++++------ src/controllers/ssoController.ts | 3 +- src/controllers/trialController.ts | 11 ++- .../userDataProcessingController.ts | 2 +- src/controllers/userMetadataController.ts | 5 +- src/server.ts | 20 +++--- src/services/ISessionStorage.ts | 5 +- src/services/IUserMetadataStorage.ts | 1 + src/services/authenticationLockService.ts | 18 ++--- src/services/bonusService.ts | 8 +-- src/services/cgnOperatorSearchService.ts | 20 +++--- src/services/cgnService.ts | 16 ++--- src/services/eucovidcertService.ts | 9 ++- src/services/fimsService.ts | 3 - src/services/functionAppService.ts | 8 +-- src/services/ioSignService.ts | 24 +++---- src/services/ioWalletService.ts | 24 +++---- src/services/lollipopService.ts | 1 + src/services/newMessagesService.ts | 69 ++++++++++--------- src/services/notificationService.ts | 5 +- src/services/notificationServiceFactory.ts | 3 +- src/services/pagoPAProxyService.ts | 1 - src/services/pnService.ts | 2 +- src/services/profileService.ts | 12 ++-- src/services/redisSessionStorage.ts | 29 ++++---- src/services/redisStorageUtils.ts | 2 +- src/services/redisUserMetadataStorage.ts | 9 +-- src/services/servicesAppBackendService.ts | 1 + src/services/trialService.ts | 25 +++---- src/services/userDataProcessingService.ts | 8 +-- src/strategies/bearerMyPortalTokenStrategy.ts | 3 +- src/strategies/bearerSessionTokenStrategy.ts | 3 +- src/types/IDPEntityDescriptor.ts | 2 +- src/types/assertionRef.ts | 5 +- src/types/fiscalCode.ts | 3 +- src/types/lollipop.ts | 33 ++++----- src/types/notification.ts | 2 +- src/types/pathParams.ts | 4 +- src/types/profile.ts | 6 +- src/types/token.ts | 4 +- src/types/user.ts | 11 ++- src/utils/AsyncIterableTask.ts | 9 ++- src/utils/appinsights.ts | 19 ++--- src/utils/attachments.ts | 3 +- src/utils/barcode.ts | 3 +- src/utils/container.ts | 1 + src/utils/date.ts | 4 +- src/utils/errorsFormatter.ts | 2 +- src/utils/express.ts | 4 +- src/utils/fastLogin.ts | 2 +- src/utils/file-type.ts | 4 +- src/utils/gracefulShutdown.ts | 5 +- src/utils/lollipop.ts | 23 ++++--- src/utils/middleware/checkIP.ts | 7 +- src/utils/middleware/dueDate.ts | 3 +- src/utils/middleware/express.ts | 3 +- src/utils/middleware/lollipop.ts | 13 ++-- src/utils/network.ts | 4 +- src/utils/ognl.ts | 4 +- src/utils/package.ts | 7 +- src/utils/profile.ts | 13 ++-- src/utils/qrcode.ts | 2 +- src/utils/redis.ts | 7 +- src/utils/responses.ts | 15 ++-- src/utils/strategies.ts | 7 +- src/utils/thirdPartyConfig.ts | 4 +- src/utils/url.ts | 2 +- 103 files changed, 521 insertions(+), 532 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index e4a30a16b..2439ab8f3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -7,10 +7,8 @@ export default [ "comma-dangle": "off", "perfectionist/sort-classes": "off", "perfectionist/sort-enums": "off", - "perfectionist/sort-imports": "off", "perfectionist/sort-interfaces": "off", "perfectionist/sort-intersection-types": "off", - "perfectionist/sort-named-imports": "off", "perfectionist/sort-objects": "off", "perfectionist/sort-object-types": "off", "perfectionist/sort-union-types": "off", diff --git a/src/adapters/pnFetch.ts b/src/adapters/pnFetch.ts index c0578343a..720e206d2 100644 --- a/src/adapters/pnFetch.ts +++ b/src/adapters/pnFetch.ts @@ -1,27 +1,28 @@ /* eslint-disable max-params */ -import { URL } from "url"; -import { flow, pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; -import * as E from "fp-ts/Either"; -import * as TE from "fp-ts/TaskEither"; -import * as O from "fp-ts/Option"; +import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; import { FiscalCode, NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; -import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; -import { Response as NodeResponse } from "node-fetch"; +import { eventLog } from "@pagopa/winston-ts"; +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; +import * as TE from "fp-ts/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; import { NotificationAttachmentDownloadMetadataResponse } from "generated/piattaforma-notifiche/NotificationAttachmentDownloadMetadataResponse"; -import { match } from "ts-pattern"; -import { LollipopLocalsType } from "src/types/lollipop"; -import { Fetch } from "src/clients/third-party-service-client"; +import * as t from "io-ts"; +import { Response as NodeResponse } from "node-fetch"; import nodeFetch from "node-fetch"; -import { eventLog } from "@pagopa/winston-ts"; +import { Fetch } from "src/clients/third-party-service-client"; +import { LollipopLocalsType } from "src/types/lollipop"; +import { match } from "ts-pattern"; +import { URL } from "url"; + import { PnAPIClient } from "../clients/pn-clients"; -import { errorsToError } from "../utils/errorsFormatter"; -import { pathParamsFromUrl } from "../types/pathParams"; import { PN_CONFIGURATION_ID } from "../config"; +import { pathParamsFromUrl } from "../types/pathParams"; +import { errorsToError } from "../utils/errorsFormatter"; const getPath = (input: RequestInfo | URL): string => input instanceof URL diff --git a/src/app.ts b/src/app.ts index 999f66019..9a049011e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -2,15 +2,6 @@ /** * Main entry point for the Digital Citizenship proxy. */ -import * as bodyParser from "body-parser"; -import * as express from "express"; -import * as helmet from "helmet"; -import * as morgan from "morgan"; -import * as passport from "passport"; - -import { Express } from "express"; -import expressEnforcesSsl = require("express-enforces-ssl"); - import { TableClient } from "@azure/data-tables"; import { NodeEnvironment, @@ -19,14 +10,21 @@ import { import { ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import { CIDR, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as appInsights from "applicationinsights"; +import * as bodyParser from "body-parser"; +import * as express from "express"; +import { Express } from "express"; import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; -import { ServerInfo } from "../generated/public/ServerInfo"; +import * as helmet from "helmet"; +import * as morgan from "morgan"; +import * as passport from "passport"; +import { ServerInfo } from "../generated/public/ServerInfo"; import { VersionPerPlatform } from "../generated/public/VersionPerPlatform"; -import { getUserIdentity } from "./controllers/authenticationController"; +import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; +import { LollipopApiClient } from "./clients/lollipop"; import { API_CLIENT, APP_MESSAGES_API_CLIENT, @@ -40,16 +38,16 @@ import { FF_ENABLE_NOTIFY_ENDPOINT, FF_ENABLE_SESSION_ENDPOINTS, FF_EUCOVIDCERT_ENABLED, - FF_IO_SIGN_ENABLED, FF_IO_FIMS_ENABLED, + FF_IO_SIGN_ENABLED, FF_IO_WALLET_ENABLED, FF_ROUTING_PUSH_NOTIF, FF_ROUTING_PUSH_NOTIF_BETA_TESTER_SHA_LIST, FF_ROUTING_PUSH_NOTIF_CANARY_SHA_USERS_REGEX, FF_TRIAL_SYSTEM_ENABLED, FIRST_LOLLIPOP_CONSUMER_CLIENT, - IO_SIGN_API_CLIENT, IO_FIMS_API_CLIENT, + IO_SIGN_API_CLIENT, IO_SIGN_SERVICE_ID, IO_WALLET_API_CLIENT, LOCKED_PROFILES_STORAGE_CONNECTION_STRING, @@ -57,13 +55,13 @@ import { LOLLIPOP_API_CLIENT, LOLLIPOP_REVOKE_QUEUE_NAME, LOLLIPOP_REVOKE_STORAGE_CONNECTION_STRING, - NOTIFICATIONS_QUEUE_NAME, - NOTIFICATIONS_STORAGE_CONNECTION_STRING, NOTIFICATION_DEFAULT_SUBJECT, NOTIFICATION_DEFAULT_TITLE, + NOTIFICATIONS_QUEUE_NAME, + NOTIFICATIONS_STORAGE_CONNECTION_STRING, PAGOPA_CLIENT, - PNAddressBookConfig, PN_ADDRESS_BOOK_CLIENT_SELECTOR, + PNAddressBookConfig, PUSH_NOTIFICATIONS_QUEUE_NAME, PUSH_NOTIFICATIONS_STORAGE_CONNECTION_STRING, ROOT_REDIRECT_URL, @@ -72,42 +70,41 @@ import { TRIAL_SYSTEM_CLIENT, URL_TOKEN_STRATEGY } from "./config"; -import MessagesController from "./controllers/messagesController"; -import NotificationController from "./controllers/notificationController"; -import PagoPAProxyController from "./controllers/pagoPAProxyController"; -import ProfileController from "./controllers/profileController"; -import ServicesController from "./controllers/servicesController"; -import SessionController from "./controllers/sessionController"; -import UserMetadataController from "./controllers/userMetadataController"; - -import { log } from "./utils/logger"; -import checkIP from "./utils/middleware/checkIP"; - -import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; -import { LollipopApiClient } from "./clients/lollipop"; +import { getUserIdentity } from "./controllers/authenticationController"; import BonusController from "./controllers/bonusController"; import CgnController from "./controllers/cgnController"; import CgnOperatorSearchController from "./controllers/cgnOperatorSearchController"; import EUCovidCertController from "./controllers/eucovidcertController"; +import IoFimsController from "./controllers/fimsController"; import { firstLollipopSign } from "./controllers/firstLollipopConsumerController"; import IoSignController from "./controllers/ioSignController"; +import IoWalletController from "./controllers/ioWalletController"; +import MessagesController from "./controllers/messagesController"; +import NotificationController from "./controllers/notificationController"; +import PagoPAProxyController from "./controllers/pagoPAProxyController"; import { getPNActivationController, upsertPNActivationController } from "./controllers/pnController"; +import ProfileController from "./controllers/profileController"; import ServicesAppBackendController from "./controllers/serviceAppBackendController"; +import ServicesController from "./controllers/servicesController"; +import SessionController from "./controllers/sessionController"; import SessionLockController from "./controllers/sessionLockController"; import { getUserForMyPortal } from "./controllers/ssoController"; +import TrialController from "./controllers/trialController"; import UserDataProcessingController from "./controllers/userDataProcessingController"; +import UserMetadataController from "./controllers/userMetadataController"; import { ISessionStorage } from "./services/ISessionStorage"; import AuthenticationLockService from "./services/authenticationLockService"; import BonusService from "./services/bonusService"; import CgnOperatorSearchService from "./services/cgnOperatorSearchService"; import CgnService from "./services/cgnService"; import EUCovidCertService from "./services/eucovidcertService"; +import IoFimsService from "./services/fimsService"; import FunctionsAppService from "./services/functionAppService"; import IoSignService from "./services/ioSignService"; -import IoFimsService from "./services/fimsService"; +import IoWalletService from "./services/ioWalletService"; import LollipopService from "./services/lollipopService"; import NewMessagesService from "./services/newMessagesService"; import NotificationService from "./services/notificationService"; @@ -121,6 +118,7 @@ import ProfileService from "./services/profileService"; import RedisSessionStorage from "./services/redisSessionStorage"; import RedisUserMetadataStorage from "./services/redisUserMetadataStorage"; import ServicesAppBackendService from "./services/servicesAppBackendService"; +import TrialService from "./services/trialService"; import UserDataProcessingService from "./services/userDataProcessingService"; import bearerMyPortalTokenStrategy from "./strategies/bearerMyPortalTokenStrategy"; import bearerSessionTokenStrategy from "./strategies/bearerSessionTokenStrategy"; @@ -128,6 +126,8 @@ import { User } from "./types/user"; import { attachTrackingData } from "./utils/appinsights"; import { getRequiredENVVar } from "./utils/container"; import { constantExpressHandler, toExpressHandler } from "./utils/express"; +import { log } from "./utils/logger"; +import checkIP from "./utils/middleware/checkIP"; import { expressErrorMiddleware } from "./utils/middleware/express"; import { expressLollipopMiddleware, @@ -139,11 +139,8 @@ import { } from "./utils/package"; import { RedisClientMode, RedisClientSelector } from "./utils/redis"; import { ResponseErrorDismissed } from "./utils/responses"; -import TrialService from "./services/trialService"; -import TrialController from "./controllers/trialController"; -import IoWalletController from "./controllers/ioWalletController"; -import IoWalletService from "./services/ioWalletService"; -import IoFimsController from "./controllers/fimsController"; + +import expressEnforcesSsl = require("express-enforces-ssl"); const defaultModule = { // eslint-disable-next-line @typescript-eslint/no-use-before-define diff --git a/src/clients/api.ts b/src/clients/api.ts index cfb8425c2..7212abeb3 100644 --- a/src/clients/api.ts +++ b/src/clients/api.ts @@ -1,5 +1,5 @@ -import nodeFetch from "node-fetch"; import { Client, createClient } from "@pagopa/io-functions-app-sdk/client"; +import nodeFetch from "node-fetch"; export function APIClient( baseUrl: string, diff --git a/src/clients/app-messages.client.ts b/src/clients/app-messages.client.ts index 538a76c1d..806b07db5 100644 --- a/src/clients/app-messages.client.ts +++ b/src/clients/app-messages.client.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-messages-api/client"; export function AppMessagesAPIClient( diff --git a/src/clients/bonus.ts b/src/clients/bonus.ts index a0ef88a28..39a71f09d 100644 --- a/src/clients/bonus.ts +++ b/src/clients/bonus.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-bonus-api/client"; export function BonusAPIClient( diff --git a/src/clients/cgn-operator-search.ts b/src/clients/cgn-operator-search.ts index fc6eacc1c..cdcb0974f 100644 --- a/src/clients/cgn-operator-search.ts +++ b/src/clients/cgn-operator-search.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient diff --git a/src/clients/cgn.ts b/src/clients/cgn.ts index ebe48ccf4..fa38ebfbc 100644 --- a/src/clients/cgn.ts +++ b/src/clients/cgn.ts @@ -1,5 +1,5 @@ -import nodeFetch from "node-fetch"; import { Client, createClient } from "@pagopa/io-functions-cgn-sdk/client"; +import nodeFetch from "node-fetch"; export function CgnAPIClient( token: string, diff --git a/src/clients/eucovidcert.client.ts b/src/clients/eucovidcert.client.ts index 3e06a7a43..ac07edba9 100644 --- a/src/clients/eucovidcert.client.ts +++ b/src/clients/eucovidcert.client.ts @@ -1,8 +1,8 @@ -import nodeFetch from "node-fetch"; import { Client, createClient } from "@pagopa/io-functions-eucovidcerts-sdk/client"; +import nodeFetch from "node-fetch"; export function EUCovidCertAPIClient( token: string, diff --git a/src/clients/firstLollipopConsumer.ts b/src/clients/firstLollipopConsumer.ts index 6afc8d43a..03f20021c 100644 --- a/src/clients/firstLollipopConsumer.ts +++ b/src/clients/firstLollipopConsumer.ts @@ -1,7 +1,8 @@ import * as nodeFetch from "node-fetch"; + import { - createClient, - Client + Client, + createClient } from "../../generated/lollipop-first-consumer/client"; export function FirstLollipopConsumerClient( diff --git a/src/clients/io-fims.ts b/src/clients/io-fims.ts index 815d7136e..49bc15987 100644 --- a/src/clients/io-fims.ts +++ b/src/clients/io-fims.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-fims-api/client"; export function IoFimsAPIClient( diff --git a/src/clients/io-sign.ts b/src/clients/io-sign.ts index 4c6a3d0cb..0395761f5 100644 --- a/src/clients/io-sign.ts +++ b/src/clients/io-sign.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/io-sign-api/client"; export function IoSignAPIClient( diff --git a/src/clients/lollipop.ts b/src/clients/lollipop.ts index 19fa48e34..97b7c6cea 100644 --- a/src/clients/lollipop.ts +++ b/src/clients/lollipop.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/lollipop-api/client"; export function LollipopApiClient( diff --git a/src/clients/pagopa.ts b/src/clients/pagopa.ts index fdb646261..46a814b20 100644 --- a/src/clients/pagopa.ts +++ b/src/clients/pagopa.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/pagopa-proxy/client"; export function PagoPAClient( diff --git a/src/clients/pn-clients.ts b/src/clients/pn-clients.ts index 42ce1c612..7ada0579f 100644 --- a/src/clients/pn-clients.ts +++ b/src/clients/pn-clients.ts @@ -1,6 +1,6 @@ -import nodeFetch from "node-fetch"; import { ValidUrl } from "@pagopa/ts-commons/lib/url"; -import { stripTrailingSlashIfPresent } from "../utils/url"; +import nodeFetch from "node-fetch"; + import { Client, createClient @@ -9,6 +9,7 @@ import { Client as AddressBookClient, createClient as createAddressBookClient } from "../../generated/piattaforma-notifiche-courtesy/client"; +import { stripTrailingSlashIfPresent } from "../utils/url"; export function PnAPIClient( baseUrl: string, diff --git a/src/clients/services-app-backend.ts b/src/clients/services-app-backend.ts index 4915808dc..bddfcde59 100644 --- a/src/clients/services-app-backend.ts +++ b/src/clients/services-app-backend.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient diff --git a/src/clients/third-party-service-client.ts b/src/clients/third-party-service-client.ts index 130d50349..dcfe7dca4 100644 --- a/src/clients/third-party-service-client.ts +++ b/src/clients/third-party-service-client.ts @@ -1,19 +1,18 @@ -import { pipe } from "fp-ts/lib/function"; - import { FiscalCode } from "@pagopa/io-functions-app-sdk/FiscalCode"; -import { LollipopLocalsType } from "src/types/lollipop"; import { eventLog } from "@pagopa/winston-ts"; -import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; - +import { pipe } from "fp-ts/lib/function"; import { RCAuthenticationConfig } from "generated/io-messages-api/RCAuthenticationConfig"; import { RCConfigurationProdEnvironment } from "generated/io-messages-api/RCConfigurationProdEnvironment"; +import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; import { RCConfigurationTestEnvironment } from "generated/io-messages-api/RCConfigurationTestEnvironment"; import { Ulid } from "generated/parameters/Ulid"; -import { pnFetch } from "../adapters/pnFetch"; +import { LollipopLocalsType } from "src/types/lollipop"; + import { Client, createClient } from "../../generated/third-party-service/client"; +import { pnFetch } from "../adapters/pnFetch"; // --- diff --git a/src/clients/trial-system.client.ts b/src/clients/trial-system.client.ts index d29edd3d6..9dfdcb1e5 100644 --- a/src/clients/trial-system.client.ts +++ b/src/clients/trial-system.client.ts @@ -1,4 +1,5 @@ import nodeFetch from "node-fetch"; + import { Client, createClient } from "../../generated/trial-system-api/client"; export function TrialSystemAPIClient( diff --git a/src/config.ts b/src/config.ts index ba0943939..7dfa543d9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,51 +2,50 @@ * Defines services and register them to the Service Container. */ -import * as dotenv from "dotenv"; -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; -import * as t from "io-ts"; import { agent } from "@pagopa/ts-commons"; - import { getNodeEnvironmentFromProcessEnv } from "@pagopa/ts-commons/lib/environment"; -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; -import { HttpsUrlFromString, UrlFromString } from "@pagopa/ts-commons/lib/url"; - import { AbortableFetch, setFetchTimeout, toFetch } from "@pagopa/ts-commons/lib/fetch"; +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { Millisecond } from "@pagopa/ts-commons/lib/units"; +import { HttpsUrlFromString, UrlFromString } from "@pagopa/ts-commons/lib/url"; +import * as dotenv from "dotenv"; +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; import { pipe } from "fp-ts/lib/function"; -import { CgnAPIClient } from "./clients/cgn"; -import { log } from "./utils/logger"; -import urlTokenStrategy from "./strategies/urlTokenStrategy"; -import { getRequiredENVVar } from "./utils/container"; -import PagoPAClientFactory from "./services/pagoPAClientFactory"; -import ApiClientFactory from "./services/apiClientFactory"; +import * as t from "io-ts"; + +import { AppMessagesAPIClient } from "./clients/app-messages.client"; import { BonusAPIClient } from "./clients/bonus"; -import { decodeCIDRs } from "./utils/network"; +import { CgnAPIClient } from "./clients/cgn"; import { CgnOperatorSearchAPIClient } from "./clients/cgn-operator-search"; -import { ServicesAppBackendAPIClient } from "./clients/services-app-backend"; import { EUCovidCertAPIClient } from "./clients/eucovidcert.client"; -import { ognlTypeFor } from "./utils/ognl"; -import { AppMessagesAPIClient } from "./clients/app-messages.client"; -import { PNClientFactory } from "./clients/pn-clients"; +import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; +import { IoFimsAPIClient } from "./clients/io-fims"; import { IoSignAPIClient } from "./clients/io-sign"; +import { IoWalletAPIClient } from "./clients/io-wallet"; +import { LollipopApiClient } from "./clients/lollipop"; +import { PNClientFactory } from "./clients/pn-clients"; +import { ServicesAppBackendAPIClient } from "./clients/services-app-backend"; +import { TrialSystemAPIClient } from "./clients/trial-system.client"; +import ApiClientFactory from "./services/apiClientFactory"; +import PagoPAClientFactory from "./services/pagoPAClientFactory"; +import urlTokenStrategy from "./strategies/urlTokenStrategy"; +import { getRequiredENVVar } from "./utils/container"; import { FeatureFlag, FeatureFlagEnum, getIsUserEligibleForNewFeature } from "./utils/featureFlag"; +import { log } from "./utils/logger"; +import { decodeCIDRs } from "./utils/network"; +import { ognlTypeFor } from "./utils/ognl"; import { CommaSeparatedListOf } from "./utils/separated-list"; -import { LollipopApiClient } from "./clients/lollipop"; -import { FirstLollipopConsumerClient } from "./clients/firstLollipopConsumer"; -import { TrialSystemAPIClient } from "./clients/trial-system.client"; -import { IoWalletAPIClient } from "./clients/io-wallet"; -import { IoFimsAPIClient } from "./clients/io-fims"; // Without this, the environment variables loaded by dotenv aren't available in // this file. diff --git a/src/controllers/authenticationController.ts b/src/controllers/authenticationController.ts index deb5dfe14..3e90e2e20 100644 --- a/src/controllers/authenticationController.ts +++ b/src/controllers/authenticationController.ts @@ -4,8 +4,6 @@ * the IDP. */ -import * as express from "express"; -import * as E from "fp-ts/lib/Either"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -13,10 +11,11 @@ import { ResponseErrorInternal, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - +import * as express from "express"; +import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; -import { UserIdentity } from "../../generated/auth/UserIdentity"; +import { UserIdentity } from "../../generated/auth/UserIdentity"; import { exactUserIdentityDecode, withUserFromRequest } from "../types/user"; /** diff --git a/src/controllers/bonusController.ts b/src/controllers/bonusController.ts index 78d7743a4..d667afd27 100644 --- a/src/controllers/bonusController.ts +++ b/src/controllers/bonusController.ts @@ -3,7 +3,6 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; import { IResponseErrorGone, IResponseErrorInternal, @@ -12,11 +11,12 @@ import { IResponseSuccessAccepted, IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { PaginatedBonusActivationsCollection } from "generated/io-bonus-api/PaginatedBonusActivationsCollection"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import BonusService from "src/services/bonusService"; + import { EligibilityCheck } from "../../generated/io-bonus-api/EligibilityCheck"; import { InstanceId } from "../../generated/io-bonus-api/InstanceId"; import { withUserFromRequest } from "../types/user"; diff --git a/src/controllers/cgnController.ts b/src/controllers/cgnController.ts index bcc7e033c..47714afb3 100644 --- a/src/controllers/cgnController.ts +++ b/src/controllers/cgnController.ts @@ -3,7 +3,9 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; +import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; +import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; +import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -15,15 +17,13 @@ import { IResponseSuccessRedirectToResource, ResponseErrorForbiddenNotAuthorized } from "@pagopa/ts-commons/lib/responses"; - -import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; -import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import { Otp } from "generated/cgn/Otp"; -import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; + import { Card } from "../../generated/cgn/Card"; -import CgnService from "../../src/services/cgnService"; import { InstanceId } from "../../generated/cgn/InstanceId"; +import CgnService from "../../src/services/cgnService"; import { User, withUserFromRequest } from "../types/user"; export const withAllowedUser = async ( diff --git a/src/controllers/cgnOperatorSearchController.ts b/src/controllers/cgnOperatorSearchController.ts index 82717f191..6035e9c6a 100644 --- a/src/controllers/cgnOperatorSearchController.ts +++ b/src/controllers/cgnOperatorSearchController.ts @@ -4,7 +4,6 @@ */ import { IResponseErrorForbiddenNotAuthorized } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; import { IResponse, IResponseErrorInternal, @@ -15,21 +14,23 @@ import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import CgnService from "src/services/cgnService"; +import * as express from "express"; import * as E from "fp-ts/Either"; -import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; -import { Card } from "generated/cgn/Card"; import { pipe } from "fp-ts/lib/function"; -import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; +import { Card } from "generated/cgn/Card"; import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; +import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; +import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; +import CgnService from "src/services/cgnService"; + import { Merchant } from "../../generated/cgn-operator-search/Merchant"; import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; -import { GetPublishedCategoriesParameters } from "../../generated/parameters/GetPublishedCategoriesParameters"; import { PublishedProductCategoriesResult } from "../../generated/cgn-operator-search/PublishedProductCategoriesResult"; import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; import { SearchRequest } from "../../generated/io-cgn-operator-search-api/SearchRequest"; +import { GetPublishedCategoriesParameters } from "../../generated/parameters/GetPublishedCategoriesParameters"; import CgnOperatorSearchService from "../services/cgnOperatorSearchService"; import { User, withUserFromRequest } from "../types/user"; import { withValidatedOrValidationError } from "../utils/responses"; diff --git a/src/controllers/eucovidcertController.ts b/src/controllers/eucovidcertController.ts index 831b55799..d8ceb0027 100644 --- a/src/controllers/eucovidcertController.ts +++ b/src/controllers/eucovidcertController.ts @@ -1,5 +1,4 @@ -import * as express from "express"; - +import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; import { IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, @@ -7,13 +6,13 @@ import { IResponseErrorValidation, IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; -import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; import { GetCertificateParams } from "../../generated/eucovidcert/GetCertificateParams"; import { PreferredLanguages } from "../../generated/eucovidcert/PreferredLanguages"; -import { withValidatedOrValidationError } from "../utils/responses"; import EUCovidService from "../services/eucovidcertService"; import { withUserFromRequest } from "../types/user"; +import { withValidatedOrValidationError } from "../utils/responses"; export const withGetCertificateParams = async ( req: express.Request, diff --git a/src/controllers/fimsController.ts b/src/controllers/fimsController.ts index 52c1765cc..4e59c824c 100644 --- a/src/controllers/fimsController.ts +++ b/src/controllers/fimsController.ts @@ -3,10 +3,6 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; -import * as t from "io-ts"; - import { IResponseErrorConflict, IResponseErrorInternal, @@ -15,18 +11,17 @@ import { IResponseSuccessJson, ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; - -import { pipe } from "fp-ts/lib/function"; import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; - +import * as express from "express"; +import * as TE from "fp-ts/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { AccessHistoryPage } from "generated/io-fims/AccessHistoryPage"; import { ExportRequest } from "generated/io-fims/ExportRequest"; +import * as t from "io-ts"; import IoFimsService from "../services/fimsService"; - -import { withUserFromRequest } from "../types/user"; import ProfileService from "../services/profileService"; - +import { withUserFromRequest } from "../types/user"; import { profileWithEmailValidatedOrError } from "../utils/profile"; const responseErrorInternal = (reason: string) => (e: Error) => diff --git a/src/controllers/firstLollipopConsumerController.ts b/src/controllers/firstLollipopConsumerController.ts index 65c65164a..6d46d6dc9 100644 --- a/src/controllers/firstLollipopConsumerController.ts +++ b/src/controllers/firstLollipopConsumerController.ts @@ -1,3 +1,4 @@ +import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -5,20 +6,18 @@ import { ResponseErrorInternal, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; -import * as express from "express"; -import { flow, pipe } from "fp-ts/lib/function"; -import * as TE from "fp-ts/TaskEither"; -import * as E from "fp-ts/Either"; -import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import { pick } from "@pagopa/ts-commons/lib/types"; +import * as express from "express"; +import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; import { SignMessageResponse } from "../../generated/first-lc-proxy-models/SignMessageResponse"; - -import { logLollipopSignRequest } from "../utils/appinsights"; import { FirstLollipopConsumerClient } from "../clients/firstLollipopConsumer"; -import { ResLocals } from "../utils/express"; import { withLollipopLocals, withRequiredRawBody } from "../types/lollipop"; +import { logLollipopSignRequest } from "../utils/appinsights"; +import { ResLocals } from "../utils/express"; const FIRST_LOLLIPOP_CONSUMER_ID = "fist-lollipop-consumer" as NonEmptyString; diff --git a/src/controllers/ioSignController.ts b/src/controllers/ioSignController.ts index 2ad8ba607..0af9d7d41 100644 --- a/src/controllers/ioSignController.ts +++ b/src/controllers/ioSignController.ts @@ -3,12 +3,7 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; -import * as E from "fp-ts/Either"; -import * as t from "io-ts"; -import { sequenceS } from "fp-ts/lib/Apply"; - +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -18,37 +13,38 @@ import { ResponseErrorInternal, ResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; - -import { pipe } from "fp-ts/lib/function"; import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import * as express from "express"; +import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; +import { sequenceS } from "fp-ts/lib/Apply"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; import { Errors } from "io-ts"; -import { - withValidatedOrValidationError, - withCatchAsInternalError -} from "../utils/responses"; + +import { CreateFilledDocument } from "../../generated/io-sign/CreateFilledDocument"; +import { CreateSignatureBody } from "../../generated/io-sign/CreateSignatureBody"; +import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; +import { Id } from "../../generated/io-sign/Id"; import { IssuerEnvironment, IssuerEnvironmentEnum } from "../../generated/io-sign/IssuerEnvironment"; -import IoSignService from "../services/ioSignService"; -import { ResLocals } from "../utils/express"; -import { LollipopLocalsType, withLollipopLocals } from "../types/lollipop"; -import { Id } from "../../generated/io-sign/Id"; import { QtspClausesMetadataDetailView } from "../../generated/io-sign/QtspClausesMetadataDetailView"; import { SignatureDetailView } from "../../generated/io-sign/SignatureDetailView"; import { SignatureRequestDetailView } from "../../generated/io-sign/SignatureRequestDetailView"; -import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; -import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; - -import { CreateFilledDocument } from "../../generated/io-sign/CreateFilledDocument"; -import { CreateSignatureBody } from "../../generated/io-sign/CreateSignatureBody"; - -import { withUserFromRequest } from "../types/user"; +import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; +import IoSignService from "../services/ioSignService"; import ProfileService from "../services/profileService"; - +import { LollipopLocalsType, withLollipopLocals } from "../types/lollipop"; +import { withUserFromRequest } from "../types/user"; +import { ResLocals } from "../utils/express"; import { profileWithEmailValidatedOrError } from "../utils/profile"; +import { + withCatchAsInternalError, + withValidatedOrValidationError +} from "../utils/responses"; const responseErrorValidation = (errs: Errors) => ResponseErrorValidation( diff --git a/src/controllers/ioWalletController.ts b/src/controllers/ioWalletController.ts index 30afd0718..8daa6340b 100644 --- a/src/controllers/ioWalletController.ts +++ b/src/controllers/ioWalletController.ts @@ -3,12 +3,8 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; -import * as E from "fp-ts/Either"; - +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { - getResponseErrorForbiddenNotAuthorized, IResponseErrorForbiddenNotAuthorized, IResponseErrorGeneric, IResponseErrorInternal, @@ -17,24 +13,26 @@ import { IResponseErrorValidation, IResponseSuccessJson, IResponseSuccessNoContent, - ResponseErrorValidation + ResponseErrorValidation, + getResponseErrorForbiddenNotAuthorized } from "@pagopa/ts-commons/lib/responses"; - -import { pipe } from "fp-ts/lib/function"; +import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; +import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; import { sequenceS } from "fp-ts/lib/Apply"; +import { pipe } from "fp-ts/lib/function"; import { Errors } from "io-ts"; -import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; -import IoWalletService from "../services/ioWalletService"; -import { NonceDetailView } from "../../generated/io-wallet/NonceDetailView"; -import { withUserFromRequest } from "../types/user"; -import { CreateWalletInstanceBody } from "../../generated/io-wallet/CreateWalletInstanceBody"; import { CreateWalletAttestationBody } from "../../generated/io-wallet/CreateWalletAttestationBody"; -import { WalletAttestationView } from "../../generated/io-wallet/WalletAttestationView"; -import { FF_IO_WALLET_TRIAL_ENABLED } from "../config"; +import { CreateWalletInstanceBody } from "../../generated/io-wallet/CreateWalletInstanceBody"; +import { NonceDetailView } from "../../generated/io-wallet/NonceDetailView"; import { SetWalletInstanceStatusBody } from "../../generated/io-wallet/SetWalletInstanceStatusBody"; +import { WalletAttestationView } from "../../generated/io-wallet/WalletAttestationView"; import { WalletInstanceData } from "../../generated/io-wallet/WalletInstanceData"; +import { FF_IO_WALLET_TRIAL_ENABLED } from "../config"; +import IoWalletService from "../services/ioWalletService"; +import { withUserFromRequest } from "../types/user"; const toValidationError = (errors: Errors) => ResponseErrorValidation( diff --git a/src/controllers/messagesController.ts b/src/controllers/messagesController.ts index 29e661f88..fe1c8e0b1 100644 --- a/src/controllers/messagesController.ts +++ b/src/controllers/messagesController.ts @@ -3,7 +3,7 @@ * forwarding the call to the API system. */ -import * as express from "express"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorBadGateway, IResponseErrorInternal, @@ -14,41 +14,40 @@ import { IResponseSuccessJson, IResponseSuccessNoContent } from "@pagopa/ts-commons/lib/responses"; - -import { CreatedMessageWithContentAndAttachments } from "generated/backend/CreatedMessageWithContentAndAttachments"; import { IResponseErrorForbiddenNotAuthorized, ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; -import * as t from "io-ts"; -import { pipe } from "fp-ts/lib/function"; -import * as TE from "fp-ts/TaskEither"; +import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import * as E from "fp-ts/Either"; +import * as TE from "fp-ts/TaskEither"; import * as B from "fp-ts/boolean"; -import { NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; -import NewMessagesService from "src/services/newMessagesService"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import { pipe } from "fp-ts/lib/function"; +import { CreatedMessageWithContentAndAttachments } from "generated/backend/CreatedMessageWithContentAndAttachments"; +import * as t from "io-ts"; import * as QueryString from "qs"; -import { User, withUserFromRequest } from "../types/user"; +import NewMessagesService from "src/services/newMessagesService"; -import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; -import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; import { PaginatedPublicMessagesCollection } from "../../generated/backend/PaginatedPublicMessagesCollection"; -import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; -import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; -import { - withValidatedOrValidationError, - IResponseSuccessOctet, - IResponseErrorNotImplemented, - IResponseErrorUnsupportedMediaType -} from "../utils/responses"; -import { LollipopLocalsType, LollipopRequiredHeaders } from "../types/lollipop"; +import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; +import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; +import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; +import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; import { LollipopApiClient } from "../clients/lollipop"; import { ISessionStorage } from "../services/ISessionStorage"; +import { LollipopLocalsType, LollipopRequiredHeaders } from "../types/lollipop"; +import { User, withUserFromRequest } from "../types/user"; import { extractLollipopLocalsFromLollipopHeadersLegacy } from "../utils/lollipop"; import { checkIfLollipopIsEnabled } from "../utils/lollipop"; +import { + IResponseErrorNotImplemented, + IResponseErrorUnsupportedMediaType, + IResponseSuccessOctet, + withValidatedOrValidationError +} from "../utils/responses"; export const withGetThirdPartyAttachmentParams = async ( req: express.Request, diff --git a/src/controllers/notificationController.ts b/src/controllers/notificationController.ts index 57ee81d24..333b5a55b 100644 --- a/src/controllers/notificationController.ts +++ b/src/controllers/notificationController.ts @@ -2,25 +2,23 @@ * This controller handles webhook requests from the API backend. */ -import * as express from "express"; import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - +import { Millisecond } from "@pagopa/ts-commons/lib/units"; +import * as express from "express"; import * as E from "fp-ts/lib/Either"; import * as TE from "fp-ts/lib/TaskEither"; -import { Millisecond } from "@pagopa/ts-commons/lib/units"; import { pipe } from "fp-ts/lib/function"; import { NotificationServiceFactory } from "src/services/notificationServiceFactory"; + import { Installation } from "../../generated/backend/Installation"; import { InstallationID } from "../../generated/backend/InstallationID"; - import { Notification } from "../../generated/notifications/Notification"; import { SuccessResponse } from "../../generated/notifications/SuccessResponse"; - import RedisSessionStorage from "../services/redisSessionStorage"; import { withUserFromRequest } from "../types/user"; import { log } from "../utils/logger"; diff --git a/src/controllers/pagoPAProxyController.ts b/src/controllers/pagoPAProxyController.ts index aca6252dd..9cd0da6e8 100644 --- a/src/controllers/pagoPAProxyController.ts +++ b/src/controllers/pagoPAProxyController.ts @@ -1,19 +1,17 @@ -import * as express from "express"; -import * as t from "io-ts"; import { IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - -import PagoPAProxyService from "../services/pagoPAProxyService"; +import * as express from "express"; +import * as t from "io-ts"; import { PaymentActivationsGetResponse } from "../../generated/backend/PaymentActivationsGetResponse"; import { PaymentActivationsPostResponse } from "../../generated/backend/PaymentActivationsPostResponse"; import { PaymentRequestsGetResponse } from "../../generated/backend/PaymentRequestsGetResponse"; import { PaymentActivationsPostRequest } from "../../generated/pagopa-proxy/PaymentActivationsPostRequest"; - +import PagoPAProxyService from "../services/pagoPAProxyService"; import { withValidatedOrInternalError } from "../utils/responses"; const parsePagopaTestParam = (testParam: unknown) => diff --git a/src/controllers/pnController.ts b/src/controllers/pnController.ts index 29668aaa0..0518c0776 100644 --- a/src/controllers/pnController.ts +++ b/src/controllers/pnController.ts @@ -6,19 +6,20 @@ import { ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; -import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; +import * as TE from "fp-ts/TaskEither"; import { pipe } from "fp-ts/lib/function"; + +import { PNActivation } from "../../generated/api_piattaforma-notifiche-courtesy/PNActivation"; import { PNEnvironment } from "../clients/pn-clients"; +import { PNService } from "../services/pnService"; import { withUserFromRequest } from "../types/user"; import { IResponseNoContent, ResponseNoContent, withValidatedOrValidationError } from "../utils/responses"; -import { PNActivation } from "../../generated/api_piattaforma-notifiche-courtesy/PNActivation"; -import { PNService } from "../services/pnService"; /** * Upsert the Activation for `Avvisi di Cortesia` Piattaforma Notifiche diff --git a/src/controllers/profileController.ts b/src/controllers/profileController.ts index 5d78ab1dc..88b58cba3 100644 --- a/src/controllers/profileController.ts +++ b/src/controllers/profileController.ts @@ -3,7 +3,7 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; +import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -14,12 +14,11 @@ import { IResponseSuccessAccepted, IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import { ISessionStorage } from "src/services/ISessionStorage"; -import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { Profile } from "../../generated/backend/Profile"; - import ProfileService from "../services/profileService"; import { profileMissingErrorResponse } from "../types/profile"; import { withUserFromRequest } from "../types/user"; diff --git a/src/controllers/serviceAppBackendController.ts b/src/controllers/serviceAppBackendController.ts index 14271400f..28174fc58 100644 --- a/src/controllers/serviceAppBackendController.ts +++ b/src/controllers/serviceAppBackendController.ts @@ -7,11 +7,12 @@ import { import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; + import { FeaturedServices } from "../../generated/services-app-backend/FeaturedServices"; -import { Institutions } from "../../generated/services-app-backend/Institutions"; import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; +import { Institutions } from "../../generated/services-app-backend/Institutions"; import { InstitutionsResource } from "../../generated/services-app-backend/InstitutionsResource"; import { ScopeType } from "../../generated/services-app-backend/ScopeType"; import { ServiceDetails } from "../../generated/services-app-backend/ServiceDetails"; diff --git a/src/controllers/servicesController.ts b/src/controllers/servicesController.ts index 684d93c79..fd6e95ae0 100644 --- a/src/controllers/servicesController.ts +++ b/src/controllers/servicesController.ts @@ -12,14 +12,13 @@ import { IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; -import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; -import { withUserFromRequest } from "../../src/types/user"; -import { withValidatedOrValidationError } from "../../src/utils/responses"; +import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; import { ServicePreference } from "../../generated/backend/ServicePreference"; import { ServicePublic } from "../../generated/backend/ServicePublic"; import { UpsertServicePreference } from "../../generated/backend/UpsertServicePreference"; - +import { withUserFromRequest } from "../../src/types/user"; +import { withValidatedOrValidationError } from "../../src/utils/responses"; import FunctionsAppService from "../services/functionAppService"; export default class ServicesController { diff --git a/src/controllers/sessionController.ts b/src/controllers/sessionController.ts index 89a73a801..b02c25d0f 100644 --- a/src/controllers/sessionController.ts +++ b/src/controllers/sessionController.ts @@ -2,7 +2,6 @@ * This controller returns data about the current user session */ -import * as express from "express"; import { IResponseErrorInternal, IResponseErrorValidation, @@ -10,7 +9,9 @@ import { ResponseErrorInternal, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import * as E from "fp-ts/lib/Either"; + import { SessionsList } from "../../generated/backend/SessionsList"; import RedisSessionStorage from "../services/redisSessionStorage"; import { withUserFromRequest } from "../types/user"; diff --git a/src/controllers/sessionLockController.ts b/src/controllers/sessionLockController.ts index 58b79aa7e..85dcac594 100644 --- a/src/controllers/sessionLockController.ts +++ b/src/controllers/sessionLockController.ts @@ -2,7 +2,7 @@ * This controller returns data about the current user session */ -import * as express from "express"; +import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -15,39 +15,38 @@ import { ResponseErrorValidation, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; -import * as E from "fp-ts/lib/Either"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import { addSeconds } from "date-fns"; +import * as express from "express"; import * as AP from "fp-ts/lib/Apply"; -import * as TE from "fp-ts/lib/TaskEither"; +import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as ROA from "fp-ts/lib/ReadonlyArray"; - -import { readableReport } from "@pagopa/ts-commons/lib/reporters"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import { pipe, flow, constVoid } from "fp-ts/lib/function"; import { ReadonlyNonEmptyArray } from "fp-ts/lib/ReadonlyNonEmptyArray"; +import * as TE from "fp-ts/lib/TaskEither"; +import { constVoid, flow, pipe } from "fp-ts/lib/function"; import { OutputOf } from "io-ts"; -import { addSeconds } from "date-fns"; -import { - IResponseNoContent, - ResponseNoContent, - withValidatedOrValidationError -} from "../utils/responses"; -import { SuccessResponse } from "../types/commons"; -import LollipopService from "../services/lollipopService"; -import { withFiscalCodeFromRequestParams } from "../types/fiscalCode"; -import RedisSessionStorage from "../services/redisSessionStorage"; -import RedisUserMetadataStorage from "../services/redisUserMetadataStorage"; -import AuthenticationLockService, { - NotReleasedAuthenticationLockData -} from "../services/authenticationLockService"; -import { NotificationServiceFactory } from "../services/notificationServiceFactory"; -import { UserSessionInfo } from "../../generated/session/UserSessionInfo"; import { AuthLockBody } from "../../generated/session/AuthLockBody"; import { AuthUnlockBody } from "../../generated/session/AuthUnlockBody"; -import { SessionState } from "../../generated/session/SessionState"; import { TypeEnum as LoginTypeEnum } from "../../generated/session/SessionInfo"; +import { SessionState } from "../../generated/session/SessionState"; import { UnlockCode } from "../../generated/session/UnlockCode"; +import { UserSessionInfo } from "../../generated/session/UserSessionInfo"; +import AuthenticationLockService, { + NotReleasedAuthenticationLockData +} from "../services/authenticationLockService"; +import LollipopService from "../services/lollipopService"; +import { NotificationServiceFactory } from "../services/notificationServiceFactory"; +import RedisSessionStorage from "../services/redisSessionStorage"; +import RedisUserMetadataStorage from "../services/redisUserMetadataStorage"; +import { SuccessResponse } from "../types/commons"; +import { withFiscalCodeFromRequestParams } from "../types/fiscalCode"; +import { + IResponseNoContent, + ResponseNoContent, + withValidatedOrValidationError +} from "../utils/responses"; const ERROR_CHECK_USER_AUTH_LOCK = "Something went wrong while checking the user authentication lock"; diff --git a/src/controllers/ssoController.ts b/src/controllers/ssoController.ts index 7ffc5e02d..f4da8f7ac 100644 --- a/src/controllers/ssoController.ts +++ b/src/controllers/ssoController.ts @@ -1,13 +1,14 @@ /** * This controller handles requests made from MyPortal. */ -import { Request } from "express"; import { IResponseErrorInternal, IResponseErrorValidation, IResponseSuccessJson, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import { Request } from "express"; + import { MyPortalUser } from "../../generated/myportal/MyPortalUser"; import { withUserFromRequest } from "../types/user"; import { withValidatedOrInternalError } from "../utils/responses"; diff --git a/src/controllers/trialController.ts b/src/controllers/trialController.ts index 58fb447d3..d621181ce 100644 --- a/src/controllers/trialController.ts +++ b/src/controllers/trialController.ts @@ -3,7 +3,6 @@ * forwarding the call to the API system. */ -import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -14,19 +13,19 @@ import { IResponseSuccessRedirectToResource, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; import TrialService from "src/services/trialService"; + +import { Subscription } from "../../generated/trial-system/Subscription"; +import { SubscriptionStateEnum } from "../../generated/trial-system/SubscriptionState"; +import { TrialId } from "../../generated/trial-system-api/TrialId"; import { FF_IO_WALLET_TRIAL_ENABLED, IO_WALLET_TRIAL_ID } from "../../src/config"; -import { TrialId } from "../../generated/trial-system-api/TrialId"; import { withUserFromRequest } from "../types/user"; - import { withValidatedOrValidationError } from "../utils/responses"; -import { Subscription } from "../../generated/trial-system/Subscription"; -import { SubscriptionStateEnum } from "../../generated/trial-system/SubscriptionState"; export default class TrialController { // eslint-disable-next-line max-params diff --git a/src/controllers/userDataProcessingController.ts b/src/controllers/userDataProcessingController.ts index 87ffd305f..c65e93d2b 100644 --- a/src/controllers/userDataProcessingController.ts +++ b/src/controllers/userDataProcessingController.ts @@ -3,7 +3,6 @@ * app by forwarding the call to the API system. */ -import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -13,6 +12,7 @@ import { IResponseSuccessAccepted, IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import { UserDataProcessing } from "../../generated/backend/UserDataProcessing"; import { UserDataProcessingChoice } from "../../generated/backend/UserDataProcessingChoice"; diff --git a/src/controllers/userMetadataController.ts b/src/controllers/userMetadataController.ts index f4be0b463..c4ab370d6 100644 --- a/src/controllers/userMetadataController.ts +++ b/src/controllers/userMetadataController.ts @@ -3,7 +3,6 @@ * redis database through the user metadata storage service. */ -import * as express from "express"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -13,9 +12,8 @@ import { ResponseErrorInternal, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - +import * as express from "express"; import * as E from "fp-ts/lib/Either"; -import { IResponseNoContent, ResponseNoContent } from "../utils/responses"; import { UserMetadata } from "../../generated/backend/UserMetadata"; import { IUserMetadataStorage } from "../services/IUserMetadataStorage"; @@ -24,6 +22,7 @@ import { metadataNotFoundError } from "../services/redisUserMetadataStorage"; import { withUserFromRequest } from "../types/user"; +import { IResponseNoContent, ResponseNoContent } from "../utils/responses"; import { withValidatedOrValidationError } from "../utils/responses"; export default class UserMetadataController { diff --git a/src/server.ts b/src/server.ts index f024d9caa..db0cde646 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,17 +1,18 @@ /** * Main entry point for the Digital Citizenship proxy. */ -import * as http from "http"; -import * as https from "https"; -import * as fs from "fs"; -import * as path from "path"; -import * as appInsights from "applicationinsights"; -import * as O from "fp-ts/lib/Option"; +import { withApplicationInsight } from "@pagopa/io-functions-commons/dist/src/utils/transports/application_insight"; import { NodeEnvironmentEnum } from "@pagopa/ts-commons/lib/environment"; -import { pipe } from "fp-ts/lib/function"; import { useWinstonFor } from "@pagopa/winston-ts"; import { LoggerId } from "@pagopa/winston-ts/dist/types/logging"; -import { withApplicationInsight } from "@pagopa/io-functions-commons/dist/src/utils/transports/application_insight"; +import * as appInsights from "applicationinsights"; +import * as O from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; +import * as fs from "fs"; +import * as http from "http"; +import * as https from "https"; +import * as path from "path"; + import { newApp } from "./app"; import { ALLOW_MYPORTAL_IP_SOURCE_RANGE, @@ -34,11 +35,10 @@ import { TRIAL_SYSTEM_API_BASE_PATH } from "./config"; import { - initAppInsights, StartupEventName, + initAppInsights, trackStartupTime } from "./utils/appinsights"; - import { initHttpGracefulShutdown } from "./utils/gracefulShutdown"; import { log } from "./utils/logger"; import { getCurrentBackendVersion } from "./utils/package"; diff --git a/src/services/ISessionStorage.ts b/src/services/ISessionStorage.ts index a34f09651..e1574e870 100644 --- a/src/services/ISessionStorage.ts +++ b/src/services/ISessionStorage.ts @@ -2,15 +2,16 @@ * Interface for the session storage services. */ +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; + import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; +import { LollipopData } from "../types/assertionRef"; import { MyPortalToken, SessionToken } from "../types/token"; import { User } from "../types/user"; -import { LollipopData } from "../types/assertionRef"; import { ActiveSessionInfo } from "../utils/fastLogin"; export interface ISessionStorage { diff --git a/src/services/IUserMetadataStorage.ts b/src/services/IUserMetadataStorage.ts index 6b60ba278..c218b5d82 100644 --- a/src/services/IUserMetadataStorage.ts +++ b/src/services/IUserMetadataStorage.ts @@ -4,6 +4,7 @@ import { Either } from "fp-ts/lib/Either"; import { UserMetadata } from "generated/backend/UserMetadata"; + import { User } from "../types/user"; export interface IUserMetadataStorage { diff --git a/src/services/authenticationLockService.ts b/src/services/authenticationLockService.ts index 62b575545..b07b7ee30 100644 --- a/src/services/authenticationLockService.ts +++ b/src/services/authenticationLockService.ts @@ -4,21 +4,17 @@ */ import { TableClient, TransactionAction, odata } from "@azure/data-tables"; - -import * as t from "io-ts"; - -import { flow, identity, pipe } from "fp-ts/lib/function"; +import { DateFromString } from "@pagopa/ts-commons/lib/dates"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as ROA from "fp-ts/ReadonlyArray"; import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/lib/Either"; -import * as ROA from "fp-ts/ReadonlyArray"; - -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; -import { DateFromString } from "@pagopa/ts-commons/lib/dates"; - -import { errorsToError } from "../utils/errorsFormatter"; -import * as AI from "../utils/AsyncIterableTask"; +import { flow, identity, pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; import { UnlockCode } from "../../generated/session/UnlockCode"; +import * as AI from "../utils/AsyncIterableTask"; +import { errorsToError } from "../utils/errorsFormatter"; export type NotReleasedAuthenticationLockData = t.TypeOf< typeof NotReleasedAuthenticationLockData diff --git a/src/services/bonusService.ts b/src/services/bonusService.ts index c4a1c3c7f..a216d2f92 100644 --- a/src/services/bonusService.ts +++ b/src/services/bonusService.ts @@ -14,16 +14,17 @@ import { ResponseSuccessAccepted, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as TE from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { PaginatedBonusActivationsCollection } from "generated/io-bonus-api/PaginatedBonusActivationsCollection"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { pipe } from "fp-ts/lib/function"; + import { EligibilityCheck } from "../../generated/io-bonus-api/EligibilityCheck"; import { InstanceId } from "../../generated/io-bonus-api/InstanceId"; - import { BonusAPIClient } from "../clients/bonus"; import { User } from "../types/user"; +import { readableProblem } from "../utils/errorsFormatter"; import { withQrcode } from "../utils/qrcode"; import { ResponseErrorStatusNotDefinedInSpec, @@ -31,7 +32,6 @@ import { withCatchAsInternalError, withValidatedOrInternalError } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; export default class BonusService { constructor(private readonly bonusApiClient: ReturnType) {} diff --git a/src/services/cgnOperatorSearchService.ts b/src/services/cgnOperatorSearchService.ts index d5d4b2967..fc88ca6e8 100644 --- a/src/services/cgnOperatorSearchService.ts +++ b/src/services/cgnOperatorSearchService.ts @@ -1,6 +1,7 @@ /** * This service interacts with the GCN operator search API */ +import { IResponseType } from "@pagopa/ts-commons/lib/requests"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -11,27 +12,26 @@ import { ResponseErrorNotFound, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { IResponseType } from "@pagopa/ts-commons/lib/requests"; +import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; import { DiscountBucketCode } from "generated/io-cgn-operator-search-api/DiscountBucketCode"; import { PublishedProductCategoriesResult } from "generated/io-cgn-operator-search-api/PublishedProductCategoriesResult"; -import { GetPublishedCategoriesParameters } from "generated/parameters/GetPublishedCategoriesParameters"; import { SearchRequest } from "generated/io-cgn-operator-search-api/SearchRequest"; import { SearchResult } from "generated/io-cgn-operator-search-api/SearchResult"; -import { CountResult } from "generated/io-cgn-operator-search-api/CountResult"; +import { GetPublishedCategoriesParameters } from "generated/parameters/GetPublishedCategoriesParameters"; + import { Merchant } from "../../generated/cgn-operator-search/Merchant"; +import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; +import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; +import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; +import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; +import { CgnOperatorSearchAPIClient } from "../../src/clients/cgn-operator-search"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; -import { CgnOperatorSearchAPIClient } from "../../src/clients/cgn-operator-search"; -import { OnlineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OnlineMerchantSearchRequest"; -import { OnlineMerchants } from "../../generated/cgn-operator-search/OnlineMerchants"; -import { OfflineMerchantSearchRequest } from "../../generated/io-cgn-operator-search-api/OfflineMerchantSearchRequest"; -import { OfflineMerchants } from "../../generated/cgn-operator-search/OfflineMerchants"; type ClientResponses = | IResponseType<200, T> diff --git a/src/services/cgnService.ts b/src/services/cgnService.ts index 70d8f97f7..21c2e6cc4 100644 --- a/src/services/cgnService.ts +++ b/src/services/cgnService.ts @@ -2,6 +2,12 @@ * This service interactsnwith the Bonus API */ +import { Card } from "@pagopa/io-functions-cgn-sdk/Card"; +import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; +import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; +import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; +import { InstanceId } from "@pagopa/io-functions-cgn-sdk/InstanceId"; +import { Otp } from "@pagopa/io-functions-cgn-sdk/Otp"; import { IResponseErrorConflict, IResponseErrorForbiddenNotAuthorized, @@ -19,24 +25,18 @@ import { ResponseSuccessJson, ResponseSuccessRedirectToResource } from "@pagopa/ts-commons/lib/responses"; - import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; -import { EycaActivationDetail } from "@pagopa/io-functions-cgn-sdk/EycaActivationDetail"; -import { EycaCard } from "@pagopa/io-functions-cgn-sdk/EycaCard"; -import { InstanceId } from "@pagopa/io-functions-cgn-sdk/InstanceId"; -import { CgnActivationDetail } from "@pagopa/io-functions-cgn-sdk/CgnActivationDetail"; -import { Card } from "@pagopa/io-functions-cgn-sdk/Card"; -import { Otp } from "@pagopa/io-functions-cgn-sdk/Otp"; + import { CgnAPIClient } from "../../src/clients/cgn"; import { User } from "../types/user"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; export default class CgnService { constructor(private readonly cgnApiClient: ReturnType) {} diff --git a/src/services/eucovidcertService.ts b/src/services/eucovidcertService.ts index c324d4386..10f785b2a 100644 --- a/src/services/eucovidcertService.ts +++ b/src/services/eucovidcertService.ts @@ -1,3 +1,5 @@ +import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; +import { PreferredLanguages } from "@pagopa/io-functions-eucovidcerts-sdk/PreferredLanguages"; import { HttpStatusCodeEnum, IResponseErrorForbiddenNotAuthorized, @@ -11,18 +13,15 @@ import { ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; -import { Certificate } from "@pagopa/io-functions-eucovidcerts-sdk/Certificate"; -import { PreferredLanguages } from "@pagopa/io-functions-eucovidcerts-sdk/PreferredLanguages"; -import { readableProblem } from "../utils/errorsFormatter"; import { EUCovidCertAPIClient } from "../clients/eucovidcert.client"; - +import { User } from "../types/user"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError } from "../utils/responses"; -import { User } from "../types/user"; /** * Returns a `504` `Gateway Timeout` error diff --git a/src/services/fimsService.ts b/src/services/fimsService.ts index 4745e8974..ee9b77265 100644 --- a/src/services/fimsService.ts +++ b/src/services/fimsService.ts @@ -14,14 +14,11 @@ import { ResponseSuccessAccepted, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; - import { AccessHistoryPage } from "generated/io-fims-api/AccessHistoryPage"; import { ExportRequest } from "generated/io-fims-api/ExportRequest"; import { IoFimsAPIClient } from "../clients/io-fims"; - import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index 468c39e15..091fc9a46 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -15,17 +15,15 @@ import { ResponseErrorValidation, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - -import * as E from "fp-ts/Either"; - import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { PromiseType } from "@pagopa/ts-commons/lib/types"; +import * as E from "fp-ts/Either"; import { UpsertServicePreference } from "generated/backend/UpsertServicePreference"; import { APIClient } from "src/clients/api"; -import { ServicePreference } from "../../generated/backend/ServicePreference"; -import { ServicePublic } from "../../generated/backend/ServicePublic"; import { PathTraversalSafePathParam } from "../../generated/backend/PathTraversalSafePathParam"; +import { ServicePreference } from "../../generated/backend/ServicePreference"; +import { ServicePublic } from "../../generated/backend/ServicePublic"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, diff --git a/src/services/ioSignService.ts b/src/services/ioSignService.ts index ad11a336a..00eebc5b8 100644 --- a/src/services/ioSignService.ts +++ b/src/services/ioSignService.ts @@ -16,37 +16,33 @@ import { ResponseSuccessJson, ResponseSuccessRedirectToResource } from "@pagopa/ts-commons/lib/responses"; - -import * as O from "fp-ts/lib/Option"; -import { flow, pipe } from "fp-ts/lib/function"; - -import * as t from "io-ts"; - import { EmailString, FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as E from "fp-ts/Either"; -import { CreateSignatureBody as CreateSignatureBodyApiModel } from "../../generated/io-sign-api/CreateSignatureBody"; -import { IssuerEnvironment } from "../../generated/io-sign/IssuerEnvironment"; -import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; -import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; +import * as O from "fp-ts/lib/Option"; +import { flow, pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; + import { FilledDocumentDetailView } from "../../generated/io-sign/FilledDocumentDetailView"; import { Id } from "../../generated/io-sign/Id"; - +import { IssuerEnvironment } from "../../generated/io-sign/IssuerEnvironment"; import { QtspClausesMetadataDetailView } from "../../generated/io-sign/QtspClausesMetadataDetailView"; - import { SignatureDetailView } from "../../generated/io-sign/SignatureDetailView"; import { SignatureRequestDetailView } from "../../generated/io-sign/SignatureRequestDetailView"; +import { CreateSignatureBody as CreateSignatureBodyApiModel } from "../../generated/io-sign-api/CreateSignatureBody"; +import { SignatureRequestList } from "../../generated/io-sign-api/SignatureRequestList"; +import { SignerDetailView } from "../../generated/io-sign-api/SignerDetailView"; import { IoSignAPIClient } from "../clients/io-sign"; +import { IoSignLollipopLocalsType } from "../controllers/ioSignController"; +import { readableProblem } from "../utils/errorsFormatter"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError } from "../utils/responses"; -import { readableProblem } from "../utils/errorsFormatter"; -import { IoSignLollipopLocalsType } from "../controllers/ioSignController"; import { ResponseErrorNotFound403 } from "./eucovidcertService"; const internalServerError = "Internal server error"; diff --git a/src/services/ioWalletService.ts b/src/services/ioWalletService.ts index e0109fc01..4afaa8bdb 100644 --- a/src/services/ioWalletService.ts +++ b/src/services/ioWalletService.ts @@ -3,7 +3,6 @@ */ import { - getResponseErrorForbiddenNotAuthorized, IResponseErrorForbiddenNotAuthorized, IResponseErrorGeneric, IResponseErrorInternal, @@ -16,26 +15,27 @@ import { ResponseErrorNotFound, ResponseErrorServiceTemporarilyUnavailable, ResponseSuccessJson, - ResponseSuccessNoContent + ResponseSuccessNoContent, + getResponseErrorForbiddenNotAuthorized } from "@pagopa/ts-commons/lib/responses"; - import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { NonceDetailView } from "generated/io-wallet-api/NonceDetailView"; -import { Grant_typeEnum } from "generated/io-wallet-api/CreateWalletAttestationBody"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/Option"; +import { pipe } from "fp-ts/lib/function"; +import { Grant_typeEnum } from "generated/io-wallet-api/CreateWalletAttestationBody"; +import { NonceDetailView } from "generated/io-wallet-api/NonceDetailView"; + +import { SetWalletInstanceStatusWithFiscalCodeData } from "../../generated/io-wallet-api/SetWalletInstanceStatusWithFiscalCodeData"; +import { WalletAttestationView } from "../../generated/io-wallet-api/WalletAttestationView"; +import { WalletInstanceData } from "../../generated/io-wallet-api/WalletInstanceData"; +import { Subscription } from "../../generated/trial-system-api/Subscription"; import { IoWalletAPIClient } from "../clients/io-wallet"; +import { TrialSystemAPIClient } from "../clients/trial-system.client"; +import { IO_WALLET_TRIAL_ID } from "../config"; import { ResponseErrorStatusNotDefinedInSpec, withCatchAsInternalError, withValidatedOrInternalError } from "../utils/responses"; -import { IO_WALLET_TRIAL_ID } from "../config"; -import { TrialSystemAPIClient } from "../clients/trial-system.client"; -import { Subscription } from "../../generated/trial-system-api/Subscription"; -import { WalletAttestationView } from "../../generated/io-wallet-api/WalletAttestationView"; -import { SetWalletInstanceStatusWithFiscalCodeData } from "../../generated/io-wallet-api/SetWalletInstanceStatusWithFiscalCodeData"; -import { WalletInstanceData } from "../../generated/io-wallet-api/WalletInstanceData"; const unprocessableContentError = "Unprocessable Content"; const invalidRequest = "Your request didn't validate"; diff --git a/src/services/lollipopService.ts b/src/services/lollipopService.ts index 1cf148deb..040dc1a3b 100644 --- a/src/services/lollipopService.ts +++ b/src/services/lollipopService.ts @@ -1,5 +1,6 @@ import { QueueClient, QueueSendMessageResponse } from "@azure/storage-queue"; import { RevokeAssertionRefInfo } from "@pagopa/io-functions-commons/dist/src/entities/revoke_assertion_ref_info"; + import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; import { base64EncodeObject } from "../utils/messages"; diff --git a/src/services/newMessagesService.ts b/src/services/newMessagesService.ts index 181c6af06..1789e803c 100644 --- a/src/services/newMessagesService.ts +++ b/src/services/newMessagesService.ts @@ -1,56 +1,67 @@ /** * This service retrieves messages from the API system using an API client. */ -import * as t from "io-ts"; -import nodeFetch from "node-fetch"; import { + IResponseErrorBadGateway, IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, - IResponseErrorServiceUnavailable, IResponseErrorNotFound, + IResponseErrorServiceUnavailable, IResponseErrorTooManyRequests, IResponseErrorValidation, IResponseSuccessJson, - ResponseErrorNotFound, - ResponseErrorTooManyRequests, - ResponseSuccessJson, + IResponseSuccessNoContent, + ResponseErrorBadGateway, ResponseErrorForbiddenNotAuthorized, ResponseErrorInternal, - ResponseErrorValidation, + ResponseErrorNotFound, ResponseErrorServiceTemporarilyUnavailable, - IResponseSuccessNoContent, - ResponseErrorBadGateway, - IResponseErrorBadGateway + ResponseErrorTooManyRequests, + ResponseErrorValidation, + ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; -import { AppMessagesAPIClient } from "src/clients/app-messages.client"; import { FiscalCode, NonEmptyString, Ulid } from "@pagopa/ts-commons/lib/strings"; -import { pipe, flow } from "fp-ts/lib/function"; -import * as TE from "fp-ts/TaskEither"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; import * as T from "fp-ts/Task"; -import { LollipopLocalsType } from "src/types/lollipop"; +import * as TE from "fp-ts/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; import { RCConfigurationPublic } from "generated/io-messages-api/RCConfigurationPublic"; -import { - Fetch, - getThirdPartyServiceClient -} from "../clients/third-party-service-client"; -import { PN_SERVICE_ID } from "../config"; -import { MessageSubject } from "../../generated/backend/MessageSubject"; +import * as t from "io-ts"; +import nodeFetch from "node-fetch"; +import { AppMessagesAPIClient } from "src/clients/app-messages.client"; +import { LollipopLocalsType } from "src/types/lollipop"; + +import { CreatedMessageWithContentAndAttachments } from "../../generated/backend/CreatedMessageWithContentAndAttachments"; import { InvalidThirdPartyMessageTypeEnum } from "../../generated/backend/InvalidThirdPartyMessageType"; +import { MessageBodyMarkdown } from "../../generated/backend/MessageBodyMarkdown"; +import { MessageSubject } from "../../generated/backend/MessageSubject"; +import { ThirdPartyData } from "../../generated/backend/ThirdPartyData"; +import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; +import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; import { CreatedMessageWithContent } from "../../generated/io-messages-api/CreatedMessageWithContent"; +import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; +import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; import { PaginatedPublicMessagesCollection } from "../../generated/io-messages-api/PaginatedPublicMessagesCollection"; import { GetMessageParameters } from "../../generated/parameters/GetMessageParameters"; import { GetMessagesParameters } from "../../generated/parameters/GetMessagesParameters"; -import { ThirdPartyMessageWithContent } from "../../generated/backend/ThirdPartyMessageWithContent"; -import { ThirdPartyMessagePrecondition } from "../../generated/backend/ThirdPartyMessagePrecondition"; -import { CreatedMessageWithContentAndAttachments } from "../../generated/backend/CreatedMessageWithContentAndAttachments"; -import { getPrescriptionAttachments } from "../utils/attachments"; +import { + ThirdPartyMessage, + ThirdPartyMessageDetails +} from "../../generated/third-party-service/ThirdPartyMessage"; +import { + Fetch, + getThirdPartyServiceClient +} from "../clients/third-party-service-client"; +import { PN_SERVICE_ID } from "../config"; import { User } from "../types/user"; +import { getPrescriptionAttachments } from "../utils/attachments"; +import { FileType, getIsFileTypeForTypes } from "../utils/file-type"; +import { log } from "../utils/logger"; import { IResponseErrorUnsupportedMediaType, IResponseSuccessOctet, @@ -63,16 +74,6 @@ import { withValidatedOrInternalError, wrapValidationWithInternalError } from "../utils/responses"; -import { MessageStatusChange } from "../../generated/io-messages-api/MessageStatusChange"; -import { MessageStatusAttributes } from "../../generated/io-messages-api/MessageStatusAttributes"; -import { - ThirdPartyMessage, - ThirdPartyMessageDetails -} from "../../generated/third-party-service/ThirdPartyMessage"; -import { ThirdPartyData } from "../../generated/backend/ThirdPartyData"; -import { log } from "../utils/logger"; -import { FileType, getIsFileTypeForTypes } from "../utils/file-type"; -import { MessageBodyMarkdown } from "../../generated/backend/MessageBodyMarkdown"; const ALLOWED_TYPES: ReadonlySet = new Set(["pdf"]); diff --git a/src/services/notificationService.ts b/src/services/notificationService.ts index 22cb01e20..4839411cc 100644 --- a/src/services/notificationService.ts +++ b/src/services/notificationService.ts @@ -2,16 +2,16 @@ * This service post a notification to the Notification queue. */ +import { QueueClient } from "@azure/storage-queue"; import { IResponseErrorInternal, IResponseSuccessJson, ResponseErrorInternal, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - -import { QueueClient } from "@azure/storage-queue"; import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; + import { FiscalCode } from "../../generated/backend/FiscalCode"; import { Installation } from "../../generated/backend/Installation"; import { @@ -29,7 +29,6 @@ import { } from "../../generated/messages/NotifyMessage"; import { Notification } from "../../generated/notifications/Notification"; import { SuccessResponse } from "../../generated/notifications/SuccessResponse"; - import { toFiscalCodeHash } from "../types/notification"; import { base64EncodeObject } from "../utils/messages"; diff --git a/src/services/notificationServiceFactory.ts b/src/services/notificationServiceFactory.ts index e92601528..0ffc98ea5 100644 --- a/src/services/notificationServiceFactory.ts +++ b/src/services/notificationServiceFactory.ts @@ -3,12 +3,11 @@ import * as B from "fp-ts/boolean"; import { flow } from "fp-ts/lib/function"; import { FiscalCode } from "../../generated/io-bonus-api/FiscalCode"; +import { toFiscalCodeHash } from "../types/notification"; import { FeatureFlag, getIsUserEligibleForNewFeature } from "../utils/featureFlag"; -import { toFiscalCodeHash } from "../types/notification"; - import NotificationService from "./notificationService"; /** diff --git a/src/services/pagoPAProxyService.ts b/src/services/pagoPAProxyService.ts index 592f30ace..c4836bdf9 100644 --- a/src/services/pagoPAProxyService.ts +++ b/src/services/pagoPAProxyService.ts @@ -13,7 +13,6 @@ import { PaymentActivationsGetResponse } from "../../generated/backend/PaymentAc import { PaymentActivationsPostResponse } from "../../generated/backend/PaymentActivationsPostResponse"; import { PaymentRequestsGetResponse } from "../../generated/backend/PaymentRequestsGetResponse"; import { PaymentActivationsPostRequest } from "../../generated/pagopa-proxy/PaymentActivationsPostRequest"; - import { ResponsePaymentError, withCatchAsInternalError, diff --git a/src/services/pnService.ts b/src/services/pnService.ts index b1a4b5df6..4c5f7ab04 100644 --- a/src/services/pnService.ts +++ b/src/services/pnService.ts @@ -1,6 +1,6 @@ +import { FiscalCode } from "../../generated/backend/FiscalCode"; import { IoCourtesyDigitalAddressActivation } from "../../generated/piattaforma-notifiche-courtesy/IoCourtesyDigitalAddressActivation"; import { PNClientFactory, PNEnvironment } from "../clients/pn-clients"; -import { FiscalCode } from "../../generated/backend/FiscalCode"; const upsertPnActivationService = (PnAddressBookIOClientSelector: ReturnType) => diff --git a/src/services/profileService.ts b/src/services/profileService.ts index e1c68fa68..82e96f392 100644 --- a/src/services/profileService.ts +++ b/src/services/profileService.ts @@ -3,6 +3,10 @@ * an API client. */ +import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; +import { NewProfile } from "@pagopa/io-functions-app-sdk/NewProfile"; +import { Profile as ProfileApi } from "@pagopa/io-functions-app-sdk/Profile"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -19,17 +23,11 @@ import { ResponseSuccessAccepted, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; - -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; -import { pipe } from "fp-ts/lib/function"; import * as E from "fp-ts/lib/Either"; -import { ExtendedProfile as ExtendedProfileApi } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; -import { NewProfile } from "@pagopa/io-functions-app-sdk/NewProfile"; -import { Profile as ProfileApi } from "@pagopa/io-functions-app-sdk/Profile"; +import { pipe } from "fp-ts/lib/function"; import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { Profile as ProfileBackend } from "../../generated/backend/Profile"; - import { toInitializedProfile } from "../types/profile"; import { User } from "../types/user"; import { diff --git a/src/services/redisSessionStorage.ts b/src/services/redisSessionStorage.ts index 42b94f72e..588212a8f 100644 --- a/src/services/redisSessionStorage.ts +++ b/src/services/redisSessionStorage.ts @@ -2,28 +2,29 @@ * This service uses the Redis client to store and retrieve session information. */ -import { isArray } from "util"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; +import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import * as A from "fp-ts/lib/Array"; -import * as ROA from "fp-ts/lib/ReadonlyArray"; import * as E from "fp-ts/lib/Either"; +import { Either } from "fp-ts/lib/Either"; +import { NonEmptyArray } from "fp-ts/lib/NonEmptyArray"; import * as O from "fp-ts/lib/Option"; -import * as B from "fp-ts/lib/boolean"; +import { Option } from "fp-ts/lib/Option"; +import * as ROA from "fp-ts/lib/ReadonlyArray"; import * as R from "fp-ts/lib/Record"; import * as TE from "fp-ts/lib/TaskEither"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; -import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { TaskEither } from "fp-ts/lib/TaskEither"; -import { Either } from "fp-ts/lib/Either"; -import { Option } from "fp-ts/lib/Option"; -import { flow, pipe, identity } from "fp-ts/lib/function"; -import { NonEmptyArray } from "fp-ts/lib/NonEmptyArray"; -import { - NullableBackendAssertionRefFromString, - LollipopData -} from "../types/assertionRef"; +import * as B from "fp-ts/lib/boolean"; +import { flow, identity, pipe } from "fp-ts/lib/function"; +import { isArray } from "util"; + import { AssertionRef as BackendAssertionRef } from "../../generated/backend/AssertionRef"; import { SessionInfo } from "../../generated/backend/SessionInfo"; import { SessionsList } from "../../generated/backend/SessionsList"; +import { + LollipopData, + NullableBackendAssertionRefFromString +} from "../types/assertionRef"; import { assertUnreachable } from "../types/commons"; import { BPDToken, @@ -34,8 +35,8 @@ import { ZendeskToken } from "../types/token"; import { User, UserV1, UserV2, UserV3, UserV4, UserV5 } from "../types/user"; -import { log } from "../utils/logger"; import { ActiveSessionInfo, LoginTypeEnum } from "../utils/fastLogin"; +import { log } from "../utils/logger"; import { RedisClientMode, RedisClientSelectorType } from "../utils/redis"; import { ISessionStorage } from "./ISessionStorage"; import RedisStorageUtils from "./redisStorageUtils"; diff --git a/src/services/redisStorageUtils.ts b/src/services/redisStorageUtils.ts index df554ce4d..c466952df 100644 --- a/src/services/redisStorageUtils.ts +++ b/src/services/redisStorageUtils.ts @@ -1,8 +1,8 @@ -import { isNumber } from "util"; import * as E from "fp-ts/lib/Either"; import { Either } from "fp-ts/lib/Either"; import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; +import { isNumber } from "util"; export default class RedisStorageUtils { /** diff --git a/src/services/redisUserMetadataStorage.ts b/src/services/redisUserMetadataStorage.ts index ce5962e90..4a0c417b6 100644 --- a/src/services/redisUserMetadataStorage.ts +++ b/src/services/redisUserMetadataStorage.ts @@ -1,12 +1,13 @@ -import * as redis from "redis"; -import * as E from "fp-ts/lib/Either"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as E from "fp-ts/lib/Either"; import { Either } from "fp-ts/lib/Either"; -import * as TE from "fp-ts/lib/TaskEither"; -import * as O from "fp-ts/lib/Option"; import { parse } from "fp-ts/lib/Json"; +import * as O from "fp-ts/lib/Option"; +import * as TE from "fp-ts/lib/TaskEither"; import { flow, pipe } from "fp-ts/lib/function"; +import * as redis from "redis"; + import { UserMetadata } from "../../generated/backend/UserMetadata"; import { User } from "../types/user"; import { log } from "../utils/logger"; diff --git a/src/services/servicesAppBackendService.ts b/src/services/servicesAppBackendService.ts index dde82d822..2bc946b27 100644 --- a/src/services/servicesAppBackendService.ts +++ b/src/services/servicesAppBackendService.ts @@ -6,6 +6,7 @@ import { ResponseErrorNotFound, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; + import { FeaturedServices } from "../../generated/services-app-backend/FeaturedServices"; import { InstitutionServicesResource } from "../../generated/services-app-backend/InstitutionServicesResource"; import { Institutions } from "../../generated/services-app-backend/Institutions"; diff --git a/src/services/trialService.ts b/src/services/trialService.ts index 00d613217..7996e6779 100644 --- a/src/services/trialService.ts +++ b/src/services/trialService.ts @@ -2,33 +2,34 @@ * This service retrieves messages from the API system using an API client. */ import { + IResponseErrorConflict, IResponseErrorInternal, IResponseErrorNotFound, IResponseErrorValidation, - ResponseErrorNotFound, - ResponseErrorInternal, - ResponseErrorValidation, IResponseSuccessAccepted, + IResponseSuccessJson, IResponseSuccessRedirectToResource, - ResponseSuccessRedirectToResource, - ResponseSuccessAccepted, ResponseErrorConflict, - IResponseErrorConflict, - IResponseSuccessJson, - ResponseSuccessJson + ResponseErrorInternal, + ResponseErrorNotFound, + ResponseErrorValidation, + ResponseSuccessAccepted, + ResponseSuccessJson, + ResponseSuccessRedirectToResource } from "@pagopa/ts-commons/lib/responses"; -import { TrialSystemAPIClient } from "src/clients/trial-system.client"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/Option"; +import { pipe } from "fp-ts/lib/function"; +import { TrialSystemAPIClient } from "src/clients/trial-system.client"; + +import { Subscription } from "../../generated/trial-system/Subscription"; +import { TrialId } from "../../generated/trial-system-api/TrialId"; import { ResponseErrorStatusNotDefinedInSpec, ResponseErrorUnexpectedAuthProblem, withCatchAsInternalError, withValidatedOrInternalError } from "../utils/responses"; -import { TrialId } from "../../generated/trial-system-api/TrialId"; -import { Subscription } from "../../generated/trial-system/Subscription"; export default class TrialService { constructor( diff --git a/src/services/userDataProcessingService.ts b/src/services/userDataProcessingService.ts index 427ad9d4a..032c48ab7 100644 --- a/src/services/userDataProcessingService.ts +++ b/src/services/userDataProcessingService.ts @@ -3,6 +3,9 @@ * an API client. */ +import { UserDataProcessing } from "@pagopa/io-functions-app-sdk/UserDataProcessing"; +import { UserDataProcessingChoice } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoice"; +import { UserDataProcessingChoiceRequest } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoiceRequest"; import { IResponseErrorConflict, IResponseErrorInternal, @@ -17,12 +20,9 @@ import { ResponseSuccessAccepted, ResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; -import * as O from "fp-ts/lib/Option"; -import { UserDataProcessing } from "@pagopa/io-functions-app-sdk/UserDataProcessing"; -import { UserDataProcessingChoice } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoice"; -import { UserDataProcessingChoiceRequest } from "@pagopa/io-functions-app-sdk/UserDataProcessingChoiceRequest"; import { User } from "../types/user"; import { unhandledResponseStatus, diff --git a/src/strategies/bearerMyPortalTokenStrategy.ts b/src/strategies/bearerMyPortalTokenStrategy.ts index d2fbbdf59..96a4777bd 100644 --- a/src/strategies/bearerMyPortalTokenStrategy.ts +++ b/src/strategies/bearerMyPortalTokenStrategy.ts @@ -6,10 +6,11 @@ import * as express from "express"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; import * as passport from "passport-http-bearer"; + import { ISessionStorage } from "../services/ISessionStorage"; import { MyPortalToken } from "../types/token"; import { User } from "../types/user"; -import { fulfill, StrategyDoneFunction } from "../utils/strategies"; +import { StrategyDoneFunction, fulfill } from "../utils/strategies"; const bearerMyPortalTokenStrategy = ( sessionStorage: ISessionStorage diff --git a/src/strategies/bearerSessionTokenStrategy.ts b/src/strategies/bearerSessionTokenStrategy.ts index 73750b9a5..045a31701 100644 --- a/src/strategies/bearerSessionTokenStrategy.ts +++ b/src/strategies/bearerSessionTokenStrategy.ts @@ -8,10 +8,11 @@ import { Either } from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import { Option } from "fp-ts/lib/Option"; import * as passport from "passport-http-bearer"; + import { ISessionStorage } from "../services/ISessionStorage"; import { SessionToken } from "../types/token"; import { User } from "../types/user"; -import { fulfill, StrategyDoneFunction } from "../utils/strategies"; +import { StrategyDoneFunction, fulfill } from "../utils/strategies"; const bearerSessionTokenStrategy = ( sessionStorage: ISessionStorage, diff --git a/src/types/IDPEntityDescriptor.ts b/src/types/IDPEntityDescriptor.ts index 107db2da8..951d1a7af 100644 --- a/src/types/IDPEntityDescriptor.ts +++ b/src/types/IDPEntityDescriptor.ts @@ -1,6 +1,6 @@ +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as t from "io-ts"; import { nonEmptyArray as createNonEmptyArrayFromArray } from "io-ts-types/lib/nonEmptyArray"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; export const IDPEntityDescriptor = t.interface({ cert: createNonEmptyArrayFromArray(NonEmptyString), diff --git a/src/types/assertionRef.ts b/src/types/assertionRef.ts index 94cc3c43d..7d22015b5 100644 --- a/src/types/assertionRef.ts +++ b/src/types/assertionRef.ts @@ -1,10 +1,9 @@ -import * as t from "io-ts"; import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; import { JsonFromString } from "io-ts-types"; -import { LoginType } from "../utils/fastLogin"; - import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; +import { LoginType } from "../utils/fastLogin"; // LollipopData export type LollipopData = t.TypeOf; diff --git a/src/types/fiscalCode.ts b/src/types/fiscalCode.ts index ad3e34646..3c4094c2d 100644 --- a/src/types/fiscalCode.ts +++ b/src/types/fiscalCode.ts @@ -1,6 +1,7 @@ -import * as express from "express"; import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import { FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import * as express from "express"; + import { withValidatedOrValidationError } from "../utils/responses"; export const withFiscalCodeFromRequestParams = async ( diff --git a/src/types/lollipop.ts b/src/types/lollipop.ts index 9cdd260ec..e27a82cb4 100644 --- a/src/types/lollipop.ts +++ b/src/types/lollipop.ts @@ -1,35 +1,36 @@ -import * as t from "io-ts"; +import { + IResponseErrorValidation, + ResponseErrorValidation +} from "@pagopa/ts-commons/lib/responses"; import { FiscalCode, NonEmptyString, PatternString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; -import { - IResponseErrorValidation, - ResponseErrorValidation -} from "@pagopa/ts-commons/lib/responses"; import * as E from "fp-ts/Either"; -import { pipe } from "fp-ts/lib/function"; import * as O from "fp-ts/Option"; -import { - JwkPubKeyHashAlgorithm, - JwkPubKeyHashAlgorithmEnum -} from "../../generated/lollipop-api/JwkPubKeyHashAlgorithm"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; + import { AssertionRefSha256 } from "../../generated/backend/AssertionRefSha256"; import { AssertionRefSha384 } from "../../generated/backend/AssertionRefSha384"; import { AssertionRefSha512 } from "../../generated/backend/AssertionRefSha512"; -import { withValidatedOrValidationError } from "../utils/responses"; -import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; -import { AssertionType } from "../../generated/lollipop-api/AssertionType"; -import { JwkPubKeyToken } from "../../generated/lollipop-api/JwkPubKeyToken"; -import { ResLocals } from "../utils/express"; +import { LollipopContentDigest } from "../../generated/lollipop/LollipopContentDigest"; import { LollipopMethod } from "../../generated/lollipop/LollipopMethod"; import { LollipopOriginalURL } from "../../generated/lollipop/LollipopOriginalURL"; import { LollipopSignature } from "../../generated/lollipop/LollipopSignature"; -import { LollipopContentDigest } from "../../generated/lollipop/LollipopContentDigest"; import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; +import { AssertionRef } from "../../generated/lollipop-api/AssertionRef"; +import { AssertionType } from "../../generated/lollipop-api/AssertionType"; +import { + JwkPubKeyHashAlgorithm, + JwkPubKeyHashAlgorithmEnum +} from "../../generated/lollipop-api/JwkPubKeyHashAlgorithm"; +import { JwkPubKeyToken } from "../../generated/lollipop-api/JwkPubKeyToken"; import LollipopService from "../services/lollipopService"; +import { ResLocals } from "../utils/express"; +import { withValidatedOrValidationError } from "../utils/responses"; export interface LollipopParams { readonly isLollipopEnabled: boolean; diff --git a/src/types/notification.ts b/src/types/notification.ts index b720dbce3..7c911088d 100644 --- a/src/types/notification.ts +++ b/src/types/notification.ts @@ -2,9 +2,9 @@ * This file contains the CreatedMessageEventSenderMetadata and Notification models. */ +import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import * as crypto from "crypto"; import * as t from "io-ts"; -import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; import { FiscalCode } from "../../generated/backend/FiscalCode"; diff --git a/src/types/pathParams.ts b/src/types/pathParams.ts index 14644b22f..4eedb5f27 100644 --- a/src/types/pathParams.ts +++ b/src/types/pathParams.ts @@ -1,7 +1,7 @@ -import { pipe } from "fp-ts/lib/function"; -import * as t from "io-ts"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; export type Encoder = (params: ReadonlyArray) => string; diff --git a/src/types/profile.ts b/src/types/profile.ts index 768d8a34b..bc2eb27bc 100644 --- a/src/types/profile.ts +++ b/src/types/profile.ts @@ -2,7 +2,7 @@ * This file contains the ProfileWithEmail and ProfileWithoutEmail models and * some functions to validate and convert type to and from them. */ -import * as O from "fp-ts/lib/Option"; +import { ExtendedProfile } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; import { IResponseErrorInternal, IResponseErrorNotFound, @@ -10,10 +10,10 @@ import { IResponseSuccessJson, ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; +import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; -import { ExtendedProfile } from "@pagopa/io-functions-app-sdk/ExtendedProfile"; -import { InitializedProfile } from "../../generated/backend/InitializedProfile"; +import { InitializedProfile } from "../../generated/backend/InitializedProfile"; import { formatDate } from "../utils/date"; import { User } from "./user"; diff --git a/src/types/token.ts b/src/types/token.ts index 04d9e5e07..dfa460e02 100644 --- a/src/types/token.ts +++ b/src/types/token.ts @@ -1,7 +1,7 @@ -import * as t from "io-ts"; import { tag } from "@pagopa/ts-commons/lib/types"; -import { PecServerConfig } from "src/config"; import * as TE from "fp-ts/TaskEither"; +import * as t from "io-ts"; +import { PecServerConfig } from "src/config"; interface ISessionTokenTag { readonly kind: "SessionToken"; diff --git a/src/types/user.ts b/src/types/user.ts index 0d14435e0..3b4d2746d 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -3,20 +3,19 @@ * validate and convert type to and from them. */ +import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; import * as express from "express"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; -import * as t from "io-ts"; -import { IResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; - import { pipe } from "fp-ts/lib/function"; -import { EmailAddress } from "../../generated/backend/EmailAddress"; -import { FiscalCode } from "../../generated/backend/FiscalCode"; -import { SpidLevel } from "../../generated/backend/SpidLevel"; +import * as t from "io-ts"; import { CieUserIdentity } from "../../generated/auth/CieUserIdentity"; import { SpidUserIdentity } from "../../generated/auth/SpidUserIdentity"; import { UserIdentity } from "../../generated/auth/UserIdentity"; +import { EmailAddress } from "../../generated/backend/EmailAddress"; +import { FiscalCode } from "../../generated/backend/FiscalCode"; +import { SpidLevel } from "../../generated/backend/SpidLevel"; import { withValidatedOrValidationError } from "../utils/responses"; import { BPDToken, diff --git a/src/utils/AsyncIterableTask.ts b/src/utils/AsyncIterableTask.ts index 829ae5526..653cbcc56 100644 --- a/src/utils/AsyncIterableTask.ts +++ b/src/utils/AsyncIterableTask.ts @@ -1,13 +1,12 @@ -import * as T from "fp-ts/lib/Task"; -import * as TE from "fp-ts/lib/TaskEither"; - import { - asyncIterableToPageArray, IPage, + asyncIterableToPageArray, mapAsyncIterator } from "@pagopa/io-functions-commons/dist/src/utils/async"; -import { pipe } from "fp-ts/lib/function"; import { NonNegativeInteger } from "@pagopa/ts-commons/lib/numbers"; +import * as T from "fp-ts/lib/Task"; +import * as TE from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; /** * @category model diff --git a/src/utils/appinsights.ts b/src/utils/appinsights.ts index 8e148cb51..9d761a95d 100644 --- a/src/utils/appinsights.ts +++ b/src/utils/appinsights.ts @@ -1,19 +1,20 @@ -import * as appInsights from "applicationinsights"; +import { + sha256, + validateDigestHeader +} from "@pagopa/io-functions-commons/dist/src/utils/crypto"; import { ApplicationInsightsConfig, initAppInsights as startAppInsights } from "@pagopa/ts-commons/lib/appinsights"; -import { eventLog } from "@pagopa/winston-ts"; import { NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { pipe } from "fp-ts/lib/function"; -import * as O from "fp-ts/lib/Option"; +import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; +import { eventLog } from "@pagopa/winston-ts"; +import * as appInsights from "applicationinsights"; import { Request } from "express"; import * as E from "fp-ts/lib/Either"; -import { - sha256, - validateDigestHeader -} from "@pagopa/io-functions-commons/dist/src/utils/crypto"; -import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; +import * as O from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; + import { LollipopLocalsType } from "../types/lollipop"; import { toFiscalCodeHash } from "../types/notification"; import { User } from "../types/user"; diff --git a/src/utils/attachments.ts b/src/utils/attachments.ts index a3b6bf00f..df14e183f 100644 --- a/src/utils/attachments.ts +++ b/src/utils/attachments.ts @@ -1,10 +1,11 @@ import * as A from "fp-ts/lib/Array"; -import { pipe } from "fp-ts/lib/function"; import * as T from "fp-ts/lib/Task"; import { Task } from "fp-ts/lib/Task"; import * as TE from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { MessageAttachment } from "generated/backend/MessageAttachment"; import { PrescriptionData } from "generated/backend/PrescriptionData"; + import { toBarcode } from "./barcode"; const MIME_TYPES = { diff --git a/src/utils/barcode.ts b/src/utils/barcode.ts index 9d38025e7..e2b994904 100644 --- a/src/utils/barcode.ts +++ b/src/utils/barcode.ts @@ -2,9 +2,10 @@ import * as bwipjs from "bwip-js"; import { ToBufferOptions } from "bwip-js"; import * as AP from "fp-ts/lib/Apply"; import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/lib/TaskEither"; import { TaskEither } from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; + import { BARCODE_ALGORITHM } from "../../src/config"; import { DrawingSVG } from "./bwipjs-svg"; diff --git a/src/utils/container.ts b/src/utils/container.ts index f4335c327..e8eb2add7 100644 --- a/src/utils/container.ts +++ b/src/utils/container.ts @@ -1,4 +1,5 @@ import * as fs from "fs"; + import { log } from "./logger"; /** diff --git a/src/utils/date.ts b/src/utils/date.ts index 3ca878ece..9fd6dd3a6 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,10 +1,10 @@ import { PatternString } from "@pagopa/ts-commons/lib/strings"; import { addYears, format, isAfter } from "date-fns"; -import { pipe } from "fp-ts/lib/function"; +import * as E from "fp-ts/Either"; import { Option, tryCatch } from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; import { FiscalCode } from "generated/backend/FiscalCode"; import * as t from "io-ts"; -import * as E from "fp-ts/Either"; /** * Returns a comparator of two dates that returns true if diff --git a/src/utils/errorsFormatter.ts b/src/utils/errorsFormatter.ts index b5d576f12..5ea984f63 100644 --- a/src/utils/errorsFormatter.ts +++ b/src/utils/errorsFormatter.ts @@ -1,6 +1,6 @@ -import { Errors } from "io-ts"; import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { ProblemJson } from "@pagopa/ts-commons/lib/responses"; +import { Errors } from "io-ts"; /** * Merge into one single Error several errors provided in input and add a context description diff --git a/src/utils/express.ts b/src/utils/express.ts index 0f1ed8cde..9f450fcc9 100644 --- a/src/utils/express.ts +++ b/src/utils/express.ts @@ -1,12 +1,12 @@ -import * as express from "express"; import { IResponse, ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; -import { flow, pipe } from "fp-ts/lib/function"; +import * as express from "express"; import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; import * as TE from "fp-ts/lib/TaskEither"; +import { flow, pipe } from "fp-ts/lib/function"; export type ExpressMiddleware = ( req: express.Request, diff --git a/src/utils/fastLogin.ts b/src/utils/fastLogin.ts index 61a767c9c..9a952c830 100644 --- a/src/utils/fastLogin.ts +++ b/src/utils/fastLogin.ts @@ -1,5 +1,5 @@ -import * as t from "io-ts"; import { enumType } from "@pagopa/ts-commons/lib/types"; +import * as t from "io-ts"; export enum LoginTypeEnum { "LV" = "LV", diff --git a/src/utils/file-type.ts b/src/utils/file-type.ts index 6aa10c70c..58d1b7630 100644 --- a/src/utils/file-type.ts +++ b/src/utils/file-type.ts @@ -1,7 +1,7 @@ -import { pipe } from "fp-ts/lib/function"; +import * as EQ from "fp-ts/Eq"; import * as RS from "fp-ts/ReadonlySet"; +import { pipe } from "fp-ts/lib/function"; import { match } from "ts-pattern"; -import * as EQ from "fp-ts/Eq"; export type FileType = "pdf" | "any"; diff --git a/src/utils/gracefulShutdown.ts b/src/utils/gracefulShutdown.ts index f5d14e5ce..648f5c6ad 100644 --- a/src/utils/gracefulShutdown.ts +++ b/src/utils/gracefulShutdown.ts @@ -1,7 +1,8 @@ -import * as http from "http"; -import * as https from "https"; import { Express } from "express"; +import * as http from "http"; import * as httpGracefulShutdown from "http-graceful-shutdown"; +import * as https from "https"; + import { log } from "./logger"; export function initHttpGracefulShutdown( diff --git a/src/utils/lollipop.ts b/src/utils/lollipop.ts index 639fd6822..92c7a206b 100644 --- a/src/utils/lollipop.ts +++ b/src/utils/lollipop.ts @@ -1,33 +1,34 @@ -import { flow, identity, pipe } from "fp-ts/lib/function"; +import { sha256 } from "@pagopa/io-functions-commons/dist/src/utils/crypto"; +import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; import { IResponseErrorForbiddenNotAuthorized, IResponseErrorInternal, ResponseErrorForbiddenNotAuthorized, ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; -import * as E from "fp-ts/Either"; -import { ulid } from "ulid"; import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; -import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters"; +import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import { eventLog } from "@pagopa/winston-ts"; -import { sha256 } from "@pagopa/io-functions-commons/dist/src/utils/crypto"; -import { Errors } from "io-ts"; +import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; -import { withoutUndefinedValues } from "@pagopa/ts-commons/lib/types"; import * as RA from "fp-ts/ReadonlyArray"; import * as TE from "fp-ts/TaskEither"; -import { RCConfigurationPublic } from "../../generated/io-messages-api/RCConfigurationPublic"; +import { flow, identity, pipe } from "fp-ts/lib/function"; +import { Errors } from "io-ts"; +import { ulid } from "ulid"; + import { AssertionRef } from "../../generated/backend/AssertionRef"; -import { ISessionStorage } from "../services/ISessionStorage"; +import { RCConfigurationPublic } from "../../generated/io-messages-api/RCConfigurationPublic"; +import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; +import { LcParams } from "../../generated/lollipop-api/LcParams"; import { LollipopApiClient } from "../clients/lollipop"; +import { ISessionStorage } from "../services/ISessionStorage"; import { LollipopLocalsType, LollipopRequiredHeaders, Thumbprint, getAlgoFromAssertionRef } from "../types/lollipop"; -import { LollipopSignatureInput } from "../../generated/lollipop/LollipopSignatureInput"; -import { LcParams } from "../../generated/lollipop-api/LcParams"; import { log } from "./logger"; type ErrorsResponses = diff --git a/src/utils/middleware/checkIP.ts b/src/utils/middleware/checkIP.ts index 57915b79b..782dd8db9 100644 --- a/src/utils/middleware/checkIP.ts +++ b/src/utils/middleware/checkIP.ts @@ -2,12 +2,13 @@ * An Express middleware that checks if source IP falls into a CIDR range. */ -import * as express from "express"; -import * as E from "fp-ts/lib/Either"; import { readableReport } from "@pagopa/ts-commons/lib/reporters"; import { CIDR, IPString } from "@pagopa/ts-commons/lib/strings"; -import * as rangeCheck from "range_check"; +import * as express from "express"; +import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; +import * as rangeCheck from "range_check"; + import { log } from "../logger"; import { decodeIPAddressFromReq } from "../network"; diff --git a/src/utils/middleware/dueDate.ts b/src/utils/middleware/dueDate.ts index 0a555c750..5ab182d41 100644 --- a/src/utils/middleware/dueDate.ts +++ b/src/utils/middleware/dueDate.ts @@ -1,5 +1,6 @@ -import { NextFunction, Request, Response } from "express"; import { ResponseErrorNotFound } from "@pagopa/ts-commons/lib/responses"; +import { NextFunction, Request, Response } from "express"; + import { log } from "../logger"; /** diff --git a/src/utils/middleware/express.ts b/src/utils/middleware/express.ts index 6edf8deb3..6de29cd6c 100644 --- a/src/utils/middleware/express.ts +++ b/src/utils/middleware/express.ts @@ -1,5 +1,6 @@ -import { NextFunction, Request, Response } from "express"; import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; +import { NextFunction, Request, Response } from "express"; + import { log } from "../logger"; /** diff --git a/src/utils/middleware/lollipop.ts b/src/utils/middleware/lollipop.ts index e2a7ba7a9..220ae76f5 100644 --- a/src/utils/middleware/lollipop.ts +++ b/src/utils/middleware/lollipop.ts @@ -1,21 +1,22 @@ -import { Request, Response, NextFunction } from "express"; -import * as TE from "fp-ts/TaskEither"; -import { pipe } from "fp-ts/lib/function"; import { ResponseErrorInternal } from "@pagopa/ts-commons/lib/responses"; +import { NextFunction, Request, Response } from "express"; import * as E from "fp-ts/Either"; import * as O from "fp-ts/Option"; +import * as TE from "fp-ts/TaskEither"; +import { pipe } from "fp-ts/lib/function"; + +import { LollipopApiClient } from "../../clients/lollipop"; +import { ISessionStorage } from "../../services/ISessionStorage"; +import { withLollipopHeadersFromRequest } from "../../types/lollipop"; import { withOptionalUserFromRequest, withUserFromRequest } from "../../types/user"; -import { LollipopApiClient } from "../../clients/lollipop"; -import { withLollipopHeadersFromRequest } from "../../types/lollipop"; import { log } from "../logger"; import { extractLollipopLocalsFromLollipopHeaders, extractLollipopLocalsFromLollipopHeadersLegacy } from "../lollipop"; -import { ISessionStorage } from "../../services/ISessionStorage"; /** * @deprecated diff --git a/src/utils/network.ts b/src/utils/network.ts index 310a34158..57c8a6ad5 100644 --- a/src/utils/network.ts +++ b/src/utils/network.ts @@ -1,7 +1,7 @@ -import { Either } from "fp-ts/lib/Either"; -import { array, Errors } from "io-ts"; import { CIDR, IPString } from "@pagopa/ts-commons/lib/strings"; import * as express from "express"; +import { Either } from "fp-ts/lib/Either"; +import { Errors, array } from "io-ts"; /** * Parse a comma separated string of CIDR(s) or IP(s) into an array diff --git a/src/utils/ognl.ts b/src/utils/ognl.ts index f635ce1ad..4b3d5b8e3 100644 --- a/src/utils/ognl.ts +++ b/src/utils/ognl.ts @@ -1,7 +1,7 @@ -import { pipe } from "fp-ts/function"; +import * as E from "fp-ts/Either"; import * as R from "fp-ts/Record"; +import { pipe } from "fp-ts/function"; import * as t from "io-ts"; -import * as E from "fp-ts/Either"; /** * Porting of lodash "set" function. diff --git a/src/utils/package.ts b/src/utils/package.ts index 88298d9a8..152cd568b 100644 --- a/src/utils/package.ts +++ b/src/utils/package.ts @@ -1,8 +1,9 @@ -import * as O from "fp-ts/lib/Option"; import * as E from "fp-ts/lib/Either"; -import * as t from "io-ts"; -import { pipe } from "fp-ts/lib/function"; +import * as O from "fp-ts/lib/Option"; import { Option } from "fp-ts/lib/Option"; +import { pipe } from "fp-ts/lib/function"; +import * as t from "io-ts"; + import * as packageJson from "../../package.json"; /** diff --git a/src/utils/profile.ts b/src/utils/profile.ts index bd41ff00c..4ef323b3c 100644 --- a/src/utils/profile.ts +++ b/src/utils/profile.ts @@ -1,12 +1,13 @@ -import * as TE from "fp-ts/lib/TaskEither"; -import * as E from "fp-ts/lib/Either"; -import * as t from "io-ts"; import { IResponseSuccessJson } from "@pagopa/ts-commons/lib/responses"; +import * as E from "fp-ts/lib/Either"; +import * as TE from "fp-ts/lib/TaskEither"; import { pipe } from "fp-ts/lib/function"; -import { User } from "../../src/types/user"; -import ProfileService from "../../src/services/profileService"; -import { InitializedProfile } from "../../generated/backend/InitializedProfile"; +import * as t from "io-ts"; + import { EmailAddress } from "../../generated/backend/EmailAddress"; +import { InitializedProfile } from "../../generated/backend/InitializedProfile"; +import ProfileService from "../../src/services/profileService"; +import { User } from "../../src/types/user"; // define a type that represents a Profile with a non optional email address const ProfileWithEmail = t.intersection([ diff --git a/src/utils/qrcode.ts b/src/utils/qrcode.ts index cfc5c0f88..ff5866757 100644 --- a/src/utils/qrcode.ts +++ b/src/utils/qrcode.ts @@ -1,8 +1,8 @@ import * as AP from "fp-ts/lib/Apply"; import * as E from "fp-ts/lib/Either"; -import { pipe } from "fp-ts/lib/function"; import * as TE from "fp-ts/lib/TaskEither"; import { TaskEither } from "fp-ts/lib/TaskEither"; +import { pipe } from "fp-ts/lib/function"; import { BonusActivationWithQrCode } from "generated/bonus/BonusActivationWithQrCode"; import { BonusActivation } from "generated/io-bonus-api/BonusActivation"; import { image } from "qr-image"; diff --git a/src/utils/redis.ts b/src/utils/redis.ts index 437dccda5..3963d95ad 100644 --- a/src/utils/redis.ts +++ b/src/utils/redis.ts @@ -1,8 +1,9 @@ -import * as redis from "redis"; import * as appInsights from "applicationinsights"; -import { pipe } from "fp-ts/lib/function"; -import * as RA from "fp-ts/lib/ReadonlyArray"; import * as O from "fp-ts/lib/Option"; +import * as RA from "fp-ts/lib/ReadonlyArray"; +import { pipe } from "fp-ts/lib/function"; +import * as redis from "redis"; + import { keyPrefixes } from "../services/redisSessionStorage"; import { log } from "./logger"; diff --git a/src/utils/responses.ts b/src/utils/responses.ts index 470a86cb5..125b5fba2 100644 --- a/src/utils/responses.ts +++ b/src/utils/responses.ts @@ -1,14 +1,8 @@ -import * as express from "express"; -import { PaymentFaultEnum } from "generated/pagopa-proxy/PaymentFault"; -import { PaymentFaultV2Enum } from "generated/pagopa-proxy/PaymentFaultV2"; -import { PaymentProblemJson } from "generated/pagopa-proxy/PaymentProblemJson"; -import * as t from "io-ts"; -import * as E from "fp-ts/lib/Either"; -import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { IWithinRangeIntegerTag, WithinRangeInteger } from "@pagopa/ts-commons/lib/numbers"; +import { errorsToReadableMessages } from "@pagopa/ts-commons/lib/reporters"; import { HttpStatusCodeEnum, IResponse, @@ -19,8 +13,15 @@ import { ResponseErrorNotFound, ResponseErrorValidation } from "@pagopa/ts-commons/lib/responses"; +import * as express from "express"; import * as TE from "fp-ts/TaskEither"; +import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; +import { PaymentFaultEnum } from "generated/pagopa-proxy/PaymentFault"; +import { PaymentFaultV2Enum } from "generated/pagopa-proxy/PaymentFaultV2"; +import { PaymentProblemJson } from "generated/pagopa-proxy/PaymentProblemJson"; +import * as t from "io-ts"; + import { errorsToError } from "./errorsFormatter"; /** diff --git a/src/utils/strategies.ts b/src/utils/strategies.ts index d4f52efd4..1ee85b5b0 100644 --- a/src/utils/strategies.ts +++ b/src/utils/strategies.ts @@ -1,9 +1,10 @@ +import * as E from "fp-ts/Either"; +import * as O from "fp-ts/Option"; import { Either } from "fp-ts/lib/Either"; import { Option } from "fp-ts/lib/Option"; -import { IVerifyOptions } from "passport-http-bearer"; -import * as E from "fp-ts/Either"; import { pipe } from "fp-ts/lib/function"; -import * as O from "fp-ts/Option"; +import { IVerifyOptions } from "passport-http-bearer"; + import { User } from "../types/user"; export type StrategyDoneFunction = ( diff --git a/src/utils/thirdPartyConfig.ts b/src/utils/thirdPartyConfig.ts index fe106b76f..b91cd5b85 100644 --- a/src/utils/thirdPartyConfig.ts +++ b/src/utils/thirdPartyConfig.ts @@ -1,9 +1,7 @@ /* eslint-disable sort-keys */ -import * as t from "io-ts"; - import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings"; - +import * as t from "io-ts"; import { BooleanFromString, JsonFromString, withFallback } from "io-ts-types"; export const ClientCert = t.interface({ diff --git a/src/utils/url.ts b/src/utils/url.ts index 14fdd1bb5..976cde102 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,6 +1,6 @@ import { ValidUrl } from "@pagopa/ts-commons/lib/url"; -import { identity, pipe } from "fp-ts/lib/function"; import * as E from "fp-ts/lib/Either"; +import { identity, pipe } from "fp-ts/lib/function"; import * as S from "fp-ts/lib/string"; export const stripTrailingSlashIfPresent = (aValidUrl: ValidUrl): string => From 973a75b9526d47488aaa00548b0949235866698d Mon Sep 17 00:00:00 2001 From: Roberto Cocco Date: Mon, 3 Feb 2025 16:49:09 +0100 Subject: [PATCH 13/13] Remove @azure/functions dependency --- package.json | 2 +- yarn.lock | 48 +++++------------------------------------------- 2 files changed, 6 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 10f4c974a..352e2f537 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,6 @@ "homepage": "https://github.com/pagopa/io-backend#readme", "dependencies": { "@azure/data-tables": "^13.2.2", - "@azure/functions": "^3.2.0", "@azure/storage-queue": "^12.0.0", "@pagopa/io-functions-app-sdk": "x", "@pagopa/io-functions-cgn-sdk": "x", @@ -204,6 +203,7 @@ "handlebars": "~4.5.3", "applicationinsights": "~2.9.5", "@types/serve-static": "1.13.10", + "@types/node": "^20.17.0", "@types/express-serve-static-core": "4.17.34" } } diff --git a/yarn.lock b/yarn.lock index d2502fc58..4b2d54ad0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -178,15 +178,6 @@ "@azure/logger" "^1.0.0" tslib "^2.2.0" -"@azure/functions@^3.2.0": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@azure/functions/-/functions-3.5.1.tgz#98ac5c18f84835fd5821de404c52abbd458871f6" - integrity sha512-6UltvJiuVpvHSwLcK/Zc6NfUwlkDLOFFx97BHCJzlWNsfiWwzwmTsxJXg4kE/LemKTHxPpfoPE+kOJ8hAdiKFQ== - dependencies: - iconv-lite "^0.6.3" - long "^4.0.0" - uuid "^8.3.0" - "@azure/logger@^1.0.0": version "1.1.4" resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.1.4.tgz#223cbf2b424dfa66478ce9a4f575f59c6f379768" @@ -1340,14 +1331,7 @@ "@types/node" "*" form-data "^4.0.0" -"@types/node@*": - version "22.12.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.12.0.tgz#bf8af3b2af0837b5a62a368756ff2b705ae0048c" - integrity sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA== - dependencies: - undici-types "~6.20.0" - -"@types/node@^20.17.0": +"@types/node@*", "@types/node@^20.17.0": version "20.17.16" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.16.tgz#b33b0edc1bf925b27349e494b871ca4451fabab4" integrity sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw== @@ -3766,13 +3750,6 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -3791,9 +3768,9 @@ import-cwd@^3.0.0: import-from "^3.0.0" import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -4930,11 +4907,6 @@ lolex@4.2.0: resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7" integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg== -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -6118,7 +6090,7 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -6960,11 +6932,6 @@ undici-types@~6.19.2: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== -undici-types@~6.20.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" - integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== - unherit@^1.0.4: version "1.1.3" resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" @@ -7080,11 +7047,6 @@ uuid@^3.0.0, uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - v8-to-istanbul@^9.0.1: version "9.3.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175"